in CoreFoundation/Parsing.subproj/CFBinaryPList.c [1167:1769]
CF_PRIVATE bool __CFBinaryPlistCreateObjectFiltered(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFAllocatorRef allocator, CFOptionFlags mutabilityOption, CFMutableDictionaryRef objects, CFMutableSetRef set, CFIndex curDepth, CFSetRef keyPaths, CFPropertyListRef *outPlist, CFTypeID *outPlistTypeID) {
// NOTE: Bailing out here will cause us to attempt to parse
// as XML (which will fail) then as a OpenSTEP plist
// the final error string is less than helpful:
// "Unexpected character b at line 1".
// It would be nice to actually be more descriptive but that
// would require a more scaffolding.
if (curDepth > _CFPropertyListMaxRecursionDepth()) {
// Bail before we get so far into the stack that we run out of space.
// Emit an `os_log_fault` to relay the issue to the debugger and to track how common this case may be.
os_log_fault(_CFOSLog(), "Too many nested arrays or dictionaries");
FAIL_FALSE;
}
if (objects && outPlist) {
*outPlist = CFDictionaryGetValue(objects, (const void *)(uintptr_t)startOffset);
if (*outPlist) {
// have to assume that '*plist' was previously created with same allocator that is now being passed in
CFRetain(*outPlist);
if (outPlistTypeID) *outPlistTypeID = CFGetTypeID(*outPlist);
return true;
}
}
// at any one invocation of this function, set should contain the offsets in the "path" down to this object
if (set && CFSetContainsValue(set, (const void *)(uintptr_t)startOffset)) FAIL_FALSE;
// databytes is trusted to be at least datalen bytes long
// *trailer contents are trusted, even for overflows -- was checked when the trailer was parsed
uint64_t objectsRangeStart = 8;
const uint64_t objectsRangeEnd = _CFBinaryPlistTrailer_objectsRangeEnd(trailer);
if (startOffset < objectsRangeStart || objectsRangeEnd < startOffset) FAIL_FALSE;
uint64_t off;
CFPropertyListRef *list = NULL;
uint8_t marker = *(databytes + startOffset);
switch (marker & 0xf0) {
case kCFBinaryPlistMarkerNull:
switch (marker) {
case kCFBinaryPlistMarkerNull:
if (outPlist) *outPlist = kCFNull;
if (outPlistTypeID) *outPlistTypeID = _kCFRuntimeIDCFNull;
return true;
case kCFBinaryPlistMarkerFalse:
if (outPlist) *outPlist = kCFBooleanFalse;
if (outPlistTypeID) *outPlistTypeID = _kCFRuntimeIDCFBoolean;
return true;
case kCFBinaryPlistMarkerTrue:
if (outPlist) *outPlist = kCFBooleanTrue;
if (outPlistTypeID) *outPlistTypeID = _kCFRuntimeIDCFBoolean;
return true;
}
FAIL_FALSE;
case kCFBinaryPlistMarkerInt:
{
const uint8_t *ptr = (databytes + startOffset);
int32_t err = CF_NO_ERROR;
ptr = check_ptr_add(ptr, 1, &err);
if (CF_NO_ERROR != err) FAIL_FALSE;
uint64_t cnt = 1 << (marker & 0x0f);
const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1;
if (CF_NO_ERROR != err) FAIL_FALSE;
if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
if (16 < cnt) FAIL_FALSE;
// in format version '00', 1, 2, and 4-byte integers have to be interpreted as unsigned,
// whereas 8-byte integers are signed (and 16-byte when available)
// negative 1, 2, 4-byte integers are always emitted as 8 bytes in format '00'
// integers are not required to be in the most compact possible representation, but only the last 64 bits are significant currently
uint64_t bigint = _getSizedInt(ptr, cnt);
if (outPlistTypeID) *outPlistTypeID = _kCFRuntimeIDCFNumber;
if (outPlist) {
CFNumberRef number = NULL;
if (8 < cnt) {
CFSInt128Struct val;
val.high = 0;
val.low = bigint;
number = CFNumberCreate(allocator, kCFNumberSInt128Type, &val);
} else {
number = CFNumberCreate(allocator, kCFNumberSInt64Type, &bigint);
}
// these are always immutable
if (objects && number) {
CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, number);
}
*outPlist = number;
return number ? true : false;
} else {
// Assume CFNumber creation would always succeed.
return true;
}
}
case kCFBinaryPlistMarkerReal:
switch (marker & 0x0f) {
case 2: {
const uint8_t *ptr = (databytes + startOffset);
int32_t err = CF_NO_ERROR;
ptr = check_ptr_add(ptr, 1, &err);
if (CF_NO_ERROR != err) FAIL_FALSE;
const uint8_t *extent = check_ptr_add(ptr, 4, &err) - 1;
if (CF_NO_ERROR != err) FAIL_FALSE;
if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
CFSwappedFloat32 swapped32;
memmove(&swapped32, ptr, 4);
float f = CFConvertFloat32SwappedToHost(swapped32);
if (outPlistTypeID) *outPlistTypeID = _kCFRuntimeIDCFNumber;
if (outPlist) {
CFNumberRef number = CFNumberCreate(allocator, kCFNumberFloat32Type, &f);
// these are always immutable
if (objects && number) {
CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, number);
}
*outPlist = number;
return number ? true : false;
} else {
// Assume CFNumber creation would always succeed.
return true;
}
}
case 3: {
const uint8_t *ptr = (databytes + startOffset);
int32_t err = CF_NO_ERROR;
ptr = check_ptr_add(ptr, 1, &err);
if (CF_NO_ERROR != err) FAIL_FALSE;
const uint8_t *extent = check_ptr_add(ptr, 8, &err) - 1;
if (CF_NO_ERROR != err) FAIL_FALSE;
if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
CFSwappedFloat64 swapped64;
memmove(&swapped64, ptr, 8);
double d = CFConvertFloat64SwappedToHost(swapped64);
if (outPlistTypeID) *outPlistTypeID = _kCFRuntimeIDCFNumber;
if (outPlist) {
CFNumberRef number = CFNumberCreate(allocator, kCFNumberFloat64Type, &d);
// these are always immutable
if (objects && number) {
CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, number);
}
*outPlist = number;
return number ? true : false;
} else {
// Assume CFNumber creation would always succeed.
return true;
}
}
}
FAIL_FALSE;
case kCFBinaryPlistMarkerDate & 0xf0:
switch (marker) {
case kCFBinaryPlistMarkerDate: {
const uint8_t *ptr = (databytes + startOffset);
int32_t err = CF_NO_ERROR;
ptr = check_ptr_add(ptr, 1, &err);
if (CF_NO_ERROR != err) FAIL_FALSE;
const uint8_t *extent = check_ptr_add(ptr, 8, &err) - 1;
if (CF_NO_ERROR != err) FAIL_FALSE;
if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
CFSwappedFloat64 swapped64;
memmove(&swapped64, ptr, 8);
double d = CFConvertFloat64SwappedToHost(swapped64);
if (outPlistTypeID) *outPlistTypeID = _kCFRuntimeIDCFDate;
if (outPlist) {
CFDateRef date = CFDateCreate(allocator, d);
// these are always immutable
if (objects && date) {
CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, date);
}
*outPlist = date;
return date ? true : false;
} else {
// Assume CFDate creation would always succeed.
return true;
}
}
}
FAIL_FALSE;
case kCFBinaryPlistMarkerData: {
const uint8_t *ptr = databytes + startOffset;
int32_t err = CF_NO_ERROR;
ptr = check_ptr_add(ptr, 1, &err);
if (CF_NO_ERROR != err) FAIL_FALSE;
CFIndex cnt = marker & 0x0f;
if (0xf == cnt) {
uint64_t bigint = 0;
if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE;
if (LONG_MAX < bigint) FAIL_FALSE;
cnt = (CFIndex)bigint;
}
const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1;
if (CF_NO_ERROR != err) FAIL_FALSE;
if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
if (outPlistTypeID) *outPlistTypeID = _kCFRuntimeIDCFData;
if (outPlist) {
CFDataRef data = NULL;
if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) {
data = CFDataCreateMutable(allocator, 0);
if (data) CFDataAppendBytes((CFMutableDataRef)data, ptr, cnt);
} else {
data = CFDataCreate(allocator, ptr, cnt);
}
if (objects && data && (mutabilityOption != kCFPropertyListMutableContainersAndLeaves)) {
CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, data);
}
*outPlist = data;
return data ? true : false;
} else {
// Assume CFData creation would always succeed
return true;
}
}
case kCFBinaryPlistMarkerASCIIString: {
const uint8_t *ptr = databytes + startOffset;
int32_t err = CF_NO_ERROR;
ptr = check_ptr_add(ptr, 1, &err);
if (CF_NO_ERROR != err) FAIL_FALSE;
CFIndex cnt = marker & 0x0f;
if (0xf == cnt) {
uint64_t bigint = 0;
if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE;
if (LONG_MAX < bigint) FAIL_FALSE;
cnt = (CFIndex)bigint;
}
const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1;
if (CF_NO_ERROR != err) FAIL_FALSE;
if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
if (outPlistTypeID) *outPlistTypeID = _kCFRuntimeIDCFString;
if (outPlist) {
CFStringRef string = CFStringCreateWithBytes(allocator, ptr, cnt, kCFStringEncodingASCII, false);
if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) {
if (string) {
CFStringRef tmp = string;
string = CFStringCreateMutableCopy(allocator, 0, string);
CFRelease(tmp);
}
}
if (objects && string && (mutabilityOption != kCFPropertyListMutableContainersAndLeaves)) {
CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, string);
}
*outPlist = string;
return string ? true : false;
} else {
// Assume CFString creation with kCFStringEncodingASCII would always succeed.
return true;
}
}
case kCFBinaryPlistMarkerUnicode16String: {
const uint8_t *ptr = databytes + startOffset;
int32_t err = CF_NO_ERROR;
ptr = check_ptr_add(ptr, 1, &err);
if (CF_NO_ERROR != err) FAIL_FALSE;
CFIndex cnt = marker & 0x0f;
if (0xf == cnt) {
uint64_t bigint = 0;
if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE;
if (LONG_MAX < bigint) FAIL_FALSE;
cnt = (CFIndex)bigint;
}
const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1;
extent = check_ptr_add(extent, cnt, &err); // 2 bytes per character
if (CF_NO_ERROR != err) FAIL_FALSE;
if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
size_t byte_cnt = check_size_t_mul(cnt, sizeof(UniChar), &err);
if (CF_NO_ERROR != err) FAIL_FALSE;
if (outPlistTypeID) *outPlistTypeID = _kCFRuntimeIDCFString;
if (outPlist) {
UniChar *chars = (UniChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, byte_cnt, 0);
if (!chars) FAIL_FALSE;
memmove(chars, ptr, byte_cnt);
for (CFIndex idx = 0; idx < cnt; idx++) {
chars[idx] = CFSwapInt16BigToHost(chars[idx]);
}
CFStringRef string = CFStringCreateWithCharacters(allocator, chars, cnt);
if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) {
if (string) {
CFStringRef tmp = string;
string = CFStringCreateMutableCopy(allocator, 0, string);
CFRelease(tmp);
}
}
CFAllocatorDeallocate(kCFAllocatorSystemDefault, chars);
if (objects && string && (mutabilityOption != kCFPropertyListMutableContainersAndLeaves)) {
CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, string);
}
*outPlist = string;
return string ? true : false;
} else {
// Assume CFStringCreateWithCharacters would always succeed.
return true;
}
}
case kCFBinaryPlistMarkerUID: {
const uint8_t *ptr = databytes + startOffset;
int32_t err = CF_NO_ERROR;
ptr = check_ptr_add(ptr, 1, &err);
if (CF_NO_ERROR != err) FAIL_FALSE;
CFIndex cnt = (marker & 0x0f) + 1;
const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1;
if (CF_NO_ERROR != err) FAIL_FALSE;
if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
// uids are not required to be in the most compact possible representation, but only the last 64 bits are significant currently
uint64_t bigint = _getSizedInt(ptr, cnt);
if (UINT32_MAX < bigint) FAIL_FALSE;
if (outPlistTypeID) *outPlistTypeID = _kCFRuntimeIDCFKeyedArchiverUID;
if (outPlist) {
CFKeyedArchiverUIDRef uid = _CFKeyedArchiverUIDCreate(allocator, (uint32_t)bigint);
// these are always immutable
if (objects && uid) {
CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, uid);
}
*outPlist = uid;
return (uid) ? true : false;
} else {
// Assume CFKeyedArchiverUID creation would always succeed.
return true;
}
}
case kCFBinaryPlistMarkerArray:
case kCFBinaryPlistMarkerSet: {
const uint8_t *ptr = databytes + startOffset;
int32_t err = CF_NO_ERROR;
ptr = check_ptr_add(ptr, 1, &err);
if (CF_NO_ERROR != err) FAIL_FALSE;
CFIndex arrayCount = marker & 0x0f;
if (0xf == arrayCount) {
uint64_t bigint = 0;
if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE;
if (LONG_MAX < bigint) FAIL_FALSE;
arrayCount = (CFIndex)bigint;
}
size_t byte_cnt = check_size_t_mul(arrayCount, trailer->_objectRefSize, &err);
if (CF_NO_ERROR != err) FAIL_FALSE;
const uint8_t *extent = check_ptr_add(ptr, byte_cnt, &err) - 1;
if (CF_NO_ERROR != err) FAIL_FALSE;
if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
byte_cnt = check_size_t_mul(arrayCount, sizeof(CFPropertyListRef), &err);
if (CF_NO_ERROR != err) FAIL_FALSE;
STACK_BUFFER_DECL(CFPropertyListRef, buffer, (arrayCount > 0 && arrayCount <= 256) ? arrayCount : 1);
if (outPlist) {
list = (arrayCount <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, byte_cnt, 0);
if (!list) FAIL_FALSE;
}
_CFReleaseDeferred CFMutableSetRef madeSet = NULL;
if (!set && 15 < curDepth) {
madeSet = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
set = madeSet;
}
Boolean success = true;
CFTypeID typeID = _kCFRuntimeNotATypeID;
if (set) CFSetAddValue(set, (const void *)(uintptr_t)startOffset);
if ((marker & 0xf0) == kCFBinaryPlistMarkerArray && keyPaths) {
// Only get a subset of this array
CFSetRef theseKeys, nextKeys;
__CFPropertyListCreateSplitKeypaths(kCFAllocatorSystemDefault, keyPaths, &theseKeys, &nextKeys);
CFMutableArrayRef array = CFArrayCreateMutable(allocator, CFSetGetCount(theseKeys), &kCFTypeArrayCallBacks);
if (theseKeys) {
CFTypeRef *keys = (CFTypeRef *)malloc(CFSetGetCount(theseKeys) * sizeof(CFTypeRef));
CFSetGetValues(theseKeys, keys);
CFIndex theseKeysCount = CFSetGetCount(theseKeys);
for (CFIndex i = 0; i < theseKeysCount; i++) {
CFStringRef key = (CFStringRef)keys[i];
SInt32 intValue = CFStringGetIntValue(key);
if ((intValue == 0 && CFStringCompare(CFSTR("0"), key, 0) != kCFCompareEqualTo) || intValue == INT_MAX || intValue == INT_MIN || intValue < 0) {
// skip, doesn't appear to be a proper integer
} else {
uint64_t valueOffset;
Boolean found = __CFBinaryPlistGetOffsetForValueFromArray2(databytes, datalen, startOffset, trailer, (CFIndex)intValue, &valueOffset, objects);
if (found) {
CFPropertyListRef result = NULL;
success = __CFBinaryPlistCreateObjectFiltered(databytes, datalen, valueOffset, trailer, allocator, mutabilityOption, objects, set, curDepth + 1, nextKeys, outPlist ? &result : NULL, NULL);
if (success) {
if (result) {
CFArrayAppendValue(array, result);
CFRelease(result);
}
} else {
break;
}
}
}
}
free(keys);
CFRelease(theseKeys);
}
if (nextKeys) CFRelease(nextKeys);
if (success && outPlist) {
if (!(mutabilityOption == kCFPropertyListMutableContainers || mutabilityOption == kCFPropertyListMutableContainersAndLeaves)) {
// make immutable
*outPlist = CFArrayCreateCopy(allocator, array);
CFRelease(array);
} else {
*outPlist = array;
}
} else if (array) {
CFRelease(array);
}
typeID = _kCFRuntimeIDCFArray;
} else {
for (CFIndex idx = 0; idx < arrayCount; idx++) {
if (!_getOffsetOfRefAt(databytes, ptr, trailer, &off)) {
if (list) {
while (idx--) {
CFRelease(list[idx]);
}
if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
}
FAIL_FALSE;
}
CFPropertyListRef pl = NULL;
if (!__CFBinaryPlistCreateObjectFiltered(databytes, datalen, off, trailer, allocator, mutabilityOption, objects, set, curDepth + 1, NULL, outPlist ? &pl : NULL, NULL)) {
if (list) {
while (idx--) {
CFRelease(list[idx]);
}
if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
}
FAIL_FALSE;
}
if (list) {
*((void **)list + idx) = (void *)pl;
}
ptr += trailer->_objectRefSize;
}
success = true;
if ((marker & 0xf0) == kCFBinaryPlistMarkerArray) {
if (outPlist) {
if (mutabilityOption != kCFPropertyListImmutable) {
*outPlist = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks);
CFArrayReplaceValues((CFMutableArrayRef)*outPlist, CFRangeMake(0, 0), list, arrayCount);
for (CFIndex idx = 0; idx < arrayCount; idx++) {
CFRelease(list[idx]);
}
} else {
*outPlist = __CFArrayCreateTransfer(allocator, list, arrayCount);
}
}
typeID = _kCFRuntimeIDCFArray;
} else {
if (outPlist) {
if (mutabilityOption != kCFPropertyListImmutable) {
*outPlist = CFSetCreateMutable(allocator, 0, &kCFTypeSetCallBacks);
for (CFIndex idx = 0; idx < arrayCount; idx++) {
CFSetAddValue((CFMutableSetRef)*outPlist, list[idx]);
}
for (CFIndex idx = 0; idx < arrayCount; idx++) {
CFRelease(list[idx]);
}
} else {
*outPlist = __CFSetCreateTransfer(allocator, list, arrayCount);
}
}
typeID = _kCFRuntimeIDCFSet;
}
}
if (outPlistTypeID) *outPlistTypeID = typeID;
if (set) CFSetRemoveValue(set, (const void *)(uintptr_t)startOffset);
if (objects && success && outPlist && (mutabilityOption == kCFPropertyListImmutable)) {
CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *outPlist);
}
if (list && list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
return success;
}
case kCFBinaryPlistMarkerDict: {
const uint8_t *ptr = databytes + startOffset;
int32_t err = CF_NO_ERROR;
ptr = check_ptr_add(ptr, 1, &err);
if (CF_NO_ERROR != err) FAIL_FALSE;
CFIndex dictionaryCount = marker & 0x0f;
if (0xf == dictionaryCount) {
uint64_t bigint = 0;
if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE;
if (LONG_MAX < bigint) FAIL_FALSE;
dictionaryCount = (CFIndex)bigint;
}
dictionaryCount = check_size_t_mul(dictionaryCount, 2, &err);
if (CF_NO_ERROR != err) FAIL_FALSE;
size_t byte_cnt = check_size_t_mul(dictionaryCount, trailer->_objectRefSize, &err);
if (CF_NO_ERROR != err) FAIL_FALSE;
const uint8_t *extent = check_ptr_add(ptr, byte_cnt, &err) - 1;
if (CF_NO_ERROR != err) FAIL_FALSE;
if (databytes + objectsRangeEnd < extent) FAIL_FALSE;
byte_cnt = check_size_t_mul(dictionaryCount, sizeof(CFPropertyListRef), &err);
if (CF_NO_ERROR != err) FAIL_FALSE;
STACK_BUFFER_DECL(CFPropertyListRef, buffer, 0 < dictionaryCount && dictionaryCount <= 256 ? dictionaryCount : 1);
if (outPlist) {
list = (dictionaryCount <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, byte_cnt, 0);
if (!list) FAIL_FALSE;
}
_CFReleaseDeferred CFMutableSetRef madeSet = NULL;
if (!set && 15 < curDepth) {
madeSet = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, NULL);
set = madeSet;
}
Boolean success = true;
if (set) CFSetAddValue(set, (const void *)(uintptr_t)startOffset);
if (keyPaths) {
// Only get a subset of this dictionary
CFSetRef theseKeys, nextKeys;
__CFPropertyListCreateSplitKeypaths(kCFAllocatorSystemDefault, keyPaths, &theseKeys, &nextKeys);
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(allocator, CFSetGetCount(theseKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (theseKeys) {
CFTypeRef *keys = (CFTypeRef *)malloc(CFSetGetCount(theseKeys) * sizeof(CFTypeRef));
CFSetGetValues(theseKeys, keys);
for (CFIndex i = 0; i < CFSetGetCount(theseKeys); i++) {
CFStringRef key = (CFStringRef)keys[i];
uint64_t keyOffset, valueOffset;
Boolean found = __CFBinaryPlistGetOffsetForValueFromDictionary3(databytes, datalen, startOffset, trailer, key, &keyOffset, &valueOffset, false, objects);
if (found) {
CFPropertyListRef result = NULL;
success = __CFBinaryPlistCreateObjectFiltered(databytes, datalen, valueOffset, trailer, allocator, mutabilityOption, objects, set, curDepth + 1, nextKeys, outPlist ? &result : NULL, NULL);
if (success) {
if (result) {
CFDictionarySetValue(dict, key, result);
CFRelease(result);
}
} else {
break;
}
}
}
free(keys);
CFRelease(theseKeys);
}
if (nextKeys) CFRelease(nextKeys);
if (success && outPlist) {
if (!(mutabilityOption == kCFPropertyListMutableContainers || mutabilityOption == kCFPropertyListMutableContainersAndLeaves)) {
// make immutable
*outPlist = CFDictionaryCreateCopy(allocator, dict);
CFRelease(dict);
} else {
*outPlist = dict;
}
} else if (dict) {
CFRelease(dict);
}
} else {
CFIndex const halfDictionaryCount = dictionaryCount / 2;
for (CFIndex idx = 0; idx < dictionaryCount; idx++) {
if (!_getOffsetOfRefAt(databytes, ptr, trailer, &off)) {
if (list) {
while (idx--) {
CFRelease(list[idx]);
}
if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
}
FAIL_FALSE;
}
CFPropertyListRef pl = NULL;
CFTypeID typeID = _kCFRuntimeNotATypeID;
if (!__CFBinaryPlistCreateObjectFiltered(databytes, datalen, off, trailer, allocator, mutabilityOption, objects, set, curDepth + 1, NULL, (outPlist ? &pl : NULL), &typeID) || (idx < halfDictionaryCount && !_typeIsPlistPrimitive(typeID))) {
if (pl) CFRelease(pl);
if (list) {
while (idx--) {
CFRelease(list[idx]);
}
if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
}
FAIL_FALSE;
}
if (list) {
*((void **)list + idx) = (void *)pl;
#if __clang_analyzer__
// The static analyzer can't reason that we're always looping through this an even number of times. It thinks list[idx + halfDictionaryCount] below will be uninitialized.
if (idx % 2 == 0) {
*((void **)list + halfDictionaryCount) = NULL;
}
#endif
}
ptr += trailer->_objectRefSize;
}
if (outPlist) {
if (mutabilityOption != kCFPropertyListImmutable) {
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
for (CFIndex idx = 0; idx < halfDictionaryCount; idx++) {
CFDictionaryAddValue((CFMutableDictionaryRef)dict, list[idx], list[idx + halfDictionaryCount]);
}
for (CFIndex idx = 0; idx < dictionaryCount; idx++) {
CFRelease(list[idx]);
}
*outPlist = dict;
} else {
*outPlist = __CFDictionaryCreateTransfer(allocator, list, list + halfDictionaryCount, halfDictionaryCount);
}
}
if (outPlistTypeID) *outPlistTypeID = _kCFRuntimeIDCFDictionary;
}
if (set) CFSetRemoveValue(set, (const void *)(uintptr_t)startOffset);
if (objects && success && outPlist && (mutabilityOption == kCFPropertyListImmutable)) {
CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *outPlist);
}
if (list && list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list);
return success;
}
}
FAIL_FALSE;
}