/ CFBundle_Grok.c
CFBundle_Grok.c
1 /* 2 * Copyright (c) 2015 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 /* CFBundle_Grok.c 25 Copyright (c) 1999-2014, Apple Inc. All rights reserved. 26 Responsibility: Tony Parker 27 */ 28 29 #include "CFBundle_Internal.h" 30 31 #if defined(BINARY_SUPPORT_DYLD) 32 // Import the mach-o headers that define the macho magic numbers 33 #include <mach-o/loader.h> 34 #include <mach-o/fat.h> 35 #include <mach-o/arch.h> 36 #include <mach-o/dyld.h> 37 #include <mach-o/getsect.h> 38 #include <unistd.h> 39 #include <fcntl.h> 40 #include <sys/mman.h> 41 #include <crt_externs.h> 42 #if defined(USE_DYLD_PRIV) 43 #include <mach-o/dyld_priv.h> 44 #endif /* USE_DYLD_PRIV */ 45 #endif /* BINARY_SUPPORT_DYLD */ 46 47 #if defined(BINARY_SUPPORT_DLFCN) 48 #include <dlfcn.h> 49 #endif /* BINARY_SUPPORT_DLFCN */ 50 51 #include <sys/stat.h> 52 #include <ctype.h> 53 54 #if DEPLOYMENT_TARGET_WINDOWS 55 #define statinfo _stat 56 #define stat(x,y) _NS_stat(x,y) 57 #define open _NS_open 58 #define MAP_FAILED 0 59 60 // Windows isspace implementation limits the input chars to < 256 in the ASCII range. It will 61 // assert in debug builds. This is annoying. We merrily grok chars > 256. 62 static inline BOOL isspace(char c) { 63 return (c == ' ' || c == '\t' || c == '\n' || c == '\r'|| c == '\v' || c == '\f'); 64 } 65 66 #else 67 #define statinfo stat 68 #endif 69 70 #define UNKNOWN_FILETYPE 0x0 71 #define PEF_FILETYPE 0x1000 72 #define PEF_MAGIC 0x4a6f7921 73 #define PEF_CIGAM 0x21796f4a 74 #define TEXT_SEGMENT "__TEXT" 75 #define PLIST_SECTION "__info_plist" 76 #define OBJC_SEGMENT "__OBJC" 77 #define IMAGE_INFO_SECTION "__image_info" 78 #define OBJC_SEGMENT_64 "__DATA" 79 #define IMAGE_INFO_SECTION_64 "__objc_imageinfo" 80 #define LIB_X11 "/usr/X11R6/lib/libX" 81 82 #define XLS_NAME "Book" 83 #define XLS_NAME2 "Workbook" 84 #define DOC_NAME "WordDocument" 85 #define PPT_NAME "PowerPoint Document" 86 87 #define ustrncmp(x, y, z) strncmp((char *)(x), (char *)(y), (z)) 88 #define ustrncasecmp(x, y, z) strncasecmp_l((char *)(x), (char *)(y), (z), NULL) 89 90 static const uint32_t __CFBundleMagicNumbersArray[] = { 91 0xcafebabe, 0xbebafeca, 0xfeedface, 0xcefaedfe, 0xfeedfacf, 0xcffaedfe, 0x4a6f7921, 0x21796f4a, 92 0x7f454c46, 0xffd8ffe0, 0x4d4d002a, 0x49492a00, 0x47494638, 0x89504e47, 0x69636e73, 0x00000100, 93 0x7b5c7274, 0x25504446, 0x2e7261fd, 0x2e524d46, 0x2e736e64, 0x2e736400, 0x464f524d, 0x52494646, 94 0x38425053, 0x000001b3, 0x000001ba, 0x4d546864, 0x504b0304, 0x53495421, 0x53495432, 0x53495435, 95 0x53495444, 0x53747566, 0x30373037, 0x3c212d2d, 0x25215053, 0xd0cf11e0, 0x62656769, 0x3d796265, 96 0x6b6f6c79, 0x3026b275, 0x0000000c, 0xfe370023, 0x09020600, 0x09040600, 0x4f676753, 0x664c6143, 97 0x00010000, 0x74727565, 0x4f54544f, 0x41433130, 0xc809fe02, 0x0809fe02, 0x2356524d, 0x67696d70, 98 0x3c435058, 0x28445746, 0x424f4d53, 0x49544f4c, 0x72746664, 0x63616666, 0x802a5fd7, 0x762f3101 99 }; 100 101 // string, with groups of 5 characters being 1 element in the array 102 static const char * __CFBundleExtensionsArray = 103 "mach\0" "mach\0" "mach\0" "mach\0" "mach\0" "mach\0" "pef\0\0" "pef\0\0" 104 "elf\0\0" "jpeg\0" "tiff\0" "tiff\0" "gif\0\0" "png\0\0" "icns\0" "ico\0\0" 105 "rtf\0\0" "pdf\0\0" "ra\0\0\0""rm\0\0\0""au\0\0\0""au\0\0\0""iff\0\0" "riff\0" 106 "psd\0\0" "mpeg\0" "mpeg\0" "mid\0\0" "zip\0\0" "sit\0\0" "sit\0\0" "sit\0\0" 107 "sit\0\0" "sit\0\0" "cpio\0" "html\0" "ps\0\0\0""ole\0\0" "uu\0\0\0""ync\0\0" 108 "dmg\0\0" "wmv\0\0" "jp2\0\0" "doc\0\0" "xls\0\0" "xls\0\0" "ogg\0\0" "flac\0" 109 "ttf\0\0" "ttf\0\0" "otf\0\0" "dwg\0\0" "dgn\0\0" "dgn\0\0" "wrl\0\0" "xcf\0\0" 110 "cpx\0\0" "dwf\0\0" "bom\0\0" "lit\0\0" "rtfd\0" "caf\0\0" "cin\0\0" "exr\0\0"; 111 112 static const char * __CFBundleOOExtensionsArray = "sxc\0\0" "sxd\0\0" "sxg\0\0" "sxi\0\0" "sxm\0\0" "sxw\0\0"; 113 static const char * __CFBundleODExtensionsArray = "odc\0\0" "odf\0\0" "odg\0\0" "oth\0\0" "odi\0\0" "odm\0\0" "odp\0\0" "ods\0\0" "odt\0\0"; 114 115 #define EXTENSION_LENGTH 5 116 #define NUM_EXTENSIONS 64 117 #define MAGIC_BYTES_TO_READ 512 118 #define DMG_BYTES_TO_READ 512 119 #define ZIP_BYTES_TO_READ 1024 120 #define OLE_BYTES_TO_READ 512 121 #define X11_BYTES_TO_READ 4096 122 #define IMAGE_INFO_BYTES_TO_READ 4096 123 124 #if defined(BINARY_SUPPORT_DYLD) 125 126 static CFMutableDictionaryRef _CFBundleCreateInfoDictFromData(const char *bytes, uint32_t length) { 127 CFMutableDictionaryRef result = NULL; 128 CFDataRef infoData = NULL; 129 if (bytes && 0 < length) { 130 infoData = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (uint8_t *)bytes, length, kCFAllocatorNull); 131 if (infoData) { 132 result = (CFMutableDictionaryRef)CFPropertyListCreateWithData(kCFAllocatorSystemDefault, infoData, kCFPropertyListMutableContainers, NULL, NULL); 133 if (result && CFDictionaryGetTypeID() != CFGetTypeID(result)) { 134 CFRelease(result); 135 result = NULL; 136 } 137 CFRelease(infoData); 138 } 139 if (!result) result = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 140 } 141 if (result) _CFBundleInfoPlistProcessInfoDictionary((CFMutableDictionaryRef)result); 142 return result; 143 } 144 145 static char *_CFBundleGetSectData(const char *segname, const char *sectname, unsigned long *size) { 146 char *retval = NULL; 147 unsigned long localSize = 0; 148 uint32_t i, numImages = _dyld_image_count(); 149 const void *mhp = (const void *)_NSGetMachExecuteHeader(); 150 151 for (i = 0; i < numImages; i++) { 152 if (mhp == (void *)_dyld_get_image_header(i)) { 153 #if __LP64__ 154 const struct section_64 *sp = getsectbynamefromheader_64((const struct mach_header_64 *)mhp, segname, sectname); 155 if (sp) { 156 retval = (char *)(sp->addr + _dyld_get_image_vmaddr_slide(i)); 157 localSize = (unsigned long)sp->size; 158 } 159 #else /* __LP64__ */ 160 const struct section *sp = getsectbynamefromheader((const struct mach_header *)mhp, segname, sectname); 161 if (sp) { 162 retval = (char *)(sp->addr + _dyld_get_image_vmaddr_slide(i)); 163 localSize = (unsigned long)sp->size; 164 } 165 #endif /* __LP64__ */ 166 break; 167 } 168 } 169 if (size) *size = localSize; 170 return retval; 171 } 172 173 CF_PRIVATE CFMutableDictionaryRef _CFBundleCreateInfoDictFromMainExecutable() { 174 char *bytes = NULL; 175 unsigned long length = 0; 176 if (getsegbyname(TEXT_SEGMENT)) bytes = _CFBundleGetSectData(TEXT_SEGMENT, PLIST_SECTION, &length); 177 return _CFBundleCreateInfoDictFromData(bytes, length); 178 } 179 180 CF_PRIVATE Boolean _CFBundleGrokObjCImageInfoFromMainExecutable(uint32_t *objcVersion, uint32_t *objcFlags) { 181 Boolean retval = false; 182 uint32_t localVersion = 0, localFlags = 0; 183 char *bytes = NULL; 184 unsigned long length = 0; 185 #if __LP64__ 186 if (getsegbyname(OBJC_SEGMENT_64)) bytes = _CFBundleGetSectData(OBJC_SEGMENT_64, IMAGE_INFO_SECTION_64, &length); 187 #else /* __LP64__ */ 188 if (getsegbyname(OBJC_SEGMENT)) bytes = _CFBundleGetSectData(OBJC_SEGMENT, IMAGE_INFO_SECTION, &length); 189 #endif /* __LP64__ */ 190 if (bytes && length >= 8) { 191 localVersion = *(uint32_t *)bytes; 192 localFlags = *(uint32_t *)(bytes + 4); 193 retval = true; 194 } 195 if (objcVersion) *objcVersion = localVersion; 196 if (objcFlags) *objcFlags = localFlags; 197 return retval; 198 } 199 200 static Boolean _CFBundleGrokX11FromFile(int fd, const void *bytes, CFIndex length, uint32_t offset, Boolean swapped, Boolean sixtyFour) { 201 static const char libX11name[] = LIB_X11; 202 char *buffer = NULL; 203 const char *loc = NULL; 204 unsigned i; 205 Boolean result = false; 206 207 if (fd >= 0 && lseek(fd, offset, SEEK_SET) == (off_t)offset) { 208 buffer = malloc(X11_BYTES_TO_READ); 209 if (buffer && read(fd, buffer, X11_BYTES_TO_READ) >= X11_BYTES_TO_READ) loc = buffer; 210 } else if (bytes && length >= offset + X11_BYTES_TO_READ) { 211 loc = bytes + offset; 212 } 213 if (loc) { 214 if (sixtyFour) { 215 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)loc)->ncmds, swapped); 216 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)loc)->sizeofcmds, swapped); 217 const char *startofcmds = loc + sizeof(struct mach_header_64); 218 const char *endofcmds = startofcmds + sizeofcmds; 219 struct dylib_command *dlp = (struct dylib_command *)startofcmds; 220 if (endofcmds > loc + X11_BYTES_TO_READ) endofcmds = loc + X11_BYTES_TO_READ; 221 for (i = 0; !result && i < ncmds && startofcmds <= (char *)dlp && (char *)dlp < endofcmds; i++) { 222 if (LC_LOAD_DYLIB == _CFBundleSwapInt32Conditional(dlp->cmd, swapped)) { 223 uint32_t nameoffset = _CFBundleSwapInt32Conditional(dlp->dylib.name.offset, swapped); 224 const char *name = (const char *)dlp + nameoffset; 225 if (startofcmds <= name && name + sizeof(libX11name) <= endofcmds && 0 == strncmp(name, libX11name, sizeof(libX11name) - 1)) result = true; 226 } 227 dlp = (struct dylib_command *)((char *)dlp + _CFBundleSwapInt32Conditional(dlp->cmdsize, swapped)); 228 } 229 } else { 230 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header *)loc)->ncmds, swapped); 231 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header *)loc)->sizeofcmds, swapped); 232 const char *startofcmds = loc + sizeof(struct mach_header); 233 const char *endofcmds = startofcmds + sizeofcmds; 234 struct dylib_command *dlp = (struct dylib_command *)startofcmds; 235 if (endofcmds > loc + X11_BYTES_TO_READ) endofcmds = loc + X11_BYTES_TO_READ; 236 for (i = 0; !result && i < ncmds && startofcmds <= (char *)dlp && (char *)dlp < endofcmds; i++) { 237 if (LC_LOAD_DYLIB == _CFBundleSwapInt32Conditional(dlp->cmd, swapped)) { 238 uint32_t nameoffset = _CFBundleSwapInt32Conditional(dlp->dylib.name.offset, swapped); 239 const char *name = (const char *)dlp + nameoffset; 240 if (startofcmds <= name && name + sizeof(libX11name) <= endofcmds && 0 == strncmp(name, libX11name, sizeof(libX11name) - 1)) result = true; 241 } 242 dlp = (struct dylib_command *)((char *)dlp + _CFBundleSwapInt32Conditional(dlp->cmdsize, swapped)); 243 } 244 } 245 } 246 if (buffer) free(buffer); 247 return result; 248 } 249 250 static CFDictionaryRef _CFBundleCreateInfoDictFromFile(int fd, const void *bytes, CFIndex length, uint32_t offset, Boolean swapped, Boolean sixtyFour) { 251 struct statinfo statBuf; 252 off_t fileLength = 0; 253 char *maploc = NULL; 254 const char *loc; 255 unsigned i, j; 256 CFDictionaryRef result = NULL; 257 Boolean foundit = false; 258 if (fd >= 0 && fstat(fd, &statBuf) == 0 && (maploc = mmap(0, statBuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) != (void *)-1) { 259 loc = maploc; 260 fileLength = statBuf.st_size; 261 } else { 262 loc = bytes; 263 fileLength = length; 264 } 265 if (fileLength > offset + sizeof(struct mach_header_64)) { 266 if (sixtyFour) { 267 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)(loc + offset))->ncmds, swapped); 268 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)(loc + offset))->sizeofcmds, swapped); 269 const char *startofcmds = loc + offset + sizeof(struct mach_header_64); 270 const char *endofcmds = startofcmds + sizeofcmds; 271 struct segment_command_64 *sgp = (struct segment_command_64 *)startofcmds; 272 if (endofcmds > loc + fileLength) endofcmds = loc + fileLength; 273 for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) { 274 if (LC_SEGMENT_64 == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) { 275 struct section_64 *sp = (struct section_64 *)((char *)sgp + sizeof(struct segment_command_64)); 276 uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped); 277 for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) { 278 if (0 == strncmp(sp->sectname, PLIST_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, TEXT_SEGMENT, sizeof(sp->segname))) { 279 uint64_t sectlength64 = _CFBundleSwapInt64Conditional(sp->size, swapped); 280 uint32_t sectlength = (uint32_t)(sectlength64 & 0xffffffff); 281 uint32_t sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped); 282 const char *sectbytes = loc + offset + sectoffset; 283 // we don't support huge-sized plists 284 if (sectlength64 <= 0xffffffff && loc <= sectbytes && sectbytes + sectlength <= loc + fileLength) result = (CFDictionaryRef)_CFBundleCreateInfoDictFromData(sectbytes, sectlength); 285 foundit = true; 286 } 287 sp = (struct section_64 *)((char *)sp + sizeof(struct section_64)); 288 } 289 } 290 sgp = (struct segment_command_64 *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped)); 291 } 292 } else { 293 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header *)(loc + offset))->ncmds, swapped); 294 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header *)(loc + offset))->sizeofcmds, swapped); 295 const char *startofcmds = loc + offset + sizeof(struct mach_header); 296 const char *endofcmds = startofcmds + sizeofcmds; 297 struct segment_command *sgp = (struct segment_command *)startofcmds; 298 if (endofcmds > loc + fileLength) endofcmds = loc + fileLength; 299 for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) { 300 if (LC_SEGMENT == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) { 301 struct section *sp = (struct section *)((char *)sgp + sizeof(struct segment_command)); 302 uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped); 303 for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) { 304 if (0 == strncmp(sp->sectname, PLIST_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, TEXT_SEGMENT, sizeof(sp->segname))) { 305 uint32_t sectlength = _CFBundleSwapInt32Conditional(sp->size, swapped); 306 uint32_t sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped); 307 const char *sectbytes = loc + offset + sectoffset; 308 if (loc <= sectbytes && sectbytes + sectlength <= loc + fileLength) result = (CFDictionaryRef)_CFBundleCreateInfoDictFromData(sectbytes, sectlength); 309 foundit = true; 310 } 311 sp = (struct section *)((char *)sp + sizeof(struct section)); 312 } 313 } 314 sgp = (struct segment_command *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped)); 315 } 316 } 317 } 318 if (maploc) munmap(maploc, statBuf.st_size); 319 return result; 320 } 321 322 static void _CFBundleGrokObjcImageInfoFromFile(int fd, const void *bytes, CFIndex length, uint32_t offset, Boolean swapped, Boolean sixtyFour, Boolean *hasObjc, uint32_t *objcVersion, uint32_t *objcFlags) { 323 uint32_t sectlength = 0, sectoffset = 0, localVersion = 0, localFlags = 0; 324 char *buffer = NULL; 325 char sectbuffer[8]; 326 const char *loc = NULL; 327 unsigned i, j; 328 Boolean foundit = false, localHasObjc = false; 329 330 if (fd >= 0 && lseek(fd, offset, SEEK_SET) == (off_t)offset) { 331 buffer = malloc(IMAGE_INFO_BYTES_TO_READ); 332 if (buffer && read(fd, buffer, IMAGE_INFO_BYTES_TO_READ) >= IMAGE_INFO_BYTES_TO_READ) loc = buffer; 333 } else if (bytes && length >= offset + IMAGE_INFO_BYTES_TO_READ) { 334 loc = bytes + offset; 335 } 336 if (loc) { 337 if (sixtyFour) { 338 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)loc)->ncmds, swapped); 339 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)loc)->sizeofcmds, swapped); 340 const char *startofcmds = loc + sizeof(struct mach_header_64); 341 const char *endofcmds = startofcmds + sizeofcmds; 342 struct segment_command_64 *sgp = (struct segment_command_64 *)startofcmds; 343 if (endofcmds > loc + IMAGE_INFO_BYTES_TO_READ) endofcmds = loc + IMAGE_INFO_BYTES_TO_READ; 344 for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) { 345 if (LC_SEGMENT_64 == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) { 346 struct section_64 *sp = (struct section_64 *)((char *)sgp + sizeof(struct segment_command_64)); 347 uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped); 348 for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) { 349 if (0 == strncmp(sp->segname, OBJC_SEGMENT_64, sizeof(sp->segname))) localHasObjc = true; 350 if (0 == strncmp(sp->sectname, IMAGE_INFO_SECTION_64, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, OBJC_SEGMENT_64, sizeof(sp->segname))) { 351 uint64_t sectlength64 = _CFBundleSwapInt64Conditional(sp->size, swapped); 352 sectlength = (uint32_t)(sectlength64 & 0xffffffff); 353 sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped); 354 foundit = true; 355 } 356 sp = (struct section_64 *)((char *)sp + sizeof(struct section_64)); 357 } 358 } 359 sgp = (struct segment_command_64 *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped)); 360 } 361 } else { 362 uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header *)loc)->ncmds, swapped); 363 uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header *)loc)->sizeofcmds, swapped); 364 const char *startofcmds = loc + sizeof(struct mach_header); 365 const char *endofcmds = startofcmds + sizeofcmds; 366 struct segment_command *sgp = (struct segment_command *)startofcmds; 367 if (endofcmds > loc + IMAGE_INFO_BYTES_TO_READ) endofcmds = loc + IMAGE_INFO_BYTES_TO_READ; 368 for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) { 369 if (LC_SEGMENT == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) { 370 struct section *sp = (struct section *)((char *)sgp + sizeof(struct segment_command)); 371 uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped); 372 for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) { 373 if (0 == strncmp(sp->segname, OBJC_SEGMENT, sizeof(sp->segname))) localHasObjc = true; 374 if (0 == strncmp(sp->sectname, IMAGE_INFO_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, OBJC_SEGMENT, sizeof(sp->segname))) { 375 sectlength = _CFBundleSwapInt32Conditional(sp->size, swapped); 376 sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped); 377 foundit = true; 378 } 379 sp = (struct section *)((char *)sp + sizeof(struct section)); 380 } 381 } 382 sgp = (struct segment_command *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped)); 383 } 384 } 385 if (sectlength >= 8) { 386 if (fd >= 0 && lseek(fd, offset + sectoffset, SEEK_SET) == (off_t)(offset + sectoffset) && read(fd, sectbuffer, 8) >= 8) { 387 localVersion = _CFBundleSwapInt32Conditional(*(uint32_t *)sectbuffer, swapped); 388 localFlags = _CFBundleSwapInt32Conditional(*(uint32_t *)(sectbuffer + 4), swapped); 389 } else if (bytes && length >= offset + sectoffset + 8) { 390 localVersion = _CFBundleSwapInt32Conditional(*(uint32_t *)(bytes + offset + sectoffset), swapped); 391 localFlags = _CFBundleSwapInt32Conditional(*(uint32_t *)(bytes + offset + sectoffset + 4), swapped); 392 } 393 } 394 } 395 if (buffer) free(buffer); 396 if (hasObjc) *hasObjc = localHasObjc; 397 if (objcVersion) *objcVersion = localVersion; 398 if (objcFlags) *objcFlags = localFlags; 399 } 400 401 static UInt32 _CFBundleGrokMachTypeForFatFile(int fd, const void *bytes, CFIndex length, Boolean swap, Boolean *isX11, CFArrayRef *architectures, CFDictionaryRef *infodict, Boolean *hasObjc, uint32_t *objcVersion, uint32_t *objcFlags) { 402 CFIndex headerLength = length; 403 unsigned char headerBuffer[MAGIC_BYTES_TO_READ]; 404 UInt32 machtype = UNKNOWN_FILETYPE, magic, numFatHeaders, maxFatHeaders, i; 405 unsigned char buffer[sizeof(struct mach_header_64)]; 406 const unsigned char *moreBytes = NULL; 407 const NXArchInfo *archInfo = NXGetLocalArchInfo(); 408 SInt32 curArch = _CFBundleCurrentArchitecture(); 409 410 struct fat_arch *fat = NULL; 411 412 if (isX11) *isX11 = false; 413 if (architectures) *architectures = NULL; 414 if (infodict) *infodict = NULL; 415 if (hasObjc) *hasObjc = false; 416 if (objcVersion) *objcVersion = 0; 417 if (objcFlags) *objcFlags = 0; 418 419 if (headerLength > MAGIC_BYTES_TO_READ) headerLength = MAGIC_BYTES_TO_READ; 420 (void)memmove(headerBuffer, bytes, headerLength); 421 if (swap) { 422 for (i = 0; i < headerLength; i += 4) *(UInt32 *)(headerBuffer + i) = CFSwapInt32(*(UInt32 *)(headerBuffer + i)); 423 } 424 numFatHeaders = ((struct fat_header *)headerBuffer)->nfat_arch; 425 maxFatHeaders = (headerLength - sizeof(struct fat_header)) / sizeof(struct fat_arch); 426 if (numFatHeaders > maxFatHeaders) numFatHeaders = maxFatHeaders; 427 if (numFatHeaders > 0) { 428 if (archInfo) fat = NXFindBestFatArch(archInfo->cputype, archInfo->cpusubtype, (struct fat_arch *)(headerBuffer + sizeof(struct fat_header)), numFatHeaders); 429 if (!fat && curArch != 0) fat = NXFindBestFatArch((cpu_type_t)curArch, (cpu_subtype_t)0, (struct fat_arch *)(headerBuffer + sizeof(struct fat_header)), numFatHeaders); 430 if (!fat) fat = (struct fat_arch *)(headerBuffer + sizeof(struct fat_header)); 431 if (architectures) { 432 CFMutableArrayRef mutableArchitectures = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); 433 for (i = 0; i < numFatHeaders; i++) { 434 CFNumberRef architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, headerBuffer + sizeof(struct fat_header) + i * sizeof(struct fat_arch)); 435 if (CFArrayGetFirstIndexOfValue(mutableArchitectures, CFRangeMake(0, CFArrayGetCount(mutableArchitectures)), architecture) < 0) CFArrayAppendValue(mutableArchitectures, architecture); 436 CFRelease(architecture); 437 } 438 *architectures = (CFArrayRef)mutableArchitectures; 439 } 440 } 441 if (fat) { 442 if (fd >= 0 && lseek(fd, fat->offset, SEEK_SET) == (off_t)fat->offset && read(fd, buffer, sizeof(struct mach_header_64)) >= (int)sizeof(struct mach_header_64)) { 443 moreBytes = buffer; 444 } else if (bytes && (uint32_t)length >= fat->offset + sizeof(struct mach_header_64)) { 445 moreBytes = bytes + fat->offset; 446 } 447 if (moreBytes) { 448 magic = *((UInt32 *)moreBytes); 449 if (MH_MAGIC == magic) { 450 machtype = ((struct mach_header *)moreBytes)->filetype; 451 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, fat->offset, false, false); 452 if (infodict) *infodict = _CFBundleCreateInfoDictFromFile(fd, bytes, length, fat->offset, false, false); 453 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, fat->offset, false, false, hasObjc, objcVersion, objcFlags); 454 } else if (MH_CIGAM == magic) { 455 machtype = CFSwapInt32(((struct mach_header *)moreBytes)->filetype); 456 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, fat->offset, true, false); 457 if (infodict) *infodict = _CFBundleCreateInfoDictFromFile(fd, bytes, length, fat->offset, true, false); 458 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, fat->offset, true, false, hasObjc, objcVersion, objcFlags); 459 } else if (MH_MAGIC_64 == magic) { 460 machtype = ((struct mach_header_64 *)moreBytes)->filetype; 461 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, fat->offset, false, true); 462 if (infodict) *infodict = _CFBundleCreateInfoDictFromFile(fd, bytes, length, fat->offset, false, true); 463 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, fat->offset, false, true, hasObjc, objcVersion, objcFlags); 464 } else if (MH_CIGAM_64 == magic) { 465 machtype = CFSwapInt32(((struct mach_header_64 *)moreBytes)->filetype); 466 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, fat->offset, true, true); 467 if (infodict) *infodict = _CFBundleCreateInfoDictFromFile(fd, bytes, length, fat->offset, true, true); 468 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, fat->offset, true, true, hasObjc, objcVersion, objcFlags); 469 } 470 } 471 } 472 return machtype; 473 } 474 475 static UInt32 _CFBundleGrokMachType(int fd, const void *bytes, CFIndex length, Boolean *isX11, CFArrayRef *architectures, CFDictionaryRef *infodict, Boolean *hasObjc, uint32_t *objcVersion, uint32_t *objcFlags) { 476 unsigned int magic = *((UInt32 *)bytes), machtype = UNKNOWN_FILETYPE, cputype; 477 CFNumberRef architecture = NULL; 478 479 if (isX11) *isX11 = false; 480 if (architectures) *architectures = NULL; 481 if (infodict) *infodict = NULL; 482 if (hasObjc) *hasObjc = false; 483 if (objcVersion) *objcVersion = 0; 484 if (objcFlags) *objcFlags = 0; 485 if (MH_MAGIC == magic) { 486 machtype = ((struct mach_header *)bytes)->filetype; 487 cputype = ((struct mach_header *)bytes)->cputype; 488 if (architectures) architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, &cputype); 489 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, 0, false, false); 490 if (infodict) *infodict = _CFBundleCreateInfoDictFromFile(fd, bytes, length, 0, false, false); 491 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, 0, false, false, hasObjc, objcVersion, objcFlags); 492 } else if (MH_CIGAM == magic) { 493 machtype = CFSwapInt32(((struct mach_header *)bytes)->filetype); 494 cputype = CFSwapInt32(((struct mach_header *)bytes)->cputype); 495 if (architectures) architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, &cputype); 496 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, 0, true, false); 497 if (infodict) *infodict = _CFBundleCreateInfoDictFromFile(fd, bytes, length, 0, true, false); 498 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, 0, true, false, hasObjc, objcVersion, objcFlags); 499 } else if (MH_MAGIC_64 == magic) { 500 machtype = ((struct mach_header_64 *)bytes)->filetype; 501 cputype = ((struct mach_header_64 *)bytes)->cputype; 502 if (architectures) architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, &cputype); 503 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, 0, false, true); 504 if (infodict) *infodict = _CFBundleCreateInfoDictFromFile(fd, bytes, length, 0, false, true); 505 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, 0, false, true, hasObjc, objcVersion, objcFlags); 506 } else if (MH_CIGAM_64 == magic) { 507 machtype = CFSwapInt32(((struct mach_header_64 *)bytes)->filetype); 508 cputype = CFSwapInt32(((struct mach_header_64 *)bytes)->cputype); 509 if (architectures) architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, &cputype); 510 if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, 0, true, true); 511 if (infodict) *infodict = _CFBundleCreateInfoDictFromFile(fd, bytes, length, 0, true, true); 512 if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, 0, true, true, hasObjc, objcVersion, objcFlags); 513 } else if (FAT_MAGIC == magic) { 514 machtype = _CFBundleGrokMachTypeForFatFile(fd, bytes, length, false, isX11, architectures, infodict, hasObjc, objcVersion, objcFlags); 515 } else if (FAT_CIGAM == magic) { 516 machtype = _CFBundleGrokMachTypeForFatFile(fd, bytes, length, true, isX11, architectures, infodict, hasObjc, objcVersion, objcFlags); 517 } else if (PEF_MAGIC == magic || PEF_CIGAM == magic) { 518 machtype = PEF_FILETYPE; 519 } 520 if (architectures && architecture) *architectures = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&architecture, 1, &kCFTypeArrayCallBacks); 521 if (architecture) CFRelease(architecture); 522 return machtype; 523 } 524 525 #endif /* BINARY_SUPPORT_DYLD */ 526 527 static Boolean _CFBundleGrokFileTypeForZipMimeType(const unsigned char *bytes, CFIndex length, const char **ext) { 528 unsigned namelength = CFSwapInt16HostToLittle(*((UInt16 *)(bytes + 26))), extralength = CFSwapInt16HostToLittle(*((UInt16 *)(bytes + 28))); 529 const unsigned char *data = bytes + 30 + namelength + extralength; 530 int i = -1; 531 if (bytes < data && data + 56 <= bytes + length && 0 == CFSwapInt16HostToLittle(*((UInt16 *)(bytes + 8))) && (0 == ustrncasecmp(data, "application/vnd.", 16) || 0 == ustrncasecmp(data, "application/x-vnd.", 18))) { 532 data += ('.' == *(data + 15)) ? 16 : 18; 533 if (0 == ustrncasecmp(data, "sun.xml.", 8)) { 534 data += 8; 535 if (0 == ustrncasecmp(data, "calc", 4)) i = 0; 536 else if (0 == ustrncasecmp(data, "draw", 4)) i = 1; 537 else if (0 == ustrncasecmp(data, "writer.global", 13)) i = 2; 538 else if (0 == ustrncasecmp(data, "impress", 7)) i = 3; 539 else if (0 == ustrncasecmp(data, "math", 4)) i = 4; 540 else if (0 == ustrncasecmp(data, "writer", 6)) i = 5; 541 if (i >= 0 && ext) *ext = __CFBundleOOExtensionsArray + i * EXTENSION_LENGTH; 542 } else if (0 == ustrncasecmp(data, "oasis.opendocument.", 19)) { 543 data += 19; 544 if (0 == ustrncasecmp(data, "chart", 5)) i = 0; 545 else if (0 == ustrncasecmp(data, "formula", 7)) i = 1; 546 else if (0 == ustrncasecmp(data, "graphics", 8)) i = 2; 547 else if (0 == ustrncasecmp(data, "text-web", 8)) i = 3; 548 else if (0 == ustrncasecmp(data, "image", 5)) i = 4; 549 else if (0 == ustrncasecmp(data, "text-master", 11)) i = 5; 550 else if (0 == ustrncasecmp(data, "presentation", 12)) i = 6; 551 else if (0 == ustrncasecmp(data, "spreadsheet", 11)) i = 7; 552 else if (0 == ustrncasecmp(data, "text", 4)) i = 8; 553 if (i >= 0 && ext) *ext = __CFBundleODExtensionsArray + i * EXTENSION_LENGTH; 554 } 555 } else if (bytes < data && data + 41 <= bytes + length && 8 == CFSwapInt16HostToLittle(*((UInt16 *)(bytes + 8))) && 0x4b2c28c8 == CFSwapInt32HostToBig(*((UInt32 *)data)) && 0xc94c4e2c == CFSwapInt32HostToBig(*((UInt32 *)(data + 4)))) { 556 // AbiWord compressed mimetype odt 557 if (ext) *ext = "odt"; 558 // almost certainly this should set i to 0 but I don't want to upset the apple cart now 559 } else if (bytes < data && data + 29 <= bytes + length && (0 == ustrncasecmp(data, "application/oebps-package+xml", 29))) { 560 // epub, official epub 3 mime type 561 if (ext) *ext = "epub"; 562 i = 0; 563 } else if (bytes < data && data + 20 <= bytes + length && (0 == ustrncasecmp(data, "application/epub+zip", 20))) { 564 // epub, unofficial epub 2 mime type 565 if (ext) *ext = "epub"; 566 i = 0; 567 } 568 return (i >= 0); 569 } 570 571 static const char *_CFBundleGrokFileTypeForZipFile(int fd, const unsigned char *bytes, CFIndex length, off_t fileLength) { 572 const char *ext = "zip"; 573 const unsigned char *moreBytes = NULL; 574 unsigned char *buffer = NULL; 575 CFIndex i; 576 Boolean foundMimetype = false, hasMetaInf = false, hasContentXML = false, hasManifestMF = false, hasManifestXML = false, hasRels = false, hasContentTypes = false, hasWordDocument = false, hasExcelDocument = false, hasPowerPointDocument = false, hasOPF = false, hasSMIL = false; 577 578 if (bytes) { 579 for (i = 0; !foundMimetype && i + 30 < length; i++) { 580 if (0x50 == bytes[i] && 0x4b == bytes[i + 1]) { 581 unsigned namelength = 0, offset = 0; 582 if (0x01 == bytes[i + 2] && 0x02 == bytes[i + 3]) { 583 namelength = (unsigned)CFSwapInt16HostToLittle(*((UInt16 *)(bytes + i + 28))); 584 offset = 46; 585 } else if (0x03 == bytes[i + 2] && 0x04 == bytes[i + 3]) { 586 namelength = (unsigned)CFSwapInt16HostToLittle(*((UInt16 *)(bytes + i + 26))); 587 offset = 30; 588 } 589 if (offset > 0 && (CFIndex)(i + offset + namelength) <= length) { 590 //printf("%.*s\n", namelength, bytes + i + offset); 591 if (8 == namelength && 30 == offset && 0 == ustrncasecmp(bytes + i + offset, "mimetype", 8)) foundMimetype = _CFBundleGrokFileTypeForZipMimeType(bytes + i, length - i, &ext); 592 else if (9 == namelength && 0 == ustrncasecmp(bytes + i + offset, "META-INF/", 9)) hasMetaInf = true; 593 else if (11 == namelength && 0 == ustrncasecmp(bytes + i + offset, "content.xml", 11)) hasContentXML = true; 594 else if (11 == namelength && 0 == ustrncasecmp(bytes + i + offset, "_rels/.rels", 11)) hasRels = true; 595 else if (19 == namelength && 0 == ustrncasecmp(bytes + i + offset, "[Content_Types].xml", 19)) hasContentTypes = true; 596 else if (20 == namelength && 0 == ustrncasecmp(bytes + i + offset, "META-INF/MANIFEST.MF", 20)) hasManifestMF = true; 597 else if (21 == namelength && 0 == ustrncasecmp(bytes + i + offset, "META-INF/manifest.xml", 21)) hasManifestXML = true; 598 else if (4 < namelength && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".opf", 4)) hasOPF = true; 599 else if (4 < namelength && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".sml", 4)) hasSMIL = true; 600 else if (5 < namelength && 0 == ustrncasecmp(bytes + i + offset + namelength - 5, ".smil", 5)) hasSMIL = true; 601 else if (7 < namelength && 0 == ustrncasecmp(bytes + i + offset, "xl/", 3) && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".xml", 4)) hasExcelDocument = true; 602 else if (8 < namelength && 0 == ustrncasecmp(bytes + i + offset, "ppt/", 4) && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".xml", 4)) hasPowerPointDocument = true; 603 else if (9 < namelength && 0 == ustrncasecmp(bytes + i + offset, "word/", 5) && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".xml", 4)) hasWordDocument = true; 604 else if (10 < namelength && 0 == ustrncasecmp(bytes + i + offset, "excel/", 6) && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".xml", 4)) hasExcelDocument = true; 605 else if (15 < namelength && 0 == ustrncasecmp(bytes + i + offset, "powerpoint/", 11) && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".xml", 4)) hasPowerPointDocument = true; 606 i += offset + namelength - 1; 607 } 608 } 609 } 610 } 611 if (!foundMimetype) { 612 if (fileLength >= ZIP_BYTES_TO_READ) { 613 if (fd >= 0 && lseek(fd, fileLength - ZIP_BYTES_TO_READ, SEEK_SET) == fileLength - ZIP_BYTES_TO_READ) { 614 buffer = (unsigned char *)malloc(ZIP_BYTES_TO_READ); 615 if (buffer && read(fd, buffer, ZIP_BYTES_TO_READ) >= ZIP_BYTES_TO_READ) moreBytes = buffer; 616 } else if (bytes && length >= ZIP_BYTES_TO_READ) { 617 moreBytes = bytes + length - ZIP_BYTES_TO_READ; 618 } 619 } 620 if (moreBytes) { 621 for (i = 0; i + 30 < ZIP_BYTES_TO_READ; i++) { 622 if (0x50 == moreBytes[i] && 0x4b == moreBytes[i + 1]) { 623 unsigned namelength = 0, offset = 0; 624 if (0x01 == moreBytes[i + 2] && 0x02 == moreBytes[i + 3]) { 625 namelength = CFSwapInt16HostToLittle(*((UInt16 *)(moreBytes + i + 28))); 626 offset = 46; 627 } else if (0x03 == moreBytes[i + 2] && 0x04 == moreBytes[i + 3]) { 628 namelength = CFSwapInt16HostToLittle(*((UInt16 *)(moreBytes + i + 26))); 629 offset = 30; 630 } 631 if (offset > 0 && i + offset + namelength <= ZIP_BYTES_TO_READ) { 632 //printf("%.*s\n", namelength, moreBytes + i + offset); 633 if (9 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "META-INF/", 9)) hasMetaInf = true; 634 else if (11 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "content.xml", 11)) hasContentXML = true; 635 else if (11 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "_rels/.rels", 11)) hasRels = true; 636 else if (19 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "[Content_Types].xml", 19)) hasContentTypes = true; 637 else if (20 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "META-INF/MANIFEST.MF", 20)) hasManifestMF = true; 638 else if (21 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "META-INF/manifest.xml", 21)) hasManifestXML = true; 639 else if (4 < namelength && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".opf", 4)) hasOPF = true; 640 else if (4 < namelength && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".sml", 4)) hasSMIL = true; 641 else if (5 < namelength && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 5, ".smil", 5)) hasSMIL = true; 642 else if (7 < namelength && 0 == ustrncasecmp(moreBytes + i + offset, "xl/", 3) && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".xml", 4)) hasExcelDocument = true; 643 else if (8 < namelength && 0 == ustrncasecmp(moreBytes + i + offset, "ppt/", 4) && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".xml", 4)) hasPowerPointDocument = true; 644 else if (9 < namelength && 0 == ustrncasecmp(moreBytes + i + offset, "word/", 5) && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".xml", 4)) hasWordDocument = true; 645 else if (10 < namelength && 0 == ustrncasecmp(moreBytes + i + offset, "excel/", 6) && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".xml", 4)) hasExcelDocument = true; 646 else if (15 < namelength && 0 == ustrncasecmp(moreBytes + i + offset, "powerpoint/", 11) && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".xml", 4)) hasPowerPointDocument = true; 647 i += offset + namelength - 1; 648 } 649 } 650 } 651 } 652 //printf("hasManifestMF %d hasManifestXML %d hasContentXML %d hasRels %d hasContentTypes %d hasWordDocument %d hasExcelDocument %d hasPowerPointDocument %d hasMetaInf %d hasOPF %d hasSMIL %d\n", hasManifestMF, hasManifestXML, hasContentXML, hasRels, hasContentTypes, hasWordDocument, hasExcelDocument, hasPowerPointDocument, hasMetaInf, hasOPF, hasSMIL); 653 if (hasManifestMF) ext = "jar"; 654 else if ((hasRels || hasContentTypes) && hasWordDocument) ext = "docx"; 655 else if ((hasRels || hasContentTypes) && hasExcelDocument) ext = "xlsx"; 656 else if ((hasRels || hasContentTypes) && hasPowerPointDocument) ext = "pptx"; 657 else if (hasManifestXML || hasContentXML) ext = "odt"; 658 else if (hasMetaInf) ext = "jar"; 659 else if (hasOPF && hasSMIL) ext = "dtb"; 660 else if (hasOPF) ext = "oeb"; 661 662 if (buffer) free(buffer); 663 } 664 return ext; 665 } 666 667 static Boolean _CFBundleCheckOLEName(const char *name, const char *bytes, unsigned length) { 668 Boolean retval = true; 669 unsigned j; 670 for (j = 0; retval && j < length; j++) if (bytes[2 * j] != name[j]) retval = false; 671 return retval; 672 } 673 674 static const char *_CFBundleGrokFileTypeForOLEFile(int fd, const void *bytes, CFIndex length, off_t offset) { 675 const char *ext = "ole", *moreBytes = NULL; 676 char *buffer = NULL; 677 678 if (fd >= 0 && lseek(fd, offset, SEEK_SET) == (off_t)offset) { 679 buffer = (char *)malloc(OLE_BYTES_TO_READ); 680 if (buffer && read(fd, buffer, OLE_BYTES_TO_READ) >= OLE_BYTES_TO_READ) moreBytes = buffer; 681 } else if (bytes && length >= offset + OLE_BYTES_TO_READ) { 682 moreBytes = (char *)bytes + offset; 683 } 684 if (moreBytes) { 685 Boolean foundit = false; 686 unsigned i; 687 for (i = 0; !foundit && i < 4; i++) { 688 char namelength = moreBytes[128 * i + 64] / 2; 689 foundit = true; 690 if (sizeof(XLS_NAME) == namelength && _CFBundleCheckOLEName(XLS_NAME, moreBytes + 128 * i, namelength - 1)) ext = "xls"; 691 else if (sizeof(XLS_NAME2) == namelength && _CFBundleCheckOLEName(XLS_NAME2, moreBytes + 128 * i, namelength - 1)) ext = "xls"; 692 else if (sizeof(DOC_NAME) == namelength && _CFBundleCheckOLEName(DOC_NAME, moreBytes + 128 * i, namelength - 1)) ext = "doc"; 693 else if (sizeof(PPT_NAME) == namelength && _CFBundleCheckOLEName(PPT_NAME, moreBytes + 128 * i, namelength - 1)) ext = "ppt"; 694 else foundit = false; 695 } 696 } 697 if (buffer) free(buffer); 698 return ext; 699 } 700 701 static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef *extension, UInt32 *machtype, CFArrayRef *architectures, CFDictionaryRef *infodict, Boolean *hasObjc, uint32_t *objcVersion, uint32_t *objcFlags) { 702 int fd = -1; 703 const unsigned char *bytes = NULL; 704 unsigned char buffer[MAGIC_BYTES_TO_READ]; 705 CFIndex i, length = 0; 706 off_t fileLength = 0; 707 const char *ext = NULL; 708 UInt32 mt = UNKNOWN_FILETYPE; 709 #if defined(BINARY_SUPPORT_DYLD) 710 Boolean isX11 = false; 711 #endif /* BINARY_SUPPORT_DYLD */ 712 Boolean isFile = false, isPlain = true, isZero = true, isSpace = true, hasBOM = false; 713 // extensions returned: o, tool, x11app, pef, core, dylib, bundle, elf, jpeg, jp2, tiff, gif, png, pict, icns, ico, rtf, rtfd, pdf, ra, rm, au, aiff, aifc, caf, wav, avi, wmv, ogg, flac, psd, mpeg, mid, zip, jar, sit, cpio, html, ps, mov, qtif, ttf, otf, sfont, bmp, hqx, bin, class, tar, txt, gz, Z, uu, ync, bz, bz2, sh, pl, py, rb, dvi, sgi, tga, mp3, xml, plist, xls, doc, ppt, mp4, m4a, m4b, m4p, m4v, 3gp, 3g2, dmg, cwk, webarchive, dwg, dgn, pfa, pfb, afm, tfm, xcf, cpx, dwf, swf, swc, abw, bom, lit, svg, rdf, x3d, oeb, dtb, docx, xlsx, pptx, sxc, sxd, sxg, sxi, sxm, sxw, odc, odf, odg, oth, odi, odm, odp, ods, cin, exr 714 // ??? we do not distinguish between different wm types, returning wmv for any of wmv, wma, or asf 715 // ??? we do not distinguish between ordinary documents and template versions (often there is no difference in file contents) 716 // ??? the distinctions between docx, xlsx, and pptx may not be entirely reliable 717 if (architectures) *architectures = NULL; 718 if (infodict) *infodict = NULL; 719 if (hasObjc) *hasObjc = false; 720 if (objcVersion) *objcVersion = 0; 721 if (objcFlags) *objcFlags = 0; 722 if (url) { 723 Boolean gotPath = FALSE; 724 char path[CFMaxPathSize]; 725 gotPath = CFURLGetFileSystemRepresentation(url, true, (uint8_t *)path, CFMaxPathSize); 726 struct statinfo statBuf; 727 if (gotPath && stat(path, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFREG && (fd = open(path, O_RDONLY | CF_OPENFLGS, 0777)) >= 0) { 728 length = read(fd, buffer, MAGIC_BYTES_TO_READ); 729 fileLength = statBuf.st_size; 730 bytes = buffer; 731 isFile = true; 732 } 733 } 734 if (!isFile && data) { 735 length = CFDataGetLength(data); 736 fileLength = (off_t)length; 737 bytes = CFDataGetBytePtr(data); 738 if (length == 0) ext = "txt"; 739 } 740 if (bytes) { 741 if (length >= 4) { 742 UInt32 magic = CFSwapInt32HostToBig(*((UInt32 *)bytes)); 743 for (i = 0; !ext && i < NUM_EXTENSIONS; i++) { 744 if (__CFBundleMagicNumbersArray[i] == magic) ext = __CFBundleExtensionsArray + i * EXTENSION_LENGTH; 745 } 746 if (ext) { 747 if (0xcafebabe == magic && 8 <= length && 0 != *((UInt16 *)(bytes + 4))) ext = "class"; 748 #if defined(BINARY_SUPPORT_DYLD) 749 else if ((int)sizeof(struct mach_header_64) <= length) mt = _CFBundleGrokMachType(fd, bytes, length, extension ? &isX11 : NULL, architectures, infodict, hasObjc, objcVersion, objcFlags); 750 751 if (MH_OBJECT == mt) ext = "o"; 752 else if (MH_EXECUTE == mt) ext = isX11 ? "x11app" : "tool"; 753 else if (PEF_FILETYPE == mt) ext = "pef"; 754 else if (MH_CORE == mt) ext = "core"; 755 else if (MH_DYLIB == mt) ext = "dylib"; 756 else if (MH_BUNDLE == mt) ext = "bundle"; 757 #endif /* BINARY_SUPPORT_DYLD */ 758 else if (0x7b5c7274 == magic && (6 > length || 'f' != bytes[4])) ext = NULL; 759 else if (0x25504446 == magic && (6 > length || '-' != bytes[4])) ext = NULL; 760 else if (0x00010000 == magic && (6 > length || 0 != bytes[4])) ext = NULL; 761 else if (0x47494638 == magic && (6 > length || (0x3761 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))) && 0x3961 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4)))))) ext = NULL; 762 else if (0x0000000c == magic && (6 > length || 0x6a50 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))))) ext = NULL; 763 else if (0x2356524d == magic && (6 > length || 0x4c20 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))))) ext = NULL; 764 else if (0x28445746 == magic && (6 > length || 0x2056 != CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))))) ext = NULL; 765 else if (0x30373037 == magic && (6 > length || 0x30 != bytes[4] || !isdigit(bytes[5]))) ext = NULL; 766 else if (0x41433130 == magic && (6 > length || 0x31 != bytes[4] || !isdigit(bytes[5]))) ext = NULL; 767 else if (0x89504e47 == magic && (8 > length || 0x0d0a1a0a != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; 768 else if (0x53747566 == magic && (8 > length || 0x66497420 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; 769 else if (0x3026b275 == magic && (8 > length || 0x8e66cf11 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; 770 else if (0x67696d70 == magic && (8 > length || 0x20786366 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; 771 else if (0x424f4d53 == magic && (8 > length || 0x746f7265 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; 772 else if (0x49544f4c == magic && (8 > length || 0x49544c53 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; 773 else if (0x72746664 == magic && (8 > length || 0x00000000 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; 774 else if (0x3d796265 == magic && (12 > length || 0x67696e20 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || (0x6c696e65 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8))) && 0x70617274 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)))))) ext = NULL; 775 else if (0x63616666 == magic && (12 > length || 0 != bytes[4] || 0x64657363 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8))))) ext = NULL; 776 else if (0x504b0304 == magic) ext = _CFBundleGrokFileTypeForZipFile(fd, bytes, length, fileLength); 777 else if (0x25215053 == magic) { 778 if (11 <= length && 0 == ustrncmp(bytes + 4, "-Adobe-", 7)) ext = "ps"; 779 else if (14 <= length && 0 == ustrncmp(bytes + 4, "-AdobeFont", 10)) ext = "pfa"; 780 else ext = NULL; 781 } else if (0x464f524d == magic) { 782 // IFF 783 ext = NULL; 784 if (12 <= length) { 785 UInt32 iffMagic = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8))); 786 if (0x41494646 == iffMagic) ext = "aiff"; 787 else if (0x414946 == iffMagic) ext = "aifc"; 788 } 789 } else if (0x52494646 == magic) { 790 // RIFF 791 ext = NULL; 792 if (12 <= length) { 793 UInt32 riffMagic = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8))); 794 if (0x57415645 == riffMagic) ext = "wav"; 795 else if (0x41564920 == riffMagic) ext = "avi"; 796 } 797 } else if (0xd0cf11e0 == magic) { 798 // OLE 799 if (52 <= length) ext = _CFBundleGrokFileTypeForOLEFile(fd, bytes, length, 512 * (1 + CFSwapInt32HostToLittle(*((UInt32 *)(bytes + 48))))); 800 } else if (0x62656769 == magic) { 801 // uu 802 ext = NULL; 803 if (76 <= length && 'n' == bytes[4] && ' ' == bytes[5] && isdigit(bytes[6]) && isdigit(bytes[7]) && isdigit(bytes[8]) && ' ' == bytes[9]) { 804 CFIndex endOfLine = 0; 805 for (i = 10; 0 == endOfLine && i < length; i++) if ('\n' == bytes[i]) endOfLine = i; 806 if (10 <= endOfLine && endOfLine + 62 < length && 'M' == bytes[endOfLine + 1] && '\n' == bytes[endOfLine + 62]) { 807 ext = "uu"; 808 for (i = endOfLine + 1; ext && i < endOfLine + 62; i++) if (!isprint(bytes[i])) ext = NULL; 809 } 810 } 811 } 812 } 813 if (extension && !ext) { 814 UInt16 shortMagic = CFSwapInt16HostToBig(*((UInt16 *)bytes)); 815 if (5 <= length && 0 == bytes[3] && 0 == bytes[4] && ((1 == bytes[1] && 1 == (0xf7 & bytes[2])) || (0 == bytes[1] && (2 == (0xf7 & bytes[2]) || (3 == (0xf7 & bytes[2])))))) ext = "tga"; 816 else if (8 <= length && (0x6d6f6f76 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x6d646174 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x77696465 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = "mov"; 817 else if (8 <= length && (0x69647363 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x69646174 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = "qtif"; 818 else if (8 <= length && 0x424f424f == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4)))) ext = "cwk"; 819 else if (8 <= length && 0x62706c69 == magic && 0x7374 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))) && isdigit(bytes[6]) && isdigit(bytes[7])) { 820 for (i = 8; !ext && i < 128 && i + 16 <= length; i++) { 821 if (0 == ustrncmp(bytes + i, "WebMainResource", 15)) ext = "webarchive"; 822 } 823 if (!ext) ext = "plist"; 824 } else if (0 == shortMagic && 12 <= length && 0x66747970 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4)))) { 825 // ??? may want more ftyp values 826 UInt32 ftyp = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8))); 827 if (0x6d703431 == ftyp || 0x6d703432 == ftyp || 0x69736f6d == ftyp || 0x69736f32 == ftyp) ext = "mp4"; 828 else if (0x4d344120 == ftyp) ext = "m4a"; 829 else if (0x4d344220 == ftyp) ext = "m4b"; 830 else if (0x4d345020 == ftyp) ext = "m4p"; 831 else if (0x4d345620 == ftyp || 0x4d345648 == ftyp || 0x4d345650 == ftyp) ext = "m4v"; 832 else if (0x3367 == (ftyp >> 16)) { 833 UInt16 remainder = (ftyp & 0xffff); 834 if (0x6536 == remainder || 0x6537 == remainder || 0x6736 == remainder || 0x7034 == remainder || 0x7035 == remainder || 0x7036 == remainder || 0x7236 == remainder || 0x7336 == remainder || 0x7337 == remainder) ext = "3gp"; 835 else if (0x3261 == remainder) ext = "3g2"; 836 } 837 } else if (0x424d == shortMagic && 18 <= length) { 838 UInt32 btyp = CFSwapInt32HostToLittle(*((UInt32 *)(bytes + 14))); 839 if (40 == btyp || btyp == 12 || btyp == 64 || btyp == 108 || btyp == 124) ext = "bmp"; 840 } else if (20 <= length && 0 == ustrncmp(bytes + 6, "%!PS-AdobeFont", 14)) ext = "pfb"; 841 else if (40 <= length && 0x42696e48 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 34))) && 0x6578 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 38)))) ext = "hqx"; 842 else if (128 <= length && 0x6d42494e == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 102)))) ext = "bin"; 843 else if (128 <= length && 0 == bytes[0] && 0 < bytes[1] && bytes[1] < 64 && 0 == bytes[74] && 0 == bytes[82] && 0 == (fileLength % 128)) { 844 UInt32 df = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 83))), rf = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 87))), blocks = 1 + (df + 127) / 128 + (rf + 127) / 128; 845 if (df < 0x00800000 && rf < 0x00800000 && 1 < blocks && (off_t)(128 * blocks) == fileLength) ext = "bin"; 846 } else if (265 <= length && 0x75737461 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 257))) && (0x72202000 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 261))) || 0x7200 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 261))))) ext = "tar"; 847 else if (0xfeff == shortMagic || 0xfffe == shortMagic) { 848 ext = "txt"; 849 if (12 <= length && ((0x3cfeff == *((UInt32 *)bytes) && 0x740068 == *((UInt32 *)(bytes + 4)) && 0x6c006d == *((UInt32 *)(bytes + 8))) || (0xfffe3c00 == *((UInt32 *)bytes) && 0x68007400 == *((UInt32 *)(bytes + 4)) && 0x6d006c00 == *((UInt32 *)(bytes + 8))))) ext = "html"; 850 } else if (0x1f9d == shortMagic) ext = "Z"; 851 else if (0x1f8b == shortMagic) ext = "gz"; 852 else if (0x71c7 == shortMagic || 0xc771 == shortMagic) ext = "cpio"; 853 else if (0xf702 == shortMagic) ext = "dvi"; 854 else if (0x01da == shortMagic && (0 == bytes[2] || 1 == bytes[2]) && (0 < bytes[3] && 16 > bytes[3])) ext = "sgi"; 855 else if (0x2321 == shortMagic) { 856 CFIndex endOfLine = 0, lastSlash = 0; 857 for (i = 2; 0 == endOfLine && i < length; i++) if ('\n' == bytes[i]) endOfLine = i; 858 if (endOfLine > 3) { 859 for (i = endOfLine - 1; 0 == lastSlash && i > 1; i--) if ('/' == bytes[i]) lastSlash = i; 860 if (lastSlash > 0) { 861 if (0 == ustrncmp(bytes + lastSlash + 1, "perl", 4)) ext = "pl"; 862 else if (0 == ustrncmp(bytes + lastSlash + 1, "python", 6)) ext = "py"; 863 else if (0 == ustrncmp(bytes + lastSlash + 1, "ruby", 4)) ext = "rb"; 864 else ext = "sh"; 865 } 866 } 867 } else if (0xffd8 == shortMagic && 0xff == bytes[2]) ext = "jpeg"; 868 else if (0x4657 == shortMagic && 0x53 == bytes[2]) ext = "swf"; 869 else if (0x4357 == shortMagic && 0x53 == bytes[2]) ext = "swc"; 870 else if (0x4944 == shortMagic && '3' == bytes[2] && 0x20 > bytes[3]) ext = "mp3"; 871 else if (0x425a == shortMagic && isdigit(bytes[2]) && isdigit(bytes[3])) ext = "bz"; 872 else if (0x425a == shortMagic && 'h' == bytes[2] && isdigit(bytes[3]) && 8 <= length && (0x31415926 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x17724538 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = "bz2"; 873 else if (0x0011 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 2))) || 0x0012 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 2)))) ext = "tfm"; 874 } 875 } 876 if (extension && !ext) { 877 //??? what about MacOSRoman? 878 if (0xef == bytes[0] && 0xbb == bytes[1] && 0xbf == bytes[2]) { // UTF-8 BOM 879 hasBOM = true; 880 isZero = false; 881 } 882 for (i = (hasBOM ? 3 : 0); (isPlain || isZero) && !ext && i < length && i < 512; i++) { 883 char c = bytes[i]; 884 if (isPlain && '<' == c && i + 14 <= length && 0 == ustrncasecmp(bytes + i + 1, "!doctype html", 13)) ext = "html"; 885 if (isSpace && '<' == c && i + 14 <= length) { 886 if (0 == ustrncasecmp(bytes + i + 1, "!doctype html", 13) || 0 == ustrncasecmp(bytes + i + 1, "head", 4) || 0 == ustrncasecmp(bytes + i + 1, "title", 5) || 0 == ustrncasecmp(bytes + i + 1, "script", 6) || 0 == ustrncasecmp(bytes + i + 1, "html", 4)) { 887 ext = "html"; 888 } else if (0 == ustrncasecmp(bytes + i + 1, "?xml", 4)) { 889 for (i += 4; !ext && i < 128 && i + 20 <= length; i++) { 890 if ('<' == bytes[i]) { 891 if (0 == ustrncasecmp(bytes + i + 1, "abiword", 7)) ext = "abw"; 892 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype svg", 12)) ext = "svg"; 893 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype rdf", 12)) ext = "rdf"; 894 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype x3d", 12)) ext = "x3d"; 895 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype html", 13)) ext = "html"; 896 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype posingfont", 19)) ext = "sfont"; 897 else if (0 == ustrncasecmp(bytes + i + 1, "!doctype plist", 14)) { 898 for (i += 14; !ext && i < 256 && i + 16 <= length; i++) { 899 if (0 == ustrncmp(bytes + i, "WebMainResource", 15)) ext = "webarchive"; 900 } 901 if (!ext) ext = "plist"; 902 } 903 } 904 } 905 if (!ext) ext = "xml"; 906 } 907 } 908 if (0 != c) isZero = false; 909 if (isZero || 0x7f <= c || (0x20 > c && !isspace(c))) isPlain = false; 910 if (isZero || !isspace(c)) isSpace = false; 911 } 912 if (!ext) { 913 if (isPlain) { 914 if (16 <= length && 0 == ustrncmp(bytes, "StartFontMetrics", 16)) ext = "afm"; 915 else ext = "txt"; 916 } else if (isZero && length >= MAGIC_BYTES_TO_READ && fileLength >= 526) { 917 if (isFile) { 918 if (lseek(fd, 512, SEEK_SET) == 512 && read(fd, buffer, MAGIC_BYTES_TO_READ) >= 14) { 919 if (0x001102ff == CFSwapInt32HostToBig(*((UInt32 *)(buffer + 10)))) ext = "pict"; 920 } 921 } else { 922 if (526 <= length && 0x001102ff == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 522)))) ext = "pict"; 923 } 924 } 925 } 926 } 927 if (extension && (!ext || 0 == strcmp(ext, "bz2")) && length >= MAGIC_BYTES_TO_READ && fileLength >= DMG_BYTES_TO_READ) { 928 if (isFile) { 929 if (lseek(fd, fileLength - DMG_BYTES_TO_READ, SEEK_SET) == fileLength - DMG_BYTES_TO_READ && read(fd, buffer, DMG_BYTES_TO_READ) >= DMG_BYTES_TO_READ) { 930 if (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32 *)buffer)) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32 *)(buffer + DMG_BYTES_TO_READ - 8))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32 *)(buffer + DMG_BYTES_TO_READ - 4))))) ext = "dmg"; 931 } 932 } else { 933 if (DMG_BYTES_TO_READ <= length && (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + length - DMG_BYTES_TO_READ))) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + length - 8))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + length - 4)))))) ext = "dmg"; 934 } 935 } 936 } 937 if (extension) *extension = ext ? CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault, ext, kCFStringEncodingUTF8, kCFAllocatorNull) : NULL; 938 if (machtype) *machtype = mt; 939 if (fd >= 0) close(fd); 940 return (ext ? true : false); 941 } 942 943 CFStringRef _CFBundleCopyFileTypeForFileURL(CFURLRef url) { 944 CFStringRef extension = NULL; 945 (void)_CFBundleGrokFileType(url, NULL, &extension, NULL, NULL, NULL, NULL, NULL, NULL); 946 return extension; 947 } 948 949 CFStringRef _CFBundleCopyFileTypeForFileData(CFDataRef data) { 950 CFStringRef extension = NULL; 951 (void)_CFBundleGrokFileType(NULL, data, &extension, NULL, NULL, NULL, NULL, NULL, NULL); 952 return extension; 953 } 954 955 CF_PRIVATE CFDictionaryRef _CFBundleCopyInfoDictionaryInExecutable(CFURLRef url) { 956 CFDictionaryRef result = NULL; 957 (void)_CFBundleGrokFileType(url, NULL, NULL, NULL, NULL, &result, NULL, NULL, NULL); 958 return result; 959 } 960 961 CF_PRIVATE CFArrayRef _CFBundleCopyArchitecturesForExecutable(CFURLRef url) { 962 CFArrayRef result = NULL; 963 (void)_CFBundleGrokFileType(url, NULL, NULL, NULL, &result, NULL, NULL, NULL, NULL); 964 return result; 965 } 966 967 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED 968 static Boolean _CFBundleGetObjCImageInfoForExecutable(CFURLRef url, uint32_t *objcVersion, uint32_t *objcFlags) { 969 Boolean retval = false; 970 (void)_CFBundleGrokFileType(url, NULL, NULL, NULL, NULL, NULL, &retval, objcVersion, objcFlags); 971 return retval; 972 } 973 974 CF_PRIVATE Boolean _CFBundleGetObjCImageInfo(CFBundleRef bundle, uint32_t *objcVersion, uint32_t *objcFlags) { 975 Boolean retval = false; 976 uint32_t localVersion = 0, localFlags = 0; 977 CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); 978 if (executableURL) { 979 retval = _CFBundleGetObjCImageInfoForExecutable(executableURL, &localVersion, &localFlags); 980 CFRelease(executableURL); 981 } 982 if (objcVersion) *objcVersion = localVersion; 983 if (objcFlags) *objcFlags = localFlags; 984 return retval; 985 } 986 #endif 987 988 #if defined(BINARY_SUPPORT_DYLD) 989 990 CF_PRIVATE __CFPBinaryType _CFBundleGrokBinaryType(CFURLRef executableURL) { 991 // Attempt to grok the type of the binary by looking for DYLD magic numbers. If one of the DYLD magic numbers is found, find out what type of Mach-o file it is. Otherwise, look for the PEF magic numbers to see if it is CFM. 992 __CFPBinaryType result = executableURL ? __CFBundleUnreadableBinary : __CFBundleNoBinary; 993 UInt32 machtype = UNKNOWN_FILETYPE; 994 if (_CFBundleGrokFileType(executableURL, NULL, NULL, &machtype, NULL, NULL, NULL, NULL, NULL)) { 995 switch (machtype) { 996 case MH_EXECUTE: 997 result = __CFBundleDYLDExecutableBinary; 998 break; 999 case MH_BUNDLE: 1000 result = __CFBundleDYLDBundleBinary; 1001 break; 1002 case MH_DYLIB: 1003 result = __CFBundleDYLDFrameworkBinary; 1004 break; 1005 case PEF_FILETYPE: 1006 result = __CFBundleCFMBinary; 1007 break; 1008 } 1009 } 1010 return result; 1011 } 1012 1013 #endif /* BINARY_SUPPORT_DYLD */ 1014