]> git.saurik.com Git - apple/cf.git/blob - CFBundle_Grok.c
CF-1153.18.tar.gz
[apple/cf.git] / 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