From 856091c50ad30d2846d4b6c52eaa7aad8e95bd67 Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 23 Aug 2012 20:45:35 +0000 Subject: [PATCH] CF-744.tar.gz --- CFApplicationPreferences.c | 2 +- CFArray.c | 28 +- CFArray.h | 4 +- CFBag.c | 75 +- CFBag.h | 4 +- CFBase.c | 145 +- CFBase.h | 139 +- CFBasicHash.m => CFBasicHash.c | 132 +- CFBasicHash.h | 2 +- CFBasicHashFindBucket.m | 2 +- CFBigNumber.c | 564 +++++++ CFBigNumber.h | 93 ++ CFBinaryHeap.c | 2 +- CFBinaryHeap.h | 4 +- CFBinaryPList.c | 1050 +++++++++--- CFBitVector.c | 10 +- CFBitVector.h | 4 +- CFBuiltinConverters.c | 4 +- CFBundle.c | 513 ++++-- CFBundle.h | 6 +- CFBundlePriv.h | 2 +- CFBundle_BinaryTypes.h | 6 +- CFBundle_Internal.h | 36 +- CFBundle_Resources.c | 1579 ++++++++++++++---- CFBurstTrie.c | 2095 ++++++++++++++++++++++++ CFBurstTrie.h | 201 +++ CFByteOrder.h | 2 +- CFCalendar.c | 48 +- CFCalendar.h | 19 +- CFCharacterSet.c | 32 +- CFCharacterSet.h | 11 +- CFCharacterSetBitmaps.bitmap | Bin 434391 -> 434391 bytes CFCharacterSetPriv.h | 7 +- CFConcreteStreams.c | 26 +- CFData.c | 38 +- CFData.h | 11 +- CFDate.c | 58 +- CFDate.h | 8 +- CFDateFormatter.c | 438 ++++- CFDateFormatter.h | 7 +- CFDictionary.c | 75 +- CFDictionary.h | 4 +- CFError.c | 66 +- CFError.h | 4 +- CFError_Private.h | 2 +- CFFileUtilities.c | 114 +- CFICUConverters.c | 4 +- CFICUConverters.h | 2 +- CFInternal.h | 216 +-- CFLocale.c | 205 ++- CFLocale.h | 7 +- CFLocaleIdentifier.c | 36 +- CFLocaleInternal.h | 3 +- CFLocaleKeys.c | 5 +- CFLogUtilities.h | 2 +- CFMachPort.c | 508 +++--- CFMachPort.h | 2 +- CFMessagePort.c | 103 +- CFMessagePort.h | 2 +- CFNumber.c | 42 +- CFNumber.h | 15 +- CFNumberFormatter.c | 183 ++- CFNumberFormatter.h | 16 +- CFOldStylePList.c | 631 +++++++ CFPlatform.c | 346 ++-- CFPlatformConverters.c | 17 +- CFPlugIn.c | 46 +- CFPlugIn.h | 2 +- CFPlugInCOM.h | 2 +- CFPlugIn_Factory.c | 233 ++- CFPlugIn_Factory.h | 47 +- CFPlugIn_Instance.c | 10 +- CFPlugIn_PlugIn.c | 12 +- CFPreferences.c | 2 +- CFPreferences.h | 2 +- CFPriv.h | 55 +- CFPropertyList.c | 2143 ++++++++++++------------ CFPropertyList.h | 23 +- CFRunLoop.c | 484 +++--- CFRunLoop.h | 5 +- CFRuntime.c | 150 +- CFRuntime.h | 2 +- CFSet.c | 75 +- CFSet.h | 4 +- CFSocket.c | 44 +- CFSocket.h | 19 +- CFSocketStream.c | 21 +- CFSortFunctions.c | 5 +- CFStorage.c | 4 +- CFStorage.h | 5 +- CFStream.c | 63 +- CFStream.h | 19 +- CFStreamAbstract.h | 2 +- CFStreamPriv.h | 11 +- CFString.c | 455 ++++-- CFString.h | 24 +- CFStringDefaultEncoding.h | 2 +- CFStringEncodingConverter.c | 25 +- CFStringEncodingConverter.h | 2 +- CFStringEncodingConverterExt.h | 2 +- CFStringEncodingConverterPriv.h | 2 +- CFStringEncodingDatabase.c | 2 +- CFStringEncodingDatabase.h | 2 +- CFStringEncodingExt.h | 15 +- CFStringEncodings.c | 13 +- CFStringScanner.c | 2 +- CFStringUtilities.c | 30 +- CFSystemDirectories.c | 2 +- CFTimeZone.c | 16 +- CFTimeZone.h | 11 +- CFTree.c | 4 +- CFTree.h | 4 +- CFURL.c | 2722 ++++++++++++++++--------------- CFURL.h | 394 +++-- CFURLAccess.c | 21 +- CFURLAccess.h | 23 +- CFURLPriv.h | 37 +- CFUUID.c | 7 +- CFUUID.h | 4 +- CFUniChar.c | 79 +- CFUniChar.h | 5 +- CFUniCharPriv.h | 2 +- CFUniCharPropertyDatabase.data | Bin 30244 -> 31780 bytes CFUnicodeData-B.mapping | Bin 89416 -> 90744 bytes CFUnicodeData-L.mapping | Bin 89416 -> 90744 bytes CFUnicodeDecomposition.c | 2 +- CFUnicodeDecomposition.h | 2 +- CFUnicodePrecomposition.c | 2 +- CFUnicodePrecomposition.h | 2 +- CFUserNotification.c | 14 +- CFUserNotification.h | 2 +- CFUtilities.c | 234 ++- CFVersion.c | 4 +- CFWindowsUtilities.c | 2 +- CFXMLInputStream.c | 2 +- CFXMLInputStream.h | 2 +- CFXMLNode.c | 2 +- CFXMLNode.h | 31 +- CFXMLParser.c | 7 +- CFXMLParser.h | 47 +- CFXMLPreferencesDomain.c | 2 +- CFXMLTree.c | 7 +- CoreFoundation.h | 3 +- CoreFoundation_Prefix.h | 54 +- ForFoundationOnly.h | 13 +- Info.plist | 2 +- Makefile | 8 +- MakefileLinux | 2 +- MakefileVersion | 2 +- TargetConditionals.h | 2 +- 150 files changed, 12317 insertions(+), 5547 deletions(-) rename CFBasicHash.m => CFBasicHash.c (96%) create mode 100644 CFBigNumber.c create mode 100644 CFBigNumber.h create mode 100644 CFBurstTrie.c create mode 100644 CFBurstTrie.h create mode 100644 CFOldStylePList.c diff --git a/CFApplicationPreferences.c b/CFApplicationPreferences.c index a66a8d9..937d7cd 100644 --- a/CFApplicationPreferences.c +++ b/CFApplicationPreferences.c @@ -22,7 +22,7 @@ */ /* CFApplicationPreferences.c - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. Responsibility: David Smith */ diff --git a/CFArray.c b/CFArray.c index 8c38e15..ff1bc59 100644 --- a/CFArray.c +++ b/CFArray.c @@ -22,7 +22,7 @@ */ /* CFArray.c - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ @@ -31,6 +31,7 @@ #include "CFInternal.h" #include + const CFArrayCallBacks kCFTypeArrayCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual}; static const CFArrayCallBacks __kCFNullArrayCallBacks = {0, NULL, NULL, NULL, NULL}; @@ -314,6 +315,7 @@ static CFStringRef __CFArrayCopyDescription(CFTypeRef cf) { static void __CFArrayDeallocate(CFTypeRef cf) { CFArrayRef array = (CFArrayRef)cf; BEGIN_MUTATION(array); +#if DEPLOYMENT_TARGET_MACOSX // Under GC, keep contents alive when we know we can, either standard callbacks or NULL // if (__CFBitfieldGetValue(cf->info, 5, 4)) return; // bits only ever set under GC CFAllocatorRef allocator = __CFGetAllocator(array); @@ -334,6 +336,7 @@ static void __CFArrayDeallocate(CFTypeRef cf) { return; } } +#endif __CFArrayReleaseValues(array, CFRangeMake(0, __CFArrayGetCount(array)), true); END_MUTATION(array); } @@ -544,7 +547,7 @@ CFMutableArrayRef CFArrayCreateMutableCopy(CFAllocatorRef allocator, CFIndex cap #endif CFIndex CFArrayGetCount(CFArrayRef array) { - CF_OBJC_FUNCDISPATCH0(__kCFArrayTypeID, CFIndex, array, "count"); + CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, CFIndex, (NSArray *)array, count); __CFGenericValidateType(array, __kCFArrayTypeID); CHECK_FOR_MUTATION(array); return __CFArrayGetCount(array); @@ -582,7 +585,7 @@ Boolean CFArrayContainsValue(CFArrayRef array, CFRange range, const void *value) } const void *CFArrayGetValueAtIndex(CFArrayRef array, CFIndex idx) { - CF_OBJC_FUNCDISPATCH1(__kCFArrayTypeID, void *, array, "objectAtIndex:", idx); + CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, const void *, (NSArray *)array, objectAtIndex:idx); __CFGenericValidateType(array, __kCFArrayTypeID); CFAssert2(0 <= idx && idx < __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index (%d) out of bounds", __PRETTY_FUNCTION__, idx); CHECK_FOR_MUTATION(array); @@ -598,7 +601,7 @@ const void *_CFArrayCheckAndGetValueAtIndex(CFArrayRef array, CFIndex idx) { void CFArrayGetValues(CFArrayRef array, CFRange range, const void **values) { - CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, void, array, "getObjects:range:", values, range); + CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, void, (NSArray *)array, getObjects:(id *)values range:NSMakeRange(range.location, range.length)); __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); CFAssert1(NULL != values, __kCFLogAssertion, "%s(): pointer to values may not be NULL", __PRETTY_FUNCTION__); @@ -682,7 +685,8 @@ CFIndex CFArrayGetLastIndexOfValue(CFArrayRef array, CFRange range, const void * } void CFArrayAppendValue(CFMutableArrayRef array, const void *value) { - CF_OBJC_FUNCDISPATCH1(__kCFArrayTypeID, void, array, "addObject:", value); + CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, void, (NSMutableArray *)array, addObject:(id)value); + __CFGenericValidateType(array, __kCFArrayTypeID); CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); CHECK_FOR_MUTATION(array); @@ -690,7 +694,7 @@ void CFArrayAppendValue(CFMutableArrayRef array, const void *value) { } void CFArraySetValueAtIndex(CFMutableArrayRef array, CFIndex idx, const void *value) { - CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, void, array, "setObject:atIndex:", value, idx); + CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, void, (NSMutableArray *)array, setObject:(id)value atIndex:(NSUInteger)idx); __CFGenericValidateType(array, __kCFArrayTypeID); CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); CFAssert2(0 <= idx && idx <= __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index (%d) out of bounds", __PRETTY_FUNCTION__, idx); @@ -717,7 +721,7 @@ void CFArraySetValueAtIndex(CFMutableArrayRef array, CFIndex idx, const void *va } void CFArrayInsertValueAtIndex(CFMutableArrayRef array, CFIndex idx, const void *value) { - CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, void, array, "insertObject:atIndex:", value, idx); + CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, void, (NSMutableArray *)array, insertObject:(id)value atIndex:(NSUInteger)idx); __CFGenericValidateType(array, __kCFArrayTypeID); CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); CFAssert2(0 <= idx && idx <= __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index (%d) out of bounds", __PRETTY_FUNCTION__, idx); @@ -730,7 +734,7 @@ void CFArrayInsertValueAtIndex(CFMutableArrayRef array, CFIndex idx, const void void CFArrayExchangeValuesAtIndices(CFMutableArrayRef array, CFIndex idx1, CFIndex idx2) { const void *tmp; struct __CFArrayBucket *bucket1, *bucket2; - CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, void, array, "exchangeObjectAtIndex:withObjectAtIndex:", idx1, idx2); + CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, void, (NSMutableArray *)array, exchangeObjectAtIndex:(NSUInteger)idx1 withObjectAtIndex:(NSUInteger)idx2); __CFGenericValidateType(array, __kCFArrayTypeID); CFAssert2(0 <= idx1 && idx1 < __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index #1 (%d) out of bounds", __PRETTY_FUNCTION__, idx1); CFAssert2(0 <= idx2 && idx2 < __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index #2 (%d) out of bounds", __PRETTY_FUNCTION__, idx2); @@ -748,7 +752,7 @@ void CFArrayExchangeValuesAtIndices(CFMutableArrayRef array, CFIndex idx1, CFInd } void CFArrayRemoveValueAtIndex(CFMutableArrayRef array, CFIndex idx) { - CF_OBJC_FUNCDISPATCH1(__kCFArrayTypeID, void, array, "removeObjectAtIndex:", idx); + CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, void, (NSMutableArray *)array, removeObjectAtIndex:(NSUInteger)idx); __CFGenericValidateType(array, __kCFArrayTypeID); CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); CFAssert2(0 <= idx && idx < __CFArrayGetCount(array), __kCFLogAssertion, "%s(): index (%d) out of bounds", __PRETTY_FUNCTION__, idx); @@ -757,7 +761,7 @@ void CFArrayRemoveValueAtIndex(CFMutableArrayRef array, CFIndex idx) { } void CFArrayRemoveAllValues(CFMutableArrayRef array) { - CF_OBJC_FUNCDISPATCH0(__kCFArrayTypeID, void, array, "removeAllObjects"); + CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, void, (NSMutableArray *)array, removeAllObjects); __CFGenericValidateType(array, __kCFArrayTypeID); CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); CHECK_FOR_MUTATION(array); @@ -905,7 +909,7 @@ void _CFArraySetCapacity(CFMutableArrayRef array, CFIndex cap) { void CFArrayReplaceValues(CFMutableArrayRef array, CFRange range, const void **newValues, CFIndex newCount) { - CF_OBJC_FUNCDISPATCH3(__kCFArrayTypeID, void, array, "replaceObjectsInRange:withObjects:count:", range, (void **)newValues, newCount); + CF_OBJC_FUNCDISPATCHV(__kCFArrayTypeID, void, (NSMutableArray *)array, replaceObjectsInRange:NSMakeRange(range.location, range.length) withObjects:(id *)newValues count:(NSUInteger)newCount); __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); @@ -1037,7 +1041,7 @@ void CFArraySortValues(CFMutableArrayRef array, CFRange range, CFComparatorFunct Boolean immutable = false; if (CF_IS_OBJC(__kCFArrayTypeID, array)) { BOOL result; - CF_OBJC_CALL1(BOOL, result, array, "isKindOfClass:", objc_lookUpClass("NSMutableArray")); + result = CF_OBJC_CALLV((NSMutableArray *)array, isKindOfClass:[NSMutableArray class]); immutable = !result; } else if (__kCFArrayImmutable == __CFArrayGetType(array)) { immutable = true; diff --git a/CFArray.h b/CFArray.h index 069d620..020cece 100644 --- a/CFArray.h +++ b/CFArray.h @@ -22,7 +22,7 @@ */ /* CFArray.h - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. */ /*! @@ -69,6 +69,7 @@ #include +CF_IMPLICIT_BRIDGING_ENABLED CF_EXTERN_C_BEGIN /*! @@ -689,6 +690,7 @@ CF_EXPORT void CFArrayAppendArray(CFMutableArrayRef theArray, CFArrayRef otherArray, CFRange otherRange); CF_EXTERN_C_END +CF_IMPLICIT_BRIDGING_DISABLED #endif /* ! __COREFOUNDATION_CFARRAY__ */ diff --git a/CFBag.c b/CFBag.c index d5eb878..da9e336 100644 --- a/CFBag.c +++ b/CFBag.c @@ -22,7 +22,7 @@ */ /* CFBag.c - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. Responsibility: Christopher Kane Machine generated from Notes/HashingCode.template */ @@ -36,6 +36,7 @@ #include "CFBasicHash.h" #include + #define CFDictionary 0 #define CFSet 0 #define CFBag 0 @@ -217,7 +218,7 @@ static CFBasicHashCallbacks *__CFBagCopyCallbacks(CFConstBasicHashRef ht, CFAllo } else { newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), 0); } - if (!newcb) HALT; + if (!newcb) return NULL; memmove(newcb, (void *)cb, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *)); return newcb; } @@ -386,7 +387,7 @@ static CFBasicHashRef __CFBagCreateGeneric(CFAllocatorRef allocator, const CFHas } else { newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), 0); } - if (!newcb) HALT; + if (!newcb) return NULL; newcb->copyCallbacks = __CFBagCopyCallbacks; newcb->freeCallbacks = __CFBagFreeCallbacks; newcb->retainValue = __CFBagRetainValue; @@ -427,7 +428,8 @@ static CFBasicHashRef __CFBagCreateGeneric(CFAllocatorRef allocator, const CFHas } CFBasicHashRef ht = CFBasicHashCreate(allocator, flags, cb); - CFBasicHashSetSpecialBits(ht, specialBits); + if (ht) CFBasicHashSetSpecialBits(ht, specialBits); + if (!ht && !CF_IS_COLLECTABLE_ALLOCATOR(allocator)) CFAllocatorDeallocate(allocator, cb); return ht; } @@ -468,6 +470,7 @@ CFHashRef CFBagCreate(CFAllocatorRef allocator, const_any_pointer_t *klist, CFIn CFTypeID typeID = CFBagGetTypeID(); CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__, numValues); CFBasicHashRef ht = __CFBagCreateGeneric(allocator, keyCallBacks, valueCallBacks, CFDictionary); + if (!ht) return NULL; if (0 < numValues) CFBasicHashSetCapacity(ht, numValues); for (CFIndex idx = 0; idx < numValues; idx++) { CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]); @@ -489,6 +492,7 @@ CFMutableHashRef CFBagCreateMutable(CFAllocatorRef allocator, CFIndex capacity, CFTypeID typeID = CFBagGetTypeID(); CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%ld) cannot be less than zero", __PRETTY_FUNCTION__, capacity); CFBasicHashRef ht = __CFBagCreateGeneric(allocator, keyCallBacks, valueCallBacks, CFDictionary); + if (!ht) return NULL; *(uintptr_t *)ht = __CFISAForTypeID(typeID); _CFRuntimeSetInstanceTypeID(ht, typeID); if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFBag (mutable)"); @@ -513,8 +517,8 @@ CFHashRef CFBagCreateCopy(CFAllocatorRef allocator, CFHashRef other) { CFDictionaryGetKeysAndValues(other, klist, vlist); #endif ht = __CFBagCreateGeneric(allocator, & kCFTypeBagKeyCallBacks, CFDictionary ? & kCFTypeBagValueCallBacks : NULL, CFDictionary); - if (0 < numValues) CFBasicHashSetCapacity(ht, numValues); - for (CFIndex idx = 0; idx < numValues; idx++) { + if (ht && 0 < numValues) CFBasicHashSetCapacity(ht, numValues); + for (CFIndex idx = 0; ht && idx < numValues; idx++) { CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]); } if (klist != kbuffer && klist != vlist) CFAllocatorDeallocate(kCFAllocatorSystemDefault, klist); @@ -522,6 +526,7 @@ CFHashRef CFBagCreateCopy(CFAllocatorRef allocator, CFHashRef other) { } else { ht = CFBasicHashCreateCopy(allocator, (CFBasicHashRef)other); } + if (!ht) return NULL; CFBasicHashMakeImmutable(ht); *(uintptr_t *)ht = __CFISAForTypeID(typeID); _CFRuntimeSetInstanceTypeID(ht, typeID); @@ -548,8 +553,8 @@ CFMutableHashRef CFBagCreateMutableCopy(CFAllocatorRef allocator, CFIndex capaci CFDictionaryGetKeysAndValues(other, klist, vlist); #endif ht = __CFBagCreateGeneric(allocator, & kCFTypeBagKeyCallBacks, CFDictionary ? & kCFTypeBagValueCallBacks : NULL, CFDictionary); - if (0 < numValues) CFBasicHashSetCapacity(ht, numValues); - for (CFIndex idx = 0; idx < numValues; idx++) { + if (ht && 0 < numValues) CFBasicHashSetCapacity(ht, numValues); + for (CFIndex idx = 0; ht && idx < numValues; idx++) { CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]); } if (klist != kbuffer && klist != vlist) CFAllocatorDeallocate(kCFAllocatorSystemDefault, klist); @@ -557,6 +562,7 @@ CFMutableHashRef CFBagCreateMutableCopy(CFAllocatorRef allocator, CFIndex capaci } else { ht = CFBasicHashCreateCopy(allocator, (CFBasicHashRef)other); } + if (!ht) return NULL; *(uintptr_t *)ht = __CFISAForTypeID(typeID); _CFRuntimeSetInstanceTypeID(ht, typeID); if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFBag (mutable)"); @@ -564,8 +570,8 @@ CFMutableHashRef CFBagCreateMutableCopy(CFAllocatorRef allocator, CFIndex capaci } CFIndex CFBagGetCount(CFHashRef hc) { - if (CFDictionary) CF_OBJC_FUNCDISPATCH0(__kCFBagTypeID, CFIndex, hc, "count"); - if (CFSet) CF_OBJC_FUNCDISPATCH0(__kCFBagTypeID, CFIndex, hc, "count"); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, CFIndex, (NSDictionary *)hc, count); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, CFIndex, (NSSet *)hc, count); __CFGenericValidateType(hc, __kCFBagTypeID); return CFBasicHashGetCount((CFBasicHashRef)hc); } @@ -576,8 +582,8 @@ CFIndex CFBagGetCountOfKey(CFHashRef hc, const_any_pointer_t key) { #if CFSet || CFBag CFIndex CFBagGetCountOfValue(CFHashRef hc, const_any_pointer_t key) { #endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, CFIndex, hc, "countForKey:", key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, CFIndex, hc, "countForObject:", key); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, CFIndex, (NSDictionary *)hc, countForKey:(id)key); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, CFIndex, (NSSet *)hc, countForObject:(id)key); __CFGenericValidateType(hc, __kCFBagTypeID); return CFBasicHashGetCountOfKey((CFBasicHashRef)hc, (uintptr_t)key); } @@ -588,23 +594,23 @@ Boolean CFBagContainsKey(CFHashRef hc, const_any_pointer_t key) { #if CFSet || CFBag Boolean CFBagContainsValue(CFHashRef hc, const_any_pointer_t key) { #endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, char, hc, "containsKey:", key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, char, hc, "containsObject:", key); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, char, (NSDictionary *)hc, containsKey:(id)key); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, char, (NSSet *)hc, containsObject:(id)key); __CFGenericValidateType(hc, __kCFBagTypeID); return (0 < CFBasicHashGetCountOfKey((CFBasicHashRef)hc, (uintptr_t)key)); } const_any_pointer_t CFBagGetValue(CFHashRef hc, const_any_pointer_t key) { - if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, const_any_pointer_t, hc, "objectForKey:", key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, const_any_pointer_t, hc, "member:", key); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, const_any_pointer_t, (NSDictionary *)hc, objectForKey:(id)key); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, const_any_pointer_t, (NSSet *)hc, member:(id)key); __CFGenericValidateType(hc, __kCFBagTypeID); CFBasicHashBucket bkt = CFBasicHashFindBucket((CFBasicHashRef)hc, (uintptr_t)key); return (0 < bkt.count ? (const_any_pointer_t)bkt.weak_value : 0); } Boolean CFBagGetValueIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *value) { - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, Boolean, hc, "__getValue:forKey:", (any_t *)value, key); - if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, Boolean, hc, "__getValue:forObj:", (any_t *)value, key); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, Boolean, (NSDictionary *)hc, __getValue:(id *)value forKey:(id)key); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, Boolean, (NSSet *)hc, __getValue:(id *)value forObj:(id)key); __CFGenericValidateType(hc, __kCFBagTypeID); CFBasicHashBucket bkt = CFBasicHashFindBucket((CFBasicHashRef)hc, (uintptr_t)key); if (0 < bkt.count) { @@ -622,19 +628,18 @@ Boolean CFBagGetValueIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_ #if CFDictionary CFIndex CFDictionaryGetCountOfValue(CFHashRef hc, const_any_pointer_t value) { - CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, CFIndex, hc, "countForObject:", value); + CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, CFIndex, (NSDictionary *)hc, countForObject:(id)value); __CFGenericValidateType(hc, __kCFBagTypeID); return CFBasicHashGetCountOfValue((CFBasicHashRef)hc, (uintptr_t)value); } Boolean CFDictionaryContainsValue(CFHashRef hc, const_any_pointer_t value) { - CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, char, hc, "containsObject:", value); + CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, char, (NSDictionary *)hc, containsObject:(id)value); __CFGenericValidateType(hc, __kCFBagTypeID); return (0 < CFBasicHashGetCountOfValue((CFBasicHashRef)hc, (uintptr_t)value)); } CF_EXPORT Boolean CFDictionaryGetKeyIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *actualkey) { - CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, Boolean, hc, "getActualKey:forKey:", actualkey, key); __CFGenericValidateType(hc, __kCFBagTypeID); CFBasicHashBucket bkt = CFBasicHashFindBucket((CFBasicHashRef)hc, (uintptr_t)key); if (0 < bkt.count) { @@ -658,8 +663,8 @@ void CFBagGetKeysAndValues(CFHashRef hc, const_any_pointer_t *keybuf, const_any_ void CFBagGetValues(CFHashRef hc, const_any_pointer_t *keybuf) { const_any_pointer_t *valuebuf = 0; #endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, void, hc, "getObjects:andKeys:", (any_t *)valuebuf, (any_t *)keybuf); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, void, hc, "getObjects:", (any_t *)keybuf); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSDictionary *)hc, getObjects:(id *)valuebuf andKeys:(id *)keybuf); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSSet *)hc, getObjects:(id *)keybuf); __CFGenericValidateType(hc, __kCFBagTypeID); if (kCFUseCollectableAllocator) { CFOptionFlags flags = CFBasicHashGetFlags((CFBasicHashRef)hc); @@ -681,8 +686,8 @@ void CFBagGetValues(CFHashRef hc, const_any_pointer_t *keybuf) { void CFBagApplyFunction(CFHashRef hc, CFBagApplierFunction applier, any_pointer_t context) { FAULT_CALLBACK((void **)&(applier)); - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, void, hc, "__apply:context:", applier, context); - if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, void, hc, "__applyValues:context:", applier, context); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSDictionary *)hc, __apply:(void (*)(const void *, const void *, void *))applier context:(void *)context); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSSet *)hc, __applyValues:(void (*)(const void *, void *))applier context:(void *)context); __CFGenericValidateType(hc, __kCFBagTypeID); CFBasicHashApply((CFBasicHashRef)hc, ^(CFBasicHashBucket bkt) { #if CFDictionary @@ -756,8 +761,8 @@ void CFBagAddValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_point void CFBagAddValue(CFMutableHashRef hc, const_any_pointer_t key) { const_any_pointer_t value = key; #endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, void, hc, "addObject:forKey:", value, key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, void, hc, "addObject:", key); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableDictionary *)hc, __addObject:(id)value forKey:(id)key); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableSet *)hc, addObject:(id)key); __CFGenericValidateType(hc, __kCFBagTypeID); CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { @@ -775,8 +780,8 @@ void CFBagReplaceValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_p void CFBagReplaceValue(CFMutableHashRef hc, const_any_pointer_t key) { const_any_pointer_t value = key; #endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, void, hc, "replaceObject:forKey:", value, key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, void, hc, "replaceObject:", key); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableDictionary *)hc, replaceObject:(id)value forKey:(id)key); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableSet *)hc, replaceObject:(id)key); __CFGenericValidateType(hc, __kCFBagTypeID); CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { @@ -794,8 +799,8 @@ void CFBagSetValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_point void CFBagSetValue(CFMutableHashRef hc, const_any_pointer_t key) { const_any_pointer_t value = key; #endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, void, hc, "setObject:forKey:", value, key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, void, hc, "setObject:", key); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableDictionary *)hc, setObject:(id)value forKey:(id)key); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableSet *)hc, setObject:(id)key); __CFGenericValidateType(hc, __kCFBagTypeID); CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { @@ -808,8 +813,8 @@ void CFBagSetValue(CFMutableHashRef hc, const_any_pointer_t key) { } void CFBagRemoveValue(CFMutableHashRef hc, const_any_pointer_t key) { - if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, void, hc, "removeObjectForKey:", key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, void, hc, "removeObject:", key); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableDictionary *)hc, removeObjectForKey:(id)key); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableSet *)hc, removeObject:(id)key); __CFGenericValidateType(hc, __kCFBagTypeID); CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { @@ -821,8 +826,8 @@ void CFBagRemoveValue(CFMutableHashRef hc, const_any_pointer_t key) { } void CFBagRemoveAllValues(CFMutableHashRef hc) { - if (CFDictionary) CF_OBJC_FUNCDISPATCH0(__kCFBagTypeID, void, hc, "removeAllObjects"); - if (CFSet) CF_OBJC_FUNCDISPATCH0(__kCFBagTypeID, void, hc, "removeAllObjects"); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableDictionary *)hc, removeAllObjects); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFBagTypeID, void, (NSMutableSet *)hc, removeAllObjects); __CFGenericValidateType(hc, __kCFBagTypeID); CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { diff --git a/CFBag.h b/CFBag.h index 1ee3663..a6e60d5 100644 --- a/CFBag.h +++ b/CFBag.h @@ -22,7 +22,7 @@ */ /* CFBag.h - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBAG__) @@ -30,6 +30,7 @@ #include +CF_IMPLICIT_BRIDGING_ENABLED CF_EXTERN_C_BEGIN typedef const void * (*CFBagRetainCallBack)(CFAllocatorRef allocator, const void *value); @@ -108,6 +109,7 @@ CF_EXPORT void CFBagRemoveAllValues(CFMutableBagRef theBag); CF_EXTERN_C_END +CF_IMPLICIT_BRIDGING_DISABLED #endif /* ! __COREFOUNDATION_CFBAG__ */ diff --git a/CFBase.c b/CFBase.c index 089aef3..2ed181d 100644 --- a/CFBase.c +++ b/CFBase.c @@ -22,35 +22,30 @@ */ /* CFBase.c - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ #include #include "CFInternal.h" -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD - #include +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD +#include #endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - #include - extern size_t malloc_good_size(size_t size); - #include - #include +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI +#include +#include +#include #endif #include #include // -------- -------- -------- -------- -------- -------- -------- -------- -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -// CFAllocator structure must match struct _malloc_zone_t! -// The first two reserved fields in struct _malloc_zone_t are for us with CFRuntimeBase -#endif - - struct __CFAllocator { CFRuntimeBase _base; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI + // CFAllocator structure must match struct _malloc_zone_t! + // The first two reserved fields in struct _malloc_zone_t are for us with CFRuntimeBase size_t (*size)(struct _malloc_zone_t *zone, const void *ptr); /* returns the size of a block or 0 if not in this zone; must be fast, especially for negative answers */ void *(*malloc)(struct _malloc_zone_t *zone, size_t size); void *(*calloc)(struct _malloc_zone_t *zone, size_t num_items, size_t size); /* same as malloc, but block returned is set to zero */ @@ -119,7 +114,7 @@ CF_INLINE CFAllocatorPreferredSizeCallBack __CFAllocatorGetPreferredSizeFunction return retval; } -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf); @@ -256,9 +251,8 @@ static void __CFAllocatorSystemDeallocate(void *ptr, void *info) { malloc_zone_free(info, ptr); } -#endif +#else -#if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) { return malloc(size); } @@ -298,7 +292,7 @@ static void __CFAllocatorCPPFree(void *ptr, void *info) static struct __CFAllocator __kCFAllocatorMalloc = { INIT_CFRUNTIME_BASE(), -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI __CFAllocatorCustomSize, __CFAllocatorCustomMalloc, __CFAllocatorCustomCalloc, @@ -327,7 +321,7 @@ static struct __CFAllocator __kCFAllocatorMalloc = { static struct __CFAllocator __kCFAllocatorMallocZone = { INIT_CFRUNTIME_BASE(), -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI __CFAllocatorCustomSize, __CFAllocatorCustomMalloc, __CFAllocatorCustomCalloc, @@ -349,7 +343,7 @@ static struct __CFAllocator __kCFAllocatorMallocZone = { static struct __CFAllocator __kCFAllocatorSystemDefault = { INIT_CFRUNTIME_BASE(), -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI __CFAllocatorCustomSize, __CFAllocatorCustomMalloc, __CFAllocatorCustomCalloc, @@ -371,7 +365,7 @@ static struct __CFAllocator __kCFAllocatorSystemDefault = { static struct __CFAllocator __kCFAllocatorNull = { INIT_CFRUNTIME_BASE(), -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI __CFAllocatorNullSize, __CFAllocatorNullMalloc, __CFAllocatorNullCalloc, @@ -457,7 +451,7 @@ __private_extern__ void __CFAllocatorInitialize(void) { _CFRuntimeSetInstanceTypeID(&__kCFAllocatorSystemDefault, __kCFAllocatorTypeID); __kCFAllocatorSystemDefault._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI __kCFAllocatorSystemDefault._context.info = (kCFUseCollectableAllocator ? objc_collectableZone() : malloc_default_zone()); #endif __kCFAllocatorSystemDefault._allocator = kCFAllocatorSystemDefault; @@ -466,8 +460,8 @@ __private_extern__ void __CFAllocatorInitialize(void) { __kCFAllocatorMalloc._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); __kCFAllocatorMalloc._allocator = kCFAllocatorSystemDefault; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMallocZone, __kCFAllocatorTypeID); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI + _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMallocZone, __kCFAllocatorTypeID); __kCFAllocatorMallocZone._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); __kCFAllocatorMallocZone._allocator = kCFAllocatorSystemDefault; __kCFAllocatorMallocZone._context.info = malloc_default_zone(); @@ -497,7 +491,7 @@ void CFAllocatorSetDefault(CFAllocatorRef allocator) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } #endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI if (allocator && allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return; // require allocator to this function to be an allocator } @@ -517,7 +511,7 @@ static CFAllocatorRef __CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorC CFAllocatorRetainCallBack retainFunc; CFAllocatorAllocateCallBack allocateFunc; void *retainedInfo; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI if (allocator && kCFAllocatorUseContext != allocator && allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return NULL; // require allocator to this function to be an allocator } @@ -558,7 +552,7 @@ static CFAllocatorRef __CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorC memory->_base._cfinfo[CF_INFO_BITS] = 0; _CFRuntimeSetInstanceTypeID(memory, __kCFAllocatorTypeID); memory->_base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI memory->size = __CFAllocatorCustomSize; memory->malloc = __CFAllocatorCustomMalloc; memory->calloc = __CFAllocatorCustomCalloc; @@ -613,7 +607,7 @@ void *CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags allocator = __CFGetDefaultAllocator(); } -#if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) +#if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI) if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } @@ -621,7 +615,7 @@ void *CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags __CFGenericValidateType(allocator, __kCFAllocatorTypeID); #endif if (0 == size) return NULL; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return malloc_zone_malloc((malloc_zone_t *)allocator, size); } @@ -653,7 +647,7 @@ void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize allocator = __CFGetDefaultAllocator(); } -#if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) +#if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI) if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } @@ -661,7 +655,7 @@ void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize __CFGenericValidateType(allocator, __kCFAllocatorTypeID); #endif if (NULL == ptr && 0 < newsize) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return malloc_zone_malloc((malloc_zone_t *)allocator, newsize); } @@ -674,7 +668,7 @@ void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize return newptr; } if (NULL != ptr && 0 == newsize) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * #if defined(DEBUG) size_t size = malloc_size(ptr); @@ -691,7 +685,7 @@ void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize return NULL; } if (NULL == ptr && 0 == newsize) return NULL; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return malloc_zone_realloc((malloc_zone_t *)allocator, ptr, newsize); } @@ -716,14 +710,14 @@ void CFAllocatorDeallocate(CFAllocatorRef allocator, void *ptr) { allocator = __CFGetDefaultAllocator(); } -#if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) +#if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI) if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } #else __CFGenericValidateType(allocator, __kCFAllocatorTypeID); #endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * #if defined(DEBUG) size_t size = malloc_size(ptr); @@ -751,14 +745,14 @@ CFIndex CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex siz allocator = __CFGetDefaultAllocator(); } -#if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) +#if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI) if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } #else __CFGenericValidateType(allocator, __kCFAllocatorTypeID); #endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return malloc_good_size(size); } @@ -781,7 +775,7 @@ void CFAllocatorGetContext(CFAllocatorRef allocator, CFAllocatorContext *context allocator = __CFGetDefaultAllocator(); } -#if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) +#if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI) if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } @@ -789,7 +783,7 @@ void CFAllocatorGetContext(CFAllocatorRef allocator, CFAllocatorContext *context __CFGenericValidateType(allocator, __kCFAllocatorTypeID); #endif CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return; } @@ -803,15 +797,6 @@ void CFAllocatorGetContext(CFAllocatorRef allocator, CFAllocatorContext *context context->reallocate = __CFAllocatorGetReallocateFunction(&allocator->_context); context->deallocate = __CFAllocatorGetDeallocateFunction(&allocator->_context); context->preferredSize = __CFAllocatorGetPreferredSizeFunction(&allocator->_context); -#if SUPPORT_CFM - context->retain = (void *)((uintptr_t)context->retain & ~0x3); - context->release = (void *)((uintptr_t)context->release & ~0x3); - context->copyDescription = (void *)((uintptr_t)context->copyDescription & ~0x3); - context->allocate = (void *)((uintptr_t)context->allocate & ~0x3); - context->reallocate = (void *)((uintptr_t)context->reallocate & ~0x3); - context->deallocate = (void *)((uintptr_t)context->deallocate & ~0x3); - context->preferredSize = (void *)((uintptr_t)context->preferredSize & ~0x3); -#endif } __private_extern__ void *_CFAllocatorAllocateGC(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) @@ -901,71 +886,9 @@ CFTypeID CFNullGetTypeID(void) { void CFCollection_non_gc_storage_error(void) { } -#if !SUPPORT_CFM -void _CFRuntimeSetCFMPresent(void *addr) { -} -#endif - -#if SUPPORT_CFM - -static int hasCFM = 0; - void _CFRuntimeSetCFMPresent(void *addr) { - hasCFM = 1; } -/* See comments below */ -__private_extern__ void __CF_FAULT_CALLBACK(void **ptr) { - uintptr_t p = (uintptr_t)*ptr; - if ((0 == p) || (p & 0x1)) return; - if (0 == hasCFM || (0x90000000 <= p && p < 0xA0000000)) { - *ptr = (void *)(p | 0x1); - } else { - uintptr_t known = ~0; - Dl_info info; - known = dladdr((void *)p, &info); - *ptr = (void *)(p | (known ? 0x1 : 0x3)); - } -} - -/* -Jump to callback function. r2 is not saved and restored -in the jump-to-CFM case, since we assume that dyld code -never uses that register and that CF is dyld. - -There are three states for (ptr & 0x3): - 0b00: check not yet done (or not going to be done, and is a dyld func ptr) - 0b01: check done, dyld function pointer - 0b11: check done, CFM tvector pointer -(but a NULL callback just stays NULL) - -There may be up to 5 word-sized arguments. Floating point -arguments can be done, but count as two word arguments. -Return value can be integral or real. -*/ - -/* Keep this assembly at the bottom of the source file! */ - -__asm__ ( -".text\n" -" .align 2\n" -".private_extern ___CF_INVOKE_CALLBACK\n" -"___CF_INVOKE_CALLBACK:\n" - "rlwinm r12,r3,0,0,29\n" - "andi. r0,r3,0x2\n" - "or r3,r4,r4\n" - "or r4,r5,r5\n" - "or r5,r6,r6\n" - "or r6,r7,r7\n" - "or r7,r8,r8\n" - "beq- Lcall\n" - "lwz r2,0x4(r12)\n" - "lwz r12,0x0(r12)\n" -"Lcall: mtspr ctr,r12\n" - "bctr\n"); - -#endif - // void __HALT(void); diff --git a/CFBase.h b/CFBase.h index f0f4ccd..e2d7aca 100644 --- a/CFBase.h +++ b/CFBase.h @@ -22,7 +22,7 @@ */ /* CFBase.h - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBASE__) @@ -34,6 +34,14 @@ #define __WIN32__ 1 #endif +#if defined(_WIN64) && !defined(__WIN64__) +#define __WIN64__ 1 +#endif + +#if defined(__WIN64__) && !defined(__LLP64__) +#define __LLP64__ 1 +#endif + #if defined(_MSC_VER) && defined(_M_IX86) #define __i386__ 1 #endif @@ -59,6 +67,15 @@ #define __has_feature(x) 0 #endif +// Some compilers provide the capability to test if certain attributes are available. This macro provides a compatibility path for other compilers. +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + +#ifndef __has_extension +#define __has_extension(x) 0 +#endif + #if defined(__GNUC__) || TARGET_OS_WIN32 #include #include @@ -69,39 +86,36 @@ #endif // The arguments to these availability macros is a version number, e.g. 10_6, 3_0 -#if TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) +#if (TARGET_OS_MAC || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) #include #include +#ifndef __IPHONE_5_0 +#define __IPHONE_5_0 50000 +#endif + +#ifndef __IPHONE_6_0 +#define __IPHONE_6_0 60000 +#endif + // Available on MacOS and iOS -#define CF_AVAILABLE(_mac, _ios) AVAILABLE_MAC_OS_X_VERSION_##_mac##_AND_LATER +#define CF_AVAILABLE(_mac, _ios) __OSX_AVAILABLE_STARTING(__MAC_##_mac, __IPHONE_##_ios) // Available on MacOS only -#define CF_AVAILABLE_MAC(_mac) AVAILABLE_MAC_OS_X_VERSION_##_mac##_AND_LATER +#define CF_AVAILABLE_MAC(_mac) __OSX_AVAILABLE_STARTING(__MAC_##_mac, __IPHONE_NA) // Available on iOS only #define CF_AVAILABLE_IOS(_ios) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios) // Deprecated on either MacOS or iOS, or deprecated on both (check version numbers for details) -#define CF_DEPRECATED(_macIntro, _macDep, _iosIntro, _iosDep) AVAILABLE_MAC_OS_X_VERSION_##_macIntro##_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_##_macDep +#define CF_DEPRECATED(_macIntro, _macDep, _iosIntro, _iosDep) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_##_macIntro, __MAC_##_macDep, __IPHONE_##_iosIntro, __IPHONE_##_iosDep) // Deprecated on MacOS, unavailable on iOS -#define CF_DEPRECATED_MAC(_macIntro, _macDep) AVAILABLE_MAC_OS_X_VERSION_##_macIntro##_AND_LATER_BUT_DEPRECATED_IN_MAC_OS_X_VERSION_##_macDep +#define CF_DEPRECATED_MAC(_macIntro, _macDep) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_##_macIntro, __MAC_##_macDep, __IPHONE_NA, __IPHONE_NA) // Unavailable on MacOS, deprecated on iOS #define CF_DEPRECATED_IOS(_iosIntro, _iosDep) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_NA, __MAC_NA, __IPHONE_##_iosIntro, __IPHONE_##_iosDep) -#elif (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) -#include -#include - -#define CF_AVAILABLE(_mac, _ios) __OSX_AVAILABLE_STARTING(__MAC_##_mac, __IPHONE_##_ios) -#define CF_AVAILABLE_MAC(_mac) __OSX_AVAILABLE_STARTING(__MAC_##_mac, __IPHONE_NA) -#define CF_AVAILABLE_IOS(_ios) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios) -#define CF_DEPRECATED(_macIntro, _macDep, _iosIntro, _iosDep) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_##_macIntro, __MAC_##_macDep, __IPHONE_##_iosIntro, __IPHONE_##_iosDep) -#define CF_DEPRECATED_MAC(_macIntro, _macDep) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_##_macIntro, __MAC_##_macDep, __IPHONE_NA, __IPHONE_NA) -#define CF_DEPRECATED_IOS(_iosIntro, _iosDep) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_NA, __MAC_NA, __IPHONE_##_iosIntro, __IPHONE_##_iosDep) - #else #if TARGET_OS_WIN32 @@ -118,6 +132,33 @@ #endif +#if __has_feature(enumerator_attributes) && __has_attribute(availability) +#define CF_ENUM_AVAILABLE(_mac, _ios) __OSX_AVAILABLE_STARTING(__MAC_##_mac, __IPHONE_##_ios) +#define CF_ENUM_AVAILABLE_MAC(_mac) __OSX_AVAILABLE_STARTING(__MAC_##_mac, __IPHONE_NA) +#define CF_ENUM_AVAILABLE_IOS(_ios) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios) +#define CF_ENUM_DEPRECATED(_macIntro, _macDep, _iosIntro, _iosDep) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_##_macIntro, __MAC_##_macDep, __IPHONE_##_iosIntro, __IPHONE_##_iosDep) +#define CF_ENUM_DEPRECATED_MAC(_macIntro, _macDep) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_##_macIntro, __MAC_##_macDep, __IPHONE_NA, __IPHONE_NA) +#define CF_ENUM_DEPRECATED_IOS(_iosIntro, _iosDep) __OSX_AVAILABLE_BUT_DEPRECATED(__MAC_NA, __MAC_NA, __IPHONE_##_iosIntro, __IPHONE_##_iosDep) +#else +#define CF_ENUM_AVAILABLE(_mac, _ios) +#define CF_ENUM_AVAILABLE_MAC(_mac) +#define CF_ENUM_AVAILABLE_IOS(_ios) +#define CF_ENUM_DEPRECATED(_macIntro, _macDep, _iosIntro, _iosDep) +#define CF_ENUM_DEPRECATED_MAC(_macIntro, _macDep) +#define CF_ENUM_DEPRECATED_IOS(_iosIntro, _iosDep) +#endif + +#if (__cplusplus && __cplusplus >= 201103L && (__has_extension(cxx_strong_enums) || __has_feature(objc_fixed_enum))) || (!__cplusplus && __has_feature(objc_fixed_enum)) +#define CF_ENUM(_type, _name) enum _name : _type _name; enum _name : _type +#if (__cplusplus) +#define CF_OPTIONS(_type, _name) _type _name; enum : _type +#else +#define CF_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type +#endif +#else +#define CF_ENUM(_type, _name) _type _name; enum +#define CF_OPTIONS(_type, _name) _type _name; enum +#endif // Older versions of these macro; use IOS versions instead #define CF_AVAILABLE_IPHONE(_ios) CF_AVAILABLE_IOS(_ios) @@ -216,7 +257,7 @@ CF_EXTERN_C_BEGIN #define CF_INLINE static __inline__ __attribute__((always_inline)) #elif defined(__GNUC__) #define CF_INLINE static __inline__ - #elif defined(__MWERKS__) || defined(__cplusplus) + #elif defined(__cplusplus) #define CF_INLINE static inline #elif defined(_MSC_VER) #define CF_INLINE static __inline @@ -227,19 +268,41 @@ CF_EXTERN_C_BEGIN // Marks functions which return a CF type that needs to be released by the caller but whose names are not consistent with CoreFoundation naming rules. The recommended fix to this is to rename the functions, but this macro can be used to let the clang static analyzer know of any exceptions that cannot be fixed. // This macro is ONLY to be used in exceptional circumstances, not to annotate functions which conform to the CoreFoundation naming rules. +#ifndef CF_RETURNS_RETAINED #if __has_feature(attribute_cf_returns_retained) #define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) #else #define CF_RETURNS_RETAINED #endif +#endif // Marks functions which return a CF type that may need to be retained by the caller but whose names are not consistent with CoreFoundation naming rules. The recommended fix to this is to rename the functions, but this macro can be used to let the clang static analyzer know of any exceptions that cannot be fixed. // This macro is ONLY to be used in exceptional circumstances, not to annotate functions which conform to the CoreFoundation naming rules. +#ifndef CF_RETURNS_NOT_RETAINED #if __has_feature(attribute_cf_returns_not_retained) #define CF_RETURNS_NOT_RETAINED __attribute__((cf_returns_not_retained)) #else #define CF_RETURNS_NOT_RETAINED #endif +#endif + +// Marks function arguments which are released by the callee. +#ifndef CF_RELEASES_ARGUMENT +#if __has_feature(attribute_cf_consumed) +#define CF_RELEASES_ARGUMENT __attribute__((cf_consumed)) +#else +#define CF_RELEASES_ARGUMENT +#endif +#endif + +// Compatibility +#ifndef CF_CONSUMED +#if __has_feature(attribute_cf_consumed) +#define CF_CONSUMED __attribute__((cf_consumed)) +#else +#define CF_CONSUMED +#endif +#endif // Marks functions which cannot be used when compiling in automatic reference counting mode. #if __has_feature(objc_arc) @@ -248,6 +311,23 @@ CF_EXTERN_C_BEGIN #define CF_AUTOMATED_REFCOUNT_UNAVAILABLE #endif +#ifndef CF_IMPLICIT_BRIDGING_ENABLED +#if __has_feature(arc_cf_code_audited) +#define CF_IMPLICIT_BRIDGING_ENABLED _Pragma("clang arc_cf_code_audited begin") +#else +#define CF_IMPLICIT_BRIDGING_ENABLED +#endif +#endif + +#ifndef CF_IMPLICIT_BRIDGING_DISABLED +#if __has_feature(arc_cf_code_audited) +#define CF_IMPLICIT_BRIDGING_DISABLED _Pragma("clang arc_cf_code_audited end") +#else +#define CF_IMPLICIT_BRIDGING_DISABLED +#endif +#endif + + CF_EXPORT double kCFCoreFoundationVersionNumber; #if TARGET_OS_MAC @@ -308,6 +388,14 @@ CF_EXPORT double kCFCoreFoundationVersionNumber; #define kCFCoreFoundationVersionNumber10_6_3 550.19 #define kCFCoreFoundationVersionNumber10_6_4 550.29 #define kCFCoreFoundationVersionNumber10_6_5 550.42 +#define kCFCoreFoundationVersionNumber10_6_6 550.42 +#define kCFCoreFoundationVersionNumber10_6_7 550.42 +#define kCFCoreFoundationVersionNumber10_6_8 550.43 +#define kCFCoreFoundationVersionNumber10_7 635.00 +#define kCFCoreFoundationVersionNumber10_7_1 635.00 +#define kCFCoreFoundationVersionNumber10_7_2 635.15 +#define kCFCoreFoundationVersionNumber10_7_3 635.19 +#define kCFCoreFoundationVersionNumber10_7_4 635.21 #endif #if TARGET_OS_IPHONE @@ -320,12 +408,22 @@ CF_EXPORT double kCFCoreFoundationVersionNumber; #define kCFCoreFoundationVersionNumber_iOS_4_0 550.32 #define kCFCoreFoundationVersionNumber_iOS_4_1 550.38 #define kCFCoreFoundationVersionNumber_iOS_4_2 550.52 +#define kCFCoreFoundationVersionNumber_iOS_4_3 550.52 +#define kCFCoreFoundationVersionNumber_iOS_5_0 675 +#define kCFCoreFoundationVersionNumber_iOS_5_1 690.1 #endif +#if __LLP64__ +typedef unsigned long long CFTypeID; +typedef unsigned long long CFOptionFlags; +typedef unsigned long long CFHashCode; +typedef signed long long CFIndex; +#else typedef unsigned long CFTypeID; typedef unsigned long CFOptionFlags; typedef unsigned long CFHashCode; typedef signed long CFIndex; +#endif /* Base "type" of all "CF objects", and polymorphic functions on them */ typedef const void * CFTypeRef; @@ -341,12 +439,11 @@ typedef struct __CFString * CFMutableStringRef; typedef CFTypeRef CFPropertyListRef; /* Values returned from comparison functions */ -enum { - kCFCompareLessThan = -1, +typedef CF_ENUM(CFIndex, CFComparisonResult) { + kCFCompareLessThan = -1L, kCFCompareEqualTo = 0, kCFCompareGreaterThan = 1 }; -typedef CFIndex CFComparisonResult; /* A standard comparison function */ typedef CFComparisonResult (*CFComparatorFunction)(const void *val1, const void *val2, void *context); diff --git a/CFBasicHash.m b/CFBasicHash.c similarity index 96% rename from CFBasicHash.m rename to CFBasicHash.c index 1554f86..6e94e1a 100644 --- a/CFBasicHash.m +++ b/CFBasicHash.c @@ -22,7 +22,7 @@ */ /* CFBasicHash.m - Copyright (c) 2008-2011, Apple Inc. All rights reserved. + Copyright (c) 2008-2012, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ @@ -32,10 +32,10 @@ #import #import -#if DEPLOYMENT_TARGET_WINDOWS -#define __SetLastAllocationEventName(A, B) do { } while (0) -#else +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED #define __SetLastAllocationEventName(A, B) do { if (__CFOASafe && (A)) __CFSetLastAllocationEventName(A, B); } while (0) +#else +#define __SetLastAllocationEventName(A, B) do { } while (0) #endif #define GCRETAIN(A, B) kCFTypeSetCallBacks.retain(A, B) @@ -283,7 +283,16 @@ CF_INLINE void *__CFBasicHashAllocateMemory(CFConstBasicHashRef ht, CFIndex coun } else { new_mem = CFAllocatorAllocate(allocator, count * elem_size, 0); } - if (!new_mem) HALT; + return new_mem; +} + +CF_INLINE void *__CFBasicHashAllocateMemory2(CFAllocatorRef allocator, CFIndex count, CFIndex elem_size, Boolean strong, Boolean compactable) { + void *new_mem = NULL; + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + new_mem = auto_zone_allocate_object(objc_collectableZone(), count * elem_size, strong ? (compactable ? AUTO_POINTERS_ONLY : AUTO_MEMORY_SCANNED) : AUTO_UNSCANNED, false, false); + } else { + new_mem = CFAllocatorAllocate(allocator, count * elem_size, 0); + } return new_mem; } @@ -329,58 +338,58 @@ struct __CFBasicHash { }; __private_extern__ Boolean CFBasicHashHasStrongValues(CFConstBasicHashRef ht) { -#if defined(__arm__) - return false; -#else +#if DEPLOYMENT_TARGET_MACOSX return ht->bits.strong_values ? true : false; +#else + return false; #endif } __private_extern__ Boolean CFBasicHashHasStrongKeys(CFConstBasicHashRef ht) { -#if defined(__arm__) - return false; -#else +#if DEPLOYMENT_TARGET_MACOSX return ht->bits.strong_keys ? true : false; +#else + return false; #endif } CF_INLINE Boolean __CFBasicHashHasCompactableKeys(CFConstBasicHashRef ht) { -#if defined(__arm__) - return false; -#else +#if DEPLOYMENT_TARGET_MACOSX return ht->bits.compactable_keys ? true : false; +#else + return false; #endif } CF_INLINE Boolean __CFBasicHashHasCompactableValues(CFConstBasicHashRef ht) { -#if defined(__arm__) - return false; -#else +#if DEPLOYMENT_TARGET_MACOSX return ht->bits.compactable_values ? true : false; +#else + return false; #endif } CF_INLINE Boolean __CFBasicHashHasWeakValues(CFConstBasicHashRef ht) { -#if defined(__arm__) - return false; -#else +#if DEPLOYMENT_TARGET_MACOSX return ht->bits.weak_values ? true : false; +#else + return false; #endif } CF_INLINE Boolean __CFBasicHashHasWeakKeys(CFConstBasicHashRef ht) { -#if defined(__arm__) - return false; -#else +#if DEPLOYMENT_TARGET_MACOSX return ht->bits.weak_keys ? true : false; +#else + return false; #endif } CF_INLINE Boolean __CFBasicHashHasHashCache(CFConstBasicHashRef ht) { -#if defined(__arm__) - return false; -#else +#if DEPLOYMENT_TARGET_MACOSX return ht->bits.hashes_offset ? true : false; +#else + return false; #endif } @@ -525,6 +534,7 @@ CF_INLINE void __CFBasicHashBumpCounts(CFBasicHashRef ht) { ht->bits.counts_width = 1; CFIndex num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx]; uint16_t *counts16 = (uint16_t *)__CFBasicHashAllocateMemory(ht, num_buckets, 2, false, false); + if (!counts16) HALT; __SetLastAllocationEventName(counts16, "CFBasicHash (count-store)"); for (CFIndex idx2 = 0; idx2 < num_buckets; idx2++) { counts16[idx2] = counts08[idx2]; @@ -540,6 +550,7 @@ CF_INLINE void __CFBasicHashBumpCounts(CFBasicHashRef ht) { ht->bits.counts_width = 2; CFIndex num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx]; uint32_t *counts32 = (uint32_t *)__CFBasicHashAllocateMemory(ht, num_buckets, 4, false, false); + if (!counts32) HALT; __SetLastAllocationEventName(counts32, "CFBasicHash (count-store)"); for (CFIndex idx2 = 0; idx2 < num_buckets; idx2++) { counts32[idx2] = counts16[idx2]; @@ -555,6 +566,7 @@ CF_INLINE void __CFBasicHashBumpCounts(CFBasicHashRef ht) { ht->bits.counts_width = 3; CFIndex num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx]; uint64_t *counts64 = (uint64_t *)__CFBasicHashAllocateMemory(ht, num_buckets, 8, false, false); + if (!counts64) HALT; __SetLastAllocationEventName(counts64, "CFBasicHash (count-store)"); for (CFIndex idx2 = 0; idx2 < num_buckets; idx2++) { counts64[idx2] = counts32[idx2]; @@ -1110,20 +1122,24 @@ static void __CFBasicHashRehash(CFBasicHashRef ht, CFIndex newItemCount) { if (0 < new_num_buckets) { new_values = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), CFBasicHashHasStrongValues(ht), __CFBasicHashHasCompactableValues(ht)); + if (!new_values) HALT; __SetLastAllocationEventName(new_values, "CFBasicHash (value-store)"); memset(new_values, 0, new_num_buckets * sizeof(CFBasicHashValue)); if (ht->bits.keys_offset) { new_keys = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), CFBasicHashHasStrongKeys(ht), __CFBasicHashHasCompactableKeys(ht)); + if (!new_keys) HALT; __SetLastAllocationEventName(new_keys, "CFBasicHash (key-store)"); memset(new_keys, 0, new_num_buckets * sizeof(CFBasicHashValue)); } if (ht->bits.counts_offset) { new_counts = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, (1 << ht->bits.counts_width), false, false); + if (!new_counts) HALT; __SetLastAllocationEventName(new_counts, "CFBasicHash (count-store)"); memset(new_counts, 0, new_num_buckets * (1 << ht->bits.counts_width)); } if (__CFBasicHashHasHashCache(ht)) { new_hashes = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false, false); + if (!new_hashes) HALT; __SetLastAllocationEventName(new_hashes, "CFBasicHash (hash-store)"); memset(new_hashes, 0, new_num_buckets * sizeof(uintptr_t)); } @@ -1541,7 +1557,7 @@ CFBasicHashRef CFBasicHashCreate(CFAllocatorRef allocator, CFOptionFlags flags, if (flags & kCFBasicHashHasCounts) size += sizeof(void *); // counts if (flags & kCFBasicHashHasHashCache) size += sizeof(uintptr_t *); // hashes CFBasicHashRef ht = (CFBasicHashRef)_CFRuntimeCreateInstance(allocator, CFBasicHashGetTypeID(), size, NULL); - if (NULL == ht) HALT; + if (NULL == ht) return NULL; ht->bits.finalized = 0; ht->bits.hash_style = (flags >> 13) & 0x3; @@ -1579,7 +1595,7 @@ CFBasicHashRef CFBasicHashCreate(CFAllocatorRef allocator, CFOptionFlags flags, ht->bits.counts_offset = (flags & kCFBasicHashHasCounts) ? offset++ : 0; ht->bits.hashes_offset = (flags & kCFBasicHashHasHashCache) ? offset++ : 0; -#if defined(__arm__) +#if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI ht->bits.hashes_offset = 0; ht->bits.strong_values = 0; ht->bits.strong_keys = 0; @@ -1605,8 +1621,42 @@ CFBasicHashRef CFBasicHashCreate(CFAllocatorRef allocator, CFOptionFlags flags, CFBasicHashRef CFBasicHashCreateCopy(CFAllocatorRef allocator, CFConstBasicHashRef src_ht) { size_t size = CFBasicHashGetSize(src_ht, false) - sizeof(CFRuntimeBase); + CFBasicHashCallbacks *newcb = src_ht->callbacks->copyCallbacks(src_ht, allocator, src_ht->callbacks); + if (NULL == newcb) { + return NULL; + } + + CFIndex new_num_buckets = __CFBasicHashTableSizes[src_ht->bits.num_buckets_idx]; + CFBasicHashValue *new_values = NULL, *new_keys = NULL; + void *new_counts = NULL; + uintptr_t *new_hashes = NULL; + + if (0 < new_num_buckets) { + Boolean strongValues = CFBasicHashHasStrongValues(src_ht) && !(kCFUseCollectableAllocator && !CF_IS_COLLECTABLE_ALLOCATOR(allocator)); + Boolean strongKeys = CFBasicHashHasStrongKeys(src_ht) && !(kCFUseCollectableAllocator && !CF_IS_COLLECTABLE_ALLOCATOR(allocator)); + Boolean compactableValues = __CFBasicHashHasCompactableValues(src_ht) && !(kCFUseCollectableAllocator && !CF_IS_COLLECTABLE_ALLOCATOR(allocator)); + new_values = (CFBasicHashValue *)__CFBasicHashAllocateMemory2(allocator, new_num_buckets, sizeof(CFBasicHashValue), strongValues, compactableValues); + if (!new_values) return NULL; // in this unusual circumstance, leak previously allocated blocks for now + __SetLastAllocationEventName(new_values, "CFBasicHash (value-store)"); + if (src_ht->bits.keys_offset) { + new_keys = (CFBasicHashValue *)__CFBasicHashAllocateMemory2(allocator, new_num_buckets, sizeof(CFBasicHashValue), strongKeys, false); + if (!new_keys) return NULL; // in this unusual circumstance, leak previously allocated blocks for now + __SetLastAllocationEventName(new_keys, "CFBasicHash (key-store)"); + } + if (src_ht->bits.counts_offset) { + new_counts = (uintptr_t *)__CFBasicHashAllocateMemory2(allocator, new_num_buckets, (1 << src_ht->bits.counts_width), false, false); + if (!new_counts) return NULL; // in this unusual circumstance, leak previously allocated blocks for now + __SetLastAllocationEventName(new_counts, "CFBasicHash (count-store)"); + } + if (__CFBasicHashHasHashCache(src_ht)) { + new_hashes = (uintptr_t *)__CFBasicHashAllocateMemory2(allocator, new_num_buckets, sizeof(uintptr_t), false, false); + if (!new_hashes) return NULL; // in this unusual circumstance, leak previously allocated blocks for now + __SetLastAllocationEventName(new_hashes, "CFBasicHash (hash-store)"); + } + } + CFBasicHashRef ht = (CFBasicHashRef)_CFRuntimeCreateInstance(allocator, CFBasicHashGetTypeID(), size, NULL); - if (NULL == ht) HALT; + if (NULL == ht) return NULL; // in this unusual circumstance, leak previously allocated blocks for now memmove((uint8_t *)ht + sizeof(CFRuntimeBase), (uint8_t *)src_ht + sizeof(CFRuntimeBase), sizeof(ht->bits)); if (kCFUseCollectableAllocator && !CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { @@ -1617,11 +1667,8 @@ CFBasicHashRef CFBasicHashCreateCopy(CFAllocatorRef allocator, CFConstBasicHashR } ht->bits.finalized = 0; ht->bits.mutations = 1; - CFBasicHashCallbacks *newcb = src_ht->callbacks->copyCallbacks(src_ht, allocator, src_ht->callbacks); - if (NULL == newcb) HALT; __AssignWithWriteBarrier(&ht->callbacks, newcb); - CFIndex new_num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx]; if (0 == new_num_buckets) { #if ENABLE_MEMORY_COUNTERS int64_t size_now = OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize); @@ -1633,27 +1680,6 @@ CFBasicHashRef CFBasicHashCreateCopy(CFAllocatorRef allocator, CFConstBasicHashR return ht; } - CFBasicHashValue *new_values = NULL, *new_keys = NULL; - void *new_counts = NULL; - uintptr_t *new_hashes = NULL; - - if (0 < new_num_buckets) { - new_values = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), CFBasicHashHasStrongValues(ht), __CFBasicHashHasCompactableValues(ht)); - __SetLastAllocationEventName(new_values, "CFBasicHash (value-store)"); - if (ht->bits.keys_offset) { - new_keys = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), CFBasicHashHasStrongKeys(ht), false); - __SetLastAllocationEventName(new_keys, "CFBasicHash (key-store)"); - } - if (ht->bits.counts_offset) { - new_counts = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, (1 << ht->bits.counts_width), false, false); - __SetLastAllocationEventName(new_counts, "CFBasicHash (count-store)"); - } - if (__CFBasicHashHasHashCache(ht)) { - new_hashes = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false, false); - __SetLastAllocationEventName(new_hashes, "CFBasicHash (hash-store)"); - } - } - CFBasicHashValue *old_values = NULL, *old_keys = NULL; void *old_counts = NULL; uintptr_t *old_hashes = NULL; diff --git a/CFBasicHash.h b/CFBasicHash.h index 3118684..eb85edf 100644 --- a/CFBasicHash.h +++ b/CFBasicHash.h @@ -22,7 +22,7 @@ */ /* CFBasicHash.h - Copyright (c) 2008-2011, Apple Inc. All rights reserved. + Copyright (c) 2008-2012, Apple Inc. All rights reserved. */ #include diff --git a/CFBasicHashFindBucket.m b/CFBasicHashFindBucket.m index ecd4e2b..ccbcb69 100644 --- a/CFBasicHashFindBucket.m +++ b/CFBasicHashFindBucket.m @@ -22,7 +22,7 @@ */ /* CFBasicHashFindBucket.m - Copyright (c) 2009-2011, Apple Inc. All rights reserved. + Copyright (c) 2009-2012, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ diff --git a/CFBigNumber.c b/CFBigNumber.c new file mode 100644 index 0000000..62ea129 --- /dev/null +++ b/CFBigNumber.c @@ -0,0 +1,564 @@ +/* + * Copyright (c) 2012 Apple 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@ + */ + +/* CFBigNumber.c + Copyright (c) 2012-2012, Apple Inc. All rights reserved. + Responsibility: Christopher Kane + Original author: Zhi Feng Huang +*/ + +#include +#include +#include +#include +#include +#include "CFInternal.h" + + +#define kCFNumberSInt128Type 17 + +#if __LP64__ + +#ifndef _INT128_T +#define _INT128_T +typedef __int128_t int128_t; +#endif + +#ifndef _UINT128_T +#define _UINT128_T +typedef __uint128_t uint128_t; +#endif + +#ifndef INT128_MIN +#define INT128_MIN ((__int128_t)0 - ((__int128_t)1 << 126) - ((__int128_t)1 << 126)) +#endif + +#ifndef INT128_MAX +#define INT128_MAX ((__int128_t)-1 + ((__int128_t)1 << 126) + ((__int128_t)1 << 126)) +#endif + +#ifndef UINT128_MAX +#define UINT128_MAX (((__uint128_t)1 << 127) - (__uint128_t)1 + ((__uint128_t)1 << 127)) +#endif + +#endif + + +#define BIG_DIGITS_LIMIT 1000000000L +#define BIG_DIGITS_LIMIT_2 ((uint64_t)BIG_DIGITS_LIMIT * (uint64_t)BIG_DIGITS_LIMIT) +#define BIG_DIGITS_LIMIT_3 ((__uint128_t)BIG_DIGITS_LIMIT_2 * (__uint128_t)BIG_DIGITS_LIMIT) +#define BIG_DIGITS_LIMIT_4 ((__uint128_t)BIG_DIGITS_LIMIT_3 * (__uint128_t)BIG_DIGITS_LIMIT) + +#define GET_FIFTH_DIGIT(A) (A / BIG_DIGITS_LIMIT_4) +#define GET_FOURTH_DIGIT(A) (A / BIG_DIGITS_LIMIT_3) +#define GET_THIRD_DIGIT(A) (A / BIG_DIGITS_LIMIT_2) +#define GET_SECOND_DIGIT(A) (A / BIG_DIGITS_LIMIT) + +#define GET_REMAINDER_FIFTH_DIGIT(A,B) (A - B * BIG_DIGITS_LIMIT_4) +#define GET_REMAINDER_FOURTH_DIGIT(A,B) (A - B * BIG_DIGITS_LIMIT_3) +#define GET_REMAINDER_THIRD_DIGIT(A,B) (A - B * BIG_DIGITS_LIMIT_2) +#define GET_REMAINDER_SECOND_DIGIT(A,B) (A - B * BIG_DIGITS_LIMIT) + + +void _CFBigNumInitWithInt8(_CFBigNum *r, int8_t inNum) { + memset(r, 0, sizeof(*r)); + uint8_t unsignInNum = inNum; + if (inNum < 0) { + r->sign = -1; + unsignInNum = -1 * inNum; + } + r->digits[0] = unsignInNum; +} + +void _CFBigNumInitWithInt16(_CFBigNum *r, int16_t inNum) { + memset(r, 0, sizeof(*r)); + uint16_t unsignInNum = inNum; + if (inNum < 0) { + r->sign = -1; + unsignInNum = -1 * inNum; + } + r->digits[0] = unsignInNum; +} + +void _CFBigNumInitWithInt32(_CFBigNum *r, int32_t inNum) { + memset(r, 0, sizeof(*r)); + uint32_t unsignInNum = inNum; + if (inNum < 0) { + r->sign = -1; + unsignInNum = -1 * inNum; + } + uint32_t dig0 = GET_SECOND_DIGIT(unsignInNum); + r->digits[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum, dig0); + r->digits[1] = dig0; +} + +void _CFBigNumInitWithInt64(_CFBigNum *r, int64_t inNum) { + memset(r, 0, sizeof(*r)); + uint64_t unsignInNum = inNum; + if (inNum < 0) { + r->sign = -1; + unsignInNum = -1 * inNum; + } + uint32_t dig2 = GET_THIRD_DIGIT(unsignInNum); + unsignInNum = GET_REMAINDER_THIRD_DIGIT(unsignInNum, (uint64_t)dig2); + uint32_t dig1 = GET_SECOND_DIGIT(unsignInNum); + r->digits[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum, (uint64_t)dig1); + r->digits[1] = dig1; + r->digits[2] = dig2; +} + +#ifdef __LP64__ +void _CFBigNumInitWithInt128(_CFBigNum *r, __int128_t inNum) { + memset(r, 0, sizeof(*r)); + __uint128_t unsignInNum = inNum; + if (inNum < 0) { + r->sign = -1; + unsignInNum = -1 * inNum; + } + uint32_t dig4 = GET_FIFTH_DIGIT(unsignInNum); + unsignInNum = GET_REMAINDER_FIFTH_DIGIT(unsignInNum, (__uint128_t)dig4); + uint32_t dig3 = GET_FOURTH_DIGIT(unsignInNum); + unsignInNum = GET_REMAINDER_FOURTH_DIGIT(unsignInNum, (__uint128_t)dig3); + uint32_t dig2 = GET_THIRD_DIGIT(unsignInNum); + unsignInNum = GET_REMAINDER_THIRD_DIGIT(unsignInNum, (__uint128_t)dig2); + uint32_t dig1 = GET_SECOND_DIGIT(unsignInNum); + r->digits[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum, (__uint128_t)dig1); + r->digits[1] = dig1; + r->digits[2] = dig2; + r->digits[3] = dig3; + r->digits[4] = dig4; +} +#endif + +void _CFBigNumInitWithUInt8(_CFBigNum *r, uint8_t inNum) { + memset(r, 0, sizeof(*r)); + uint8_t unsignInNum = inNum; + r->digits[0] = unsignInNum; +} + +void _CFBigNumInitWithUInt16(_CFBigNum *r, uint16_t inNum) { + memset(r, 0, sizeof(*r)); + uint16_t unsignInNum = inNum; + r->digits[0] = unsignInNum; +} + +void _CFBigNumInitWithUInt32(_CFBigNum *r, uint32_t inNum) { + memset(r, 0, sizeof(*r)); + uint32_t unsignInNum = inNum; + uint32_t dig0 = GET_SECOND_DIGIT(unsignInNum); + r->digits[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum, dig0); + r->digits[1] = dig0; +} + +void _CFBigNumInitWithUInt64(_CFBigNum *r, uint64_t inNum) { + memset(r, 0, sizeof(*r)); + uint64_t unsignInNum = inNum; + uint32_t dig2 = GET_THIRD_DIGIT(unsignInNum); + unsignInNum = GET_REMAINDER_THIRD_DIGIT(unsignInNum, (uint64_t)dig2); + uint32_t dig1 = GET_SECOND_DIGIT(unsignInNum); + r->digits[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum, (uint64_t)dig1); + r->digits[1] = dig1; + r->digits[2] = dig2; +} + +#ifdef __LP64__ +void _CFBigNumInitWithUInt128(_CFBigNum *r, __uint128_t inNum) { + memset(r, 0, sizeof(*r)); + __uint128_t unsignInNum = inNum; + uint32_t dig4 = GET_FIFTH_DIGIT(unsignInNum); + unsignInNum = GET_REMAINDER_FIFTH_DIGIT(unsignInNum, (__uint128_t)dig4); + uint32_t dig3 = GET_FOURTH_DIGIT(unsignInNum); + unsignInNum = GET_REMAINDER_FOURTH_DIGIT(unsignInNum, (__uint128_t)dig3); + uint32_t dig2 = GET_THIRD_DIGIT(unsignInNum); + unsignInNum = GET_REMAINDER_THIRD_DIGIT(unsignInNum, (__uint128_t)dig2); + uint32_t dig1 = GET_SECOND_DIGIT(unsignInNum); + r->digits[0] = GET_REMAINDER_SECOND_DIGIT(unsignInNum, (__uint128_t)dig1); + r->digits[1] = dig1; + r->digits[2] = dig2; + r->digits[3] = dig3; + r->digits[4] = dig4; +} +#endif + + +int8_t _CFBigNumGetInt8(const _CFBigNum *num) { + int8_t result = num->digits[0]; + if (num->sign < 0) { + result = -1 * result; + } + return result; +} + +int16_t _CFBigNumGetInt16(const _CFBigNum *num) { + int16_t result = num->digits[0]; + if (num->sign < 0) { + result = -1 * result; + } + return result; +} + +int32_t _CFBigNumGetInt32(const _CFBigNum *num) { + int32_t result = num->digits[0]; + result += num->digits[1] * BIG_DIGITS_LIMIT; + if (num->sign < 0) { + result = -1 * result; + } + return result; +} + +int64_t _CFBigNumGetInt64(const _CFBigNum *num) { + int64_t result = num->digits[0]; + result += (int64_t)num->digits[1] * BIG_DIGITS_LIMIT; + result += (int64_t)num->digits[2] * BIG_DIGITS_LIMIT_2; + if (num->sign < 0) { + result = -1 * result; + } + return result; +} + +#if __LP64__ +__int128_t _CFBigNumGetInt128(const _CFBigNum *num) { + __int128_t result = num->digits[0]; + result += (__int128_t)num->digits[1] * BIG_DIGITS_LIMIT; + result += (__int128_t)num->digits[2] * BIG_DIGITS_LIMIT_2; + result += (__int128_t)num->digits[3] * BIG_DIGITS_LIMIT_3; + result += (__int128_t)num->digits[4] * BIG_DIGITS_LIMIT_4; + if (num->sign < 0) { + result = -1 * result; + } + return result; +} +#endif + +uint8_t _CFBigNumGetUInt8(const _CFBigNum *num) { + uint8_t result = num->digits[0]; + return result; +} + +uint16_t _CFBigNumGetUInt16(const _CFBigNum *num) { + uint16_t result = num->digits[0]; + return result; +} + +uint32_t _CFBigNumGetUInt32(const _CFBigNum *num) { + uint32_t result = num->digits[0]; + result += num->digits[1] * BIG_DIGITS_LIMIT; + return result; +} + +uint64_t _CFBigNumGetUInt64(const _CFBigNum *num) { + uint64_t result = num->digits[0]; + result += (uint64_t)num->digits[1] * BIG_DIGITS_LIMIT; + result += (uint64_t)num->digits[2] * BIG_DIGITS_LIMIT_2; + return result; +} + +#if __LP64__ +__uint128_t _CFBigNumGetUInt128(const _CFBigNum *num) { + __uint128_t result = num->digits[0]; + result += (__uint128_t)num->digits[1] * BIG_DIGITS_LIMIT; + result += (__uint128_t)num->digits[2] * BIG_DIGITS_LIMIT_2; + result += (__uint128_t)num->digits[3] * BIG_DIGITS_LIMIT_3; + result += (__uint128_t)num->digits[4] * BIG_DIGITS_LIMIT_4; + return result; +} +#endif + + +void _CFBigNumInitWithCFNumber(_CFBigNum *r, CFNumberRef inNum) { + uint8_t bytes[128]; + memset(bytes, 0, sizeof(bytes)); + CFNumberType type = CFNumberGetType(inNum); + CFNumberGetValue(inNum, type, (void *)bytes); + _CFBigNumInitWithBytes(r, (const void *)bytes, type); +} + +void _CFBigNumInitWithBytes(_CFBigNum *r, const void *bytes, CFNumberType type) { + switch (type) { + case kCFNumberSInt8Type: + _CFBigNumInitWithInt8(r, *(int8_t *)bytes); + return; + case kCFNumberSInt16Type: + _CFBigNumInitWithInt16(r, *(int16_t *)bytes); + return; + case kCFNumberSInt32Type: + _CFBigNumInitWithInt32(r, *(int32_t *)bytes); + return; + case kCFNumberSInt64Type: + _CFBigNumInitWithInt64(r, *(int64_t *)bytes); + return; + case kCFNumberCharType: + _CFBigNumInitWithInt8(r, *(int8_t *)bytes); + return; + case kCFNumberShortType: + _CFBigNumInitWithInt16(r, *(int16_t *)bytes); + return; + case kCFNumberIntType: + _CFBigNumInitWithInt32(r, *(int32_t *)bytes); + return; + case kCFNumberLongType: + if (sizeof(long) == 8) { + _CFBigNumInitWithInt64(r, *(int64_t *)bytes); + } else { + _CFBigNumInitWithInt32(r, *(int32_t *)bytes); + } + return; + case kCFNumberLongLongType: + _CFBigNumInitWithInt64(r, *(int64_t *)bytes); + return; + case kCFNumberCFIndexType: + if (sizeof(CFIndex) == 8) { + _CFBigNumInitWithInt64(r, *(int64_t *)bytes); + } else { + _CFBigNumInitWithInt32(r, *(int32_t *)bytes); + } + return; + case kCFNumberNSIntegerType: + if (sizeof(long) == 8) { // NSInteger follows long + _CFBigNumInitWithInt64(r, *(int64_t *)bytes); + } else { + _CFBigNumInitWithInt32(r, *(int32_t *)bytes); + } + return; +#if __LP64__ + case kCFNumberSInt128Type: + _CFBigNumInitWithInt128(r, *(__int128_t *)bytes); + return; +#endif + default: + return; + } +} + +CFNumberRef _CFNumberCreateWithBigNum(const _CFBigNum *input) { + if (0 == input->digits[4] && 0 == input->digits[3] && 0 == input->digits[2] && 0 == input->digits[1]) { + // This bumps up the size of the most negative n-bit value to the next larger size; oh well + if (input->digits[0] <= INT8_MAX) { + int8_t num = _CFBigNumGetInt8(input); + CFNumberRef result = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt8Type, (const void *)&num); + return result; + } else if (input->digits[0] <= INT16_MAX) { + int16_t num = _CFBigNumGetInt16(input); + CFNumberRef result = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt16Type, (const void *)&num); + return result; + } + } + _CFBigNum maxlimit, minlimit; + if (0 == input->digits[4] && 0 == input->digits[3] && 0 == input->digits[2]) { + _CFBigNumInitWithInt32(&maxlimit, INT32_MAX); + _CFBigNumInitWithInt32(&minlimit, INT32_MIN); + CFComparisonResult cr = _CFBigNumCompare(input, &maxlimit); + CFComparisonResult crn = _CFBigNumCompare(input, &minlimit); + if ((kCFCompareLessThan == cr || kCFCompareEqualTo == cr) && (kCFCompareLessThan != crn)) { + int32_t num = _CFBigNumGetInt32(input); + CFNumberRef result = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, (const void *)&num); + return result; + } + } + if (0 == input->digits[4] && 0 == input->digits[3]) { + _CFBigNumInitWithInt64(&maxlimit, INT64_MAX); + _CFBigNumInitWithInt64(&minlimit, INT64_MIN); + CFComparisonResult cr = _CFBigNumCompare(input, &maxlimit); + CFComparisonResult crn = _CFBigNumCompare(input, &minlimit); + if ((kCFCompareLessThan == cr || kCFCompareEqualTo == cr) && (kCFCompareLessThan != crn)) { + int64_t num = _CFBigNumGetInt64(input); + CFNumberRef result = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt64Type, (const void *)&num); + return result; + } + } +#if __LP64__ + _CFBigNumInitWithInt128(&maxlimit, INT128_MAX); + _CFBigNumInitWithInt128(&minlimit, INT128_MIN); + CFComparisonResult cr = _CFBigNumCompare(input, &maxlimit); + CFComparisonResult crn = _CFBigNumCompare(input, &minlimit); + if ((kCFCompareLessThan == cr || kCFCompareEqualTo == cr) && (kCFCompareLessThan != crn)) { + __int128_t num = _CFBigNumGetInt128(input); + CFNumberRef result = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt128Type, (const void *)&num); + return result; + } +#endif + return NULL; +} + +CFComparisonResult _CFBigNumCompare(const _CFBigNum *a, const _CFBigNum *b) { + Boolean sameSign = a->sign == b->sign; + if (sameSign) { + Boolean negative = a->sign < 0; + for (CFIndex i = sizeof(a->digits) / sizeof(a->digits[0]); i--;) { + if (a->digits[i] < b->digits[i]) { + return !negative ? kCFCompareLessThan : kCFCompareGreaterThan; + } + if (a->digits[i] > b->digits[i]) { + return negative ? kCFCompareLessThan : kCFCompareGreaterThan; + } + } + return kCFCompareEqualTo; + } + return (a->sign < b->sign) ? kCFCompareLessThan : kCFCompareGreaterThan; +} + +// abs(a) < abs(b) +// do not care about the sign +static Boolean _CFBigNumAbsoluteLessThan(const _CFBigNum *a, const _CFBigNum *b) { + for (CFIndex i = sizeof(a->digits) / sizeof(a->digits[0]); i--;) { + if (a->digits[i] < b->digits[i]) { + return true; + } + if (a->digits[i] > b->digits[i]) { + return false; + } + } + return false; +} + +// r = a * -1 +void _CFBigNumNeg(_CFBigNum *r, const _CFBigNum *a) { + memmove(r, a, sizeof(*a)); + Boolean aIsZero = true; + for (CFIndex i = 0; i < sizeof(a->digits) / sizeof(a->digits[0]); i++) { + if (a->digits[i] != 0) { + aIsZero = false; + break; + } + } + // if a is zero, we do not flip the sign + if (!aIsZero) { + // 0 -> -1 + // -1 -> 0 + r->sign = r->sign * r->sign - 1; + } +} + +uint8_t _CFBigNumAdd(_CFBigNum *r, const _CFBigNum *a, const _CFBigNum *b) { + uint8_t carry = 0; + Boolean sameSign = a->sign == b->sign; + if (sameSign) { + for (CFIndex i = 0; i < sizeof(a->digits) / sizeof(a->digits[0]); i++) { + uint32_t result = a->digits[i] + b->digits[i] + carry; + if (result > BIG_DIGITS_LIMIT) { + carry = 1; + result -= BIG_DIGITS_LIMIT; + } else { + carry = 0; + } + r->digits[i] = result; + } + r->sign = a->sign; + return carry; + } else { + // the algorithm here is to find the larger one and do the subtraction and then neg the result if necessary + const _CFBigNum *bigNum = NULL; + const _CFBigNum *smallNum = NULL; + if (_CFBigNumAbsoluteLessThan(a, b)) { + bigNum = b; + smallNum = a; + } else { + bigNum = a; + smallNum = b; + } + for (int i = 0; i < sizeof(a->digits) / sizeof(a->digits[0]); i++) { + int64_t result = (int64_t)bigNum->digits[i] - (int64_t)smallNum->digits[i] - carry; + if (result < 0) { + carry = 1; + result += BIG_DIGITS_LIMIT; + } else { + carry = 0; + } + r->digits[i] = result; + } + if (bigNum->sign < 0) { + r->sign = -1; + } else { + r->sign = 0; + } + return carry; + } +} + +uint8_t _CFBigNumSub(_CFBigNum *r, const _CFBigNum *a, const _CFBigNum *b) { + _CFBigNum nb; + _CFBigNumNeg(&nb, b); + return _CFBigNumAdd(r, a, &nb); +} + + +void _CFBigNumToCString(const _CFBigNum *vp, Boolean leading_zeros, Boolean leading_plus, char *buffer, size_t buflen) { + if (vp->sign < 0) { + *buffer++ = '-'; + buflen--; + } else if (leading_plus) { + *buffer++ = '+'; + buflen--; + } + char tmp[46]; + snprintf(tmp, sizeof(tmp), "%09u%09u%09u%09u%09u", vp->digits[4], vp->digits[3], vp->digits[2], vp->digits[1], vp->digits[0]); + if (leading_zeros) { + memset(buffer, '0', buflen); + uint32_t tocopy = __CFMin(sizeof(tmp), buflen); + memmove(buffer + buflen - tocopy, tmp + sizeof(tmp) - tocopy, tocopy); // copies trailing nul from tmp to nul-terminate + } else { + char *s = tmp; + while (*s == '0') s++; + if (*s == 0) s--; // if tmp is all zeros, copy out at least one zero + strlcpy(buffer, s, buflen); + } +} + +void _CFBigNumFromCString(_CFBigNum *r, const char *string) { + memset(r, 0, sizeof(*r)); + char *copy = (char *)calloc(strlen(string)+1, sizeof(char)); + memcpy(copy, string, strlen(string)+1); + char *working = copy; + if (*working == '-') { + r->sign = -1; + working++; + } else if (*working == '+') { + working++; + } + while (*working == '0') { + working++; + } + + size_t length = strlen(working); + if (length == 0) { // the number is zero + return; + } + int curDigit = 0; + while (curDigit + 1 < sizeof(r->digits) / sizeof(r->digits[0]) && 9 < length) { + uint32_t digit = atol(working+length-9); + r->digits[curDigit] = digit; + *(working+length-9) = 0; + length -= 9; + curDigit++; + } + uint32_t digit = atol(working); + r->digits[curDigit] = digit; + free(copy); +} + +char *_CFBigNumCopyDescription(const _CFBigNum *num) { + char *result = (char *)calloc(1024, sizeof(char)); + sprintf(result, "sign:%s 1st:%u 2nd:%u 3rd:%u 4th:%u 5th:%u", num->sign < 0 ? "-" : "+", num->digits[0], num->digits[1], num->digits[2], num->digits[3], num->digits[4]); + return result; +} + diff --git a/CFBigNumber.h b/CFBigNumber.h new file mode 100644 index 0000000..7fc0a89 --- /dev/null +++ b/CFBigNumber.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2012 Apple 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@ + */ + +/* CFBigNumber.h + Copyright (c) 2012-2012, Apple Inc. All rights reserved. +*/ + +#if !defined(__COREFOUNDATION_CFBIGNUMBER__) +#define __COREFOUNDATION_CFBIGNUMBER__ 1 + +#include +#include + + +// Base 1 billion number: each digit represents 0 to 999999999 +typedef struct { + uint32_t digits[5]; + int32_t sign:8; + uint32_t __:24; +} _CFBigNum; + +void _CFBigNumInitWithInt8(_CFBigNum *r, int8_t inNum); +void _CFBigNumInitWithInt16(_CFBigNum *r, int16_t inNum); +void _CFBigNumInitWithInt32(_CFBigNum *r, int32_t inNum); +void _CFBigNumInitWithInt64(_CFBigNum *r, int64_t inNum); +#ifdef __LP64__ +void _CFBigNumInitWithInt128(_CFBigNum *r, __int128_t inNum); +#endif + +void _CFBigNumInitWithUInt8(_CFBigNum *r, uint8_t inNum); +void _CFBigNumInitWithUInt16(_CFBigNum *r, uint16_t inNum); +void _CFBigNumInitWithUInt32(_CFBigNum *r, uint32_t inNum); +void _CFBigNumInitWithUInt64(_CFBigNum *r, uint64_t inNum); +#ifdef __LP64__ +void _CFBigNumInitWithUInt128(_CFBigNum *r, __uint128_t inNum); +#endif + +int8_t _CFBigNumGetInt8(const _CFBigNum *num); +int16_t _CFBigNumGetInt16(const _CFBigNum *num); +int32_t _CFBigNumGetInt32(const _CFBigNum *num); +int64_t _CFBigNumGetInt64(const _CFBigNum *num); +#ifdef __LP64__ +__int128_t _CFBigNumGetInt128(const _CFBigNum *num); +#endif + +uint8_t _CFBigNumGetUInt8(const _CFBigNum *num); +uint16_t _CFBigNumGetUInt16(const _CFBigNum *num); +uint32_t _CFBigNumGetUInt32(const _CFBigNum *num); +uint64_t _CFBigNumGetUInt64(const _CFBigNum *num); +#ifdef __LP64__ +__uint128_t _CFBigNumGetUInt128(const _CFBigNum *num); +#endif + +void _CFBigNumInitWithCFNumber(_CFBigNum *r, CFNumberRef input); +void _CFBigNumInitWithBytes(_CFBigNum *r, const void *bytes, CFNumberType type); +CFNumberRef _CFNumberCreateWithBigNum(const _CFBigNum *input); + + +CFComparisonResult _CFBigNumCompare(const _CFBigNum *a, const _CFBigNum *b); + +void _CFBigNumNeg(_CFBigNum *r, const _CFBigNum *a); +uint8_t _CFBigNumAdd(_CFBigNum *r, const _CFBigNum *a, const _CFBigNum *b); +uint8_t _CFBigNumSub(_CFBigNum *r, const _CFBigNum *a, const _CFBigNum *b); + + +void _CFBigNumToCString(const _CFBigNum *vp, Boolean leading_zeros, Boolean leading_plus, char *buffer, size_t buflen); +void _CFBigNumFromCString(_CFBigNum *r, const char *string); + +char *_CFBigNumCopyDescription(const _CFBigNum *num); // caller must free() returned ptr + + +#endif /* ! __COREFOUNDATION_CFBIGNUMBER__ */ + diff --git a/CFBinaryHeap.c b/CFBinaryHeap.c index 77bf232..f711b8f 100644 --- a/CFBinaryHeap.c +++ b/CFBinaryHeap.c @@ -22,7 +22,7 @@ */ /* CFBinaryHeap.c - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ diff --git a/CFBinaryHeap.h b/CFBinaryHeap.h index 8d3ab23..da94e9a 100644 --- a/CFBinaryHeap.h +++ b/CFBinaryHeap.h @@ -22,7 +22,7 @@ */ /* CFBinaryHeap.h - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. */ /*! @header CFBinaryHeap @@ -36,6 +36,7 @@ #include +CF_IMPLICIT_BRIDGING_ENABLED CF_EXTERN_C_BEGIN typedef struct { @@ -305,6 +306,7 @@ CF_EXPORT void CFBinaryHeapRemoveMinimumValue(CFBinaryHeapRef heap); CF_EXPORT void CFBinaryHeapRemoveAllValues(CFBinaryHeapRef heap); CF_EXTERN_C_END +CF_IMPLICIT_BRIDGING_DISABLED #endif /* ! __COREFOUNDATION_CFBINARYHEAP__ */ diff --git a/CFBinaryPList.c b/CFBinaryPList.c index 36742ea..ed1a854 100644 --- a/CFBinaryPList.c +++ b/CFBinaryPList.c @@ -22,7 +22,7 @@ */ /* CFBinaryPList.c - Copyright (c) 2000-2011, Apple Inc. All rights reserved. + Copyright (c) 2000-2012, Apple Inc. All rights reserved. Responsibility: Tony Parker */ @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -55,9 +56,6 @@ enum { kCFNumberSInt128Type = 17 }; -CF_EXPORT CFNumberType _CFNumberGetType2(CFNumberRef number); -__private_extern__ CFErrorRef __CFPropertyListCreateError(CFIndex code, CFStringRef debugString, ...); - enum { CF_NO_ERROR = 0, CF_OVERFLOW_ERROR = (1 << 0), @@ -98,6 +96,8 @@ CF_INLINE uint64_t __check_uint64_mul_unsigned_unsigned(uint64_t x, uint64_t y, #define check_size_t_mul(b, a, err) (size_t)__check_uint32_mul_unsigned_unsigned((size_t)b, (size_t)a, err) #endif +#pragma mark - +#pragma mark Keyed Archiver UID struct __CFKeyedArchiverUID { CFRuntimeBase _base; @@ -151,6 +151,10 @@ uint32_t _CFKeyedArchiverUIDGetValue(CFKeyedArchiverUIDRef uid) { return uid->_value; } +#pragma mark - +#pragma mark Writing + +__private_extern__ CFErrorRef __CFPropertyListCreateError(CFIndex code, CFStringRef debugString, ...); typedef struct { CFTypeRef stream; @@ -217,17 +221,23 @@ static void bufferFlush(__CFBinaryPlistWriteBuffer *buf) { HEADER magic number ("bplist") file format version + byte length of plist incl. header, an encoded int number object (as below) [v.2+ only] + 32-bit CRC (ISO/IEC 8802-3:1989) of plist bytes w/o CRC, encoded always as + "0x12 0x__ 0x__ 0x__ 0x__", big-endian, may be 0 to indicate no CRC [v.2+ only] OBJECT TABLE variable-sized objects Object Formats (marker byte followed by additional info in some cases) - null 0000 0000 + null 0000 0000 // null object [v1+ only] bool 0000 1000 // false bool 0000 1001 // true + url 0000 1100 string // URL with no base URL, recursive encoding of URL string [v1+ only] + url 0000 1101 base string // URL with base URL, recursive encoding of base URL, then recursive encoding of URL string [v1+ only] + uuid 0000 1110 // 16-byte UUID [v1+ only] 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 + int 0001 0nnn ... // # of bytes is 2^nnn, big-endian bytes + real 0010 0nnn ... // # of bytes is 2^nnn, 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 @@ -236,8 +246,8 @@ OBJECT TABLE 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 - set 1100 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows + ordset 1011 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows [v1+ only] + set 1100 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows [v1+ only] dict 1101 nnnn [int] keyref* objref* // nnnn is count, unless '1111', then int count follows 1110 xxxx // unused 1111 xxxx // unused @@ -254,11 +264,17 @@ TRAILER element # in offset table which is top level object offset table offset +Version 1.5 binary plists do not use object references (uid), +but instead inline the object serialization itself at that point. +It also doesn't use an offset table or a trailer. It does have +an extended header, and the top-level object follows the header. + */ static CFTypeID stringtype = -1, datatype = -1, numbertype = -1, datetype = -1; -static CFTypeID booltype = -1, nulltype = -1, dicttype = -1, arraytype = -1, settype = -1; +static CFTypeID booltype = -1, nulltype = -1, dicttype = -1, arraytype = -1; +static CFTypeID uuidtype = -1, urltype = -1, osettype = -1, settype = -1; static void initStatics() { if ((CFTypeID)-1 == stringtype) { @@ -288,6 +304,15 @@ static void initStatics() { if ((CFTypeID)-1 == nulltype) { nulltype = CFNullGetTypeID(); } + if ((CFTypeID)-1 == uuidtype) { + uuidtype = CFUUIDGetTypeID(); + } + if ((CFTypeID)-1 == urltype) { + urltype = CFURLGetTypeID(); + } + if ((CFTypeID)-1 == osettype) { + osettype = -1; + } } static void _appendInt(__CFBinaryPlistWriteBuffer *buf, uint64_t bigint) { @@ -334,6 +359,228 @@ static void _appendUID(__CFBinaryPlistWriteBuffer *buf, CFKeyedArchiverUIDRef ui bufferWrite(buf, bytes, nbytes); } +static void _appendString(__CFBinaryPlistWriteBuffer *buf, CFStringRef str) { + CFIndex ret, count = CFStringGetLength(str); + CFIndex needed, idx2; + uint8_t *bytes, buffer[1024]; + bytes = (count <= 1024) ? buffer : (uint8_t *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, 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(str, CFRangeMake(0, count), kCFStringEncodingASCII, 0, false, bytes, count, &needed); + if (ret == count) { + uint8_t marker = (uint8_t)(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 = (uint8_t)(kCFBinaryPlistMarkerUnicode16String | (count < 15 ? count : 0xf)); + bufferWrite(buf, &marker, 1); + if (15 <= count) { + _appendInt(buf, (uint64_t)count); + } + chars = (UniChar *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, count * sizeof(UniChar), 0); + CFStringGetCharacters(str, CFRangeMake(0, count), chars); + for (idx2 = 0; idx2 < count; idx2++) { + chars[idx2] = CFSwapInt16HostToBig(chars[idx2]); + } + bufferWrite(buf, (uint8_t *)chars, count * sizeof(UniChar)); + CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, chars); + } + if (bytes != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, bytes); +} + +CF_EXPORT CFNumberType _CFNumberGetType2(CFNumberRef number); + +static void _appendNumber(__CFBinaryPlistWriteBuffer *buf, CFNumberRef num) { + uint8_t marker; + uint64_t bigint; + uint8_t *bytes; + CFIndex nbytes; + if (CFNumberIsFloatType(num)) { + CFSwappedFloat64 swapped64; + CFSwappedFloat32 swapped32; + if (CFNumberGetByteSize(num) <= (CFIndex)sizeof(float)) { + float v; + CFNumberGetValue(num, kCFNumberFloat32Type, &v); + swapped32 = CFConvertFloat32HostToSwapped(v); + bytes = (uint8_t *)&swapped32; + nbytes = sizeof(float); + marker = kCFBinaryPlistMarkerReal | 2; + } else { + double v; + CFNumberGetValue(num, kCFNumberFloat64Type, &v); + swapped64 = CFConvertFloat64HostToSwapped(v); + bytes = (uint8_t *)&swapped64; + nbytes = sizeof(double); + marker = kCFBinaryPlistMarkerReal | 3; + } + bufferWrite(buf, &marker, 1); + bufferWrite(buf, bytes, nbytes); + } else { + CFNumberType type = _CFNumberGetType2(num); + if (kCFNumberSInt128Type == type) { + CFSInt128Struct s; + CFNumberGetValue(num, kCFNumberSInt128Type, &s); + struct { + int64_t high; + uint64_t low; + } storage; + storage.high = CFSwapInt64HostToBig(s.high); + storage.low = CFSwapInt64HostToBig(s.low); + uint8_t *bytes = (uint8_t *)&storage; + uint8_t marker = kCFBinaryPlistMarkerInt | 4; + CFIndex nbytes = 16; + bufferWrite(buf, &marker, 1); + bufferWrite(buf, bytes, nbytes); + } else { + CFNumberGetValue(num, kCFNumberSInt64Type, &bigint); + _appendInt(buf, bigint); + } + } +} + +// 0 == objRefSize means version 1.5, else version 0.0 or 0.1 +static Boolean _appendObject(__CFBinaryPlistWriteBuffer *buf, CFTypeRef obj, CFDictionaryRef objtable, uint32_t objRefSize) { + uint64_t refnum; + CFIndex idx2; + CFTypeID type = CFGetTypeID(obj); + if (stringtype == type) { + _appendString(buf, (CFStringRef)obj); + } else if (numbertype == type) { + _appendNumber(buf, (CFNumberRef)obj); + } else if (booltype == type) { + uint8_t marker = CFBooleanGetValue((CFBooleanRef)obj) ? kCFBinaryPlistMarkerTrue : kCFBinaryPlistMarkerFalse; + bufferWrite(buf, &marker, 1); + } else if (0 == objRefSize && nulltype == type) { + uint8_t marker = 0x00; + bufferWrite(buf, &marker, 1); + } else if (datatype == type) { + CFIndex count = CFDataGetLength((CFDataRef)obj); + uint8_t marker = (uint8_t)(kCFBinaryPlistMarkerData | (count < 15 ? count : 0xf)); + bufferWrite(buf, &marker, 1); + if (15 <= count) { + _appendInt(buf, (uint64_t)count); + } + bufferWrite(buf, CFDataGetBytePtr((CFDataRef)obj), count); + } else if (datetype == type) { + CFSwappedFloat64 swapped; + uint8_t marker = kCFBinaryPlistMarkerDate; + bufferWrite(buf, &marker, 1); + swapped = CFConvertFloat64HostToSwapped(CFDateGetAbsoluteTime((CFDateRef)obj)); + bufferWrite(buf, (uint8_t *)&swapped, sizeof(swapped)); + } else if (dicttype == type) { + CFIndex count = CFDictionaryGetCount((CFDictionaryRef)obj); + uint8_t marker = (uint8_t)(kCFBinaryPlistMarkerDict | (count < 15 ? count : 0xf)); + bufferWrite(buf, &marker, 1); + if (15 <= count) { + _appendInt(buf, (uint64_t)count); + } + CFPropertyListRef *list, buffer[512]; + list = (count <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, 2 * count * sizeof(CFTypeRef), __kCFAllocatorGCScannedMemory); + CFDictionaryGetKeysAndValues((CFDictionaryRef)obj, list, list + count); + for (idx2 = 0; idx2 < 2 * count; idx2++) { + CFPropertyListRef value = list[idx2]; + if (objtable) { + uint32_t swapped = 0; + uint8_t *source = (uint8_t *)&swapped; + refnum = (uint32_t)(uintptr_t)CFDictionaryGetValue(objtable, value); + swapped = CFSwapInt32HostToBig((uint32_t)refnum); + bufferWrite(buf, source + sizeof(swapped) - objRefSize, objRefSize); + } else { + Boolean ret = _appendObject(buf, value, objtable, objRefSize); + if (!ret) { + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); + return false; + } + } + } + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); + } else if (arraytype == type) { + CFIndex count = CFArrayGetCount((CFArrayRef)obj); + CFPropertyListRef *list, buffer[256]; + uint8_t marker = (uint8_t)(kCFBinaryPlistMarkerArray | (count < 15 ? count : 0xf)); + bufferWrite(buf, &marker, 1); + if (15 <= count) { + _appendInt(buf, (uint64_t)count); + } + list = (count <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, count * sizeof(CFTypeRef), __kCFAllocatorGCScannedMemory); + CFArrayGetValues((CFArrayRef)obj, CFRangeMake(0, count), list); + for (idx2 = 0; idx2 < count; idx2++) { + CFPropertyListRef value = list[idx2]; + if (objtable) { + uint32_t swapped = 0; + uint8_t *source = (uint8_t *)&swapped; + refnum = (uint32_t)(uintptr_t)CFDictionaryGetValue(objtable, value); + swapped = CFSwapInt32HostToBig((uint32_t)refnum); + bufferWrite(buf, source + sizeof(swapped) - objRefSize, objRefSize); + } else { + Boolean ret = _appendObject(buf, value, objtable, objRefSize); + if (!ret) { + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); + return false; + } + } + } + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); + } else if (0 == objRefSize && settype == type) { + CFIndex count = CFSetGetCount((CFSetRef)obj); + CFPropertyListRef *list, buffer[256]; + uint8_t marker = (uint8_t)(0xc0 | (count < 15 ? count : 0xf)); + bufferWrite(buf, &marker, 1); + if (15 <= count) { + _appendInt(buf, (uint64_t)count); + } + list = (count <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, count * sizeof(CFTypeRef), __kCFAllocatorGCScannedMemory); + CFSetGetValues((CFSetRef)obj, list); + for (idx2 = 0; idx2 < count; idx2++) { + CFPropertyListRef value = list[idx2]; + if (objtable) { + uint32_t swapped = 0; + uint8_t *source = (uint8_t *)&swapped; + refnum = (uint32_t)(uintptr_t)CFDictionaryGetValue(objtable, value); + swapped = CFSwapInt32HostToBig((uint32_t)refnum); + bufferWrite(buf, source + sizeof(swapped) - objRefSize, objRefSize); + } else { + Boolean ret = _appendObject(buf, value, objtable, objRefSize); + if (!ret) { + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); + return false; + } + } + } + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); + } else if (0 == objRefSize && osettype == type) { + // Not actually implemented + } else if (0 == objRefSize && uuidtype == type) { + uint8_t marker = (uint8_t)(0x0e); + bufferWrite(buf, &marker, 1); + { + CFUUIDBytes uu = CFUUIDGetUUIDBytes((CFUUIDRef)obj); + bufferWrite(buf, (const uint8_t *)&uu, 16); + } + } else if (0 == objRefSize && urltype == type) { + CFStringRef string = CFURLGetString((CFURLRef)obj); + if (!string) { + return false; + } + CFURLRef base = CFURLGetBaseURL((CFURLRef)obj); + uint8_t marker = (uint8_t)(0x00 | (base ? 0xd : 0xc)); + bufferWrite(buf, &marker, 1); + if (base) { + _appendObject(buf, base, objtable, objRefSize); + } + _appendObject(buf, string, objtable, objRefSize); + } else if (0 != objRefSize && _CFKeyedArchiverUIDGetTypeID() == type) { + _appendUID(buf, (CFKeyedArchiverUIDRef)obj); + } else { + return false; + } + return true; +} + static void _flattenPlist(CFPropertyListRef plist, CFMutableArrayRef objlist, CFMutableDictionaryRef objtable, CFMutableSetRef uniquingset) { CFPropertyListRef unique; uint32_t refnum; @@ -384,33 +631,31 @@ static void _flattenPlist(CFPropertyListRef plist, CFMutableArrayRef objlist, CF CF_INLINE uint8_t _byteCount(uint64_t count) { uint64_t mask = ~(uint64_t)0; uint8_t size = 0; - + // Find something big enough to hold 'count' while (count & mask) { size++; mask = mask << 8; } - + // Ensure that 'count' is a power of 2 // For sizes bigger than 8, just use the required count while ((size != 1 && size != 2 && size != 4 && size != 8) && size <= 8) { size++; } - + return size; } - // stream can be a CFWriteStreamRef (on supported platforms) or a CFMutableDataRef /* Write a property list to a stream, in binary format. plist is the property list to write (one of the basic property list types), stream is the destination of the property list, and estimate is a best-guess at the total number of objects in the property list. The estimate parameter is for efficiency in pre-allocating memory for the uniquing step. Pass in a 0 if no estimate is available. The options flag specifies sort options. If the error parameter is non-NULL and an error occurs, it will be used to return a CFError explaining the problem. It is the callers responsibility to release the error. */ CFIndex __CFBinaryPlistWrite(CFPropertyListRef plist, CFTypeRef stream, uint64_t estimate, CFOptionFlags options, CFErrorRef *error) { - CFMutableDictionaryRef objtable; - CFMutableArrayRef objlist; - CFMutableSetRef uniquingset; + CFMutableDictionaryRef objtable = NULL; + CFMutableArrayRef objlist = NULL; + CFMutableSetRef uniquingset = NULL; CFBinaryPlistTrailer trailer; uint64_t *offsets, length_so_far; - uint64_t refnum; - int64_t idx, idx2, cnt; + int64_t idx, cnt; __CFBinaryPlistWriteBuffer *buf; initStatics(); @@ -451,147 +696,10 @@ CFIndex __CFBinaryPlistWrite(CFPropertyListRef plist, CFTypeRef stream, uint64_t trailer._topObject = 0; // true for this implementation trailer._objectRefSize = _byteCount(cnt); for (idx = 0; idx < cnt; idx++) { - CFPropertyListRef obj = CFArrayGetValueAtIndex(objlist, (CFIndex)idx); - CFTypeID type = CFGetTypeID(obj); offsets[idx] = buf->written + buf->used; - if (stringtype == type) { - CFIndex ret, count = CFStringGetLength((CFStringRef)obj); - CFIndex needed; - uint8_t *bytes, buffer[1024]; - bytes = (count <= 1024) ? buffer : (uint8_t *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, 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((CFStringRef)obj, CFRangeMake(0, count), kCFStringEncodingASCII, 0, false, bytes, count, &needed); - if (ret == count) { - uint8_t marker = (uint8_t)(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 = (uint8_t)(kCFBinaryPlistMarkerUnicode16String | (count < 15 ? count : 0xf)); - bufferWrite(buf, &marker, 1); - if (15 <= count) { - _appendInt(buf, (uint64_t)count); - } - chars = (UniChar *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, count * sizeof(UniChar), 0); - CFStringGetCharacters((CFStringRef)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(kCFAllocatorSystemDefaultGCRefZero, chars); - } - if (bytes != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, bytes); - } else if (numbertype == type) { - uint8_t marker; - uint64_t bigint; - uint8_t *bytes; - CFIndex nbytes; - if (CFNumberIsFloatType((CFNumberRef)obj)) { - CFSwappedFloat64 swapped64; - CFSwappedFloat32 swapped32; - if (CFNumberGetByteSize((CFNumberRef)obj) <= (CFIndex)sizeof(float)) { - float v; - CFNumberGetValue((CFNumberRef)obj, kCFNumberFloat32Type, &v); - swapped32 = CFConvertFloat32HostToSwapped(v); - bytes = (uint8_t *)&swapped32; - nbytes = sizeof(float); - marker = kCFBinaryPlistMarkerReal | 2; - } else { - double v; - CFNumberGetValue((CFNumberRef)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 { - CFNumberType type = _CFNumberGetType2((CFNumberRef)obj); - if (kCFNumberSInt128Type == type) { - CFSInt128Struct s; - CFNumberGetValue((CFNumberRef)obj, kCFNumberSInt128Type, &s); - struct { - int64_t high; - uint64_t low; - } storage; - storage.high = CFSwapInt64HostToBig(s.high); - storage.low = CFSwapInt64HostToBig(s.low); - uint8_t *bytes = (uint8_t *)&storage; - uint8_t marker = kCFBinaryPlistMarkerInt | 4; - CFIndex nbytes = 16; - bufferWrite(buf, &marker, 1); - bufferWrite(buf, bytes, nbytes); - } else { - CFNumberGetValue((CFNumberRef)obj, kCFNumberSInt64Type, &bigint); - _appendInt(buf, bigint); - } - } - } else if (_CFKeyedArchiverUIDGetTypeID() == type) { - _appendUID(buf, (CFKeyedArchiverUIDRef)obj); - } else if (booltype == type) { - uint8_t marker = CFBooleanGetValue((CFBooleanRef)obj) ? kCFBinaryPlistMarkerTrue : kCFBinaryPlistMarkerFalse; - bufferWrite(buf, &marker, 1); - } else if (datatype == type) { - CFIndex count = CFDataGetLength((CFDataRef)obj); - uint8_t marker = (uint8_t)(kCFBinaryPlistMarkerData | (count < 15 ? count : 0xf)); - bufferWrite(buf, &marker, 1); - if (15 <= count) { - _appendInt(buf, (uint64_t)count); - } - bufferWrite(buf, CFDataGetBytePtr((CFDataRef)obj), count); - } else if (datetype == type) { - CFSwappedFloat64 swapped; - uint8_t marker = kCFBinaryPlistMarkerDate; - bufferWrite(buf, &marker, 1); - swapped = CFConvertFloat64HostToSwapped(CFDateGetAbsoluteTime((CFDateRef)obj)); - bufferWrite(buf, (uint8_t *)&swapped, sizeof(swapped)); - } else if (dicttype == type) { - CFIndex count = CFDictionaryGetCount((CFDictionaryRef)obj); - - uint8_t marker = (uint8_t)(kCFBinaryPlistMarkerDict | (count < 15 ? count : 0xf)); - bufferWrite(buf, &marker, 1); - if (15 <= count) { - _appendInt(buf, (uint64_t)count); - } - - CFPropertyListRef *list, buffer[512]; - - list = (count <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, 2 * count * sizeof(CFTypeRef), __kCFAllocatorGCScannedMemory); - CFDictionaryGetKeysAndValues((CFDictionaryRef)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)(uintptr_t)CFDictionaryGetValue(objtable, value); - swapped = CFSwapInt32HostToBig((uint32_t)refnum); - bufferWrite(buf, source + sizeof(swapped) - trailer._objectRefSize, trailer._objectRefSize); - } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); - } else if (arraytype == type) { - CFIndex count = CFArrayGetCount((CFArrayRef)obj); - CFPropertyListRef *list, buffer[256]; - uint8_t marker = (uint8_t)(kCFBinaryPlistMarkerArray | (count < 15 ? count : 0xf)); - bufferWrite(buf, &marker, 1); - if (15 <= count) { - _appendInt(buf, (uint64_t)count); - } - list = (count <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, count * sizeof(CFTypeRef), __kCFAllocatorGCScannedMemory); - CFArrayGetValues((CFArrayRef)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)(uintptr_t)CFDictionaryGetValue(objtable, value); - swapped = CFSwapInt32HostToBig((uint32_t)refnum); - bufferWrite(buf, source + sizeof(swapped) - trailer._objectRefSize, trailer._objectRefSize); - } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); - } else { + CFPropertyListRef obj = CFArrayGetValueAtIndex(objlist, (CFIndex)idx); + Boolean success = _appendObject(buf, obj, objtable, trailer._objectRefSize); + if (!success) { CFRelease(objtable); CFRelease(objlist); if (error && buf->error) { @@ -653,9 +761,52 @@ CFIndex __CFBinaryPlistWriteToStreamWithOptions(CFPropertyListRef plist, CFTypeR return __CFBinaryPlistWrite(plist, stream, estimate, options, NULL); } +// Write a version 1.5 plist to the data; extra objects + inlined objects (no references, no uniquing) +__private_extern__ Boolean __CFBinaryPlistWrite15(CFPropertyListRef plist, CFMutableDataRef data, CFErrorRef *error) { + initStatics(); + + __CFBinaryPlistWriteBuffer *buf = (__CFBinaryPlistWriteBuffer *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFBinaryPlistWriteBuffer), 0); + memset(buf, 0, sizeof(__CFBinaryPlistWriteBuffer)); + buf->stream = data; + buf->error = NULL; + buf->streamIsData = 1; + buf->written = 0; + buf->used = 0; + + bufferWrite(buf, (uint8_t *)"bplist15", 8); // header + bufferWrite(buf, (uint8_t *)"\023\000\000\000\000\000\000\000\000", 9); // header (byte length) + bufferWrite(buf, (uint8_t *)"\022\000\000\000\000", 5); // header (crc) + + Boolean success = _appendObject(buf, plist, NULL, 0); + if (!success) { + if (error && buf->error) { + // caller will release error + *error = buf->error; + } else if (buf->error) { + // caller is not interested in error, release it here + CFRelease(buf->error); + } + CFAllocatorDeallocate(kCFAllocatorSystemDefault, buf); + return false; + } + bufferFlush(buf); + + uint64_t swapped_len = CFSwapInt64HostToBig(buf->written); + CFDataReplaceBytes(data, CFRangeMake(9, 8), (uint8_t *)&swapped_len, (CFIndex)sizeof(swapped_len)); + + CFAllocatorDeallocate(kCFAllocatorSystemDefault, buf); + return true; +} + + +#pragma mark - +#pragma mark Reading + #define FAIL_FALSE do { return false; } while (0) #define FAIL_MAXOFFSET do { return UINT64_MAX; } while (0) +__private_extern__ 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 *plist); + /* Grab a valSize-bytes integer out of the buffer pointed at by data and return it. */ CF_INLINE uint64_t _getSizedInt(const uint8_t *data, uint8_t valSize) { @@ -776,7 +927,7 @@ bool __CFBinaryPlistGetTopLevelInfo(const uint8_t *databytes, uint64_t datalen, CF_INLINE Boolean _plistIsPrimitive(CFPropertyListRef pl) { CFTypeID type = CFGetTypeID(pl); - if (dicttype == type || arraytype == type || settype == type) FAIL_FALSE; + if (dicttype == type || arraytype == type || settype == type || osettype == type) FAIL_FALSE; return true; } @@ -840,11 +991,6 @@ bool __CFBinaryPlistGetOffsetForValueFromArray2(const uint8_t *databytes, uint64 return true; } -// Compatibility method, to be removed soon -CF_EXPORT 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) { - return __CFBinaryPlistGetOffsetForValueFromDictionary3(databytes, datalen, startOffset, trailer, key, koffset, voffset, false, objects); -} - /* Get the offset for a value in a dictionary in a binary property list. @param databytes A pointer to the start of the binary property list data. @param datalen The length of the data. @@ -962,10 +1108,10 @@ bool __CFBinaryPlistGetOffsetForValueFromDictionary3(const uint8_t *databytes, u } } else { // temp object not saved in 'objects', because we don't know what allocator to use - // (what allocator __CFBinaryPlistCreateObject2() or __CFBinaryPlistCreateObject() + // (what allocator __CFBinaryPlistCreateObjectFiltered() or __CFBinaryPlistCreateObject() // will eventually be called with which results in that object) keyInData = NULL; - if (!__CFBinaryPlistCreateObject2(databytes, datalen, off, trailer, kCFAllocatorSystemDefault, kCFPropertyListImmutable, NULL /*objects*/, NULL, 0, &keyInData) || !_plistIsPrimitive(keyInData)) { + if (!__CFBinaryPlistCreateObjectFiltered(databytes, datalen, off, trailer, kCFAllocatorSystemDefault, kCFPropertyListImmutable, NULL /*objects*/, NULL, 0, NULL, &keyInData) || !_plistIsPrimitive(keyInData)) { if (keyInData) CFRelease(keyInData); return false; } @@ -989,8 +1135,9 @@ bool __CFBinaryPlistGetOffsetForValueFromDictionary3(const uint8_t *databytes, u extern CFDictionaryRef __CFDictionaryCreateTransfer(CFAllocatorRef allocator, const void * *klist, const void * *vlist, CFIndex numValues); extern CFSetRef __CFSetCreateTransfer(CFAllocatorRef allocator, const void * *klist, CFIndex numValues); extern CFArrayRef __CFArrayCreateTransfer(CFAllocatorRef allocator, const void * *klist, CFIndex numValues); +__private_extern__ void __CFPropertyListCreateSplitKeypaths(CFAllocatorRef allocator, CFSetRef currentKeys, CFSetRef *theseKeys, CFSetRef *nextKeys); -CF_EXPORT 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) { +__private_extern__ 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 *plist) { if (objects) { *plist = CFDictionaryGetValue(objects, (const void *)(uintptr_t)startOffset); @@ -1236,83 +1383,133 @@ CF_EXPORT bool __CFBinaryPlistCreateObject2(const uint8_t *databytes, uint64_t d 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) { + 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; - cnt = (CFIndex)bigint; + arrayCount = (CFIndex)bigint; } - size_t byte_cnt = check_size_t_mul(cnt, trailer->_objectRefSize, &err); + 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(cnt, sizeof(CFPropertyListRef), &err); + byte_cnt = check_size_t_mul(arrayCount, sizeof(CFPropertyListRef), &err); if (CF_NO_ERROR != err) FAIL_FALSE; - list = (cnt <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, byte_cnt, __kCFAllocatorGCScannedMemory); + list = (arrayCount <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, byte_cnt, __kCFAllocatorGCScannedMemory); if (!list) FAIL_FALSE; Boolean madeSet = false; if (!set && 15 < curDepth) { set = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, NULL); madeSet = set ? true : false; } - if (set) CFSetAddValue(set, (const void *)(uintptr_t)startOffset); - for (CFIndex idx = 0; idx < cnt; idx++) { - CFPropertyListRef pl; - off = _getOffsetOfRefAt(databytes, ptr, trailer); - if (!__CFBinaryPlistCreateObject2(databytes, datalen, off, trailer, allocator, mutabilityOption, objects, set, curDepth + 1, &pl)) { - while (idx--) { - if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); - } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); - FAIL_FALSE; - } - __CFAssignWithWriteBarrier((void **)list + idx, (void *)pl); - ptr += trailer->_objectRefSize; - } - if (set) CFSetRemoveValue(set, (const void *)(uintptr_t)startOffset); - if (madeSet) { - CFRelease(set); - set = NULL; - } - if ((marker & 0xf0) == kCFBinaryPlistMarkerArray) { - if (mutabilityOption != kCFPropertyListImmutable) { - *plist = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks); - CFArrayReplaceValues((CFMutableArrayRef)*plist, CFRangeMake(0, 0), list, cnt); - for (CFIndex idx = 0; idx < cnt; idx++) { - if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); - } - } else { - if (!kCFUseCollectableAllocator) { - *plist = __CFArrayCreateTransfer(allocator, list, cnt); - } else { - *plist = CFArrayCreate(allocator, list, cnt, &kCFTypeArrayCallBacks); - for (CFIndex idx = 0; idx < cnt; idx++) { - if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); + + 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); + + Boolean success = true; + CFMutableArrayRef array = CFArrayCreateMutable(allocator, CFSetGetCount(theseKeys), &kCFTypeArrayCallBacks); + 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]; + 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; + success = __CFBinaryPlistCreateObjectFiltered(databytes, datalen, valueOffset, trailer, allocator, mutabilityOption, objects, set, curDepth + 1, nextKeys, &result); + if (success) { + CFArrayAppendValue(array, result); + CFRelease(result); + } else { + break; + } + } } } - } - } else { - if (mutabilityOption != kCFPropertyListImmutable) { - *plist = CFSetCreateMutable(allocator, 0, &kCFTypeSetCallBacks); - for (CFIndex idx = 0; idx < cnt; idx++) { - CFSetAddValue((CFMutableSetRef)*plist, list[idx]); - } - for (CFIndex idx = 0; idx < cnt; idx++) { - if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); - } - } else { - if (!kCFUseCollectableAllocator) { - *plist = __CFSetCreateTransfer(allocator, list, cnt); + + free(keys); + CFRelease(theseKeys); + } + if (nextKeys) CFRelease(nextKeys); + + if (success) { + if (!(mutabilityOption == kCFPropertyListMutableContainers || mutabilityOption == kCFPropertyListMutableContainersAndLeaves)) { + // make immutable + *plist = CFArrayCreateCopy(allocator, array); + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(array); } else { - *plist = CFSetCreate(allocator, list, cnt, &kCFTypeSetCallBacks); - for (CFIndex idx = 0; idx < cnt; idx++) { + *plist = array; + } + } else if (array) { + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(array); + } + } else { + for (CFIndex idx = 0; idx < arrayCount; idx++) { + CFPropertyListRef pl; + off = _getOffsetOfRefAt(databytes, ptr, trailer); + if (!__CFBinaryPlistCreateObjectFiltered(databytes, datalen, off, trailer, allocator, mutabilityOption, objects, set, curDepth + 1, NULL, &pl)) { + while (idx--) { if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); + } + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); + FAIL_FALSE; + } + __CFAssignWithWriteBarrier((void **)list + idx, (void *)pl); + ptr += trailer->_objectRefSize; + } + if ((marker & 0xf0) == kCFBinaryPlistMarkerArray) { + if (mutabilityOption != kCFPropertyListImmutable) { + *plist = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks); + CFArrayReplaceValues((CFMutableArrayRef)*plist, CFRangeMake(0, 0), list, arrayCount); + for (CFIndex idx = 0; idx < arrayCount; idx++) { + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); + } + } else { + if (!kCFUseCollectableAllocator) { + *plist = __CFArrayCreateTransfer(allocator, list, arrayCount); + } else { + *plist = CFArrayCreate(allocator, list, arrayCount, &kCFTypeArrayCallBacks); + for (CFIndex idx = 0; idx < arrayCount; idx++) { + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); + } } } - } - } + } else { + if (mutabilityOption != kCFPropertyListImmutable) { + *plist = CFSetCreateMutable(allocator, 0, &kCFTypeSetCallBacks); + for (CFIndex idx = 0; idx < arrayCount; idx++) { + CFSetAddValue((CFMutableSetRef)*plist, list[idx]); + } + for (CFIndex idx = 0; idx < arrayCount; idx++) { + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); + } + } else { + if (!kCFUseCollectableAllocator) { + *plist = __CFSetCreateTransfer(allocator, list, arrayCount); + } else { + *plist = CFSetCreate(allocator, list, arrayCount, &kCFTypeSetCallBacks); + for (CFIndex idx = 0; idx < arrayCount; idx++) { + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); + } + } + } + } + } + if (set) CFSetRemoveValue(set, (const void *)(uintptr_t)startOffset); + if (madeSet) { + CFRelease(set); + set = NULL; + } if (objects && *plist && (mutabilityOption == kCFPropertyListImmutable)) { CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist); } @@ -1324,67 +1521,112 @@ CF_EXPORT bool __CFBinaryPlistCreateObject2(const uint8_t *databytes, uint64_t d 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) { + 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; - cnt = (CFIndex)bigint; + dictionaryCount = (CFIndex)bigint; } - cnt = check_size_t_mul(cnt, 2, &err); + dictionaryCount = check_size_t_mul(dictionaryCount, 2, &err); if (CF_NO_ERROR != err) FAIL_FALSE; - size_t byte_cnt = check_size_t_mul(cnt, trailer->_objectRefSize, &err); + 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(cnt, sizeof(CFPropertyListRef), &err); + byte_cnt = check_size_t_mul(dictionaryCount, sizeof(CFPropertyListRef), &err); if (CF_NO_ERROR != err) FAIL_FALSE; - list = (cnt <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, byte_cnt, __kCFAllocatorGCScannedMemory); + list = (dictionaryCount <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, byte_cnt, __kCFAllocatorGCScannedMemory); if (!list) FAIL_FALSE; Boolean madeSet = false; if (!set && 15 < curDepth) { set = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, NULL); madeSet = set ? true : false; } - if (set) CFSetAddValue(set, (const void *)(uintptr_t)startOffset); - for (CFIndex idx = 0; idx < cnt; idx++) { - CFPropertyListRef pl = NULL; - off = _getOffsetOfRefAt(databytes, ptr, trailer); - if (!__CFBinaryPlistCreateObject2(databytes, datalen, off, trailer, allocator, mutabilityOption, objects, set, curDepth + 1, &pl) || (idx < cnt / 2 && !_plistIsPrimitive(pl))) { - if (pl && !_CFAllocatorIsGCRefZero(allocator)) CFRelease(pl); - while (idx--) { + + 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); + + Boolean success = true; + 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; + success = __CFBinaryPlistCreateObjectFiltered(databytes, datalen, valueOffset, trailer, allocator, mutabilityOption, objects, set, curDepth + 1, nextKeys, &result); + if (success) { + CFDictionarySetValue(dict, key, result); + CFRelease(result); + } else { + break; + } + } + } + + free(keys); + CFRelease(theseKeys); + } + if (nextKeys) CFRelease(nextKeys); + + if (success) { + if (!(mutabilityOption == kCFPropertyListMutableContainers || mutabilityOption == kCFPropertyListMutableContainersAndLeaves)) { + // make immutable + *plist = CFDictionaryCreateCopy(allocator, dict); + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(dict); + } else { + *plist = dict; + } + } else if (dict) { + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(dict); + } + } else { + for (CFIndex idx = 0; idx < dictionaryCount; idx++) { + CFPropertyListRef pl = NULL; + off = _getOffsetOfRefAt(databytes, ptr, trailer); + if (!__CFBinaryPlistCreateObjectFiltered(databytes, datalen, off, trailer, allocator, mutabilityOption, objects, set, curDepth + 1, NULL, &pl) || (idx < dictionaryCount / 2 && !_plistIsPrimitive(pl))) { + if (pl && !_CFAllocatorIsGCRefZero(allocator)) CFRelease(pl); + while (idx--) { + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); + } + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); + FAIL_FALSE; + } + __CFAssignWithWriteBarrier((void **)list + idx, (void *)pl); + ptr += trailer->_objectRefSize; + } + if (mutabilityOption != kCFPropertyListImmutable) { + *plist = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + for (CFIndex idx = 0; idx < dictionaryCount / 2; idx++) { + CFDictionaryAddValue((CFMutableDictionaryRef)*plist, list[idx], list[idx + dictionaryCount / 2]); + } + for (CFIndex idx = 0; idx < dictionaryCount; idx++) { if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); - } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); - FAIL_FALSE; - } - __CFAssignWithWriteBarrier((void **)list + idx, (void *)pl); - ptr += trailer->_objectRefSize; - } - if (set) CFSetRemoveValue(set, (const void *)(uintptr_t)startOffset); - if (madeSet) { - CFRelease(set); - set = NULL; - } - if (mutabilityOption != kCFPropertyListImmutable) { - *plist = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - for (CFIndex idx = 0; idx < cnt / 2; idx++) { - CFDictionaryAddValue((CFMutableDictionaryRef)*plist, list[idx], list[idx + cnt / 2]); - } - for (CFIndex idx = 0; idx < cnt; idx++) { - if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); - } - } else { - if (!kCFUseCollectableAllocator) { - *plist = __CFDictionaryCreateTransfer(allocator, list, list + cnt / 2, cnt / 2); + } } else { - *plist = CFDictionaryCreate(allocator, list, list + cnt / 2, cnt / 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - for (CFIndex idx = 0; idx < cnt; idx++) { - if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); - } - } - } + if (!kCFUseCollectableAllocator) { + *plist = __CFDictionaryCreateTransfer(allocator, list, list + dictionaryCount / 2, dictionaryCount / 2); + } else { + *plist = CFDictionaryCreate(allocator, list, list + dictionaryCount / 2, dictionaryCount / 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + for (CFIndex idx = 0; idx < dictionaryCount; idx++) { + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); + } + } + } + } + if (set) CFSetRemoveValue(set, (const void *)(uintptr_t)startOffset); + if (madeSet) { + CFRelease(set); + set = NULL; + } if (objects && *plist && (mutabilityOption == kCFPropertyListImmutable)) { CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist); } @@ -1397,7 +1639,7 @@ CF_EXPORT bool __CFBinaryPlistCreateObject2(const uint8_t *databytes, uint64_t d bool __CFBinaryPlistCreateObject(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFAllocatorRef allocator, CFOptionFlags mutabilityOption, CFMutableDictionaryRef objects, CFPropertyListRef *plist) { // for compatibility with Foundation's use, need to leave this here - return __CFBinaryPlistCreateObject2(databytes, datalen, startOffset, trailer, allocator, mutabilityOption, objects, NULL, 0, plist); + return __CFBinaryPlistCreateObjectFiltered(databytes, datalen, startOffset, trailer, allocator, mutabilityOption, objects, NULL, 0, NULL, plist); } __private_extern__ bool __CFTryParseBinaryPlist(CFAllocatorRef allocator, CFDataRef data, CFOptionFlags option, CFPropertyListRef *plist, CFStringRef *errorString) { @@ -1417,14 +1659,282 @@ __private_extern__ bool __CFTryParseBinaryPlist(CFAllocatorRef allocator, CFData CFMutableDictionaryRef objects = CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero, 0, NULL, &kCFTypeDictionaryValueCallBacks); _CFDictionarySetCapacity(objects, trailer._numObjects); CFPropertyListRef pl = NULL; - if (__CFBinaryPlistCreateObject2(databytes, datalen, offset, &trailer, allocator, option, objects, NULL, 0, &pl)) { + bool result = true; + if (__CFBinaryPlistCreateObjectFiltered(databytes, datalen, offset, &trailer, allocator, option, objects, NULL, 0, NULL, &pl)) { if (plist) *plist = pl; } else { if (plist) *plist = NULL; if (errorString) *errorString = (CFStringRef)CFRetain(CFSTR("binary data is corrupt")); + result = false; } if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(objects); - return true; + return result; } return false; } + + +static CFPropertyListRef __CFBinaryPlistCreateObject15(const uint8_t *databytes, uint64_t datalen, const uint8_t **ptr) { + const uint8_t *objectsRangeStart = databytes + 22, *objectsRangeEnd = databytes + datalen - 1; + if (*ptr < objectsRangeStart || objectsRangeEnd < *ptr) return NULL; + uint8_t marker = **ptr; + int32_t err = CF_NO_ERROR; + *ptr = check_ptr_add(*ptr, 1, &err); + if (CF_NO_ERROR != err) return NULL; + switch (marker & 0xf0) { + case 0x0: + switch (marker) { + case kCFBinaryPlistMarkerNull: + return kCFNull; + case kCFBinaryPlistMarkerFalse: + return kCFBooleanFalse; + case kCFBinaryPlistMarkerTrue: + return kCFBooleanTrue; + case 0x0c: { + CFStringRef string = (CFStringRef)__CFBinaryPlistCreateObject15(databytes, datalen, ptr); + if (!string) { + return NULL; + } + CFURLRef result = CFURLCreateWithString(kCFAllocatorSystemDefault, string, NULL); + CFRelease(string); + return result; + } + case 0x0d: { + CFURLRef base = (CFURLRef)__CFBinaryPlistCreateObject15(databytes, datalen, ptr); + if (!base) return NULL; + CFStringRef string = (CFStringRef)__CFBinaryPlistCreateObject15(databytes, datalen, ptr); + if (!string) { + CFRelease(base); + return NULL; + } + CFURLRef result = CFURLCreateWithString(kCFAllocatorSystemDefault, string, base); + CFRelease(base); + CFRelease(string); + return result; + } + case 0x0e: { + int32_t err = CF_NO_ERROR; + const uint8_t *extent = check_ptr_add(*ptr, 16, &err) - 1; + if (CF_NO_ERROR != err) return NULL; + if (objectsRangeEnd < extent) return NULL; + CFUUIDBytes uuid; + memmove(&uuid, *ptr, 16); + *ptr = extent + 1; + return CFUUIDCreateFromUUIDBytes(kCFAllocatorSystemDefault, uuid); + } + case 0x0f: + break; + } + return NULL; + case kCFBinaryPlistMarkerInt: { + int32_t err = CF_NO_ERROR; + uint64_t cnt = 1 << (marker & 0x0f); + const uint8_t *extent = check_ptr_add(*ptr, cnt, &err) - 1; + if (CF_NO_ERROR != err) return NULL; + if (objectsRangeEnd < extent) return NULL; + if (16 < cnt) return NULL; + // in format version '15', 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 '15' + // 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); + *ptr = extent + 1; + CFPropertyListRef plist = NULL; + if (8 < cnt) { + CFSInt128Struct val; + val.high = 0; + val.low = bigint; + plist = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt128Type, &val); + } else { + plist = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt64Type, &bigint); + } + return plist; + } + case kCFBinaryPlistMarkerReal: + switch (marker & 0x0f) { + case 2: { + int32_t err = CF_NO_ERROR; + const uint8_t *extent = check_ptr_add(*ptr, 4, &err) - 1; + if (CF_NO_ERROR != err) return NULL; + if (objectsRangeEnd < extent) return NULL; + CFSwappedFloat32 swapped32; + memmove(&swapped32, *ptr, 4); + *ptr = extent + 1; + float f = CFConvertFloat32SwappedToHost(swapped32); + CFPropertyListRef plist = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberFloat32Type, &f); + return plist; + } + case 3: { + int32_t err = CF_NO_ERROR; + const uint8_t *extent = check_ptr_add(*ptr, 8, &err) - 1; + if (CF_NO_ERROR != err) return NULL; + if (objectsRangeEnd < extent) return NULL; + CFSwappedFloat64 swapped64; + memmove(&swapped64, *ptr, 8); + *ptr = extent + 1; + double d = CFConvertFloat64SwappedToHost(swapped64); + CFPropertyListRef plist = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberFloat64Type, &d); + return plist; + } + } + return NULL; + case kCFBinaryPlistMarkerDate & 0xf0: + switch (marker) { + case kCFBinaryPlistMarkerDate: { + int32_t err = CF_NO_ERROR; + const uint8_t *extent = check_ptr_add(*ptr, 8, &err) - 1; + if (CF_NO_ERROR != err) return NULL; + if (objectsRangeEnd < extent) return NULL; + CFSwappedFloat64 swapped64; + memmove(&swapped64, *ptr, 8); + *ptr = extent + 1; + double d = CFConvertFloat64SwappedToHost(swapped64); + CFPropertyListRef plist = CFDateCreate(kCFAllocatorSystemDefault, d); + return plist; + } + } + return NULL; + case kCFBinaryPlistMarkerData: { + int32_t err = CF_NO_ERROR; + CFIndex cnt = marker & 0x0f; + if (0xf == cnt) { + uint64_t bigint = 0; + if (!_readInt(*ptr, objectsRangeEnd, &bigint, ptr)) return NULL; + if (LONG_MAX < bigint) return NULL; + cnt = (CFIndex)bigint; + } + const uint8_t *extent = check_ptr_add(*ptr, cnt, &err) - 1; + if (CF_NO_ERROR != err) return NULL; + if (objectsRangeEnd < extent) return NULL; + CFPropertyListRef plist = CFDataCreate(kCFAllocatorSystemDefault, *ptr, cnt); + *ptr = extent + 1; + return plist; + } + case kCFBinaryPlistMarkerASCIIString: { + int32_t err = CF_NO_ERROR; + CFIndex cnt = marker & 0x0f; + if (0xf == cnt) { + uint64_t bigint = 0; + if (!_readInt(*ptr, objectsRangeEnd, &bigint, ptr)) return NULL; + if (LONG_MAX < bigint) return NULL; + cnt = (CFIndex)bigint; + } + const uint8_t *extent = check_ptr_add(*ptr, cnt, &err) - 1; + if (CF_NO_ERROR != err) return NULL; + if (objectsRangeEnd < extent) return NULL; + CFPropertyListRef plist = CFStringCreateWithBytes(kCFAllocatorSystemDefault, *ptr, cnt, kCFStringEncodingASCII, false); + *ptr = extent + 1; + return plist; + } + case kCFBinaryPlistMarkerUnicode16String: { + int32_t err = CF_NO_ERROR; + CFIndex cnt = marker & 0x0f; + if (0xf == cnt) { + uint64_t bigint = 0; + if (!_readInt(*ptr, objectsRangeEnd, &bigint, ptr)) return NULL; + if (LONG_MAX < bigint) return NULL; + 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) return NULL; + if (objectsRangeEnd < extent) return NULL; + size_t byte_cnt = check_size_t_mul(cnt, sizeof(UniChar), &err); + if (CF_NO_ERROR != err) return NULL; + UniChar *chars = (UniChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, byte_cnt, 0); + if (!chars) return NULL; + memmove(chars, *ptr, byte_cnt); + for (CFIndex idx = 0; idx < cnt; idx++) { + chars[idx] = CFSwapInt16BigToHost(chars[idx]); + } + CFPropertyListRef plist = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, chars, cnt); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, chars); + *ptr = extent + 1; + return plist; + } + case kCFBinaryPlistMarkerArray: + case 0xb0: // ordset + case kCFBinaryPlistMarkerSet: + case kCFBinaryPlistMarkerDict: { + int32_t err = CF_NO_ERROR; + CFIndex cnt = marker & 0x0f; + if (0xf == cnt) { + uint64_t bigint = 0; + if (!_readInt(*ptr, objectsRangeEnd, &bigint, ptr)) return NULL; + if (LONG_MAX < bigint) return NULL; + cnt = (CFIndex)bigint; + } + if ((marker & 0xf0) == kCFBinaryPlistMarkerDict) { + cnt = check_size_t_mul(cnt, 2, &err); + if (CF_NO_ERROR != err) return NULL; + } + size_t byte_cnt = check_size_t_mul(cnt, sizeof(CFPropertyListRef), &err); // check now for a later overflow + if (CF_NO_ERROR != err) return NULL; + CFPropertyListRef *list, buffer[256]; + list = (cnt <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, byte_cnt, 0); + if (!list) return NULL; + + CFMutableArrayRef tmparray = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + for (CFIndex idx = 0; idx < cnt; idx++) { + CFPropertyListRef pl = __CFBinaryPlistCreateObject15(databytes, datalen, ptr); + if (!pl) { + CFRelease(tmparray); + return NULL; + } + if ((marker & 0xf0) == kCFBinaryPlistMarkerDict) { + if (idx < cnt / 2 && !_plistIsPrimitive(pl)) { + CFRelease(pl); + CFRelease(tmparray); + return NULL; + } + } + CFArrayAppendValue(tmparray, pl); +// CFRelease(pl); // don't release pl here, we're going to transfer the retain to the ultimate collection owner + } + CFArrayGetValues(tmparray, CFRangeMake(0, cnt), list); + CFPropertyListRef plist = NULL; + if ((marker & 0xf0) == kCFBinaryPlistMarkerArray) { + plist = __CFArrayCreateTransfer(kCFAllocatorSystemDefault, list, cnt); + } else if ((marker & 0xf0) == 0xb0) { + plist = NULL; // Not actually implemented + // leaks contents of tmparray, but this path shouldn't be exercised anyway + } else if ((marker & 0xf0) == kCFBinaryPlistMarkerSet) { + plist = __CFSetCreateTransfer(kCFAllocatorSystemDefault, list, cnt); + } else { + plist = __CFDictionaryCreateTransfer(kCFAllocatorSystemDefault, list, list + cnt / 2, cnt / 2); + } + CFRelease(tmparray); + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + return plist; + } + default: + break; + } + return NULL; +} + +// *error is currently never set +__private_extern__ CFPropertyListRef __CFBinaryPlistCreate15(CFDataRef data, CFErrorRef *error) { + initStatics(); + const uint8_t *databytes = CFDataGetBytePtr(data); + uint64_t datalen = CFDataGetLength(data); + if (23 <= datalen) { // header is 22 bytes, plus 1 byte minimum for smallest object + const uint8_t *ptr = databytes; + if (0 != memcmp((uint8_t *)"bplist15", ptr, 8)) return NULL; + ptr += 8; + if (*ptr != (kCFBinaryPlistMarkerInt | 3)) return NULL; + ptr += 1; + uint64_t swapped_len; + memmove(&swapped_len, ptr, 8); + uint64_t bytelen = CFSwapInt64BigToHost(swapped_len); + if (bytelen != datalen) return NULL; + ptr += 8; + if (*ptr != (kCFBinaryPlistMarkerInt | 2)) return NULL; + ptr += 5; // skip crc + CFPropertyListRef pl = __CFBinaryPlistCreateObject15(databytes, datalen, &ptr); + // ptr should equal (databytes+datalen) if there is no junk at the end of top-level object + return pl; + } + return NULL; +} + diff --git a/CFBitVector.c b/CFBitVector.c index fab7ce3..6043b9f 100644 --- a/CFBitVector.c +++ b/CFBitVector.c @@ -22,7 +22,7 @@ */ /* CFBitVector.c - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ @@ -35,8 +35,10 @@ to right (bit 0 is the most significant) */ typedef uint8_t __CFBitVectorBucket; +#define __CFBITVECTORBUCKET_SIZE 8 +#define __CF_BITS_PER_BYTE 8 + enum { - __CF_BITS_PER_BYTE = 8, __CF_BITS_PER_BYTE_MASK = 0x07 }; @@ -388,7 +390,11 @@ static __CFBitVectorBucket __CFBitVectorGetBits(__CFBitVectorBucket bucketValue, context->curByte++; context->totalBits -= context->initBits; nBits -= __CF_BITS_PER_BYTE; +#if __CFBITVECTORBUCKET_SIZE > __CF_BITS_PER_BYTE val <<= __CF_BITS_PER_BYTE; +#else + val = 0; +#endif } /* ... then remaining bits go in *curByte */ if (0 < nBits) { diff --git a/CFBitVector.h b/CFBitVector.h index 502bac5..4b44927 100644 --- a/CFBitVector.h +++ b/CFBitVector.h @@ -22,7 +22,7 @@ */ /* CFBitVector.h - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBITVECTOR__) @@ -30,6 +30,7 @@ #include +CF_IMPLICIT_BRIDGING_ENABLED CF_EXTERN_C_BEGIN typedef UInt32 CFBit; @@ -60,6 +61,7 @@ CF_EXPORT void CFBitVectorSetBits(CFMutableBitVectorRef bv, CFRange range, CFBi CF_EXPORT void CFBitVectorSetAllBits(CFMutableBitVectorRef bv, CFBit value); CF_EXTERN_C_END +CF_IMPLICIT_BRIDGING_DISABLED #endif /* ! __COREFOUNDATION_CFBITVECTOR__ */ diff --git a/CFBuiltinConverters.c b/CFBuiltinConverters.c index c754227..279f063 100644 --- a/CFBuiltinConverters.c +++ b/CFBuiltinConverters.c @@ -22,7 +22,7 @@ */ /* CFBuiltinConverters.c - Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Copyright (c) 1999-2012, Apple Inc. All rights reserved. Responsibility: Aki Inoue */ @@ -38,7 +38,7 @@ static int8_t __CFMapsParagraphSeparator = -1; CF_INLINE bool __CFIsParagraphSeparator(UTF16Char character) { - if (-1 == __CFMapsParagraphSeparator) __CFMapsParagraphSeparator = (_CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard) ? false : true); + if (-1 == __CFMapsParagraphSeparator) __CFMapsParagraphSeparator = (1 ? false : true); return ((__CFMapsParagraphSeparator && (ParagraphSeparator == character)) ? true : false); } diff --git a/CFBundle.c b/CFBundle.c index 5ea739c..254fd92 100644 --- a/CFBundle.c +++ b/CFBundle.c @@ -22,8 +22,8 @@ */ /* CFBundle.c - Copyright (c) 1999-2011, Apple Inc. All rights reserved. - Responsibility: David Smith + Copyright (c) 1999-2012, Apple Inc. All rights reserved. + Responsibility: Tony Parker */ #include "CFBundle_Internal.h" @@ -41,9 +41,14 @@ #include #include +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS +#else +#error Unknown deployment target +#endif + #define AVOID_WEAK_COLLECTIONS 1 -#if !defined(AVOID_WEAK_COLLECTIONS) +#if !AVOID_WEAK_COLLECTIONS #include "CFHashTable.h" #include "CFMapTable.h" #include "CFPointerArray.h" @@ -69,7 +74,7 @@ #include #endif /* BINARY_SUPPORT_DLFCN */ -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI #include #elif DEPLOYMENT_TARGET_WINDOWS #include @@ -77,15 +82,25 @@ #define open _NS_open #define stat(x,y) _NS_stat(x,y) +#endif + +#if DEPLOYMENT_TARGET_WINDOWS +#define statinfo _stat + +// Windows isspace implementation limits the input chars to < 256 in the ASCII range. It will +// assert in debug builds. This is annoying. We merrily grok chars > 256. +static inline BOOL isspace(char c) { + return (c == ' ' || c == '\t' || c == '\n' || c == '\r'|| c == '\v' || c == '\f'); +} #else -#error Unknown or unspecified DEPLOYMENT_TARGET +#define statinfo stat #endif -extern void _processInfoDictionary(CFMutableDictionaryRef dict, CFStringRef platformSuffix, CFStringRef productSuffix); -extern CFStringRef _CFGetProductName(void); -extern CFStringRef _CFGetPlatformName(void); -extern CFStringRef _CFGetAlternatePlatformName(void); +__private_extern__ void _processInfoDictionary(CFMutableDictionaryRef dict, CFStringRef platformSuffix, CFStringRef productSuffix); +CF_EXPORT CFStringRef _CFGetProductName(void); +CF_EXPORT CFStringRef _CFGetPlatformName(void); +CF_EXPORT CFStringRef _CFGetAlternatePlatformName(void); static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle, Boolean alreadyLocked); @@ -199,18 +214,24 @@ struct __CFBundle { _CFPlugInData _plugInData; - CFSpinLock_t _bundleLoadingLock; + pthread_mutex_t _bundleLoadingLock; + // ZFH + /* resouce fast lookup*/ + CFSpinLock_t _queryLock; + CFMutableDictionaryRef _queryTable; + CFStringRef _bundleBasePath; + #if defined(BINARY_SUPPORT_DLL) HMODULE _hModule; #endif /* BINARY_SUPPORT_DLL */ }; -static CFSpinLock_t CFBundleGlobalDataLock = CFSpinLockInit; +static pthread_mutex_t CFBundleGlobalDataLock = PTHREAD_MUTEX_INITIALIZER; static CFMutableDictionaryRef _bundlesByIdentifier = NULL; -#if defined(AVOID_WEAK_COLLECTIONS) +#if AVOID_WEAK_COLLECTIONS static CFMutableDictionaryRef _bundlesByURL = NULL; static CFMutableArrayRef _allBundles = NULL; static CFMutableSetRef _bundlesToUnload = NULL; @@ -230,7 +251,6 @@ static CFStringRef _CFBundleCopyExecutableName(CFBundleRef bundle, CFURLRef url, static CFURLRef _CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle); static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint); static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void); -static void _CFBundleCheckWorkarounds(CFBundleRef bundle); static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath); static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths); #if defined(BINARY_SUPPORT_DYLD) @@ -249,12 +269,12 @@ static CFStringRef _CFBundleDlfcnCopyLoadedImagePathForPointer(void *p); #endif /* BINARY_SUPPORT_DLFCN */ -#if defined(AVOID_WEAK_COLLECTIONS) +#if AVOID_WEAK_COLLECTIONS static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) { CFStringRef bundleID = CFBundleGetIdentifier(bundle); - if (!alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock); + if (!alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock); // Add to the _allBundles list if (!_allBundles) { @@ -302,11 +322,11 @@ static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) { CFRelease(bundlesWithThisID); } } - if (!alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock); + if (!alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock); } static void _CFBundleRemoveFromTables(CFBundleRef bundle, CFURLRef bundleURL, CFStringRef bundleID) { - __CFSpinLock(&CFBundleGlobalDataLock); + pthread_mutex_lock(&CFBundleGlobalDataLock); // Remove from the various lists if (_allBundles) { CFIndex i = CFArrayGetFirstIndexOfValue(_allBundles, CFRangeMake(0, CFArrayGetCount(_allBundles)), bundle); @@ -328,19 +348,19 @@ static void _CFBundleRemoveFromTables(CFBundleRef bundle, CFURLRef bundleURL, CF if (0 == CFArrayGetCount(bundlesWithThisID)) CFDictionaryRemoveValue(_bundlesByIdentifier, bundleID); } } - __CFSpinUnlock(&CFBundleGlobalDataLock); + pthread_mutex_unlock(&CFBundleGlobalDataLock); } static CFBundleRef _CFBundleCopyBundleForURL(CFURLRef url, Boolean alreadyLocked) { CFBundleRef result = NULL; - if (!alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock); + if (!alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock); if (_bundlesByURL) result = (CFBundleRef)CFDictionaryGetValue(_bundlesByURL, url); if (result && !result->_url) { result = NULL; CFDictionaryRemoveValue(_bundlesByURL, url); } if (result) CFRetain(result); - if (!alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock); + if (!alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock); return result; } @@ -419,7 +439,7 @@ static CFBundleRef _getFromBundlesByURL(CFURLRef key) { static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) { CFStringRef bundleID = CFBundleGetIdentifier(bundle); - if (!alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock); + if (!alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock); // Add to the _allBundles list if (!_allBundles) _allBundles = [[__CFHashTable alloc] initWithOptions:CFPointerFunctionsZeroingWeakMemory capacity:0]; @@ -458,11 +478,11 @@ static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) { [bundlesWithThisID release]; } } - if (!alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock); + if (!alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock); } static void _CFBundleRemoveFromTables(CFBundleRef bundle, CFURLRef bundleURL, CFStringRef bundleID) { - __CFSpinLock(&CFBundleGlobalDataLock); + pthread_mutex_lock(&CFBundleGlobalDataLock); // Remove from the various lists if (_allBundles && [_allBundles member:(id)bundle]) [_allBundles removeObject:(id)bundle]; @@ -481,19 +501,19 @@ static void _CFBundleRemoveFromTables(CFBundleRef bundle, CFURLRef bundleURL, CF if (0 == [bundlesWithThisID count]) CFDictionaryRemoveValue(_bundlesByIdentifier, bundleID); } } - __CFSpinUnlock(&CFBundleGlobalDataLock); + pthread_mutex_unlock(&CFBundleGlobalDataLock); } static CFBundleRef _CFBundleCopyBundleForURL(CFURLRef url, Boolean alreadyLocked) { CFBundleRef result = NULL; - if (!alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock); + if (!alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock); result = _getFromBundlesByURL(url); if (result && !result->_url) { result = NULL; _removeFromBundlesByURL(url); } if (result) CFRetain(result); - if (!alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock); + if (!alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock); return result; } @@ -526,11 +546,6 @@ static CFBundleRef _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(CFStri #endif /* AVOID_WEAK_COLLECTIONS */ -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif - static CFURLRef _CFBundleCopyBundleURLForExecutablePath(CFStringRef str) { //!!! need to handle frameworks, NT; need to integrate with NSBundle - drd UniChar buff[CFMaxPathSize]; @@ -542,7 +557,7 @@ static CFURLRef _CFBundleCopyBundleURLForExecutablePath(CFStringRef str) { if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize; CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff); -#if DEPLOYMENT_TARGET_WINDOWS +#if DEPLOYMENT_TARGET_WINDOWS // Is this a .dll or .exe? if (buffLen >= 5 && (_wcsnicmp((wchar_t *)&(buff[buffLen-4]), L".dll", 4) == 0 || _wcsnicmp((wchar_t *)&(buff[buffLen-4]), L".exe", 4) == 0)) { CFIndex extensionLength = CFStringGetLength(_CFBundleWindowsResourceDirectoryExtension); @@ -560,15 +575,11 @@ static CFURLRef _CFBundleCopyBundleURLForExecutablePath(CFStringRef str) { CFRelease(outstr); } } -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif if (!url) { buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); // Remove exe name -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS if (buffLen > 0) { // See if this is a new bundle. If it is, we have to remove more path components. CFIndex startOfLastDir = _CFStartOfLastPathComponent(buff, buffLen); @@ -593,18 +604,11 @@ static CFURLRef _CFBundleCopyBundleURLForExecutablePath(CFStringRef str) { if (buffLen > 0) { // Remove support files folder buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif } } -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS CFRelease(lastDirName); } } -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif if (buffLen > 0) { outstr = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, buff, buffLen, kCFAllocatorNull); @@ -891,9 +895,9 @@ static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle, Boolean } if (bundle == _mainBundle) { CFStringRef executablePath = oldInfoDict ? (CFStringRef)CFDictionaryGetValue(oldInfoDict, _kCFBundleExecutablePathKey) : NULL; - if (!alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock); + if (!alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock); _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(executablePath); - if (!alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock); + if (!alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock); } else { CFBundleGetInfoDictionary(bundle); } @@ -962,11 +966,10 @@ static CFBundleRef _CFBundleGetMainBundleAlreadyLocked(void) { _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(str); // Perform delayed final processing steps. // This must be done after _isLoaded has been set, for security reasons (3624341). - _CFBundleCheckWorkarounds(_mainBundle); if (_CFBundleNeedsInitPlugIn(_mainBundle)) { - __CFSpinUnlock(&CFBundleGlobalDataLock); + pthread_mutex_unlock(&CFBundleGlobalDataLock); _CFBundleInitPlugIn(_mainBundle); - __CFSpinLock(&CFBundleGlobalDataLock); + pthread_mutex_lock(&CFBundleGlobalDataLock); } } } @@ -979,19 +982,19 @@ static CFBundleRef _CFBundleGetMainBundleAlreadyLocked(void) { CFBundleRef CFBundleGetMainBundle(void) { CFBundleRef mainBundle; - __CFSpinLock(&CFBundleGlobalDataLock); + pthread_mutex_lock(&CFBundleGlobalDataLock); mainBundle = _CFBundleGetMainBundleAlreadyLocked(); - __CFSpinUnlock(&CFBundleGlobalDataLock); + pthread_mutex_unlock(&CFBundleGlobalDataLock); return mainBundle; } CFBundleRef CFBundleGetBundleWithIdentifier(CFStringRef bundleID) { CFBundleRef result = NULL; if (bundleID) { - __CFSpinLock(&CFBundleGlobalDataLock); + pthread_mutex_lock(&CFBundleGlobalDataLock); (void)_CFBundleGetMainBundleAlreadyLocked(); result = _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI if (!result) { // Try to create the bundle for the caller and try again void *p = __builtin_return_address(0); @@ -1009,9 +1012,6 @@ CFBundleRef CFBundleGetBundleWithIdentifier(CFStringRef bundleID) { result = _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID); } } -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif if (!result) { // Try to guess the bundle from the identifier and try again @@ -1023,7 +1023,7 @@ CFBundleRef CFBundleGetBundleWithIdentifier(CFStringRef bundleID) { _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(); result = _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(bundleID); } - __CFSpinUnlock(&CFBundleGlobalDataLock); + pthread_mutex_unlock(&CFBundleGlobalDataLock); } return result; } @@ -1094,6 +1094,12 @@ static void __CFBundleDeallocate(CFTypeRef cf) { CFRelease(bundle->_glueDict); } if (bundle->_resourceData._stringTableCache) CFRelease(bundle->_resourceData._stringTableCache); + + // ZFH + if (bundle->_bundleBasePath) CFRelease(bundle->_bundleBasePath); + if (bundle->_queryTable) CFRelease(bundle->_queryTable); + + pthread_mutex_destroy(&(bundle->_bundleLoadingLock)); } static const CFRuntimeClass __CFBundleClass = { @@ -1109,7 +1115,7 @@ static const CFRuntimeClass __CFBundleClass = { }; // From CFBundle_Resources.c -void _CFBundleResourcesInitialize(); +__private_extern__ void _CFBundleResourcesInitialize(); __private_extern__ void __CFBundleInitialize(void) { __kCFBundleTypeID = _CFRuntimeRegisterClass(&__CFBundleClass); @@ -1212,13 +1218,10 @@ static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, bundle->_isLoaded = false; bundle->_sharesStringsFiles = false; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI if (!__CFgetenv("CFBundleDisableStringsSharing") && (strncmp(buff, "/System/Library/Frameworks", 26) == 0) && (strncmp(buff + strlen(buff) - 10, ".framework", 10) == 0)) bundle->_sharesStringsFiles = true; -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif bundle->_connectionCookie = NULL; @@ -1238,18 +1241,32 @@ static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, bundle->_plugInData._instanceCount = 0; bundle->_plugInData._factories = NULL; - bundle->_bundleLoadingLock = CFSpinLockInit; + pthread_mutexattr_t mattr; + pthread_mutexattr_init(&mattr); + pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_DEFAULT); + int32_t mret = pthread_mutex_init(&(bundle->_bundleLoadingLock), &mattr); + pthread_mutexattr_destroy(&mattr); + if (0 != mret) { + CFLog(4, CFSTR("%s: failed to initialize bundle loading lock for bundle %@."), __PRETTY_FUNCTION__, bundle); + } + + // ZFH + /* resource fast look up */ + bundle->_queryLock = CFSpinLockInit; + bundle->_queryTable = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFURLRef absoURL = CFURLCopyAbsoluteURL(bundle->_url); + bundle->_bundleBasePath = CFURLCopyFileSystemPath(absoURL, PLATFORM_PATH_STYLE); + CFRelease(absoURL); CFBundleGetInfoDictionary(bundle); _CFBundleAddToTables(bundle, alreadyLocked); if (doFinalProcessing) { - _CFBundleCheckWorkarounds(bundle); if (_CFBundleNeedsInitPlugIn(bundle)) { - if (alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock); + if (alreadyLocked) pthread_mutex_unlock(&CFBundleGlobalDataLock); _CFBundleInitPlugIn(bundle); - if (alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock); + if (alreadyLocked) pthread_mutex_lock(&CFBundleGlobalDataLock); } } @@ -1362,7 +1379,7 @@ CFDictionaryRef _CFBundleGetLocalInfoDictionary(CFBundleRef bundle) { } CFDictionaryRef CFBundleGetLocalInfoDictionary(CFBundleRef bundle) { - static CFSpinLock_t CFBundleLocalInfoLock = CFSpinLockInit; + static pthread_mutex_t CFBundleLocalInfoLock = PTHREAD_MUTEX_INITIALIZER; CFDictionaryRef localInfoDict = bundle->_localInfoDict; if (!localInfoDict) { CFURLRef url = CFBundleCopyResourceURL(bundle, _CFBundleLocalInfoName, _CFBundleStringTableType, NULL); @@ -1383,14 +1400,14 @@ CFDictionaryRef CFBundleGetLocalInfoDictionary(CFBundleRef bundle) { CFRelease(url); } if (localInfoDict) _processInfoDictionary((CFMutableDictionaryRef)localInfoDict, _CFGetPlatformName(), _CFGetProductName()); - __CFSpinLock(&CFBundleLocalInfoLock); + pthread_mutex_lock(&CFBundleLocalInfoLock); if (!bundle->_localInfoDict) { bundle->_localInfoDict = localInfoDict; } else { if (localInfoDict && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(localInfoDict); localInfoDict = bundle->_localInfoDict; } - __CFSpinUnlock(&CFBundleLocalInfoLock); + pthread_mutex_unlock(&CFBundleLocalInfoLock); } return localInfoDict; } @@ -1692,7 +1709,7 @@ static Boolean _urlExists(CFURLRef url) { // See static Boolean _binaryLoadable(CFURLRef url) { Boolean loadable = _urlExists(url); -#if DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI if (!loadable) { uint8_t path[PATH_MAX]; if (url && CFURLGetFileSystemRepresentation(url, true, path, sizeof(path))) { @@ -1764,7 +1781,7 @@ static CFURLRef _CFBundleCopyExecutableURLRaw(CFURLRef urlPath, CFStringRef exeN CFURLRef executableURL = NULL; if (!urlPath || !exeName) return NULL; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI const uint8_t *image_suffix = (uint8_t *)__CFgetenv("DYLD_IMAGE_SUFFIX"); if (image_suffix) { CFStringRef newExeName, imageSuffix; @@ -1831,8 +1848,6 @@ static CFURLRef _CFBundleCopyExecutableURLRaw(CFURLRef urlPath, CFStringRef exeN CFRelease(newExeName); } } -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif return executableURL; } @@ -1878,15 +1893,66 @@ static CFStringRef _CFBundleCopyExecutableName(CFBundleRef bundle, CFURLRef url, return executableName; } +__private_extern__ CFURLRef _CFBundleCopyResourceForkURLWithoutLocal(CFBundleRef bundle) { + CFStringRef executableName = _CFBundleCopyExecutableName(bundle, NULL, NULL); + CFURLRef resourceForkURL = NULL; + if (executableName) { + UniChar *path = (UniChar *) CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UniChar) * CFMaxPathSize, 0); + CFIndex pathLen = CFStringGetLength(bundle->_bundleBasePath); + CFStringGetCharacters(bundle->_bundleBasePath, CFRangeMake(0, CFStringGetLength(bundle->_bundleBasePath)), path); + _CFBundleSetResourceDir(path, &pathLen, CFMaxPathSize, bundle->_version); + _CFAppendTrailingPathSlash(path, &pathLen, CFMaxPathSize); + CFStringGetCharacters(executableName, CFRangeMake(0, CFStringGetLength(executableName)), path+pathLen); + pathLen += CFStringGetLength(executableName); + path[pathLen++] = '.'; + CFStringGetCharacters(CFSTR("rsrc"), CFRangeMake(0, 4), path+pathLen); + pathLen += 4; + CFStringRef pathStr = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, path, pathLen); + Boolean found = false; + found = _CFIsResourceAtPath(pathStr, NULL); + if (found) { + resourceForkURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, pathStr, PLATFORM_PATH_STYLE, false); + } + CFRelease(pathStr); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, path); + CFRelease(executableName); + } + + return resourceForkURL; +} + __private_extern__ CFURLRef _CFBundleCopyResourceForkURLMayBeLocal(CFBundleRef bundle, Boolean mayBeLocal) { CFStringRef executableName = _CFBundleCopyExecutableName(bundle, NULL, NULL); CFURLRef resourceForkURL = NULL; if (executableName) { + CFStringRef type = CFSTR("rsrc"); +#ifdef CFBUNDLE_NEWLOOKUP if (mayBeLocal) { - resourceForkURL = CFBundleCopyResourceURL(bundle, executableName, CFSTR("rsrc"), NULL); + resourceForkURL = (CFURLRef) _CFBundleCopyFindResourcesWithNoBlock(bundle, NULL, NULL, executableName, type, NULL, NULL, NO, NO); } else { - resourceForkURL = CFBundleCopyResourceURLForLocalization(bundle, executableName, CFSTR("rsrc"), NULL, NULL); + CFArrayRef languages = CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); + resourceForkURL = (CFURLRef) _CFBundleCopyFindResourcesWithNoBlock(bundle, NULL, languages, executableName, type, NULL, NULL, NO, NO); + CFRelease(languages); } +#else + CFArrayRef types = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&type, 1, &kCFTypeArrayCallBacks); + CFArrayRef array = NULL; + if (mayBeLocal) { + CFArrayRef languages = _CFBundleGetLanguageSearchList(bundle); + array = _CFFindBundleResourcesNoBlock(bundle, NULL, NULL, languages, executableName, types, 1, _CFBundleLayoutVersion(bundle)); + if (array) { + if (CFArrayGetCount(array) > 0) resourceForkURL = (CFURLRef)CFRetain(CFArrayGetValueAtIndex(array, 0)); + CFRelease(array); + } + } else { + array = _CFFindBundleResourcesNoBlock(bundle, NULL, NULL, NULL, executableName, types, 1, _CFBundleLayoutVersion(bundle)); + if (array) { + if (CFArrayGetCount(array) > 0) resourceForkURL = (CFURLRef)CFRetain(CFArrayGetValueAtIndex(array, 0)); + CFRelease(array); + } + } + CFRelease(types); +#endif CFRelease(executableName); } @@ -1920,12 +1986,10 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectory2(CFBundleRef bundle, CFURL if (executablePath) CFRetain(executablePath); __CFSpinUnlock(&CFBundleExecutablePathLock); if (executablePath) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, executablePath, kCFURLPOSIXPathStyle, false); #elif DEPLOYMENT_TARGET_WINDOWS executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, executablePath, kCFURLWindowsPathStyle, false); -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif if (executableURL) { foundIt = true; @@ -1941,14 +2005,14 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectory2(CFBundleRef bundle, CFURL if (!foundIt) { if (lookupMainExe) executableName = _CFBundleCopyExecutableName(bundle, url, infoDict); if (executableName) { -#if DEPLOYMENT_TARGET_EMBEDDED +#if (DEPLOYMENT_TARGET_EMBEDDED && !TARGET_IPHONE_SIMULATOR) Boolean doExecSearch = false; #else Boolean doExecSearch = true; #endif // Now, look for the executable inside the bundle. if (doExecSearch && 0 != version) { - CFURLRef exeDirURL; + CFURLRef exeDirURL = NULL; CFURLRef exeSubdirURL; if (1 == version) { @@ -1964,10 +2028,8 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectory2(CFBundleRef bundle, CFURL } else { exeDirURL = (CFURLRef)CFRetain(url); } -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI exeDirURL = (CFURLRef)CFRetain(url); -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif } CFStringRef platformSubDir = useOtherPlatform ? _CFBundleGetOtherPlatformExecutablesSubdirectoryName() : _CFBundleGetPlatformExecutablesSubdirectoryName(); @@ -2007,9 +2069,6 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectory2(CFBundleRef bundle, CFURL executableURL = _CFBundleCopyExecutableURLRaw(exeDirURL, executableName); CFRelease(exeDirURL); } -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif if (lookupMainExe && !ignoreCache && !useOtherPlatform && bundle && infoDict && executableURL) { @@ -2017,10 +2076,8 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectory2(CFBundleRef bundle, CFURL CFURLRef absURL = CFURLCopyAbsoluteURL(executableURL); #if DEPLOYMENT_TARGET_WINDOWS executablePath = CFURLCopyFileSystemPath(absURL, kCFURLWindowsPathStyle); -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI executablePath = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle); -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif CFRelease(absURL); __CFSpinLock(&CFBundleExecutablePathLock); @@ -2289,7 +2346,7 @@ static Boolean _CFBundleGrokX11FromFile(int fd, const void *bytes, CFIndex lengt // returns zero-ref dictionary under GC static CFDictionaryRef _CFBundleGrokInfoDictFromFile(int fd, const void *bytes, CFIndex length, uint32_t offset, Boolean swapped, Boolean sixtyFour) { - struct stat statBuf; + struct statinfo statBuf; off_t fileLength = 0; char *maploc = NULL; const char *loc; @@ -2598,6 +2655,15 @@ static Boolean _CFBundleGrokFileTypeForZipMimeType(const unsigned char *bytes, C } else if (bytes < data && data + 41 <= bytes + length && 8 == CFSwapInt16HostToLittle(*((UInt16 *)(bytes + 8))) && 0x4b2c28c8 == CFSwapInt32HostToBig(*((UInt32 *)data)) && 0xc94c4e2c == CFSwapInt32HostToBig(*((UInt32 *)(data + 4)))) { // AbiWord compressed mimetype odt if (ext) *ext = "odt"; + // almost certainly this should set i to 0 but I don't want to upset the apple cart now + } else if (bytes < data && data + 29 <= bytes + length && (0 == ustrncasecmp(data, "application/oebps-package+xml", 29))) { + // epub, official epub 3 mime type + if (ext) *ext = "epub"; + i = 0; + } else if (bytes < data && data + 20 <= bytes + length && (0 == ustrncasecmp(data, "application/epub+zip", 20))) { + // epub, unofficial epub 2 mime type + if (ext) *ext = "epub"; + i = 0; } return (i >= 0); } @@ -2732,14 +2798,6 @@ static const char *_CFBundleGrokFileTypeForOLEFile(int fd, const void *bytes, CF return ext; } -#if DEPLOYMENT_TARGET_WINDOWS -// Windows isspace implementation limits the input chars to < 256 in the ASCII range. It will -// assert in debug builds. This is annoying. We merrily grok chars > 256. -static inline BOOL isspace(char c) { - return (c == ' ' || c == '\t' || c == '\n' || c == '\r'|| c == '\v' || c == '\f'); -} -#endif - // returns zero-ref dictionary in *infodict under GC static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef *extension, UInt32 *machtype, CFArrayRef *architectures, CFDictionaryRef *infodict, Boolean *hasObjc, uint32_t *objcVersion, uint32_t *objcFlags) { int fd = -1; @@ -2766,13 +2824,7 @@ static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef * Boolean gotPath = FALSE; char path[CFMaxPathSize]; gotPath = CFURLGetFileSystemRepresentation(url, true, (uint8_t *)path, CFMaxPathSize); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - struct stat statBuf; -#elif DEPLOYMENT_TARGET_WINDOWS - struct _stat statBuf; -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif + struct statinfo statBuf; if (gotPath && stat(path, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFREG && (fd = open(path, O_RDONLY | CF_OPENFLGS, 0777)) >= 0) { length = read(fd, buffer, MAGIC_BYTES_TO_READ); fileLength = statBuf.st_size; @@ -3161,7 +3213,7 @@ Boolean _CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, Boolean forceG CFErrorRef localError = NULL, *subError = (error ? &localError : NULL); CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); - __CFSpinLock(&(bundle->_bundleLoadingLock)); + pthread_mutex_lock(&(bundle->_bundleLoadingLock)); if (!executableURL) bundle->_binaryType = __CFBundleNoBinary; // make sure we know whether bundle is already loaded or not #if defined(BINARY_SUPPORT_DLFCN) @@ -3179,38 +3231,38 @@ Boolean _CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, Boolean forceG if (executableURL) CFRelease(executableURL); if (bundle->_isLoaded) { - __CFSpinUnlock(&(bundle->_bundleLoadingLock)); + pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); // Remove from the scheduled unload set if we are there. - __CFSpinLock(&CFBundleGlobalDataLock); -#if defined(AVOID_WEAK_COLLECTIONS) + pthread_mutex_lock(&CFBundleGlobalDataLock); +#if AVOID_WEAK_COLLECTIONS if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle); #else /* AVOID_WEAK_COLLECTIONS */ if (_bundlesToUnload) [_bundlesToUnload removeObject:(id)bundle]; #endif /* AVOID_WEAK_COLLECTIONS */ - __CFSpinUnlock(&CFBundleGlobalDataLock); + pthread_mutex_unlock(&CFBundleGlobalDataLock); return true; } // Unload bundles scheduled for unloading if (!_scheduledBundlesAreUnloading) { - __CFSpinUnlock(&(bundle->_bundleLoadingLock)); + pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); _CFBundleUnloadScheduledBundles(); - __CFSpinLock(&(bundle->_bundleLoadingLock)); + pthread_mutex_lock(&(bundle->_bundleLoadingLock)); } if (bundle->_isLoaded) { - __CFSpinUnlock(&(bundle->_bundleLoadingLock)); + pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); // Remove from the scheduled unload set if we are there. - __CFSpinLock(&CFBundleGlobalDataLock); -#if defined(AVOID_WEAK_COLLECTIONS) + pthread_mutex_lock(&CFBundleGlobalDataLock); +#if AVOID_WEAK_COLLECTIONS if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle); #else /* AVOID_WEAK_COLLECTIONS */ if (_bundlesToUnload) [_bundlesToUnload removeObject:(id)bundle]; #endif /* AVOID_WEAK_COLLECTIONS */ - __CFSpinUnlock(&CFBundleGlobalDataLock); + pthread_mutex_unlock(&CFBundleGlobalDataLock); return true; } - __CFSpinUnlock(&(bundle->_bundleLoadingLock)); + pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); switch (bundle->_binaryType) { #if defined(BINARY_SUPPORT_DLFCN) @@ -3288,7 +3340,7 @@ Boolean CFBundlePreflightExecutable(CFBundleRef bundle, CFErrorRef *error) { #endif CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); - __CFSpinLock(&(bundle->_bundleLoadingLock)); + pthread_mutex_lock(&(bundle->_bundleLoadingLock)); if (!executableURL) bundle->_binaryType = __CFBundleNoBinary; // make sure we know whether bundle is already loaded or not #if defined(BINARY_SUPPORT_DLFCN) @@ -3306,10 +3358,10 @@ Boolean CFBundlePreflightExecutable(CFBundleRef bundle, CFErrorRef *error) { if (executableURL) CFRelease(executableURL); if (bundle->_isLoaded) { - __CFSpinUnlock(&(bundle->_bundleLoadingLock)); + pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); return true; } - __CFSpinUnlock(&(bundle->_bundleLoadingLock)); + pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); switch (bundle->_binaryType) { #if defined(BINARY_SUPPORT_DLFCN) @@ -3388,23 +3440,23 @@ void CFBundleUnloadExecutable(CFBundleRef bundle) { if (!bundle->_isLoaded) return; // Remove from the scheduled unload set if we are there. - if (!_scheduledBundlesAreUnloading) __CFSpinLock(&CFBundleGlobalDataLock); -#if defined(AVOID_WEAK_COLLECTIONS) + if (!_scheduledBundlesAreUnloading) pthread_mutex_lock(&CFBundleGlobalDataLock); +#if AVOID_WEAK_COLLECTIONS if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle); #else /* AVOID_WEAK_COLLECTIONS */ if (_bundlesToUnload) [_bundlesToUnload removeObject:(id)bundle]; #endif /* AVOID_WEAK_COLLECTIONS */ - if (!_scheduledBundlesAreUnloading) __CFSpinUnlock(&CFBundleGlobalDataLock); + if (!_scheduledBundlesAreUnloading) pthread_mutex_unlock(&CFBundleGlobalDataLock); // Give the plugIn code a chance to realize this... _CFPlugInWillUnload(bundle); - __CFSpinLock(&(bundle->_bundleLoadingLock)); + pthread_mutex_lock(&(bundle->_bundleLoadingLock)); if (!bundle->_isLoaded) { - __CFSpinUnlock(&(bundle->_bundleLoadingLock)); + pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); return; } - __CFSpinUnlock(&(bundle->_bundleLoadingLock)); + pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); switch (bundle->_binaryType) { #if defined(BINARY_SUPPORT_DYLD) @@ -3439,10 +3491,10 @@ void CFBundleUnloadExecutable(CFBundleRef bundle) { } } -#if defined(AVOID_WEAK_COLLECTIONS) +#if AVOID_WEAK_COLLECTIONS __private_extern__ void _CFBundleScheduleForUnloading(CFBundleRef bundle) { - __CFSpinLock(&CFBundleGlobalDataLock); + pthread_mutex_lock(&CFBundleGlobalDataLock); if (!_bundlesToUnload) { CFSetCallBacks nonRetainingCallbacks = kCFTypeSetCallBacks; nonRetainingCallbacks.retain = NULL; @@ -3450,17 +3502,17 @@ __private_extern__ void _CFBundleScheduleForUnloading(CFBundleRef bundle) { _bundlesToUnload = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingCallbacks); } CFSetAddValue(_bundlesToUnload, bundle); - __CFSpinUnlock(&CFBundleGlobalDataLock); + pthread_mutex_unlock(&CFBundleGlobalDataLock); } __private_extern__ void _CFBundleUnscheduleForUnloading(CFBundleRef bundle) { - __CFSpinLock(&CFBundleGlobalDataLock); + pthread_mutex_lock(&CFBundleGlobalDataLock); if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle); - __CFSpinUnlock(&CFBundleGlobalDataLock); + pthread_mutex_unlock(&CFBundleGlobalDataLock); } __private_extern__ void _CFBundleUnloadScheduledBundles(void) { - __CFSpinLock(&CFBundleGlobalDataLock); + pthread_mutex_lock(&CFBundleGlobalDataLock); if (_bundlesToUnload) { CFIndex i, c = CFSetGetCount(_bundlesToUnload); if (c > 0) { @@ -3475,26 +3527,26 @@ __private_extern__ void _CFBundleUnloadScheduledBundles(void) { CFAllocatorDeallocate(kCFAllocatorSystemDefault, unloadThese); } } - __CFSpinUnlock(&CFBundleGlobalDataLock); + pthread_mutex_unlock(&CFBundleGlobalDataLock); } #else /* AVOID_WEAK_COLLECTIONS */ __private_extern__ void _CFBundleScheduleForUnloading(CFBundleRef bundle) { - __CFSpinLock(&CFBundleGlobalDataLock); + pthread_mutex_lock(&CFBundleGlobalDataLock); if (!_bundlesToUnload) _bundlesToUnload = [[__CFHashTable alloc] initWithOptions:CFPointerFunctionsZeroingWeakMemory capacity:0]; [_bundlesToUnload addObject:(id)bundle]; - __CFSpinUnlock(&CFBundleGlobalDataLock); + pthread_mutex_unlock(&CFBundleGlobalDataLock); } __private_extern__ void _CFBundleUnscheduleForUnloading(CFBundleRef bundle) { - __CFSpinLock(&CFBundleGlobalDataLock); + pthread_mutex_lock(&CFBundleGlobalDataLock); if (_bundlesToUnload) [_bundlesToUnload removeObject:(id)bundle]; - __CFSpinUnlock(&CFBundleGlobalDataLock); + pthread_mutex_unlock(&CFBundleGlobalDataLock); } __private_extern__ void _CFBundleUnloadScheduledBundles(void) { - __CFSpinLock(&CFBundleGlobalDataLock); + pthread_mutex_lock(&CFBundleGlobalDataLock); if (_bundlesToUnload && [_bundlesToUnload count] > 0) { CFIndex i, c; CFMutableArrayRef unloadThese = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); @@ -3510,7 +3562,7 @@ __private_extern__ void _CFBundleUnloadScheduledBundles(void) { } CFRelease(unloadThese); } - __CFSpinUnlock(&CFBundleGlobalDataLock); + pthread_mutex_unlock(&CFBundleGlobalDataLock); } #endif /* AVOID_WEAK_COLLECTIONS */ @@ -3660,13 +3712,10 @@ __private_extern__ Boolean _CFBundleCouldBeBundle(CFURLRef url) { //If 'permissive' is set, we will maintain the historical behavior of returning frameworks with names that don't match, and frameworks for executables in Resources/ static CFURLRef __CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath, Boolean permissive) { // MF:!!! Implement me. We need to be able to find the bundle from the exe, dealing with old vs. new as well as the Executables dir business on Windows. -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -#elif DEPLOYMENT_TARGET_WINDOWS +#if DEPLOYMENT_TARGET_WINDOWS UniChar executablesToFrameworksPathBuff[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'}; UniChar executablesToPrivateFrameworksPathBuff[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'}; UniChar frameworksExtension[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'}; -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif UniChar pathBuff[CFMaxPathSize] = {0}; UniChar nameBuff[CFMaxPathSize] = {0}; @@ -3710,10 +3759,6 @@ static CFURLRef __CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executab } } } - -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif // * Finally check the executable inside the framework case. if (!bundleURL) { @@ -3783,7 +3828,7 @@ static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath) { createdBundle = true; } if (bundle) { - __CFSpinLock(&(bundle->_bundleLoadingLock)); + pthread_mutex_lock(&(bundle->_bundleLoadingLock)); if (!bundle->_isLoaded) { // make sure that these bundles listed as loaded, and mark them frameworks (we probably can't see anything else here, and we cannot unload them) #if defined(BINARY_SUPPORT_DLFCN) @@ -3800,15 +3845,14 @@ static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath) { #endif /* LOG_BUNDLE_LOAD */ bundle->_isLoaded = true; } - __CFSpinUnlock(&(bundle->_bundleLoadingLock)); + pthread_mutex_unlock(&(bundle->_bundleLoadingLock)); if (createdBundle) { // Perform delayed final processing steps. // This must be done after _isLoaded has been set, for security reasons (3624341). - _CFBundleCheckWorkarounds(bundle); if (_CFBundleNeedsInitPlugIn(bundle)) { - __CFSpinUnlock(&CFBundleGlobalDataLock); + pthread_mutex_unlock(&CFBundleGlobalDataLock); _CFBundleInitPlugIn(bundle); - __CFSpinLock(&CFBundleGlobalDataLock); + pthread_mutex_lock(&CFBundleGlobalDataLock); } } else { // Release the bundle if we did not create it here @@ -3860,13 +3904,13 @@ static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void) { CFArrayRef CFBundleGetAllBundles(void) { // To answer this properly, we have to have created the static bundles! -#if !defined(AVOID_WEAK_COLLECTIONS) +#if !AVOID_WEAK_COLLECTIONS static CFMutableArrayRef externalAllBundles = NULL; #endif /* AVOID_WEAK_COLLECTIONS */ CFArrayRef bundles; - __CFSpinLock(&CFBundleGlobalDataLock); + pthread_mutex_lock(&CFBundleGlobalDataLock); _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(); -#if defined(AVOID_WEAK_COLLECTIONS) +#if AVOID_WEAK_COLLECTIONS bundles = _allBundles; #else /* AVOID_WEAK_COLLECTIONS */ if (!externalAllBundles) { @@ -3879,21 +3923,21 @@ CFArrayRef CFBundleGetAllBundles(void) { for (id value in _allBundles) CFArrayAppendValue(externalAllBundles, value); bundles = externalAllBundles; #endif /* AVOID_WEAK_COLLECTIONS */ - __CFSpinUnlock(&CFBundleGlobalDataLock); + pthread_mutex_unlock(&CFBundleGlobalDataLock); return bundles; } CF_EXPORT CFArrayRef _CFBundleCopyAllBundles(void) { // To answer this properly, we have to have created the static bundles! - __CFSpinLock(&CFBundleGlobalDataLock); + pthread_mutex_lock(&CFBundleGlobalDataLock); _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(); -#if defined(AVOID_WEAK_COLLECTIONS) +#if AVOID_WEAK_COLLECTIONS CFArrayRef bundles = CFArrayCreateCopy(kCFAllocatorSystemDefault, _allBundles); #else /* AVOID_WEAK_COLLECTIONS */ CFMutableArrayRef bundles = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); for (id value in _allBundles) CFArrayAppendValue(bundles, value); #endif /* AVOID_WEAK_COLLECTIONS */ - __CFSpinUnlock(&CFBundleGlobalDataLock); + pthread_mutex_unlock(&CFBundleGlobalDataLock); return bundles; } @@ -3901,13 +3945,113 @@ uint8_t _CFBundleLayoutVersion(CFBundleRef bundle) { return bundle->_version; } +static void __addPlatformAndProductNamesToKeys(const void *value, void *context) { + CFMutableSetRef newKeys = (CFMutableSetRef)context; + CFStringRef key = (CFStringRef)value; + CFStringRef firstPartOfKey = NULL; + CFStringRef restOfKey = NULL; + + // Find the first ':' + CFRange range; + Boolean success = CFStringFindWithOptions(key, CFSTR(":"), CFRangeMake(0, CFStringGetLength(key)), 0, &range); + if (success) { + firstPartOfKey = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, key, CFRangeMake(0, range.location)); + restOfKey = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, key, CFRangeMake(range.location + 1, CFStringGetLength(key) - range.location - 1)); + } else { + firstPartOfKey = (CFStringRef)CFRetain(key); + } + + // only apply product and platform to top-level key + CFStringRef newKeyWithPlatform = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@-%@%@%@"), firstPartOfKey, _CFGetPlatformName(), restOfKey ? CFSTR(":") : CFSTR(""), restOfKey ? restOfKey : CFSTR("")); + CFStringRef newKeyWithProduct = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@~%@%@%@"), firstPartOfKey, _CFGetProductName(), restOfKey ? CFSTR(":") : CFSTR(""), restOfKey ? restOfKey : CFSTR("")); + CFStringRef newKeyWithProductAndPlatform = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@-%@~%@%@%@"), firstPartOfKey, _CFGetPlatformName(), _CFGetProductName(), restOfKey ? CFSTR(":") : CFSTR(""), restOfKey ? restOfKey : CFSTR("")); + + CFSetAddValue(newKeys, key); + CFSetAddValue(newKeys, newKeyWithPlatform); + CFSetAddValue(newKeys, newKeyWithProduct); + CFSetAddValue(newKeys, newKeyWithProductAndPlatform); + + if (firstPartOfKey) CFRelease(firstPartOfKey); + if (restOfKey) CFRelease(restOfKey); + CFRelease(newKeyWithPlatform); + CFRelease(newKeyWithProduct); + CFRelease(newKeyWithProductAndPlatform); +} + +// from CFUtilities.c +__private_extern__ Boolean _CFReadMappedFromFile(CFStringRef path, Boolean map, Boolean uncached, void **outBytes, CFIndex *outLength, CFErrorRef *errorPtr); + +// implementation of below functions - takes URL as parameter +static CFPropertyListRef _CFBundleCreateFilteredInfoPlistWithURL(CFURLRef infoPlistURL, CFSetRef keyPaths, _CFBundleFilteredPlistOptions options) { + CFPropertyListRef result = NULL; + + if (!infoPlistURL) return CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + CFURLRef absoluteURL = CFURLCopyAbsoluteURL(infoPlistURL); + CFStringRef filePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); + CFRelease(absoluteURL); + + if (!filePath) return CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + void *bytes = NULL; + CFIndex length = 0; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI + Boolean mapped = options & _CFBundleFilteredPlistMemoryMapped ? true : false; +#else + Boolean mapped = false; +#endif + Boolean success = _CFReadMappedFromFile(filePath, mapped, false, &bytes, &length, NULL); + CFRelease(filePath); + if (!success) return CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + CFDataRef infoPlistData = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8 *)bytes, length, kCFAllocatorNull); + // We need to include all possible variants of the platform/product combo as possible keys. + CFMutableSetRef newKeyPaths = CFSetCreateMutable(kCFAllocatorSystemDefault, CFSetGetCount(keyPaths), &kCFTypeSetCallBacks); + CFSetApplyFunction(keyPaths, __addPlatformAndProductNamesToKeys, newKeyPaths); + + success = _CFPropertyListCreateFiltered(kCFAllocatorSystemDefault, infoPlistData, kCFPropertyListMutableContainers, newKeyPaths, &result, NULL); + + if (!success) { + result = CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + } else { + _processInfoDictionary((CFMutableDictionaryRef)result, _CFGetPlatformName(), _CFGetProductName()); + } + + CFRelease(newKeyPaths); + CFRelease(infoPlistData); + if (mapped) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI + munmap(bytes, length); +#endif + } else { + free(bytes); + } + + return result; +} + +// Returns a subset of the bundle's property list, only including the keyPaths in the CFSet. If the top level object is not a dictionary, you will get back an empty dictionary as the result. If the Info.plist does not exist or could not be parsed, you will get back an empty dictionary. +CF_EXPORT CFPropertyListRef _CFBundleCreateFilteredInfoPlist(CFBundleRef bundle, CFSetRef keyPaths, _CFBundleFilteredPlistOptions options) { + CFURLRef infoPlistURL = _CFBundleCopyInfoPlistURL(bundle); + CFPropertyListRef result = _CFBundleCreateFilteredInfoPlistWithURL(infoPlistURL, keyPaths, options); + if (infoPlistURL) CFRelease(infoPlistURL); + return result; +} + +CF_EXPORT CFPropertyListRef _CFBundleCreateFilteredLocalizedInfoPlist(CFBundleRef bundle, CFSetRef keyPaths, CFStringRef localizationName, _CFBundleFilteredPlistOptions options) { + CFURLRef infoPlistURL = CFBundleCopyResourceURLForLocalization(bundle, _CFBundleLocalInfoName, _CFBundleStringTableType, NULL, localizationName); + CFPropertyListRef result = _CFBundleCreateFilteredInfoPlistWithURL(infoPlistURL, keyPaths, options); + if (infoPlistURL) CFRelease(infoPlistURL); + return result; +} + CF_EXPORT CFURLRef _CFBundleCopyInfoPlistURL(CFBundleRef bundle) { CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); CFURLRef url = (CFURLRef)CFDictionaryGetValue(infoDict, _kCFBundleInfoPlistURLKey); if (!url) url = (CFURLRef)CFDictionaryGetValue(infoDict, _kCFBundleRawInfoPlistURLKey); return (url ? (CFURLRef)CFRetain(url) : NULL); } - + CF_EXPORT CFURLRef _CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle) { return CFBundleCopyPrivateFrameworksURL(bundle); } @@ -4443,9 +4587,12 @@ CF_EXPORT Boolean _CFBundleDlfcnPreflight(CFBundleRef bundle, CFErrorRef *error) } #if defined(BINARY_SUPPORT_DYLD) if (hasSuitableArch) { - uint32_t mainFlags = 0, bundleFlags = 0; + uint32_t mainFlags = 0; if (_CFBundleGrokObjCImageInfoFromMainExecutable(NULL, &mainFlags) && (mainFlags & 0x2) != 0) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + uint32_t bundleFlags = 0; if (_CFBundleGetObjCImageInfo(bundle, NULL, &bundleFlags) && (bundleFlags & 0x2) == 0) hasRuntimeMismatch = true; +#endif } } #endif /* BINARY_SUPPORT_DYLD */ @@ -4683,7 +4830,51 @@ __private_extern__ void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle, CFStrin /* Workarounds to be applied in the presence of certain bundles can go here. This is called on every bundle creation. */ + +// ZFH +__private_extern__ CFStringRef _CFBundleGetBundlePath(CFBundleRef bundle){ + return bundle->_bundleBasePath; +} -static void _CFBundleCheckWorkarounds(CFBundleRef bundle) { +// caller need to release the table +__private_extern__ CFDictionaryRef _CFBundleCopyQueryTable(CFBundleRef bundle, CFURLRef bundleURL, CFArrayRef languages, UniChar *resDir, CFIndex resDirLen, UniChar *subDirBuffer, CFIndex subDirLen) +{ + CFDictionaryRef subTable = NULL; + CFIndex savedResDirLen = resDirLen; + Boolean appendSucc = true; + + if (subDirLen > 0) { + appendSucc = _CFAppendPathComponent(resDir, &resDirLen, CFMaxPathSize, subDirBuffer, subDirLen); + } + + if (appendSucc) { + CFStringRef argDirStr = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, resDir, resDirLen, CFMaxPathSize, kCFAllocatorNull); + // take the lock + if (bundle) { + __CFSpinLock(&bundle->_queryLock); + + // check if the query table for the given sub dir has been created + subTable = (CFDictionaryRef) CFDictionaryGetValue(bundle->_queryTable, argDirStr); + + if (!subTable) { + // create the query table for the given sub dir + subTable = _CFBundleCreateQueryTableAtPath(bundle, bundleURL, languages, resDir, savedResDirLen, subDirBuffer, subDirLen); + + CFDictionarySetValue(bundle->_queryTable, argDirStr, subTable); + } else { + CFRetain(subTable); + } + __CFSpinUnlock(&bundle->_queryLock); + } else { + subTable = _CFBundleCreateQueryTableAtPath(NULL, bundleURL, languages, resDir, savedResDirLen, subDirBuffer, subDirLen); + } + CFRelease(argDirStr); + } + + return subTable; } + + + + diff --git a/CFBundle.h b/CFBundle.h index 7797987..304ab6a 100644 --- a/CFBundle.h +++ b/CFBundle.h @@ -22,7 +22,7 @@ */ /* CFBundle.h - Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Copyright (c) 1999-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBUNDLE__) @@ -261,14 +261,12 @@ CFArrayRef CFBundleCopyExecutableArchitecturesForURL(CFURLRef url) CF_AVAILABLE( CF_EXPORT CFURLRef CFBundleCopyExecutableURL(CFBundleRef bundle); -#if MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED enum { kCFBundleExecutableArchitectureI386 = 0x00000007, kCFBundleExecutableArchitecturePPC = 0x00000012, kCFBundleExecutableArchitectureX86_64 = 0x01000007, kCFBundleExecutableArchitecturePPC64 = 0x01000012 -}; -#endif /* MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED */ +} CF_ENUM_AVAILABLE(10_5, 2_0); CF_EXPORT CFArrayRef CFBundleCopyExecutableArchitectures(CFBundleRef bundle) CF_AVAILABLE(10_5, 2_0); diff --git a/CFBundlePriv.h b/CFBundlePriv.h index a78efcb..97b5402 100644 --- a/CFBundlePriv.h +++ b/CFBundlePriv.h @@ -22,7 +22,7 @@ */ /* CFBundlePriv.h - Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Copyright (c) 1999-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBUNDLEPRIV__) diff --git a/CFBundle_BinaryTypes.h b/CFBundle_BinaryTypes.h index 49d8f63..a85bae6 100644 --- a/CFBundle_BinaryTypes.h +++ b/CFBundle_BinaryTypes.h @@ -22,7 +22,7 @@ */ /* CFBundle_BinaryTypes.h - Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Copyright (c) 1999-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBUNDLE_BINARYTYPES__) @@ -34,12 +34,10 @@ CF_EXTERN_C_BEGIN #define BINARY_SUPPORT_DYLD 1 #define BINARY_SUPPORT_DLFCN 1 #define USE_DYLD_PRIV 1 -#elif DEPLOYMENT_TARGET_EMBEDDED +#elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI #define BINARY_SUPPORT_DYLD 1 #define BINARY_SUPPORT_DLFCN 1 -#if !defined(TARGET_IPHONE_SIMULATOR) #define USE_DYLD_PRIV 1 -#endif #elif DEPLOYMENT_TARGET_WINDOWS #define BINARY_SUPPORT_DLL 1 #else diff --git a/CFBundle_Internal.h b/CFBundle_Internal.h index 9da42d5..b612fd9 100644 --- a/CFBundle_Internal.h +++ b/CFBundle_Internal.h @@ -22,7 +22,7 @@ */ /* CFBundle_Internal.h - Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Copyright (c) 1999-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBUNDLE_INTERNAL__) @@ -41,12 +41,10 @@ CF_EXTERN_C_BEGIN #define __kCFLogBundle 3 #define __kCFLogPlugIn 3 -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -#define PLATFORM_PATH_STYLE kCFURLPOSIXPathStyle -#elif DEPLOYMENT_TARGET_WINDOWS +#if DEPLOYMENT_TARGET_WINDOWS #define PLATFORM_PATH_STYLE kCFURLWindowsPathStyle #else -#error Unknown or unspecified DEPLOYMENT_TARGET +#define PLATFORM_PATH_STYLE kCFURLPOSIXPathStyle #endif #define CFBundleExecutableNotFoundError 4 @@ -56,6 +54,12 @@ CF_EXTERN_C_BEGIN #define CFBundleExecutableLoadError 3587 #define CFBundleExecutableLinkError 3588 +// uncomment this to enable the new look up algorithm +#define CFBUNDLE_NEWLOOKUP + +// uncomment this to enable the checking for 8302591 +//#define CFBUNDLE_NO_TRAVERSE_OUTSIDE + typedef struct __CFResourceData { CFMutableDictionaryRef _stringTableCache; Boolean _executableLacksResourceFork; @@ -90,7 +94,9 @@ extern CFURLRef _CFBundleCopyResourcesDirectoryURLInDirectory(CFURLRef bundleURL extern Boolean _CFBundleCouldBeBundle(CFURLRef url); extern CFURLRef _CFBundleCopyResourceForkURLMayBeLocal(CFBundleRef bundle, Boolean mayBeLocal); extern CFDictionaryRef _CFBundleCopyInfoDictionaryInResourceForkWithAllocator(CFAllocatorRef alloc, CFURLRef url); -extern CFStringRef _CFBundleCopyBundleDevelopmentRegionFromVersResource(CFBundleRef bundle); +#if DEPLOYMENT_TARGET_MACOSX +__private_extern__ CFStringRef _CFBundleCopyBundleDevelopmentRegionFromVersResource(CFBundleRef bundle); +#endif extern CFDictionaryRef _CFBundleCopyInfoDictionaryInExecutable(CFURLRef url); extern CFArrayRef _CFBundleCopyArchitecturesForExecutable(CFURLRef url); @@ -108,6 +114,13 @@ extern void _CFBundleScheduleForUnloading(CFBundleRef bundle); extern void _CFBundleUnscheduleForUnloading(CFBundleRef bundle); extern void _CFBundleUnloadScheduledBundles(void); +__private_extern__ CFStringRef _CFBundleGetBundlePath(CFBundleRef bundle); +__private_extern__ void _CFBundleSetResourceDir(UniChar *buffer, CFIndex *currLen, CFIndex maxLen, uint8_t version); +__private_extern__ CFURLRef _CFBundleCopyResourceForkURLWithoutLocal(CFBundleRef bundle); +__private_extern__ CFDictionaryRef _CFBundleCreateQueryTableAtPath(CFBundleRef bundle, CFURLRef bundleURL, CFArrayRef languages, UniChar *resDir, CFIndex resDirLen, UniChar *subDir, CFIndex subDirLen); +__private_extern__ CFDictionaryRef _CFBundleCopyQueryTable(CFBundleRef bundle, CFURLRef bundleURL, CFArrayRef languages, UniChar *resDir, CFIndex resDirLen, UniChar *subDirBuffer, CFIndex subDirLen); +__private_extern__ CFArrayRef _CFFindBundleResourcesNoBlock(CFBundleRef bundle, CFURLRef bundleURL, CFStringRef subDirName, CFArrayRef searchLanguages, CFStringRef resName, CFArrayRef resTypes, CFIndex limit, uint8_t version); +__private_extern__ CFTypeRef _CFBundleCopyFindResourcesWithNoBlock(CFBundleRef bundle, CFURLRef bundleURL, CFArrayRef languages, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subPath, CFStringRef lproj, Boolean returnArray, Boolean localized); #if defined(BINARY_SUPPORT_DYLD) // DYLD API @@ -152,8 +165,8 @@ extern void _CFPlugInWillUnload(CFPlugInRef plugIn); extern void _CFPlugInAddPlugInInstance(CFPlugInRef plugIn); extern void _CFPlugInRemovePlugInInstance(CFPlugInRef plugIn); -extern void _CFPlugInAddFactory(CFPlugInRef plugIn, _CFPFactory *factory); -extern void _CFPlugInRemoveFactory(CFPlugInRef plugIn, _CFPFactory *factory); +extern void _CFPlugInAddFactory(CFPlugInRef plugIn, _CFPFactoryRef factory); +extern void _CFPlugInRemoveFactory(CFPlugInRef plugIn, _CFPFactoryRef factory); /* Strings for parsing bundle structure */ @@ -205,6 +218,11 @@ extern void _CFPlugInRemoveFactory(CFPlugInRef plugIn, _CFPFactory *factory); #define _CFBundleLprojExtension CFSTR("lproj") #define _CFBundleLprojExtensionWithDot CFSTR(".lproj") +#define _CFBundleDot CFSTR(".") +#define _CFBundleAllFiles CFSTR("_CFBAF_") +#define _CFBundleTypeIndicator CFSTR("_CFBT_") +// This directory contains resources (especially nibs) that may look up localized resources or may fall back to the development language resources +#define _CFBundleBaseDirectory CFSTR("Base") #define _CFBundleMacOSXPlatformName CFSTR("macos") #define _CFBundleAlternateMacOSXPlatformName CFSTR("macosx") @@ -226,9 +244,7 @@ extern void _CFPlugInRemoveFactory(CFPlugInRef plugIn, _CFPFactory *factory); #define _CFBundleLocalizedResourceForkFileName CFSTR("Localized") -#if DEPLOYMENT_TARGET_WINDOWS #define _CFBundleWindowsResourceDirectoryExtension CFSTR("resources") -#endif /* Old platform names (no longer used) */ #define _CFBundleMacOSXPlatformName_OLD CFSTR("macintosh") diff --git a/CFBundle_Resources.c b/CFBundle_Resources.c index a985bd2..ec36901 100644 --- a/CFBundle_Resources.c +++ b/CFBundle_Resources.c @@ -22,20 +22,10 @@ */ /* CFBundle_Resources.c - Copyright (c) 1999-2011, Apple Inc. All rights reserved. - Responsibility: David Smith + Copyright (c) 1999-2012, Apple Inc. All rights reserved. + Responsibility: Tony Parker */ -#if DEPLOYMENT_TARGET_MACOSX -#define READ_DIRECTORIES 1 -#elif DEPLOYMENT_TARGET_EMBEDDED -#define READ_DIRECTORIES 1 -#elif DEPLOYMENT_TARGET_WINDOWS -#define READ_DIRECTORIES 0 -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif - #define READ_DIRECTORIES_CACHE_CAPACITY 128 #include "CFBundle_Internal.h" @@ -54,25 +44,40 @@ #include #include #include -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX +#include #include +#include +#include #endif #if DEPLOYMENT_TARGET_MACOSX -#include -#elif DEPLOYMENT_TARGET_EMBEDDED -#include -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET + #endif -#if READ_DIRECTORIES -#include -#endif /* READ_DIRECTORIES */ +#if DEPLOYMENT_TARGET_WINDOWS +#include +#include +#include +#include + +#define close _close +#define write _write +#define read _read +#define open _NS_open +#define stat _NS_stat +#define fstat _fstat +#define mkdir(a,b) _NS_mkdir(a) +#define rmdir _NS_rmdir +#define unlink _NS_unlink + +#endif CF_EXPORT bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict, const void *key, const void **actualkey); +extern void _CFStrSetDesiredCapacity(CFMutableStringRef str, CFIndex len); + static inline Boolean _CFBundleSortedArrayContains(CFArrayRef arr, CFStringRef target) { CFRange arrRange = CFRangeMake(0, CFArrayGetCount(arr)); @@ -80,13 +85,13 @@ static inline Boolean _CFBundleSortedArrayContains(CFArrayRef arr, CFStringRef t return itemIdx < arrRange.length && CFEqual(CFArrayGetValueAtIndex(arr, itemIdx), target); } -// The following strings are initialized 'later' (i.e., not at static initialization time) because static init time is too early for CFSTR to work, on Windows -// This is here to make sure it gets updated when _CFGetPlatformName does +// The following strings are initialized 'later' (i.e., not at static initialization time) because static init time is too early for CFSTR to work, on platforms without constant CF strings +#if !__CONSTANT_STRINGS__ + #define _CFBundleNumberOfPlatforms 7 static CFStringRef _CFBundleSupportedPlatforms[_CFBundleNumberOfPlatforms] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; static const char *_CFBundleSupportedPlatformStrings[_CFBundleNumberOfPlatforms] = { "iphoneos", "macos", "windows", "linux", "freebsd", "solaris", "hpux" }; -// This is here to make sure it gets updated when _CFGetProductName does #define _CFBundleNumberOfProducts 3 static CFStringRef _CFBundleSupportedProducts[_CFBundleNumberOfProducts] = { NULL, NULL, NULL }; static const char *_CFBundleSupportedProductStrings[_CFBundleNumberOfProducts] = { "iphone", "ipod", "ipad" }; @@ -95,7 +100,7 @@ static const char *_CFBundleSupportedProductStrings[_CFBundleNumberOfProducts] = static CFStringRef _CFBundleSupportediPhoneOSPlatformProducts[_CFBundleNumberOfiPhoneOSPlatformProducts] = { NULL, NULL, NULL }; static const char *_CFBundleSupportediPhoneOSPlatformProductStrings[_CFBundleNumberOfiPhoneOSPlatformProducts] = { "iphone", "ipod", "ipad" }; -void _CFBundleResourcesInitialize() { +__private_extern__ void _CFBundleResourcesInitialize() { for (unsigned int i = 0; i < _CFBundleNumberOfPlatforms; i++) _CFBundleSupportedPlatforms[i] = CFStringCreateWithCString(kCFAllocatorSystemDefault, _CFBundleSupportedPlatformStrings[i], kCFStringEncodingUTF8); for (unsigned int i = 0; i < _CFBundleNumberOfProducts; i++) _CFBundleSupportedProducts[i] = CFStringCreateWithCString(kCFAllocatorSystemDefault, _CFBundleSupportedProductStrings[i], kCFStringEncodingUTF8); @@ -103,6 +108,27 @@ void _CFBundleResourcesInitialize() { for (unsigned int i = 0; i < _CFBundleNumberOfiPhoneOSPlatformProducts; i++) _CFBundleSupportediPhoneOSPlatformProducts[i] = CFStringCreateWithCString(kCFAllocatorSystemDefault, _CFBundleSupportediPhoneOSPlatformProductStrings[i], kCFStringEncodingUTF8); } +#else + +#if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI +// On iOS, we only support one platform +#define _CFBundleNumberOfPlatforms 1 +static CFStringRef _CFBundleSupportedPlatforms[_CFBundleNumberOfPlatforms] = { CFSTR("iphoneos") }; +#else +// On other platforms, we support the following platforms +#define _CFBundleNumberOfPlatforms 7 +static CFStringRef _CFBundleSupportedPlatforms[_CFBundleNumberOfPlatforms] = { CFSTR("iphoneos"), CFSTR("macos"), CFSTR("windows"), CFSTR("linux"), CFSTR("freebsd"), CFSTR("solaris"), CFSTR("hpux") }; +#endif + +#define _CFBundleNumberOfProducts 3 +static CFStringRef _CFBundleSupportedProducts[_CFBundleNumberOfProducts] = { CFSTR("iphone"), CFSTR("ipod"), CFSTR("ipad") }; + +#define _CFBundleNumberOfiPhoneOSPlatformProducts 3 +static CFStringRef _CFBundleSupportediPhoneOSPlatformProducts[_CFBundleNumberOfiPhoneOSPlatformProducts] = { CFSTR("iphone"), CFSTR("ipod"), CFSTR("ipad") }; + +__private_extern__ void _CFBundleResourcesInitialize() { } +#endif + static CFStringRef platform = NULL; void _CFSetProductName(CFStringRef str) { @@ -115,8 +141,8 @@ void _CFSetProductName(CFStringRef str) { // shouldn't be screwing around with this value casually. } -CFStringRef _CFGetProductName(void) { -#if DEPLOYMENT_TARGET_EMBEDDED +CF_EXPORT CFStringRef _CFGetProductName(void) { +#if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI if (!platform) { char buffer[256]; memset(buffer, 0, sizeof(buffer)); @@ -152,10 +178,10 @@ CFStringRef _CFGetProductName(void) { } // All new-style bundles will have these extensions. -__private_extern__ CFStringRef _CFGetPlatformName(void) { +CF_EXPORT CFStringRef _CFGetPlatformName(void) { #if DEPLOYMENT_TARGET_MACOSX return _CFBundleMacOSXPlatformName; -#elif DEPLOYMENT_TARGET_EMBEDDED +#elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI return _CFBundleiPhoneOSPlatformName; #elif DEPLOYMENT_TARGET_WINDOWS return _CFBundleWindowsPlatformName; @@ -172,10 +198,10 @@ __private_extern__ CFStringRef _CFGetPlatformName(void) { #endif } -__private_extern__ CFStringRef _CFGetAlternatePlatformName(void) { +CF_EXPORT CFStringRef _CFGetAlternatePlatformName(void) { #if DEPLOYMENT_TARGET_MACOSX return _CFBundleAlternateMacOSXPlatformName; -#elif DEPLOYMENT_TARGET_EMBEDDED +#elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI return _CFBundleMacOSXPlatformName; #elif DEPLOYMENT_TARGET_WINDOWS return CFSTR(""); @@ -184,7 +210,6 @@ __private_extern__ CFStringRef _CFGetAlternatePlatformName(void) { #endif } -static CFSpinLock_t CFBundleResourceGlobalDataLock = CFSpinLockInit; static UniChar *_AppSupportUniChars1 = NULL; static CFIndex _AppSupportLen1 = 0; static UniChar *_AppSupportUniChars2 = NULL; @@ -197,13 +222,17 @@ static UniChar *_AlternatePlatformUniChars = NULL; static CFIndex _AlternatePlatformLen = 0; static UniChar *_LprojUniChars = NULL; static CFIndex _LprojLen = 0; +static UniChar *_BaseUniChars = NULL; +static CFIndex _BaseLen; static UniChar *_GlobalResourcesUniChars = NULL; static CFIndex _GlobalResourcesLen = 0; static UniChar *_InfoExtensionUniChars = NULL; static CFIndex _InfoExtensionLen = 0; +#if 0 static UniChar _ResourceSuffix3[32]; static CFIndex _ResourceSuffix3Len = 0; +#endif static UniChar _ResourceSuffix2[16]; static CFIndex _ResourceSuffix2Len = 0; static UniChar _ResourceSuffix1[16]; @@ -218,6 +247,7 @@ static void _CFBundleInitStaticUniCharBuffers(void) { CFStringRef lprojStr = _CFBundleLprojExtension; CFStringRef globalResourcesStr = _CFBundleNonLocalizedResourcesDirectoryName; CFStringRef infoExtensionStr = _CFBundleInfoExtension; + CFStringRef baseStr = _CFBundleBaseDirectory; _AppSupportLen1 = CFStringGetLength(appSupportStr1); _AppSupportLen2 = CFStringGetLength(appSupportStr2); @@ -227,8 +257,9 @@ static void _CFBundleInitStaticUniCharBuffers(void) { _LprojLen = CFStringGetLength(lprojStr); _GlobalResourcesLen = CFStringGetLength(globalResourcesStr); _InfoExtensionLen = CFStringGetLength(infoExtensionStr); + _BaseLen = CFStringGetLength(baseStr); - _AppSupportUniChars1 = (UniChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UniChar) * (_AppSupportLen1 + _AppSupportLen2 + _ResourcesLen + _PlatformLen + _AlternatePlatformLen + _LprojLen + _GlobalResourcesLen + _InfoExtensionLen), 0); + _AppSupportUniChars1 = (UniChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UniChar) * (_AppSupportLen1 + _AppSupportLen2 + _ResourcesLen + _PlatformLen + _AlternatePlatformLen + _LprojLen + _GlobalResourcesLen + _InfoExtensionLen + _BaseLen), 0); _AppSupportUniChars2 = _AppSupportUniChars1 + _AppSupportLen1; _ResourcesUniChars = _AppSupportUniChars2 + _AppSupportLen2; _PlatformUniChars = _ResourcesUniChars + _ResourcesLen; @@ -236,7 +267,8 @@ static void _CFBundleInitStaticUniCharBuffers(void) { _LprojUniChars = _AlternatePlatformUniChars + _AlternatePlatformLen; _GlobalResourcesUniChars = _LprojUniChars + _LprojLen; _InfoExtensionUniChars = _GlobalResourcesUniChars + _GlobalResourcesLen; - + _BaseUniChars = _InfoExtensionUniChars + _InfoExtensionLen; + if (_AppSupportLen1 > 0) CFStringGetCharacters(appSupportStr1, CFRangeMake(0, _AppSupportLen1), _AppSupportUniChars1); if (_AppSupportLen2 > 0) CFStringGetCharacters(appSupportStr2, CFRangeMake(0, _AppSupportLen2), _AppSupportUniChars2); if (_ResourcesLen > 0) CFStringGetCharacters(resourcesStr, CFRangeMake(0, _ResourcesLen), _ResourcesUniChars); @@ -245,6 +277,7 @@ static void _CFBundleInitStaticUniCharBuffers(void) { if (_LprojLen > 0) CFStringGetCharacters(lprojStr, CFRangeMake(0, _LprojLen), _LprojUniChars); if (_GlobalResourcesLen > 0) CFStringGetCharacters(globalResourcesStr, CFRangeMake(0, _GlobalResourcesLen), _GlobalResourcesUniChars); if (_InfoExtensionLen > 0) CFStringGetCharacters(infoExtensionStr, CFRangeMake(0, _InfoExtensionLen), _InfoExtensionUniChars); + if (_BaseLen > 0) CFStringGetCharacters(baseStr, CFRangeMake(0, _BaseLen), _BaseUniChars); _ResourceSuffix1Len = CFStringGetLength(platformStr); if (_ResourceSuffix1Len > 0) _ResourceSuffix1[0] = '-'; @@ -258,24 +291,26 @@ static void _CFBundleInitStaticUniCharBuffers(void) { if (_ResourceSuffix2Len > 0) _ResourceSuffix2[0] = '~'; if (_ResourceSuffix2Len > 0) CFStringGetCharacters(productStr, CFRangeMake(0, _ResourceSuffix2Len), _ResourceSuffix2 + 1); if (_ResourceSuffix2Len > 0) _ResourceSuffix2Len++; +#if 0 if (_ResourceSuffix1Len > 1 && _ResourceSuffix2Len > 1) { _ResourceSuffix3Len = _ResourceSuffix1Len + _ResourceSuffix2Len; memmove(_ResourceSuffix3, _ResourceSuffix1, sizeof(UniChar) * _ResourceSuffix1Len); memmove(_ResourceSuffix3 + _ResourceSuffix1Len, _ResourceSuffix2, sizeof(UniChar) * _ResourceSuffix2Len); } +#endif } CF_INLINE void _CFEnsureStaticBuffersInited(void) { - __CFSpinLock(&CFBundleResourceGlobalDataLock); - if (!_AppSupportUniChars1) _CFBundleInitStaticUniCharBuffers(); - __CFSpinUnlock(&CFBundleResourceGlobalDataLock); + static dispatch_once_t once = 0; + dispatch_once(&once, ^{ + _CFBundleInitStaticUniCharBuffers(); + }); } -#if READ_DIRECTORIES - -static CFMutableDictionaryRef contentsCache = NULL; -static CFMutableDictionaryRef directoryContentsCache = NULL; -static CFMutableDictionaryRef unknownContentsCache = NULL; +static CFSpinLock_t _cacheLock = CFSpinLockInit; +static CFMutableDictionaryRef _contentsCache = NULL; +static CFMutableDictionaryRef _directoryContentsCache = NULL; +static CFMutableDictionaryRef _unknownContentsCache = NULL; typedef enum { _CFBundleAllContents = 0, @@ -288,23 +323,21 @@ extern void _CFArraySortValues(CFMutableArrayRef array, CFComparatorFunction com static CFArrayRef _CFBundleCopySortedDirectoryContentsAtPath(CFStringRef path, _CFBundleDirectoryContentsType contentsType) { CFArrayRef result = NULL; - __CFSpinLock(&CFBundleResourceGlobalDataLock); + __CFSpinLock(&_cacheLock); if (contentsType == _CFBundleUnknownContents) { - if (unknownContentsCache) result = (CFMutableArrayRef)CFDictionaryGetValue(unknownContentsCache, path); + if (_unknownContentsCache) result = (CFMutableArrayRef)CFDictionaryGetValue(_unknownContentsCache, path); } else if (contentsType == _CFBundleDirectoryContents) { - if (directoryContentsCache) result = (CFMutableArrayRef)CFDictionaryGetValue(directoryContentsCache, path); + if (_directoryContentsCache) result = (CFMutableArrayRef)CFDictionaryGetValue(_directoryContentsCache, path); } else { - if (contentsCache) result = (CFMutableArrayRef)CFDictionaryGetValue(contentsCache, path); + if (_contentsCache) result = (CFMutableArrayRef)CFDictionaryGetValue(_contentsCache, path); } if (result) CFRetain(result); - __CFSpinUnlock(&CFBundleResourceGlobalDataLock); + __CFSpinUnlock(&_cacheLock); if (!result) { Boolean tryToOpen = false, allDots = true; char cpathBuff[CFMaxPathSize]; CFIndex cpathLen = 0, idx, lastSlashIdx = 0; - DIR *dirp = NULL; - struct dirent *dent; CFMutableArrayRef contents = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks), directoryContents = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks), unknownContents = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); CFStringRef dirName, name; @@ -315,7 +348,7 @@ static CFArrayRef _CFBundleCopySortedDirectoryContentsAtPath(CFStringRef path, _ // First see whether we already know that the directory doesn't exist for (idx = cpathLen; lastSlashIdx == 0 && idx-- > 0;) { - if (cpathBuff[idx] == '/') lastSlashIdx = idx; + if (cpathBuff[idx] == PATH_SEP) lastSlashIdx = idx; else if (cpathBuff[idx] != '.') allDots = false; } if (lastSlashIdx > 0 && lastSlashIdx + 1 < cpathLen && !allDots) { @@ -324,25 +357,70 @@ static CFArrayRef _CFBundleCopySortedDirectoryContentsAtPath(CFStringRef path, _ if (dirName) { name = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, cpathBuff + lastSlashIdx + 1); if (name) { - // ??? we might like to use directoryContentsCache rather than contentsCache here, but we cannot unless we resolve DT_LNKs below + // ??? we might like to use _directoryContentsCache rather than _contentsCache here, but we cannot unless we resolve DT_LNKs below CFArrayRef dirDirContents = NULL; - __CFSpinLock(&CFBundleResourceGlobalDataLock); - if (contentsCache) dirDirContents = (CFArrayRef)CFDictionaryGetValue(contentsCache, dirName); + __CFSpinLock(&_cacheLock); + if (_contentsCache) dirDirContents = (CFArrayRef)CFDictionaryGetValue(_contentsCache, dirName); if (dirDirContents) { Boolean foundIt = false; CFIndex dirDirIdx, dirDirLength = CFArrayGetCount(dirDirContents); - for (dirDirIdx = 0; !foundIt && dirDirIdx < dirDirLength; dirDirIdx++) if (kCFCompareEqualTo == CFStringCompare(name, CFArrayGetValueAtIndex(dirDirContents, dirDirIdx), kCFCompareCaseInsensitive)) foundIt = true; + for (dirDirIdx = 0; !foundIt && dirDirIdx < dirDirLength; dirDirIdx++) if (kCFCompareEqualTo == CFStringCompare(name, (CFStringRef)CFArrayGetValueAtIndex(dirDirContents, dirDirIdx), kCFCompareCaseInsensitive)) foundIt = true; if (!foundIt) tryToOpen = false; } - __CFSpinUnlock(&CFBundleResourceGlobalDataLock); + __CFSpinUnlock(&_cacheLock); CFRelease(name); } CFRelease(dirName); } - cpathBuff[lastSlashIdx] = '/'; + cpathBuff[lastSlashIdx] = PATH_SEP; } } +#if DEPLOYMENT_TARGET_WINDOWS + // Make sure there is room for the additional space we need in the win32 api + if (tryToOpen && cpathLen + 2 < CFMaxPathSize) { + WIN32_FIND_DATAW file; + HANDLE handle; + + cpathBuff[cpathLen++] = '\\'; + cpathBuff[cpathLen++] = '*'; + cpathBuff[cpathLen] = '\0'; + + // Convert UTF8 buffer to windows appropriate UTF-16LE + // Get the real length of the string in UTF16 characters + CFStringRef cfStr = CFStringCreateWithCString(kCFAllocatorSystemDefault, cpathBuff, kCFStringEncodingUTF8); + cpathLen = CFStringGetLength(cfStr); + // Allocate a wide buffer to hold the converted string, including space for a NULL terminator + wchar_t *wideBuf = (wchar_t *)malloc((cpathLen + 1) * sizeof(wchar_t)); + // Copy the string into the buffer and terminate + CFStringGetCharacters(cfStr, CFRangeMake(0, cpathLen), (UniChar *)wideBuf); + wideBuf[cpathLen] = 0; + CFRelease(cfStr); + + handle = FindFirstFileW(wideBuf, (LPWIN32_FIND_DATAW)&file); + if (handle != INVALID_HANDLE_VALUE) { + do { + CFIndex nameLen = wcslen(file.cFileName); + if (0 == nameLen || ('.' == file.cFileName[0] && (1 == nameLen || (2 == nameLen && '.' == file.cFileName[1]) || '_' == file.cFileName[1]))) continue; + name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (const uint8_t *)file.cFileName, nameLen * sizeof(wchar_t), kCFStringEncodingUTF16, NO); + if (name) { + CFArrayAppendValue(contents, name); + if (file.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) { + CFArrayAppendValue(directoryContents, name); + } /* else if (file.dwFileAttributes == DT_UNKNOWN) { + CFArrayAppendValue(unknownContents, name); + } */ + CFRelease(name); + } + } while (FindNextFileW(handle, &file)); + + FindClose(handle); + } + free(wideBuf); + } +#else + DIR *dirp = NULL; + struct dirent *dent; if (tryToOpen && (dirp = opendir(cpathBuff))) { while ((dent = readdir(dirp))) { CFIndex nameLen = dent->d_namlen; @@ -363,46 +441,47 @@ static CFArrayRef _CFBundleCopySortedDirectoryContentsAtPath(CFStringRef path, _ } (void)closedir(dirp); } +#endif _CFArraySortValues(contents, (CFComparatorFunction)CFStringCompare, NULL); _CFArraySortValues(directoryContents, (CFComparatorFunction)CFStringCompare, NULL); _CFArraySortValues(unknownContents, (CFComparatorFunction)CFStringCompare, NULL); - __CFSpinLock(&CFBundleResourceGlobalDataLock); - if (!contentsCache) contentsCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, READ_DIRECTORIES_CACHE_CAPACITY, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (READ_DIRECTORIES_CACHE_CAPACITY <= CFDictionaryGetCount(contentsCache)) CFDictionaryRemoveAllValues(contentsCache); - CFDictionaryAddValue(contentsCache, path, contents); + __CFSpinLock(&_cacheLock); + if (!_contentsCache) _contentsCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, READ_DIRECTORIES_CACHE_CAPACITY, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (READ_DIRECTORIES_CACHE_CAPACITY <= CFDictionaryGetCount(_contentsCache)) CFDictionaryRemoveAllValues(_contentsCache); + CFDictionaryAddValue(_contentsCache, path, contents); - if (!directoryContentsCache) directoryContentsCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, READ_DIRECTORIES_CACHE_CAPACITY, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (READ_DIRECTORIES_CACHE_CAPACITY <= CFDictionaryGetCount(directoryContentsCache)) CFDictionaryRemoveAllValues(directoryContentsCache); - CFDictionaryAddValue(directoryContentsCache, path, directoryContents); + if (!_directoryContentsCache) _directoryContentsCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, READ_DIRECTORIES_CACHE_CAPACITY, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (READ_DIRECTORIES_CACHE_CAPACITY <= CFDictionaryGetCount(_directoryContentsCache)) CFDictionaryRemoveAllValues(_directoryContentsCache); + CFDictionaryAddValue(_directoryContentsCache, path, directoryContents); - if (!unknownContentsCache) unknownContentsCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, READ_DIRECTORIES_CACHE_CAPACITY, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (READ_DIRECTORIES_CACHE_CAPACITY <= CFDictionaryGetCount(unknownContentsCache)) CFDictionaryRemoveAllValues(unknownContentsCache); - CFDictionaryAddValue(unknownContentsCache, path, unknownContents); + if (!_unknownContentsCache) _unknownContentsCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, READ_DIRECTORIES_CACHE_CAPACITY, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (READ_DIRECTORIES_CACHE_CAPACITY <= CFDictionaryGetCount(_unknownContentsCache)) CFDictionaryRemoveAllValues(_unknownContentsCache); + CFDictionaryAddValue(_unknownContentsCache, path, unknownContents); if (contentsType == _CFBundleUnknownContents) { - result = CFRetain(unknownContents); + result = (CFArrayRef)CFRetain(unknownContents); } else if (contentsType == _CFBundleDirectoryContents) { - result = CFRetain(directoryContents); + result = (CFArrayRef)CFRetain(directoryContents); } else { - result = CFRetain(contents); + result = (CFArrayRef)CFRetain(contents); } CFRelease(contents); CFRelease(directoryContents); CFRelease(unknownContents); - __CFSpinUnlock(&CFBundleResourceGlobalDataLock); + __CFSpinUnlock(&_cacheLock); } return result; } static void _CFBundleFlushContentsCaches(void) { - __CFSpinLock(&CFBundleResourceGlobalDataLock); - if (contentsCache) CFDictionaryRemoveAllValues(contentsCache); - if (directoryContentsCache) CFDictionaryRemoveAllValues(directoryContentsCache); - if (unknownContentsCache) CFDictionaryRemoveAllValues(unknownContentsCache); - __CFSpinUnlock(&CFBundleResourceGlobalDataLock); + __CFSpinLock(&_cacheLock); + if (_contentsCache) CFDictionaryRemoveAllValues(_contentsCache); + if (_directoryContentsCache) CFDictionaryRemoveAllValues(_directoryContentsCache); + if (_unknownContentsCache) CFDictionaryRemoveAllValues(_unknownContentsCache); + __CFSpinUnlock(&_cacheLock); } static void _CFBundleFlushContentsCacheForPath(CFMutableDictionaryRef cache, CFStringRef path) { @@ -417,29 +496,23 @@ static void _CFBundleFlushContentsCacheForPath(CFMutableDictionaryRef cache, CFS } static void _CFBundleFlushContentsCachesForPath(CFStringRef path) { - __CFSpinLock(&CFBundleResourceGlobalDataLock); - if (contentsCache) _CFBundleFlushContentsCacheForPath(contentsCache, path); - if (directoryContentsCache) _CFBundleFlushContentsCacheForPath(directoryContentsCache, path); - if (unknownContentsCache) _CFBundleFlushContentsCacheForPath(unknownContentsCache, path); - __CFSpinUnlock(&CFBundleResourceGlobalDataLock); + __CFSpinLock(&_cacheLock); + if (_contentsCache) _CFBundleFlushContentsCacheForPath(_contentsCache, path); + if (_directoryContentsCache) _CFBundleFlushContentsCacheForPath(_directoryContentsCache, path); + if (_unknownContentsCache) _CFBundleFlushContentsCacheForPath(_unknownContentsCache, path); + __CFSpinUnlock(&_cacheLock); } -#endif /* READ_DIRECTORIES */ - CF_EXPORT void _CFBundleFlushCachesForURL(CFURLRef url) { -#if READ_DIRECTORIES CFURLRef absoluteURL = CFURLCopyAbsoluteURL(url); CFStringRef path = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); _CFBundleFlushContentsCachesForPath(path); CFRelease(path); CFRelease(absoluteURL); -#endif /* READ_DIRECTORIES */ } CF_EXPORT void _CFBundleFlushCaches(void) { -#if READ_DIRECTORIES _CFBundleFlushContentsCaches(); -#endif /* READ_DIRECTORIES */ } static inline Boolean _CFIsResourceCommon(char *path, Boolean *isDir) { @@ -466,7 +539,15 @@ __private_extern__ Boolean _CFIsResourceAtPath(CFStringRef path, Boolean *isDir) return _CFIsResourceCommon(pathBuf, isDir); } -#if READ_DIRECTORIES +__private_extern__ void _CFBundleSetResourceDir(UniChar *buffer, CFIndex *currLen, CFIndex maxLen, uint8_t version){ + if (1 == version) { + _CFAppendPathComponent(buffer, currLen, maxLen, _AppSupportUniChars1, _AppSupportLen1); + } else if (2 == version) { + _CFAppendPathComponent(buffer, currLen, maxLen, _AppSupportUniChars2, _AppSupportLen2); + } + if (0 == version || 1 == version || 2 == version) _CFAppendPathComponent(buffer, currLen, maxLen, _ResourcesUniChars, _ResourcesLen); +} + static CFArrayRef _CFCopyTypesForSearchBundleDirectory(CFAllocatorRef alloc, UniChar *pathUniChars, CFIndex pathLen, UniChar *nameUniChars, CFIndex nameLen, CFArrayRef resTypes, CFMutableStringRef cheapStr, CFMutableStringRef tmpString, uint8_t version) { CFMutableArrayRef result = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks); CFArrayRef contents; @@ -482,11 +563,11 @@ static CFArrayRef _CFCopyTypesForSearchBundleDirectory(CFAllocatorRef alloc, Uni CFStringSetExternalCharactersNoCopy(tmpString, nameUniChars, nameLen, nameLen); CFStringReplaceAll(cheapStr, tmpString); for (i = 0; i < contentsRange.length; i++) { - CFStringRef content = CFArrayGetValueAtIndex(contents, i); + CFStringRef content = (CFStringRef)CFArrayGetValueAtIndex(contents, i); if (CFStringHasPrefix(content, cheapStr)) { //fprintf(stderr, "found ");CFShow(content); for (j = 0; j < numResTypes; j++) { - CFStringRef resType = CFArrayGetValueAtIndex(resTypes, j); + CFStringRef resType = (CFStringRef)CFArrayGetValueAtIndex(resTypes, j); if (!CFArrayContainsValue(result, resultRange, resType) && CFStringHasSuffix(content, resType)) { CFArrayAppendValue(result, resType); resultRange.length = CFArrayGetCount(result); @@ -498,9 +579,8 @@ static CFArrayRef _CFCopyTypesForSearchBundleDirectory(CFAllocatorRef alloc, Uni CFRelease(contents); return result; } -#endif /* READ_DIRECTORIES */ -#if DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI static void _CFSearchBundleDirectory2(CFAllocatorRef alloc, CFMutableArrayRef result, UniChar *pathUniChars, CFIndex pathLen, UniChar *nameUniChars, CFIndex nameLen, UniChar *typeUniChars, CFIndex typeLen, CFMutableStringRef cheapStr, CFMutableStringRef tmpString, uint8_t version) { // pathUniChars is the full path to the directory we are searching. // nameUniChars is what we are looking for. @@ -603,7 +683,7 @@ static void _CFSearchBundleDirectory2(CFAllocatorRef alloc, CFMutableArrayRef re static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef result, UniChar *pathUniChars, CFIndex pathLen, UniChar *nameUniChars, CFIndex nameLen, UniChar *typeUniChars, CFIndex typeLen, CFMutableStringRef cheapStr, CFMutableStringRef tmpString, uint8_t version) { -#if DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI _CFSearchBundleDirectory2(alloc, result, pathUniChars, pathLen, nameUniChars, nameLen, typeUniChars, typeLen, cheapStr, tmpString, version); #else // pathUniChars is the full path to the directory we are searching. @@ -614,12 +694,9 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res // URLs for found resources get added to result. CFIndex savedPathLen; Boolean appendSucceeded = true, platformGenericFound = false, platformSpecificFound = false, platformGenericIsDir = false, platformSpecificIsDir = false; -#if READ_DIRECTORIES Boolean platformGenericIsUnknown = false, platformSpecificIsUnknown = false; -#endif CFStringRef platformGenericStr = NULL; -#if READ_DIRECTORIES CFIndex dirPathLen = pathLen; CFArrayRef contents, directoryContents, unknownContents; CFRange contentsRange, directoryContentsRange, unknownContentsRange; @@ -633,13 +710,11 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res directoryContentsRange = CFRangeMake(0, CFArrayGetCount(directoryContents)); unknownContents = _CFBundleCopySortedDirectoryContentsAtPath(cheapStr, _CFBundleUnknownContents); unknownContentsRange = CFRangeMake(0, CFArrayGetCount(unknownContents)); -#endif /* READ_DIRECTORIES */ if (nameLen > 0) appendSucceeded = _CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, nameUniChars, nameLen); savedPathLen = pathLen; if (appendSucceeded && typeLen > 0) appendSucceeded = _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, typeUniChars, typeLen); if (appendSucceeded) { -#if READ_DIRECTORIES CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + dirPathLen + 1, pathLen - dirPathLen - 1, pathLen - dirPathLen - 1); CFStringReplaceAll(cheapStr, tmpString); platformGenericFound = _CFBundleSortedArrayContains(contents, cheapStr); @@ -652,11 +727,6 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res (void)_CFIsResourceAtPath(cheapStr, &platformGenericIsDir); //if (platformGenericIsDir) fprintf(stderr, "a directory after all\n"); else fprintf(stderr, "not a directory after all\n"); } -#else /* READ_DIRECTORIES */ - CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); - CFStringReplaceAll(cheapStr, tmpString); - platformGenericFound = _CFIsResourceAtPath(cheapStr, &platformGenericIsDir); -#endif /* READ_DIRECTORIES */ } // Check for platform specific. @@ -669,7 +739,6 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res pathLen += _PlatformLen; if (appendSucceeded && typeLen > 0) appendSucceeded = _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, typeUniChars, typeLen); if (appendSucceeded) { -#if READ_DIRECTORIES CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + dirPathLen + 1, pathLen - dirPathLen - 1, pathLen - dirPathLen - 1); CFStringReplaceAll(cheapStr, tmpString); platformSpecificFound = _CFBundleSortedArrayContains(contents, cheapStr); @@ -682,11 +751,6 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res (void)_CFIsResourceAtPath(cheapStr, &platformSpecificIsDir); //if (platformSpecificIsDir) fprintf(stderr, "a directory after all\n"); else fprintf(stderr, "not a directory after all\n"); } -#else /* READ_DIRECTORIES */ - CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); - CFStringReplaceAll(cheapStr, tmpString); - platformSpecificFound = _CFIsResourceAtPath(cheapStr, &platformSpecificIsDir); -#endif /* READ_DIRECTORIES */ } } } @@ -700,15 +764,12 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res CFRelease(url); } if (platformGenericStr) CFRelease(platformGenericStr); -#if READ_DIRECTORIES CFRelease(contents); CFRelease(directoryContents); CFRelease(unknownContents); -#endif /* READ_DIRECTORIES */ #endif } -#if READ_DIRECTORIES static void _CFSearchBundleDirectoryWithPredicate(CFAllocatorRef alloc, CFMutableArrayRef result, UniChar *pathUniChars, CFIndex dirPathLen, Boolean (^predicate)(CFStringRef filename, Boolean *stop), CFMutableStringRef cheapStr, CFMutableStringRef tmpString, Boolean *stopLooking, uint8_t version) { // pathUniChars is the full path to the directory we are searching. @@ -736,7 +797,7 @@ static void _CFSearchBundleDirectoryWithPredicate(CFAllocatorRef alloc, CFMutabl // scan directory contents for matches against predicate for (int i = 0; i < contentsRange.length; i++) { - CFStringRef candidateFilename = CFArrayGetValueAtIndex(contents, i); + CFStringRef candidateFilename = (CFStringRef)CFArrayGetValueAtIndex(contents, i); if (predicate(candidateFilename, stopLooking)) { // we want this resource, though possibly a platform specific version of it // unpack candidateFilename string into pathUniChars after verifying that we have enough space in the buffer @@ -794,17 +855,12 @@ static void _CFSearchBundleDirectoryWithPredicate(CFAllocatorRef alloc, CFMutabl CFRelease(directoryContents); CFRelease(unknownContents); } -#endif + static void _CFFindBundleResourcesInRawDir(CFAllocatorRef alloc, UniChar *workingUniChars, CFIndex workingLen, UniChar *nameUniChars, CFIndex nameLen, CFArrayRef resTypes, CFIndex limit, Boolean *stopLooking, Boolean (^predicate)(CFStringRef filename, Boolean *stop), uint8_t version, CFMutableStringRef cheapStr, CFMutableStringRef tmpString, CFMutableArrayRef result) { if (predicate) { -#if READ_DIRECTORIES _CFSearchBundleDirectoryWithPredicate(alloc, result, workingUniChars, workingLen, predicate, cheapStr, tmpString, stopLooking, version); return; -#else - CFLog(kCFLogLevelCritical, CFSTR("_CFFindBundleResourcesInRawDir: predicate blocks are not supported on this platform")); - HALT; -#endif } if (nameLen > 0) { // If we have a resName, just call the search API. We may have to loop over the resTypes. @@ -814,7 +870,6 @@ static void _CFFindBundleResourcesInRawDir(CFAllocatorRef alloc, UniChar *workin CFArrayRef subResTypes = resTypes; Boolean releaseSubResTypes = false; CFIndex i, c = CFArrayGetCount(resTypes); -#if READ_DIRECTORIES if (c > 2) { // this is an optimization we employ when searching for large numbers of types, if the directory contents are available // we scan the directory contents and restrict the list of resTypes to the types that might actually occur with the specified name @@ -822,7 +877,6 @@ static void _CFFindBundleResourcesInRawDir(CFAllocatorRef alloc, UniChar *workin c = CFArrayGetCount(subResTypes); releaseSubResTypes = true; } -#endif /* READ_DIRECTORIES */ for (i = 0; i < c; i++) { CFStringRef curType = (CFStringRef)CFArrayGetValueAtIndex(subResTypes, i); CFIndex typeLen = CFStringGetLength(curType); @@ -869,6 +923,7 @@ static void _CFFindBundleResourcesInRawDir(CFAllocatorRef alloc, UniChar *workin } } + static void _CFFindBundleResourcesInResourcesDir(CFAllocatorRef alloc, UniChar *workingUniChars, CFIndex workingLen, UniChar *subDirUniChars, CFIndex subDirLen, CFArrayRef searchLanguages, UniChar *nameUniChars, CFIndex nameLen, CFArrayRef resTypes, CFIndex limit, Boolean (^predicate)(CFStringRef filename, Boolean *stop), uint8_t version, CFMutableStringRef cheapStr, CFMutableStringRef tmpString, CFMutableArrayRef result) { CFIndex savedWorkingLen = workingLen; Boolean stopLooking = false; // for predicate based-queries, we set stopLooking instead of using a limit @@ -881,24 +936,68 @@ static void _CFFindBundleResourcesInResourcesDir(CFAllocatorRef alloc, UniChar * // Strip the non-localized resource directory. workingLen = savedWorkingLen; } + if (CFArrayGetCount(result) < limit && !stopLooking) { Boolean appendSucceeded = true; if (subDirLen > 0) appendSucceeded = _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, subDirUniChars, subDirLen); if (appendSucceeded) _CFFindBundleResourcesInRawDir(alloc, workingUniChars, workingLen, nameUniChars, nameLen, resTypes, limit, &stopLooking, predicate, version, cheapStr, tmpString, result); } - // Now search the local resources. + // Now search the first localized resources (user language). + CFIndex langCount = (searchLanguages ? CFArrayGetCount(searchLanguages) : 0); + UniChar curLangUniChars[255]; + workingLen = savedWorkingLen; + if (CFArrayGetCount(result) < limit && !stopLooking && langCount >= 1) { + CFIndex numResults = CFArrayGetCount(result); + CFStringRef curLangStr = (CFStringRef)CFArrayGetValueAtIndex(searchLanguages, 0); + CFIndex curLangLen = MIN(CFStringGetLength(curLangStr), 255); + CFStringGetCharacters(curLangStr, CFRangeMake(0, curLangLen), curLangUniChars); + + savedWorkingLen = workingLen; + if (_CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, curLangUniChars, curLangLen) && + _CFAppendPathExtension(workingUniChars, &workingLen, CFMaxPathSize, _LprojUniChars, _LprojLen) && + (subDirLen == 0 || (subDirLen > 0 && _CFAppendPathExtension(workingUniChars, &workingLen, CFMaxPathSize, subDirUniChars, subDirLen)))) { + + _CFFindBundleResourcesInRawDir(alloc, workingUniChars, workingLen, nameUniChars, nameLen, resTypes, limit, &stopLooking, predicate, version, cheapStr, tmpString, result); + + if (CFArrayGetCount(result) != numResults) { + // We found resources in a language we already searched. Don't look any farther. + // We also don't need to check the limit, since if the count changed at all, we are bailing. + return; + } + } + } + + workingLen = savedWorkingLen; + // Now search the Base.lproj directory if (CFArrayGetCount(result) < limit && !stopLooking) { - CFIndex langCount = (searchLanguages ? CFArrayGetCount(searchLanguages) : 0); - // MF:??? OK to hard-wire this length? - UniChar curLangUniChars[255]; CFIndex numResults = CFArrayGetCount(result); + savedWorkingLen = workingLen; + if (_CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _BaseUniChars, _BaseLen) && + _CFAppendPathExtension(workingUniChars, &workingLen, CFMaxPathSize, _LprojUniChars, _LprojLen) && + (subDirLen == 0 || (subDirLen > 0 && _CFAppendPathExtension(workingUniChars, &workingLen, CFMaxPathSize, subDirUniChars, subDirLen)))) { + + _CFFindBundleResourcesInRawDir(alloc, workingUniChars, workingLen, nameUniChars, nameLen, resTypes, limit, &stopLooking, predicate, version, cheapStr, tmpString, result); + + if (CFArrayGetCount(result) != numResults) { + // We found resources in a language we already searched. Don't look any farther. + // We also don't need to check the limit, since if the count changed at all, we are bailing. + return; + } + } + } - for (CFIndex langIndex = 0; langIndex < langCount; langIndex++) { + // Now search remaining localized resources (developer language) + workingLen = savedWorkingLen; + if (CFArrayGetCount(result) < limit && !stopLooking && langCount >= 2) { + // MF:??? OK to hard-wire this length? + CFIndex numResults = CFArrayGetCount(result); + + // start after 1st language + for (CFIndex langIndex = 1; langIndex < langCount; langIndex++) { CFStringRef curLangStr = (CFStringRef)CFArrayGetValueAtIndex(searchLanguages, langIndex); - CFIndex curLangLen = CFStringGetLength(curLangStr); - if (curLangLen > 255) curLangLen = 255; + CFIndex curLangLen = MIN(CFStringGetLength(curLangStr), 255); CFStringGetCharacters(curLangStr, CFRangeMake(0, curLangLen), curLangUniChars); savedWorkingLen = workingLen; if (!_CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, curLangUniChars, curLangLen)) { @@ -928,8 +1027,6 @@ static void _CFFindBundleResourcesInResourcesDir(CFAllocatorRef alloc, UniChar * } } -extern void _CFStrSetDesiredCapacity(CFMutableStringRef str, CFIndex len); - CFArrayRef _CFFindBundleResources(CFBundleRef bundle, CFURLRef bundleURL, CFStringRef subDirName, CFArrayRef searchLanguages, CFStringRef resName, CFArrayRef resTypes, CFIndex limit, Boolean (^predicate)(CFStringRef filename, Boolean *stop), uint8_t version) { CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); @@ -975,12 +1072,7 @@ CFArrayRef _CFFindBundleResources(CFBundleRef bundle, CFURLRef bundleURL, CFStri if ((workingLen = CFStringGetLength(basePath)) > 0) CFStringGetCharacters(basePath, CFRangeMake(0, workingLen), workingUniChars); savedWorkingLen = workingLen; - if (1 == version) { - _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _AppSupportUniChars1, _AppSupportLen1); - } else if (2 == version) { - _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _AppSupportUniChars2, _AppSupportLen2); - } - if (0 == version || 1 == version || 2 == version) _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _ResourcesUniChars, _ResourcesLen); + _CFBundleSetResourceDir(workingUniChars, &workingLen, CFMaxPathSize, version); // both of these used for temp string operations, for slightly different purposes, where each type is appropriate cheapStr = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); @@ -989,13 +1081,6 @@ CFArrayRef _CFFindBundleResources(CFBundleRef bundle, CFURLRef bundleURL, CFStri _CFFindBundleResourcesInResourcesDir(kCFAllocatorSystemDefault, workingUniChars, workingLen, subDirUniChars, subDirLen, searchLanguages, nameUniChars, nameLen, resTypes, limit, predicate, version, cheapStr, tmpString, result); - // drd: This unfortunate hack is still necessary because of installer packages and Spotlight importers - if (CFArrayGetCount(result) == 0 && (0 == version || (2 == version && CFEqual(CFSTR("/Library/Spotlight"), basePath)))) { - // Try looking directly in the bundle path - workingLen = savedWorkingLen; - _CFFindBundleResourcesInResourcesDir(kCFAllocatorSystemDefault, workingUniChars, workingLen, subDirUniChars, subDirLen, searchLanguages, nameUniChars, nameLen, resTypes, limit, predicate, version, cheapStr, tmpString, result); - } - CFRelease(cheapStr); CFRelease(tmpString); CFAllocatorDeallocate(kCFAllocatorSystemDefault, nameUniChars); @@ -1005,9 +1090,16 @@ CFArrayRef _CFFindBundleResources(CFBundleRef bundle, CFURLRef bundleURL, CFStri return result; } +__private_extern__ CFArrayRef _CFFindBundleResourcesNoBlock(CFBundleRef bundle, CFURLRef bundleURL, CFStringRef subDirName, CFArrayRef searchLanguages, CFStringRef resName, CFArrayRef resTypes, CFIndex limit, uint8_t version){ + return _CFFindBundleResources(bundle, bundleURL, subDirName, searchLanguages, resName, resTypes, limit, NULL, version); +} + CF_EXPORT CFURLRef CFBundleCopyResourceURL(CFBundleRef bundle, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName) { - if (!bundle) - return NULL; + if (!bundle) return NULL; +#ifdef CFBUNDLE_NEWLOOKUP + CFURLRef result = (CFURLRef) _CFBundleCopyFindResources(bundle, NULL, NULL, resourceName, resourceType, subDirName, NULL, NO, NO, NULL); + return result; +#else CFURLRef result = NULL; CFArrayRef languages = _CFBundleGetLanguageSearchList(bundle), types = NULL, array; if (resourceType) types = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); @@ -1018,9 +1110,15 @@ CF_EXPORT CFURLRef CFBundleCopyResourceURL(CFBundleRef bundle, CFStringRef resou CFRelease(array); } return result; +#endif } CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfType(CFBundleRef bundle, CFStringRef resourceType, CFStringRef subDirName) { +#ifdef CFBUNDLE_NEWLOOKUP + if (!bundle) return CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + CFArrayRef result = (CFArrayRef) _CFBundleCopyFindResources(bundle, NULL, NULL, NULL, resourceType, subDirName, NULL, YES, NO, NULL); + return result; +#else CFArrayRef languages = _CFBundleGetLanguageSearchList(bundle), types = NULL, array; if (resourceType) types = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); // MF:!!! Better "limit" than 1,000,000? @@ -1028,6 +1126,7 @@ CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfType(CFBundleRef bundle, CFString if (types) CFRelease(types); return array; +#endif } CF_EXPORT CFURLRef _CFBundleCopyResourceURLForLanguage(CFBundleRef bundle, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName, CFStringRef language) { @@ -1035,6 +1134,11 @@ CF_EXPORT CFURLRef _CFBundleCopyResourceURLForLanguage(CFBundleRef bundle, CFStr } CF_EXPORT CFURLRef CFBundleCopyResourceURLForLocalization(CFBundleRef bundle, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName, CFStringRef localizationName) { +#ifdef CFBUNDLE_NEWLOOKUP + if (!bundle) return NULL; + CFURLRef result = (CFURLRef) _CFBundleCopyFindResources(bundle, NULL, NULL, resourceName, resourceType, subDirName, localizationName, NO, YES, NULL); + return result; +#else CFURLRef result = NULL; CFArrayRef languages = NULL, types = NULL, array; @@ -1048,6 +1152,7 @@ CF_EXPORT CFURLRef CFBundleCopyResourceURLForLocalization(CFBundleRef bundle, CF if (types) CFRelease(types); if (languages) CFRelease(languages); return result; +#endif } CF_EXPORT CFArrayRef _CFBundleCopyResourceURLsOfTypeForLanguage(CFBundleRef bundle, CFStringRef resourceType, CFStringRef subDirName, CFStringRef language) { @@ -1055,6 +1160,11 @@ CF_EXPORT CFArrayRef _CFBundleCopyResourceURLsOfTypeForLanguage(CFBundleRef bund } CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfTypeForLocalization(CFBundleRef bundle, CFStringRef resourceType, CFStringRef subDirName, CFStringRef localizationName) { +#ifdef CFBUNDLE_NEWLOOKUP + if (!bundle) return CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + CFArrayRef result = (CFArrayRef) _CFBundleCopyFindResources(bundle, NULL, NULL, NULL, resourceType, subDirName, localizationName, YES, YES, NULL); + return result; +#else CFArrayRef languages = NULL, types = NULL, array; if (localizationName) languages = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&localizationName, 1, &kCFTypeArrayCallBacks); @@ -1064,9 +1174,12 @@ CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfTypeForLocalization(CFBundleRef b if (types) CFRelease(types); if (languages) CFRelease(languages); return array; +#endif } +static Boolean CFBundleAllowMixedLocalizations(void); + CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName) { CFStringRef result = NULL; CFDictionaryRef stringTable = NULL; @@ -1074,6 +1187,9 @@ CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRe if (!key) return (value ? (CFStringRef)CFRetain(value) : (CFStringRef)CFRetain(CFSTR(""))); + // Make sure to check the mixed localizations key early -- if the main bundle has not yet been cached, then we need to create the cache of the Info.plist before we start asking for resources (11172381) + (void)CFBundleAllowMixedLocalizations(); + if (!tableName || CFEqual(tableName, CFSTR(""))) tableName = _CFBundleDefaultStringTableName; __CFSpinLock(&CFBundleLocalizedStringLock); @@ -1121,7 +1237,6 @@ CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRe result = (CFStringRef)CFDictionaryGetValue(stringTable, key); if (!result) { - static int capitalize = -1; if (!value) { result = (CFStringRef)CFRetain(key); } else if (CFEqual(value, CFSTR(""))) { @@ -1129,14 +1244,13 @@ CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRe } else { result = (CFStringRef)CFRetain(value); } - if (capitalize != 0) { - if (capitalize != 0) { - CFMutableStringRef capitalizedResult = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, 0, result); - CFLog(__kCFLogBundle, CFSTR("Localizable string \"%@\" not found in strings table \"%@\" of bundle %@."), key, tableName, bundle); - CFStringUppercase(capitalizedResult, NULL); - CFRelease(result); - result = capitalizedResult; - } + __block Boolean capitalize = false; + if (capitalize) { + CFMutableStringRef capitalizedResult = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, 0, result); + CFLog(__kCFLogBundle, CFSTR("Localizable string \"%@\" not found in strings table \"%@\" of bundle %@."), key, tableName, bundle); + CFStringUppercase(capitalizedResult, NULL); + CFRelease(result); + result = capitalizedResult; } } else { CFRetain(result); @@ -1155,6 +1269,9 @@ CF_EXPORT CFURLRef CFBundleCopyResourceURLInDirectory(CFURLRef bundleURL, CFStri newURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, buff, strlen((char *)buff), true); if (!newURL) newURL = (CFURLRef)CFRetain(bundleURL); if (_CFBundleCouldBeBundle(newURL)) { +#ifdef CFBUNDLE_NEWLOOKUP + result = (CFURLRef) _CFBundleCopyFindResources(NULL, bundleURL, NULL, resourceName, resourceType, subDirName, NULL, NO, NO, NULL); +#else uint8_t version = 0; CFArrayRef languages = _CFBundleCopyLanguageSearchListInDirectory(kCFAllocatorSystemDefault, newURL, &version), types = NULL, array; if (resourceType) types = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); @@ -1165,6 +1282,7 @@ CF_EXPORT CFURLRef CFBundleCopyResourceURLInDirectory(CFURLRef bundleURL, CFStri if (CFArrayGetCount(array) > 0) result = (CFURLRef)CFRetain(CFArrayGetValueAtIndex(array, 0)); CFRelease(array); } +#endif } if (newURL) CFRelease(newURL); return result; @@ -1180,6 +1298,9 @@ CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfTypeInDirectory(CFURLRef bundleUR newURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, buff, strlen((char *)buff), true); if (!newURL) newURL = (CFURLRef)CFRetain(bundleURL); if (_CFBundleCouldBeBundle(newURL)) { +#ifdef CFBUNDLE_NEWLOOKUP + array = (CFArrayRef) _CFBundleCopyFindResources(NULL, bundleURL, NULL, NULL, resourceType, subDirName, NULL, YES, NO, NULL); +#else uint8_t version = 0; CFArrayRef languages = _CFBundleCopyLanguageSearchListInDirectory(kCFAllocatorSystemDefault, newURL, &version), types = NULL; if (resourceType) types = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); @@ -1187,6 +1308,7 @@ CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfTypeInDirectory(CFURLRef bundleUR array = _CFFindBundleResources(NULL, newURL, subDirName, languages, NULL, types, 1000000, NULL, version); if (types) CFRelease(types); if (languages) CFRelease(languages); +#endif } if (newURL) CFRelease(newURL); return array; @@ -1518,63 +1640,12 @@ CFStringRef CFBundleCopyLocalizationForLocalizationInfo(SInt32 languageCode, SIn extern void *__CFAppleLanguages; -#if DEPLOYMENT_TARGET_WINDOWS - -extern CFStringRef copyLocaleLanguageName(void); -extern CFStringRef copyLocaleCountryName(void); - -static CFArrayRef copyWindowsLanguagePrefsArray() { - CFArrayRef result; - CFStringRef locales[4]; - CFStringRef languageName = copyLocaleLanguageName(), countryName = copyLocaleCountryName(); - if (!languageName) languageName = CFSTR("en"); - if (!countryName) countryName = CFSTR(""); - CFIndex i, localesCount = 0; - if (CFStringGetLength(countryName) > 0) locales[localesCount++] = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@_%@"), languageName, countryName); - if (CFStringGetLength(languageName) != 0) { - // special-case for zh since we don't have a generic zh localization - if (CFStringCompare(languageName, CFSTR("zh"), kCFCompareCaseInsensitive) != 0) { - locales[localesCount++] = CFStringCreateCopy(kCFAllocatorSystemDefault, languageName);//languageName; - } else { - CFStringRef moreSpecificLanguageName; - - // See http://intrigue-build.apple.com/changeset/14948 for the details on the change. Copied below is the snippet of the code change. - // According to http://www.microsoft.com/globaldev/reference/win2k/setup/lcid.mspx, the locales that use - // 126 // simplified chinese are CN (PRC) and SG (Singapore). The rest use traditional chinese. - // 127 languageName = (countryName == TEXT("CN") || countryName == TEXT("SG")) ? TEXT("zh_CN") : TEXT("zh_TW"); - - // Compare for CN or SG - if (CFStringCompare(countryName, CFSTR("CN"), kCFCompareCaseInsensitive) == 0 || CFStringCompare(countryName, CFSTR("SG"), kCFCompareCaseInsensitive) == 0) { - moreSpecificLanguageName = CFSTR("zh_CN"); - } else { - moreSpecificLanguageName = CFSTR("zh_TW"); - } - locales[localesCount++] = CFStringCreateCopy(kCFAllocatorSystemDefault, moreSpecificLanguageName); - } - // Don't need this now - if (languageName) CFRelease(languageName); - if (countryName) CFRelease(countryName); - } - if (localesCount == 0) locales[localesCount++] = CFStringCreateCopy(kCFAllocatorSystemDefault, CFSTR("en")); - result = CFArrayCreate(kCFAllocatorDefault, (const void **)locales, localesCount, &kCFTypeArrayCallBacks); - for (i = 0; i < localesCount; i++) CFRelease(locales[i]); - return result; -} - -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif - -static CFArrayRef _CFBundleUserLanguages = NULL; __private_extern__ CFArrayRef _CFBundleCopyUserLanguages(Boolean useBackstops) { - CFArrayRef result = NULL; - static Boolean didit = false; - CFArrayRef preferencesArray = NULL; - // This is a temporary solution, until the argument domain is moved down into CFPreferences - __CFSpinLock(&CFBundleResourceGlobalDataLock); - if (!didit) { + static CFArrayRef _CFBundleUserLanguages = NULL; + static dispatch_once_t once = 0; + dispatch_once(&once, ^{ + CFArrayRef preferencesArray = NULL; if (__CFAppleLanguages) { CFDataRef data; CFIndex length = strlen((const char *)__CFAppleLanguages); @@ -1597,12 +1668,15 @@ __private_extern__ CFArrayRef _CFBundleCopyUserLanguages(Boolean useBackstops) { CFRelease(_CFBundleUserLanguages); _CFBundleUserLanguages = NULL; } - didit = true; + if (preferencesArray) CFRelease(preferencesArray); + }); + + if (_CFBundleUserLanguages) { + CFRetain(_CFBundleUserLanguages); + return _CFBundleUserLanguages; + } else { + return NULL; } - __CFSpinUnlock(&CFBundleResourceGlobalDataLock); - if (preferencesArray) CFRelease(preferencesArray); - if (!result && _CFBundleUserLanguages) result = (CFArrayRef)CFRetain(_CFBundleUserLanguages); - return result; } CF_EXPORT void _CFBundleGetLanguageAndRegionCodes(SInt32 *languageCode, SInt32 *regionCode) { @@ -1651,12 +1725,8 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc CFArrayRef predefinedLocalizations = NULL; CFRange predefinedLocalizationsRange; CFMutableStringRef cheapStr, tmpString; -#if READ_DIRECTORIES CFArrayRef contents; CFRange contentsRange; -#else /* READ_DIRECTORIES */ - Boolean isDir = false; -#endif /* READ_DIRECTORIES */ // both of these used for temp string operations, for slightly // different purposes, where each type is appropriate @@ -1664,12 +1734,10 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc _CFStrSetDesiredCapacity(cheapStr, CFMaxPathSize); tmpString = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, kCFAllocatorNull); -#if READ_DIRECTORIES CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); contents = _CFBundleCopySortedDirectoryContentsAtPath(cheapStr, _CFBundleAllContents); contentsRange = CFRangeMake(0, CFArrayGetCount(contents)); -#endif /* READ_DIRECTORIES */ if (infoDict) { predefinedLocalizations = (CFArrayRef)CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey); @@ -1684,23 +1752,15 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc CFStringGetCharacters(curLangStr, CFRangeMake(0, curLangLen), curLangUniChars); savedPathLen = pathLen; if (_CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, curLangUniChars, curLangLen) && _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, _LprojUniChars, _LprojLen)) { -#if READ_DIRECTORIES CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + savedPathLen + 1, pathLen - savedPathLen - 1, pathLen - savedPathLen - 1); CFStringReplaceAll(cheapStr, tmpString); if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, curLangStr)) || (version != 4 && _CFBundleSortedArrayContains(contents, cheapStr))) { -#else /* READ_DIRECTORIES */ - CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); - CFStringReplaceAll(cheapStr, tmpString); - if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, curLangStr)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) { -#endif /* READ_DIRECTORIES */ if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), curLangStr)) CFArrayAppendValue(lprojNames, curLangStr); foundOne = true; if (CFStringGetLength(curLangStr) <= 2) { CFRelease(cheapStr); CFRelease(tmpString); -#if READ_DIRECTORIES CFRelease(contents); -#endif /* READ_DIRECTORIES */ return foundOne; } } @@ -1717,9 +1777,7 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc if (foundOne && altLangStr) { CFRelease(cheapStr); CFRelease(tmpString); -#if READ_DIRECTORIES CFRelease(contents); -#endif /* READ_DIRECTORIES */ return foundOne; } if (altLangStr) { @@ -1728,32 +1786,23 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc CFStringGetCharacters(altLangStr, CFRangeMake(0, curLangLen), curLangUniChars); pathLen = savedPathLen; if (_CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, curLangUniChars, curLangLen) && _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, _LprojUniChars, _LprojLen)) { -#if READ_DIRECTORIES CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + savedPathLen + 1, pathLen - savedPathLen - 1, pathLen - savedPathLen - 1); CFStringReplaceAll(cheapStr, tmpString); if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, altLangStr)) || (version != 4 && _CFBundleSortedArrayContains(contents, cheapStr))) { -#else /* READ_DIRECTORIES */ - CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); - CFStringReplaceAll(cheapStr, tmpString); - if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, altLangStr)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) { -#endif /* READ_DIRECTORIES */ if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), altLangStr)) CFArrayAppendValue(lprojNames, altLangStr); foundOne = true; CFRelease(cheapStr); CFRelease(tmpString); -#if READ_DIRECTORIES CFRelease(contents); -#endif /* READ_DIRECTORIES */ return foundOne; } } } -#if READ_DIRECTORIES if (!foundOne && (!predefinedLocalizations || CFArrayGetCount(predefinedLocalizations) == 0)) { Boolean hasLocalizations = false; CFIndex idx; for (idx = 0; !hasLocalizations && idx < contentsRange.length; idx++) { - CFStringRef name = CFArrayGetValueAtIndex(contents, idx); + CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(contents, idx); if (CFStringHasSuffix(name, _CFBundleLprojExtensionWithDot)) hasLocalizations = true; } if (!hasLocalizations) { @@ -1763,22 +1812,15 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc return foundOne; } } -#endif /* READ_DIRECTORIES */ if (!altLangStr && (modifiedLangStr = _CFBundleCopyModifiedLocalization(curLangStr))) { curLangLen = CFStringGetLength(modifiedLangStr); if (curLangLen > 255) curLangLen = 255; CFStringGetCharacters(modifiedLangStr, CFRangeMake(0, curLangLen), curLangUniChars); pathLen = savedPathLen; if (_CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, curLangUniChars, curLangLen) && _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, _LprojUniChars, _LprojLen)) { -#if READ_DIRECTORIES CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + savedPathLen + 1, pathLen - savedPathLen - 1, pathLen - savedPathLen - 1); CFStringReplaceAll(cheapStr, tmpString); if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, modifiedLangStr)) || (version != 4 && _CFBundleSortedArrayContains(contents, cheapStr))) { -#else /* READ_DIRECTORIES */ - CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); - CFStringReplaceAll(cheapStr, tmpString); - if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, modifiedLangStr)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) { -#endif /* READ_DIRECTORIES */ if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), modifiedLangStr)) CFArrayAppendValue(lprojNames, modifiedLangStr); foundOne = true; } @@ -1790,15 +1832,9 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc CFStringGetCharacters(languageAbbreviation, CFRangeMake(0, curLangLen), curLangUniChars); pathLen = savedPathLen; if (_CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, curLangUniChars, curLangLen) && _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, _LprojUniChars, _LprojLen)) { -#if READ_DIRECTORIES CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + savedPathLen + 1, pathLen - savedPathLen - 1, pathLen - savedPathLen - 1); CFStringReplaceAll(cheapStr, tmpString); if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageAbbreviation)) || (version != 4 && _CFBundleSortedArrayContains(contents, cheapStr))) { -#else /* READ_DIRECTORIES */ - CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); - CFStringReplaceAll(cheapStr, tmpString); - if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageAbbreviation)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) { -#endif /* READ_DIRECTORIES */ if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), languageAbbreviation)) CFArrayAppendValue(lprojNames, languageAbbreviation); foundOne = true; } @@ -1810,15 +1846,9 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc CFStringGetCharacters(languageName, CFRangeMake(0, curLangLen), curLangUniChars); pathLen = savedPathLen; if (_CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, curLangUniChars, curLangLen) && _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, _LprojUniChars, _LprojLen)) { -#if READ_DIRECTORIES CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + savedPathLen + 1, pathLen - savedPathLen - 1, pathLen - savedPathLen - 1); CFStringReplaceAll(cheapStr, tmpString); if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageName)) || (version != 4 && _CFBundleSortedArrayContains(contents, cheapStr))) { -#else /* READ_DIRECTORIES */ - CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); - CFStringReplaceAll(cheapStr, tmpString); - if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageName)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) { -#endif /* READ_DIRECTORIES */ if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), languageName)) CFArrayAppendValue(lprojNames, languageName); foundOne = true; } @@ -1833,15 +1863,14 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc if (canonicalLanguageAbbreviation) CFRelease(canonicalLanguageAbbreviation); CFRelease(cheapStr); CFRelease(tmpString); -#if READ_DIRECTORIES CFRelease(contents); -#endif /* READ_DIRECTORIES */ return foundOne; } static Boolean CFBundleAllowMixedLocalizations(void) { - static Boolean allowMixed = false, examinedMain = false; - if (!examinedMain) { + static Boolean allowMixed = false; + static dispatch_once_t once = 0; + dispatch_once(&once, ^{ CFBundleRef mainBundle = CFBundleGetMainBundle(); CFDictionaryRef infoDict = mainBundle ? CFBundleGetInfoDictionary(mainBundle) : NULL; CFTypeRef allowMixedValue = infoDict ? CFDictionaryGetValue(infoDict, _kCFBundleAllowMixedLocalizationsKey) : NULL; @@ -1855,9 +1884,8 @@ static Boolean CFBundleAllowMixedLocalizations(void) { SInt32 val = 0; if (CFNumberGetValue((CFNumberRef)allowMixedValue, kCFNumberSInt32Type, &val)) allowMixed = (val != 0); } - } - examinedMain = true; - } + } + }); return allowMixed; } @@ -2121,11 +2149,15 @@ __private_extern__ Boolean _CFBundleURLLooksLikeBundleVersion(CFURLRef url, uint // version 3: none of the above (see below) // version 4: not a bundle (for main bundle only) uint8_t localVersion = 3; -#if READ_DIRECTORIES CFURLRef absoluteURL = CFURLCopyAbsoluteURL(url); CFStringRef directoryPath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); CFArrayRef contents = _CFBundleCopySortedDirectoryContentsAtPath(directoryPath, _CFBundleAllContents); - if (CFStringHasSuffix(CFURLGetString(url), CFSTR(".framework/"))) { + Boolean hasFrameworkSuffix = CFStringHasSuffix(CFURLGetString(url), CFSTR(".framework/")); +#if DEPLOYMENT_TARGET_WINDOWS + hasFrameworkSuffix = hasFrameworkSuffix || CFStringHasSuffix(CFURLGetString(url), CFSTR(".framework\\")); +#endif + + if (hasFrameworkSuffix) { if (_CFBundleSortedArrayContains(contents, _CFBundleResourcesDirectoryName)) localVersion = 0; else if (_CFBundleSortedArrayContains(contents, _CFBundleSupportFilesDirectoryName2)) localVersion = 2; else if (_CFBundleSortedArrayContains(contents, _CFBundleSupportFilesDirectoryName1)) localVersion = 1; @@ -2137,15 +2169,9 @@ __private_extern__ Boolean _CFBundleURLLooksLikeBundleVersion(CFURLRef url, uint CFRelease(contents); CFRelease(directoryPath); CFRelease(absoluteURL); -#endif /* READ_DIRECTORIES */ +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_WINDOWS if (localVersion == 3) { -#if DEPLOYMENT_TARGET_EMBEDDED -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_WINDOWS -#if DEPLOYMENT_TARGET_WINDOWS - if (CFStringHasSuffix(CFURLGetString(url), CFSTR(".framework/")) || CFStringHasSuffix(CFURLGetString(url), CFSTR(".framework\\"))) { -#else - if (CFStringHasSuffix(CFURLGetString(url), CFSTR(".framework/"))) { -#endif + if (hasFrameworkSuffix) { if (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) localVersion = 0; else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase2)) localVersion = 2; else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase1)) localVersion = 1; @@ -2154,8 +2180,8 @@ __private_extern__ Boolean _CFBundleURLLooksLikeBundleVersion(CFURLRef url, uint else if (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) localVersion = 0; else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase1)) localVersion = 1; } -#endif } +#endif if (version) *version = localVersion; return (localVersion != 3); } @@ -2196,12 +2222,14 @@ static Boolean _isValidPlatformAndProductSuffixPair(CFStringRef platform, CFStri } static Boolean _isBlacklistedKey(CFStringRef keyName) { +#if __CONSTANT_STRINGS__ #define _CFBundleNumberOfBlacklistedInfoDictionaryKeys 2 static const CFStringRef _CFBundleBlacklistedInfoDictionaryKeys[_CFBundleNumberOfBlacklistedInfoDictionaryKeys] = { CFSTR("CFBundleExecutable"), CFSTR("CFBundleIdentifier") }; for (CFIndex idx = 0; idx < _CFBundleNumberOfBlacklistedInfoDictionaryKeys; idx++) { if (CFEqual(keyName, _CFBundleBlacklistedInfoDictionaryKeys[idx])) return true; } +#endif return false; } @@ -2410,31 +2438,23 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer CFMutableStringRef cheapStr; CFStringRef infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension0, infoURLFromBase = _CFBundleInfoURLFromBase0; Boolean tryPlatformSpecific = true, tryGlobal = true; -#if READ_DIRECTORIES CFURLRef directoryURL = NULL, absoluteURL; CFStringRef directoryPath; CFArrayRef contents = NULL; CFRange contentsRange = CFRangeMake(0, 0); -#endif /* READ_DIRECTORIES */ _CFEnsureStaticBuffersInited(); if (0 == version) { -#if READ_DIRECTORIES directoryURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase0, url); -#endif /* READ_DIRECTORIES */ infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension0; infoURLFromBase = _CFBundleInfoURLFromBase0; } else if (1 == version) { -#if READ_DIRECTORIES directoryURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleSupportFilesURLFromBase1, url); -#endif /* READ_DIRECTORIES */ infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension1; infoURLFromBase = _CFBundleInfoURLFromBase1; } else if (2 == version) { -#if READ_DIRECTORIES directoryURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleSupportFilesURLFromBase2, url); -#endif /* READ_DIRECTORIES */ infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension2; infoURLFromBase = _CFBundleInfoURLFromBase2; } else if (3 == version) { @@ -2442,16 +2462,13 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer // this test is necessary to exclude the case where a bundle is spuriously created from the innards of another bundle if (path) { if (!(CFStringHasSuffix(path, _CFBundleSupportFilesDirectoryName1) || CFStringHasSuffix(path, _CFBundleSupportFilesDirectoryName2) || CFStringHasSuffix(path, _CFBundleResourcesDirectoryName))) { -#if READ_DIRECTORIES - directoryURL = CFRetain(url); -#endif /* READ_DIRECTORIES */ + directoryURL = (CFURLRef)CFRetain(url); infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension3; infoURLFromBase = _CFBundleInfoURLFromBase3; } CFRelease(path); } } -#if READ_DIRECTORIES if (directoryURL) { absoluteURL = CFURLCopyAbsoluteURL(directoryURL); directoryPath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); @@ -2461,7 +2478,6 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer CFRelease(absoluteURL); CFRelease(directoryURL); } -#endif /* READ_DIRECTORIES */ len = CFStringGetLength(infoURLFromBaseNoExtension); CFStringGetCharacters(infoURLFromBaseNoExtension, CFRangeMake(0, len), buff); @@ -2472,18 +2488,16 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer cheapStr = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); CFStringAppendCharacters(cheapStr, buff, len); infoURL = CFURLCreateWithString(kCFAllocatorSystemDefault, cheapStr, url); -#if READ_DIRECTORIES if (contents) { CFIndex resourcesLen, idx; - for (resourcesLen = len; resourcesLen > 0; resourcesLen--) if (buff[resourcesLen - 1] == '/') break; + for (resourcesLen = len; resourcesLen > 0; resourcesLen--) if (buff[resourcesLen - 1] == PATH_SEP) break; CFStringDelete(cheapStr, CFRangeMake(0, CFStringGetLength(cheapStr))); CFStringAppendCharacters(cheapStr, buff + resourcesLen, len - resourcesLen); for (tryPlatformSpecific = false, idx = 0; !tryPlatformSpecific && idx < contentsRange.length; idx++) { // Need to do this case-insensitive to accommodate Palm - if (kCFCompareEqualTo == CFStringCompare(cheapStr, CFArrayGetValueAtIndex(contents, idx), kCFCompareCaseInsensitive)) tryPlatformSpecific = true; + if (kCFCompareEqualTo == CFStringCompare(cheapStr, (CFStringRef)CFArrayGetValueAtIndex(contents, idx), kCFCompareCaseInsensitive)) tryPlatformSpecific = true; } } -#endif /* READ_DIRECTORIES */ if (tryPlatformSpecific) CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, infoURL, &infoData, NULL, NULL, NULL); //fprintf(stderr, "looking for ");CFShow(infoURL);fprintf(stderr, infoData ? "found it\n" : (tryPlatformSpecific ? "missed it\n" : "skipped it\n")); CFRelease(cheapStr); @@ -2491,15 +2505,13 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer // Check for global Info.plist CFRelease(infoURL); infoURL = CFURLCreateWithString(kCFAllocatorSystemDefault, infoURLFromBase, url); -#if READ_DIRECTORIES if (contents) { CFIndex idx; for (tryGlobal = false, idx = 0; !tryGlobal && idx < contentsRange.length; idx++) { // Need to do this case-insensitive to accommodate Palm - if (kCFCompareEqualTo == CFStringCompare(_CFBundleInfoFileName, CFArrayGetValueAtIndex(contents, idx), kCFCompareCaseInsensitive)) tryGlobal = true; + if (kCFCompareEqualTo == CFStringCompare(_CFBundleInfoFileName, (CFStringRef)CFArrayGetValueAtIndex(contents, idx), kCFCompareCaseInsensitive)) tryGlobal = true; } } -#endif /* READ_DIRECTORIES */ if (tryGlobal) CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, infoURL, &infoData, NULL, NULL, NULL); //fprintf(stderr, "looking for ");CFShow(infoURL);fprintf(stderr, infoData ? "found it\n" : (tryGlobal ? "missed it\n" : "skipped it\n")); } @@ -2523,9 +2535,7 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer } CFRelease(infoURL); -#if READ_DIRECTORIES if (contents) CFRelease(contents); -#endif /* READ_DIRECTORIES */ } _processInfoDictionary((CFMutableDictionaryRef)result, _CFGetPlatformName(), _CFGetProductName()); return result; @@ -2602,19 +2612,19 @@ static Boolean _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFAllocatorR CFStringGetCharacters(urlStr, CFRangeMake(0, strLen), buff); CFRelease(urlStr); startOfExtension = _CFStartOfPathExtension(buff, strLen); - if ((strLen - startOfExtension == 4 || strLen - startOfExtension == 5) && buff[startOfExtension] == (UniChar)'.' && buff[startOfExtension+1] == (UniChar)'a' && buff[startOfExtension+2] == (UniChar)'p' && buff[startOfExtension+3] == (UniChar)'p' && (strLen - startOfExtension == 4 || buff[startOfExtension+4] == (UniChar)'/')) { + if ((strLen - startOfExtension == 4 || strLen - startOfExtension == 5) && buff[startOfExtension] == (UniChar)'.' && buff[startOfExtension+1] == (UniChar)'a' && buff[startOfExtension+2] == (UniChar)'p' && buff[startOfExtension+3] == (UniChar)'p' && (strLen - startOfExtension == 4 || buff[startOfExtension+4] == (UniChar)PATH_SEP)) { // This is an app *packageType = 0x4150504c; // 'APPL' - } else if ((strLen - startOfExtension == 6 || strLen - startOfExtension == 7) && buff[startOfExtension] == (UniChar)'.' && buff[startOfExtension+1] == (UniChar)'d' && buff[startOfExtension+2] == (UniChar)'e' && buff[startOfExtension+3] == (UniChar)'b' && buff[startOfExtension+4] == (UniChar)'u' && buff[startOfExtension+5] == (UniChar)'g' && (strLen - startOfExtension == 6 || buff[startOfExtension+6] == (UniChar)'/')) { + } else if ((strLen - startOfExtension == 6 || strLen - startOfExtension == 7) && buff[startOfExtension] == (UniChar)'.' && buff[startOfExtension+1] == (UniChar)'d' && buff[startOfExtension+2] == (UniChar)'e' && buff[startOfExtension+3] == (UniChar)'b' && buff[startOfExtension+4] == (UniChar)'u' && buff[startOfExtension+5] == (UniChar)'g' && (strLen - startOfExtension == 6 || buff[startOfExtension+6] == (UniChar)PATH_SEP)) { // This is an app (debug version) *packageType = 0x4150504c; // 'APPL' - } else if ((strLen - startOfExtension == 8 || strLen - startOfExtension == 9) && buff[startOfExtension] == (UniChar)'.' && buff[startOfExtension+1] == (UniChar)'p' && buff[startOfExtension+2] == (UniChar)'r' && buff[startOfExtension+3] == (UniChar)'o' && buff[startOfExtension+4] == (UniChar)'f' && buff[startOfExtension+5] == (UniChar)'i' && buff[startOfExtension+6] == (UniChar)'l' && buff[startOfExtension+7] == (UniChar)'e' && (strLen - startOfExtension == 8 || buff[startOfExtension+8] == (UniChar)'/')) { + } else if ((strLen - startOfExtension == 8 || strLen - startOfExtension == 9) && buff[startOfExtension] == (UniChar)'.' && buff[startOfExtension+1] == (UniChar)'p' && buff[startOfExtension+2] == (UniChar)'r' && buff[startOfExtension+3] == (UniChar)'o' && buff[startOfExtension+4] == (UniChar)'f' && buff[startOfExtension+5] == (UniChar)'i' && buff[startOfExtension+6] == (UniChar)'l' && buff[startOfExtension+7] == (UniChar)'e' && (strLen - startOfExtension == 8 || buff[startOfExtension+8] == (UniChar)PATH_SEP)) { // This is an app (profile version) *packageType = 0x4150504c; // 'APPL' - } else if ((strLen - startOfExtension == 8 || strLen - startOfExtension == 9) && buff[startOfExtension] == (UniChar)'.' && buff[startOfExtension+1] == (UniChar)'s' && buff[startOfExtension+2] == (UniChar)'e' && buff[startOfExtension+3] == (UniChar)'r' && buff[startOfExtension+4] == (UniChar)'v' && buff[startOfExtension+5] == (UniChar)'i' && buff[startOfExtension+6] == (UniChar)'c' && buff[startOfExtension+7] == (UniChar)'e' && (strLen - startOfExtension == 8 || buff[startOfExtension+8] == (UniChar)'/')) { + } else if ((strLen - startOfExtension == 8 || strLen - startOfExtension == 9) && buff[startOfExtension] == (UniChar)'.' && buff[startOfExtension+1] == (UniChar)'s' && buff[startOfExtension+2] == (UniChar)'e' && buff[startOfExtension+3] == (UniChar)'r' && buff[startOfExtension+4] == (UniChar)'v' && buff[startOfExtension+5] == (UniChar)'i' && buff[startOfExtension+6] == (UniChar)'c' && buff[startOfExtension+7] == (UniChar)'e' && (strLen - startOfExtension == 8 || buff[startOfExtension+8] == (UniChar)PATH_SEP)) { // This is a service *packageType = 0x4150504c; // 'APPL' - } else if ((strLen - startOfExtension == 10 || strLen - startOfExtension == 11) && buff[startOfExtension] == (UniChar)'.' && buff[startOfExtension+1] == (UniChar)'f' && buff[startOfExtension+2] == (UniChar)'r' && buff[startOfExtension+3] == (UniChar)'a' && buff[startOfExtension+4] == (UniChar)'m' && buff[startOfExtension+5] == (UniChar)'e' && buff[startOfExtension+6] == (UniChar)'w' && buff[startOfExtension+7] == (UniChar)'o' && buff[startOfExtension+8] == (UniChar)'r' && buff[startOfExtension+9] == (UniChar)'k' && (strLen - startOfExtension == 10 || buff[startOfExtension+10] == (UniChar)'/')) { + } else if ((strLen - startOfExtension == 10 || strLen - startOfExtension == 11) && buff[startOfExtension] == (UniChar)'.' && buff[startOfExtension+1] == (UniChar)'f' && buff[startOfExtension+2] == (UniChar)'r' && buff[startOfExtension+3] == (UniChar)'a' && buff[startOfExtension+4] == (UniChar)'m' && buff[startOfExtension+5] == (UniChar)'e' && buff[startOfExtension+6] == (UniChar)'w' && buff[startOfExtension+7] == (UniChar)'o' && buff[startOfExtension+8] == (UniChar)'r' && buff[startOfExtension+9] == (UniChar)'k' && (strLen - startOfExtension == 10 || buff[startOfExtension+10] == (UniChar)PATH_SEP)) { // This is a framework *packageType = 0x464d574b; // 'FMWK' } else { @@ -2709,7 +2719,7 @@ CF_EXPORT CFArrayRef _CFBundleGetSupportedPlatforms(CFBundleRef bundle) { CF_EXPORT CFStringRef _CFBundleGetCurrentPlatform(void) { #if DEPLOYMENT_TARGET_MACOSX return CFSTR("MacOS"); -#elif DEPLOYMENT_TARGET_EMBEDDED +#elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI return CFSTR("iPhoneOS"); #elif DEPLOYMENT_TARGET_WINDOWS return CFSTR("Windows"); @@ -2727,7 +2737,7 @@ CF_EXPORT CFStringRef _CFBundleGetCurrentPlatform(void) { } __private_extern__ CFStringRef _CFBundleGetPlatformExecutablesSubdirectoryName(void) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI return CFSTR("MacOS"); #elif DEPLOYMENT_TARGET_WINDOWS return CFSTR("Windows"); @@ -2745,7 +2755,7 @@ __private_extern__ CFStringRef _CFBundleGetPlatformExecutablesSubdirectoryName(v } __private_extern__ CFStringRef _CFBundleGetAlternatePlatformExecutablesSubdirectoryName(void) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI return CFSTR("Mac OS X"); #elif DEPLOYMENT_TARGET_WINDOWS return CFSTR("WinNT"); @@ -2763,7 +2773,7 @@ __private_extern__ CFStringRef _CFBundleGetAlternatePlatformExecutablesSubdirect } __private_extern__ CFStringRef _CFBundleGetOtherPlatformExecutablesSubdirectoryName(void) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI return CFSTR("MacOSClassic"); #elif DEPLOYMENT_TARGET_WINDOWS return CFSTR("Other"); @@ -2781,7 +2791,7 @@ __private_extern__ CFStringRef _CFBundleGetOtherPlatformExecutablesSubdirectoryN } __private_extern__ CFStringRef _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(void) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI return CFSTR("Mac OS 8"); #elif DEPLOYMENT_TARGET_WINDOWS return CFSTR("Other"); @@ -2805,15 +2815,11 @@ __private_extern__ CFArrayRef _CFBundleCopyBundleRegionsArray(CFBundleRef bundle CF_EXPORT CFArrayRef CFBundleCopyBundleLocalizations(CFBundleRef bundle) { CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle); -#if READ_DIRECTORIES CFURLRef absoluteURL; CFStringRef directoryPath; CFArrayRef contents; CFRange contentsRange; CFIndex idx; -#else /* READ_DIRECTORIES */ - CFArrayRef urls = ((_CFBundleLayoutVersion(bundle) != 4) ? _CFContentsOfDirectory(CFGetAllocator(bundle), NULL, NULL, resourcesURL, _CFBundleLprojExtension) : NULL); -#endif /* READ_DIRECTORIES */ CFArrayRef predefinedLocalizations = NULL; CFMutableArrayRef result = NULL; @@ -2830,14 +2836,13 @@ CF_EXPORT CFArrayRef CFBundleCopyBundleLocalizations(CFBundleRef bundle) { } } -#if READ_DIRECTORIES if (resourcesURL) { absoluteURL = CFURLCopyAbsoluteURL(resourcesURL); directoryPath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); contents = _CFBundleCopySortedDirectoryContentsAtPath(directoryPath, _CFBundleAllContents); contentsRange = CFRangeMake(0, CFArrayGetCount(contents)); for (idx = 0; idx < contentsRange.length; idx++) { - CFStringRef name = CFArrayGetValueAtIndex(contents, idx); + CFStringRef name = (CFStringRef)CFArrayGetValueAtIndex(contents, idx); if (CFStringHasSuffix(name, _CFBundleLprojExtensionWithDot)) { CFStringRef localization = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, name, CFRangeMake(0, CFStringGetLength(name) - 6)); if (!result) result = CFArrayCreateMutable(CFGetAllocator(bundle), 0, &kCFTypeArrayCallBacks); @@ -2849,34 +2854,6 @@ CF_EXPORT CFArrayRef CFBundleCopyBundleLocalizations(CFBundleRef bundle) { CFRelease(directoryPath); CFRelease(absoluteURL); } -#else /* READ_DIRECTORIES */ - if (urls) { - CFIndex i, c = CFArrayGetCount(urls); - CFURLRef curURL, curAbsoluteURL; - CFStringRef curStr, regionStr; - UniChar buff[CFMaxPathSize]; - CFIndex strLen, startOfLastPathComponent, regionLen; - - if (c > 0 && !result) result = CFArrayCreateMutable(CFGetAllocator(bundle), 0, &kCFTypeArrayCallBacks); - for (i = 0; i < c; i++) { - curURL = (CFURLRef)CFArrayGetValueAtIndex(urls, i); - curAbsoluteURL = CFURLCopyAbsoluteURL(curURL); - curStr = CFURLCopyFileSystemPath(curAbsoluteURL, PLATFORM_PATH_STYLE); - CFRelease(curAbsoluteURL); - strLen = CFStringGetLength(curStr); - if (strLen > CFMaxPathSize) strLen = CFMaxPathSize; - CFStringGetCharacters(curStr, CFRangeMake(0, strLen), buff); - - startOfLastPathComponent = _CFStartOfLastPathComponent(buff, strLen); - regionLen = _CFLengthAfterDeletingPathExtension(&(buff[startOfLastPathComponent]), strLen - startOfLastPathComponent); - regionStr = CFStringCreateWithCharacters(CFGetAllocator(bundle), &(buff[startOfLastPathComponent]), regionLen); - CFArrayAppendValue(result, regionStr); - CFRelease(regionStr); - CFRelease(curStr); - } - CFRelease(urls); - } -#endif /* READ_DIRECTORIES */ if (!result) { CFStringRef developmentLocalization = CFBundleGetDevelopmentRegion(bundle); @@ -2937,3 +2914,919 @@ CFArrayRef CFBundleCopyLocalizationsForURL(CFURLRef url) { } return result; } + + + +CF_INLINE Boolean _CFBundleFindCharacterInStr(const UniChar *str, UniChar c, Boolean backward, CFIndex start, CFIndex length, CFRange *result){ + *result = CFRangeMake(kCFNotFound, 0); + Boolean found = false; + if (backward) { + for (CFIndex i = start; i > start-length; i--) { + if (c == str[i]) { + result->location = i; + found = true; + break; + } + } + } else { + for (CFIndex i = start; i < start+length; i++) { + if (c == str[i]) { + result->location = i; + found = true; + break; + } + } + } + return found; +} + + +typedef enum { + _CFBundleFileVersionNoProductNoPlatform = 1, + _CFBundleFileVersionWithProductNoPlatform, + _CFBundleFileVersionNoProductWithPlatform, + _CFBundleFileVersionWithProductWithPlatform, + _CFBundleFileVersionUnmatched +} _CFBundleFileVersion; + +static _CFBundleFileVersion _CFBundleCheckFileProductAndPlatform(CFStringRef file, UniChar *fileBuffer1, CFIndex fileLen, CFRange searchRange, CFStringRef product, CFStringRef platform, CFRange* prodp, CFRange* platp, CFIndex prodLen) +{ + _CFBundleFileVersion version; + CFRange found; + Boolean foundprod, foundplat; + foundplat = foundprod = NO; + UniChar fileBuffer2[CFMaxPathSize]; + UniChar *fileBuffer; + Boolean wrong = false; + + if (fileBuffer1) { + fileBuffer = fileBuffer1; + }else{ + fileLen = CFStringGetLength(file); + if (fileLen > CFMaxPathSize) fileLen = CFMaxPathSize; + CFStringGetCharacters(file, CFRangeMake(0, fileLen), fileBuffer2); + fileBuffer = fileBuffer2; + } + + if (_CFBundleFindCharacterInStr(fileBuffer, '~', NO, searchRange.location, searchRange.length, &found)) { + if (prodLen != 1) { + if (CFStringFindWithOptions(file, product, searchRange, kCFCompareEqualTo, prodp)) { + foundprod = YES; + } + } + if (!foundprod) { + for (CFIndex i = 0; i < _CFBundleNumberOfProducts; i++) { + if (CFStringFindWithOptions(file, _CFBundleSupportedProducts[i], searchRange, kCFCompareEqualTo, &found)) { + wrong = true; + break; + } + } + } + } + + if (!wrong && _CFBundleFindCharacterInStr(fileBuffer, '-', NO, searchRange.location, searchRange.length, &found)) { + if (CFStringFindWithOptions(file, platform, searchRange, kCFCompareEqualTo, platp)) { + foundplat = YES; + } + if (!foundplat) { + for (CFIndex i = 0; i < _CFBundleNumberOfPlatforms; i++) { + if (CFStringFindWithOptions(file, _CFBundleSupportedPlatforms[i], searchRange, kCFCompareEqualTo, &found)) { + wrong = true; + break; + } + } + } + } + + if (wrong) { + version = _CFBundleFileVersionUnmatched; + } else if (foundplat && foundprod) { + version = _CFBundleFileVersionWithProductWithPlatform; + } else if (foundplat) { + version = _CFBundleFileVersionNoProductWithPlatform; + } else if (foundprod) { + version = _CFBundleFileVersionWithProductNoPlatform; + } else { + version = _CFBundleFileVersionNoProductNoPlatform; + } + return version; +} + + +// ZFH + + +static void _CFBundleAddValueForType(CFMutableStringRef type, UniChar* fileNameBuffer, CFMutableDictionaryRef queryTable, CFRange dotPosition, CFIndex fileLen, CFMutableDictionaryRef typeDir, CFTypeRef value, CFMutableDictionaryRef addedTypes, Boolean firstLproj){ + CFIndex typeLen = fileLen - dotPosition.location - 1; + CFStringSetExternalCharactersNoCopy(type, fileNameBuffer+dotPosition.location+1, typeLen, typeLen); + CFMutableArrayRef tFiles = (CFMutableArrayRef) CFDictionaryGetValue(typeDir, type); + if (!tFiles) { + CFStringRef key = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@.%@"), _CFBundleTypeIndicator, type); + tFiles = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + CFDictionarySetValue(queryTable, key, tFiles); + CFDictionarySetValue(typeDir, type, tFiles); + CFRelease(tFiles); + CFRelease(key); + } + if (!addedTypes) { + CFArrayAppendValue(tFiles, value); + } else if (firstLproj) { + CFDictionarySetValue(addedTypes, type, type); + CFArrayAppendValue(tFiles, value); + } else if (!(CFDictionaryGetValue(addedTypes, type))) { + CFArrayAppendValue(tFiles, value); + } +} + +static Boolean _CFBundleReadDirectory(CFStringRef pathOfDir, CFBundleRef bundle, CFURLRef bundleURL, UniChar *resDir, UniChar *subDir, CFIndex subDirLen, CFMutableArrayRef allFiles, Boolean hasFileAdded, CFMutableStringRef type, CFMutableDictionaryRef queryTable, CFMutableDictionaryRef typeDir, CFMutableDictionaryRef addedTypes, Boolean firstLproj, CFStringRef product, CFStringRef platform, CFStringRef lprojName, Boolean appendLprojCharacters) { + + Boolean result = true; + + const CFIndex cPathBuffLen = CFStringGetMaximumSizeOfFileSystemRepresentation(pathOfDir) + 1; + const CFIndex valueBufferLen = cPathBuffLen + 1 + CFMaxPathSize; + UniChar *valueBuff = (UniChar *) CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UniChar) * valueBufferLen, 0); + CFMutableStringRef valueStr = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, kCFAllocatorNull); + CFIndex pathOfDirWithSlashLen = 0; + + CFIndex productLen = CFStringGetLength(product); + CFIndex platformLen = CFStringGetLength(platform); + + if (lprojName) { + // valueBuff is allocated with the actual length of lprojTarget + CFRange lprojRange = CFRangeMake(0, CFStringGetLength(lprojName)); + CFStringGetCharacters(lprojName, lprojRange, valueBuff); + pathOfDirWithSlashLen += lprojRange.length; + if (appendLprojCharacters) _CFAppendPathExtension(valueBuff, &pathOfDirWithSlashLen, valueBufferLen, _LprojUniChars, _LprojLen); + _CFAppendTrailingPathSlash(valueBuff, &pathOfDirWithSlashLen, valueBufferLen); + } + + if (subDirLen) { + memmove(valueBuff+pathOfDirWithSlashLen, subDir, subDirLen*sizeof(UniChar)); + pathOfDirWithSlashLen += subDirLen; + if (subDir[subDirLen-1] != _CFGetSlash()) { + _CFAppendTrailingPathSlash(valueBuff, &pathOfDirWithSlashLen, valueBufferLen); + } + } + + UniChar *fileNameBuffer = valueBuff + pathOfDirWithSlashLen; + char *cPathBuff = (char *)malloc(sizeof(char) * cPathBuffLen); + + if (CFStringGetFileSystemRepresentation(pathOfDir, cPathBuff, cPathBuffLen)) { +// this is a fix for traversing ouside of a bundle security issue: 8302591 +// it will be enabled after the bug 10956699 gets fixed +#ifdef CFBUNDLE_NO_TRAVERSE_OUTSIDE +#endif // CFBUNDLE_NO_TRAVERSE_OUTSIDE + +#if DEPLOYMENT_TARGET_WINDOWS + wchar_t pathBuf[CFMaxPathSize]; + CFStringRef pathInUTF8 = CFStringCreateWithCString(kCFAllocatorSystemDefault, cPathBuff, kCFStringEncodingUTF8); + CFIndex pathInUTF8Len = CFStringGetLength(pathInUTF8); + if (pathInUTF8Len > CFMaxPathSize) pathInUTF8Len = CFMaxPathSize; + + CFStringGetCharacters(pathInUTF8, CFRangeMake(0, pathInUTF8Len), (UniChar *)pathBuf); + pathBuf[pathInUTF8Len] = 0; + CFRelease(pathInUTF8); + WIN32_FIND_DATAW filePt; + HANDLE handle; + + if (pathInUTF8Len + 2 >= CFMaxPathLength) { + result = false; + } + + pathBuf[pathInUTF8Len] = '\\'; + pathBuf[pathInUTF8Len + 1] = '*'; + pathBuf[pathInUTF8Len + 2] = '\0'; + handle = FindFirstFileW(pathBuf, (LPWIN32_FIND_DATAW)&filePt); + if (INVALID_HANDLE_VALUE == handle) { + pathBuf[pathInUTF8Len] = '\0'; + result = false; + } + if (!result) { + free(cPathBuff); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, valueBuff); + CFRelease(valueStr); + return result; + } + + do { + CFIndex nameLen = wcslen(filePt.cFileName); + if (filePt.cFileName[0] == '.' && (nameLen == 1 || (nameLen == 2 && filePt.cFileName[1] == '.'))) { + continue; + } + CFStringRef file = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (const uint8_t *)filePt.cFileName, nameLen * sizeof(wchar_t), kCFStringEncodingUTF16, NO); +#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD + DIR *dirp = NULL; + struct dirent* dent; + if ( result && (dirp = opendir(cPathBuff))) { + + while ((dent = readdir(dirp))) { + +#if DEPLOYMENT_TARGET_LINUX + CFIndex nameLen = strlen(dent->d_name); +#else + CFIndex nameLen = dent->d_namlen; +#endif + if (0 == nameLen || 0 == dent->d_fileno || ('.' == dent->d_name[0] && (1 == nameLen || (2 == nameLen && '.' == dent->d_name[1]) || '_' == dent->d_name[1]))) + continue; + + CFStringRef file = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, dent->d_name); +#else +#error unknown architecture, not implemented +#endif + if (file) { + + CFIndex fileNameLen = CFStringGetLength(file); + if (fileNameLen > CFMaxPathSize) fileNameLen = CFMaxPathSize; + CFStringGetCharacters(file, CFRangeMake(0, fileNameLen), fileNameBuffer); + CFIndex valueTotalLen = pathOfDirWithSlashLen + fileNameLen; + +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD + // construct the path for a file, which is the value in the query table + // if it is a dir + if (dent->d_type == DT_DIR) { + _CFAppendTrailingPathSlash(valueBuff, &valueTotalLen, valueBufferLen); + } else if (dent->d_type == DT_UNKNOWN) { + Boolean isDir = false; + char subdirPath[CFMaxPathLength]; + struct stat statBuf; + strlcpy(subdirPath, cPathBuff, sizeof(subdirPath)); + strlcat(subdirPath, "/", sizeof(subdirPath)); + strlcat(subdirPath, dent->d_name, sizeof(subdirPath)); + if (stat(subdirPath, &statBuf) == 0) { + isDir = ((statBuf.st_mode & S_IFMT) == S_IFDIR); + } + if (isDir) { + _CFAppendTrailingPathSlash(valueBuff, &valueTotalLen, valueBufferLen); + } + } +#elif DEPLOYMENT_TARGET_WINDOWS + if ((filePt.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + _CFAppendTrailingPathSlash(valueBuff, &valueTotalLen, valueBufferLen); + } +#endif + CFStringSetExternalCharactersNoCopy(valueStr, valueBuff, valueTotalLen, valueBufferLen); + CFTypeRef value = CFStringCreateCopy(kCFAllocatorSystemDefault, valueStr); + + // put it into all file array + if (!hasFileAdded) { + CFArrayAppendValue(allFiles, value); + } + + // put it into type array + // search the type from the end + CFRange backDotPosition, dotPosition; + Boolean foundDot = _CFBundleFindCharacterInStr(fileNameBuffer, '.', YES, fileNameLen-1, fileNameLen, &backDotPosition); + + if (foundDot && backDotPosition.location != (fileNameLen-1)) { + _CFBundleAddValueForType(type, fileNameBuffer, queryTable, backDotPosition, fileNameLen, typeDir, value, addedTypes, firstLproj); + } + + // search the type from the beginning + //CFRange dotPosition = CFStringFind(file, _CFBundleDot, kCFCompareEqualTo); + foundDot = _CFBundleFindCharacterInStr(fileNameBuffer, '.', NO, 0, fileNameLen, &dotPosition); + if (dotPosition.location != backDotPosition.location && foundDot) { + _CFBundleAddValueForType(type, fileNameBuffer, queryTable, dotPosition, fileNameLen, typeDir, value, addedTypes, firstLproj); + } + + // check if the file is product and platform specific + CFRange productRange, platformRange; + _CFBundleFileVersion fileVersion = _CFBundleCheckFileProductAndPlatform(file, fileNameBuffer, fileNameLen, CFRangeMake(0, fileNameLen), product, platform, &productRange, &platformRange, productLen); + + if (fileVersion == _CFBundleFileVersionNoProductNoPlatform || fileVersion == _CFBundleFileVersionUnmatched) { + // No product/no platform, or unmatched files get added directly to the query table. + CFStringRef prevPath = (CFStringRef)CFDictionaryGetValue(queryTable, file); + if (!prevPath) { + CFDictionarySetValue(queryTable, file, value); + } + } else { + // If the file has a product or platform extension, we add the full name to the query table so that it may be found using that name. + // Then we add the more specific name as well. + CFDictionarySetValue(queryTable, file, value); + + CFIndex searchOffset = platformLen; + CFStringRef key = NULL; + + // set the key accordining to the version of the file (product and platform) + switch (fileVersion) { + case _CFBundleFileVersionWithProductNoPlatform: + platformRange = productRange; + searchOffset = productLen; + case _CFBundleFileVersionNoProductWithPlatform: + case _CFBundleFileVersionWithProductWithPlatform: + foundDot = _CFBundleFindCharacterInStr(fileNameBuffer, '.', NO, platformRange.location+searchOffset, fileNameLen-platformRange.location-searchOffset, &dotPosition); + if (foundDot) { + CFMutableStringRef mutableKey = CFStringCreateMutable(kCFAllocatorSystemDefault, platformRange.location + (fileNameLen - dotPosition.location)); + CFStringAppendCharacters(mutableKey, fileNameBuffer, platformRange.location); + CFStringAppendCharacters(mutableKey, fileNameBuffer+dotPosition.location, fileNameLen - dotPosition.location); + key = (CFStringRef)mutableKey; + } else { + key = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, fileNameBuffer, platformRange.location); + } + break; + default: + CFLog(kCFLogLevelError, CFSTR("CFBundle: Unknown kind of file (%d) when creating CFBundle: %@"), pathOfDir); + break; + } + + if (key) { + // add the path of the key into the query table + CFStringRef prevPath = (CFStringRef) CFDictionaryGetValue(queryTable, key); + if (!prevPath) { + CFDictionarySetValue(queryTable, key, value); + } else { + if (!lprojName || CFStringHasPrefix(prevPath, lprojName)) { + // we need to know the version of exisiting path to see if we can replace it by the current path + CFRange searchRange; + if (lprojName) { + searchRange.location = CFStringGetLength(lprojName); + searchRange.length = CFStringGetLength(prevPath) - searchRange.location; + } else { + searchRange.location = 0; + searchRange.length = CFStringGetLength(prevPath); + } + _CFBundleFileVersion prevFileVersion = _CFBundleCheckFileProductAndPlatform(prevPath, NULL, 0, searchRange, product, platform, &productRange, &platformRange, productLen); + switch (prevFileVersion) { + case _CFBundleFileVersionNoProductNoPlatform: + CFDictionarySetValue(queryTable, key, value); + break; + case _CFBundleFileVersionWithProductNoPlatform: + if (fileVersion == _CFBundleFileVersionWithProductWithPlatform) CFDictionarySetValue(queryTable, key, value); + break; + case _CFBundleFileVersionNoProductWithPlatform: + CFDictionarySetValue(queryTable, key, value); + break; + default: + break; + } + } + } + + CFRelease(key); + } + } + + CFRelease(value); + CFRelease(file); + } + + +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD + } + closedir(dirp); + } else { // opendir + result = false; + } +#elif DEPLOYMENT_TARGET_WINDOWS + } while ((FindNextFileW(handle, &filePt))); + FindClose(handle); + pathBuf[pathInUTF8Len] = '\0'; +#endif + + } else { // the path counld not be resolved to be a file system representation + result = false; + } + + free(cPathBuff); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, valueBuff); + CFRelease(valueStr); + return result; +} + +__private_extern__ CFDictionaryRef _CFBundleCreateQueryTableAtPath(CFBundleRef bundle, CFURLRef bundleURL, CFArrayRef languages, UniChar *resDir, CFIndex resDirLen, UniChar *subDir, CFIndex subDirLen) +{ + const CFIndex pathBufferSize = 2*CFMaxPathSize+resDirLen+subDirLen+2; + UniChar *pathBuffer = (UniChar *) CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UniChar) * pathBufferSize, 0); + + CFMutableDictionaryRef queryTable = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFMutableArrayRef allFiles = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + CFMutableDictionaryRef typeDir = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFMutableStringRef type = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, kCFAllocatorNull); + + CFStringRef productName = _CFGetProductName();//CFSTR("iphone"); + CFStringRef platformName = _CFGetPlatformName();//CFSTR("iphoneos"); + if (CFEqual(productName, CFSTR("ipod"))) { + productName = CFSTR("iphone"); + } + CFStringRef product = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("~%@"), productName); + CFStringRef platform = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("-%@"), platformName); + + CFStringRef bundlePath = NULL; + if (bundle) { + bundlePath = _CFBundleGetBundlePath(bundle); + CFRetain(bundlePath); + } else { + CFURLRef url = CFURLCopyAbsoluteURL(bundleURL); + bundlePath = CFURLCopyFileSystemPath(url, PLATFORM_PATH_STYLE); + CFRelease(url); + } + // bundlePath is an actual path, so it should not have a length greater than CFMaxPathSize + CFIndex pathLen = CFStringGetLength(bundlePath); + CFStringGetCharacters(bundlePath, CFRangeMake(0, pathLen), pathBuffer); + CFRelease(bundlePath); + + Boolean appendSucc = true; + if (resDirLen > 0) { // should not fail, buffer has enought space + appendSucc = _CFAppendPathComponent(pathBuffer, &pathLen, pathBufferSize, resDir, resDirLen); + } + + CFStringRef basePath = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, pathBuffer, pathLen); + + if (subDirLen > 0) { // should not fail, buffer has enought space + appendSucc = _CFAppendPathComponent(pathBuffer, &pathLen, pathBufferSize, subDir, subDirLen); + } + + CFStringRef pathToRead = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, pathBuffer, pathLen); + + // read the content in sub dir and put them into query table + _CFBundleReadDirectory(pathToRead, bundle, bundleURL, resDir, subDir, subDirLen, allFiles, false, type, queryTable, typeDir, NULL, false, product, platform, NULL, false); + + CFRelease(pathToRead); + + CFIndex numOfAllFiles = CFArrayGetCount(allFiles); + + if (bundle && !languages) { + languages = _CFBundleGetLanguageSearchList(bundle); + } + CFIndex numLprojs = languages ? CFArrayGetCount(languages) : 0; + CFMutableDictionaryRef addedTypes = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + CFIndex basePathLen = CFStringGetLength(basePath); + Boolean hasFileAdded = false; + Boolean firstLproj = true; + + // First, search lproj for user's chosen language + if (numLprojs >= 1) { + CFStringRef lprojTarget = (CFStringRef)CFArrayGetValueAtIndex(languages, 0); + // lprojTarget is from _CFBundleGetLanguageSearchList, so it should not have a length greater than CFMaxPathSize + UniChar lprojBuffer[CFMaxPathSize]; + CFIndex lprojLen = CFStringGetLength(lprojTarget); + CFStringGetCharacters(lprojTarget, CFRangeMake(0, lprojLen), lprojBuffer); + + pathLen = basePathLen; + _CFAppendPathComponent(pathBuffer, &pathLen, pathBufferSize, lprojBuffer, lprojLen); + _CFAppendPathExtension(pathBuffer, &pathLen, pathBufferSize, _LprojUniChars, _LprojLen); + if (subDirLen > 0) { + _CFAppendPathComponent(pathBuffer, &pathLen, pathBufferSize, subDir, subDirLen); + } + pathToRead = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, pathBuffer, pathLen); + _CFBundleReadDirectory(pathToRead, bundle, bundleURL, resDir, subDir, subDirLen, allFiles, hasFileAdded, type, queryTable, typeDir, addedTypes, firstLproj, product, platform, lprojTarget, true); + CFRelease(pathToRead); + + if (!hasFileAdded && numOfAllFiles < CFArrayGetCount(allFiles)) { + hasFileAdded = true; + } + firstLproj = false; + } + + // Next, search Base.lproj folder + pathLen = basePathLen; + _CFAppendPathComponent(pathBuffer, &pathLen, pathBufferSize, _BaseUniChars, _BaseLen); + _CFAppendPathExtension(pathBuffer, &pathLen, pathBufferSize, _LprojUniChars, _LprojLen); + if (subDirLen > 0) { + _CFAppendPathComponent(pathBuffer, &pathLen, pathBufferSize, subDir, subDirLen); + } + pathToRead = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, pathBuffer, pathLen); + _CFBundleReadDirectory(pathToRead, bundle, bundleURL, resDir, subDir, subDirLen, allFiles, hasFileAdded, type, queryTable, typeDir, addedTypes, YES, product, platform, _CFBundleBaseDirectory, true); + CFRelease(pathToRead); + + if (!hasFileAdded && numOfAllFiles < CFArrayGetCount(allFiles)) { + hasFileAdded = true; + } + + // Finally, search remaining languages (development language first) + if (numLprojs >= 2) { + // for each lproj we are interested in, read the content and put them into query table + for (CFIndex i = 1; i < CFArrayGetCount(languages); i++) { + CFStringRef lprojTarget = (CFStringRef) CFArrayGetValueAtIndex(languages, i); + // lprojTarget is from _CFBundleGetLanguageSearchList, so it should not have a length greater than CFMaxPathSize + UniChar lprojBuffer[CFMaxPathSize]; + CFIndex lprojLen = CFStringGetLength(lprojTarget); + CFStringGetCharacters(lprojTarget, CFRangeMake(0, lprojLen), lprojBuffer); + + pathLen = basePathLen; + _CFAppendPathComponent(pathBuffer, &pathLen, pathBufferSize, lprojBuffer, lprojLen); + _CFAppendPathExtension(pathBuffer, &pathLen, pathBufferSize, _LprojUniChars, _LprojLen); + if (subDirLen > 0) { + _CFAppendPathComponent(pathBuffer, &pathLen, pathBufferSize, subDir, subDirLen); + } + pathToRead = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, pathBuffer, pathLen); + _CFBundleReadDirectory(pathToRead, bundle, bundleURL, resDir, subDir, subDirLen, allFiles, hasFileAdded, type, queryTable, typeDir, addedTypes, false, product, platform, lprojTarget, true); + CFRelease(pathToRead); + + if (!hasFileAdded && numOfAllFiles < CFArrayGetCount(allFiles)) { + hasFileAdded = true; + } + } + } + + CFRelease(addedTypes); + + // put the array of all files in sub dir to the query table + if (CFArrayGetCount(allFiles) > 0) { + CFDictionarySetValue(queryTable, _CFBundleAllFiles, allFiles); + } + + CFRelease(platform); + CFRelease(product); + CFRelease(allFiles); + CFRelease(typeDir); + CFRelease(type); + CFRelease(basePath); + + CFAllocatorDeallocate(kCFAllocatorSystemDefault, pathBuffer); + return queryTable; +} + +static CFURLRef _CFBundleCreateURLFromPath(CFStringRef path, UniChar slash, UniChar *urlBuffer, CFIndex urlBufferLen, CFMutableStringRef urlStr) +{ + CFURLRef url = NULL; + // path is a part of an actual path in the query table, so it should not have a length greater than the buffer size + CFIndex pathLen = CFStringGetLength(path); + CFStringGetCharacters(path, CFRangeMake(0, pathLen), urlBuffer+urlBufferLen); + CFStringSetExternalCharactersNoCopy(urlStr, urlBuffer, urlBufferLen+pathLen, CFMaxPathSize); + if (CFStringGetCharacterAtIndex(path, pathLen-1) == slash) { + url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, urlStr, PLATFORM_PATH_STYLE, YES); + } else { + url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, urlStr, PLATFORM_PATH_STYLE, NO); + } + + return url; +} + +static CFURLRef _CFBundleCreateRelativeURLFromBaseAndPath(CFStringRef path, CFURLRef base, UniChar slash, CFStringRef slashStr) +{ + CFURLRef url = NULL; + CFRange resultRange; + Boolean needToRelease = false; + if (CFStringFindWithOptions(path, slashStr, CFRangeMake(0, CFStringGetLength(path)-1), kCFCompareBackwards, &resultRange)) { + CFStringRef subPathCom = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, path, CFRangeMake(0, resultRange.location)); + base = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, base, subPathCom, YES); + path = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, path, CFRangeMake(resultRange.location+1, CFStringGetLength(path)-resultRange.location-1)); + CFRelease(subPathCom); + needToRelease = true; + } + if (CFStringGetCharacterAtIndex(path, CFStringGetLength(path)-1) == slash) { + url = (CFURLRef)CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, path, PLATFORM_PATH_STYLE, YES, base); + } else { + url = (CFURLRef)CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, path, PLATFORM_PATH_STYLE, NO, base); + } + if (needToRelease) { + CFRelease(base); + CFRelease(path); + } + return url; +} + +static void _CFBundleFindResourcesWithPredicate(CFMutableArrayRef interResult, CFDictionaryRef queryTable, Boolean (^predicate)(CFStringRef filename, Boolean *stop), Boolean *stop) +{ + CFIndex dictSize = CFDictionaryGetCount(queryTable); + if (dictSize == 0) { + return; + } + STACK_BUFFER_DECL(CFTypeRef, keys, dictSize); + STACK_BUFFER_DECL(CFTypeRef, values, dictSize); + CFDictionaryGetKeysAndValues(queryTable, keys, values); + for (CFIndex i = 0; i < dictSize; i++) { + if (predicate((CFStringRef)keys[i], stop)) { + if (CFGetTypeID(values[i]) == CFStringGetTypeID()) { + CFArrayAppendValue(interResult, values[i]); + } else { + CFArrayAppendArray(interResult, (CFArrayRef)values[i], CFRangeMake(0, CFArrayGetCount((CFArrayRef)values[i]))); + } + } + + if (*stop) break; + } +} + +static CFTypeRef _CFBundleCopyURLsOfKey(CFBundleRef bundle, CFURLRef bundleURL, CFArrayRef languages, UniChar *resDir, CFIndex resDirLen, UniChar *subDirBuffer, CFIndex subDirLen, CFStringRef subDir, CFStringRef key, CFStringRef lproj, UniChar *lprojBuff, Boolean returnArray, Boolean localized, uint8_t bundleVersion, Boolean (^predicate)(CFStringRef filename, Boolean *stop)) +{ + CFTypeRef value = NULL; + Boolean stop = false; // for predicate + CFMutableArrayRef interResult = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + CFDictionaryRef subTable = NULL; + + if (1 == bundleVersion) { + CFIndex savedResDirLen = resDirLen; + // add the non-localized resource dir + Boolean appendSucc = _CFAppendPathComponent(resDir, &resDirLen, CFMaxPathSize, _GlobalResourcesUniChars, _GlobalResourcesLen); + if (appendSucc) { + subTable = _CFBundleCopyQueryTable(bundle, bundleURL, languages, resDir, resDirLen, subDirBuffer, subDirLen); + if (predicate) { + _CFBundleFindResourcesWithPredicate(interResult, subTable, predicate, &stop); + } else { + value = CFDictionaryGetValue(subTable, key); + } + } + resDirLen = savedResDirLen; + } + + if (!value && !stop) { + if (subTable) CFRelease(subTable); + subTable = _CFBundleCopyQueryTable(bundle, bundleURL, languages, resDir, resDirLen, subDirBuffer, subDirLen); + if (predicate) { + _CFBundleFindResourcesWithPredicate(interResult, subTable, predicate, &stop); + } else { + // get the path or paths for the given key + value = CFDictionaryGetValue(subTable, key); + } + } + + // if localization is needed, we filter out the paths for the localization and put the valid ones in the interResult + Boolean checkLP = true; + CFIndex lpLen = lproj ? CFStringGetLength(lproj) : 0; + if (localized && value) { + + if (CFGetTypeID(value) == CFStringGetTypeID()){ + // We had one result, but since we are going to do a search in a different localization, we will convert the one result into an array of results. + value = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&value, 1, &kCFTypeArrayCallBacks); + } else { + CFRetain(value); + } + + CFRange resultRange, searchRange; + CFIndex pathValueLen; + CFIndex limit = returnArray ? CFArrayGetCount((CFArrayRef)value) : 1; + searchRange.location = 0; + for (CFIndex i = 0; i < limit; i++) { + CFStringRef pathValue = (CFStringRef) CFArrayGetValueAtIndex((CFArrayRef)value, i); + pathValueLen = CFStringGetLength(pathValue); + searchRange.length = pathValueLen; + + // if we have subdir, we find the subdir and see if it is after the base path (bundle path + res dir) + Boolean searchForLocalization = false; + if (subDirLen) { + if (CFStringFindWithOptions(pathValue, subDir, searchRange, kCFCompareEqualTo, &resultRange) && resultRange.location != searchRange.location) { + searchForLocalization = true; + } + } else if (!subDirLen && searchRange.length != 0) { + if (CFStringFindWithOptions(pathValue, _CFBundleLprojExtensionWithDot, searchRange, kCFCompareEqualTo, &resultRange) && resultRange.location + 7 < pathValueLen) { + searchForLocalization = true; + } + } + + if (searchForLocalization) { + if (!lpLen || !(CFStringFindWithOptions(pathValue, lproj, searchRange, kCFCompareEqualTo | kCFCompareAnchored, &resultRange) && CFStringFindWithOptions(pathValue, CFSTR("."), CFRangeMake(resultRange.location + resultRange.length, 1), kCFCompareEqualTo, &resultRange))) { + break; + } + checkLP = false; + } + + CFArrayAppendValue(interResult, pathValue); + } + + CFRelease(value); + + if (!returnArray && CFArrayGetCount(interResult) != 0) { + checkLP = false; + } + } else if (value) { + if (CFGetTypeID(value) == CFArrayGetTypeID()) { + CFArrayAppendArray(interResult, (CFArrayRef)value, CFRangeMake(0, CFArrayGetCount((CFArrayRef)value))); + } else { + CFArrayAppendValue(interResult, value); + } + } + + value = NULL; + CFRelease(subTable); + + // we fetch the result for a given lproj and join them with the nonlocalized result fetched above + if (lpLen && checkLP) { + CFIndex lprojBuffLen = lpLen; + // lprojBuff is allocated with the actual size of lproj + CFStringGetCharacters(lproj, CFRangeMake(0, lpLen), lprojBuff); + _CFAppendPathExtension(lprojBuff, &lprojBuffLen, lprojBuffLen+7, _LprojUniChars, _LprojLen); + + if (subDirLen) { + _CFAppendTrailingPathSlash(lprojBuff, &lprojBuffLen, lprojBuffLen+1); + } + subTable = _CFBundleCopyQueryTable(bundle, bundleURL, languages, resDir, resDirLen, lprojBuff, subDirLen+lprojBuffLen); + + value = CFDictionaryGetValue(subTable, key); + + if (value) { + if (CFGetTypeID(value) == CFStringGetTypeID()) { + CFArrayAppendValue(interResult, value); + } else { + CFArrayAppendArray(interResult, (CFArrayRef)value, CFRangeMake(0, CFArrayGetCount((CFArrayRef)value))); + } + } + + CFRelease(subTable); + } + + // after getting paths, we create urls from the paths + CFTypeRef result = NULL; + if (CFArrayGetCount(interResult) > 0) { + UniChar slash = _CFGetSlash(); + UniChar *urlBuffer = (UniChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UniChar) * CFMaxPathSize, 0); + CFMutableStringRef urlStr = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, kCFAllocatorNull); + CFStringRef bundlePath = NULL; + if (bundle) { + bundlePath = _CFBundleGetBundlePath(bundle); + CFRetain(bundlePath); + } else { + CFURLRef url = CFURLCopyAbsoluteURL(bundleURL); + bundlePath = CFURLCopyFileSystemPath(url, PLATFORM_PATH_STYLE); + CFRelease(url); + } + CFIndex urlBufferLen = CFStringGetLength(bundlePath); + CFStringGetCharacters(bundlePath, CFRangeMake(0, urlBufferLen), urlBuffer); + CFRelease(bundlePath); + + if (resDirLen) { + _CFAppendPathComponent(urlBuffer, &urlBufferLen, CFMaxPathSize, resDir, resDirLen); + } + _CFAppendTrailingPathSlash(urlBuffer, &urlBufferLen, CFMaxPathSize); + + if (!returnArray) { + Boolean isOnlyTypeOrAllFiles = CFStringHasPrefix(key, _CFBundleTypeIndicator); + isOnlyTypeOrAllFiles |= CFStringHasPrefix(key, _CFBundleAllFiles); + + CFStringRef resultPath = (CFStringRef)CFArrayGetValueAtIndex((CFArrayRef)interResult, 0); + if (!isOnlyTypeOrAllFiles) { + result = (CFURLRef)_CFBundleCreateURLFromPath((CFStringRef)resultPath, slash, urlBuffer, urlBufferLen, urlStr); + } else { // need to create relative URLs for binary compatibility issues + CFStringSetExternalCharactersNoCopy(urlStr, urlBuffer, urlBufferLen, CFMaxPathSize); + CFURLRef base = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, urlStr, PLATFORM_PATH_STYLE, YES); + CFStringRef slashStr = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &slash, 1); + result = (CFURLRef)_CFBundleCreateRelativeURLFromBaseAndPath(resultPath, base, slash, slashStr); + CFRelease(slashStr); + CFRelease(base); + } + } else { + // need to create relative URLs for binary compatibility issues + CFIndex numOfPaths = CFArrayGetCount((CFArrayRef)interResult); + CFStringSetExternalCharactersNoCopy(urlStr, urlBuffer, urlBufferLen, CFMaxPathSize); + CFURLRef base = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, urlStr, PLATFORM_PATH_STYLE, YES); + CFStringRef slashStr = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &slash, 1); + CFMutableArrayRef urls = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + for (CFIndex i = 0; i < numOfPaths; i++) { + CFStringRef path = (CFStringRef)CFArrayGetValueAtIndex((CFArrayRef)interResult, i); + CFURLRef url = _CFBundleCreateRelativeURLFromBaseAndPath(path, base, slash, slashStr); + CFArrayAppendValue(urls, url); + CFRelease(url); + } + result = urls; + CFRelease(base); + } + CFRelease(urlStr); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, urlBuffer); + } else if (returnArray) { + result = CFRetain(interResult); + } + + CFRelease(interResult); + return result; +} + +CFTypeRef _CFBundleCopyFindResources(CFBundleRef bundle, CFURLRef bundleURL, CFArrayRef languages, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subPath, CFStringRef lproj, Boolean returnArray, Boolean localized, Boolean (^predicate)(CFStringRef filename, Boolean *stop)) +{ + CFIndex rnameLen = 0; + CFIndex typeLen = resourceType ? CFStringGetLength(resourceType) : 0; + CFIndex lprojLen = lproj ? CFStringGetLength(lproj) + 7 : 0; // 7 is the length of ".lproj/" + CFStringRef subPathFromResourceName = NULL; + CFIndex subPathFromResourceNameLen = 0; + if (resourceName) { + UniChar tmpNameBuffer[CFMaxPathSize]; + rnameLen = CFStringGetLength(resourceName); + if (rnameLen > CFMaxPathSize) rnameLen = CFMaxPathSize; + CFStringGetCharacters(resourceName, CFRangeMake(0, rnameLen), tmpNameBuffer); + CFIndex rnameIndex = _CFStartOfLastPathComponent(tmpNameBuffer, rnameLen); + if (rnameIndex != 0) { + resourceName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, tmpNameBuffer+rnameIndex, rnameLen - rnameIndex); + subPathFromResourceName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, tmpNameBuffer, rnameIndex-1); + subPathFromResourceNameLen = rnameIndex-1; + } else { + CFRetain(resourceName); + } + + char buff[CFMaxPathSize]; + CFStringRef newResName = NULL; + if (CFStringGetFileSystemRepresentation(resourceName, buff, CFMaxPathSize)) { + newResName = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, buff); + } + CFStringRef tmpStr = resourceName; + resourceName = newResName ? newResName : (CFStringRef)CFRetain(resourceName); + rnameLen = CFStringGetLength(resourceName); + CFRelease(tmpStr); + } + CFIndex subDirLen = subPath ? CFStringGetLength(subPath) : 0; + if (subDirLen == 0) subPath = NULL; + if (subDirLen && subPathFromResourceName) { + subDirLen += (subPathFromResourceNameLen + 1); + } else if (subPathFromResourceNameLen) { + subDirLen = subPathFromResourceNameLen; + } + + // the nameBuff have the format: [resourceName].[resourceType][lprojName.lproj/][subPath][resource dir] + UniChar *nameBuff = (UniChar *) CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UniChar) * (rnameLen + 1 + typeLen + subDirLen + lprojLen + CFMaxPathSize), 0); + UniChar *typeBuff = rnameLen ? nameBuff + rnameLen + 1 : nameBuff + CFStringGetLength(_CFBundleTypeIndicator) + 1; + UniChar *lprojBuffer = typeBuff + typeLen; + UniChar *subDirBuffer = lprojBuffer + lprojLen; + UniChar *resDir = subDirBuffer + subDirLen; + + CFStringRef key = NULL; + + CFIndex typeP = 0; + if (typeLen && CFStringGetCharacterAtIndex(resourceType, 0) == '.') { + typeP = 1; + typeLen--; + } + if (rnameLen && typeLen) { + CFStringGetCharacters(resourceName, CFRangeMake(0, rnameLen), nameBuff); + nameBuff[rnameLen] = '.'; + CFStringGetCharacters(resourceType, CFRangeMake(typeP, typeLen), typeBuff); + key = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, nameBuff, rnameLen+typeLen+1); + } else if (rnameLen) { + CFStringGetCharacters(resourceName, CFRangeMake(0, rnameLen), nameBuff); + key = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, nameBuff, rnameLen); + } else if (typeLen) { + rnameLen = CFStringGetLength(_CFBundleTypeIndicator); + CFStringGetCharacters(_CFBundleTypeIndicator, CFRangeMake(0, rnameLen), nameBuff); + nameBuff[rnameLen] = '.'; + CFStringGetCharacters(resourceType, CFRangeMake(typeP, typeLen), typeBuff); + key = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, nameBuff, rnameLen+typeLen+1); + } else { + key = (CFStringRef)CFRetain(_CFBundleAllFiles); + } + + if (subDirLen) { + CFIndex subPathLen = 0; + if (subPath) { + subPathLen = CFStringGetLength(subPath); + CFStringGetCharacters(subPath, CFRangeMake(0, subPathLen), subDirBuffer); + if (subPathFromResourceName) _CFAppendTrailingPathSlash(subDirBuffer, &subPathLen, subDirLen); + } + if (subPathFromResourceName) { + CFStringGetCharacters(subPathFromResourceName, CFRangeMake(0, subPathFromResourceNameLen), subDirBuffer+subPathLen); + subPathLen += subPathFromResourceNameLen; + subPath = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, subDirBuffer, subPathLen); + } else { + CFRetain(subPath); + } + } + + // Init the one-time-only unichar buffers. + _CFEnsureStaticBuffersInited(); + + CFIndex resDirLen = 0; + uint8_t bundleVersion = bundle ? _CFBundleLayoutVersion(bundle) : 0; + if (bundleURL && !languages) { + languages = _CFBundleCopyLanguageSearchListInDirectory(kCFAllocatorSystemDefault, bundleURL, &bundleVersion); + } else if (languages) { + CFRetain(languages); + } + + _CFBundleSetResourceDir(resDir, &resDirLen, CFMaxPathSize, bundleVersion); + + CFTypeRef returnValue = _CFBundleCopyURLsOfKey(bundle, bundleURL, languages, resDir, resDirLen, subDirBuffer, subDirLen, subPath, key, lproj, lprojBuffer, returnArray, localized, bundleVersion, predicate); + + if ((!returnValue || (CFGetTypeID(returnValue) == CFArrayGetTypeID() && CFArrayGetCount((CFArrayRef)returnValue) == 0)) && (0 == bundleVersion || 2 == bundleVersion)) { + CFStringRef bundlePath = NULL; + if (bundle) { + bundlePath = _CFBundleGetBundlePath(bundle); + CFRetain(bundlePath); + } else { + CFURLRef absoluteURL = CFURLCopyAbsoluteURL(bundleURL); + bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); + CFRelease(absoluteURL); + } + if ((0 == bundleVersion) || CFEqual(CFSTR("/Library/Spotlight"), bundlePath)){ + if (returnValue) CFRelease(returnValue); + CFRange found; + // 9 is the length of "Resources" + if ((bundleVersion == 0 && subPath && CFEqual(subPath, CFSTR("Resources"))) || (bundleVersion == 2 && subPath && CFEqual(subPath, CFSTR("Contents/Resources")))){ + subDirLen = 0; + } else if ((bundleVersion == 0 && subPath && CFStringFindWithOptions(subPath, CFSTR("Resources/"), CFRangeMake(0, 10), kCFCompareEqualTo, &found) && found.location+10 < subDirLen)) { + subDirBuffer = subDirBuffer + 10; + subDirLen -= 10; + } else if ((bundleVersion == 2 && subPath && CFStringFindWithOptions(subPath, CFSTR("Contents/Resources/"), CFRangeMake(0, 19), kCFCompareEqualTo, &found) && found.location+19 < subDirLen)) { + subDirBuffer = subDirBuffer + 19; + subDirLen -= 19; + } else { + resDirLen = 0; + } + if (subDirLen > 0) { + CFRelease(subPath); + subPath = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, subDirBuffer, subDirLen); + } + returnValue = _CFBundleCopyURLsOfKey(bundle, bundleURL, languages, resDir, resDirLen, subDirBuffer, subDirLen, subPath, key, lproj, lprojBuffer, returnArray, localized, bundleVersion, predicate); + } + CFRelease(bundlePath); + } + + if (resourceName) CFRelease(resourceName); + if (subPath) CFRelease(subPath); + if (subPathFromResourceName) CFRelease(subPathFromResourceName); + if (languages) CFRelease(languages); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, nameBuff); + CFRelease(key); + return returnValue; +} + +__private_extern__ CFTypeRef _CFBundleCopyFindResourcesWithNoBlock(CFBundleRef bundle, CFURLRef bundleURL, CFArrayRef languages, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subPath, CFStringRef lproj, Boolean returnArray, Boolean localized) +{ + return _CFBundleCopyFindResources(bundle, bundleURL, languages, resourceName, resourceType, subPath, lproj, returnArray, localized, NULL); +} diff --git a/CFBurstTrie.c b/CFBurstTrie.c new file mode 100644 index 0000000..b723321 --- /dev/null +++ b/CFBurstTrie.c @@ -0,0 +1,2095 @@ +/* + * Copyright (c) 2012 Apple 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@ + */ + +/* CFBurstTrie.c + Copyright (c) 2008-2012, Apple Inc. All rights reserved. + Responsibility: Jennifer Moore +*/ + +#include "CFInternal.h" +#include "CFBurstTrie.h" +#include "CFByteOrder.h" +#include "CFNumber.h" +#include +#include +#include +#include +#include +#include +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI +#include +#include +#include +#endif + +#include +#include + +#if DEPLOYMENT_TARGET_WINDOWS +#define open _NS_open +#define statinfo _stat +#define stat(x,y) _NS_stat(x,y) +#define __builtin_memcmp(x, y, z) memcmp(x, y, z) +#define __builtin_popcountll(x) popcountll(x) +#define bzero(dst, size) ZeroMemory(dst, size) +#define S_IWUSR 0 +#define S_IRUSR 0 + +static int pwrite(int fd, const void *buf, size_t nbyte, off_t offset) { + // Get where we are + long pos = _tell(fd); + + // Move to new offset + _lseek(fd, offset, SEEK_SET); + + // Write data + int res = _write(fd, buf, nbyte); + + // Return to previous offset + _lseek(fd, pos, SEEK_SET); + + return res; +} + +#else +#define statinfo stat +#endif + +#if 0 +#pragma mark Types and Utilities +#endif + +#define MAX_STRING_ALLOCATION_SIZE 342 +#define MAX_STRING_SIZE 1024 +#define MAX_KEY_LENGTH MAX_STRING_SIZE * 4 +#define CHARACTER_SET_SIZE 256 +#define MAX_LIST_SIZE 256 // 64 +#define MAX_BITMAP_SIZE 200 +#define MAX_BUFFER_SIZE (4096<<2) + +#define NextTrie_GetPtr(p) (p & ((~(uintptr_t)0)-3)) +#define NextTrie_GetKind(p) (p & 3) +#define NextTrie_SetKind(p, kind) (p |= (3&kind)) + +#define DiskNextTrie_GetPtr(map,offset) (((uintptr_t)map) + (uintptr_t)(offset & ((~(uintptr_t)0)-3))) +#define DiskNextTrie_GetKind(p) (p & 3) +#define DiskNextTrie_SetKind(p, kind) (p |= (3&kind)) + +// Use this macro to avoid forgetting to check the pointer before assigning value to it. +#define SetPayload(pointer, value) do { if (pointer) *pointer = value; } while (0) + +enum { Nothing = 0, TrieKind = 1, ListKind = 2, CompactTrieKind = 3 }; +typedef enum { FailedInsert = 0, NewTerm = 1, ExistingTerm = 2 } CFBTInsertCode; + +#pragma pack (1) +typedef uintptr_t NextTrie; + +typedef struct _TrieLevel { + NextTrie slots[CHARACTER_SET_SIZE]; + uint32_t weight; + uint32_t payload; +} TrieLevel; +typedef TrieLevel *TrieLevelRef; + +typedef struct _MapTrieLevel { + uint32_t slots[CHARACTER_SET_SIZE]; + uint32_t payload; +} MapTrieLevel; +typedef MapTrieLevel *MapTrieLevelRef; + +typedef struct _CompactMapTrieLevel { + uint64_t bitmap[CHARACTER_SET_SIZE / 64]; + uint32_t payload; + uint32_t slots[]; +} CompactMapTrieLevel; +typedef CompactMapTrieLevel *CompactMapTrieLevelRef; + +typedef struct _ListNode { + struct _ListNode *next; + uint32_t weight; + uint32_t payload; + uint16_t length; + UInt8 string[]; +}* ListNodeRef; + +typedef struct _Page { + uint32_t length; + char data[]; +} Page; + +typedef struct _PageEntryPacked { + uint8_t pfxLen; + uint16_t strlen; + uint32_t payload; + UInt8 string[]; +} PageEntryPacked; + +typedef struct _PageEntry { + uint16_t strlen; + uint32_t payload; + UInt8 string[]; +} PageEntry; + +typedef struct _TrieHeader { + uint32_t signature; + uint32_t rootOffset; + uint32_t count; + uint32_t size; + uint32_t flags; + uint64_t reserved[16]; +} TrieHeader; + +typedef struct _TrieCursor { + uint64_t signature; + uint64_t counter; + NextTrie next; + uint32_t keylen; + uint32_t prefixlen; + const uint8_t *prefix; + uint8_t key[MAX_KEY_LENGTH]; +} TrieCursor; + +typedef struct _MapCursor { + uint64_t signature; + TrieHeader *header; + uint32_t next; + uint32_t prefixlen; + uint32_t keylen; + const uint8_t *prefix; + uint8_t key[MAX_STRING_SIZE*4]; +} MapCursor; + +typedef struct _CompactMapCursor { + uint32_t next; + uint32_t entryOffsetInPage; + uint32_t offsetInEntry; + uint32_t payload; + // On a page, the first entry could has 0 strlen. So we need this variable to tell us whether + // the cursor is merely pointing at the beginning of the page, or the first entry. + // For example, if the trie contains "ab" and "abc", where "a" is stored on an array level, + // while "b" and "bc" are stored on a page level. If we creat a cursor for string "a", this cursor + // will point at the beginning of the page, but not at any particular key. The both entryOffsetInPage and + // offsetInEntry fields of the cursor are set to 0 in this case. Now if we add "a" to the + // trie. the page level will actually contains three entries. The first entry corresponds to string "a". + // That entry has 0 strlen value. If we creat a cursor for string "a" again, this cursor will + // point at the first entry on the page. But the entryOffsetInPage and offsetInEntry fields are still + // set to 0s. So we need an additional variable to make distinction between these two situations. + BOOL isOnPage; +} CompactMapCursor; +typedef struct _CompactMapCursor *MapCursorRef; + +enum { + _kCFBurstTrieCursorTrieType = 0, + _kCFBurstTrieCursorMapType +}; + +typedef struct _CFBurstTrieCursor { + CompactMapCursor mapCursor; + CFIndex cursorType; + CFBurstTrieRef trie; +} _CFBurstTrieCursor; + +// ** Legacy +typedef struct _DiskTrieLevel { + uint32_t slots[CHARACTER_SET_SIZE]; + uint32_t weight; + uint32_t payload; +} DiskTrieLevel; +typedef DiskTrieLevel *DiskTrieLevelRef; + +typedef struct _CompactDiskTrieLevel { + uint64_t bitmap[CHARACTER_SET_SIZE / 64]; // CHARACTER_SET_SIZE / 64bits per word + uint32_t weight; + uint32_t payload; + uint32_t slots[]; +} CompactDiskTrieLevel; +typedef CompactDiskTrieLevel *CompactDiskTrieLevelRef; + +typedef struct _StringPage { + uint32_t length; + char data[]; +} StringPage; + +typedef struct _StringPageEntryPacked { + uint8_t pfxLen; + uint16_t strlen; // make uint8_t if possible + uint32_t payload; + char string[]; +} StringPageEntryPacked; + +typedef struct _StringPageEntry { + uint16_t strlen; // make uint8_t if possible + uint32_t payload; + char string[]; +} StringPageEntry; + +typedef struct _fileHeader { + uint32_t signature; + uint32_t rootOffset; + uint32_t count; + uint32_t size; + uint32_t flags; +} fileHeader; +// ** +#pragma pack() + +struct _CFBurstTrie { + union { + TrieLevel root; + DiskTrieLevel diskRoot; + MapTrieLevel maproot; + }; + char *mapBase; + uint32_t mapSize; + uint32_t mapOffset; + uint32_t cflags; + uint32_t count; + uint32_t containerSize; + int retain; +#if DEPLOYMENT_TARGET_WINDOWS + HANDLE mapHandle; + HANDLE mappedFileHandle; +#endif +}; + +#if 0 +#pragma mark - +#pragma mark Forward declarations +#endif + +typedef struct _TraverseContext { + void *context; + void (*callback)(void*, const UInt8*, uint32_t, uint32_t); +} TraverseContext; + +bool foundKey(void *context, const uint8_t *key, uint32_t payload, bool exact) +{ + if (context != NULL) { + TraverseContext *ctx = (TraverseContext *)context; + if (ctx->context && ctx->callback) { + ctx->callback(ctx->context, key, 1, payload); + } + } + return false; +} + +void CFBurstTrieTraverseWithCursor(CFBurstTrieRef trie, const uint8_t *prefix, uint32_t prefixLen, void **cursor, void *ctx, bool (*callback)(void *, const uint8_t *, uint32_t, bool)); + +static CFBTInsertCode addCFBurstTrieLevel(CFBurstTrieRef trie, TrieLevelRef root, const uint8_t *key, uint32_t keylen, uint32_t weight, uint32_t payload); + +static void findCFBurstTrieLevel(CFBurstTrieRef trie, TrieCursor *cursor, bool exactmatch, void *ctx, bool (*callback)(void*, const uint8_t*, uint32_t, bool)); +static void findCFBurstTrieMappedLevel(CFBurstTrieRef trie, MapCursor *cursor, bool exactmatch, void *ctx, bool (*callback)(void*, const uint8_t*, uint32_t, bool)); +static void traverseCFBurstTrieLevel(CFBurstTrieRef trie, TrieLevelRef root, TrieCursor *cursor, bool exactmatch, void *ctx, bool (*callback)(void *, const uint8_t *, uint32_t, bool)); +static void traverseCFBurstTrieMappedLevel(CFBurstTrieRef trie, MapTrieLevelRef root, MapCursor *cursor, bool exactmatch, void *ctx, bool (*callback)(void *, const uint8_t *, uint32_t, bool)); +static void traverseCFBurstTrieCompactMappedLevel(CFBurstTrieRef trie, CompactMapTrieLevelRef root, MapCursor *cursor, bool exactmatch, void *ctx, bool (*callback)(void *, const uint8_t *, uint32_t, bool)); +static void traverseCFBurstTrieWithCursor(CFBurstTrieRef trie, const uint8_t *prefix, uint32_t prefixLen, void **cursor, bool exactmatch, void *ctx, bool (*callback)(void *, const uint8_t *, uint32_t, bool)); + +static size_t serializeCFBurstTrie(CFBurstTrieRef trie, size_t start_offset, int fd); + +static Boolean burstTrieMappedFind(DiskTrieLevelRef trie, char *map, const UInt8 *key, uint32_t length, uint32_t *payload, bool prefix); +static Boolean burstTrieMappedPageFind(StringPage *page, const UInt8 *key, uint32_t length, uint32_t *payload, bool prefix); +static Boolean burstTrieCompactTrieMappedFind(CompactDiskTrieLevelRef trie, char *map, const UInt8 *key, uint32_t length, uint32_t *payload, bool prefix); + +static void destroyCFBurstTrie(CFBurstTrieRef trie); +static void finalizeCFBurstTrie(TrieLevelRef trie); +static void finalizeCFBurstTrieList(ListNodeRef node); + +static int nodeWeightCompare(const void *a, const void *b); +static int nodeStringCompare(const void *a, const void *b); + +bool foundKey(void *context, const uint8_t *key, uint32_t payload, bool exact); +bool containsKey(void *context, const uint8_t *key, uint32_t payload, bool exact); + +static CFIndex burstTrieConvertCharactersToUTF8(UniChar *chars, CFIndex numChars, UInt8 *buffer); + +static Boolean advanceMapCursor(CFBurstTrieRef trie, CompactMapCursor *cursor, const UInt8* bytes, CFIndex length); +static Boolean getMapCursorPayload(CFBurstTrieRef trie, const CompactMapCursor *cursor, uint32_t *payload); +static void copyMapCursor(const CompactMapCursor *source, CompactMapCursor* destination); +static Boolean areMapCursorsEqual(const CompactMapCursor *lhs, const CompactMapCursor *rhs); +static void traverseFromMapCursor(CFBurstTrieRef trie, CompactMapCursor *cursor, UInt8* bytes, uint32_t capacity, uint32_t length, Boolean *stop, void *ctx, CFBurstTrieTraversalCallback callback); +static Boolean getMapCursorPayloadFromPackedPageEntry(PageEntryPacked *entry, const CompactMapCursor *cursor, uint32_t *payload); +static Boolean getMapCursorPayloadFromPageEntry(PageEntry *entry, const CompactMapCursor *cursor, uint32_t *payload); + +#if 0 +#pragma mark - +#pragma mark Core Foundation boilerplate +#endif + +static const void *_CFBurstTrieRetainCallback(CFAllocatorRef allocator, const void *value) { + CFBurstTrieRetain((CFBurstTrieRef)value); + return value; +} + +static void _CFBurstTrieReleaseCallback(CFAllocatorRef allocator, const void *value) { + CFBurstTrieRelease((CFBurstTrieRef)value); +} + +const CFDictionaryValueCallBacks kCFBurstTrieValueCallbacks = {0, _CFBurstTrieRetainCallback, _CFBurstTrieReleaseCallback, NULL, NULL}; + +#if 0 +#pragma mark - +#pragma mark Public Interface +#endif + +CFBurstTrieRef CFBurstTrieCreateWithOptions(CFDictionaryRef options) { + CFBurstTrieRef trie = NULL; + trie = (CFBurstTrieRef) calloc(1, sizeof(struct _CFBurstTrie)); + trie->containerSize = MAX_LIST_SIZE; + + CFNumberRef valueAsCFNumber; + if (CFDictionaryGetValueIfPresent(options, kCFBurstTrieCreationOptionNameContainerSize, (const void **)&valueAsCFNumber)) { + int value; + CFNumberGetValue(valueAsCFNumber, kCFNumberIntType, &value); + trie->containerSize = value > 2 && value < 4096 ? value : MAX_LIST_SIZE; + } + trie->retain = 1; + return trie; +} + +CFBurstTrieRef CFBurstTrieCreate() { + CFBurstTrieRef trie = NULL; + int listSize = MAX_LIST_SIZE; + CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &listSize); + CFMutableDictionaryRef options = CFDictionaryCreateMutable(kCFAllocatorDefault, 1, NULL, NULL); + CFDictionarySetValue(options, kCFBurstTrieCreationOptionNameContainerSize, value); + trie = CFBurstTrieCreateWithOptions(options); + CFRelease(value); + CFRelease(options); + return trie; +} + +CFBurstTrieRef CFBurstTrieCreateFromFile(CFStringRef path) { + struct statinfo sb; + char filename[PATH_MAX]; + int fd; + + /* Check valid path name */ + if (!CFStringGetCString(path, filename, PATH_MAX, kCFStringEncodingUTF8)) return NULL; + + /* Check if file exists */ + if (stat(filename, &sb) != 0) return NULL; + + /* Check if file can be opened */ + if ((fd=open(filename, CF_OPENFLGS|O_RDONLY)) < 0) return NULL; + +#if DEPLOYMENT_TARGET_WINDOWS + HANDLE mappedFileHandle = (HANDLE)_get_osfhandle(fd); + if (!mappedFileHandle) return NULL; + + HANDLE mapHandle = CreateFileMapping(mappedFileHandle, NULL, PAGE_READONLY, 0, 0, NULL); + if (!mapHandle) return NULL; + + char *map = (char *)MapViewOfFile(mapHandle, FILE_MAP_READ, 0, 0, sb.st_size); + if (!map) return NULL; +#else + char *map = mmap(0, sb.st_size, PROT_READ, MAP_FILE|MAP_SHARED, fd, 0); +#endif + + CFBurstTrieRef trie = NULL; + TrieHeader *header = (TrieHeader *)map; + + if (((uint32_t*)map)[0] == 0xbabeface) { + trie = (CFBurstTrieRef) calloc(1, sizeof(struct _CFBurstTrie)); + trie->mapBase = map; + trie->mapSize = CFSwapInt32LittleToHost(sb.st_size); + trie->mapOffset = CFSwapInt32LittleToHost(((fileHeader*)trie->mapBase)->rootOffset); + trie->cflags = CFSwapInt32LittleToHost(((fileHeader*)trie->mapBase)->flags); + trie->count = CFSwapInt32LittleToHost(((fileHeader*)trie->mapBase)->count); + trie->retain = 1; +#if DEPLOYMENT_TARGET_WINDOWS + trie->mappedFileHandle = mappedFileHandle; + trie->mapHandle = mapHandle; +#else + // On Windows, the file being mapped must stay open as long as the map exists. Don't close it early. Other platforms close it here. + close(fd); +#endif + } else if (header->signature == 0xcafebabe || header->signature == 0x0ddba11) { + trie = (CFBurstTrieRef) calloc(1, sizeof(struct _CFBurstTrie)); + trie->mapBase = map; + trie->mapSize = CFSwapInt32LittleToHost(sb.st_size); + trie->cflags = CFSwapInt32LittleToHost(header->flags); + trie->count = CFSwapInt32LittleToHost(header->count); + trie->retain = 1; +#if DEPLOYMENT_TARGET_WINDOWS + trie->mappedFileHandle = mappedFileHandle; + trie->mapHandle = mapHandle; +#else + // On Windows, the file being mapped must stay open as long as the map exists. Don't close it early. Other platforms close it here. + close(fd); +#endif + } + return trie; +} + +CFBurstTrieRef CFBurstTrieCreateFromMapBytes(char *mapBase) { + CFBurstTrieRef trie = NULL; + TrieHeader *header = (TrieHeader *)mapBase; + + if (mapBase && ((uint32_t*)mapBase)[0] == 0xbabeface) { + trie = (CFBurstTrieRef) malloc(sizeof(struct _CFBurstTrie)); + trie->mapBase = mapBase; + trie->mapSize = CFSwapInt32LittleToHost(((fileHeader*)trie->mapBase)->size); + trie->mapOffset = CFSwapInt32LittleToHost(((fileHeader*)trie->mapBase)->rootOffset); + trie->cflags = CFSwapInt32LittleToHost(((fileHeader*)trie->mapBase)->flags); + trie->count = CFSwapInt32LittleToHost(((fileHeader*)trie->mapBase)->count); + trie->retain = 1; + } else if (mapBase && (header->signature == 0xcafebabe || header->signature == 0x0ddba11)) { + trie = (CFBurstTrieRef) malloc(sizeof(struct _CFBurstTrie)); + trie->mapBase = mapBase; + trie->mapSize = CFSwapInt32LittleToHost(header->size); + trie->cflags = CFSwapInt32LittleToHost(header->flags); + trie->count = CFSwapInt32LittleToHost(header->count); + trie->retain = 1; + } + return trie; +} + +Boolean CFBurstTrieInsert(CFBurstTrieRef trie, CFStringRef term, CFRange termRange, CFIndex payload) { + return CFBurstTrieAddWithWeight(trie, term, termRange, 1, (uint32_t)payload); +} + +Boolean CFBurstTrieAdd(CFBurstTrieRef trie, CFStringRef term, CFRange termRange, uint32_t payload) { + return CFBurstTrieAddWithWeight(trie, term, termRange, 1, payload); +} + +Boolean CFBurstTrieInsertCharacters(CFBurstTrieRef trie, UniChar *chars, CFIndex numChars, CFIndex payload) { + return CFBurstTrieAddCharactersWithWeight(trie, chars, numChars, 1, (uint32_t)payload); +} + +Boolean CFBurstTrieAddCharacters(CFBurstTrieRef trie, UniChar *chars, CFIndex numChars, uint32_t payload) { + return CFBurstTrieAddCharactersWithWeight(trie, chars, numChars, 1, payload); +} + +Boolean CFBurstTrieInsertUTF8String(CFBurstTrieRef trie, UInt8 *chars, CFIndex numChars, CFIndex payload) { + return CFBurstTrieAddUTF8StringWithWeight(trie, chars, numChars, 1, (uint32_t)payload); +} + +Boolean CFBurstTrieAddUTF8String(CFBurstTrieRef trie, UInt8 *chars, CFIndex numChars, uint32_t payload) { + return CFBurstTrieAddUTF8StringWithWeight(trie, chars, numChars, 1, payload); +} + +Boolean CFBurstTrieInsertWithWeight(CFBurstTrieRef trie, CFStringRef term, CFRange termRange, CFIndex weight, CFIndex payload) { + return CFBurstTrieAddWithWeight(trie, term, termRange, weight, (uint32_t)payload); +} + +Boolean CFBurstTrieAddWithWeight(CFBurstTrieRef trie, CFStringRef term, CFRange termRange, uint32_t weight, uint32_t payload) { + Boolean success = false; + CFIndex size = MAX_STRING_ALLOCATION_SIZE; + CFIndex bytesize = termRange.length * 4; //** 4-byte max character size + if (!trie->mapBase && termRange.length < MAX_STRING_SIZE && payload > 0) { + CFIndex length; + UInt8 buffer[MAX_STRING_ALLOCATION_SIZE + 1]; + UInt8 *key = buffer; + if (bytesize >= size) { + size = bytesize; + key = (UInt8 *) malloc(sizeof(UInt8) * size + 1); + } + CFStringGetBytes(term, termRange, kCFStringEncodingUTF8, (UInt8)'-', (Boolean)0, key, size, &length); + key[length] = 0; + + success = CFBurstTrieAddUTF8StringWithWeight(trie, key, length, weight, payload); + if (buffer != key) free(key); + } + return success; +} + +Boolean CFBurstTrieInsertCharactersWithWeight(CFBurstTrieRef trie, UniChar *chars, CFIndex numChars, CFIndex weight, CFIndex payload) { + return CFBurstTrieAddCharactersWithWeight(trie, chars, numChars, weight, (uint32_t)payload); +} + +Boolean CFBurstTrieAddCharactersWithWeight(CFBurstTrieRef trie, UniChar *chars, CFIndex numChars, uint32_t weight, uint32_t payload) { + Boolean success = false; + CFIndex size = MAX_STRING_ALLOCATION_SIZE; + CFIndex bytesize = numChars * 4; //** 4-byte max character size + if (!trie->mapBase && numChars < MAX_STRING_SIZE && payload > 0) { + CFIndex length; + UInt8 buffer[MAX_STRING_ALLOCATION_SIZE + 1]; + UInt8 *key = buffer; + if (bytesize >= size) { + size = bytesize; + key = (UInt8 *) malloc(sizeof(UInt8) * size + 1); + } + length = burstTrieConvertCharactersToUTF8(chars, numChars, key); + key[length] = 0; + + success = CFBurstTrieAddUTF8StringWithWeight(trie, key, length, weight, payload); + if (buffer != key) free(key); + } + return success; +} + +Boolean CFBurstTrieInsertUTF8StringWithWeight(CFBurstTrieRef trie, UInt8 *chars, CFIndex numChars, CFIndex weight, CFIndex payload) { + return CFBurstTrieAddUTF8StringWithWeight(trie, chars, numChars, weight, (uint32_t)payload); +} + +Boolean CFBurstTrieAddUTF8StringWithWeight(CFBurstTrieRef trie, UInt8 *chars, CFIndex numChars, uint32_t weight, uint32_t payload) { + CFBTInsertCode code = FailedInsert; + + if (!trie->mapBase && numChars < MAX_STRING_SIZE*4 && payload > 0) { + code = addCFBurstTrieLevel(trie, &trie->root, chars, numChars, weight, payload); + if (code == NewTerm) trie->count++; + } + return code > FailedInsert; +} + +Boolean CFBurstTrieFind(CFBurstTrieRef trie, CFStringRef term, CFRange termRange, CFIndex *payload) { + uint32_t p; + if (CFBurstTrieContains(trie, term, termRange, &p)) { + SetPayload(payload, p); + return true; + } + return false; +} + +Boolean CFBurstTrieContains(CFBurstTrieRef trie, CFStringRef term, CFRange termRange, uint32_t *payload) { + Boolean success = false; + CFIndex size = MAX_STRING_ALLOCATION_SIZE; + CFIndex bytesize = termRange.length * 4; //** 4-byte max character size + if (termRange.length < MAX_STRING_SIZE) { + CFIndex length; + UInt8 buffer[MAX_STRING_ALLOCATION_SIZE+1]; + UInt8 *key = buffer; + if (bytesize >= size) { + size = bytesize; + key = (UInt8 *) malloc(sizeof(UInt8) * size + 1); + } + CFStringGetBytes(term, termRange, kCFStringEncodingUTF8, (UInt8)'-', (Boolean)0, key, size, &length); + key[length] = 0; + + success = CFBurstTrieContainsUTF8String(trie, key, length, payload); + if (buffer != key) free(key); + } + return success; +} + +Boolean CFBurstTrieFindCharacters(CFBurstTrieRef trie, UniChar *chars, CFIndex numChars, CFIndex *payload) { + uint32_t p; + if (CFBurstTrieContainsCharacters(trie, chars, numChars, &p)) { + SetPayload(payload, p); + return true; + } + return false; +} + +Boolean CFBurstTrieContainsCharacters(CFBurstTrieRef trie, UniChar *chars, CFIndex numChars, uint32_t *payload) { + Boolean success = false; + CFIndex size = MAX_STRING_ALLOCATION_SIZE; + CFIndex bytesize = numChars * 4; //** 4-byte max character size + if (numChars < MAX_STRING_SIZE) { + CFIndex length; + UInt8 buffer[MAX_STRING_ALLOCATION_SIZE + 1]; + UInt8 *key = buffer; + if (bytesize >= size) { + size = bytesize; + key = (UInt8 *) malloc(sizeof(UInt8) * size + 1); + } + length = burstTrieConvertCharactersToUTF8(chars, numChars, key); + key[length] = 0; + + success = CFBurstTrieContainsUTF8String(trie, key, length, payload); + if (buffer != key) free(key); + } + return success; +} + +Boolean CFBurstTrieFindUTF8String(CFBurstTrieRef trie, UInt8 *key, CFIndex length, CFIndex *payload) { + uint32_t p; + if (CFBurstTrieContainsUTF8String(trie, key, length, &p)) { + SetPayload(payload, p); + return true; + } + return false; +} + +Boolean CFBurstTrieContainsUTF8String(CFBurstTrieRef trie, UInt8 *key, CFIndex length, uint32_t *payload) { + Boolean success = false; + if (length < MAX_STRING_SIZE) { + if (trie->mapBase && ((fileHeader *)trie->mapBase)->signature == 0xbabeface) { + bool prefix = (trie->cflags & kCFBurstTriePrefixCompression); + success = burstTrieMappedFind((DiskTrieLevelRef)(trie->mapBase+CFSwapInt32LittleToHost((((uint32_t*)trie->mapBase)[1]))), trie->mapBase, key, length, payload, prefix); + } else if (trie->mapBase && trie->cflags & (kCFBurstTriePrefixCompression | kCFBurstTrieSortByKey)) { + _CFBurstTrieCursor cursor; + if (!CFBurstTrieSetCursorForBytes(trie, &cursor, key, length)) + return FALSE; + return CFBurstTrieCursorGetPayload(&cursor, payload); + } else { + uint32_t found = 0; + void *cursor = 0; + traverseCFBurstTrieWithCursor(trie, key, length, &cursor, true, &found, containsKey); + if (found) SetPayload(payload, found); + success = found > 0; + } + } + return success; +} + +Boolean CFBurstTrieSerialize(CFBurstTrieRef trie, CFStringRef path, CFBurstTrieOpts opts) { + Boolean success = false; + if (trie->mapBase) { + return success; + } else { + int fd; + char filename[PATH_MAX]; + + /* Check valid path name */ + if (!CFStringGetCString(path, filename, PATH_MAX, kCFStringEncodingUTF8)) return success; + + /* Check if file can be opened */ + if ((fd=open(filename, CF_OPENFLGS|O_RDWR|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR)) < 0) return success; + + if (CFBurstTrieSerializeWithFileDescriptor(trie, fd, opts)) success = true; + + close(fd); + } + return success; +} + +Boolean CFBurstTrieSerializeWithFileDescriptor(CFBurstTrieRef trie, int fd, CFBurstTrieOpts opts) { + Boolean success = false; + if (!trie->mapBase && fd >= 0) { + off_t start_offset = lseek(fd, 0, SEEK_END); + + trie->cflags = opts; + trie->mapSize = serializeCFBurstTrie(trie, start_offset, fd); + +#if DEPLOYMENT_TARGET_WINDOWS + HANDLE mappedFileHandle = (HANDLE)_get_osfhandle(fd); + // We need to make sure we have our own handle to keep this file open as long as the mmap lasts + DuplicateHandle(GetCurrentProcess(), mappedFileHandle, GetCurrentProcess(), &mappedFileHandle, 0, 0, DUPLICATE_SAME_ACCESS); + HANDLE mapHandle = CreateFileMapping(mappedFileHandle, NULL, PAGE_READONLY, 0, 0, NULL); + if (!mapHandle) return NULL; + char *map = (char *)MapViewOfFile(mapHandle, FILE_MAP_READ, 0, start_offset, trie->mapSize); + if (!map) return NULL; + trie->mapBase = map; + trie->mapHandle = mapHandle; + trie->mappedFileHandle = mappedFileHandle; +#else + trie->mapBase = mmap(0, trie->mapSize, PROT_READ, MAP_FILE|MAP_SHARED, fd, start_offset); +#endif + success = true; + } + + return success; +} + +void CFBurstTrieTraverse(CFBurstTrieRef trie, void *ctx, void (*callback)(void*, const UInt8*, uint32_t, uint32_t)) { + TrieHeader *header = (TrieHeader *)trie->mapBase; + if (!trie->mapBase || (header->signature == 0xcafebabe || header->signature == 0x0ddba11)) { + void *cursor = 0; + TraverseContext context; + context.context = ctx; + context.callback = callback; + traverseCFBurstTrieWithCursor(trie, (const uint8_t *)"", 0, &cursor, false, &context, foundKey); + } +} + + +void CFBurstTrieTraverseWithCursor(CFBurstTrieRef trie, const uint8_t *prefix, uint32_t prefixLen, void **cursor, void *ctx, bool (*callback)(void *, const uint8_t *, uint32_t, bool)) +{ + traverseCFBurstTrieWithCursor(trie, prefix, prefixLen, cursor, false, ctx, callback); +} + +void CFBurstTriePrint(CFBurstTrieRef trie) { + +} + +CFIndex CFBurstTrieGetCount(CFBurstTrieRef trie) { + return trie->count; +} + +CFBurstTrieRef CFBurstTrieRetain(CFBurstTrieRef trie) { + trie->retain++; + return trie; +} + +void CFBurstTrieRelease(CFBurstTrieRef trie) { + trie->retain--; + if (trie->retain == 0) destroyCFBurstTrie(trie); + return; +} + +Boolean CFBurstTrieSetCursorForBytes(CFBurstTrieRef trie, CFBurstTrieCursorRef cursor, const UInt8* bytes, CFIndex length) +{ + if (!trie->mapBase || !(trie->cflags & (kCFBurstTriePrefixCompression | kCFBurstTrieSortByKey))) { + //fprintf(stderr, "CFBurstTrieCreateCursorForBytes() only support file based trie in prefix compression format.\n"); + return FALSE; + } + + TrieHeader *header = (TrieHeader*)trie->mapBase; + if (length < 0 || !trie) + return FALSE; + + cursor->trie = trie; + if (trie->mapBase) { + cursor->cursorType = _kCFBurstTrieCursorMapType; + cursor->mapCursor.next = header->rootOffset; + cursor->mapCursor.isOnPage = FALSE; + cursor->mapCursor.entryOffsetInPage = 0; + cursor->mapCursor.offsetInEntry = 0; + cursor->mapCursor.payload = 0; + } else + assert(false); + + if (!bytes || length == 0) + return TRUE; + + return CFBurstTrieCursorAdvanceForBytes(cursor, bytes, length); +} + + +CFBurstTrieCursorRef CFBurstTrieCreateCursorForBytes(CFBurstTrieRef trie, const UInt8* bytes, CFIndex length) +{ + CFBurstTrieCursorRef cursor = (CFBurstTrieCursorRef)calloc(sizeof(_CFBurstTrieCursor), 1); + if (!CFBurstTrieSetCursorForBytes(trie, cursor, bytes, length)) { + CFBurstTrieCursorRelease(cursor); + return NULL; + } + return cursor; +} + +CFBurstTrieCursorRef CFBurstTrieCursorCreateByCopy(CFBurstTrieCursorRef cursor) +{ + if (!cursor) + return NULL; + + CFBurstTrieCursorRef newCursor = (CFBurstTrieCursorRef)calloc(sizeof(_CFBurstTrieCursor), 1); + switch (cursor->cursorType) { + case _kCFBurstTrieCursorMapType: + copyMapCursor(&cursor->mapCursor, &newCursor->mapCursor); + break; + case _kCFBurstTrieCursorTrieType: + assert(false); + break; + } + newCursor->cursorType = cursor->cursorType; + newCursor->trie = cursor->trie; + return newCursor; +} + +Boolean CFBurstTrieCursorIsEqual(CFBurstTrieCursorRef lhs, CFBurstTrieCursorRef rhs) +{ + if (lhs->trie != rhs->trie || lhs->cursorType != rhs->cursorType) + return FALSE; + + if (lhs->cursorType == _kCFBurstTrieCursorMapType) + return areMapCursorsEqual(&lhs->mapCursor, &rhs->mapCursor); + else + return FALSE; +} + +Boolean CFBurstTrieCursorAdvanceForBytes(CFBurstTrieCursorRef cursor, const UInt8* bytes, CFIndex length) +{ + switch (cursor->cursorType) { + case _kCFBurstTrieCursorMapType: { + CompactMapCursor tempCursor; + copyMapCursor(&cursor->mapCursor, &tempCursor); + if (advanceMapCursor(cursor->trie, (CompactMapCursor*)&cursor->mapCursor, bytes, length)) + return TRUE; + else { + copyMapCursor(&tempCursor, &cursor->mapCursor); + return FALSE; + } + } + case _kCFBurstTrieCursorTrieType: + return FALSE; + } + return FALSE; +} + +Boolean CFBurstTrieCursorGetPayload(CFBurstTrieCursorRef cursor, uint32_t *payload) +{ + switch (cursor->cursorType) { + case _kCFBurstTrieCursorMapType: + return getMapCursorPayload(cursor->trie, (CompactMapCursor*)&cursor->mapCursor, payload); + case _kCFBurstTrieCursorTrieType: + return FALSE; + } + return FALSE; +} + +void CFBurstTrieCursorRelease(CFBurstTrieCursorRef cursor) +{ + if (!cursor) + return; + free(cursor); +} + +void CFBurstTrieTraverseFromCursor(CFBurstTrieCursorRef cursor, void *ctx, CFBurstTrieTraversalCallback callback) +{ + if (!cursor) + return; + + UInt8 *bytes = (UInt8*)calloc(1, MAX_KEY_LENGTH); + uint32_t capacity = MAX_KEY_LENGTH; + uint32_t length = 0; + Boolean stop = FALSE; + switch (cursor->cursorType) { + case _kCFBurstTrieCursorMapType: { + CompactMapCursor tempCursor; + copyMapCursor(&cursor->mapCursor, &tempCursor); + traverseFromMapCursor(cursor->trie, &tempCursor, bytes, capacity,length, &stop, ctx, callback); + break; + } + case _kCFBurstTrieCursorTrieType: + break; + } + free(bytes); +} + +#if 0 +#pragma mark - +#pragma mark Insertion +#endif + +static ListNodeRef makeCFBurstTrieListNode(const uint8_t *key, uint32_t keylen, uint32_t weight, uint32_t payload) { + ListNodeRef node = (ListNodeRef) calloc(1, sizeof(*node) + keylen + 1); + memcpy(node->string, key, keylen); + node->string[keylen] = 0; + node->next = 0; + node->length = keylen; + node->weight = weight; + node->payload = payload; + return node; +} + +static void addCFBurstTrieBurstLevel(CFBurstTrieRef trie, TrieLevelRef root, const uint8_t *key, uint32_t keylen, uint32_t weight, uint32_t payload) { + if (keylen) { + NextTrie next = root->slots[*key]; + ListNodeRef newNode = makeCFBurstTrieListNode(key+1, keylen-1, weight, payload); + newNode->weight = weight; + newNode->next = (ListNodeRef) NextTrie_GetPtr(next); + next = (uintptr_t) newNode; + NextTrie_SetKind(next, ListKind); + root->slots[*key] = next; + } else { + // ** Handle payload. + root->weight = weight; + root->payload = payload; + } +} + +static TrieLevelRef burstCFBurstTrieLevel(CFBurstTrieRef trie, ListNodeRef list, uint32_t listCount) { + TrieLevelRef newLevel = (TrieLevelRef) calloc(1, sizeof(struct _TrieLevel)); + while (list) { + addCFBurstTrieBurstLevel(trie, newLevel, list->string, list->length, list->weight, list->payload); + ListNodeRef temp = list; + list = list->next; + free(temp); + } + return newLevel; +} + +static CFBTInsertCode addCFBurstTrieListNode(CFBurstTrieRef trie, ListNodeRef list, const uint8_t *key, uint32_t keylen, uint32_t weight, uint32_t payload, uint32_t *listCount) +{ + CFBTInsertCode code = FailedInsert; + uint32_t count = 1; + + ListNodeRef last = list; + while (list) { + if (list->length == keylen && memcmp(key, list->string, keylen) == 0) { + list->weight += weight; + list->payload = payload; + code = ExistingTerm; + break; + } else { + count++; + last = list; + list = list->next; + } + } + + if (!list) { + last->next = makeCFBurstTrieListNode(key, keylen, weight, payload); + code = NewTerm; + } + + *listCount = count; + return code; +} + +static CFBTInsertCode addCFBurstTrieLevel(CFBurstTrieRef trie, TrieLevelRef root, const uint8_t *key, uint32_t keylen, uint32_t weight, uint32_t payload) +{ + CFBTInsertCode code = FailedInsert; + if (keylen) { + NextTrie next = root->slots[*key]; + if (NextTrie_GetKind(next) == TrieKind) { + TrieLevelRef nextLevel = (TrieLevelRef) NextTrie_GetPtr(next); + code = addCFBurstTrieLevel(trie, nextLevel, key+1, keylen-1, weight, payload); + } else { + if (NextTrie_GetKind(next) == ListKind) { + uint32_t listCount; + ListNodeRef listNode = (ListNodeRef) NextTrie_GetPtr(next); + code = addCFBurstTrieListNode(trie, listNode, key+1, keylen-1, weight, payload, &listCount); + if (listCount > trie->containerSize) { + next = (uintptr_t) burstCFBurstTrieLevel(trie, listNode, listCount); + NextTrie_SetKind(next, TrieKind); + } + } else { + // ** Make a new list node + next = (uintptr_t) makeCFBurstTrieListNode(key+1, keylen-1, weight, payload); + NextTrie_SetKind(next, ListKind); + code = NewTerm; + } + root->slots[*key] = next; + } + } else { + // ** Handle payload + if (!root->weight) code = NewTerm; + else code = ExistingTerm; + root->weight += weight; + root->payload = payload; + } + + return code; +} +#if 0 +#pragma mark - +#pragma mark Searching +#endif +static void findCFBurstTrieList(CFBurstTrieRef trie, TrieCursor *cursor, void *ctx, bool (*callback)(void*, const uint8_t*, uint32_t, bool)) +{ + ListNodeRef list = (ListNodeRef)NextTrie_GetPtr(cursor->next); + int len = cursor->prefixlen-cursor->keylen; + len = len <= 0 ? 0 : len; + while (list) { + int lencompare = list->length-len; + if (list->length >= len && + (len == 0 || memcmp(list->string, cursor->prefix+cursor->keylen, len) == 0)) { + memcpy(cursor->key+cursor->keylen, list->string, list->length); + cursor->key[cursor->keylen+list->length] = 0; + cursor->next = (NextTrie)list; + if (list->payload && callback(ctx, cursor->key, list->payload, lencompare==0)) return; + } + list = list->next; + } +} + +static void findCFBurstTrieMappedPage(CFBurstTrieRef trie, MapCursor *cursor, void *ctx, bool (*callback)(void*, const uint8_t*, uint32_t, bool)) +{ + Page *page = (Page *)DiskNextTrie_GetPtr(trie->mapBase, cursor->next); + uint32_t end = page->length; + uint32_t cur = 0; + int len = cursor->prefixlen-cursor->keylen; + len = len <= 0 ? 0 : len; + if (trie->cflags & kCFBurstTriePrefixCompression) { + uint8_t pfx[CHARACTER_SET_SIZE]; + PageEntryPacked *lastEntry = 0; + while (cur < end) { + PageEntryPacked *entry = (PageEntryPacked *)&page->data[cur]; + int lencompare = (entry->strlen+entry->pfxLen)-len; + if (lastEntry && entry->pfxLen>lastEntry->pfxLen) memcpy(pfx+lastEntry->pfxLen, lastEntry->string, entry->pfxLen-lastEntry->pfxLen); + if (lencompare >= 0 && + (len == 0 || (__builtin_memcmp(pfx, cursor->prefix+cursor->keylen, entry->pfxLen) == 0 && + __builtin_memcmp(entry->string, cursor->prefix+cursor->keylen+entry->pfxLen, cursor->prefixlen-cursor->keylen-entry->pfxLen) == 0))) { + memcpy(cursor->key+cursor->keylen, pfx, entry->pfxLen); + memcpy(cursor->key+cursor->keylen+entry->pfxLen, entry->string, entry->strlen); + cursor->key[cursor->keylen+entry->pfxLen+entry->strlen] = 0; + if (entry->payload && callback(ctx, (const uint8_t *)cursor->key, entry->payload, lencompare==0)) return; + } + lastEntry = entry; + cur += sizeof(*entry) + entry->strlen; + } + } else { + while (cur < end) { + PageEntry *entry = (PageEntry *)&page->data[cur]; + int lencompare = entry->strlen-len; + if (lencompare >= 0 && __builtin_memcmp(entry->string, cursor->prefix+cursor->keylen, len) == 0) { + memcpy(cursor->key+cursor->keylen, entry->string, entry->strlen); + cursor->key[cursor->keylen+entry->strlen] = 0; + if (entry->payload && callback(ctx, (const uint8_t *)cursor->key, entry->payload, lencompare==0)) return; + } + cur += sizeof(*entry) + entry->strlen; + } + } +} + + +static void findCFBurstTrieLevel(CFBurstTrieRef trie, TrieCursor *cursor, bool exactmatch, void *ctx, bool (*callback)(void*, const uint8_t*, uint32_t, bool)) +{ + if (cursor->keylen < cursor->prefixlen) { + cursor->next = ((TrieLevelRef)NextTrie_GetPtr(cursor->next))->slots[cursor->prefix[cursor->keylen]]; + cursor->key[cursor->keylen++] = cursor->prefix[cursor->keylen]; + + if (NextTrie_GetKind(cursor->next) == TrieKind) { + findCFBurstTrieLevel(trie, cursor, exactmatch, ctx, callback); + } else if (NextTrie_GetKind(cursor->next) == ListKind) { + findCFBurstTrieList(trie, cursor, ctx, callback); + } + } else { + TrieLevelRef root = (TrieLevelRef)NextTrie_GetPtr(cursor->next); + if (root->payload && callback(ctx, cursor->key, root->payload, cursor->prefixlen==cursor->keylen)) return; + if (cursor->keylen == cursor->prefixlen && exactmatch) return; + traverseCFBurstTrieLevel(trie, root, cursor, exactmatch, ctx, callback); + } +} + +static void findCFBurstTrieCompactMappedLevel(CFBurstTrieRef trie, MapCursor *cursor, bool exactmatch, void *ctx, bool (*callback)(void*, const uint8_t*, uint32_t, bool)) +{ + CompactMapTrieLevelRef root = (CompactMapTrieLevelRef)DiskNextTrie_GetPtr(trie->mapBase, cursor->next); + if (cursor->keylen < cursor->prefixlen) { + uint8_t mykey = *(cursor->prefix+cursor->keylen); + cursor->key[cursor->keylen++] = *(cursor->prefix+cursor->keylen); + + uint8_t slot = mykey / 64; + uint8_t bit = mykey % 64; + uint32_t item = 0; + uint64_t bword = root->bitmap[slot]; + + if (bword & (1ull << bit)) { + // ** Count all the set bits up to this bit + for (int i=0; i < slot; i++) item += __builtin_popcountll(root->bitmap[i]); + item += __builtin_popcountll(bword & ((1ull << bit)-1)); + uint32_t offset = root->slots[item]; + cursor->next = offset; + + if (DiskNextTrie_GetKind(offset) == TrieKind) { + findCFBurstTrieMappedLevel(trie, cursor, exactmatch, ctx, callback); + } else if (DiskNextTrie_GetKind(offset) == CompactTrieKind) { + findCFBurstTrieCompactMappedLevel(trie, cursor, exactmatch, ctx, callback); + } else if (DiskNextTrie_GetKind(offset) == ListKind) { + findCFBurstTrieMappedPage(trie, cursor, ctx, callback); + } + } + } else { + if(root->payload && callback(ctx, cursor->key, root->payload, cursor->prefixlen==cursor->keylen)) return; + if (cursor->keylen == cursor->prefixlen && exactmatch) return; + traverseCFBurstTrieCompactMappedLevel(trie, root, cursor, exactmatch, ctx, callback); + } +} + +static void findCFBurstTrieMappedLevel(CFBurstTrieRef trie, MapCursor *cursor, bool exactmatch, void *ctx, bool (*callback)(void*, const uint8_t*, uint32_t, bool)) +{ + MapTrieLevelRef root = (MapTrieLevelRef)DiskNextTrie_GetPtr(trie->mapBase, cursor->next); + if (cursor->keylen < cursor->prefixlen) { + uint8_t slot = *(cursor->prefix+cursor->keylen); + cursor->next = root->slots[slot]; + cursor->key[cursor->keylen++] = slot; + + if (DiskNextTrie_GetKind(cursor->next) == TrieKind) { + findCFBurstTrieMappedLevel(trie, cursor, exactmatch, ctx, callback); + } else if (DiskNextTrie_GetKind(cursor->next) == CompactTrieKind) { + findCFBurstTrieCompactMappedLevel(trie, cursor, exactmatch, ctx, callback); + } else if (DiskNextTrie_GetKind(cursor->next) == ListKind) { + findCFBurstTrieMappedPage(trie, cursor, ctx, callback); + } + } else { + if (root->payload && callback(ctx, cursor->key, root->payload, cursor->prefixlen==cursor->keylen)) return; + if (cursor->keylen == cursor->prefixlen && exactmatch) return; + traverseCFBurstTrieMappedLevel(trie, root, cursor, exactmatch, ctx, callback); + } +} + +static void traverseCFBurstTrieLevel(CFBurstTrieRef trie, TrieLevelRef root, TrieCursor *cursor, bool exactmatch, void *ctx, bool (*callback)(void *, const uint8_t *, uint32_t, bool)) +{ + cursor->key[cursor->keylen] = 0; + uint32_t len = cursor->keylen; + for (int i=0; i < CHARACTER_SET_SIZE; i++) { + NextTrie next = root->slots[i]; + cursor->keylen = len; + cursor->key[cursor->keylen++] = i; + + if (NextTrie_GetKind(next) == TrieKind) { + TrieLevelRef level = (TrieLevelRef)NextTrie_GetPtr(next); + if (level->payload && callback(ctx, cursor->key, level->payload, cursor->prefixlen==cursor->keylen)) return; + if (cursor->keylen == cursor->prefixlen && exactmatch) return; + traverseCFBurstTrieLevel(trie, level, cursor, exactmatch, ctx, callback); + } else if (NextTrie_GetKind(next) == ListKind) { + cursor->next = next; + cursor->key[cursor->keylen] = 0; + findCFBurstTrieList(trie, cursor, ctx, callback); + } + } +} + +static void traverseCFBurstTrieMappedLevel(CFBurstTrieRef trie, MapTrieLevelRef root, MapCursor *cursor, bool exactmatch, void *ctx, bool (*callback)(void *, const uint8_t *, uint32_t, bool)) +{ + cursor->key[cursor->keylen] = 0; + uint32_t len = cursor->keylen; + + for (int i=0; i < CHARACTER_SET_SIZE; i++) { + uint32_t offset = (uint32_t)root->slots[i]; + cursor->keylen = len; + cursor->key[cursor->keylen++] = i; + + if (DiskNextTrie_GetKind(offset) == TrieKind) { + MapTrieLevelRef level = (MapTrieLevelRef)DiskNextTrie_GetPtr(trie->mapBase, offset); + if (level->payload && callback(ctx, cursor->key, level->payload, cursor->prefixlen==cursor->keylen)) return; + if (cursor->keylen == cursor->prefixlen && exactmatch) return; + traverseCFBurstTrieMappedLevel(trie, level, cursor, exactmatch, ctx, callback); + } else if (DiskNextTrie_GetKind(offset) == CompactTrieKind) { + CompactMapTrieLevelRef level = (CompactMapTrieLevelRef)DiskNextTrie_GetPtr(trie->mapBase, offset); + if (level->payload && callback(ctx, cursor->key, level->payload, cursor->prefixlen==cursor->keylen)) return; + if (cursor->keylen == cursor->prefixlen && exactmatch) return; + traverseCFBurstTrieCompactMappedLevel(trie, level, cursor, exactmatch, ctx, callback); + } else if (DiskNextTrie_GetKind(offset) == ListKind) { + cursor->next = offset; + cursor->key[cursor->keylen] = 0; + findCFBurstTrieMappedPage(trie, cursor, ctx, callback); + } + } +} + +static void traverseCFBurstTrieCompactMappedLevel(CFBurstTrieRef trie, CompactMapTrieLevelRef root, MapCursor *cursor, bool exactmatch, void *ctx, bool (*callback)(void *, const uint8_t *, uint32_t, bool)) +{ + cursor->key[cursor->keylen] = 0; + uint32_t len = cursor->keylen; + for (uint32_t c=0; c < CHARACTER_SET_SIZE; c++) { + //** This could be optimized to remember what the last slot/item was and not count bits over and over. + uint8_t mykey = c; + uint32_t slot = mykey / 64; + uint32_t bit = mykey % 64; + uint32_t item = 0; + uint64_t bword = root->bitmap[slot]; + cursor->keylen = len; + + if (bword & (1ull << bit)) { + // ** Count all the set bits up to this bit + for (int i=0; i < slot; i++) item += __builtin_popcountll(root->bitmap[i]); + item += __builtin_popcountll(bword & ((1ull << bit)-1)); + uint32_t offset = root->slots[item]; + cursor->key[cursor->keylen++] = mykey; + + if(DiskNextTrie_GetKind(offset) == CompactTrieKind) { + CompactMapTrieLevelRef level = (CompactMapTrieLevelRef)DiskNextTrie_GetPtr(trie->mapBase, offset); + if (level->payload && callback(ctx, cursor->key, level->payload, cursor->prefixlen==cursor->keylen)) return; + if (cursor->keylen == cursor->prefixlen && exactmatch) return; + traverseCFBurstTrieCompactMappedLevel(trie, level, cursor, exactmatch, ctx, callback); + } else if(DiskNextTrie_GetKind(offset) == TrieKind) { + traverseCFBurstTrieMappedLevel(trie, (MapTrieLevelRef)DiskNextTrie_GetPtr(trie->mapBase, offset), cursor, exactmatch, ctx, callback); + } else if (DiskNextTrie_GetKind(offset) == ListKind) { + cursor->next = offset; + cursor->key[cursor->keylen] = 0; + findCFBurstTrieMappedPage(trie, cursor, ctx, callback); + } + } + } +} + +static void traverseCFBurstTrieWithCursor(CFBurstTrieRef trie, const uint8_t *prefix, uint32_t prefixLen, void **cursor, bool exactmatch, void *ctx, bool (*callback)(void *, const uint8_t *, uint32_t, bool)) { + if (trie->mapBase) { + if (trie->cflags & kCFBurstTriePrefixCompression) { + fprintf(stderr, "Please use CFBurstTrieCursorRef API for file based trie.\n"); + return; + } else { + TrieHeader *header = (TrieHeader *)trie->mapBase; + MapCursor csr; + csr.next = header->rootOffset; + csr.prefix = prefix; + csr.prefixlen = prefixLen; + csr.key[0] = 0; + csr.keylen = 0; + findCFBurstTrieMappedLevel(trie, &csr, exactmatch, ctx, callback); + } + } else { + TrieCursor csr; + csr.next = ((unsigned long)&trie->root)|TrieKind; + csr.prefix = prefix; + csr.prefixlen = prefixLen; + csr.key[0] = 0; + csr.keylen = 0; + findCFBurstTrieLevel(trie, &csr, exactmatch, ctx, callback); + } +} + +CF_INLINE uint32_t getPackedPageEntrySize(PageEntryPacked *entry) +{ + return sizeof(PageEntryPacked) + entry->strlen; +} + +CF_INLINE uint32_t getPageEntrySize(PageEntry *entry) +{ + return sizeof(PageEntry) + entry->strlen; +} + +/* +static void _printPageEntry(PageEntryPacked *entry) { + printf("entry 0x%p:\n", entry); + printf("pfxLen = %d, strLen = %d\n", entry->pfxLen, entry->strlen); + if (entry->strlen > 0) { + printf("string = "); + for (int i = 0; i < entry->strlen; ++i) + printf("%d ", entry->string[i]); + printf("\n"); + } + printf("\n"); +} +*/ +static Boolean advanceCursorOnMappedPageForByte(Page *page, CompactMapCursor *cursor, UInt8 byte) { + PageEntryPacked *entry; + Boolean found = FALSE; + uint32_t minPrefixLength = 0; + + if (cursor->isOnPage) { + entry = (PageEntryPacked *)&page->data[cursor->entryOffsetInPage]; + //_printPageEntry(entry); + BOOL shouldContinue = TRUE; + + if (!(cursor->entryOffsetInPage == 0 && entry->strlen == 0)) { + if (cursor->entryOffsetInPage == entry->strlen - 1) { + minPrefixLength = entry->pfxLen + entry->strlen; + cursor->entryOffsetInPage += getPackedPageEntrySize(entry); + } else { + cursor->offsetInEntry++; + if (entry->string[cursor->offsetInEntry] == byte) + found = TRUE; + else if (entry->string[cursor->offsetInEntry] > byte) + shouldContinue = FALSE; + else { + minPrefixLength = entry->pfxLen + cursor->offsetInEntry; + cursor->entryOffsetInPage += getPackedPageEntrySize(entry); + } + } + } + + if (found) { + cursor->isOnPage = TRUE; + return TRUE; + } else if (!shouldContinue) + return FALSE; + } else { + cursor->entryOffsetInPage = 0; + } + + uint32_t pageSize = page->length - sizeof(Page); + while (cursor->entryOffsetInPage < pageSize) { + entry = (PageEntryPacked *)&page->data[cursor->entryOffsetInPage]; + //_printPageEntry(entry); + if (minPrefixLength > entry->pfxLen) + break; + else if (minPrefixLength < entry->pfxLen) + cursor->entryOffsetInPage += getPackedPageEntrySize(entry); + else { + if (entry->strlen == 0) + cursor->entryOffsetInPage += getPackedPageEntrySize(entry); + else { + if (entry->string[0] > byte) + // Entries are sorted alphabetically + break; + else if (entry->string[0] < byte) + cursor->entryOffsetInPage += getPackedPageEntrySize(entry); + else { + cursor->offsetInEntry = 0; + found = TRUE; + break; + } + } + } + } + + if (found) + cursor->isOnPage = TRUE; + + return found; +} + +static Boolean advanceCursorMappedPageWithPerfixCompression(Page *page, CompactMapCursor *cursor, const UInt8* bytes, CFIndex length) +{ + if (length == 0) { + PageEntryPacked *entry = (PageEntryPacked*)&page->data[0]; + if (!cursor->isOnPage) { + cursor->entryOffsetInPage = 0; + cursor->offsetInEntry = 0; + cursor->isOnPage = entry->pfxLen == 0 && entry->strlen == 0; + } + getMapCursorPayloadFromPackedPageEntry(entry, cursor, &cursor->payload); + return TRUE; + } + + for (CFIndex i = 0; i < length; ++i) { + if (!advanceCursorOnMappedPageForByte(page, cursor, bytes[i])) + return FALSE; + } + PageEntryPacked *entry = (PageEntryPacked*)&page->data[cursor->entryOffsetInPage]; + getMapCursorPayloadFromPackedPageEntry(entry, cursor, &cursor->payload); + return TRUE; +} + +static Boolean advanceCursorMappedPageSortedByKey(Page *page, CompactMapCursor *cursor, const UInt8* bytes, CFIndex length) +{ + if (length == 0) { + PageEntry*entry = (PageEntry*)&page->data[0]; + if (!cursor->isOnPage) { + cursor->entryOffsetInPage = 0; + cursor->offsetInEntry = 0; + cursor->isOnPage = entry->strlen == 0; + } + getMapCursorPayloadFromPageEntry(entry, cursor, &cursor->payload); + return TRUE; + } + + PageEntry *entry; + uint32_t pageSize = page->length - sizeof(Page); + const UInt8 * prefix = NULL; + uint32_t prefixLength = 0; + + if (cursor->isOnPage) { + entry = (PageEntry*)&page->data[cursor->entryOffsetInPage]; + prefix = entry->string; + prefixLength = cursor->offsetInEntry + 1; + } + + while (cursor->entryOffsetInPage < pageSize) { + PageEntry *entry = (PageEntry*)&page->data[cursor->entryOffsetInPage]; + if (entry->strlen == 0) { + cursor->entryOffsetInPage += getPageEntrySize(entry); + continue; + } + + if (entry->strlen <= prefixLength) + return FALSE; + else { + int cmpResult = 0; + if (prefixLength > 0) + cmpResult = __builtin_memcmp(entry->string, prefix, prefixLength); + if (cmpResult > 0) + return FALSE; + else if (cmpResult == 0) { + if (entry->strlen < prefixLength + length) { + int cmpResult2 = __builtin_memcmp(entry->string + prefixLength, bytes, entry->strlen - prefixLength); + if (cmpResult2 > 0) + return FALSE; + else + cursor->entryOffsetInPage += getPageEntrySize(entry); + } else { + int cmpResult2 = __builtin_memcmp(entry->string + prefixLength, bytes, length); + if (cmpResult2 > 0) + return FALSE; + else if (cmpResult2 == 0) { + cursor->isOnPage = TRUE; + cursor->offsetInEntry = prefixLength + length - 1; + getMapCursorPayloadFromPageEntry(entry, cursor, &cursor->payload); + return TRUE; + } else + cursor->entryOffsetInPage += getPageEntrySize(entry); + } + } else + cursor->entryOffsetInPage += getPageEntrySize(entry); + } + } + return FALSE; +} + +static Boolean advanceCursorMappedPage(CFBurstTrieRef trie, CompactMapCursor *cursor, const UInt8* bytes, CFIndex length) +{ + if (!bytes || length < 0) + return FALSE; + + Page *page = (Page *)DiskNextTrie_GetPtr(trie->mapBase, cursor->next); + uint32_t pageSize = page->length - sizeof(Page); + if (pageSize == 0) + return FALSE; + + if (trie->cflags & kCFBurstTrieSortByKey) + return advanceCursorMappedPageSortedByKey(page, cursor, bytes, length); + else if (trie->cflags & kCFBurstTriePrefixCompression) + return advanceCursorMappedPageWithPerfixCompression(page, cursor, bytes, length); + else + return FALSE; +} + +static Boolean advanceCursorCompactMappedLevel(CFBurstTrieRef trie, CompactMapCursor *cursor, const UInt8* bytes, CFIndex length) +{ + if (!bytes || length < 0) + return FALSE; + + CompactMapTrieLevelRef root = (CompactMapTrieLevelRef)DiskNextTrie_GetPtr(trie->mapBase, cursor->next); + if (length == 0) { + cursor->payload = root->payload; + return TRUE; + } + + uint8_t slot = bytes[0] / 64; + uint8_t bit = bytes[0] % 64; + uint32_t item = 0; + uint64_t bword = root->bitmap[slot]; + if (bword & (1ull << bit)) { + // Count all the set bits up to this bit + for (int i = 0; i < slot; ++i) + item += __builtin_popcountll(root->bitmap[i]); + item += __builtin_popcountll(bword & ((1ull << bit)-1)); + cursor->next = root->slots[item]; + return advanceMapCursor(trie, cursor, bytes + 1, length - 1); + } else { + return FALSE; + } +} + +static Boolean advanceCursorMappedLevel(CFBurstTrieRef trie, CompactMapCursor *cursor, const UInt8* bytes, CFIndex length) +{ + if (!bytes || length < 0) + return FALSE; + + MapTrieLevelRef root = (MapTrieLevelRef)DiskNextTrie_GetPtr(trie->mapBase, cursor->next); + if (length == 0) { + cursor->payload = root->payload; + return TRUE; + } + + cursor->next = root->slots[bytes[0]]; + return advanceMapCursor(trie, cursor, bytes + 1, length - 1); +} + +static Boolean advanceMapCursor(CFBurstTrieRef trie, CompactMapCursor *cursor, const UInt8* bytes, CFIndex length) +{ + bool result = FALSE; + switch (DiskNextTrie_GetKind(cursor->next)) { + case TrieKind: + result = advanceCursorMappedLevel(trie, cursor, bytes, length); + break; + case CompactTrieKind: + result = advanceCursorCompactMappedLevel(trie, cursor, bytes, length); + break; + case ListKind: + result = advanceCursorMappedPage(trie, cursor, bytes, length); + break; + case Nothing: { + TrieHeader *header = (TrieHeader*)trie->mapBase; + if (cursor->next == header->rootOffset) + result = advanceCursorMappedLevel(trie, cursor, bytes, length); + } + } + + return result; +} + +static void traverseFromMapCursorMappedLevel(CFBurstTrieRef trie, CompactMapCursor *cursor, UInt8* bytes, uint32_t capacity, uint32_t length, Boolean *stop, void *ctx, CFBurstTrieTraversalCallback callback) +{ + MapTrieLevelRef root = (MapTrieLevelRef)DiskNextTrie_GetPtr(trie->mapBase, cursor->next); + if (root->payload) { + callback(ctx, bytes, length, root->payload, stop); + if (*stop) + return; + } + + if (length >= capacity) + return; + + for (int i = 0; i < CHARACTER_SET_SIZE; ++i) {i = + bytes[length] = i; + cursor->next = (uint32_t)root->slots[i];; + cursor->isOnPage = FALSE; + cursor->entryOffsetInPage = 0; + cursor->offsetInEntry = 0; + cursor->payload = 0; + traverseFromMapCursor(trie, cursor, bytes, capacity - 1, length + 1, stop, ctx, callback); + if (*stop) + return; + } +} + +static void traverseFromMapCursorCompactMappedLevel(CFBurstTrieRef trie, CompactMapCursor *cursor, UInt8* bytes, uint32_t capacity, uint32_t length, Boolean *stop, void *ctx, CFBurstTrieTraversalCallback callback) +{ + CompactMapTrieLevelRef root = (CompactMapTrieLevelRef)DiskNextTrie_GetPtr(trie->mapBase, cursor->next); + if (root->payload) { + callback(ctx, bytes, length, root->payload, stop); + if (*stop) + return; + } + + if (length >= capacity) + return; + for (int c = 0; c < CHARACTER_SET_SIZE; ++c) { + bytes[length] = c; + //This could be optimized to remember what the last slot/item was and not count bits over and over. + uint8_t slot = c / 64; + uint8_t bit = c % 64; + uint32_t item = 0; + uint64_t bword = root->bitmap[slot]; + if (bword & (1ull << bit)) { + // Count all the set bits up to this bit + for (int i = 0; i < slot; ++i) + item += __builtin_popcountll(root->bitmap[i]); + item += __builtin_popcountll(bword & ((1ull << bit)-1)); + cursor->next = root->slots[item]; + cursor->isOnPage = FALSE; + cursor->entryOffsetInPage = 0; + cursor->offsetInEntry = 0; + cursor->payload = 0; + traverseFromMapCursor(trie, cursor, bytes, capacity - 1, length + 1, stop, ctx, callback); + if (*stop) + return; + } + } +} + +static void traverseFromMapCursorMappedPageWithPrefixCompression(Page *page, CompactMapCursor *cursor, UInt8* bytes, uint32_t capacity, uint32_t length, Boolean *stop, void *ctx, CFBurstTrieTraversalCallback callback) +{ + uint32_t pageSize = page->length - sizeof(Page); + uint32_t offset = cursor->entryOffsetInPage; + uint32_t minPrefixLength = 0; + if (cursor->isOnPage) { + PageEntryPacked *entry = (PageEntryPacked*)&page->data[offset]; + int32_t remainingLength = entry->strlen - cursor->offsetInEntry - 1; + if (remainingLength >= 0 && remainingLength <= capacity) { + memcpy(bytes + length, entry->string + cursor->offsetInEntry + 1, remainingLength); + callback(ctx, bytes, length + remainingLength, entry->payload, stop); + if (*stop) + return; + } + minPrefixLength = entry->pfxLen + cursor->offsetInEntry; + offset += getPackedPageEntrySize(entry); + } + PageEntryPacked *previousEntry = NULL; + while (offset < pageSize) { + PageEntryPacked *entry = (PageEntryPacked*)&page->data[offset]; + if (minPrefixLength > entry->pfxLen) + break; + else if (entry->payload && entry->strlen <= capacity) { + if (previousEntry) + length -= previousEntry->strlen + previousEntry->pfxLen - entry->pfxLen; + memcpy(bytes + length, entry->string, entry->strlen); + callback(ctx, bytes, length + entry->strlen, entry->payload, stop); + length += entry->strlen; + if (*stop) + return; + } + previousEntry = entry; + offset += getPackedPageEntrySize(entry); + } +} + +static void traverseFromMapCursorMappedPageSortedByKey(Page *page, CompactMapCursor *cursor, UInt8* bytes, uint32_t capacity, uint32_t length, Boolean *stop, void *ctx, CFBurstTrieTraversalCallback callback) +{ + uint32_t pageSize = page->length - sizeof(Page); + uint32_t offset = cursor->entryOffsetInPage; + uint32_t prefixLength = 0; + const UInt8 *prefix = NULL; + if (cursor->isOnPage) { + PageEntry *entry = (PageEntry*)&page->data[offset]; + int32_t remainingLength = entry->strlen - cursor->offsetInEntry - 1; + if (remainingLength >= 0 && remainingLength <= capacity) { + memcpy(bytes + length, entry->string + cursor->offsetInEntry, remainingLength); + callback(ctx, bytes, length + remainingLength, entry->payload, stop); + if (*stop) + return; + } + prefixLength = cursor->offsetInEntry + 1; + prefix = entry->string; + offset += getPageEntrySize(entry); + } + + while (offset < pageSize) { + PageEntry *entry = (PageEntry*)&page->data[offset]; + if (entry->strlen < prefixLength) + break; + else { + int cmpResult = __builtin_memcmp(entry->string, prefix, prefixLength); + if (cmpResult > 0) + break; + else if (entry->payload && entry->strlen <= capacity) { + if (entry->strlen > 0) + memcpy(bytes + length, entry->string + prefixLength, entry->strlen - prefixLength); + callback(ctx, bytes, length + entry->strlen - prefixLength, entry->payload, stop); + if (*stop) + return; + } + offset += getPageEntrySize(entry); + } + } +} + +static void traverseFromMapCursorMappedPage(CFBurstTrieRef trie, CompactMapCursor *cursor, UInt8* bytes, uint32_t capacity, uint32_t length, Boolean *stop, void *ctx, CFBurstTrieTraversalCallback callback) +{ + Page *page = (Page *)DiskNextTrie_GetPtr(trie->mapBase, cursor->next); + if (trie->cflags & kCFBurstTrieSortByKey) + traverseFromMapCursorMappedPageSortedByKey(page, cursor, bytes, capacity, length, stop, ctx, callback); + else if (trie->cflags & kCFBurstTriePrefixCompression) + traverseFromMapCursorMappedPageWithPrefixCompression(page, cursor, bytes, capacity, length, stop, ctx, callback); +} + +void traverseFromMapCursor(CFBurstTrieRef trie, CompactMapCursor *cursor, UInt8* bytes, uint32_t capacity, uint32_t length, Boolean *stop, void *ctx, CFBurstTrieTraversalCallback callback) +{ + switch (DiskNextTrie_GetKind(cursor->next)) { + case TrieKind: + traverseFromMapCursorMappedLevel(trie, cursor, bytes, capacity, length, stop, ctx, callback); + break; + case CompactTrieKind: + traverseFromMapCursorCompactMappedLevel(trie, cursor, bytes, capacity, length, stop, ctx, callback); + break; + case ListKind: + traverseFromMapCursorMappedPage(trie, cursor, bytes, capacity, length, stop, ctx, callback); + break; + case Nothing: { + TrieHeader *header = (TrieHeader*)trie->mapBase; + if (cursor->next == header->rootOffset) { + traverseFromMapCursorMappedLevel(trie, cursor, bytes, capacity, length, stop, ctx, callback); + } + break; + } + } +} + +void copyMapCursor(const CompactMapCursor *source, CompactMapCursor* destination) +{ + destination->next = source->next; + destination->entryOffsetInPage = source->entryOffsetInPage; + destination->offsetInEntry = source->offsetInEntry; + destination->isOnPage = source->isOnPage; + destination->payload = source->payload; +} + +Boolean areMapCursorsEqual(const CompactMapCursor *lhs, const CompactMapCursor *rhs) +{ + return lhs->entryOffsetInPage == rhs->entryOffsetInPage && lhs->isOnPage == rhs->isOnPage && lhs->next == rhs->next && lhs->offsetInEntry == rhs->offsetInEntry; +} + +static Boolean getMapCursorPayloadFromPackedPageEntry(PageEntryPacked *entry, const CompactMapCursor *cursor, uint32_t *payload) +{ + if (payload) + *payload = 0; + if (cursor->entryOffsetInPage == 0 && cursor->offsetInEntry == 0 && entry->strlen == 0) { + if (payload) + *payload = entry->payload; + return TRUE; + } else if (cursor->offsetInEntry != entry->strlen - 1) + return FALSE; + else { + if (payload) + *payload = entry->payload; + return TRUE; + } +} + +static Boolean getMapCursorPayloadFromPageEntry(PageEntry *entry, const CompactMapCursor *cursor, uint32_t *payload) +{ + if (payload) + *payload = 0; + if (cursor->entryOffsetInPage == 0 && cursor->offsetInEntry == 0 && entry->strlen == 0) { + if (payload) + *payload = entry->payload; + return TRUE; + } else if (cursor->offsetInEntry != entry->strlen - 1) + return FALSE; + else { + if (payload) + *payload = entry->payload; + return TRUE; + } +} + +Boolean getMapCursorPayload(CFBurstTrieRef trie, const CompactMapCursor *cursor, uint32_t *payload) +{ + if (!cursor) + return FALSE; + if (cursor->payload) { + if (payload) + *payload = cursor->payload; + return TRUE; + } + return FALSE; +} + +// Legacy + +static Boolean burstTrieMappedFind(DiskTrieLevelRef trie, char *map, const UInt8 *key, uint32_t length, uint32_t *payload, bool prefix) { + Boolean success = false; + if (length) { + uint32_t offset = CFSwapInt32LittleToHost((uint32_t)trie->slots[*key]); + if(DiskNextTrie_GetKind(offset) == TrieKind) { + return burstTrieMappedFind((DiskTrieLevelRef)DiskNextTrie_GetPtr(map,offset), map, key+1, length-1, payload, prefix); + } else if(DiskNextTrie_GetKind(offset) == CompactTrieKind) { + return burstTrieCompactTrieMappedFind((CompactDiskTrieLevelRef)DiskNextTrie_GetPtr(map, offset), map, key+1, length-1, payload, prefix); + } else { + if(DiskNextTrie_GetKind(offset) == ListKind) { + return burstTrieMappedPageFind((StringPage *)DiskNextTrie_GetPtr(map, offset), key+1, length-1, payload, prefix); + } else { + return success; + } + } + } else { + if (trie->weight) { + SetPayload(payload, CFSwapInt32LittleToHost(trie->payload)); + success = true; + } + } + return success; +} + +static Boolean burstTrieCompactTrieMappedFind(CompactDiskTrieLevelRef trie, char *map, const UInt8 *key, uint32_t length, uint32_t *payload, bool prefix) { + Boolean success = false; + if (length) { + uint32_t mykey = *key; + uint32_t slot = mykey / 64; + uint32_t bit = mykey % 64; + uint32_t item = 0; + uint64_t bword = CFSwapInt64LittleToHost(trie->bitmap[slot]); + if (bword & (1ull << bit)) { + /* Count all the set bits up to this bit */ + for (int i=0; i < slot; i++) { + item += __builtin_popcountll(trie->bitmap[i]); + } + item += __builtin_popcountll(bword & ((1ull << bit)-1)); + uint32_t offset = CFSwapInt32LittleToHost((uint32_t)trie->slots[item]); + if(DiskNextTrie_GetKind(offset) == TrieKind) { + return burstTrieMappedFind((DiskTrieLevelRef)DiskNextTrie_GetPtr(map, offset), map, key+1, length-1, payload, prefix); + } else if(DiskNextTrie_GetKind(offset) == CompactTrieKind) { + return burstTrieCompactTrieMappedFind((CompactDiskTrieLevelRef)DiskNextTrie_GetPtr(map, offset), map, key+1, length-1, payload, prefix); + } + else { + if(DiskNextTrie_GetKind(offset) == ListKind) { + return burstTrieMappedPageFind((StringPage *)DiskNextTrie_GetPtr(map, offset), key+1, length-1, payload, prefix); + } else { + return success; + } + } + } + } else { + if (trie->weight) { + SetPayload(payload, CFSwapInt32LittleToHost(trie->payload)); + success = true; + } + } + return success; +} + +static Boolean burstTrieMappedPageFind(StringPage *page, const UInt8 *key, uint32_t length, uint32_t *payload, bool prefix) { + Boolean success = false; + uint32_t end = CFSwapInt32LittleToHost(page->length); + uint32_t cur = 0; + if (prefix) { + uint8_t pfx[256]; + while (cur < end) { + StringPageEntryPacked *entry = (StringPageEntryPacked *)&page->data[cur]; + uint16_t strlen = entry->pfxLen+CFSwapInt16LittleToHost(entry->strlen); + if (strlen == length && __builtin_memcmp(pfx, key, entry->pfxLen) == 0 && __builtin_memcmp(entry->string, key+entry->pfxLen, length-entry->pfxLen) == 0) { + SetPayload(payload, CFSwapInt32LittleToHost(entry->payload)); + success = true; + return success; + } else { + memcpy(pfx+entry->pfxLen, entry->string, MIN(255-entry->pfxLen, length-entry->pfxLen)); + cur += sizeof(*entry) + strlen - entry->pfxLen; + } + } + } else { + while (cur < end) { + StringPageEntry *entry = (StringPageEntry *)&page->data[cur]; + uint16_t strlen = CFSwapInt16LittleToHost(entry->strlen); + if (strlen == length && __builtin_memcmp(entry->string, key, length) == 0) { + SetPayload(payload, CFSwapInt32LittleToHost(entry->payload)); + success = true; + return success; + } else { + cur += sizeof(*entry) + strlen; + } + } + + } + return success; +} + + +#if 0 +#pragma mark - +#pragma mark Serialization +#endif + +static bool serializeCFBurstTrieLevels(CFBurstTrieRef trie, TrieLevelRef root, uint32_t *offset, off_t start_offset, bool dispose, bool isroot, int fd) +{ + bool dense = true; + int count = 0; + + for (int i=0; i < CHARACTER_SET_SIZE; i++) if (root->slots[i]) count++; + + uint32_t this_offset = *offset; + + if ((trie->cflags & kCFBurstTrieBitmapCompression) && count < MAX_BITMAP_SIZE && !isroot) { + size_t size = sizeof(CompactMapTrieLevel) + sizeof(uint32_t) * count; + int offsetSlot = 0; + + CompactMapTrieLevel *maptrie = (CompactMapTrieLevel *)alloca(size); + bzero(maptrie, size); + *offset += size; + + for (int i=0; i < CHARACTER_SET_SIZE; i++) { + NextTrie next = root->slots[i]; + if (next) { + uint32_t slot = i / 64; + uint32_t bit = i % 64; + maptrie->bitmap[slot] |= 1ull<slots[offsetSlot] = (TrieKind|childOffset); + } else { + maptrie->slots[offsetSlot] = (CompactTrieKind|childOffset); + } + } else { + maptrie->slots[offsetSlot] = next; + } + offsetSlot++; + } + } + maptrie->payload = root->payload; + + int bitcount = 0; + for (int i=0; i < 4; i++) bitcount += __builtin_popcountll(maptrie->bitmap[i]); + assert(bitcount == count); + + pwrite(fd, maptrie, size, this_offset+start_offset); + dense = false; + } else { + MapTrieLevel maptrie; + *offset += sizeof(maptrie); + + for (int i=0; i < CHARACTER_SET_SIZE; i++) { + NextTrie next = root->slots[i]; + if (NextTrie_GetKind(next) == TrieKind) { + TrieLevelRef nextLevel = (TrieLevelRef)NextTrie_GetPtr(next); + uint32_t childOffset = *offset; + if (serializeCFBurstTrieLevels(trie, nextLevel, offset, start_offset, true, false, fd)) { + maptrie.slots[i] = (TrieKind|childOffset); + } else { + maptrie.slots[i] = (CompactTrieKind|childOffset); + } + } else { + maptrie.slots[i] = next; + } + } + maptrie.payload = root->payload; + pwrite(fd, &maptrie, sizeof(maptrie), this_offset+start_offset); + } + + if (dispose) free(root); + return dense; +} + +static void serializeCFBurstTrieList(CFBurstTrieRef trie, ListNodeRef listNode, int fd) +{ + uint32_t listCount; + size_t size = trie->containerSize; + + // ** Temp list of nodes to sort + ListNodeRef *nodes = (ListNodeRef *)malloc(sizeof(ListNodeRef) * size); + for (listCount = 0; listNode; listCount++) { + if (listCount >= size) { + size *= 2; + nodes = (ListNodeRef *)realloc(nodes, sizeof(ListNodeRef) * size); + } + nodes[listCount] = listNode; + listNode = listNode->next; + } + + char _buffer[MAX_BUFFER_SIZE]; + char bufferSize = (sizeof(Page) + size * (sizeof(PageEntryPacked) + MAX_STRING_SIZE)); + char *buffer = bufferSize < MAX_BUFFER_SIZE ? _buffer : (char *) malloc(bufferSize); + + Page *page = (Page *)buffer; + uint32_t current = 0; + + if (trie->cflags & kCFBurstTriePrefixCompression) { + qsort(nodes, listCount, sizeof(ListNodeRef), nodeStringCompare); + + ListNodeRef last = 0; + for (int i=0; i < listCount; i++) { + listNode = nodes[i]; + uint8_t pfxLen = 0; + if (last) { + for ( ; + pfxLen < CHARACTER_SET_SIZE-1 && + pfxLen < listNode->length && + pfxLen < last->length && + listNode->string[pfxLen] == last->string[pfxLen]; + pfxLen++); + } + + PageEntryPacked *entry = (PageEntryPacked *)(&page->data[current]); + entry->strlen = listNode->length - pfxLen; + entry->payload = listNode->payload; + entry->pfxLen = pfxLen; + memcpy(entry->string, listNode->string+pfxLen, listNode->length-pfxLen); + current += listNode->length - pfxLen + sizeof(PageEntryPacked); + last = listNode; + } + } else { + if (trie->cflags & kCFBurstTrieSortByKey) + qsort(nodes, listCount, sizeof(ListNodeRef), nodeStringCompare); + else + qsort(nodes, listCount, sizeof(ListNodeRef), nodeWeightCompare); + + for (int i=0; i < listCount; i++) { + listNode = nodes[i]; + PageEntry *entry = (PageEntry *)(&page->data[current]); + entry->strlen = listNode->length; + entry->payload = listNode->payload; + memcpy(entry->string, listNode->string, listNode->length); + current += listNode->length + sizeof(PageEntry); + } + } + + size_t len = (sizeof(Page) + current + 3) & ~3; + page->length = current; + write(fd, page, len); + + free(nodes); + if (buffer != _buffer) free(buffer); +} + +static void serializeCFBurstTrieLists(CFBurstTrieRef trie, TrieLevelRef root, off_t start_offset, int fd) +{ + for (int i=0; i < CHARACTER_SET_SIZE; i++) { + NextTrie next = root->slots[i]; + uint32_t offset; + if (NextTrie_GetKind(next) == TrieKind) { + TrieLevelRef nextLevel = (TrieLevelRef)NextTrie_GetPtr(next); + serializeCFBurstTrieLists(trie, nextLevel, start_offset, fd); + } else { + if (NextTrie_GetKind(next) == ListKind) { + ListNodeRef listNode = (ListNodeRef)NextTrie_GetPtr(next); + offset = lseek(fd, 0, SEEK_CUR) - start_offset; + serializeCFBurstTrieList(trie, listNode, fd); + finalizeCFBurstTrieList(listNode); + //assert((offset & 3)==0); + root->slots[i] = (offset|ListKind); + } + } + } +} + +static size_t serializeCFBurstTrie(CFBurstTrieRef trie, size_t start_offset, int fd) +{ + TrieHeader header; + header.signature = 0x0ddba11; + header.rootOffset = 0; + header.count = trie->count; + header.size = 0; + header.flags = trie->cflags; + header.reserved[0] = 0; + + uint32_t offset; + lseek(fd, start_offset, SEEK_SET); + + size_t header_size = sizeof(header); + write(fd, &header, header_size); + + serializeCFBurstTrieLists(trie, &trie->root, start_offset, fd); + + offset = lseek(fd, 0, SEEK_CUR) - start_offset; + size_t off = offsetof(TrieHeader, rootOffset); + size_t offsize = sizeof(offset); + pwrite(fd, &offset, offsize, off+start_offset); + + serializeCFBurstTrieLevels(trie, &trie->root, &offset, start_offset, false, true, fd); + + size_t off2 = offsetof(TrieHeader, size); + offsize = sizeof(offset); + pwrite(fd, &offset, offsize, off2+start_offset); + + offset = lseek(fd, 0, SEEK_END); + return (size_t)(offset-start_offset); +} + +#if 0 +#pragma mark - +#pragma mark Release +#endif + +static void destroyCFBurstTrie(CFBurstTrieRef trie) { + if (trie->mapBase) { +#if DEPLOYMENT_TARGET_WINDOWS + UnmapViewOfFile(trie->mapBase); + CloseHandle(trie->mapHandle); + CloseHandle(trie->mappedFileHandle); +#else + munmap(trie->mapBase, trie->mapSize); +#endif + } else { + finalizeCFBurstTrie(&trie->root); + } + free(trie); + return; +} + +static void finalizeCFBurstTrie(TrieLevelRef trie) { + for (int i=0; i < CHARACTER_SET_SIZE; i++) { + if (NextTrie_GetKind(trie->slots[i]) == TrieKind) { + finalizeCFBurstTrie((TrieLevelRef)NextTrie_GetPtr(trie->slots[i])); + free((void *)NextTrie_GetPtr(trie->slots[i])); + } else if (NextTrie_GetKind(trie->slots[i]) == ListKind) { + finalizeCFBurstTrieList((ListNodeRef)NextTrie_GetPtr(trie->slots[i])); + } + } +} + +static void finalizeCFBurstTrieList(ListNodeRef node) { + do { + ListNodeRef next = node->next; + free(node); + node = next; + } while(node); +} + +#if 0 +#pragma mark - +#pragma mark Helpers +#endif + +static int nodeWeightCompare(const void *a, const void *b) { + ListNodeRef nodeA = *(ListNodeRef *)a; + ListNodeRef nodeB = *(ListNodeRef *)b; + return (nodeB->weight - nodeA->weight); +} + +static int nodeStringCompare(const void *a, const void *b) { + ListNodeRef nodeA = *(ListNodeRef *)a; + ListNodeRef nodeB = *(ListNodeRef *)b; + int result = memcmp((char *)nodeA->string, (char *)nodeB->string, MIN(nodeA->length, nodeB->length)); + if (result == 0) result = nodeA->length-nodeB->length; + return result; +} + +bool containsKey(void *context, const uint8_t *key, uint32_t payload, bool exact) +{ + uint32_t *ctx = (uint32_t *)context; + if (exact) *ctx = payload; + return exact; +} + +static CFIndex burstTrieConvertCharactersToUTF8(UniChar *chars, CFIndex numChars, UInt8 *buffer) { + uint32_t i, j; + for (i = j = 0; i < numChars; i++) { + UniChar c = chars[i]; + if (CFStringIsSurrogateHighCharacter(c) && i + 1 < numChars && CFStringIsSurrogateLowCharacter(chars[i + 1])) { + UTF32Char lc = CFStringGetLongCharacterForSurrogatePair(c, chars[i + 1]); + buffer[j++] = 0xf0 + (lc >> 18); + buffer[j++] = 0x80 + ((lc & 0x3ffff) >> 12); + buffer[j++] = 0x80 + ((lc & 0xfff) >> 6); + buffer[j++] = 0x80 + (lc & 0x3f); + i++; + } else { + if (c < 0x80) { + buffer[j++] = c; + } else if (c < 0x800) { + buffer[j++] = 0xc0 + (c >> 6); + buffer[j++] = 0x80 + (c & 0x3f); + } else { + buffer[j++] = 0xe0 + (c >> 12); + buffer[j++] = 0x80 + ((c & 0xfff) >> 6); + buffer[j++] = 0x80 + (c & 0x3f); + } + } + } + buffer[j] = 0; + return j; +} + diff --git a/CFBurstTrie.h b/CFBurstTrie.h new file mode 100644 index 0000000..e6c8830 --- /dev/null +++ b/CFBurstTrie.h @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2012 Apple 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@ + */ + +/* CFBurstTrie.h + Copyright (c) 2008-2012, Apple Inc. All rights reserved. +*/ + +#if !defined(__COREFOUNDATION_CFBURSTTRIE__) +#define __COREFOUNDATION_CFBURSTTRIE__ 1 + +#include +#include + +CF_EXTERN_C_BEGIN + +typedef struct _CFBurstTrie *CFBurstTrieRef; +typedef struct _CFBurstTrieCursor *CFBurstTrieCursorRef; + +typedef CF_OPTIONS(CFOptionFlags, CFBurstTrieOpts) { + /*! + BurstTrie Options + Use one or more of these options with CFBurstTrieCreate to tailor optimizations to the data + structure for a specific kind of application. Default is no read-write, no compression. + */ + + /* kCFBurstTrieReadOnly + When specified, the dictionary file will be serialized in an optimized format so as to be + memory-mapped on the next read. Once a trie is serialized as read-only, insertions can no + longer occur. + */ + kCFBurstTrieReadOnly = 1<<1, + + /* kCFBurstTrieBitmapCompression + This option can only be used with a read-only trie, and can be used to reduce on disk file size. + */ + kCFBurstTrieBitmapCompression = 1<<2, + + /* + kCFBurstTriePrefixCompression + This option can only be used with a read-only trie, and can be used to reduce on-disk file size. + It is important to note that any optimizations based on word frequency will be lost; recommended + for applications that often search for infrequent or uncommon words. This also allow you to use + cursor interface. + */ + kCFBurstTriePrefixCompression = 1<<3, + + /* + kCFBurstTriePrefixCompression + By default, keys at list level are sorted by weight. Use this option to sort them by key value. + This allow you to use cursor interface. + */ + kCFBurstTrieSortByKey = 1 << 4 +}; + +// Value for this option should be a CFNumber which contains an int. +#define kCFBurstTrieCreationOptionNameContainerSize CFSTR("ContainerSize") + +typedef void (*CFBurstTrieTraversalCallback)(void* context, const UInt8* key, uint32_t keyLength, uint32_t payload, Boolean *stop); + +CF_EXPORT +CFBurstTrieRef CFBurstTrieCreate() CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +CFBurstTrieRef CFBurstTrieCreateWithOptions(CFDictionaryRef options) CF_AVAILABLE(10_8, 6_0); + +CF_EXPORT +CFBurstTrieRef CFBurstTrieCreateFromFile(CFStringRef path) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +CFBurstTrieRef CFBurstTrieCreateFromMapBytes(char *mapBase) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +Boolean CFBurstTrieInsert(CFBurstTrieRef trie, CFStringRef term, CFRange termRange, CFIndex payload) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +Boolean CFBurstTrieAdd(CFBurstTrieRef trie, CFStringRef term, CFRange termRange, uint32_t payload) CF_AVAILABLE(10_7, 5_0); + + +CF_EXPORT +Boolean CFBurstTrieInsertCharacters(CFBurstTrieRef trie, UniChar *chars, CFIndex numChars, CFIndex payload) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +Boolean CFBurstTrieAddCharacters(CFBurstTrieRef trie, UniChar *chars, CFIndex numChars, uint32_t payload) CF_AVAILABLE(10_7, 5_0); + + +CF_EXPORT +Boolean CFBurstTrieInsertUTF8String(CFBurstTrieRef trie, UInt8 *chars, CFIndex numChars, CFIndex payload) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +Boolean CFBurstTrieAddUTF8String(CFBurstTrieRef trie, UInt8 *chars, CFIndex numChars, uint32_t payload) CF_AVAILABLE(10_7, 5_0); + + +CF_EXPORT +Boolean CFBurstTrieInsertWithWeight(CFBurstTrieRef trie, CFStringRef term, CFRange termRange, CFIndex weight, CFIndex payload) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +Boolean CFBurstTrieAddWithWeight(CFBurstTrieRef trie, CFStringRef term, CFRange termRange, uint32_t weight, uint32_t payload) CF_AVAILABLE(10_7, 5_0); + + +CF_EXPORT +Boolean CFBurstTrieInsertCharactersWithWeight(CFBurstTrieRef trie, UniChar *chars, CFIndex numChars, CFIndex weight, CFIndex payload) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +Boolean CFBurstTrieAddCharactersWithWeight(CFBurstTrieRef trie, UniChar *chars, CFIndex numChars, uint32_t weight, uint32_t payload) CF_AVAILABLE(10_7, 5_0); + + +CF_EXPORT +Boolean CFBurstTrieInsertUTF8StringWithWeight(CFBurstTrieRef trie, UInt8 *chars, CFIndex numChars, CFIndex weight, CFIndex payload) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +Boolean CFBurstTrieAddUTF8StringWithWeight(CFBurstTrieRef trie, UInt8 *chars, CFIndex numChars, uint32_t weight, uint32_t payload) CF_AVAILABLE(10_7, 5_0); + + +CF_EXPORT +Boolean CFBurstTrieFind(CFBurstTrieRef trie, CFStringRef term, CFRange termRange, CFIndex *payload) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +Boolean CFBurstTrieContains(CFBurstTrieRef trie, CFStringRef term, CFRange termRange, uint32_t *payload) CF_AVAILABLE(10_7, 5_0); + + +CF_EXPORT +Boolean CFBurstTrieFindCharacters(CFBurstTrieRef trie, UniChar *chars, CFIndex numChars, CFIndex *payload) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +Boolean CFBurstTrieContainsCharacters(CFBurstTrieRef trie, UniChar *chars, CFIndex numChars, uint32_t *payload) CF_AVAILABLE(10_7, 5_0); + + +CF_EXPORT +Boolean CFBurstTrieFindUTF8String(CFBurstTrieRef trie, UInt8 *key, CFIndex length, CFIndex *payload) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +Boolean CFBurstTrieContainsUTF8String(CFBurstTrieRef trie, UInt8 *key, CFIndex length, uint32_t *payload) CF_AVAILABLE(10_7, 5_0); + + +CF_EXPORT +Boolean CFBurstTrieSerialize(CFBurstTrieRef trie, CFStringRef path, CFBurstTrieOpts opts) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +Boolean CFBurstTrieSerializeWithFileDescriptor(CFBurstTrieRef trie, int fd, CFBurstTrieOpts opts) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +void CFBurstTrieTraverse(CFBurstTrieRef trie, void *ctx, void (*callback)(void*, const UInt8*, uint32_t, uint32_t)) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +CFIndex CFBurstTrieGetCount(CFBurstTrieRef trie) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +CFBurstTrieRef CFBurstTrieRetain(CFBurstTrieRef trie) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +void CFBurstTrieRelease(CFBurstTrieRef trie) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +CFBurstTrieCursorRef CFBurstTrieCreateCursorForBytes(CFBurstTrieRef trie, const UInt8* bytes, CFIndex length) CF_AVAILABLE(10_8, 6_0); + +CF_EXPORT +CFBurstTrieCursorRef CFBurstTrieCursorCreateByCopy(CFBurstTrieCursorRef cursor) CF_AVAILABLE(10_8, 6_0); + +CF_EXPORT +Boolean CFBurstTrieSetCursorForBytes(CFBurstTrieRef trie, CFBurstTrieCursorRef cursor, const UInt8* bytes, CFIndex length) CF_AVAILABLE(10_8, 6_0); + +CF_EXPORT +Boolean CFBurstTrieCursorIsEqual(CFBurstTrieCursorRef lhs, CFBurstTrieCursorRef rhs) CF_AVAILABLE(10_8, 6_0); + +CF_EXPORT +Boolean CFBurstTrieCursorAdvanceForBytes(CFBurstTrieCursorRef cursor, const UInt8* bytes, CFIndex length) CF_AVAILABLE(10_8, 6_0); + +CF_EXPORT +Boolean CFBurstTrieCursorGetPayload(CFBurstTrieCursorRef cursor, uint32_t *payload) CF_AVAILABLE(10_8, 6_0); + +CF_EXPORT +void CFBurstTrieTraverseFromCursor(CFBurstTrieCursorRef cursor, void *ctx, CFBurstTrieTraversalCallback callback) CF_AVAILABLE(10_8, 6_0); + +CF_EXPORT +void CFBurstTrieCursorRelease(CFBurstTrieCursorRef cursor) CF_AVAILABLE(10_8, 6_0); + +__private_extern__ const CFDictionaryValueCallBacks kCFBurstTrieValueCallbacks; + +CF_EXTERN_C_END + +#endif /* __COREFOUNDATION_CFBURSTTRIE__ */ diff --git a/CFByteOrder.h b/CFByteOrder.h index 4c05f6a..d7d506e 100644 --- a/CFByteOrder.h +++ b/CFByteOrder.h @@ -22,7 +22,7 @@ */ /* CFByteOrder.h - Copyright (c) 1995-2011, Apple Inc. All rights reserved. + Copyright (c) 1995-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBYTEORDER__) diff --git a/CFCalendar.c b/CFCalendar.c index a95c515..c3a1920 100644 --- a/CFCalendar.c +++ b/CFCalendar.c @@ -22,7 +22,7 @@ */ /* CFCalendar.c - Copyright (c) 2004-2011, Apple Inc. All rights reserved. + Copyright (c) 2004-2012, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ @@ -176,19 +176,19 @@ CFCalendarRef CFCalendarCreateWithIdentifier(CFAllocatorRef allocator, CFStringR } CFStringRef CFCalendarGetIdentifier(CFCalendarRef calendar) { - CF_OBJC_FUNCDISPATCH0(CFCalendarGetTypeID(), CFStringRef, calendar, "calendarIdentifier"); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFStringRef, calendar, calendarIdentifier); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); return calendar->_identifier; } CFLocaleRef CFCalendarCopyLocale(CFCalendarRef calendar) { - CF_OBJC_FUNCDISPATCH0(CFCalendarGetTypeID(), CFLocaleRef, calendar, "_copyLocale"); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFLocaleRef, calendar, _copyLocale); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); return (CFLocaleRef)CFLocaleCreate(kCFAllocatorSystemDefault, calendar->_localeID); } void CFCalendarSetLocale(CFCalendarRef calendar, CFLocaleRef locale) { - CF_OBJC_FUNCDISPATCH1(CFCalendarGetTypeID(), void, calendar, "setLocale:", locale); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), void, calendar, setLocale:locale); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); __CFGenericValidateType(locale, CFLocaleGetTypeID()); CFStringRef localeID = CFLocaleGetIdentifier(locale); @@ -201,13 +201,13 @@ void CFCalendarSetLocale(CFCalendarRef calendar, CFLocaleRef locale) { } CFTimeZoneRef CFCalendarCopyTimeZone(CFCalendarRef calendar) { - CF_OBJC_FUNCDISPATCH0(CFCalendarGetTypeID(), CFTimeZoneRef, calendar, "_copyTimeZone"); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFTimeZoneRef, calendar_copyTimeZone); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); return (CFTimeZoneRef)CFRetain(calendar->_tz); } void CFCalendarSetTimeZone(CFCalendarRef calendar, CFTimeZoneRef tz) { - CF_OBJC_FUNCDISPATCH1(CFCalendarGetTypeID(), void, calendar, "setTimeZone:", tz); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), void, calendar, setTimeZone:tz); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (tz) __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); if (tz != calendar->_tz) { @@ -218,7 +218,7 @@ void CFCalendarSetTimeZone(CFCalendarRef calendar, CFTimeZoneRef tz) { } CFIndex CFCalendarGetFirstWeekday(CFCalendarRef calendar) { - CF_OBJC_FUNCDISPATCH0(CFCalendarGetTypeID(), CFIndex, calendar, "firstWeekday"); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFIndex, calendar, firstWeekday); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); if (calendar->_cal) { @@ -228,7 +228,7 @@ CFIndex CFCalendarGetFirstWeekday(CFCalendarRef calendar) { } void CFCalendarSetFirstWeekday(CFCalendarRef calendar, CFIndex wkdy) { - CF_OBJC_FUNCDISPATCH1(CFCalendarGetTypeID(), void, calendar, "setFirstWeekday:", wkdy); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), void, calendar, setFirstWeekday:wkdy); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); if (calendar->_cal) { @@ -237,21 +237,21 @@ void CFCalendarSetFirstWeekday(CFCalendarRef calendar, CFIndex wkdy) { } CFIndex CFCalendarGetMinimumDaysInFirstWeek(CFCalendarRef calendar) { - CF_OBJC_FUNCDISPATCH0(CFCalendarGetTypeID(), CFIndex, calendar, "minimumDaysInFirstWeek"); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFIndex, calendar, minimumDaysInFirstWeek); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); return calendar->_cal ? ucal_getAttribute(calendar->_cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK) : -1; } void CFCalendarSetMinimumDaysInFirstWeek(CFCalendarRef calendar, CFIndex mwd) { - CF_OBJC_FUNCDISPATCH1(CFCalendarGetTypeID(), void, calendar, "setMinimumDaysInFirstWeek:", mwd); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), void, calendar, setMinimumDaysInFirstWeek:mwd); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); if (calendar->_cal) ucal_setAttribute(calendar->_cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK, mwd); } CFDateRef CFCalendarCopyGregorianStartDate(CFCalendarRef calendar) { - CF_OBJC_FUNCDISPATCH0(CFCalendarGetTypeID(), CFDateRef, calendar, "_gregorianStartDate"); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFDateRef, calendar, _gregorianStartDate); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); UErrorCode status = U_ZERO_ERROR; @@ -264,7 +264,7 @@ CFDateRef CFCalendarCopyGregorianStartDate(CFCalendarRef calendar) { } void CFCalendarSetGregorianStartDate(CFCalendarRef calendar, CFDateRef date) { - CF_OBJC_FUNCDISPATCH1(CFCalendarGetTypeID(), void, calendar, "_setGregorianStartDate:", date); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), void, calendar, _setGregorianStartDate:date); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (date) __CFGenericValidateType(date, CFDateGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); @@ -348,7 +348,7 @@ static CFCalendarUnit __CFCalendarGetCalendarUnitFromChar(char ch) { } CFRange CFCalendarGetMinimumRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit) { - CF_OBJC_FUNCDISPATCH1(CFCalendarGetTypeID(), CFRange, calendar, "_minimumRangeOfUnit:", unit); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFRange, calendar, _minimumRangeOfUnit:unit); CFRange range = {kCFNotFound, kCFNotFound}; __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); @@ -365,7 +365,7 @@ CFRange CFCalendarGetMinimumRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit u } CFRange CFCalendarGetMaximumRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit) { - CF_OBJC_FUNCDISPATCH1(CFCalendarGetTypeID(), CFRange, calendar, "_maximumRangeOfUnit:", unit); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFRange, calendar, _maximumRangeOfUnit:unit); CFRange range = {kCFNotFound, kCFNotFound}; __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); @@ -505,7 +505,7 @@ static Boolean __validUnits(CFCalendarUnit smaller, CFCalendarUnit bigger) { static CFRange __CFCalendarGetRangeOfUnit1(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) { CFRange range = {kCFNotFound, kCFNotFound}; if (!__validUnits(smallerUnit, biggerUnit)) return range; - CF_OBJC_FUNCDISPATCH3(CFCalendarGetTypeID(), CFRange, calendar, "_rangeOfUnit:inUnit:forAT:", smallerUnit, biggerUnit, at); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFRange, calendar, _rangeOfUnit:smallerUnit inUnit:biggerUnit forAT:at); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); if (calendar->_cal) { @@ -604,7 +604,7 @@ static CFRange __CFCalendarGetRangeOfUnit1(CFCalendarRef calendar, CFCalendarUni static CFRange __CFCalendarGetRangeOfUnit2(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) __attribute__((noinline)); static CFRange __CFCalendarGetRangeOfUnit2(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) { - CF_OBJC_FUNCDISPATCH3(CFCalendarGetTypeID(), CFRange, calendar, "_rangeOfUnit:inUnit:forAT:", smallerUnit, biggerUnit, at); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFRange, calendar, _rangeOfUnit:smallerUnit inUnit:biggerUnit forAT:at); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); CFRange range = {kCFNotFound, kCFNotFound}; if (!calendar->_cal) __CFCalendarSetupCal(calendar); @@ -766,17 +766,13 @@ static CFRange __CFCalendarGetRangeOfUnit2(CFCalendarRef calendar, CFCalendarUni } CFRange CFCalendarGetRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) { - if (_CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard)) { return __CFCalendarGetRangeOfUnit2(calendar, smallerUnit, biggerUnit, at); - } else { - return __CFCalendarGetRangeOfUnit1(calendar, smallerUnit, biggerUnit, at); - } } CFIndex CFCalendarGetOrdinalityOfUnit(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) { CFIndex result = kCFNotFound; if (!__validUnits(smallerUnit, biggerUnit)) return result; - CF_OBJC_FUNCDISPATCH3(CFCalendarGetTypeID(), CFIndex, calendar, "_ordinalityOfUnit:inUnit:forAT:", smallerUnit, biggerUnit, at); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), CFIndex, calendar, _ordinalityOfUnit:smallerUnit inUnit:biggerUnit forAT:at); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (!calendar->_cal) __CFCalendarSetupCal(calendar); if (calendar->_cal) { @@ -974,7 +970,7 @@ Boolean _CFCalendarGetComponentDifferenceV(CFCalendarRef calendar, CFAbsoluteTim Boolean CFCalendarComposeAbsoluteTime(CFCalendarRef calendar, /* out */ CFAbsoluteTime *atp, const char *componentDesc, ...) { va_list args; va_start(args, componentDesc); - CF_OBJC_FUNCDISPATCH3(CFCalendarGetTypeID(), Boolean, calendar, "_composeAbsoluteTime:::", atp, componentDesc, args); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), Boolean, calendar, _composeAbsoluteTime:atp :componentDesc :args); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); int idx, cnt = strlen((char *)componentDesc); STACK_BUFFER_DECL(int, vector, cnt); @@ -989,7 +985,7 @@ Boolean CFCalendarComposeAbsoluteTime(CFCalendarRef calendar, /* out */ CFAbsolu Boolean CFCalendarDecomposeAbsoluteTime(CFCalendarRef calendar, CFAbsoluteTime at, const char *componentDesc, ...) { va_list args; va_start(args, componentDesc); - CF_OBJC_FUNCDISPATCH3(CFCalendarGetTypeID(), Boolean, calendar, "_decomposeAbsoluteTime:::", at, componentDesc, args); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), Boolean, calendar, _decomposeAbsoluteTime:at :componentDesc :args); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); int idx, cnt = strlen((char *)componentDesc); STACK_BUFFER_DECL(int *, vector, cnt); @@ -1004,7 +1000,7 @@ Boolean CFCalendarDecomposeAbsoluteTime(CFCalendarRef calendar, CFAbsoluteTime a Boolean CFCalendarAddComponents(CFCalendarRef calendar, /* inout */ CFAbsoluteTime *atp, CFOptionFlags options, const char *componentDesc, ...) { va_list args; va_start(args, componentDesc); - CF_OBJC_FUNCDISPATCH4(CFCalendarGetTypeID(), Boolean, calendar, "_addComponents::::", atp, options, componentDesc, args); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), Boolean, calendar, _addComponents:atp :options :componentDesc :args); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); int idx, cnt = strlen((char *)componentDesc); STACK_BUFFER_DECL(int, vector, cnt); @@ -1019,7 +1015,7 @@ Boolean CFCalendarAddComponents(CFCalendarRef calendar, /* inout */ CFAbsoluteTi Boolean CFCalendarGetComponentDifference(CFCalendarRef calendar, CFAbsoluteTime startingAT, CFAbsoluteTime resultAT, CFOptionFlags options, const char *componentDesc, ...) { va_list args; va_start(args, componentDesc); - CF_OBJC_FUNCDISPATCH5(CFCalendarGetTypeID(), Boolean, calendar, "_diffComponents:::::", startingAT, resultAT, options, componentDesc, args); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), Boolean, calendar, _diffComponents:startingAT :resultAT :options :componentDesc :args); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); int idx, cnt = strlen((char *)componentDesc); STACK_BUFFER_DECL(int *, vector, cnt); @@ -1033,7 +1029,7 @@ Boolean CFCalendarGetComponentDifference(CFCalendarRef calendar, CFAbsoluteTime } Boolean CFCalendarGetTimeRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit, CFAbsoluteTime at, CFAbsoluteTime *startp, CFTimeInterval *tip) { - CF_OBJC_FUNCDISPATCH4(CFCalendarGetTypeID(), Boolean, calendar, "_rangeOfUnit:startTime:interval:forAT:", unit, startp, tip, at); + CF_OBJC_FUNCDISPATCHV(CFCalendarGetTypeID(), Boolean, calendar, _rangeOfUnit:unit startTime:startp interval:tip forAT:at); __CFGenericValidateType(calendar, CFCalendarGetTypeID()); if (kCFCalendarUnitWeekdayOrdinal == unit) return false; if (kCFCalendarUnitWeekday == unit) unit = kCFCalendarUnitDay; diff --git a/CFCalendar.h b/CFCalendar.h index 1751434..8cee565 100644 --- a/CFCalendar.h +++ b/CFCalendar.h @@ -22,7 +22,7 @@ */ /* CFCalendar.h - Copyright (c) 2004-2011, Apple Inc. All rights reserved. + Copyright (c) 2004-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFCALENDAR__) @@ -33,6 +33,7 @@ #include #include +CF_IMPLICIT_BRIDGING_ENABLED CF_EXTERN_C_BEGIN typedef struct __CFCalendar * CFCalendarRef; @@ -77,7 +78,7 @@ CF_EXPORT void CFCalendarSetMinimumDaysInFirstWeek(CFCalendarRef calendar, CFIndex mwd); -enum { +typedef CF_OPTIONS(CFOptionFlags, CFCalendarUnit) { kCFCalendarUnitEra = (1UL << 1), kCFCalendarUnitYear = (1UL << 2), kCFCalendarUnitMonth = (1UL << 3), @@ -88,16 +89,11 @@ enum { kCFCalendarUnitWeek = (1UL << 8) /* CF_DEPRECATED(10_4, 10_7, 2_0, 5_0) */, kCFCalendarUnitWeekday = (1UL << 9), kCFCalendarUnitWeekdayOrdinal = (1UL << 10), -#if MAC_OS_X_VERSION_10_6 <= MAC_OS_X_VERSION_MAX_ALLOWED || __IPHONE_4_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED - kCFCalendarUnitQuarter = (1UL << 11), -#endif -#if MAC_OS_X_VERSION_10_7 <= MAC_OS_X_VERSION_MAX_ALLOWED || __IPHONE_5_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED - kCFCalendarUnitWeekOfMonth = (1UL << 12), - kCFCalendarUnitWeekOfYear = (1UL << 13), - kCFCalendarUnitYearForWeekOfYear = (1UL << 14), -#endif + kCFCalendarUnitQuarter CF_ENUM_AVAILABLE(10_6, 4_0) = (1UL << 11), + kCFCalendarUnitWeekOfMonth CF_ENUM_AVAILABLE(10_7, 5_0) = (1UL << 12), + kCFCalendarUnitWeekOfYear CF_ENUM_AVAILABLE(10_7, 5_0) = (1UL << 13), + kCFCalendarUnitYearForWeekOfYear CF_ENUM_AVAILABLE(10_7, 5_0) = (1UL << 14), }; -typedef CFOptionFlags CFCalendarUnit; CF_EXPORT CFRange CFCalendarGetMinimumRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit); @@ -133,6 +129,7 @@ Boolean CFCalendarGetComponentDifference(CFCalendarRef calendar, CFAbsoluteTime CF_EXTERN_C_END +CF_IMPLICIT_BRIDGING_DISABLED #endif /* ! __COREFOUNDATION_CFCALENDAR__ */ diff --git a/CFCharacterSet.c b/CFCharacterSet.c index 5e45395..771ee4d 100644 --- a/CFCharacterSet.c +++ b/CFCharacterSet.c @@ -22,7 +22,7 @@ */ /* CFCharacterSet.c - Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Copyright (c) 1999-2012, Apple Inc. All rights reserved. Responsibility: Aki Inoue */ @@ -1484,7 +1484,7 @@ CFCharacterSetRef CFCharacterSetCreateWithBitmapRepresentation(CFAllocatorRef al CFCharacterSetRef CFCharacterSetCreateInvertedSet(CFAllocatorRef alloc, CFCharacterSetRef theSet) { CFMutableCharacterSetRef cset; - CF_OBJC_FUNCDISPATCH0(__kCFCharacterSetTypeID, CFCharacterSetRef , theSet, "invertedSet"); + CF_OBJC_FUNCDISPATCHV(__kCFCharacterSetTypeID, CFCharacterSetRef , (NSCharacterSet *)theSet, invertedSet); cset = CFCharacterSetCreateMutableCopy(alloc, theSet); CFCharacterSetInvert(cset); @@ -1508,7 +1508,7 @@ CFMutableCharacterSetRef CFCharacterSetCreateMutable(CFAllocatorRef allocator) { static CFMutableCharacterSetRef __CFCharacterSetCreateCopy(CFAllocatorRef alloc, CFCharacterSetRef theSet, bool isMutable) { CFMutableCharacterSetRef cset; - CF_OBJC_FUNCDISPATCH0(__kCFCharacterSetTypeID, CFMutableCharacterSetRef , theSet, "mutableCopy"); + CF_OBJC_FUNCDISPATCHV(__kCFCharacterSetTypeID, CFMutableCharacterSetRef , (NSCharacterSet *)theSet, mutableCopy); __CFGenericValidateType(theSet, __kCFCharacterSetTypeID); @@ -1606,7 +1606,7 @@ Boolean CFCharacterSetIsCharacterMember(CFCharacterSetRef theSet, UniChar theCha Boolean isInverted; Boolean result = false; - CF_OBJC_FUNCDISPATCH1(__kCFCharacterSetTypeID, Boolean, theSet, "longCharacterIsMember:", theChar); + CF_OBJC_FUNCDISPATCHV(__kCFCharacterSetTypeID, Boolean, (NSCharacterSet *)theSet, longCharacterIsMember:(UTF32Char)theChar); __CFGenericValidateType(theSet, __kCFCharacterSetTypeID); @@ -1649,7 +1649,7 @@ Boolean CFCharacterSetIsLongCharacterMember(CFCharacterSetRef theSet, UTF32Char Boolean isInverted; Boolean result = false; - CF_OBJC_FUNCDISPATCH1(__kCFCharacterSetTypeID, Boolean, theSet, "longCharacterIsMember:", theChar); + CF_OBJC_FUNCDISPATCHV(__kCFCharacterSetTypeID, Boolean, (NSCharacterSet *)theSet, longCharacterIsMember:(UTF32Char)theChar); __CFGenericValidateType(theSet, __kCFCharacterSetTypeID); @@ -1715,7 +1715,7 @@ Boolean CFCharacterSetIsSurrogatePairMember(CFCharacterSetRef theSet, UniChar su static inline CFCharacterSetRef __CFCharacterSetGetExpandedSetForNSCharacterSet(const void *characterSet) { - CF_OBJC_FUNCDISPATCH0(__kCFCharacterSetTypeID, CFCharacterSetRef , characterSet, "_expandedCFCharacterSet"); + CF_OBJC_FUNCDISPATCHV(__kCFCharacterSetTypeID, CFCharacterSetRef , (NSCharacterSet *)characterSet, _expandedCFCharacterSet); return NULL; } @@ -1818,7 +1818,7 @@ Boolean CFCharacterSetIsSupersetOfSet(CFCharacterSetRef theSet, CFCharacterSetRe Boolean CFCharacterSetHasMemberInPlane(CFCharacterSetRef theSet, CFIndex thePlane) { Boolean isInverted = __CFCSetIsInverted(theSet); - CF_OBJC_FUNCDISPATCH1(__kCFCharacterSetTypeID, Boolean, theSet, "hasMemberInPlane:", thePlane); + CF_OBJC_FUNCDISPATCHV(__kCFCharacterSetTypeID, Boolean, (NSCharacterSet *)theSet, hasMemberInPlane:(uint8_t)thePlane); if (__CFCSetIsEmpty(theSet)) { return (isInverted ? TRUE : FALSE); @@ -1903,7 +1903,7 @@ CFDataRef CFCharacterSetCreateBitmapRepresentation(CFAllocatorRef alloc, CFChara int length; bool isAnnexInverted; - CF_OBJC_FUNCDISPATCH0(__kCFCharacterSetTypeID, CFDataRef , theSet, "_retainedBitmapRepresentation"); + CF_OBJC_FUNCDISPATCHV(__kCFCharacterSetTypeID, CFDataRef , (NSCharacterSet *)theSet, _retainedBitmapRepresentation); __CFGenericValidateType(theSet, __kCFCharacterSetTypeID); @@ -2059,7 +2059,7 @@ CFDataRef CFCharacterSetCreateBitmapRepresentation(CFAllocatorRef alloc, CFChara /*** MutableCharacterSet functions ***/ void CFCharacterSetAddCharactersInRange(CFMutableCharacterSetRef theSet, CFRange theRange) { - CF_OBJC_FUNCDISPATCH1(__kCFCharacterSetTypeID, void, theSet, "addCharactersInRange:", theRange); + CF_OBJC_FUNCDISPATCHV(__kCFCharacterSetTypeID, void, (NSMutableCharacterSet *)theSet, addCharactersInRange:NSMakeRange(theRange.location, theRange.length)); __CFCSetValidateTypeAndMutability(theSet, __PRETTY_FUNCTION__); __CFCSetValidateRange(theRange, __PRETTY_FUNCTION__); @@ -2078,7 +2078,7 @@ void CFCharacterSetAddCharactersInRange(CFMutableCharacterSetRef theSet, CFRange CFIndex length = __CFCSetRangeLength(theSet); if (firstChar == theRange.location) { - __CFCSetPutRangeLength(theSet, __CFMin(length, theRange.length)); + __CFCSetPutRangeLength(theSet, __CFMax(length, theRange.length)); __CFCSetPutHasHashValue(theSet, false); return; } else if (firstChar < theRange.location && theRange.location <= firstChar + length) { @@ -2117,7 +2117,7 @@ void CFCharacterSetAddCharactersInRange(CFMutableCharacterSetRef theSet, CFRange } void CFCharacterSetRemoveCharactersInRange(CFMutableCharacterSetRef theSet, CFRange theRange) { - CF_OBJC_FUNCDISPATCH1(__kCFCharacterSetTypeID, void, theSet, "removeCharactersInRange:", theRange); + CF_OBJC_FUNCDISPATCHV(__kCFCharacterSetTypeID, void, (NSMutableCharacterSet *)theSet, removeCharactersInRange:NSMakeRange(theRange.location, theRange.length)); __CFCSetValidateTypeAndMutability(theSet, __PRETTY_FUNCTION__); __CFCSetValidateRange(theRange, __PRETTY_FUNCTION__); @@ -2184,7 +2184,7 @@ void CFCharacterSetAddCharactersInString(CFMutableCharacterSetRef theSet, CFStr CFIndex length; BOOL hasSurrogate = NO; - CF_OBJC_FUNCDISPATCH1(__kCFCharacterSetTypeID, void, theSet, "addCharactersInString:", theString); + CF_OBJC_FUNCDISPATCHV(__kCFCharacterSetTypeID, void, (NSMutableCharacterSet *)theSet, addCharactersInString:(NSString *)theString); __CFCSetValidateTypeAndMutability(theSet, __PRETTY_FUNCTION__); @@ -2268,7 +2268,7 @@ void CFCharacterSetRemoveCharactersInString(CFMutableCharacterSetRef theSet, CFS CFIndex length; BOOL hasSurrogate = NO; - CF_OBJC_FUNCDISPATCH1(__kCFCharacterSetTypeID, void, theSet, "removeCharactersInString:", theString); + CF_OBJC_FUNCDISPATCHV(__kCFCharacterSetTypeID, void, (NSMutableCharacterSet *)theSet, removeCharactersInString:(NSString *)theString); __CFCSetValidateTypeAndMutability(theSet, __PRETTY_FUNCTION__); @@ -2344,7 +2344,7 @@ void CFCharacterSetRemoveCharactersInString(CFMutableCharacterSetRef theSet, CFS void CFCharacterSetUnion(CFMutableCharacterSetRef theSet, CFCharacterSetRef theOtherSet) { CFCharacterSetRef expandedSet = NULL; - CF_OBJC_FUNCDISPATCH1(__kCFCharacterSetTypeID, void, theSet, "formUnionWithCharacterSet:", theOtherSet); + CF_OBJC_FUNCDISPATCHV(__kCFCharacterSetTypeID, void, (NSMutableCharacterSet *)theSet, formUnionWithCharacterSet:(NSCharacterSet *)theOtherSet); __CFCSetValidateTypeAndMutability(theSet, __PRETTY_FUNCTION__); @@ -2467,7 +2467,7 @@ void CFCharacterSetUnion(CFMutableCharacterSetRef theSet, CFCharacterSetRef theO void CFCharacterSetIntersect(CFMutableCharacterSetRef theSet, CFCharacterSetRef theOtherSet) { CFCharacterSetRef expandedSet = NULL; - CF_OBJC_FUNCDISPATCH1(__kCFCharacterSetTypeID, void, theSet, "formIntersectionWithCharacterSet:", theOtherSet); + CF_OBJC_FUNCDISPATCHV(__kCFCharacterSetTypeID, void, (NSMutableCharacterSet *)theSet, formIntersectionWithCharacterSet:(NSCharacterSet *)theOtherSet); __CFCSetValidateTypeAndMutability(theSet, __PRETTY_FUNCTION__); @@ -2648,7 +2648,7 @@ void CFCharacterSetIntersect(CFMutableCharacterSetRef theSet, CFCharacterSetRef void CFCharacterSetInvert(CFMutableCharacterSetRef theSet) { - CF_OBJC_FUNCDISPATCH0(__kCFCharacterSetTypeID, void, theSet, "invert"); + CF_OBJC_FUNCDISPATCHV(__kCFCharacterSetTypeID, void, (NSMutableCharacterSet *)theSet, invert); __CFCSetValidateTypeAndMutability(theSet, __PRETTY_FUNCTION__); diff --git a/CFCharacterSet.h b/CFCharacterSet.h index 769db15..f499893 100644 --- a/CFCharacterSet.h +++ b/CFCharacterSet.h @@ -22,7 +22,7 @@ */ /* CFCharacterSet.h - Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Copyright (c) 1999-2012, Apple Inc. All rights reserved. */ /*! @@ -57,6 +57,7 @@ #include #include +CF_IMPLICIT_BRIDGING_ENABLED CF_EXTERN_C_BEGIN /*! @@ -76,7 +77,7 @@ typedef struct __CFCharacterSet * CFMutableCharacterSetRef; Type of the predefined CFCharacterSet selector values. */ -enum { +typedef CF_ENUM(CFIndex, CFCharacterSetPredefinedSet) { kCFCharacterSetControl = 1, /* Control character set (Unicode General Category Cc and Cf) */ kCFCharacterSetWhitespace, /* Whitespace character set (Unicode General Category Zs and U0009 CHARACTER TABULATION) */ kCFCharacterSetWhitespaceAndNewline, /* Whitespace and Newline character set (Unicode General Category Z*, U000A ~ U000D, and U0085) */ @@ -90,12 +91,9 @@ enum { kCFCharacterSetPunctuation, /* Punctuation character set (Unicode General Category P*) */ kCFCharacterSetCapitalizedLetter = 13, /* Titlecase character set (Unicode General Category Lt) */ kCFCharacterSetSymbol = 14, /* Symbol character set (Unicode General Category S*) */ -#if MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED - kCFCharacterSetNewline = 15, /* Newline character set (U000A ~ U000D, U0085, U2028, and U2029) */ -#endif + kCFCharacterSetNewline CF_ENUM_AVAILABLE(10_5, 2_0) = 15, /* Newline character set (U000A ~ U000D, U0085, U2028, and U2029) */ kCFCharacterSetIllegal = 12/* Illegal character set */ }; -typedef CFIndex CFCharacterSetPredefinedSet; /*! @function CFCharacterSetGetTypeID @@ -401,6 +399,7 @@ CF_EXPORT void CFCharacterSetInvert(CFMutableCharacterSetRef theSet); CF_EXTERN_C_END +CF_IMPLICIT_BRIDGING_DISABLED #endif /* ! __COREFOUNDATION_CFCHARACTERSET__ */ diff --git a/CFCharacterSetBitmaps.bitmap b/CFCharacterSetBitmaps.bitmap index cd0af97b1f1f211aecbc1f7fde28ec011ef8611f..a80d388ad54d384ea2316beafe696864e06d7221 100644 GIT binary patch delta 2601 zcmbW3e{fXQ7036S``+7SNwO>XvCRguyTLFKC`H3qO^|GwH7ZpB?II&WHyO3XnIbct zI*wBEf}kQp<@qp283u)^;-DkZ9l1qpvl}7NsU6lj3u!*g(z4pj4;uHvN%P5H%yxAJEolR0HhdX*-o(jfb<<;DnVn6mnB_QYULKhO zZPcRRz46}2M(}tXa(dp&vglq7Z;kJ1K2rz*O7`P=^JKWdoEyDH8|V`AbaO+rvPk$i zbDN7_%iI&agIU%}3YB3X{_};s<0!M4jWexZJL5&MkH9525SB3i*K#-@1|Xbl%b!3l zlDB}7B+BUEhK*E-oad&S>c!#X5B6f&39)U*@PK>GXB|5`1_qW|Lzd_G5KmO# zRE)o_`@(c2qfCf@l32^oF&MvRUlx3xo#&ZRa8e*6>A)K)4wu`n-U47$Ve&T z3GFg!mER8PP&uDd4_h=v)|~e>!aEs6VQVc?7%AFdBn&6`yqTbWel@)7;rCq zNm~&wKrPK+D6pkH3qU{nj!+d6uc)vm;&M)EeA)s815H8HAq z9>&w3R%1E%=!Mm|j=bAZHPz)F`S(rq#6$RZk>JJ-T*iCX;69M+*75xh<5Ca3c_jvD z<96m1k^9}UjuoN@DYX7sTufc9;#BXq-bkr!=;YyT_%hJ1o*R^W z4-e-uBCm)u;P}|G4v4liiFPEhb}S41Nt^?Ws=INeKw^70&K9>t%>5Y`Eo?f_v2Gkk zk$vcQTK0XjJJ=%r*L{d!Zk)SA^8Ak8VrjHJUw7r_Jea6VsEniD{EvuaY+%#J9#^>MIyWU9Md;xG|+Y9mNr+CZv(9_4HcO~_8qejO!GnaWZEK1&k3fG3Po&Ds( zO;02uc^Yf%9MXZUtb&dXVCI%Otyxp9`$!;xS!SHq!DN+%z++DttzQEvfvjdql_jSRoYfGkt7u^4NZr zR*lrFGFa6ez9E0|AZ-XKL2+$f4k>lu;hpWO56$^y|Bwe)_`8=XZ(Mzm?WC$)f#?nWZBt5M8K0O{7O1WZi&8bXdGa;o_Gv$Co`0H=a`XP6 z`pKnA{rxM>N*$=(-K-k*AY|H4!!gkKtLpS)k7!!XjGS3|`Xv)kQFyf6%YKRU|$>#B`l@ zoKmMLEaGxdCZd+ou~X``ICGJaoW$pyR!3y)#Hfrhdy@pU{6Su;g;>)iB-TG3><@&x zg54F`7gKVfo@&$%0(8ql#5Ld@5m6E%daVpCuc;qJpwoN4rlzCX5|~M$7*xtg u{y)x0&81Z_sFg$&nr~#nTx2T=G(%@j`gf~Vo>SZ(6zZtfa(qxrSAPxm8*f+u delta 2013 zcmbW2e^69a6vy8=_r14(z+%X6Wfv3%#dHhD5=@prDw|T%^|u9#S>sqb)5J8Ey7;SX zhH`t-nHf=!m#ADBOg*L@GfGM#C%MZ`JLSMN@6GTAQsPWd-8?9qKo8rxy8ZTH_s@-#`R0&EsbOQY$-OR_>+ zyXB;)FZ*M9t9DOAUri|U;VK1>Xu-S=zEXzs-~;a{E3J=%Q4Ay(Ke=5=M6pL}7@cdA zBgpTUqdh@cd_sj$dxg&f<#rOElm}Z?@qnK%fYTuRMSZBHP#r}V3t_sb__!j-qO^87 z-dHTw$$Ui-JTw?B4sB1lgT8gaLTYLQ8_%5u)sfV)7E{HkR}-i!7oFnUW`#Gnp*SBV zYWhpb-0p`aBP}(N|9TdF$-K(~T?MRx9NLC>9~x*3LxBSwU?_Od8Rg0-fZzfMUBF;B z*!c$xTS4NH7OZ&?599k;ppWD5UKr?b9GWz6K|^OB37T3`#Xq;>)IJ=DrQ^LkaKXbH z;o@?p~yX4AL|>@s3fcETX~U=1dT zqJOalH$txlug4mCJx3p{#qa3i23*3M*I^@2ft%&>qZ{x=D_tmKHrlj<#fWp0BWUS% zT%pyM&!C_eE!^qFy&w)=jC^J_4j&q;_8Nr}Eg)VNo7AG~Eu!Iu(XIgI(3uiUq3!^V z1*D9__>K@`$6=g^`4TxAafsICOyQz4M}sNAq(-z`B(n?6zMR7kH6jAEY86wK(W8r5 zf{B?nsW>59*O__nfI@C?>-uVGb^kDPGT#_&TFfT!rY8JXC(jPy6RP!^kv(k*{aduA zP@iZ<3#anJ(|Bw^xkR4bh9|&tJccY6g>Kz4&J|^;yxYfV+|_|E^ojRbeYuHxD*e2L zMQfLxR`NHY%+=diA>?$L_o9|RuqPZ`^2NUUn(<2RZzdV<4@A7V|r?$CBpekzdjDCOq1=fn)as2xx!s#-s^^TG+2}Q$r19w z38JV^6~zlX%4?r5%jDqiKFI#E`pF znFBriOs8@zT3C`1PrJI6Y&zvqb1Cw=GJ@hjwehLfmFh@exHmGfE=B!4bKvlv0<{Ie zO(zP~Red>Rc>>9%Q #include #include -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX #include #include -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif @@ -70,7 +67,9 @@ typedef struct { CONST_STRING_DECL(kCFStreamPropertyFileCurrentOffset, "kCFStreamPropertyFileCurrentOffset"); - +#if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI +CONST_STRING_DECL(_kCFStreamPropertyFileNativeHandle, "_kCFStreamPropertyFileNativeHandle"); +#endif #ifdef REAL_FILE_SCHEDULING extern void _CFFileDescriptorInduceFakeReadCallBack(CFFileDescriptorRef); @@ -101,11 +100,9 @@ static Boolean constructFD(_CFFileStreamContext *fileStream, CFStreamError *erro wchar_t path[CFMaxPathSize]; flags |= (_O_BINARY|_O_NOINHERIT); if (_CFURLGetWideFileSystemRepresentation(fileStream->url, TRUE, path, CFMaxPathSize) == FALSE) -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI char path[CFMaxPathSize]; if (CFURLGetFileSystemRepresentation(fileStream->url, TRUE, (UInt8 *)path, CFMaxPathSize) == FALSE) -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif { error->error = ENOENT; @@ -118,7 +115,7 @@ static Boolean constructFD(_CFFileStreamContext *fileStream, CFStreamError *erro } do { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI fileStream->fd = open((const char *)path, flags, 0666); #elif DEPLOYMENT_TARGET_WINDOWS fileStream->fd = _wopen(path, flags, 0666); @@ -438,7 +435,14 @@ static CFTypeRef fileCopyProperty(struct _CFStream *stream, CFStringRef property if (fileStream->offset != -1) { result = CFNumberCreate(CFGetAllocator((CFTypeRef)stream), kCFNumberSInt64Type, &(fileStream->offset)); } - } +#if DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI + } else if (CFEqual(propertyName, _kCFStreamPropertyFileNativeHandle)) { + int fd = fileStream->fd; + if (fd != -1) { + result = CFDataCreate(CFGetAllocator((CFTypeRef) stream), (const uint8_t *)&fd, sizeof(fd)); + } +#endif + } return result; } diff --git a/CFData.c b/CFData.c index c1775c5..b6528f5 100644 --- a/CFData.c +++ b/CFData.c @@ -22,7 +22,7 @@ */ /* CFData.c - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. Responsibility: Kevin Perry */ @@ -30,11 +30,8 @@ #include #include "CFInternal.h" #include -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -#include -#elif DEPLOYMENT_TARGET_WINDOWS -#include // For GetSystemInfo() -#endif + + #if __LP64__ #define CFDATA_MAX_SIZE ((1ULL << 42) - 1) @@ -42,7 +39,8 @@ #define CFDATA_MAX_SIZE ((1ULL << 31) - 1) #endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI +#import CF_INLINE unsigned long __CFPageSize() { return vm_page_size; } #elif DEPLOYMENT_TARGET_WINDOWS CF_INLINE unsigned long __CFPageSize() { @@ -176,14 +174,14 @@ CF_INLINE CFIndex __CFDataRoundUpCapacity(CFIndex capacity) { return 16; } else if (capacity < LOW_THRESHOLD) { /* Up to 4x */ - int idx = flsl(capacity); - return (1 << (idx + ((idx % 2 == 0) ? 0 : 1))); + long idx = flsl(capacity); + return (1L << (long)(idx + ((idx % 2 == 0) ? 0 : 1))); } else if (capacity < HIGH_THRESHOLD) { /* Up to 2x */ - return (1 << flsl(capacity)); + return (1L << (long)flsl(capacity)); } else { /* Round up to next multiple of CHUNK_SIZE */ - unsigned long newCapacity = CHUNK_SIZE * (1+(capacity >> (flsl(CHUNK_SIZE)-1))); + unsigned long newCapacity = CHUNK_SIZE * (1+(capacity >> ((long)flsl(CHUNK_SIZE)-1))); return __CFMin(newCapacity, CFDATA_MAX_SIZE); } } @@ -491,27 +489,27 @@ CFMutableDataRef CFDataCreateMutableCopy(CFAllocatorRef allocator, CFIndex capac } CFIndex CFDataGetLength(CFDataRef data) { - CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID, CFIndex, data, "length"); + CF_OBJC_FUNCDISPATCHV(__kCFDataTypeID, CFIndex, (NSData *)data, length); __CFGenericValidateType(data, __kCFDataTypeID); return __CFDataLength(data); } const uint8_t *CFDataGetBytePtr(CFDataRef data) { - CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID, const uint8_t *, data, "bytes"); + CF_OBJC_FUNCDISPATCHV(__kCFDataTypeID, const uint8_t *, (NSData *)data, bytes); __CFGenericValidateType(data, __kCFDataTypeID); // compaction: if inline, always do the computation. return __CFDataBytesInline(data) ? (uint8_t *)__CFDataInlineBytesPtr(data) : data->_bytes; } uint8_t *CFDataGetMutableBytePtr(CFMutableDataRef data) { - CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID, uint8_t *, data, "mutableBytes"); + CF_OBJC_FUNCDISPATCHV(__kCFDataTypeID, uint8_t *, (NSMutableData *)data, mutableBytes); CFAssert1(__CFDataIsMutable(data), __kCFLogAssertion, "%s(): data is immutable", __PRETTY_FUNCTION__); // compaction: if inline, always do the computation. return __CFDataBytesInline(data) ? (uint8_t *)__CFDataInlineBytesPtr(data) : data->_bytes; } void CFDataGetBytes(CFDataRef data, CFRange range, uint8_t *buffer) { - CF_OBJC_FUNCDISPATCH2(__kCFDataTypeID, void, data, "getBytes:range:", buffer, range); + CF_OBJC_FUNCDISPATCHV(__kCFDataTypeID, void, (NSData *)data, getBytes:(void *)buffer range:NSMakeRange(range.location, range.length)); __CFDataValidateRange(data, range, __PRETTY_FUNCTION__); memmove(buffer, CFDataGetBytePtr(data) + range.location, range.length); } @@ -556,7 +554,7 @@ static void __CFDataGrow(CFMutableDataRef data, CFIndex numNewValues, Boolean cl void CFDataSetLength(CFMutableDataRef data, CFIndex newLength) { CFIndex oldLength, capacity; Boolean isGrowable; - CF_OBJC_FUNCDISPATCH1(__kCFDataTypeID, void, data, "setLength:", newLength); + CF_OBJC_FUNCDISPATCHV(__kCFDataTypeID, void, (NSMutableData *)data, setLength:(NSUInteger)newLength); CFAssert1(__CFDataIsMutable(data), __kCFLogAssertion, "%s(): data is immutable", __PRETTY_FUNCTION__); oldLength = __CFDataLength(data); capacity = __CFDataCapacity(data); @@ -585,26 +583,26 @@ void CFDataSetLength(CFMutableDataRef data, CFIndex newLength) { } void CFDataIncreaseLength(CFMutableDataRef data, CFIndex extraLength) { - CF_OBJC_FUNCDISPATCH1(__kCFDataTypeID, void, data, "increaseLengthBy:", extraLength); + CF_OBJC_FUNCDISPATCHV(__kCFDataTypeID, void, (NSMutableData *)data, increaseLengthBy:(NSUInteger)extraLength); CFAssert1(__CFDataIsMutable(data), __kCFLogAssertion, "%s(): data is immutable", __PRETTY_FUNCTION__); if (extraLength < 0) HALT; // Avoid integer overflow. CFDataSetLength(data, __CFDataLength(data) + extraLength); } void CFDataAppendBytes(CFMutableDataRef data, const uint8_t *bytes, CFIndex length) { - CF_OBJC_FUNCDISPATCH2(__kCFDataTypeID, void, data, "appendBytes:length:", bytes, length); + CF_OBJC_FUNCDISPATCHV(__kCFDataTypeID, void, (NSMutableData *)data, appendBytes:(const void *)bytes length:(NSUInteger)length); CFAssert1(__CFDataIsMutable(data), __kCFLogAssertion, "%s(): data is immutable", __PRETTY_FUNCTION__); CFDataReplaceBytes(data, CFRangeMake(__CFDataLength(data), 0), bytes, length); } void CFDataDeleteBytes(CFMutableDataRef data, CFRange range) { - CF_OBJC_FUNCDISPATCH3(__kCFDataTypeID, void, data, "replaceBytesInRange:withBytes:length:", range, NULL, 0); + CF_OBJC_FUNCDISPATCHV(__kCFDataTypeID, void, (NSMutableData *)data, replaceBytesInRange:NSMakeRange(range.location, range.length) withBytes:NULL length:0); CFAssert1(__CFDataIsMutable(data), __kCFLogAssertion, "%s(): data is immutable", __PRETTY_FUNCTION__); CFDataReplaceBytes(data, range, NULL, 0); } void CFDataReplaceBytes(CFMutableDataRef data, CFRange range, const uint8_t *newBytes, CFIndex newLength) { - CF_OBJC_FUNCDISPATCH3(__kCFDataTypeID, void, data, "replaceBytesInRange:withBytes:length:", range, newBytes, newLength); + CF_OBJC_FUNCDISPATCHV(__kCFDataTypeID, void, (NSMutableData *)data, replaceBytesInRange:NSMakeRange(range.location, range.length) withBytes:(const void *)newBytes length:(NSUInteger)newLength); __CFGenericValidateType(data, __kCFDataTypeID); __CFDataValidateRange(data, range, __PRETTY_FUNCTION__); CFAssert1(__CFDataIsMutable(data), __kCFLogAssertion, "%s(): data is immutable", __PRETTY_FUNCTION__); diff --git a/CFData.h b/CFData.h index 2283a6d..8647e6e 100644 --- a/CFData.h +++ b/CFData.h @@ -22,7 +22,7 @@ */ /* CFData.h - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFDATA__) @@ -30,6 +30,7 @@ #include +CF_IMPLICIT_BRIDGING_ENABLED CF_EXTERN_C_BEGIN typedef const struct __CFData * CFDataRef; @@ -81,18 +82,16 @@ void CFDataReplaceBytes(CFMutableDataRef theData, CFRange range, const UInt8 *ne CF_EXPORT void CFDataDeleteBytes(CFMutableDataRef theData, CFRange range); -#if MAC_OS_X_VERSION_10_6 <= MAC_OS_X_VERSION_MAX_ALLOWED || __IPHONE_4_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED -enum { +typedef CF_OPTIONS(CFOptionFlags, CFDataSearchFlags) { kCFDataSearchBackwards = 1UL << 0, kCFDataSearchAnchored = 1UL << 1 -}; -#endif -typedef CFOptionFlags CFDataSearchFlags; +} CF_ENUM_AVAILABLE(10_6, 4_0); CF_EXPORT CFRange CFDataFind(CFDataRef theData, CFDataRef dataToFind, CFRange searchRange, CFDataSearchFlags compareOptions) CF_AVAILABLE(10_6, 4_0); CF_EXTERN_C_END +CF_IMPLICIT_BRIDGING_DISABLED #endif /* ! __COREFOUNDATION_CFDATA__ */ diff --git a/CFDate.c b/CFDate.c index 01e6e86..766ebda 100644 --- a/CFDate.c +++ b/CFDate.c @@ -22,7 +22,7 @@ */ /* CFDate.c - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ @@ -34,19 +34,15 @@ #include #include "CFInternal.h" #include -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX #include -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif +#define DEFINE_CFDATE_FUNCTIONS 1 /* cjk: The Julian Date for the reference date is 2451910.5, I think, in case that's ever useful. */ -#define DEFINE_CFDATE_FUNCTIONS 1 - #if DEFINE_CFDATE_FUNCTIONS const CFTimeInterval kCFAbsoluteTimeIntervalSince1970 = 978307200.0L; @@ -66,23 +62,15 @@ __private_extern__ CFTimeInterval __CFTSRToTimeInterval(int64_t tsr) { CFAbsoluteTime CFAbsoluteTimeGetCurrent(void) { CFAbsoluteTime ret; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX struct timeval tv; gettimeofday(&tv, NULL); ret = (CFTimeInterval)tv.tv_sec - kCFAbsoluteTimeIntervalSince1970; ret += (1.0E-6 * (CFTimeInterval)tv.tv_usec); -#elif DEPLOYMENT_TARGET_WINDOWS - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - ret = _CFAbsoluteTimeFromFileTime(&ft); -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif return ret; } __private_extern__ void __CFDateInitialize(void) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI struct mach_timebase_info info; mach_timebase_info(&info); __CFTSRRate = (1.0E9 / (double)info.numer) * (double)info.denom; @@ -102,12 +90,11 @@ __private_extern__ void __CFDateInitialize(void) { __CFTSRRate = res.tv_sec + (1000000000 * res.tv_nsec); __CF1_TSRRate = 1.0 / __CFTSRRate; #else -#error Unknown or unspecified DEPLOYMENT_TARGET +#error Unable to initialize date #endif CFDateGetTypeID(); // cause side-effects } -#if 1 struct __CFDate { CFRuntimeBase _base; CFAbsoluteTime _time; /* immutable */ @@ -162,27 +149,26 @@ CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at) { } CFTimeInterval CFDateGetAbsoluteTime(CFDateRef date) { - CF_OBJC_FUNCDISPATCH0(CFDateGetTypeID(), CFTimeInterval, date, "timeIntervalSinceReferenceDate"); + CF_OBJC_FUNCDISPATCHV(CFDateGetTypeID(), CFTimeInterval, (NSDate *)date, timeIntervalSinceReferenceDate); __CFGenericValidateType(date, CFDateGetTypeID()); return date->_time; } CFTimeInterval CFDateGetTimeIntervalSinceDate(CFDateRef date, CFDateRef otherDate) { - CF_OBJC_FUNCDISPATCH1(CFDateGetTypeID(), CFTimeInterval, date, "timeIntervalSinceDate:", otherDate); + CF_OBJC_FUNCDISPATCHV(CFDateGetTypeID(), CFTimeInterval, (NSDate *)date, timeIntervalSinceDate:(NSDate *)otherDate); __CFGenericValidateType(date, CFDateGetTypeID()); __CFGenericValidateType(otherDate, CFDateGetTypeID()); return date->_time - otherDate->_time; } CFComparisonResult CFDateCompare(CFDateRef date, CFDateRef otherDate, void *context) { - CF_OBJC_FUNCDISPATCH1(CFDateGetTypeID(), CFComparisonResult, date, "compare:", otherDate); + CF_OBJC_FUNCDISPATCHV(CFDateGetTypeID(), CFComparisonResult, (NSDate *)date, compare:(NSDate *)otherDate); __CFGenericValidateType(date, CFDateGetTypeID()); __CFGenericValidateType(otherDate, CFDateGetTypeID()); if (date->_time < otherDate->_time) return kCFCompareLessThan; if (date->_time > otherDate->_time) return kCFCompareGreaterThan; return kCFCompareEqualTo; } -#endif #endif @@ -283,17 +269,19 @@ Boolean CFGregorianDateIsValid(CFGregorianDate gdate, CFOptionFlags unitFlags) { CFAbsoluteTime CFGregorianDateGetAbsoluteTime(CFGregorianDate gdate, CFTimeZoneRef tz) { CFAbsoluteTime at; - CFTimeInterval offset0, offset1; + at = 86400.0 * __CFAbsoluteFromYMD(gdate.year - 2001, gdate.month, gdate.day); + at += 3600.0 * gdate.hour + 60.0 * gdate.minute + gdate.second; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX if (NULL != tz) { __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); } - at = 86400.0 * __CFAbsoluteFromYMD(gdate.year - 2001, gdate.month, gdate.day); - at += 3600.0 * gdate.hour + 60.0 * gdate.minute + gdate.second; + CFTimeInterval offset0, offset1; if (NULL != tz) { offset0 = CFTimeZoneGetSecondsFromGMT(tz, at); offset1 = CFTimeZoneGetSecondsFromGMT(tz, at - offset0); at -= offset1; } +#endif return at; } @@ -302,10 +290,14 @@ CFGregorianDate CFAbsoluteTimeGetGregorianDate(CFAbsoluteTime at, CFTimeZoneRef int64_t absolute, year; int8_t month, day; CFAbsoluteTime fixedat; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX if (NULL != tz) { __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); } fixedat = at + (NULL != tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0); +#else + fixedat = at; +#endif absolute = (int64_t)floor(fixedat / 86400.0); __CFYMDFromAbsolute(absolute, &year, &month, &day); if (INT32_MAX - 2001 < year) year = INT32_MAX - 2001; @@ -326,10 +318,12 @@ CFAbsoluteTime CFAbsoluteTimeAddGregorianUnits(CFAbsoluteTime at, CFTimeZoneRef CFAbsoluteTime candidate_at0, candidate_at1; uint8_t monthdays; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX if (NULL != tz) { __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); } - +#endif + /* Most people seem to expect years, then months, then days, etc. to be added in that order. Thus, 27 April + (4 days, 1 month) = 31 May, and not 1 June. This is also relatively predictable. @@ -440,10 +434,14 @@ CFGregorianUnits CFAbsoluteTimeGetDifferenceAsGregorianUnits(CFAbsoluteTime at1, SInt32 CFAbsoluteTimeGetDayOfWeek(CFAbsoluteTime at, CFTimeZoneRef tz) { int64_t absolute; CFAbsoluteTime fixedat; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX if (NULL != tz) { __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); } fixedat = at + (NULL != tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0); +#else + fixedat = at; +#endif absolute = (int64_t)floor(fixedat / 86400.0); return (absolute < 0) ? ((absolute + 1) % 7 + 7) : (absolute % 7 + 1); /* Monday = 1, etc. */ } @@ -452,10 +450,14 @@ SInt32 CFAbsoluteTimeGetDayOfYear(CFAbsoluteTime at, CFTimeZoneRef tz) { CFAbsoluteTime fixedat; int64_t absolute, year; int8_t month, day; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX if (NULL != tz) { __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); } fixedat = at + (NULL != tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0); +#else + fixedat = at; +#endif absolute = (int64_t)floor(fixedat / 86400.0); __CFYMDFromAbsolute(absolute, &year, &month, &day); return __CFDaysBeforeMonth(month, year, isleap(year)) + day; @@ -466,10 +468,14 @@ SInt32 CFAbsoluteTimeGetWeekOfYear(CFAbsoluteTime at, CFTimeZoneRef tz) { int64_t absolute, year; int8_t month, day; CFAbsoluteTime fixedat; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX if (NULL != tz) { __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); } fixedat = at + (NULL != tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0); +#else + fixedat = at; +#endif absolute = (int64_t)floor(fixedat / 86400.0); __CFYMDFromAbsolute(absolute, &year, &month, &day); double absolute0101 = __CFAbsoluteFromYMD(year, 1, 1); diff --git a/CFDate.h b/CFDate.h index 354aae3..fada953 100644 --- a/CFDate.h +++ b/CFDate.h @@ -22,7 +22,7 @@ */ /* CFDate.h - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFDATE__) @@ -30,6 +30,7 @@ #include +CF_IMPLICIT_BRIDGING_ENABLED CF_EXTERN_C_BEGIN typedef double CFTimeInterval; @@ -62,6 +63,8 @@ CFTimeInterval CFDateGetTimeIntervalSinceDate(CFDateRef theDate, CFDateRef other CF_EXPORT CFComparisonResult CFDateCompare(CFDateRef theDate, CFDateRef otherDate, void *context); +CF_IMPLICIT_BRIDGING_DISABLED + typedef const struct __CFTimeZone * CFTimeZoneRef; typedef struct { @@ -82,7 +85,7 @@ typedef struct { double seconds; } CFGregorianUnits; -enum { +typedef CF_OPTIONS(CFOptionFlags, CFGregorianUnitFlags) { kCFGregorianUnitsYears = (1UL << 0), kCFGregorianUnitsMonths = (1UL << 1), kCFGregorianUnitsDays = (1UL << 2), @@ -91,7 +94,6 @@ enum { kCFGregorianUnitsSeconds = (1UL << 5), kCFGregorianAllUnits = 0x00FFFFFF }; -typedef CFOptionFlags CFGregorianUnitFlags; CF_EXPORT Boolean CFGregorianDateIsValid(CFGregorianDate gdate, CFOptionFlags unitFlags); diff --git a/CFDateFormatter.c b/CFDateFormatter.c index d751f6e..1b14265 100644 --- a/CFDateFormatter.c +++ b/CFDateFormatter.c @@ -22,7 +22,7 @@ */ /* CFDateFormatter.c - Copyright (c) 2002-2011, Apple Inc. All rights reserved. + Copyright (c) 2002-2012, Apple Inc. All rights reserved. Responsibility: David Smith */ @@ -41,6 +41,17 @@ #include #include +typedef CF_ENUM(CFIndex, CFDateFormatterAmbiguousYearHandling) { + kCFDateFormatterAmbiguousYearFailToParse = 0, // fail the parse; the default formatter behavior + kCFDateFormatterAmbiguousYearAssumeToNone = 1, // default to assuming era 1, or the year 0-99 + kCFDateFormatterAmbiguousYearAssumeToCurrent = 2, // default to assuming the current century or era + kCFDateFormatterAmbiguousYearAssumeToCenteredAroundCurrentDate = 3, + kCFDateFormatterAmbiguousYearAssumeToFuture = 4, + kCFDateFormatterAmbiguousYearAssumeToPast = 5, + kCFDateFormatterAmbiguousYearAssumeToLikelyFuture = 6, + kCFDateFormatterAmbiguousYearAssumeToLikelyPast = 7 +}; + extern UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID, CFStringRef localeID, CFTimeZoneRef tz); static void __CFDateFormatterCustomize(CFDateFormatterRef formatter); @@ -148,7 +159,7 @@ struct __CFDateFormatter { CFBooleanRef _IsLenient; CFBooleanRef _DoesRelativeDateFormatting; CFBooleanRef _HasCustomFormat; - CFTimeZoneRef _TimeZone; + CFTimeZoneRef _TimeZone; CFCalendarRef _Calendar; CFStringRef _CalendarName; CFDateRef _TwoDigitStartDate; @@ -174,6 +185,7 @@ struct __CFDateFormatter { CFArrayRef _ShortStandaloneQuarterSymbols; CFStringRef _AMSymbol; CFStringRef _PMSymbol; + CFNumberRef _AmbiguousYearStrategy; } _property; }; @@ -216,6 +228,7 @@ static void __CFDateFormatterDeallocate(CFTypeRef cf) { CFReleaseIfNotNull(formatter->_property._ShortStandaloneQuarterSymbols); CFReleaseIfNotNull(formatter->_property._AMSymbol); CFReleaseIfNotNull(formatter->_property._PMSymbol); + CFReleaseIfNotNull(formatter->_property._AmbiguousYearStrategy); } static CFStringRef __CFDateFormatterCreateForcedString(CFDateFormatterRef formatter, CFStringRef inString); @@ -261,7 +274,7 @@ static void __ResetUDateFormat(CFDateFormatterRef df, Boolean goingToHaveCustomF } Boolean wantRelative = (NULL != df->_property._DoesRelativeDateFormatting && df->_property._DoesRelativeDateFormatting == kCFBooleanTrue); Boolean hasFormat = (NULL != df->_property._HasCustomFormat && df->_property._HasCustomFormat == kCFBooleanTrue) || goingToHaveCustomFormat; - if (wantRelative && !hasFormat) { + if (wantRelative && !hasFormat && kCFDateFormatterNoStyle != df->_dateStyle) { udstyle |= UDAT_RELATIVE; } @@ -272,7 +285,12 @@ static void __ResetUDateFormat(CFDateFormatterRef df, Boolean goingToHaveCustomF } udat_setLenient(icudf, 0); if (kCFDateFormatterNoStyle == df->_dateStyle && kCFDateFormatterNoStyle == df->_timeStyle) { - udat_applyPattern(icudf, false, NULL, 0); + if (wantRelative && !hasFormat && kCFDateFormatterNoStyle != df->_dateStyle) { + UErrorCode s = U_ZERO_ERROR; + udat_applyPatternRelative(icudf, NULL, 0, NULL, 0, &s); + } else { + udat_applyPattern(icudf, false, NULL, 0); + } } CFStringRef calident = (CFStringRef)CFLocaleGetValue(df->_locale, kCFLocaleCalendarIdentifierKey); if (calident && CFEqual(calident, kCFCalendarIdentifierGregorian)) { @@ -283,35 +301,81 @@ static void __ResetUDateFormat(CFDateFormatterRef df, Boolean goingToHaveCustomF __CFDateFormatterCustomize(df); - UChar ubuffer[BUFFER_SIZE]; - status = U_ZERO_ERROR; - int32_t ret = udat_toPattern(icudf, false, ubuffer, BUFFER_SIZE, &status); - if (U_SUCCESS(status) && ret <= BUFFER_SIZE) { - CFStringRef newFormat = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)ubuffer, ret); - CFStringRef formatString = __CFDateFormatterCreateForcedString(df, newFormat); - CFIndex cnt = CFStringGetLength(formatString); - CFAssert1(cnt <= 1024, __kCFLogAssertion, "%s(): format string too long", __PRETTY_FUNCTION__); - if (df->_format != formatString && cnt <= 1024) { - STACK_BUFFER_DECL(UChar, ubuffer, cnt); - const UChar *ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)formatString); - if (NULL == ustr) { - CFStringGetCharacters(formatString, CFRangeMake(0, cnt), (UniChar *)ubuffer); - ustr = ubuffer; + if (wantRelative && !hasFormat && kCFDateFormatterNoStyle != df->_dateStyle) { + UChar dateBuffer[BUFFER_SIZE]; + UChar timeBuffer[BUFFER_SIZE]; + status = U_ZERO_ERROR; + CFIndex dateLen = udat_toPatternRelativeDate(icudf, dateBuffer, BUFFER_SIZE, &status); + CFIndex timeLen = (utstyle != UDAT_NONE) ? udat_toPatternRelativeTime(icudf, timeBuffer, BUFFER_SIZE, &status) : 0; + if (U_SUCCESS(status) && dateLen <= BUFFER_SIZE && timeLen <= BUFFER_SIZE) { + // We assume that the 12/24-hour forcing preferences only affect the Time component + CFStringRef newFormat = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)timeBuffer, timeLen); + CFStringRef formatString = __CFDateFormatterCreateForcedString(df, newFormat); + CFIndex cnt = CFStringGetLength(formatString); + CFAssert1(cnt <= BUFFER_SIZE, __kCFLogAssertion, "%s(): time format string too long", __PRETTY_FUNCTION__); + if (cnt <= BUFFER_SIZE) { + CFStringGetCharacters(formatString, CFRangeMake(0, cnt), (UniChar *)timeBuffer); + timeLen = cnt; + status = U_ZERO_ERROR; + udat_applyPatternRelative(icudf, dateBuffer, dateLen, timeBuffer, timeLen, &status); + // ignore error and proceed anyway, what else can be done? + + UChar ubuffer[BUFFER_SIZE]; + status = U_ZERO_ERROR; + int32_t ret = udat_toPattern(icudf, false, ubuffer, BUFFER_SIZE, &status); // read out current pattern + if (U_SUCCESS(status) && ret <= BUFFER_SIZE) { + if (df->_format) CFRelease(df->_format); + df->_format = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)ubuffer, ret); + } } - UErrorCode status = U_ZERO_ERROR; + CFRelease(formatString); + CFRelease(newFormat); + } + } else { + UChar ubuffer[BUFFER_SIZE]; + status = U_ZERO_ERROR; + int32_t ret = udat_toPattern(icudf, false, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && ret <= BUFFER_SIZE) { + CFStringRef newFormat = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)ubuffer, ret); + CFStringRef formatString = __CFDateFormatterCreateForcedString(df, newFormat); + CFIndex cnt = CFStringGetLength(formatString); + CFAssert1(cnt <= 1024, __kCFLogAssertion, "%s(): format string too long", __PRETTY_FUNCTION__); + if (df->_format != formatString && cnt <= 1024) { + STACK_BUFFER_DECL(UChar, ubuffer, cnt); + const UChar *ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)formatString); + if (NULL == ustr) { + CFStringGetCharacters(formatString, CFRangeMake(0, cnt), (UniChar *)ubuffer); + ustr = ubuffer; + } + UErrorCode status = U_ZERO_ERROR; // udat_applyPattern(df->_df, false, ustr, cnt, &status); - udat_applyPattern(df->_df, false, ustr, cnt); - if (U_SUCCESS(status)) { - if (df->_format) CFRelease(df->_format); - df->_format = (CFStringRef)CFStringCreateCopy(CFGetAllocator(df), formatString); + udat_applyPattern(df->_df, false, ustr, cnt); + if (U_SUCCESS(status)) { + if (df->_format) CFRelease(df->_format); + df->_format = (CFStringRef)CFStringCreateCopy(CFGetAllocator(df), formatString); + } } + CFRelease(formatString); + CFRelease(newFormat); } - CFRelease(formatString); - CFRelease(newFormat); } if (df->_defformat) CFRelease(df->_defformat); df->_defformat = df->_format ? (CFStringRef)CFRetain(df->_format) : NULL; + CFStringRef calName = df->_property._CalendarName ? (df->_property._CalendarName) : NULL; + if (!calName) { + calName = (CFStringRef)CFLocaleGetValue(df->_locale, kCFLocaleCalendarIdentifierKey); + } + if (calName && CFEqual(calName, kCFCalendarIdentifierGregorian)) { + UCalendar *cal = (UCalendar *)udat_getCalendar(df->_df); + status = U_ZERO_ERROR; + UDate udate = ucal_getGregorianChange(cal, &status); + CFAbsoluteTime at = U_SUCCESS(status) ? (udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970) : -13197600000.0; // Oct 15, 1582 + udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0; + status = U_ZERO_ERROR; + ucal_setGregorianChange(cal, udate, &status); + } + RESET_PROPERTY(_IsLenient, kCFDateFormatterIsLenientKey); RESET_PROPERTY(_DoesRelativeDateFormatting, kCFDateFormatterDoesRelativeDateFormattingKey); RESET_PROPERTY(_Calendar, kCFDateFormatterCalendarKey); @@ -340,6 +404,7 @@ static void __ResetUDateFormat(CFDateFormatterRef df, Boolean goingToHaveCustomF RESET_PROPERTY(_ShortStandaloneQuarterSymbols, kCFDateFormatterShortStandaloneQuarterSymbolsKey); RESET_PROPERTY(_AMSymbol, kCFDateFormatterAMSymbolKey); RESET_PROPERTY(_PMSymbol, kCFDateFormatterPMSymbolKey); + RESET_PROPERTY(_AmbiguousYearStrategy, kCFDateFormatterAmbiguousYearStrategyKey); } static CFTypeID __kCFDateFormatterTypeID = _kCFRuntimeNotATypeID; @@ -352,7 +417,7 @@ static const CFRuntimeClass __CFDateFormatterClass = { __CFDateFormatterDeallocate, NULL, NULL, - NULL, // + NULL, // __CFDateFormatterCopyDescription }; @@ -410,6 +475,7 @@ CFDateFormatterRef CFDateFormatterCreate(CFAllocatorRef allocator, CFLocaleRef l memory->_property._ShortStandaloneQuarterSymbols = NULL; memory->_property._AMSymbol = NULL; memory->_property._PMSymbol = NULL; + memory->_property._AmbiguousYearStrategy = NULL; switch (dateStyle) { case kCFDateFormatterNoStyle: @@ -639,7 +705,7 @@ static CFStringRef __CFDateFormatterCreateForcedTemplate(CFLocaleRef locale, CFS } if (emit) CFStringAppendCharacters(outString, &ch, 1); } - + return outString; } @@ -728,7 +794,7 @@ static CFStringRef __CFDateFormatterCreateForcedString(CFDateFormatterRef format static void __CFDateFormatterCustomize(CFDateFormatterRef formatter) { Boolean wantRelative = (NULL != formatter->_property._DoesRelativeDateFormatting && formatter->_property._DoesRelativeDateFormatting == kCFBooleanTrue); Boolean hasFormat = (NULL != formatter->_property._HasCustomFormat && formatter->_property._HasCustomFormat == kCFBooleanTrue); - if (wantRelative && !hasFormat) { + if (wantRelative && !hasFormat && kCFDateFormatterNoStyle != formatter->_dateStyle) { __substituteFormatStringFromPrefsDFRelative(formatter); } else { __substituteFormatStringFromPrefsDF(formatter, false); @@ -796,6 +862,7 @@ void CFDateFormatterSetFormat(CFDateFormatterRef formatter, CFStringRef formatSt // the whole UDateFormat. if (formatter->_property._HasCustomFormat != kCFBooleanTrue && formatter->_property._DoesRelativeDateFormatting == kCFBooleanTrue) { __ResetUDateFormat(formatter, true); + // the "true" results in: if you set a custom format string, you don't get relative date formatting } STACK_BUFFER_DECL(UChar, ubuffer, cnt); const UChar *ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)formatString); @@ -846,6 +913,256 @@ CFStringRef CFDateFormatterCreateStringWithAbsoluteTime(CFAllocatorRef allocator return string; } +static UDate __CFDateFormatterCorrectTimeWithTarget(UCalendar *calendar, UDate at, int32_t target, Boolean isEra, UErrorCode *status) { + ucal_setMillis(calendar, at, status); + UCalendarDateFields field = isEra ? UCAL_ERA : UCAL_YEAR; + ucal_set(calendar, field, target); + return ucal_getMillis(calendar, status); +} + +static UDate __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(UCalendar *calendar, UDate at, CFIndex period, CFIndex pastYears, CFIndex futureYears, Boolean isEra, UErrorCode *status) { + ucal_setMillis(calendar, ucal_getNow(), status); + int32_t currYear = ucal_get(calendar, UCAL_YEAR, status); + UCalendarDateFields field = isEra ? UCAL_ERA : UCAL_YEAR; + int32_t currEraOrCentury = ucal_get(calendar, field, status); + if (!isEra) { + currYear %= 100; + currEraOrCentury = currEraOrCentury / 100 * 100; // get century + } + + CFIndex futureMax = currYear + futureYears; + CFIndex pastMin = currYear - pastYears; + + CFRange currRange, futureRange, pastRange; + currRange.location = futureRange.location = pastRange.location = kCFNotFound; + currRange.length = futureRange.length = pastRange.length = 0; + if (!isEra) { + if (period < INT_MAX && futureMax >= period) { + futureRange.location = 0; + futureRange.length = futureMax - period + 1; + } + if (pastMin < 0) { + pastRange.location = period + pastMin; + pastRange.length = period - pastRange.location; + } + if (pastRange.location != kCFNotFound) { + currRange.location = 0; + } else { + currRange.location = pastMin; + } + } else { + if (period < INT_MAX && futureMax > period) { + futureRange.location = 1, + futureRange.length = futureMax - period; + } + if (pastMin <= 0) { + pastRange.location = period + pastMin; + pastRange.length = period - pastRange.location + 1; + } + if (pastRange.location != kCFNotFound) { + currRange.location = 1; + } else { + currRange.location = pastMin; + } + + } + currRange.length = period - pastRange.length - futureRange.length; + + ucal_setMillis(calendar, at, status); + int32_t atYear = ucal_get(calendar, UCAL_YEAR, status); + if (!isEra) { + atYear %= 100; + currEraOrCentury += atYear; + } + + int32_t offset = 0; // current era or century + if (pastRange.location != kCFNotFound && atYear >= pastRange.location && atYear - pastRange.location + 1 <= pastRange.length) { + offset = -1; // past era or century + } else if (futureRange.location != kCFNotFound && atYear >= futureRange.location && atYear - futureRange.location + 1 <= futureRange.length) { + offset = 1; // next era or century + } + if (!isEra) offset *= 100; + return __CFDateFormatterCorrectTimeWithTarget(calendar, at, currEraOrCentury+offset, isEra, status); +} + +static int32_t __CFDateFormatterGetMaxYearGivenJapaneseEra(UCalendar *calendar, int32_t era, UErrorCode *status) { + int32_t years = 0; + ucal_clear(calendar); + ucal_set(calendar, UCAL_ERA, era+1); + UDate target = ucal_getMillis(calendar, status); + ucal_set(calendar, UCAL_ERA, era); + years = ucal_getFieldDifference(calendar, target, UCAL_YEAR, status); + return years+1; +} + +static Boolean __CFDateFormatterHandleAmbiguousYear(CFDateFormatterRef formatter, CFStringRef calendar_id, UDateFormat *df, UCalendar *cal, UDate *at, const UChar *ustr, CFIndex length, UErrorCode *status) { + Boolean success = true; + int64_t ambigStrat = kCFDateFormatterAmbiguousYearAssumeToNone; + if (formatter->_property._AmbiguousYearStrategy) { + CFNumberGetValue(formatter->_property._AmbiguousYearStrategy, kCFNumberSInt64Type, &ambigStrat); + } + if (calendar_id == kCFCalendarIdentifierChinese) { + // we default to era 1 if era is missing, however, we cannot just test if the era is 1 becuase we may get era 2 or larger if the year in the string is greater than 60 + // now I just assume that the year will not be greater than 600 in the string + if (ucal_get(cal, UCAL_ERA, status) < 10) { + switch (ambigStrat) { + case kCFDateFormatterAmbiguousYearFailToParse: + success = false; + break; + case kCFDateFormatterAmbiguousYearAssumeToCurrent: { + ucal_setMillis(cal, ucal_getNow(), status); + int32_t currEra = ucal_get(cal, UCAL_ERA, status); + *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, currEra, true, status); + break; + } + case kCFDateFormatterAmbiguousYearAssumeToCenteredAroundCurrentDate: + *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 60, 29, 30, true, status); + break; + case kCFDateFormatterAmbiguousYearAssumeToFuture: + *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 60, 0, 59, true, status); + break; + case kCFDateFormatterAmbiguousYearAssumeToPast: + *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 60, 59, 0, true, status); + break; + case kCFDateFormatterAmbiguousYearAssumeToLikelyFuture: + *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 60, 10, 49, true, status); + break; + case kCFDateFormatterAmbiguousYearAssumeToLikelyPast: + *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 60, 49, 10, true, status); + break; + case kCFDateFormatterAmbiguousYearAssumeToNone: + default: + break; // do nothing + } + } + } else if (calendar_id == kCFCalendarIdentifierJapanese) { // ??? need more work + ucal_clear(cal); + ucal_set(cal, UCAL_ERA, 1); + udat_parseCalendar(df, cal, ustr, length, NULL, status); + UDate test = ucal_getMillis(cal, status); + if (test != *at) { // missing era + ucal_setMillis(cal, *at, status); + int32_t givenYear = ucal_get(cal, UCAL_YEAR, status); + ucal_setMillis(cal, ucal_getNow(), status); + int32_t currYear = ucal_get(cal, UCAL_YEAR, status); + int32_t currEra = ucal_get(cal, UCAL_ERA, status); + switch (ambigStrat) { + case kCFDateFormatterAmbiguousYearFailToParse: + success = false; + break; + case kCFDateFormatterAmbiguousYearAssumeToCurrent: + *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, currEra, true, status); + break; + case kCFDateFormatterAmbiguousYearAssumeToCenteredAroundCurrentDate: + // we allow the ball up to 30 years + // if the given year is larger than the current year + 30 years, we check the previous era + if (givenYear > currYear + 30) { + success = false; // if the previous era cannot have the given year, fail the parse + int32_t years = __CFDateFormatterGetMaxYearGivenJapaneseEra(cal, currEra-1, status); + if (givenYear <= years) { + success = true; + *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, currEra-1, true, status); + } + } else { // current era + *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, currEra, true, status); + } + break; + case kCFDateFormatterAmbiguousYearAssumeToFuture: + if (givenYear < currYear) { // we only consider current or the future + success = false; + } else { // current era + *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, currEra, true, status); + } + break; + case kCFDateFormatterAmbiguousYearAssumeToPast: + if (givenYear > currYear) { // past era + success = false; + // we find the closest era that has the given year + // if no era has such given year, we fail the parse + for (CFIndex era = currEra-1; era >= 234; era--) { // Showa era (234) is the longest era + int32_t years = __CFDateFormatterGetMaxYearGivenJapaneseEra(cal, era, status); + if (givenYear > years) { + continue; + } + success = true; + *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, era, true, status); + break; + } + } else { // current era + *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, currEra, true, status); + } + break; + case kCFDateFormatterAmbiguousYearAssumeToLikelyFuture: + if (givenYear < currYear - 10) { // we allow 10 years to the past + success = false; + } else { + *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, currEra, true, status); + } + break; + case kCFDateFormatterAmbiguousYearAssumeToLikelyPast: + if (givenYear > currYear + 10) { + success = false; + // we find the closest era that has the given year + // if no era has such given year, we fail the parse + for (CFIndex era = currEra-1; era >= 234; era--) { // Showa era (234) is the longest era + int32_t years = __CFDateFormatterGetMaxYearGivenJapaneseEra(cal, era, status); + if (givenYear > years) { + continue; + } + success = true; + *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, era, true, status); + break; + } + } else { // current era + *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, currEra, true, status); + } + break; + case kCFDateFormatterAmbiguousYearAssumeToNone: + default: + break; // do nothing + } + } + } else { // calenders other than chinese and japanese + int32_t parsedYear = ucal_get(cal, UCAL_YEAR, status); + ucal_setMillis(cal, ucal_getNow(), status); + int32_t currYear = ucal_get(cal, UCAL_YEAR, status); + if (currYear + 1500 < parsedYear) { // most likely that the parsed string had a 2-digits year + switch (ambigStrat) { + case kCFDateFormatterAmbiguousYearFailToParse: + success = false; + break; + case kCFDateFormatterAmbiguousYearAssumeToCurrent: + *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, (currYear / 100 * 100) + parsedYear % 100, false, status); + break; + case kCFDateFormatterAmbiguousYearAssumeToCenteredAroundCurrentDate: + *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 100, 50, 49, false, status); + break; + case kCFDateFormatterAmbiguousYearAssumeToFuture: + *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 100, 0, 99, false, status); + break; + case kCFDateFormatterAmbiguousYearAssumeToPast: + *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 100, 99, 0, false, status); + break; + case kCFDateFormatterAmbiguousYearAssumeToLikelyFuture: + *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 100, 9, 90, false, status); + break; + case kCFDateFormatterAmbiguousYearAssumeToLikelyPast: + *at = __CFDateFormatterCorrectTimeToARangeAroundCurrentDate(cal, *at, 100, 90, 9, false, status); + break; + case kCFDateFormatterAmbiguousYearAssumeToNone: + default: + if (calendar_id == kCFCalendarIdentifierGregorian) { // historical default behavior of 1950 - 2049 + int32_t twoDigits = parsedYear % 100; + *at = __CFDateFormatterCorrectTimeWithTarget(cal, *at, ((twoDigits < 50) ? 2000 : 1900) + twoDigits, false, status); + } + break; // do nothing + } + } + + } + return success; +} + CFDateRef CFDateFormatterCreateDateFromString(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFStringRef string, CFRange *rangep) { if (allocator == NULL) allocator = __CFGetDefaultAllocator(); __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); @@ -879,26 +1196,54 @@ Boolean CFDateFormatterGetAbsoluteTimeFromString(CFDateFormatterRef formatter, C UDate udate; int32_t dpos = 0; UErrorCode status = U_ZERO_ERROR; + UDateFormat *df2 = udat_clone(formatter->_df, &status); + UCalendar *cal2 = (UCalendar *)udat_getCalendar(df2); + CFStringRef calendar_id = (CFStringRef) CFDateFormatterCopyProperty(formatter, kCFDateFormatterCalendarIdentifierKey); + // we can do this direct comparison because locale in the formatter normalizes the identifier + if (formatter->_property._TwoDigitStartDate) { + // if set, don't use hint, leave it all to ICU, as historically + } else if (calendar_id != kCFCalendarIdentifierChinese && calendar_id != kCFCalendarIdentifierJapanese) { + ucal_setMillis(cal2, ucal_getNow(), &status); + int32_t newYear = ((ucal_get(cal2, UCAL_YEAR, &status) / 100) + 16) * 100; // move ahead 1501-1600 years, to the beginning of a century + ucal_set(cal2, UCAL_YEAR, newYear); + ucal_set(cal2, UCAL_MONTH, ucal_getLimit(cal2, UCAL_MONTH, UCAL_ACTUAL_MINIMUM, &status)); + ucal_set(cal2, UCAL_IS_LEAP_MONTH, 0); + ucal_set(cal2, UCAL_DAY_OF_MONTH, ucal_getLimit(cal2, UCAL_DAY_OF_MONTH, UCAL_ACTUAL_MINIMUM, &status)); + ucal_set(cal2, UCAL_HOUR_OF_DAY, ucal_getLimit(cal2, UCAL_HOUR_OF_DAY, UCAL_ACTUAL_MINIMUM, &status)); + ucal_set(cal2, UCAL_MINUTE, ucal_getLimit(cal2, UCAL_MINUTE, UCAL_ACTUAL_MINIMUM, &status)); + ucal_set(cal2, UCAL_SECOND, ucal_getLimit(cal2, UCAL_SECOND, UCAL_ACTUAL_MINIMUM, &status)); + ucal_set(cal2, UCAL_MILLISECOND, 0); + UDate future = ucal_getMillis(cal2, &status); + ucal_clear(cal2); + udat_set2DigitYearStart(df2, future, &status); + } else if (calendar_id == kCFCalendarIdentifierChinese) { + ucal_clear(cal2); + ucal_set(cal2, UCAL_ERA, 1); // default to era 1 if no era info in the string for chinese + } else if (calendar_id == kCFCalendarIdentifierJapanese) { // default to the current era + ucal_setMillis(cal2, ucal_getNow(), &status); + int32_t currEra = ucal_get(cal2, UCAL_ERA, &status); + ucal_clear(cal2); + ucal_set(cal2, UCAL_ERA, currEra); + } if (formatter->_property._DefaultDate) { CFAbsoluteTime at = CFDateGetAbsoluteTime(formatter->_property._DefaultDate); udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0; - UDateFormat *df2 = udat_clone(formatter->_df, &status); - UCalendar *cal2 = (UCalendar *)udat_getCalendar(df2); ucal_setMillis(cal2, udate, &status); - udat_parseCalendar(formatter->_df, cal2, ustr, range.length, &dpos, &status); - udate = ucal_getMillis(cal2, &status); - udat_close(df2); - } else { - udate = udat_parse(formatter->_df, ustr, range.length, &dpos, &status); } + udat_parseCalendar(df2, cal2, ustr, range.length, &dpos, &status); + udate = ucal_getMillis(cal2, &status); if (rangep) rangep->length = dpos; - if (U_FAILURE(status)) { - return false; - } - if (atp) { - *atp = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970; + Boolean success = false; + // first status check is for parsing and the second status check is for the work done inside __CFDateFormatterHandleAmbiguousYear() + if (!U_FAILURE(status) && (formatter->_property._TwoDigitStartDate || __CFDateFormatterHandleAmbiguousYear(formatter, calendar_id, df2, cal2, &udate, ustr, range.length, &status)) && !U_FAILURE(status)) { + if (atp) { + *atp = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970; + } + success = true; } - return true; + CFRelease(calendar_id); + udat_close(df2); + return success; } static void __CFDateFormatterSetSymbolsArray(UDateFormat *icudf, int32_t icucode, int index_base, CFTypeRef value) { @@ -1163,6 +1508,11 @@ static void __CFDateFormatterSetProperty(CFDateFormatterRef formatter, CFStringR if (!directToICU) { formatter->_property. _PMSymbol = (CFStringRef)CFDateFormatterCopyProperty(formatter, kCFDateFormatterPMSymbolKey); } + } else if (kCFDateFormatterAmbiguousYearStrategyKey == key) { + oldProperty = formatter->_property._AmbiguousYearStrategy; + formatter->_property._AmbiguousYearStrategy = NULL; + __CFGenericValidateType(value, CFNumberGetTypeID()); + formatter->_property._AmbiguousYearStrategy = (CFNumberRef)CFRetain(value); } else { CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key); } @@ -1277,7 +1627,7 @@ CFTypeRef CFDateFormatterCopyProperty(CFDateFormatterRef formatter, CFStringRef if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { return CFStringCreateWithCharacters(CFGetAllocator(formatter), (UniChar *)ubuffer, ucnt); } - } + } } else if (kCFDateFormatterPMSymbolKey == key) { if (formatter->_property._PMSymbol) return CFRetain(formatter->_property._PMSymbol); CFIndex cnt = udat_countSymbols(formatter->_df, UDAT_AM_PMS); @@ -1286,7 +1636,9 @@ CFTypeRef CFDateFormatterCopyProperty(CFDateFormatterRef formatter, CFStringRef if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { return CFStringCreateWithCharacters(CFGetAllocator(formatter), (UniChar *)ubuffer, ucnt); } - } + } + } else if (kCFDateFormatterAmbiguousYearStrategyKey == key) { + if (formatter->_property._AmbiguousYearStrategy) return CFRetain(formatter->_property._AmbiguousYearStrategy); } else { CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key); } diff --git a/CFDateFormatter.h b/CFDateFormatter.h index 065f5b9..49ca968 100644 --- a/CFDateFormatter.h +++ b/CFDateFormatter.h @@ -22,7 +22,7 @@ */ /* CFDateFormatter.h - Copyright (c) 2003-2011, Apple Inc. All rights reserved. + Copyright (c) 2003-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFDATEFORMATTER__) @@ -45,14 +45,13 @@ CFStringRef CFDateFormatterCreateDateFormatFromTemplate(CFAllocatorRef allocator CF_EXPORT CFTypeID CFDateFormatterGetTypeID(void); -enum { // date and time format styles +typedef CF_ENUM(CFIndex, CFDateFormatterStyle) { // date and time format styles kCFDateFormatterNoStyle = 0, kCFDateFormatterShortStyle = 1, kCFDateFormatterMediumStyle = 2, kCFDateFormatterLongStyle = 3, kCFDateFormatterFullStyle = 4 }; -typedef CFIndex CFDateFormatterStyle; // The exact formatted result for these date and time styles depends on the // locale, but generally: @@ -165,7 +164,7 @@ CF_EXPORT const CFStringRef kCFDateFormatterDoesRelativeDateFormattingKey CF_AVA // const CFStringRef kCFRepublicOfChinaCalendar; // const CFStringRef kCFPersianCalendar; // const CFStringRef kCFIndianCalendar; -// const CFStringRef kCFISO8601Calendar; not yet implemented +// const CFStringRef kCFISO8601Calendar; CF_EXTERN_C_END diff --git a/CFDictionary.c b/CFDictionary.c index de1067f..173c0ae 100644 --- a/CFDictionary.c +++ b/CFDictionary.c @@ -22,7 +22,7 @@ */ /* CFDictionary.c - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. Responsibility: Christopher Kane Machine generated from Notes/HashingCode.template */ @@ -36,6 +36,7 @@ #include "CFBasicHash.h" #include + #define CFDictionary 0 #define CFSet 0 #define CFBag 0 @@ -217,7 +218,7 @@ static CFBasicHashCallbacks *__CFDictionaryCopyCallbacks(CFConstBasicHashRef ht, } else { newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), 0); } - if (!newcb) HALT; + if (!newcb) return NULL; memmove(newcb, (void *)cb, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *)); return newcb; } @@ -386,7 +387,7 @@ static CFBasicHashRef __CFDictionaryCreateGeneric(CFAllocatorRef allocator, cons } else { newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), 0); } - if (!newcb) HALT; + if (!newcb) return NULL; newcb->copyCallbacks = __CFDictionaryCopyCallbacks; newcb->freeCallbacks = __CFDictionaryFreeCallbacks; newcb->retainValue = __CFDictionaryRetainValue; @@ -427,7 +428,8 @@ static CFBasicHashRef __CFDictionaryCreateGeneric(CFAllocatorRef allocator, cons } CFBasicHashRef ht = CFBasicHashCreate(allocator, flags, cb); - CFBasicHashSetSpecialBits(ht, specialBits); + if (ht) CFBasicHashSetSpecialBits(ht, specialBits); + if (!ht && !CF_IS_COLLECTABLE_ALLOCATOR(allocator)) CFAllocatorDeallocate(allocator, cb); return ht; } @@ -468,6 +470,7 @@ CFHashRef CFDictionaryCreate(CFAllocatorRef allocator, const_any_pointer_t *klis CFTypeID typeID = CFDictionaryGetTypeID(); CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__, numValues); CFBasicHashRef ht = __CFDictionaryCreateGeneric(allocator, keyCallBacks, valueCallBacks, CFDictionary); + if (!ht) return NULL; if (0 < numValues) CFBasicHashSetCapacity(ht, numValues); for (CFIndex idx = 0; idx < numValues; idx++) { CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]); @@ -489,6 +492,7 @@ CFMutableHashRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex cap CFTypeID typeID = CFDictionaryGetTypeID(); CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%ld) cannot be less than zero", __PRETTY_FUNCTION__, capacity); CFBasicHashRef ht = __CFDictionaryCreateGeneric(allocator, keyCallBacks, valueCallBacks, CFDictionary); + if (!ht) return NULL; *(uintptr_t *)ht = __CFISAForTypeID(typeID); _CFRuntimeSetInstanceTypeID(ht, typeID); if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFDictionary (mutable)"); @@ -513,8 +517,8 @@ CFHashRef CFDictionaryCreateCopy(CFAllocatorRef allocator, CFHashRef other) { CFDictionaryGetKeysAndValues(other, klist, vlist); #endif ht = __CFDictionaryCreateGeneric(allocator, & kCFTypeDictionaryKeyCallBacks, CFDictionary ? & kCFTypeDictionaryValueCallBacks : NULL, CFDictionary); - if (0 < numValues) CFBasicHashSetCapacity(ht, numValues); - for (CFIndex idx = 0; idx < numValues; idx++) { + if (ht && 0 < numValues) CFBasicHashSetCapacity(ht, numValues); + for (CFIndex idx = 0; ht && idx < numValues; idx++) { CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]); } if (klist != kbuffer && klist != vlist) CFAllocatorDeallocate(kCFAllocatorSystemDefault, klist); @@ -522,6 +526,7 @@ CFHashRef CFDictionaryCreateCopy(CFAllocatorRef allocator, CFHashRef other) { } else { ht = CFBasicHashCreateCopy(allocator, (CFBasicHashRef)other); } + if (!ht) return NULL; CFBasicHashMakeImmutable(ht); *(uintptr_t *)ht = __CFISAForTypeID(typeID); _CFRuntimeSetInstanceTypeID(ht, typeID); @@ -548,8 +553,8 @@ CFMutableHashRef CFDictionaryCreateMutableCopy(CFAllocatorRef allocator, CFIndex CFDictionaryGetKeysAndValues(other, klist, vlist); #endif ht = __CFDictionaryCreateGeneric(allocator, & kCFTypeDictionaryKeyCallBacks, CFDictionary ? & kCFTypeDictionaryValueCallBacks : NULL, CFDictionary); - if (0 < numValues) CFBasicHashSetCapacity(ht, numValues); - for (CFIndex idx = 0; idx < numValues; idx++) { + if (ht && 0 < numValues) CFBasicHashSetCapacity(ht, numValues); + for (CFIndex idx = 0; ht && idx < numValues; idx++) { CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]); } if (klist != kbuffer && klist != vlist) CFAllocatorDeallocate(kCFAllocatorSystemDefault, klist); @@ -557,6 +562,7 @@ CFMutableHashRef CFDictionaryCreateMutableCopy(CFAllocatorRef allocator, CFIndex } else { ht = CFBasicHashCreateCopy(allocator, (CFBasicHashRef)other); } + if (!ht) return NULL; *(uintptr_t *)ht = __CFISAForTypeID(typeID); _CFRuntimeSetInstanceTypeID(ht, typeID); if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFDictionary (mutable)"); @@ -564,8 +570,8 @@ CFMutableHashRef CFDictionaryCreateMutableCopy(CFAllocatorRef allocator, CFIndex } CFIndex CFDictionaryGetCount(CFHashRef hc) { - if (CFDictionary) CF_OBJC_FUNCDISPATCH0(__kCFDictionaryTypeID, CFIndex, hc, "count"); - if (CFSet) CF_OBJC_FUNCDISPATCH0(__kCFDictionaryTypeID, CFIndex, hc, "count"); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, CFIndex, (NSDictionary *)hc, count); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, CFIndex, (NSSet *)hc, count); __CFGenericValidateType(hc, __kCFDictionaryTypeID); return CFBasicHashGetCount((CFBasicHashRef)hc); } @@ -576,8 +582,8 @@ CFIndex CFDictionaryGetCountOfKey(CFHashRef hc, const_any_pointer_t key) { #if CFSet || CFBag CFIndex CFDictionaryGetCountOfValue(CFHashRef hc, const_any_pointer_t key) { #endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, CFIndex, hc, "countForKey:", key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, CFIndex, hc, "countForObject:", key); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, CFIndex, (NSDictionary *)hc, countForKey:(id)key); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, CFIndex, (NSSet *)hc, countForObject:(id)key); __CFGenericValidateType(hc, __kCFDictionaryTypeID); return CFBasicHashGetCountOfKey((CFBasicHashRef)hc, (uintptr_t)key); } @@ -588,23 +594,23 @@ Boolean CFDictionaryContainsKey(CFHashRef hc, const_any_pointer_t key) { #if CFSet || CFBag Boolean CFDictionaryContainsValue(CFHashRef hc, const_any_pointer_t key) { #endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, char, hc, "containsKey:", key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, char, hc, "containsObject:", key); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, char, (NSDictionary *)hc, containsKey:(id)key); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, char, (NSSet *)hc, containsObject:(id)key); __CFGenericValidateType(hc, __kCFDictionaryTypeID); return (0 < CFBasicHashGetCountOfKey((CFBasicHashRef)hc, (uintptr_t)key)); } const_any_pointer_t CFDictionaryGetValue(CFHashRef hc, const_any_pointer_t key) { - if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, const_any_pointer_t, hc, "objectForKey:", key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, const_any_pointer_t, hc, "member:", key); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, const_any_pointer_t, (NSDictionary *)hc, objectForKey:(id)key); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, const_any_pointer_t, (NSSet *)hc, member:(id)key); __CFGenericValidateType(hc, __kCFDictionaryTypeID); CFBasicHashBucket bkt = CFBasicHashFindBucket((CFBasicHashRef)hc, (uintptr_t)key); return (0 < bkt.count ? (const_any_pointer_t)bkt.weak_value : 0); } Boolean CFDictionaryGetValueIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *value) { - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, Boolean, hc, "__getValue:forKey:", (any_t *)value, key); - if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, Boolean, hc, "__getValue:forObj:", (any_t *)value, key); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, Boolean, (NSDictionary *)hc, __getValue:(id *)value forKey:(id)key); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, Boolean, (NSSet *)hc, __getValue:(id *)value forObj:(id)key); __CFGenericValidateType(hc, __kCFDictionaryTypeID); CFBasicHashBucket bkt = CFBasicHashFindBucket((CFBasicHashRef)hc, (uintptr_t)key); if (0 < bkt.count) { @@ -622,19 +628,18 @@ Boolean CFDictionaryGetValueIfPresent(CFHashRef hc, const_any_pointer_t key, con #if CFDictionary CFIndex CFDictionaryGetCountOfValue(CFHashRef hc, const_any_pointer_t value) { - CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, CFIndex, hc, "countForObject:", value); + CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, CFIndex, (NSDictionary *)hc, countForObject:(id)value); __CFGenericValidateType(hc, __kCFDictionaryTypeID); return CFBasicHashGetCountOfValue((CFBasicHashRef)hc, (uintptr_t)value); } Boolean CFDictionaryContainsValue(CFHashRef hc, const_any_pointer_t value) { - CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, char, hc, "containsObject:", value); + CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, char, (NSDictionary *)hc, containsObject:(id)value); __CFGenericValidateType(hc, __kCFDictionaryTypeID); return (0 < CFBasicHashGetCountOfValue((CFBasicHashRef)hc, (uintptr_t)value)); } CF_EXPORT Boolean CFDictionaryGetKeyIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *actualkey) { - CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, Boolean, hc, "getActualKey:forKey:", actualkey, key); __CFGenericValidateType(hc, __kCFDictionaryTypeID); CFBasicHashBucket bkt = CFBasicHashFindBucket((CFBasicHashRef)hc, (uintptr_t)key); if (0 < bkt.count) { @@ -658,8 +663,8 @@ void CFDictionaryGetKeysAndValues(CFHashRef hc, const_any_pointer_t *keybuf, con void CFDictionaryGetValues(CFHashRef hc, const_any_pointer_t *keybuf) { const_any_pointer_t *valuebuf = 0; #endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, void, hc, "getObjects:andKeys:", (any_t *)valuebuf, (any_t *)keybuf); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, void, hc, "getObjects:", (any_t *)keybuf); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, void, (NSDictionary *)hc, getObjects:(id *)valuebuf andKeys:(id *)keybuf); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, void, (NSSet *)hc, getObjects:(id *)keybuf); __CFGenericValidateType(hc, __kCFDictionaryTypeID); if (kCFUseCollectableAllocator) { CFOptionFlags flags = CFBasicHashGetFlags((CFBasicHashRef)hc); @@ -681,8 +686,8 @@ void CFDictionaryGetValues(CFHashRef hc, const_any_pointer_t *keybuf) { void CFDictionaryApplyFunction(CFHashRef hc, CFDictionaryApplierFunction applier, any_pointer_t context) { FAULT_CALLBACK((void **)&(applier)); - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, void, hc, "__apply:context:", applier, context); - if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, void, hc, "__applyValues:context:", applier, context); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, void, (NSDictionary *)hc, __apply:(void (*)(const void *, const void *, void *))applier context:(void *)context); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, void, (NSSet *)hc, __applyValues:(void (*)(const void *, void *))applier context:(void *)context); __CFGenericValidateType(hc, __kCFDictionaryTypeID); CFBasicHashApply((CFBasicHashRef)hc, ^(CFBasicHashBucket bkt) { #if CFDictionary @@ -756,8 +761,8 @@ void CFDictionaryAddValue(CFMutableHashRef hc, const_any_pointer_t key, const_an void CFDictionaryAddValue(CFMutableHashRef hc, const_any_pointer_t key) { const_any_pointer_t value = key; #endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, void, hc, "addObject:forKey:", value, key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, void, hc, "addObject:", key); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, void, (NSMutableDictionary *)hc, __addObject:(id)value forKey:(id)key); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, void, (NSMutableSet *)hc, addObject:(id)key); __CFGenericValidateType(hc, __kCFDictionaryTypeID); CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { @@ -775,8 +780,8 @@ void CFDictionaryReplaceValue(CFMutableHashRef hc, const_any_pointer_t key, cons void CFDictionaryReplaceValue(CFMutableHashRef hc, const_any_pointer_t key) { const_any_pointer_t value = key; #endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, void, hc, "replaceObject:forKey:", value, key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, void, hc, "replaceObject:", key); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, void, (NSMutableDictionary *)hc, replaceObject:(id)value forKey:(id)key); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, void, (NSMutableSet *)hc, replaceObject:(id)key); __CFGenericValidateType(hc, __kCFDictionaryTypeID); CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { @@ -794,8 +799,8 @@ void CFDictionarySetValue(CFMutableHashRef hc, const_any_pointer_t key, const_an void CFDictionarySetValue(CFMutableHashRef hc, const_any_pointer_t key) { const_any_pointer_t value = key; #endif - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, void, hc, "setObject:forKey:", value, key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, void, hc, "setObject:", key); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, void, (NSMutableDictionary *)hc, __setObject:(id)value forKey:(id)key); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, void, (NSMutableSet *)hc, setObject:(id)key); __CFGenericValidateType(hc, __kCFDictionaryTypeID); CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { @@ -808,8 +813,8 @@ void CFDictionarySetValue(CFMutableHashRef hc, const_any_pointer_t key) { } void CFDictionaryRemoveValue(CFMutableHashRef hc, const_any_pointer_t key) { - if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, void, hc, "removeObjectForKey:", key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, void, hc, "removeObject:", key); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, void, (NSMutableDictionary *)hc, removeObjectForKey:(id)key); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, void, (NSMutableSet *)hc, removeObject:(id)key); __CFGenericValidateType(hc, __kCFDictionaryTypeID); CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { @@ -821,8 +826,8 @@ void CFDictionaryRemoveValue(CFMutableHashRef hc, const_any_pointer_t key) { } void CFDictionaryRemoveAllValues(CFMutableHashRef hc) { - if (CFDictionary) CF_OBJC_FUNCDISPATCH0(__kCFDictionaryTypeID, void, hc, "removeAllObjects"); - if (CFSet) CF_OBJC_FUNCDISPATCH0(__kCFDictionaryTypeID, void, hc, "removeAllObjects"); + if (CFDictionary) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, void, (NSMutableDictionary *)hc, removeAllObjects); + if (CFSet) CF_OBJC_FUNCDISPATCHV(__kCFDictionaryTypeID, void, (NSMutableSet *)hc, removeAllObjects); __CFGenericValidateType(hc, __kCFDictionaryTypeID); CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { diff --git a/CFDictionary.h b/CFDictionary.h index 590c990..41c75d2 100644 --- a/CFDictionary.h +++ b/CFDictionary.h @@ -22,7 +22,7 @@ */ /* CFDictionary.h - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. */ /*! @@ -84,6 +84,7 @@ #include +CF_IMPLICIT_BRIDGING_ENABLED CF_EXTERN_C_BEGIN /*! @@ -685,6 +686,7 @@ CF_EXPORT void CFDictionaryRemoveAllValues(CFMutableDictionaryRef theDict); CF_EXTERN_C_END +CF_IMPLICIT_BRIDGING_DISABLED #endif /* ! __COREFOUNDATION_CFDICTIONARY__ */ diff --git a/CFError.c b/CFError.c index df64105..d1cee84 100644 --- a/CFError.c +++ b/CFError.c @@ -22,7 +22,7 @@ */ /* CFError.c - Copyright (c) 2006-2011, Apple Inc. All rights reserved. + Copyright (c) 2006-2012, Apple Inc. All rights reserved. Responsibility: Ali Ozer */ @@ -34,6 +34,7 @@ #include #endif + /* Pre-defined userInfo keys */ CONST_STRING_DECL(kCFErrorLocalizedDescriptionKey, "NSLocalizedDescription"); @@ -198,7 +199,7 @@ static CFDictionaryRef _CFErrorCreateEmptyDictionary(CFAllocatorRef allocator) { /* A non-retained accessor for the userInfo. Might return NULL in some cases, if the subclass of NSError returned nil for some reason. It works with a CF or NSError. */ static CFDictionaryRef _CFErrorGetUserInfo(CFErrorRef err) { - CF_OBJC_FUNCDISPATCH0(__kCFErrorTypeID, CFDictionaryRef, err, "userInfo"); + CF_OBJC_FUNCDISPATCHV(__kCFErrorTypeID, CFDictionaryRef, (NSError *)err, userInfo); __CFAssertIsError(err); return err->userInfo; } @@ -314,7 +315,7 @@ CFStringRef _CFErrorCreateDebugDescription(CFErrorRef err) { CFStringAppendFormat(result, NULL, CFSTR("Error Domain=%@ Code=%d"), CFErrorGetDomain(err), (long)CFErrorGetCode(err)); CFStringAppendFormat(result, NULL, CFSTR(" \"%@\""), desc); if (debugDesc && CFStringGetLength(debugDesc) > 0) CFStringAppendFormat(result, NULL, CFSTR(" (%@)"), debugDesc); - if (userInfo) { + if (userInfo && CFDictionaryGetCount(userInfo)) { CFStringAppendFormat(result, NULL, CFSTR(" UserInfo=%p {"), userInfo); CFDictionaryApplyFunction(userInfo, userInfoKeyValueShow, (void *)result); CFIndex commaLength = (CFStringHasSuffix(result, CFSTR(", "))) ? 2 : 0; @@ -362,13 +363,13 @@ CFErrorRef CFErrorCreateWithUserInfoKeysAndValues(CFAllocatorRef allocator, CFSt } CFStringRef CFErrorGetDomain(CFErrorRef err) { - CF_OBJC_FUNCDISPATCH0(__kCFErrorTypeID, CFStringRef, err, "domain"); + CF_OBJC_FUNCDISPATCHV(__kCFErrorTypeID, CFStringRef, (NSError *)err, domain); __CFAssertIsError(err); return err->domain; } CFIndex CFErrorGetCode(CFErrorRef err) { - CF_OBJC_FUNCDISPATCH0(__kCFErrorTypeID, CFIndex, err, "code"); + CF_OBJC_FUNCDISPATCHV(__kCFErrorTypeID, CFIndex, (NSError *)err, code); __CFAssertIsError(err); return err->code; } @@ -382,8 +383,7 @@ CFDictionaryRef CFErrorCopyUserInfo(CFErrorRef err) { CFStringRef CFErrorCopyDescription(CFErrorRef err) { if (CF_IS_OBJC(__kCFErrorTypeID, err)) { // Since we have to return a retained result, we need to treat the toll-free bridging specially - CFStringRef desc; - CF_OBJC_CALL0(CFStringRef, desc, err, "localizedDescription"); + CFStringRef desc = (CFStringRef) CF_OBJC_CALLV((NSError *)err, localizedDescription); return desc ? (CFStringRef)CFRetain(desc) : NULL; // !!! It really should never return nil. } __CFAssertIsError(err); @@ -392,8 +392,7 @@ CFStringRef CFErrorCopyDescription(CFErrorRef err) { CFStringRef CFErrorCopyFailureReason(CFErrorRef err) { if (CF_IS_OBJC(__kCFErrorTypeID, err)) { // Since we have to return a retained result, we need to treat the toll-free bridging specially - CFStringRef str; - CF_OBJC_CALL0(CFStringRef, str, err, "localizedFailureReason"); + CFStringRef str = (CFStringRef) CF_OBJC_CALLV((NSError *)err, localizedFailureReason); return str ? (CFStringRef)CFRetain(str) : NULL; // It's possible for localizedFailureReason to return nil } __CFAssertIsError(err); @@ -402,8 +401,7 @@ CFStringRef CFErrorCopyFailureReason(CFErrorRef err) { CFStringRef CFErrorCopyRecoverySuggestion(CFErrorRef err) { if (CF_IS_OBJC(__kCFErrorTypeID, err)) { // Since we have to return a retained result, we need to treat the toll-free bridging specially - CFStringRef str; - CF_OBJC_CALL0(CFStringRef, str, err, "localizedRecoverySuggestion"); + CFStringRef str = (CFStringRef) CF_OBJC_CALLV((NSError *)err, localizedRecoverySuggestion); return str ? (CFStringRef)CFRetain(str) : NULL; // It's possible for localizedRecoverySuggestion to return nil } __CFAssertIsError(err); @@ -435,26 +433,30 @@ static CFTypeRef _CFErrorPOSIXCallBack(CFErrorRef err, CFStringRef key) { CFArrayRef paths = CFCopySearchPathForDirectoriesInDomains(kCFLibraryDirectory, kCFSystemDomainMask, false); if (paths) { if (CFArrayGetCount(paths) > 0) { - CFStringRef path = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@/CoreServices/CoreTypes.bundle"), CFArrayGetValueAtIndex(paths, 0)); - CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, path, kCFURLPOSIXPathStyle, false /* not a directory */); - if (url) { - CFBundleRef bundle = CFBundleCreate(kCFAllocatorSystemDefault, url); - if (bundle) { - // We only want to return a result if there was a localization - CFStringRef localizedErrStr = CFBundleCopyLocalizedString(bundle, errStr, errStr, CFSTR("ErrnoErrors")); - if (localizedErrStr == errStr) { - CFRelease(localizedErrStr); - CFRelease(errStr); - errStr = NULL; - } else { - CFRelease(errStr); - errStr = localizedErrStr; - } - CFRelease(bundle); - } - CFRelease(url); - } - CFRelease(path); + CFStringRef fileSystemPath = CFURLCopyFileSystemPath((CFURLRef)CFArrayGetValueAtIndex(paths, 0), kCFURLPOSIXPathStyle); + if (fileSystemPath) { + CFStringRef path = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@/CoreServices/CoreTypes.bundle"), fileSystemPath); + CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, path, kCFURLPOSIXPathStyle, false /* not a directory */); + CFRelease(fileSystemPath); + if (url) { + CFBundleRef bundle = CFBundleCreate(kCFAllocatorSystemDefault, url); + if (bundle) { + // We only want to return a result if there was a localization + CFStringRef localizedErrStr = CFBundleCopyLocalizedString(bundle, errStr, errStr, CFSTR("ErrnoErrors")); + if (localizedErrStr == errStr) { + CFRelease(localizedErrStr); + CFRelease(errStr); + errStr = NULL; + } else { + CFRelease(errStr); + errStr = localizedErrStr; + } + CFRelease(bundle); + } + CFRelease(url); + } + CFRelease(path); + } } CFRelease(paths); } @@ -500,7 +502,7 @@ void CFErrorSetCallBackForDomain(CFStringRef domainName, CFErrorUserInfoKeyCallB if (!_CFErrorCallBackTable) _CFErrorInitializeCallBackTable(); __CFSpinLock(&_CFErrorSpinlock); if (callBack) { - CFDictionarySetValue(_CFErrorCallBackTable, domainName, callBack); + CFDictionarySetValue(_CFErrorCallBackTable, domainName, (void *)callBack); } else { CFDictionaryRemoveValue(_CFErrorCallBackTable, domainName); } diff --git a/CFError.h b/CFError.h index a887811..61ee8a1 100644 --- a/CFError.h +++ b/CFError.h @@ -22,7 +22,7 @@ */ /* CFError.h - Copyright (c) 2006-2011, Apple Inc. All rights reserved. + Copyright (c) 2006-2012, Apple Inc. All rights reserved. */ /*! @@ -56,6 +56,7 @@ #include #include +CF_IMPLICIT_BRIDGING_ENABLED CF_EXTERN_C_BEGIN /*! @@ -190,6 +191,7 @@ CFStringRef CFErrorCopyRecoverySuggestion(CFErrorRef err) CF_AVAILABLE(10_5, 2_0 CF_EXTERN_C_END +CF_IMPLICIT_BRIDGING_DISABLED #endif /* ! __COREFOUNDATION_CFERROR__ */ diff --git a/CFError_Private.h b/CFError_Private.h index d43971c..6a9b6ef 100644 --- a/CFError_Private.h +++ b/CFError_Private.h @@ -22,7 +22,7 @@ */ /* CFError_Private.h - Copyright (c) 2006-2011, Apple Inc. All rights reserved. + Copyright (c) 2006-2012, Apple Inc. All rights reserved. This is Apple-internal SPI for CFError. */ diff --git a/CFFileUtilities.c b/CFFileUtilities.c index 0bffeb9..4334b0e 100644 --- a/CFFileUtilities.c +++ b/CFFileUtilities.c @@ -22,17 +22,21 @@ */ /* CFFileUtilities.c - Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Copyright (c) 1999-2012, Apple Inc. All rights reserved. Responsibility: Tony Parker */ #include "CFInternal.h" #include + +#include +#include +#include +#include + #if DEPLOYMENT_TARGET_WINDOWS #include #include -#include -#include #define close _close #define write _write @@ -47,15 +51,12 @@ #define statinfo _stat #else - #include - #include - #include - #include - #include - #include - #include - #include - #include + +#include +#include +#include +#include +#include #define statinfo stat @@ -70,10 +71,7 @@ CF_INLINE int openAutoFSNoWait() { } CF_INLINE void closeAutoFSNoWait(int fd) { -#if DEPLOYMENT_TARGET_WINDOWS -#else if (-1 != fd) close(fd); -#endif } __private_extern__ CFStringRef _CFCopyExtensionForAbstractType(CFStringRef abstractType) { @@ -88,13 +86,6 @@ __private_extern__ Boolean _CFCreateDirectory(const char *path) { return ret; } -#if DEPLOYMENT_TARGET_WINDOWS -// todo: remove this function and make callers use _CFCreateDirectory -__private_extern__ Boolean _CFCreateDirectoryWide(const wchar_t *path) { - return CreateDirectoryW(path, 0); -} -#endif - __private_extern__ Boolean _CFRemoveDirectory(const char *path) { int no_hang_fd = openAutoFSNoWait(); int ret = ((rmdir(path) == 0) ? true : false); @@ -109,34 +100,30 @@ __private_extern__ Boolean _CFDeleteFile(const char *path) { return ret; } -__private_extern__ Boolean _CFReadBytesFromFile(CFAllocatorRef alloc, CFURLRef url, void **bytes, CFIndex *length, CFIndex maxLength) { - // maxLength is the number of bytes desired, or 0 if the whole file is desired regardless of length. - int fd = -1; +__private_extern__ Boolean _CFReadBytesFromPathAndGetFD(CFAllocatorRef alloc, const char *path, void **bytes, CFIndex *length, CFIndex maxLength, int extraOpenFlags, int *fd) { // maxLength is the number of bytes desired, or 0 if the whole file is desired regardless of length. struct statinfo statBuf; - char path[CFMaxPathSize]; - if (!CFURLGetFileSystemRepresentation(url, true, (uint8_t *)path, CFMaxPathSize)) { - return false; - } - + *bytes = NULL; - + int no_hang_fd = openAutoFSNoWait(); - fd = open(path, O_RDONLY|CF_OPENFLGS, 0666); - - if (fd < 0) { + *fd = open(path, O_RDONLY|extraOpenFlags|CF_OPENFLGS, 0666); + + if (*fd < 0) { closeAutoFSNoWait(no_hang_fd); return false; } - if (fstat(fd, &statBuf) < 0) { + if (fstat(*fd, &statBuf) < 0) { int saveerr = thread_errno(); - close(fd); + close(*fd); + *fd = -1; closeAutoFSNoWait(no_hang_fd); thread_set_errno(saveerr); return false; } if ((statBuf.st_mode & S_IFMT) != S_IFREG) { - close(fd); + close(*fd); + *fd = -1; closeAutoFSNoWait(no_hang_fd); thread_set_errno(EACCES); return false; @@ -154,20 +141,38 @@ __private_extern__ Boolean _CFReadBytesFromFile(CFAllocatorRef alloc, CFURLRef u } *bytes = CFAllocatorAllocate(alloc, desiredLength, 0); if (__CFOASafe) __CFSetLastAllocationEventName(*bytes, "CFUtilities (file-bytes)"); -// fcntl(fd, F_NOCACHE, 1); - if (read(fd, *bytes, desiredLength) < 0) { + // fcntl(fd, F_NOCACHE, 1); + if (read(*fd, *bytes, desiredLength) < 0) { CFAllocatorDeallocate(alloc, *bytes); - close(fd); - closeAutoFSNoWait(no_hang_fd); + close(*fd); + *fd = -1; + closeAutoFSNoWait(no_hang_fd); return false; } *length = desiredLength; } - close(fd); closeAutoFSNoWait(no_hang_fd); return true; } +__private_extern__ Boolean _CFReadBytesFromPath(CFAllocatorRef alloc, const char *path, void **bytes, CFIndex *length, CFIndex maxLength, int extraOpenFlags) { + int fd = -1; + Boolean result = _CFReadBytesFromPathAndGetFD(alloc, path, bytes, length, maxLength, extraOpenFlags, &fd); + if (fd >= 0) { + close(fd); + } + return result; +} +__private_extern__ Boolean _CFReadBytesFromFile(CFAllocatorRef alloc, CFURLRef url, void **bytes, CFIndex *length, CFIndex maxLength, int extraOpenFlags) { + // maxLength is the number of bytes desired, or 0 if the whole file is desired regardless of length. + + char path[CFMaxPathSize]; + if (!CFURLGetFileSystemRepresentation(url, true, (uint8_t *)path, CFMaxPathSize)) { + return false; + } + return _CFReadBytesFromPath(alloc, (const char *)path, bytes, length, maxLength, extraOpenFlags); +} + __private_extern__ Boolean _CFWriteBytesToFile(CFURLRef url, const void *bytes, CFIndex length) { int fd = -1; int mode; @@ -348,7 +353,7 @@ __private_extern__ CFMutableArrayRef _CFContentsOfDirectory(CFAllocatorRef alloc FindClose(handle); pathBuf[pathLength] = '\0'; -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD +#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD uint8_t extBuff[CFMaxPathSize]; int extBuffInteriorDotCount = 0; //people insist on using extensions like ".trace.plist", so we need to know how many dots back to look :( @@ -445,7 +450,7 @@ __private_extern__ CFMutableArrayRef _CFContentsOfDirectory(CFAllocatorRef alloc dirURL = CFURLCreateFromFileSystemRepresentation(alloc, (uint8_t *)dirPath, pathLength, true); releaseBase = true; } - if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) { + if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN || dp->d_type == DT_LNK || dp->d_type == DT_WHT) { Boolean isDir = (dp->d_type == DT_DIR); if (!isDir) { // Ugh; must stat. @@ -601,13 +606,10 @@ __private_extern__ SInt32 _CFGetFileProperties(CFAllocatorRef alloc, CFURLRef pa } -// MF:!!! Should pull in the rest of the UniChar based path utils from Foundation. -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD - #define UNIX_PATH_SEMANTICS -#elif DEPLOYMENT_TARGET_WINDOWS - #define WINDOWS_PATH_SEMANTICS +#if DEPLOYMENT_TARGET_WINDOWS +#define WINDOWS_PATH_SEMANTICS #else -#error Unknown platform +#define UNIX_PATH_SEMANTICS #endif #if defined(WINDOWS_PATH_SEMANTICS) @@ -636,6 +638,10 @@ __private_extern__ SInt32 _CFGetFileProperties(CFAllocatorRef alloc, CFURLRef pa #define IS_SLASH(C) ((C) == ':') #endif +__private_extern__ UniChar _CFGetSlash(){ + return CFPreferredSlash; +} + __private_extern__ Boolean _CFIsAbsolutePath(UniChar *unichars, CFIndex length) { if (length < 1) { return false; @@ -837,12 +843,4 @@ __private_extern__ CFIndex _CFLengthAfterDeletingPathExtension(UniChar *unichars return ((0 < start) ? start : length); } -#undef CF_OPENFLGS -#undef UNIX_PATH_SEMANTICS -#undef WINDOWS_PATH_SEMANTICS -#undef HFS_PATH_SEMANTICS -#undef CFPreferredSlash -#undef HAS_DRIVE -#undef HAS_NET -#undef IS_SLASH diff --git a/CFICUConverters.c b/CFICUConverters.c index 4094da4..3414ca3 100644 --- a/CFICUConverters.c +++ b/CFICUConverters.c @@ -22,7 +22,7 @@ */ /* CFICUConverters.c - Copyright (c) 2004-2011, Apple Inc. All rights reserved. + Copyright (c) 2004-2012, Apple Inc. All rights reserved. Responsibility: Aki Inoue */ @@ -238,7 +238,7 @@ static CFIndex __CFStringEncodingConverterReleaseICUConverter(UConverter *conver #define MAX_BUFFER_SIZE (1000) #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -#if (U_ICU_VERSION_MAJOR_NUM > 4) || ((U_ICU_VERSION_MAJOR_NUM == 4) && (U_ICU_VERSION_MINOR_NUM > 6)) +#if (U_ICU_VERSION_MAJOR_NUM > 49) #warning Unknown ICU version. Check binary compatibility issues for rdar://problem/6024743 #endif #endif diff --git a/CFICUConverters.h b/CFICUConverters.h index 0d6fa74..cffc26c 100644 --- a/CFICUConverters.h +++ b/CFICUConverters.h @@ -26,7 +26,7 @@ * CoreFoundation * * Created by Aki Inoue on 07/12/04. - * Copyright (c) 2007-2011, Apple Inc. All rights reserved. + * Copyright (c) 2007-2012, Apple Inc. All rights reserved. * */ diff --git a/CFInternal.h b/CFInternal.h index 4c0c22e..dffc016 100644 --- a/CFInternal.h +++ b/CFInternal.h @@ -22,7 +22,7 @@ */ /* CFInternal.h - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. */ /* @@ -87,18 +87,13 @@ CF_EXTERN_C_BEGIN #include #include #include -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX #include #include -#endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD #include -#include #include #endif -#if DEPLOYMENT_TARGET_WINDOWS #include -#endif #if defined(__BIG_ENDIAN__) @@ -123,16 +118,14 @@ CF_EXPORT CFArrayRef _CFGetWindowsBinaryDirectories(void); CF_EXPORT CFStringRef _CFStringCreateHostName(void); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI #include CF_EXPORT void _CFMachPortInstallNotifyPort(CFRunLoopRef rl, CFStringRef mode); #endif __private_extern__ CFIndex __CFActiveProcessorCount(); -#if defined(__ppc__) - #define HALT do {asm __volatile__("trap"); kill(getpid(), 9); } while (0) -#elif defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) #if defined(__GNUC__) #define HALT do {asm __volatile__("int3"); kill(getpid(), 9); } while (0) #elif defined(_MSC_VER) @@ -141,9 +134,7 @@ __private_extern__ CFIndex __CFActiveProcessorCount(); #error Compiler not supported #endif #endif -#if defined(__arm__) - #define HALT do {asm __volatile__("bkpt 0xCF"); kill(getpid(), 9); } while (0) -#endif + #if defined(DEBUG) #define __CFAssert(cond, prio, desc, a1, a2, a3, a4, a5) \ @@ -284,6 +275,11 @@ extern CFTimeInterval __CFTSRToTimeInterval(SInt64 tsr); extern CFStringRef __CFCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions); +/* Enhanced string formatting support + */ +__private_extern__ CFDictionaryRef _CFStringGetFormatSpecifierConfiguration(CFStringRef aFormatString); +__private_extern__ CFStringRef _CFStringCopyWithFomatStringConfiguration(CFStringRef aFormatString, CFDictionaryRef formatConfiguration); +__private_extern__ CFStringRef _CFCopyResolvedFormatStringWithConfiguration(CFTypeRef anObject, CFDictionaryRef aConfiguration, CFDictionaryRef formatOptions); /* result is long long or int, depending on doLonglong */ @@ -293,12 +289,11 @@ extern Boolean __CFStringScanHex(CFStringInlineBuffer *buf, SInt32 *indexPtr, un extern const char *__CFgetenv(const char *n); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX -#define STACK_BUFFER_DECL(T, N, C) T N[C] -#elif DEPLOYMENT_TARGET_WINDOWS +// This is really about the availability of C99. We don't have that on Windows, but we should everywhere else. +#if DEPLOYMENT_TARGET_WINDOWS #define STACK_BUFFER_DECL(T, N, C) T *N = (T *)_alloca((C) * sizeof(T)) #else -#error Unknown or unspecified DEPLOYMENT_TARGET +#define STACK_BUFFER_DECL(T, N, C) T N[C] #endif @@ -321,40 +316,28 @@ CF_EXPORT int __CFConstantStringClassReference[]; /* CFNetwork also has a copy of the CONST_STRING_DECL macro (for use on platforms without constant string support in cc); please warn cfnetwork-core@group.apple.com of any necessary changes to this macro. -- REW, 1/28/2002 */ -#if __CF_BIG_ENDIAN__ && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX) +#if __CF_BIG_ENDIAN__ + #define CONST_STRING_DECL(S, V) \ static struct CF_CONST_STRING __ ## S ## __ = {{(uintptr_t)&__CFConstantStringClassReference, {0x00, 0x00, 0x07, 0xc8}}, (uint8_t *)V, sizeof(V) - 1}; \ const CFStringRef S = (CFStringRef) & __ ## S ## __; #define PE_CONST_STRING_DECL(S, V) \ static struct CF_CONST_STRING __ ## S ## __ = {{(uintptr_t)&__CFConstantStringClassReference, {0x00, 0x00, 0x07, 0xc8}}, (uint8_t *)V, sizeof(V) - 1}; \ __private_extern__ const CFStringRef S = (CFStringRef) & __ ## S ## __; -#elif __CF_LITTLE_ENDIAN__ && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX) -#define CONST_STRING_DECL(S, V) \ -static struct CF_CONST_STRING __ ## S ## __ = {{(uintptr_t)&__CFConstantStringClassReference, {0xc8, 0x07, 0x00, 0x00}}, (uint8_t *)V, sizeof(V) - 1}; \ -const CFStringRef S = (CFStringRef) & __ ## S ## __; -#define PE_CONST_STRING_DECL(S, V) \ -static struct CF_CONST_STRING __ ## S ## __ = {{(uintptr_t)&__CFConstantStringClassReference, {0xc8, 0x07, 0x00, 0x00}}, (uint8_t *)V, sizeof(V) - 1}; \ -__private_extern__ const CFStringRef S = (CFStringRef) & __ ## S ## __; -#elif DEPLOYMENT_TARGET_WINDOWS + +#elif __CF_LITTLE_ENDIAN__ + #define CONST_STRING_DECL(S, V) \ static struct CF_CONST_STRING __ ## S ## __ = {{(uintptr_t)&__CFConstantStringClassReference, {0xc8, 0x07, 0x00, 0x00}}, (uint8_t *)(V), sizeof(V) - 1}; \ const CFStringRef S = (CFStringRef) & __ ## S ## __; #define PE_CONST_STRING_DECL(S, V) \ static struct CF_CONST_STRING __ ## S ## __ = {{(uintptr_t)&__CFConstantStringClassReference, {0xc8, 0x07, 0x00, 0x00}}, (uint8_t *)(V), sizeof(V) - 1}; \ __private_extern__ const CFStringRef S = (CFStringRef) & __ ## S ## __; -#endif // __BIG_ENDIAN__ -#endif // __CONSTANT_CFSTRINGS__ - -/* Buffer size for file pathname */ -#if DEPLOYMENT_TARGET_WINDOWS - #define CFMaxPathSize ((CFIndex)262) - #define CFMaxPathLength ((CFIndex)260) -#else - #define CFMaxPathSize ((CFIndex)1026) - #define CFMaxPathLength ((CFIndex)1024) #endif +#endif // __CONSTANT_CFSTRINGS__ + CF_EXPORT bool __CFOASafe; CF_EXPORT void __CFSetLastAllocationEventName(void *ptr, const char *classname); @@ -414,7 +397,7 @@ typedef OSSpinLock CFSpinLock_t; } \ OSSpinLockTry(__lockp__); }) -#elif DEPLOYMENT_TARGET_EMBEDDED +#elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI typedef OSSpinLock CFSpinLock_t; @@ -461,7 +444,7 @@ typedef int32_t CFSpinLock_t; #define CF_SPINLOCK_INIT_FOR_STRUCTS(X) (X = CFSpinLockInit) CF_INLINE void __CFSpinLock(volatile CFSpinLock_t *lock) { - while (__sync_val_compare_and_swap(lock, ~0, 0) != 0) { + while (__sync_val_compare_and_swap(lock, 0, ~0) != 0) { sleep(0); } } @@ -472,7 +455,7 @@ CF_INLINE void __CFSpinUnlock(volatile CFSpinLock_t *lock) { } CF_INLINE Boolean __CFSpinLockTry(volatile CFSpinLock_t *lock) { - return (__sync_val_compare_and_swap(lock, ~0, 0) == 0); + return (__sync_val_compare_and_swap(lock, 0, ~0) == 0); } #else @@ -484,7 +467,7 @@ CF_INLINE Boolean __CFSpinLockTry(volatile CFSpinLock_t *lock) { #endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI extern uint8_t __CF120293; extern uint8_t __CF120290; extern void __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__(void); @@ -505,11 +488,7 @@ extern void __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNC #define HAS_FORKED() 0 #endif -#if DEPLOYMENT_TARGET_WINDOWS #include -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX -#include -#endif #define thread_errno() errno #define thread_set_errno(V) do {errno = (V);} while (0) @@ -525,20 +504,16 @@ CF_EXPORT CFStringRef _CFCopyExtensionForAbstractType(CFStringRef abstractType); /* These functions all act on a c-strings which must be in the file system encoding. */ CF_EXPORT Boolean _CFCreateDirectory(const char *path); -#if DEPLOYMENT_TARGET_WINDOWS -CF_EXPORT Boolean _CFCreateDirectoryWide(const wchar_t *path); -#endif CF_EXPORT Boolean _CFRemoveDirectory(const char *path); CF_EXPORT Boolean _CFDeleteFile(const char *path); -CF_EXPORT Boolean _CFReadBytesFromFile(CFAllocatorRef alloc, CFURLRef url, void **bytes, CFIndex *length, CFIndex maxLength); +CF_EXPORT Boolean _CFReadBytesFromPathAndGetFD(CFAllocatorRef alloc, const char *path, void **bytes, CFIndex *length, CFIndex maxLength, int extraOpenFlags, int *fd); +CF_EXPORT Boolean _CFReadBytesFromPath(CFAllocatorRef alloc, const char *path, void **bytes, CFIndex *length, CFIndex maxLength, int extraOpenFlags); +CF_EXPORT Boolean _CFReadBytesFromFile(CFAllocatorRef alloc, CFURLRef url, void **bytes, CFIndex *length, CFIndex maxLength, int extraOpenFlags); /* resulting bytes are allocated from alloc which MUST be non-NULL. */ /* maxLength of zero means the whole file. Otherwise it sets a limit on the number of bytes read. */ CF_EXPORT Boolean _CFWriteBytesToFile(CFURLRef url, const void *bytes, CFIndex length); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -CF_EXPORT Boolean _CFWriteBytesToFileWithAtomicity(CFURLRef url, const void *bytes, unsigned int length, SInt32 mode, Boolean atomic); -#endif CF_EXPORT CFMutableArrayRef _CFContentsOfDirectory(CFAllocatorRef alloc, char *dirPath, void *dirSpec, CFURLRef dirURL, CFStringRef matchingAbstractType); /* On Mac OS 8/9, one of dirSpec, dirPath and dirURL must be non-NULL */ @@ -559,6 +534,7 @@ CF_EXPORT SInt32 _CFGetFileProperties(CFAllocatorRef alloc, CFURLRef pathURL, Bo /* ==================== Simple path manipulation ==================== */ /* These functions all act on a UniChar buffers. */ +CF_EXPORT UniChar _CFGetSlash(); CF_EXPORT Boolean _CFIsAbsolutePath(UniChar *unichars, CFIndex length); CF_EXPORT Boolean _CFStripTrailingPathSlashes(UniChar *unichars, CFIndex *length); __private_extern__ Boolean _CFAppendTrailingPathSlash(UniChar *unichars, CFIndex *length, CFIndex maxLength); @@ -584,7 +560,7 @@ CF_EXPORT CFIndex _CFLengthAfterDeletingPathExtension(UniChar *unichars, CFIndex // to release (that's why this stuff is in CF*Internal*.h), // as can the definition of type info vs payload above. // -#if defined(__x86_64__) +#if __LP64__ #define CF_IS_TAGGED_OBJ(PTR) ((uintptr_t)(PTR) & 0x1) #define CF_TAGGED_OBJ_TYPE(PTR) ((uintptr_t)(PTR) & 0xF) #else @@ -594,14 +570,14 @@ CF_EXPORT CFIndex _CFLengthAfterDeletingPathExtension(UniChar *unichars, CFIndex enum { kCFTaggedObjectID_Invalid = 0, - kCFTaggedObjectID_Undefined0 = (0 << 1) + 1, - kCFTaggedObjectID_Integer = (1 << 1) + 1, + kCFTaggedObjectID_Atom = (0 << 1) + 1, + kCFTaggedObjectID_Undefined3 = (1 << 1) + 1, kCFTaggedObjectID_Undefined2 = (2 << 1) + 1, - kCFTaggedObjectID_Undefined3 = (3 << 1) + 1, - kCFTaggedObjectID_Undefined4 = (4 << 1) + 1, + kCFTaggedObjectID_Integer = (3 << 1) + 1, + kCFTaggedObjectID_DateTS = (4 << 1) + 1, kCFTaggedObjectID_ManagedObjectID = (5 << 1) + 1, // Core Data kCFTaggedObjectID_Date = (6 << 1) + 1, - kCFTaggedObjectID_DateTS = (7 << 1) + 1, + kCFTaggedObjectID_Undefined7 = (7 << 1) + 1, }; @@ -613,6 +589,7 @@ CF_INLINE uintptr_t __CFISAForTypeID(CFTypeID typeID) { } CF_INLINE Boolean CF_IS_OBJC(CFTypeID typeID, const void *obj) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS if (CF_IS_TAGGED_OBJ(obj)) return true; uintptr_t cfisa = ((CFRuntimeBase *)obj)->_cfisa; if (cfisa == 0) return false; @@ -634,45 +611,18 @@ CF_INLINE Boolean CF_IS_OBJC(CFTypeID typeID, const void *obj) { uintptr_t type_isa = (uintptr_t)(typeID < __CFRuntimeClassTableSize ? __CFRuntimeObjCClassTable[typeID] : 0); if (cfisa == type_isa) return false; return true; +#else + return false; +#endif } -#define STUB_CF_OBJC 1 - -#if STUB_CF_OBJC - -#define CF_IS_OBJC(typeID, obj) (false) - -#define CF_OBJC_VOIDCALL0(obj, sel) do { } while (0) -#define CF_OBJC_VOIDCALL1(obj, sel, a1) do { } while (0) -#define CF_OBJC_VOIDCALL2(obj, sel, a1, a2) do { } while (0) -#define CF_OBJC_CALL0(rettype, retvar, obj, sel) do { } while (0) -#define CF_OBJC_CALL1(rettype, retvar, obj, sel, a1) do { } while (0) -#define CF_OBJC_CALL2(rettype, retvar, obj, sel, a1, a2) do { } while (0) - -#define CF_OBJC_FUNCDISPATCH0(typeID, rettype, obj, sel) do { } while (0) -#define CF_OBJC_FUNCDISPATCH1(typeID, rettype, obj, sel, a1) do { } while (0) -#define CF_OBJC_FUNCDISPATCH2(typeID, rettype, obj, sel, a1, a2) do { } while (0) -#define CF_OBJC_FUNCDISPATCH3(typeID, rettype, obj, sel, a1, a2, a3) do { } while (0) -#define CF_OBJC_FUNCDISPATCH4(typeID, rettype, obj, sel, a1, a2, a3, a4) do { } while (0) -#define CF_OBJC_FUNCDISPATCH5(typeID, rettype, obj, sel, a1, a2, a3, a4, a5) do { } while (0) - -#endif // STUB_CF_OBJC +#define CF_OBJC_FUNCDISPATCHV(typeID, obj, ...) do { } while (0) +#define CF_OBJC_CALLV(obj, ...) (0) /* See comments in CFBase.c */ -#if SUPPORT_CFM -extern void __CF_FAULT_CALLBACK(void **ptr); -extern void *__CF_INVOKE_CALLBACK(void *, ...); -#define FAULT_CALLBACK(V) __CF_FAULT_CALLBACK(V) -#define INVOKE_CALLBACK1(P, A) (__CF_INVOKE_CALLBACK(P, A)) -#define INVOKE_CALLBACK2(P, A, B) (__CF_INVOKE_CALLBACK(P, A, B)) -#define INVOKE_CALLBACK3(P, A, B, C) (__CF_INVOKE_CALLBACK(P, A, B, C)) -#define INVOKE_CALLBACK4(P, A, B, C, D) (__CF_INVOKE_CALLBACK(P, A, B, C, D)) -#define INVOKE_CALLBACK5(P, A, B, C, D, E) (__CF_INVOKE_CALLBACK(P, A, B, C, D, E)) -#define UNFAULT_CALLBACK(V) do { V = (void *)((uintptr_t)V & ~0x3); } while (0) -#else #define FAULT_CALLBACK(V) #define INVOKE_CALLBACK1(P, A) (P)(A) #define INVOKE_CALLBACK2(P, A, B) (P)(A, B) @@ -680,7 +630,6 @@ extern void *__CF_INVOKE_CALLBACK(void *, ...); #define INVOKE_CALLBACK4(P, A, B, C, D) (P)(A, B, C, D) #define INVOKE_CALLBACK5(P, A, B, C, D, E) (P)(A, B, C, D, E) #define UNFAULT_CALLBACK(V) do { } while (0) -#endif /* For the support of functionality which needs CarbonCore or other frameworks */ // These macros define an upcall or weak "symbol-lookup" wrapper function. @@ -727,17 +676,30 @@ static R __CFNetwork_ ## N P { \ } #else - #define DEFINE_WEAK_CFNETWORK_FUNC(R, N, P, A, ...) #define DEFINE_WEAK_CFNETWORK_FUNC_FAIL(R, N, P, A, ...) - #endif - -#if !defined(DEFINE_WEAK_CARBONCORE_FUNC) #define DEFINE_WEAK_CARBONCORE_FUNC(R, N, P, A, ...) -#endif -#if !defined(DEFINE_WEAK_CORESERVICESINTERNAL_FUNC) + +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + +extern void *__CFLookupCoreServicesInternalFunction(const char *name); + +#define DEFINE_WEAK_CORESERVICESINTERNAL_FUNC(R, N, P, A, ...) \ + static R __CFCoreServicesInternal_ ## N P { \ + typedef R (*dyfuncptr)P; \ + static dyfuncptr dyfunc = (dyfuncptr)(~(uintptr_t)0); \ + if ((dyfuncptr)(~(uintptr_t)0) == dyfunc) { \ + dyfunc = (dyfuncptr)__CFLookupCoreServicesInternalFunction(#N); \ + } \ + if (dyfunc) { \ + return dyfunc A ; \ + } \ + return __VA_ARGS__ ; \ + } + +#else #define DEFINE_WEAK_CORESERVICESINTERNAL_FUNC(R, N, P, A, ...) #endif @@ -760,15 +722,6 @@ CF_INLINE CFAllocatorRef __CFGetAllocator(CFTypeRef cf) { // !!! Use with CF typ return *(CFAllocatorRef *)((char *)cf - sizeof(CFAllocatorRef)); } - -#if DEPLOYMENT_TARGET_WINDOWS -__private_extern__ const wchar_t *_CFDLLPath(void); -__private_extern__ void __CFStringCleanup(void); -__private_extern__ void __CFSocketCleanup(void); -__private_extern__ void __CFUniCharCleanup(void); -__private_extern__ void __CFStreamCleanup(void); -#endif - /* !!! Avoid #importing objc.h; e.g. converting this to a .m file */ struct __objcFastEnumerationStateEquivalent { unsigned long state; @@ -777,6 +730,57 @@ struct __objcFastEnumerationStateEquivalent { unsigned long extra[5]; }; +#pragma mark - +#pragma mark Windows Compatability + +// Need to use the _O_BINARY flag on Windows to get the correct behavior +#if DEPLOYMENT_TARGET_WINDOWS +#define CF_OPENFLGS (_O_BINARY|_O_NOINHERIT) +#else +#define CF_OPENFLGS (0) +#endif + +#if DEPLOYMENT_TARGET_WINDOWS + +// These are replacements for pthread calls on Windows +CF_EXPORT int _NS_pthread_main_np(); +CF_EXPORT int _NS_pthread_setspecific(pthread_key_t key, const void *val); +CF_EXPORT void* _NS_pthread_getspecific(pthread_key_t key); +CF_EXPORT int _NS_pthread_key_init_np(int key, void (*destructor)(void *)); +CF_EXPORT void _NS_pthread_setname_np(const char *name); + +// map use of pthread_set/getspecific to internal API +#define pthread_setspecific _NS_pthread_setspecific +#define pthread_getspecific _NS_pthread_getspecific +#define pthread_key_init_np _NS_pthread_key_init_np +#define pthread_main_np _NS_pthread_main_np +#define pthread_setname_np _NS_pthread_setname_np +#endif + +#if DEPLOYMENT_TARGET_WINDOWS +// replacement for DISPATCH_QUEUE_OVERCOMMIT until we get a bug fix in dispatch on Windows +// dispatch on Windows: Need queue_private.h +#define DISPATCH_QUEUE_OVERCOMMIT 2 +#endif + +#if DEPLOYMENT_TARGET_WINDOWS +__private_extern__ const wchar_t *_CFDLLPath(void); +#endif + +/* Buffer size for file pathname */ +#if DEPLOYMENT_TARGET_WINDOWS +#define CFMaxPathSize ((CFIndex)262) +#define CFMaxPathLength ((CFIndex)260) +#define PATH_SEP '\\' +#define PATH_SEP_STR CFSTR("\\") +#define PATH_MAX MAX_PATH +#else +#define CFMaxPathSize ((CFIndex)1026) +#define CFMaxPathLength ((CFIndex)1024) +#define PATH_SEP '/' +#define PATH_SEP_STR CFSTR("/") +#endif + CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFINTERNAL__ */ diff --git a/CFLocale.c b/CFLocale.c index d8d356c..d6eb54d 100644 --- a/CFLocale.c +++ b/CFLocale.c @@ -22,7 +22,7 @@ */ /* CFLocale.c - Copyright (c) 2002-2011, Apple Inc. All rights reserved. + Copyright (c) 2002-2012, Apple Inc. All rights reserved. Responsibility: David Smith */ @@ -37,6 +37,7 @@ #include #include "CFInternal.h" #include "CFLocaleInternal.h" +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX #include // ICU locales #include // ICU locale data #include @@ -44,16 +45,26 @@ #include // ICU Unicode sets #include // ICU low-level utilities #include // ICU message formatting -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX +#include +#endif #include #include #include -#include -#elif DEPLOYMENT_TARGET_WINDOWS -#include -#endif #include +#if DEPLOYMENT_TARGET_EMBEDDED_MINI +// Some compatability definitions +#define ULOC_FULLNAME_CAPACITY 157 +#define ULOC_KEYWORD_AND_VALUES_CAPACITY 100 + +//typedef long UErrorCode; +//#define U_BUFFER_OVERFLOW_ERROR 15 +//#define U_ZERO_ERROR 0 +// +//typedef uint16_t UChar; +#endif + + CONST_STRING_DECL(kCFLocaleCurrentLocaleDidChangeNotification, "kCFLocaleCurrentLocaleDidChangeNotification") static const char *kCalendarKeyword = "calendar"; @@ -282,23 +293,45 @@ static CFLocaleRef __CFLocaleCurrent = NULL; #if DEPLOYMENT_TARGET_MACOSX #define FALLBACK_LOCALE_NAME CFSTR("") -#elif DEPLOYMENT_TARGET_EMBEDDED +#elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI #define FALLBACK_LOCALE_NAME CFSTR("en_US") #elif DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX #define FALLBACK_LOCALE_NAME CFSTR("en_US") -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif CFLocaleRef CFLocaleCopyCurrent(void) { + CFStringRef name = NULL, ident = NULL; + // We cannot be helpful here, because it causes performance problems, + // even though the preference lookup is relatively quick, as there are + // things which call this function thousands or millions of times in + // a short period. +#if 0 // DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX + name = (CFStringRef)CFPreferencesCopyAppValue(CFSTR("AppleLocale"), kCFPreferencesCurrentApplication); +#endif + if (name && (CFStringGetTypeID() == CFGetTypeID(name))) { + ident = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault, name); + } + if (name) CFRelease(name); + CFLocaleRef oldLocale = NULL; __CFLocaleLockGlobal(); if (__CFLocaleCurrent) { - CFRetain(__CFLocaleCurrent); - __CFLocaleUnlockGlobal(); - return __CFLocaleCurrent; + if (ident && !CFEqual(__CFLocaleCurrent->_identifier, ident)) { + oldLocale = __CFLocaleCurrent; + __CFLocaleCurrent = NULL; + } else { + CFLocaleRef res = __CFLocaleCurrent; + CFRetain(res); + __CFLocaleUnlockGlobal(); + if (ident) CFRelease(ident); + return res; + } } __CFLocaleUnlockGlobal(); + if (oldLocale) CFRelease(oldLocale); + if (ident) CFRelease(ident); + // We could *probably* re-use ident down below, but that would't + // get us out of querying CFPrefs for the current application state. CFDictionaryRef prefs = NULL; CFStringRef identifier = NULL; @@ -332,7 +365,7 @@ CFLocaleRef CFLocaleCopyCurrent(void) { } __private_extern__ CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale) { - CF_OBJC_FUNCDISPATCH0(CFLocaleGetTypeID(), CFDictionaryRef, locale, "_prefs"); + CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFDictionaryRef, (NSLocale *)locale, _prefs); return locale->_prefs; } @@ -390,7 +423,7 @@ CFLocaleRef CFLocaleCreateCopy(CFAllocatorRef allocator, CFLocaleRef locale) { } CFStringRef CFLocaleGetIdentifier(CFLocaleRef locale) { - CF_OBJC_FUNCDISPATCH0(CFLocaleGetTypeID(), CFStringRef, locale, "localeIdentifier"); + CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFStringRef, (NSLocale *)locale, localeIdentifier); return locale->_identifier; } @@ -404,7 +437,7 @@ CFTypeRef CFLocaleGetValue(CFLocaleRef locale, CFStringRef key) { } } #endif - CF_OBJC_FUNCDISPATCH1(CFLocaleGetTypeID(), CFTypeRef, locale, "objectForKey:", key); + CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFTypeRef, (NSLocale *)locale, objectForKey:(id)key); CFIndex idx, slot = -1; for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { if (__CFLocaleKeyTable[idx].key == key) { @@ -449,7 +482,7 @@ CFTypeRef CFLocaleGetValue(CFLocaleRef locale, CFStringRef key) { } CFStringRef CFLocaleCopyDisplayNameForPropertyValue(CFLocaleRef displayLocale, CFStringRef key, CFStringRef value) { - CF_OBJC_FUNCDISPATCH2(CFLocaleGetTypeID(), CFStringRef, displayLocale, "_copyDisplayNameForKey:value:", key, value); + CF_OBJC_FUNCDISPATCHV(CFLocaleGetTypeID(), CFStringRef, (NSLocale *)displayLocale, _copyDisplayNameForKey:(id)key value:(id)value); CFIndex idx, slot = -1; for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { if (__CFLocaleKeyTable[idx].key == key) { @@ -478,12 +511,14 @@ CFStringRef CFLocaleCopyDisplayNameForPropertyValue(CFLocaleRef displayLocale, C } // We could not find a result using the requested language. Fall back through all preferred languages. - CFArrayRef langPref; + CFArrayRef langPref = NULL; if (displayLocale->_prefs) { langPref = (CFArrayRef)CFDictionaryGetValue(displayLocale->_prefs, CFSTR("AppleLanguages")); if (langPref) CFRetain(langPref); } else { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX langPref = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication); +#endif } if (langPref != NULL) { CFIndex count = CFArrayGetCount(langPref); @@ -506,6 +541,7 @@ CFStringRef CFLocaleCopyDisplayNameForPropertyValue(CFLocaleRef displayLocale, C } CFArrayRef CFLocaleCopyAvailableLocaleIdentifiers(void) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX int32_t locale, localeCount = uloc_countAvailable(); CFMutableSetRef working = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); for (locale = 0; locale < localeCount; ++locale) { @@ -521,8 +557,12 @@ CFArrayRef CFLocaleCopyAvailableLocaleIdentifiers(void) { CFArrayRef result = CFArrayCreate(kCFAllocatorSystemDefault, buffer, cnt, &kCFTypeArrayCallBacks); CFRelease(working); return result; +#else + return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); +#endif } +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX static CFArrayRef __CFLocaleCopyCStringsAsArray(const char* const* p) { CFMutableArrayRef working = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); for (; *p; ++p) { @@ -559,34 +599,52 @@ static CFArrayRef __CFLocaleCopyUEnumerationAsArray(UEnumeration *enumer, UError } return result; } +#endif CFArrayRef CFLocaleCopyISOLanguageCodes(void) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX const char* const* p = uloc_getISOLanguages(); return __CFLocaleCopyCStringsAsArray(p); +#else + return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); +#endif } CFArrayRef CFLocaleCopyISOCountryCodes(void) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX const char* const* p = uloc_getISOCountries(); return __CFLocaleCopyCStringsAsArray(p); +#else + return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); +#endif } CFArrayRef CFLocaleCopyISOCurrencyCodes(void) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX UErrorCode icuStatus = U_ZERO_ERROR; UEnumeration *enumer = ucurr_openISOCurrencies(UCURR_ALL, &icuStatus); CFArrayRef result = __CFLocaleCopyUEnumerationAsArray(enumer, &icuStatus); uenum_close(enumer); +#else + CFArrayRef result = CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); +#endif return result; } CFArrayRef CFLocaleCopyCommonISOCurrencyCodes(void) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX UErrorCode icuStatus = U_ZERO_ERROR; UEnumeration *enumer = ucurr_openISOCurrencies(UCURR_COMMON|UCURR_NON_DEPRECATED, &icuStatus); CFArrayRef result = __CFLocaleCopyUEnumerationAsArray(enumer, &icuStatus); uenum_close(enumer); +#else + CFArrayRef result = CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); +#endif return result; } CFStringRef CFLocaleCreateLocaleIdentifierFromWindowsLocaleCode(CFAllocatorRef allocator, uint32_t lcid) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX char buffer[kMaxICUNameSize]; UErrorCode status = U_ZERO_ERROR; int32_t ret = uloc_getLocaleForLCID(lcid, buffer, kMaxICUNameSize, &status); @@ -595,19 +653,27 @@ CFStringRef CFLocaleCreateLocaleIdentifierFromWindowsLocaleCode(CFAllocatorRef a CFStringRef ident = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault, str); CFRelease(str); return ident; +#else + return CFSTR(""); +#endif } uint32_t CFLocaleGetWindowsLocaleCodeFromLocaleIdentifier(CFStringRef localeIdentifier) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX CFStringRef ident = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault, localeIdentifier); char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; - Boolean b = CFStringGetCString(ident, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII); - CFRelease(ident); + Boolean b = ident ? CFStringGetCString(ident, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII) : false; + if (ident) CFRelease(ident); return b ? uloc_getLCID(localeID) : 0; +#else + return 0; +#endif } CFLocaleLanguageDirection CFLocaleGetLanguageCharacterDirection(CFStringRef isoLangCode) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; - Boolean b = CFStringGetCString(isoLangCode, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII); + Boolean b = isoLangCode ? CFStringGetCString(isoLangCode, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII) : false; CFLocaleLanguageDirection dir; UErrorCode status = U_ZERO_ERROR; ULayoutType idir = b ? uloc_getCharacterOrientation(localeID, &status) : ULOC_LAYOUT_UNKNOWN; @@ -619,11 +685,15 @@ CFLocaleLanguageDirection CFLocaleGetLanguageCharacterDirection(CFStringRef isoL default: dir = kCFLocaleLanguageDirectionUnknown; break; } return dir; +#else + return kCFLocaleLanguageDirectionLeftToRight; +#endif } CFLocaleLanguageDirection CFLocaleGetLanguageLineDirection(CFStringRef isoLangCode) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; - Boolean b = CFStringGetCString(isoLangCode, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII); + Boolean b = isoLangCode ? CFStringGetCString(isoLangCode, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII) : false; CFLocaleLanguageDirection dir; UErrorCode status = U_ZERO_ERROR; ULayoutType idir = b ? uloc_getLineOrientation(localeID, &status) : ULOC_LAYOUT_UNKNOWN; @@ -635,10 +705,14 @@ CFLocaleLanguageDirection CFLocaleGetLanguageLineDirection(CFStringRef isoLangCo default: dir = kCFLocaleLanguageDirectionUnknown; break; } return dir; +#else + return kCFLocaleLanguageDirectionLeftToRight; +#endif } CFArrayRef CFLocaleCopyPreferredLanguages(void) { CFMutableArrayRef newArray = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS CFArrayRef languagesArray = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication); if (languagesArray && (CFArrayGetTypeID() == CFGetTypeID(languagesArray))) { for (CFIndex idx = 0, cnt = CFArrayGetCount(languagesArray); idx < cnt; idx++) { @@ -651,6 +725,7 @@ CFArrayRef CFLocaleCopyPreferredLanguages(void) { } } if (languagesArray) CFRelease(languagesArray); +#endif return newArray; } @@ -686,6 +761,7 @@ static bool __CFLocaleCopyCodes(CFLocaleRef locale, bool user, CFTypeRef *cf, CF return false; } +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX CFCharacterSetRef _CFCreateCharacterSetFromUSet(USet *set) { UErrorCode icuErr = U_ZERO_ERROR; CFMutableCharacterSetRef working = CFCharacterSetCreateMutable(NULL); @@ -738,9 +814,10 @@ CFCharacterSetRef _CFCreateCharacterSetFromUSet(USet *set) { CFRelease(working); return result; } - +#endif static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) { UErrorCode icuStatus = U_ZERO_ERROR; @@ -755,11 +832,13 @@ static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale, bool user, CFTypeR uset_close(set); return (*cf != NULL); } +#endif return false; } static bool __CFLocaleCopyICUKeyword(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context, const char *keyword) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) { @@ -771,11 +850,13 @@ static bool __CFLocaleCopyICUKeyword(CFLocaleRef locale, bool user, CFTypeRef *c return true; } } +#endif *cf = NULL; return false; } static bool __CFLocaleCopyICUCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context, const char *keyword) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; if (CFStringGetCString(locale->_identifier, localeID, sizeof(localeID)/sizeof(char), kCFStringEncodingASCII)) { UErrorCode icuStatus = U_ZERO_ERROR; @@ -789,6 +870,7 @@ static bool __CFLocaleCopyICUCalendarID(CFLocaleRef locale, bool user, CFTypeRef } uenum_close(en); } +#endif *cf = NULL; return false; } @@ -853,6 +935,7 @@ static bool __CFLocaleCopyCalendarID(CFLocaleRef locale, bool user, CFTypeRef *c } static bool __CFLocaleCopyCalendar(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX if (__CFLocaleCopyCalendarID(locale, user, cf, context)) { CFCalendarRef calendar = CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault, (CFStringRef)*cf); CFCalendarSetLocale(calendar, locale); @@ -881,10 +964,12 @@ static bool __CFLocaleCopyCalendar(CFLocaleRef locale, bool user, CFTypeRef *cf, *cf = calendar; return true; } +#endif return false; } static bool __CFLocaleCopyDelimiter(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX ULocaleDataDelimiterType type = (ULocaleDataDelimiterType)0; if (context == kCFLocaleQuotationBeginDelimiterKey) { type = ULOCDATA_QUOTATION_START; @@ -914,6 +999,14 @@ static bool __CFLocaleCopyDelimiter(CFLocaleRef locale, bool user, CFTypeRef *cf *cf = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)buffer, len); return (*cf != NULL); +#else + if (context == kCFLocaleQuotationBeginDelimiterKey || context == kCFLocaleQuotationEndDelimiterKey || context == kCFLocaleAlternateQuotationBeginDelimiterKey || context == kCFLocaleAlternateQuotationEndDelimiterKey) { + *cf = CFRetain(CFSTR("\"")); + return true; + } else { + return false; + } +#endif } static bool __CFLocaleCopyCollationID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { @@ -922,7 +1015,7 @@ static bool __CFLocaleCopyCollationID(CFLocaleRef locale, bool user, CFTypeRef * static bool __CFLocaleCopyCollatorID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { CFStringRef canonLocaleCFStr = NULL; - if (user) { + if (user && locale->_prefs) { CFStringRef pref = (CFStringRef)CFDictionaryGetValue(locale->_prefs, CFSTR("AppleCollationOrder")); if (pref) { // Canonicalize pref string in case it's not in the canonical format. @@ -948,6 +1041,7 @@ static bool __CFLocaleCopyCollatorID(CFLocaleRef locale, bool user, CFTypeRef *c } static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX bool us = false; // Default is Metric bool done = false; #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED @@ -981,6 +1075,10 @@ static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale, bool user, CFTypeRef *c us = false; *cf = us ? CFRetain(kCFBooleanFalse) : CFRetain(kCFBooleanTrue); return true; +#else + *cf = CFRetain(kCFBooleanFalse); + return true; +#endif } static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { @@ -995,13 +1093,10 @@ static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale, bool user, CFTyp static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { CFStringRef str = NULL; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale, kCFNumberFormatterDecimalStyle); - str = nf ? CFNumberFormatterCopyProperty(nf, context) : NULL; + str = nf ? (CFStringRef)CFNumberFormatterCopyProperty(nf, context) : NULL; if (nf) CFRelease(nf); -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif if (str) { *cf = str; @@ -1014,13 +1109,10 @@ static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale, bool user, CFTypeRef // so we have to have another routine here which creates a Currency number formatter. static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { CFStringRef str = NULL; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale, kCFNumberFormatterCurrencyStyle); - str = nf ? CFNumberFormatterCopyProperty(nf, context) : NULL; + str = nf ? (CFStringRef)CFNumberFormatterCopyProperty(nf, context) : NULL; if (nf) CFRelease(nf); -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif if (str) { *cf = str; @@ -1029,6 +1121,7 @@ static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale, bool user, CFTypeRef return false; } +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX typedef int32_t (*__CFICUFunction)(const char *, const char *, UChar *, int32_t, UErrorCode *); static bool __CFLocaleICUName(const char *locale, const char *valLocale, CFStringRef *out, __CFICUFunction icu) { @@ -1097,8 +1190,10 @@ static bool __CFLocaleICUCurrencyName(const char *locale, const char *value, UCu *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); return (*out != NULL); } +#endif static bool __CFLocaleFullName(const char *locale, const char *value, CFStringRef *out) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX UErrorCode icuStatus = U_ZERO_ERROR; int32_t size; UChar name[kMaxICUNameSize]; @@ -1124,13 +1219,23 @@ static bool __CFLocaleFullName(const char *locale, const char *value, CFStringRe // This locale is OK, so use the result. *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); return (*out != NULL); +#else + *out = CFRetain(CFSTR("(none)")); + return true; +#endif } static bool __CFLocaleLanguageName(const char *locale, const char *value, CFStringRef *out) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX return __CFLocaleICUName(locale, value, out, uloc_getDisplayLanguage); +#else + *out = CFRetain(CFSTR("(none)")); + return true; +#endif } static bool __CFLocaleCountryName(const char *locale, const char *value, CFStringRef *out) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX // Need to make a fake locale ID char lid[ULOC_FULLNAME_CAPACITY]; if (strlen(value) < sizeof(lid) - 3) { @@ -1139,9 +1244,14 @@ static bool __CFLocaleCountryName(const char *locale, const char *value, CFStrin return __CFLocaleICUName(locale, lid, out, uloc_getDisplayCountry); } return false; +#else + *out = CFRetain(CFSTR("(none)")); + return true; +#endif } static bool __CFLocaleScriptName(const char *locale, const char *value, CFStringRef *out) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX // Need to make a fake locale ID char lid[ULOC_FULLNAME_CAPACITY]; if (strlen(value) == 4) { @@ -1151,9 +1261,14 @@ static bool __CFLocaleScriptName(const char *locale, const char *value, CFString return __CFLocaleICUName(locale, lid, out, uloc_getDisplayScript); } return false; +#else + *out = CFRetain(CFSTR("(none)")); + return true; +#endif } static bool __CFLocaleVariantName(const char *locale, const char *value, CFStringRef *out) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX // Need to make a fake locale ID char lid[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; if (strlen(value) < sizeof(lid) - 6) { @@ -1162,22 +1277,46 @@ static bool __CFLocaleVariantName(const char *locale, const char *value, CFStrin return __CFLocaleICUName(locale, lid, out, uloc_getDisplayVariant); } return false; +#else + *out = CFRetain(CFSTR("(none)")); + return true; +#endif } static bool __CFLocaleCalendarName(const char *locale, const char *value, CFStringRef *out) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX return __CFLocaleICUKeywordValueName(locale, value, kCalendarKeyword, out); +#else + *out = CFRetain(CFSTR("(none)")); + return true; +#endif } static bool __CFLocaleCollationName(const char *locale, const char *value, CFStringRef *out) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX return __CFLocaleICUKeywordValueName(locale, value, kCollationKeyword, out); +#else + *out = CFRetain(CFSTR("(none)")); + return true; +#endif } static bool __CFLocaleCurrencyShortName(const char *locale, const char *value, CFStringRef *out) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX return __CFLocaleICUCurrencyName(locale, value, UCURR_SYMBOL_NAME, out); +#else + *out = CFRetain(CFSTR("(none)")); + return true; +#endif } static bool __CFLocaleCurrencyFullName(const char *locale, const char *value, CFStringRef *out) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX return __CFLocaleICUCurrencyName(locale, value, UCURR_LONG_NAME, out); +#else + *out = CFRetain(CFSTR("(none)")); + return true; +#endif } static bool __CFLocaleNoName(const char *locale, const char *value, CFStringRef *out) { diff --git a/CFLocale.h b/CFLocale.h index ef192a3..3f575fc 100644 --- a/CFLocale.h +++ b/CFLocale.h @@ -22,7 +22,7 @@ */ /* CFLocale.h - Copyright (c) 2002-2011, Apple Inc. All rights reserved. + Copyright (c) 2002-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFLOCALE__) @@ -32,6 +32,7 @@ #include #include +CF_IMPLICIT_BRIDGING_ENABLED CF_EXTERN_C_BEGIN typedef const struct __CFLocale *CFLocaleRef; @@ -108,14 +109,13 @@ CF_EXPORT uint32_t CFLocaleGetWindowsLocaleCodeFromLocaleIdentifier(CFStringRef localeIdentifier) CF_AVAILABLE(10_6, 4_0); // Map a locale identifier to a Windows LCID. -enum { +typedef CF_ENUM(CFIndex, CFLocaleLanguageDirection) { kCFLocaleLanguageDirectionUnknown = 0, kCFLocaleLanguageDirectionLeftToRight = 1, kCFLocaleLanguageDirectionRightToLeft = 2, kCFLocaleLanguageDirectionTopToBottom = 3, kCFLocaleLanguageDirectionBottomToTop = 4 }; -typedef CFIndex CFLocaleLanguageDirection; CF_EXPORT CFLocaleLanguageDirection CFLocaleGetLanguageCharacterDirection(CFStringRef isoLangCode) CF_AVAILABLE(10_6, 4_0); @@ -208,6 +208,7 @@ CF_EXPORT const CFStringRef kCFIndianCalendar CF_AVAILABLE(10_6, 4_0); CF_EXPORT const CFStringRef kCFISO8601Calendar CF_AVAILABLE(10_6, 4_0); CF_EXTERN_C_END +CF_IMPLICIT_BRIDGING_DISABLED #endif /* ! __COREFOUNDATION_CFLOCALE__ */ diff --git a/CFLocaleIdentifier.c b/CFLocaleIdentifier.c index 8b81a05..9da7ecd 100644 --- a/CFLocaleIdentifier.c +++ b/CFLocaleIdentifier.c @@ -23,7 +23,7 @@ /* CFLocaleIdentifier.c - Copyright (c) 2002-2011, Apple Inc. All rights reserved. + Copyright (c) 2002-2012, Apple Inc. All rights reserved. Responsibility: David Smith CFLocaleIdentifier.c defines @@ -76,7 +76,13 @@ #include #include #include +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX #include +#else +#define ULOC_KEYWORD_SEPARATOR '@' +#define ULOC_FULLNAME_CAPACITY 56 +#define ULOC_KEYWORD_AND_VALUES_CAPACITY 100 +#endif #include "CFInternal.h" #include "CFLocaleInternal.h" @@ -1369,6 +1375,7 @@ static void _UpdateFullLocaleString(char inLocaleString[], int locStringMaxLen, // If so, copy the keywords to varKeyValueString and delete the variant tag // from the original string (but don't otherwise use the ICU canonicalization). varKeyValueString[0] = 0; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX if (variantTag) { UErrorCode icuStatus; int icuCanonStringLen; @@ -1397,6 +1404,7 @@ static void _UpdateFullLocaleString(char inLocaleString[], int locStringMaxLen, *varKeyValueStringPtr = 0; } } +#endif // 4. Handle special cases of updating region codes, or updating language codes based on // region code. @@ -1494,6 +1502,7 @@ static void _GetKeyValueString(char inLocaleString[], char keyValueString[]) { } static void _AppendKeyValueString(char inLocaleString[], int locStringMaxLen, char keyValueString[]) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX if (keyValueString[0] != 0) { UErrorCode uerr = U_ZERO_ERROR; UEnumeration * uenum = uloc_openKeywords(keyValueString, &uerr); @@ -1512,6 +1521,7 @@ static void _AppendKeyValueString(char inLocaleString[], int locStringMaxLen, ch uenum_close(uenum); } } +#endif } // __private_extern__ CFStringRef _CFLocaleCreateCanonicalLanguageIdentifierForCFBundle(CFAllocatorRef allocator, CFStringRef localeIdentifier) {} @@ -1711,9 +1721,12 @@ SPI: CFLocaleGetLanguageRegionEncodingForLocaleIdentifier gets the appropriate preferred localization in the current context (this function returns NO for a NULL localeIdentifier); and in this function langCode, regCode, and scriptCode are all SInt16* (not SInt32* like the equivalent parameters in CFBundleGetLocalizationInfoForLocalization). */ +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX static int CompareLocaleToLegacyCodesEntries( const void *entry1, const void *entry2 ); +#endif Boolean CFLocaleGetLanguageRegionEncodingForLocaleIdentifier(CFStringRef localeIdentifier, LangCode *langCode, RegionCode *regCode, ScriptCode *scriptCode, CFStringEncoding *stringEncoding) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX Boolean returnValue = false; CFStringRef canonicalIdentifier = CFLocaleCreateCanonicalLocaleIdentifierFromString(NULL, localeIdentifier); if (canonicalIdentifier) { @@ -1786,23 +1799,30 @@ Boolean CFLocaleGetLanguageRegionEncodingForLocaleIdentifier(CFStringRef localeI CFRelease(canonicalIdentifier); } return returnValue; +#else + return false; +#endif } +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX static int CompareLocaleToLegacyCodesEntries( const void *entry1, const void *entry2 ) { const char * localeString1 = ((const LocaleToLegacyCodes *)entry1)->locale; const char * localeString2 = ((const LocaleToLegacyCodes *)entry2)->locale; return strcmp(localeString1, localeString2); } - +#endif CFDictionaryRef CFLocaleCreateComponentsFromLocaleIdentifier(CFAllocatorRef allocator, CFStringRef localeID) { + CFMutableDictionaryRef working = CFDictionaryCreateMutable(allocator, 10, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX char cLocaleID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; char buffer[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; - CFMutableDictionaryRef working = CFDictionaryCreateMutable(allocator, 10, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); UErrorCode icuStatus = U_ZERO_ERROR; int32_t length = 0; - + + if (!localeID) goto out; + // Extract the C string locale ID, for ICU CFIndex outBytes = 0; CFStringGetBytes(localeID, CFRangeMake(0, CFStringGetLength(localeID)), kCFStringEncodingASCII, (UInt8) '?', true, (unsigned char *)cLocaleID, sizeof(cLocaleID)/sizeof(char) - 1, &outBytes); @@ -1869,6 +1889,8 @@ CFDictionaryRef CFLocaleCreateComponentsFromLocaleIdentifier(CFAllocatorRef allo } uenum_close(iter); + out:; +#endif // Convert to an immutable dictionary and return CFDictionaryRef result = CFDictionaryCreateCopy(allocator, working); CFRelease(working); @@ -1887,6 +1909,8 @@ static char *__CStringFromString(CFStringRef str) { } CFStringRef CFLocaleCreateLocaleIdentifierFromComponents(CFAllocatorRef allocator, CFDictionaryRef dictionary) { + if (!dictionary) return NULL; + CFIndex cnt = CFDictionaryGetCount(dictionary); STACK_BUFFER_DECL(CFStringRef, values, cnt); STACK_BUFFER_DECL(CFStringRef, keys, cnt); @@ -1920,6 +1944,7 @@ CFStringRef CFLocaleCreateLocaleIdentifierFromComponents(CFAllocatorRef allocato free(variant); free(buf1); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX for (CFIndex idx = 0; idx < cnt; idx++) { if (keys[idx]) { char *key = __CStringFromString(keys[idx]); @@ -1943,7 +1968,8 @@ CFStringRef CFLocaleCreateLocaleIdentifierFromComponents(CFAllocatorRef allocato free(value); } } - +#endif + return CFStringCreateWithCString(allocator, cLocaleID, kCFStringEncodingASCII); } diff --git a/CFLocaleInternal.h b/CFLocaleInternal.h index edb0ece..c1b5b98 100644 --- a/CFLocaleInternal.h +++ b/CFLocaleInternal.h @@ -23,7 +23,7 @@ /* CFLocaleInternal.h - Copyright (c) 2008-2011, Apple Inc. All rights reserved. + Copyright (c) 2008-2012, Apple Inc. All rights reserved. */ /* @@ -65,6 +65,7 @@ CF_EXPORT CFStringRef const kCFDateFormatterIsLenientKey; CF_EXPORT CFStringRef const kCFDateFormatterLongEraSymbolsKey; CF_EXPORT CFStringRef const kCFDateFormatterMonthSymbolsKey; CF_EXPORT CFStringRef const kCFDateFormatterPMSymbolKey; +CF_EXPORT CFStringRef const kCFDateFormatterAmbiguousYearStrategyKey; CF_EXPORT CFStringRef const kCFDateFormatterQuarterSymbolsKey; CF_EXPORT CFStringRef const kCFDateFormatterShortMonthSymbolsKey; CF_EXPORT CFStringRef const kCFDateFormatterShortQuarterSymbolsKey; diff --git a/CFLocaleKeys.c b/CFLocaleKeys.c index 5c6b9c3..425c9af 100644 --- a/CFLocaleKeys.c +++ b/CFLocaleKeys.c @@ -22,11 +22,11 @@ */ /* CFLocaleKeys.c - Copyright (c) 2008-2011, Apple Inc. All rights reserved. + Copyright (c) 2008-2012, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ -#include +#include "CFInternal.h" CONST_STRING_DECL(kCFLocaleAlternateQuotationBeginDelimiterKey, "kCFLocaleAlternateQuotationBeginDelimiterKey"); CONST_STRING_DECL(kCFLocaleAlternateQuotationEndDelimiterKey, "kCFLocaleAlternateQuotationEndDelimiterKey"); @@ -62,6 +62,7 @@ CONST_STRING_DECL(kCFDateFormatterIsLenientKey, "kCFDateFormatterIsLenientKey"); CONST_STRING_DECL(kCFDateFormatterLongEraSymbolsKey, "kCFDateFormatterLongEraSymbolsKey"); CONST_STRING_DECL(kCFDateFormatterMonthSymbolsKey, "kCFDateFormatterMonthSymbolsKey"); CONST_STRING_DECL(kCFDateFormatterPMSymbolKey, "kCFDateFormatterPMSymbolKey"); +CONST_STRING_DECL(kCFDateFormatterAmbiguousYearStrategyKey, "kCFDateFormatterAmbiguousYearStrategyKey"); CONST_STRING_DECL(kCFDateFormatterQuarterSymbolsKey, "kCFDateFormatterQuarterSymbolsKey"); CONST_STRING_DECL(kCFDateFormatterShortMonthSymbolsKey, "kCFDateFormatterShortMonthSymbolsKey"); CONST_STRING_DECL(kCFDateFormatterShortQuarterSymbolsKey, "kCFDateFormatterShortQuarterSymbolsKey"); diff --git a/CFLogUtilities.h b/CFLogUtilities.h index 90e556e..b4b0623 100644 --- a/CFLogUtilities.h +++ b/CFLogUtilities.h @@ -22,7 +22,7 @@ */ /* CFLogUtilities.h - Copyright (c) 2004-2011, Apple Inc. All rights reserved. + Copyright (c) 2004-2012, Apple Inc. All rights reserved. */ /* diff --git a/CFMachPort.c b/CFMachPort.c index 0f2add4..d5df91e 100644 --- a/CFMachPort.c +++ b/CFMachPort.c @@ -22,7 +22,7 @@ */ /* CFMachPort.c - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ @@ -30,21 +30,24 @@ #include #include #include +#include #include #include #include "CFInternal.h" -#define AVOID_WEAK_COLLECTIONS 1 -#if DEPLOYMENT_TARGET_EMBEDDED #define AVOID_WEAK_COLLECTIONS 1 -#endif -#if !defined(AVOID_WEAK_COLLECTIONS) +#if !AVOID_WEAK_COLLECTIONS #import "CFPointerArray.h" #endif -DISPATCH_HELPER_FUNCTIONS(port, CFMachPort) +static dispatch_queue_t _CFMachPortQueue() { + static volatile dispatch_queue_t __CFMachPortQueue = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ __CFMachPortQueue = dispatch_queue_create("CFMachPort Queue", NULL); }); + return __CFMachPortQueue; +} enum { @@ -57,15 +60,16 @@ enum { struct __CFMachPort { CFRuntimeBase _base; int32_t _state; - mach_port_t _port; /* immutable */ - dispatch_source_t _dsrc; - dispatch_source_t _dsrc2; - dispatch_semaphore_t _dsrc_sem; - dispatch_semaphore_t _dsrc2_sem; - CFMachPortInvalidationCallBack _icallout; - CFRunLoopSourceRef _source; /* immutable, once created */ - CFMachPortCallBack _callout; /* immutable */ - CFMachPortContext _context; /* immutable */ + mach_port_t _port; /* immutable */ + dispatch_source_t _dsrc; /* protected by _lock */ + dispatch_source_t _dsrc2; /* protected by _lock */ + dispatch_semaphore_t _dsrc_sem; /* protected by _lock */ + dispatch_semaphore_t _dsrc2_sem; /* protected by _lock */ + CFMachPortInvalidationCallBack _icallout; /* protected by _lock */ + CFRunLoopSourceRef _source; /* immutable, once created */ + CFMachPortCallBack _callout; /* immutable */ + CFMachPortContext _context; /* immutable */ + CFSpinLock_t _lock; }; /* Bit 1 in the base reserved bits is used for has-receive-ref state */ @@ -134,51 +138,55 @@ static CFStringRef __CFMachPortCopyDescription(CFTypeRef cf) { return result; } +// Only call with mp->_lock locked +CF_INLINE void __CFMachPortInvalidateLocked(CFRunLoopSourceRef source, CFMachPortRef mp) { + CFMachPortInvalidationCallBack cb = mp->_icallout; + if (cb) { + __CFSpinUnlock(&mp->_lock); + cb(mp, mp->_context.info); + __CFSpinLock(&mp->_lock); + } + if (NULL != source) { + __CFSpinUnlock(&mp->_lock); + CFRunLoopSourceInvalidate(source); + CFRelease(source); + __CFSpinLock(&mp->_lock); + } + void *info = mp->_context.info; + mp->_context.info = NULL; + if (mp->_context.release) { + __CFSpinUnlock(&mp->_lock); + mp->_context.release(info); + __CFSpinLock(&mp->_lock); + } + mp->_state = kCFMachPortStateInvalid; + OSMemoryBarrier(); +} + static void __CFMachPortDeallocate(CFTypeRef cf) { CHECK_FOR_FORK_RET(); CFMachPortRef mp = (CFMachPortRef)cf; // CFMachPortRef is invalid before we get here, except under GC - __block CFRunLoopSourceRef source = NULL; - __block Boolean wasReady = false; - void (^block)(void) = ^{ - wasReady = (mp->_state == kCFMachPortStateReady); - if (wasReady) { - mp->_state = kCFMachPortStateInvalidating; - OSMemoryBarrier(); - if (mp->_dsrc) { - dispatch_source_cancel(mp->_dsrc); - mp->_dsrc = NULL; - } - if (mp->_dsrc2) { - dispatch_source_cancel(mp->_dsrc2); - mp->_dsrc2 = NULL; - } - source = mp->_source; - mp->_source = NULL; - } - }; - if (!__portSyncDispatchIsSafe(__portQueue())) { - block(); - } else { - dispatch_sync(__portQueue(), block); - } + __CFSpinLock(&mp->_lock); + CFRunLoopSourceRef source = NULL; + Boolean wasReady = (mp->_state == kCFMachPortStateReady); if (wasReady) { - CFMachPortInvalidationCallBack cb = mp->_icallout; - if (cb) { - cb(mp, mp->_context.info); - } - if (NULL != source) { - CFRunLoopSourceInvalidate(source); - CFRelease(source); + mp->_state = kCFMachPortStateInvalidating; + OSMemoryBarrier(); + if (mp->_dsrc) { + dispatch_source_cancel(mp->_dsrc); + mp->_dsrc = NULL; } - void *info = mp->_context.info; - mp->_context.info = NULL; - if (mp->_context.release) { - mp->_context.release(info); + if (mp->_dsrc2) { + dispatch_source_cancel(mp->_dsrc2); + mp->_dsrc2 = NULL; } - mp->_state = kCFMachPortStateInvalid; - OSMemoryBarrier(); + source = mp->_source; + mp->_source = NULL; + } + if (wasReady) { + __CFMachPortInvalidateLocked(source, mp); } mp->_state = kCFMachPortStateDeallocating; @@ -188,6 +196,8 @@ static void __CFMachPortDeallocate(CFTypeRef cf) { dispatch_semaphore_t sem2 = mp->_dsrc2_sem; Boolean doSend2 = __CFMachPortHasSend2(mp), doSend = __CFMachPortHasSend(mp), doReceive = __CFMachPortHasReceive(mp); + __CFSpinUnlock(&mp->_lock); + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ if (sem1) { dispatch_semaphore_wait(sem1, DISPATCH_TIME_FOREVER); @@ -215,7 +225,10 @@ static void __CFMachPortDeallocate(CFTypeRef cf) { }); } -#if defined(AVOID_WEAK_COLLECTIONS) +// This lock protects __CFAllMachPorts. Take before any instance-specific lock. +static CFSpinLock_t __CFAllMachPortsLock = CFSpinLockInit; + +#if AVOID_WEAK_COLLECTIONS static CFMutableArrayRef __CFAllMachPorts = NULL; #else static __CFPointerArray *__CFAllMachPorts = nil; @@ -227,8 +240,9 @@ static Boolean __CFMachPortCheck(mach_port_t port) { return (KERN_SUCCESS != ret || (0 == (type & MACH_PORT_TYPE_PORT_RIGHTS))) ? false : true; } -static void __CFMachPortChecker(Boolean fromTimer) { // only call on __portQueue() -#if defined(AVOID_WEAK_COLLECTIONS) +static void __CFMachPortChecker(Boolean fromTimer) { + __CFSpinLock(&__CFAllMachPortsLock); // take this lock first before any instance-specific lock +#if AVOID_WEAK_COLLECTIONS for (CFIndex idx = 0, cnt = __CFAllMachPorts ? CFArrayGetCount(__CFAllMachPorts) : 0; idx < cnt; idx++) { CFMachPortRef mp = (CFMachPortRef)CFArrayGetValueAtIndex(__CFAllMachPorts, idx); #else @@ -241,6 +255,7 @@ static void __CFMachPortChecker(Boolean fromTimer) { // only call on __portQueue CFRunLoopSourceRef source = NULL; Boolean wasReady = (mp->_state == kCFMachPortStateReady); if (wasReady) { + __CFSpinLock(&mp->_lock); // take this lock second mp->_state = kCFMachPortStateInvalidating; OSMemoryBarrier(); if (mp->_dsrc) { @@ -254,27 +269,17 @@ static void __CFMachPortChecker(Boolean fromTimer) { // only call on __portQueue source = mp->_source; mp->_source = NULL; CFRetain(mp); + __CFSpinUnlock(&mp->_lock); dispatch_async(dispatch_get_main_queue(), ^{ - CFMachPortInvalidationCallBack cb = mp->_icallout; - if (cb) { - cb(mp, mp->_context.info); - } - if (NULL != source) { - CFRunLoopSourceInvalidate(source); - CFRelease(source); - } - void *info = mp->_context.info; - mp->_context.info = NULL; - if (mp->_context.release) { - mp->_context.release(info); - } - // For hashing and equality purposes, cannot get rid of _port here - mp->_state = kCFMachPortStateInvalid; - OSMemoryBarrier(); - CFRelease(mp); - }); + // We can grab the mach port-specific spin lock here since we're no longer on the same thread as the one taking the all mach ports spin lock. + // But be sure to release it during callouts + __CFSpinLock(&mp->_lock); + __CFMachPortInvalidateLocked(source, mp); + __CFSpinUnlock(&mp->_lock); + CFRelease(mp); + }); } -#if defined(AVOID_WEAK_COLLECTIONS) +#if AVOID_WEAK_COLLECTIONS CFArrayRemoveValueAtIndex(__CFAllMachPorts, idx); #else [__CFAllMachPorts removePointerAtIndex:idx]; @@ -283,9 +288,10 @@ static void __CFMachPortChecker(Boolean fromTimer) { // only call on __portQueue cnt--; } } -#if !defined(AVOID_WEAK_COLLECTIONS) +#if !AVOID_WEAK_COLLECTIONS [__CFAllMachPorts compact]; #endif + __CFSpinUnlock(&__CFAllMachPortsLock); }; @@ -328,96 +334,103 @@ CFMachPortRef _CFMachPortCreateWithPort2(CFAllocatorRef allocator, mach_port_t p return NULL; } - __block CFMachPortRef mp = NULL; - dispatch_sync(__portQueue(), ^{ - static dispatch_source_t timerSource = NULL; - if (timerSource == NULL) { - uint64_t nanos = 63 * 1000 * 1000 * 1000ULL; - uint64_t leeway = 9 * 1000ULL; - timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, __portQueue()); - dispatch_source_set_timer(timerSource, dispatch_time(DISPATCH_TIME_NOW, nanos), nanos, leeway); - dispatch_source_set_event_handler(timerSource, ^{ - __CFMachPortChecker(true); - }); - dispatch_resume(timerSource); - } + static dispatch_source_t timerSource = NULL; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + uint64_t nanos = 63 * 1000 * 1000 * 1000ULL; + uint64_t leeway = 9 * 1000ULL; + timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _CFMachPortQueue()); + dispatch_source_set_timer(timerSource, dispatch_time(DISPATCH_TIME_NOW, nanos), nanos, leeway); + dispatch_source_set_event_handler(timerSource, ^{ + __CFMachPortChecker(true); + }); + dispatch_resume(timerSource); + }); -#if defined(AVOID_WEAK_COLLECTIONS) - for (CFIndex idx = 0, cnt = __CFAllMachPorts ? CFArrayGetCount(__CFAllMachPorts) : 0; idx < cnt; idx++) { - CFMachPortRef p = (CFMachPortRef)CFArrayGetValueAtIndex(__CFAllMachPorts, idx); - if (p && p->_port == port) { - CFRetain(p); - mp = p; - return; - } - } + CFMachPortRef mp = NULL; + __CFSpinLock(&__CFAllMachPortsLock); +#if AVOID_WEAK_COLLECTIONS + for (CFIndex idx = 0, cnt = __CFAllMachPorts ? CFArrayGetCount(__CFAllMachPorts) : 0; idx < cnt; idx++) { + CFMachPortRef p = (CFMachPortRef)CFArrayGetValueAtIndex(__CFAllMachPorts, idx); + if (p && p->_port == port) { + CFRetain(p); + mp = p; + break; + } + } #else - for (CFIndex idx = 0, cnt = __CFAllMachPorts ? [__CFAllMachPorts count] : 0; idx < cnt; idx++) { - CFMachPortRef p = (CFMachPortRef)[__CFAllMachPorts pointerAtIndex:idx]; - if (p && p->_port == port) { - CFRetain(p); - mp = p; - return; - } - } -#endif - - CFIndex size = sizeof(struct __CFMachPort) - sizeof(CFRuntimeBase); - CFMachPortRef memory = (CFMachPortRef)_CFRuntimeCreateInstance(allocator, CFMachPortGetTypeID(), size, NULL); - if (NULL == memory) { - return; - } - memory->_port = port; - memory->_dsrc = NULL; - memory->_dsrc2 = NULL; - memory->_dsrc_sem = NULL; - memory->_dsrc2_sem = NULL; - memory->_icallout = NULL; - memory->_source = NULL; - memory->_context.info = NULL; - memory->_context.retain = NULL; - memory->_context.release = NULL; - memory->_context.copyDescription = NULL; - memory->_callout = callout; - if (NULL != context) { - objc_memmove_collectable(&memory->_context, context, sizeof(CFMachPortContext)); - memory->_context.info = context->retain ? (void *)context->retain(context->info) : context->info; - } - memory->_state = kCFMachPortStateReady; -#if defined(AVOID_WEAK_COLLECTIONS) - if (!__CFAllMachPorts) __CFAllMachPorts = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); - CFArrayAppendValue(__CFAllMachPorts, memory); -#else - if (!__CFAllMachPorts) __CFAllMachPorts = [[__CFPointerArray alloc] initWithOptions:(kCFUseCollectableAllocator ? CFPointerFunctionsZeroingWeakMemory : CFPointerFunctionsStrongMemory)]; - [__CFAllMachPorts addPointer:memory]; + for (CFIndex idx = 0, cnt = __CFAllMachPorts ? [__CFAllMachPorts count] : 0; idx < cnt; idx++) { + CFMachPortRef p = (CFMachPortRef)[__CFAllMachPorts pointerAtIndex:idx]; + if (p && p->_port == port) { + CFRetain(p); + mp = p; + break; + } + } #endif - mp = memory; - if (shouldFreeInfo) *shouldFreeInfo = false; - - if (type & MACH_PORT_TYPE_SEND_RIGHTS) { - dispatch_source_t theSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, port, DISPATCH_MACH_SEND_DEAD, __portQueue()); - dispatch_source_set_cancel_handler(theSource, ^{ - dispatch_release(theSource); - }); - dispatch_source_set_event_handler(theSource, ^{ - __CFMachPortChecker(false); - }); - memory->_dsrc = theSource; - dispatch_resume(theSource); - } - if (memory->_dsrc) { - dispatch_source_t source = memory->_dsrc; // put these in locals so they are fully copied into the block - dispatch_semaphore_t sem = dispatch_semaphore_create(0); - memory->_dsrc_sem = sem; - dispatch_source_set_cancel_handler(memory->_dsrc, ^{ dispatch_semaphore_signal(sem); dispatch_release(source); }); - } - if (memory->_dsrc2) { - dispatch_source_t source = memory->_dsrc2; - dispatch_semaphore_t sem = dispatch_semaphore_create(0); - memory->_dsrc2_sem = sem; - dispatch_source_set_cancel_handler(memory->_dsrc2, ^{ dispatch_semaphore_signal(sem); dispatch_release(source); }); - } - }); + __CFSpinUnlock(&__CFAllMachPortsLock); + + if (!mp) { + CFIndex size = sizeof(struct __CFMachPort) - sizeof(CFRuntimeBase); + CFMachPortRef memory = (CFMachPortRef)_CFRuntimeCreateInstance(allocator, CFMachPortGetTypeID(), size, NULL); + if (NULL == memory) { + return NULL; + } + memory->_port = port; + memory->_dsrc = NULL; + memory->_dsrc2 = NULL; + memory->_dsrc_sem = NULL; + memory->_dsrc2_sem = NULL; + memory->_icallout = NULL; + memory->_source = NULL; + memory->_context.info = NULL; + memory->_context.retain = NULL; + memory->_context.release = NULL; + memory->_context.copyDescription = NULL; + memory->_callout = callout; + memory->_lock = CFSpinLockInit; + if (NULL != context) { + objc_memmove_collectable(&memory->_context, context, sizeof(CFMachPortContext)); + memory->_context.info = context->retain ? (void *)context->retain(context->info) : context->info; + } + memory->_state = kCFMachPortStateReady; + __CFSpinLock(&__CFAllMachPortsLock); + #if AVOID_WEAK_COLLECTIONS + if (!__CFAllMachPorts) __CFAllMachPorts = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(__CFAllMachPorts, memory); + #else + if (!__CFAllMachPorts) __CFAllMachPorts = [[__CFPointerArray alloc] initWithOptions:(kCFUseCollectableAllocator ? CFPointerFunctionsZeroingWeakMemory : CFPointerFunctionsStrongMemory)]; + [__CFAllMachPorts addPointer:memory]; + #endif + __CFSpinUnlock(&__CFAllMachPortsLock); + mp = memory; + if (shouldFreeInfo) *shouldFreeInfo = false; + + if (type & MACH_PORT_TYPE_SEND_RIGHTS) { + dispatch_source_t theSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, port, DISPATCH_MACH_SEND_DEAD, _CFMachPortQueue()); + dispatch_source_set_cancel_handler(theSource, ^{ + dispatch_release(theSource); + }); + dispatch_source_set_event_handler(theSource, ^{ + __CFMachPortChecker(false); + }); + memory->_dsrc = theSource; + dispatch_resume(theSource); + } + if (memory->_dsrc) { + dispatch_source_t source = memory->_dsrc; // put these in locals so they are fully copied into the block + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + memory->_dsrc_sem = sem; + dispatch_source_set_cancel_handler(memory->_dsrc, ^{ dispatch_semaphore_signal(sem); dispatch_release(source); }); + } + if (memory->_dsrc2) { + dispatch_source_t source = memory->_dsrc2; + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + memory->_dsrc2_sem = sem; + dispatch_source_set_cancel_handler(memory->_dsrc2, ^{ dispatch_semaphore_signal(sem); dispatch_release(source); }); + } + } + if (mp && !CFMachPortIsValid(mp)) { // must do this outside lock to avoid deadlock CFRelease(mp); mp = NULL; @@ -453,69 +466,58 @@ CFMachPortRef CFMachPortCreate(CFAllocatorRef allocator, CFMachPortCallBack call void CFMachPortInvalidate(CFMachPortRef mp) { CHECK_FOR_FORK_RET(); - CF_OBJC_FUNCDISPATCH0(CFMachPortGetTypeID(), void, mp, "invalidate"); + CF_OBJC_FUNCDISPATCHV(CFMachPortGetTypeID(), void, (NSMachPort *)mp, invalidate); __CFGenericValidateType(mp, CFMachPortGetTypeID()); CFRetain(mp); - __block CFRunLoopSourceRef source = NULL; - __block Boolean wasReady = false; - dispatch_sync(__portQueue(), ^{ - wasReady = (mp->_state == kCFMachPortStateReady); - if (wasReady) { - mp->_state = kCFMachPortStateInvalidating; - OSMemoryBarrier(); -#if defined(AVOID_WEAK_COLLECTIONS) - for (CFIndex idx = 0, cnt = __CFAllMachPorts ? CFArrayGetCount(__CFAllMachPorts) : 0; idx < cnt; idx++) { - CFMachPortRef p = (CFMachPortRef)CFArrayGetValueAtIndex(__CFAllMachPorts, idx); - if (p == mp) { - CFArrayRemoveValueAtIndex(__CFAllMachPorts, idx); - break; - } - } + CFRunLoopSourceRef source = NULL; + Boolean wasReady = false; + __CFSpinLock(&__CFAllMachPortsLock); // take this lock first + __CFSpinLock(&mp->_lock); + wasReady = (mp->_state == kCFMachPortStateReady); + if (wasReady) { + mp->_state = kCFMachPortStateInvalidating; + OSMemoryBarrier(); +#if AVOID_WEAK_COLLECTIONS + for (CFIndex idx = 0, cnt = __CFAllMachPorts ? CFArrayGetCount(__CFAllMachPorts) : 0; idx < cnt; idx++) { + CFMachPortRef p = (CFMachPortRef)CFArrayGetValueAtIndex(__CFAllMachPorts, idx); + if (p == mp) { + CFArrayRemoveValueAtIndex(__CFAllMachPorts, idx); + break; + } + } #else - for (CFIndex idx = 0, cnt = __CFAllMachPorts ? [__CFAllMachPorts count] : 0; idx < cnt; idx++) { - CFMachPortRef p = (CFMachPortRef)[__CFAllMachPorts pointerAtIndex:idx]; - if (p == mp) { - [__CFAllMachPorts removePointerAtIndex:idx]; - break; - } - } -#endif - if (mp->_dsrc) { - dispatch_source_cancel(mp->_dsrc); - mp->_dsrc = NULL; - } - if (mp->_dsrc2) { - dispatch_source_cancel(mp->_dsrc2); - mp->_dsrc2 = NULL; - } - source = mp->_source; - mp->_source = NULL; + for (CFIndex idx = 0, cnt = __CFAllMachPorts ? [__CFAllMachPorts count] : 0; idx < cnt; idx++) { + CFMachPortRef p = (CFMachPortRef)[__CFAllMachPorts pointerAtIndex:idx]; + if (p == mp) { + [__CFAllMachPorts removePointerAtIndex:idx]; + break; } - }); - if (wasReady) { - CFMachPortInvalidationCallBack cb = mp->_icallout; - if (cb) { - cb(mp, mp->_context.info); } - if (NULL != source) { - CFRunLoopSourceInvalidate(source); - CFRelease(source); +#endif + if (mp->_dsrc) { + dispatch_source_cancel(mp->_dsrc); + mp->_dsrc = NULL; } - void *info = mp->_context.info; - mp->_context.info = NULL; - if (mp->_context.release) { - mp->_context.release(info); + if (mp->_dsrc2) { + dispatch_source_cancel(mp->_dsrc2); + mp->_dsrc2 = NULL; } - // For hashing and equality purposes, cannot get rid of _port here - mp->_state = kCFMachPortStateInvalid; - OSMemoryBarrier(); + source = mp->_source; + mp->_source = NULL; + } + __CFSpinUnlock(&mp->_lock); + __CFSpinUnlock(&__CFAllMachPortsLock); // release this lock last + if (wasReady) { + __CFSpinLock(&mp->_lock); + __CFMachPortInvalidateLocked(source, mp); + __CFSpinUnlock(&mp->_lock); } CFRelease(mp); } mach_port_t CFMachPortGetPort(CFMachPortRef mp) { CHECK_FOR_FORK_RET(0); - CF_OBJC_FUNCDISPATCH0(CFMachPortGetTypeID(), mach_port_t, mp, "machPort"); + CF_OBJC_FUNCDISPATCHV(CFMachPortGetTypeID(), mach_port_t, (NSMachPort *)mp, machPort); __CFGenericValidateType(mp, CFMachPortGetTypeID()); return mp->_port; } @@ -527,7 +529,7 @@ void CFMachPortGetContext(CFMachPortRef mp, CFMachPortContext *context) { } Boolean CFMachPortIsValid(CFMachPortRef mp) { - CF_OBJC_FUNCDISPATCH0(CFMachPortGetTypeID(), Boolean, mp, "isValid"); + CF_OBJC_FUNCDISPATCHV(CFMachPortGetTypeID(), Boolean, (NSMachPort *)mp, isValid); __CFGenericValidateType(mp, CFMachPortGetTypeID()); if (!__CFMachPortIsValid(mp)) return false; mach_port_type_t type = 0; @@ -540,7 +542,10 @@ Boolean CFMachPortIsValid(CFMachPortRef mp) { CFMachPortInvalidationCallBack CFMachPortGetInvalidationCallBack(CFMachPortRef mp) { __CFGenericValidateType(mp, CFMachPortGetTypeID()); - return mp->_icallout; + __CFSpinLock(&mp->_lock); + CFMachPortInvalidationCallBack cb = mp->_icallout; + __CFSpinUnlock(&mp->_lock); + return cb; } /* After the CFMachPort has started going invalid, or done invalid, you can't change this, and @@ -548,13 +553,17 @@ CFMachPortInvalidationCallBack CFMachPortGetInvalidationCallBack(CFMachPortRef m void CFMachPortSetInvalidationCallBack(CFMachPortRef mp, CFMachPortInvalidationCallBack callout) { CHECK_FOR_FORK_RET(); __CFGenericValidateType(mp, CFMachPortGetTypeID()); + __CFSpinLock(&mp->_lock); if (__CFMachPortIsValid(mp) || !callout) { mp->_icallout = callout; } else if (!mp->_icallout && callout) { + __CFSpinUnlock(&mp->_lock); callout(mp, mp->_context.info); + __CFSpinLock(&mp->_lock); } else { CFLog(kCFLogLevelWarning, CFSTR("CFMachPortSetInvalidationCallBack(): attempt to set invalidation callback (%p) on invalid CFMachPort (%p) thwarted"), callout, mp); } + __CFSpinUnlock(&mp->_lock); } /* Returns the number of messages queued for a receive port. */ @@ -575,19 +584,19 @@ static mach_port_t __CFMachPortGetPort(void *info) { static void *__CFMachPortPerform(void *msg, CFIndex size, CFAllocatorRef allocator, void *info) { CHECK_FOR_FORK_RET(NULL); CFMachPortRef mp = (CFMachPortRef)info; - __block Boolean isValid = false; - __block void *context_info = NULL; - __block void (*context_release)(const void *) = NULL; - dispatch_sync(__portQueue(), ^{ - isValid = __CFMachPortIsValid(mp); - if (!isValid) return; - if (mp->_context.retain) { - context_info = (void *)mp->_context.retain(mp->_context.info); - context_release = mp->_context.release; - } else { - context_info = mp->_context.info; - } - }); + __CFSpinLock(&mp->_lock); + Boolean isValid = __CFMachPortIsValid(mp); + void *context_info = NULL; + void (*context_release)(const void *) = NULL; + if (isValid) { + if (mp->_context.retain) { + context_info = (void *)mp->_context.retain(mp->_context.info); + context_release = mp->_context.release; + } else { + context_info = mp->_context.info; + } + } + __CFSpinUnlock(&mp->_lock); if (!isValid) return NULL; mp->_callout(mp, msg, size, context_info); @@ -603,28 +612,29 @@ CFRunLoopSourceRef CFMachPortCreateRunLoopSource(CFAllocatorRef allocator, CFMac CHECK_FOR_FORK_RET(NULL); __CFGenericValidateType(mp, CFMachPortGetTypeID()); if (!CFMachPortIsValid(mp)) return NULL; - __block CFRunLoopSourceRef result = NULL; - dispatch_sync(__portQueue(), ^{ - if (!__CFMachPortIsValid(mp)) return; - if (NULL != mp->_source && !CFRunLoopSourceIsValid(mp->_source)) { - CFRelease(mp->_source); - mp->_source = NULL; - } - if (NULL == mp->_source) { - CFRunLoopSourceContext1 context; - context.version = 1; - context.info = (void *)mp; - context.retain = (const void *(*)(const void *))CFRetain; - context.release = (void (*)(const void *))CFRelease; - context.copyDescription = (CFStringRef (*)(const void *))__CFMachPortCopyDescription; - context.equal = (Boolean (*)(const void *, const void *))__CFMachPortEqual; - context.hash = (CFHashCode (*)(const void *))__CFMachPortHash; - context.getPort = __CFMachPortGetPort; - context.perform = __CFMachPortPerform; - mp->_source = CFRunLoopSourceCreate(allocator, order, (CFRunLoopSourceContext *)&context); - } - result = mp->_source ? (CFRunLoopSourceRef)CFRetain(mp->_source) : NULL; - }); + CFRunLoopSourceRef result = NULL; + __CFSpinLock(&mp->_lock); + if (__CFMachPortIsValid(mp)) { + if (NULL != mp->_source && !CFRunLoopSourceIsValid(mp->_source)) { + CFRelease(mp->_source); + mp->_source = NULL; + } + if (NULL == mp->_source) { + CFRunLoopSourceContext1 context; + context.version = 1; + context.info = (void *)mp; + context.retain = (const void *(*)(const void *))CFRetain; + context.release = (void (*)(const void *))CFRelease; + context.copyDescription = (CFStringRef (*)(const void *))__CFMachPortCopyDescription; + context.equal = (Boolean (*)(const void *, const void *))__CFMachPortEqual; + context.hash = (CFHashCode (*)(const void *))__CFMachPortHash; + context.getPort = __CFMachPortGetPort; + context.perform = __CFMachPortPerform; + mp->_source = CFRunLoopSourceCreate(allocator, order, (CFRunLoopSourceContext *)&context); + } + result = mp->_source ? (CFRunLoopSourceRef)CFRetain(mp->_source) : NULL; + } + __CFSpinUnlock(&mp->_lock); return result; } diff --git a/CFMachPort.h b/CFMachPort.h index fa1d9fb..de87262 100644 --- a/CFMachPort.h +++ b/CFMachPort.h @@ -22,7 +22,7 @@ */ /* CFMachPort.h - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFMACHPORT__) diff --git a/CFMessagePort.c b/CFMessagePort.c index 620f509..f28a81f 100644 --- a/CFMessagePort.c +++ b/CFMessagePort.c @@ -22,7 +22,7 @@ */ /* CFMessagePort.c - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ @@ -41,6 +41,7 @@ #include #include #include +#include extern pid_t getpid(void); @@ -59,12 +60,6 @@ extern pid_t getpid(void); #define __CFMessagePortMaxDataSize 0x60000000L -//#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-function" -DISPATCH_HELPER_FUNCTIONS(mport, CFMessagePort) -//#pragma GCC diagnostic pop - - static CFSpinLock_t __CFAllMessagePortsLock = CFSpinLockInit; static CFMutableDictionaryRef __CFAllLocalMessagePorts = NULL; static CFMutableDictionaryRef __CFAllRemoteMessagePorts = NULL; @@ -321,7 +316,7 @@ static CFStringRef __CFMessagePortSanitizeStringName(CFStringRef name, uint8_t * utfname = CFAllocatorAllocate(kCFAllocatorSystemDefault, __kCFMessagePortMaxNameLength + 1, 0); CFStringGetBytes(name, CFRangeMake(0, CFStringGetLength(name)), kCFStringEncodingUTF8, 0, false, utfname, __kCFMessagePortMaxNameLength, &utflen); utfname[utflen] = '\0'; - if (strlen(utfname) != utflen) { + if (strlen((const char *)utfname) != utflen) { /* PCA 9194709: refuse to sanitize a string with an embedded nul character */ CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); utfname = NULL; @@ -576,6 +571,7 @@ static CFMessagePortRef __CFMessagePortCreateRemote(CFAllocatorRef allocator, CF } CFDictionaryAddValue(__CFAllRemoteMessagePorts, name, memory); } + CFRetain(native); __CFSpinUnlock(&__CFAllMessagePortsLock); CFMachPortSetInvalidationCallBack(native, __CFMessagePortInvalidationCallBack); // that set-invalidation-callback might have called back into us @@ -584,8 +580,10 @@ static CFMessagePortRef __CFMessagePortCreateRemote(CFAllocatorRef allocator, CF // went invalid; so check for validity manually and react if (!CFMachPortIsValid(native)) { CFRelease(memory); // does the invalidate + CFRelease(native); return NULL; } + CFRelease(native); return (CFMessagePortRef)memory; } @@ -740,7 +738,7 @@ void CFMessagePortInvalidate(CFMessagePortRef ms) { __CFMessagePortUnlock(ms); __CFSpinLock(&__CFAllMessagePortsLock); - if (0 == ms->_perPID && NULL != (__CFMessagePortIsRemote(ms) ? __CFAllRemoteMessagePorts : __CFAllLocalMessagePorts)) { + if (0 == ms->_perPID && NULL != name && NULL != (__CFMessagePortIsRemote(ms) ? __CFAllRemoteMessagePorts : __CFAllLocalMessagePorts)) { CFDictionaryRemoveValue(__CFMessagePortIsRemote(ms) ? __CFAllRemoteMessagePorts : __CFAllLocalMessagePorts, name); } __CFSpinUnlock(&__CFAllMessagePortsLock); @@ -787,14 +785,18 @@ void CFMessagePortInvalidate(CFMessagePortRef ms) { Boolean CFMessagePortIsValid(CFMessagePortRef ms) { __CFGenericValidateType(ms, __kCFMessagePortTypeID); if (!__CFMessagePortIsValid(ms)) return false; + CFRetain(ms); if (NULL != ms->_port && !CFMachPortIsValid(ms->_port)) { CFMessagePortInvalidate(ms); + CFRelease(ms); return false; } if (NULL != ms->_replyPort && !CFMachPortIsValid(ms->_replyPort)) { CFMessagePortInvalidate(ms); + CFRelease(ms); return false; } + CFRelease(ms); return true; } @@ -927,7 +929,9 @@ SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CFDataRef if (sendTimeout < 1.0) sendTimeout = 0.0; sendTimeOut = floor(sendTimeout); } + __CFMessagePortUnlock(remote); ret = mach_msg((mach_msg_header_t *)sendmsg, MACH_SEND_MSG|sendOpts, sendmsg->header.msgh_size, 0, MACH_PORT_NULL, sendTimeOut, MACH_PORT_NULL); + __CFMessagePortLock(remote); if (KERN_SUCCESS != ret) { // need to deallocate the send-once right that might have been created if (replyMode != NULL) mach_port_deallocate(mach_task_self(), ((mach_msg_header_t *)sendmsg)->msgh_local_port); @@ -1155,44 +1159,49 @@ void CFMessagePortSetDispatchQueue(CFMessagePortRef ms, dispatch_queue_t queue) if (queue) { mach_port_t port = __CFMessagePortGetPort(ms); if (MACH_PORT_NULL != port) { - dispatch_source_t theSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, port, 0, __mportQueue()); - dispatch_source_set_cancel_handler(theSource, ^{ - dispatch_release(queue); - dispatch_release(theSource); - }); - dispatch_source_set_event_handler(theSource, ^{ - CFRetain(ms); - mach_msg_header_t *msg = (mach_msg_header_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 2048, 0); - msg->msgh_size = 2048; - - for (;;) { - msg->msgh_bits = 0; - msg->msgh_local_port = port; - msg->msgh_remote_port = MACH_PORT_NULL; - msg->msgh_id = 0; - - kern_return_t ret = mach_msg(msg, MACH_RCV_MSG|MACH_RCV_LARGE|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV), 0, msg->msgh_size, port, 0, MACH_PORT_NULL); - if (MACH_MSG_SUCCESS == ret) break; - if (MACH_RCV_TOO_LARGE != ret) HALT; - - uint32_t newSize = round_msg(msg->msgh_size + MAX_TRAILER_SIZE); - msg = CFAllocatorReallocate(kCFAllocatorSystemDefault, msg, newSize, 0); - msg->msgh_size = newSize; - } - - dispatch_async(queue, ^{ - mach_msg_header_t *reply = __CFMessagePortPerform(msg, msg->msgh_size, kCFAllocatorSystemDefault, ms); - if (NULL != reply) { - kern_return_t ret = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL); - if (KERN_SUCCESS != ret) mach_msg_destroy(reply); - CFAllocatorDeallocate(kCFAllocatorSystemDefault, reply); - } - CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg); - CFRelease(ms); - }); - }); - ms->_dispatchSource = theSource; - } + static dispatch_queue_t mportQueue = NULL; + static dispatch_once_t once; + dispatch_once(&once, ^{ + mportQueue = dispatch_queue_create("CFMessagePort Queue", NULL); + }); + dispatch_source_t theSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, port, 0, mportQueue); + dispatch_source_set_cancel_handler(theSource, ^{ + dispatch_release(queue); + dispatch_release(theSource); + }); + dispatch_source_set_event_handler(theSource, ^{ + CFRetain(ms); + mach_msg_header_t *msg = (mach_msg_header_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 2048, 0); + msg->msgh_size = 2048; + + for (;;) { + msg->msgh_bits = 0; + msg->msgh_local_port = port; + msg->msgh_remote_port = MACH_PORT_NULL; + msg->msgh_id = 0; + + kern_return_t ret = mach_msg(msg, MACH_RCV_MSG|MACH_RCV_LARGE|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV), 0, msg->msgh_size, port, 0, MACH_PORT_NULL); + if (MACH_MSG_SUCCESS == ret) break; + if (MACH_RCV_TOO_LARGE != ret) HALT; + + uint32_t newSize = round_msg(msg->msgh_size + MAX_TRAILER_SIZE); + msg = CFAllocatorReallocate(kCFAllocatorSystemDefault, msg, newSize, 0); + msg->msgh_size = newSize; + } + + dispatch_async(queue, ^{ + mach_msg_header_t *reply = __CFMessagePortPerform(msg, msg->msgh_size, kCFAllocatorSystemDefault, ms); + if (NULL != reply) { + kern_return_t ret = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL); + if (KERN_SUCCESS != ret) mach_msg_destroy(reply); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, reply); + } + CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg); + CFRelease(ms); + }); + }); + ms->_dispatchSource = theSource; + } if (ms->_dispatchSource) { dispatch_retain(queue); ms->_dispatchQ = queue; diff --git a/CFMessagePort.h b/CFMessagePort.h index e55cf82..4d8f9b7 100644 --- a/CFMessagePort.h +++ b/CFMessagePort.h @@ -22,7 +22,7 @@ */ /* CFMessagePort.h - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFMESSAGEPORT__) diff --git a/CFNumber.c b/CFNumber.c index 2c6a70a..4ddbcc0 100644 --- a/CFNumber.c +++ b/CFNumber.c @@ -22,7 +22,7 @@ */ /* CFNumber.c - Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Copyright (c) 1999-2012, Apple Inc. All rights reserved. Responsibility: Ali Ozer */ @@ -32,6 +32,7 @@ #include #include + #if DEPLOYMENT_TARGET_WINDOWS #define isnan(A) _isnan(A) #define isinf(A) !_finite(A) @@ -100,7 +101,7 @@ CFTypeID CFBooleanGetTypeID(void) { } Boolean CFBooleanGetValue(CFBooleanRef boolean) { - CF_OBJC_FUNCDISPATCH0(__kCFBooleanTypeID, Boolean, boolean, "boolValue"); + CF_OBJC_FUNCDISPATCHV(__kCFBooleanTypeID, Boolean, (NSNumber *)boolean, boolValue); return (boolean == kCFBooleanTrue) ? true : false; } @@ -111,6 +112,8 @@ Boolean CFBooleanGetValue(CFBooleanRef boolean) { #if OLD_CRAP_TOO +// old implementation, for runtime comparison purposes + typedef union { SInt32 valSInt32; int64_t valSInt64; @@ -150,7 +153,7 @@ static CFComparisonResult CFNumberCompare_old(struct __CFNumber_old * number1, s #define BITSFORDOUBLEPOSINF ((uint64_t)0x7ff0000000000000ULL) #define BITSFORDOUBLENEGINF ((uint64_t)0xfff0000000000000ULL) -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX #define FLOAT_POSITIVE_2_TO_THE_64 0x1.0p+64L #define FLOAT_NEGATIVE_2_TO_THE_127 -0x1.0p+127L #define FLOAT_POSITIVE_2_TO_THE_127 0x1.0p+127L @@ -1025,6 +1028,7 @@ static const CFRuntimeClass __CFNumberClass = { __CFNumberCopyDescription }; + __private_extern__ void __CFNumberInitialize(void) { __kCFNumberTypeID = _CFRuntimeRegisterClass(&__CFNumberClass); @@ -1076,22 +1080,30 @@ CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType type, const vo case kCFNumberSInt32Type: { int32_t value = *(int32_t *)valuePtr; #if !__LP64__ - // We don't bother allowing the min 24-bit integer -2^24 to also be fast-pathed; + // We don't bother allowing the min 24-bit integer -2^23 to also be fast-pathed; // tell anybody that complains about that to go ... hang. - if ((1L << 23) <= -value || (1L << 23) <= value) break; + int32_t limit = (1L << 23); + if (value <= -limit || limit <= value) break; #endif - return (CFNumberRef)((uintptr_t)((intptr_t)value << 8) | (2 << 6) | kCFTaggedObjectID_Integer); + uintptr_t ptr_val = ((uintptr_t)((intptr_t)value << 8) | (2 << 6) | kCFTaggedObjectID_Integer); + return (CFNumberRef)ptr_val; } -#if __LP64__ case kCFNumberSInt64Type: { int64_t value = *(int64_t *)valuePtr; - // We don't bother allowing the min 56-bit integer -2^56 to also be fast-pathed; +#if __LP64__ + // We don't bother allowing the min 56-bit integer -2^55 to also be fast-pathed; + // tell anybody that complains about that to go ... hang. + int64_t limit = (1L << 55); + if (value <= -limit || limit <= value) break; +#else + // We don't bother allowing the min 24-bit integer -2^23 to also be fast-pathed; // tell anybody that complains about that to go ... hang. - if ((1L << 55) <= -value || (1L << 55) <= value) break; - uintptr_t ptr_val = ((uintptr_t)(value << 8) | (3 << 6) | kCFTaggedObjectID_Integer); + int64_t limit = (1L << 23); + if (value <= -limit || limit <= value) break; +#endif + uintptr_t ptr_val = ((uintptr_t)((intptr_t)value << 8) | (3 << 6) | kCFTaggedObjectID_Integer); return (CFNumberRef)ptr_val; } -#endif } } @@ -1185,7 +1197,7 @@ CFNumberType CFNumberGetType(CFNumberRef number) { if (CF_IS_TAGGED_INT(number)) { return __CFNumberGetType(number); } - CF_OBJC_FUNCDISPATCH0(__kCFNumberTypeID, CFNumberType, number, "_cfNumberType"); + CF_OBJC_FUNCDISPATCHV(__kCFNumberTypeID, CFNumberType, (NSNumber *)number, _cfNumberType); __CFAssertIsNumber(number); CFNumberType type = __CFNumberGetType(number); if (kCFNumberSInt128Type == type) type = kCFNumberSInt64Type; // must hide this type, since it is not public @@ -1291,7 +1303,7 @@ Boolean CFNumberGetValue(CFNumberRef number, CFNumberType type, void *valuePtr) Boolean r = __CFNumberGetValueCompat(number, type, valuePtr); return r; } - CF_OBJC_FUNCDISPATCH2(__kCFNumberTypeID, Boolean, number, "_getValue:forType:", valuePtr, __CFNumberTypeTable[type].canonicalType); + CF_OBJC_FUNCDISPATCHV(__kCFNumberTypeID, Boolean, (NSNumber *)number, _getValue:(void *)valuePtr forType:(CFNumberType)__CFNumberTypeTable[type].canonicalType); __CFAssertIsNumber(number); __CFAssertIsValidNumberType(type); uint8_t localMemory[128]; @@ -1315,8 +1327,8 @@ CFLog(kCFLogLevelWarning, CFSTR("*** TEST FAIL 2 in CFNumberGetValue: BYTES NOT } static CFComparisonResult CFNumberCompare_new(CFNumberRef number1, CFNumberRef number2, void *context) { - CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID, CFComparisonResult, number1, "compare:", number2); - CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID, CFComparisonResult, number2, "_reverseCompare:", number1); + CF_OBJC_FUNCDISPATCHV(__kCFNumberTypeID, CFComparisonResult, (NSNumber *)number1, compare:(NSNumber *)number2); + CF_OBJC_FUNCDISPATCHV(__kCFNumberTypeID, CFComparisonResult, (NSNumber *)number2, _reverseCompare:(NSNumber *)number1); __CFAssertIsNumber(number1); __CFAssertIsNumber(number2); diff --git a/CFNumber.h b/CFNumber.h index 5e1f5e3..5cddcbb 100644 --- a/CFNumber.h +++ b/CFNumber.h @@ -22,7 +22,7 @@ */ /* CFNumber.h - Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Copyright (c) 1999-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFNUMBER__) @@ -30,6 +30,7 @@ #include +CF_IMPLICIT_BRIDGING_ENABLED CF_EXTERN_C_BEGIN typedef const struct __CFBoolean * CFBooleanRef; @@ -45,7 +46,7 @@ CFTypeID CFBooleanGetTypeID(void); CF_EXPORT Boolean CFBooleanGetValue(CFBooleanRef boolean); -enum { +typedef CF_ENUM(CFIndex, CFNumberType) { /* Fixed-width types */ kCFNumberSInt8Type = 1, kCFNumberSInt16Type = 2, @@ -63,15 +64,10 @@ enum { kCFNumberDoubleType = 13, /* Other */ kCFNumberCFIndexType = 14, -#if MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED - kCFNumberNSIntegerType = 15, - kCFNumberCGFloatType = 16, + kCFNumberNSIntegerType CF_ENUM_AVAILABLE(10_5, 2_0) = 15, + kCFNumberCGFloatType CF_ENUM_AVAILABLE(10_5, 2_0) = 16, kCFNumberMaxType = 16 -#else - kCFNumberMaxType = 14 -#endif }; -typedef CFIndex CFNumberType; typedef const struct __CFNumber * CFNumberRef; @@ -145,6 +141,7 @@ CF_EXPORT CFComparisonResult CFNumberCompare(CFNumberRef number, CFNumberRef otherNumber, void *context); CF_EXTERN_C_END +CF_IMPLICIT_BRIDGING_DISABLED #endif /* ! __COREFOUNDATION_CFNUMBER__ */ diff --git a/CFNumberFormatter.c b/CFNumberFormatter.c index 8007b1e..2a3fc8c 100644 --- a/CFNumberFormatter.c +++ b/CFNumberFormatter.c @@ -22,12 +22,13 @@ */ /* CFNumberFormatter.c - Copyright (c) 2002-2011, Apple Inc. All rights reserved. + Copyright (c) 2002-2012, Apple Inc. All rights reserved. Responsibility: David Smith */ #include #include +#include #include "CFInternal.h" #include "CFLocaleInternal.h" #include @@ -35,6 +36,7 @@ #include #include + static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter); static CFStringRef __CFNumberFormatterCreateCompressedString(CFStringRef inString, Boolean isFormat, CFRange *rangep); static UErrorCode __CFNumberFormatterApplyPattern(CFNumberFormatterRef formatter, CFStringRef pattern); @@ -406,6 +408,18 @@ void CFNumberFormatterSetFormat(CFNumberFormatterRef formatter, CFStringRef form } } +#define GET_MULTIPLIER \ + double multiplier = 1.0; \ + double dummy = 0.0; \ + if (formatter->_multiplier) { \ + if (!CFNumberGetValue(formatter->_multiplier, kCFNumberFloat64Type, &multiplier)) { \ + multiplier = 1.0; \ + } \ + } \ + if (modf(multiplier, &dummy) < FLT_EPSILON) { \ + multiplier = floor(multiplier); \ + } + CFStringRef CFNumberFormatterCreateStringWithNumber(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberRef number) { if (allocator == NULL) allocator = __CFGetDefaultAllocator(); __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); @@ -417,16 +431,11 @@ CFStringRef CFNumberFormatterCreateStringWithNumber(CFAllocatorRef allocator, CF return CFNumberFormatterCreateStringWithValue(allocator, formatter, type, buffer); } -#define FORMAT(T, FUNC) \ +#define FORMAT_FLT(T, FUNC) \ T value = *(T *)valuePtr; \ if (0 == value && formatter->_zeroSym) { return (CFStringRef)CFRetain(formatter->_zeroSym); } \ if (1.0 != multiplier) { \ - double dummy; \ - if (modf(multiplier, &dummy) < FLT_EPSILON) { /* float epsilon specifically chosen cuz it is a bit bigger */ \ - value = value * (T)floor(multiplier); \ - } else { \ - value = (T)(value * multiplier); \ - } \ + value = (T)(value * multiplier); \ } \ status = U_ZERO_ERROR; \ used = FUNC(formatter->_nf, value, ubuffer, cnt, NULL, &status); \ @@ -437,37 +446,51 @@ CFStringRef CFNumberFormatterCreateStringWithNumber(CFAllocatorRef allocator, CF used = FUNC(formatter->_nf, value, ustr, cnt, NULL, &status); \ } +#define FORMAT_INT(T, FUN) \ + T value = *(T *)valuePtr; \ + if (0 == value && formatter->_zeroSym) { return (CFStringRef)CFRetain(formatter->_zeroSym); } \ + if (1.0 != multiplier) { \ + value = (T)(value * multiplier); \ + } \ + _CFBigNum bignum; \ + FUN(&bignum, value); \ + char buffer[BUFFER_SIZE]; \ + _CFBigNumToCString(&bignum, false, true, buffer, BUFFER_SIZE); \ + status = U_ZERO_ERROR; \ + used = unum_formatDecimal(formatter->_nf, buffer, strlen(buffer), ubuffer, BUFFER_SIZE, NULL, &status); \ + if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) { \ + cnt = used + 1; \ + ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0); \ + status = U_ZERO_ERROR; \ + used = unum_formatDecimal(formatter->_nf, buffer, strlen(buffer), ustr, cnt, NULL, &status); \ + } \ + CFStringRef CFNumberFormatterCreateStringWithValue(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberType numberType, const void *valuePtr) { if (allocator == NULL) allocator = __CFGetDefaultAllocator(); __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID()); - double multiplier = 1.0; - if (formatter->_multiplier) { - if (!CFNumberGetValue(formatter->_multiplier, kCFNumberFloat64Type, &multiplier)) { - multiplier = 1.0; - } - } + GET_MULTIPLIER; UChar *ustr = NULL, ubuffer[BUFFER_SIZE]; UErrorCode status = U_ZERO_ERROR; CFIndex used, cnt = BUFFER_SIZE; if (numberType == kCFNumberFloat64Type || numberType == kCFNumberDoubleType) { - FORMAT(double, unum_formatDouble) + FORMAT_FLT(double, unum_formatDouble) } else if (numberType == kCFNumberFloat32Type || numberType == kCFNumberFloatType) { - FORMAT(float, unum_formatDouble) + FORMAT_FLT(float, unum_formatDouble) } else if (numberType == kCFNumberSInt64Type || numberType == kCFNumberLongLongType) { - FORMAT(int64_t, unum_formatInt64) + FORMAT_INT(int64_t, _CFBigNumInitWithInt64) } else if (numberType == kCFNumberLongType || numberType == kCFNumberCFIndexType) { #if __LP64__ - FORMAT(int64_t, unum_formatInt64) + FORMAT_INT(int64_t, _CFBigNumInitWithInt64) #else - FORMAT(int32_t, unum_formatInt64) + FORMAT_INT(int32_t, _CFBigNumInitWithInt32) #endif } else if (numberType == kCFNumberSInt32Type || numberType == kCFNumberIntType) { - FORMAT(int32_t, unum_formatInt64) + FORMAT_INT(int32_t, _CFBigNumInitWithInt32) } else if (numberType == kCFNumberSInt16Type || numberType == kCFNumberShortType) { - FORMAT(int16_t, unum_formatInt64) + FORMAT_INT(int16_t, _CFBigNumInitWithInt16) } else if (numberType == kCFNumberSInt8Type || numberType == kCFNumberCharType) { - FORMAT(int8_t, unum_formatInt64) + FORMAT_INT(int8_t, _CFBigNumInitWithInt8) } else { CFAssert2(0, __kCFLogAssertion, "%s(): unknown CFNumberType (%d)", __PRETTY_FUNCTION__, numberType); return NULL; @@ -480,17 +503,92 @@ CFStringRef CFNumberFormatterCreateStringWithValue(CFAllocatorRef allocator, CFN return string; } -#undef FORMAT +#undef FORMAT_FLT +#undef FORMAT_INT +#undef GET_MULTIPLIER CFNumberRef CFNumberFormatterCreateNumberFromString(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFStringRef string, CFRange *rangep, CFOptionFlags options) { if (allocator == NULL) allocator = __CFGetDefaultAllocator(); __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID()); __CFGenericValidateType(string, CFStringGetTypeID()); - CFNumberType type = (options & kCFNumberFormatterParseIntegersOnly) ? kCFNumberSInt64Type : kCFNumberFloat64Type; - char buffer[16]; - if (CFNumberFormatterGetValueFromString(formatter, string, rangep, type, buffer)) { - return CFNumberCreate(allocator, type, buffer); + char buffer[16] __attribute__ ((aligned (8))); + CFRange r = rangep ? *rangep : CFRangeMake(0, CFStringGetLength(string)); + CFNumberRef multiplierRef = formatter->_multiplier; + formatter->_multiplier = NULL; + Boolean b = CFNumberFormatterGetValueFromString(formatter, string, &r, kCFNumberSInt64Type, buffer); + formatter->_multiplier = multiplierRef; + if (b) { + Boolean passedMultiplier = true; + // We handle the multiplier case here manually; the final + // result is supposed to be (parsed value) / (multiplier), but + // the int case here should only succeed if the parsed value + // is an exact multiple of the multiplier. + if (multiplierRef) { + int64_t tmp = *(int64_t *)buffer; + double multiplier = 1.0; + if (!CFNumberGetValue(multiplierRef, kCFNumberFloat64Type, &multiplier)) { + multiplier = 1.0; + } + double dummy; + if (llabs(tmp) < fabs(multiplier)) { + passedMultiplier = false; + } else if (fabs(multiplier) < 1.0) { // We can't handle this math yet + passedMultiplier = false; + } else if (modf(multiplier, &dummy) == 0.0) { // multiplier is an integer + int64_t imult = (int64_t)multiplier; + int64_t rem = tmp % imult; + if (rem != 0) passedMultiplier = false; + if (passedMultiplier) { + tmp = tmp / imult; + *(int64_t *)buffer = tmp; + } + } else if (multiplier == -1.0) { // simple + tmp = tmp * -1; + *(int64_t *)buffer = tmp; + } else if (multiplier != 1.0) { + // First, throw away integer multiples of the multiplier to + // bring the value down to less than 2^53, so that we can + // cast it to double without losing any precision, important + // for the "remainder is zero" test. + // Find power of two which, when multiplier is multiplied by it, + // results in an integer value. pwr will be <= 52 since multiplier + // is at least 1. + int pwr = 0; + double intgrl; + while (modf(scalbn(multiplier, pwr), &intgrl) != 0.0) pwr++; + int64_t i2 = (int64_t)intgrl; + // scale pwr and i2 up to a reasonably large value so the next loop doesn't take forever + while (llabs(i2) < (1LL << 50)) { i2 *= 2; pwr++; } + int64_t cnt = 0; + while ((1LL << 53) <= llabs(tmp)) { + // subtract (multiplier * 2^pwr) each time + tmp -= i2; // move tmp toward zero + cnt += (1LL << pwr); // remember how many 2^pwr we subtracted + } + // If the integer is less than 2^53, there is no loss + // in converting it to double, so we can just do the + // direct operation now. + double rem = fmod((double)tmp, multiplier); + if (rem != 0.0) passedMultiplier = false; + if (passedMultiplier) { + // The original tmp, which we need to divide by multiplier, is at this point: + // tmp + k * 2^n * multiplier, where k is the number of loop iterations + // That original value needs to be divided by multiplier and put back in the + // buffer. Noting that k * 2^n == cnt, and after some algebra, we have: + tmp = (int64_t)((double)tmp / multiplier) + cnt; + *(int64_t *)buffer = tmp; + } + } + } + if (passedMultiplier && ((r.length == CFStringGetLength(string)) || (options & kCFNumberFormatterParseIntegersOnly))) { + if (rangep) *rangep = r; + return CFNumberCreate(allocator, kCFNumberSInt64Type, buffer); + } + } + if (options & kCFNumberFormatterParseIntegersOnly) return NULL; + if (CFNumberFormatterGetValueFromString(formatter, string, rangep, kCFNumberFloat64Type, buffer)) { + return CFNumberCreate(allocator, kCFNumberFloat64Type, buffer); } return NULL; } @@ -532,7 +630,13 @@ Boolean CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter, CFSt } else if (!formatter->_isLenient) { ustr += range.location; } - if (formatter->_isLenient) __CFNumberFormatterApplyPattern(formatter, formatter->_compformat); + CFNumberRef multiplierRef = formatter->_multiplier; + formatter->_multiplier = NULL; + if (formatter->_isLenient) { + __CFNumberFormatterApplyPattern(formatter, formatter->_compformat); + if (formatter->_multiplier) CFRelease(formatter->_multiplier); + formatter->_multiplier = NULL; + } Boolean integerOnly = 1; switch (numberType) { case kCFNumberSInt8Type: case kCFNumberCharType: @@ -554,10 +658,20 @@ Boolean CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter, CFSt if (isZero) { dpos = rangep ? rangep->length : 0; } else { - if (integerOnly) { - dreti = unum_parseInt64(formatter->_nf, ustr, range.length, &dpos, &status); - } else { - dretd = unum_parseDouble(formatter->_nf, ustr, range.length, &dpos, &status); + char buffer[1024]; + memset(buffer, 0, sizeof(buffer)); + int32_t len = unum_parseDecimal(formatter->_nf, ustr, range.length, &dpos, buffer, sizeof(buffer), &status); + if (!U_FAILURE(status) && 0 < len && integerOnly) { + char *endptr = NULL; + errno = 0; + dreti = strtoll_l(buffer, &endptr, 10, NULL); + if (!(errno == 0 && *endptr == '\0')) status = U_INVALID_FORMAT_ERROR; + } + if (!U_FAILURE(status) && 0 < len) { + char *endptr = NULL; + errno = 0; + dretd = strtod_l(buffer, &endptr, NULL); + if (!(errno == 0 && *endptr == '\0')) status = U_INVALID_FORMAT_ERROR; } } if (formatter->_isLenient) { @@ -570,9 +684,12 @@ Boolean CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter, CFSt rangep->length = uncompIdx - rangep->location; } __CFNumberFormatterApplyPattern(formatter, formatter->_format); + if (formatter->_multiplier) CFRelease(formatter->_multiplier); + formatter->_multiplier = NULL; } else if (rangep) { rangep->length = dpos + (range.location - rangep->location); } + formatter->_multiplier = multiplierRef; CFRelease(stringToParse); if (U_FAILURE(status)) { return false; @@ -582,7 +699,7 @@ Boolean CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter, CFSt if (!CFNumberGetValue(formatter->_multiplier, kCFNumberFloat64Type, &multiplier)) { multiplier = 1.0; } - dreti = (int64_t)((double)dreti / multiplier); // integer truncation + dreti = (int64_t)((double)dreti / multiplier); // integer truncation, plus double cast can be lossy for dreti > 2^53 dretd = dretd / multiplier; } switch (numberType) { diff --git a/CFNumberFormatter.h b/CFNumberFormatter.h index bce9115..9c17102 100644 --- a/CFNumberFormatter.h +++ b/CFNumberFormatter.h @@ -22,7 +22,7 @@ */ /* CFNumberFormatter.h - Copyright (c) 2003-2011, Apple Inc. All rights reserved. + Copyright (c) 2003-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFNUMBERFORMATTER__) @@ -41,7 +41,7 @@ typedef struct __CFNumberFormatter *CFNumberFormatterRef; CF_EXPORT CFTypeID CFNumberFormatterGetTypeID(void); -enum { // number format styles +typedef CF_ENUM(CFIndex, CFNumberFormatterStyle) { // number format styles kCFNumberFormatterNoStyle = 0, kCFNumberFormatterDecimalStyle = 1, kCFNumberFormatterCurrencyStyle = 2, @@ -49,7 +49,6 @@ enum { // number format styles kCFNumberFormatterScientificStyle = 4, kCFNumberFormatterSpellOutStyle = 5 }; -typedef CFIndex CFNumberFormatterStyle; CF_EXPORT @@ -72,7 +71,7 @@ void CFNumberFormatterSetFormat(CFNumberFormatterRef formatter, CFStringRef form // Set the format description string of the number formatter. This // overrides the style settings. The format of the format string // is as defined by the ICU library, and is similar to that found - // in Microsoft Excel and NSNumberFormatter (and Java I believe). + // in Microsoft Excel and NSNumberFormatter. // The number formatter starts with a default format string defined // by the style argument with which it was created. @@ -86,10 +85,9 @@ CFStringRef CFNumberFormatterCreateStringWithValue(CFAllocatorRef allocator, CFN // using the current state of the number formatter. -enum { +typedef CF_OPTIONS(CFOptionFlags, CFNumberFormatterOptionFlags) { kCFNumberFormatterParseIntegersOnly = 1 /* only parse integers */ }; -typedef CFOptionFlags CFNumberFormatterOptionFlags; CF_EXPORT CFNumberRef CFNumberFormatterCreateNumberFromString(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFStringRef string, CFRange *rangep, CFOptionFlags options); @@ -154,7 +152,7 @@ CF_EXPORT const CFStringRef kCFNumberFormatterUseSignificantDigits CF_AVAILABLE( CF_EXPORT const CFStringRef kCFNumberFormatterMinSignificantDigits CF_AVAILABLE(10_5, 2_0); // CFNumber CF_EXPORT const CFStringRef kCFNumberFormatterMaxSignificantDigits CF_AVAILABLE(10_5, 2_0); // CFNumber -enum { +typedef CF_ENUM(CFIndex, CFNumberFormatterRoundingMode) { kCFNumberFormatterRoundCeiling = 0, kCFNumberFormatterRoundFloor = 1, kCFNumberFormatterRoundDown = 2, @@ -163,15 +161,13 @@ enum { kCFNumberFormatterRoundHalfDown = 5, kCFNumberFormatterRoundHalfUp = 6 }; -typedef CFIndex CFNumberFormatterRoundingMode; -enum { +typedef CF_ENUM(CFIndex, CFNumberFormatterPadPosition) { kCFNumberFormatterPadBeforePrefix = 0, kCFNumberFormatterPadAfterPrefix = 1, kCFNumberFormatterPadBeforeSuffix = 2, kCFNumberFormatterPadAfterSuffix = 3 }; -typedef CFIndex CFNumberFormatterPadPosition; CF_EXPORT diff --git a/CFOldStylePList.c b/CFOldStylePList.c new file mode 100644 index 0000000..3881788 --- /dev/null +++ b/CFOldStylePList.c @@ -0,0 +1,631 @@ +/* + * Copyright (c) 2012 Apple 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@ + */ + +/* CFOldStylePList.c + Copyright (c) 1999-2012, Apple Inc. All rights reserved. + Responsibility: Tony Parker +*/ + +#include +#include +#include +#include +#include +#include "CFInternal.h" +#include +#include + +#include + +// +// Old NeXT-style property lists +// + +CF_INLINE void __CFPListRelease(CFTypeRef cf, CFAllocatorRef allocator) { + if (cf && !_CFAllocatorIsGCRefZero(allocator)) CFRelease(cf); +} + +__private_extern__ CFErrorRef __CFPropertyListCreateError(CFIndex code, CFStringRef debugString, ...); + +typedef struct { + const UniChar *begin; + const UniChar *curr; + const UniChar *end; + CFErrorRef error; + CFAllocatorRef allocator; + UInt32 mutabilityOption; + CFMutableSetRef stringSet; // set of all strings involved in this parse; allows us to share non-mutable strings in the returned plist +} _CFStringsFileParseInfo; + +// warning: doesn't have a good idea of Unicode line separators +static UInt32 lineNumberStrings(_CFStringsFileParseInfo *pInfo) { + const UniChar *p = pInfo->begin; + UInt32 count = 1; + while (p < pInfo->curr) { + if (*p == '\r') { + count ++; + if (*(p + 1) == '\n') + p ++; + } else if (*p == '\n') { + count ++; + } + p ++; + } + return count; +} + +static CFTypeRef parsePlistObject(_CFStringsFileParseInfo *pInfo, bool requireObject); + +#define isValidUnquotedStringCharacter(x) (((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z') || ((x) >= '0' && (x) <= '9') || (x) == '_' || (x) == '$' || (x) == '/' || (x) == ':' || (x) == '.' || (x) == '-') + +// Returns true if the advance found something before the end of the buffer, false otherwise +static Boolean advanceToNonSpace(_CFStringsFileParseInfo *pInfo) { + UniChar ch2; + while (pInfo->curr < pInfo->end) { + ch2 = *(pInfo->curr); + pInfo->curr ++; + if (ch2 >= 9 && ch2 <= 0x0d) continue; // tab, newline, vt, form feed, carriage return + if (ch2 == ' ' || ch2 == 0x2028 || ch2 == 0x2029) continue; // space and Unicode line sep, para sep + if (ch2 == '/') { + if (pInfo->curr >= pInfo->end) { + // whoops; back up and return + pInfo->curr --; + return true; + } else if (*(pInfo->curr) == '/') { + pInfo->curr ++; + while (pInfo->curr < pInfo->end) { // go to end of comment line + UniChar ch3 = *(pInfo->curr); + if (ch3 == '\n' || ch3 == '\r' || ch3 == 0x2028 || ch3 == 0x2029) break; + pInfo->curr ++; + } + } else if (*(pInfo->curr) == '*') { // handle /* ... */ + pInfo->curr ++; + while (pInfo->curr < pInfo->end) { + ch2 = *(pInfo->curr); + pInfo->curr ++; + if (ch2 == '*' && pInfo->curr < pInfo->end && *(pInfo->curr) == '/') { + pInfo->curr ++; // advance past the '/' + break; + } + } + } else { + pInfo->curr --; + return true; + } + } else { + pInfo->curr --; + return true; + } + } + return false; +} + +static UniChar getSlashedChar(_CFStringsFileParseInfo *pInfo) { + UniChar ch = *(pInfo->curr); + pInfo->curr ++; + switch (ch) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': { + uint8_t num = ch - '0'; + UniChar result; + CFIndex usedCharLen; + /* three digits maximum to avoid reading \000 followed by 5 as \5 ! */ + if ((ch = *(pInfo->curr)) >= '0' && ch <= '7') { // we use in this test the fact that the buffer is zero-terminated + pInfo->curr ++; + num = (num << 3) + ch - '0'; + if ((pInfo->curr < pInfo->end) && (ch = *(pInfo->curr)) >= '0' && ch <= '7') { + pInfo->curr ++; + num = (num << 3) + ch - '0'; + } + } + CFStringEncodingBytesToUnicode(kCFStringEncodingNextStepLatin, 0, &num, sizeof(uint8_t), NULL, &result, 1, &usedCharLen); + return (usedCharLen == 1) ? result : 0; + } + case 'U': { + unsigned num = 0, numDigits = 4; /* Parse four digits */ + while (pInfo->curr < pInfo->end && numDigits--) { + if (((ch = *(pInfo->curr)) < 128) && isxdigit(ch)) { + pInfo->curr ++; + num = (num << 4) + ((ch <= '9') ? (ch - '0') : ((ch <= 'F') ? (ch - 'A' + 10) : (ch - 'a' + 10))); + } + } + return num; + } + case 'a': return '\a'; // Note: the meaning of '\a' varies with -traditional to gcc + case 'b': return '\b'; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case 't': return '\t'; + case 'v': return '\v'; + case '"': return '\"'; + case '\n': return '\n'; + } + return ch; +} + +static CFStringRef _uniqueStringForCharacters(_CFStringsFileParseInfo *pInfo, const UniChar *base, CFIndex length) { + if (0 == length) return !_CFAllocatorIsGCRefZero(pInfo->allocator) ? (CFStringRef)CFRetain(CFSTR("")) : CFSTR(""); + // This is to avoid having to promote the buffers of all the strings compared against + // during the set probe; if a Unicode string is passed in, that's what happens. + CFStringRef stringToUnique = NULL; + Boolean use_stack = (length < 2048); + STACK_BUFFER_DECL(uint8_t, buffer, use_stack ? length + 1 : 1); + uint8_t *ascii = use_stack ? buffer : (uint8_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, length + 1, 0); + for (CFIndex idx = 0; idx < length; idx++) { + UniChar ch = base[idx]; + if (ch < 0x80) { + ascii[idx] = (uint8_t)ch; + } else { + stringToUnique = CFStringCreateWithCharacters(pInfo->allocator, base, length); + break; + } + } + if (!stringToUnique) { + ascii[length] = '\0'; + stringToUnique = CFStringCreateWithBytes(pInfo->allocator, ascii, length, kCFStringEncodingASCII, false); + } + if (ascii != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, ascii); + CFStringRef uniqued = (CFStringRef)CFSetGetValue(pInfo->stringSet, stringToUnique); + if (!uniqued) { + CFSetAddValue(pInfo->stringSet, stringToUnique); + uniqued = stringToUnique; + } + __CFPListRelease(stringToUnique, pInfo->allocator); + if (uniqued && !_CFAllocatorIsGCRefZero(pInfo->allocator)) CFRetain(uniqued); + return uniqued; +} + +static CFStringRef _uniqueStringForString(_CFStringsFileParseInfo *pInfo, CFStringRef stringToUnique) { + CFStringRef uniqued = (CFStringRef)CFSetGetValue(pInfo->stringSet, stringToUnique); + if (!uniqued) { + uniqued = (CFStringRef)__CFStringCollectionCopy(pInfo->allocator, stringToUnique); + CFSetAddValue(pInfo->stringSet, uniqued); + __CFTypeCollectionRelease(pInfo->allocator, uniqued); + } + if (uniqued && !_CFAllocatorIsGCRefZero(pInfo->allocator)) CFRetain(uniqued); + return uniqued; +} + +static CFStringRef parseQuotedPlistString(_CFStringsFileParseInfo *pInfo, UniChar quote) { + CFMutableStringRef str = NULL; + const UniChar *startMark = pInfo->curr; + const UniChar *mark = pInfo->curr; + while (pInfo->curr < pInfo->end) { + UniChar ch = *(pInfo->curr); + if (ch == quote) break; + if (ch == '\\') { + if (!str) str = CFStringCreateMutable(pInfo->allocator, 0); + CFStringAppendCharacters(str, mark, pInfo->curr - mark); + pInfo->curr ++; + ch = getSlashedChar(pInfo); + CFStringAppendCharacters(str, &ch, 1); + mark = pInfo->curr; + } else { + // Note that the original NSParser code was much more complex at this point, but it had to deal with 8-bit characters in a non-UniChar stream. We always have UniChar (we translated the data by the system encoding at the very beginning, hopefully), so this is safe. + pInfo->curr ++; + } + } + if (pInfo->end <= pInfo->curr) { + __CFPListRelease(str, pInfo->allocator); + pInfo->curr = startMark; + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Unterminated quoted string starting on line %d"), lineNumberStrings(pInfo)); + return NULL; + } + if (!str) { + if (pInfo->mutabilityOption == kCFPropertyListMutableContainersAndLeaves) { + str = CFStringCreateMutable(pInfo->allocator, 0); + CFStringAppendCharacters(str, mark, pInfo->curr - mark); + } else { + str = (CFMutableStringRef)_uniqueStringForCharacters(pInfo, mark, pInfo->curr-mark); + } + } else { + if (mark != pInfo->curr) { + CFStringAppendCharacters(str, mark, pInfo->curr - mark); + } + if (pInfo->mutabilityOption != kCFPropertyListMutableContainersAndLeaves) { + CFStringRef uniqueString = _uniqueStringForString(pInfo, str); + __CFPListRelease(str, pInfo->allocator); + str = (CFMutableStringRef)uniqueString; + } + } + pInfo->curr ++; // Advance past the quote character before returning. + if (pInfo->error) { + CFRelease(pInfo->error); + pInfo->error = NULL; + } + return str; +} + +static CFStringRef parseUnquotedPlistString(_CFStringsFileParseInfo *pInfo) { + const UniChar *mark = pInfo->curr; + while (pInfo->curr < pInfo->end) { + UniChar ch = *pInfo->curr; + if (isValidUnquotedStringCharacter(ch)) + pInfo->curr ++; + else break; + } + if (pInfo->curr != mark) { + if (pInfo->mutabilityOption != kCFPropertyListMutableContainersAndLeaves) { + CFStringRef str = _uniqueStringForCharacters(pInfo, mark, pInfo->curr-mark); + return str; + } else { + CFMutableStringRef str = CFStringCreateMutable(pInfo->allocator, 0); + CFStringAppendCharacters(str, mark, pInfo->curr - mark); + return str; + } + } + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Unexpected EOF")); + return NULL; +} + +static CFStringRef parsePlistString(_CFStringsFileParseInfo *pInfo, bool requireObject) { + UniChar ch; + Boolean foundChar = advanceToNonSpace(pInfo); + if (!foundChar) { + if (requireObject) { + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Unexpected EOF while parsing string")); + } + return NULL; + } + ch = *(pInfo->curr); + if (ch == '\'' || ch == '\"') { + pInfo->curr ++; + return parseQuotedPlistString(pInfo, ch); + } else if (isValidUnquotedStringCharacter(ch)) { + return parseUnquotedPlistString(pInfo); + } else { + if (requireObject) { + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Invalid string character at line %d"), lineNumberStrings(pInfo)); + } + return NULL; + } +} + +static CFTypeRef parsePlistArray(_CFStringsFileParseInfo *pInfo) { + CFMutableArrayRef array = CFArrayCreateMutable(pInfo->allocator, 0, &kCFTypeArrayCallBacks); + CFTypeRef tmp = parsePlistObject(pInfo, false); + Boolean foundChar; + while (tmp) { + CFArrayAppendValue(array, tmp); + __CFPListRelease(tmp, pInfo->allocator); + foundChar = advanceToNonSpace(pInfo); + if (!foundChar) { + __CFPListRelease(array, pInfo->allocator); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Expected ',' for array at line %d"), lineNumberStrings(pInfo)); + return NULL; + } + if (*pInfo->curr != ',') { + tmp = NULL; + } else { + pInfo->curr ++; + tmp = parsePlistObject(pInfo, false); + } + } + foundChar = advanceToNonSpace(pInfo); + if (!foundChar || *pInfo->curr != ')') { + __CFPListRelease(array, pInfo->allocator); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Expected terminating ')' for array at line %d"), lineNumberStrings(pInfo)); + return NULL; + } + if (pInfo->error) { + CFRelease(pInfo->error); + pInfo->error = NULL; + } + pInfo->curr ++; + return array; +} + +__attribute__((noinline)) void _CFPropertyListMissingSemicolon(UInt32 line) { + CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListCreateFromXMLData(): Old-style plist parser: missing semicolon in dictionary on line %d. Parsing will be abandoned. Break on _CFPropertyListMissingSemicolon to debug."), line); +} + +__attribute__((noinline)) void _CFPropertyListMissingSemicolonOrValue(UInt32 line) { + CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListCreateFromXMLData(): Old-style plist parser: missing semicolon or value in dictionary on line %d. Parsing will be abandoned. Break on _CFPropertyListMissingSemicolonOrValue to debug."), line); +} + +static CFDictionaryRef parsePlistDictContent(_CFStringsFileParseInfo *pInfo) { + CFMutableDictionaryRef dict = CFDictionaryCreateMutable(pInfo->allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFStringRef key = NULL; + Boolean failedParse = false; + key = parsePlistString(pInfo, false); + while (key) { + CFTypeRef value; + Boolean foundChar = advanceToNonSpace(pInfo); + if (!foundChar) { + UInt32 line = lineNumberStrings(pInfo); + _CFPropertyListMissingSemicolonOrValue(line); + failedParse = true; + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Missing ';' on line %d"), line); + break; + } + + if (*pInfo->curr == ';') { + /* This is a strings file using the shortcut format */ + /* although this check here really applies to all plists. */ + value = CFRetain(key); + } else if (*pInfo->curr == '=') { + pInfo->curr ++; + value = parsePlistObject(pInfo, true); + if (!value) { + failedParse = true; + break; + } + } else { + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Unexpected ';' or '=' after key at line %d"), lineNumberStrings(pInfo)); + failedParse = true; + break; + } + CFDictionarySetValue(dict, key, value); + __CFPListRelease(key, pInfo->allocator); + key = NULL; + __CFPListRelease(value, pInfo->allocator); + value = NULL; + foundChar = advanceToNonSpace(pInfo); + if (foundChar && *pInfo->curr == ';') { + pInfo->curr ++; + key = parsePlistString(pInfo, false); + } else if (true || !foundChar) { + UInt32 line = lineNumberStrings(pInfo); + _CFPropertyListMissingSemicolon(line); + failedParse = true; + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Missing ';' on line %d"), line); + } + } + + if (failedParse) { + __CFPListRelease(key, pInfo->allocator); + __CFPListRelease(dict, pInfo->allocator); + return NULL; + } + if (pInfo->error) { + CFRelease(pInfo->error); + pInfo->error = NULL; + } + return dict; +} + +static CFTypeRef parsePlistDict(_CFStringsFileParseInfo *pInfo) { + CFDictionaryRef dict = parsePlistDictContent(pInfo); + if (!dict) return NULL; + Boolean foundChar = advanceToNonSpace(pInfo); + if (!foundChar || *pInfo->curr != '}') { + __CFPListRelease(dict, pInfo->allocator); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Expected terminating '}' for dictionary at line %d"), lineNumberStrings(pInfo)); + return NULL; + } + pInfo->curr ++; + return dict; +} + +CF_INLINE unsigned char fromHexDigit(unsigned char ch) { + if (isdigit(ch)) return ch - '0'; + if ((ch >= 'a') && (ch <= 'f')) return ch - 'a' + 10; + if ((ch >= 'A') && (ch <= 'F')) return ch - 'A' + 10; + return 0xff; // Just choose a large number for the error code +} + +/* Gets up to bytesSize bytes from a plist data. Returns number of bytes actually read. Leaves cursor at first non-space, non-hex character. + -1 is returned for unexpected char, -2 for uneven number of hex digits + */ +static int getDataBytes(_CFStringsFileParseInfo *pInfo, unsigned char *bytes, int bytesSize) { + int numBytesRead = 0; + while ((pInfo->curr < pInfo->end) && (numBytesRead < bytesSize)) { + int first, second; + UniChar ch1 = *pInfo->curr; + if (ch1 == '>') return numBytesRead; // Meaning we're done + first = fromHexDigit((unsigned char)ch1); + if (first != 0xff) { // If the first char is a hex, then try to read a second hex + pInfo->curr++; + if (pInfo->curr >= pInfo->end) return -2; // Error: uneven number of hex digits + UniChar ch2 = *pInfo->curr; + second = fromHexDigit((unsigned char)ch2); + if (second == 0xff) return -2; // Error: uneven number of hex digits + bytes[numBytesRead++] = (first << 4) + second; + pInfo->curr++; + } else if (ch1 == ' ' || ch1 == '\n' || ch1 == '\t' || ch1 == '\r' || ch1 == 0x2028 || ch1 == 0x2029) { + pInfo->curr++; + } else { + return -1; // Error: unexpected character + } + } + return numBytesRead; // This does likely mean we didn't encounter a '>', but we'll let the caller deal with that +} + +#define numBytes 400 +static CFTypeRef parsePlistData(_CFStringsFileParseInfo *pInfo) { + CFMutableDataRef result = CFDataCreateMutable(pInfo->allocator, 0); + + // Read hex bytes and append them to result + while (1) { + unsigned char bytes[numBytes]; + int numBytesRead = getDataBytes(pInfo, bytes, numBytes); + if (numBytesRead < 0) { + __CFPListRelease(result, pInfo->allocator); + switch (numBytesRead) { + case -2: + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Malformed data byte group at line %d; uneven length"), lineNumberStrings(pInfo)); + break; + default: + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Malformed data byte group at line %d; invalid hex"), lineNumberStrings(pInfo)); + break; + } + return NULL; + } + if (numBytesRead == 0) break; + CFDataAppendBytes(result, bytes, numBytesRead); + } + + if (pInfo->error) { + CFRelease(pInfo->error); + pInfo->error = NULL; + } + + if (*(pInfo->curr) == '>') { + pInfo->curr ++; // Move past '>' + return result; + } else { + __CFPListRelease(result, pInfo->allocator); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Expected terminating '>' for data at line %d"), lineNumberStrings(pInfo)); + return NULL; + } +} +#undef numBytes + +// Returned object is retained; caller must free. +static CFTypeRef parsePlistObject(_CFStringsFileParseInfo *pInfo, bool requireObject) { + UniChar ch; + Boolean foundChar = advanceToNonSpace(pInfo); + if (!foundChar) { + if (requireObject) { + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Unexpected EOF while parsing plist")); + } + return NULL; + } + ch = *(pInfo->curr); + pInfo->curr ++; + if (ch == '{') { + return parsePlistDict(pInfo); + } else if (ch == '(') { + return parsePlistArray(pInfo); + } else if (ch == '<') { + return parsePlistData(pInfo); + } else if (ch == '\'' || ch == '\"') { + return parseQuotedPlistString(pInfo, ch); + } else if (isValidUnquotedStringCharacter(ch)) { + pInfo->curr --; + return parseUnquotedPlistString(pInfo); + } else { + pInfo->curr --; // Must back off the charcter we just read + if (requireObject) { + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Unexpected character '0x%x' at line %d"), ch, lineNumberStrings(pInfo)); + } + return NULL; + } +} + +// CFAllocatorRef allocator, CFDataRef xmlData, CFStringRef originalString, CFStringEncoding guessedEncoding, CFOptionFlags option, CFErrorRef *outError, Boolean allowNewTypes, CFPropertyListFormat *format, CFSetRef keyPaths + +__private_extern__ CFTypeRef __CFParseOldStylePropertyListOrStringsFile(CFAllocatorRef allocator, CFDataRef xmlData, CFStringRef originalString, CFStringEncoding guessedEncoding, CFOptionFlags option, CFErrorRef *outError,CFPropertyListFormat *format) { + + // Convert the string to UTF16 for parsing old-style + if (originalString) { + // Ensure that originalString is not collected while we are using it + CFRetain(originalString); + } else { + originalString = CFStringCreateWithBytes(kCFAllocatorSystemDefault, CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData), guessedEncoding, NO); + if (!originalString) { + // Couldn't convert + if (outError) *outError = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Conversion of string failed.")); + return NULL; + } + } + + UInt32 length; + Boolean createdBuffer = false; + length = CFStringGetLength(originalString); + if (!length) { + if (outError) *outError = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Conversion of string failed. The string is empty.")); + return NULL; + } + + UniChar *buf = (UniChar *)CFStringGetCharactersPtr(originalString); + if (!buf) { + buf = (UniChar *)CFAllocatorAllocate(allocator, length * sizeof(UniChar), 0); + if (!buf) { + CRSetCrashLogMessage("CFPropertyList ran out of memory while attempting to allocate temporary storage."); + return NULL; + } + CFStringGetCharacters(originalString, CFRangeMake(0, length), buf); + createdBuffer = true; + } + + _CFStringsFileParseInfo stringsPInfo; + stringsPInfo.begin = buf; + stringsPInfo.end = buf+length; + stringsPInfo.curr = buf; + stringsPInfo.allocator = allocator; + stringsPInfo.mutabilityOption = option; + stringsPInfo.stringSet = CFSetCreateMutable(allocator, 0, &kCFTypeSetCallBacks); + stringsPInfo.error = NULL; + + const UniChar *begin = stringsPInfo.curr; + CFTypeRef result = NULL; + Boolean foundChar = advanceToNonSpace(&stringsPInfo); + if (!foundChar) { + // A file consisting only of whitespace (or empty) is now defined to be an empty dictionary + result = CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + } else { + result = parsePlistObject(&stringsPInfo, true); + if (result) { + foundChar = advanceToNonSpace(&stringsPInfo); + if (foundChar) { + if (CFGetTypeID(result) != CFStringGetTypeID()) { + __CFPListRelease(result, allocator); + result = NULL; + if (stringsPInfo.error) CFRelease(stringsPInfo.error); + stringsPInfo.error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Junk after plist at line %d"), lineNumberStrings(&stringsPInfo)); + } else { + // Reset info and keep parsing + __CFPListRelease(result, allocator); + if (stringsPInfo.error) CFRelease(stringsPInfo.error); + stringsPInfo.error = NULL; + + // Check for a strings file (looks like a dictionary without the opening/closing curly braces) + stringsPInfo.curr = begin; + result = parsePlistDictContent(&stringsPInfo); + } + } + } + } + + if (!result) { + // Must return some kind of error if requested + if (outError) { + if (stringsPInfo.error) { + // Transfer ownership + *outError = stringsPInfo.error; + } else { + *outError = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Unknown error parsing property list around line %d"), lineNumberStrings(&stringsPInfo)); + } + } else if (stringsPInfo.error) { + // Caller doesn't want it, so we need to free it + CFRelease(stringsPInfo.error); + } + } + + if (result && format) *format = kCFPropertyListOpenStepFormat; + + if (createdBuffer && !_CFAllocatorIsGCRefZero(allocator)) CFAllocatorDeallocate(allocator, buf); + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(stringsPInfo.stringSet); + CFRelease(originalString); + return result; +} + +#undef isValidUnquotedStringCharacter diff --git a/CFPlatform.c b/CFPlatform.c index 1170cd1..7d51cfa 100644 --- a/CFPlatform.c +++ b/CFPlatform.c @@ -22,13 +22,13 @@ */ /* CFPlatform.c - Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Copyright (c) 1999-2012, Apple Inc. All rights reserved. Responsibility: Tony Parker */ #include "CFInternal.h" #include -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI #include #include #include @@ -48,15 +48,15 @@ #endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_WINDOWS #define kCFPlatformInterfaceStringEncoding kCFStringEncodingUTF8 #else #define kCFPlatformInterfaceStringEncoding CFStringGetSystemEncoding() #endif -static CFStringRef _CFUserName(void); +extern void __CFGetUGIDs(uid_t *euid, gid_t *egid); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI // CoreGraphics and LaunchServices are only projects (1 Dec 2006) that use these char **_CFArgv(void) { return *_NSGetArgv(); } int _CFArgc(void) { return *_NSGetArgc(); } @@ -67,22 +67,6 @@ __private_extern__ Boolean _CFGetCurrentDirectory(char *path, int maxlen) { return getcwd(path, maxlen) != NULL; } -#if SUPPORT_CFM -static Boolean __CFIsCFM = false; - -// If called super early, we just return false -__private_extern__ Boolean _CFIsCFM(void) { - return __CFIsCFM; -} -#endif - -#if DEPLOYMENT_TARGET_WINDOWS -#define PATH_SEP '\\' -#else -#define PATH_SEP '/' -#endif - - #if DEPLOYMENT_TARGET_WINDOWS // Returns the path to the CF DLL, which we can then use to find resources like char sets bool bDllPathCached = false; @@ -155,7 +139,7 @@ const char *_CFProcessPath(void) { } #endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI const char *_CFProcessPath(void) { if (__CFProcessPath) return __CFProcessPath; #if DEPLOYMENT_TARGET_MACOSX @@ -172,20 +156,6 @@ const char *_CFProcessPath(void) { uint32_t size = CFMaxPathSize; char buffer[size]; if (0 == _NSGetExecutablePath(buffer, &size)) { -#if SUPPORT_CFM - size_t len = strlen(buffer); - if (12 <= len && 0 == strcmp("LaunchCFMApp", buffer + len - 12)) { - struct stat exec, lcfm; - const char *launchcfm = "/System/Library/Frameworks/Carbon.framework/Versions/Current/Support/LaunchCFMApp"; - if (0 == stat(launchcfm, &lcfm) && 0 == stat(buffer, &exec) && (lcfm.st_dev == exec.st_dev) && (lcfm.st_ino == exec.st_ino)) { - // Executable is LaunchCFMApp, take special action - __CFIsCFM = true; - if ((*_NSGetArgv())[1] && '/' == *((*_NSGetArgv())[1])) { - strlcpy(buffer, (*_NSGetArgv())[1], sizeof(buffer)); - } - } - } -#endif __CFProcessPath = strdup(buffer); __CFprogname = strrchr(__CFProcessPath, PATH_SEP); __CFprogname = (__CFprogname ? __CFprogname + 1 : __CFProcessPath); @@ -233,104 +203,95 @@ __private_extern__ CFStringRef _CFProcessNameString(void) { return __CFProcessNameString; } -static CFStringRef __CFUserName = NULL; -static CFSpinLock_t __CFPlatformCacheLock = CFSpinLockInit; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD #include +#include -static CFURLRef __CFHomeDirectory = NULL; -static uint32_t __CFEUID = -1; -static uint32_t __CFUID = -1; - -static CFURLRef _CFCopyHomeDirURLForUser(struct passwd *upwd) { // __CFPlatformCacheLock must be locked on entry and will be on exit +// Set the fallBackToHome parameter to true if we should fall back to the HOME environment variable if all else fails. Otherwise return NULL. +static CFURLRef _CFCopyHomeDirURLForUser(struct passwd *upwd, bool fallBackToHome) { + const char *fixedHomePath = issetugid() ? NULL : __CFgetenv("CFFIXED_USER_HOME"); + const char *homePath = NULL; + + // Calculate the home directory we will use + // First try CFFIXED_USER_HOME (only if not setugid), then fall back to the upwd, then fall back to HOME environment variable CFURLRef home = NULL; - if (!issetugid()) { - const char *path = __CFgetenv("CFFIXED_USER_HOME"); - if (path) { - home = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)path, strlen(path), true); - } - } - if (!home) { - if (upwd && upwd->pw_dir) { - home = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)upwd->pw_dir, strlen(upwd->pw_dir), true); - } - } + if (!issetugid() && fixedHomePath) home = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)fixedHomePath, strlen(fixedHomePath), true); + if (!home && upwd && upwd->pw_dir) home = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)upwd->pw_dir, strlen(upwd->pw_dir), true); + if (fallBackToHome && !home) homePath = __CFgetenv("HOME"); + if (fallBackToHome && !home && homePath) home = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)homePath, strlen(homePath), true); + return home; } -static void _CFUpdateUserInfo(void) { // __CFPlatformCacheLock must be locked on entry and will be on exit - struct passwd *upwd; - - __CFEUID = geteuid(); - __CFUID = getuid(); - if (__CFHomeDirectory) CFRelease(__CFHomeDirectory); - __CFHomeDirectory = NULL; - if (__CFUserName) CFRelease(__CFUserName); - __CFUserName = NULL; - - upwd = getpwuid(__CFEUID ? __CFEUID : __CFUID); - __CFHomeDirectory = _CFCopyHomeDirURLForUser(upwd); - if (!__CFHomeDirectory) { - const char *cpath = __CFgetenv("HOME"); - if (cpath) { - __CFHomeDirectory = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)cpath, strlen(cpath), true); - } - } +#endif + + +#define CFMaxHostNameLength 256 +#define CFMaxHostNameSize (CFMaxHostNameLength+1) + +__private_extern__ CFStringRef _CFStringCreateHostName(void) { + char myName[CFMaxHostNameSize]; + + // return @"" instead of nil a la CFUserName() and Ali Ozer + if (0 != gethostname(myName, CFMaxHostNameSize)) myName[0] = '\0'; + return CFStringCreateWithCString(kCFAllocatorSystemDefault, myName, kCFPlatformInterfaceStringEncoding); +} + +/* These are sanitized versions of the above functions. We might want to eliminate the above ones someday. + These can return NULL. +*/ +CF_EXPORT CFStringRef CFGetUserName(void) { + return CFCopyUserName(); +} - // This implies that UserManager stores directory info in CString - // rather than FileSystemRep. Perhaps this is wrong & we should - // expect NeXTSTEP encodings. A great test of our localized system would - // be to have a user "O-umlat z e r". XXX +CF_EXPORT CFStringRef CFCopyUserName(void) { + CFStringRef result = NULL; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD + uid_t euid; + __CFGetUGIDs(&euid, NULL); + struct passwd *upwd = getpwuid(euid ? euid : getuid()); if (upwd && upwd->pw_name) { - __CFUserName = CFStringCreateWithCString(kCFAllocatorSystemDefault, upwd->pw_name, kCFPlatformInterfaceStringEncoding); + result = CFStringCreateWithCString(kCFAllocatorSystemDefault, upwd->pw_name, kCFPlatformInterfaceStringEncoding); } else { const char *cuser = __CFgetenv("USER"); - if (cuser) - __CFUserName = CFStringCreateWithCString(kCFAllocatorSystemDefault, cuser, kCFPlatformInterfaceStringEncoding); + if (cuser) { + result = CFStringCreateWithCString(kCFAllocatorSystemDefault, cuser, kCFPlatformInterfaceStringEncoding); + } } -} +#elif DEPLOYMENT_TARGET_WINDOWS + wchar_t username[1040]; + DWORD size = 1040; + username[0] = 0; + if (GetUserNameW(username, &size)) { + // discount the extra NULL by decrementing the size + result = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)username, size - 1); + } else { + const char *cname = __CFgetenv("USERNAME"); + if (cname) { + result = CFStringCreateWithCString(kCFAllocatorSystemDefault, cname, kCFPlatformInterfaceStringEncoding); + } + } +#else +#error Dont know how to compute user name on this platform #endif + if (!result) + result = (CFStringRef)CFRetain(CFSTR("")); + return result; +} -static CFURLRef _CFCreateHomeDirectoryURLForUser(CFStringRef uName) { // __CFPlatformCacheLock must be locked on entry and will be on exit -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD - if (!uName) { - if (geteuid() != __CFEUID || getuid() != __CFUID || !__CFHomeDirectory) - _CFUpdateUserInfo(); - if (__CFHomeDirectory) CFRetain(__CFHomeDirectory); - return __CFHomeDirectory; - } else { - struct passwd *upwd = NULL; - char buf[128], *user; - SInt32 len = CFStringGetLength(uName), size = CFStringGetMaximumSizeForEncoding(len, kCFPlatformInterfaceStringEncoding); - CFIndex usedSize; - if (size < 127) { - user = buf; - } else { - user = CFAllocatorAllocate(kCFAllocatorSystemDefault, size+1, 0); - if (__CFOASafe) __CFSetLastAllocationEventName(user, "CFUtilities (temp)"); - } - if (CFStringGetBytes(uName, CFRangeMake(0, len), kCFPlatformInterfaceStringEncoding, 0, true, (uint8_t *)user, size, &usedSize) == len) { - user[usedSize] = '\0'; - upwd = getpwnam(user); - } - if (buf != user) { - CFAllocatorDeallocate(kCFAllocatorSystemDefault, user); - } - return _CFCopyHomeDirURLForUser(upwd); - } +CFURLRef CFCopyHomeDirectoryURL(void) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD + uid_t euid; + __CFGetUGIDs(&euid, NULL); + struct passwd *upwd = getpwuid(euid ? euid : getuid()); + return _CFCopyHomeDirURLForUser(upwd, true); #elif DEPLOYMENT_TARGET_WINDOWS - // This code can only get the directory for the current user - if (uName && !CFEqual(uName, _CFUserName())) { - CFLog(kCFLogLevelError, CFSTR("CFCopyHomeDirectoryURLForUser(): Unable to get home directory for other user")); - return NULL; - } - CFURLRef retVal = NULL; CFIndex len = 0; CFStringRef str = NULL; - + UniChar pathChars[MAX_PATH]; if (S_OK == SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, (wchar_t *)pathChars)) { len = (CFIndex)wcslen((wchar_t *)pathChars); @@ -338,7 +299,7 @@ static CFURLRef _CFCreateHomeDirectoryURLForUser(CFStringRef uName) { // __CFPla retVal = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, kCFURLWindowsPathStyle, true); CFRelease(str); } - + if (!retVal) { // Fall back to environment variable, but this will not be unicode compatible const char *cpath = __CFgetenv("HOMEPATH"); @@ -352,7 +313,7 @@ static CFURLRef _CFCreateHomeDirectoryURLForUser(CFStringRef uName) { // __CFPla CFRelease(str); } } - + if (!retVal) { // Last resort: We have to get "some" directory location, so fall-back to the processes current directory. UniChar currDir[MAX_PATH]; @@ -364,7 +325,7 @@ static CFURLRef _CFCreateHomeDirectoryURLForUser(CFStringRef uName) { // __CFPla CFRelease(str); } } - + // We could do more here (as in KB Article Q101507). If that article is to be believed, we should only run into this case on Win95, or through user error. CFStringRef testPath = CFURLCopyFileSystemPath(retVal, kCFURLWindowsPathStyle); if (CFStringGetLength(testPath) == 0) { @@ -372,76 +333,54 @@ static CFURLRef _CFCreateHomeDirectoryURLForUser(CFStringRef uName) { // __CFPla retVal = NULL; } if (testPath) CFRelease(testPath); - + return retVal; #else #error Dont know how to compute users home directories on this platform #endif } -static CFStringRef _CFUserName(void) { // __CFPlatformCacheLock must be locked on entry and will be on exit -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD - if (geteuid() != __CFEUID || getuid() != __CFUID) - _CFUpdateUserInfo(); +CF_EXPORT CFURLRef CFCopyHomeDirectoryURLForUser(CFStringRef uName) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD + if (!uName) { + uid_t euid; + __CFGetUGIDs(&euid, NULL); + struct passwd *upwd = getpwuid(euid ? euid : getuid()); + return _CFCopyHomeDirURLForUser(upwd, true); + } else { + struct passwd *upwd = NULL; + char buf[128], *user; + SInt32 len = CFStringGetLength(uName), size = CFStringGetMaximumSizeForEncoding(len, kCFPlatformInterfaceStringEncoding); + CFIndex usedSize; + if (size < 127) { + user = buf; + } else { + user = CFAllocatorAllocate(kCFAllocatorSystemDefault, size+1, 0); + } + if (CFStringGetBytes(uName, CFRangeMake(0, len), kCFPlatformInterfaceStringEncoding, 0, true, (uint8_t *)user, size, &usedSize) == len) { + user[usedSize] = '\0'; + upwd = getpwnam(user); + } + if (buf != user) { + CFAllocatorDeallocate(kCFAllocatorSystemDefault, user); + } + return _CFCopyHomeDirURLForUser(upwd, false); + } #elif DEPLOYMENT_TARGET_WINDOWS - if (!__CFUserName) { - wchar_t username[1040]; - DWORD size = 1040; - username[0] = 0; - if (GetUserNameW(username, &size)) { - // discount the extra NULL by decrementing the size - __CFUserName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)username, size - 1); - } else { - const char *cname = __CFgetenv("USERNAME"); - if (cname) - __CFUserName = CFStringCreateWithCString(kCFAllocatorSystemDefault, cname, kCFPlatformInterfaceStringEncoding); - } + // This code can only get the directory for the current user + CFStringRef userName = uName ? CFCopyUserName() : NULL; + if (uName && !CFEqual(uName, userName)) { + CFLog(kCFLogLevelError, CFSTR("CFCopyHomeDirectoryURLForUser(): Unable to get home directory for other user")); + if (userName) CFRelease(userName); + return NULL; } + if (userName) CFRelease(userName); + return CFCopyHomeDirectoryURL(); #else -#error Dont know how to compute user name on this platform +#error Dont know how to compute users home directories on this platform #endif - if (!__CFUserName) - __CFUserName = (CFStringRef)CFRetain(CFSTR("")); - return __CFUserName; } -#define CFMaxHostNameLength 256 -#define CFMaxHostNameSize (CFMaxHostNameLength+1) - -__private_extern__ CFStringRef _CFStringCreateHostName(void) { - char myName[CFMaxHostNameSize]; - - // return @"" instead of nil a la CFUserName() and Ali Ozer - if (0 != gethostname(myName, CFMaxHostNameSize)) myName[0] = '\0'; - return CFStringCreateWithCString(kCFAllocatorSystemDefault, myName, kCFPlatformInterfaceStringEncoding); -} - -/* These are sanitized versions of the above functions. We might want to eliminate the above ones someday. - These can return NULL. -*/ -CF_EXPORT CFStringRef CFGetUserName(void) { - CFStringRef result = NULL; - __CFSpinLock(&__CFPlatformCacheLock); - result = CFStringCreateCopy(kCFAllocatorSystemDefault, _CFUserName()); - __CFSpinUnlock(&__CFPlatformCacheLock); - return result; -} - -CF_EXPORT CFStringRef CFCopyUserName(void) { - CFStringRef result = NULL; - __CFSpinLock(&__CFPlatformCacheLock); - result = CFStringCreateCopy(kCFAllocatorSystemDefault, _CFUserName()); - __CFSpinUnlock(&__CFPlatformCacheLock); - return result; -} - -CF_EXPORT CFURLRef CFCopyHomeDirectoryURLForUser(CFStringRef uName) { - CFURLRef result = NULL; - __CFSpinLock(&__CFPlatformCacheLock); - result = _CFCreateHomeDirectoryURLForUser(uName); - __CFSpinUnlock(&__CFPlatformCacheLock); - return result; -} #undef CFMaxHostNameLength #undef CFMaxHostNameSize @@ -570,7 +509,7 @@ CF_EXPORT int _NS_pthread_main_np() { // If thread data has been torn down, these functions should crash on CF_TSD_BAD_PTR + slot address. #define CF_TSD_MAX_SLOTS 70 -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI #define CF_TSD_KEY 55 #endif @@ -627,7 +566,7 @@ __private_extern__ void __CFTSDLinuxInitialize() { #endif static void __CFTSDSetSpecific(void *arg) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI pthread_setspecific(CF_TSD_KEY, arg); #elif DEPLOYMENT_TARGET_LINUX pthread_setspecific(__CFTSDIndexKey, arg); @@ -637,7 +576,7 @@ static void __CFTSDSetSpecific(void *arg) { } static void *__CFTSDGetSpecific() { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI return pthread_getspecific(CF_TSD_KEY); #elif DEPLOYMENT_TARGET_LINUX return pthread_getspecific(__CFTSDIndexKey); @@ -647,7 +586,7 @@ static void *__CFTSDGetSpecific() { } static void __CFTSDFinalize(void *arg) { - // Set our TSD so we're called again by pthreads. It will call the destructor 5 times as long as a value is set in the thread specific data. We handle each case below. + // Set our TSD so we're called again by pthreads. It will call the destructor PTHREAD_DESTRUCTOR_ITERATIONS times as long as a value is set in the thread specific data. We handle each case below. __CFTSDSetSpecific(arg); if (!arg || arg == CF_TSD_BAD_PTR) { @@ -658,12 +597,9 @@ static void __CFTSDFinalize(void *arg) { __CFTSDTable *table = (__CFTSDTable *)arg; table->destructorCount++; - // On 1st, 2nd, 3rd, 4th calls, invoke destructor + // On first calls invoke destructor. Later we destroy the data. // Note that invocation of the destructor may cause a value to be set again in the per-thread data slots. The destructor count and destructors are preserved. // This logic is basically the same as what pthreads does. We just skip the 'created' flag. -#if COCOA_ARR0 - uintptr_t pool = _CFAutoreleasePoolPush(); -#endif for (int32_t i = 0; i < CF_TSD_MAX_SLOTS; i++) { if (table->data[i] && table->destructors[i]) { uintptr_t old = table->data[i]; @@ -671,11 +607,8 @@ static void __CFTSDFinalize(void *arg) { table->destructors[i]((void *)(old)); } } -#if COCOA_ARR0 - _CFAutoreleasePoolPop(pool); -#endif - if (table->destructorCount == PTHREAD_DESTRUCTOR_ITERATIONS - 1) { // On 4th call, destroy our data + if (table->destructorCount == PTHREAD_DESTRUCTOR_ITERATIONS - 1) { // On PTHREAD_DESTRUCTOR_ITERATIONS-1 call, destroy our data free(table); // Now if the destructor is called again we will take the shortcut at the beginning of this function. @@ -684,7 +617,7 @@ static void __CFTSDFinalize(void *arg) { } } -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI extern int pthread_key_init_np(int, void (*)(void *)); #endif @@ -700,7 +633,7 @@ static __CFTSDTable *__CFTSDGetTable() { // This memory is freed in the finalize function table = (__CFTSDTable *)calloc(1, sizeof(__CFTSDTable)); // Windows and Linux have created the table already, we need to initialize it here for other platforms. On Windows, the cleanup function is called by DllMain when a thread exits. On Linux the destructor is set at init time. -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI pthread_key_init_np(CF_TSD_KEY, __CFTSDFinalize); #endif __CFTSDSetSpecific(table); @@ -747,6 +680,7 @@ CF_EXPORT void *_CFSetTSD(uint32_t slot, void *newVal, tsdDestructor destructor) return oldVal; } + #pragma mark - #pragma mark Windows Wide to UTF8 and UTF8 to Wide @@ -952,9 +886,7 @@ CF_EXPORT int _NS_mkstemp(char *name, int bufSize) { return fd; } -#endif -#if DEPLOYMENT_TARGET_WINDOWS // Utilities to convert from a volume name to a drive letter Boolean _isAFloppy(char driveLetter) @@ -1086,6 +1018,35 @@ extern CFStringRef CFCreateWindowsDrivePathFromVolumeName(CFStringRef volNameStr return drivePathResult; } +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +__private_extern__ int _NS_gettimeofday(struct timeval *tv, struct timezone *tz) { + if (tv) { + FILETIME ft; + GetSystemTimeAsFileTime(&ft); + unsigned __int64 t = 0; + t |= ft.dwHighDateTime; + t <<= 32; + t |= ft.dwLowDateTime; + + // Convert to microseconds + t /= 10; + + // Difference between 1/1/1970 and 1/1/1601 + t -= 11644473600000000Ui64; + + // Convert microseconds to seconds + tv->tv_sec = (long)(t / 1000000UL); + tv->tv_usec = (long)(t % 1000000UL); + } + + // We don't support tz + return 0; +} + #endif // DEPLOYMENT_TARGET_WINDOWS #pragma mark - @@ -1175,3 +1136,4 @@ __private_extern__ int asprintf(char **ret, const char *format, ...) { } #endif + diff --git a/CFPlatformConverters.c b/CFPlatformConverters.c index 5c1a5ad..b4b8d09 100644 --- a/CFPlatformConverters.c +++ b/CFPlatformConverters.c @@ -22,7 +22,7 @@ */ /* CFPlatformConverters.c - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. Responsibility: Aki Inoue */ @@ -30,7 +30,6 @@ #include #include "CFStringEncodingConverterExt.h" #include -#include #include "CFUniChar.h" #include "CFUnicodeDecomposition.h" #include "CFStringEncodingConverterPriv.h" @@ -62,7 +61,17 @@ static const CFStringEncodingConverter __CFPlatformBootstrap = { __private_extern__ const CFStringEncodingConverter *__CFStringEncodingGetExternalConverter(uint32_t encoding) { - return (__CFIsPlatformConverterAvailable(encoding) ? &__CFPlatformBootstrap : (__CFStringEncodingGetICUName(encoding) ? &__CFICUBootstrap : NULL)); // we prefer Text Encoding Converter ICU since it's more reliable + // we prefer Text Encoding Converter ICU since it's more reliable + if (__CFIsPlatformConverterAvailable(encoding)) { + return &__CFPlatformBootstrap; + } else { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX + if (__CFStringEncodingGetICUName(encoding)) { + return &__CFICUBootstrap; + } +#endif + return NULL; + } } #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED @@ -173,7 +182,7 @@ __private_extern__ CFIndex __CFStringEncodingPlatformBytesToUnicode(uint32_t enc dwFlags |= (flags & (kCFStringEncodingUseCanonical|kCFStringEncodingUseHFSPlusCanonical) ? MB_COMPOSITE : MB_PRECOMPOSED); } - if ((usedLen = MultiByteToWideChar(CFStringConvertEncodingToWindowsCodepage(encoding), dwFlags, (LPCSTR)bytes, numBytes, (LPWSTR)characters, maxCharLen) == 0)) { + if ((usedLen = MultiByteToWideChar(CFStringConvertEncodingToWindowsCodepage(encoding), dwFlags, (LPCSTR)bytes, numBytes, (LPWSTR)characters, maxCharLen)) == 0) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { CPINFO cpInfo; diff --git a/CFPlugIn.c b/CFPlugIn.c index 6f805fa..1a28795 100644 --- a/CFPlugIn.c +++ b/CFPlugIn.c @@ -22,8 +22,8 @@ */ /* CFPlugIn.c - Copyright (c) 1999-2011, Apple Inc. All rights reserved. - Responsibility: David Smith + Copyright (c) 1999-2012, Apple Inc. All rights reserved. + Responsibility: Tony Parker */ #include "CFBundle_Internal.h" @@ -43,35 +43,49 @@ __private_extern__ void __CFPlugInInitialize(void) { /* Functions for finding factories to create specific types and actually creating instances of a type. */ CF_EXPORT CFArrayRef CFPlugInFindFactoriesForPlugInType(CFUUIDRef typeID) { - CFArrayRef array = _CFPFactoryFindForType(typeID); + CFArrayRef array = _CFPFactoryFindCopyForType(typeID); CFMutableArrayRef result = NULL; if (array) { SInt32 i, c = CFArrayGetCount(array); result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); - for (i = 0; i < c; i++) CFArrayAppendValue(result, _CFPFactoryGetFactoryID((_CFPFactory *)CFArrayGetValueAtIndex(array, i))); + for (i = 0; i < c; i++) { + CFUUIDRef factoryId = _CFPFactoryCopyFactoryID((_CFPFactoryRef)CFArrayGetValueAtIndex(array, i)); + if (factoryId) { + CFArrayAppendValue(result, factoryId); + CFRelease(factoryId); + } + } + CFRelease(array); } return result; } CF_EXPORT CFArrayRef CFPlugInFindFactoriesForPlugInTypeInPlugIn(CFUUIDRef typeID, CFPlugInRef plugIn) { - CFArrayRef array = _CFPFactoryFindForType(typeID); + CFArrayRef array = _CFPFactoryFindCopyForType(typeID); CFMutableArrayRef result = NULL; if (array) { SInt32 i, c = CFArrayGetCount(array); - _CFPFactory *factory; + _CFPFactoryRef factory; result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); for (i = 0; i < c; i++) { - factory = (_CFPFactory *)CFArrayGetValueAtIndex(array, i); - if (_CFPFactoryGetPlugIn(factory) == plugIn) CFArrayAppendValue(result, _CFPFactoryGetFactoryID(factory)); + factory = (_CFPFactoryRef )CFArrayGetValueAtIndex(array, i); + CFPlugInRef factoryPlugIn = _CFPFactoryCopyPlugIn(factory); + if (factoryPlugIn == plugIn) { + CFUUIDRef factoryId = _CFPFactoryCopyFactoryID(factory); + CFArrayAppendValue(result, factoryId); + CFRelease(factoryId); + } + if (factoryPlugIn) CFRelease(factoryPlugIn); } + CFRelease(array); } return result; } CF_EXPORT void *CFPlugInInstanceCreate(CFAllocatorRef allocator, CFUUIDRef factoryID, CFUUIDRef typeID) { - _CFPFactory *factory = _CFPFactoryFind(factoryID, true); + _CFPFactoryRef factory = _CFPFactoryFind(factoryID, true); void *result = NULL; if (!factory) { /* MF:!!! No such factory. */ @@ -94,7 +108,7 @@ CF_EXPORT void *CFPlugInInstanceCreate(CFAllocatorRef allocator, CFUUIDRef facto CF_EXPORT Boolean CFPlugInRegisterFactoryFunction(CFUUIDRef factoryID, CFPlugInFactoryFunction func) { // Create factories without plugIns from default allocator // MF:!!! Should probably check that this worked, and maybe do some pre-checking to see if it already exists - // _CFPFactory *factory = + // _CFPFactoryRef factory = (void)_CFPFactoryCreate(kCFAllocatorSystemDefault, factoryID, func); return true; } @@ -102,13 +116,13 @@ CF_EXPORT Boolean CFPlugInRegisterFactoryFunction(CFUUIDRef factoryID, CFPlugInF CF_EXPORT Boolean CFPlugInRegisterFactoryFunctionByName(CFUUIDRef factoryID, CFPlugInRef plugIn, CFStringRef functionName) { // Create factories with plugIns from plugIn's allocator // MF:!!! Should probably check that this worked, and maybe do some pre-checking to see if it already exists - // _CFPFactory *factory = + // _CFPFactoryRef factory = (void)_CFPFactoryCreateByName(CFGetAllocator(plugIn), factoryID, plugIn, functionName); return true; } CF_EXPORT Boolean CFPlugInUnregisterFactory(CFUUIDRef factoryID) { - _CFPFactory *factory = _CFPFactoryFind(factoryID, true); + _CFPFactoryRef factory = _CFPFactoryFind(factoryID, true); if (!factory) { /* MF:!!! Error. No factory registered for this ID. */ @@ -119,7 +133,7 @@ CF_EXPORT Boolean CFPlugInUnregisterFactory(CFUUIDRef factoryID) { } CF_EXPORT Boolean CFPlugInRegisterPlugInType(CFUUIDRef factoryID, CFUUIDRef typeID) { - _CFPFactory *factory = _CFPFactoryFind(factoryID, true); + _CFPFactoryRef factory = _CFPFactoryFind(factoryID, true); if (!factory) { /* MF:!!! Error. Factory must be registered (and not disabled) before types can be associated with it. */ @@ -130,7 +144,7 @@ CF_EXPORT Boolean CFPlugInRegisterPlugInType(CFUUIDRef factoryID, CFUUIDRef type } CF_EXPORT Boolean CFPlugInUnregisterPlugInType(CFUUIDRef factoryID, CFUUIDRef typeID) { - _CFPFactory *factory = _CFPFactoryFind(factoryID, true); + _CFPFactoryRef factory = _CFPFactoryFind(factoryID, true); if (!factory) { /* MF:!!! Error. Could not find factory. */ @@ -146,7 +160,7 @@ CF_EXPORT Boolean CFPlugInUnregisterPlugInType(CFUUIDRef factoryID, CFUUIDRef ty /* This means that an instance must keep track of the CFUUIDRef of the factory that created it so it can unregister when it goes away. */ CF_EXPORT void CFPlugInAddInstanceForFactory(CFUUIDRef factoryID) { - _CFPFactory *factory = _CFPFactoryFind(factoryID, true); + _CFPFactoryRef factory = _CFPFactoryFind(factoryID, true); if (!factory) { /* MF:!!! Error. Could not find factory. */ @@ -156,7 +170,7 @@ CF_EXPORT void CFPlugInAddInstanceForFactory(CFUUIDRef factoryID) { } CF_EXPORT void CFPlugInRemoveInstanceForFactory(CFUUIDRef factoryID) { - _CFPFactory *factory = _CFPFactoryFind(factoryID, true); + _CFPFactoryRef factory = _CFPFactoryFind(factoryID, true); if (!factory) { /* MF:!!! Error. Could not find factory. */ diff --git a/CFPlugIn.h b/CFPlugIn.h index 318d3e4..d51e0be 100644 --- a/CFPlugIn.h +++ b/CFPlugIn.h @@ -22,7 +22,7 @@ */ /* CFPlugIn.h - Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Copyright (c) 1999-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFPLUGIN__) diff --git a/CFPlugInCOM.h b/CFPlugInCOM.h index f48fee3..cc41e52 100644 --- a/CFPlugInCOM.h +++ b/CFPlugInCOM.h @@ -22,7 +22,7 @@ */ /* CFPlugInCOM.h - Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Copyright (c) 1999-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFPLUGINCOM__) diff --git a/CFPlugIn_Factory.c b/CFPlugIn_Factory.c index 1e99031..b65a86a 100644 --- a/CFPlugIn_Factory.c +++ b/CFPlugIn_Factory.c @@ -22,53 +22,111 @@ */ /* CFPlugIn_Factory.c - Copyright (c) 1999-2011, Apple Inc. All rights reserved. - Responsibility: David Smith + Copyright (c) 1999-2012, Apple Inc. All rights reserved. + Responsibility: Tony Parker */ #include "CFBundle_Internal.h" #include "CFInternal.h" -static CFSpinLock_t CFPlugInGlobalDataLock = CFSpinLockInit; -static CFMutableDictionaryRef _factoriesByFactoryID = NULL; /* Value is _CFPFactory */ -static CFMutableDictionaryRef _factoriesByTypeID = NULL; /* Value is array of _CFPFactory */ +static CFTypeID __kCFPFactoryTypeID = _kCFRuntimeNotATypeID; -static void _CFPFactoryAddToTable(_CFPFactory *factory) { - __CFSpinLock(&CFPlugInGlobalDataLock); +struct __CFPFactory { + CFRuntimeBase _base; + + CFUUIDRef _uuid; + Boolean _enabled; + char _padding[3]; + + CFPlugInFactoryFunction _func; + + CFPlugInRef _plugIn; + CFStringRef _funcName; + + CFMutableArrayRef _types; + CFSpinLock_t _lock; +}; + +static void _CFPFactoryDeallocate(CFTypeRef factory); + +static const CFRuntimeClass __CFPFactoryClass = { + 0, + "_CFPFactory", + NULL, // init + NULL, // copy + _CFPFactoryDeallocate, + NULL, // equal + NULL, // hash + NULL, // formatting desc + NULL, // debug desc +}; + +__private_extern__ void __CFPFactoryInitialize(void) { + __kCFPFactoryTypeID = _CFRuntimeRegisterClass(&__CFPFactoryClass); +} + +static CFTypeID _CFPFactoryGetTypeID(void) { + return __kCFPFactoryTypeID; +} + +static CFSpinLock_t CFPlugInGlobalDataLock = CFSpinLockInit; +static CFMutableDictionaryRef _factoriesByFactoryID = NULL; /* Value is _CFPFactoryRef */ +static CFMutableDictionaryRef _factoriesByTypeID = NULL; /* Value is array of _CFPFactoryRef */ + +static void _CFPFactoryAddToTable(_CFPFactoryRef factory) { + __CFSpinLock(&factory->_lock); + CFUUIDRef uuid = (CFUUIDRef)CFRetain(factory->_uuid); + CFRetain(factory); + __CFSpinUnlock(&factory->_lock); + + __CFSpinLock(&CFPlugInGlobalDataLock); if (!_factoriesByFactoryID) { CFDictionaryValueCallBacks _factoryDictValueCallbacks = {0, NULL, NULL, NULL, NULL}; _factoriesByFactoryID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &_factoryDictValueCallbacks); } - CFDictionarySetValue(_factoriesByFactoryID, factory->_uuid, factory); + CFDictionarySetValue(_factoriesByFactoryID, uuid, factory); __CFSpinUnlock(&CFPlugInGlobalDataLock); + + if (uuid) CFRelease(uuid); + CFRelease(factory); } -static void _CFPFactoryRemoveFromTable(_CFPFactory *factory) { +static void _CFPFactoryRemoveFromTable(_CFPFactoryRef factory) { + __CFSpinLock(&factory->_lock); + CFUUIDRef uuid = factory->_uuid; + if (uuid) CFRetain(uuid); + __CFSpinUnlock(&factory->_lock); + __CFSpinLock(&CFPlugInGlobalDataLock); - if (_factoriesByFactoryID) CFDictionaryRemoveValue(_factoriesByFactoryID, factory->_uuid); + if (uuid && _factoriesByTypeID) CFDictionaryRemoveValue(_factoriesByFactoryID, uuid); __CFSpinUnlock(&CFPlugInGlobalDataLock); + + if (uuid) CFRelease(uuid); } -__private_extern__ _CFPFactory *_CFPFactoryFind(CFUUIDRef factoryID, Boolean enabled) { - _CFPFactory *result = NULL; +__private_extern__ _CFPFactoryRef _CFPFactoryFind(CFUUIDRef factoryID, Boolean enabled) { + _CFPFactoryRef result = NULL; __CFSpinLock(&CFPlugInGlobalDataLock); if (_factoriesByFactoryID) { - result = (_CFPFactory *)CFDictionaryGetValue(_factoriesByFactoryID, factoryID); + result = (_CFPFactoryRef )CFDictionaryGetValue(_factoriesByFactoryID, factoryID); if (result && result->_enabled != enabled) result = NULL; } __CFSpinUnlock(&CFPlugInGlobalDataLock); return result; } -static void _CFPFactoryDeallocate(_CFPFactory *factory) { - CFAllocatorRef allocator = factory->_allocator; +static void _CFPFactoryDeallocate(CFTypeRef ty) { SInt32 c; + _CFPFactoryRef factory = (_CFPFactoryRef)ty; _CFPFactoryRemoveFromTable(factory); - if (factory->_plugIn) _CFPlugInRemoveFactory(factory->_plugIn, factory); - + if (factory->_plugIn) { + _CFPlugInRemoveFactory(factory->_plugIn, factory); + CFRelease(factory->_plugIn); + } + /* Remove all types for this factory. */ c = CFArrayGetCount(factory->_types); while (c-- > 0) _CFPFactoryRemoveType(factory, (CFUUIDRef)CFArrayGetValueAtIndex(factory->_types, c)); @@ -76,65 +134,70 @@ static void _CFPFactoryDeallocate(_CFPFactory *factory) { if (factory->_funcName) CFRelease(factory->_funcName); if (factory->_uuid) CFRelease(factory->_uuid); - - CFAllocatorDeallocate(allocator, factory); - CFRelease(allocator); } -static _CFPFactory *_CFPFactoryCommonCreate(CFAllocatorRef allocator, CFUUIDRef factoryID) { - _CFPFactory *factory; - UInt32 size; - size = sizeof(_CFPFactory); - allocator = (allocator ? (CFAllocatorRef)CFRetain(allocator) : (CFAllocatorRef)CFRetain(__CFGetDefaultAllocator())); - factory = (_CFPFactory *)CFAllocatorAllocate(allocator, size, 0); - if (!factory) { - CFRelease(allocator); - return NULL; - } +static _CFPFactoryRef _CFPFactoryCommonCreate(CFAllocatorRef allocator, CFUUIDRef factoryID) { + _CFPFactoryRef factory; + uint32_t size; + size = sizeof(struct __CFPFactory) - sizeof(CFRuntimeBase); + factory = (_CFPFactoryRef)_CFRuntimeCreateInstance(allocator, _CFPFactoryGetTypeID(), size, NULL); + if (!factory) return NULL; - factory->_allocator = allocator; factory->_uuid = (CFUUIDRef)CFRetain(factoryID); factory->_enabled = true; - factory->_instanceCount = 0; - - _CFPFactoryAddToTable(factory); - factory->_types = CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks); + factory->_lock = CFSpinLockInit; // WARNING: grab global lock before this lock + + _CFPFactoryAddToTable(factory); return factory; } -__private_extern__ _CFPFactory *_CFPFactoryCreate(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInFactoryFunction func) { - _CFPFactory *factory = _CFPFactoryCommonCreate(allocator, factoryID); +__private_extern__ _CFPFactoryRef _CFPFactoryCreate(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInFactoryFunction func) { + _CFPFactoryRef factory = _CFPFactoryCommonCreate(allocator, factoryID); + __CFSpinLock(&factory->_lock); factory->_func = func; factory->_plugIn = NULL; factory->_funcName = NULL; + __CFSpinUnlock(&factory->_lock); return factory; } -__private_extern__ _CFPFactory *_CFPFactoryCreateByName(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInRef plugIn, CFStringRef funcName) { - _CFPFactory *factory = _CFPFactoryCommonCreate(allocator, factoryID); +__private_extern__ _CFPFactoryRef _CFPFactoryCreateByName(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInRef plugIn, CFStringRef funcName) { + _CFPFactoryRef factory = _CFPFactoryCommonCreate(allocator, factoryID); + __CFSpinLock(&factory->_lock); factory->_func = NULL; - factory->_plugIn = plugIn; + factory->_plugIn = (CFPlugInRef)CFRetain(plugIn); if (plugIn) _CFPlugInAddFactory(plugIn, factory); factory->_funcName = (funcName ? (CFStringRef)CFStringCreateCopy(allocator, funcName) : NULL); + __CFSpinUnlock(&factory->_lock); return factory; } -__private_extern__ CFUUIDRef _CFPFactoryGetFactoryID(_CFPFactory *factory) { - return factory->_uuid; +__private_extern__ CFUUIDRef _CFPFactoryCopyFactoryID(_CFPFactoryRef factory) { + __CFSpinLock(&factory->_lock); + CFUUIDRef uuid = factory->_uuid; + if (uuid) CFRetain(uuid); + __CFSpinUnlock(&factory->_lock); + return uuid; } -__private_extern__ CFPlugInRef _CFPFactoryGetPlugIn(_CFPFactory *factory) { - return factory->_plugIn; +__private_extern__ CFPlugInRef _CFPFactoryCopyPlugIn(_CFPFactoryRef factory) { + __CFSpinLock(&factory->_lock); + CFPlugInRef result = factory->_plugIn; + if (result) CFRetain(result); + __CFSpinUnlock(&factory->_lock); + return result; } -__private_extern__ void *_CFPFactoryCreateInstance(CFAllocatorRef allocator, _CFPFactory *factory, CFUUIDRef typeID) { +__private_extern__ void *_CFPFactoryCreateInstance(CFAllocatorRef allocator, _CFPFactoryRef factory, CFUUIDRef typeID) { void *result = NULL; + + __CFSpinLock(&factory->_lock); if (factory->_enabled) { if (!factory->_func) { factory->_func = (CFPlugInFactoryFunction)CFBundleGetFunctionPointerForName(factory->_plugIn, factory->_funcName); @@ -142,40 +205,45 @@ __private_extern__ void *_CFPFactoryCreateInstance(CFAllocatorRef allocator, _CF } if (factory->_func) { // UPPGOOP - FAULT_CALLBACK((void **)&(factory->_func)); - result = (void *)INVOKE_CALLBACK2(factory->_func, allocator, typeID); + CFPlugInFactoryFunction f = factory->_func; + __CFSpinUnlock(&factory->_lock); + FAULT_CALLBACK((void **)&(f)); + result = (void *)INVOKE_CALLBACK2(f, allocator, typeID); + __CFSpinLock(&factory->_lock); } } else { CFLog(__kCFLogPlugIn, CFSTR("Factory %@ is disabled"), factory->_uuid); - } + } + __CFSpinUnlock(&factory->_lock); + return result; } -__private_extern__ void _CFPFactoryDisable(_CFPFactory *factory) { +__private_extern__ void _CFPFactoryDisable(_CFPFactoryRef factory) { + __CFSpinLock(&factory->_lock); factory->_enabled = false; - if (factory->_instanceCount == 0) _CFPFactoryDeallocate(factory); -} - -__private_extern__ Boolean _CFPFactoryIsEnabled(_CFPFactory *factory) { - return factory->_enabled; + __CFSpinUnlock(&factory->_lock); + CFRelease(factory); } -__private_extern__ void _CFPFactoryFlushFunctionCache(_CFPFactory *factory) { +__private_extern__ void _CFPFactoryFlushFunctionCache(_CFPFactoryRef factory) { /* MF:!!! Assert that this factory belongs to a plugIn. */ /* This is called by the factory's plugIn when the plugIn unloads its code. */ + __CFSpinLock(&factory->_lock); factory->_func = NULL; + __CFSpinUnlock(&factory->_lock); } -__private_extern__ void _CFPFactoryAddType(_CFPFactory *factory, CFUUIDRef typeID) { - CFMutableArrayRef array; - +__private_extern__ void _CFPFactoryAddType(_CFPFactoryRef factory, CFUUIDRef typeID) { + /* Add the factory to the type's array of factories */ + __CFSpinLock(&factory->_lock); /* Add the type to the factory's type list */ CFArrayAppendValue(factory->_types, typeID); + __CFSpinUnlock(&factory->_lock); - /* Add the factory to the type's array of factories */ __CFSpinLock(&CFPlugInGlobalDataLock); if (!_factoriesByTypeID) _factoriesByTypeID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID); + CFMutableArrayRef array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID); if (!array) { CFArrayCallBacks _factoryArrayCallbacks = {0, NULL, NULL, NULL, NULL}; // Create this from default allocator @@ -187,12 +255,14 @@ __private_extern__ void _CFPFactoryAddType(_CFPFactory *factory, CFUUIDRef typeI __CFSpinUnlock(&CFPlugInGlobalDataLock); } -__private_extern__ void _CFPFactoryRemoveType(_CFPFactory *factory, CFUUIDRef typeID) { +__private_extern__ void _CFPFactoryRemoveType(_CFPFactoryRef factory, CFUUIDRef typeID) { /* Remove it from the factory's type list */ SInt32 idx; + __CFSpinLock(&factory->_lock); idx = CFArrayGetFirstIndexOfValue(factory->_types, CFRangeMake(0, CFArrayGetCount(factory->_types)), typeID); if (idx >= 0) CFArrayRemoveValueAtIndex(factory->_types, idx); + __CFSpinUnlock(&factory->_lock); /* Remove the factory from the type's list of factories */ __CFSpinLock(&CFPlugInGlobalDataLock); @@ -209,33 +279,50 @@ __private_extern__ void _CFPFactoryRemoveType(_CFPFactory *factory, CFUUIDRef ty __CFSpinUnlock(&CFPlugInGlobalDataLock); } -__private_extern__ Boolean _CFPFactorySupportsType(_CFPFactory *factory, CFUUIDRef typeID) { +__private_extern__ Boolean _CFPFactorySupportsType(_CFPFactoryRef factory, CFUUIDRef typeID) { SInt32 idx; + __CFSpinLock(&factory->_lock); idx = CFArrayGetFirstIndexOfValue(factory->_types, CFRangeMake(0, CFArrayGetCount(factory->_types)), typeID); + __CFSpinUnlock(&factory->_lock); + return (idx >= 0 ? true : false); } -__private_extern__ CFArrayRef _CFPFactoryFindForType(CFUUIDRef typeID) { +__private_extern__ CFArrayRef _CFPFactoryFindCopyForType(CFUUIDRef typeID) { CFArrayRef result = NULL; - __CFSpinLock(&CFPlugInGlobalDataLock); - if (_factoriesByTypeID) result = (CFArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID); + if (_factoriesByTypeID) { + result = (CFArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID); + if (result) CFRetain(result); + } __CFSpinUnlock(&CFPlugInGlobalDataLock); return result; } /* These methods are called by CFPlugInInstance when an instance is created or destroyed. If a factory's instance count goes to 0 and the factory has been disabled, the factory is destroyed. */ -__private_extern__ void _CFPFactoryAddInstance(_CFPFactory *factory) { +__private_extern__ void _CFPFactoryAddInstance(_CFPFactoryRef factory) { /* MF:!!! Assert that factory is enabled. */ - factory->_instanceCount++; - if (factory->_plugIn) _CFPlugInAddPlugInInstance(factory->_plugIn); + CFRetain(factory); + __CFSpinLock(&factory->_lock); + CFPlugInRef plugin = factory->_plugIn; + if (plugin) CFRetain(plugin); + __CFSpinUnlock(&factory->_lock); + if (plugin) { + _CFPlugInAddPlugInInstance(plugin); + CFRelease(plugin); + } } -__private_extern__ void _CFPFactoryRemoveInstance(_CFPFactory *factory) { - /* MF:!!! Assert that _instanceCount > 0. */ - factory->_instanceCount--; - if (factory->_plugIn) _CFPlugInRemovePlugInInstance(factory->_plugIn); - if (factory->_instanceCount == 0 && !factory->_enabled) _CFPFactoryDeallocate(factory); +__private_extern__ void _CFPFactoryRemoveInstance(_CFPFactoryRef factory) { + __CFSpinLock(&factory->_lock); + CFPlugInRef plugin = factory->_plugIn; + if (plugin) CFRetain(plugin); + __CFSpinUnlock(&factory->_lock); + if (plugin) { + _CFPlugInRemovePlugInInstance(factory->_plugIn); + CFRelease(plugin); + } + CFRelease(factory); } diff --git a/CFPlugIn_Factory.h b/CFPlugIn_Factory.h index e4a37cd..2b4320a 100644 --- a/CFPlugIn_Factory.h +++ b/CFPlugIn_Factory.h @@ -22,7 +22,7 @@ */ /* CFPlugIn_Factory.h - Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Copyright (c) 1999-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFPLUGIN_FACTORY__) @@ -32,45 +32,30 @@ CF_EXTERN_C_BEGIN -typedef struct __CFPFactory { - CFAllocatorRef _allocator; +typedef struct __CFPFactory *_CFPFactoryRef; - CFUUIDRef _uuid; - Boolean _enabled; - char _padding[3]; - SInt32 _instanceCount; +extern _CFPFactoryRef _CFPFactoryCreate(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInFactoryFunction func); +extern _CFPFactoryRef _CFPFactoryCreateByName(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInRef plugIn, CFStringRef funcName); - CFPlugInFactoryFunction _func; - - CFPlugInRef _plugIn; - CFStringRef _funcName; +extern _CFPFactoryRef _CFPFactoryFind(CFUUIDRef factoryID, Boolean enabled); - CFMutableArrayRef _types; -} _CFPFactory; +extern CFUUIDRef _CFPFactoryCopyFactoryID(_CFPFactoryRef factory); +extern CFPlugInRef _CFPFactoryCopyPlugIn(_CFPFactoryRef factory); -extern _CFPFactory *_CFPFactoryCreate(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInFactoryFunction func); -extern _CFPFactory *_CFPFactoryCreateByName(CFAllocatorRef allocator, CFUUIDRef factoryID, CFPlugInRef plugIn, CFStringRef funcName); +extern void *_CFPFactoryCreateInstance(CFAllocatorRef allocator, _CFPFactoryRef factory, CFUUIDRef typeID); +extern void _CFPFactoryDisable(_CFPFactoryRef factory); -extern _CFPFactory *_CFPFactoryFind(CFUUIDRef factoryID, Boolean enabled); +extern void _CFPFactoryFlushFunctionCache(_CFPFactoryRef factory); -extern CFUUIDRef _CFPFactoryGetFactoryID(_CFPFactory *factory); -extern CFPlugInRef _CFPFactoryGetPlugIn(_CFPFactory *factory); +extern void _CFPFactoryAddType(_CFPFactoryRef factory, CFUUIDRef typeID); +extern void _CFPFactoryRemoveType(_CFPFactoryRef factory, CFUUIDRef typeID); -extern void *_CFPFactoryCreateInstance(CFAllocatorRef allocator, _CFPFactory *factory, CFUUIDRef typeID); -extern void _CFPFactoryDisable(_CFPFactory *factory); -extern Boolean _CFPFactoryIsEnabled(_CFPFactory *factory); - -extern void _CFPFactoryFlushFunctionCache(_CFPFactory *factory); - -extern void _CFPFactoryAddType(_CFPFactory *factory, CFUUIDRef typeID); -extern void _CFPFactoryRemoveType(_CFPFactory *factory, CFUUIDRef typeID); - -extern Boolean _CFPFactorySupportsType(_CFPFactory *factory, CFUUIDRef typeID); -extern CFArrayRef _CFPFactoryFindForType(CFUUIDRef typeID); +extern Boolean _CFPFactorySupportsType(_CFPFactoryRef factory, CFUUIDRef typeID); +extern CFArrayRef _CFPFactoryFindCopyForType(CFUUIDRef typeID); /* These methods are called by CFPlugInInstance when an instance is created or destroyed. If a factory's instance count goes to 0 and the factory has been disabled, the factory is destroyed. */ -extern void _CFPFactoryAddInstance(_CFPFactory *factory); -extern void _CFPFactoryRemoveInstance(_CFPFactory *factory); +extern void _CFPFactoryAddInstance(_CFPFactoryRef factory); +extern void _CFPFactoryRemoveInstance(_CFPFactoryRef factory); CF_EXTERN_C_END diff --git a/CFPlugIn_Instance.c b/CFPlugIn_Instance.c index 62b1611..afc17eb 100644 --- a/CFPlugIn_Instance.c +++ b/CFPlugIn_Instance.c @@ -22,8 +22,8 @@ */ /* CFPlugIn_Instance.c - Copyright (c) 1999-2011, Apple Inc. All rights reserved. - Responsibility: David Smith + Copyright (c) 1999-2012, Apple Inc. All rights reserved. + Responsibility: Tony Parker */ #include "CFBundle_Internal.h" @@ -34,7 +34,7 @@ static CFTypeID __kCFPlugInInstanceTypeID = _kCFRuntimeNotATypeID; struct __CFPlugInInstance { CFRuntimeBase _base; - _CFPFactory *factory; + _CFPFactoryRef factory; CFPlugInInstanceGetInterfaceFunction getInterfaceFunction; CFPlugInInstanceDeallocateInstanceDataFunction deallocateInstanceDataFunction; @@ -115,7 +115,9 @@ CF_EXPORT Boolean CFPlugInInstanceGetInterfaceFunctionTable(CFPlugInInstanceRef } CF_EXPORT CFStringRef CFPlugInInstanceGetFactoryName(CFPlugInInstanceRef instance) { - return (CFStringRef)_CFPFactoryGetFactoryID(instance->factory); + // This function leaks, but it's the only safe way to access the factory name + CFUUIDRef factoryId = _CFPFactoryCopyFactoryID(instance->factory); + return (CFStringRef)factoryId; } CF_EXPORT void *CFPlugInInstanceGetInstanceData(CFPlugInInstanceRef instance) { diff --git a/CFPlugIn_PlugIn.c b/CFPlugIn_PlugIn.c index ce89300..c922f8c 100644 --- a/CFPlugIn_PlugIn.c +++ b/CFPlugIn_PlugIn.c @@ -22,8 +22,8 @@ */ /* CFPlugIn_PlugIn.c - Copyright (c) 1999-2011, Apple Inc. All rights reserved. - Responsibility: David Smith + Copyright (c) 1999-2012, Apple Inc. All rights reserved. + Responsibility: Tony Parker */ #include "CFBundle_Internal.h" @@ -154,7 +154,7 @@ __private_extern__ void _CFBundleDeallocatePlugIn(CFBundleRef bundle) { /* Go through factories disabling them. Disabling these factories should cause them to dealloc since we wouldn't be deallocating if any of the factories had outstanding instances. So go backwards. */ c = CFArrayGetCount(__CFBundleGetPlugInData(bundle)->_factories); - while (c-- > 0) _CFPFactoryDisable((_CFPFactory *)CFArrayGetValueAtIndex(__CFBundleGetPlugInData(bundle)->_factories, c)); + while (c-- > 0) _CFPFactoryDisable((_CFPFactoryRef)CFArrayGetValueAtIndex(__CFBundleGetPlugInData(bundle)->_factories, c)); CFRelease(__CFBundleGetPlugInData(bundle)->_factories); __CFBundleGetPlugInData(bundle)->_isPlugIn = false; @@ -200,7 +200,7 @@ __private_extern__ void _CFPlugInWillUnload(CFPlugInRef plugIn) { if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) { SInt32 c = CFArrayGetCount(__CFBundleGetPlugInData(plugIn)->_factories); /* First, flush all the function pointers that may be cached by our factories. */ - while (c-- > 0) _CFPFactoryFlushFunctionCache((_CFPFactory *)CFArrayGetValueAtIndex(__CFBundleGetPlugInData(plugIn)->_factories, c)); + while (c-- > 0) _CFPFactoryFlushFunctionCache((_CFPFactoryRef)CFArrayGetValueAtIndex(__CFBundleGetPlugInData(plugIn)->_factories, c)); } } @@ -228,11 +228,11 @@ __private_extern__ void _CFPlugInRemovePlugInInstance(CFPlugInRef plugIn) { } } -__private_extern__ void _CFPlugInAddFactory(CFPlugInRef plugIn, _CFPFactory *factory) { +__private_extern__ void _CFPlugInAddFactory(CFPlugInRef plugIn, _CFPFactoryRef factory) { if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) CFArrayAppendValue(__CFBundleGetPlugInData(plugIn)->_factories, factory); } -__private_extern__ void _CFPlugInRemoveFactory(CFPlugInRef plugIn, _CFPFactory *factory) { +__private_extern__ void _CFPlugInRemoveFactory(CFPlugInRef plugIn, _CFPFactoryRef factory) { if (__CFBundleGetPlugInData(plugIn)->_isPlugIn) { SInt32 idx = CFArrayGetFirstIndexOfValue(__CFBundleGetPlugInData(plugIn)->_factories, CFRangeMake(0, CFArrayGetCount(__CFBundleGetPlugInData(plugIn)->_factories)), factory); if (idx >= 0) CFArrayRemoveValueAtIndex(__CFBundleGetPlugInData(plugIn)->_factories, idx); diff --git a/CFPreferences.c b/CFPreferences.c index 5f6280d..5364c34 100644 --- a/CFPreferences.c +++ b/CFPreferences.c @@ -22,7 +22,7 @@ */ /* CFPreferences.c - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. Responsibility: David Smith */ diff --git a/CFPreferences.h b/CFPreferences.h index 3d83886..9a59a26 100644 --- a/CFPreferences.h +++ b/CFPreferences.h @@ -22,7 +22,7 @@ */ /* CFPreferences.h - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFPREFERENCES__) diff --git a/CFPriv.h b/CFPriv.h index 34306c4..3ce6702 100644 --- a/CFPriv.h +++ b/CFPriv.h @@ -22,7 +22,7 @@ */ /* CFPriv.h - Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Copyright (c) 1998-2012, Apple Inc. All rights reserved. */ /* @@ -39,6 +39,7 @@ #include #include #include +#include #include @@ -64,11 +65,14 @@ CF_EXPORT const char **_CFGetProcessPath(void); CF_EXPORT const char **_CFGetProgname(void); +#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_OS_LINUX)) +CF_EXPORT void _CFRunLoopSetCurrent(CFRunLoopRef rl); +#endif + #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_OS_LINUX)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) CF_EXPORT CFRunLoopRef CFRunLoopGetMain(void); CF_EXPORT SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled); -CF_EXPORT void _CFRunLoopSetCurrent(CFRunLoopRef rl); CF_EXPORT void _CFRunLoopStopMode(CFRunLoopRef rl, CFStringRef modeName); @@ -96,12 +100,11 @@ CFURLRef _CFCreateURLFromFSSpec(CFAllocatorRef alloc, const struct FSSpec *voids #endif #endif -enum { +typedef CF_ENUM(CFIndex, CFURLComponentDecomposition) { kCFURLComponentDecompositionNonHierarchical, kCFURLComponentDecompositionRFC1808, /* use this for RFC 1738 decompositions as well */ kCFURLComponentDecompositionRFC2396 }; -typedef CFIndex CFURLComponentDecomposition; typedef struct { CFStringRef scheme; @@ -179,7 +182,7 @@ CFURLRef CFCopyHomeDirectoryURLForUser(CFStringRef uName); /* Pass NULL for the directories! ??? On MacOS 8 this function currently returns an empty array. */ -enum { +typedef CF_ENUM(CFIndex, CFSearchPathDirectory) { kCFApplicationDirectory = 1, /* supported applications (Applications) */ kCFDemoApplicationDirectory, /* unsupported applications, demonstration versions (Demos) */ kCFDeveloperApplicationDirectory, /* developer applications (Developer/Applications) */ @@ -189,19 +192,32 @@ enum { kCFUserDirectory, /* user home directories (Users) */ kCFDocumentationDirectory, /* documentation (Documentation) */ kCFDocumentDirectory, /* documents (Library/Documents) */ + + kCFCoreServiceDirectory = 10, // location of CoreServices directory (System/Library/CoreServices) + kCFAutosavedInformationDirectory = 11, // location of autosaved documents (Documents/Autosaved) + kCFDesktopDirectory = 12, // location of user's desktop + kCFCachesDirectory = 13, // location of discardable cache files (Library/Caches) + kCFApplicationSupportDirectory = 14, // location of application support files (plug-ins, etc) (Library/Application Support) + kCFDownloadsDirectory = 15, // location of the user's "Downloads" directory + kCFInputMethodsDirectory = 16, // input methods (Library/Input Methods) + kCFMoviesDirectory = 17, // location of user's Movies directory (~/Movies) + kCFMusicDirectory = 18, // location of user's Music directory (~/Music) + kCFPicturesDirectory = 19, // location of user's Pictures directory (~/Pictures) + kCFPrinterDescriptionDirectory = 20, // location of system's PPDs directory (Library/Printers/PPDs) + kCFSharedPublicDirectory = 21, // location of user's Public sharing directory (~/Public) + kCFPreferencePanesDirectory = 22, // location of the PreferencePanes directory for use with System Preferences (Library/PreferencePanes) + kCFAllApplicationsDirectory = 100, /* all directories where applications can occur (ie Applications, Demos, Administration, Developer/Applications) */ kCFAllLibrariesDirectory = 101 /* all directories where resources can occur (Library, Developer) */ }; -typedef CFIndex CFSearchPathDirectory; -enum { +typedef CF_OPTIONS(CFOptionFlags, CFSearchPathDomainMask) { kCFUserDomainMask = 1, /* user's home directory --- place to install user's personal items (~) */ kCFLocalDomainMask = 2, /* local to the current machine --- place to install items available to everyone on this machine (/Local) */ kCFNetworkDomainMask = 4, /* publically available location in the local area network --- place to install items available on the network (/Network) */ kCFSystemDomainMask = 8, /* provided by Apple, unmodifiable (/System) */ kCFAllDomainsMask = 0x0ffff /* all domains: all of the above and more, future items */ }; -typedef CFOptionFlags CFSearchPathDomainMask; CF_EXPORT CFArrayRef CFCopySearchPathForDirectoriesInDomains(CFSearchPathDirectory directory, CFSearchPathDomainMask domainMask, Boolean expandTilde); @@ -238,7 +254,7 @@ CF_EXPORT void CFQSortArray(void *list, CFIndex count, CFIndex elementSize, CFCo Note that for non-MACH this function always returns true. */ -enum { +typedef CF_ENUM(CFIndex, CFSystemVersion) { CFSystemVersionCheetah = 0, /* 10.0 */ CFSystemVersionPuma = 1, /* 10.1 */ CFSystemVersionJaguar = 2, /* 10.2 */ @@ -247,21 +263,20 @@ enum { CFSystemVersionLeopard = 5, /* 10.5 */ CFSystemVersionSnowLeopard = 6, /* 10.6 */ CFSystemVersionLion = 7, /* 10.7 */ + CFSystemVersionMountainLion = 8, /* 10.8 */ CFSystemVersionMax, /* This should bump up when new entries are added */ }; -typedef CFIndex CFSystemVersion; CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version); -enum { +typedef CF_ENUM(CFIndex, CFStringCharacterClusterType) { kCFStringGraphemeCluster = 1, /* Unicode Grapheme Cluster */ kCFStringComposedCharacterCluster = 2, /* Compose all non-base (including spacing marks) */ kCFStringCursorMovementCluster = 3, /* Cluster suitable for cursor movements */ kCFStringBackwardDeletionCluster = 4 /* Cluster suitable for backward deletion */ }; -typedef CFIndex CFStringCharacterClusterType; CF_EXPORT CFRange CFStringGetRangeOfCharacterClusterAtIndex(CFStringRef string, CFIndex charIndex, CFStringCharacterClusterType type); @@ -492,8 +507,19 @@ CF_INLINE struct timespec _CFFileTimeSpecFromAbsoluteTime(CFAbsoluteTime at) { return ts; } +// The 'filtered' function below is preferred to this older one CF_EXPORT bool _CFPropertyListCreateSingleValue(CFAllocatorRef allocator, CFDataRef data, CFOptionFlags option, CFStringRef keyPath, CFPropertyListRef *value, CFErrorRef *error); +// Returns a subset of the property list, only including the keyPaths in the CFSet. If the top level object is not a dictionary, you will get back an empty dictionary as the result. +CF_EXPORT bool _CFPropertyListCreateFiltered(CFAllocatorRef allocator, CFDataRef data, CFOptionFlags option, CFSetRef keyPaths, CFPropertyListRef *value, CFErrorRef *error) CF_AVAILABLE(10_8, 6_0); + +// Returns a subset of a bundle's Info.plist. The keyPaths follow the same rules as above CFPropertyList function. This function takes platform and product keys into account. +typedef CF_OPTIONS(CFOptionFlags, _CFBundleFilteredPlistOptions) { + _CFBundleFilteredPlistMemoryMapped = 1 +} CF_ENUM_AVAILABLE(10_8, 6_0); + +CF_EXPORT CFPropertyListRef _CFBundleCreateFilteredInfoPlist(CFBundleRef bundle, CFSetRef keyPaths, _CFBundleFilteredPlistOptions options) CF_AVAILABLE(10_8, 6_0); +CF_EXPORT CFPropertyListRef _CFBundleCreateFilteredLocalizedInfoPlist(CFBundleRef bundle, CFSetRef keyPaths, CFStringRef localizationName, _CFBundleFilteredPlistOptions options) CF_AVAILABLE(10_8, 6_0); #if TARGET_OS_WIN32 #include @@ -521,6 +547,11 @@ CF_EXPORT void _CFRunLoopSetWindowsMessageQueueHandler(CFRunLoopRef rl, CFString CF_EXPORT CFArrayRef CFDateFormatterCreateDateFormatsFromTemplates(CFAllocatorRef allocator, CFArrayRef tmplates, CFOptionFlags options, CFLocaleRef locale); +#if (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) +// Available for internal use on embedded +CF_EXPORT CFNotificationCenterRef CFNotificationCenterGetDistributedCenter(void); +#endif + CF_EXTERN_C_END diff --git a/CFPropertyList.c b/CFPropertyList.c index 7cc7f6d..b22218c 100644 --- a/CFPropertyList.c +++ b/CFPropertyList.c @@ -22,7 +22,7 @@ */ /* CFPropertyList.c - Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Copyright (c) 1999-2012, Apple Inc. All rights reserved. Responsibility: Tony Parker */ @@ -34,7 +34,9 @@ #include #include #include -#include +#include "CFInternal.h" +#include +#include #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS #include #endif @@ -75,23 +77,11 @@ #define DOCTYPE_TAG_LENGTH 7 #define CDSECT_TAG_LENGTH 9 -#if DEPLOYMENT_TARGET_MACOSX -// Set for some exceptional circumstances, like running out of memory -extern char * __crashreporter_info__; - -#define out_of_memory_warning() \ - do { \ - __crashreporter_info__ = "CFPropertyList ran out of memory while attempting to allocate temporary storage."; \ - } while (0) -#else -#define out_of_memory_warning() do {} while (0) -#endif - #if !defined(new_cftype_array) #define new_cftype_array(N, C) \ size_t N ## _count__ = (C); \ if (N ## _count__ > LONG_MAX / sizeof(CFTypeRef)) { \ - out_of_memory_warning(); \ + CRSetCrashLogMessage("CFPropertyList ran out of memory while attempting to allocate temporary storage."); \ HALT; \ } \ Boolean N ## _is_stack__ = (N ## _count__ <= 256); \ @@ -100,7 +90,7 @@ extern char * __crashreporter_info__; if (N ## _is_stack__) memset(N ## _buffer__, 0, N ## _count__ * sizeof(CFTypeRef)); \ CFTypeRef * N = N ## _is_stack__ ? N ## _buffer__ : (CFTypeRef *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, (N ## _count__) * sizeof(CFTypeRef), __kCFAllocatorGCScannedMemory); \ if (! N) { \ - out_of_memory_warning(); \ + CRSetCrashLogMessage("CFPropertyList ran out of memory while attempting to allocate temporary storage."); \ HALT; \ } \ do {} while (0) @@ -117,42 +107,22 @@ extern char * __crashreporter_info__; // Used to reference an old-style plist parser error inside of a more general XML error #define CFPropertyListOldStyleParserErrorKey CFSTR("kCFPropertyListOldStyleParsingError") -// don't allow _CFKeyedArchiverUID here -#define __CFAssertIsPList(cf) CFAssert2(CFGetTypeID(cf) == CFStringGetTypeID() || CFGetTypeID(cf) == CFArrayGetTypeID() || CFGetTypeID(cf) == CFBooleanGetTypeID() || CFGetTypeID(cf) == CFNumberGetTypeID() || CFGetTypeID(cf) == CFDictionaryGetTypeID() || CFGetTypeID(cf) == CFDateGetTypeID() || CFGetTypeID(cf) == CFDataGetTypeID(), __kCFLogAssertion, "%s(): %p not of a property list type", __PRETTY_FUNCTION__, cf); - -static bool __CFPropertyListIsValidAux(CFPropertyListRef plist, bool recursive, CFMutableSetRef set, CFPropertyListFormat format, CFStringRef *error); - -static CFTypeID stringtype = -1, datatype = -1, numbertype = -1, datetype = -1; -static CFTypeID booltype = -1, nulltype = -1, dicttype = -1, arraytype = -1, settype = -1; +static CFTypeID stringtype, datatype, numbertype, datetype; +static CFTypeID booltype, nulltype, dicttype, arraytype, settype; static void initStatics() { - if ((CFTypeID)-1 == stringtype) { + static dispatch_once_t once; + dispatch_once(&once, ^{ stringtype = CFStringGetTypeID(); - } - if ((CFTypeID)-1 == datatype) { - datatype = CFDataGetTypeID(); - } - if ((CFTypeID)-1 == numbertype) { + datatype = CFDataGetTypeID(); numbertype = CFNumberGetTypeID(); - } - if ((CFTypeID)-1 == booltype) { booltype = CFBooleanGetTypeID(); - } - if ((CFTypeID)-1 == datetype) { datetype = CFDateGetTypeID(); - } - if ((CFTypeID)-1 == dicttype) { dicttype = CFDictionaryGetTypeID(); - } - if ((CFTypeID)-1 == arraytype) { arraytype = CFArrayGetTypeID(); - } - if ((CFTypeID)-1 == settype) { settype = CFSetGetTypeID(); - } - if ((CFTypeID)-1 == nulltype) { nulltype = CFNullGetTypeID(); - } + }); } __private_extern__ CFErrorRef __CFPropertyListCreateError(CFIndex code, CFStringRef debugString, ...) { @@ -179,7 +149,7 @@ __private_extern__ CFErrorRef __CFPropertyListCreateError(CFIndex code, CFString return error; } -CFStringRef __CFPropertyListCopyErrorDebugDescription(CFErrorRef error) { +static CFStringRef __copyErrorDebugDescription(CFErrorRef error) { CFStringRef result = NULL; if (error) { CFDictionaryRef userInfo = CFErrorCopyUserInfo(error); @@ -189,6 +159,11 @@ CFStringRef __CFPropertyListCopyErrorDebugDescription(CFErrorRef error) { return result; } +#pragma mark - +#pragma mark Property List Validation + +// don't allow _CFKeyedArchiverUID here +#define __CFAssertIsPList(cf) CFAssert2(CFGetTypeID(cf) == CFStringGetTypeID() || CFGetTypeID(cf) == CFArrayGetTypeID() || CFGetTypeID(cf) == CFBooleanGetTypeID() || CFGetTypeID(cf) == CFNumberGetTypeID() || CFGetTypeID(cf) == CFDictionaryGetTypeID() || CFGetTypeID(cf) == CFDateGetTypeID() || CFGetTypeID(cf) == CFDataGetTypeID(), __kCFLogAssertion, "%s(): %p not of a property list type", __PRETTY_FUNCTION__, cf); struct context { bool answer; @@ -197,6 +172,8 @@ struct context { CFStringRef *error; }; +static bool __CFPropertyListIsValidAux(CFPropertyListRef plist, bool recursive, CFMutableSetRef set, CFPropertyListFormat format, CFStringRef *error); + static void __CFPropertyListIsArrayPlistAux(const void *value, void *context) { struct context *ctx = (struct context *)context; if (!ctx->answer) return; @@ -263,22 +240,6 @@ static bool __CFPropertyListIsValidAux(CFPropertyListRef plist, bool recursive, return false; } -Boolean CFPropertyListIsValid(CFPropertyListRef plist, CFPropertyListFormat format) { - initStatics(); - CFAssert1(plist != NULL, __kCFLogAssertion, "%s(): NULL is not a property list", __PRETTY_FUNCTION__); - CFMutableSetRef set = CFSetCreateMutable(kCFAllocatorSystemDefaultGCRefZero, 0, NULL); - CFStringRef error = NULL; - bool result = __CFPropertyListIsValidAux(plist, true, set, format, &error); - if (error) { -#if defined(DEBUG) - CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListIsValid(): %@"), error); -#endif - CFRelease(error); - } - if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(set); - return result; -} - static Boolean _CFPropertyListIsValidWithErrorString(CFPropertyListRef plist, CFPropertyListFormat format, CFStringRef *error) { initStatics(); CFAssert1(plist != NULL, __kCFLogAssertion, "%s(): NULL is not a property list", __PRETTY_FUNCTION__); @@ -288,7 +249,10 @@ static Boolean _CFPropertyListIsValidWithErrorString(CFPropertyListRef plist, CF return result; } -static const UniChar CFXMLPlistTags[13][10]= { +#pragma mark - +#pragma mark Writing Property Lists + +static const char CFXMLPlistTags[13][10]= { {'p', 'l', 'i', 's', 't', '\0', '\0', '\0', '\0', '\0'}, {'a', 'r', 'r', 'a', 'y', '\0', '\0', '\0', '\0', '\0'}, {'d', 'i', 'c', 't', '\0', '\0', '\0', '\0', '\0', '\0'}, @@ -304,22 +268,40 @@ static const UniChar CFXMLPlistTags[13][10]= { {'<', '!', '[', 'C', 'D', 'A', 'T', 'A', '[', '\0'} }; +static const UniChar CFXMLPlistTagsUnicode[13][10]= { + {'p', 'l', 'i', 's', 't', '\0', '\0', '\0', '\0', '\0'}, + {'a', 'r', 'r', 'a', 'y', '\0', '\0', '\0', '\0', '\0'}, + {'d', 'i', 'c', 't', '\0', '\0', '\0', '\0', '\0', '\0'}, + {'k', 'e', 'y', '\0', '\0', '\0', '\0', '\0', '\0', '\0'}, + {'s', 't', 'r', 'i', 'n', 'g', '\0', '\0', '\0', '\0'}, + {'d', 'a', 't', 'a', '\0', '\0', '\0', '\0', '\0', '\0'}, + {'d', 'a', 't', 'e', '\0', '\0', '\0', '\0', '\0', '\0'}, + {'r', 'e', 'a', 'l', '\0', '\0', '\0', '\0', '\0', '\0'}, + {'i', 'n', 't', 'e', 'g', 'e', 'r', '\0', '\0', '\0'}, + {'t', 'r', 'u', 'e', '\0', '\0', '\0', '\0', '\0', '\0'}, + {'f', 'a', 'l', 's', 'e', '\0', '\0', '\0', '\0', '\0'}, + {'D', 'O', 'C', 'T', 'Y', 'P', 'E', '\0', '\0', '\0'}, + {'<', '!', '[', 'C', 'D', 'A', 'T', 'A', '[', '\0'} +}; + typedef struct { - const UniChar *begin; // first character of the XML to be parsed - const UniChar *curr; // current parse location - const UniChar *end; // the first character _after_ the end of the XML + const char *begin; // first character of the XML to be parsed + const char *curr; // current parse location + const char *end; // the first character _after_ the end of the XML CFErrorRef error; CFAllocatorRef allocator; UInt32 mutabilityOption; - CFMutableSetRef stringSet; // set of all strings involved in this parse; allows us to share non-mutable strings in the returned plist + CFBurstTrieRef stringTrie; // map of cached strings + CFMutableArrayRef stringCache; // retaining array of strings Boolean allowNewTypes; // Whether to allow the new types supported by XML property lists, but not by the old, OPENSTEP ASCII property lists (CFNumber, CFBoolean, CFDate) - char _padding[3]; + CFSetRef keyPaths; // if NULL, no filtering + Boolean skip; // if true, do not create any objects. } _CFXMLPlistParseInfo; -static CFTypeRef parseOldStylePropertyListOrStringsFile(_CFXMLPlistParseInfo *pInfo); +__private_extern__ CFTypeRef __CFParseOldStylePropertyListOrStringsFile(CFAllocatorRef allocator, CFDataRef xmlData, CFStringRef originalString, CFStringEncoding guessedEncoding, CFOptionFlags option, CFErrorRef *outError,CFPropertyListFormat *format); -CF_INLINE void __CFPListRelease(CFTypeRef cf, _CFXMLPlistParseInfo *pInfo) { - if (cf && !_CFAllocatorIsGCRefZero(pInfo->allocator)) CFRelease(cf); +CF_INLINE void __CFPListRelease(CFTypeRef cf, CFAllocatorRef allocator) { + if (cf && !_CFAllocatorIsGCRefZero(allocator)) CFRelease(cf); } @@ -536,41 +518,41 @@ static void _CFAppendXML0(CFTypeRef object, UInt32 indentation, CFMutableDataRef _appendIndents(indentation, xmlString); if (typeID == stringtype) { _plistAppendUTF8CString(xmlString, "<"); - _plistAppendCharacters(xmlString, CFXMLPlistTags[STRING_IX], STRING_TAG_LENGTH); + _plistAppendCharacters(xmlString, CFXMLPlistTagsUnicode[STRING_IX], STRING_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">"); _appendEscapedString((CFStringRef)object, xmlString); _plistAppendUTF8CString(xmlString, "\n"); } else if (typeID == arraytype) { UInt32 i, count = CFArrayGetCount((CFArrayRef)object); if (count == 0) { _plistAppendUTF8CString(xmlString, "<"); - _plistAppendCharacters(xmlString, CFXMLPlistTags[ARRAY_IX], ARRAY_TAG_LENGTH); + _plistAppendCharacters(xmlString, CFXMLPlistTagsUnicode[ARRAY_IX], ARRAY_TAG_LENGTH); _plistAppendUTF8CString(xmlString, "/>\n"); return; } _plistAppendUTF8CString(xmlString, "<"); - _plistAppendCharacters(xmlString, CFXMLPlistTags[ARRAY_IX], ARRAY_TAG_LENGTH); + _plistAppendCharacters(xmlString, CFXMLPlistTagsUnicode[ARRAY_IX], ARRAY_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">\n"); for (i = 0; i < count; i ++) { _CFAppendXML0(CFArrayGetValueAtIndex((CFArrayRef)object, i), indentation+1, xmlString); } _appendIndents(indentation, xmlString); _plistAppendUTF8CString(xmlString, "\n"); } else if (typeID == dicttype) { UInt32 i, count = CFDictionaryGetCount((CFDictionaryRef)object); CFMutableArrayRef keyArray; if (count == 0) { _plistAppendUTF8CString(xmlString, "<"); - _plistAppendCharacters(xmlString, CFXMLPlistTags[DICT_IX], DICT_TAG_LENGTH); + _plistAppendCharacters(xmlString, CFXMLPlistTagsUnicode[DICT_IX], DICT_TAG_LENGTH); _plistAppendUTF8CString(xmlString, "/>\n"); return; } _plistAppendUTF8CString(xmlString, "<"); - _plistAppendCharacters(xmlString, CFXMLPlistTags[DICT_IX], DICT_TAG_LENGTH); + _plistAppendCharacters(xmlString, CFXMLPlistTagsUnicode[DICT_IX], DICT_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">\n"); new_cftype_array(keys, count); CFDictionaryGetKeysAndValues((CFDictionaryRef)object, keys, NULL); @@ -583,27 +565,27 @@ static void _CFAppendXML0(CFTypeRef object, UInt32 indentation, CFMutableDataRef CFTypeRef key = keys[i]; _appendIndents(indentation+1, xmlString); _plistAppendUTF8CString(xmlString, "<"); - _plistAppendCharacters(xmlString, CFXMLPlistTags[KEY_IX], KEY_TAG_LENGTH); + _plistAppendCharacters(xmlString, CFXMLPlistTagsUnicode[KEY_IX], KEY_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">"); _appendEscapedString((CFStringRef)key, xmlString); _plistAppendUTF8CString(xmlString, "\n"); _CFAppendXML0(CFDictionaryGetValue((CFDictionaryRef)object, key), indentation+1, xmlString); } free_cftype_array(keys); _appendIndents(indentation, xmlString); _plistAppendUTF8CString(xmlString, "\n"); } else if (typeID == datatype) { _plistAppendUTF8CString(xmlString, "<"); - _plistAppendCharacters(xmlString, CFXMLPlistTags[DATA_IX], DATA_TAG_LENGTH); + _plistAppendCharacters(xmlString, CFXMLPlistTagsUnicode[DATA_IX], DATA_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">\n"); _XMLPlistAppendDataUsingBase64(xmlString, (CFDataRef)object, indentation); _appendIndents(indentation, xmlString); _plistAppendUTF8CString(xmlString, "\n"); } else if (typeID == datetype) { // YYYY '-' MM '-' DD 'T' hh ':' mm ':' ss 'Z' @@ -625,42 +607,42 @@ static void _CFAppendXML0(CFTypeRef object, UInt32 indentation, CFMutableDataRef CFRelease(tz); #endif _plistAppendUTF8CString(xmlString, "<"); - _plistAppendCharacters(xmlString, CFXMLPlistTags[DATE_IX], DATE_TAG_LENGTH); + _plistAppendCharacters(xmlString, CFXMLPlistTagsUnicode[DATE_IX], DATE_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">"); _plistAppendFormat(xmlString, CFSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), y, M, d, H, m, s); _plistAppendUTF8CString(xmlString, "\n"); } else if (typeID == numbertype) { if (CFNumberIsFloatType((CFNumberRef)object)) { _plistAppendUTF8CString(xmlString, "<"); - _plistAppendCharacters(xmlString, CFXMLPlistTags[REAL_IX], REAL_TAG_LENGTH); + _plistAppendCharacters(xmlString, CFXMLPlistTagsUnicode[REAL_IX], REAL_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">"); CFStringRef s = __CFNumberCopyFormattingDescriptionAsFloat64(object); _plistAppendString(xmlString, s); CFRelease(s); _plistAppendUTF8CString(xmlString, "\n"); } else { _plistAppendUTF8CString(xmlString, "<"); - _plistAppendCharacters(xmlString, CFXMLPlistTags[INTEGER_IX], INTEGER_TAG_LENGTH); + _plistAppendCharacters(xmlString, CFXMLPlistTagsUnicode[INTEGER_IX], INTEGER_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">"); _plistAppendFormat(xmlString, CFSTR("%@"), object); _plistAppendUTF8CString(xmlString, "\n"); } } else if (typeID == booltype) { if (CFBooleanGetValue((CFBooleanRef)object)) { _plistAppendUTF8CString(xmlString, "<"); - _plistAppendCharacters(xmlString, CFXMLPlistTags[TRUE_IX], TRUE_TAG_LENGTH); + _plistAppendCharacters(xmlString, CFXMLPlistTagsUnicode[TRUE_IX], TRUE_TAG_LENGTH); _plistAppendUTF8CString(xmlString, "/>\n"); } else { _plistAppendUTF8CString(xmlString, "<"); - _plistAppendCharacters(xmlString, CFXMLPlistTags[FALSE_IX], FALSE_TAG_LENGTH); + _plistAppendCharacters(xmlString, CFXMLPlistTagsUnicode[FALSE_IX], FALSE_TAG_LENGTH); _plistAppendUTF8CString(xmlString, "/>\n"); } } @@ -668,18 +650,22 @@ static void _CFAppendXML0(CFTypeRef object, UInt32 indentation, CFMutableDataRef static void _CFGenerateXMLPropertyListToData(CFMutableDataRef xml, CFTypeRef propertyList) { _plistAppendUTF8CString(xml, "\n\n<"); - _plistAppendCharacters(xml, CFXMLPlistTags[PLIST_IX], PLIST_TAG_LENGTH); + _plistAppendCharacters(xml, CFXMLPlistTagsUnicode[PLIST_IX], PLIST_TAG_LENGTH); _plistAppendUTF8CString(xml, " version=\"1.0\">\n"); _CFAppendXML0(propertyList, 0, xml); _plistAppendUTF8CString(xml, "\n"); } +// ======================================================================== +#pragma mark - +#pragma mark Exported Creation Functions + CFDataRef _CFPropertyListCreateXMLData(CFAllocatorRef allocator, CFPropertyListRef propertyList, Boolean checkValidPlist) { initStatics(); CFMutableDataRef xml; @@ -701,18 +687,36 @@ CF_EXPORT CFDataRef _CFPropertyListCreateXMLDataWithExtras(CFAllocatorRef alloca return _CFPropertyListCreateXMLData(allocator, propertyList, false); } +Boolean CFPropertyListIsValid(CFPropertyListRef plist, CFPropertyListFormat format) { + initStatics(); + CFAssert1(plist != NULL, __kCFLogAssertion, "%s(): NULL is not a property list", __PRETTY_FUNCTION__); + CFMutableSetRef set = CFSetCreateMutable(kCFAllocatorSystemDefaultGCRefZero, 0, NULL); + CFStringRef error = NULL; + bool result = __CFPropertyListIsValidAux(plist, true, set, format, &error); + if (error) { +#if defined(DEBUG) + CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListIsValid(): %@"), error); +#endif + CFRelease(error); + } + if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(set); + return result; +} + // ======================================================================== +#pragma mark - +#pragma mark Reading Plists // // ------------------------- Reading plists ------------------ // static void skipInlineDTD(_CFXMLPlistParseInfo *pInfo); -static CFTypeRef parseXMLElement(_CFXMLPlistParseInfo *pInfo, Boolean *isKey); +static Boolean parseXMLElement(_CFXMLPlistParseInfo *pInfo, Boolean *isKey, CFTypeRef *out); // warning: doesn't have a good idea of Unicode line separators static UInt32 lineNumber(_CFXMLPlistParseInfo *pInfo) { - const UniChar *p = pInfo->begin; + const char *p = pInfo->begin; UInt32 count = 1; while (p < pInfo->curr) { if (*p == '\r') { @@ -747,8 +751,8 @@ CF_INLINE void skipWhitespace(_CFXMLPlistParseInfo *pInfo) { // pInfo should be just past "