CF_PRIVATE bool __CFBinaryPlistCreateObjectFiltered()

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;
}