]> git.saurik.com Git - apple/cf.git/blob - CFBinaryPList.c
CF-476.10.tar.gz
[apple/cf.git] / CFBinaryPList.c
1 /*
2 * Copyright (c) 2008 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 /* CFBinaryPList.c
24 Copyright 2000-2002, Apple, Inc. All rights reserved.
25 Responsibility: Christopher Kane
26 */
27
28
29 #include <CoreFoundation/CFString.h>
30 #include <CoreFoundation/CFNumber.h>
31 #include <CoreFoundation/CFDate.h>
32 #include <CoreFoundation/CFData.h>
33 #include <CoreFoundation/CFArray.h>
34 #include <CoreFoundation/CFDictionary.h>
35 #include <CoreFoundation/CFSet.h>
36 #include <CoreFoundation/CFPropertyList.h>
37 #include <CoreFoundation/CFByteOrder.h>
38 #include <CoreFoundation/CFRuntime.h>
39 #include <stdio.h>
40 #include <limits.h>
41 #include <string.h>
42 #include "CFInternal.h"
43
44 typedef struct {
45 int64_t high;
46 uint64_t low;
47 } CFSInt128Struct;
48
49 enum {
50 kCFNumberSInt128Type = 17
51 };
52
53 extern CFNumberType _CFNumberGetType2(CFNumberRef number);
54
55 enum {
56 CF_NO_ERROR = 0,
57 CF_OVERFLOW_ERROR = (1 << 0),
58 };
59
60 CF_INLINE uint32_t __check_uint32_add_unsigned_unsigned(uint32_t x, uint32_t y, int32_t* err) {
61 if((UINT_MAX - y) < x)
62 *err = *err | CF_OVERFLOW_ERROR;
63 return x + y;
64 };
65
66 CF_INLINE uint64_t __check_uint64_add_unsigned_unsigned(uint64_t x, uint64_t y, int32_t* err) {
67 if((ULLONG_MAX - y) < x)
68 *err = *err | CF_OVERFLOW_ERROR;
69 return x + y;
70 };
71
72 CF_INLINE uint32_t __check_uint32_mul_unsigned_unsigned(uint32_t x, uint32_t y, int32_t* err) {
73 uint64_t tmp = (uint64_t) x * (uint64_t) y;
74 /* If any of the upper 32 bits touched, overflow */
75 if(tmp & 0xffffffff00000000ULL)
76 *err = *err | CF_OVERFLOW_ERROR;
77 return (uint32_t) tmp;
78 };
79
80 CF_INLINE uint64_t __check_uint64_mul_unsigned_unsigned(uint64_t x, uint64_t y, int32_t* err) {
81 if(x == 0) return 0;
82 if(ULLONG_MAX/x < y)
83 *err = *err | CF_OVERFLOW_ERROR;
84 return x * y;
85 };
86
87 #if __LP64__
88 #define check_ptr_add(p, a, err) (const uint8_t *)__check_uint64_add_unsigned_unsigned((uintptr_t)p, (uintptr_t)a, err)
89 #define check_size_t_mul(b, a, err) (size_t)__check_uint64_mul_unsigned_unsigned((size_t)b, (size_t)a, err)
90 #else
91 #define check_ptr_add(p, a, err) (const uint8_t *)__check_uint32_add_unsigned_unsigned((uintptr_t)p, (uintptr_t)a, err)
92 #define check_size_t_mul(b, a, err) (size_t)__check_uint32_mul_unsigned_unsigned((size_t)b, (size_t)a, err)
93 #endif
94
95
96 CF_INLINE CFTypeID __CFGenericTypeID_genericobj_inline(const void *cf) {
97 CFTypeID typeID = (*(uint32_t *)(((CFRuntimeBase *)cf)->_cfinfo) >> 8) & 0xFFFF;
98 return CF_IS_OBJC(typeID, cf) ? CFGetTypeID(cf) : typeID;
99 }
100
101 struct __CFKeyedArchiverUID {
102 CFRuntimeBase _base;
103 uint32_t _value;
104 };
105
106 static CFStringRef __CFKeyedArchiverUIDCopyDescription(CFTypeRef cf) {
107 CFKeyedArchiverUIDRef uid = (CFKeyedArchiverUIDRef)cf;
108 return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFKeyedArchiverUID %p [%p]>{value = %u}"), cf, CFGetAllocator(cf), uid->_value);
109 }
110
111 static CFStringRef __CFKeyedArchiverUIDCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
112 CFKeyedArchiverUIDRef uid = (CFKeyedArchiverUIDRef)cf;
113 return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("@%u@"), uid->_value);
114 }
115
116 static CFTypeID __kCFKeyedArchiverUIDTypeID = _kCFRuntimeNotATypeID;
117
118 static const CFRuntimeClass __CFKeyedArchiverUIDClass = {
119 0,
120 "CFKeyedArchiverUID",
121 NULL, // init
122 NULL, // copy
123 NULL, // finalize
124 NULL, // equal -- pointer equality only
125 NULL, // hash -- pointer hashing only
126 __CFKeyedArchiverUIDCopyFormattingDescription,
127 __CFKeyedArchiverUIDCopyDescription
128 };
129
130 __private_extern__ void __CFKeyedArchiverUIDInitialize(void) {
131 __kCFKeyedArchiverUIDTypeID = _CFRuntimeRegisterClass(&__CFKeyedArchiverUIDClass);
132 }
133
134 CFTypeID _CFKeyedArchiverUIDGetTypeID(void) {
135 return __kCFKeyedArchiverUIDTypeID;
136 }
137
138 CFKeyedArchiverUIDRef _CFKeyedArchiverUIDCreate(CFAllocatorRef allocator, uint32_t value) {
139 CFKeyedArchiverUIDRef uid;
140 uid = (CFKeyedArchiverUIDRef)_CFRuntimeCreateInstance(allocator, __kCFKeyedArchiverUIDTypeID, sizeof(struct __CFKeyedArchiverUID) - sizeof(CFRuntimeBase), NULL);
141 if (NULL == uid) {
142 return NULL;
143 }
144 ((struct __CFKeyedArchiverUID *)uid)->_value = value;
145 return uid;
146 }
147
148
149 uint32_t _CFKeyedArchiverUIDGetValue(CFKeyedArchiverUIDRef uid) {
150 return uid->_value;
151 }
152
153
154 typedef struct {
155 CFTypeRef stream;
156 CFTypeRef error;
157 uint64_t written;
158 int32_t used;
159 bool streamIsData;
160 uint8_t buffer[8192 - 32];
161 } __CFBinaryPlistWriteBuffer;
162
163 static void writeBytes(__CFBinaryPlistWriteBuffer *buf, const UInt8 *bytes, CFIndex length) {
164 if (0 == length) return;
165 if (buf->error) return;
166 if (buf->streamIsData) {
167 CFDataAppendBytes((CFMutableDataRef)buf->stream, bytes, length);
168 buf->written += length;
169 } else {
170 CFAssert(false, __kCFLogAssertion, "Streams are not supported on this platform");
171 }
172 }
173
174 static void bufferWrite(__CFBinaryPlistWriteBuffer *buf, const uint8_t *buffer, CFIndex count) {
175 if (0 == count) return;
176 if ((CFIndex)sizeof(buf->buffer) <= count) {
177 writeBytes(buf, buf->buffer, buf->used);
178 buf->used = 0;
179 writeBytes(buf, buffer, count);
180 return;
181 }
182 CFIndex copyLen = __CFMin(count, (CFIndex)sizeof(buf->buffer) - buf->used);
183 memmove(buf->buffer + buf->used, buffer, copyLen);
184 buf->used += copyLen;
185 if (sizeof(buf->buffer) == buf->used) {
186 writeBytes(buf, buf->buffer, sizeof(buf->buffer));
187 memmove(buf->buffer, buffer + copyLen, count - copyLen);
188 buf->used = count - copyLen;
189 }
190 }
191
192 static void bufferFlush(__CFBinaryPlistWriteBuffer *buf) {
193 writeBytes(buf, buf->buffer, buf->used);
194 buf->used = 0;
195 }
196
197 /*
198 HEADER
199 magic number ("bplist")
200 file format version
201
202 OBJECT TABLE
203 variable-sized objects
204
205 Object Formats (marker byte followed by additional info in some cases)
206 null 0000 0000
207 bool 0000 1000 // false
208 bool 0000 1001 // true
209 fill 0000 1111 // fill byte
210 int 0001 nnnn ... // # of bytes is 2^nnnn, big-endian bytes
211 real 0010 nnnn ... // # of bytes is 2^nnnn, big-endian bytes
212 date 0011 0011 ... // 8 byte float follows, big-endian bytes
213 data 0100 nnnn [int] ... // nnnn is number of bytes unless 1111 then int count follows, followed by bytes
214 string 0101 nnnn [int] ... // ASCII string, nnnn is # of chars, else 1111 then int count, then bytes
215 string 0110 nnnn [int] ... // Unicode string, nnnn is # of chars, else 1111 then int count, then big-endian 2-byte uint16_t
216 0111 xxxx // unused
217 uid 1000 nnnn ... // nnnn+1 is # of bytes
218 1001 xxxx // unused
219 array 1010 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows
220 1011 xxxx // unused
221 set 1100 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows
222 dict 1101 nnnn [int] keyref* objref* // nnnn is count, unless '1111', then int count follows
223 1110 xxxx // unused
224 1111 xxxx // unused
225
226 OFFSET TABLE
227 list of ints, byte size of which is given in trailer
228 -- these are the byte offsets into the file
229 -- number of these is in the trailer
230
231 TRAILER
232 byte size of offset ints in offset table
233 byte size of object refs in arrays and dicts
234 number of offsets in offset table (also is number of objects)
235 element # in offset table which is top level object
236 offset table offset
237
238 */
239
240
241 static CFTypeID stringtype = -1, datatype = -1, numbertype = -1, datetype = -1;
242 static CFTypeID booltype = -1, nulltype = -1, dicttype = -1, arraytype = -1, settype = -1;
243
244 static void _appendInt(__CFBinaryPlistWriteBuffer *buf, uint64_t bigint) {
245 uint8_t marker;
246 uint8_t *bytes;
247 CFIndex nbytes;
248 if (bigint <= (uint64_t)0xff) {
249 nbytes = 1;
250 marker = kCFBinaryPlistMarkerInt | 0;
251 } else if (bigint <= (uint64_t)0xffff) {
252 nbytes = 2;
253 marker = kCFBinaryPlistMarkerInt | 1;
254 } else if (bigint <= (uint64_t)0xffffffff) {
255 nbytes = 4;
256 marker = kCFBinaryPlistMarkerInt | 2;
257 } else {
258 nbytes = 8;
259 marker = kCFBinaryPlistMarkerInt | 3;
260 }
261 bigint = CFSwapInt64HostToBig(bigint);
262 bytes = (uint8_t *)&bigint + sizeof(bigint) - nbytes;
263 bufferWrite(buf, &marker, 1);
264 bufferWrite(buf, bytes, nbytes);
265 }
266
267 static void _appendUID(__CFBinaryPlistWriteBuffer *buf, CFKeyedArchiverUIDRef uid) {
268 uint8_t marker;
269 uint8_t *bytes;
270 CFIndex nbytes;
271 uint64_t bigint = _CFKeyedArchiverUIDGetValue(uid);
272 if (bigint <= (uint64_t)0xff) {
273 nbytes = 1;
274 } else if (bigint <= (uint64_t)0xffff) {
275 nbytes = 2;
276 } else if (bigint <= (uint64_t)0xffffffff) {
277 nbytes = 4;
278 } else {
279 nbytes = 8;
280 }
281 marker = kCFBinaryPlistMarkerUID | (uint8_t)(nbytes - 1);
282 bigint = CFSwapInt64HostToBig(bigint);
283 bytes = (uint8_t *)&bigint + sizeof(bigint) - nbytes;
284 bufferWrite(buf, &marker, 1);
285 bufferWrite(buf, bytes, nbytes);
286 }
287
288 static Boolean __plistNumberEqual(CFTypeRef cf1, CFTypeRef cf2) {
289 // As long as this equals function is more restrictive than the
290 // existing one, for any given type, the hash function need not
291 // also be provided for the uniquing set.
292 if (CFNumberIsFloatType((CFNumberRef)cf1) != CFNumberIsFloatType((CFNumberRef)cf2)) return false;
293 return CFEqual(cf1, cf2);
294 }
295
296 static CFHashCode __plistDataHash(CFTypeRef cf) {
297 CFDataRef data = (CFDataRef)cf;
298 return CFHashBytes((UInt8 *)CFDataGetBytePtr(data), __CFMin(CFDataGetLength(data), 1280));
299 }
300
301 static void _flattenPlist(CFPropertyListRef plist, CFMutableArrayRef objlist, CFMutableDictionaryRef objtable, CFMutableSetRef uniquingsets[]) {
302 CFPropertyListRef unique;
303 uint32_t refnum;
304 CFTypeID type = __CFGenericTypeID_genericobj_inline(plist);
305 CFIndex idx;
306 CFPropertyListRef *list, buffer[256];
307
308 // Do not unique dictionaries or arrays, because: they
309 // are slow to compare, and have poor hash codes.
310 // Uniquing bools is unnecessary.
311 int which = -1;
312 if (stringtype == type) {
313 which = 0;
314 } else if (numbertype == type) {
315 which = 1;
316 } else if (datetype == type) {
317 which = 2;
318 } else if (datatype == type) {
319 which = 3;
320 }
321 if (1 && -1 != which) {
322 CFMutableSetRef uniquingset = uniquingsets[which];
323 CFIndex before = CFSetGetCount(uniquingset);
324 CFSetAddValue(uniquingset, plist);
325 CFIndex after = CFSetGetCount(uniquingset);
326 if (after == before) { // already in set
327 unique = CFSetGetValue(uniquingset, plist);
328 if (unique != plist) {
329 refnum = (uint32_t)(uintptr_t)CFDictionaryGetValue(objtable, unique);
330 CFDictionaryAddValue(objtable, plist, (const void *)(uintptr_t)refnum);
331 }
332 return;
333 }
334 }
335 refnum = CFArrayGetCount(objlist);
336 CFArrayAppendValue(objlist, plist);
337 CFDictionaryAddValue(objtable, plist, (const void *)(uintptr_t)refnum);
338 if (dicttype == type) {
339 CFIndex count = CFDictionaryGetCount((CFDictionaryRef)plist);
340 list = (count <= 128) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 2 * count * sizeof(CFTypeRef), 0);
341 CFDictionaryGetKeysAndValues((CFDictionaryRef)plist, list, list + count);
342 for (idx = 0; idx < 2 * count; idx++) {
343 _flattenPlist(list[idx], objlist, objtable, uniquingsets);
344 }
345 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
346 } else if (arraytype == type) {
347 CFIndex count = CFArrayGetCount((CFArrayRef)plist);
348 list = (count <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, count * sizeof(CFTypeRef), 0);
349 CFArrayGetValues((CFArrayRef)plist, CFRangeMake(0, count), list);
350 for (idx = 0; idx < count; idx++) {
351 _flattenPlist(list[idx], objlist, objtable, uniquingsets);
352 }
353 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
354 }
355 }
356
357 // stream must be a CFMutableDataRef
358 CFIndex __CFBinaryPlistWriteToStream(CFPropertyListRef plist, CFTypeRef stream) {
359 CFMutableDictionaryRef objtable;
360 CFMutableArrayRef objlist;
361 CFBinaryPlistTrailer trailer;
362 uint64_t *offsets, length_so_far;
363 uint64_t mask, refnum;
364 int64_t idx, idx2, cnt;
365 __CFBinaryPlistWriteBuffer *buf;
366
367 if ((CFTypeID)-1 == stringtype) {
368 stringtype = CFStringGetTypeID();
369 }
370 if ((CFTypeID)-1 == datatype) {
371 datatype = CFDataGetTypeID();
372 }
373 if ((CFTypeID)-1 == numbertype) {
374 numbertype = CFNumberGetTypeID();
375 }
376 if ((CFTypeID)-1 == booltype) {
377 booltype = CFBooleanGetTypeID();
378 }
379 if ((CFTypeID)-1 == datetype) {
380 datetype = CFDateGetTypeID();
381 }
382 if ((CFTypeID)-1 == dicttype) {
383 dicttype = CFDictionaryGetTypeID();
384 }
385 if ((CFTypeID)-1 == arraytype) {
386 arraytype = CFArrayGetTypeID();
387 }
388 if ((CFTypeID)-1 == settype) {
389 settype = CFSetGetTypeID();
390 }
391 if ((CFTypeID)-1 == nulltype) {
392 nulltype = CFNullGetTypeID();
393 }
394
395 objtable = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
396 _CFDictionarySetCapacity(objtable, 640);
397 objlist = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
398 _CFArraySetCapacity(objlist, 640);
399 CFSetCallBacks cb = kCFTypeSetCallBacks;
400 cb.retain = NULL;
401 cb.release = NULL;
402 CFMutableSetRef uniquingsets[4];
403 uniquingsets[0] = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &cb);
404 _CFSetSetCapacity(uniquingsets[0], 1000);
405 cb.equal = __plistNumberEqual;
406 uniquingsets[1] = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &cb);
407 _CFSetSetCapacity(uniquingsets[1], 500);
408 cb.equal = kCFTypeSetCallBacks.equal;
409 uniquingsets[2] = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &cb);
410 _CFSetSetCapacity(uniquingsets[2], 500);
411 cb.hash = __plistDataHash;
412 uniquingsets[3] = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &cb);
413 _CFSetSetCapacity(uniquingsets[3], 500);
414
415 _flattenPlist(plist, objlist, objtable, uniquingsets);
416
417 CFRelease(uniquingsets[0]);
418 CFRelease(uniquingsets[1]);
419 CFRelease(uniquingsets[2]);
420 CFRelease(uniquingsets[3]);
421
422 cnt = CFArrayGetCount(objlist);
423 offsets = (uint64_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, (CFIndex)(cnt * sizeof(*offsets)), 0);
424
425 buf = (__CFBinaryPlistWriteBuffer *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFBinaryPlistWriteBuffer), 0);
426 buf->stream = stream;
427 buf->error = NULL;
428 buf->streamIsData = (CFGetTypeID(stream) == CFDataGetTypeID());
429 buf->written = 0;
430 buf->used = 0;
431 bufferWrite(buf, (uint8_t *)"bplist00", 8); // header
432
433 memset(&trailer, 0, sizeof(trailer));
434 trailer._numObjects = CFSwapInt64HostToBig(cnt);
435 trailer._topObject = 0; // true for this implementation
436 mask = ~(uint64_t)0;
437 while (cnt & mask) {
438 trailer._objectRefSize++;
439 mask = mask << 8;
440 }
441
442 for (idx = 0; idx < cnt; idx++) {
443 CFPropertyListRef obj = CFArrayGetValueAtIndex(objlist, (CFIndex)idx);
444 CFTypeID type = __CFGenericTypeID_genericobj_inline(obj);
445 offsets[idx] = buf->written + buf->used;
446 if (stringtype == type) {
447 CFIndex ret, count = CFStringGetLength((CFStringRef)obj);
448 CFIndex needed;
449 uint8_t *bytes, buffer[1024];
450 bytes = (count <= 1024) ? buffer : (uint8_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, count, 0);
451 // presumption, believed to be true, is that ASCII encoding may need
452 // less bytes, but will not need greater, than the # of unichars
453 ret = CFStringGetBytes((CFStringRef)obj, CFRangeMake(0, count), kCFStringEncodingASCII, 0, false, bytes, count, &needed);
454 if (ret == count) {
455 uint8_t marker = (uint8_t)(kCFBinaryPlistMarkerASCIIString | (needed < 15 ? needed : 0xf));
456 bufferWrite(buf, &marker, 1);
457 if (15 <= needed) {
458 _appendInt(buf, (uint64_t)needed);
459 }
460 bufferWrite(buf, bytes, needed);
461 } else {
462 UniChar *chars;
463 uint8_t marker = (uint8_t)(kCFBinaryPlistMarkerUnicode16String | (count < 15 ? count : 0xf));
464 bufferWrite(buf, &marker, 1);
465 if (15 <= count) {
466 _appendInt(buf, (uint64_t)count);
467 }
468 chars = (UniChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, count * sizeof(UniChar), 0);
469 CFStringGetCharacters((CFStringRef)obj, CFRangeMake(0, count), chars);
470 for (idx2 = 0; idx2 < count; idx2++) {
471 chars[idx2] = CFSwapInt16HostToBig(chars[idx2]);
472 }
473 bufferWrite(buf, (uint8_t *)chars, count * sizeof(UniChar));
474 CFAllocatorDeallocate(kCFAllocatorSystemDefault, chars);
475 }
476 if (bytes != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, bytes);
477 } else if (numbertype == type) {
478 uint8_t marker;
479 uint64_t bigint;
480 uint8_t *bytes;
481 CFIndex nbytes;
482 if (CFNumberIsFloatType((CFNumberRef)obj)) {
483 CFSwappedFloat64 swapped64;
484 CFSwappedFloat32 swapped32;
485 if (CFNumberGetByteSize((CFNumberRef)obj) <= (CFIndex)sizeof(float)) {
486 float v;
487 CFNumberGetValue((CFNumberRef)obj, kCFNumberFloat32Type, &v);
488 swapped32 = CFConvertFloat32HostToSwapped(v);
489 bytes = (uint8_t *)&swapped32;
490 nbytes = sizeof(float);
491 marker = kCFBinaryPlistMarkerReal | 2;
492 } else {
493 double v;
494 CFNumberGetValue((CFNumberRef)obj, kCFNumberFloat64Type, &v);
495 swapped64 = CFConvertFloat64HostToSwapped(v);
496 bytes = (uint8_t *)&swapped64;
497 nbytes = sizeof(double);
498 marker = kCFBinaryPlistMarkerReal | 3;
499 }
500 bufferWrite(buf, &marker, 1);
501 bufferWrite(buf, bytes, nbytes);
502 } else {
503 CFNumberType type = _CFNumberGetType2((CFNumberRef)obj);
504 if (kCFNumberSInt128Type == type) {
505 CFSInt128Struct s;
506 CFNumberGetValue((CFNumberRef)obj, kCFNumberSInt128Type, &s);
507 struct {
508 int64_t high;
509 uint64_t low;
510 } storage;
511 storage.high = CFSwapInt64HostToBig(s.high);
512 storage.low = CFSwapInt64HostToBig(s.low);
513 uint8_t *bytes = (uint8_t *)&storage;
514 uint8_t marker = kCFBinaryPlistMarkerInt | 4;
515 CFIndex nbytes = 16;
516 bufferWrite(buf, &marker, 1);
517 bufferWrite(buf, bytes, nbytes);
518 } else {
519 CFNumberGetValue((CFNumberRef)obj, kCFNumberSInt64Type, &bigint);
520 _appendInt(buf, bigint);
521 }
522 }
523 } else if (_CFKeyedArchiverUIDGetTypeID() == type) {
524 _appendUID(buf, (CFKeyedArchiverUIDRef)obj);
525 } else if (booltype == type) {
526 uint8_t marker = CFBooleanGetValue((CFBooleanRef)obj) ? kCFBinaryPlistMarkerTrue : kCFBinaryPlistMarkerFalse;
527 bufferWrite(buf, &marker, 1);
528 } else if (datatype == type) {
529 CFIndex count = CFDataGetLength((CFDataRef)obj);
530 uint8_t marker = (uint8_t)(kCFBinaryPlistMarkerData | (count < 15 ? count : 0xf));
531 bufferWrite(buf, &marker, 1);
532 if (15 <= count) {
533 _appendInt(buf, (uint64_t)count);
534 }
535 bufferWrite(buf, CFDataGetBytePtr((CFDataRef)obj), count);
536 } else if (datetype == type) {
537 CFSwappedFloat64 swapped;
538 uint8_t marker = kCFBinaryPlistMarkerDate;
539 bufferWrite(buf, &marker, 1);
540 swapped = CFConvertFloat64HostToSwapped(CFDateGetAbsoluteTime((CFDateRef)obj));
541 bufferWrite(buf, (uint8_t *)&swapped, sizeof(swapped));
542 } else if (dicttype == type) {
543 CFIndex count = CFDictionaryGetCount((CFDictionaryRef)obj);
544 CFPropertyListRef *list, buffer[512];
545 uint8_t marker = (uint8_t)(kCFBinaryPlistMarkerDict | (count < 15 ? count : 0xf));
546 bufferWrite(buf, &marker, 1);
547 if (15 <= count) {
548 _appendInt(buf, (uint64_t)count);
549 }
550 list = (count <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 2 * count * sizeof(CFTypeRef), 0);
551 CFDictionaryGetKeysAndValues((CFDictionaryRef)obj, list, list + count);
552 for (idx2 = 0; idx2 < 2 * count; idx2++) {
553 CFPropertyListRef value = list[idx2];
554 uint32_t swapped = 0;
555 uint8_t *source = (uint8_t *)&swapped;
556 refnum = (uint32_t)(uintptr_t)CFDictionaryGetValue(objtable, value);
557 swapped = CFSwapInt32HostToBig((uint32_t)refnum);
558 bufferWrite(buf, source + sizeof(swapped) - trailer._objectRefSize, trailer._objectRefSize);
559 }
560 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
561 } else if (arraytype == type) {
562 CFIndex count = CFArrayGetCount((CFArrayRef)obj);
563 CFPropertyListRef *list, buffer[256];
564 uint8_t marker = (uint8_t)(kCFBinaryPlistMarkerArray | (count < 15 ? count : 0xf));
565 bufferWrite(buf, &marker, 1);
566 if (15 <= count) {
567 _appendInt(buf, (uint64_t)count);
568 }
569 list = (count <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, count * sizeof(CFTypeRef), 0);
570 CFArrayGetValues((CFArrayRef)obj, CFRangeMake(0, count), list);
571 for (idx2 = 0; idx2 < count; idx2++) {
572 CFPropertyListRef value = list[idx2];
573 uint32_t swapped = 0;
574 uint8_t *source = (uint8_t *)&swapped;
575 refnum = (uint32_t)(uintptr_t)CFDictionaryGetValue(objtable, value);
576 swapped = CFSwapInt32HostToBig((uint32_t)refnum);
577 bufferWrite(buf, source + sizeof(swapped) - trailer._objectRefSize, trailer._objectRefSize);
578 }
579 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
580 } else {
581 CFRelease(objtable);
582 CFRelease(objlist);
583 if (buf->error) CFRelease(buf->error);
584 CFAllocatorDeallocate(kCFAllocatorSystemDefault, buf);
585 CFAllocatorDeallocate(kCFAllocatorSystemDefault, offsets);
586 return 0;
587 }
588 }
589 CFRelease(objtable);
590 CFRelease(objlist);
591
592 length_so_far = buf->written + buf->used;
593 trailer._offsetTableOffset = CFSwapInt64HostToBig(length_so_far);
594 trailer._offsetIntSize = 0;
595 mask = ~(uint64_t)0;
596 while (length_so_far & mask) {
597 trailer._offsetIntSize++;
598 mask = mask << 8;
599 }
600
601 for (idx = 0; idx < cnt; idx++) {
602 uint64_t swapped = CFSwapInt64HostToBig(offsets[idx]);
603 uint8_t *source = (uint8_t *)&swapped;
604 bufferWrite(buf, source + sizeof(*offsets) - trailer._offsetIntSize, trailer._offsetIntSize);
605 }
606 length_so_far += cnt * trailer._offsetIntSize;
607
608 bufferWrite(buf, (uint8_t *)&trailer, sizeof(trailer));
609 bufferFlush(buf);
610 length_so_far += sizeof(trailer);
611 if (buf->error) {
612 CFRelease(buf->error);
613 return 0;
614 }
615 CFAllocatorDeallocate(kCFAllocatorSystemDefault, buf);
616 CFAllocatorDeallocate(kCFAllocatorSystemDefault, offsets);
617 return (CFIndex)length_so_far;
618 }
619
620
621 #define FAIL_FALSE do { return false; } while (0)
622 #define FAIL_MAXOFFSET do { return UINT64_MAX; } while (0)
623
624 bool __CFBinaryPlistGetTopLevelInfo(const uint8_t *databytes, uint64_t datalen, uint8_t *marker, uint64_t *offset, CFBinaryPlistTrailer *trailer) {
625 CFBinaryPlistTrailer trail;
626
627 if ((CFTypeID)-1 == stringtype) {
628 stringtype = CFStringGetTypeID();
629 }
630 if ((CFTypeID)-1 == datatype) {
631 datatype = CFDataGetTypeID();
632 }
633 if ((CFTypeID)-1 == numbertype) {
634 numbertype = CFNumberGetTypeID();
635 }
636 if ((CFTypeID)-1 == booltype) {
637 booltype = CFBooleanGetTypeID();
638 }
639 if ((CFTypeID)-1 == datetype) {
640 datetype = CFDateGetTypeID();
641 }
642 if ((CFTypeID)-1 == dicttype) {
643 dicttype = CFDictionaryGetTypeID();
644 }
645 if ((CFTypeID)-1 == arraytype) {
646 arraytype = CFArrayGetTypeID();
647 }
648 if ((CFTypeID)-1 == settype) {
649 settype = CFSetGetTypeID();
650 }
651 if ((CFTypeID)-1 == nulltype) {
652 nulltype = CFNullGetTypeID();
653 }
654
655 if (!databytes || datalen < sizeof(trail) + 8 + 1) FAIL_FALSE;
656 if (0 != memcmp("bplist00", databytes, 8) && 0 != memcmp("bplist01", databytes, 8)) return false;
657 memmove(&trail, databytes + datalen - sizeof(trail), sizeof(trail));
658 if (trail._unused[0] != 0 || trail._unused[1] != 0 || trail._unused[2] != 0 || trail._unused[3] != 0 || trail._unused[4] != 0 || trail._unused[5] != 0) FAIL_FALSE;
659 trail._numObjects = CFSwapInt64BigToHost(trail._numObjects);
660 trail._topObject = CFSwapInt64BigToHost(trail._topObject);
661 trail._offsetTableOffset = CFSwapInt64BigToHost(trail._offsetTableOffset);
662 if (LONG_MAX < trail._numObjects) FAIL_FALSE;
663 if (LONG_MAX < trail._offsetTableOffset) FAIL_FALSE;
664 if (trail._numObjects < 1) FAIL_FALSE;
665 if (trail._numObjects <= trail._topObject) FAIL_FALSE;
666 if (trail._offsetTableOffset < 9) FAIL_FALSE;
667 if (datalen - sizeof(trail) <= trail._offsetTableOffset) FAIL_FALSE;
668 if (trail._offsetIntSize < 1) FAIL_FALSE;
669 if (trail._objectRefSize < 1) FAIL_FALSE;
670 int32_t err = CF_NO_ERROR;
671 uint64_t offsetIntSize = trail._offsetIntSize;
672 uint64_t offsetTableSize = __check_uint64_mul_unsigned_unsigned(trail._numObjects, offsetIntSize, &err);
673 if (CF_NO_ERROR!= err) FAIL_FALSE;
674 if (offsetTableSize < 1) FAIL_FALSE;
675 uint64_t objectDataSize = trail._offsetTableOffset - 8;
676 uint64_t tmpSum = __check_uint64_add_unsigned_unsigned(8, objectDataSize, &err);
677 tmpSum = __check_uint64_add_unsigned_unsigned(tmpSum, offsetTableSize, &err);
678 tmpSum = __check_uint64_add_unsigned_unsigned(tmpSum, sizeof(trail), &err);
679 if (CF_NO_ERROR != err) FAIL_FALSE;
680 if (datalen != tmpSum) FAIL_FALSE;
681 if (trail._objectRefSize < 8 && (1ULL << (8 * trail._objectRefSize)) <= trail._numObjects) FAIL_FALSE;
682 if (trail._offsetIntSize < 8 && (1ULL << (8 * trail._offsetIntSize)) <= trail._offsetTableOffset) FAIL_FALSE;
683 const uint8_t *objectsFirstByte;
684 objectsFirstByte = check_ptr_add(databytes, 8, &err);
685 if (CF_NO_ERROR != err) FAIL_FALSE;
686 const uint8_t *offsetsFirstByte = check_ptr_add(databytes, trail._offsetTableOffset, &err);
687 if (CF_NO_ERROR != err) FAIL_FALSE;
688 const uint8_t *offsetsLastByte;
689 offsetsLastByte = check_ptr_add(offsetsFirstByte, offsetTableSize - 1, &err);
690 if (CF_NO_ERROR != err) FAIL_FALSE;
691
692 const uint8_t *bytesptr = databytes + trail._offsetTableOffset;
693 uint64_t maxOffset = trail._offsetTableOffset - 1;
694 for (CFIndex idx = 0; idx < trail._numObjects; idx++) {
695 uint64_t off = 0;
696 for (CFIndex idx2 = 0; idx2 < trail._offsetIntSize; idx2++) {
697 off = (off << 8) + bytesptr[idx2];
698 }
699 if (maxOffset < off) FAIL_FALSE;
700 bytesptr += trail._offsetIntSize;
701 }
702
703 bytesptr = databytes + trail._offsetTableOffset + trail._topObject * trail._offsetIntSize;
704 uint64_t off = 0;
705 for (CFIndex idx = 0; idx < trail._offsetIntSize; idx++) {
706 off = (off << 8) + bytesptr[idx];
707 }
708 if (off < 8 || trail._offsetTableOffset <= off) FAIL_FALSE;
709 if (trailer) *trailer = trail;
710 if (offset) *offset = off;
711 if (marker) *marker = *(databytes + off);
712 return true;
713 }
714
715 CF_INLINE Boolean _plistIsPrimitive(CFPropertyListRef pl) {
716 CFTypeID type = __CFGenericTypeID_genericobj_inline(pl);
717 if (dicttype == type || arraytype == type || settype == type) FAIL_FALSE;
718 return true;
719 }
720
721 CF_INLINE bool _readInt(const uint8_t *ptr, const uint8_t *end_byte_ptr, uint64_t *bigint, const uint8_t **newptr) {
722 if (end_byte_ptr < ptr) FAIL_FALSE;
723 uint8_t marker = *ptr++;
724 if ((marker & 0xf0) != kCFBinaryPlistMarkerInt) FAIL_FALSE;
725 uint64_t cnt = 1 << (marker & 0x0f);
726 int32_t err = CF_NO_ERROR;
727 const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1;
728 if (CF_NO_ERROR != err) FAIL_FALSE;
729 if (end_byte_ptr < extent) FAIL_FALSE;
730 // integers are not required to be in the most compact possible representation, but only the last 64 bits are significant currently
731 *bigint = 0;
732 for (CFIndex idx = 0; idx < cnt; idx++) {
733 *bigint = (*bigint << 8) + *ptr++;
734 }
735 if (newptr) *newptr = ptr;
736 return true;
737 }
738
739 // bytesptr points at a ref
740 CF_INLINE uint64_t _getOffsetOfRefAt(const uint8_t *databytes, const uint8_t *bytesptr, const CFBinaryPlistTrailer *trailer) {
741 // *trailer contents are trusted, even for overflows -- was checked when the trailer was parsed;
742 // this pointer arithmetic and the multiplication was also already done once and checked,
743 // and the offsetTable was already validated.
744 const uint8_t *objectsFirstByte = databytes + 8;
745 const uint8_t *offsetsFirstByte = databytes + trailer->_offsetTableOffset;
746 if (bytesptr < objectsFirstByte || offsetsFirstByte - trailer->_objectRefSize < bytesptr) FAIL_MAXOFFSET;
747
748 uint64_t ref = 0;
749 for (CFIndex idx = 0; idx < trailer->_objectRefSize; idx++) {
750 ref = (ref << 8) + bytesptr[idx];
751 }
752 if (trailer->_numObjects <= ref) FAIL_MAXOFFSET;
753
754 bytesptr = databytes + trailer->_offsetTableOffset + ref * trailer->_offsetIntSize;
755 uint64_t off = 0;
756 for (CFIndex idx = 0; idx < trailer->_offsetIntSize; idx++) {
757 off = (off << 8) + bytesptr[idx];
758 }
759 return off;
760 }
761
762 static bool __CFBinaryPlistCreateObject2(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFAllocatorRef allocator, CFOptionFlags mutabilityOption, CFMutableDictionaryRef objects, CFMutableSetRef set, CFIndex curDepth, CFPropertyListRef *plist);
763
764 bool __CFBinaryPlistGetOffsetForValueFromArray2(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFIndex idx, uint64_t *offset, CFMutableDictionaryRef objects) {
765 uint64_t objectsRangeStart = 8, objectsRangeEnd = trailer->_offsetTableOffset - 1;
766 if (startOffset < objectsRangeStart || objectsRangeEnd < startOffset) FAIL_FALSE;
767 const uint8_t *ptr = databytes + startOffset;
768 uint8_t marker = *ptr;
769 if ((marker & 0xf0) != kCFBinaryPlistMarkerArray) FAIL_FALSE;
770 int32_t err = CF_NO_ERROR;
771 ptr = check_ptr_add(ptr, 1, &err);
772 if (CF_NO_ERROR != err) FAIL_FALSE;
773 uint64_t cnt = (marker & 0x0f);
774 if (0xf == cnt) {
775 uint64_t bigint;
776 if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE;
777 if (LONG_MAX < bigint) FAIL_FALSE;
778 cnt = bigint;
779 }
780 if (cnt <= idx) FAIL_FALSE;
781 size_t byte_cnt = check_size_t_mul(cnt, trailer->_objectRefSize, &err);
782 if (CF_NO_ERROR != err) FAIL_FALSE;
783 const uint8_t *extent = check_ptr_add(ptr, byte_cnt, &err) - 1;
784 if (CF_NO_ERROR != err) FAIL_FALSE;
785 if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
786 uint64_t off = _getOffsetOfRefAt(databytes, ptr + idx * trailer->_objectRefSize, trailer);
787 if (offset) *offset = off;
788 return true;
789 }
790
791 bool __CFBinaryPlistGetOffsetForValueFromDictionary2(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFTypeRef key, uint64_t *koffset, uint64_t *voffset, CFMutableDictionaryRef objects) {
792 if (!key || !_plistIsPrimitive(key)) FAIL_FALSE;
793 uint64_t objectsRangeStart = 8, objectsRangeEnd = trailer->_offsetTableOffset - 1;
794 if (startOffset < objectsRangeStart || objectsRangeEnd < startOffset) FAIL_FALSE;
795 const uint8_t *ptr = databytes + startOffset;
796 uint8_t marker = *ptr;
797 if ((marker & 0xf0) != kCFBinaryPlistMarkerDict) FAIL_FALSE;
798 int32_t err = CF_NO_ERROR;
799 ptr = check_ptr_add(ptr, 1, &err);
800 if (CF_NO_ERROR != err) FAIL_FALSE;
801 uint64_t cnt = (marker & 0x0f);
802 if (0xf == cnt) {
803 uint64_t bigint = 0;
804 if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE;
805 if (LONG_MAX < bigint) FAIL_FALSE;
806 cnt = bigint;
807 }
808 cnt = check_size_t_mul(cnt, 2, &err);
809 if (CF_NO_ERROR != err) FAIL_FALSE;
810 size_t byte_cnt = check_size_t_mul(cnt, trailer->_objectRefSize, &err);
811 if (CF_NO_ERROR != err) FAIL_FALSE;
812 const uint8_t *extent = check_ptr_add(ptr, byte_cnt, &err) - 1;
813 if (CF_NO_ERROR != err) FAIL_FALSE;
814 if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
815 CFIndex stringKeyLen = -1;
816 UniChar ubuffer[16];
817 if (__CFGenericTypeID_genericobj_inline(key) == stringtype) {
818 stringKeyLen = CFStringGetLength((CFStringRef)key);
819 if (stringKeyLen < 0xf) {
820 CFStringGetCharacters((CFStringRef)key, CFRangeMake(0, stringKeyLen), ubuffer);
821 }
822 }
823 cnt = cnt / 2;
824 for (CFIndex idx = 0; idx < cnt; idx++) {
825 uint64_t off = _getOffsetOfRefAt(databytes, ptr, trailer);
826 uint8_t marker = *(databytes + off);
827 CFIndex len = marker & 0x0f;
828 // if it is a short ascii string in the data, and the key is a string
829 if ((marker & 0xf0) == kCFBinaryPlistMarkerASCIIString && len < 0xf && stringKeyLen != -1) {
830 if (len != stringKeyLen) goto miss;
831 err = CF_NO_ERROR;
832 const uint8_t *ptr2 = databytes + off;
833 extent = check_ptr_add(ptr2, len, &err);
834 if (CF_NO_ERROR != err) FAIL_FALSE;
835 if (databytes + trailer->_offsetTableOffset <= extent) FAIL_FALSE;
836 for (CFIndex idx2 = 0; idx2 < stringKeyLen; idx2++) {
837 if ((UniChar)ptr2[idx2 + 1] != ubuffer[idx2]) goto miss;
838 }
839 if (koffset) *koffset = off;
840 if (voffset) {
841 off = _getOffsetOfRefAt(databytes, ptr + cnt * trailer->_objectRefSize, trailer);
842 *voffset = off;
843 }
844 return true;
845 miss:;
846 } else {
847 CFPropertyListRef pl = NULL;
848 if (!__CFBinaryPlistCreateObject2(databytes, datalen, off, trailer, kCFAllocatorSystemDefault, kCFPropertyListImmutable, objects, NULL, 0, &pl) || !_plistIsPrimitive(pl)) {
849 if (pl) CFRelease(pl);
850 FAIL_FALSE;
851 }
852 if (CFEqual(key, pl)) {
853 CFRelease(pl);
854 if (koffset) *koffset = off;
855 if (voffset) {
856 off = _getOffsetOfRefAt(databytes, ptr + cnt * trailer->_objectRefSize, trailer);
857 *voffset = off;
858 }
859 return true;
860 }
861 CFRelease(pl);
862 }
863 ptr += trailer->_objectRefSize;
864 }
865 return false;
866 }
867
868 extern CFArrayRef _CFArrayCreate_ex(CFAllocatorRef allocator, Boolean isMutable, const void **values, CFIndex numValues);
869 extern CFSetRef _CFSetCreate_ex(CFAllocatorRef allocator, Boolean isMutable, const void **values, CFIndex numValues);
870 extern CFDictionaryRef _CFDictionaryCreate_ex(CFAllocatorRef allocator, Boolean isMutable, const void **keys, const void **values, CFIndex numValues);
871
872 static bool __CFBinaryPlistCreateObject2(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFAllocatorRef allocator, CFOptionFlags mutabilityOption, CFMutableDictionaryRef objects, CFMutableSetRef set, CFIndex curDepth, CFPropertyListRef *plist) {
873
874 if (objects) {
875 *plist = CFDictionaryGetValue(objects, (const void *)(uintptr_t)startOffset);
876 if (*plist) {
877 CFRetain(*plist);
878 return true;
879 }
880 }
881
882 // at any one invocation of this function, set should contain the offsets in the "path" down to this object
883 if (set && CFSetContainsValue(set, (const void *)(uintptr_t)startOffset)) return false;
884
885 // databytes is trusted to be at least datalen bytes long
886 // *trailer contents are trusted, even for overflows -- was checked when the trailer was parsed
887 uint64_t objectsRangeStart = 8, objectsRangeEnd = trailer->_offsetTableOffset - 1;
888 if (startOffset < objectsRangeStart || objectsRangeEnd < startOffset) FAIL_FALSE;
889
890 uint64_t off;
891 CFPropertyListRef *list, buffer[256];
892 CFAllocatorRef listAllocator;
893
894 uint8_t marker = *(databytes + startOffset);
895 switch (marker & 0xf0) {
896 case kCFBinaryPlistMarkerNull:
897 switch (marker) {
898 case kCFBinaryPlistMarkerNull:
899 *plist = kCFNull;
900 return true;
901 case kCFBinaryPlistMarkerFalse:
902 *plist = CFRetain(kCFBooleanFalse);
903 return true;
904 case kCFBinaryPlistMarkerTrue:
905 *plist = CFRetain(kCFBooleanTrue);
906 return true;
907 }
908 FAIL_FALSE;
909 case kCFBinaryPlistMarkerInt:
910 {
911 const uint8_t *ptr = (databytes + startOffset);
912 int32_t err = CF_NO_ERROR;
913 ptr = check_ptr_add(ptr, 1, &err);
914 if (CF_NO_ERROR != err) FAIL_FALSE;
915 uint64_t cnt = 1 << (marker & 0x0f);
916 const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1;
917 if (CF_NO_ERROR != err) FAIL_FALSE;
918 if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
919 if (16 < cnt) FAIL_FALSE;
920 // in format version '00', 1, 2, and 4-byte integers have to be interpreted as unsigned,
921 // whereas 8-byte integers are signed (and 16-byte when available)
922 // negative 1, 2, 4-byte integers are always emitted as 8 bytes in format '00'
923 uint64_t bigint = 0;
924 // integers are not required to be in the most compact possible representation, but only the last 64 bits are significant currently
925 for (CFIndex idx = 0; idx < cnt; idx++) {
926 bigint = (bigint << 8) + *ptr++;
927 }
928 if (8 < cnt) {
929 CFSInt128Struct val;
930 val.high = 0;
931 val.low = bigint;
932 *plist = CFNumberCreate(allocator, kCFNumberSInt128Type, &val);
933 } else {
934 *plist = CFNumberCreate(allocator, kCFNumberSInt64Type, &bigint);
935 }
936 // these are always immutable
937 if (objects && *plist) {
938 CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist);
939 }
940 return (*plist) ? true : false;
941 }
942 case kCFBinaryPlistMarkerReal:
943 switch (marker & 0x0f) {
944 case 2: {
945 const uint8_t *ptr = (databytes + startOffset);
946 int32_t err = CF_NO_ERROR;
947 ptr = check_ptr_add(ptr, 1, &err);
948 if (CF_NO_ERROR != err) FAIL_FALSE;
949 const uint8_t *extent = check_ptr_add(ptr, 4, &err) - 1;
950 if (CF_NO_ERROR != err) FAIL_FALSE;
951 if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
952 CFSwappedFloat32 swapped32;
953 memmove(&swapped32, ptr, 4);
954 float f = CFConvertFloat32SwappedToHost(swapped32);
955 *plist = CFNumberCreate(allocator, kCFNumberFloat32Type, &f);
956 // these are always immutable
957 if (objects && *plist) {
958 CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist);
959 }
960 return (*plist) ? true : false;
961 }
962 case 3: {
963 const uint8_t *ptr = (databytes + startOffset);
964 int32_t err = CF_NO_ERROR;
965 ptr = check_ptr_add(ptr, 1, &err);
966 if (CF_NO_ERROR != err) FAIL_FALSE;
967 const uint8_t *extent = check_ptr_add(ptr, 8, &err) - 1;
968 if (CF_NO_ERROR != err) FAIL_FALSE;
969 if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
970 CFSwappedFloat64 swapped64;
971 memmove(&swapped64, ptr, 8);
972 double d = CFConvertFloat64SwappedToHost(swapped64);
973 *plist = CFNumberCreate(allocator, kCFNumberFloat64Type, &d);
974 // these are always immutable
975 if (objects && *plist) {
976 CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist);
977 }
978 return (*plist) ? true : false;
979 }
980 }
981 FAIL_FALSE;
982 case kCFBinaryPlistMarkerDate & 0xf0:
983 switch (marker) {
984 case kCFBinaryPlistMarkerDate: {
985 const uint8_t *ptr = (databytes + startOffset);
986 int32_t err = CF_NO_ERROR;
987 ptr = check_ptr_add(ptr, 1, &err);
988 if (CF_NO_ERROR != err) FAIL_FALSE;
989 const uint8_t *extent = check_ptr_add(ptr, 8, &err) - 1;
990 if (CF_NO_ERROR != err) FAIL_FALSE;
991 if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
992 CFSwappedFloat64 swapped64;
993 memmove(&swapped64, ptr, 8);
994 double d = CFConvertFloat64SwappedToHost(swapped64);
995 *plist = CFDateCreate(allocator, d);
996 // these are always immutable
997 if (objects && *plist) {
998 CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist);
999 }
1000 return (*plist) ? true : false;
1001 }
1002 }
1003 FAIL_FALSE;
1004 case kCFBinaryPlistMarkerData: {
1005 const uint8_t *ptr = databytes + startOffset;
1006 int32_t err = CF_NO_ERROR;
1007 ptr = check_ptr_add(ptr, 1, &err);
1008 if (CF_NO_ERROR != err) FAIL_FALSE;
1009 CFIndex cnt = marker & 0x0f;
1010 if (0xf == cnt) {
1011 uint64_t bigint = 0;
1012 if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE;
1013 if (LONG_MAX < bigint) FAIL_FALSE;
1014 cnt = (CFIndex)bigint;
1015 }
1016 const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1;
1017 if (CF_NO_ERROR != err) FAIL_FALSE;
1018 if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
1019 if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) {
1020 *plist = CFDataCreateMutable(allocator, 0);
1021 if (*plist) CFDataAppendBytes((CFMutableDataRef)*plist, ptr, cnt);
1022 } else {
1023 *plist = CFDataCreate(allocator, ptr, cnt);
1024 }
1025 if (objects && *plist && (mutabilityOption != kCFPropertyListMutableContainersAndLeaves)) {
1026 CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist);
1027 }
1028 return (*plist) ? true : false;
1029 }
1030 case kCFBinaryPlistMarkerASCIIString: {
1031 const uint8_t *ptr = databytes + startOffset;
1032 int32_t err = CF_NO_ERROR;
1033 ptr = check_ptr_add(ptr, 1, &err);
1034 if (CF_NO_ERROR != err) FAIL_FALSE;
1035 CFIndex cnt = marker & 0x0f;
1036 if (0xf == cnt) {
1037 uint64_t bigint = 0;
1038 if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE;
1039 if (LONG_MAX < bigint) FAIL_FALSE;
1040 cnt = (CFIndex)bigint;
1041 }
1042 const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1;
1043 if (CF_NO_ERROR != err) FAIL_FALSE;
1044 if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
1045 if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) {
1046 CFStringRef str = CFStringCreateWithBytes(allocator, ptr, cnt, kCFStringEncodingASCII, false);
1047 *plist = str ? CFStringCreateMutableCopy(allocator, 0, str) : NULL;
1048 if (str) CFRelease(str);
1049 } else {
1050 *plist = CFStringCreateWithBytes(allocator, ptr, cnt, kCFStringEncodingASCII, false);
1051 }
1052 if (objects && *plist && (mutabilityOption != kCFPropertyListMutableContainersAndLeaves)) {
1053 CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist);
1054 }
1055 return (*plist) ? true : false;
1056 }
1057 case kCFBinaryPlistMarkerUnicode16String: {
1058 const uint8_t *ptr = databytes + startOffset;
1059 int32_t err = CF_NO_ERROR;
1060 ptr = check_ptr_add(ptr, 1, &err);
1061 if (CF_NO_ERROR != err) FAIL_FALSE;
1062 CFIndex cnt = marker & 0x0f;
1063 if (0xf == cnt) {
1064 uint64_t bigint = 0;
1065 if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE;
1066 if (LONG_MAX < bigint) FAIL_FALSE;
1067 cnt = (CFIndex)bigint;
1068 }
1069 const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1;
1070 extent = check_ptr_add(extent, cnt, &err); // 2 bytes per character
1071 if (CF_NO_ERROR != err) FAIL_FALSE;
1072 if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
1073 size_t byte_cnt = check_size_t_mul(cnt, sizeof(UniChar), &err);
1074 if (CF_NO_ERROR != err) FAIL_FALSE;
1075 UniChar *chars = (UniChar *)CFAllocatorAllocate(allocator, byte_cnt, 0);
1076 if (!chars) FAIL_FALSE;
1077 memmove(chars, ptr, byte_cnt);
1078 for (CFIndex idx = 0; idx < cnt; idx++) {
1079 chars[idx] = CFSwapInt16BigToHost(chars[idx]);
1080 }
1081 if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) {
1082 CFStringRef str = CFStringCreateWithCharactersNoCopy(allocator, chars, cnt, allocator);
1083 *plist = str ? CFStringCreateMutableCopy(allocator, 0, str) : NULL;
1084 if (str) CFRelease(str);
1085 } else {
1086 *plist = CFStringCreateWithCharactersNoCopy(allocator, chars, cnt, allocator);
1087 }
1088 if (objects && *plist && (mutabilityOption != kCFPropertyListMutableContainersAndLeaves)) {
1089 CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist);
1090 }
1091 return (*plist) ? true : false;
1092 }
1093 case kCFBinaryPlistMarkerUID: {
1094 const uint8_t *ptr = databytes + startOffset;
1095 int32_t err = CF_NO_ERROR;
1096 ptr = check_ptr_add(ptr, 1, &err);
1097 if (CF_NO_ERROR != err) FAIL_FALSE;
1098 CFIndex cnt = (marker & 0x0f) + 1;
1099 const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1;
1100 if (CF_NO_ERROR != err) FAIL_FALSE;
1101 if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
1102 // uids are not required to be in the most compact possible representation, but only the last 64 bits are significant currently
1103 uint64_t bigint = 0;
1104 for (CFIndex idx = 0; idx < cnt; idx++) {
1105 bigint = (bigint << 8) + *ptr++;
1106 }
1107 if (UINT32_MAX < bigint) FAIL_FALSE;
1108 *plist = _CFKeyedArchiverUIDCreate(allocator, (uint32_t)bigint);
1109 // these are always immutable
1110 if (objects && *plist) {
1111 CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist);
1112 }
1113 return (*plist) ? true : false;
1114 }
1115 case kCFBinaryPlistMarkerArray:
1116 case kCFBinaryPlistMarkerSet: {
1117 const uint8_t *ptr = databytes + startOffset;
1118 int32_t err = CF_NO_ERROR;
1119 ptr = check_ptr_add(ptr, 1, &err);
1120 if (CF_NO_ERROR != err) FAIL_FALSE;
1121 CFIndex cnt = marker & 0x0f;
1122 if (0xf == cnt) {
1123 uint64_t bigint = 0;
1124 if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE;
1125 if (LONG_MAX < bigint) FAIL_FALSE;
1126 cnt = (CFIndex)bigint;
1127 }
1128 size_t byte_cnt = check_size_t_mul(cnt, trailer->_objectRefSize, &err);
1129 if (CF_NO_ERROR != err) FAIL_FALSE;
1130 const uint8_t *extent = check_ptr_add(ptr, byte_cnt, &err) - 1;
1131 if (CF_NO_ERROR != err) FAIL_FALSE;
1132 if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
1133 byte_cnt = check_size_t_mul(cnt, sizeof(CFPropertyListRef), &err);
1134 if (CF_NO_ERROR != err) FAIL_FALSE;
1135 list = (cnt <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, byte_cnt, __kCFAllocatorGCScannedMemory);
1136 listAllocator = (list == buffer ? kCFAllocatorNull : kCFAllocatorSystemDefault);
1137 if (!list) FAIL_FALSE;
1138 Boolean madeSet = false;
1139 if (!set && 15 < curDepth) {
1140 set = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
1141 madeSet = set ? true : false;
1142 }
1143 if (set) CFSetAddValue(set, (const void *)(uintptr_t)startOffset);
1144 for (CFIndex idx = 0; idx < cnt; idx++) {
1145 CFPropertyListRef pl;
1146 off = _getOffsetOfRefAt(databytes, ptr, trailer);
1147 if (!__CFBinaryPlistCreateObject2(databytes, datalen, off, trailer, allocator, mutabilityOption, objects, set, curDepth + 1, &pl)) {
1148 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
1149 while (idx--) {
1150 CFRelease(list[idx]);
1151 }
1152 }
1153 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1154 FAIL_FALSE;
1155 }
1156 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
1157 CF_WRITE_BARRIER_BASE_ASSIGN(listAllocator, list, list[idx], CFMakeCollectable(pl));
1158 } else {
1159 list[idx] = pl;
1160 }
1161 ptr += trailer->_objectRefSize;
1162 }
1163 if (set) CFSetRemoveValue(set, (const void *)(uintptr_t)startOffset);
1164 if (madeSet) {
1165 CFRelease(set);
1166 set = NULL;
1167 }
1168 if ((marker & 0xf0) == kCFBinaryPlistMarkerArray) {
1169 *plist = _CFArrayCreate_ex(allocator, (mutabilityOption != kCFPropertyListImmutable), list, cnt);
1170 } else {
1171 *plist = _CFSetCreate_ex(allocator, (mutabilityOption != kCFPropertyListImmutable), list, cnt);
1172 }
1173 if (objects && *plist && (mutabilityOption == kCFPropertyListImmutable)) {
1174 CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist);
1175 }
1176 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1177 return (*plist) ? true : false;
1178 }
1179 case kCFBinaryPlistMarkerDict: {
1180 const uint8_t *ptr = databytes + startOffset;
1181 int32_t err = CF_NO_ERROR;
1182 ptr = check_ptr_add(ptr, 1, &err);
1183 if (CF_NO_ERROR != err) FAIL_FALSE;
1184 CFIndex cnt = marker & 0x0f;
1185 if (0xf == cnt) {
1186 uint64_t bigint = 0;
1187 if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE;
1188 if (LONG_MAX < bigint) FAIL_FALSE;
1189 cnt = (CFIndex)bigint;
1190 }
1191 cnt = check_size_t_mul(cnt, 2, &err);
1192 if (CF_NO_ERROR != err) FAIL_FALSE;
1193 size_t byte_cnt = check_size_t_mul(cnt, trailer->_objectRefSize, &err);
1194 if (CF_NO_ERROR != err) FAIL_FALSE;
1195 const uint8_t *extent = check_ptr_add(ptr, byte_cnt, &err) - 1;
1196 if (CF_NO_ERROR != err) FAIL_FALSE;
1197 if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
1198 byte_cnt = check_size_t_mul(cnt, sizeof(CFPropertyListRef), &err);
1199 if (CF_NO_ERROR != err) FAIL_FALSE;
1200 list = (cnt <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, byte_cnt, __kCFAllocatorGCScannedMemory);
1201 listAllocator = (list == buffer ? kCFAllocatorNull : kCFAllocatorSystemDefault);
1202 if (!list) FAIL_FALSE;
1203 Boolean madeSet = false;
1204 if (!set && 15 < curDepth) {
1205 set = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
1206 madeSet = set ? true : false;
1207 }
1208 if (set) CFSetAddValue(set, (const void *)(uintptr_t)startOffset);
1209 for (CFIndex idx = 0; idx < cnt; idx++) {
1210 CFPropertyListRef pl = NULL;
1211 off = _getOffsetOfRefAt(databytes, ptr, trailer);
1212 if (!__CFBinaryPlistCreateObject2(databytes, datalen, off, trailer, allocator, mutabilityOption, objects, set, curDepth + 1, &pl) || (idx < cnt / 2 && !_plistIsPrimitive(pl))) {
1213 if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
1214 if (pl) CFRelease(pl);
1215 while (idx--) {
1216 CFRelease(list[idx]);
1217 }
1218 }
1219 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1220 FAIL_FALSE;
1221 }
1222 if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
1223 CF_WRITE_BARRIER_BASE_ASSIGN(listAllocator, list, list[idx], CFMakeCollectable(pl));
1224 } else {
1225 list[idx] = pl;
1226 }
1227 ptr += trailer->_objectRefSize;
1228 }
1229 if (set) CFSetRemoveValue(set, (const void *)(uintptr_t)startOffset);
1230 if (madeSet) {
1231 CFRelease(set);
1232 set = NULL;
1233 }
1234 *plist = _CFDictionaryCreate_ex(allocator, (mutabilityOption != kCFPropertyListImmutable), list, list + cnt / 2, cnt / 2);
1235 if (objects && *plist && (mutabilityOption == kCFPropertyListImmutable)) {
1236 CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist);
1237 }
1238 if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
1239 return (*plist) ? true : false;
1240 }
1241 }
1242 FAIL_FALSE;
1243 }
1244
1245 bool __CFBinaryPlistCreateObject(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFAllocatorRef allocator, CFOptionFlags mutabilityOption, CFMutableDictionaryRef objects, CFPropertyListRef *plist) {
1246 // for compatibility with Foundation's use, need to leave this here
1247 return __CFBinaryPlistCreateObject2(databytes, datalen, startOffset, trailer, allocator, mutabilityOption, objects, NULL, 0, plist);
1248 }
1249
1250 __private_extern__ bool __CFTryParseBinaryPlist(CFAllocatorRef allocator, CFDataRef data, CFOptionFlags option, CFPropertyListRef *plist, CFStringRef *errorString) {
1251 uint8_t marker;
1252 CFBinaryPlistTrailer trailer;
1253 uint64_t offset;
1254 const uint8_t *databytes = CFDataGetBytePtr(data);
1255 uint64_t datalen = CFDataGetLength(data);
1256
1257 if (8 <= datalen && __CFBinaryPlistGetTopLevelInfo(databytes, datalen, &marker, &offset, &trailer)) {
1258 // FALSE: We know for binary plist parsing that the result objects will be retained
1259 // by their containing collections as the parsing proceeds, so we do not need
1260 // to use retaining callbacks for the objects map in this case. WHY: the file might
1261 // be malformed and contain hash-equal keys for the same dictionary (for example)
1262 // and the later key will cause the previous one to be released when we set the second
1263 // in the dictionary.
1264 CFMutableDictionaryRef objects = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
1265 _CFDictionarySetCapacity(objects, 4000);
1266 CFPropertyListRef pl = NULL;
1267 if (__CFBinaryPlistCreateObject2(databytes, datalen, offset, &trailer, allocator, option, objects, NULL, 0, &pl)) {
1268 if (plist) *plist = pl;
1269 } else {
1270 if (plist) *plist = NULL;
1271 if (errorString) *errorString = (CFStringRef)CFRetain(CFSTR("binary data is corrupt"));
1272 }
1273 CFRelease(objects);
1274 return true;
1275 }
1276 return false;
1277 }
1278