+++ /dev/null
-/*
- * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-/* CFBinaryPList.c
- Copyright 2000-2002, Apple, Inc. All rights reserved.
- Responsibility: Christopher Kane
-*/
-
-#include <CoreFoundation/CFBase.h>
-#include <CoreFoundation/CFString.h>
-#include <CoreFoundation/CFNumber.h>
-#include <CoreFoundation/CFDate.h>
-#include <CoreFoundation/CFData.h>
-#include <CoreFoundation/CFArray.h>
-#include <CoreFoundation/CFDictionary.h>
-#include <CoreFoundation/CFSet.h>
-#include <CoreFoundation/CFPropertyList.h>
-#include <CoreFoundation/CFByteOrder.h>
-#include <CoreFoundation/CFRuntime.h>
-#include <CoreFoundation/CFStream.h>
-#include <stdio.h>
-#include <limits.h>
-#include <string.h>
-#include "CFInternal.h"
-
-
-CF_INLINE CFTypeID __CFGenericTypeID_genericobj_inline(const void *cf) {
- CFTypeID typeID = __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 15, 8);
- return CF_IS_OBJC(typeID, cf) ? CFGetTypeID(cf) : typeID;
-}
-
-struct __CFKeyedArchiverUID {
- CFRuntimeBase _base;
- uint32_t _value;
-};
-
-static CFStringRef __CFKeyedArchiverUIDCopyDescription(CFTypeRef cf) {
- CFKeyedArchiverUIDRef uid = (CFKeyedArchiverUIDRef)cf;
- return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<CFKeyedArchiverUID %p [%p]>{value = %u}"), cf, CFGetAllocator(cf), uid->_value);
-}
-
-static CFStringRef __CFKeyedArchiverUIDCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
- CFKeyedArchiverUIDRef uid = (CFKeyedArchiverUIDRef)cf;
- return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("@%u@"), uid->_value);
-}
-
-static CFTypeID __kCFKeyedArchiverUIDTypeID = _kCFRuntimeNotATypeID;
-
-static const CFRuntimeClass __CFKeyedArchiverUIDClass = {
- 0,
- "CFKeyedArchiverUID",
- NULL, // init
- NULL, // copy
- NULL, // finalize
- NULL, // equal -- pointer equality only
- NULL, // hash -- pointer hashing only
- __CFKeyedArchiverUIDCopyFormattingDescription,
- __CFKeyedArchiverUIDCopyDescription
-};
-
-__private_extern__ void __CFKeyedArchiverUIDInitialize(void) {
- __kCFKeyedArchiverUIDTypeID = _CFRuntimeRegisterClass(&__CFKeyedArchiverUIDClass);
-}
-
-CFTypeID _CFKeyedArchiverUIDGetTypeID(void) {
- return __kCFKeyedArchiverUIDTypeID;
-}
-
-CFKeyedArchiverUIDRef _CFKeyedArchiverUIDCreate(CFAllocatorRef allocator, uint32_t value) {
- CFKeyedArchiverUIDRef uid;
- uid = (CFKeyedArchiverUIDRef)_CFRuntimeCreateInstance(allocator, __kCFKeyedArchiverUIDTypeID, sizeof(struct __CFKeyedArchiverUID) - sizeof(CFRuntimeBase), NULL);
- if (NULL == uid) {
- return NULL;
- }
- ((struct __CFKeyedArchiverUID *)uid)->_value = value;
- return uid;
-}
-
-
-uint32_t _CFKeyedArchiverUIDGetValue(CFKeyedArchiverUIDRef uid) {
- return uid->_value;
-}
-
-
-typedef struct {
- CFTypeRef stream;
- bool streamIsData;
- uint64_t written;
- int32_t used;
- uint8_t buffer[8192 - 16];
-} __CFBinaryPlistWriteBuffer;
-
-CF_INLINE void writeBytes(__CFBinaryPlistWriteBuffer *buf, const UInt8 *bytes, CFIndex length) {
- if (buf->streamIsData) {
- CFDataAppendBytes((CFMutableDataRef)buf->stream, bytes, length);
- } else {
- CFWriteStreamWrite((CFWriteStreamRef)buf->stream, bytes, length);
- }
-}
-
-static void bufferWrite(__CFBinaryPlistWriteBuffer *buf, const uint8_t *buffer, CFIndex count) {
- CFIndex copyLen;
- if ((CFIndex)sizeof(buf->buffer) <= count) {
- writeBytes(buf, buf->buffer, buf->used);
- buf->written += buf->used;
- buf->used = 0;
- writeBytes(buf, buffer, count);
- buf->written += count;
- return;
- }
- copyLen = __CFMin(count, (CFIndex)sizeof(buf->buffer) - buf->used);
- memmove(buf->buffer + buf->used, buffer, copyLen);
- buf->used += copyLen;
- if (sizeof(buf->buffer) == buf->used) {
- writeBytes(buf, buf->buffer, sizeof(buf->buffer));
- buf->written += sizeof(buf->buffer);
- memmove(buf->buffer, buffer + copyLen, count - copyLen);
- buf->used = count - copyLen;
- }
-}
-
-static void bufferFlush(__CFBinaryPlistWriteBuffer *buf) {
- writeBytes(buf, buf->buffer, buf->used);
- buf->written += buf->used;
- buf->used = 0;
-}
-
-/*
-HEADER
- magic number ("bplist")
- file format version
-
-OBJECT TABLE
- variable-sized objects
-
- Object Formats (marker byte followed by additional info in some cases)
- null 0000 0000
- bool 0000 1000 // false
- bool 0000 1001 // true
- fill 0000 1111 // fill byte
- int 0001 nnnn ... // # of bytes is 2^nnnn, big-endian bytes
- real 0010 nnnn ... // # of bytes is 2^nnnn, big-endian bytes
- date 0011 0011 ... // 8 byte float follows, big-endian bytes
- data 0100 nnnn [int] ... // nnnn is number of bytes unless 1111 then int count follows, followed by bytes
- string 0101 nnnn [int] ... // ASCII string, nnnn is # of chars, else 1111 then int count, then bytes
- string 0110 nnnn [int] ... // Unicode string, nnnn is # of chars, else 1111 then int count, then big-endian 2-byte uint16_t
- 0111 xxxx // unused
- uid 1000 nnnn ... // nnnn+1 is # of bytes
- 1001 xxxx // unused
- array 1010 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows
- 1011 xxxx // unused
- 1100 xxxx // unused
- dict 1101 nnnn [int] keyref* objref* // nnnn is count, unless '1111', then int count follows
- 1110 xxxx // unused
- 1111 xxxx // unused
-
-OFFSET TABLE
- list of ints, byte size of which is given in trailer
- -- these are the byte offsets into the file
- -- number of these is in the trailer
-
-TRAILER
- byte size of offset ints in offset table
- byte size of object refs in arrays and dicts
- number of offsets in offset table (also is number of objects)
- element # in offset table which is top level object
-
-*/
-
-
-static CFTypeID stringtype = -1, datatype = -1, numbertype = -1, datetype = -1;
-static CFTypeID booltype = -1, dicttype = -1, arraytype = -1;
-
-static void _appendInt(__CFBinaryPlistWriteBuffer *buf, uint64_t bigint) {
- uint8_t marker;
- uint8_t *bytes;
- CFIndex nbytes;
- if (bigint <= (uint64_t)0xff) {
- nbytes = 1;
- marker = kCFBinaryPlistMarkerInt | 0;
- } else if (bigint <= (uint64_t)0xffff) {
- nbytes = 2;
- marker = kCFBinaryPlistMarkerInt | 1;
- } else if (bigint <= (uint64_t)0xffffffff) {
- nbytes = 4;
- marker = kCFBinaryPlistMarkerInt | 2;
- } else {
- nbytes = 8;
- marker = kCFBinaryPlistMarkerInt | 3;
- }
- bigint = CFSwapInt64HostToBig(bigint);
- bytes = (uint8_t *)&bigint + sizeof(bigint) - nbytes;
- bufferWrite(buf, &marker, 1);
- bufferWrite(buf, bytes, nbytes);
-}
-
-static void _appendUID(__CFBinaryPlistWriteBuffer *buf, CFKeyedArchiverUIDRef uid) {
- uint8_t marker;
- uint8_t *bytes;
- CFIndex nbytes;
- uint64_t bigint = _CFKeyedArchiverUIDGetValue(uid);
- if (bigint <= (uint64_t)0xff) {
- nbytes = 1;
- } else if (bigint <= (uint64_t)0xffff) {
- nbytes = 2;
- } else if (bigint <= (uint64_t)0xffffffff) {
- nbytes = 4;
- } else {
- nbytes = 8;
- }
- marker = kCFBinaryPlistMarkerUID | (nbytes - 1);
- bigint = CFSwapInt64HostToBig(bigint);
- bytes = (uint8_t *)&bigint + sizeof(bigint) - nbytes;
- bufferWrite(buf, &marker, 1);
- bufferWrite(buf, bytes, nbytes);
-}
-
-static Boolean __plistUniquingEqual(CFTypeRef cf1, CFTypeRef cf2) {
- // As long as this equals function is more restrictive than the
- // existing one, for any given type, the hash function need not
- // also be provided for the uniquing set.
- if (__CFGenericTypeID_genericobj_inline(cf1) != __CFGenericTypeID_genericobj_inline(cf2)) return false;
- if (__CFGenericTypeID_genericobj_inline(cf1) == numbertype) {
- if (CFNumberIsFloatType(cf1) != CFNumberIsFloatType(cf2)) return false;
- return CFEqual(cf1, cf2);
- }
- return CFEqual(cf1, cf2);
-}
-
-static void _flattenPlist(CFPropertyListRef plist, CFMutableArrayRef objlist, CFMutableDictionaryRef objtable, CFMutableSetRef uniquingsets[]) {
- CFPropertyListRef unique;
- uint32_t refnum;
- CFTypeID type = __CFGenericTypeID_genericobj_inline(plist);
- CFIndex idx;
- CFPropertyListRef *list, buffer[256];
-
- // Do not unique dictionaries or arrays, because: they
- // are slow to compare, and have poor hash codes.
- // Uniquing bools is unnecessary.
- int which = -1;
- if (stringtype == type) {
- which = 0;
- } else if (numbertype == type) {
- which = 1;
- } else if (datatype == type) {
- which = 2;
- } else if (datetype == type) {
- which = 3;
- }
- if (1 && -1 != which) {
- CFMutableSetRef uniquingset = uniquingsets[which];
- CFIndex before = CFSetGetCount(uniquingset);
- CFSetAddValue(uniquingset, plist);
- CFIndex after = CFSetGetCount(uniquingset);
- if (after == before) { // already in set
- unique = CFSetGetValue(uniquingset, plist);
- if (unique != plist) {
- refnum = (uint32_t)CFDictionaryGetValue(objtable, unique);
- CFDictionaryAddValue(objtable, plist, (const void *)refnum);
- }
- return;
- }
- }
- refnum = CFArrayGetCount(objlist);
- CFArrayAppendValue(objlist, plist);
- CFDictionaryAddValue(objtable, plist, (const void *)refnum);
- if (dicttype == type) {
- CFIndex count = CFDictionaryGetCount(plist);
- list = (count <= 128) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, 2 * count * sizeof(CFTypeRef), 0);
- CFDictionaryGetKeysAndValues(plist, list, list + count);
- for (idx = 0; idx < 2 * count; idx++) {
- _flattenPlist(list[idx], objlist, objtable, uniquingsets);
- }
- if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
- } else if (arraytype == type) {
- CFIndex count = CFArrayGetCount(plist);
- list = (count <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, count * sizeof(CFTypeRef), 0);
- CFArrayGetValues(plist, CFRangeMake(0, count), list);
- for (idx = 0; idx < count; idx++) {
- _flattenPlist(list[idx], objlist, objtable, uniquingsets);
- }
- if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
- }
-}
-
-// stream can be a CFWriteStreamRef or a CFMutableDataRef
-CFIndex __CFBinaryPlistWriteToStream(CFPropertyListRef plist, CFTypeRef stream) {
- CFMutableDictionaryRef objtable;
- CFMutableArrayRef objlist;
- CFBinaryPlistTrailer trailer;
- uint64_t *offsets, length_so_far;
- uint64_t mask, refnum;
- int64_t idx, idx2, cnt;
- __CFBinaryPlistWriteBuffer *buf;
- CFSetCallBacks cb = kCFTypeSetCallBacks;
-
- if ((CFTypeID)-1 == stringtype) {
- stringtype = CFStringGetTypeID();
- datatype = CFDataGetTypeID();
- numbertype = CFNumberGetTypeID();
- booltype = CFBooleanGetTypeID();
- datetype = CFDateGetTypeID();
- dicttype = CFDictionaryGetTypeID();
- arraytype = CFArrayGetTypeID();
- }
- objtable = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL);
- _CFDictionarySetCapacity(objtable, 640);
- objlist = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
- _CFArraySetCapacity(objlist, 640);
- cb.equal = __plistUniquingEqual;
- CFMutableSetRef uniquingsets[4];
- uniquingsets[0] = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &cb);
- _CFSetSetCapacity(uniquingsets[0], 1000);
- uniquingsets[1] = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &cb);
- _CFSetSetCapacity(uniquingsets[1], 500);
- uniquingsets[2] = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &cb);
- _CFSetSetCapacity(uniquingsets[2], 250);
- uniquingsets[3] = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &cb);
- _CFSetSetCapacity(uniquingsets[3], 250);
-
- _flattenPlist(plist, objlist, objtable, uniquingsets);
-
- CFRelease(uniquingsets[0]);
- CFRelease(uniquingsets[1]);
- CFRelease(uniquingsets[2]);
- CFRelease(uniquingsets[3]);
-
- cnt = CFArrayGetCount(objlist);
- offsets = CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(*offsets), 0);
-
- buf = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFBinaryPlistWriteBuffer), 0);
- buf->stream = stream;
- buf->streamIsData = (CFGetTypeID(stream) == CFDataGetTypeID());
- buf->written = 0;
- buf->used = 0;
- bufferWrite(buf, "bplist00", 8); // header
-
- memset(&trailer, 0, sizeof(trailer));
- trailer._numObjects = CFSwapInt64HostToBig(cnt);
- trailer._topObject = 0; // true for this implementation
- mask = ~(uint64_t)0;
- while (cnt & mask) {
- trailer._objectRefSize++;
- mask = mask << 8;
- }
-
- for (idx = 0; idx < cnt; idx++) {
- CFPropertyListRef obj = CFArrayGetValueAtIndex(objlist, idx);
- CFTypeID type = CFGetTypeID(obj);
- offsets[idx] = buf->written + buf->used;
- if (stringtype == type) {
- CFIndex ret, count = CFStringGetLength(obj);
- CFIndex needed;
- uint8_t *bytes, buffer[1024];
- bytes = (count <= 1024) ? buffer : CFAllocatorAllocate(kCFAllocatorDefault, count, 0);
- // presumption, believed to be true, is that ASCII encoding may need
- // less bytes, but will not need greater, than the # of unichars
- ret = CFStringGetBytes(obj, CFRangeMake(0, count), kCFStringEncodingASCII, 0, false, bytes, count, &needed);
- if (ret == count) {
- uint8_t marker = kCFBinaryPlistMarkerASCIIString | (needed < 15 ? needed : 0xf);
- bufferWrite(buf, &marker, 1);
- if (15 <= needed) {
- _appendInt(buf, (uint64_t)needed);
- }
- bufferWrite(buf, bytes, needed);
- } else {
- UniChar *chars;
- uint8_t marker = kCFBinaryPlistMarkerUnicode16String | (count < 15 ? count : 0xf);
- bufferWrite(buf, &marker, 1);
- if (15 <= count) {
- _appendInt(buf, (uint64_t)count);
- }
- chars = CFAllocatorAllocate(kCFAllocatorDefault, count * sizeof(UniChar), 0);
- CFStringGetCharacters(obj, CFRangeMake(0, count), chars);
- for (idx2 = 0; idx2 < count; idx2++) {
- chars[idx2] = CFSwapInt16HostToBig(chars[idx2]);
- }
- bufferWrite(buf, (uint8_t *)chars, count * sizeof(UniChar));
- CFAllocatorDeallocate(kCFAllocatorDefault, chars);
- }
- if (bytes != buffer) CFAllocatorDeallocate(kCFAllocatorDefault, bytes);
- } else if (numbertype == type) {
- uint8_t marker;
- CFSwappedFloat64 swapped64;
- CFSwappedFloat32 swapped32;
- uint64_t bigint;
- uint8_t *bytes;
- CFIndex nbytes;
- if (CFNumberIsFloatType(obj)) {
- if (CFNumberGetByteSize(obj) <= (CFIndex)sizeof(float)) {
- float v;
- CFNumberGetValue(obj, kCFNumberFloat32Type, &v);
- swapped32 = CFConvertFloat32HostToSwapped(v);
- bytes = (uint8_t *)&swapped32;
- nbytes = sizeof(float);
- marker = kCFBinaryPlistMarkerReal | 2;
- } else {
- double v;
- CFNumberGetValue(obj, kCFNumberFloat64Type, &v);
- swapped64 = CFConvertFloat64HostToSwapped(v);
- bytes = (uint8_t *)&swapped64;
- nbytes = sizeof(double);
- marker = kCFBinaryPlistMarkerReal | 3;
- }
- bufferWrite(buf, &marker, 1);
- bufferWrite(buf, bytes, nbytes);
- } else {
- CFNumberGetValue(obj, kCFNumberSInt64Type, &bigint);
- _appendInt(buf, bigint);
- }
- } else if (_CFKeyedArchiverUIDGetTypeID() == type) {
- _appendUID(buf, (CFKeyedArchiverUIDRef)obj);
- } else if (booltype == type) {
- uint8_t marker = CFBooleanGetValue(obj) ? kCFBinaryPlistMarkerTrue : kCFBinaryPlistMarkerFalse;
- bufferWrite(buf, &marker, 1);
- } else if (datatype == type) {
- CFIndex count = CFDataGetLength(obj);
- uint8_t marker = kCFBinaryPlistMarkerData | (count < 15 ? count : 0xf);
- bufferWrite(buf, &marker, 1);
- if (15 <= count) {
- _appendInt(buf, (uint64_t)count);
- }
- bufferWrite(buf, CFDataGetBytePtr(obj), count);
- } else if (datetype == type) {
- CFSwappedFloat64 swapped;
- uint8_t marker = kCFBinaryPlistMarkerDate;
- bufferWrite(buf, &marker, 1);
- swapped = CFConvertFloat64HostToSwapped(CFDateGetAbsoluteTime(obj));
- bufferWrite(buf, (uint8_t *)&swapped, sizeof(swapped));
- } else if (dicttype == type) {
- CFIndex count = CFDictionaryGetCount(obj);
- CFPropertyListRef *list, buffer[512];
- uint8_t marker = kCFBinaryPlistMarkerDict | (count < 15 ? count : 0xf);
- bufferWrite(buf, &marker, 1);
- if (15 <= count) {
- _appendInt(buf, (uint64_t)count);
- }
- list = (count <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, 2 * count * sizeof(CFTypeRef), 0);
- CFDictionaryGetKeysAndValues(obj, list, list + count);
- for (idx2 = 0; idx2 < 2 * count; idx2++) {
- CFPropertyListRef value = list[idx2];
- uint32_t swapped = 0;
- uint8_t *source = (uint8_t *)&swapped;
- refnum = (uint32_t)CFDictionaryGetValue(objtable, value);
- swapped = CFSwapInt32HostToBig(refnum);
- bufferWrite(buf, source + sizeof(swapped) - trailer._objectRefSize, trailer._objectRefSize);
- }
- if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
- } else if (arraytype == type) {
- CFIndex count = CFArrayGetCount(obj);
- CFPropertyListRef *list, buffer[256];
- uint8_t marker = kCFBinaryPlistMarkerArray | (count < 15 ? count : 0xf);
- bufferWrite(buf, &marker, 1);
- if (15 <= count) {
- _appendInt(buf, (uint64_t)count);
- }
- list = (count <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, count * sizeof(CFTypeRef), 0);
- CFArrayGetValues(obj, CFRangeMake(0, count), list);
- for (idx2 = 0; idx2 < count; idx2++) {
- CFPropertyListRef value = list[idx2];
- uint32_t swapped = 0;
- uint8_t *source = (uint8_t *)&swapped;
- refnum = (uint32_t)CFDictionaryGetValue(objtable, value);
- swapped = CFSwapInt32HostToBig(refnum);
- bufferWrite(buf, source + sizeof(swapped) - trailer._objectRefSize, trailer._objectRefSize);
- }
- if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
- } else {
- CFRelease(objtable);
- CFRelease(objlist);
- CFAllocatorDeallocate(kCFAllocatorSystemDefault, buf);
- CFAllocatorDeallocate(kCFAllocatorSystemDefault, offsets);
- return 0;
- }
- }
- CFRelease(objtable);
- CFRelease(objlist);
-
- length_so_far = buf->written + buf->used;
- trailer._offsetTableOffset = CFSwapInt64HostToBig(length_so_far);
- trailer._offsetIntSize = 0;
- mask = ~(uint64_t)0;
- while (length_so_far & mask) {
- trailer._offsetIntSize++;
- mask = mask << 8;
- }
-
- for (idx = 0; idx < cnt; idx++) {
- uint64_t swapped = CFSwapInt64HostToBig(offsets[idx]);
- uint8_t *source = (uint8_t *)&swapped;
- bufferWrite(buf, source + sizeof(*offsets) - trailer._offsetIntSize, trailer._offsetIntSize);
- }
- length_so_far += cnt * trailer._offsetIntSize;
-
- bufferWrite(buf, (uint8_t *)&trailer, sizeof(trailer));
- bufferFlush(buf);
- length_so_far += sizeof(trailer);
- CFAllocatorDeallocate(kCFAllocatorSystemDefault, buf);
- CFAllocatorDeallocate(kCFAllocatorSystemDefault, offsets);
- return (CFIndex)length_so_far;
-}
-
-bool __CFBinaryPlistGetTopLevelInfo(const uint8_t *databytes, uint64_t datalen, uint8_t *marker, uint64_t *offset, CFBinaryPlistTrailer *trailer) {
- const uint8_t *bytesptr;
- CFBinaryPlistTrailer trail;
- uint64_t off;
- CFIndex idx;
-
- if ((CFTypeID)-1 == stringtype) {
- stringtype = CFStringGetTypeID();
- datatype = CFDataGetTypeID();
- numbertype = CFNumberGetTypeID();
- booltype = CFBooleanGetTypeID();
- datetype = CFDateGetTypeID();
- dicttype = CFDictionaryGetTypeID();
- arraytype = CFArrayGetTypeID();
- }
- if (!databytes || datalen < 8 || 0 != memcmp("bplist00", databytes, 8)) return false;
- if (datalen < sizeof(trail) + 8 + 1) return false;
- memmove(&trail, databytes + datalen - sizeof(trail), sizeof(trail));
- trail._numObjects = CFSwapInt64BigToHost(trail._numObjects);
- trail._topObject = CFSwapInt64BigToHost(trail._topObject);
- if (trail._numObjects < trail._topObject) return false;
- trail._offsetTableOffset = CFSwapInt64BigToHost(trail._offsetTableOffset);
- if (datalen < trail._offsetTableOffset + trail._numObjects * trail._offsetIntSize + sizeof(trail)) return false;
- bytesptr = databytes + trail._offsetTableOffset + trail._topObject * trail._offsetIntSize;
- off = 0;
- for (idx = 0; idx < trail._offsetIntSize; idx++) {
- off = (off << 8) + bytesptr[idx];
- }
- if (trail._offsetTableOffset <= off) return false;
- if (trailer) *trailer = trail;
- if (offset) *offset = off;
- if (marker) *marker = *(databytes + off);
- return true;
-}
-
-static bool _readInt(const uint8_t *ptr, uint64_t *bigint, const uint8_t **newptr) {
- uint8_t marker;
- CFIndex idx, cnt;
- marker = *ptr++;
- if ((marker & 0xf0) != kCFBinaryPlistMarkerInt) return false;
- cnt = 1 << (marker & 0xf);
- *bigint = 0;
- for (idx = 0; idx < cnt; idx++) {
- *bigint = (*bigint << 8) + *ptr++;
- }
- if (newptr) *newptr = ptr;
- return true;
-}
-
-static uint64_t _getOffsetOfRefAt(const uint8_t *databytes, const uint8_t *bytesptr, const CFBinaryPlistTrailer *trailer) {
- uint64_t ref = 0, off = 0;
- CFIndex idx;
- for (idx = 0; idx < trailer->_objectRefSize; idx++) {
- ref = (ref << 8) + bytesptr[idx];
- }
- bytesptr = databytes + trailer->_offsetTableOffset + ref * trailer->_offsetIntSize;
- for (idx = 0; idx < trailer->_offsetIntSize; idx++) {
- off = (off << 8) + bytesptr[idx];
- }
- return off;
-}
-
-bool __CFBinaryPlistGetOffsetForValueFromArray(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFIndex idx, uint64_t *offset) {
- const uint8_t *bytesptr;
- uint8_t marker;
- CFIndex cnt;
- uint64_t off;
-
- marker = *(databytes + startOffset);
- if ((marker & 0xf0) != kCFBinaryPlistMarkerArray) return false;
- cnt = (marker & 0x0f);
- if (cnt < 15 && cnt <= idx) return false;
- bytesptr = databytes + startOffset + 1;
- if (0xf == cnt) {
- uint64_t bigint;
- if (!_readInt(bytesptr, &bigint, &bytesptr)) return false;
- if (INT_MAX < bigint) return false;
- cnt = (CFIndex)bigint;
- }
- if (cnt <= idx) return false;
- off = _getOffsetOfRefAt(databytes, bytesptr + idx * trailer->_objectRefSize, trailer);
- if (datalen <= off) return false;
- if (offset) *offset = off;
- return true;
-}
-
-bool __CFBinaryPlistGetOffsetForValueFromDictionary(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFTypeRef key, uint64_t *koffset, uint64_t *voffset) {
- const uint8_t *refsptr, *bytesptr;
- uint64_t off;
- uint8_t marker;
- CFTypeID keytype = CFGetTypeID(key);
- CFIndex idx, keyn, cnt, cnt2;
-
- marker = *(databytes + startOffset);
- if ((marker & 0xf0) != kCFBinaryPlistMarkerDict) return false;
- cnt = (marker & 0x0f);
- refsptr = databytes + startOffset + 1 + 0;
- if (0xf == cnt) {
- uint64_t bigint;
- if (!_readInt(refsptr, &bigint, &refsptr)) return false;
- if (INT_MAX < bigint) return false;
- cnt = (CFIndex)bigint;
- }
- for (keyn = 0; keyn < cnt; keyn++) {
- off = _getOffsetOfRefAt(databytes, refsptr, trailer);
- if (datalen <= off) return false;
- refsptr += trailer->_objectRefSize;
- bytesptr = databytes + off;
- marker = *bytesptr & 0xf0;
- cnt2 = *bytesptr & 0x0f;
- if (kCFBinaryPlistMarkerASCIIString == marker || kCFBinaryPlistMarkerUnicode16String == marker) {
- CFStringInlineBuffer strbuf;
- UniChar uchar;
- if (keytype != stringtype) goto miss;
- if (0xf == cnt2 && CFStringGetLength(key) < 15) goto miss;
- bytesptr++;
- if (0xf == cnt2) {
- uint64_t bigint;
- if (!_readInt(bytesptr, &bigint, &bytesptr)) return false;
- if (INT_MAX < bigint) return false;
- cnt2 = (CFIndex)bigint;
- }
- if (cnt2 != CFStringGetLength(key)) goto miss;
- uchar = (kCFBinaryPlistMarkerASCIIString == marker) ? (UniChar)bytesptr[0] : (UniChar)(bytesptr[0] * 256 + bytesptr[1]);
- if (uchar != CFStringGetCharacterAtIndex(key, 0)) goto miss;
- bytesptr += (kCFBinaryPlistMarkerASCIIString == marker) ? 1 : 2;
- CFStringInitInlineBuffer(key, &strbuf, CFRangeMake(0, cnt2));
- for (idx = 1; idx < cnt2; idx++) {
- uchar = (kCFBinaryPlistMarkerASCIIString == marker) ? (UniChar)bytesptr[0] : (UniChar)(bytesptr[0] * 256 + bytesptr[1]);
- if (uchar != __CFStringGetCharacterFromInlineBufferQuick(&strbuf, idx)) goto miss;
- bytesptr += (kCFBinaryPlistMarkerASCIIString == marker) ? 1 : 2;
- }
- if (koffset) *koffset = off;
- off = _getOffsetOfRefAt(databytes, refsptr + (cnt - 1) * trailer->_objectRefSize, trailer);
- if (datalen <= off) return false;
- if (voffset) *voffset = off;
- return true;
- } else {
-//#warning the other primitive types should be allowed as keys in a binary plist dictionary, I think
- return false;
- }
- miss: ;
- }
- return false;
-}
-
-extern CFArrayRef _CFArrayCreate_ex(CFAllocatorRef allocator, bool mutable, const void **values, CFIndex numValues);
-
-extern CFDictionaryRef _CFDictionaryCreate_ex(CFAllocatorRef allocator, bool mutable, const void **keys, const void **values, CFIndex numValues);
-
-#if 0
-static bool _getUIDFromData(const uint8_t *datap, uint64_t *vp) {
- int32_t idx, cnt;
- uint8_t marker = *datap;
- uint64_t bigint;
- if ((marker & 0xf0) != kCFBinaryPlistMarkerUID) return false;
- cnt = (marker & 0x0f) + 1;
- datap++;
- bigint = 0;
- for (idx = 0; idx < cnt; idx++) {
- bigint = (bigint << 8) + *datap++;
- }
- *vp = bigint;
- return true;
-}
-#endif
-
-static bool _getFloatFromData(const uint8_t *datap, float *vp) {
- CFSwappedFloat32 swapped32;
- if (*datap != (kCFBinaryPlistMarkerReal | 2)) return false;
- datap++;
- memmove(&swapped32, datap, sizeof(swapped32));
- *vp = CFConvertFloat32SwappedToHost(swapped32);
- return true;
-}
-
-static bool _getDoubleFromData(const uint8_t *datap, double *vp) {
- CFSwappedFloat64 swapped64;
- if (*datap != (kCFBinaryPlistMarkerReal | 3)) return false;
- datap++;
- memmove(&swapped64, datap, sizeof(swapped64));
- *vp = CFConvertFloat64SwappedToHost(swapped64);
- return true;
-}
-
-bool __CFBinaryPlistCreateObject(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFAllocatorRef allocator, CFOptionFlags mutabilityOption, CFMutableDictionaryRef objects, CFPropertyListRef *plist) {
- const uint8_t *bytesptr;
- uint64_t off;
- uint8_t marker;
- CFIndex idx, cnt;
- uint64_t bigint;
- UniChar *chars;
- CFPropertyListRef *list, buffer[256];
- CFAllocatorRef listAllocator;
-
- if (objects) {
- *plist = CFDictionaryGetValue(objects, (const void *)(intptr_t)startOffset);
- if (*plist) {
- CFRetain(*plist);
- return true;
- }
- }
-
- marker = *(databytes + startOffset);
- switch (marker & 0xf0) {
- case kCFBinaryPlistMarkerNull:
- switch (marker) {
- case kCFBinaryPlistMarkerNull:
- *plist = NULL;
- return true;
- case kCFBinaryPlistMarkerFalse:
- *plist = CFRetain(kCFBooleanFalse);
- return true;
- case kCFBinaryPlistMarkerTrue:
- *plist = CFRetain(kCFBooleanTrue);
- return true;
- }
- return false;
- case kCFBinaryPlistMarkerInt:
- if (!_readInt(databytes + startOffset, &bigint, NULL)) return false;
- *plist = CFNumberCreate(allocator, kCFNumberSInt64Type, &bigint);
- if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist);
- return (*plist) ? true : false;
- case kCFBinaryPlistMarkerReal:
- cnt = marker & 0x0f;
- if (2 == cnt) {
- float f;
- _getFloatFromData(databytes + startOffset, &f);
- *plist = CFNumberCreate(allocator, kCFNumberFloat32Type, &f);
- if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist);
- return (*plist) ? true : false;
- } else if (3 == cnt) {
- double d;
- _getDoubleFromData(databytes + startOffset, &d);
- *plist = CFNumberCreate(allocator, kCFNumberFloat64Type, &d);
- if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist);
- return (*plist) ? true : false;
- }
- return false;
- case kCFBinaryPlistMarkerDate & 0xf0: {
- CFSwappedFloat64 swapped64;
- double d;
- cnt = marker & 0x0f;
- if (3 != cnt) return false;
- memmove(&swapped64, databytes + startOffset + 1, sizeof(swapped64));
- d = CFConvertFloat64SwappedToHost(swapped64);
- *plist = CFDateCreate(allocator, d);
- if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist);
- return (*plist) ? true : false;
- }
- case kCFBinaryPlistMarkerData:
- cnt = marker & 0x0f;
- bytesptr = databytes + startOffset + 1;
- if (0xf == cnt) {
- if (!_readInt(bytesptr, &bigint, &bytesptr)) return false;
- if (INT_MAX < bigint) return false;
- cnt = (CFIndex)bigint;
- }
- if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) {
- *plist = CFDataCreateMutable(allocator, 0);
- CFDataAppendBytes((CFMutableDataRef)*plist, bytesptr, cnt);
- } else {
- *plist = CFDataCreate(allocator, bytesptr, cnt);
- }
- if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist);
- return (*plist) ? true : false;
- case kCFBinaryPlistMarkerASCIIString:
- cnt = marker & 0x0f;
- bytesptr = databytes + startOffset + 1;
- if (0xf == cnt) {
- if (!_readInt(bytesptr, &bigint, &bytesptr)) return false;
- if (INT_MAX < bigint) return false;
- cnt = (CFIndex)bigint;
- }
- if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) {
- CFStringRef str = CFStringCreateWithBytes(allocator, bytesptr, cnt, kCFStringEncodingASCII, false);
- *plist = CFStringCreateMutableCopy(allocator, 0, str);
- CFRelease(str);
- } else {
- *plist = CFStringCreateWithBytes(allocator, bytesptr, cnt, kCFStringEncodingASCII, false);
- }
- if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist);
- return (*plist) ? true : false;
- case kCFBinaryPlistMarkerUnicode16String:
- cnt = marker & 0x0f;
- bytesptr = databytes + startOffset + 1;
- if (0xf == cnt) {
- if (!_readInt(bytesptr, &bigint, &bytesptr)) return false;
- if (INT_MAX < bigint) return false;
- cnt = (CFIndex)bigint;
- }
- chars = CFAllocatorAllocate(allocator, cnt * sizeof(UniChar), 0);
- memmove(chars, bytesptr, cnt * sizeof(UniChar));
- for (idx = 0; idx < cnt; idx++) {
- chars[idx] = CFSwapInt16BigToHost(chars[idx]);
- }
- if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) {
- CFStringRef str = CFStringCreateWithCharactersNoCopy(allocator, chars, cnt, allocator);
- *plist = CFStringCreateMutableCopy(allocator, 0, str);
- CFRelease(str);
- } else {
- *plist = CFStringCreateWithCharactersNoCopy(allocator, chars, cnt, allocator);
- }
- if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist);
- return (*plist) ? true : false;
- case kCFBinaryPlistMarkerUID:
- cnt = (marker & 0x0f) + 1;
- bytesptr = databytes + startOffset + 1;
- bigint = 0;
- for (idx = 0; idx < cnt; idx++) {
- bigint = (bigint << 8) + *bytesptr++;
- }
- if (UINT_MAX < bigint) return false;
- *plist = _CFKeyedArchiverUIDCreate(allocator, (uint32_t)bigint);
- if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist);
- return (*plist) ? true : false;
- case kCFBinaryPlistMarkerArray:
- cnt = marker & 0x0f;
- bytesptr = databytes + startOffset + 1;
- if (0xf == cnt) {
- if (!_readInt(bytesptr, &bigint, &bytesptr)) return false;
- if (INT_MAX < bigint) return false;
- cnt = (CFIndex)bigint;
- }
- list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(CFPropertyListRef) * cnt, 0);
- listAllocator = (list == buffer ? kCFAllocatorNull : kCFAllocatorSystemDefault);
- for (idx = 0; idx < cnt; idx++) {
- CFPropertyListRef pl;
- off = _getOffsetOfRefAt(databytes, bytesptr, trailer);
- if (datalen <= off) return false;
- if (!__CFBinaryPlistCreateObject(databytes, datalen, off, trailer, allocator, mutabilityOption, objects, &pl)) {
- if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
- while (idx--) {
- CFRelease(list[idx]);
- }
- }
- if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
- return false;
- }
- if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
- CF_WRITE_BARRIER_BASE_ASSIGN(listAllocator, list, list[idx], CFMakeCollectable(pl));
- } else {
- list[idx] = pl;
- }
- bytesptr += trailer->_objectRefSize;
- }
- *plist = _CFArrayCreate_ex(allocator, (mutabilityOption != kCFPropertyListImmutable), list, cnt);
- if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist);
- if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
- return (*plist) ? true : false;
- case kCFBinaryPlistMarkerDict:
- cnt = marker & 0x0f;
- bytesptr = databytes + startOffset + 1;
- if (0xf == cnt) {
- if (!_readInt(bytesptr, &bigint, &bytesptr)) return false;
- if (INT_MAX < bigint) return false;
- cnt = (CFIndex)bigint;
- }
- cnt *= 2;
- list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(CFPropertyListRef) * cnt, 0);
- listAllocator = (list == buffer ? kCFAllocatorNull : kCFAllocatorSystemDefault);
- for (idx = 0; idx < cnt; idx++) {
- CFPropertyListRef pl;
- off = _getOffsetOfRefAt(databytes, bytesptr, trailer);
- if (datalen <= off) return false;
- if (!__CFBinaryPlistCreateObject(databytes, datalen, off, trailer, allocator, mutabilityOption, objects, &pl)) {
- if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
- while (idx--) {
- CFRelease(list[idx]);
- }
- }
- if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
- return false;
- }
- if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) {
- CF_WRITE_BARRIER_BASE_ASSIGN(listAllocator, list, list[idx], CFMakeCollectable(pl));
- } else {
- list[idx] = pl;
- }
- bytesptr += trailer->_objectRefSize;
- }
- *plist = _CFDictionaryCreate_ex(allocator, (mutabilityOption != kCFPropertyListImmutable), list, list + cnt / 2, cnt / 2);
- if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist);
- if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
- return (*plist) ? true : false;
- }
- return false;
-}
-
-__private_extern__ bool __CFTryParseBinaryPlist(CFAllocatorRef allocator, CFDataRef data, CFOptionFlags option, CFPropertyListRef *plist, CFStringRef *errorString) {
- uint8_t marker;
- CFBinaryPlistTrailer trailer;
- uint64_t offset;
- CFPropertyListRef pl;
- const uint8_t *databytes = CFDataGetBytePtr(data);
- uint64_t datalen = CFDataGetLength(data);
-
- if (8 <= datalen && __CFBinaryPlistGetTopLevelInfo(databytes, datalen, &marker, &offset, &trailer)) {
- if (__CFBinaryPlistCreateObject(databytes, datalen, offset, &trailer, allocator, option, NULL, &pl)) {
- if (plist) *plist = pl;
- } else {
- if (plist) *plist = NULL;
- if (errorString) *errorString = CFRetain(CFSTR("binary data is corrupt"));
- }
- return true;
- }
- return false;
-}
-