From 8ca704e1d77f5328769c66e7f562f0d947165d71 Mon Sep 17 00:00:00 2001 From: Apple Date: Fri, 15 Jul 2011 16:26:19 +0000 Subject: [PATCH] CF-635.tar.gz --- BuildCFLite | 102 -- CFApplicationPreferences.c | 6 +- CFArray.c | 445 ++--- CFArray.h | 4 +- CFBag.c | 375 +++- CFBag.h | 4 +- CFBase.c | 233 +-- CFBase.h | 122 +- CFBasicHash.h | 125 +- CFBasicHash.m | 1862 ++++++++++--------- CFBasicHashFindBucket.m | 198 ++ CFBinaryHeap.c | 8 +- CFBinaryHeap.h | 4 +- CFBinaryPList.c | 276 ++- CFBitVector.c | 4 +- CFBitVector.h | 4 +- CFBuiltinConverters.c | 4 +- CFBundle.c | 604 ++++--- CFBundle.h | 20 +- CFBundlePriv.h | 10 +- CFBundle_BinaryTypes.h | 5 +- CFBundle_Internal.h | 15 +- CFBundle_Resources.c | 855 +++++++-- CFByteOrder.h | 4 +- CFCalendar.c | 45 +- CFCalendar.h | 59 +- CFCharacterSet.c | 5 +- CFCharacterSet.h | 16 +- CFCharacterSetBitmaps.bitmap | Bin 434391 -> 434391 bytes CFCharacterSetPriv.h | 6 +- CFConcreteStreams.c | 106 +- CFData.c | 106 +- CFData.h | 8 +- CFDate.c | 25 +- CFDate.h | 4 +- CFDateFormatter.c | 150 +- CFDateFormatter.h | 94 +- CFDictionary.c | 376 +++- CFDictionary.h | 4 +- CFError.c | 53 +- CFError.h | 42 +- CFError_Private.h | 10 +- CFFileUtilities.c | 231 ++- CFICUConverters.c | 86 +- CFICUConverters.h | 7 +- CFInternal.h | 442 +++-- CFLocale.c | 56 +- CFLocale.h | 120 +- CFLocaleIdentifier.c | 23 +- CFLocaleInternal.h | 4 +- CFLocaleKeys.c | 237 +++ CFLocaleKeys.m | 144 -- CFLogUtilities.h | 4 +- CFMachPort.c | 39 +- CFMachPort.h | 4 +- CFMessagePort.c | 76 +- CFMessagePort.h | 10 +- CFNumber.c | 160 +- CFNumber.h | 4 +- CFNumberFormatter.c | 40 +- CFNumberFormatter.h | 110 +- CFPlatform.c | 655 ++++++- CFPlatformConverters.c | 22 +- CFPlugIn.c | 6 +- CFPlugIn.h | 4 +- CFPlugInCOM.h | 4 +- CFPlugIn_Factory.c | 12 +- CFPlugIn_Factory.h | 4 +- CFPlugIn_Instance.c | 6 +- CFPlugIn_PlugIn.c | 6 +- CFPreferences.c | 12 +- CFPreferences.h | 4 +- CFPriv.h | 83 +- CFPropertyList.c | 732 ++++---- CFPropertyList.h | 25 +- CFRunLoop.c | 3020 ++++++++++++++----------------- CFRunLoop.h | 17 +- CFRuntime.c | 1018 ++++++----- CFRuntime.h | 123 +- CFSet.c | 375 +++- CFSet.h | 8 +- CFSocket.c | 410 +++-- CFSocket.h | 28 +- CFSocketStream.c | 4 +- CFSortFunctions.c | 83 +- CFStorage.c | 1548 +++++++++++----- CFStorage.h | 138 +- CFStream.c | 146 +- CFStream.h | 20 +- CFStreamAbstract.h | 11 +- CFStreamInternal.h | 2 +- CFStreamPriv.h | 4 +- CFString.c | 397 +++- CFString.h | 123 +- CFStringDefaultEncoding.h | 4 +- CFStringEncodingConverter.c | 10 +- CFStringEncodingConverter.h | 4 +- CFStringEncodingConverterExt.h | 4 +- CFStringEncodingConverterPriv.h | 4 +- CFStringEncodingDatabase.c | 19 +- CFStringEncodingDatabase.h | 4 +- CFStringEncodingExt.h | 14 +- CFStringEncodings.c | 28 +- CFStringScanner.c | 6 +- CFStringUtilities.c | 31 +- CFSystemDirectories.c | 8 +- CFTimeZone.c | 442 +---- CFTimeZone.h | 14 +- CFTree.c | 18 +- CFTree.h | 4 +- CFURL.c | 517 ++++-- CFURL.h | 340 +++- CFURLAccess.c | 28 +- CFURLAccess.h | 28 +- CFURLPriv.h | 608 +++++++ CFUUID.c | 164 +- CFUUID.h | 4 +- CFUniChar.c | 130 +- CFUniChar.h | 7 +- CFUniCharPriv.h | 4 +- CFUniCharPropertyDatabase.data | Bin 25636 -> 30244 bytes CFUnicodeData-B.mapping | Bin 87224 -> 89416 bytes CFUnicodeData-L.mapping | Bin 87224 -> 89416 bytes CFUnicodeDecomposition.c | 4 +- CFUnicodeDecomposition.h | 4 +- CFUnicodePrecomposition.c | 4 +- CFUnicodePrecomposition.h | 4 +- CFUserNotification.c | 16 +- CFUserNotification.h | 8 +- CFUtilities.c | 307 ++-- CFVersion.c | 10 +- CFWindowsMessageQueue.c | 244 --- CFWindowsMessageQueue.h | 52 - CFXMLInputStream.c | 6 +- CFXMLInputStream.h | 4 +- CFXMLNode.c | 8 +- CFXMLNode.h | 11 +- CFXMLParser.c | 10 +- CFXMLParser.h | 25 +- CFXMLPreferencesDomain.c | 19 +- CFXMLTree.c | 6 +- CoreFoundation.h | 28 +- CoreFoundation_Prefix.h | 237 ++- Examples/plconvert.c | 110 ++ ForFoundationOnly.h | 39 +- Info.plist | 20 +- Makefile | 83 +- MakefileLinux | 75 + MakefileVersion | 1 + README_CFLITE | 74 + SymbolAliases | 96 + TargetConditionals.h | 17 + plconvert.c | 133 ++ 153 files changed, 13001 insertions(+), 8343 deletions(-) delete mode 100755 BuildCFLite create mode 100644 CFBasicHashFindBucket.m create mode 100644 CFLocaleKeys.c delete mode 100644 CFLocaleKeys.m create mode 100644 CFURLPriv.h delete mode 100644 CFWindowsMessageQueue.c delete mode 100644 CFWindowsMessageQueue.h create mode 100644 Examples/plconvert.c create mode 100644 MakefileLinux create mode 100644 MakefileVersion create mode 100644 README_CFLITE create mode 100644 SymbolAliases create mode 100644 TargetConditionals.h create mode 100644 plconvert.c diff --git a/BuildCFLite b/BuildCFLite deleted file mode 100755 index cc606d2..0000000 --- a/BuildCFLite +++ /dev/null @@ -1,102 +0,0 @@ -#/bin/sh - -echo "Setup ..." - -ALL_CFILES=`ls *.c` -ALL_HFILES=`ls *.h` -ALL_MFILES=`ls *.m` - -MACHINE_TYPE=`uname -p` -UNICODE_DATA_FILE="UNKNOWN" - -if [ "$MACHINE_TYPE" == "i386" ]; then - UNICODE_DATA_FILE="CFUnicodeData-L.mapping" -fi - -if [ "$MACHINE_TYPE" == "i686" ]; then - UNICODE_DATA_FILE="CFUnicodeData-L.mapping" -fi - -if [ "$MACHINE_TYPE" == "powerpc" ]; then - UNICODE_DATA_FILE="CFUnicodeData-B.mapping" -fi - -PUBLIC_HEADERS="CFArray.h CFBag.h CFBase.h CFBinaryHeap.h CFBitVector.h CFBundle.h CFByteOrder.h CFCalendar.h CFCharacterSet.h CFData.h CFDate.h CFDateFormatter.h CFDictionary.h CFError.h CFLocale.h CFMachPort.h CFMessagePort.h CFNumber.h CFNumberFormatter.h CFPlugIn.h CFPlugInCOM.h CFPreferences.h CFPropertyList.h CFRunLoop.h CFSet.h CFSocket.h CFStream.h CFString.h CFStringEncodingExt.h CFTimeZone.h CFTree.h CFURL.h CFURLAccess.h CFUUID.h CFUserNotification.h CFXMLNode.h CFXMLParser.h CoreFoundation.h" -PRIVATE_HEADERS="CFBundlePriv.h CFCharacterSetPriv.h CFError_Private.h CFLogUtilities.h CFPriv.h CFRuntime.h CFStorage.h CFStreamAbstract.h CFStreamPriv.h CFStreamInternal.h CFStringDefaultEncoding.h CFStringEncodingConverter.h CFStringEncodingConverterExt.h CFUniChar.h CFUnicodeDecomposition.h CFUnicodePrecomposition.h ForFoundationOnly.h" - -OBJBASE=./CF-Objects -ARCHFLAGS="-arch ppc -arch i386 -arch x86_64" -CFLAGS="-c -x objective-c -pipe -std=gnu99 -g -Wmost -Wno-trigraphs -mmacosx-version-min=10.6 -fconstant-cfstrings -fexceptions -DCF_BUILDING_CF=1 -DDEPLOYMENT_TARGET_MACOSX=1 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_6 -DU_SHOW_DRAFT_API=1 -I$OBJBASE -DVERSION=535 -include CoreFoundation_Prefix.h" -LFLAGS="-dynamiclib -mmacosx-version-min=10.6 -twolevel_namespace -init ___CFInitialize -compatibility_version 150 -current_version 535 -sectcreate __UNICODE __csbitmaps CFCharacterSetBitmaps.bitmap -sectcreate __UNICODE __properties CFUniCharPropertyDatabase.data -sectcreate __UNICODE __data $UNICODE_DATA_FILE -segprot __UNICODE r r" - -/bin/rm -rf $OBJBASE -/bin/mkdir -p $OBJBASE -/bin/mkdir $OBJBASE/normal -/bin/mkdir $OBJBASE/CoreFoundation -/bin/cp $ALL_HFILES $OBJBASE/CoreFoundation -if [ $? -ne 0 ]; then - echo "Setup failed" - exit 1 -fi - -Build () { - echo "Compiling $STYLE ..." - for F in $ALL_CFILES ; do - echo /usr/bin/gcc $STYLE_CFLAGS $ARCHFLAGS $CFLAGS $F -o $OBJBASE/$STYLE/`basename $F .c`.o - /usr/bin/gcc $STYLE_CFLAGS $ARCHFLAGS $CFLAGS $F -o $OBJBASE/$STYLE/`basename $F .c`.o - if [ $? -ne 0 ]; then - echo "*** Compiling $STYLE failed ***" - exit 1 - fi - done - for F in $ALL_MFILES ; do - echo /usr/bin/gcc $STYLE_CFLAGS $ARCHFLAGS $CFLAGS $F -o $OBJBASE/$STYLE/`basename $F .m`.o - /usr/bin/gcc $STYLE_CFLAGS $ARCHFLAGS $CFLAGS $F -o $OBJBASE/$STYLE/`basename $F .m`.o - if [ $? -ne 0 ]; then - echo "*** Compiling $STYLE failed ***" - exit 1 - fi - done - echo "Linking $STYLE ..." - echo /usr/bin/gcc $STYLE_LFLAGS -install_name /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation_$STYLE $ARCHFLAGS $LFLAGS $OBJBASE/$STYLE/*.o -licucore.A -lobjc -o $OBJBASE/CoreFoundation_$STYLE - /usr/bin/gcc $STYLE_LFLAGS -install_name /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation_$STYLE $ARCHFLAGS $LFLAGS $OBJBASE/$STYLE/*.o -licucore.A -lobjc -o $OBJBASE/CoreFoundation_$STYLE - if [ $? -ne 0 ]; then - echo "*** Linking $STYLE failed ***" - exit 1 - fi -} - -STYLE=normal -STYLE_CFLAGS="-O2" -STYLE_LFLAGS= -Build - -echo "Building done." - -echo "Installing ..." -if [ -z "$DSTBASE" ]; then DSTBASE=../CF-Root ; fi - -/bin/rm -rf $DSTBASE/CoreFoundation.framework -/bin/mkdir -p $DSTBASE/CoreFoundation.framework/Versions/A/Resources -/bin/mkdir -p $DSTBASE/CoreFoundation.framework/Versions/A/Headers -/bin/mkdir -p $DSTBASE/CoreFoundation.framework/Versions/A/PrivateHeaders -/bin/ln -sf A $DSTBASE/CoreFoundation.framework/Versions/Current -/bin/ln -sf Versions/Current/Resources $DSTBASE/CoreFoundation.framework/Resources -/bin/ln -sf Versions/Current/Headers $DSTBASE/CoreFoundation.framework/Headers -/bin/ln -sf Versions/Current/PrivateHeaders $DSTBASE/CoreFoundation.framework/PrivateHeaders -/bin/ln -sf Versions/Current/CoreFoundation $DSTBASE/CoreFoundation.framework/CoreFoundation -/bin/cp Info.plist $DSTBASE/CoreFoundation.framework/Versions/A/Resources -/bin/mkdir -p $DSTBASE/CoreFoundation.framework/Versions/A/Resources/en.lproj -/bin/cp $PUBLIC_HEADERS $DSTBASE/CoreFoundation.framework/Versions/A/Headers -/bin/cp $PRIVATE_HEADERS $DSTBASE/CoreFoundation.framework/Versions/A/PrivateHeaders -/usr/bin/strip -S -o $DSTBASE/CoreFoundation.framework/Versions/A/CoreFoundation $OBJBASE/CoreFoundation_normal -/usr/sbin/chown -RH -f root:wheel $DSTBASE/CoreFoundation.framework -/bin/chmod -RH a-w,a+rX $DSTBASE/CoreFoundation.framework -/bin/chmod -RH u+w $DSTBASE - -install_name_tool -id /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation $DSTBASE/CoreFoundation.framework/Versions/A/CoreFoundation - -echo "Installing done. The framework is in $DSTBASE" - -exit 0 - diff --git a/CFApplicationPreferences.c b/CFApplicationPreferences.c index 864f0c7..343da00 100644 --- a/CFApplicationPreferences.c +++ b/CFApplicationPreferences.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFApplicationPreferences.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. - Responsibility: Chris Parker + Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ #include diff --git a/CFArray.c b/CFArray.c index dced26d..d5b0704 100644 --- a/CFArray.c +++ b/CFArray.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,20 +22,15 @@ */ /* CFArray.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ #include -#include "CFStorage.h" #include #include "CFInternal.h" #include -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -#include -#endif - -__private_extern__ void _CFStorageSetWeak(CFStorageRef storage); +#include const CFArrayCallBacks kCFTypeArrayCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual}; static const CFArrayCallBacks __kCFNullArrayCallBacks = {0, NULL, NULL, NULL, NULL}; @@ -45,7 +40,7 @@ struct __CFArrayBucket { }; enum { - __CF_MAX_BUCKETS_PER_DEQUE = 262140 + __CF_MAX_BUCKETS_PER_DEQUE = LONG_MAX }; CF_INLINE CFIndex __CFArrayDequeRoundUpCapacity(CFIndex capacity) { @@ -54,12 +49,8 @@ CF_INLINE CFIndex __CFArrayDequeRoundUpCapacity(CFIndex capacity) { } struct __CFArrayDeque { - uint32_t _leftIdx; - uint32_t _capacity; - int32_t _bias; -#if __LP64__ - uint32_t _pad; // GC: pointers must be 8-byte aligned for the collector to find them. -#endif + uintptr_t _leftIdx; + uintptr_t _capacity; /* struct __CFArrayBucket buckets follow here */ }; @@ -68,14 +59,13 @@ struct __CFArray { CFIndex _count; /* number of objects */ CFIndex _mutations; int32_t _mutInProgress; - void *_store; /* can be NULL when MutableDeque */ + __strong void *_store; /* can be NULL when MutableDeque */ }; /* Flag bits */ enum { /* Bits 0-1 */ __kCFArrayImmutable = 0, __kCFArrayDeque = 2, - __kCFArrayStorage = 3 }; enum { /* Bits 2-3 */ @@ -147,15 +137,11 @@ CF_INLINE struct __CFArrayBucket *__CFArrayGetBucketAtIndex(CFArrayRef array, CF case __kCFArrayImmutable: case __kCFArrayDeque: return __CFArrayGetBucketsPtr(array) + idx; - case __kCFArrayStorage: { - CFStorageRef store = (CFStorageRef)array->_store; - return (struct __CFArrayBucket *)CFStorageGetValueAtIndex(store, idx, NULL); - } } return NULL; } -CF_INLINE CFArrayCallBacks *__CFArrayGetCallBacks(CFArrayRef array) { +__private_extern__ CFArrayCallBacks *__CFArrayGetCallBacks(CFArrayRef array) { CFArrayCallBacks *result = NULL; switch (__CFBitfieldGetValue(((const CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS], 3, 2)) { case __kCFArrayHasNullCallBacks: @@ -170,7 +156,6 @@ CF_INLINE CFArrayCallBacks *__CFArrayGetCallBacks(CFArrayRef array) { result = (CFArrayCallBacks *)((uint8_t *)array + sizeof(struct __CFArray)); break; case __kCFArrayDeque: - case __kCFArrayStorage: result = (CFArrayCallBacks *)((uint8_t *)array + sizeof(struct __CFArray)); break; } @@ -208,12 +193,6 @@ struct _releaseContext { CFAllocatorRef allocator; }; -static void __CFArrayStorageRelease(const void *itemptr, void *context) { - struct _releaseContext *rc = (struct _releaseContext *)context; - INVOKE_CALLBACK2(rc->release, rc->allocator, *(const void **)itemptr); - *(const void **)itemptr = NULL; // GC: clear item to break strong reference. -} - static void __CFArrayReleaseValues(CFArrayRef array, CFRange range, bool releaseStorageIfPossible) { const CFArrayCallBacks *cb = __CFArrayGetCallBacks(array); CFAllocatorRef allocator; @@ -250,26 +229,9 @@ static void __CFArrayReleaseValues(CFArrayRef array, CFRange range, bool release } if (releaseStorageIfPossible && 0 == range.location && __CFArrayGetCount(array) == range.length) { allocator = __CFGetAllocator(array); - if (NULL != deque) _CFAllocatorDeallocateGC(allocator, deque); - __CFArraySetCount(array, 0); // GC: _count == 0 ==> _store == NULL. - ((struct __CFArray *)array)->_store = NULL; - } - break; - } - case __kCFArrayStorage: { - CFStorageRef store = (CFStorageRef)array->_store; - if (NULL != cb->release && 0 < range.length && !hasBeenFinalized(array)) { - struct _releaseContext context; - allocator = __CFGetAllocator(array); - context.release = cb->release; - context.allocator = allocator; - CFStorageApplyFunction(store, range, __CFArrayStorageRelease, &context); - } - if (releaseStorageIfPossible && 0 == range.location && __CFArrayGetCount(array) == range.length) { - _CFReleaseGC(store); + if (NULL != deque && !CF_IS_COLLECTABLE_ALLOCATOR(allocator)) CFAllocatorDeallocate(allocator, deque); __CFArraySetCount(array, 0); // GC: _count == 0 ==> _store == NULL. ((struct __CFArray *)array)->_store = NULL; - __CFBitfieldSetValue(((CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS], 1, 0, __kCFArrayDeque); } break; } @@ -330,9 +292,6 @@ static CFStringRef __CFArrayCopyDescription(CFTypeRef cf) { case __kCFArrayDeque: CFStringAppendFormat(result, NULL, CFSTR("{type = mutable-small, count = %u, values = (%s"), cf, allocator, cnt, cnt ? "\n" : ""); break; - case __kCFArrayStorage: - CFStringAppendFormat(result, NULL, CFSTR("{type = mutable-large, count = %u, values = (%s"), cf, allocator, cnt, cnt ? "\n" : ""); - break; } cb = __CFArrayGetCallBacks(array); for (idx = 0; idx < cnt; idx++) { @@ -369,7 +328,7 @@ static void __CFArrayDeallocate(CFTypeRef cf) { if (cb == &kCFTypeArrayCallBacks || cb->release == kCFTypeArrayCallBacks.release) { markFinalized(cf); for (CFIndex idx = 0; idx < __CFArrayGetCount(array); idx++) { - const void *item = __CFArrayGetBucketAtIndex(array, 0 + idx)->_item; + const void *item = CFArrayGetValueAtIndex(array, 0 + idx); kCFTypeArrayCallBacks.release(kCFAllocatorSystemDefault, item); } END_MUTATION(array); @@ -424,7 +383,6 @@ static CFArrayRef __CFArrayInit(CFAllocatorRef allocator, UInt32 flags, CFIndex size += capacity * sizeof(struct __CFArrayBucket); break; case __kCFArrayDeque: - case __kCFArrayStorage: break; } memory = (struct __CFArray*)_CFRuntimeCreateInstance(allocator, __kCFArrayTypeID, size, NULL); @@ -436,12 +394,11 @@ static CFArrayRef __CFArrayInit(CFAllocatorRef allocator, UInt32 flags, CFIndex switch (__CFBitfieldGetValue(flags, 1, 0)) { case __kCFArrayImmutable: if (isWeakMemory(memory)) { // if weak, don't scan - auto_zone_set_unscanned(auto_zone(), memory); + auto_zone_set_unscanned(objc_collectableZone(), memory); } if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFArray (immutable)"); break; case __kCFArrayDeque: - case __kCFArrayStorage: if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFArray (mutable-variable)"); ((struct __CFArray *)memory)->_mutations = 1; ((struct __CFArray *)memory)->_mutInProgress = 0; @@ -459,7 +416,25 @@ static CFArrayRef __CFArrayInit(CFAllocatorRef allocator, UInt32 flags, CFIndex return (CFArrayRef)memory; } -CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks) { +__private_extern__ CFArrayRef __CFArrayCreateTransfer(CFAllocatorRef allocator, const void **values, CFIndex numValues) { + CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%d) cannot be less than zero", __PRETTY_FUNCTION__, numValues); + UInt32 flags = __kCFArrayImmutable; + __CFBitfieldSetValue(flags, 31, 2, 0); + __CFBitfieldSetValue(flags, 3, 2, __kCFArrayHasCFTypeCallBacks); + UInt32 size = __CFArrayGetSizeOfType(flags) - sizeof(CFRuntimeBase); + size += numValues * sizeof(struct __CFArrayBucket); + struct __CFArray *memory = (struct __CFArray*)_CFRuntimeCreateInstance(allocator, __kCFArrayTypeID, size, NULL); + if (NULL == memory) { + return NULL; + } + __CFBitfieldSetValue(memory->_base._cfinfo[CF_INFO_BITS], 6, 0, flags); + __CFArraySetCount(memory, numValues); + memmove(__CFArrayGetBucketsPtr(memory), values, sizeof(void *) * numValues); + if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFArray (immutable)"); + return (CFArrayRef)memory; +} + +__private_extern__ CFArrayRef __CFArrayCreate0(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks) { CFArrayRef result; const CFArrayCallBacks *cb; struct __CFArrayBucket *buckets; @@ -471,7 +446,7 @@ CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex cb = __CFArrayGetCallBacks(result); buckets = __CFArrayGetBucketsPtr(result); bucketsAllocator = isStrongMemory(result) ? allocator : kCFAllocatorNull; - bucketsBase = CF_IS_COLLECTABLE_ALLOCATOR(bucketsAllocator) ? (void *)auto_zone_base_pointer(auto_zone(), buckets) : NULL; + bucketsBase = CF_IS_COLLECTABLE_ALLOCATOR(bucketsAllocator) ? (void *)auto_zone_base_pointer(objc_collectableZone(), buckets) : NULL; if (NULL != cb->retain) { for (idx = 0; idx < numValues; idx++) { __CFAssignWithWriteBarrier((void **)&buckets->_item, (void *)INVOKE_CALLBACK2(cb->retain, allocator, *values)); @@ -490,13 +465,13 @@ CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex return result; } -CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks) { +__private_extern__ CFMutableArrayRef __CFArrayCreateMutable0(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks) { CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%d) cannot be less than zero", __PRETTY_FUNCTION__, capacity); CFAssert2(capacity <= LONG_MAX / sizeof(void *), __kCFLogAssertion, "%s(): capacity (%d) is too large for this architecture", __PRETTY_FUNCTION__, capacity); return (CFMutableArrayRef)__CFArrayInit(allocator, __kCFArrayDeque, capacity, callBacks); } -CFArrayRef CFArrayCreateCopy(CFAllocatorRef allocator, CFArrayRef array) { +__private_extern__ CFArrayRef __CFArrayCreateCopy0(CFAllocatorRef allocator, CFArrayRef array) { CFArrayRef result; const CFArrayCallBacks *cb; struct __CFArrayBucket *buckets; @@ -513,7 +488,7 @@ CFArrayRef CFArrayCreateCopy(CFAllocatorRef allocator, CFArrayRef array) { cb = __CFArrayGetCallBacks(result); // GC: use the new array's callbacks so we don't leak. buckets = __CFArrayGetBucketsPtr(result); bucketsAllocator = isStrongMemory(result) ? allocator : kCFAllocatorNull; - bucketsBase = CF_IS_COLLECTABLE_ALLOCATOR(bucketsAllocator) ? (void *)auto_zone_base_pointer(auto_zone(), buckets) : NULL; + bucketsBase = CF_IS_COLLECTABLE_ALLOCATOR(bucketsAllocator) ? (void *)auto_zone_base_pointer(objc_collectableZone(), buckets) : NULL; for (idx = 0; idx < numValues; idx++) { const void *value = CFArrayGetValueAtIndex(array, idx); if (NULL != cb->retain) { @@ -526,7 +501,7 @@ CFArrayRef CFArrayCreateCopy(CFAllocatorRef allocator, CFArrayRef array) { return result; } -CFMutableArrayRef CFArrayCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFArrayRef array) { +__private_extern__ CFMutableArrayRef __CFArrayCreateMutableCopy0(CFAllocatorRef allocator, CFIndex capacity, CFArrayRef array) { CFMutableArrayRef result; const CFArrayCallBacks *cb; CFIndex idx, numValues = CFArrayGetCount(array); @@ -547,6 +522,28 @@ CFMutableArrayRef CFArrayCreateMutableCopy(CFAllocatorRef allocator, CFIndex cap return result; } +#define DEFINE_CREATION_METHODS 1 + +#if DEFINE_CREATION_METHODS + +CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFArrayCallBacks *callBacks) { + return __CFArrayCreate0(allocator, values, numValues, callBacks); +} + +CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks) { + return __CFArrayCreateMutable0(allocator, capacity, callBacks); +} + +CFArrayRef CFArrayCreateCopy(CFAllocatorRef allocator, CFArrayRef array) { + return __CFArrayCreateCopy0(allocator, array); +} + +CFMutableArrayRef CFArrayCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFArrayRef array) { + return __CFArrayCreateMutableCopy0(allocator, capacity, array); +} + +#endif + CFIndex CFArrayGetCount(CFArrayRef array) { CF_OBJC_FUNCDISPATCH0(__kCFArrayTypeID, CFIndex, array, "count"); __CFGenericValidateType(array, __kCFArrayTypeID); @@ -556,16 +553,13 @@ CFIndex CFArrayGetCount(CFArrayRef array) { CFIndex CFArrayGetCountOfValue(CFArrayRef array, CFRange range, const void *value) { - const CFArrayCallBacks *cb; CFIndex idx, count = 0; -// CF: this ignores range - CF_OBJC_FUNCDISPATCH1(__kCFArrayTypeID, CFIndex, array, "_cfcountOccurrences:", value); __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); CHECK_FOR_MUTATION(array); - cb = __CFArrayGetCallBacks(array); + const CFArrayCallBacks *cb = CF_IS_OBJC(CFArrayGetTypeID(), array) ? &kCFTypeArrayCallBacks : __CFArrayGetCallBacks(array); for (idx = 0; idx < range.length; idx++) { - const void *item = __CFArrayGetBucketAtIndex(array, range.location + idx)->_item; + const void *item = CFArrayGetValueAtIndex(array, range.location + idx); if (value == item || (cb->equal && INVOKE_CALLBACK2(cb->equal, value, item))) { count++; } @@ -575,13 +569,12 @@ CFIndex CFArrayGetCountOfValue(CFArrayRef array, CFRange range, const void *valu Boolean CFArrayContainsValue(CFArrayRef array, CFRange range, const void *value) { CFIndex idx; - CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, char, array, "containsObject:inRange:", value, range); __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); CHECK_FOR_MUTATION(array); - const CFArrayCallBacks *cb = __CFArrayGetCallBacks(array); + const CFArrayCallBacks *cb = CF_IS_OBJC(CFArrayGetTypeID(), array) ? &kCFTypeArrayCallBacks : __CFArrayGetCallBacks(array); for (idx = 0; idx < range.length; idx++) { - const void *item = __CFArrayGetBucketAtIndex(array, range.location + idx)->_item; + const void *item = CFArrayGetValueAtIndex(array, range.location + idx); if (value == item || (cb->equal && INVOKE_CALLBACK2(cb->equal, value, item))) { return true; } @@ -617,16 +610,10 @@ void CFArrayGetValues(CFArrayRef array, CFRange range, const void **values) { case __kCFArrayDeque: objc_memmove_collectable(values, __CFArrayGetBucketsPtr(array) + range.location, range.length * sizeof(struct __CFArrayBucket)); break; - case __kCFArrayStorage: { - CFStorageRef store = (CFStorageRef)array->_store; - CFStorageGetValues(store, range, values); - break; - } } } } - CF_EXPORT unsigned long _CFArrayFastEnumeration(CFArrayRef array, struct __objcFastEnumerationStateEquivalent *state, void *stackbuffer, unsigned long count) { CHECK_FOR_MUTATION(array); if (array->_count == 0) return 0; @@ -649,9 +636,6 @@ CF_EXPORT unsigned long _CFArrayFastEnumeration(CFArrayRef array, struct __objcF return array->_count; } return 0; - case __kCFArrayStorage: - state->mutationsPtr = (unsigned long *)&array->_mutations; - return _CFStorageFastEnumeration((CFStorageRef)array->_store, state, stackbuffer, count); } return 0; } @@ -660,27 +644,24 @@ CF_EXPORT unsigned long _CFArrayFastEnumeration(CFArrayRef array, struct __objcF void CFArrayApplyFunction(CFArrayRef array, CFRange range, CFArrayApplierFunction applier, void *context) { CFIndex idx; FAULT_CALLBACK((void **)&(applier)); - CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, void, array, "_cfapply:context:", applier, context); __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); CFAssert1(NULL != applier, __kCFLogAssertion, "%s(): pointer to applier function may not be NULL", __PRETTY_FUNCTION__); CHECK_FOR_MUTATION(array); for (idx = 0; idx < range.length; idx++) { - const void *item = __CFArrayGetBucketAtIndex(array, range.location + idx)->_item; + const void *item = CFArrayGetValueAtIndex(array, range.location + idx); INVOKE_CALLBACK2(applier, item, context); } } CFIndex CFArrayGetFirstIndexOfValue(CFArrayRef array, CFRange range, const void *value) { - const CFArrayCallBacks *cb; CFIndex idx; - CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, CFIndex, array, "_cfindexOfObject:inRange:", value, range); __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); CHECK_FOR_MUTATION(array); - cb = __CFArrayGetCallBacks(array); + const CFArrayCallBacks *cb = CF_IS_OBJC(CFArrayGetTypeID(), array) ? &kCFTypeArrayCallBacks : __CFArrayGetCallBacks(array); for (idx = 0; idx < range.length; idx++) { - const void *item = __CFArrayGetBucketAtIndex(array, range.location + idx)->_item; + const void *item = CFArrayGetValueAtIndex(array, range.location + idx); if (value == item || (cb->equal && INVOKE_CALLBACK2(cb->equal, value, item))) return idx + range.location; } @@ -688,15 +669,13 @@ CFIndex CFArrayGetFirstIndexOfValue(CFArrayRef array, CFRange range, const void } CFIndex CFArrayGetLastIndexOfValue(CFArrayRef array, CFRange range, const void *value) { - const CFArrayCallBacks *cb; CFIndex idx; - CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, CFIndex, array, "_cflastIndexOfObject:inRange:", value, range); __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); CHECK_FOR_MUTATION(array); - cb = __CFArrayGetCallBacks(array); + const CFArrayCallBacks *cb = CF_IS_OBJC(CFArrayGetTypeID(), array) ? &kCFTypeArrayCallBacks : __CFArrayGetCallBacks(array); for (idx = range.length; idx--;) { - const void *item = __CFArrayGetBucketAtIndex(array, range.location + idx)->_item; + const void *item = CFArrayGetValueAtIndex(array, range.location + idx); if (value == item || (cb->equal && INVOKE_CALLBACK2(cb->equal, value, item))) return idx + range.location; } @@ -747,11 +726,12 @@ void CFArrayInsertValueAtIndex(CFMutableArrayRef array, CFIndex idx, const void _CFArrayReplaceValues(array, CFRangeMake(idx, 0), &value, 1); } +// NB: AddressBook on the Phone is a fragile flower, so this function cannot do anything +// that causes the values to be retained or released. void CFArrayExchangeValuesAtIndices(CFMutableArrayRef array, CFIndex idx1, CFIndex idx2) { const void *tmp; struct __CFArrayBucket *bucket1, *bucket2; - CFAllocatorRef bucketsAllocator; - CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, void, array, "_cfexchange::", idx1, idx2); + CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, void, array, "exchangeObjectAtIndex:withObjectAtIndex:", idx1, 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); @@ -761,7 +741,6 @@ void CFArrayExchangeValuesAtIndices(CFMutableArrayRef array, CFIndex idx1, CFInd bucket1 = __CFArrayGetBucketAtIndex(array, idx1); bucket2 = __CFArrayGetBucketAtIndex(array, idx2); tmp = bucket1->_item; - bucketsAllocator = isStrongMemory(array) ? __CFGetAllocator(array) : kCFAllocatorNull; // XXX these aren't needed. __CFAssignWithWriteBarrier((void **)&bucket1->_item, (void *)bucket2->_item); __CFAssignWithWriteBarrier((void **)&bucket2->_item, (void *)tmp); @@ -790,48 +769,6 @@ void CFArrayRemoveAllValues(CFMutableArrayRef array) { END_MUTATION(array); } -static void __CFArrayConvertDequeToStore(CFMutableArrayRef array) { - struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store; - struct __CFArrayBucket *raw_buckets = (struct __CFArrayBucket *)((uint8_t *)deque + sizeof(struct __CFArrayDeque)); - CFStorageRef store; - CFIndex count = __CFArrayGetCount(array); - CFAllocatorRef allocator = __CFGetAllocator(array); - Boolean collectableMemory = CF_IS_COLLECTABLE_ALLOCATOR(allocator); - if (collectableMemory) auto_zone_retain(auto_zone(), deque); - store = CFStorageCreate(allocator, sizeof(const void *)); - if (__CFOASafe) __CFSetLastAllocationEventName(store, "CFArray (store-storage)"); - __CFAssignWithWriteBarrier((void **)&array->_store, (void *)store); - CFMakeCollectable(store); // GC: now safe to unroot the store. - CFStorageInsertValues(store, CFRangeMake(0, count)); - CFStorageReplaceValues(store, CFRangeMake(0, count), raw_buckets + deque->_leftIdx); - CFAllocatorDeallocate(__CFGetAllocator(array), deque); - __CFBitfieldSetValue(((CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS], 1, 0, __kCFArrayStorage); -} - -static void __CFArrayConvertStoreToDeque(CFMutableArrayRef array) { - CFStorageRef store = (CFStorageRef)array->_store; - struct __CFArrayDeque *deque; - struct __CFArrayBucket *raw_buckets; - CFIndex count = CFStorageGetCount(store);// storage, not array, has correct count at this point - // do not resize down to a completely tight deque - CFIndex capacity = __CFArrayDequeRoundUpCapacity(count + 6); - CFIndex size = sizeof(struct __CFArrayDeque) + capacity * sizeof(struct __CFArrayBucket); - CFAllocatorRef allocator = __CFGetAllocator(array); - Boolean collectableMemory = CF_IS_COLLECTABLE_ALLOCATOR(allocator); - if (collectableMemory) CFRetain(store); // GC: need to root the CFStorage - deque = (struct __CFArrayDeque *)CFAllocatorAllocate(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0); - if (__CFOASafe) __CFSetLastAllocationEventName(deque, "CFArray (store-deque)"); - deque->_leftIdx = (capacity - count) / 2; - deque->_capacity = capacity; - deque->_bias = 0; - __CFAssignWithWriteBarrier((void **)&array->_store, (void *)deque); - if (collectableMemory) auto_zone_release(auto_zone(), deque); - raw_buckets = (struct __CFArrayBucket *)((uint8_t *)deque + sizeof(struct __CFArrayDeque)); - CFStorageGetValues(store, CFRangeMake(0, count), raw_buckets + deque->_leftIdx); - CFRelease(store); - __CFBitfieldSetValue(((CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS], 1, 0, __kCFArrayDeque); -} - // may move deque storage, as it may need to grow deque static void __CFArrayRepositionDequeRegions(CFMutableArrayRef array, CFRange range, CFIndex newCount) { // newCount elements are going to replace the range, and the result will fit in the deque @@ -858,6 +795,8 @@ static void __CFArrayRepositionDequeRegions(CFMutableArrayRef array, CFRange ran CFIndex capacity = __CFArrayDequeRoundUpCapacity(futureCnt + wiggle); CFIndex size = sizeof(struct __CFArrayDeque) + capacity * sizeof(struct __CFArrayBucket); CFAllocatorRef allocator = __CFGetAllocator(array); + allocator = _CFConvertAllocatorToGCRefZeroEquivalent(allocator); + Boolean collectableMemory = CF_IS_COLLECTABLE_ALLOCATOR(allocator); struct __CFArrayDeque *newDeque = (struct __CFArrayDeque *)CFAllocatorAllocate(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0); if (__CFOASafe) __CFSetLastAllocationEventName(newDeque, "CFArray (store-deque)"); struct __CFArrayBucket *newBuckets = (struct __CFArrayBucket *)((uint8_t *)newDeque + sizeof(struct __CFArrayDeque)); @@ -867,12 +806,11 @@ static void __CFArrayRepositionDequeRegions(CFMutableArrayRef array, CFRange ran CFIndex newC0 = newL + A + newCount; newDeque->_leftIdx = newL; newDeque->_capacity = capacity; - newDeque->_bias = 0; if (0 < A) objc_memmove_collectable(newBuckets + newL, buckets + oldL, A * sizeof(struct __CFArrayBucket)); if (0 < C) objc_memmove_collectable(newBuckets + newC0, buckets + oldC0, C * sizeof(struct __CFArrayBucket)); - if (deque) _CFAllocatorDeallocateGC(allocator, deque); __CFAssignWithWriteBarrier((void **)&array->_store, (void *)newDeque); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) auto_zone_release(auto_zone(), newDeque); + if (!collectableMemory && deque) CFAllocatorDeallocate(allocator, deque); +//printf("3: array %p store is now %p (%lx)\n", array, array->_store, *(unsigned long *)(array->_store)); return; } @@ -900,13 +838,7 @@ static void __CFArrayRepositionDequeRegions(CFMutableArrayRef array, CFRange ran // re-center everything CFIndex oldL = L; CFIndex newL = (L + R - numNewElems) / 2; - CFIndex oldBias = deque->_bias; - deque->_bias = (newL < oldL) ? -1 : 1; - if (oldBias < 0) { - newL = newL - newL / 2; - } else if (0 < oldBias) { - newL = newL + newL / 2; - } + newL = newL - newL / 2; CFIndex oldC0 = oldL + A + B; CFIndex newC0 = newL + A + newCount; deque->_leftIdx = newL; @@ -950,6 +882,7 @@ void _CFArraySetCapacity(CFMutableArrayRef array, CFIndex cap) { CFIndex capacity = __CFArrayDequeRoundUpCapacity(cap); CFIndex size = sizeof(struct __CFArrayDeque) + capacity * sizeof(struct __CFArrayBucket); CFAllocatorRef allocator = __CFGetAllocator(array); + allocator = _CFConvertAllocatorToGCRefZeroEquivalent(allocator); Boolean collectableMemory = CF_IS_COLLECTABLE_ALLOCATOR(allocator); if (NULL == deque) { deque = (struct __CFArrayDeque *)CFAllocatorAllocate(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0); @@ -962,14 +895,12 @@ void _CFArraySetCapacity(CFMutableArrayRef array, CFIndex cap) { deque = (struct __CFArrayDeque *)CFAllocatorAllocate(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0); if (NULL == deque) __CFArrayHandleOutOfMemory(array, size); objc_memmove_collectable(deque, olddeque, sizeof(struct __CFArrayDeque) + oldcap * sizeof(struct __CFArrayBucket)); - _CFAllocatorDeallocateGC(allocator, olddeque); + if (!collectableMemory) CFAllocatorDeallocate(allocator, olddeque); if (__CFOASafe) __CFSetLastAllocationEventName(deque, "CFArray (store-deque)"); } deque->_capacity = capacity; - deque->_bias = 0; __CFAssignWithWriteBarrier((void **)&array->_store, (void *)deque); - if (collectableMemory) auto_zone_release(auto_zone(), deque); - } + } END_MUTATION(array); } @@ -990,18 +921,17 @@ void _CFArrayReplaceValues(CFMutableArrayRef array, CFRange range, const void ** CHECK_FOR_MUTATION(array); BEGIN_MUTATION(array); const CFArrayCallBacks *cb; - CFAllocatorRef allocator; CFIndex idx, cnt, futureCnt; const void **newv, *buffer[256]; cnt = __CFArrayGetCount(array); futureCnt = cnt - range.length + newCount; CFAssert1(newCount <= futureCnt, __kCFLogAssertion, "%s(): internal error 1", __PRETTY_FUNCTION__); cb = __CFArrayGetCallBacks(array); - allocator = __CFGetAllocator(array); + CFAllocatorRef allocator = __CFGetAllocator(array); /* Retain new values if needed, possibly allocating a temporary buffer for them */ if (NULL != cb->retain && !hasBeenFinalized(array)) { - newv = (newCount <= 256) ? (const void **)buffer : (const void **)CFAllocatorAllocate(allocator, newCount * sizeof(void *), 0); // GC OK + newv = (newCount <= 256) ? (const void **)buffer : (const void **)CFAllocatorAllocate(kCFAllocatorSystemDefault, newCount * sizeof(void *), 0); // GC OK if (newv != buffer && __CFOASafe) __CFSetLastAllocationEventName(newv, "CFArray (temp)"); for (idx = 0; idx < newCount; idx++) { newv[idx] = (void *)INVOKE_CALLBACK2(cb->retain, allocator, (void *)newValues[idx]); @@ -1025,58 +955,29 @@ void _CFArrayReplaceValues(CFMutableArrayRef array, CFRange range, const void ** __CFArrayReleaseValues(array, range, false); } // region B elements are now "dead" - if (__kCFArrayStorage == __CFArrayGetType(array)) { - CFStorageRef store = (CFStorageRef)array->_store; - // reposition regions A and C for new region B elements in gap - if (range.length < newCount) { - CFStorageInsertValues(store, CFRangeMake(range.location + range.length, newCount - range.length)); - } else if (newCount < range.length) { - CFStorageDeleteValues(store, CFRangeMake(range.location + newCount, range.length - newCount)); - } - if (futureCnt <= __CF_MAX_BUCKETS_PER_DEQUE / 2) { - __CFArrayConvertStoreToDeque(array); - } + if (0) { } else if (NULL == array->_store) { - if (__CF_MAX_BUCKETS_PER_DEQUE <= futureCnt) { - CFStorageRef store = CFStorageCreate(allocator, sizeof(const void *)); - if (! isStrongMemory(array)) _CFStorageSetWeak(store); - if (__CFOASafe) __CFSetLastAllocationEventName(store, "CFArray (store-storage)"); - __CFAssignWithWriteBarrier((void **)&array->_store, (void *)store); - CFMakeCollectable(store); - CFStorageInsertValues(store, CFRangeMake(0, newCount)); - __CFBitfieldSetValue(((CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS], 1, 0, __kCFArrayStorage); + if (0) { } else if (0 <= futureCnt) { struct __CFArrayDeque *deque; CFIndex capacity = __CFArrayDequeRoundUpCapacity(futureCnt); CFIndex size = sizeof(struct __CFArrayDeque) + capacity * sizeof(struct __CFArrayBucket); - deque = (struct __CFArrayDeque *)CFAllocatorAllocate(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0); + deque = (struct __CFArrayDeque *)CFAllocatorAllocate(_CFConvertAllocatorToGCRefZeroEquivalent(allocator), size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0); if (__CFOASafe) __CFSetLastAllocationEventName(deque, "CFArray (store-deque)"); deque->_leftIdx = (capacity - newCount) / 2; deque->_capacity = capacity; - deque->_bias = 0; __CFAssignWithWriteBarrier((void **)&array->_store, (void *)deque); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) auto_zone_release(auto_zone(), deque); // GC: now safe to unroot the array body. } } else { // Deque // reposition regions A and C for new region B elements in gap - if (__CF_MAX_BUCKETS_PER_DEQUE <= futureCnt) { - CFStorageRef store; - __CFArrayConvertDequeToStore(array); - store = (CFStorageRef)array->_store; - if (range.length < newCount) { - CFStorageInsertValues(store, CFRangeMake(range.location + range.length, newCount - range.length)); - } else if (newCount < range.length) { // this won't happen, but is here for completeness - CFStorageDeleteValues(store, CFRangeMake(range.location + newCount, range.length - newCount)); - } + if (0) { } else if (range.length != newCount) { __CFArrayRepositionDequeRegions(array, range, newCount); } } // copy in new region B elements if (0 < newCount) { - if (__kCFArrayStorage == __CFArrayGetType(array)) { - CFStorageRef store = (CFStorageRef)array->_store; - CFStorageReplaceValues(store, CFRangeMake(range.location, newCount), newv); + if (0) { } else { // Deque struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store; struct __CFArrayBucket *raw_buckets = (struct __CFArrayBucket *)((uint8_t *)deque + sizeof(struct __CFArrayDeque)); @@ -1084,7 +985,7 @@ void _CFArrayReplaceValues(CFMutableArrayRef array, CFRange range, const void ** } } __CFArraySetCount(array, futureCnt); - if (newv != buffer && newv != newValues) CFAllocatorDeallocate(allocator, newv); + if (newv != buffer && newv != newValues) CFAllocatorDeallocate(kCFAllocatorSystemDefault, newv); END_MUTATION(array); } @@ -1099,123 +1000,107 @@ static CFComparisonResult __CFArrayCompareValues(const void *v1, const void *v2, return (CFComparisonResult)(INVOKE_CALLBACK3(context->func, *val1, *val2, context->context)); } +CF_INLINE void __CFZSort(CFMutableArrayRef array, CFRange range, CFComparatorFunction comparator, void *context) { + CFIndex cnt = range.length; + while (1 < cnt) { + for (CFIndex idx = range.location; idx < range.location + cnt - 1; idx++) { + const void *a = CFArrayGetValueAtIndex(array, idx); + const void *b = CFArrayGetValueAtIndex(array, idx + 1); + if ((CFComparisonResult)(INVOKE_CALLBACK3(comparator, b, a, context)) < 0) { + CFArrayExchangeValuesAtIndices(array, idx, idx + 1); + } + } + cnt--; + } +} + +__private_extern__ void _CFArraySortValues(CFMutableArrayRef array, CFComparatorFunction comparator, void *context) { + CFRange range = {0, CFArrayGetCount(array)}; + if (range.length < 2) { + return; + } + // implemented abstractly, careful! + const void **values, *buffer[256]; + values = (range.length <= 256) ? (const void **)buffer : (const void **)CFAllocatorAllocate(kCFAllocatorSystemDefault, range.length * sizeof(void *), 0); // GC OK + CFArrayGetValues(array, range, values); + struct _acompareContext ctx; + ctx.func = comparator; + ctx.context = context; + CFQSortArray(values, range.length, sizeof(void *), (CFComparatorFunction)__CFArrayCompareValues, &ctx); + CFArrayReplaceValues(array, range, values, range.length); + if (values != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, values); +} + void CFArraySortValues(CFMutableArrayRef array, CFRange range, CFComparatorFunction comparator, void *context) { FAULT_CALLBACK((void **)&(comparator)); - CF_OBJC_FUNCDISPATCH3(__kCFArrayTypeID, void, array, "sortUsingFunction:context:range:", comparator, context, range); - __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); - CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); CFAssert1(NULL != comparator, __kCFLogAssertion, "%s(): pointer to comparator function may not be NULL", __PRETTY_FUNCTION__); - CHECK_FOR_MUTATION(array); - BEGIN_MUTATION(array); - array->_mutations++; - - if (1 < range.length) { - struct _acompareContext ctx; - struct __CFArrayBucket *bucket; - ctx.func = comparator; - ctx.context = context; - switch (__CFArrayGetType(array)) { - case __kCFArrayDeque: - bucket = __CFArrayGetBucketsPtr(array) + range.location; - CFQSortArray(bucket, range.length, sizeof(void *), (CFComparatorFunction)__CFArrayCompareValues, &ctx); - break; - case __kCFArrayStorage: { - CFStorageRef store = (CFStorageRef)array->_store; - const void **values, *buffer[256]; - values = (range.length <= 256) ? (const void **)buffer : (const void **)CFAllocatorAllocate(kCFAllocatorSystemDefault, range.length * sizeof(void *), 0); // GC OK - if (values != buffer && __CFOASafe) __CFSetLastAllocationEventName(values, "CFArray (temp)"); - CFStorageGetValues(store, range, values); - CFQSortArray(values, range.length, sizeof(void *), (CFComparatorFunction)__CFArrayCompareValues, &ctx); - CFStorageReplaceValues(store, range, values); - if (values != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, values); // GC OK - break; - } - } + Boolean immutable = false; + if (CF_IS_OBJC(__kCFArrayTypeID, array)) { + BOOL result; + CF_OBJC_CALL1(BOOL, result, array, "isKindOfClass:", objc_lookUpClass("NSMutableArray")); + immutable = !result; + } else if (__kCFArrayImmutable == __CFArrayGetType(array)) { + immutable = true; } - END_MUTATION(array); + const CFArrayCallBacks *cb = NULL; + if (CF_IS_OBJC(__kCFArrayTypeID, array)) { + cb = &kCFTypeArrayCallBacks; + } else { + cb = __CFArrayGetCallBacks(array); + } + if (!immutable && ((cb->retain && !cb->release) || (!cb->retain && cb->release))) { + __CFZSort(array, range, comparator, context); + return; + } + if (range.length < 2) { + return; + } + // implemented abstractly, careful! + const void **values, *buffer[256]; + values = (range.length <= 256) ? (const void **)buffer : (const void **)CFAllocatorAllocate(kCFAllocatorSystemDefault, range.length * sizeof(void *), 0); // GC OK + CFArrayGetValues(array, range, values); + struct _acompareContext ctx; + ctx.func = comparator; + ctx.context = context; + CFQSortArray(values, range.length, sizeof(void *), (CFComparatorFunction)__CFArrayCompareValues, &ctx); + if (!immutable) CFArrayReplaceValues(array, range, values, range.length); + if (values != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, values); } CFIndex CFArrayBSearchValues(CFArrayRef array, CFRange range, const void *value, CFComparatorFunction comparator, void *context) { - __CFGenericValidateType(array, __kCFArrayTypeID); + FAULT_CALLBACK((void **)&(comparator)); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); CFAssert1(NULL != comparator, __kCFLogAssertion, "%s(): pointer to comparator function may not be NULL", __PRETTY_FUNCTION__); - bool isObjC = CF_IS_OBJC(__kCFArrayTypeID, array); - FAULT_CALLBACK((void **)&(comparator)); - if (!isObjC) CHECK_FOR_MUTATION(array); - CFIndex idx = 0; + // implemented abstractly, careful! if (range.length <= 0) return range.location; - if (isObjC || __kCFArrayStorage == __CFArrayGetType(array)) { - const void *item; - SInt32 lg; - item = CFArrayGetValueAtIndex(array, range.location + range.length - 1); + const void *item = CFArrayGetValueAtIndex(array, range.location + range.length - 1); + if ((CFComparisonResult)(INVOKE_CALLBACK3(comparator, item, value, context)) < 0) { + return range.location + range.length; + } + item = CFArrayGetValueAtIndex(array, range.location); + if ((CFComparisonResult)(INVOKE_CALLBACK3(comparator, value, item, context)) < 0) { + return range.location; + } + SInt32 lg = flsl(range.length) - 1; // lg2(range.length) + item = CFArrayGetValueAtIndex(array, range.location + -1 + (1 << lg)); + CFIndex idx = range.location + ((CFComparisonResult)(INVOKE_CALLBACK3(comparator, item, value, context)) < 0) ? range.length - (1 << lg) : -1; + while (lg--) { + item = CFArrayGetValueAtIndex(array, range.location + idx + (1 << lg)); if ((CFComparisonResult)(INVOKE_CALLBACK3(comparator, item, value, context)) < 0) { - return range.location + range.length; + idx += (1 << lg); } - item = CFArrayGetValueAtIndex(array, range.location); - if ((CFComparisonResult)(INVOKE_CALLBACK3(comparator, value, item, context)) < 0) { - return range.location; - } - lg = flsl(range.length) - 1; // lg2(range.length) - item = CFArrayGetValueAtIndex(array, range.location + -1 + (1 << lg)); - idx = range.location + ((CFComparisonResult)(INVOKE_CALLBACK3(comparator, item, value, context)) < 0) ? range.length - (1 << lg) : -1; - while (lg--) { - item = CFArrayGetValueAtIndex(array, range.location + idx + (1 << lg)); - if ((CFComparisonResult)(INVOKE_CALLBACK3(comparator, item, value, context)) < 0) { - idx += (1 << lg); - } - } - idx++; - } else { - struct _acompareContext ctx; - ctx.func = comparator; - ctx.context = context; - idx = CFBSearch(&value, sizeof(void *), __CFArrayGetBucketsPtr(array) + range.location, range.length, (CFComparatorFunction)__CFArrayCompareValues, &ctx); } + idx++; return idx + range.location; } void CFArrayAppendArray(CFMutableArrayRef array, CFArrayRef otherArray, CFRange otherRange) { - CFIndex idx; - __CFGenericValidateType(array, __kCFArrayTypeID); - __CFGenericValidateType(otherArray, __kCFArrayTypeID); - CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); __CFArrayValidateRange(otherArray, otherRange, __PRETTY_FUNCTION__); - CHECK_FOR_MUTATION(array); - for (idx = otherRange.location; idx < otherRange.location + otherRange.length; idx++) { + // implemented abstractly, careful! + for (CFIndex idx = otherRange.location; idx < otherRange.location + otherRange.length; idx++) { CFArrayAppendValue(array, CFArrayGetValueAtIndex(otherArray, idx)); } } -// ----====---- ----====---- ----====---- ----====---- - -__private_extern__ Boolean __CFArray6130(CFMutableArrayRef array, CFIndex *p, void **list) { - if (CF_IS_OBJC(__kCFArrayTypeID, array)) return false; - CHECK_FOR_MUTATION(array); - if (__kCFArrayStorage == __CFArrayGetType(array)) { - CFStorageRef store = (CFStorageRef)array->_store; - CFRange range = {0, 0}; - void *bytes = NULL; - for (CFIndex idx = 0; idx < __CFArrayGetCount(array); idx++) { - if (range.location + range.length - 1 < idx) { - bytes = CFStorageGetValueAtIndex(store, idx, &range); - } - ((void **)bytes)[idx - range.location] = list[p[idx]]; - } - } else if (kCFUseCollectableAllocator) { // Deque - struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store; - struct __CFArrayBucket *raw_buckets = (struct __CFArrayBucket *)((uint8_t *)deque + sizeof(struct __CFArrayDeque)) + deque->_leftIdx; - for (CFIndex idx = 0; idx < __CFArrayGetCount(array); idx++) { - struct __CFArrayBucket *dest = raw_buckets + idx; - objc_memmove_collectable(dest, list + p[idx], sizeof(struct __CFArrayBucket)); - } - } else { // Deque - struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store; - struct __CFArrayBucket *raw_buckets = (struct __CFArrayBucket *)((uint8_t *)deque + sizeof(struct __CFArrayDeque)) + deque->_leftIdx; - for (CFIndex idx = 0; idx < __CFArrayGetCount(array); idx++) { - raw_buckets[idx]._item = list[p[idx]]; - } - } - return true; -} diff --git a/CFArray.h b/CFArray.h index 6e1f843..1dab6c8 100644 --- a/CFArray.h +++ b/CFArray.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFArray.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ /*! diff --git a/CFBag.c b/CFBag.c index facf851..5da22be 100644 --- a/CFBag.c +++ b/CFBag.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFBag.c - Copyright 1998-2008, Apple, Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane Machine generated from Notes/HashingCode.template */ @@ -46,6 +46,7 @@ const CFBagKeyCallBacks kCFTypeBagKeyCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; const CFBagKeyCallBacks kCFCopyStringBagKeyCallBacks = {0, __CFStringCollectionCopy, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; const CFBagValueCallBacks kCFTypeBagValueCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual}; +__private_extern__ const CFBagValueCallBacks kCFTypeBagValueCompactableCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual}; static const CFBagKeyCallBacks __kCFNullBagKeyCallBacks = {0, NULL, NULL, NULL, NULL, NULL}; static const CFBagValueCallBacks __kCFNullBagValueCallBacks = {0, NULL, NULL, NULL, NULL}; @@ -131,95 +132,232 @@ CFTypeID CFBagGetTypeID(void) { return __kCFBagTypeID; } -static uintptr_t __CFBagCallback(CFBasicHashRef ht, uint8_t op, uintptr_t a1, uintptr_t a2, CFBasicHashCallbacks *cb) { - switch (op) { - case kCFBasicHashCallbackOpCopyCallbacks: { - CFBasicHashCallbacks *newcb = NULL; - if (CF_IS_COLLECTABLE_ALLOCATOR((CFAllocatorRef)a1)) { - newcb = (CFBasicHashCallbacks *)auto_zone_allocate_object(auto_zone(), 10 * sizeof(void *), AUTO_MEMORY_UNSCANNED, true, false); - } else { - newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate((CFAllocatorRef)a1, 10 * sizeof(void *), 0); - } - if (!newcb) HALT; - memmove(newcb, (void *)cb, 10 * sizeof(void *)); - return (uintptr_t)newcb; - } - case kCFBasicHashCallbackOpFreeCallbacks: { - if (CF_IS_COLLECTABLE_ALLOCATOR((CFAllocatorRef)a1)) { - auto_zone_release(auto_zone(), cb); - } else { - CFAllocatorDeallocate((CFAllocatorRef)a1, cb); - } - return 0; - } - case kCFBasicHashCallbackOpRetainValue: { - const_any_pointer_t (*value_retain)(CFAllocatorRef, const_any_pointer_t) = (const_any_pointer_t (*)(CFAllocatorRef, const_any_pointer_t))cb->context[0]; - if (NULL == value_retain) return a1; - return (uintptr_t)INVOKE_CALLBACK2(value_retain, CFGetAllocator(ht), (const_any_pointer_t)a1); - } - case kCFBasicHashCallbackOpRetainKey: { - const_any_pointer_t (*key_retain)(CFAllocatorRef, const_any_pointer_t) = (const_any_pointer_t (*)(CFAllocatorRef, const_any_pointer_t))cb->context[1]; - if (NULL == key_retain) return a1; - return (uintptr_t)INVOKE_CALLBACK2(key_retain, CFGetAllocator(ht), (const_any_pointer_t)a1); - } - case kCFBasicHashCallbackOpReleaseValue: { - void (*value_release)(CFAllocatorRef, const_any_pointer_t) = (void (*)(CFAllocatorRef, const_any_pointer_t))cb->context[2]; - if (NULL != value_release) INVOKE_CALLBACK2(value_release, CFGetAllocator(ht), (const_any_pointer_t)a1); - return 0; - } - case kCFBasicHashCallbackOpReleaseKey: { - void (*key_release)(CFAllocatorRef, const_any_pointer_t) = (void (*)(CFAllocatorRef, const_any_pointer_t))cb->context[3]; - if (NULL != key_release) INVOKE_CALLBACK2(key_release, CFGetAllocator(ht), (const_any_pointer_t)a1); - return 0; - } - case kCFBasicHashCallbackOpValueEqual: { - Boolean (*value_equal)(const_any_pointer_t, const_any_pointer_t) = (Boolean (*)(const_any_pointer_t, const_any_pointer_t))cb->context[4]; - if (NULL == value_equal) return (a1 == a2); - return INVOKE_CALLBACK2(value_equal, (const_any_pointer_t)a1, (const_any_pointer_t)a2) ? 1 : 0; - } - case kCFBasicHashCallbackOpKeyEqual: { - Boolean (*key_equal)(const_any_pointer_t, const_any_pointer_t) = (Boolean (*)(const_any_pointer_t, const_any_pointer_t))cb->context[5]; - if (NULL == key_equal) return (a1 == a2); - return INVOKE_CALLBACK2(key_equal, (const_any_pointer_t)a1, (const_any_pointer_t)a2) ? 1 : 0; - } - case kCFBasicHashCallbackOpHashKey: { - CFHashCode (*hash)(const_any_pointer_t) = (CFHashCode (*)(const_any_pointer_t))cb->context[6]; - if (NULL == hash) return a1; - return (uintptr_t)INVOKE_CALLBACK1(hash, (const_any_pointer_t)a1); - } - case kCFBasicHashCallbackOpDescribeValue: { - CFStringRef (*value_describe)(const_any_pointer_t) = (CFStringRef (*)(const_any_pointer_t))cb->context[7]; - if (NULL == value_describe) return (uintptr_t)CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (const_any_pointer_t)a1); - return (uintptr_t)INVOKE_CALLBACK1(value_describe, (const_any_pointer_t)a1); - } - case kCFBasicHashCallbackOpDescribeKey: { - CFStringRef (*key_describe)(const_any_pointer_t) = (CFStringRef (*)(const_any_pointer_t))cb->context[8]; - if (NULL == key_describe) return (uintptr_t)CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (const_any_pointer_t)a1); - return (uintptr_t)INVOKE_CALLBACK1(key_describe, (const_any_pointer_t)a1); +#define GCRETAIN(A, B) kCFTypeSetCallBacks.retain(A, B) +#define GCRELEASE(A, B) kCFTypeSetCallBacks.release(A, B) + +static uintptr_t __CFBagStandardRetainValue(CFConstBasicHashRef ht, uintptr_t stack_value) { + if (CFBasicHashGetSpecialBits(ht) & 0x0100) return stack_value; + return (CFBasicHashHasStrongValues(ht)) ? (uintptr_t)GCRETAIN(kCFAllocatorSystemDefault, (CFTypeRef)stack_value) : (uintptr_t)CFRetain((CFTypeRef)stack_value); +} + +static uintptr_t __CFBagStandardRetainKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + if (CFBasicHashGetSpecialBits(ht) & 0x0001) return stack_key; + return (CFBasicHashHasStrongKeys(ht)) ? (uintptr_t)GCRETAIN(kCFAllocatorSystemDefault, (CFTypeRef)stack_key) : (uintptr_t)CFRetain((CFTypeRef)stack_key); +} + +static void __CFBagStandardReleaseValue(CFConstBasicHashRef ht, uintptr_t stack_value) { + if (CFBasicHashGetSpecialBits(ht) & 0x0200) return; + if (CFBasicHashHasStrongValues(ht)) GCRELEASE(kCFAllocatorSystemDefault, (CFTypeRef)stack_value); else CFRelease((CFTypeRef)stack_value); +} + +static void __CFBagStandardReleaseKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + if (CFBasicHashGetSpecialBits(ht) & 0x0002) return; + if (CFBasicHashHasStrongKeys(ht)) GCRELEASE(kCFAllocatorSystemDefault, (CFTypeRef)stack_key); else CFRelease((CFTypeRef)stack_key); +} + +static Boolean __CFBagStandardEquateValues(CFConstBasicHashRef ht, uintptr_t coll_value1, uintptr_t stack_value2) { + if (CFBasicHashGetSpecialBits(ht) & 0x0400) return coll_value1 == stack_value2; + return CFEqual((CFTypeRef)coll_value1, (CFTypeRef)stack_value2); +} + +static Boolean __CFBagStandardEquateKeys(CFConstBasicHashRef ht, uintptr_t coll_key1, uintptr_t stack_key2) { + if (CFBasicHashGetSpecialBits(ht) & 0x0004) return coll_key1 == stack_key2; + return CFEqual((CFTypeRef)coll_key1, (CFTypeRef)stack_key2); +} + +static uintptr_t __CFBagStandardHashKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + if (CFBasicHashGetSpecialBits(ht) & 0x0008) return stack_key; + return (uintptr_t)CFHash((CFTypeRef)stack_key); +} + +static uintptr_t __CFBagStandardGetIndirectKey(CFConstBasicHashRef ht, uintptr_t coll_value) { + return 0; +} + +static CFStringRef __CFBagStandardCopyValueDescription(CFConstBasicHashRef ht, uintptr_t stack_value) { + if (CFBasicHashGetSpecialBits(ht) & 0x0800) return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)stack_value); + return CFCopyDescription((CFTypeRef)stack_value); +} + +static CFStringRef __CFBagStandardCopyKeyDescription(CFConstBasicHashRef ht, uintptr_t stack_key) { + if (CFBasicHashGetSpecialBits(ht) & 0x0010) return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)stack_key); + return CFCopyDescription((CFTypeRef)stack_key); +} + +static CFBasicHashCallbacks *__CFBagStandardCopyCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb); +static void __CFBagStandardFreeCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb); + +static const CFBasicHashCallbacks CFBagStandardCallbacks = { + __CFBagStandardCopyCallbacks, + __CFBagStandardFreeCallbacks, + __CFBagStandardRetainValue, + __CFBagStandardRetainKey, + __CFBagStandardReleaseValue, + __CFBagStandardReleaseKey, + __CFBagStandardEquateValues, + __CFBagStandardEquateKeys, + __CFBagStandardHashKey, + __CFBagStandardGetIndirectKey, + __CFBagStandardCopyValueDescription, + __CFBagStandardCopyKeyDescription +}; + +static CFBasicHashCallbacks *__CFBagStandardCopyCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) { + return (CFBasicHashCallbacks *)&CFBagStandardCallbacks; +} + +static void __CFBagStandardFreeCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) { +} + + +static CFBasicHashCallbacks *__CFBagCopyCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) { + CFBasicHashCallbacks *newcb = NULL; + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + newcb = (CFBasicHashCallbacks *)auto_zone_allocate_object(objc_collectableZone(), sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), AUTO_MEMORY_UNSCANNED, false, false); + } else { + newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), 0); } + if (!newcb) HALT; + memmove(newcb, (void *)cb, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *)); + return newcb; +} + +static void __CFBagFreeCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) { + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + } else { + CFAllocatorDeallocate(allocator, cb); } +} + +static uintptr_t __CFBagRetainValue(CFConstBasicHashRef ht, uintptr_t stack_value) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + const_any_pointer_t (*value_retain)(CFAllocatorRef, const_any_pointer_t) = (const_any_pointer_t (*)(CFAllocatorRef, const_any_pointer_t))cb->context[0]; + if (NULL == value_retain) return stack_value; + return (uintptr_t)INVOKE_CALLBACK2(value_retain, CFGetAllocator(ht), (const_any_pointer_t)stack_value); +} + +static uintptr_t __CFBagRetainKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + const_any_pointer_t (*key_retain)(CFAllocatorRef, const_any_pointer_t) = (const_any_pointer_t (*)(CFAllocatorRef, const_any_pointer_t))cb->context[1]; + if (NULL == key_retain) return stack_key; + return (uintptr_t)INVOKE_CALLBACK2(key_retain, CFGetAllocator(ht), (const_any_pointer_t)stack_key); +} + +static void __CFBagReleaseValue(CFConstBasicHashRef ht, uintptr_t stack_value) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + void (*value_release)(CFAllocatorRef, const_any_pointer_t) = (void (*)(CFAllocatorRef, const_any_pointer_t))cb->context[2]; + if (NULL != value_release) INVOKE_CALLBACK2(value_release, CFGetAllocator(ht), (const_any_pointer_t) stack_value); +} + +static void __CFBagReleaseKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + void (*key_release)(CFAllocatorRef, const_any_pointer_t) = (void (*)(CFAllocatorRef, const_any_pointer_t))cb->context[3]; + if (NULL != key_release) INVOKE_CALLBACK2(key_release, CFGetAllocator(ht), (const_any_pointer_t) stack_key); +} + +static Boolean __CFBagEquateValues(CFConstBasicHashRef ht, uintptr_t coll_value1, uintptr_t stack_value2) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + Boolean (*value_equal)(const_any_pointer_t, const_any_pointer_t) = (Boolean (*)(const_any_pointer_t, const_any_pointer_t))cb->context[4]; + if (NULL == value_equal) return (coll_value1 == stack_value2); + return INVOKE_CALLBACK2(value_equal, (const_any_pointer_t) coll_value1, (const_any_pointer_t) stack_value2) ? 1 : 0; +} + +static Boolean __CFBagEquateKeys(CFConstBasicHashRef ht, uintptr_t coll_key1, uintptr_t stack_key2) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + Boolean (*key_equal)(const_any_pointer_t, const_any_pointer_t) = (Boolean (*)(const_any_pointer_t, const_any_pointer_t))cb->context[5]; + if (NULL == key_equal) return (coll_key1 == stack_key2); + return INVOKE_CALLBACK2(key_equal, (const_any_pointer_t) coll_key1, (const_any_pointer_t) stack_key2) ? 1 : 0; +} + +static uintptr_t __CFBagHashKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + CFHashCode (*hash)(const_any_pointer_t) = (CFHashCode (*)(const_any_pointer_t))cb->context[6]; + if (NULL == hash) return stack_key; + return (uintptr_t)INVOKE_CALLBACK1(hash, (const_any_pointer_t) stack_key); +} + +static uintptr_t __CFBagGetIndirectKey(CFConstBasicHashRef ht, uintptr_t coll_value) { return 0; } -static CFBasicHashRef __CFBagCreateGeneric(CFAllocatorRef allocator, const CFHashKeyCallBacks *keyCallBacks, const CFHashValueCallBacks *valueCallBacks, Boolean useValueCB) { +static CFStringRef __CFBagCopyValueDescription(CFConstBasicHashRef ht, uintptr_t stack_value) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + CFStringRef (*value_describe)(const_any_pointer_t) = (CFStringRef (*)(const_any_pointer_t))cb->context[8]; + if (NULL == value_describe) return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (const_any_pointer_t) stack_value); + return (CFStringRef)INVOKE_CALLBACK1(value_describe, (const_any_pointer_t) stack_value); +} - CFBasicHashCallbacks *cb = NULL; +static CFStringRef __CFBagCopyKeyDescription(CFConstBasicHashRef ht, uintptr_t stack_key) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + CFStringRef (*key_describe)(const_any_pointer_t) = (CFStringRef (*)(const_any_pointer_t))cb->context[9]; + if (NULL == key_describe) return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (const_any_pointer_t) stack_key); + return (CFStringRef)INVOKE_CALLBACK1(key_describe, (const_any_pointer_t) stack_key); +} + +static CFBasicHashRef __CFBagCreateGeneric(CFAllocatorRef allocator, const CFHashKeyCallBacks *keyCallBacks, const CFHashValueCallBacks *valueCallBacks, Boolean useValueCB) { CFOptionFlags flags = kCFBasicHashLinearHashing; // kCFBasicHashExponentialHashing flags |= (CFDictionary ? kCFBasicHashHasKeys : 0) | (CFBag ? kCFBasicHashHasCounts : 0); + CFBasicHashCallbacks *cb = NULL; + Boolean std_cb = false; + uint16_t specialBits = 0; const_any_pointer_t (*key_retain)(CFAllocatorRef, const_any_pointer_t) = NULL; void (*key_release)(CFAllocatorRef, const_any_pointer_t) = NULL; const_any_pointer_t (*value_retain)(CFAllocatorRef, const_any_pointer_t) = NULL; void (*value_release)(CFAllocatorRef, const_any_pointer_t) = NULL; - Boolean std_cb = false; - if ((NULL == keyCallBacks || (keyCallBacks && 0 == memcmp(&__kCFNullBagKeyCallBacks, keyCallBacks, sizeof(__kCFNullBagKeyCallBacks)))) - && (!useValueCB || (NULL == valueCallBacks || (valueCallBacks && 0 == memcmp(&__kCFNullBagValueCallBacks, valueCallBacks, sizeof(__kCFNullBagValueCallBacks)))))) { - cb = (CFBasicHashCallbacks *)& CFBasicHashNullCallbacks; - } else if ((&kCFTypeBagKeyCallBacks == keyCallBacks || (keyCallBacks && 0 == memcmp(&kCFTypeBagKeyCallBacks, keyCallBacks, sizeof(kCFTypeBagKeyCallBacks)))) - && (!useValueCB || (&kCFTypeBagValueCallBacks == valueCallBacks || (valueCallBacks && 0 == memcmp(&kCFTypeBagValueCallBacks, valueCallBacks, sizeof(kCFTypeBagValueCallBacks)))))) { - std_cb = true; - cb = (CFBasicHashCallbacks *)& CFBasicHashStandardCallbacks; - } else { + + if ((NULL == keyCallBacks || 0 == keyCallBacks->version) && (!useValueCB || NULL == valueCallBacks || 0 == valueCallBacks->version)) { + Boolean keyRetainNull = NULL == keyCallBacks || NULL == keyCallBacks->retain; + Boolean keyReleaseNull = NULL == keyCallBacks || NULL == keyCallBacks->release; + Boolean keyEquateNull = NULL == keyCallBacks || NULL == keyCallBacks->equal; + Boolean keyHashNull = NULL == keyCallBacks || NULL == keyCallBacks->hash; + Boolean keyDescribeNull = NULL == keyCallBacks || NULL == keyCallBacks->copyDescription; + + Boolean valueRetainNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->retain)) || (!useValueCB && keyRetainNull); + Boolean valueReleaseNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->release)) || (!useValueCB && keyReleaseNull); + Boolean valueEquateNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->equal)) || (!useValueCB && keyEquateNull); + Boolean valueDescribeNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->copyDescription)) || (!useValueCB && keyDescribeNull); + + Boolean keyRetainStd = keyRetainNull || __CFTypeCollectionRetain == keyCallBacks->retain; + Boolean keyReleaseStd = keyReleaseNull || __CFTypeCollectionRelease == keyCallBacks->release; + Boolean keyEquateStd = keyEquateNull || CFEqual == keyCallBacks->equal; + Boolean keyHashStd = keyHashNull || CFHash == keyCallBacks->hash; + Boolean keyDescribeStd = keyDescribeNull || CFCopyDescription == keyCallBacks->copyDescription; + + Boolean valueRetainStd = (useValueCB && (valueRetainNull || __CFTypeCollectionRetain == valueCallBacks->retain)) || (!useValueCB && keyRetainStd); + Boolean valueReleaseStd = (useValueCB && (valueReleaseNull || __CFTypeCollectionRelease == valueCallBacks->release)) || (!useValueCB && keyReleaseStd); + Boolean valueEquateStd = (useValueCB && (valueEquateNull || CFEqual == valueCallBacks->equal)) || (!useValueCB && keyEquateStd); + Boolean valueDescribeStd = (useValueCB && (valueDescribeNull || CFCopyDescription == valueCallBacks->copyDescription)) || (!useValueCB && keyDescribeStd); + + if (keyRetainStd && keyReleaseStd && keyEquateStd && keyHashStd && keyDescribeStd && valueRetainStd && valueReleaseStd && valueEquateStd && valueDescribeStd) { + cb = (CFBasicHashCallbacks *)&CFBagStandardCallbacks; + if (!(keyRetainNull || keyReleaseNull || keyEquateNull || keyHashNull || keyDescribeNull || valueRetainNull || valueReleaseNull || valueEquateNull || valueDescribeNull)) { + std_cb = true; + } else { + // just set these to tickle the GC Strong logic below in a way that mimics past practice + key_retain = keyCallBacks ? keyCallBacks->retain : NULL; + key_release = keyCallBacks ? keyCallBacks->release : NULL; + if (useValueCB) { + value_retain = valueCallBacks ? valueCallBacks->retain : NULL; + value_release = valueCallBacks ? valueCallBacks->release : NULL; + } else { + value_retain = key_retain; + value_release = key_release; + } + } + if (keyRetainNull) specialBits |= 0x0001; + if (keyReleaseNull) specialBits |= 0x0002; + if (keyEquateNull) specialBits |= 0x0004; + if (keyHashNull) specialBits |= 0x0008; + if (keyDescribeNull) specialBits |= 0x0010; + if (valueRetainNull) specialBits |= 0x0100; + if (valueReleaseNull) specialBits |= 0x0200; + if (valueEquateNull) specialBits |= 0x0400; + if (valueDescribeNull) specialBits |= 0x0800; + } + } + + if (!cb) { Boolean (*key_equal)(const_any_pointer_t, const_any_pointer_t) = NULL; Boolean (*value_equal)(const_any_pointer_t, const_any_pointer_t) = NULL; CFStringRef (*key_describe)(const_any_pointer_t) = NULL; @@ -241,24 +379,26 @@ static CFBasicHashRef __CFBagCreateGeneric(CFAllocatorRef allocator, const CFHas value_describe = key_describe; } hash_key = keyCallBacks ? keyCallBacks->hash : NULL; - FAULT_CALLBACK((void **)&key_retain); - FAULT_CALLBACK((void **)&key_release); - FAULT_CALLBACK((void **)&value_retain); - FAULT_CALLBACK((void **)&value_release); - FAULT_CALLBACK((void **)&key_equal); - FAULT_CALLBACK((void **)&value_equal); - FAULT_CALLBACK((void **)&key_describe); - FAULT_CALLBACK((void **)&value_describe); - FAULT_CALLBACK((void **)&hash_key); CFBasicHashCallbacks *newcb = NULL; if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - newcb = (CFBasicHashCallbacks *)auto_zone_allocate_object(auto_zone(), 10 * sizeof(void *), AUTO_MEMORY_UNSCANNED, true, false); + newcb = (CFBasicHashCallbacks *)auto_zone_allocate_object(objc_collectableZone(), sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), AUTO_MEMORY_UNSCANNED, false, false); } else { - newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, 10 * sizeof(void *), 0); + newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), 0); } if (!newcb) HALT; - newcb->func = (CFBasicHashCallbackType)__CFBagCallback; + newcb->copyCallbacks = __CFBagCopyCallbacks; + newcb->freeCallbacks = __CFBagFreeCallbacks; + newcb->retainValue = __CFBagRetainValue; + newcb->retainKey = __CFBagRetainKey; + newcb->releaseValue = __CFBagReleaseValue; + newcb->releaseKey = __CFBagReleaseKey; + newcb->equateValues = __CFBagEquateValues; + newcb->equateKeys = __CFBagEquateKeys; + newcb->hashKey = __CFBagHashKey; + newcb->getIndirectKey = __CFBagGetIndirectKey; + newcb->copyValueDescription = __CFBagCopyValueDescription; + newcb->copyKeyDescription = __CFBagCopyKeyDescription; newcb->context[0] = (uintptr_t)value_retain; newcb->context[1] = (uintptr_t)key_retain; newcb->context[2] = (uintptr_t)value_release; @@ -266,8 +406,8 @@ static CFBasicHashRef __CFBagCreateGeneric(CFAllocatorRef allocator, const CFHas newcb->context[4] = (uintptr_t)value_equal; newcb->context[5] = (uintptr_t)key_equal; newcb->context[6] = (uintptr_t)hash_key; - newcb->context[7] = (uintptr_t)value_describe; - newcb->context[8] = (uintptr_t)key_describe; + newcb->context[8] = (uintptr_t)value_describe; + newcb->context[9] = (uintptr_t)key_describe; cb = newcb; } @@ -278,9 +418,43 @@ static CFBasicHashRef __CFBagCreateGeneric(CFAllocatorRef allocator, const CFHas if (std_cb || key_retain != NULL || key_release != NULL) { flags |= kCFBasicHashStrongKeys; } +#if CFDictionary + if (valueCallBacks == &kCFTypeDictionaryValueCompactableCallBacks) { + // Foundation allocated collections will have compactable values + flags |= kCFBasicHashCompactableValues; + } +#endif } - return CFBasicHashCreate(allocator, flags, cb); + CFBasicHashRef ht = CFBasicHashCreate(allocator, flags, cb); + CFBasicHashSetSpecialBits(ht, specialBits); + return ht; +} + +#if CFDictionary +__private_extern__ CFHashRef __CFBagCreateTransfer(CFAllocatorRef allocator, const_any_pointer_t *klist, const_any_pointer_t *vlist, CFIndex numValues) { +#endif +#if CFSet || CFBag +__private_extern__ CFHashRef __CFBagCreateTransfer(CFAllocatorRef allocator, const_any_pointer_t *klist, CFIndex numValues) { + const_any_pointer_t *vlist = klist; +#endif + CFTypeID typeID = CFBagGetTypeID(); + CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__, numValues); + CFOptionFlags flags = kCFBasicHashLinearHashing; // kCFBasicHashExponentialHashing + flags |= (CFDictionary ? kCFBasicHashHasKeys : 0) | (CFBag ? kCFBasicHashHasCounts : 0); + CFBasicHashCallbacks *cb = (CFBasicHashCallbacks *)&CFBagStandardCallbacks; + CFBasicHashRef ht = CFBasicHashCreate(allocator, flags, cb); + CFBasicHashSetSpecialBits(ht, 0x0303); + if (0 < numValues) CFBasicHashSetCapacity(ht, numValues); + for (CFIndex idx = 0; idx < numValues; idx++) { + CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]); + } + CFBasicHashSetSpecialBits(ht, 0x0000); + CFBasicHashMakeImmutable(ht); + *(uintptr_t *)ht = __CFISAForTypeID(typeID); + _CFRuntimeSetInstanceTypeID(ht, typeID); + if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFBag (immutable)"); + return (CFHashRef)ht; } #if CFDictionary @@ -429,8 +603,8 @@ const_any_pointer_t CFBagGetValue(CFHashRef hc, const_any_pointer_t key) { } 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_FUNCDISPATCH2(__kCFBagTypeID, Boolean, hc, "__getValue:forKey:", (any_t *)value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, Boolean, hc, "__getValue:forObj:", (any_t *)value, key); __CFGenericValidateType(hc, __kCFBagTypeID); CFBasicHashBucket bkt = CFBasicHashFindBucket((CFBasicHashRef)hc, (uintptr_t)key); if (0 < bkt.count) { @@ -489,7 +663,8 @@ void CFBagGetValues(CFHashRef hc, const_any_pointer_t *keybuf) { __CFGenericValidateType(hc, __kCFBagTypeID); if (kCFUseCollectableAllocator) { CFOptionFlags flags = CFBasicHashGetFlags((CFBasicHashRef)hc); - __block const_any_pointer_t *keys = keybuf, *values = valuebuf; + __block const_any_pointer_t *keys = keybuf; + __block const_any_pointer_t *values = valuebuf; CFBasicHashApply((CFBasicHashRef)hc, ^(CFBasicHashBucket bkt) { for (CFIndex cnt = bkt.count; cnt--;) { if (keybuf && (flags & kCFBasicHashStrongKeys)) { __CFAssignWithWriteBarrier((void **)keys, (void *)bkt.weak_key); keys++; } @@ -500,14 +675,14 @@ void CFBagGetValues(CFHashRef hc, const_any_pointer_t *keybuf) { return (Boolean)true; }); } else { - CFBasicHashGetElements((CFBasicHashRef)hc, CFBagGetCount(hc), (uintptr_t *)valuebuf, NULL, (uintptr_t *)keybuf, NULL); + CFBasicHashGetElements((CFBasicHashRef)hc, CFBagGetCount(hc), (uintptr_t *)valuebuf, (uintptr_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_FUNCDISPATCH2(__kCFBagTypeID, void, hc, "__apply:context:", applier, context); + if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFBagTypeID, void, hc, "__applyValues:context:", applier, context); __CFGenericValidateType(hc, __kCFBagTypeID); CFBasicHashApply((CFBasicHashRef)hc, ^(CFBasicHashBucket bkt) { #if CFDictionary @@ -620,7 +795,7 @@ 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 (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFBagTypeID, void, hc, "setObject:", key); __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 d56d54e..2598b21 100644 --- a/CFBag.h +++ b/CFBag.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFBag.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBAG__) diff --git a/CFBase.c b/CFBase.c index 584dc4b..195d2da 100644 --- a/CFBase.c +++ b/CFBase.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFBase.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ @@ -49,22 +49,29 @@ struct __CFAllocator { - - CFRuntimeBase _base; #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - 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 */ - void *(*valloc)(struct _malloc_zone_t *zone, size_t size); /* same as malloc, but block returned is set to zero and is guaranteed to be page aligned */ - void (*free)(struct _malloc_zone_t *zone, void *ptr); - void *(*realloc)(struct _malloc_zone_t *zone, void *ptr, size_t size); - void (*destroy)(struct _malloc_zone_t *zone); /* zone is destroyed and all memory reclaimed */ + 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 */ + void *(*valloc)(struct _malloc_zone_t *zone, size_t size); /* same as malloc, but block returned is set to zero and is guaranteed to be page aligned */ + void (*free)(struct _malloc_zone_t *zone, void *ptr); + void *(*realloc)(struct _malloc_zone_t *zone, void *ptr, size_t size); + void (*destroy)(struct _malloc_zone_t *zone); /* zone is destroyed and all memory reclaimed */ const char *zone_name; - unsigned (*batch_malloc)(struct _malloc_zone_t *zone, size_t size, void **results, unsigned num_requested); /* given a size, returns pointers capable of holding that size; returns the number of pointers allocated (maybe 0 or less than num_requested) */ - void (*batch_free)(struct _malloc_zone_t *zone, void **to_be_freed, unsigned num_to_be_freed); /* frees all the pointers in to_be_freed; note that to_be_freed may be overwritten during the process */ + + /* Optional batch callbacks; these may be NULL */ + unsigned (*batch_malloc)(struct _malloc_zone_t *zone, size_t size, void **results, unsigned num_requested); /* given a size, returns pointers capable of holding that size; returns the number of pointers allocated (maybe 0 or less than num_requested) */ + void (*batch_free)(struct _malloc_zone_t *zone, void **to_be_freed, unsigned num_to_be_freed); /* frees all the pointers in to_be_freed; note that to_be_freed may be overwritten during the process */ + struct malloc_introspection_t *introspect; - void *reserved5; + unsigned version; + + /* aligned memory allocation. The callback may be NULL. */ + void *(*memalign)(struct _malloc_zone_t *zone, size_t alignment, size_t size); + + /* free a pointer known to be in zone and known to have the given size. The callback may be NULL. */ + void (*free_definite_size)(struct _malloc_zone_t *zone, void *ptr, size_t size); #endif CFAllocatorRef _allocator; CFAllocatorContext _context; @@ -149,6 +156,7 @@ static void *__CFAllocatorCustomCalloc(malloc_zone_t *zone, size_t num_items, si static void *__CFAllocatorCustomValloc(malloc_zone_t *zone, size_t size) { CFAllocatorRef allocator = (CFAllocatorRef)zone; + if (size >= ULONG_MAX - 2 * vm_page_size) return NULL; // avoid integer overflow plus don't allow all pages to be allocated either void *newptr = CFAllocatorAllocate(allocator, size + vm_page_size, 0); newptr = (void *)round_page((uintptr_t)newptr); return newptr; @@ -302,6 +310,8 @@ static struct __CFAllocator __kCFAllocatorMalloc = { NULL, NULL, &__CFAllocatorZoneIntrospect, + 6, + NULL, NULL, #endif NULL, // _allocator @@ -329,6 +339,8 @@ static struct __CFAllocator __kCFAllocatorMallocZone = { NULL, NULL, &__CFAllocatorZoneIntrospect, + 6, + NULL, NULL, #endif NULL, // _allocator @@ -349,6 +361,8 @@ static struct __CFAllocator __kCFAllocatorSystemDefault = { NULL, NULL, &__CFAllocatorZoneIntrospect, + 6, + NULL, NULL, #endif NULL, // _allocator @@ -369,6 +383,8 @@ static struct __CFAllocator __kCFAllocatorNull = { NULL, NULL, &__CFAllocatorNullZoneIntrospect, + 6, + NULL, NULL, #endif NULL, // _allocator @@ -380,7 +396,11 @@ const CFAllocatorRef kCFAllocatorSystemDefault = &__kCFAllocatorSystemDefault; const CFAllocatorRef kCFAllocatorMalloc = &__kCFAllocatorMalloc; const CFAllocatorRef kCFAllocatorMallocZone = &__kCFAllocatorMallocZone; const CFAllocatorRef kCFAllocatorNull = &__kCFAllocatorNull; -const CFAllocatorRef kCFAllocatorUseContext = (CFAllocatorRef)0x0257; +const CFAllocatorRef kCFAllocatorUseContext = (CFAllocatorRef)0x03ab; +#undef kCFAllocatorSystemDefaultGCRefZero +#undef kCFAllocatorDefaultGCRefZero +const CFAllocatorRef kCFAllocatorSystemDefaultGCRefZero = (CFAllocatorRef)0x03ad; +const CFAllocatorRef kCFAllocatorDefaultGCRefZero = (CFAllocatorRef)0x03af; static CFStringRef __CFAllocatorCopyDescription(CFTypeRef cf) { CFAllocatorRef self = (CFAllocatorRef)cf; @@ -414,7 +434,7 @@ __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf) { if (NULL != releaseFunc) { INVOKE_CALLBACK1(releaseFunc, self->_context.info); } - _CFAllocatorDeallocateGC(allocator, (void *)self); + if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) CFAllocatorDeallocate(allocator, (void *)self); } } @@ -438,8 +458,7 @@ __private_extern__ void __CFAllocatorInitialize(void) { _CFRuntimeSetInstanceTypeID(&__kCFAllocatorSystemDefault, __kCFAllocatorTypeID); __kCFAllocatorSystemDefault._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - __kCFAllocatorSystemDefault._context.info = (kCFUseCollectableAllocator ? auto_zone() : malloc_default_zone()); - memset(malloc_default_zone(), 0, 2 * sizeof(void *)); + __kCFAllocatorSystemDefault._context.info = (kCFUseCollectableAllocator ? objc_collectableZone() : malloc_default_zone()); #endif __kCFAllocatorSystemDefault._allocator = kCFAllocatorSystemDefault; @@ -469,6 +488,9 @@ CFAllocatorRef CFAllocatorGetDefault(void) { } void CFAllocatorSetDefault(CFAllocatorRef allocator) { + if (kCFAllocatorSystemDefaultGCRefZero == allocator || kCFAllocatorDefaultGCRefZero == allocator) { + HALT; + } CFAllocatorRef current = __CFGetDefaultAllocator(); #if defined(DEBUG) if (NULL != allocator) { @@ -483,15 +505,10 @@ void CFAllocatorSetDefault(CFAllocatorRef allocator) { if (NULL != allocator && allocator != current) { if (current) CFRelease(current); CFRetain(allocator); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - // extra retain not needed here, since we never attempt cleanup of this key - pthread_setspecific(__CFTSDKeyAllocator, allocator); -#else // We retain an extra time so that anything set as the default // allocator never goes away. CFRetain(allocator); - __CFGetThreadSpecificData_inline()->_allocator = (void *)allocator; -#endif + _CFSetTSD(__CFTSDKeyAllocator, (void *)allocator, NULL); } } @@ -526,11 +543,12 @@ static CFAllocatorRef __CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorC } else { allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; memory = (struct __CFAllocator *)CFAllocatorAllocate(allocator, sizeof(struct __CFAllocator), __kCFAllocatorGCObjectMemory); - if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFAllocator"); if (NULL == memory) { return NULL; } + if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFAllocator"); } + memset(memory, 0, sizeof(CFRuntimeBase)); memory->_base._cfisa = 0; #if __LP64__ memory->_base._rc = 1; @@ -552,7 +570,9 @@ static CFAllocatorRef __CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorC memory->batch_malloc = NULL; memory->batch_free = NULL; memory->introspect = &__CFAllocatorZoneIntrospect; - memory->reserved5 = NULL; + memory->version = 6; + memory->memalign = NULL; + memory->free_definite_size = NULL; #endif memory->_allocator = allocator; memory->_context.version = context->version; @@ -580,7 +600,19 @@ CFAllocatorRef CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorContext *c void *CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) { CFAllocatorAllocateCallBack allocateFunc; void *newptr = NULL; - allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; + + Boolean initialRefcountOne = true; + if (kCFAllocatorSystemDefaultGCRefZero == allocator) { + allocator = kCFAllocatorSystemDefault; + initialRefcountOne = false; + } else if (kCFAllocatorDefaultGCRefZero == allocator) { + // Under GC, we can't use just any old allocator when the GCRefZero allocator was requested + allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator(); + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) initialRefcountOne = false; + } else if (NULL == allocator) { + allocator = __CFGetDefaultAllocator(); + } + #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); @@ -595,7 +627,7 @@ void *CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags } #endif if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - newptr = auto_zone_allocate_object((auto_zone_t*)allocator->_context.info, size, CF_GET_GC_MEMORY_TYPE(hint), true, false); + newptr = auto_zone_allocate_object((auto_zone_t*)allocator->_context.info, size, CF_GET_GC_MEMORY_TYPE(hint), initialRefcountOne, false); } else { newptr = NULL; allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context); @@ -611,7 +643,16 @@ void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize CFAllocatorReallocateCallBack reallocateFunc; CFAllocatorDeallocateCallBack deallocateFunc; void *newptr; - allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; + + if (kCFAllocatorSystemDefaultGCRefZero == allocator) { + allocator = kCFAllocatorSystemDefault; + } else if (kCFAllocatorDefaultGCRefZero == allocator) { + // Under GC, we can't use just any old allocator when the GCRefZero allocator was requested + allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator(); + } else if (NULL == allocator) { + allocator = __CFGetDefaultAllocator(); + } + #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); @@ -663,7 +704,18 @@ void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize void CFAllocatorDeallocate(CFAllocatorRef allocator, void *ptr) { CFAllocatorDeallocateCallBack deallocateFunc; - allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; + + if (kCFAllocatorSystemDefaultGCRefZero == allocator) { + if (_CFAllocatorIsGCRefZero(allocator)) return; + allocator = kCFAllocatorSystemDefault; + } else if (kCFAllocatorDefaultGCRefZero == allocator) { + // Under GC, we can't use just any old allocator when the GCRefZero allocator was requested + allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator(); + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) return; + } else if (NULL == allocator) { + allocator = __CFGetDefaultAllocator(); + } + #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); @@ -689,7 +741,16 @@ void CFAllocatorDeallocate(CFAllocatorRef allocator, void *ptr) { CFIndex CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) { CFAllocatorPreferredSizeCallBack prefFunc; CFIndex newsize = 0; - allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; + + if (kCFAllocatorSystemDefaultGCRefZero == allocator) { + allocator = kCFAllocatorSystemDefault; + } else if (kCFAllocatorDefaultGCRefZero == allocator) { + // Under GC, we can't use just any old allocator when the GCRefZero allocator was requested + allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator(); + } else if (NULL == allocator) { + allocator = __CFGetDefaultAllocator(); + } + #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); @@ -711,7 +772,15 @@ CFIndex CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex siz } void CFAllocatorGetContext(CFAllocatorRef allocator, CFAllocatorContext *context) { - allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; + if (kCFAllocatorSystemDefaultGCRefZero == allocator) { + allocator = kCFAllocatorSystemDefault; + } else if (kCFAllocatorDefaultGCRefZero == allocator) { + // Under GC, we can't use just any old allocator when the GCRefZero allocator was requested + allocator = kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : __CFGetDefaultAllocator(); + } else if (NULL == allocator) { + allocator = __CFGetDefaultAllocator(); + } + #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); @@ -734,7 +803,7 @@ void CFAllocatorGetContext(CFAllocatorRef allocator, CFAllocatorContext *context context->reallocate = __CFAllocatorGetReallocateFunction(&allocator->_context); context->deallocate = __CFAllocatorGetDeallocateFunction(&allocator->_context); context->preferredSize = __CFAllocatorGetPreferredSizeFunction(&allocator->_context); -#if DEPLOYMENT_TARGET_MACOSX && defined(__ppc__) +#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); @@ -775,50 +844,6 @@ __private_extern__ void _CFAllocatorDeallocateGC(CFAllocatorRef allocator, void // -------- -------- -------- -------- -------- -------- -------- -------- -#if DEPLOYMENT_TARGET_WINDOWS -__private_extern__ DWORD __CFTSDKey = 0xFFFFFFFF; -#endif - -#if DEPLOYMENT_TARGET_WINDOWS -extern void __CFStringEncodingICUThreadDataCleaner(void *); - -// Called for each thread as it exits -__private_extern__ void __CFFinalizeThreadData(void *arg) { - __CFThreadSpecificData *tsd = (__CFThreadSpecificData*)TlsGetValue(__CFTSDKey); - TlsSetValue(__CFTSDKey, NULL); - if (NULL == tsd) return; - if (tsd->_allocator) CFRelease(tsd->_allocator); - if (tsd->_messageHook) UnhookWindowsHookEx(tsd->_messageHook); - if (tsd->_icuThreadData) __CFStringEncodingICUThreadDataCleaner(tsd->_icuThreadData); - CFAllocatorDeallocate(kCFAllocatorSystemDefault, tsd); -} - -__private_extern__ __CFThreadSpecificData *__CFGetThreadSpecificData(void) { - __CFThreadSpecificData *data; - data = (__CFThreadSpecificData *)TlsGetValue(__CFTSDKey); - if (data) { - return data; - } - data = (__CFThreadSpecificData *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFThreadSpecificData), 0); - if (__CFOASafe) __CFSetLastAllocationEventName(data, "CFUtilities (thread-data)"); - memset(data, 0, sizeof(__CFThreadSpecificData)); - TlsSetValue(__CFTSDKey, data); - return data; -} -#endif - -__private_extern__ void __CFBaseInitialize(void) { -#if DEPLOYMENT_TARGET_WINDOWS - __CFTSDKey = TlsAlloc(); -#endif -} - -#if DEPLOYMENT_TARGET_WINDOWS -__private_extern__ void __CFBaseCleanup(void) { - TlsFree(__CFTSDKey); -} -#endif - CFRange __CFRangeMake(CFIndex loc, CFIndex len) { CFRange range; @@ -876,14 +901,19 @@ 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; } -#if DEPLOYMENT_TARGET_MACOSX && defined(__ppc__) - /* See comments below */ __private_extern__ void __CF_FAULT_CALLBACK(void **ptr) { uintptr_t p = (uintptr_t)*ptr; @@ -891,19 +921,9 @@ __private_extern__ void __CF_FAULT_CALLBACK(void **ptr) { if (0 == hasCFM || (0x90000000 <= p && p < 0xA0000000)) { *ptr = (void *)(p | 0x1); } else { - static CFMutableDictionaryRef cache = NULL; - static CFSpinLock_t lock = CFSpinLockInit; uintptr_t known = ~0; - __CFSpinLock(&lock); - if (!cache || !CFDictionaryGetValueIfPresent(cache, (const void *)p, (const void **)&known)) { - if (!cache) { - cache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); - } Dl_info info; known = dladdr((void *)p, &info); - CFDictionarySetValue(cache, (const void *)p, (const void *)known); - } - __CFSpinUnlock(&lock); *ptr = (void *)(p | (known ? 0x1 : 0x3)); } } @@ -949,38 +969,19 @@ __asm__ ( // void __HALT(void); -#if defined(__ppc__) -__asm__ ( -".text\n" -" .align 2\n" -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -".private_extern ___HALT\n" -#else -".globl ___HALT\n" -#endif -"___HALT:\n" -" trap\n" -); -#endif +/* Keep this assembly at the bottom of the source file! */ + -#if defined(__i386__) || defined(__x86_64__) +extern void __HALT() { +#if defined(__ppc__) + __asm__("trap"); +#elif defined(__i386__) || defined(__x86_64__) #if defined(_MSC_VER) -void __HALT() { __asm int 3; -} -#else -__asm__ ( -".text\n" -" .align 2, 0x90\n" -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -".private_extern ___HALT\n" #else -".globl ___HALT\n" -#endif -"___HALT:\n" -" int3\n" -); + __asm__("int3"); #endif #endif +} diff --git a/CFBase.h b/CFBase.h index c1e1590..d514ffd 100644 --- a/CFBase.h +++ b/CFBase.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFBase.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBASE__) @@ -54,19 +54,79 @@ #error Both __BIG_ENDIAN__ and __LITTLE_ENDIAN__ cannot be true #endif -#if TARGET_OS_WIN32 -#include -#include -#elif defined(__GNUC__) +// Some compilers provide the capability to test if certain features are available. This macro provides a compatibility path for other compilers. +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#if defined(__GNUC__) || TARGET_OS_WIN32 #include #include #endif + +#if __BLOCKS__ +#include +#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) #include +#include + +// Available on MacOS and iOS +#define CF_AVAILABLE(_mac, _ios) AVAILABLE_MAC_OS_X_VERSION_##_mac##_AND_LATER + +// Available on MacOS only +#define CF_AVAILABLE_MAC(_mac) AVAILABLE_MAC_OS_X_VERSION_##_mac##_AND_LATER + +// Available on iOS only +#define CF_AVAILABLE_IOS(_ios) __OSX_AVAILABLE_STARTING(__MAC_NA, __IPHONE_##_ios) -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) -#include +// 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 + +// 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 + +// 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 +#include +#include #endif +#define CF_AVAILABLE(_mac, _ios) +#define CF_AVAILABLE_MAC(_mac) +#define CF_AVAILABLE_IOS(_ios) +#define CF_DEPRECATED(_macIntro, _macDep, _iosIntro, _iosDep) +#define CF_DEPRECATED_MAC(_macIntro, _macDep) +#define CF_DEPRECATED_IOS(_iosIntro, _iosDep) + +#endif + + +// Older versions of these macro; use IOS versions instead +#define CF_AVAILABLE_IPHONE(_ios) CF_AVAILABLE_IOS(_ios) +#define CF_DEPRECATED_IPHONE(_iosIntro, _iosDep) CF_DEPRECATED_IOS(_iosIntro, _iosDep) + + #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) + #include + #endif + #if !defined(__MACTYPES__) #if !defined(_OS_OSTYPES_H) typedef unsigned char Boolean; @@ -113,14 +173,20 @@ #endif #endif -#if TARGET_OS_WIN32 && defined(CF_BUILDING_CF) && defined(__cplusplus) +#if TARGET_OS_WIN32 + +#if !defined(CF_EXPORT) +#if defined(CF_BUILDING_CF) && defined(__cplusplus) #define CF_EXPORT extern "C" __declspec(dllexport) -#elif TARGET_OS_WIN32 && defined(CF_BUILDING_CF) && !defined(__cplusplus) +#elif defined(CF_BUILDING_CF) && !defined(__cplusplus) #define CF_EXPORT extern __declspec(dllexport) -#elif TARGET_OS_WIN32 && defined(__cplusplus) +#elif defined(__cplusplus) #define CF_EXPORT extern "C" __declspec(dllimport) -#elif TARGET_OS_WIN32 +#else #define CF_EXPORT extern __declspec(dllimport) +#endif +#endif + #else #define CF_EXPORT extern #endif @@ -159,13 +225,28 @@ CF_EXTERN_C_BEGIN #endif #endif -// 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 the rename the functions, but this macro can be used to let the clang static analyzer know of any exceptions that cannot be fixed. -#if defined(__clang__) +// 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. +#if __has_feature(attribute_cf_returns_retained) #define CF_RETURNS_RETAINED __attribute__((cf_returns_retained)) #else #define CF_RETURNS_RETAINED #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. +#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 + +// Marks functions which cannot be used when compiling in automatic reference counting mode. +#if __has_feature(objc_arc) +#define CF_AUTOMATED_REFCOUNT_UNAVAILABLE __attribute__((unavailable("not available in automatic reference counting mode"))) +#else +#define CF_AUTOMATED_REFCOUNT_UNAVAILABLE +#endif CF_EXPORT double kCFCoreFoundationVersionNumber; @@ -225,6 +306,8 @@ CF_EXPORT double kCFCoreFoundationVersionNumber; #define kCFCoreFoundationVersionNumber10_6_1 550.00 #define kCFCoreFoundationVersionNumber10_6_2 550.13 #define kCFCoreFoundationVersionNumber10_6_3 550.19 +#define kCFCoreFoundationVersionNumber10_6_4 550.29 +#define kCFCoreFoundationVersionNumber10_6_5 550.42 #endif #if TARGET_OS_IPHONE @@ -234,6 +317,9 @@ CF_EXPORT double kCFCoreFoundationVersionNumber; #define kCFCoreFoundationVersionNumber_iPhoneOS_3_0 478.47 #define kCFCoreFoundationVersionNumber_iPhoneOS_3_1 478.52 #define kCFCoreFoundationVersionNumber_iPhoneOS_3_2 478.61 +#define kCFCoreFoundationVersionNumber_iOS_4_0 550.32 +#define kCFCoreFoundationVersionNumber_iOS_4_1 550.38 +#define kCFCoreFoundationVersionNumber_iOS_4_2 550.52 #endif typedef unsigned long CFTypeID; @@ -294,7 +380,6 @@ CF_EXPORT CFRange __CFRangeMake(CFIndex loc, CFIndex len); -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED /* Null representant */ typedef const struct __CFNull * CFNullRef; @@ -305,8 +390,6 @@ CFTypeID CFNullGetTypeID(void); CF_EXPORT const CFNullRef kCFNull; // the singleton null instance -#endif - /* Allocator API @@ -341,7 +424,7 @@ const CFAllocatorRef kCFAllocatorMalloc; safe to be allocated in non-scanned memory. */ CF_EXPORT -const CFAllocatorRef kCFAllocatorMallocZone AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +const CFAllocatorRef kCFAllocatorMallocZone; /* Null allocator which does nothing and allocates no memory. This allocator is useful as the "bytesDeallocator" in CFData or "contentsDeallocator" @@ -444,8 +527,9 @@ void CFRelease(CFTypeRef cf); CF_EXPORT CFIndex CFGetRetainCount(CFTypeRef cf); +// This function is unavailable in ARC mode. Use CFBridgingRelease instead. CF_EXPORT -CFTypeRef CFMakeCollectable(CFTypeRef cf) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFTypeRef CFMakeCollectable(CFTypeRef cf) CF_AUTOMATED_REFCOUNT_UNAVAILABLE; CF_EXPORT Boolean CFEqual(CFTypeRef cf1, CFTypeRef cf2); diff --git a/CFBasicHash.h b/CFBasicHash.h index b959da3..7beaec8 100644 --- a/CFBasicHash.h +++ b/CFBasicHash.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFBasicHash.h - Copyright (c) 2008-2009, Apple Inc. All rights reserved. + Copyright (c) 2008-2011, Apple Inc. All rights reserved. */ #include @@ -45,23 +45,29 @@ enum { }; enum { - kCFBasicHashHasValues2 = (1UL << 2), - kCFBasicHashHasKeys = (1UL << 3), - kCFBasicHashHasKeys2 = (1UL << 4), - kCFBasicHashHasCounts = (1UL << 5), - kCFBasicHashHasOrder = (1UL << 6), - kCFBasicHashHasHashCache = (1UL << 7), - - kCFBasicHashStrongValues = (1UL << 9), - kCFBasicHashStrongValues2 = (1UL << 10), - kCFBasicHashStrongKeys = (1UL << 11), - kCFBasicHashStrongKeys2 = (1UL << 12), + kCFBasicHashHasKeys = (1UL << 0), + kCFBasicHashHasCounts = (1UL << 1), + kCFBasicHashHasHashCache = (1UL << 2), + + kCFBasicHashIntegerValues = (1UL << 6), + kCFBasicHashIntegerKeys = (1UL << 7), + + kCFBasicHashStrongValues = (1UL << 8), + kCFBasicHashStrongKeys = (1UL << 9), + + kCFBasicHashWeakValues = (1UL << 10), + kCFBasicHashWeakKeys = (1UL << 11), + + kCFBasicHashIndirectKeys = (1UL << 12), kCFBasicHashLinearHashing = (__kCFBasicHashLinearHashingValue << 13), // bits 13-14 kCFBasicHashDoubleHashing = (__kCFBasicHashDoubleHashingValue << 13), kCFBasicHashExponentialHashing = (__kCFBasicHashExponentialHashingValue << 13), kCFBasicHashAggressiveGrowth = (1UL << 15), + + kCFBasicHashCompactableValues = (1UL << 16), + kCFBasicHashCompactableKeys = (1UL << 17), }; // Note that for a hash table without keys, the value is treated as the key, @@ -70,19 +76,18 @@ enum { typedef struct { CFIndex idx; uintptr_t weak_key; - uintptr_t weak_key2; uintptr_t weak_value; - uintptr_t weak_value2; uintptr_t count; - uintptr_t order; } CFBasicHashBucket; typedef struct __CFBasicHash *CFBasicHashRef; +typedef const struct __CFBasicHash *CFConstBasicHashRef; // Bit 6 in the CF_INFO_BITS of the CFRuntimeBase inside the CFBasicHashRef is the "is immutable" bit -CF_INLINE Boolean CFBasicHashIsMutable(CFBasicHashRef ht) { +CF_INLINE Boolean CFBasicHashIsMutable(CFConstBasicHashRef ht) { return __CFBitfieldGetValue(((CFRuntimeBase *)ht)->_cfinfo[CF_INFO_BITS], 6, 6) ? false : true; } + CF_INLINE void CFBasicHashMakeImmutable(CFBasicHashRef ht) { __CFBitfieldSetValue(((CFRuntimeBase *)ht)->_cfinfo[CF_INFO_BITS], 6, 6, 1); } @@ -90,64 +95,57 @@ CF_INLINE void CFBasicHashMakeImmutable(CFBasicHashRef ht) { typedef struct __CFBasicHashCallbacks CFBasicHashCallbacks; -typedef uintptr_t (*CFBasicHashCallbackType)(CFBasicHashRef ht, uint8_t op, uintptr_t a1, uintptr_t a2, const CFBasicHashCallbacks *cb); - -enum { - kCFBasicHashCallbackOpCopyCallbacks = 8, // Return new value; REQUIRED - kCFBasicHashCallbackOpFreeCallbacks = 9, // Return 0; REQUIRED - - kCFBasicHashCallbackOpRetainValue = 10, // Return first arg or new value; REQUIRED - kCFBasicHashCallbackOpRetainValue2 = 11, // Return first arg or new value - kCFBasicHashCallbackOpRetainKey = 12, // Return first arg or new key; REQUIRED - kCFBasicHashCallbackOpRetainKey2 = 13, // Return first arg or new key - kCFBasicHashCallbackOpReleaseValue = 14, // Return 0; REQUIRED - kCFBasicHashCallbackOpReleaseValue2 = 15, // Return 0 - kCFBasicHashCallbackOpReleaseKey = 16, // Return 0; REQUIRED - kCFBasicHashCallbackOpReleaseKey2 = 17, // Return 0 - kCFBasicHashCallbackOpValueEqual = 18, // Return 0 or 1; REQUIRED - kCFBasicHashCallbackOpValue2Equal = 19, // Return 0 or 1 - kCFBasicHashCallbackOpKeyEqual = 20, // Return 0 or 1; REQUIRED - kCFBasicHashCallbackOpKey2Equal = 21, // Return 0 or 1 - kCFBasicHashCallbackOpHashKey = 22, // Return hash code; REQUIRED - kCFBasicHashCallbackOpHashKey2 = 23, // Return hash code - kCFBasicHashCallbackOpDescribeValue = 24, // Return retained CFStringRef; REQUIRED - kCFBasicHashCallbackOpDescribeValue2 = 25, // Return retained CFStringRef - kCFBasicHashCallbackOpDescribeKey = 26, // Return retained CFStringRef; REQUIRED - kCFBasicHashCallbackOpDescribeKey2 = 27, // Return retained CFStringRef -}; - struct __CFBasicHashCallbacks { - CFBasicHashCallbackType func; // must not be NULL + CFBasicHashCallbacks *(*copyCallbacks)(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb); // Return new value + void (*freeCallbacks)(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb); + uintptr_t (*retainValue)(CFConstBasicHashRef ht, uintptr_t stack_value); // Return 2nd arg or new value + uintptr_t (*retainKey)(CFConstBasicHashRef ht, uintptr_t stack_key); // Return 2nd arg or new key + void (*releaseValue)(CFConstBasicHashRef ht, uintptr_t stack_value); + void (*releaseKey)(CFConstBasicHashRef ht, uintptr_t stack_key); + Boolean (*equateValues)(CFConstBasicHashRef ht, uintptr_t coll_value1, uintptr_t stack_value2); // 2nd arg is in-collection value, 3rd arg is probe parameter OR in-collection value for a second collection + Boolean (*equateKeys)(CFConstBasicHashRef ht, uintptr_t coll_key1, uintptr_t stack_key2); // 2nd arg is in-collection key, 3rd arg is probe parameter + uintptr_t (*hashKey)(CFConstBasicHashRef ht, uintptr_t stack_key); + uintptr_t (*getIndirectKey)(CFConstBasicHashRef ht, uintptr_t coll_value); // Return key; 2nd arg is in-collection value + CFStringRef (*copyValueDescription)(CFConstBasicHashRef ht, uintptr_t stack_value); + CFStringRef (*copyKeyDescription)(CFConstBasicHashRef ht, uintptr_t stack_key); uintptr_t context[0]; // variable size; any pointers in here must remain valid as long as the CFBasicHash }; -extern const CFBasicHashCallbacks CFBasicHashNullCallbacks; -extern const CFBasicHashCallbacks CFBasicHashStandardCallbacks; +Boolean CFBasicHashHasStrongValues(CFConstBasicHashRef ht); +Boolean CFBasicHashHasStrongKeys(CFConstBasicHashRef ht); +uint16_t CFBasicHashGetSpecialBits(CFConstBasicHashRef ht); +uint16_t CFBasicHashSetSpecialBits(CFBasicHashRef ht, uint16_t bits); -CFOptionFlags CFBasicHashGetFlags(CFBasicHashRef ht); -CFIndex CFBasicHashGetNumBuckets(CFBasicHashRef ht); -CFIndex CFBasicHashGetCapacity(CFBasicHashRef ht); +CFOptionFlags CFBasicHashGetFlags(CFConstBasicHashRef ht); +CFIndex CFBasicHashGetNumBuckets(CFConstBasicHashRef ht); +CFIndex CFBasicHashGetCapacity(CFConstBasicHashRef ht); void CFBasicHashSetCapacity(CFBasicHashRef ht, CFIndex capacity); -CFIndex CFBasicHashGetCount(CFBasicHashRef ht); -CFBasicHashBucket CFBasicHashGetBucket(CFBasicHashRef ht, CFIndex idx); -CFBasicHashBucket CFBasicHashFindBucket(CFBasicHashRef ht, uintptr_t stack_key); -CFIndex CFBasicHashGetCountOfKey(CFBasicHashRef ht, uintptr_t stack_key); -CFIndex CFBasicHashGetCountOfValue(CFBasicHashRef ht, uintptr_t stack_value); -Boolean CFBasicHashesAreEqual(CFBasicHashRef ht1, CFBasicHashRef ht2); -void CFBasicHashApply(CFBasicHashRef ht, Boolean (^block)(CFBasicHashBucket)); -void CFBasicHashGetElements(CFBasicHashRef ht, CFIndex bufferslen, uintptr_t *weak_values, uintptr_t *weak_values2, uintptr_t *weak_keys, uintptr_t *weak_keys2); - -void CFBasicHashAddValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value); +const CFBasicHashCallbacks *CFBasicHashGetCallbacks(CFConstBasicHashRef ht); +CFIndex CFBasicHashGetCount(CFConstBasicHashRef ht); +CFBasicHashBucket CFBasicHashGetBucket(CFConstBasicHashRef ht, CFIndex idx); +CFBasicHashBucket CFBasicHashFindBucket(CFConstBasicHashRef ht, uintptr_t stack_key); +CFIndex CFBasicHashGetCountOfKey(CFConstBasicHashRef ht, uintptr_t stack_key); +CFIndex CFBasicHashGetCountOfValue(CFConstBasicHashRef ht, uintptr_t stack_value); +Boolean CFBasicHashesAreEqual(CFConstBasicHashRef ht1, CFConstBasicHashRef ht2); +void CFBasicHashApply(CFConstBasicHashRef ht, Boolean (^block)(CFBasicHashBucket)); +void CFBasicHashApplyIndexed(CFConstBasicHashRef ht, CFRange range, Boolean (^block)(CFBasicHashBucket)); +void CFBasicHashGetElements(CFConstBasicHashRef ht, CFIndex bufferslen, uintptr_t *weak_values, uintptr_t *weak_keys); + +Boolean CFBasicHashAddValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value); void CFBasicHashReplaceValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value); void CFBasicHashSetValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value); CFIndex CFBasicHashRemoveValue(CFBasicHashRef ht, uintptr_t stack_key); +CFIndex CFBasicHashRemoveValueAtIndex(CFBasicHashRef ht, CFIndex idx); void CFBasicHashRemoveAllValues(CFBasicHashRef ht); -size_t CFBasicHashGetSize(CFBasicHashRef ht, Boolean total); +Boolean CFBasicHashAddIntValueAndInc(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t int_value); +void CFBasicHashRemoveIntValueAndDec(CFBasicHashRef ht, uintptr_t int_value); + +size_t CFBasicHashGetSize(CFConstBasicHashRef ht, Boolean total); -CFStringRef CFBasicHashCopyDescription(CFBasicHashRef ht, Boolean detailed, CFStringRef linePrefix, CFStringRef entryLinePrefix, Boolean describeElements); +CFStringRef CFBasicHashCopyDescription(CFConstBasicHashRef ht, Boolean detailed, CFStringRef linePrefix, CFStringRef entryLinePrefix, Boolean describeElements); CFTypeID CFBasicHashGetTypeID(void); @@ -155,11 +153,12 @@ extern Boolean __CFBasicHashEqual(CFTypeRef cf1, CFTypeRef cf2); extern CFHashCode __CFBasicHashHash(CFTypeRef cf); extern CFStringRef __CFBasicHashCopyDescription(CFTypeRef cf); extern void __CFBasicHashDeallocate(CFTypeRef cf); -extern unsigned long __CFBasicHashFastEnumeration(CFBasicHashRef ht, struct __objcFastEnumerationStateEquivalent2 *state, void *stackbuffer, unsigned long count); +extern unsigned long __CFBasicHashFastEnumeration(CFConstBasicHashRef ht, struct __objcFastEnumerationStateEquivalent2 *state, void *stackbuffer, unsigned long count); // creation functions create mutable CFBasicHashRefs CFBasicHashRef CFBasicHashCreate(CFAllocatorRef allocator, CFOptionFlags flags, const CFBasicHashCallbacks *cb); -CFBasicHashRef CFBasicHashCreateCopy(CFAllocatorRef allocator, CFBasicHashRef ht); +CFBasicHashRef CFBasicHashCreateCopy(CFAllocatorRef allocator, CFConstBasicHashRef ht); +void __CFBasicHashSetCallbacks(CFBasicHashRef ht, const CFBasicHashCallbacks *cb); CF_EXTERN_C_END diff --git a/CFBasicHash.m b/CFBasicHash.m index f932d5f..449b1eb 100644 --- a/CFBasicHash.m +++ b/CFBasicHash.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFBasicHash.m - Copyright (c) 2008-2009, Apple Inc. All rights reserved. + Copyright (c) 2008-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ @@ -30,7 +30,6 @@ #import #import #import -#import #import #if DEPLOYMENT_TARGET_WINDOWS @@ -47,10 +46,15 @@ #define ENABLE_DTRACE_PROBES 0 #define ENABLE_MEMORY_COUNTERS 0 +#if defined(DTRACE_PROBES_DISABLED) && DTRACE_PROBES_DISABLED +#undef ENABLE_DTRACE_PROBES +#define ENABLE_DTRACE_PROBES 0 +#endif /* // dtrace -h -s foo.d -// Note: output then changed by putting do/while around macro bodies and adding a cast of the arguments +// Note: output then changed by casts of the arguments +// dtrace macros last generated 2010-09-08 on 10.7 prerelease (11A259) provider Cocoa_HashTable { probe hash_key(unsigned long table, unsigned long key, unsigned long hash); @@ -83,77 +87,91 @@ do { \ __dtrace_probe$Cocoa_HashTable$rehash_end$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1), (unsigned long)(arg2)); \ __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \ } while (0) -#define COCOA_HASHTABLE_REHASH_END_ENABLED() \ - __dtrace_isenabled$Cocoa_HashTable$rehash_end$v1() +#define COCOA_HASHTABLE_REHASH_END_ENABLED() \ + ({ int _r = __dtrace_isenabled$Cocoa_HashTable$rehash_end$v1(); \ + __asm__ volatile(""); \ + _r; }) #define COCOA_HASHTABLE_REHASH_START(arg0, arg1, arg2) \ do { \ __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \ __dtrace_probe$Cocoa_HashTable$rehash_start$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1), (unsigned long)(arg2)); \ __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \ } while (0) -#define COCOA_HASHTABLE_REHASH_START_ENABLED() \ - __dtrace_isenabled$Cocoa_HashTable$rehash_start$v1() +#define COCOA_HASHTABLE_REHASH_START_ENABLED() \ + ({ int _r = __dtrace_isenabled$Cocoa_HashTable$rehash_start$v1(); \ + __asm__ volatile(""); \ + _r; }) #define COCOA_HASHTABLE_HASH_KEY(arg0, arg1, arg2) \ do { \ __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \ __dtrace_probe$Cocoa_HashTable$hash_key$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1), (unsigned long)(arg2)); \ __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \ } while (0) -#define COCOA_HASHTABLE_HASH_KEY_ENABLED() \ - __dtrace_isenabled$Cocoa_HashTable$hash_key$v1() +#define COCOA_HASHTABLE_HASH_KEY_ENABLED() \ + ({ int _r = __dtrace_isenabled$Cocoa_HashTable$hash_key$v1(); \ + __asm__ volatile(""); \ + _r; }) #define COCOA_HASHTABLE_PROBE_DELETED(arg0, arg1) \ do { \ __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \ __dtrace_probe$Cocoa_HashTable$probe_deleted$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1)); \ __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \ } while (0) -#define COCOA_HASHTABLE_PROBE_DELETED_ENABLED() \ - __dtrace_isenabled$Cocoa_HashTable$probe_deleted$v1() +#define COCOA_HASHTABLE_PROBE_DELETED_ENABLED() \ + ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probe_deleted$v1(); \ + __asm__ volatile(""); \ + _r; }) #define COCOA_HASHTABLE_PROBE_EMPTY(arg0, arg1) \ do { \ __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \ __dtrace_probe$Cocoa_HashTable$probe_empty$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1)); \ __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \ } while (0) -#define COCOA_HASHTABLE_PROBE_EMPTY_ENABLED() \ - __dtrace_isenabled$Cocoa_HashTable$probe_empty$v1() +#define COCOA_HASHTABLE_PROBE_EMPTY_ENABLED() \ + ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probe_empty$v1(); \ + __asm__ volatile(""); \ + _r; }) #define COCOA_HASHTABLE_PROBE_VALID(arg0, arg1) \ do { \ __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \ __dtrace_probe$Cocoa_HashTable$probe_valid$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1)); \ __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \ } while (0) -#define COCOA_HASHTABLE_PROBE_VALID_ENABLED() \ - __dtrace_isenabled$Cocoa_HashTable$probe_valid$v1() +#define COCOA_HASHTABLE_PROBE_VALID_ENABLED() \ + ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probe_valid$v1(); \ + __asm__ volatile(""); \ + _r; }) #define COCOA_HASHTABLE_PROBING_END(arg0, arg1) \ do { \ __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \ __dtrace_probe$Cocoa_HashTable$probing_end$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1)); \ __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \ } while (0) -#define COCOA_HASHTABLE_PROBING_END_ENABLED() \ - __dtrace_isenabled$Cocoa_HashTable$probing_end$v1() +#define COCOA_HASHTABLE_PROBING_END_ENABLED() \ + ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probing_end$v1(); \ + __asm__ volatile(""); \ + _r; }) #define COCOA_HASHTABLE_PROBING_START(arg0, arg1) \ do { \ __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \ __dtrace_probe$Cocoa_HashTable$probing_start$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1)); \ __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \ } while (0) -#define COCOA_HASHTABLE_PROBING_START_ENABLED() \ - __dtrace_isenabled$Cocoa_HashTable$probing_start$v1() +#define COCOA_HASHTABLE_PROBING_START_ENABLED() \ + ({ int _r = __dtrace_isenabled$Cocoa_HashTable$probing_start$v1(); \ + __asm__ volatile(""); \ + _r; }) #define COCOA_HASHTABLE_TEST_EQUAL(arg0, arg1, arg2) \ do { \ __asm__ volatile(".reference " COCOA_HASHTABLE_TYPEDEFS); \ __dtrace_probe$Cocoa_HashTable$test_equal$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67((unsigned long)(arg0), (unsigned long)(arg1), (unsigned long)(arg2)); \ __asm__ volatile(".reference " COCOA_HASHTABLE_STABILITY); \ } while (0) -#define COCOA_HASHTABLE_TEST_EQUAL_ENABLED() \ - __dtrace_isenabled$Cocoa_HashTable$test_equal$v1() +#define COCOA_HASHTABLE_TEST_EQUAL_ENABLED() \ + ({ int _r = __dtrace_isenabled$Cocoa_HashTable$test_equal$v1(); \ + __asm__ volatile(""); \ + _r; }) -extern void __dtrace_probe$Cocoa_HashTable$rehash_end$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long); -extern int __dtrace_isenabled$Cocoa_HashTable$rehash_end$v1(void); -extern void __dtrace_probe$Cocoa_HashTable$rehash_start$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long); -extern int __dtrace_isenabled$Cocoa_HashTable$rehash_start$v1(void); extern void __dtrace_probe$Cocoa_HashTable$hash_key$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long); extern int __dtrace_isenabled$Cocoa_HashTable$hash_key$v1(void); extern void __dtrace_probe$Cocoa_HashTable$probe_deleted$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long); @@ -166,6 +184,10 @@ extern void __dtrace_probe$Cocoa_HashTable$probing_end$v1$756e7369676e6564206c6f extern int __dtrace_isenabled$Cocoa_HashTable$probing_end$v1(void); extern void __dtrace_probe$Cocoa_HashTable$probing_start$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long); extern int __dtrace_isenabled$Cocoa_HashTable$probing_start$v1(void); +extern void __dtrace_probe$Cocoa_HashTable$rehash_end$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long); +extern int __dtrace_isenabled$Cocoa_HashTable$rehash_end$v1(void); +extern void __dtrace_probe$Cocoa_HashTable$rehash_start$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long); +extern int __dtrace_isenabled$Cocoa_HashTable$rehash_start$v1(void); extern void __dtrace_probe$Cocoa_HashTable$test_equal$v1$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67$756e7369676e6564206c6f6e67(unsigned long, unsigned long, unsigned long); extern int __dtrace_isenabled$Cocoa_HashTable$test_equal$v1(void); @@ -197,374 +219,434 @@ extern int __dtrace_isenabled$Cocoa_HashTable$test_equal$v1(void); #define __LP64__ 0 #endif -enum { +// Prime numbers. Values above 100 have been adjusted up so that the +// malloced block size will be just below a multiple of 512; values +// above 1200 have been adjusted up to just below a multiple of 4096. +static const uintptr_t __CFBasicHashTableSizes[64] = { + 0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723, + 2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607, + 214519, 346607, 561109, 907759, 1468927, 2376191, 3845119, + 6221311, 10066421, 16287743, 26354171, 42641881, 68996069, + 111638519, 180634607, 292272623, 472907251, #if __LP64__ - __CFBasicHashMarkerShift = 40 // 64 - 24 -#else - __CFBasicHashMarkerShift = 8 // 32 - 24 + 765180413UL, 1238087663UL, 2003267557UL, 3241355263UL, 5244622819UL, +#if 0 + 8485977589UL, 13730600407UL, 22216578047UL, 35947178479UL, + 58163756537UL, 94110934997UL, 152274691561UL, 246385626107UL, + 398660317687UL, 645045943807UL, 1043706260983UL, 1688752204787UL, + 2732458465769UL, 4421210670577UL, 7153669136377UL, + 11574879807461UL, 18728548943849UL, 30303428750843UL +#endif +#endif +}; + +static const uintptr_t __CFBasicHashTableCapacities[64] = { + 0, 3, 6, 11, 19, 32, 52, 85, 118, 155, 237, 390, 672, 1065, + 1732, 2795, 4543, 7391, 12019, 19302, 31324, 50629, 81956, + 132580, 214215, 346784, 561026, 907847, 1468567, 2376414, + 3844982, 6221390, 10066379, 16287773, 26354132, 42641916, + 68996399, 111638327, 180634415, 292272755, +#if __LP64__ + 472907503UL, 765180257UL, 1238087439UL, 2003267722UL, 3241355160UL, +#if 0 + 5244622578UL, 8485977737UL, 13730600347UL, 22216578100UL, + 35947178453UL, 58163756541UL, 94110935011UL, 152274691274UL, + 246385626296UL, 398660317578UL, 645045943559UL, 1043706261135UL, + 1688752204693UL, 2732458465840UL, 4421210670552UL, + 7153669136706UL, 11574879807265UL, 18728548943682UL +#endif +#endif +}; + +// Primitive roots for the primes above +static const uintptr_t __CFBasicHashPrimitiveRoots[64] = { + 0, 2, 3, 2, 5, 6, 7, 3, 19, 6, 5, 3, 3, 3, + 2, 5, 6, 3, 3, 6, 2, 3, 3, + 3, 5, 10, 3, 3, 22, 3, + 3, 3, 5, 2, 22, 2, + 11, 5, 5, 2, +#if __LP64__ + 3, 10, 2, 3, 10, + 2, 3, 5, 3, + 3, 2, 7, 2, + 3, 3, 3, 2, + 3, 5, 5, + 2, 3, 2 #endif }; +CF_INLINE void *__CFBasicHashAllocateMemory(CFConstBasicHashRef ht, CFIndex count, CFIndex elem_size, Boolean strong, Boolean compactable) { + CFAllocatorRef allocator = CFGetAllocator(ht); + 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); + } + if (!new_mem) HALT; + return new_mem; +} + +#define __CFBasicHashSubABZero 0xa7baadb1 +#define __CFBasicHashSubABOne 0xa5baadb9 + typedef union { - uintptr_t weak; + uintptr_t neutral; id strong; + id weak; } CFBasicHashValue; struct __CFBasicHash { CFRuntimeBase base; struct { // 128 bits - uint64_t hash_style:2; - uint64_t values2_offset:1; - uint64_t keys_offset:2; - uint64_t keys2_offset:2; - uint64_t counts_offset:3; - uint64_t orders_offset:3; - uint64_t hashes_offset:3; - uint64_t num_buckets_idx:6; /* index to number of buckets */ - uint64_t used_buckets:42; /* number of used buckets */ - uint64_t __0:2; - uint64_t finalized:1; - uint64_t fast_grow:1; - uint64_t strong_values:1; - uint64_t strong_values2:1; - uint64_t strong_keys:1; - uint64_t strong_keys2:1; - uint64_t marker:24; - uint64_t deleted:16; - uint64_t mutations:16; + uint8_t hash_style:2; + uint8_t fast_grow:1; + uint8_t keys_offset:1; + uint8_t counts_offset:2; + uint8_t counts_width:2; + uint8_t hashes_offset:2; + uint8_t strong_values:1; + uint8_t strong_keys:1; + uint8_t weak_values:1; + uint8_t weak_keys:1; + uint8_t int_values:1; + uint8_t int_keys:1; + uint8_t indirect_keys:1; + uint8_t compactable_keys:1; + uint8_t compactable_values:1; + uint8_t finalized:1; + uint8_t __2:4; + uint8_t num_buckets_idx; /* index to number of buckets */ + uint32_t used_buckets; /* number of used buckets */ + uint8_t __8:8; + uint8_t __9:8; + uint16_t special_bits; + uint16_t deleted; + uint16_t mutations; } bits; - __strong const CFBasicHashCallbacks *callbacks; + __strong CFBasicHashCallbacks *callbacks; void *pointers[1]; }; -CF_INLINE CFBasicHashValue *__CFBasicHashGetValues(CFBasicHashRef ht) { - return (CFBasicHashValue *)ht->pointers[0]; -} - -CF_INLINE void __CFBasicHashSetValues(CFBasicHashRef ht, CFBasicHashValue *ptr) { - __AssignWithWriteBarrier(&ht->pointers[0], ptr); +__private_extern__ Boolean CFBasicHashHasStrongValues(CFConstBasicHashRef ht) { +#if defined(__arm__) + return false; +#else + return ht->bits.strong_values ? true : false; +#endif } -CF_INLINE CFBasicHashValue *__CFBasicHashGetValues2(CFBasicHashRef ht) { - if (0 == ht->bits.values2_offset) HALT; - return (CFBasicHashValue *)ht->pointers[ht->bits.values2_offset]; +__private_extern__ Boolean CFBasicHashHasStrongKeys(CFConstBasicHashRef ht) { +#if defined(__arm__) + return false; +#else + return ht->bits.strong_keys ? true : false; +#endif } -CF_INLINE void __CFBasicHashSetValues2(CFBasicHashRef ht, CFBasicHashValue *ptr) { - if (0 == ht->bits.values2_offset) HALT; - __AssignWithWriteBarrier(&ht->pointers[ht->bits.values2_offset], ptr); +CF_INLINE Boolean __CFBasicHashHasCompactableKeys(CFConstBasicHashRef ht) { +#if defined(__arm__) + return false; +#else + return ht->bits.compactable_keys ? true : false; +#endif } -CF_INLINE CFBasicHashValue *__CFBasicHashGetKeys(CFBasicHashRef ht) { - if (0 == ht->bits.keys_offset) HALT; - return (CFBasicHashValue *)ht->pointers[ht->bits.keys_offset]; +CF_INLINE Boolean __CFBasicHashHasCompactableValues(CFConstBasicHashRef ht) { +#if defined(__arm__) + return false; +#else + return ht->bits.compactable_values ? true : false; +#endif } -CF_INLINE void __CFBasicHashSetKeys(CFBasicHashRef ht, CFBasicHashValue *ptr) { - if (0 == ht->bits.keys_offset) HALT; - __AssignWithWriteBarrier(&ht->pointers[ht->bits.keys_offset], ptr); +CF_INLINE Boolean __CFBasicHashHasWeakValues(CFConstBasicHashRef ht) { +#if defined(__arm__) + return false; +#else + return ht->bits.weak_values ? true : false; +#endif } -CF_INLINE CFBasicHashValue *__CFBasicHashGetKeys2(CFBasicHashRef ht) { - if (0 == ht->bits.keys2_offset) HALT; - return (CFBasicHashValue *)ht->pointers[ht->bits.keys2_offset]; +CF_INLINE Boolean __CFBasicHashHasWeakKeys(CFConstBasicHashRef ht) { +#if defined(__arm__) + return false; +#else + return ht->bits.weak_keys ? true : false; +#endif } -CF_INLINE void __CFBasicHashSetKeys2(CFBasicHashRef ht, CFBasicHashValue *ptr) { - if (0 == ht->bits.keys2_offset) HALT; - __AssignWithWriteBarrier(&ht->pointers[ht->bits.keys2_offset], ptr); +CF_INLINE Boolean __CFBasicHashHasHashCache(CFConstBasicHashRef ht) { +#if defined(__arm__) + return false; +#else + return ht->bits.hashes_offset ? true : false; +#endif } -CF_INLINE uintptr_t *__CFBasicHashGetCounts(CFBasicHashRef ht) { - if (0 == ht->bits.counts_offset) HALT; - return (uintptr_t *)ht->pointers[ht->bits.counts_offset]; +CF_INLINE uintptr_t __CFBasicHashImportValue(CFConstBasicHashRef ht, uintptr_t stack_value) { + return ht->callbacks->retainValue(ht, stack_value); } -CF_INLINE void __CFBasicHashSetCounts(CFBasicHashRef ht, uintptr_t *ptr) { - if (0 == ht->bits.counts_offset) HALT; - __AssignWithWriteBarrier(&ht->pointers[ht->bits.counts_offset], ptr); +CF_INLINE uintptr_t __CFBasicHashImportKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + return ht->callbacks->retainKey(ht, stack_key); } -CF_INLINE uintptr_t *__CFBasicHashGetOrders(CFBasicHashRef ht) { - if (0 == ht->bits.orders_offset) HALT; - return (uintptr_t *)ht->pointers[ht->bits.orders_offset]; +CF_INLINE void __CFBasicHashEjectValue(CFConstBasicHashRef ht, uintptr_t stack_value) { + ht->callbacks->releaseValue(ht, stack_value); } -CF_INLINE void __CFBasicHashSetOrders(CFBasicHashRef ht, uintptr_t *ptr) { - if (0 == ht->bits.orders_offset) HALT; - __AssignWithWriteBarrier(&ht->pointers[ht->bits.orders_offset], ptr); +CF_INLINE void __CFBasicHashEjectKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + ht->callbacks->releaseKey(ht, stack_key); } -CF_INLINE uintptr_t *__CFBasicHashGetHashes(CFBasicHashRef ht) { - if (0 == ht->bits.hashes_offset) HALT; - return (uintptr_t *)ht->pointers[ht->bits.hashes_offset]; +CF_INLINE Boolean __CFBasicHashTestEqualValue(CFConstBasicHashRef ht, uintptr_t stack_value_a, uintptr_t stack_value_b) { + return ht->callbacks->equateValues(ht, stack_value_a, stack_value_b); } -CF_INLINE void __CFBasicHashSetHashes(CFBasicHashRef ht, uintptr_t *ptr) { - if (0 == ht->bits.hashes_offset) HALT; - __AssignWithWriteBarrier(&ht->pointers[ht->bits.hashes_offset], ptr); +CF_INLINE Boolean __CFBasicHashTestEqualKey(CFConstBasicHashRef ht, uintptr_t in_coll_key, uintptr_t stack_key) { + COCOA_HASHTABLE_TEST_EQUAL(ht, in_coll_key, stack_key); + return ht->callbacks->equateKeys(ht, in_coll_key, stack_key); } -static uintptr_t __CFBasicHashNullCallback(CFBasicHashRef ht, uint8_t op, uintptr_t a1, uintptr_t a2, const CFBasicHashCallbacks *cb) { - switch (op) { - case kCFBasicHashCallbackOpCopyCallbacks: return (uintptr_t)&CFBasicHashNullCallbacks; - case kCFBasicHashCallbackOpFreeCallbacks: return 0; - case kCFBasicHashCallbackOpRetainValue: - case kCFBasicHashCallbackOpRetainValue2: - case kCFBasicHashCallbackOpRetainKey: - case kCFBasicHashCallbackOpRetainKey2: return a1; - case kCFBasicHashCallbackOpReleaseValue: - case kCFBasicHashCallbackOpReleaseValue2: - case kCFBasicHashCallbackOpReleaseKey: - case kCFBasicHashCallbackOpReleaseKey2: return 0; - case kCFBasicHashCallbackOpValueEqual: - case kCFBasicHashCallbackOpValue2Equal: - case kCFBasicHashCallbackOpKeyEqual: - case kCFBasicHashCallbackOpKey2Equal: return a1 == a2; - case kCFBasicHashCallbackOpHashKey: - case kCFBasicHashCallbackOpHashKey2: return a1; - case kCFBasicHashCallbackOpDescribeValue: - case kCFBasicHashCallbackOpDescribeValue2: - case kCFBasicHashCallbackOpDescribeKey: - case kCFBasicHashCallbackOpDescribeKey2: return (uintptr_t)CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)a1); - } - return 0; +CF_INLINE CFHashCode __CFBasicHashHashKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + CFHashCode hash_code = (CFHashCode)ht->callbacks->hashKey(ht, stack_key); + COCOA_HASHTABLE_HASH_KEY(ht, stack_key, hash_code); + return hash_code; } -static uintptr_t __CFBasicHashStandardCallback(CFBasicHashRef ht, uint8_t op, uintptr_t a1, uintptr_t a2, const CFBasicHashCallbacks *cb) { - switch (op) { - case kCFBasicHashCallbackOpCopyCallbacks: return (uintptr_t)&CFBasicHashStandardCallbacks; - case kCFBasicHashCallbackOpFreeCallbacks: return 0; - case kCFBasicHashCallbackOpRetainValue: return (ht->bits.strong_values) ? (uintptr_t)GCRETAIN(kCFAllocatorSystemDefault, (CFTypeRef)a1) : (uintptr_t)CFRetain((CFTypeRef)a1); - case kCFBasicHashCallbackOpRetainValue2: return (ht->bits.strong_values2) ? (uintptr_t)GCRETAIN(kCFAllocatorSystemDefault, (CFTypeRef)a1) : (uintptr_t)CFRetain((CFTypeRef)a1); - case kCFBasicHashCallbackOpRetainKey: return (ht->bits.strong_keys) ? (uintptr_t)GCRETAIN(kCFAllocatorSystemDefault, (CFTypeRef)a1) : (uintptr_t)CFRetain((CFTypeRef)a1); - case kCFBasicHashCallbackOpRetainKey2: return (ht->bits.strong_keys2) ? (uintptr_t)GCRETAIN(kCFAllocatorSystemDefault, (CFTypeRef)a1) : (uintptr_t)CFRetain((CFTypeRef)a1); - case kCFBasicHashCallbackOpReleaseValue: if (ht->bits.strong_values) GCRELEASE(kCFAllocatorSystemDefault, (CFTypeRef)a1); else CFRelease((CFTypeRef)a1); return 0; - case kCFBasicHashCallbackOpReleaseValue2: if (ht->bits.strong_values2) GCRELEASE(kCFAllocatorSystemDefault, (CFTypeRef)a1); else CFRelease((CFTypeRef)a1); return 0; - case kCFBasicHashCallbackOpReleaseKey: if (ht->bits.strong_keys) GCRELEASE(kCFAllocatorSystemDefault, (CFTypeRef)a1); else CFRelease((CFTypeRef)a1); return 0; - case kCFBasicHashCallbackOpReleaseKey2: if (ht->bits.strong_keys2) GCRELEASE(kCFAllocatorSystemDefault, (CFTypeRef)a1); else CFRelease((CFTypeRef)a1); return 0; - case kCFBasicHashCallbackOpValueEqual: - case kCFBasicHashCallbackOpValue2Equal: - case kCFBasicHashCallbackOpKeyEqual: - case kCFBasicHashCallbackOpKey2Equal: return CFEqual((CFTypeRef)a1, (CFTypeRef)a2); - case kCFBasicHashCallbackOpHashKey: - case kCFBasicHashCallbackOpHashKey2: return (uintptr_t)CFHash((CFTypeRef)a1); - case kCFBasicHashCallbackOpDescribeValue: - case kCFBasicHashCallbackOpDescribeValue2: - case kCFBasicHashCallbackOpDescribeKey: - case kCFBasicHashCallbackOpDescribeKey2: return (uintptr_t)CFCopyDescription((CFTypeRef)a1); - } - return 0; +CF_INLINE CFBasicHashValue *__CFBasicHashGetValues(CFConstBasicHashRef ht) { + return (CFBasicHashValue *)ht->pointers[0]; } -__private_extern__ const CFBasicHashCallbacks CFBasicHashNullCallbacks = {__CFBasicHashNullCallback}; -__private_extern__ const CFBasicHashCallbacks CFBasicHashStandardCallbacks = {__CFBasicHashStandardCallback}; - -CF_INLINE uintptr_t __CFBasicHashImportValue(CFBasicHashRef ht, uintptr_t stack_value) { - return ht->callbacks->func(ht, kCFBasicHashCallbackOpRetainValue, stack_value, 0, ht->callbacks); +CF_INLINE void __CFBasicHashSetValues(CFBasicHashRef ht, CFBasicHashValue *ptr) { + __AssignWithWriteBarrier(&ht->pointers[0], ptr); } -CF_INLINE uintptr_t __CFBasicHashImportValue2(CFBasicHashRef ht, uintptr_t stack_value) { - return ht->callbacks->func(ht, kCFBasicHashCallbackOpRetainValue2, stack_value, 0, ht->callbacks); +CF_INLINE CFBasicHashValue *__CFBasicHashGetKeys(CFConstBasicHashRef ht) { + return (CFBasicHashValue *)ht->pointers[ht->bits.keys_offset]; } -CF_INLINE uintptr_t __CFBasicHashImportKey(CFBasicHashRef ht, uintptr_t stack_key) { - return ht->callbacks->func(ht, kCFBasicHashCallbackOpRetainKey, stack_key, 0, ht->callbacks); +CF_INLINE void __CFBasicHashSetKeys(CFBasicHashRef ht, CFBasicHashValue *ptr) { + __AssignWithWriteBarrier(&ht->pointers[ht->bits.keys_offset], ptr); } -CF_INLINE uintptr_t __CFBasicHashImportKey2(CFBasicHashRef ht, uintptr_t stack_key) { - return ht->callbacks->func(ht, kCFBasicHashCallbackOpRetainKey2, stack_key, 0, ht->callbacks); +CF_INLINE void *__CFBasicHashGetCounts(CFConstBasicHashRef ht) { + return (void *)ht->pointers[ht->bits.counts_offset]; } -CF_INLINE void __CFBasicHashEjectValue(CFBasicHashRef ht, uintptr_t stack_value) { - ht->callbacks->func(ht, kCFBasicHashCallbackOpReleaseValue, stack_value, 0, ht->callbacks); +CF_INLINE void __CFBasicHashSetCounts(CFBasicHashRef ht, void *ptr) { + __AssignWithWriteBarrier(&ht->pointers[ht->bits.counts_offset], ptr); } -CF_INLINE void __CFBasicHashEjectValue2(CFBasicHashRef ht, uintptr_t stack_value) { - ht->callbacks->func(ht, kCFBasicHashCallbackOpReleaseValue2, stack_value, 0, ht->callbacks); +CF_INLINE uintptr_t __CFBasicHashGetValue(CFConstBasicHashRef ht, CFIndex idx) { + uintptr_t val = __CFBasicHashGetValues(ht)[idx].neutral; + if (__CFBasicHashSubABZero == val) return 0UL; + if (__CFBasicHashSubABOne == val) return ~0UL; + return val; } -CF_INLINE void __CFBasicHashEjectKey(CFBasicHashRef ht, uintptr_t stack_key) { - ht->callbacks->func(ht, kCFBasicHashCallbackOpReleaseKey, stack_key, 0, ht->callbacks); +CF_INLINE void __CFBasicHashSetValue(CFBasicHashRef ht, CFIndex idx, uintptr_t stack_value, Boolean ignoreOld, Boolean literal) { + CFBasicHashValue *valuep = &(__CFBasicHashGetValues(ht)[idx]); + uintptr_t old_value = ignoreOld ? 0 : valuep->neutral; + if (!literal) { + if (0UL == stack_value) stack_value = __CFBasicHashSubABZero; + if (~0UL == stack_value) stack_value = __CFBasicHashSubABOne; + } + if (CFBasicHashHasStrongValues(ht)) valuep->strong = (id)stack_value; else valuep->neutral = stack_value; + if (!ignoreOld) { + if (!(old_value == 0UL || old_value == ~0UL)) { + if (__CFBasicHashSubABZero == old_value) old_value = 0UL; + if (__CFBasicHashSubABOne == old_value) old_value = ~0UL; + __CFBasicHashEjectValue(ht, old_value); + } + } } -CF_INLINE void __CFBasicHashEjectKey2(CFBasicHashRef ht, uintptr_t stack_key) { - ht->callbacks->func(ht, kCFBasicHashCallbackOpReleaseKey2, stack_key, 0, ht->callbacks); +CF_INLINE uintptr_t __CFBasicHashGetKey(CFConstBasicHashRef ht, CFIndex idx) { + if (ht->bits.keys_offset) { + uintptr_t key = __CFBasicHashGetKeys(ht)[idx].neutral; + if (__CFBasicHashSubABZero == key) return 0UL; + if (__CFBasicHashSubABOne == key) return ~0UL; + return key; + } + if (ht->bits.indirect_keys) { + uintptr_t stack_value = __CFBasicHashGetValue(ht, idx); + return ht->callbacks->getIndirectKey(ht, stack_value); + } + return __CFBasicHashGetValue(ht, idx); } -CF_INLINE Boolean __CFBasicHashTestEqualValue(CFBasicHashRef ht, uintptr_t stack_value_a, uintptr_t stack_value_b) { - return (Boolean)ht->callbacks->func(ht, kCFBasicHashCallbackOpValueEqual, stack_value_a, stack_value_b, ht->callbacks); +CF_INLINE void __CFBasicHashSetKey(CFBasicHashRef ht, CFIndex idx, uintptr_t stack_key, Boolean ignoreOld, Boolean literal) { + if (0 == ht->bits.keys_offset) HALT; + CFBasicHashValue *keyp = &(__CFBasicHashGetKeys(ht)[idx]); + uintptr_t old_key = ignoreOld ? 0 : keyp->neutral; + if (!literal) { + if (0UL == stack_key) stack_key = __CFBasicHashSubABZero; + if (~0UL == stack_key) stack_key = __CFBasicHashSubABOne; + } + if (CFBasicHashHasStrongKeys(ht)) keyp->strong = (id)stack_key; else keyp->neutral = stack_key; + if (!ignoreOld) { + if (!(old_key == 0UL || old_key == ~0UL)) { + if (__CFBasicHashSubABZero == old_key) old_key = 0UL; + if (__CFBasicHashSubABOne == old_key) old_key = ~0UL; + __CFBasicHashEjectKey(ht, old_key); + } + } } -CF_INLINE Boolean __CFBasicHashTestEqualValue2(CFBasicHashRef ht, uintptr_t stack_value_a, uintptr_t stack_value_b) { - return (Boolean)ht->callbacks->func(ht, kCFBasicHashCallbackOpValue2Equal, stack_value_a, stack_value_b, ht->callbacks); +CF_INLINE uintptr_t __CFBasicHashIsEmptyOrDeleted(CFConstBasicHashRef ht, CFIndex idx) { + uintptr_t stack_value = __CFBasicHashGetValues(ht)[idx].neutral; + return (0UL == stack_value || ~0UL == stack_value); } -CF_INLINE Boolean __CFBasicHashTestEqualKey(CFBasicHashRef ht, uintptr_t stack_key_a, uintptr_t stack_key_b) { - COCOA_HASHTABLE_TEST_EQUAL(ht, stack_key_a, stack_key_b); - return (Boolean)ht->callbacks->func(ht, kCFBasicHashCallbackOpKeyEqual, stack_key_a, stack_key_b, ht->callbacks); +CF_INLINE uintptr_t __CFBasicHashIsDeleted(CFConstBasicHashRef ht, CFIndex idx) { + uintptr_t stack_value = __CFBasicHashGetValues(ht)[idx].neutral; + return (~0UL == stack_value); } -CF_INLINE Boolean __CFBasicHashTestEqualKey2(CFBasicHashRef ht, uintptr_t stack_key_a, uintptr_t stack_key_b) { - COCOA_HASHTABLE_TEST_EQUAL(ht, stack_key_a, stack_key_b); - return (Boolean)ht->callbacks->func(ht, kCFBasicHashCallbackOpKey2Equal, stack_key_a, stack_key_b, ht->callbacks); +CF_INLINE uintptr_t __CFBasicHashGetSlotCount(CFConstBasicHashRef ht, CFIndex idx) { + void *counts = __CFBasicHashGetCounts(ht); + switch (ht->bits.counts_width) { + case 0: return ((uint8_t *)counts)[idx]; + case 1: return ((uint16_t *)counts)[idx]; + case 2: return ((uint32_t *)counts)[idx]; + case 3: return ((uint64_t *)counts)[idx]; + } + return 0; } -CF_INLINE CFHashCode __CFBasicHashHashKey(CFBasicHashRef ht, uintptr_t stack_key) { - CFHashCode hash_code = (CFHashCode)ht->callbacks->func(ht, kCFBasicHashCallbackOpHashKey, stack_key, 0, ht->callbacks); - COCOA_HASHTABLE_HASH_KEY(ht, stack_key, hash_code); - return hash_code; +CF_INLINE void __CFBasicHashBumpCounts(CFBasicHashRef ht) { + void *counts = __CFBasicHashGetCounts(ht); + CFAllocatorRef allocator = CFGetAllocator(ht); + switch (ht->bits.counts_width) { + case 0: { + uint8_t *counts08 = (uint8_t *)counts; + 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); + __SetLastAllocationEventName(counts16, "CFBasicHash (count-store)"); + for (CFIndex idx2 = 0; idx2 < num_buckets; idx2++) { + counts16[idx2] = counts08[idx2]; + } + __CFBasicHashSetCounts(ht, counts16); + if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + CFAllocatorDeallocate(allocator, counts08); + } + break; + } + case 1: { + uint16_t *counts16 = (uint16_t *)counts; + 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); + __SetLastAllocationEventName(counts32, "CFBasicHash (count-store)"); + for (CFIndex idx2 = 0; idx2 < num_buckets; idx2++) { + counts32[idx2] = counts16[idx2]; + } + __CFBasicHashSetCounts(ht, counts32); + if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + CFAllocatorDeallocate(allocator, counts16); + } + break; + } + case 2: { + uint32_t *counts32 = (uint32_t *)counts; + 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); + __SetLastAllocationEventName(counts64, "CFBasicHash (count-store)"); + for (CFIndex idx2 = 0; idx2 < num_buckets; idx2++) { + counts64[idx2] = counts32[idx2]; + } + __CFBasicHashSetCounts(ht, counts64); + if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + CFAllocatorDeallocate(allocator, counts32); + } + break; + } + case 3: { + HALT; + break; + } + } } -CF_INLINE CFHashCode __CFBasicHashHashKey2(CFBasicHashRef ht, uintptr_t stack_key) { - CFHashCode hash_code = (CFHashCode)ht->callbacks->func(ht, kCFBasicHashCallbackOpHashKey2, stack_key, 0, ht->callbacks); - COCOA_HASHTABLE_HASH_KEY(ht, stack_key, hash_code); - return hash_code; +static void __CFBasicHashIncSlotCount(CFBasicHashRef ht, CFIndex idx) { + void *counts = __CFBasicHashGetCounts(ht); + switch (ht->bits.counts_width) { + case 0: { + uint8_t *counts08 = (uint8_t *)counts; + uint8_t val = counts08[idx]; + if (val < INT8_MAX) { + counts08[idx] = val + 1; + return; + } + __CFBasicHashBumpCounts(ht); + __CFBasicHashIncSlotCount(ht, idx); + break; + } + case 1: { + uint16_t *counts16 = (uint16_t *)counts; + uint16_t val = counts16[idx]; + if (val < INT16_MAX) { + counts16[idx] = val + 1; + return; + } + __CFBasicHashBumpCounts(ht); + __CFBasicHashIncSlotCount(ht, idx); + break; + } + case 2: { + uint32_t *counts32 = (uint32_t *)counts; + uint32_t val = counts32[idx]; + if (val < INT32_MAX) { + counts32[idx] = val + 1; + return; + } + __CFBasicHashBumpCounts(ht); + __CFBasicHashIncSlotCount(ht, idx); + break; + } + case 3: { + uint64_t *counts64 = (uint64_t *)counts; + uint64_t val = counts64[idx]; + if (val < INT64_MAX) { + counts64[idx] = val + 1; + return; + } + __CFBasicHashBumpCounts(ht); + __CFBasicHashIncSlotCount(ht, idx); + break; + } + } } -CF_INLINE void *__CFBasicHashAllocateMemory(CFBasicHashRef ht, CFIndex count, CFIndex elem_size, Boolean strong) { - CFAllocatorRef allocator = CFGetAllocator(ht); - void *new_mem = NULL; - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - new_mem = auto_zone_allocate_object(auto_zone(), count * elem_size, strong ? AUTO_MEMORY_SCANNED : AUTO_UNSCANNED, false, false); - } else { - new_mem = CFAllocatorAllocate(allocator, count * elem_size, 0); +CF_INLINE void __CFBasicHashDecSlotCount(CFBasicHashRef ht, CFIndex idx) { + void *counts = __CFBasicHashGetCounts(ht); + switch (ht->bits.counts_width) { + case 0: ((uint8_t *)counts)[idx]--; return; + case 1: ((uint16_t *)counts)[idx]--; return; + case 2: ((uint32_t *)counts)[idx]--; return; + case 3: ((uint64_t *)counts)[idx]--; return; } - if (!new_mem) HALT; - return new_mem; } +CF_INLINE uintptr_t *__CFBasicHashGetHashes(CFConstBasicHashRef ht) { + return (uintptr_t *)ht->pointers[ht->bits.hashes_offset]; +} -// Prime numbers. Values above 100 have been adjusted up so that the -// malloced block size will be just below a multiple of 512; values -// above 1200 have been adjusted up to just below a multiple of 4096. -static const uintptr_t __CFBasicHashTableSizes[64] = { - 0, 3, 7, 13, 23, 41, 71, 127, 191, 251, 383, 631, 1087, 1723, - 2803, 4523, 7351, 11959, 19447, 31231, 50683, 81919, 132607, - 214519, 346607, 561109, 907759, 1468927, 2376191, 3845119, - 6221311, 10066421, 16287743, 26354171, 42641881, 68996069, - 111638519, 180634607, 292272623, 472907251, -#if __LP64__ - 765180413UL, 1238087663UL, 2003267557UL, 3241355263UL, 5244622819UL, - 8485977589UL, 13730600407UL, 22216578047UL, 35947178479UL, - 58163756537UL, 94110934997UL, 152274691561UL, 246385626107UL, - 398660317687UL, 645045943807UL, 1043706260983UL, 1688752204787UL, - 2732458465769UL, 4421210670577UL, 7153669136377UL, - 11574879807461UL, 18728548943849UL, 30303428750843UL -#endif -}; - -// Primitive roots for the primes above -static const uintptr_t __CFBasicHashPrimitiveRoots[64] = { - 0, 2, 3, 2, 5, 6, 7, 3, 19, 6, 5, 3, 3, 3, - 2, 5, 6, 3, 3, 6, 2, 3, 3, - 3, 5, 10, 3, 3, 22, 3, - 3, 3, 5, 2, 22, 2, - 11, 5, 5, 2, -#if __LP64__ - 3, 10, 2, 3, 10, - 2, 3, 5, 3, - 3, 2, 7, 2, - 3, 3, 3, 2, - 3, 5, 5, - 2, 3, 2 -#endif -}; - -/* Primitive roots under 100 for the primes above -3: 2 -7: 3 5 -13: 2 6 7 11 -23: 5 7 10 11 14 15 17 19 20 21 -41: 6 7 11 12 13 15 17 19 22 24 26 28 29 30 34 35 -71: 7 11 13 21 22 28 31 33 35 42 44 47 52 53 55 56 59 61 62 63 65 67 68 69 -127: 3 6 7 12 14 23 29 39 43 45 46 48 53 55 56 57 58 65 67 78 83 85 86 91 92 93 96 97 -191: 19 21 22 28 29 33 35 42 44 47 53 56 57 58 61 62 63 71 73 74 76 83 87 88 89 91 93 94 95 99 -251: 6 11 14 18 19 24 26 29 30 33 34 37 42 43 44 46 53 54 55 56 57 59 61 62 70 71 72 76 77 78 82 87 90 95 96 97 98 99 -383: 5 10 11 13 15 20 22 26 30 33 35 37 39 40 41 44 45 47 52 53 59 60 61 66 70 74 77 78 79 80 82 83 85 88 89 90 91 94 95 97 99 -631: 3 7 12 13 14 15 19 26 51 53 54 56 59 60 61 63 65 70 75 76 87 93 95 96 99 -1087: 3 10 12 13 14 20 22 24 28 29 31 38 44 45 46 51 52 53 54 58 59 61 62 63 67 74 75 76 80 89 90 92 94 96 97 99 -1723: 3 12 17 18 29 30 38 45 46 48 55 63 74 75 77 78 82 83 86 88 94 95 -2803: 2 11 12 18 20 21 29 30 32 34 35 38 41 46 48 50 52 56 66 67 74 78 79 80 83 84 86 91 93 94 98 99 -4523: 5 6 7 15 18 20 22 24 26 31 34 41 45 54 55 57 60 65 66 70 72 74 76 77 83 85 88 93 94 96 98 -7351: 6 7 12 15 17 22 28 31 35 38 44 52 54 55 56 60 65 69 71 75 96 -11959: 3 6 12 24 29 33 37 39 41 47 48 51 53 57 58 59 66 67 69 73 74 75 78 82 94 96 -19447: 3 5 6 7 10 12 14 20 23 24 28 29 37 39 45 46 47 51 55 56 58 65 71 73 74 75 78 79 80 82 83 90 91 92 94 96 -31231: 6 7 24 29 30 33 41 43 48 52 53 54 56 57 59 60 62 65 69 70 73 75 77 83 86 -50683: 2 3 12 14 17 18 20 32 33 35 39 41 45 50 55 56 57 58 61 62 65 68 69 71 72 74 75 80 84 86 88 93 95 -81919: 3 12 23 24 26 30 33 43 52 53 54 57 59 60 65 66 75 84 86 87 91 92 93 96 97 -132607: 3 5 6 17 19 20 21 23 24 26 29 33 34 35 38 40 42 45 48 52 54 61 62 67 71 73 75 79 82 86 89 90 92 -214519: 3 7 12 15 19 24 26 28 30 33 35 38 41 52 54 56 61 65 69 70 73 77 86 87 89 93 96 97 -346607: 5 10 14 15 17 19 20 21 28 30 34 38 40 41 42 45 51 55 56 57 59 60 63 65 67 68 76 77 80 82 84 89 90 91 97 -561109: 10 11 18 21 26 30 33 35 38 40 41 43 46 47 50 51 53 61 62 72 73 74 84 85 91 96 -907759: 3 6 12 13 17 24 26 33 34 41 47 48 52 57 61 66 68 71 75 79 82 87 89 93 94 -1468927: 3 5 6 11 20 21 22 23 24 26 35 40 42 45 48 51 52 54 58 71 73 75 77 79 86 88 90 92 93 94 95 -2376191: 22 29 31 33 37 43 44 47 55 58 59 62 66 77 86 87 88 93 99 -3845119: 3 11 12 13 15 23 24 30 37 42 43 44 51 52 53 54 55 57 65 73 84 86 87 88 89 92 94 96 97 -6221311: 3 12 13 15 21 24 30 31 33 46 54 57 61 66 67 74 82 84 87 89 91 92 96 -10066421: 3 10 11 12 17 18 19 21 23 27 39 40 41 48 50 56 58 60 61 66 68 71 72 73 74 75 76 77 83 85 86 87 92 94 95 97 -16287743: 5 10 15 20 30 31 35 40 43 45 47 53 55 59 60 61 62 65 70 73 79 80 85 86 89 90 93 94 95 -26354171: 2 6 7 8 10 17 18 21 22 23 24 26 30 35 38 40 50 51 53 59 62 63 66 67 68 69 71 72 74 77 78 83 84 85 87 88 90 91 96 98 -42641881: 22 31 38 44 46 57 59 62 67 69 73 76 77 83 92 99 -68996069: 2 3 8 10 11 12 14 15 17 18 21 26 27 32 37 38 40 43 44 46 47 48 50 53 55 56 58 60 61 62 66 67 68 69 70 72 75 77 82 84 85 87 89 90 93 98 99 -111638519: 11 13 17 22 26 29 33 34 39 41 44 51 52 53 55 58 59 61 65 66 67 68 71 77 78 79 82 83 85 87 88 91 97 99 -180634607: 5 10 15 19 20 23 30 31 35 37 38 40 43 45 46 47 55 57 60 62 65 69 70 74 76 79 80 85 86 89 90 92 93 94 -292272623: 5 10 11 13 15 20 22 23 26 30 31 33 35 39 40 44 45 46 47 52 59 60 61 62 66 67 69 70 71 77 78 79 80 83 85 88 90 91 92 93 94 95 97 99 -472907251: 2 10 12 14 17 18 29 31 37 46 50 60 61 65 68 70 78 82 84 85 90 91 94 98 -765180413: 3 5 11 12 14 18 20 21 23 26 27 29 30 34 35 38 39 44 45 47 48 50 51 56 57 59 62 66 67 71 72 73 74 75 77 80 82 84 85 86 89 92 93 95 97 98 99 -1238087663: 10 13 14 15 20 21 23 28 38 40 41 42 43 45 46 52 55 56 57 60 63 67 69 71 76 78 80 82 84 85 86 89 90 92 -2003267557: 2 13 14 18 20 22 23 24 31 32 34 37 38 41 43 47 50 54 59 60 67 69 79 80 85 87 91 93 96 -3241355263: 3 6 10 11 20 21 22 24 34 42 43 45 46 48 54 57 61 65 68 70 71 75 77 78 80 83 86 87 88 92 93 94 -5244622819: 10 15 17 23 29 31 35 38 40 50 57 60 65 67 68 71 73 74 75 79 90 92 94 -8485977589: 2 6 10 17 18 19 22 28 30 31 32 35 37 40 47 51 52 54 57 58 59 61 65 66 76 77 79 84 85 86 88 90 93 96 98 -13730600407: 3 5 10 12 19 24 33 35 40 42 43 45 46 51 54 55 65 73 75 76 78 80 82 84 87 89 92 93 94 96 -22216578047: 5 10 11 15 17 20 22 30 33 34 35 40 44 45 51 59 60 61 65 66 68 70 73 77 79 80 88 90 95 99 -35947178479: 3 12 14 15 22 24 29 30 38 41 44 51 54 55 56 58 63 69 70 73 76 78 89 91 95 96 97 99 -58163756537: 3 5 6 7 10 11 12 14 17 20 22 23 24 27 28 31 39 40 43 44 45 46 47 48 53 54 56 57 59 61 62 63 65 68 71 73 75 78 79 80 86 87 88 89 90 91 92 94 95 96 97 99 -94110934997: 2 3 5 8 11 12 14 18 19 20 21 23 26 27 29 30 32 34 35 39 41 43 44 48 51 56 59 62 66 67 71 72 74 75 76 77 79 80 84 85 92 93 94 98 99 -152274691561: 7 17 26 35 37 39 41 42 43 53 56 62 63 65 67 74 82 84 85 89 93 94 -246385626107UL: 2 5 6 8 11 14 15 18 20 23 24 26 29 31 32 33 34 35 37 38 42 43 44 45 50 54 56 60 61 65 67 69 71 72 77 78 80 82 83 85 87 89 92 93 94 95 96 98 99 -398660317687UL: 3 5 6 7 11 13 20 24 26 28 40 44 45 48 54 56 59 63 69 75 79 85 88 89 90 93 95 99 -645045943807UL: 3 5 10 12 21 22 23 24 26 35 37 40 41 44 45 47 51 52 53 59 70 75 79 85 87 92 93 95 96 97 99 -1043706260983UL: 3 7 11 24 28 29 (<= 32) -1688752204787UL: 2 5 6 7 8 13 18 20 21 22 23 24 28 32 (<= 32) -2732458465769UL: 3 6 11 12 13 15 17 19 21 22 23 24 26 27 30 31 (<= 32) -4421210670577UL: 5 (<= 9) - -*/ +CF_INLINE void __CFBasicHashSetHashes(CFBasicHashRef ht, uintptr_t *ptr) { + __AssignWithWriteBarrier(&ht->pointers[ht->bits.hashes_offset], ptr); +} -static const uintptr_t __CFBasicHashTableCapacities[64] = { - 0, 3, 6, 11, 19, 32, 52, 85, 118, 155, 237, 390, 672, 1065, - 1732, 2795, 4543, 7391, 12019, 19302, 31324, 50629, 81956, - 132580, 214215, 346784, 561026, 907847, 1468567, 2376414, - 3844982, 6221390, 10066379, 16287773, 26354132, 42641916, - 68996399, 111638327, 180634415, 292272755, -#if __LP64__ - 472907503UL, 765180257UL, 1238087439UL, 2003267722UL, 3241355160UL, - 5244622578UL, 8485977737UL, 13730600347UL, 22216578100UL, - 35947178453UL, 58163756541UL, 94110935011UL, 152274691274UL, - 246385626296UL, 398660317578UL, 645045943559UL, 1043706261135UL, - 1688752204693UL, 2732458465840UL, 4421210670552UL, - 7153669136706UL, 11574879807265UL, 18728548943682UL -#endif -}; // to expose the load factor, expose this function to customization -CF_INLINE CFIndex __CFBasicHashGetCapacityForNumBuckets(CFBasicHashRef ht, CFIndex num_buckets_idx) { +CF_INLINE CFIndex __CFBasicHashGetCapacityForNumBuckets(CFConstBasicHashRef ht, CFIndex num_buckets_idx) { return __CFBasicHashTableCapacities[num_buckets_idx]; -#if 0 - CFIndex num_buckets = __CFBasicHashTableSizes[num_buckets_idx]; - if (num_buckets_idx < 8) { - double dep = 0.0545665730357293074; // (1 - (sqrt(5) - 1) / 2) / 7 - double factor = 1.0 - (num_buckets_idx - 1) * dep; - return (CFIndex)floor(num_buckets * factor + 0.375); // 0.375 is intentional - } - double factor = 0.6180339887498948482; // (sqrt(5) - 1) / 2 - return (CFIndex)floor(num_buckets * factor + 0.5); -#endif } -CF_INLINE CFIndex __CFBasicHashGetNumBucketsIndexForCapacity(CFBasicHashRef ht, CFIndex capacity) { +CF_INLINE CFIndex __CFBasicHashGetNumBucketsIndexForCapacity(CFConstBasicHashRef ht, CFIndex capacity) { for (CFIndex idx = 0; idx < 64; idx++) { if (capacity <= __CFBasicHashGetCapacityForNumBuckets(ht, idx)) return idx; } @@ -572,11 +654,11 @@ CF_INLINE CFIndex __CFBasicHashGetNumBucketsIndexForCapacity(CFBasicHashRef ht, return 0; } -__private_extern__ CFIndex CFBasicHashGetNumBuckets(CFBasicHashRef ht) { +__private_extern__ CFIndex CFBasicHashGetNumBuckets(CFConstBasicHashRef ht) { return __CFBasicHashTableSizes[ht->bits.num_buckets_idx]; } -__private_extern__ CFIndex CFBasicHashGetCapacity(CFBasicHashRef ht) { +__private_extern__ CFIndex CFBasicHashGetCapacity(CFConstBasicHashRef ht) { return __CFBasicHashGetCapacityForNumBuckets(ht, ht->bits.num_buckets_idx); } @@ -585,280 +667,252 @@ __private_extern__ CFIndex CFBasicHashGetCapacity(CFBasicHashRef ht) { // the found bucket or the index of the bucket which should be filled by // an add operation. For a set or multiset, the .weak_key and .weak_value // are the same. -__private_extern__ CFBasicHashBucket CFBasicHashGetBucket(CFBasicHashRef ht, CFIndex idx) { - uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty; +__private_extern__ CFBasicHashBucket CFBasicHashGetBucket(CFConstBasicHashRef ht, CFIndex idx) { CFBasicHashBucket result; result.idx = idx; - result.weak_value = __CFBasicHashGetValues(ht)[idx].weak; - result.weak_value2 = (0 != ht->bits.values2_offset) ? __CFBasicHashGetValues2(ht)[idx].weak : 0; - result.weak_key = (0 != ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht)[idx].weak : result.weak_value; - result.weak_key2 = (0 != ht->bits.keys2_offset) ? __CFBasicHashGetKeys2(ht)[idx].weak : 0; - result.count = (0 != ht->bits.counts_offset) ? __CFBasicHashGetCounts(ht)[idx] : ((result.weak_key == empty || result.weak_key == deleted) ? 0 : 1); - result.order = (0 != ht->bits.orders_offset) ? __CFBasicHashGetOrders(ht)[idx] : 0; + if (__CFBasicHashIsEmptyOrDeleted(ht, idx)) { + result.count = 0; + result.weak_value = 0; + result.weak_key = 0; + } else { + result.count = (ht->bits.counts_offset) ? __CFBasicHashGetSlotCount(ht, idx) : 1; + result.weak_value = __CFBasicHashGetValue(ht, idx); + result.weak_key = __CFBasicHashGetKey(ht, idx); + } return result; } -// During rehashing of a mutable CFBasicHash, we know that there are no -// deleted slots and the keys have already been uniqued. When rehashing, -// if key_hash is non-0, we use it as the hash code. -static CFBasicHashBucket ___CFBasicHashFindBucket1(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t key_hash, Boolean rehashing) { - CFHashCode hash_code = key_hash ? key_hash : __CFBasicHashHashKey(ht, stack_key); - uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty; - CFBasicHashValue *keys = (0 != ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht) : __CFBasicHashGetValues(ht); - uintptr_t *hashes = (0 != ht->bits.hashes_offset) ? __CFBasicHashGetHashes(ht) : NULL; - uintptr_t num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx]; - CFBasicHashBucket result = {kCFNotFound, deleted, 0, deleted, 0, 0, 0}; - - uintptr_t h1 = 0; - // Linear probing, with c = 1 - // probe[0] = h1(k) - // probe[i] = (h1(k) + i * c) mod num_buckets, i = 1 .. num_buckets - 1 - // h1(k) = k mod num_buckets - h1 = hash_code % num_buckets; - - COCOA_HASHTABLE_PROBING_START(ht, num_buckets); - uintptr_t probe = h1; - for (CFIndex idx = 0; idx < num_buckets; idx++) { - uintptr_t stack_curr = keys[probe].weak; - if (stack_curr == empty) { - COCOA_HASHTABLE_PROBE_EMPTY(ht, probe); - if (kCFNotFound == result.idx) { - result.idx = probe; - result.weak_value = empty; - result.weak_key = empty; - } - COCOA_HASHTABLE_PROBING_END(ht, idx + 1); - return result; - } else if (__builtin_expect(!rehashing, 0)) { - if (stack_curr == deleted) { - COCOA_HASHTABLE_PROBE_DELETED(ht, probe); - if (kCFNotFound == result.idx) { - result.idx = probe; - } - } else { - COCOA_HASHTABLE_PROBE_VALID(ht, probe); - if (stack_curr == stack_key || ((!hashes || hashes[probe] == hash_code) && __CFBasicHashTestEqualKey(ht, stack_curr, stack_key))) { - COCOA_HASHTABLE_PROBING_END(ht, idx + 1); - result.idx = probe; - result.weak_value = (0 != ht->bits.keys_offset) ? __CFBasicHashGetValues(ht)[probe].weak : stack_curr; - result.weak_value2 = (0 != ht->bits.values2_offset) ? __CFBasicHashGetValues2(ht)[probe].weak : 0; - result.weak_key = stack_curr; - result.weak_key2 = (0 != ht->bits.keys2_offset) ? __CFBasicHashGetKeys2(ht)[probe].weak : 0; - result.count = (0 != ht->bits.counts_offset) ? __CFBasicHashGetCounts(ht)[probe] : 1; - result.order = (0 != ht->bits.orders_offset) ? __CFBasicHashGetOrders(ht)[probe] : 1; - return result; - } - } - } - // Linear probing, with c = 1 - probe += 1; - if (__builtin_expect(num_buckets <= probe, 0)) { - probe -= num_buckets; - } +#if defined(__arm__) +static uintptr_t __CFBasicHashFold(uintptr_t dividend, uint8_t idx) { + switch (idx) { + case 1: return dividend % 3; + case 2: return dividend % 7; + case 3: return dividend % 13; + case 4: return dividend % 23; + case 5: return dividend % 41; + case 6: return dividend % 71; + case 7: return dividend % 127; + case 8: return dividend % 191; + case 9: return dividend % 251; + case 10: return dividend % 383; + case 11: return dividend % 631; + case 12: return dividend % 1087; + case 13: return dividend % 1723; + case 14: return dividend % 2803; + case 15: return dividend % 4523; + case 16: return dividend % 7351; + case 17: return dividend % 11959; + case 18: return dividend % 19447; + case 19: return dividend % 31231; + case 20: return dividend % 50683; + case 21: return dividend % 81919; + case 22: return dividend % 132607; + case 23: return dividend % 214519; + case 24: return dividend % 346607; + case 25: return dividend % 561109; + case 26: return dividend % 907759; + case 27: return dividend % 1468927; + case 28: return dividend % 2376191; + case 29: return dividend % 3845119; + case 30: return dividend % 6221311; + case 31: return dividend % 10066421; + case 32: return dividend % 16287743; + case 33: return dividend % 26354171; + case 34: return dividend % 42641881; + case 35: return dividend % 68996069; + case 36: return dividend % 111638519; + case 37: return dividend % 180634607; + case 38: return dividend % 292272623; + case 39: return dividend % 472907251; } - COCOA_HASHTABLE_PROBING_END(ht, num_buckets); - return result; // all buckets full or deleted, return first deleted element which was found -} - -static CFBasicHashBucket ___CFBasicHashFindBucket2(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t key_hash, Boolean rehashing) { - CFHashCode hash_code = key_hash ? key_hash : __CFBasicHashHashKey(ht, stack_key); - uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty; - CFBasicHashValue *keys = (0 != ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht) : __CFBasicHashGetValues(ht); - uintptr_t *hashes = (0 != ht->bits.hashes_offset) ? __CFBasicHashGetHashes(ht) : NULL; - uintptr_t num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx]; - CFBasicHashBucket result = {kCFNotFound, deleted, 0, deleted, 0, 0, 0}; - - uintptr_t h1 = 0, h2 = 0; - // Double hashing - // probe[0] = h1(k) - // probe[i] = (h1(k) + i * h2(k)) mod num_buckets, i = 1 .. num_buckets - 1 - // h1(k) = k mod num_buckets - // h2(k) = floor(k / num_buckets) mod num_buckets - h1 = hash_code % num_buckets; - h2 = (hash_code / num_buckets) % num_buckets; - if (0 == h2) h2 = num_buckets - 1; - - COCOA_HASHTABLE_PROBING_START(ht, num_buckets); - uintptr_t probe = h1; - for (CFIndex idx = 0; idx < num_buckets; idx++) { - uintptr_t stack_curr = keys[probe].weak; - if (stack_curr == empty) { - COCOA_HASHTABLE_PROBE_EMPTY(ht, probe); - if (kCFNotFound == result.idx) { - result.idx = probe; - result.weak_value = empty; - result.weak_key = empty; - } - COCOA_HASHTABLE_PROBING_END(ht, idx + 1); - return result; - } else if (__builtin_expect(!rehashing, 0)) { - if (stack_curr == deleted) { - COCOA_HASHTABLE_PROBE_DELETED(ht, probe); - if (kCFNotFound == result.idx) { - result.idx = probe; - } - } else { - COCOA_HASHTABLE_PROBE_VALID(ht, probe); - if (stack_curr == stack_key || ((!hashes || hashes[probe] == hash_code) && __CFBasicHashTestEqualKey(ht, stack_curr, stack_key))) { - COCOA_HASHTABLE_PROBING_END(ht, idx + 1); - result.idx = probe; - result.weak_value = (0 != ht->bits.keys_offset) ? __CFBasicHashGetValues(ht)[probe].weak : stack_curr; - result.weak_value2 = (0 != ht->bits.values2_offset) ? __CFBasicHashGetValues2(ht)[probe].weak : 0; - result.weak_key = stack_curr; - result.weak_key2 = (0 != ht->bits.keys2_offset) ? __CFBasicHashGetKeys2(ht)[probe].weak : 0; - result.count = (0 != ht->bits.counts_offset) ? __CFBasicHashGetCounts(ht)[probe] : 1; - result.order = (0 != ht->bits.orders_offset) ? __CFBasicHashGetOrders(ht)[probe] : 1; - return result; - } - } - } - // Double hashing - probe += h2; - if (__builtin_expect(num_buckets <= probe, 1)) { - probe -= num_buckets; - } + HALT; + return ~0; +} +#endif + + +#define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Linear +#define FIND_BUCKET_HASH_STYLE 1 +#define FIND_BUCKET_FOR_REHASH 0 +#define FIND_BUCKET_FOR_INDIRECT_KEY 0 +#include "CFBasicHashFindBucket.m" + +#define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Linear_NoCollision +#define FIND_BUCKET_HASH_STYLE 1 +#define FIND_BUCKET_FOR_REHASH 1 +#define FIND_BUCKET_FOR_INDIRECT_KEY 0 +#include "CFBasicHashFindBucket.m" + +#define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Linear_Indirect +#define FIND_BUCKET_HASH_STYLE 1 +#define FIND_BUCKET_FOR_REHASH 0 +#define FIND_BUCKET_FOR_INDIRECT_KEY 1 +#include "CFBasicHashFindBucket.m" + +#define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Linear_Indirect_NoCollision +#define FIND_BUCKET_HASH_STYLE 1 +#define FIND_BUCKET_FOR_REHASH 1 +#define FIND_BUCKET_FOR_INDIRECT_KEY 1 +#include "CFBasicHashFindBucket.m" + +#define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Double +#define FIND_BUCKET_HASH_STYLE 2 +#define FIND_BUCKET_FOR_REHASH 0 +#define FIND_BUCKET_FOR_INDIRECT_KEY 0 +#include "CFBasicHashFindBucket.m" + +#define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Double_NoCollision +#define FIND_BUCKET_HASH_STYLE 2 +#define FIND_BUCKET_FOR_REHASH 1 +#define FIND_BUCKET_FOR_INDIRECT_KEY 0 +#include "CFBasicHashFindBucket.m" + +#define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Double_Indirect +#define FIND_BUCKET_HASH_STYLE 2 +#define FIND_BUCKET_FOR_REHASH 0 +#define FIND_BUCKET_FOR_INDIRECT_KEY 1 +#include "CFBasicHashFindBucket.m" + +#define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Double_Indirect_NoCollision +#define FIND_BUCKET_HASH_STYLE 2 +#define FIND_BUCKET_FOR_REHASH 1 +#define FIND_BUCKET_FOR_INDIRECT_KEY 1 +#include "CFBasicHashFindBucket.m" + +#define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Exponential +#define FIND_BUCKET_HASH_STYLE 3 +#define FIND_BUCKET_FOR_REHASH 0 +#define FIND_BUCKET_FOR_INDIRECT_KEY 0 +#include "CFBasicHashFindBucket.m" + +#define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Exponential_NoCollision +#define FIND_BUCKET_HASH_STYLE 3 +#define FIND_BUCKET_FOR_REHASH 1 +#define FIND_BUCKET_FOR_INDIRECT_KEY 0 +#include "CFBasicHashFindBucket.m" + +#define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Exponential_Indirect +#define FIND_BUCKET_HASH_STYLE 3 +#define FIND_BUCKET_FOR_REHASH 0 +#define FIND_BUCKET_FOR_INDIRECT_KEY 1 +#include "CFBasicHashFindBucket.m" + +#define FIND_BUCKET_NAME ___CFBasicHashFindBucket_Exponential_Indirect_NoCollision +#define FIND_BUCKET_HASH_STYLE 3 +#define FIND_BUCKET_FOR_REHASH 1 +#define FIND_BUCKET_FOR_INDIRECT_KEY 1 +#include "CFBasicHashFindBucket.m" + + +CF_INLINE CFBasicHashBucket __CFBasicHashFindBucket(CFConstBasicHashRef ht, uintptr_t stack_key) { + if (0 == ht->bits.num_buckets_idx) { + CFBasicHashBucket result = {kCFNotFound, 0UL, 0UL, 0}; + return result; } - COCOA_HASHTABLE_PROBING_END(ht, num_buckets); - return result; // all buckets full or deleted, return first deleted element which was found -} - -static CFBasicHashBucket ___CFBasicHashFindBucket3(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t key_hash, Boolean rehashing) { - CFHashCode hash_code = key_hash ? key_hash : __CFBasicHashHashKey(ht, stack_key); - uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty; - CFBasicHashValue *keys = (0 != ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht) : __CFBasicHashGetValues(ht); - uintptr_t *hashes = (0 != ht->bits.hashes_offset) ? __CFBasicHashGetHashes(ht) : NULL; - uintptr_t num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx]; - CFBasicHashBucket result = {kCFNotFound, deleted, 0, deleted, 0, 0, 0}; - - uintptr_t h1 = 0, h2 = 0, pr = 0; - // Improved exponential hashing - // probe[0] = h1(k) - // probe[i] = (h1(k) + pr(k)^i * h2(k)) mod num_buckets, i = 1 .. num_buckets - 1 - // h1(k) = k mod num_buckets - // h2(k) = floor(k / num_buckets) mod num_buckets - // note: h2(k) has the effect of rotating the sequence if it is constant - // note: pr(k) is any primitive root of num_buckets, varying this gives different sequences - h1 = hash_code % num_buckets; - h2 = (hash_code / num_buckets) % num_buckets; - if (0 == h2) h2 = num_buckets - 1; - pr = __CFBasicHashPrimitiveRoots[ht->bits.num_buckets_idx]; - - COCOA_HASHTABLE_PROBING_START(ht, num_buckets); - uintptr_t probe = h1, acc = pr; - for (CFIndex idx = 0; idx < num_buckets; idx++) { - uintptr_t stack_curr = keys[probe].weak; - if (stack_curr == empty) { - COCOA_HASHTABLE_PROBE_EMPTY(ht, probe); - if (kCFNotFound == result.idx) { - result.idx = probe; - result.weak_value = empty; - result.weak_key = empty; - } - COCOA_HASHTABLE_PROBING_END(ht, idx + 1); - return result; - } else if (__builtin_expect(!rehashing, 0)) { - if (stack_curr == deleted) { - COCOA_HASHTABLE_PROBE_DELETED(ht, probe); - if (kCFNotFound == result.idx) { - result.idx = probe; - } - } else { - COCOA_HASHTABLE_PROBE_VALID(ht, probe); - if (stack_curr == stack_key || ((!hashes || hashes[probe] == hash_code) && __CFBasicHashTestEqualKey(ht, stack_curr, stack_key))) { - COCOA_HASHTABLE_PROBING_END(ht, idx + 1); - result.idx = probe; - result.weak_value = (0 != ht->bits.keys_offset) ? __CFBasicHashGetValues(ht)[probe].weak : stack_curr; - result.weak_value2 = (0 != ht->bits.values2_offset) ? __CFBasicHashGetValues2(ht)[probe].weak : 0; - result.weak_key = stack_curr; - result.weak_key2 = (0 != ht->bits.keys2_offset) ? __CFBasicHashGetKeys2(ht)[probe].weak : 0; - result.count = (0 != ht->bits.counts_offset) ? __CFBasicHashGetCounts(ht)[probe] : 1; - result.order = (0 != ht->bits.orders_offset) ? __CFBasicHashGetOrders(ht)[probe] : 1; - return result; - } - } + if (ht->bits.indirect_keys) { + switch (ht->bits.hash_style) { + case __kCFBasicHashLinearHashingValue: return ___CFBasicHashFindBucket_Linear_Indirect(ht, stack_key); + case __kCFBasicHashDoubleHashingValue: return ___CFBasicHashFindBucket_Double_Indirect(ht, stack_key); + case __kCFBasicHashExponentialHashingValue: return ___CFBasicHashFindBucket_Exponential_Indirect(ht, stack_key); + } + } else { + switch (ht->bits.hash_style) { + case __kCFBasicHashLinearHashingValue: return ___CFBasicHashFindBucket_Linear(ht, stack_key); + case __kCFBasicHashDoubleHashingValue: return ___CFBasicHashFindBucket_Double(ht, stack_key); + case __kCFBasicHashExponentialHashingValue: return ___CFBasicHashFindBucket_Exponential(ht, stack_key); } - // Improved exponential hashing - probe = h1 + h2 * acc; - if (__builtin_expect(num_buckets <= probe, 1)) { - probe = probe % num_buckets; - } - acc = acc * pr; - if (__builtin_expect(num_buckets <= acc, 1)) { - acc = acc % num_buckets; - } } - COCOA_HASHTABLE_PROBING_END(ht, num_buckets); - return result; // all buckets full or deleted, return first deleted element which was found + HALT; + CFBasicHashBucket result = {kCFNotFound, 0UL, 0UL, 0}; + return result; } -CF_INLINE CFBasicHashBucket ___CFBasicHashFindBucket(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t key_hash, Boolean rehashing) { - switch (ht->bits.hash_style) { - case __kCFBasicHashLinearHashingValue: - return ___CFBasicHashFindBucket1(ht, stack_key, 0, rehashing); - case __kCFBasicHashDoubleHashingValue: - return ___CFBasicHashFindBucket2(ht, stack_key, 0, rehashing); - case __kCFBasicHashExponentialHashingValue: - return ___CFBasicHashFindBucket3(ht, stack_key, 0, rehashing); +CF_INLINE CFIndex __CFBasicHashFindBucket_NoCollision(CFConstBasicHashRef ht, uintptr_t stack_key, uintptr_t key_hash) { + if (0 == ht->bits.num_buckets_idx) { + return kCFNotFound; + } + if (ht->bits.indirect_keys) { + switch (ht->bits.hash_style) { + case __kCFBasicHashLinearHashingValue: return ___CFBasicHashFindBucket_Linear_Indirect_NoCollision(ht, stack_key, key_hash); + case __kCFBasicHashDoubleHashingValue: return ___CFBasicHashFindBucket_Double_Indirect_NoCollision(ht, stack_key, key_hash); + case __kCFBasicHashExponentialHashingValue: return ___CFBasicHashFindBucket_Exponential_Indirect_NoCollision(ht, stack_key, key_hash); + } + } else { + switch (ht->bits.hash_style) { + case __kCFBasicHashLinearHashingValue: return ___CFBasicHashFindBucket_Linear_NoCollision(ht, stack_key, key_hash); + case __kCFBasicHashDoubleHashingValue: return ___CFBasicHashFindBucket_Double_NoCollision(ht, stack_key, key_hash); + case __kCFBasicHashExponentialHashingValue: return ___CFBasicHashFindBucket_Exponential_NoCollision(ht, stack_key, key_hash); + } } HALT; - CFBasicHashBucket result = {kCFNotFound, 0, 0, 0}; - return result; + return kCFNotFound; } -CF_INLINE CFBasicHashBucket __CFBasicHashFindBucket(CFBasicHashRef ht, uintptr_t stack_key) { - if (0 == ht->bits.num_buckets_idx) { - uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift); - CFBasicHashBucket result = {kCFNotFound, empty, empty, 0}; +__private_extern__ CFBasicHashBucket CFBasicHashFindBucket(CFConstBasicHashRef ht, uintptr_t stack_key) { + if (__CFBasicHashSubABZero == stack_key || __CFBasicHashSubABOne == stack_key) { + CFBasicHashBucket result = {kCFNotFound, 0UL, 0UL, 0}; return result; } - return ___CFBasicHashFindBucket(ht, stack_key, 0, false); + return __CFBasicHashFindBucket(ht, stack_key); } -__private_extern__ CFBasicHashBucket CFBasicHashFindBucket(CFBasicHashRef ht, uintptr_t stack_key) { - return __CFBasicHashFindBucket(ht, stack_key); +__private_extern__ uint16_t CFBasicHashGetSpecialBits(CFConstBasicHashRef ht) { + return ht->bits.special_bits; } -__private_extern__ CFOptionFlags CFBasicHashGetFlags(CFBasicHashRef ht) { +__private_extern__ uint16_t CFBasicHashSetSpecialBits(CFBasicHashRef ht, uint16_t bits) { + uint16_t old = ht->bits.special_bits; + ht->bits.special_bits = bits; + return old; +} + +__private_extern__ CFOptionFlags CFBasicHashGetFlags(CFConstBasicHashRef ht) { CFOptionFlags flags = (ht->bits.hash_style << 13); - if (ht->bits.strong_values) flags |= kCFBasicHashStrongValues; - if (ht->bits.strong_values2) flags |= kCFBasicHashStrongValues2; - if (ht->bits.strong_keys) flags |= kCFBasicHashStrongKeys; - if (ht->bits.strong_keys2) flags |= kCFBasicHashStrongKeys2; + if (CFBasicHashHasStrongValues(ht)) flags |= kCFBasicHashStrongValues; + if (CFBasicHashHasStrongKeys(ht)) flags |= kCFBasicHashStrongKeys; + if (__CFBasicHashHasCompactableKeys(ht)) flags |= kCFBasicHashCompactableKeys; + if (__CFBasicHashHasCompactableValues(ht)) flags |= kCFBasicHashCompactableValues; if (ht->bits.fast_grow) flags |= kCFBasicHashAggressiveGrowth; - if (ht->bits.values2_offset) flags |= kCFBasicHashHasValues2; if (ht->bits.keys_offset) flags |= kCFBasicHashHasKeys; - if (ht->bits.keys2_offset) flags |= kCFBasicHashHasKeys2; if (ht->bits.counts_offset) flags |= kCFBasicHashHasCounts; - if (ht->bits.orders_offset) flags |= kCFBasicHashHasOrder; - if (ht->bits.hashes_offset) flags |= kCFBasicHashHasHashCache; + if (__CFBasicHashHasHashCache(ht)) flags |= kCFBasicHashHasHashCache; return flags; } -__private_extern__ CFIndex CFBasicHashGetCount(CFBasicHashRef ht) { - if (0 != ht->bits.counts_offset) { +__private_extern__ const CFBasicHashCallbacks *CFBasicHashGetCallbacks(CFConstBasicHashRef ht) { + return ht->callbacks; +} + +__private_extern__ CFIndex CFBasicHashGetCount(CFConstBasicHashRef ht) { + if (ht->bits.counts_offset) { CFIndex total = 0L; CFIndex cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx]; - uintptr_t *counts = __CFBasicHashGetCounts(ht); for (CFIndex idx = 0; idx < cnt; idx++) { - total += counts[idx]; + total += __CFBasicHashGetSlotCount(ht, idx); } return total; } return (CFIndex)ht->bits.used_buckets; } -__private_extern__ CFIndex CFBasicHashGetCountOfKey(CFBasicHashRef ht, uintptr_t stack_key) { +__private_extern__ CFIndex CFBasicHashGetCountOfKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + if (__CFBasicHashSubABZero == stack_key || __CFBasicHashSubABOne == stack_key) { + return 0L; + } if (0L == ht->bits.used_buckets) { return 0L; } return __CFBasicHashFindBucket(ht, stack_key).count; } -__private_extern__ CFIndex CFBasicHashGetCountOfValue(CFBasicHashRef ht, uintptr_t stack_value) { +__private_extern__ CFIndex CFBasicHashGetCountOfValue(CFConstBasicHashRef ht, uintptr_t stack_value) { + if (__CFBasicHashSubABZero == stack_value) { + return 0L; + } if (0L == ht->bits.used_buckets) { return 0L; } - if (!(0 != ht->bits.keys_offset)) { + if (!(ht->bits.keys_offset)) { return __CFBasicHashFindBucket(ht, stack_value).count; } __block CFIndex total = 0L; @@ -869,7 +923,7 @@ __private_extern__ CFIndex CFBasicHashGetCountOfValue(CFBasicHashRef ht, uintptr return total; } -__private_extern__ Boolean CFBasicHashesAreEqual(CFBasicHashRef ht1, CFBasicHashRef ht2) { +__private_extern__ Boolean CFBasicHashesAreEqual(CFConstBasicHashRef ht1, CFConstBasicHashRef ht2) { CFIndex cnt1 = CFBasicHashGetCount(ht1); if (cnt1 != CFBasicHashGetCount(ht2)) return false; if (0 == cnt1) return true; @@ -880,7 +934,7 @@ __private_extern__ Boolean CFBasicHashesAreEqual(CFBasicHashRef ht1, CFBasicHash equal = false; return (Boolean)false; } - if ((0 != ht1->bits.keys_offset) && (bkt1.weak_value != bkt2.weak_value) && !__CFBasicHashTestEqualValue(ht1, bkt1.weak_value, bkt2.weak_value)) { + if ((ht1->bits.keys_offset) && (bkt1.weak_value != bkt2.weak_value) && !__CFBasicHashTestEqualValue(ht1, bkt1.weak_value, bkt2.weak_value)) { equal = false; return (Boolean)false; } @@ -889,7 +943,7 @@ __private_extern__ Boolean CFBasicHashesAreEqual(CFBasicHashRef ht1, CFBasicHash return equal; } -__private_extern__ void CFBasicHashApply(CFBasicHashRef ht, Boolean (^block)(CFBasicHashBucket)) { +__private_extern__ void CFBasicHashApply(CFConstBasicHashRef ht, Boolean (^block)(CFBasicHashBucket)) { CFIndex used = (CFIndex)ht->bits.used_buckets, cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx]; for (CFIndex idx = 0; 0 < used && idx < cnt; idx++) { CFBasicHashBucket bkt = CFBasicHashGetBucket(ht, idx); @@ -902,32 +956,38 @@ __private_extern__ void CFBasicHashApply(CFBasicHashRef ht, Boolean (^block)(CFB } } -__private_extern__ void CFBasicHashGetElements(CFBasicHashRef ht, CFIndex bufferslen, uintptr_t *weak_values, uintptr_t *weak_values2, uintptr_t *weak_keys, uintptr_t *weak_keys2) { +__private_extern__ void CFBasicHashApplyIndexed(CFConstBasicHashRef ht, CFRange range, Boolean (^block)(CFBasicHashBucket)) { + if (range.length < 0) HALT; + if (range.length == 0) return; + CFIndex cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx]; + if (cnt < range.location + range.length) HALT; + for (CFIndex idx = 0; idx < range.length; idx++) { + CFBasicHashBucket bkt = CFBasicHashGetBucket(ht, range.location + idx); + if (0 < bkt.count) { + if (!block(bkt)) { + return; + } + } + } +} + +__private_extern__ void CFBasicHashGetElements(CFConstBasicHashRef ht, CFIndex bufferslen, uintptr_t *weak_values, uintptr_t *weak_keys) { CFIndex used = (CFIndex)ht->bits.used_buckets, cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx]; - uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty; - CFBasicHashValue *values = __CFBasicHashGetValues(ht); - CFBasicHashValue *values2 = (0 != ht->bits.values2_offset) ? __CFBasicHashGetValues2(ht) : NULL; - CFBasicHashValue *keys = (0 != ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht) : NULL; - CFBasicHashValue *keys2 = (0 != ht->bits.keys2_offset) ? __CFBasicHashGetKeys2(ht) : NULL; - uintptr_t *counts = (0 != ht->bits.counts_offset) ? __CFBasicHashGetCounts(ht) : NULL; CFIndex offset = 0; for (CFIndex idx = 0; 0 < used && idx < cnt && offset < bufferslen; idx++) { - uintptr_t weak_key = keys ? keys[idx].weak : values[idx].weak; - uintptr_t count = counts ? counts[idx] : ((weak_key == empty || weak_key == deleted) ? 0 : 1); - if (0 < count) { + CFBasicHashBucket bkt = CFBasicHashGetBucket(ht, idx); + if (0 < bkt.count) { used--; - for (CFIndex cnt = count; cnt-- && offset < bufferslen;) { - if (weak_values) { weak_values[offset] = values[idx].weak; } - if (weak_values2) { weak_values2[offset] = values2 ? values2[idx].weak : 0; } - if (weak_keys) { weak_keys[offset] = weak_key; } - if (weak_keys2) { weak_keys2[offset] = keys2 ? keys2[idx].weak : 0; } + for (CFIndex cnt = bkt.count; cnt-- && offset < bufferslen;) { + if (weak_values) { weak_values[offset] = bkt.weak_value; } + if (weak_keys) { weak_keys[offset] = bkt.weak_key; } offset++; } } } } -__private_extern__ unsigned long __CFBasicHashFastEnumeration(CFBasicHashRef ht, struct __objcFastEnumerationStateEquivalent2 *state, void *stackbuffer, unsigned long count) { +__private_extern__ unsigned long __CFBasicHashFastEnumeration(CFConstBasicHashRef ht, struct __objcFastEnumerationStateEquivalent2 *state, void *stackbuffer, unsigned long count) { /* copy as many as count items over */ if (0 == state->state) { /* first time */ state->mutationsPtr = (unsigned long *)&ht->bits + (__LP64__ ? 1 : 3); @@ -959,38 +1019,26 @@ static void __CFBasicHashDrain(CFBasicHashRef ht, Boolean forFinalization) { OSAtomicAdd64Barrier(-1 * (int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize); #endif - uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty; CFIndex old_num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx]; CFAllocatorRef allocator = CFGetAllocator(ht); Boolean nullify = (!forFinalization || !CF_IS_COLLECTABLE_ALLOCATOR(allocator)); - CFBasicHashValue *old_values = NULL, *old_values2 = NULL, *old_keys = NULL, *old_keys2 = NULL; - uintptr_t *old_counts = NULL, *old_orders = NULL, *old_hashes = NULL; + CFBasicHashValue *old_values = NULL, *old_keys = NULL; + void *old_counts = NULL; + uintptr_t *old_hashes = NULL; old_values = __CFBasicHashGetValues(ht); if (nullify) __CFBasicHashSetValues(ht, NULL); - if (0 != ht->bits.values2_offset) { - old_values2 = __CFBasicHashGetValues2(ht); - if (nullify) __CFBasicHashSetValues2(ht, NULL); - } - if (0 != ht->bits.keys_offset) { + if (ht->bits.keys_offset) { old_keys = __CFBasicHashGetKeys(ht); if (nullify) __CFBasicHashSetKeys(ht, NULL); } - if (0 != ht->bits.keys2_offset) { - old_keys2 = __CFBasicHashGetKeys2(ht); - if (nullify) __CFBasicHashSetKeys2(ht, NULL); - } - if (0 != ht->bits.counts_offset) { + if (ht->bits.counts_offset) { old_counts = __CFBasicHashGetCounts(ht); if (nullify) __CFBasicHashSetCounts(ht, NULL); } - if (0 != ht->bits.orders_offset) { - old_orders = __CFBasicHashGetOrders(ht); - if (nullify) __CFBasicHashSetOrders(ht, NULL); - } - if (0 != ht->bits.hashes_offset) { + if (__CFBasicHashHasHashCache(ht)) { old_hashes = __CFBasicHashGetHashes(ht); if (nullify) __CFBasicHashSetHashes(ht, NULL); } @@ -999,40 +1047,33 @@ static void __CFBasicHashDrain(CFBasicHashRef ht, Boolean forFinalization) { ht->bits.mutations++; ht->bits.num_buckets_idx = 0; ht->bits.used_buckets = 0; - ht->bits.marker = 0; ht->bits.deleted = 0; } - if (ht->callbacks != &CFBasicHashNullCallbacks) { - CFBasicHashValue *keys = old_keys ? old_keys : old_values; for (CFIndex idx = 0; idx < old_num_buckets; idx++) { - uintptr_t stack_key = keys[idx].weak; - if (stack_key != empty && stack_key != deleted) { - __CFBasicHashEjectValue(ht, old_values[idx].weak); - if (old_values2) { - __CFBasicHashEjectValue2(ht, old_values2[idx].weak); - } + uintptr_t stack_value = old_values[idx].neutral; + if (stack_value != 0UL && stack_value != ~0UL) { + uintptr_t old_value = stack_value; + if (__CFBasicHashSubABZero == old_value) old_value = 0UL; + if (__CFBasicHashSubABOne == old_value) old_value = ~0UL; + __CFBasicHashEjectValue(ht, old_value); if (old_keys) { - __CFBasicHashEjectKey(ht, old_keys[idx].weak); - } - if (old_keys2) { - __CFBasicHashEjectKey2(ht, old_keys2[idx].weak); + uintptr_t old_key = old_keys[idx].neutral; + if (__CFBasicHashSubABZero == old_key) old_key = 0UL; + if (__CFBasicHashSubABOne == old_key) old_key = ~0UL; + __CFBasicHashEjectKey(ht, old_key); } } } - } if (forFinalization) { - ht->callbacks->func(ht, kCFBasicHashCallbackOpFreeCallbacks, (uintptr_t)allocator, 0, ht->callbacks); + ht->callbacks->freeCallbacks(ht, allocator, ht->callbacks); } if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { CFAllocatorDeallocate(allocator, old_values); - CFAllocatorDeallocate(allocator, old_values2); CFAllocatorDeallocate(allocator, old_keys); - CFAllocatorDeallocate(allocator, old_keys2); CFAllocatorDeallocate(allocator, old_counts); - CFAllocatorDeallocate(allocator, old_orders); CFAllocatorDeallocate(allocator, old_hashes); } @@ -1063,114 +1104,83 @@ static void __CFBasicHashRehash(CFBasicHashRef ht, CFIndex newItemCount) { CFIndex new_num_buckets = __CFBasicHashTableSizes[new_num_buckets_idx]; CFIndex old_num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx]; - CFBasicHashValue *new_values = NULL, *new_values2 = NULL, *new_keys = NULL, *new_keys2 = NULL; - uintptr_t *new_counts = NULL, *new_orders = NULL, *new_hashes = NULL; + 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), ht->bits.strong_values); + new_values = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), CFBasicHashHasStrongValues(ht), __CFBasicHashHasCompactableValues(ht)); __SetLastAllocationEventName(new_values, "CFBasicHash (value-store)"); - if (0 != ht->bits.values2_offset) { - new_values2 = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), ht->bits.strong_values2); - __SetLastAllocationEventName(new_values2, "CFBasicHash (value2-store)"); - } - if (0 != ht->bits.keys_offset) { - new_keys = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), ht->bits.strong_keys); + 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)); __SetLastAllocationEventName(new_keys, "CFBasicHash (key-store)"); + memset(new_keys, 0, new_num_buckets * sizeof(CFBasicHashValue)); } - if (0 != ht->bits.keys2_offset) { - new_keys2 = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), ht->bits.strong_keys2); - __SetLastAllocationEventName(new_keys2, "CFBasicHash (key2-store)"); - } - if (0 != ht->bits.counts_offset) { - new_counts = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false); + 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)"); - memset(new_counts, 0, new_num_buckets * sizeof(uintptr_t)); - } - if (0 != ht->bits.orders_offset) { - new_orders = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false); - __SetLastAllocationEventName(new_orders, "CFBasicHash (order-store)"); - memset(new_orders, 0, new_num_buckets * sizeof(uintptr_t)); + memset(new_counts, 0, new_num_buckets * (1 << ht->bits.counts_width)); } - if (0 != ht->bits.hashes_offset) { - new_hashes = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false); + if (__CFBasicHashHasHashCache(ht)) { + new_hashes = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false, false); __SetLastAllocationEventName(new_hashes, "CFBasicHash (hash-store)"); memset(new_hashes, 0, new_num_buckets * sizeof(uintptr_t)); } } - uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty; - // if we knew the allocations were coming from already-cleared memory, and the marker was still 0, we could skip all this next stuff - for (CFIndex idx = 0; idx < new_num_buckets; idx++) { - if (ht->bits.strong_values) new_values[idx].strong = (id)empty; else new_values[idx].weak = empty; - if (new_values2) { - if (ht->bits.strong_values2) new_values2[idx].strong = (id)empty; else new_values2[idx].weak = empty; - } - if (new_keys) { - if (ht->bits.strong_keys) new_keys[idx].strong = (id)empty; else new_keys[idx].weak = empty; - } - if (new_keys2) { - if (ht->bits.strong_keys2) new_keys2[idx].strong = (id)empty; else new_keys2[idx].weak = empty; - } - } - ht->bits.num_buckets_idx = new_num_buckets_idx; ht->bits.deleted = 0; - CFBasicHashValue *old_values = NULL, *old_values2 = NULL, *old_keys = NULL, *old_keys2 = NULL; - uintptr_t *old_counts = NULL, *old_orders = NULL, *old_hashes = NULL; + CFBasicHashValue *old_values = NULL, *old_keys = NULL; + void *old_counts = NULL; + uintptr_t *old_hashes = NULL; old_values = __CFBasicHashGetValues(ht); __CFBasicHashSetValues(ht, new_values); - if (0 != ht->bits.values2_offset) { - old_values2 = __CFBasicHashGetValues2(ht); - __CFBasicHashSetValues2(ht, new_values2); - } - if (0 != ht->bits.keys_offset) { + if (ht->bits.keys_offset) { old_keys = __CFBasicHashGetKeys(ht); __CFBasicHashSetKeys(ht, new_keys); } - if (0 != ht->bits.keys2_offset) { - old_keys2 = __CFBasicHashGetKeys2(ht); - __CFBasicHashSetKeys2(ht, new_keys2); - } - if (0 != ht->bits.counts_offset) { + if (ht->bits.counts_offset) { old_counts = __CFBasicHashGetCounts(ht); __CFBasicHashSetCounts(ht, new_counts); } - if (0 != ht->bits.orders_offset) { - old_orders = __CFBasicHashGetOrders(ht); - __CFBasicHashSetOrders(ht, new_orders); - } - if (0 != ht->bits.hashes_offset) { + if (__CFBasicHashHasHashCache(ht)) { old_hashes = __CFBasicHashGetHashes(ht); __CFBasicHashSetHashes(ht, new_hashes); } if (0 < old_num_buckets) { - CFBasicHashValue *keys = old_keys ? old_keys : old_values; for (CFIndex idx = 0; idx < old_num_buckets; idx++) { - uintptr_t stack_key = keys[idx].weak; - if (stack_key != empty && stack_key != deleted) { - CFBasicHashBucket bkt = ___CFBasicHashFindBucket(ht, stack_key, old_hashes ? old_hashes[idx] : 0, true); - uintptr_t stack_value = old_values[idx].weak; - if (ht->bits.strong_values) new_values[bkt.idx].strong = (id)stack_value; else new_values[bkt.idx].weak = stack_value; - if (old_values2) { - if (ht->bits.strong_values2) new_values2[bkt.idx].strong = (id)old_values2[idx].weak; else new_values2[bkt.idx].weak = old_values2[idx].weak; + uintptr_t stack_value = old_values[idx].neutral; + if (stack_value != 0UL && stack_value != ~0UL) { + if (__CFBasicHashSubABZero == stack_value) stack_value = 0UL; + if (__CFBasicHashSubABOne == stack_value) stack_value = ~0UL; + uintptr_t stack_key = stack_value; + if (ht->bits.keys_offset) { + stack_key = old_keys[idx].neutral; + if (__CFBasicHashSubABZero == stack_key) stack_key = 0UL; + if (__CFBasicHashSubABOne == stack_key) stack_key = ~0UL; } - if (old_keys) { - if (ht->bits.strong_keys) new_keys[bkt.idx].strong = (id)stack_key; else new_keys[bkt.idx].weak = stack_key; + if (ht->bits.indirect_keys) { + stack_key = ht->callbacks->getIndirectKey(ht, stack_value); } - if (old_keys2) { - if (ht->bits.strong_keys2) new_keys2[bkt.idx].strong = (id)old_keys2[idx].weak; else new_keys2[bkt.idx].weak = old_keys2[idx].weak; + CFIndex bkt_idx = __CFBasicHashFindBucket_NoCollision(ht, stack_key, old_hashes ? old_hashes[idx] : 0UL); + __CFBasicHashSetValue(ht, bkt_idx, stack_value, false, false); + if (old_keys) { + __CFBasicHashSetKey(ht, bkt_idx, stack_key, false, false); } if (old_counts) { - new_counts[bkt.idx] = old_counts[idx]; - } - if (old_orders) { - new_orders[bkt.idx] = old_orders[idx]; + switch (ht->bits.counts_width) { + case 0: ((uint8_t *)new_counts)[bkt_idx] = ((uint8_t *)old_counts)[idx]; break; + case 1: ((uint16_t *)new_counts)[bkt_idx] = ((uint16_t *)old_counts)[idx]; break; + case 2: ((uint32_t *)new_counts)[bkt_idx] = ((uint32_t *)old_counts)[idx]; break; + case 3: ((uint64_t *)new_counts)[bkt_idx] = ((uint64_t *)old_counts)[idx]; break; + } } if (old_hashes) { - new_hashes[bkt.idx] = old_hashes[idx]; + new_hashes[bkt_idx] = old_hashes[idx]; } } } @@ -1179,11 +1189,8 @@ static void __CFBasicHashRehash(CFBasicHashRef ht, CFIndex newItemCount) { CFAllocatorRef allocator = CFGetAllocator(ht); if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { CFAllocatorDeallocate(allocator, old_values); - CFAllocatorDeallocate(allocator, old_values2); CFAllocatorDeallocate(allocator, old_keys); - CFAllocatorDeallocate(allocator, old_keys2); CFAllocatorDeallocate(allocator, old_counts); - CFAllocatorDeallocate(allocator, old_orders); CFAllocatorDeallocate(allocator, old_hashes); } @@ -1204,164 +1211,58 @@ __private_extern__ void CFBasicHashSetCapacity(CFBasicHashRef ht, CFIndex capaci } } -static void __CFBasicHashFindNewMarker(CFBasicHashRef ht, uintptr_t stack_key) { - uintptr_t marker = ht->bits.marker; - uintptr_t empty = (marker << __CFBasicHashMarkerShift), deleted = ~empty; - CFBasicHashValue *keys = (0 != ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht) : __CFBasicHashGetValues(ht); - Boolean strong = (0 != ht->bits.keys_offset) ? ht->bits.strong_keys : ht->bits.strong_values; - CFIndex cnt = __CFBasicHashTableSizes[ht->bits.num_buckets_idx]; - if (0 == marker) marker = 4096; - - again:; - marker++; - if ((1UL << 26) <= marker) HALT; - uintptr_t new_empty = (marker << __CFBasicHashMarkerShift), new_deleted = ~new_empty; - if (stack_key == new_empty || stack_key == new_deleted) { - goto again; - } - for (CFIndex idx = 0; idx < cnt; idx++) { - uintptr_t stack_curr = strong ? (uintptr_t)keys[idx].strong : keys[idx].weak; - if (stack_curr == new_empty || stack_curr == new_deleted) { - goto again; - } - } - for (CFIndex idx = 0; idx < cnt; idx++) { - uintptr_t stack_curr = strong ? (uintptr_t)keys[idx].strong : keys[idx].weak; - if (stack_curr == empty) { - if (strong) keys[idx].strong = (id)new_empty; else keys[idx].weak = new_empty; - } else if (stack_curr == deleted) { - if (strong) keys[idx].strong = (id)new_deleted; else keys[idx].weak = new_deleted; - } - } - ht->bits.marker = marker; -} - -static void __CFBasicHashAddValue(CFBasicHashRef ht, CFBasicHashBucket bkt, uintptr_t stack_key, uintptr_t stack_key2, uintptr_t stack_value, uintptr_t stack_value2) { +static void __CFBasicHashAddValue(CFBasicHashRef ht, CFIndex bkt_idx, uintptr_t stack_key, uintptr_t stack_value) { ht->bits.mutations++; - stack_value = __CFBasicHashImportValue(ht, stack_value); - if (0 != ht->bits.keys_offset) { - stack_key = __CFBasicHashImportKey(ht, stack_key); - } else { - stack_key = stack_value; - } - if (0 != ht->bits.values2_offset) { - stack_value2 = __CFBasicHashImportValue2(ht, stack_value2); - } - if (0 != ht->bits.keys2_offset) { - stack_key2 = __CFBasicHashImportKey2(ht, stack_key2); - } if (CFBasicHashGetCapacity(ht) < ht->bits.used_buckets + 1) { __CFBasicHashRehash(ht, 1); - bkt = ___CFBasicHashFindBucket(ht, stack_key, 0, true); - } - uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty; - if (bkt.weak_key == deleted) { + bkt_idx = __CFBasicHashFindBucket_NoCollision(ht, stack_key, 0); + } else if (__CFBasicHashIsDeleted(ht, bkt_idx)) { ht->bits.deleted--; } - if (stack_key == empty || stack_key == deleted) { - __CFBasicHashFindNewMarker(ht, stack_key); - } - CFBasicHashValue *value = &(__CFBasicHashGetValues(ht)[bkt.idx]); - if (ht->bits.strong_values) value->strong = (id)stack_value; else value->weak = stack_value; - if (0 != ht->bits.values2_offset) { - CFBasicHashValue *value2 = &(__CFBasicHashGetValues2(ht)[bkt.idx]); - if (ht->bits.strong_values2) value2->strong = (id)stack_value2; else value2->weak = stack_value2; - } - if (0 != ht->bits.keys_offset) { - CFBasicHashValue *key = &(__CFBasicHashGetKeys(ht)[bkt.idx]); - if (ht->bits.strong_keys) key->strong = (id)stack_key; else key->weak = stack_key; + uintptr_t key_hash = 0; + if (__CFBasicHashHasHashCache(ht)) { + key_hash = __CFBasicHashHashKey(ht, stack_key); } - if (0 != ht->bits.keys2_offset) { - CFBasicHashValue *key2 = &(__CFBasicHashGetKeys2(ht)[bkt.idx]); - if (ht->bits.strong_keys2) key2->strong = (id)stack_key2; else key2->weak = stack_key2; + stack_value = __CFBasicHashImportValue(ht, stack_value); + if (ht->bits.keys_offset) { + stack_key = __CFBasicHashImportKey(ht, stack_key); } - if (0 != ht->bits.counts_offset) { - __CFBasicHashGetCounts(ht)[bkt.idx] = 1; + __CFBasicHashSetValue(ht, bkt_idx, stack_value, false, false); + if (ht->bits.keys_offset) { + __CFBasicHashSetKey(ht, bkt_idx, stack_key, false, false); } - if (0 != ht->bits.orders_offset) { - __CFBasicHashGetOrders(ht)[bkt.idx] = 0; + if (ht->bits.counts_offset) { + __CFBasicHashIncSlotCount(ht, bkt_idx); } - if (ht->bits.hashes_offset) { - __CFBasicHashGetHashes(ht)[bkt.idx] = __CFBasicHashHashKey(ht, stack_key); + if (__CFBasicHashHasHashCache(ht)) { + __CFBasicHashGetHashes(ht)[bkt_idx] = key_hash; } ht->bits.used_buckets++; } -static void __CFBasicHashReplaceValue(CFBasicHashRef ht, CFBasicHashBucket bkt, uintptr_t stack_key, uintptr_t stack_key2, uintptr_t stack_value, uintptr_t stack_value2) { +static void __CFBasicHashReplaceValue(CFBasicHashRef ht, CFIndex bkt_idx, uintptr_t stack_key, uintptr_t stack_value) { ht->bits.mutations++; stack_value = __CFBasicHashImportValue(ht, stack_value); - if (0 != ht->bits.keys_offset) { + if (ht->bits.keys_offset) { stack_key = __CFBasicHashImportKey(ht, stack_key); - } else { - stack_key = stack_value; - } - if (0 != ht->bits.values2_offset) { - stack_value2 = __CFBasicHashImportValue2(ht, stack_value2); - } - if (0 != ht->bits.keys2_offset) { - stack_key2 = __CFBasicHashImportKey2(ht, stack_key2); - } - uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty; - if (stack_key == empty || stack_key == deleted) { - __CFBasicHashFindNewMarker(ht, stack_key); - } - CFBasicHashValue *value = &(__CFBasicHashGetValues(ht)[bkt.idx]); - uintptr_t old_value = value->weak; - if (ht->bits.strong_values) value->strong = (id)stack_value; else value->weak = stack_value; - __CFBasicHashEjectValue(ht, old_value); - if (0 != ht->bits.values2_offset) { - CFBasicHashValue *value2 = &(__CFBasicHashGetValues2(ht)[bkt.idx]); - uintptr_t old_value2 = value2->weak; - if (ht->bits.strong_values2) value2->strong = (id)stack_value2; else value2->weak = stack_value2; - __CFBasicHashEjectValue2(ht, old_value2); } - if (0 != ht->bits.keys_offset) { - CFBasicHashValue *key = &(__CFBasicHashGetKeys(ht)[bkt.idx]); - uintptr_t old_key = key->weak; - if (ht->bits.strong_keys) key->strong = (id)stack_key; else key->weak = stack_key; - __CFBasicHashEjectKey(ht, old_key); - } - if (0 != ht->bits.keys2_offset) { - CFBasicHashValue *key2 = &(__CFBasicHashGetKeys2(ht)[bkt.idx]); - uintptr_t old_key2 = key2->weak; - if (ht->bits.strong_keys2) key2->strong = (id)stack_key2; else key2->weak = stack_key2; - __CFBasicHashEjectKey2(ht, old_key2); + __CFBasicHashSetValue(ht, bkt_idx, stack_value, false, false); + if (ht->bits.keys_offset) { + __CFBasicHashSetKey(ht, bkt_idx, stack_key, false, false); } } -static void __CFBasicHashRemoveValue(CFBasicHashRef ht, CFBasicHashBucket bkt, uintptr_t stack_key, uintptr_t stack_key2) { +static void __CFBasicHashRemoveValue(CFBasicHashRef ht, CFIndex bkt_idx) { ht->bits.mutations++; - uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty; - CFBasicHashValue *value = &(__CFBasicHashGetValues(ht)[bkt.idx]); - uintptr_t old_value = value->weak; - if (ht->bits.strong_values) value->strong = (id)deleted; else value->weak = deleted; - __CFBasicHashEjectValue(ht, old_value); - if (0 != ht->bits.values2_offset) { - CFBasicHashValue *value2 = &(__CFBasicHashGetValues2(ht)[bkt.idx]); - uintptr_t old_value2 = value2->weak; - if (ht->bits.strong_values2) value2->strong = (id)deleted; else value2->weak = deleted; - __CFBasicHashEjectValue2(ht, old_value2); - } - if (0 != ht->bits.keys_offset) { - CFBasicHashValue *key = &(__CFBasicHashGetKeys(ht)[bkt.idx]); - uintptr_t old_key = key->weak; - if (ht->bits.strong_keys) key->strong = (id)deleted; else key->weak = deleted; - __CFBasicHashEjectKey(ht, old_key); - } - if (0 != ht->bits.keys2_offset) { - CFBasicHashValue *key2 = &(__CFBasicHashGetKeys2(ht)[bkt.idx]); - uintptr_t old_key2 = key2->weak; - if (ht->bits.strong_keys2) key2->strong = (id)deleted; else key2->weak = deleted; - __CFBasicHashEjectKey2(ht, old_key2); - } - if (0 != ht->bits.counts_offset) { - __CFBasicHashGetCounts(ht)[bkt.idx] = 0; - } - if (0 != ht->bits.orders_offset) { - __CFBasicHashGetOrders(ht)[bkt.idx] = 0; - } - if (ht->bits.hashes_offset) { - __CFBasicHashGetHashes(ht)[bkt.idx] = 0; + __CFBasicHashSetValue(ht, bkt_idx, ~0UL, false, true); + if (ht->bits.keys_offset) { + __CFBasicHashSetKey(ht, bkt_idx, ~0UL, false, true); + } + if (ht->bits.counts_offset) { + __CFBasicHashDecSlotCount(ht, bkt_idx); + } + if (__CFBasicHashHasHashCache(ht)) { + __CFBasicHashGetHashes(ht)[bkt_idx] = 0; } ht->bits.used_buckets--; ht->bits.deleted++; @@ -1383,47 +1284,77 @@ static void __CFBasicHashRemoveValue(CFBasicHashRef ht, CFBasicHashBucket bkt, u } } -__private_extern__ void CFBasicHashAddValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value) { +__private_extern__ Boolean CFBasicHashAddValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value) { if (!CFBasicHashIsMutable(ht)) HALT; + if (__CFBasicHashSubABZero == stack_key) HALT; + if (__CFBasicHashSubABOne == stack_key) HALT; + if (__CFBasicHashSubABZero == stack_value) HALT; + if (__CFBasicHashSubABOne == stack_value) HALT; CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key); if (0 < bkt.count) { ht->bits.mutations++; - if (0 != ht->bits.counts_offset) { - __CFBasicHashGetCounts(ht)[bkt.idx]++; + if (ht->bits.counts_offset && bkt.count < LONG_MAX) { // if not yet as large as a CFIndex can be... otherwise clamp and do nothing + __CFBasicHashIncSlotCount(ht, bkt.idx); + return true; } } else { - __CFBasicHashAddValue(ht, bkt, stack_key, 0, stack_value, 0); + __CFBasicHashAddValue(ht, bkt.idx, stack_key, stack_value); + return true; } + return false; } __private_extern__ void CFBasicHashReplaceValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value) { if (!CFBasicHashIsMutable(ht)) HALT; + if (__CFBasicHashSubABZero == stack_key) HALT; + if (__CFBasicHashSubABOne == stack_key) HALT; + if (__CFBasicHashSubABZero == stack_value) HALT; + if (__CFBasicHashSubABOne == stack_value) HALT; CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key); if (0 < bkt.count) { - __CFBasicHashReplaceValue(ht, bkt, stack_key, 0, stack_value, 0); + __CFBasicHashReplaceValue(ht, bkt.idx, stack_key, stack_value); } } __private_extern__ void CFBasicHashSetValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value) { if (!CFBasicHashIsMutable(ht)) HALT; + if (__CFBasicHashSubABZero == stack_key) HALT; + if (__CFBasicHashSubABOne == stack_key) HALT; + if (__CFBasicHashSubABZero == stack_value) HALT; + if (__CFBasicHashSubABOne == stack_value) HALT; CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key); if (0 < bkt.count) { - __CFBasicHashReplaceValue(ht, bkt, stack_key, 0, stack_value, 0); + __CFBasicHashReplaceValue(ht, bkt.idx, stack_key, stack_value); } else { - __CFBasicHashAddValue(ht, bkt, stack_key, 0, stack_value, 0); + __CFBasicHashAddValue(ht, bkt.idx, stack_key, stack_value); } } __private_extern__ CFIndex CFBasicHashRemoveValue(CFBasicHashRef ht, uintptr_t stack_key) { if (!CFBasicHashIsMutable(ht)) HALT; + if (__CFBasicHashSubABZero == stack_key || __CFBasicHashSubABOne == stack_key) return 0; CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key); if (1 < bkt.count) { ht->bits.mutations++; - if (0 != ht->bits.counts_offset) { - __CFBasicHashGetCounts(ht)[bkt.idx]--; + if (ht->bits.counts_offset && bkt.count < LONG_MAX) { // if not as large as a CFIndex can be... otherwise clamp and do nothing + __CFBasicHashDecSlotCount(ht, bkt.idx); } } else if (0 < bkt.count) { - __CFBasicHashRemoveValue(ht, bkt, stack_key, 0); + __CFBasicHashRemoveValue(ht, bkt.idx); + } + return bkt.count; +} + +__private_extern__ CFIndex CFBasicHashRemoveValueAtIndex(CFBasicHashRef ht, CFIndex idx) { + if (!CFBasicHashIsMutable(ht)) HALT; + CFBasicHashBucket bkt = CFBasicHashGetBucket(ht, idx); + if (1 < bkt.count) { + ht->bits.mutations++; + if (ht->bits.counts_offset && bkt.count < LONG_MAX) { // if not as large as a CFIndex can be... otherwise clamp and do nothing + __CFBasicHashDecSlotCount(ht, bkt.idx); + } + } else if (0 < bkt.count) { + __CFBasicHashRemoveValue(ht, bkt.idx); } return bkt.count; } @@ -1434,61 +1365,108 @@ __private_extern__ void CFBasicHashRemoveAllValues(CFBasicHashRef ht) { __CFBasicHashDrain(ht, false); } -__private_extern__ size_t CFBasicHashGetSize(CFBasicHashRef ht, Boolean total) { +Boolean CFBasicHashAddIntValueAndInc(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t int_value) { + if (!CFBasicHashIsMutable(ht)) HALT; + if (__CFBasicHashSubABZero == stack_key) HALT; + if (__CFBasicHashSubABOne == stack_key) HALT; + if (__CFBasicHashSubABZero == int_value) HALT; + if (__CFBasicHashSubABOne == int_value) HALT; + CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key); + if (0 < bkt.count) { + ht->bits.mutations++; + } else { + // must rehash before renumbering + if (CFBasicHashGetCapacity(ht) < ht->bits.used_buckets + 1) { + __CFBasicHashRehash(ht, 1); + bkt.idx = __CFBasicHashFindBucket_NoCollision(ht, stack_key, 0); + } + CFIndex cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx]; + for (CFIndex idx = 0; idx < cnt; idx++) { + if (!__CFBasicHashIsEmptyOrDeleted(ht, idx)) { + uintptr_t stack_value = __CFBasicHashGetValue(ht, idx); + if (int_value <= stack_value) { + stack_value++; + __CFBasicHashSetValue(ht, idx, stack_value, true, false); + ht->bits.mutations++; + } + } + } + __CFBasicHashAddValue(ht, bkt.idx, stack_key, int_value); + return true; + } + return false; +} + +void CFBasicHashRemoveIntValueAndDec(CFBasicHashRef ht, uintptr_t int_value) { + if (!CFBasicHashIsMutable(ht)) HALT; + if (__CFBasicHashSubABZero == int_value) HALT; + if (__CFBasicHashSubABOne == int_value) HALT; + uintptr_t bkt_idx = ~0UL; + CFIndex cnt = (CFIndex)__CFBasicHashTableSizes[ht->bits.num_buckets_idx]; + for (CFIndex idx = 0; idx < cnt; idx++) { + if (!__CFBasicHashIsEmptyOrDeleted(ht, idx)) { + uintptr_t stack_value = __CFBasicHashGetValue(ht, idx); + if (int_value == stack_value) { + bkt_idx = idx; + } + if (int_value < stack_value) { + stack_value--; + __CFBasicHashSetValue(ht, idx, stack_value, true, false); + ht->bits.mutations++; + } + } + } + __CFBasicHashRemoveValue(ht, bkt_idx); +} + +__private_extern__ size_t CFBasicHashGetSize(CFConstBasicHashRef ht, Boolean total) { size_t size = sizeof(struct __CFBasicHash); - if (0 != ht->bits.values2_offset) size += sizeof(CFBasicHashValue *); - if (0 != ht->bits.keys_offset) size += sizeof(CFBasicHashValue *); - if (0 != ht->bits.keys2_offset) size += sizeof(CFBasicHashValue *); - if (0 != ht->bits.counts_offset) size += sizeof(uintptr_t *); - if (0 != ht->bits.orders_offset) size += sizeof(uintptr_t *); - if (0 != ht->bits.hashes_offset) size += sizeof(uintptr_t *); + if (ht->bits.keys_offset) size += sizeof(CFBasicHashValue *); + if (ht->bits.counts_offset) size += sizeof(void *); + if (__CFBasicHashHasHashCache(ht)) size += sizeof(uintptr_t *); if (total) { CFIndex num_buckets = __CFBasicHashTableSizes[ht->bits.num_buckets_idx]; if (0 < num_buckets) { size += malloc_size(__CFBasicHashGetValues(ht)); - if (0 != ht->bits.values2_offset) size += malloc_size(__CFBasicHashGetValues2(ht)); - if (0 != ht->bits.keys_offset) size += malloc_size(__CFBasicHashGetKeys(ht)); - if (0 != ht->bits.keys2_offset) size += malloc_size(__CFBasicHashGetKeys2(ht)); - if (0 != ht->bits.counts_offset) size += malloc_size(__CFBasicHashGetCounts(ht)); - if (0 != ht->bits.orders_offset) size += malloc_size(__CFBasicHashGetOrders(ht)); - if (0 != ht->bits.hashes_offset) size += malloc_size(__CFBasicHashGetHashes(ht)); + if (ht->bits.keys_offset) size += malloc_size(__CFBasicHashGetKeys(ht)); + if (ht->bits.counts_offset) size += malloc_size(__CFBasicHashGetCounts(ht)); + if (__CFBasicHashHasHashCache(ht)) size += malloc_size(__CFBasicHashGetHashes(ht)); size += malloc_size((void *)ht->callbacks); } } return size; } -__private_extern__ CFStringRef CFBasicHashCopyDescription(CFBasicHashRef ht, Boolean detailed, CFStringRef prefix, CFStringRef entryPrefix, Boolean describeElements) { +__private_extern__ CFStringRef CFBasicHashCopyDescription(CFConstBasicHashRef ht, Boolean detailed, CFStringRef prefix, CFStringRef entryPrefix, Boolean describeElements) { CFMutableStringRef result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); - CFStringAppendFormat(result, NULL, CFSTR("%@{type = %s %s%s, count = %ld,\n"), prefix, (CFBasicHashIsMutable(ht) ? "mutable" : "immutable"), ((0 != ht->bits.counts_offset) ? "multi" : ""), ((0 != ht->bits.keys_offset) ? "dict" : "set"), CFBasicHashGetCount(ht)); + CFStringAppendFormat(result, NULL, CFSTR("%@{type = %s %s%s, count = %ld,\n"), prefix, (CFBasicHashIsMutable(ht) ? "mutable" : "immutable"), ((ht->bits.counts_offset) ? "multi" : ""), ((ht->bits.keys_offset) ? "dict" : "set"), CFBasicHashGetCount(ht)); if (detailed) { const char *cb_type = "custom"; - if (&CFBasicHashNullCallbacks == ht->callbacks) { - cb_type = "null"; - } else if (&CFBasicHashStandardCallbacks == ht->callbacks) { - cb_type = "standard"; - } - CFStringAppendFormat(result, NULL, CFSTR("%@hash cache = %s, strong values = %s, strong keys = %s, cb = %s,\n"), prefix, ((0 != ht->bits.hashes_offset) ? "yes" : "no"), (ht->bits.strong_values ? "yes" : "no"), (ht->bits.strong_keys ? "yes" : "no"), cb_type); - CFStringAppendFormat(result, NULL, CFSTR("%@num bucket index = %d, num buckets = %ld, capacity = %ld, num buckets used = %ld,\n"), prefix, ht->bits.num_buckets_idx, CFBasicHashGetNumBuckets(ht), CFBasicHashGetCapacity(ht), ht->bits.used_buckets); - uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty; - CFStringAppendFormat(result, NULL, CFSTR("%@empty marker = 0x%lx, deleted marker = 0x%lx, finalized = %s,\n"), prefix, empty, deleted, (ht->bits.finalized ? "yes" : "no")); + CFStringAppendFormat(result, NULL, CFSTR("%@hash cache = %s, strong values = %s, strong keys = %s, cb = %s,\n"), prefix, (__CFBasicHashHasHashCache(ht) ? "yes" : "no"), (CFBasicHashHasStrongValues(ht) ? "yes" : "no"), (CFBasicHashHasStrongKeys(ht) ? "yes" : "no"), cb_type); + CFStringAppendFormat(result, NULL, CFSTR("%@num bucket index = %d, num buckets = %ld, capacity = %d, num buckets used = %u,\n"), prefix, ht->bits.num_buckets_idx, CFBasicHashGetNumBuckets(ht), CFBasicHashGetCapacity(ht), ht->bits.used_buckets); + CFStringAppendFormat(result, NULL, CFSTR("%@counts width = %d, finalized = %s,\n"), prefix,((ht->bits.counts_offset) ? (1 << ht->bits.counts_width) : 0), (ht->bits.finalized ? "yes" : "no")); CFStringAppendFormat(result, NULL, CFSTR("%@num mutations = %ld, num deleted = %ld, size = %ld, total size = %ld,\n"), prefix, ht->bits.mutations, ht->bits.deleted, CFBasicHashGetSize(ht, false), CFBasicHashGetSize(ht, true)); - CFStringAppendFormat(result, NULL, CFSTR("%@values ptr = %p, keys ptr = %p, counts ptr = %p, hashes ptr = %p,\n"), prefix, __CFBasicHashGetValues(ht), ((0 != ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht) : NULL), ((0 != ht->bits.counts_offset) ? __CFBasicHashGetCounts(ht) : NULL), ((0 != ht->bits.hashes_offset) ? __CFBasicHashGetHashes(ht) : NULL)); + CFStringAppendFormat(result, NULL, CFSTR("%@values ptr = %p, keys ptr = %p, counts ptr = %p, hashes ptr = %p,\n"), prefix, __CFBasicHashGetValues(ht), ((ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht) : NULL), ((ht->bits.counts_offset) ? __CFBasicHashGetCounts(ht) : NULL), (__CFBasicHashHasHashCache(ht) ? __CFBasicHashGetHashes(ht) : NULL)); } CFStringAppendFormat(result, NULL, CFSTR("%@entries =>\n"), prefix); CFBasicHashApply(ht, ^(CFBasicHashBucket bkt) { CFStringRef vDesc = NULL, kDesc = NULL; - CFBasicHashCallbackType cb = ht->callbacks->func; - if (!describeElements) cb = __CFBasicHashNullCallback; - vDesc = (CFStringRef)cb(ht, kCFBasicHashCallbackOpDescribeValue, bkt.weak_value, 0, ht->callbacks); - if (0 != ht->bits.keys_offset) { - kDesc = (CFStringRef)cb(ht, kCFBasicHashCallbackOpDescribeKey, bkt.weak_key, 0, ht->callbacks); + if (!describeElements) { + vDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)bkt.weak_value); + if (ht->bits.keys_offset) { + kDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)bkt.weak_key); + } + } else { + vDesc = ht->callbacks->copyValueDescription(ht, bkt.weak_value); + if (ht->bits.keys_offset) { + kDesc = ht->callbacks->copyKeyDescription(ht, bkt.weak_key); + } } - if ((0 != ht->bits.keys_offset) && (0 != ht->bits.counts_offset)) { + if (ht->bits.keys_offset && ht->bits.counts_offset) { CFStringAppendFormat(result, NULL, CFSTR("%@%ld : %@ = %@ (%ld)\n"), entryPrefix, bkt.idx, kDesc, vDesc, bkt.count); - } else if (0 != ht->bits.keys_offset) { + } else if (ht->bits.keys_offset) { CFStringAppendFormat(result, NULL, CFSTR("%@%ld : %@ = %@\n"), entryPrefix, bkt.idx, kDesc, vDesc); - } else if (0 != ht->bits.counts_offset) { + } else if (ht->bits.counts_offset) { CFStringAppendFormat(result, NULL, CFSTR("%@%ld : %@ (%ld)\n"), entryPrefix, bkt.idx, vDesc, bkt.count); } else { CFStringAppendFormat(result, NULL, CFSTR("%@%ld : %@\n"), entryPrefix, bkt.idx, vDesc); @@ -1501,7 +1479,7 @@ __private_extern__ CFStringRef CFBasicHashCopyDescription(CFBasicHashRef ht, Boo return result; } -__private_extern__ void CFBasicHashShow(CFBasicHashRef ht) { +__private_extern__ void CFBasicHashShow(CFConstBasicHashRef ht) { CFStringRef str = CFBasicHashCopyDescription(ht, true, CFSTR(""), CFSTR("\t"), false); CFShow(str); CFRelease(str); @@ -1559,37 +1537,56 @@ __private_extern__ CFTypeID CFBasicHashGetTypeID(void) { CFBasicHashRef CFBasicHashCreate(CFAllocatorRef allocator, CFOptionFlags flags, const CFBasicHashCallbacks *cb) { size_t size = sizeof(struct __CFBasicHash) - sizeof(CFRuntimeBase); - if (flags & kCFBasicHashHasValues2) size += sizeof(CFBasicHashValue *); // values2 if (flags & kCFBasicHashHasKeys) size += sizeof(CFBasicHashValue *); // keys - if (flags & kCFBasicHashHasKeys2) size += sizeof(CFBasicHashValue *); // keys2 - if (flags & kCFBasicHashHasCounts) size += sizeof(uintptr_t *); // counts - if (flags & kCFBasicHashHasOrder) size += sizeof(uintptr_t *); // order + 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; ht->bits.finalized = 0; - ht->bits.strong_values = (flags & kCFBasicHashStrongValues) ? 1 : 0; - ht->bits.strong_values2 = 0; - ht->bits.strong_keys = (flags & kCFBasicHashStrongKeys) ? 1 : 0; - ht->bits.strong_keys2 = 0; ht->bits.hash_style = (flags >> 13) & 0x3; ht->bits.fast_grow = (flags & kCFBasicHashAggressiveGrowth) ? 1 : 0; - ht->bits.__0 = 0; + ht->bits.counts_width = 0; + ht->bits.strong_values = (flags & kCFBasicHashStrongValues) ? 1 : 0; + ht->bits.strong_keys = (flags & kCFBasicHashStrongKeys) ? 1 : 0; + ht->bits.weak_values = (flags & kCFBasicHashWeakValues) ? 1 : 0; + ht->bits.weak_keys = (flags & kCFBasicHashWeakKeys) ? 1 : 0; + ht->bits.int_values = (flags & kCFBasicHashIntegerValues) ? 1 : 0; + ht->bits.int_keys = (flags & kCFBasicHashIntegerKeys) ? 1 : 0; + ht->bits.indirect_keys = (flags & kCFBasicHashIndirectKeys) ? 1 : 0; + ht->bits.compactable_keys = (flags & kCFBasicHashCompactableKeys) ? 1 : 0; + ht->bits.compactable_values = (flags & kCFBasicHashCompactableValues) ? 1 : 0; + ht->bits.__2 = 0; + ht->bits.__8 = 0; + ht->bits.__9 = 0; ht->bits.num_buckets_idx = 0; ht->bits.used_buckets = 0; - ht->bits.marker = 0; ht->bits.deleted = 0; ht->bits.mutations = 1; + if (ht->bits.strong_values && ht->bits.weak_values) HALT; + if (ht->bits.strong_values && ht->bits.int_values) HALT; + if (ht->bits.strong_keys && ht->bits.weak_keys) HALT; + if (ht->bits.strong_keys && ht->bits.int_keys) HALT; + if (ht->bits.weak_values && ht->bits.int_values) HALT; + if (ht->bits.weak_keys && ht->bits.int_keys) HALT; + if (ht->bits.indirect_keys && ht->bits.strong_keys) HALT; + if (ht->bits.indirect_keys && ht->bits.weak_keys) HALT; + if (ht->bits.indirect_keys && ht->bits.int_keys) HALT; + uint64_t offset = 1; - ht->bits.values2_offset = 0; ht->bits.keys_offset = (flags & kCFBasicHashHasKeys) ? offset++ : 0; - ht->bits.keys2_offset = 0; ht->bits.counts_offset = (flags & kCFBasicHashHasCounts) ? offset++ : 0; - ht->bits.orders_offset = 0; ht->bits.hashes_offset = (flags & kCFBasicHashHasHashCache) ? offset++ : 0; +#if defined(__arm__) + ht->bits.hashes_offset = 0; + ht->bits.strong_values = 0; + ht->bits.strong_keys = 0; + ht->bits.weak_values = 0; + ht->bits.weak_keys = 0; +#endif + __AssignWithWriteBarrier(&ht->callbacks, cb); for (CFIndex idx = 0; idx < offset; idx++) { ht->pointers[idx] = NULL; @@ -1606,7 +1603,7 @@ CFBasicHashRef CFBasicHashCreate(CFAllocatorRef allocator, CFOptionFlags flags, return ht; } -CFBasicHashRef CFBasicHashCreateCopy(CFAllocatorRef allocator, CFBasicHashRef src_ht) { +CFBasicHashRef CFBasicHashCreateCopy(CFAllocatorRef allocator, CFConstBasicHashRef src_ht) { size_t size = CFBasicHashGetSize(src_ht, false) - sizeof(CFRuntimeBase); CFBasicHashRef ht = (CFBasicHashRef)_CFRuntimeCreateInstance(allocator, CFBasicHashGetTypeID(), size, NULL); if (NULL == ht) HALT; @@ -1614,14 +1611,15 @@ CFBasicHashRef CFBasicHashCreateCopy(CFAllocatorRef allocator, CFBasicHashRef sr memmove((uint8_t *)ht + sizeof(CFRuntimeBase), (uint8_t *)src_ht + sizeof(CFRuntimeBase), sizeof(ht->bits)); if (kCFUseCollectableAllocator && !CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { ht->bits.strong_values = 0; - ht->bits.strong_values2 = 0; ht->bits.strong_keys = 0; - ht->bits.strong_keys2 = 0; + ht->bits.weak_values = 0; + ht->bits.weak_keys = 0; } ht->bits.finalized = 0; ht->bits.mutations = 1; - __AssignWithWriteBarrier(&ht->callbacks, src_ht->callbacks->func(ht, kCFBasicHashCallbackOpCopyCallbacks, (uintptr_t)allocator, 0, src_ht->callbacks)); - if (NULL == ht->callbacks) HALT; + 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) { @@ -1635,116 +1633,76 @@ CFBasicHashRef CFBasicHashCreateCopy(CFAllocatorRef allocator, CFBasicHashRef sr return ht; } - CFBasicHashValue *new_values = NULL, *new_values2 = NULL, *new_keys = NULL, *new_keys2 = NULL; - uintptr_t *new_counts = NULL, *new_orders = NULL, *new_hashes = NULL; + 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), ht->bits.strong_values); + new_values = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), CFBasicHashHasStrongValues(ht), __CFBasicHashHasCompactableValues(ht)); __SetLastAllocationEventName(new_values, "CFBasicHash (value-store)"); - if (0 != ht->bits.values2_offset) { - new_values2 = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), ht->bits.strong_values2); - __SetLastAllocationEventName(new_values2, "CFBasicHash (value2-store)"); - } - if (0 != ht->bits.keys_offset) { - new_keys = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), ht->bits.strong_keys); + 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 (0 != ht->bits.keys2_offset) { - new_keys2 = (CFBasicHashValue *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(CFBasicHashValue), ht->bits.strong_keys2); - __SetLastAllocationEventName(new_keys2, "CFBasicHash (key2-store)"); - } - if (0 != ht->bits.counts_offset) { - new_counts = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false); + 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 (0 != ht->bits.orders_offset) { - new_orders = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false); - __SetLastAllocationEventName(new_orders, "CFBasicHash (order-store)"); - } - if (0 != ht->bits.hashes_offset) { - new_hashes = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false); + if (__CFBasicHashHasHashCache(ht)) { + new_hashes = (uintptr_t *)__CFBasicHashAllocateMemory(ht, new_num_buckets, sizeof(uintptr_t), false, false); __SetLastAllocationEventName(new_hashes, "CFBasicHash (hash-store)"); } } - uintptr_t empty = ((uintptr_t)ht->bits.marker << __CFBasicHashMarkerShift), deleted = ~empty; - CFBasicHashValue *old_values = NULL, *old_values2 = NULL, *old_keys = NULL, *old_keys2 = NULL; - uintptr_t *old_counts = NULL, *old_orders = NULL, *old_hashes = NULL; + CFBasicHashValue *old_values = NULL, *old_keys = NULL; + void *old_counts = NULL; + uintptr_t *old_hashes = NULL; + old_values = __CFBasicHashGetValues(src_ht); - if (0 != src_ht->bits.values2_offset) { - old_values2 = __CFBasicHashGetValues2(src_ht); - } - if (0 != src_ht->bits.keys_offset) { + if (src_ht->bits.keys_offset) { old_keys = __CFBasicHashGetKeys(src_ht); } - if (0 != src_ht->bits.keys2_offset) { - old_keys2 = __CFBasicHashGetKeys2(src_ht); - } - if (0 != src_ht->bits.counts_offset) { + if (src_ht->bits.counts_offset) { old_counts = __CFBasicHashGetCounts(src_ht); } - if (0 != src_ht->bits.orders_offset) { - old_orders = __CFBasicHashGetOrders(src_ht); - } - if (0 != src_ht->bits.hashes_offset) { + if (__CFBasicHashHasHashCache(src_ht)) { old_hashes = __CFBasicHashGetHashes(src_ht); } - CFBasicHashValue *keys = old_keys ? old_keys : old_values; - for (CFIndex idx = 0; idx < new_num_buckets; idx++) { - uintptr_t stack_key = keys[idx].weak; - if (stack_key != empty && stack_key != deleted) { - uintptr_t stack_value = __CFBasicHashImportValue(ht, old_values[idx].weak); - if (ht->bits.strong_values) new_values[idx].strong = (id)stack_value; else new_values[idx].weak = stack_value; - if (new_values2) { - uintptr_t stack_value2 = __CFBasicHashImportValue2(ht, old_values2[idx].weak); - if (ht->bits.strong_values2) new_values2[idx].strong = (id)stack_value2; else new_values2[idx].weak = stack_value2; - } - if (new_keys) { - uintptr_t stack_key = __CFBasicHashImportKey(ht, old_keys[idx].weak); - if (ht->bits.strong_keys) new_keys[idx].strong = (id)stack_key; else new_keys[idx].weak = stack_key; - } - if (new_keys2) { - uintptr_t stack_key2 = __CFBasicHashImportKey2(ht, old_keys2[idx].weak); - if (ht->bits.strong_keys2) new_keys2[idx].strong = (id)stack_key2; else new_keys2[idx].weak = stack_key2; - } - } else { - if (ht->bits.strong_values) new_values[idx].strong = (id)stack_key; else new_values[idx].weak = stack_key; - if (new_values2) { - if (ht->bits.strong_values2) new_values2[idx].strong = (id)stack_key; else new_values2[idx].weak = stack_key; - } - if (new_keys) { - if (ht->bits.strong_keys) new_keys[idx].strong = (id)stack_key; else new_keys[idx].weak = stack_key; - } - if (new_keys2) { - if (ht->bits.strong_keys2) new_keys2[idx].strong = (id)stack_key; else new_keys2[idx].weak = stack_key; - } - } - } - if (new_counts) memmove(new_counts, old_counts, new_num_buckets * sizeof(uintptr_t)); - if (new_orders) memmove(new_orders, old_orders, new_num_buckets * sizeof(uintptr_t)); - if (new_hashes) memmove(new_hashes, old_hashes, new_num_buckets * sizeof(uintptr_t)); - __CFBasicHashSetValues(ht, new_values); - if (new_values2) { - __CFBasicHashSetValues2(ht, new_values2); - } if (new_keys) { __CFBasicHashSetKeys(ht, new_keys); } - if (new_keys2) { - __CFBasicHashSetKeys2(ht, new_keys2); - } if (new_counts) { __CFBasicHashSetCounts(ht, new_counts); } - if (new_orders) { - __CFBasicHashSetOrders(ht, new_orders); - } if (new_hashes) { __CFBasicHashSetHashes(ht, new_hashes); } + for (CFIndex idx = 0; idx < new_num_buckets; idx++) { + uintptr_t stack_value = old_values[idx].neutral; + if (stack_value != 0UL && stack_value != ~0UL) { + uintptr_t old_value = stack_value; + if (__CFBasicHashSubABZero == old_value) old_value = 0UL; + if (__CFBasicHashSubABOne == old_value) old_value = ~0UL; + __CFBasicHashSetValue(ht, idx, __CFBasicHashImportValue(ht, old_value), true, false); + if (new_keys) { + uintptr_t old_key = old_keys[idx].neutral; + if (__CFBasicHashSubABZero == old_key) old_key = 0UL; + if (__CFBasicHashSubABOne == old_key) old_key = ~0UL; + __CFBasicHashSetKey(ht, idx, __CFBasicHashImportKey(ht, old_key), true, false); + } + } else { + __CFBasicHashSetValue(ht, idx, stack_value, true, true); + if (new_keys) { + __CFBasicHashSetKey(ht, idx, stack_value, true, true); + } + } + } + if (new_counts) memmove(new_counts, old_counts, new_num_buckets * (1 << ht->bits.counts_width)); + if (new_hashes) memmove(new_hashes, old_hashes, new_num_buckets * sizeof(uintptr_t)); + #if ENABLE_MEMORY_COUNTERS int64_t size_now = OSAtomicAdd64Barrier((int64_t) CFBasicHashGetSize(ht, true), & __CFBasicHashTotalSize); while (__CFBasicHashPeakSize < size_now && !OSAtomicCompareAndSwap64Barrier(__CFBasicHashPeakSize, size_now, & __CFBasicHashPeakSize)); @@ -1756,6 +1714,10 @@ CFBasicHashRef CFBasicHashCreateCopy(CFAllocatorRef allocator, CFBasicHashRef sr return ht; } +__private_extern__ void __CFBasicHashSetCallbacks(CFBasicHashRef ht, const CFBasicHashCallbacks *cb) { + __AssignWithWriteBarrier(&ht->callbacks, cb); +} + void _CFbhx588461(CFBasicHashRef ht, Boolean growth) { if (!CFBasicHashIsMutable(ht)) HALT; if (ht->bits.finalized) HALT; diff --git a/CFBasicHashFindBucket.m b/CFBasicHashFindBucket.m new file mode 100644 index 0000000..0eba573 --- /dev/null +++ b/CFBasicHashFindBucket.m @@ -0,0 +1,198 @@ +/* + * Copyright (c) 2011 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@ + */ + +/* CFBasicHashFindBucket.m + Copyright (c) 2009-2011, Apple Inc. All rights reserved. + Responsibility: Christopher Kane +*/ + + +#if !defined(FIND_BUCKET_NAME) || !defined(FIND_BUCKET_HASH_STYLE) || !defined(FIND_BUCKET_FOR_REHASH) || !defined(FIND_BUCKET_FOR_INDIRECT_KEY) +#error All of FIND_BUCKET_NAME, FIND_BUCKET_HASH_STYLE, FIND_BUCKET_FOR_REHASH, and FIND_BUCKET_FOR_INDIRECT_KEY must be defined before #including this file. +#endif + + +// During rehashing of a mutable CFBasicHash, we know that there are no +// deleted slots and the keys have already been uniqued. When rehashing, +// if key_hash is non-0, we use it as the hash code. +static +#if FIND_BUCKET_FOR_REHASH +CFIndex +#else +CFBasicHashBucket +#endif +FIND_BUCKET_NAME (CFConstBasicHashRef ht, uintptr_t stack_key +#if FIND_BUCKET_FOR_REHASH +, uintptr_t key_hash +#endif +) { + uint8_t num_buckets_idx = ht->bits.num_buckets_idx; + uintptr_t num_buckets = __CFBasicHashTableSizes[num_buckets_idx]; +#if FIND_BUCKET_FOR_REHASH + CFHashCode hash_code = key_hash ? key_hash : __CFBasicHashHashKey(ht, stack_key); +#else + CFHashCode hash_code = __CFBasicHashHashKey(ht, stack_key); +#endif + +#if FIND_BUCKET_HASH_STYLE == 1 // __kCFBasicHashLinearHashingValue + // Linear probing, with c = 1 + // probe[0] = h1(k) + // probe[i] = (h1(k) + i * c) mod num_buckets, i = 1 .. num_buckets - 1 + // h1(k) = k mod num_buckets +#if defined(__arm__) + uintptr_t h1 = __CFBasicHashFold(hash_code, num_buckets_idx); +#else + uintptr_t h1 = hash_code % num_buckets; +#endif +#elif FIND_BUCKET_HASH_STYLE == 2 // __kCFBasicHashDoubleHashingValue + // Double hashing + // probe[0] = h1(k) + // probe[i] = (h1(k) + i * h2(k)) mod num_buckets, i = 1 .. num_buckets - 1 + // h1(k) = k mod num_buckets + // h2(k) = floor(k / num_buckets) mod num_buckets +#if defined(__arm__) + uintptr_t h1 = __CFBasicHashFold(hash_code, num_buckets_idx); + uintptr_t h2 = __CFBasicHashFold(hash_code / num_buckets, num_buckets_idx); +#else + uintptr_t h1 = hash_code % num_buckets; + uintptr_t h2 = (hash_code / num_buckets) % num_buckets; +#endif + if (0 == h2) h2 = num_buckets - 1; +#elif FIND_BUCKET_HASH_STYLE == 3 // __kCFBasicHashExponentialHashingValue + // Improved exponential hashing + // probe[0] = h1(k) + // probe[i] = (h1(k) + pr(k)^i * h2(k)) mod num_buckets, i = 1 .. num_buckets - 1 + // h1(k) = k mod num_buckets + // h2(k) = floor(k / num_buckets) mod num_buckets + // note: h2(k) has the effect of rotating the sequence if it is constant + // note: pr(k) is any primitive root of num_buckets, varying this gives different sequences +#if defined(__arm__) + uintptr_t h1 = __CFBasicHashFold(hash_code, num_buckets_idx); + uintptr_t h2 = __CFBasicHashFold(hash_code / num_buckets, num_buckets_idx); +#else + uintptr_t h1 = hash_code % num_buckets; + uintptr_t h2 = (hash_code / num_buckets) % num_buckets; +#endif + if (0 == h2) h2 = num_buckets - 1; + uintptr_t pr = __CFBasicHashPrimitiveRoots[num_buckets_idx]; +#endif + + COCOA_HASHTABLE_PROBING_START(ht, num_buckets); + CFBasicHashValue *keys = (ht->bits.keys_offset) ? __CFBasicHashGetKeys(ht) : __CFBasicHashGetValues(ht); +#if !FIND_BUCKET_FOR_REHASH + uintptr_t *hashes = (__CFBasicHashHasHashCache(ht)) ? __CFBasicHashGetHashes(ht) : NULL; +#endif + CFIndex deleted_idx = kCFNotFound; + uintptr_t probe = h1; +#if FIND_BUCKET_HASH_STYLE == 3 // __kCFBasicHashExponentialHashingValue + uintptr_t acc = pr; +#endif + for (CFIndex idx = 0; idx < num_buckets; idx++) { + uintptr_t curr_key = keys[probe].neutral; + if (curr_key == 0UL) { + COCOA_HASHTABLE_PROBE_EMPTY(ht, probe); +#if FIND_BUCKET_FOR_REHASH + CFIndex result = (kCFNotFound == deleted_idx) ? probe : deleted_idx; +#else + CFBasicHashBucket result; + result.idx = (kCFNotFound == deleted_idx) ? probe : deleted_idx; + result.count = 0; +#endif + COCOA_HASHTABLE_PROBING_END(ht, idx + 1); + return result; +#if !FIND_BUCKET_FOR_REHASH + } else if (curr_key == ~0UL) { + COCOA_HASHTABLE_PROBE_DELETED(ht, probe); + if (kCFNotFound == deleted_idx) { + deleted_idx = probe; + } + } else { + COCOA_HASHTABLE_PROBE_VALID(ht, probe); + if (__CFBasicHashSubABZero == curr_key) curr_key = 0UL; + if (__CFBasicHashSubABOne == curr_key) curr_key = ~0UL; +#if FIND_BUCKET_FOR_INDIRECT_KEY + // curr_key holds the value coming in here + curr_key = ht->callbacks->getIndirectKey(ht, curr_key); +#endif + if (curr_key == stack_key || ((!hashes || hashes[probe] == hash_code) && __CFBasicHashTestEqualKey(ht, curr_key, stack_key))) { + COCOA_HASHTABLE_PROBING_END(ht, idx + 1); +#if FIND_BUCKET_FOR_REHASH + CFIndex result = probe; +#else + CFBasicHashBucket result; + result.idx = probe; + result.weak_value = __CFBasicHashGetValue(ht, probe); + result.weak_key = curr_key; + result.count = (ht->bits.counts_offset) ? __CFBasicHashGetSlotCount(ht, probe) : 1; +#endif + return result; + } +#endif + } + +#if FIND_BUCKET_HASH_STYLE == 1 // __kCFBasicHashLinearHashingValue + probe += 1; + if (num_buckets <= probe) { + probe -= num_buckets; + } +#elif FIND_BUCKET_HASH_STYLE == 2 // __kCFBasicHashDoubleHashingValue + probe += h2; + if (num_buckets <= probe) { + probe -= num_buckets; + } +#elif FIND_BUCKET_HASH_STYLE == 3 // __kCFBasicHashExponentialHashingValue + probe = h1 + h2 * acc; + if (num_buckets <= probe) { +#if defined(__arm__) + probe = __CFBasicHashFold(probe, num_buckets_idx); +#else + probe = probe % num_buckets; +#endif + } + acc = acc * pr; + if (num_buckets <= acc) { +#if defined(__arm__) + acc = __CFBasicHashFold(acc, num_buckets_idx); +#else + acc = acc % num_buckets; +#endif + } +#endif + + } + COCOA_HASHTABLE_PROBING_END(ht, num_buckets); +#if FIND_BUCKET_FOR_REHASH + CFIndex result = deleted_idx; +#else + CFBasicHashBucket result; + result.idx = deleted_idx; + result.count = 0; +#endif + return result; // all buckets full or deleted, return first deleted element which was found +} + +#undef FIND_BUCKET_NAME +#undef FIND_BUCKET_HASH_STYLE +#undef FIND_BUCKET_FOR_REHASH +#undef FIND_BUCKET_FOR_INDIRECT_KEY + diff --git a/CFBinaryHeap.c b/CFBinaryHeap.c index 6203df3..38d46b0 100644 --- a/CFBinaryHeap.c +++ b/CFBinaryHeap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFBinaryHeap.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ @@ -167,7 +167,7 @@ static CFStringRef __CFBinaryHeapCopyDescription(CFTypeRef cf) { desc = heap->_callbacks.copyDescription(item); } if (NULL != desc) { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : %s\n"), idx, desc); + CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@\n"), idx, desc); CFRelease(desc); } else { CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p>\n"), idx, item); @@ -320,7 +320,7 @@ const void *CFBinaryHeapGetMinimum(CFBinaryHeapRef heap) { Boolean CFBinaryHeapGetMinimumIfPresent(CFBinaryHeapRef heap, const void **value) { __CFGenericValidateType(heap, __kCFBinaryHeapTypeID); if (0 == __CFBinaryHeapCount(heap)) return false; - if (NULL != value) __CFAssignWithWriteBarrier((void **)&heap->_buckets[0]._item, value); + if (NULL != value) __CFAssignWithWriteBarrier((void **)value, heap->_buckets[0]._item); return true; } diff --git a/CFBinaryHeap.h b/CFBinaryHeap.h index a5e2cc6..f87fe04 100644 --- a/CFBinaryHeap.h +++ b/CFBinaryHeap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFBinaryHeap.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ /*! @header CFBinaryHeap diff --git a/CFBinaryPList.c b/CFBinaryPList.c index 4ca94c8..49865dc 100644 --- a/CFBinaryPList.c +++ b/CFBinaryPList.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFBinaryPList.c - Copyright (c) 2000-2009, Apple Inc. All rights reserved. + Copyright (c) 2000-2011, Apple Inc. All rights reserved. Responsibility: Tony Parker */ @@ -42,6 +42,9 @@ #include #include #include "CFInternal.h" +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS +#include +#endif typedef struct { int64_t high; @@ -53,7 +56,7 @@ enum { }; CF_EXPORT CFNumberType _CFNumberGetType2(CFNumberRef number); -__private_extern__ CFErrorRef __CFPropertyListCreateError(CFAllocatorRef allocator, CFIndex code, CFStringRef debugString, ...); +__private_extern__ CFErrorRef __CFPropertyListCreateError(CFIndex code, CFStringRef debugString, ...); enum { CF_NO_ERROR = 0, @@ -96,11 +99,6 @@ CF_INLINE uint64_t __check_uint64_mul_unsigned_unsigned(uint64_t x, uint64_t y, #endif -CF_INLINE CFTypeID __CFGenericTypeID_genericobj_inline(const void *cf) { - CFTypeID typeID = (*(uint32_t *)(((CFRuntimeBase *)cf)->_cfinfo) >> 8) & 0xFFFF; - return CF_IS_OBJC(typeID, cf) ? CFGetTypeID(cf) : typeID; -} - struct __CFKeyedArchiverUID { CFRuntimeBase _base; uint32_t _value; @@ -170,7 +168,25 @@ static void writeBytes(__CFBinaryPlistWriteBuffer *buf, const UInt8 *bytes, CFIn CFDataAppendBytes((CFMutableDataRef)buf->stream, bytes, length); buf->written += length; } else { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS + while (0 < length) { + CFIndex ret = CFWriteStreamWrite((CFWriteStreamRef)buf->stream, bytes, length); + if (ret == 0) { + buf->error = __CFPropertyListCreateError(kCFPropertyListWriteStreamError, CFSTR("Binary property list writing could not be completed because stream is full.")); + return; + } + if (ret < 0) { + CFErrorRef err = CFWriteStreamCopyError((CFWriteStreamRef)buf->stream); + buf->error = err ? err : __CFPropertyListCreateError(kCFPropertyListWriteStreamError, CFSTR("Binary property list writing could not be completed because the stream had an unknown error.")); + return; + } + buf->written += ret; + length -= ret; + bytes += ret; + } +#else CFAssert(false, __kCFLogAssertion, "Streams are not supported on this platform"); +#endif } } @@ -321,7 +337,7 @@ static void _appendUID(__CFBinaryPlistWriteBuffer *buf, CFKeyedArchiverUIDRef ui static void _flattenPlist(CFPropertyListRef plist, CFMutableArrayRef objlist, CFMutableDictionaryRef objtable, CFMutableSetRef uniquingset) { CFPropertyListRef unique; uint32_t refnum; - CFTypeID type = __CFGenericTypeID_genericobj_inline(plist); + CFTypeID type = CFGetTypeID(plist); CFIndex idx; CFPropertyListRef *list, buffer[256]; @@ -346,20 +362,20 @@ static void _flattenPlist(CFPropertyListRef plist, CFMutableArrayRef objlist, CF CFDictionaryAddValue(objtable, plist, (const void *)(uintptr_t)refnum); if (dicttype == type) { CFIndex count = CFDictionaryGetCount((CFDictionaryRef)plist); - list = (count <= 128) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 2 * count * sizeof(CFTypeRef), 0); + list = (count <= 128) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, 2 * count * sizeof(CFTypeRef), __kCFAllocatorGCScannedMemory); CFDictionaryGetKeysAndValues((CFDictionaryRef)plist, list, list + count); for (idx = 0; idx < 2 * count; idx++) { _flattenPlist(list[idx], objlist, objtable, uniquingset); } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); } else if (arraytype == type) { CFIndex count = CFArrayGetCount((CFArrayRef)plist); - list = (count <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, count * sizeof(CFTypeRef), 0); + list = (count <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, count * sizeof(CFTypeRef), __kCFAllocatorGCScannedMemory); CFArrayGetValues((CFArrayRef)plist, CFRangeMake(0, count), list); for (idx = 0; idx < count; idx++) { _flattenPlist(list[idx], objlist, objtable, uniquingset); } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); } } @@ -385,7 +401,7 @@ CF_INLINE uint8_t _byteCount(uint64_t count) { } -// stream must be a CFMutableDataRef +// 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; @@ -399,9 +415,16 @@ CFIndex __CFBinaryPlistWrite(CFPropertyListRef plist, CFTypeRef stream, uint64_t initStatics(); - objtable = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); - objlist = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, NULL); - uniquingset = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, NULL); + const CFDictionaryKeyCallBacks dictKeyCallbacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, 0, 0, 0}; + objtable = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &dictKeyCallbacks, NULL); + + const CFArrayCallBacks arrayCallbacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, 0, 0}; + objlist = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &arrayCallbacks); + + + const CFSetCallBacks setCallbacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, 0, 0, 0}; + uniquingset = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &setCallbacks); + #if DEPLOYMENT_TARGET_MACOSX _CFDictionarySetCapacity(objtable, estimate ? estimate : 650); _CFArraySetCapacity(objlist, estimate ? estimate : 650); @@ -413,9 +436,9 @@ CFIndex __CFBinaryPlistWrite(CFPropertyListRef plist, CFTypeRef stream, uint64_t CFRelease(uniquingset); cnt = CFArrayGetCount(objlist); - offsets = (uint64_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, (CFIndex)(cnt * sizeof(*offsets)), 0); + offsets = (uint64_t *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, (CFIndex)(cnt * sizeof(*offsets)), 0); - buf = (__CFBinaryPlistWriteBuffer *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFBinaryPlistWriteBuffer), 0); + buf = (__CFBinaryPlistWriteBuffer *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, sizeof(__CFBinaryPlistWriteBuffer), 0); buf->stream = stream; buf->error = NULL; buf->streamIsData = (CFGetTypeID(stream) == CFDataGetTypeID()); @@ -429,13 +452,13 @@ CFIndex __CFBinaryPlistWrite(CFPropertyListRef plist, CFTypeRef stream, uint64_t trailer._objectRefSize = _byteCount(cnt); for (idx = 0; idx < cnt; idx++) { CFPropertyListRef obj = CFArrayGetValueAtIndex(objlist, (CFIndex)idx); - CFTypeID type = __CFGenericTypeID_genericobj_inline(obj); + 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(kCFAllocatorSystemDefault, count, 0); + 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); @@ -453,15 +476,15 @@ CFIndex __CFBinaryPlistWrite(CFPropertyListRef plist, CFTypeRef stream, uint64_t if (15 <= count) { _appendInt(buf, (uint64_t)count); } - chars = (UniChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, count * sizeof(UniChar), 0); + 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(kCFAllocatorSystemDefault, chars); + CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, chars); } - if (bytes != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, bytes); + if (bytes != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, bytes); } else if (numbertype == type) { uint8_t marker; uint64_t bigint; @@ -538,7 +561,7 @@ CFIndex __CFBinaryPlistWrite(CFPropertyListRef plist, CFTypeRef stream, uint64_t CFPropertyListRef *list, buffer[512]; - list = (count <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 2 * count * sizeof(CFTypeRef), 0); + 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]; @@ -548,7 +571,7 @@ CFIndex __CFBinaryPlistWrite(CFPropertyListRef plist, CFTypeRef stream, uint64_t swapped = CFSwapInt32HostToBig((uint32_t)refnum); bufferWrite(buf, source + sizeof(swapped) - trailer._objectRefSize, trailer._objectRefSize); } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); } else if (arraytype == type) { CFIndex count = CFArrayGetCount((CFArrayRef)obj); CFPropertyListRef *list, buffer[256]; @@ -557,7 +580,7 @@ CFIndex __CFBinaryPlistWrite(CFPropertyListRef plist, CFTypeRef stream, uint64_t if (15 <= count) { _appendInt(buf, (uint64_t)count); } - list = (count <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, count * sizeof(CFTypeRef), 0); + 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]; @@ -567,7 +590,7 @@ CFIndex __CFBinaryPlistWrite(CFPropertyListRef plist, CFTypeRef stream, uint64_t swapped = CFSwapInt32HostToBig((uint32_t)refnum); bufferWrite(buf, source + sizeof(swapped) - trailer._objectRefSize, trailer._objectRefSize); } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); } else { CFRelease(objtable); CFRelease(objlist); @@ -578,8 +601,8 @@ CFIndex __CFBinaryPlistWrite(CFPropertyListRef plist, CFTypeRef stream, uint64_t // caller is not interested in error, release it here CFRelease(buf->error); } - CFAllocatorDeallocate(kCFAllocatorSystemDefault, buf); - CFAllocatorDeallocate(kCFAllocatorSystemDefault, offsets); + CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, buf); + CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, offsets); return 0; } } @@ -596,6 +619,7 @@ CFIndex __CFBinaryPlistWrite(CFPropertyListRef plist, CFTypeRef stream, uint64_t bufferWrite(buf, source + sizeof(*offsets) - trailer._offsetIntSize, trailer._offsetIntSize); } length_so_far += cnt * trailer._offsetIntSize; + CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, offsets); bufferWrite(buf, (uint8_t *)&trailer, sizeof(trailer)); bufferFlush(buf); @@ -607,10 +631,10 @@ CFIndex __CFBinaryPlistWrite(CFPropertyListRef plist, CFTypeRef stream, uint64_t } else { CFRelease(buf->error); } + CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, buf); return 0; } - CFAllocatorDeallocate(kCFAllocatorSystemDefault, buf); - CFAllocatorDeallocate(kCFAllocatorSystemDefault, offsets); + CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, buf); return (CFIndex)length_so_far; } @@ -635,6 +659,7 @@ CFIndex __CFBinaryPlistWriteToStreamWithOptions(CFPropertyListRef plist, CFTypeR /* 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) { +#if defined(__i386__) || defined(__x86_64__) if (valSize == 1) { return (uint64_t)*data; } else if (valSize == 2) { @@ -646,16 +671,15 @@ CF_INLINE uint64_t _getSizedInt(const uint8_t *data, uint8_t valSize) { } else if (valSize == 8) { uint64_t val = *(uint64_t *)data; return CFSwapInt64BigToHost(val); - } else { - // Compatability with existing archives, including anything with a non-power-of-2 size and 16-byte values - uint64_t res = 0; - for (CFIndex idx = 0; idx < valSize; idx++) { - res = (res << 8) + data[idx]; - } - return res; } - // shouldn't get here - return 0; +#endif + // Compatability with existing archives, including anything with a non-power-of-2 + // size and 16-byte values, and architectures that don't support unaligned access + uint64_t res = 0; + for (CFIndex idx = 0; idx < valSize; idx++) { + res = (res << 8) + data[idx]; + } + return res; } bool __CFBinaryPlistGetTopLevelInfo(const uint8_t *databytes, uint64_t datalen, uint8_t *marker, uint64_t *offset, CFBinaryPlistTrailer *trailer) { @@ -676,27 +700,54 @@ bool __CFBinaryPlistGetTopLevelInfo(const uint8_t *databytes, uint64_t datalen, trail._numObjects = CFSwapInt64BigToHost(trail._numObjects); trail._topObject = CFSwapInt64BigToHost(trail._topObject); trail._offsetTableOffset = CFSwapInt64BigToHost(trail._offsetTableOffset); + + // Don't overflow on the number of objects or offset of the table if (LONG_MAX < trail._numObjects) FAIL_FALSE; if (LONG_MAX < trail._offsetTableOffset) FAIL_FALSE; + + // Must be a minimum of 1 object if (trail._numObjects < 1) FAIL_FALSE; + + // The ref to the top object must be a value in the range of 1 to the total number of objects if (trail._numObjects <= trail._topObject) FAIL_FALSE; + + // The offset table must be after at least 9 bytes of other data ('bplist??' + 1 byte of object table data). if (trail._offsetTableOffset < 9) FAIL_FALSE; + + // The trailer must point to a value before itself in the data. if (datalen - sizeof(trail) <= trail._offsetTableOffset) FAIL_FALSE; + + // Minimum of 1 byte for the size of integers and references in the data if (trail._offsetIntSize < 1) FAIL_FALSE; if (trail._objectRefSize < 1) FAIL_FALSE; + int32_t err = CF_NO_ERROR; + + // The total size of the offset table (number of objects * size of each int in the table) must not overflow uint64_t offsetIntSize = trail._offsetIntSize; uint64_t offsetTableSize = __check_uint64_mul_unsigned_unsigned(trail._numObjects, offsetIntSize, &err); if (CF_NO_ERROR!= err) FAIL_FALSE; + + // The offset table must have at least 1 entry if (offsetTableSize < 1) FAIL_FALSE; + + // Make sure the size of the offset table and data sections do not overflow uint64_t objectDataSize = trail._offsetTableOffset - 8; uint64_t tmpSum = __check_uint64_add_unsigned_unsigned(8, objectDataSize, &err); tmpSum = __check_uint64_add_unsigned_unsigned(tmpSum, offsetTableSize, &err); tmpSum = __check_uint64_add_unsigned_unsigned(tmpSum, sizeof(trail), &err); if (CF_NO_ERROR != err) FAIL_FALSE; + + // The total size of the data should be equal to the sum of offsetTableOffset + sizeof(trailer) if (datalen != tmpSum) FAIL_FALSE; + + // The object refs must be the right size to point into the offset table. That is, if the count of objects is 260, but only 1 byte is used to store references (max value 255), something is wrong. if (trail._objectRefSize < 8 && (1ULL << (8 * trail._objectRefSize)) <= trail._numObjects) FAIL_FALSE; + + // The integers used for pointers in the offset table must be able to reach as far as the start of the offset table. if (trail._offsetIntSize < 8 && (1ULL << (8 * trail._offsetIntSize)) <= trail._offsetTableOffset) FAIL_FALSE; + + const uint8_t *objectsFirstByte; objectsFirstByte = check_ptr_add(databytes, 8, &err); if (CF_NO_ERROR != err) FAIL_FALSE; @@ -724,7 +775,7 @@ bool __CFBinaryPlistGetTopLevelInfo(const uint8_t *databytes, uint64_t datalen, } CF_INLINE Boolean _plistIsPrimitive(CFPropertyListRef pl) { - CFTypeID type = __CFGenericTypeID_genericobj_inline(pl); + CFTypeID type = CFGetTypeID(pl); if (dicttype == type || arraytype == type || settype == type) FAIL_FALSE; return true; } @@ -850,7 +901,7 @@ bool __CFBinaryPlistGetOffsetForValueFromDictionary3(const uint8_t *databytes, u // For short keys (15 bytes or less) in ASCII form, we can do a quick comparison check // We get the pointer or copy the buffer here, outside of the loop CFIndex stringKeyLen = -1; - if (__CFGenericTypeID_genericobj_inline(key) == stringtype) { + if (CFGetTypeID(key) == stringtype) { stringKeyLen = CFStringGetLength((CFStringRef)key); } @@ -861,14 +912,16 @@ bool __CFBinaryPlistGetOffsetForValueFromDictionary3(const uint8_t *databytes, u Boolean match = false; CFPropertyListRef keyInData = NULL; - char keyBuffer[16]; - const char *keyBufferPtr = keyBuffer; +#define KEY_BUFF_SIZE 16 + char keyBuffer[KEY_BUFF_SIZE]; + const char *keyBufferPtr = NULL; - if (stringKeyLen < 0xf) { + // If we have a string for the key, then we will grab the ASCII encoded version of it, if possible, and do a memcmp on it + if (stringKeyLen != -1) { // Since we will only be comparing ASCII strings, we can attempt to get a pointer using MacRoman encoding // (this is cheaper than a copy) - if (!(keyBufferPtr = CFStringGetCStringPtr((CFStringRef)key, kCFStringEncodingMacRoman))) { - CFStringGetCString((CFStringRef)key, keyBuffer, 16, kCFStringEncodingMacRoman); + if (!(keyBufferPtr = CFStringGetCStringPtr((CFStringRef)key, kCFStringEncodingMacRoman)) && stringKeyLen < KEY_BUFF_SIZE) { + CFStringGetCString((CFStringRef)key, keyBuffer, KEY_BUFF_SIZE, kCFStringEncodingMacRoman); // The pointer should now point to our keyBuffer instead of the original string buffer, since we've copied it keyBufferPtr = keyBuffer; } @@ -878,31 +931,47 @@ bool __CFBinaryPlistGetOffsetForValueFromDictionary3(const uint8_t *databytes, u for (CFIndex idx = 0; idx < cnt; idx++) { off = _getOffsetOfRefAt(databytes, ptr, trailer); marker = *(databytes + off); - CFIndex len = marker & 0x0f; - // if it is a short ascii string in the data, and the key is a string - if (stringKeyLen != -1 && len < 0xf && (marker & 0xf0) == kCFBinaryPlistMarkerASCIIString) { + // if it is an ASCII string in the data, then we do a memcmp. If the key isn't ASCII, then it won't pass the compare, unless it hits some odd edge case of the ASCII string actually containing the unicode escape sequence. + if (keyBufferPtr && (marker & 0xf0) == kCFBinaryPlistMarkerASCIIString) { + CFIndex len = marker & 0x0f; + // move past the marker + const uint8_t *ptr2 = databytes + off; + err = CF_NO_ERROR; + ptr2 = check_ptr_add(ptr2, 1, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + + // If the key's length is large, and the length we are querying is also large, then we have to read it in. If stringKeyLen is less than 0xf, then len will never be equal to it if it was encoded as large. + if (0xf == len && stringKeyLen >= 0xf) { + uint64_t bigint = 0; + if (!_readInt(ptr2, databytes + objectsRangeEnd, &bigint, &ptr2)) FAIL_FALSE; + if (LONG_MAX < bigint) FAIL_FALSE; + len = (CFIndex)bigint; + } + if (len == stringKeyLen) { err = CF_NO_ERROR; - const uint8_t *ptr2 = databytes + off; extent = check_ptr_add(ptr2, len, &err); if (CF_NO_ERROR != err) FAIL_FALSE; if (databytes + trailer->_offsetTableOffset <= extent) FAIL_FALSE; - // Compare the key to this potential match (ptr2 + 1 moves past the marker) - if (memcmp(ptr2 + 1, keyBufferPtr, stringKeyLen) == 0) { + // Compare the key to this potential match + if (memcmp(ptr2, keyBufferPtr, stringKeyLen) == 0) { match = true; } } } else { + // temp object not saved in 'objects', because we don't know what allocator to use + // (what allocator __CFBinaryPlistCreateObject2() or __CFBinaryPlistCreateObject() + // will eventually be called with which results in that object) keyInData = NULL; - if (!__CFBinaryPlistCreateObject2(databytes, datalen, off, trailer, kCFAllocatorSystemDefault, kCFPropertyListImmutable, objects, NULL, 0, &keyInData) || !_plistIsPrimitive(keyInData)) { + if (!__CFBinaryPlistCreateObject2(databytes, datalen, off, trailer, kCFAllocatorSystemDefault, kCFPropertyListImmutable, NULL /*objects*/, NULL, 0, &keyInData) || !_plistIsPrimitive(keyInData)) { if (keyInData) CFRelease(keyInData); return false; } match = CFEqual(key, keyInData); - CFRelease(keyInData); + CFRelease(keyInData); } if (match) { @@ -910,19 +979,24 @@ bool __CFBinaryPlistGetOffsetForValueFromDictionary3(const uint8_t *databytes, u if (voffset) *voffset = _getOffsetOfRefAt(databytes, ptr + totalKeySize, trailer); return true; } - + ptr += trailer->_objectRefSize; } return false; } +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); + 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) { if (objects) { *plist = CFDictionaryGetValue(objects, (const void *)(uintptr_t)startOffset); if (*plist) { - CFRetain(*plist); + // have to assume that '*plist' was previously created with same allocator that is now being passed in + if (!_CFAllocatorIsGCRefZero(allocator)) CFRetain(*plist); return true; } } @@ -937,7 +1011,6 @@ CF_EXPORT bool __CFBinaryPlistCreateObject2(const uint8_t *databytes, uint64_t d uint64_t off; CFPropertyListRef *list, buffer[256]; - CFAllocatorRef listAllocator; uint8_t marker = *(databytes + startOffset); switch (marker & 0xf0) { @@ -947,10 +1020,10 @@ CF_EXPORT bool __CFBinaryPlistCreateObject2(const uint8_t *databytes, uint64_t d *plist = kCFNull; return true; case kCFBinaryPlistMarkerFalse: - *plist = CFRetain(kCFBooleanFalse); + *plist = !_CFAllocatorIsGCRefZero(allocator) ? CFRetain(kCFBooleanFalse) : kCFBooleanFalse; return true; case kCFBinaryPlistMarkerTrue: - *plist = CFRetain(kCFBooleanTrue); + *plist = !_CFAllocatorIsGCRefZero(allocator) ? CFRetain(kCFBooleanTrue) : kCFBooleanTrue; return true; } FAIL_FALSE; @@ -1091,7 +1164,7 @@ CF_EXPORT bool __CFBinaryPlistCreateObject2(const uint8_t *databytes, uint64_t d if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) { CFStringRef str = CFStringCreateWithBytes(allocator, ptr, cnt, kCFStringEncodingASCII, false); *plist = str ? CFStringCreateMutableCopy(allocator, 0, str) : NULL; - if (str) CFRelease(str); + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(str); } else { *plist = CFStringCreateWithBytes(allocator, ptr, cnt, kCFStringEncodingASCII, false); } @@ -1118,19 +1191,20 @@ CF_EXPORT bool __CFBinaryPlistCreateObject2(const uint8_t *databytes, uint64_t d if (databytes + objectsRangeEnd < extent) FAIL_FALSE; size_t byte_cnt = check_size_t_mul(cnt, sizeof(UniChar), &err); if (CF_NO_ERROR != err) FAIL_FALSE; - UniChar *chars = (UniChar *)CFAllocatorAllocate(allocator, byte_cnt, 0); + UniChar *chars = (UniChar *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, byte_cnt, 0); if (!chars) FAIL_FALSE; memmove(chars, ptr, byte_cnt); for (CFIndex idx = 0; idx < cnt; idx++) { chars[idx] = CFSwapInt16BigToHost(chars[idx]); } if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) { - CFStringRef str = CFStringCreateWithCharactersNoCopy(allocator, chars, cnt, allocator); + CFStringRef str = CFStringCreateWithCharacters(allocator, chars, cnt); *plist = str ? CFStringCreateMutableCopy(allocator, 0, str) : NULL; - if (str) CFRelease(str); + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(str); } else { - *plist = CFStringCreateWithCharactersNoCopy(allocator, chars, cnt, allocator); + *plist = CFStringCreateWithCharacters(allocator, chars, cnt); } + CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, chars); if (objects && *plist && (mutabilityOption != kCFPropertyListMutableContainersAndLeaves)) { CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist); } @@ -1176,8 +1250,7 @@ CF_EXPORT bool __CFBinaryPlistCreateObject2(const uint8_t *databytes, uint64_t d if (databytes + objectsRangeEnd < extent) FAIL_FALSE; byte_cnt = check_size_t_mul(cnt, sizeof(CFPropertyListRef), &err); if (CF_NO_ERROR != err) FAIL_FALSE; - list = (cnt <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, byte_cnt, 0); - listAllocator = (list == buffer ? kCFAllocatorNull : kCFAllocatorSystemDefault); + list = (cnt <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, byte_cnt, __kCFAllocatorGCScannedMemory); if (!list) FAIL_FALSE; Boolean madeSet = false; if (!set && 15 < curDepth) { @@ -1190,12 +1263,12 @@ CF_EXPORT bool __CFBinaryPlistCreateObject2(const uint8_t *databytes, uint64_t d off = _getOffsetOfRefAt(databytes, ptr, trailer); if (!__CFBinaryPlistCreateObject2(databytes, datalen, off, trailer, allocator, mutabilityOption, objects, set, curDepth + 1, &pl)) { while (idx--) { - CFRelease(list[idx]); + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); FAIL_FALSE; } - list[idx] = pl; + __CFAssignWithWriteBarrier((void **)list + idx, (void *)pl); ptr += trailer->_objectRefSize; } if (set) CFSetRemoveValue(set, (const void *)(uintptr_t)startOffset); @@ -1207,8 +1280,18 @@ CF_EXPORT bool __CFBinaryPlistCreateObject2(const uint8_t *databytes, uint64_t d 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 { - *plist = CFArrayCreate(allocator, list, cnt, &kCFTypeArrayCallBacks); + 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]); + } + } } } else { if (mutabilityOption != kCFPropertyListImmutable) { @@ -1216,17 +1299,24 @@ CF_EXPORT bool __CFBinaryPlistCreateObject2(const uint8_t *databytes, uint64_t d 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 { - *plist = CFSetCreate(allocator, list, cnt, &kCFTypeSetCallBacks); + if (!kCFUseCollectableAllocator) { + *plist = __CFSetCreateTransfer(allocator, list, cnt); + } else { + *plist = CFSetCreate(allocator, list, cnt, &kCFTypeSetCallBacks); + for (CFIndex idx = 0; idx < cnt; idx++) { + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); + } + } } } - for (CFIndex idx = 0; idx < cnt; idx++) { - CFRelease(list[idx]); - } if (objects && *plist && (mutabilityOption == kCFPropertyListImmutable)) { CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist); } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); return (*plist) ? true : false; } case kCFBinaryPlistMarkerDict: { @@ -1250,8 +1340,7 @@ CF_EXPORT bool __CFBinaryPlistCreateObject2(const uint8_t *databytes, uint64_t d if (databytes + objectsRangeEnd < extent) FAIL_FALSE; byte_cnt = check_size_t_mul(cnt, sizeof(CFPropertyListRef), &err); if (CF_NO_ERROR != err) FAIL_FALSE; - list = (cnt <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, byte_cnt, 0); - listAllocator = (list == buffer ? kCFAllocatorNull : kCFAllocatorSystemDefault); + list = (cnt <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, byte_cnt, __kCFAllocatorGCScannedMemory); if (!list) FAIL_FALSE; Boolean madeSet = false; if (!set && 15 < curDepth) { @@ -1263,14 +1352,14 @@ CF_EXPORT bool __CFBinaryPlistCreateObject2(const uint8_t *databytes, uint64_t d 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) CFRelease(pl); + if (pl && !_CFAllocatorIsGCRefZero(allocator)) CFRelease(pl); while (idx--) { - CFRelease(list[idx]); + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(list[idx]); } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); FAIL_FALSE; } - list[idx] = pl; + __CFAssignWithWriteBarrier((void **)list + idx, (void *)pl); ptr += trailer->_objectRefSize; } if (set) CFSetRemoveValue(set, (const void *)(uintptr_t)startOffset); @@ -1283,16 +1372,23 @@ CF_EXPORT bool __CFBinaryPlistCreateObject2(const uint8_t *databytes, uint64_t d 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 { - *plist = CFDictionaryCreate(allocator, list, list + cnt / 2, cnt / 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - } - for (CFIndex idx = 0; idx < cnt; idx++) { - CFRelease(list[idx]); + 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 (objects && *plist && (mutabilityOption == kCFPropertyListImmutable)) { CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist); } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, list); return (*plist) ? true : false; } } @@ -1318,7 +1414,7 @@ __private_extern__ bool __CFTryParseBinaryPlist(CFAllocatorRef allocator, CFData // be malformed and contain hash-equal keys for the same dictionary (for example) // and the later key will cause the previous one to be released when we set the second // in the dictionary. - CFMutableDictionaryRef objects = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); + 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)) { @@ -1327,7 +1423,7 @@ __private_extern__ bool __CFTryParseBinaryPlist(CFAllocatorRef allocator, CFData if (plist) *plist = NULL; if (errorString) *errorString = (CFStringRef)CFRetain(CFSTR("binary data is corrupt")); } - CFRelease(objects); + if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(objects); return true; } return false; diff --git a/CFBitVector.c b/CFBitVector.c index cc319c6..038add4 100644 --- a/CFBitVector.c +++ b/CFBitVector.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFBitVector.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ diff --git a/CFBitVector.h b/CFBitVector.h index b5c5851..aae18f6 100644 --- a/CFBitVector.h +++ b/CFBitVector.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFBitVector.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBITVECTOR__) diff --git a/CFBuiltinConverters.c b/CFBuiltinConverters.c index 49e0a67..b6003a5 100644 --- a/CFBuiltinConverters.c +++ b/CFBuiltinConverters.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFBuiltinConverters.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. Responsibility: Aki Inoue */ diff --git a/CFBundle.c b/CFBundle.c index 4b29fb4..2bfea0f 100644 --- a/CFBundle.c +++ b/CFBundle.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFBundle.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. - Responsibility: Doug Davidson + Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ #include "CFBundle_Internal.h" @@ -37,6 +37,7 @@ #include "CFInternal.h" #include #include "CFBundle_BinaryTypes.h" +#include #include #include #include @@ -72,7 +73,6 @@ #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED #include #elif DEPLOYMENT_TARGET_WINDOWS -#define strncasecmp_l(a, b, c, d) _strnicmp(a, b, c) #include #include @@ -83,6 +83,12 @@ #error Unknown or unspecified DEPLOYMENT_TARGET #endif +extern void _processInfoDictionary(CFMutableDictionaryRef dict, CFStringRef platformSuffix, CFStringRef productSuffix); +extern CFStringRef _CFGetProductName(void); +extern CFStringRef _CFGetPlatformName(void); +extern CFStringRef _CFGetAlternatePlatformName(void); + +static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle, Boolean alreadyLocked); #define LOG_BUNDLE_LOAD 0 @@ -155,6 +161,9 @@ CONST_STRING_DECL(_kCFBundleInitialPathKey, "NSBundleInitialPath") CONST_STRING_DECL(_kCFBundleResolvedPathKey, "NSBundleResolvedPath") CONST_STRING_DECL(_kCFBundlePrincipalClassKey, "NSPrincipalClass") +static char __CFBundleMainID__[1026] = {0}; +__private_extern__ char *__CFBundleMainID = __CFBundleMainID__; + static CFTypeID __kCFBundleTypeID = _kCFRuntimeNotATypeID; struct __CFBundle { @@ -163,8 +172,8 @@ struct __CFBundle { CFURLRef _url; CFDateRef _modDate; - CFDictionaryRef _infoDict; - CFDictionaryRef _localInfoDict; + __strong CFDictionaryRef _infoDict; // the ref stored in here must always be allocated with kCFAllocatorSystemDefaultGCRefZero + __strong CFDictionaryRef _localInfoDict; // the ref stored in here must always be allocated with kCFAllocatorSystemDefaultGCRefZero CFArrayRef _searchLanguages; __CFPBinaryType _binaryType; @@ -207,7 +216,6 @@ static CFMutableDictionaryRef _bundlesByURL = NULL; static CFMutableArrayRef _allBundles = NULL; static CFMutableSetRef _bundlesToUnload = NULL; #else /* AVOID_WEAK_COLLECTIONS */ -static __CFMapTable *_bundlesByURL = nil; static __CFHashTable *_allBundles = nil; static __CFHashTable *_bundlesToUnload = nil; #endif /* AVOID_WEAK_COLLECTIONS */ @@ -219,7 +227,7 @@ static CFStringRef _defaultLocalization = NULL; // Forward declares functions. static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, Boolean alreadyLocked, Boolean doFinalProcessing); -static CFStringRef _CFBundleCopyExecutableName(CFAllocatorRef alloc, CFBundleRef bundle, CFURLRef url, CFDictionaryRef infoDict); +static CFStringRef _CFBundleCopyExecutableName(CFBundleRef bundle, CFURLRef url, CFDictionaryRef infoDict); static CFURLRef _CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle); static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint); static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void); @@ -240,10 +248,7 @@ static void *_CFBundleDlfcnGetSymbolByNameWithSearch(CFBundleRef bundle, CFStrin static CFStringRef _CFBundleDlfcnCopyLoadedImagePathForPointer(void *p); #endif /* !BINARY_SUPPORT_DYLD */ #endif /* BINARY_SUPPORT_DLFCN */ -#if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) -static void *_CFBundleFunctionPointerForTVector(CFAllocatorRef allocator, void *tvp); -static void *_CFBundleTVectorForFunctionPointer(CFAllocatorRef allocator, void *fp); -#endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM */ + #if defined(AVOID_WEAK_COLLECTIONS) @@ -254,7 +259,6 @@ static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) { // Add to the _allBundles list if (!_allBundles) { - // Create this from the default allocator CFArrayCallBacks nonRetainingArrayCallbacks = kCFTypeArrayCallBacks; nonRetainingArrayCallbacks.retain = NULL; nonRetainingArrayCallbacks.release = NULL; @@ -264,7 +268,6 @@ static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) { // Add to the table that maps urls to bundles if (!_bundlesByURL) { - // Create this from the default allocator CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks = kCFTypeDictionaryValueCallBacks; nonRetainingDictionaryValueCallbacks.retain = NULL; nonRetainingDictionaryValueCallbacks.release = NULL; @@ -277,7 +280,6 @@ static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) { CFMutableArrayRef bundlesWithThisID = NULL; CFBundleRef existingBundle = NULL; if (!_bundlesByIdentifier) { - // Create this from the default allocator _bundlesByIdentifier = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } bundlesWithThisID = (CFMutableArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); @@ -292,7 +294,6 @@ static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) { } CFArrayInsertValueAtIndex(bundlesWithThisID, i, bundle); } else { - // Create this from the default allocator CFArrayCallBacks nonRetainingArrayCallbacks = kCFTypeArrayCallBacks; nonRetainingArrayCallbacks.retain = NULL; nonRetainingArrayCallbacks.release = NULL; @@ -367,6 +368,55 @@ static CFBundleRef _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(CFStri #else /* AVOID_WEAK_COLLECTIONS */ +/* + An explanation of what I'm doing here is probably in order. + 8029300 has cast suspicion on the correctness of __CFMapTable with strong keys and weak values, at least under non-GC. + An early attempt to work around it by inserting dummy values instead of removing things succeeded, as did turning on the AVOID_WEAK_COLLECTIONS #ifdef + This indicates that it's not an overrelease in securityd, since AVOID_WEAK_COLLECTIONS wouldn't help in that case. + Therefore, these functions following this comment allow us to have _bundlesByURL be a CFDictionary on non-GC and keep __CFMapTable to GC where it's needed. + */ +static inline id _getBundlesByURL() { + static id _bundles = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (CF_USING_COLLECTABLE_MEMORY) { + _bundles = [[__CFMapTable alloc] initWithKeyOptions:CFPointerFunctionsStrongMemory valueOptions:CFPointerFunctionsZeroingWeakMemory capacity:0]; + } else { + CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks = kCFTypeDictionaryValueCallBacks; + nonRetainingDictionaryValueCallbacks.retain = NULL; + nonRetainingDictionaryValueCallbacks.release = NULL; + _bundles = (id)CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &nonRetainingDictionaryValueCallbacks); + } + }); + return _bundles; +} + +#define _bundlesByURL _getBundlesByURL() + +static void _setInBundlesByURL(CFURLRef key, CFBundleRef bundle) { + if (CF_USING_COLLECTABLE_MEMORY) { + [(__CFMapTable *)_bundlesByURL setObject:(id)bundle forKey:(id)key]; + } else { + CFDictionarySetValue((CFMutableDictionaryRef)_bundlesByURL, key, bundle); + } +} + +static void _removeFromBundlesByURL(CFURLRef key) { + if (CF_USING_COLLECTABLE_MEMORY) { + [(__CFMapTable *)_bundlesByURL removeObjectForKey:(id)key]; + } else { + CFDictionaryRemoveValue((CFMutableDictionaryRef)_bundlesByURL, key); + } +} + +static CFBundleRef _getFromBundlesByURL(CFURLRef key) { + if (CF_USING_COLLECTABLE_MEMORY) { + return (CFBundleRef)[(__CFMapTable *)_bundlesByURL objectForKey:(id)key]; + } else { + return (CFBundleRef)CFDictionaryGetValue((CFMutableDictionaryRef)_bundlesByURL, key); + } +} + static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) { CFStringRef bundleID = CFBundleGetIdentifier(bundle); @@ -377,15 +427,13 @@ static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) { [_allBundles addObject:(id)bundle]; // Add to the table that maps urls to bundles - if (!_bundlesByURL) _bundlesByURL = [[__CFMapTable alloc] initWithKeyOptions:CFPointerFunctionsStrongMemory valueOptions:CFPointerFunctionsZeroingWeakMemory capacity:0]; - [_bundlesByURL setObject:(id)bundle forKey:(id)bundle->_url]; + _setInBundlesByURL(bundle->_url, bundle); // Add to the table that maps identifiers to bundles if (bundleID) { __CFPointerArray *bundlesWithThisID = nil; CFBundleRef existingBundle = NULL; if (!_bundlesByIdentifier) { - // Create this from the default allocator _bundlesByIdentifier = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } bundlesWithThisID = (__CFPointerArray *)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); @@ -420,9 +468,8 @@ static void _CFBundleRemoveFromTables(CFBundleRef bundle, CFURLRef bundleURL, CF if (_allBundles && [_allBundles member:(id)bundle]) [_allBundles removeObject:(id)bundle]; // Remove from the table that maps urls to bundles - if (bundleURL && _bundlesByURL) { - CFBundleRef bundleForURL = (CFBundleRef)[_bundlesByURL objectForKey:(id)bundleURL]; - if (bundleForURL == bundle) [_bundlesByURL removeObjectForKey:(id)bundleURL]; + if (bundleURL) { + _removeFromBundlesByURL(bundleURL); } // Remove from the table that maps identifiers to bundles @@ -441,10 +488,10 @@ static void _CFBundleRemoveFromTables(CFBundleRef bundle, CFURLRef bundleURL, CF static CFBundleRef _CFBundleCopyBundleForURL(CFURLRef url, Boolean alreadyLocked) { CFBundleRef result = NULL; if (!alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock); - if (_bundlesByURL) result = (CFBundleRef)[_bundlesByURL objectForKey:(id)url]; + result = _getFromBundlesByURL(url); if (result && !result->_url) { result = NULL; - [_bundlesByURL removeObjectForKey:(id)url]; + _removeFromBundlesByURL(url); } if (result) CFRetain(result); if (!alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock); @@ -480,7 +527,7 @@ static CFBundleRef _CFBundlePrimitiveGetBundleWithIdentifierAlreadyLocked(CFStri #endif /* AVOID_WEAK_COLLECTIONS */ -#if 0 && DEPLOYMENT_TARGET_WINDOWS_SYNC +#if 0 && DEPLOYMENT_TARGET_WINDOWS static CFStringRef _CFBundleCopyWrapperInBinaryDirectory(CFStringRef strippedExeName) { char buff[CFMaxPathSize]; CFIndex buffLen; @@ -515,7 +562,7 @@ static CFURLRef _CFBundleCopyBundleURLForExecutablePath(CFStringRef str) { if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize; CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff); -#if 0 && DEPLOYMENT_TARGET_WINDOWS_SYNC +#if 0 && DEPLOYMENT_TARGET_WINDOWS CFIndex startOfBinaryName = _CFLengthAfterDeletingLastPathComponent(buff, buffLen) + 1; // Remove exe name CFIndex endOfBinaryName = _CFLengthAfterDeletingPathExtension(buff, buffLen); if (startOfBinaryName > 0 && startOfBinaryName < buffLen && endOfBinaryName > 0 && endOfBinaryName <= buffLen) { @@ -583,7 +630,7 @@ static CFURLRef _CFBundleCopyBundleURLForExecutablePath(CFStringRef str) { if (buffLen > 0) { // Remove support files folder buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); -#elif 0 && DEPLOYMENT_TARGET_WINDOWS_SYNC +#elif 0 && 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); @@ -612,7 +659,7 @@ static CFURLRef _CFBundleCopyBundleURLForExecutablePath(CFStringRef str) { CFRelease(lastDirName); } } -#elif 0 && DEPLOYMENT_TARGET_WINDOWS_SYNC +#elif 0 && DEPLOYMENT_TARGET_WINDOWS if (buffLen > 0) { // Remove support files folder buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); @@ -712,8 +759,6 @@ static uint8_t _CFBundleEffectiveLayoutVersion(CFBundleRef bundle) { } else { localVersion = 4; } -#elif defined(BINARY_SUPPORT_CFM) - localVersion = 4; #else CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); if (executableURL) { @@ -721,7 +766,7 @@ static uint8_t _CFBundleEffectiveLayoutVersion(CFBundleRef bundle) { } else { localVersion = 4; } -#endif /* BINARY_SUPPORT_CFM && BINARY_SUPPORT_DYLD */ +#endif /* BINARY_SUPPORT_DYLD */ } } return localVersion; @@ -788,7 +833,7 @@ CFBundleRef _CFBundleCreateIfMightBeBundle(CFAllocatorRef allocator, CFURLRef ur if (supportedPlatforms && CFArrayGetCount(supportedPlatforms) > 0 && CFArrayGetFirstIndexOfValue(supportedPlatforms, CFRangeMake(0, CFArrayGetCount(supportedPlatforms)), CFSTR("iPhoneOS")) >= 0) { mightBeBundle = true; } else if (resourceSpecificationFile && CFGetTypeID(resourceSpecificationFile) == CFStringGetTypeID() && (supportFilesURL = CFBundleCopySupportFilesDirectoryURL(bundle))) { - resourceSpecificationFileURL = CFURLCreateWithFileSystemPathRelativeToBase(allocator, resourceSpecificationFile, kCFURLPOSIXPathStyle, false, supportFilesURL); + resourceSpecificationFileURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, resourceSpecificationFile, kCFURLPOSIXPathStyle, false, supportFilesURL); if (resourceSpecificationFileURL) { if (_CFIsResourceAtURL(resourceSpecificationFileURL, &isDir) && !isDir) mightBeBundle = true; CFRelease(resourceSpecificationFileURL); @@ -850,62 +895,31 @@ CFURLRef _CFBundleCopyMainBundleExecutableURL(Boolean *looksLikeBundle) { } static void _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(CFStringRef executablePath) { -#if defined(BINARY_SUPPORT_CFM) - Boolean versRegionOverrides = false; -#endif /* BINARY_SUPPORT_CFM */ CFBundleGetInfoDictionary(_mainBundle); if (!_mainBundle->_infoDict || CFDictionaryGetCount(_mainBundle->_infoDict) == 0) { // if type 3 bundle and no Info.plist, treat as unbundled, since this gives too many false positives if (_mainBundle->_version == 3) _mainBundle->_version = 4; if (_mainBundle->_version == 0) { // if type 0 bundle and no Info.plist and not main executable for bundle, treat as unbundled, since this gives too many false positives - CFStringRef executableName = _CFBundleCopyExecutableName(kCFAllocatorSystemDefault, _mainBundle, NULL, NULL); + CFStringRef executableName = _CFBundleCopyExecutableName(_mainBundle, NULL, NULL); if (!executableName || !executablePath || !CFStringHasSuffix(executablePath, executableName)) _mainBundle->_version = 4; if (executableName) CFRelease(executableName); } #if defined(BINARY_SUPPORT_DYLD) if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary) { - if (_mainBundle->_infoDict) CFRelease(_mainBundle->_infoDict); + if (_mainBundle->_infoDict && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(_mainBundle->_infoDict); _mainBundle->_infoDict = (CFDictionaryRef)_CFBundleGrokInfoDictFromMainExecutable(); } #endif /* BINARY_SUPPORT_DYLD */ -#if defined(BINARY_SUPPORT_CFM) - if (_mainBundle->_binaryType == __CFBundleCFMBinary || _mainBundle->_binaryType == __CFBundleUnreadableBinary) { - // if type 0 bundle and CFM binary and no Info.plist, treat as unbundled, since this also gives too many false positives - if (_mainBundle->_version == 0) _mainBundle->_version = 4; - if (_mainBundle->_version != 4) { - // if CFM binary and no Info.plist and not main executable for bundle, treat as unbundled, since this also gives too many false positives - // except for Macromedia Director MX, which is unbundled but wants to be treated as bundled - CFStringRef executableName = _CFBundleCopyExecutableName(kCFAllocatorSystemDefault, _mainBundle, NULL, NULL); - Boolean treatAsBundled = false; - if (executablePath) { - CFIndex strLength = CFStringGetLength(executablePath); - if (strLength > 10) treatAsBundled = CFStringFindWithOptions(executablePath, CFSTR(" MX"), CFRangeMake(strLength - 10, 10), 0, NULL); - } - if (!treatAsBundled && (!executableName || !executablePath || !CFStringHasSuffix(executablePath, executableName))) _mainBundle->_version = 4; - if (executableName) CFRelease(executableName); - } - if (_mainBundle->_infoDict) CFRelease(_mainBundle->_infoDict); - if (executablePath) { - CFURLRef executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, executablePath, PLATFORM_PATH_STYLE, false); - if (executableURL) { - _mainBundle->_infoDict = _CFBundleCopyInfoDictionaryInResourceForkWithAllocator(CFGetAllocator(_mainBundle), executableURL); - if (_mainBundle->_infoDict) _mainBundle->_resourceData._infoDictionaryFromResourceFork = true; - CFRelease(executableURL); - } - } - if (_mainBundle->_binaryType == __CFBundleUnreadableBinary && _mainBundle->_infoDict && CFDictionaryGetValue(_mainBundle->_infoDict, kCFBundleDevelopmentRegionKey)) versRegionOverrides = true; - } -#endif /* BINARY_SUPPORT_CFM */ } else { #if defined(BINARY_SUPPORT_DYLD) if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary) { // if dyld and not main executable for bundle, prefer info dictionary from executable - CFStringRef executableName = _CFBundleCopyExecutableName(kCFAllocatorSystemDefault, _mainBundle, NULL, NULL); + CFStringRef executableName = _CFBundleCopyExecutableName(_mainBundle, NULL, NULL); if (!executableName || !executablePath || !CFStringHasSuffix(executablePath, executableName)) { CFDictionaryRef infoDictFromExecutable = (CFDictionaryRef)_CFBundleGrokInfoDictFromMainExecutable(); if (infoDictFromExecutable && CFDictionaryGetCount(infoDictFromExecutable) > 0) { - if (_mainBundle->_infoDict) CFRelease(_mainBundle->_infoDict); + if (_mainBundle->_infoDict && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(_mainBundle->_infoDict); _mainBundle->_infoDict = infoDictFromExecutable; } } @@ -913,28 +927,24 @@ static void _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(CFStringRef } #endif /* BINARY_SUPPORT_DYLD */ } - if (!_mainBundle->_infoDict) _mainBundle->_infoDict = CFDictionaryCreateMutable(CFGetAllocator(_mainBundle), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!_mainBundle->_infoDict) _mainBundle->_infoDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (!CFDictionaryGetValue(_mainBundle->_infoDict, _kCFBundleExecutablePathKey)) CFDictionarySetValue((CFMutableDictionaryRef)(_mainBundle->_infoDict), _kCFBundleExecutablePathKey, executablePath); -#if defined(BINARY_SUPPORT_CFM) - if (versRegionOverrides) { - // This is a hack to preserve backward compatibility for certain broken applications (2761067) - CFStringRef devLang = _CFBundleCopyBundleDevelopmentRegionFromVersResource(_mainBundle); - if (devLang) { - CFDictionarySetValue((CFMutableDictionaryRef)(_mainBundle->_infoDict), kCFBundleDevelopmentRegionKey, devLang); - CFRelease(devLang); + CFStringRef bundleID = (CFStringRef)CFDictionaryGetValue(_mainBundle->_infoDict, kCFBundleIdentifierKey); + if (bundleID) { + if (!CFStringGetCString(bundleID, __CFBundleMainID__, sizeof(__CFBundleMainID__) - 2, kCFStringEncodingUTF8)) { + __CFBundleMainID__[0] = '\0'; } } -#endif /* BINARY_SUPPORT_CFM */ } - -CF_EXPORT void _CFBundleFlushBundleCaches(CFBundleRef bundle) { + +static void _CFBundleFlushBundleCachesAlreadyLocked(CFBundleRef bundle, Boolean alreadyLocked) { CFDictionaryRef oldInfoDict = bundle->_infoDict; CFTypeRef val; _CFBundleFlushCachesForURL(bundle->_url); bundle->_infoDict = NULL; if (bundle->_localInfoDict) { - CFRelease(bundle->_localInfoDict); + if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(bundle->_localInfoDict); bundle->_localInfoDict = NULL; } if (bundle->_searchLanguages) { @@ -947,24 +957,28 @@ CF_EXPORT void _CFBundleFlushBundleCaches(CFBundleRef bundle) { } if (bundle == _mainBundle) { CFStringRef executablePath = oldInfoDict ? (CFStringRef)CFDictionaryGetValue(oldInfoDict, _kCFBundleExecutablePathKey) : NULL; - __CFSpinLock(&CFBundleGlobalDataLock); + if (!alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock); _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(executablePath); - __CFSpinUnlock(&CFBundleGlobalDataLock); + if (!alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock); } else { CFBundleGetInfoDictionary(bundle); } if (oldInfoDict) { - if (!bundle->_infoDict) bundle->_infoDict = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!bundle->_infoDict) bundle->_infoDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); val = CFDictionaryGetValue(oldInfoDict, _kCFBundleInitialPathKey); if (val) CFDictionarySetValue((CFMutableDictionaryRef)bundle->_infoDict, _kCFBundleInitialPathKey, val); val = CFDictionaryGetValue(oldInfoDict, _kCFBundleResolvedPathKey); if (val) CFDictionarySetValue((CFMutableDictionaryRef)bundle->_infoDict, _kCFBundleResolvedPathKey, val); val = CFDictionaryGetValue(oldInfoDict, _kCFBundlePrincipalClassKey); if (val) CFDictionarySetValue((CFMutableDictionaryRef)bundle->_infoDict, _kCFBundlePrincipalClassKey, val); - CFRelease(oldInfoDict); + if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(oldInfoDict); } } +CF_EXPORT void _CFBundleFlushBundleCaches(CFBundleRef bundle) { + _CFBundleFlushBundleCachesAlreadyLocked(bundle, false); +} + static CFBundleRef _CFBundleGetMainBundleAlreadyLocked(void) { if (!_initedMainBundle) { const char *processPath; @@ -1123,12 +1137,10 @@ static void _CFBundleDeallocateGlue(const void *key, const void *value, void *co static void __CFBundleDeallocate(CFTypeRef cf) { CFBundleRef bundle = (CFBundleRef)cf; - CFAllocatorRef allocator; CFURLRef bundleURL; CFStringRef bundleID = NULL; __CFGenericValidateType(cf, __kCFBundleTypeID); - allocator = CFGetAllocator(bundle); bundleURL = bundle->_url; bundle->_url = NULL; if (bundle->_infoDict) bundleID = (CFStringRef)CFDictionaryGetValue(bundle->_infoDict, kCFBundleIdentifierKey); @@ -1139,19 +1151,19 @@ static void __CFBundleDeallocate(CFTypeRef cf) { _CFBundleFlushCachesForURL(bundleURL); CFRelease(bundleURL); } - if (bundle->_infoDict) CFRelease(bundle->_infoDict); + if (bundle->_infoDict && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(bundle->_infoDict); if (bundle->_modDate) CFRelease(bundle->_modDate); - if (bundle->_localInfoDict) CFRelease(bundle->_localInfoDict); + if (bundle->_localInfoDict && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(bundle->_localInfoDict); if (bundle->_searchLanguages) CFRelease(bundle->_searchLanguages); if (bundle->_glueDict) { - CFDictionaryApplyFunction(bundle->_glueDict, _CFBundleDeallocateGlue, (void *)allocator); + CFDictionaryApplyFunction(bundle->_glueDict, _CFBundleDeallocateGlue, (void *)CFGetAllocator(bundle)); CFRelease(bundle->_glueDict); } if (bundle->_resourceData._stringTableCache) CFRelease(bundle->_resourceData._stringTableCache); } static const CFRuntimeClass __CFBundleClass = { - 0, + _kCFRuntimeScannedObject, "CFBundle", NULL, // init NULL, // copy @@ -1162,8 +1174,12 @@ static const CFRuntimeClass __CFBundleClass = { __CFBundleCopyDescription }; +// From CFBundle_Resources.c +void _CFBundleResourcesInitialize(); + __private_extern__ void __CFBundleInitialize(void) { __kCFBundleTypeID = _CFRuntimeRegisterClass(&__CFBundleClass); + _CFBundleResourcesInitialize(); } CFTypeID CFBundleGetTypeID(void) { @@ -1186,9 +1202,10 @@ CFBundleRef _CFBundleGetExistingBundleWithBundleURL(CFURLRef bundleURL) { } static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, Boolean alreadyLocked, Boolean doFinalProcessing) { + allocator = _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator); CFBundleRef bundle = NULL; char buff[CFMaxPathSize]; - CFDateRef modDate = NULL; + CFDateRef modDate = NULL; // do not actually fetch the modDate, since that can cause something like 7609956, unless absolutely found to be necessary in the future Boolean exists = false; SInt32 mode = 0; CFURLRef newURL = NULL; @@ -1206,7 +1223,7 @@ static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, if (!_CFBundleURLLooksLikeBundleVersion(newURL, &localVersion)) { localVersion = 3; - SInt32 res = _CFGetFileProperties(allocator, newURL, &exists, &mode, NULL, &modDate, NULL, NULL); + SInt32 res = _CFGetPathProperties(allocator, (char *)buff, &exists, &mode, NULL, NULL, NULL, NULL); #if DEPLOYMENT_TARGET_WINDOWS if (!(res == 0 && exists && ((mode & S_IFMT) == S_IFDIR))) { // 2nd chance at finding a bundle path - remove the last path component (e.g., mybundle.resources) and try again @@ -1217,7 +1234,7 @@ static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, CFURLRef shorterPath = CFURLCreateCopyDeletingLastPathComponent(allocator, newURL); CFRelease(newURL); newURL = shorterPath; - res = _CFGetFileProperties(allocator, newURL, &exists, &mode, NULL, &modDate, NULL, NULL); + res = _CFGetFileProperties(allocator, newURL, &exists, &mode, NULL, NULL, NULL, NULL); } #endif if (res == 0) { @@ -1249,9 +1266,6 @@ static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, #if defined(BINARY_SUPPORT_DYLD) /* We'll have to figure it out later */ bundle->_binaryType = __CFBundleUnknownBinary; -#elif defined(BINARY_SUPPORT_CFM) - /* We support CFM only */ - bundle->_binaryType = __CFBundleCFMBinary; #elif defined(BINARY_SUPPORT_DLL) /* We support DLL only */ bundle->_binaryType = __CFBundleDLLBinary; @@ -1313,6 +1327,7 @@ CFBundleRef CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL) { } CFArrayRef CFBundleCreateBundlesFromDirectory(CFAllocatorRef alloc, CFURLRef directoryURL, CFStringRef bundleType) { + alloc = _CFConvertAllocatorToNonGCRefZeroEquivalent(alloc); CFMutableArrayRef bundles = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks); CFArrayRef URLs = _CFContentsOfDirectory(alloc, NULL, NULL, directoryURL, bundleType); if (URLs) { @@ -1398,11 +1413,13 @@ CFArrayRef _CFBundleGetLanguageSearchList(CFBundleRef bundle) { } CFDictionaryRef CFBundleCopyInfoDictionaryInDirectory(CFURLRef url) { - return _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefault, url, NULL); + CFDictionaryRef dict = _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefaultGCRefZero, url, NULL); + if (dict && _CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRetain(dict); // conditionally put on a retain for a Copy function + return dict; } CFDictionaryRef CFBundleGetInfoDictionary(CFBundleRef bundle) { - if (!bundle->_infoDict) bundle->_infoDict = _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFGetAllocator(bundle), bundle->_url, bundle->_version); + if (!bundle->_infoDict) bundle->_infoDict = _CFBundleCopyInfoDictionaryInDirectoryWithVersion(kCFAllocatorSystemDefaultGCRefZero, bundle->_url, bundle->_version); return bundle->_infoDict; } @@ -1420,22 +1437,23 @@ CFDictionaryRef CFBundleGetLocalInfoDictionary(CFBundleRef bundle) { SInt32 errCode; CFStringRef errStr = NULL; - if (CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(bundle), url, &data, NULL, NULL, &errCode)) { - localInfoDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(CFGetAllocator(bundle), data, kCFPropertyListImmutable, &errStr); + if (CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, url, &data, NULL, NULL, &errCode)) { + localInfoDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefaultGCRefZero, data, kCFPropertyListMutableContainers, &errStr); if (errStr) CFRelease(errStr); if (localInfoDict && CFDictionaryGetTypeID() != CFGetTypeID(localInfoDict)) { - CFRelease(localInfoDict); + if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(localInfoDict); localInfoDict = NULL; } CFRelease(data); } CFRelease(url); } + if (localInfoDict) _processInfoDictionary((CFMutableDictionaryRef)localInfoDict, _CFGetPlatformName(), _CFGetProductName()); __CFSpinLock(&CFBundleLocalInfoLock); if (!bundle->_localInfoDict) { bundle->_localInfoDict = localInfoDict; } else { - if (localInfoDict) CFRelease(localInfoDict); + if (localInfoDict && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(localInfoDict); localInfoDict = bundle->_localInfoDict; } __CFSpinUnlock(&CFBundleLocalInfoLock); @@ -1728,9 +1746,9 @@ Boolean _CFBundleGetStringsFilesShared(CFBundleRef bundle) { return bundle->_sharesStringsFiles; } -static Boolean _urlExists(CFAllocatorRef alloc, CFURLRef url) { +static Boolean _urlExists(CFURLRef url) { Boolean exists; - return url && (0 == _CFGetFileProperties(alloc, url, &exists, NULL, NULL, NULL, NULL, NULL)) && exists; + return url && (0 == _CFGetFileProperties(kCFAllocatorSystemDefault, url, &exists, NULL, NULL, NULL, NULL, NULL)) && exists; } // This is here because on iPhoneOS with the dyld shared cache, we remove binaries from their @@ -1738,8 +1756,8 @@ static Boolean _urlExists(CFAllocatorRef alloc, CFURLRef url) { // For performance reasons, we only call dlopen_preflight() after we've verified that the binary // does not exist at its original path with _urlExists(). // See -static Boolean _binaryLoadable(CFAllocatorRef alloc, CFURLRef url) { - Boolean loadable = _urlExists(alloc, url); +static Boolean _binaryLoadable(CFURLRef url) { + Boolean loadable = _urlExists(url); #if DEPLOYMENT_TARGET_EMBEDDED if (!loadable) { uint8_t path[PATH_MAX]; @@ -1751,13 +1769,13 @@ static Boolean _binaryLoadable(CFAllocatorRef alloc, CFURLRef url) { return loadable; } -__private_extern__ CFURLRef _CFBundleCopySupportFilesDirectoryURLInDirectory(CFAllocatorRef alloc, CFURLRef bundleURL, uint8_t version) { +__private_extern__ CFURLRef _CFBundleCopySupportFilesDirectoryURLInDirectory(CFURLRef bundleURL, uint8_t version) { CFURLRef result = NULL; if (bundleURL) { if (1 == version) { - result = CFURLCreateWithString(alloc, _CFBundleSupportFilesURLFromBase1, bundleURL); + result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleSupportFilesURLFromBase1, bundleURL); } else if (2 == version) { - result = CFURLCreateWithString(alloc, _CFBundleSupportFilesURLFromBase2, bundleURL); + result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleSupportFilesURLFromBase2, bundleURL); } else { result = (CFURLRef)CFRetain(bundleURL); } @@ -1766,18 +1784,18 @@ __private_extern__ CFURLRef _CFBundleCopySupportFilesDirectoryURLInDirectory(CFA } CF_EXPORT CFURLRef CFBundleCopySupportFilesDirectoryURL(CFBundleRef bundle) { - return _CFBundleCopySupportFilesDirectoryURLInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version); + return _CFBundleCopySupportFilesDirectoryURLInDirectory(bundle->_url, bundle->_version); } -__private_extern__ CFURLRef _CFBundleCopyResourcesDirectoryURLInDirectory(CFAllocatorRef alloc, CFURLRef bundleURL, uint8_t version) { +__private_extern__ CFURLRef _CFBundleCopyResourcesDirectoryURLInDirectory(CFURLRef bundleURL, uint8_t version) { CFURLRef result = NULL; if (bundleURL) { if (0 == version) { - result = CFURLCreateWithString(alloc, _CFBundleResourcesURLFromBase0, bundleURL); + result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase0, bundleURL); } else if (1 == version) { - result = CFURLCreateWithString(alloc, _CFBundleResourcesURLFromBase1, bundleURL); + result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase1, bundleURL); } else if (2 == version) { - result = CFURLCreateWithString(alloc, _CFBundleResourcesURLFromBase2, bundleURL); + result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase2, bundleURL); } else { result = (CFURLRef)CFRetain(bundleURL); } @@ -1786,10 +1804,28 @@ __private_extern__ CFURLRef _CFBundleCopyResourcesDirectoryURLInDirectory(CFAllo } CFURLRef CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle) { - return _CFBundleCopyResourcesDirectoryURLInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version); + return _CFBundleCopyResourcesDirectoryURLInDirectory(bundle->_url, bundle->_version); +} + +__private_extern__ CFURLRef _CFBundleCopyAppStoreReceiptURLInDirectory(CFURLRef bundleURL, uint8_t version) { + CFURLRef result = NULL; + if (bundleURL) { + if (0 == version) { + result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleAppStoreReceiptURLFromBase0, bundleURL); + } else if (1 == version) { + result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleAppStoreReceiptURLFromBase1, bundleURL); + } else if (2 == version) { + result = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleAppStoreReceiptURLFromBase2, bundleURL); + } + } + return result; } -static CFURLRef _CFBundleCopyExecutableURLRaw(CFAllocatorRef alloc, CFURLRef urlPath, CFStringRef exeName) { +CFURLRef _CFBundleCopyAppStoreReceiptURL(CFBundleRef bundle) { + return _CFBundleCopyAppStoreReceiptURLInDirectory(bundle->_url, bundle->_version); +} + +static CFURLRef _CFBundleCopyExecutableURLRaw(CFURLRef urlPath, CFStringRef exeName) { // Given an url to a folder and a name, this returns the url to the executable in that folder with that name, if it exists, and NULL otherwise. This function deals with appending the ".exe" or ".dll" on Windows. CFURLRef executableURL = NULL; if (!urlPath || !exeName) return NULL; @@ -1800,14 +1836,14 @@ static CFURLRef _CFBundleCopyExecutableURLRaw(CFAllocatorRef alloc, CFURLRef url CFStringRef newExeName, imageSuffix; imageSuffix = CFStringCreateWithCString(kCFAllocatorSystemDefault, (char *)image_suffix, kCFStringEncodingUTF8); if (CFStringHasSuffix(exeName, CFSTR(".dylib"))) { - CFStringRef bareExeName = CFStringCreateWithSubstring(alloc, exeName, CFRangeMake(0, CFStringGetLength(exeName)-6)); - newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@.dylib"), exeName, imageSuffix); + CFStringRef bareExeName = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, exeName, CFRangeMake(0, CFStringGetLength(exeName)-6)); + newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@.dylib"), exeName, imageSuffix); CFRelease(bareExeName); } else { - newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@"), exeName, imageSuffix); + newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@"), exeName, imageSuffix); } - executableURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, newExeName, kCFURLPOSIXPathStyle, false, urlPath); - if (executableURL && !_binaryLoadable(alloc, executableURL)) { + executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, newExeName, kCFURLPOSIXPathStyle, false, urlPath); + if (executableURL && !_binaryLoadable(executableURL)) { CFRelease(executableURL); executableURL = NULL; } @@ -1815,47 +1851,30 @@ static CFURLRef _CFBundleCopyExecutableURLRaw(CFAllocatorRef alloc, CFURLRef url CFRelease(imageSuffix); } if (!executableURL) { - executableURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, exeName, kCFURLPOSIXPathStyle, false, urlPath); - if (executableURL && !_binaryLoadable(alloc, executableURL)) { + executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, exeName, kCFURLPOSIXPathStyle, false, urlPath); + if (executableURL && !_binaryLoadable(executableURL)) { CFRelease(executableURL); executableURL = NULL; } } #elif DEPLOYMENT_TARGET_WINDOWS if (!executableURL) { - executableURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, exeName, kCFURLWindowsPathStyle, false, urlPath); - if (executableURL && !_urlExists(alloc, executableURL)) { + executableURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, exeName, kCFURLWindowsPathStyle, false, urlPath); + if (executableURL && !_urlExists(executableURL)) { CFRelease(executableURL); executableURL = NULL; } } if (!executableURL) { if (!CFStringFindWithOptions(exeName, CFSTR(".dll"), CFRangeMake(0, CFStringGetLength(exeName)), kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL)) { - CFStringRef newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@"), exeName, CFSTR(".dll")); - executableURL = CFURLCreateWithString(alloc, newExeName, urlPath); - if (executableURL && !_binaryLoadable(alloc, executableURL)) { - CFRelease(executableURL); - executableURL = NULL; - } - CFRelease(newExeName); - } - } - if (!executableURL) { - if (!CFStringFindWithOptions(exeName, CFSTR(".dll"), CFRangeMake(0, CFStringGetLength(exeName)), kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL)) { - CFStringRef newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@"), exeName, CFSTR("_debug.dll")); - executableURL = CFURLCreateWithString(alloc, newExeName, urlPath); - if (executableURL && !_urlExists(alloc, executableURL)) { - CFRelease(executableURL); - executableURL = NULL; - } - CFRelease(newExeName); - } - } - if (!executableURL) { - if (!CFStringFindWithOptions(exeName, CFSTR(".exe"), CFRangeMake(0, CFStringGetLength(exeName)), kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL)) { - CFStringRef newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@"), exeName, CFSTR(".exe")); - executableURL = CFURLCreateWithString(alloc, newExeName, urlPath); - if (executableURL && !_binaryLoadable(alloc, executableURL)) { +#if defined(DEBUG) + CFStringRef extension = CFSTR("_debug.dll"); +#else + CFStringRef extension = CFSTR(".dll"); +#endif + CFStringRef newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@"), exeName, extension); + executableURL = CFURLCreateWithString(kCFAllocatorSystemDefault, newExeName, urlPath); + if (executableURL && !_binaryLoadable(executableURL)) { CFRelease(executableURL); executableURL = NULL; } @@ -1864,9 +1883,14 @@ static CFURLRef _CFBundleCopyExecutableURLRaw(CFAllocatorRef alloc, CFURLRef url } if (!executableURL) { if (!CFStringFindWithOptions(exeName, CFSTR(".exe"), CFRangeMake(0, CFStringGetLength(exeName)), kCFCompareAnchored|kCFCompareBackwards|kCFCompareCaseInsensitive, NULL)) { - CFStringRef newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@"), exeName, CFSTR("_debug.exe")); - executableURL = CFURLCreateWithString(alloc, newExeName, urlPath); - if (executableURL && !_urlExists(alloc, executableURL)) { +#if defined(DEBUG) + CFStringRef extension = CFSTR("_debug.exe"); +#else + CFStringRef extension = CFSTR(".exe"); +#endif + CFStringRef newExeName = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@%@"), exeName, extension); + executableURL = CFURLCreateWithString(kCFAllocatorSystemDefault, newExeName, urlPath); + if (executableURL && !_binaryLoadable(executableURL)) { CFRelease(executableURL); executableURL = NULL; } @@ -1879,10 +1903,9 @@ static CFURLRef _CFBundleCopyExecutableURLRaw(CFAllocatorRef alloc, CFURLRef url return executableURL; } -static CFStringRef _CFBundleCopyExecutableName(CFAllocatorRef alloc, CFBundleRef bundle, CFURLRef url, CFDictionaryRef infoDict) { +static CFStringRef _CFBundleCopyExecutableName(CFBundleRef bundle, CFURLRef url, CFDictionaryRef infoDict) { CFStringRef executableName = NULL; - if (!alloc && bundle) alloc = CFGetAllocator(bundle); if (!infoDict && bundle) infoDict = CFBundleGetInfoDictionary(bundle); if (!url && bundle) url = bundle->_url; @@ -1902,25 +1925,27 @@ static CFStringRef _CFBundleCopyExecutableName(CFAllocatorRef alloc, CFBundleRef // Third, take the name of the bundle itself (with path extension stripped) CFURLRef absoluteURL = CFURLCopyAbsoluteURL(url); CFStringRef bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); - UniChar buff[CFMaxPathSize]; - CFIndex len = CFStringGetLength(bundlePath); - CFIndex startOfBundleName, endOfBundleName; - CFRelease(absoluteURL); - if (len > CFMaxPathSize) len = CFMaxPathSize; - CFStringGetCharacters(bundlePath, CFRangeMake(0, len), buff); - startOfBundleName = _CFStartOfLastPathComponent(buff, len); - endOfBundleName = _CFLengthAfterDeletingPathExtension(buff, len); - - if (startOfBundleName <= len && endOfBundleName <= len && startOfBundleName < endOfBundleName) executableName = CFStringCreateWithCharacters(alloc, &(buff[startOfBundleName]), endOfBundleName - startOfBundleName); - CFRelease(bundlePath); + if (bundlePath) { + UniChar buff[CFMaxPathSize]; + CFIndex len = CFStringGetLength(bundlePath); + CFIndex startOfBundleName, endOfBundleName; + + if (len > CFMaxPathSize) len = CFMaxPathSize; + CFStringGetCharacters(bundlePath, CFRangeMake(0, len), buff); + startOfBundleName = _CFStartOfLastPathComponent(buff, len); + endOfBundleName = _CFLengthAfterDeletingPathExtension(buff, len); + + if (startOfBundleName <= len && endOfBundleName <= len && startOfBundleName < endOfBundleName) executableName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfBundleName]), endOfBundleName - startOfBundleName); + CFRelease(bundlePath); + } } return executableName; } __private_extern__ CFURLRef _CFBundleCopyResourceForkURLMayBeLocal(CFBundleRef bundle, Boolean mayBeLocal) { - CFStringRef executableName = _CFBundleCopyExecutableName(kCFAllocatorSystemDefault, bundle, NULL, NULL); + CFStringRef executableName = _CFBundleCopyExecutableName(bundle, NULL, NULL); CFURLRef resourceForkURL = NULL; if (executableName) { if (mayBeLocal) { @@ -1938,7 +1963,7 @@ CFURLRef _CFBundleCopyResourceForkURL(CFBundleRef bundle) { return _CFBundleCopyResourceForkURLMayBeLocal(bundle, true); } -static CFURLRef _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRef alloc, CFBundleRef bundle, CFURLRef url, CFStringRef executableName, Boolean ignoreCache, Boolean useOtherPlatform) { +static CFURLRef _CFBundleCopyExecutableURLInDirectory2(CFBundleRef bundle, CFURLRef url, CFStringRef executableName, Boolean ignoreCache, Boolean useOtherPlatform) { uint8_t version = 0; CFDictionaryRef infoDict = NULL; CFStringRef executablePath = NULL; @@ -1951,7 +1976,7 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRe infoDict = CFBundleGetInfoDictionary(bundle); version = bundle->_version; } else { - infoDict = _CFBundleCopyInfoDictionaryInDirectory(alloc, url, &version); + infoDict = _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefaultGCRefZero, url, &version); } // If we have a bundle instance and an info dict, see if we have already cached the path @@ -1962,9 +1987,9 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRe __CFSpinUnlock(&CFBundleExecutablePathLock); if (executablePath) { #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - executableURL = CFURLCreateWithFileSystemPath(alloc, executablePath, kCFURLPOSIXPathStyle, false); + executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, executablePath, kCFURLPOSIXPathStyle, false); #elif DEPLOYMENT_TARGET_WINDOWS - executableURL = CFURLCreateWithFileSystemPath(alloc, executablePath, kCFURLWindowsPathStyle, false); + executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, executablePath, kCFURLWindowsPathStyle, false); #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif @@ -1980,7 +2005,7 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRe } if (!foundIt) { - if (lookupMainExe) executableName = _CFBundleCopyExecutableName(alloc, bundle, url, infoDict); + if (lookupMainExe) executableName = _CFBundleCopyExecutableName(bundle, url, infoDict); if (executableName) { #if DEPLOYMENT_TARGET_EMBEDDED Boolean doExecSearch = false; @@ -1993,15 +2018,15 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRe CFURLRef exeSubdirURL; if (1 == version) { - exeDirURL = CFURLCreateWithString(alloc, _CFBundleExecutablesURLFromBase1, url); + exeDirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleExecutablesURLFromBase1, url); } else if (2 == version) { - exeDirURL = CFURLCreateWithString(alloc, _CFBundleExecutablesURLFromBase2, url); + exeDirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleExecutablesURLFromBase2, url); } else { #if DEPLOYMENT_TARGET_WINDOWS // On Windows, if the bundle URL is foo.resources, then the executable is at the same level as the .resources directory CFStringRef extension = CFURLCopyPathExtension(url); if (extension && CFEqual(extension, _CFBundleWindowsResourceDirectoryExtension)) { - exeDirURL = CFURLCreateCopyDeletingLastPathComponent(alloc, url); + exeDirURL = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault, url); } else { exeDirURL = (CFURLRef)CFRetain(url); } @@ -2012,40 +2037,40 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRe #endif } CFStringRef platformSubDir = useOtherPlatform ? _CFBundleGetOtherPlatformExecutablesSubdirectoryName() : _CFBundleGetPlatformExecutablesSubdirectoryName(); - exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL); - executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeSubdirURL, executableName); + exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL); + executableURL = _CFBundleCopyExecutableURLRaw(exeSubdirURL, executableName); if (!executableURL) { CFRelease(exeSubdirURL); platformSubDir = useOtherPlatform ? _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetAlternatePlatformExecutablesSubdirectoryName(); - exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL); - executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeSubdirURL, executableName); + exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL); + executableURL = _CFBundleCopyExecutableURLRaw(exeSubdirURL, executableName); } if (!executableURL) { CFRelease(exeSubdirURL); platformSubDir = useOtherPlatform ? _CFBundleGetPlatformExecutablesSubdirectoryName() : _CFBundleGetOtherPlatformExecutablesSubdirectoryName(); - exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL); - executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeSubdirURL, executableName); + exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL); + executableURL = _CFBundleCopyExecutableURLRaw(exeSubdirURL, executableName); } if (!executableURL) { CFRelease(exeSubdirURL); platformSubDir = useOtherPlatform ? _CFBundleGetAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(); - exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL); - executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeSubdirURL, executableName); + exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL); + executableURL = _CFBundleCopyExecutableURLRaw(exeSubdirURL, executableName); } - if (!executableURL) executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeDirURL, executableName); + if (!executableURL) executableURL = _CFBundleCopyExecutableURLRaw(exeDirURL, executableName); CFRelease(exeDirURL); CFRelease(exeSubdirURL); } // If this was an old bundle, or we did not find the executable in the Executables subdirectory, look directly in the bundle wrapper. - if (!executableURL) executableURL = _CFBundleCopyExecutableURLRaw(alloc, url, executableName); + if (!executableURL) executableURL = _CFBundleCopyExecutableURLRaw(url, executableName); #if DEPLOYMENT_TARGET_WINDOWS // Windows only: If we still haven't found the exe, look in the Executables folder. // But only for the main bundle exe if (lookupMainExe && !executableURL) { - CFURLRef exeDirURL = CFURLCreateWithString(alloc, CFSTR("../../Executables"), url); - executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeDirURL, executableName); + CFURLRef exeDirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, CFSTR("../../Executables"), url); + executableURL = _CFBundleCopyExecutableURLRaw(exeDirURL, executableName); CFRelease(exeDirURL); } #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED @@ -2073,28 +2098,28 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRe if (lookupMainExe) CFRelease(executableName); } } - if (!bundle && infoDict) CFRelease(infoDict); + if (!bundle && infoDict && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(infoDict); return executableURL; } CFURLRef _CFBundleCopyExecutableURLInDirectory(CFURLRef url) { - return _CFBundleCopyExecutableURLInDirectoryWithAllocator(kCFAllocatorSystemDefault, NULL, url, NULL, true, false); + return _CFBundleCopyExecutableURLInDirectory2(NULL, url, NULL, true, false); } CFURLRef _CFBundleCopyOtherExecutableURLInDirectory(CFURLRef url) { - return _CFBundleCopyExecutableURLInDirectoryWithAllocator(kCFAllocatorSystemDefault, NULL, url, NULL, true, true); + return _CFBundleCopyExecutableURLInDirectory2(NULL, url, NULL, true, true); } CFURLRef CFBundleCopyExecutableURL(CFBundleRef bundle) { - return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle), bundle, bundle->_url, NULL, false, false); + return _CFBundleCopyExecutableURLInDirectory2(bundle, bundle->_url, NULL, false, false); } static CFURLRef _CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle) { - return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle), bundle, bundle->_url, NULL, true, false); + return _CFBundleCopyExecutableURLInDirectory2(bundle, bundle->_url, NULL, true, false); } CFURLRef CFBundleCopyAuxiliaryExecutableURL(CFBundleRef bundle, CFStringRef executableName) { - return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle), bundle, bundle->_url, executableName, true, false); + return _CFBundleCopyExecutableURLInDirectory2(bundle, bundle->_url, executableName, true, false); } Boolean CFBundleIsExecutableLoaded(CFBundleRef bundle) { @@ -2202,21 +2227,23 @@ static const char * __CFBundleODExtensionsArray = "odc\0\0" "odf\0\0" "odg\0\0" CF_INLINE uint32_t _CFBundleSwapInt32Conditional(uint32_t arg, Boolean swap) {return swap ? CFSwapInt32(arg) : arg;} CF_INLINE uint32_t _CFBundleSwapInt64Conditional(uint64_t arg, Boolean swap) {return swap ? CFSwapInt64(arg) : arg;} +// returns zero-ref dictionary under GC static CFMutableDictionaryRef _CFBundleGrokInfoDictFromData(const char *bytes, uint32_t length) { CFMutableDictionaryRef result = NULL; CFDataRef infoData = NULL; if (bytes && 0 < length) { infoData = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (uint8_t *)bytes, length, kCFAllocatorNull); if (infoData) { - result = (CFMutableDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, infoData, kCFPropertyListMutableContainers, NULL); + result = (CFMutableDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefaultGCRefZero, infoData, kCFPropertyListMutableContainers, NULL); if (result && CFDictionaryGetTypeID() != CFGetTypeID(result)) { CFRelease(result); result = NULL; } CFRelease(infoData); } - if (!result) result = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!result) result = CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } + if (result) _processInfoDictionary((CFMutableDictionaryRef)result, _CFGetPlatformName(), _CFGetProductName()); return result; } @@ -2248,6 +2275,7 @@ static char *_CFBundleGetSectData(const char *segname, const char *sectname, uns return retval; } +// returns zero-ref dictionary under GC static CFMutableDictionaryRef _CFBundleGrokInfoDictFromMainExecutable() { char *bytes = NULL; unsigned long length = 0; @@ -2325,6 +2353,7 @@ static Boolean _CFBundleGrokX11FromFile(int fd, const void *bytes, CFIndex lengt return result; } +// 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; off_t fileLength = 0; @@ -2475,7 +2504,8 @@ static void _CFBundleGrokObjcImageInfoFromFile(int fd, const void *bytes, CFInde if (objcVersion) *objcVersion = localVersion; if (objcFlags) *objcFlags = localFlags; } - + +// returns zero-ref dictionary in *infodict under GC static UInt32 _CFBundleGrokMachTypeForFatFile(int fd, const void *bytes, CFIndex length, Boolean swap, Boolean *isX11, CFArrayRef *architectures, CFDictionaryRef *infodict, Boolean *hasObjc, uint32_t *objcVersion, uint32_t *objcFlags) { CFIndex headerLength = length; unsigned char headerBuffer[MAGIC_BYTES_TO_READ]; @@ -2550,6 +2580,7 @@ static UInt32 _CFBundleGrokMachTypeForFatFile(int fd, const void *bytes, CFIndex return machtype; } +// returns zero-ref dictionary in *infodict under GC static UInt32 _CFBundleGrokMachType(int fd, const void *bytes, CFIndex length, Boolean *isX11, CFArrayRef *architectures, CFDictionaryRef *infodict, Boolean *hasObjc, uint32_t *objcVersion, uint32_t *objcFlags) { unsigned int magic = *((UInt32 *)bytes), machtype = UNKNOWN_FILETYPE, cputype; CFNumberRef architecture = NULL; @@ -2667,6 +2698,8 @@ static const char *_CFBundleGrokFileTypeForZipFile(int fd, const unsigned char * else if (4 < namelength && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".opf", 4)) hasOPF = true; else if (4 < namelength && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".sml", 4)) hasSMIL = true; else if (5 < namelength && 0 == ustrncasecmp(bytes + i + offset + namelength - 5, ".smil", 5)) hasSMIL = true; + else if (7 < namelength && 0 == ustrncasecmp(bytes + i + offset, "xl/", 3) && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".xml", 4)) hasExcelDocument = true; + else if (8 < namelength && 0 == ustrncasecmp(bytes + i + offset, "ppt/", 4) && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".xml", 4)) hasPowerPointDocument = true; else if (9 < namelength && 0 == ustrncasecmp(bytes + i + offset, "word/", 5) && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".xml", 4)) hasWordDocument = true; else if (10 < namelength && 0 == ustrncasecmp(bytes + i + offset, "excel/", 6) && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".xml", 4)) hasExcelDocument = true; else if (15 < namelength && 0 == ustrncasecmp(bytes + i + offset, "powerpoint/", 11) && 0 == ustrncasecmp(bytes + i + offset + namelength - 4, ".xml", 4)) hasPowerPointDocument = true; @@ -2706,6 +2739,8 @@ static const char *_CFBundleGrokFileTypeForZipFile(int fd, const unsigned char * else if (4 < namelength && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".opf", 4)) hasOPF = true; else if (4 < namelength && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".sml", 4)) hasSMIL = true; else if (5 < namelength && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 5, ".smil", 5)) hasSMIL = true; + else if (7 < namelength && 0 == ustrncasecmp(moreBytes + i + offset, "xl/", 3) && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".xml", 4)) hasExcelDocument = true; + else if (8 < namelength && 0 == ustrncasecmp(moreBytes + i + offset, "ppt/", 4) && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".xml", 4)) hasPowerPointDocument = true; else if (9 < namelength && 0 == ustrncasecmp(moreBytes + i + offset, "word/", 5) && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".xml", 4)) hasWordDocument = true; else if (10 < namelength && 0 == ustrncasecmp(moreBytes + i + offset, "excel/", 6) && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".xml", 4)) hasExcelDocument = true; else if (15 < namelength && 0 == ustrncasecmp(moreBytes + i + offset, "powerpoint/", 11) && 0 == ustrncasecmp(moreBytes + i + offset + namelength - 4, ".xml", 4)) hasPowerPointDocument = true; @@ -2771,6 +2806,7 @@ static inline BOOL isspace(char c) { } #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; const unsigned char *bytes = NULL; @@ -2923,8 +2959,10 @@ static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef * UInt32 df = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 83))), rf = CFSwapInt32HostToBig(*((UInt32 *)(bytes + 87))), blocks = 1 + (df + 127) / 128 + (rf + 127) / 128; if (df < 0x00800000 && rf < 0x00800000 && 1 < blocks && (off_t)(128 * blocks) == fileLength) ext = "bin"; } else if (265 <= length && 0x75737461 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 257))) && (0x72202000 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 261))) || 0x7200 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 261))))) ext = "tar"; - else if (0xfeff == shortMagic || 0xfffe == shortMagic) ext = "txt"; - else if (0x1f9d == shortMagic) ext = "Z"; + else if (0xfeff == shortMagic || 0xfffe == shortMagic) { + ext = "txt"; + if (12 <= length && ((0x3cfeff == *((UInt32 *)bytes) && 0x740068 == *((UInt32 *)(bytes + 4)) && 0x6c006d == *((UInt32 *)(bytes + 8))) || (0xfffe3c00 == *((UInt32 *)bytes) && 0x68007400 == *((UInt32 *)(bytes + 4)) && 0x6d006c00 == *((UInt32 *)(bytes + 8))))) ext = "html"; + } else if (0x1f9d == shortMagic) ext = "Z"; else if (0x1f8b == shortMagic) ext = "gz"; else if (0x71c7 == shortMagic || 0xc771 == shortMagic) ext = "cpio"; else if (0xf702 == shortMagic) ext = "dvi"; @@ -3029,6 +3067,7 @@ CFStringRef _CFBundleCopyFileTypeForFileData(CFDataRef data) { return extension; } +// returns zero-ref dictionary under GC __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInExecutable(CFURLRef url) { CFDictionaryRef result = NULL; (void)_CFBundleGrokFileType(url, NULL, NULL, NULL, NULL, &result, NULL, NULL, NULL); @@ -3077,9 +3116,6 @@ __private_extern__ __CFPBinaryType _CFBundleGrokBinaryType(CFURLRef executableUR #endif /* BINARY_SUPPORT_DYLD */ void _CFBundleSetCFMConnectionID(CFBundleRef bundle, void *connectionID) { -#if defined(BINARY_SUPPORT_CFM) - if (bundle->_binaryType == __CFBundleUnknownBinary || bundle->_binaryType == __CFBundleUnreadableBinary) bundle->_binaryType = __CFBundleCFMBinary; -#endif /* BINARY_SUPPORT_CFM */ bundle->_connectionCookie = connectionID; bundle->_isLoaded = true; } @@ -3182,6 +3218,7 @@ static CFErrorRef _CFBundleCreateErrorDebug(CFAllocatorRef allocator, CFBundleRe } CFErrorRef _CFBundleCreateError(CFAllocatorRef allocator, CFBundleRef bundle, CFIndex code) { + allocator = _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator); return _CFBundleCreateErrorDebug(allocator, bundle, code, NULL); } @@ -3242,16 +3279,11 @@ Boolean _CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, Boolean forceG __CFSpinUnlock(&(bundle->_bundleLoadingLock)); switch (bundle->_binaryType) { -#if defined(BINARY_SUPPORT_CFM) - case __CFBundleCFMBinary: - case __CFBundleUnreadableBinary: - result = _CFBundleCFMLoad(bundle, subError); - break; -#elif defined(BINARY_SUPPORT_DLFCN) +#if defined(BINARY_SUPPORT_DLFCN) case __CFBundleUnreadableBinary: result = _CFBundleDlfcnLoadBundle(bundle, forceGlobal, subError); break; -#endif /* BINARY_SUPPORT_CFM */ +#endif /* BINARY_SUPPORT_DLFCN */ #if defined(BINARY_SUPPORT_DYLD) case __CFBundleDYLDBundleBinary: #if defined(BINARY_SUPPORT_DLFCN) @@ -3346,16 +3378,11 @@ Boolean CFBundlePreflightExecutable(CFBundleRef bundle, CFErrorRef *error) { __CFSpinUnlock(&(bundle->_bundleLoadingLock)); switch (bundle->_binaryType) { -#if defined(BINARY_SUPPORT_CFM) - case __CFBundleCFMBinary: - case __CFBundleUnreadableBinary: - result = true; - break; -#elif defined(BINARY_SUPPORT_DLFCN) +#if defined(BINARY_SUPPORT_DLFCN) case __CFBundleUnreadableBinary: result = _CFBundleDlfcnPreflight(bundle, subError); break; -#endif /* BINARY_SUPPORT_CFM */ +#endif /* BINARY_SUPPORT_DLFCN */ #if defined(BINARY_SUPPORT_DYLD) case __CFBundleDYLDBundleBinary: result = true; @@ -3425,7 +3452,7 @@ void CFBundleUnloadExecutable(CFBundleRef bundle) { if (!_scheduledBundlesAreUnloading) _CFBundleUnloadScheduledBundles(); if (!bundle->_isLoaded) return; - + // Remove from the scheduled unload set if we are there. if (!_scheduledBundlesAreUnloading) __CFSpinLock(&CFBundleGlobalDataLock); #if defined(AVOID_WEAK_COLLECTIONS) @@ -3446,11 +3473,6 @@ void CFBundleUnloadExecutable(CFBundleRef bundle) { __CFSpinUnlock(&(bundle->_bundleLoadingLock)); switch (bundle->_binaryType) { -#if defined(BINARY_SUPPORT_CFM) - case __CFBundleCFMBinary: - _CFBundleCFMUnload(bundle); - break; -#endif /* BINARY_SUPPORT_CFM */ #if defined(BINARY_SUPPORT_DYLD) case __CFBundleDYLDBundleBinary: #if defined(BINARY_SUPPORT_DLFCN) @@ -3488,7 +3510,6 @@ void CFBundleUnloadExecutable(CFBundleRef bundle) { __private_extern__ void _CFBundleScheduleForUnloading(CFBundleRef bundle) { __CFSpinLock(&CFBundleGlobalDataLock); if (!_bundlesToUnload) { - // Create this from the default allocator CFSetCallBacks nonRetainingCallbacks = kCFTypeSetCallBacks; nonRetainingCallbacks.retain = NULL; nonRetainingCallbacks.release = NULL; @@ -3568,11 +3589,6 @@ void *CFBundleGetFunctionPointerForName(CFBundleRef bundle, CFStringRef funcName } switch (bundle->_binaryType) { -#if defined(BINARY_SUPPORT_CFM) - case __CFBundleCFMBinary: - tvp = _CFBundleCFMGetSymbolByName(bundle, funcName, kTVectorCFragSymbol); - break; -#endif /* BINARY_SUPPORT_CFM */ #if defined(BINARY_SUPPORT_DYLD) case __CFBundleDYLDBundleBinary: case __CFBundleDYLDFrameworkBinary: @@ -3595,17 +3611,6 @@ void *CFBundleGetFunctionPointerForName(CFBundleRef bundle, CFStringRef funcName #endif /* BINARY_SUPPORT_DLFCN */ break; } -#if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) - if (tvp) { - if (!bundle->_glueDict) bundle->_glueDict = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, NULL, NULL); - void *fp = (void *)CFDictionaryGetValue(bundle->_glueDict, tvp); - if (!fp) { - fp = _CFBundleFunctionPointerForTVector(CFGetAllocator(bundle), tvp); - CFDictionarySetValue(bundle->_glueDict, tvp, fp); - } - return fp; - } -#endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM */ return tvp; } @@ -3615,13 +3620,8 @@ void *_CFBundleGetCFMFunctionPointerForName(CFBundleRef bundle, CFStringRef func if (!bundle->_isLoaded) { if (!CFBundleLoadExecutable(bundle)) return NULL; } -#if defined (BINARY_SUPPORT_CFM) || defined (BINARY_SUPPORT_DYLD) || defined (BINARY_SUPPORT_DLFCN) +#if defined (BINARY_SUPPORT_DYLD) || defined (BINARY_SUPPORT_DLFCN) switch (bundle->_binaryType) { -#if defined(BINARY_SUPPORT_CFM) - case __CFBundleCFMBinary: - return _CFBundleCFMGetSymbolByName(bundle, funcName, kTVectorCFragSymbol); - break; -#endif /* BINARY_SUPPORT_CFM */ #if defined(BINARY_SUPPORT_DYLD) case __CFBundleDYLDBundleBinary: case __CFBundleDYLDFrameworkBinary: @@ -3639,18 +3639,7 @@ void *_CFBundleGetCFMFunctionPointerForName(CFBundleRef bundle, CFStringRef func #endif /* BINARY_SUPPORT_DLFCN */ break; } -#endif /* BINARY_SUPPORT_CFM || BINARY_SUPPORT_DYLD || BINARY_SUPPORT_DLFCN */ -#if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) - if (fp) { - if (!bundle->_glueDict) bundle->_glueDict = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, NULL, NULL); - void *tvp = (void *)CFDictionaryGetValue(bundle->_glueDict, fp); - if (!tvp) { - tvp = _CFBundleTVectorForFunctionPointer(CFGetAllocator(bundle), fp); - CFDictionarySetValue(bundle->_glueDict, fp, tvp); - } - return tvp; - } -#endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM */ +#endif /* BINARY_SUPPORT_DYLD || BINARY_SUPPORT_DLFCN */ return fp; } @@ -3678,11 +3667,6 @@ void *CFBundleGetDataPointerForName(CFBundleRef bundle, CFStringRef symbolName) if (!bundle->_isLoaded && !CFBundleLoadExecutable(bundle)) return NULL; switch (bundle->_binaryType) { -#if defined(BINARY_SUPPORT_CFM) - case __CFBundleCFMBinary: - dp = _CFBundleCFMGetSymbolByName(bundle, symbolName, kDataCFragSymbol); - break; -#endif /* BINARY_SUPPORT_CFM */ #if defined(BINARY_SUPPORT_DYLD) case __CFBundleDYLDBundleBinary: case __CFBundleDYLDFrameworkBinary: @@ -3738,11 +3722,12 @@ __private_extern__ Boolean _CFBundleCouldBeBundle(CFURLRef url) { } #define LENGTH_OF(A) (sizeof(A) / sizeof(A[0])) - -__private_extern__ CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFAllocatorRef alloc, CFStringRef executablePath) { + +//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 0 && DEPLOYMENT_TARGET_WINDOWS_SYNC +#elif 0 && 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 executablesToSystemFrameworksPathBuff[MAX_PATH+1] = { 0 }; @@ -3755,12 +3740,12 @@ __private_extern__ CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFAllocat #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif - UniChar pathBuff[CFMaxPathSize]; - UniChar nameBuff[CFMaxPathSize]; + UniChar pathBuff[CFMaxPathSize] = {0}; + UniChar nameBuff[CFMaxPathSize] = {0}; CFIndex length, nameStart, nameLength, savedLength; - CFMutableStringRef cheapStr = CFStringCreateMutableWithExternalCharactersNoCopy(alloc, NULL, 0, 0, NULL); + CFMutableStringRef cheapStr = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, NULL); CFURLRef bundleURL = NULL; - + length = CFStringGetLength(executablePath); if (length > CFMaxPathSize) length = CFMaxPathSize; CFStringGetCharacters(executablePath, CFRangeMake(0, length), pathBuff); @@ -3779,7 +3764,7 @@ __private_extern__ CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFAllocat // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case. if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToFrameworksPathBuff, LENGTH_OF(executablesToFrameworksPathBuff)) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, LENGTH_OF(frameworksExtension))) { CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize); - bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true); + bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true); if (!_CFBundleCouldBeBundle(bundleURL)) { CFRelease(bundleURL); bundleURL = NULL; @@ -3790,7 +3775,7 @@ __private_extern__ CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFAllocat length = savedLength; if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToPrivateFrameworksPathBuff, LENGTH_OF(executablesToPrivateFrameworksPathBuff)) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, LENGTH_OF(frameworksExtension))) { CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize); - bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true); + bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true); if (!_CFBundleCouldBeBundle(bundleURL)) { CFRelease(bundleURL); bundleURL = NULL; @@ -3798,11 +3783,11 @@ __private_extern__ CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFAllocat } } -#elif 0 && DEPLOYMENT_TARGET_WINDOWS_SYNC +#elif 0 && DEPLOYMENT_TARGET_WINDOWS // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case. if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToFrameworksPathBuff, LENGTH_OF(executablesToFrameworksPathBuff)) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, LENGTH_OF(frameworksExtension))) { CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize); - bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true); + bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true); if (!_CFBundleCouldBeBundle(bundleURL)) { CFRelease(bundleURL); bundleURL = NULL; @@ -3813,7 +3798,7 @@ __private_extern__ CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFAllocat length = savedLength; if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToPrivateFrameworksPathBuff, LENGTH_OF(executablesToPrivateFrameworksPathBuff)) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, LENGTH_OF(frameworksExtension))) { CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize); - bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true); + bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true); if (!_CFBundleCouldBeBundle(bundleURL)) { CFRelease(bundleURL); bundleURL = NULL; @@ -3825,7 +3810,7 @@ __private_extern__ CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFAllocat length = 0; if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToSystemFrameworksPathBuff, wcslen(executablesToSystemFrameworksPathBuff)) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, LENGTH_OF(frameworksExtension))) { CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize); - bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true); + bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true); if (!_CFBundleCouldBeBundle(bundleURL)) { CFRelease(bundleURL); bundleURL = NULL; @@ -3837,29 +3822,36 @@ __private_extern__ CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFAllocat #error Unknown or unspecified DEPLOYMENT_TARGET #endif // * Finally check the executable inside the framework case. - if (!bundleURL) { - // MF:!!! This should ensure the framework name is the same as the library name! - CFIndex curStart; - + if (!bundleURL) { length = savedLength; // To catch all the cases, we just peel off level looking for one ending in .framework or one called "Supporting Files". - + + CFStringRef name = permissive ? CFSTR("") : CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, (const char *)nameBuff); + while (length > 0) { - curStart = _CFStartOfLastPathComponent(pathBuff, length); + CFIndex curStart = _CFStartOfLastPathComponent(pathBuff, length); if (curStart >= length) break; CFStringSetExternalCharactersNoCopy(cheapStr, &(pathBuff[curStart]), length - curStart, CFMaxPathSize - curStart); + if (!permissive && CFEqual(cheapStr, _CFBundleResourcesDirectoryName)) break; if (CFEqual(cheapStr, _CFBundleSupportFilesDirectoryName1) || CFEqual(cheapStr, _CFBundleSupportFilesDirectoryName2)) { - length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length); - CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize); - bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true); - if (!_CFBundleCouldBeBundle(bundleURL)) { - CFRelease(bundleURL); - bundleURL = NULL; + if (!permissive) { + CFIndex fmwkStart = _CFStartOfLastPathComponent(pathBuff, length); + CFStringSetExternalCharactersNoCopy(cheapStr, &(pathBuff[fmwkStart]), length - fmwkStart, CFMaxPathSize - fmwkStart); } - break; - } else if (CFStringHasSuffix(cheapStr, CFSTR(".framework"))) { + if (permissive || CFStringHasPrefix(cheapStr, name)) { + length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length); + CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize); + + bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true); + if (!_CFBundleCouldBeBundle(bundleURL)) { + CFRelease(bundleURL); + bundleURL = NULL; + } + break; + } + } else if (CFStringHasSuffix(cheapStr, CFSTR(".framework")) && (permissive || CFStringHasPrefix(cheapStr, name))) { CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize); - bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true); + bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, cheapStr, PLATFORM_PATH_STYLE, true); if (!_CFBundleCouldBeBundle(bundleURL)) { CFRelease(bundleURL); bundleURL = NULL; @@ -3868,17 +3860,24 @@ __private_extern__ CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFAllocat } length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length); } + if (!permissive) CFRelease(name); } CFStringSetExternalCharactersNoCopy(cheapStr, NULL, 0, 0); CFRelease(cheapStr); + return bundleURL; } + +//SPI version; separated out to minimize linkage changes +CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath) { + return __CFBundleCopyFrameworkURLForExecutablePath(executablePath, false); +} static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath) { // This finds the bundle for the given path. // If an image path corresponds to a bundle, we see if there is already a bundle instance. If there is and it is NOT in the _dynamicBundles array, it is added to the staticBundles. Do not add the main bundle to the list here. CFBundleRef bundle; - CFURLRef curURL = _CFBundleCopyFrameworkURLForExecutablePath(kCFAllocatorSystemDefault, imagePath); + CFURLRef curURL = __CFBundleCopyFrameworkURLForExecutablePath(imagePath, true); Boolean createdBundle = false; if (curURL) { @@ -3956,10 +3955,6 @@ static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void) { // Dont know how to find static bundles for DLLs #endif /* BINARY_SUPPORT_DLL */ -#if defined(BINARY_SUPPORT_CFM) -// CFM bundles are supplied to us by CFM, so we do not need to figure them out ourselves -#endif /* BINARY_SUPPORT_CFM */ - #if defined(BINARY_SUPPORT_DYLD) imagePaths = _CFBundleDYLDCopyLoadedImagePathsIfChanged(); #endif /* BINARY_SUPPORT_DYLD */ @@ -3993,6 +3988,20 @@ CFArrayRef CFBundleGetAllBundles(void) { __CFSpinUnlock(&CFBundleGlobalDataLock); return bundles; } + +CF_EXPORT CFArrayRef _CFBundleCopyAllBundles(void) { + // To answer this properly, we have to have created the static bundles! + __CFSpinLock(&CFBundleGlobalDataLock); + _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(); +#if defined(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); + return bundles; +} uint8_t _CFBundleLayoutVersion(CFBundleRef bundle) { return bundle->_version; @@ -4071,7 +4080,7 @@ CF_EXPORT CFURLRef CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle) { } else { result = CFURLCreateWithString(alloc, _CFBundleBuiltInPlugInsURLFromBase0, bundle->_url); } - if (!result || !_urlExists(alloc, result)) { + if (!result || !_urlExists(result)) { if (1 == bundle->_version) { alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase1, bundle->_url); } else if (2 == bundle->_version) { @@ -4079,7 +4088,7 @@ CF_EXPORT CFURLRef CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle) { } else { alternateResult = CFURLCreateWithString(alloc, _CFBundleAlternateBuiltInPlugInsURLFromBase0, bundle->_url); } - if (alternateResult && _urlExists(alloc, alternateResult)) { + if (alternateResult && _urlExists(alternateResult)) { if (result) CFRelease(result); result = alternateResult; } else { @@ -4089,8 +4098,6 @@ CF_EXPORT CFURLRef CFBundleCopyBuiltInPlugInsURL(CFBundleRef bundle) { return result; } - - #if defined(BINARY_SUPPORT_DYLD) __private_extern__ CFArrayRef _CFBundleDYLDCopyLoadedImagePathsForHint(CFStringRef hint) { @@ -4463,7 +4470,7 @@ static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle, CFString } if (!symbol && !bundle->_moduleCookie && (!bundle->_imageCookie || globalSearch)) { char hintBuff[1026]; - CFStringRef executableName = _CFBundleCopyExecutableName(kCFAllocatorSystemDefault, bundle, NULL, NULL); + CFStringRef executableName = _CFBundleCopyExecutableName(bundle, NULL, NULL); hintBuff[0] = '\0'; if (executableName) { if (!CFStringGetCString(executableName, hintBuff, 1024, kCFStringEncodingUTF8)) hintBuff[0] = '\0'; @@ -4731,7 +4738,6 @@ static CFStringRef _CFBundleDlfcnCopyLoadedImagePathForPointer(void *p) { #endif /* !BINARY_SUPPORT_DYLD */ #endif /* BINARY_SUPPORT_DLFCN */ - #if defined(BINARY_SUPPORT_DLL) __private_extern__ Boolean _CFBundleDLLLoad(CFBundleRef bundle, CFErrorRef *error) { diff --git a/CFBundle.h b/CFBundle.h index 04b1367..649e3f3 100644 --- a/CFBundle.h +++ b/CFBundle.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFBundle.h - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBUNDLE__) @@ -62,7 +62,7 @@ CF_EXPORT const CFStringRef kCFBundleNameKey; /* The human-readable name of the bundle. This key is often found in the InfoPlist.strings since it is usually localized. */ CF_EXPORT -const CFStringRef kCFBundleLocalizationsKey AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER; +const CFStringRef kCFBundleLocalizationsKey; /* Allows an unbundled application that handles localization itself to specify which localizations it has available. */ /* ===================== Finding Bundles ===================== */ @@ -208,7 +208,7 @@ CFArrayRef CFBundleCopyPreferredLocalizationsFromArray(CFArrayRef locArray); /* result of CFBundleCopyBundleLocalizations(). */ CF_EXPORT -CFArrayRef CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, CFArrayRef prefArray) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER; +CFArrayRef CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, CFArrayRef prefArray); /* Given an array of possible localizations, returns the one or more of */ /* them that CFBundle would use, without reference to the current application */ /* context, if the user's preferred localizations were given by prefArray. */ @@ -233,14 +233,14 @@ CFArrayRef CFBundleCopyResourceURLsOfTypeForLocalization(CFBundleRef bundle, CFS /* This API is provided to enable developers to retrieve bundle-related */ /* information about an application that may be bundled or unbundled. */ CF_EXPORT -CFDictionaryRef CFBundleCopyInfoDictionaryForURL(CFURLRef url) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER; +CFDictionaryRef CFBundleCopyInfoDictionaryForURL(CFURLRef url); /* For a directory URL, this is equivalent to CFBundleCopyInfoDictionaryInDirectory(). */ /* For a plain file URL representing an unbundled executable, this will attempt to read */ /* an info dictionary from the (__TEXT, __info_plist) section, if it is a Mach-o file, */ /* or from a 'plst' resource. */ CF_EXPORT -CFArrayRef CFBundleCopyLocalizationsForURL(CFURLRef url) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER; +CFArrayRef CFBundleCopyLocalizationsForURL(CFURLRef url); /* For a directory URL, this is equivalent to calling CFBundleCopyBundleLocalizations() */ /* on the corresponding bundle. For a plain file URL representing an unbundled executable, */ /* this will attempt to determine its localizations using the CFBundleLocalizations and */ @@ -248,7 +248,7 @@ CFArrayRef CFBundleCopyLocalizationsForURL(CFURLRef url) AVAILABLE_MAC_OS_X_VERS /* or from a 'vers' resource if those are not present. */ CF_EXPORT -CFArrayRef CFBundleCopyExecutableArchitecturesForURL(CFURLRef url) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFArrayRef CFBundleCopyExecutableArchitecturesForURL(CFURLRef url) CF_AVAILABLE(10_5, 2_0); /* For a directory URL, this is equivalent to calling CFBundleCopyExecutableArchitectures() */ /* on the corresponding bundle. For a plain file URL representing an unbundled executable, */ /* this will return the architectures it provides, if it is a Mach-o file, or NULL otherwise. */ @@ -271,14 +271,14 @@ enum { #endif /* MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED */ CF_EXPORT -CFArrayRef CFBundleCopyExecutableArchitectures(CFBundleRef bundle) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFArrayRef CFBundleCopyExecutableArchitectures(CFBundleRef bundle) CF_AVAILABLE(10_5, 2_0); /* If the bundle's executable exists and is a Mach-o file, this function will return an array */ /* of CFNumbers whose values are integers representing the architectures the file provides. */ /* The values currently in use are those listed in the enum above, but others may be added */ /* in the future. If the executable is not a Mach-o file, this function returns NULL. */ CF_EXPORT -Boolean CFBundlePreflightExecutable(CFBundleRef bundle, CFErrorRef *error) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +Boolean CFBundlePreflightExecutable(CFBundleRef bundle, CFErrorRef *error) CF_AVAILABLE(10_5, 2_0); /* This function will return true if the bundle is loaded, or if the bundle appears to be */ /* loadable upon inspection. This does not mean that the bundle is definitively loadable, */ /* since it may fail to load due to link errors or other problems not readily detectable. */ @@ -286,7 +286,7 @@ Boolean CFBundlePreflightExecutable(CFBundleRef bundle, CFErrorRef *error) AVAIL /* It is the responsibility of the caller to release the CFError. */ CF_EXPORT -Boolean CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, CFErrorRef *error) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +Boolean CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, CFErrorRef *error) CF_AVAILABLE(10_5, 2_0); /* If the bundle is already loaded, this function will return true. Otherwise, it will attempt */ /* to load the bundle, and it will return true if that attempt succeeds. If the bundle fails */ /* to load, this function will return false, and it will return a CFError by reference. */ diff --git a/CFBundlePriv.h b/CFBundlePriv.h index fb43736..66e537b 100644 --- a/CFBundlePriv.h +++ b/CFBundlePriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFBundlePriv.h - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBUNDLEPRIV__) @@ -236,12 +236,18 @@ void _CFBundleFlushCachesForURL(CFURLRef url); CF_EXPORT void _CFBundleFlushBundleCaches(CFBundleRef bundle); // The previous two functions flush cached resource paths; this one also flushes bundle-specific caches such as the info dictionary and strings files +CF_EXPORT +CFArrayRef _CFBundleCopyAllBundles(void); // Pending publication, the only known client of this is PowerBox. Email david_smith@apple.com before using this. + CF_EXPORT void _CFBundleSetStringsFilesShared(CFBundleRef bundle, Boolean flag); CF_EXPORT Boolean _CFBundleGetStringsFilesShared(CFBundleRef bundle); +CF_EXPORT +CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFStringRef executablePath); + /* Functions deprecated as SPI */ diff --git a/CFBundle_BinaryTypes.h b/CFBundle_BinaryTypes.h index f891583..58fbb56 100644 --- a/CFBundle_BinaryTypes.h +++ b/CFBundle_BinaryTypes.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFBundle_BinaryTypes.h - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBUNDLE_BINARYTYPES__) @@ -30,7 +30,6 @@ CF_EXTERN_C_BEGIN - #if DEPLOYMENT_TARGET_MACOSX #define BINARY_SUPPORT_DYLD 1 #define BINARY_SUPPORT_DLFCN 1 diff --git a/CFBundle_Internal.h b/CFBundle_Internal.h index 0f47749..95988aa 100644 --- a/CFBundle_Internal.h +++ b/CFBundle_Internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFBundle_Internal.h - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBUNDLE_INTERNAL__) @@ -84,11 +84,10 @@ extern Boolean _CFIsResourceAtPath(CFStringRef path, Boolean *isDir); extern Boolean _CFBundleURLLooksLikeBundleVersion(CFURLRef url, UInt8 *version); extern CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectory(CFAllocatorRef alloc, CFURLRef url, UInt8 *version); extern CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFAllocatorRef alloc, CFURLRef url, UInt8 version); -extern CFURLRef _CFBundleCopySupportFilesDirectoryURLInDirectory(CFAllocatorRef alloc, CFURLRef bundleURL, UInt8 version); -extern CFURLRef _CFBundleCopyResourcesDirectoryURLInDirectory(CFAllocatorRef alloc, CFURLRef bundleURL, UInt8 version); +extern CFURLRef _CFBundleCopySupportFilesDirectoryURLInDirectory(CFURLRef bundleURL, UInt8 version); +extern CFURLRef _CFBundleCopyResourcesDirectoryURLInDirectory(CFURLRef bundleURL, UInt8 version); extern Boolean _CFBundleCouldBeBundle(CFURLRef url); -extern CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFAllocatorRef alloc, CFStringRef executablePath); extern CFURLRef _CFBundleCopyResourceForkURLMayBeLocal(CFBundleRef bundle, Boolean mayBeLocal); extern CFDictionaryRef _CFBundleCopyInfoDictionaryInResourceForkWithAllocator(CFAllocatorRef alloc, CFURLRef url); extern CFStringRef _CFBundleCopyBundleDevelopmentRegionFromVersResource(CFBundleRef bundle); @@ -134,7 +133,6 @@ extern void _CFBundleDlfcnUnload(CFBundleRef bundle); extern void *_CFBundleDlfcnGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName); #endif /* BINARY_SUPPORT_DLFCN */ - #if defined(BINARY_SUPPORT_DLL) extern Boolean _CFBundleDLLLoad(CFBundleRef bundle, CFErrorRef *error); extern void _CFBundleDLLUnload(CFBundleRef bundle); @@ -170,6 +168,9 @@ extern void _CFPlugInRemoveFactory(CFPlugInRef plugIn, _CFPFactory *factory); #define _CFBundleResourcesURLFromBase0 CFSTR("Resources/") #define _CFBundleResourcesURLFromBase1 CFSTR("Support%20Files/Resources/") #define _CFBundleResourcesURLFromBase2 CFSTR("Contents/Resources/") +#define _CFBundleAppStoreReceiptURLFromBase0 CFSTR("_MASReceipt/receipt") +#define _CFBundleAppStoreReceiptURLFromBase1 CFSTR("Support%20Files/_MASReceipt/receipt") +#define _CFBundleAppStoreReceiptURLFromBase2 CFSTR("Contents/_MASReceipt/receipt") #define _CFBundleExecutablesURLFromBase1 CFSTR("Support%20Files/Executables/") #define _CFBundleExecutablesURLFromBase2 CFSTR("Contents/") #define _CFBundleInfoURLFromBase0 CFSTR("Resources/Info.plist") @@ -207,6 +208,7 @@ extern void _CFPlugInRemoveFactory(CFPlugInRef plugIn, _CFPFactory *factory); #define _CFBundleMacOSXPlatformName CFSTR("macos") #define _CFBundleAlternateMacOSXPlatformName CFSTR("macosx") +#define _CFBundleiPhoneOSPlatformName CFSTR("iphoneos") #define _CFBundleMacOS8PlatformName CFSTR("macosclassic") #define _CFBundleAlternateMacOS8PlatformName CFSTR("macos8") #define _CFBundleWindowsPlatformName CFSTR("windows") @@ -217,6 +219,7 @@ extern void _CFPlugInRemoveFactory(CFPlugInRef plugIn, _CFPFactory *factory); #define _CFBundleDefaultStringTableName CFSTR("Localizable") #define _CFBundleStringTableType CFSTR("strings") +#define _CFBundleStringDictTableType CFSTR("stringsdict") #define _CFBundleUserLanguagesPreferenceName CFSTR("AppleLanguages") #define _CFBundleOldUserLanguagesPreferenceName CFSTR("NSLanguages") diff --git a/CFBundle_Resources.c b/CFBundle_Resources.c index 6a1b6ec..4462884 100644 --- a/CFBundle_Resources.c +++ b/CFBundle_Resources.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,11 +22,13 @@ */ /* CFBundle_Resources.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. - Responsibility: Doug Davidson + Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX +#define READ_DIRECTORIES 1 +#elif DEPLOYMENT_TARGET_EMBEDDED #define READ_DIRECTORIES 1 #elif DEPLOYMENT_TARGET_WINDOWS #define READ_DIRECTORIES 0 @@ -50,6 +52,11 @@ #include #include #include +#include +#include +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#include +#endif #if DEPLOYMENT_TARGET_MACOSX #include @@ -64,12 +71,92 @@ #include #endif /* READ_DIRECTORIES */ +CF_EXPORT bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict, const void *key, const void **actualkey); +static inline Boolean _CFBundleSortedArrayContains(CFArrayRef arr, CFStringRef target) { + CFRange arrRange = CFRangeMake(0, CFArrayGetCount(arr)); + CFIndex itemIdx = CFArrayBSearchValues(arr, arrRange, target, (CFComparatorFunction)CFStringCompare, NULL); + 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 +#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" }; + +#define _CFBundleNumberOfiPhoneOSPlatformProducts 3 +static CFStringRef _CFBundleSupportediPhoneOSPlatformProducts[_CFBundleNumberOfiPhoneOSPlatformProducts] = { NULL, NULL, NULL }; +static const char *_CFBundleSupportediPhoneOSPlatformProductStrings[_CFBundleNumberOfiPhoneOSPlatformProducts] = { "iphone", "ipod", "ipad" }; + +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); + + for (unsigned int i = 0; i < _CFBundleNumberOfiPhoneOSPlatformProducts; i++) _CFBundleSupportediPhoneOSPlatformProducts[i] = CFStringCreateWithCString(kCFAllocatorSystemDefault, _CFBundleSupportediPhoneOSPlatformProductStrings[i], kCFStringEncodingUTF8); +} + +static CFStringRef platform = NULL; + +void _CFSetProductName(CFStringRef str) { + if (str) CFRetain(str); + platform = str; + // Note that the previous value is leaked, which is fine normally + // because the initial values would tend to be the constant strings + // below. That is required for thread-safety value due to the Get + // function [not being Copy]. It is also fine because people + // shouldn't be screwing around with this value casually. +} + +CFStringRef _CFGetProductName(void) { +#if DEPLOYMENT_TARGET_EMBEDDED + if (!platform) { + char buffer[256]; + memset(buffer, 0, sizeof(buffer)); + size_t buflen = sizeof(buffer); + int ret = sysctlbyname("hw.machine", buffer, &buflen, NULL, 0); + if (0 == ret || (-1 == ret && ENOMEM == errno)) { + if (6 <= buflen && 0 == memcmp(buffer, "iPhone", 6)) { + platform = CFSTR("iphone"); + } else if (4 <= buflen && 0 == memcmp(buffer, "iPod", 4)) { + platform = CFSTR("ipod"); + } else if (4 <= buflen && 0 == memcmp(buffer, "iPad", 4)) { + platform = CFSTR("ipad"); + } else { + const char *env = __CFgetenv("IPHONE_SIMULATOR_DEVICE"); + if (env) { + if (0 == strcmp(env, "iPhone")) { + platform = CFSTR("iphone"); + } else if (0 == strcmp(env, "iPad")) { + platform = CFSTR("ipad"); + } else { + // fallback, unrecognized IPHONE_SIMULATOR_DEVICE + } + } else { + // fallback, unrecognized hw.machine and no IPHONE_SIMULATOR_DEVICE + } + } + } + if (!platform) platform = CFSTR("iphone"); // fallback + } + return platform; +#endif + return CFSTR(""); +} + // All new-style bundles will have these extensions. -CF_INLINE CFStringRef _CFGetPlatformName(void) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +__private_extern__ CFStringRef _CFGetPlatformName(void) { +#if DEPLOYMENT_TARGET_MACOSX return _CFBundleMacOSXPlatformName; +#elif DEPLOYMENT_TARGET_EMBEDDED + return _CFBundleiPhoneOSPlatformName; #elif DEPLOYMENT_TARGET_WINDOWS return _CFBundleWindowsPlatformName; #elif DEPLOYMENT_TARGET_SOLARIS @@ -85,9 +172,11 @@ CF_INLINE CFStringRef _CFGetPlatformName(void) { #endif } -CF_INLINE CFStringRef _CFGetAlternatePlatformName(void) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +__private_extern__ CFStringRef _CFGetAlternatePlatformName(void) { +#if DEPLOYMENT_TARGET_MACOSX return _CFBundleAlternateMacOSXPlatformName; +#elif DEPLOYMENT_TARGET_EMBEDDED + return _CFBundleMacOSXPlatformName; #elif DEPLOYMENT_TARGET_WINDOWS return CFSTR(""); #else @@ -113,6 +202,13 @@ static CFIndex _GlobalResourcesLen = 0; static UniChar *_InfoExtensionUniChars = NULL; static CFIndex _InfoExtensionLen = 0; +static UniChar _ResourceSuffix3[32]; +static CFIndex _ResourceSuffix3Len = 0; +static UniChar _ResourceSuffix2[16]; +static CFIndex _ResourceSuffix2Len = 0; +static UniChar _ResourceSuffix1[16]; +static CFIndex _ResourceSuffix1Len = 0; + static void _CFBundleInitStaticUniCharBuffers(void) { CFStringRef appSupportStr1 = _CFBundleSupportFilesDirectoryName1; CFStringRef appSupportStr2 = _CFBundleSupportFilesDirectoryName2; @@ -123,8 +219,6 @@ static void _CFBundleInitStaticUniCharBuffers(void) { CFStringRef globalResourcesStr = _CFBundleNonLocalizedResourcesDirectoryName; CFStringRef infoExtensionStr = _CFBundleInfoExtension; - CFAllocatorRef alloc = __CFGetDefaultAllocator(); - _AppSupportLen1 = CFStringGetLength(appSupportStr1); _AppSupportLen2 = CFStringGetLength(appSupportStr2); _ResourcesLen = CFStringGetLength(resourcesStr); @@ -134,7 +228,7 @@ static void _CFBundleInitStaticUniCharBuffers(void) { _GlobalResourcesLen = CFStringGetLength(globalResourcesStr); _InfoExtensionLen = CFStringGetLength(infoExtensionStr); - _AppSupportUniChars1 = (UniChar *)CFAllocatorAllocate(alloc, 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), 0); _AppSupportUniChars2 = _AppSupportUniChars1 + _AppSupportLen1; _ResourcesUniChars = _AppSupportUniChars2 + _AppSupportLen2; _PlatformUniChars = _ResourcesUniChars + _ResourcesLen; @@ -151,6 +245,24 @@ 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); + + _ResourceSuffix1Len = CFStringGetLength(platformStr); + if (_ResourceSuffix1Len > 0) _ResourceSuffix1[0] = '-'; + if (_ResourceSuffix1Len > 0) CFStringGetCharacters(platformStr, CFRangeMake(0, _ResourceSuffix1Len), _ResourceSuffix1 + 1); + if (_ResourceSuffix1Len > 0) _ResourceSuffix1Len++; + CFStringRef productStr = _CFGetProductName(); + if (CFEqual(productStr, CFSTR("ipod"))) { // For now, for resource lookups, hide ipod distinction and make it look for iphone resources + productStr = CFSTR("iphone"); + } + _ResourceSuffix2Len = CFStringGetLength(productStr); + if (_ResourceSuffix2Len > 0) _ResourceSuffix2[0] = '~'; + if (_ResourceSuffix2Len > 0) CFStringGetCharacters(productStr, CFRangeMake(0, _ResourceSuffix2Len), _ResourceSuffix2 + 1); + if (_ResourceSuffix2Len > 0) _ResourceSuffix2Len++; + if (_ResourceSuffix1Len > 1 && _ResourceSuffix2Len > 1) { + _ResourceSuffix3Len = _ResourceSuffix1Len + _ResourceSuffix2Len; + memmove(_ResourceSuffix3, _ResourceSuffix1, sizeof(UniChar) * _ResourceSuffix1Len); + memmove(_ResourceSuffix3 + _ResourceSuffix1Len, _ResourceSuffix2, sizeof(UniChar) * _ResourceSuffix2Len); + } } CF_INLINE void _CFEnsureStaticBuffersInited(void) { @@ -171,7 +283,9 @@ typedef enum { _CFBundleUnknownContents = 2 } _CFBundleDirectoryContentsType; -static CFArrayRef _CFBundleCopyDirectoryContentsAtPath(CFStringRef path, _CFBundleDirectoryContentsType contentsType) { +extern void _CFArraySortValues(CFMutableArrayRef array, CFComparatorFunction comparator, void *context); + +static CFArrayRef _CFBundleCopySortedDirectoryContentsAtPath(CFStringRef path, _CFBundleDirectoryContentsType contentsType) { CFArrayRef result = NULL; __CFSpinLock(&CFBundleResourceGlobalDataLock); @@ -193,7 +307,6 @@ static CFArrayRef _CFBundleCopyDirectoryContentsAtPath(CFStringRef path, _CFBund struct dirent *dent; CFMutableArrayRef contents = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks), directoryContents = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks), unknownContents = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); CFStringRef dirName, name; - struct stat statBuf; cpathBuff[0] = '\0'; if (CFStringGetFileSystemRepresentation(path, cpathBuff, CFMaxPathSize)) { @@ -230,9 +343,9 @@ static CFArrayRef _CFBundleCopyDirectoryContentsAtPath(CFStringRef path, _CFBund cpathBuff[lastSlashIdx] = '/'; } } - if (tryToOpen && stat(cpathBuff, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFDIR && (dirp = opendir(cpathBuff))) { + if (tryToOpen && (dirp = opendir(cpathBuff))) { while ((dent = readdir(dirp))) { - CFIndex nameLen = strlen(dent->d_name); + CFIndex nameLen = dent->d_namlen; if (0 == nameLen || 0 == dent->d_fileno || ('.' == dent->d_name[0] && (1 == nameLen || (2 == nameLen && '.' == dent->d_name[1]) || '_' == dent->d_name[1]))) continue; name = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, dent->d_name); if (name) { @@ -251,6 +364,10 @@ static CFArrayRef _CFBundleCopyDirectoryContentsAtPath(CFStringRef path, _CFBund (void)closedir(dirp); } + _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); @@ -325,25 +442,28 @@ CF_EXPORT void _CFBundleFlushCaches(void) { #endif /* READ_DIRECTORIES */ } -__private_extern__ Boolean _CFIsResourceAtURL(CFURLRef url, Boolean *isDir) { +static inline Boolean _CFIsResourceCommon(char *path, Boolean *isDir) { Boolean exists; SInt32 mode; - if (_CFGetFileProperties(kCFAllocatorSystemDefault, url, &exists, &mode, NULL, NULL, NULL, NULL) == 0) { + if (_CFGetPathProperties(kCFAllocatorSystemDefault, path, &exists, &mode, NULL, NULL, NULL, NULL) == 0) { if (isDir) *isDir = ((exists && ((mode & S_IFMT) == S_IFDIR)) ? true : false); return (exists && (mode & 0444)); - } else { - return false; } + return false; +} + +__private_extern__ Boolean _CFIsResourceAtURL(CFURLRef url, Boolean *isDir) { + char path[CFMaxPathSize]; + if (!CFURLGetFileSystemRepresentation(url, true, (uint8_t *)path, CFMaxPathLength)) return false; + + return _CFIsResourceCommon(path, isDir); } __private_extern__ Boolean _CFIsResourceAtPath(CFStringRef path, Boolean *isDir) { - Boolean result = false; - CFURLRef url = CFURLCreateWithFileSystemPath(CFGetAllocator(path), path, PLATFORM_PATH_STYLE, false); - if (url) { - result = _CFIsResourceAtURL(url, isDir); - CFRelease(url); - } - return result; + char pathBuf[CFMaxPathSize]; + if (!CFStringGetFileSystemRepresentation(path, pathBuf, CFMaxPathSize)) return false; + + return _CFIsResourceCommon(pathBuf, isDir); } #if READ_DIRECTORIES @@ -356,7 +476,7 @@ static CFArrayRef _CFCopyTypesForSearchBundleDirectory(CFAllocatorRef alloc, Uni CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, dirPathLen, dirPathLen); CFStringReplaceAll(cheapStr, tmpString); //fprintf(stderr, "looking in ");CFShow(cheapStr); - contents = _CFBundleCopyDirectoryContentsAtPath(cheapStr, _CFBundleAllContents); + contents = _CFBundleCopySortedDirectoryContentsAtPath(cheapStr, _CFBundleAllContents); contentsRange = CFRangeMake(0, CFArrayGetCount(contents)); CFStringSetExternalCharactersNoCopy(tmpString, nameUniChars, nameLen, nameLen); @@ -380,7 +500,112 @@ static CFArrayRef _CFCopyTypesForSearchBundleDirectory(CFAllocatorRef alloc, Uni } #endif /* READ_DIRECTORIES */ +#if DEPLOYMENT_TARGET_EMBEDDED +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. + // typeUniChars is the type we are looking for. + // platformUniChars is the platform name. + // cheapStr is available for our use for whatever we want. + // URLs for found resources get added to result. + + Boolean appendSucceeded = true; + if (nameLen > 0) appendSucceeded = _CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, nameUniChars, nameLen); + if (! appendSucceeded) return; + CFIndex savedPathLen = pathLen; + + // Try in order: + // NAME-PLATFORM~PRODUCT.TYPE (disabled for now) + // NAME~PRODUCT.TYPE + // NAME-PLATFORM.TYPE (disabled for now) + // NAME.TYPE + +#if 0 + appendSucceeded = (pathLen + _ResourceSuffix3Len < CFMaxPathSize); + if (appendSucceeded) { + memmove(pathUniChars + pathLen, _ResourceSuffix3, _ResourceSuffix3Len * sizeof(UniChar)); + pathLen += _ResourceSuffix3Len; + } + if (appendSucceeded && typeLen > 0) appendSucceeded = _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, typeUniChars, typeLen); + if (appendSucceeded) { + CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); + CFStringReplaceAll(cheapStr, tmpString); + Boolean Found = false, IsDir = false; + Found = _CFIsResourceAtPath(cheapStr, &IsDir); + if (Found) { + CFURLRef url = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, IsDir); + CFArrayAppendValue(result, url); + CFRelease(url); + return; + } + } +#endif + + pathLen = savedPathLen; + appendSucceeded = (pathLen + _ResourceSuffix2Len < CFMaxPathSize); + if (appendSucceeded) { + memmove(pathUniChars + pathLen, _ResourceSuffix2, _ResourceSuffix2Len * sizeof(UniChar)); + pathLen += _ResourceSuffix2Len; + } + if (appendSucceeded && typeLen > 0) appendSucceeded = _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, typeUniChars, typeLen); + if (appendSucceeded) { + CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); + CFStringReplaceAll(cheapStr, tmpString); + Boolean Found = false, IsDir = false; + Found = _CFIsResourceAtPath(cheapStr, &IsDir); + if (Found) { + CFURLRef url = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, IsDir); + CFArrayAppendValue(result, url); + CFRelease(url); + return; + } + } + +#if 0 + pathLen = savedPathLen; + appendSucceeded = (pathLen + _ResourceSuffix1Len < CFMaxPathSize); + if (appendSucceeded) { + memmove(pathUniChars + pathLen, _ResourceSuffix1, _ResourceSuffix1Len * sizeof(UniChar)); + pathLen += _ResourceSuffix1Len; + } + if (appendSucceeded && typeLen > 0) appendSucceeded = _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, typeUniChars, typeLen); + if (appendSucceeded) { + CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); + CFStringReplaceAll(cheapStr, tmpString); + Boolean Found = false, IsDir = false; + Found = _CFIsResourceAtPath(cheapStr, &IsDir); + if (Found) { + CFURLRef url = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, IsDir); + CFArrayAppendValue(result, url); + CFRelease(url); + return; + } + } +#endif + + pathLen = savedPathLen; + appendSucceeded = true; + if (appendSucceeded && typeLen > 0) appendSucceeded = _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, typeUniChars, typeLen); + if (appendSucceeded) { + CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); + CFStringReplaceAll(cheapStr, tmpString); + Boolean Found = false, IsDir = false; + Found = _CFIsResourceAtPath(cheapStr, &IsDir); + if (Found) { + CFURLRef url = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, IsDir); + CFArrayAppendValue(result, url); + CFRelease(url); + return; + } + } +} +#endif + 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 + _CFSearchBundleDirectory2(alloc, result, pathUniChars, pathLen, nameUniChars, nameLen, typeUniChars, typeLen, cheapStr, tmpString, version); +#else // pathUniChars is the full path to the directory we are searching. // nameUniChars is what we are looking for. // typeUniChars is the type we are looking for. @@ -402,14 +627,14 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, dirPathLen, dirPathLen); CFStringReplaceAll(cheapStr, tmpString); //fprintf(stderr, "looking in ");CFShow(cheapStr); - contents = _CFBundleCopyDirectoryContentsAtPath(cheapStr, _CFBundleAllContents); + contents = _CFBundleCopySortedDirectoryContentsAtPath(cheapStr, _CFBundleAllContents); contentsRange = CFRangeMake(0, CFArrayGetCount(contents)); - directoryContents = _CFBundleCopyDirectoryContentsAtPath(cheapStr, _CFBundleDirectoryContents); + directoryContents = _CFBundleCopySortedDirectoryContentsAtPath(cheapStr, _CFBundleDirectoryContents); directoryContentsRange = CFRangeMake(0, CFArrayGetCount(directoryContents)); - unknownContents = _CFBundleCopyDirectoryContentsAtPath(cheapStr, _CFBundleUnknownContents); + 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); @@ -417,9 +642,9 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res #if READ_DIRECTORIES CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + dirPathLen + 1, pathLen - dirPathLen - 1, pathLen - dirPathLen - 1); CFStringReplaceAll(cheapStr, tmpString); - platformGenericFound = CFArrayContainsValue(contents, contentsRange, cheapStr); - platformGenericIsDir = CFArrayContainsValue(directoryContents, directoryContentsRange, cheapStr); - platformGenericIsUnknown = CFArrayContainsValue(unknownContents, unknownContentsRange, cheapStr); + platformGenericFound = _CFBundleSortedArrayContains(contents, cheapStr); + platformGenericIsDir = _CFBundleSortedArrayContains(directoryContents, cheapStr); + platformGenericIsUnknown = _CFBundleSortedArrayContains(unknownContents, cheapStr); //fprintf(stderr, "looking for ");CFShow(cheapStr);if (platformGenericFound) fprintf(stderr, "found it\n"); if (platformGenericIsDir) fprintf(stderr, "a directory\n"); CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); @@ -436,7 +661,7 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res // Check for platform specific. if (platformGenericFound) { - platformGenericStr = (CFStringRef)CFStringCreateCopy(alloc, cheapStr); + platformGenericStr = (CFStringRef)CFStringCreateCopy(kCFAllocatorSystemDefault, cheapStr); if (!platformSpecificFound && (_PlatformLen > 0)) { pathLen = savedPathLen; pathUniChars[pathLen++] = (UniChar)'-'; @@ -447,9 +672,9 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res #if READ_DIRECTORIES CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + dirPathLen + 1, pathLen - dirPathLen - 1, pathLen - dirPathLen - 1); CFStringReplaceAll(cheapStr, tmpString); - platformSpecificFound = CFArrayContainsValue(contents, contentsRange, cheapStr); - platformSpecificIsDir = CFArrayContainsValue(directoryContents, directoryContentsRange, cheapStr); - platformSpecificIsUnknown = CFArrayContainsValue(unknownContents, unknownContentsRange, cheapStr); + platformSpecificFound = _CFBundleSortedArrayContains(contents, cheapStr); + platformSpecificIsDir = _CFBundleSortedArrayContains(directoryContents, cheapStr); + platformSpecificIsUnknown = _CFBundleSortedArrayContains(unknownContents, cheapStr); //fprintf(stderr, "looking for ");CFShow(cheapStr);if (platformSpecificFound) fprintf(stderr, "found it\n"); if (platformSpecificIsDir) fprintf(stderr, "a directory\n"); CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); @@ -480,9 +705,107 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res 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. + // platformUniChars is the platform name. + // predicate is a block that evaluates a given filename to see if it's a match. + // cheapStr is available for our use for whatever we want. + // URLs for found resources get added to result. + + // get the contents of the directory + CFArrayRef contents, directoryContents, unknownContents; + CFRange contentsRange; + + CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, dirPathLen, dirPathLen); + CFStringReplaceAll(cheapStr, tmpString); + + if (!_CFAppendTrailingPathSlash(pathUniChars, &dirPathLen, CFMaxPathSize)) { + return; + } + + //fprintf(stderr, "looking in ");CFShow(cheapStr); + contents = _CFBundleCopySortedDirectoryContentsAtPath(cheapStr, _CFBundleAllContents); + contentsRange = CFRangeMake(0, CFArrayGetCount(contents)); + directoryContents = _CFBundleCopySortedDirectoryContentsAtPath(cheapStr, _CFBundleDirectoryContents); + unknownContents = _CFBundleCopySortedDirectoryContentsAtPath(cheapStr, _CFBundleUnknownContents); + + // scan directory contents for matches against predicate + for (int i = 0; i < contentsRange.length; i++) { + CFStringRef candidateFilename = 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 + CFIndex candidateFilenameLength = CFStringGetLength(candidateFilename); + if ((dirPathLen + candidateFilenameLength < CFMaxPathSize)) { + CFStringGetCharacters(candidateFilename, CFRangeMake(0, candidateFilenameLength), pathUniChars + dirPathLen); + + // is there a platform specific version available? if so update pathUniChars to contain it and candidateFilenameLength to describe its length. + static const int platformSeparatorLen = 1; // the length of '-', as appears in foo-macos.tiff. sugar to make the following easier to read. + if (_PlatformLen && (dirPathLen + candidateFilenameLength + platformSeparatorLen + _PlatformLen < CFMaxPathSize)) { + CFIndex candidateFilenameWithoutExtensionLen = _CFLengthAfterDeletingPathExtension(pathUniChars + dirPathLen, candidateFilenameLength); + CFIndex extensionLen = candidateFilenameLength - candidateFilenameWithoutExtensionLen; + // shift the extension over to make space for the platform + memmove(pathUniChars + dirPathLen + candidateFilenameWithoutExtensionLen + platformSeparatorLen + _PlatformLen, pathUniChars + dirPathLen + candidateFilenameWithoutExtensionLen, extensionLen * sizeof(UniChar)); + // write the platform into the middle of the string + pathUniChars[dirPathLen + candidateFilenameWithoutExtensionLen] = (UniChar)'-'; + memcpy(pathUniChars + dirPathLen + candidateFilenameWithoutExtensionLen + platformSeparatorLen, _PlatformUniChars, _PlatformLen * sizeof(UniChar)); + // pack it up as a CFStringRef + CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + dirPathLen, candidateFilenameLength + platformSeparatorLen + _PlatformLen, candidateFilenameLength + _PlatformLen); + CFStringReplaceAll(cheapStr, tmpString); + // is the platform specialized version there? + if (_CFBundleSortedArrayContains(contents, cheapStr)) { + // woo. update the candidateFilenameLength. we'll update the candidateFilename too for consistency, but we don't actually use it again. + // the pathUniChars now contains the full path to the file + candidateFilename = cheapStr; + candidateFilenameLength = candidateFilenameLength + _PlatformLen + platformSeparatorLen; + } else { + // nope, no platform specific resource. Put the pathUniChars back how they were before, without the platform. + memmove(pathUniChars + dirPathLen + candidateFilenameWithoutExtensionLen, pathUniChars + dirPathLen + candidateFilenameWithoutExtensionLen + platformSeparatorLen + _PlatformLen, extensionLen * sizeof(UniChar)); + } + } + + // get the full path into cheapStr + CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, dirPathLen + candidateFilenameLength, dirPathLen + candidateFilenameLength); + CFStringReplaceAll(cheapStr, tmpString); + + // is the resource a directory? we need to know so that we can avoid file access when making a URL. + Boolean isDir = 0; + if (_CFBundleSortedArrayContains(directoryContents, cheapStr)) { + isDir = 1; + } else if (_CFBundleSortedArrayContains(unknownContents, cheapStr)) { + _CFIsResourceAtPath(cheapStr, &isDir); + } + + CFURLRef url = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, isDir); + CFArrayAppendValue(result, url); + CFRelease(url); + } + } + + if (*stopLooking) break; + } + + CFRelease(contents); + CFRelease(directoryContents); + CFRelease(unknownContents); } +#endif -static void _CFFindBundleResourcesInRawDir(CFAllocatorRef alloc, UniChar *workingUniChars, CFIndex workingLen, UniChar *nameUniChars, CFIndex nameLen, CFArrayRef resTypes, CFIndex limit, uint8_t version, CFMutableStringRef cheapStr, CFMutableStringRef tmpString, CFMutableArrayRef result) { +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. if (!resTypes) { @@ -546,38 +869,35 @@ 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, uint8_t version, CFMutableStringRef cheapStr, CFMutableStringRef tmpString, CFMutableArrayRef result) { +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 // Look directly in the directory specified in workingUniChars. as if it is a Resources directory. if (1 == version) { // Add the non-localized resource directory. Boolean appendSucceeded = _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _GlobalResourcesUniChars, _GlobalResourcesLen); if (appendSucceeded && subDirLen > 0) appendSucceeded = _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, subDirUniChars, subDirLen); - if (appendSucceeded) _CFFindBundleResourcesInRawDir(alloc, workingUniChars, workingLen, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result); + if (appendSucceeded) _CFFindBundleResourcesInRawDir(alloc, workingUniChars, workingLen, nameUniChars, nameLen, resTypes, limit, &stopLooking, predicate, version, cheapStr, tmpString, result); // Strip the non-localized resource directory. workingLen = savedWorkingLen; } - if (CFArrayGetCount(result) < limit) { + 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, version, cheapStr, tmpString, result); + if (appendSucceeded) _CFFindBundleResourcesInRawDir(alloc, workingUniChars, workingLen, nameUniChars, nameLen, resTypes, limit, &stopLooking, predicate, version, cheapStr, tmpString, result); } // Now search the local resources. workingLen = savedWorkingLen; - if (CFArrayGetCount(result) < limit) { - CFIndex langIndex; + if (CFArrayGetCount(result) < limit && !stopLooking) { CFIndex langCount = (searchLanguages ? CFArrayGetCount(searchLanguages) : 0); - CFStringRef curLangStr; - CFIndex curLangLen; // MF:??? OK to hard-wire this length? UniChar curLangUniChars[255]; CFIndex numResults = CFArrayGetCount(result); - for (langIndex = 0; langIndex < langCount; langIndex++) { - curLangStr = (CFStringRef)CFArrayGetValueAtIndex(searchLanguages, langIndex); - curLangLen = CFStringGetLength(curLangStr); + for (CFIndex langIndex = 0; langIndex < langCount; langIndex++) { + CFStringRef curLangStr = (CFStringRef)CFArrayGetValueAtIndex(searchLanguages, langIndex); + CFIndex curLangLen = CFStringGetLength(curLangStr); if (curLangLen > 255) curLangLen = 255; CFStringGetCharacters(curLangStr, CFRangeMake(0, curLangLen), curLangUniChars); savedWorkingLen = workingLen; @@ -595,7 +915,7 @@ static void _CFFindBundleResourcesInResourcesDir(CFAllocatorRef alloc, UniChar * continue; } } - _CFFindBundleResourcesInRawDir(alloc, workingUniChars, workingLen, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result); + _CFFindBundleResourcesInRawDir(alloc, workingUniChars, workingLen, nameUniChars, nameLen, resTypes, limit, &stopLooking, predicate, version, cheapStr, tmpString, result); // Back off this lproj component workingLen = savedWorkingLen; @@ -610,22 +930,32 @@ 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, uint8_t version) { - CFAllocatorRef alloc = (bundle ? CFGetAllocator(bundle) : (CFAllocatorRef)CFRetain(__CFGetDefaultAllocator())); - CFMutableArrayRef result; +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); + + // Build an absolute path to the base directory. + // If no URL was passed, we get it from the bundle. + CFURLRef baseURL = bundleURL ? (CFURLRef)CFRetain(bundleURL) : (bundle ? CFBundleCopyBundleURL(bundle) : NULL); + CFURLRef absoluteURL = baseURL ? CFURLCopyAbsoluteURL(baseURL) : NULL; + CFStringRef basePath = absoluteURL ? CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE) : NULL; + if (absoluteURL) CFRelease(absoluteURL); + if (baseURL) CFRelease(baseURL); + baseURL = absoluteURL = bundleURL = NULL; + bundle = NULL; + // bundle and bundleURL arguments are not used any further + + if (!basePath) return result; + + UniChar *workingUniChars, *nameUniChars, *subDirUniChars; CFIndex nameLen = 0; - CFIndex subDirLen = (subDirName ? CFStringGetLength(subDirName) : 0); CFIndex workingLen, savedWorkingLen; - CFURLRef absoluteURL; - CFStringRef bundlePath; CFMutableStringRef cheapStr, tmpString; - char buff[CFMaxPathSize]; - result = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks); if (resName) { + char buff[CFMaxPathSize]; CFStringRef newResName = NULL; - if (CFStringGetFileSystemRepresentation(resName, buff, CFMaxPathSize)) newResName = CFStringCreateWithFileSystemRepresentation(alloc, buff); + if (CFStringGetFileSystemRepresentation(resName, buff, CFMaxPathSize)) newResName = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, buff); resName = newResName ? newResName : (CFStringRef)CFRetain(resName); nameLen = CFStringGetLength(resName); } @@ -634,20 +964,16 @@ CFArrayRef _CFFindBundleResources(CFBundleRef bundle, CFURLRef bundleURL, CFStri _CFEnsureStaticBuffersInited(); // Build UniChar buffers for some of the string pieces we need. - // One malloc will do. - nameUniChars = (UniChar *)CFAllocatorAllocate(alloc, sizeof(UniChar) * (nameLen + subDirLen + CFMaxPathSize), 0); + CFIndex subDirLen = (subDirName ? CFStringGetLength(subDirName) : 0); + nameUniChars = (UniChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UniChar) * (nameLen + subDirLen + CFMaxPathSize), 0); if (nameUniChars) { subDirUniChars = nameUniChars + nameLen; workingUniChars = subDirUniChars + subDirLen; if (nameLen > 0) CFStringGetCharacters(resName, CFRangeMake(0, nameLen), nameUniChars); if (subDirLen > 0) CFStringGetCharacters(subDirName, CFRangeMake(0, subDirLen), subDirUniChars); - // Build a UniChar buffer with the absolute path to the bundle's resources directory. - // If no URL was passed, we get it from the bundle. - bundleURL = (bundleURL ? (CFURLRef)CFRetain(bundleURL) : CFBundleCopyBundleURL(bundle)); - absoluteURL = CFURLCopyAbsoluteURL(bundleURL); - bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); - if ((workingLen = CFStringGetLength(bundlePath)) > 0) CFStringGetCharacters(bundlePath, CFRangeMake(0, workingLen), workingUniChars); + + if ((workingLen = CFStringGetLength(basePath)) > 0) CFStringGetCharacters(basePath, CFRangeMake(0, workingLen), workingUniChars); savedWorkingLen = workingLen; if (1 == version) { _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _AppSupportUniChars1, _AppSupportLen1); @@ -657,36 +983,35 @@ CFArrayRef _CFFindBundleResources(CFBundleRef bundle, CFURLRef bundleURL, CFStri if (0 == version || 1 == version || 2 == version) _CFAppendPathComponent(workingUniChars, &workingLen, CFMaxPathSize, _ResourcesUniChars, _ResourcesLen); // both of these used for temp string operations, for slightly different purposes, where each type is appropriate - cheapStr = CFStringCreateMutable(alloc, 0); + cheapStr = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); _CFStrSetDesiredCapacity(cheapStr, CFMaxPathSize); tmpString = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, kCFAllocatorNull); - _CFFindBundleResourcesInResourcesDir(alloc, workingUniChars, workingLen, subDirUniChars, subDirLen, searchLanguages, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result); + _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 && bundlePath && CFEqual(CFSTR("/Library/Spotlight"), bundlePath)))) { + if (CFArrayGetCount(result) == 0 && (0 == version || (2 == version && CFEqual(CFSTR("/Library/Spotlight"), basePath)))) { // Try looking directly in the bundle path workingLen = savedWorkingLen; - _CFFindBundleResourcesInResourcesDir(alloc, workingUniChars, workingLen, subDirUniChars, subDirLen, searchLanguages, nameUniChars, nameLen, resTypes, limit, version, cheapStr, tmpString, result); + _CFFindBundleResourcesInResourcesDir(kCFAllocatorSystemDefault, workingUniChars, workingLen, subDirUniChars, subDirLen, searchLanguages, nameUniChars, nameLen, resTypes, limit, predicate, version, cheapStr, tmpString, result); } - CFRelease(absoluteURL); - CFRelease(bundlePath); - CFRelease(bundleURL); CFRelease(cheapStr); CFRelease(tmpString); - CFAllocatorDeallocate(alloc, nameUniChars); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, nameUniChars); } if (resName) CFRelease(resName); - if (!bundle) CFRelease(alloc); + if (basePath) CFRelease(basePath); return result; } CF_EXPORT CFURLRef CFBundleCopyResourceURL(CFBundleRef bundle, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName) { + if (!bundle) + return NULL; CFURLRef result = NULL; CFArrayRef languages = _CFBundleGetLanguageSearchList(bundle), types = NULL, array; - if (resourceType) types = CFArrayCreate(CFGetAllocator(bundle), (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); - array = _CFFindBundleResources(bundle, NULL, subDirName, languages, resourceName, types, 1, _CFBundleLayoutVersion(bundle)); + if (resourceType) types = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); + array = _CFFindBundleResources(bundle, NULL, subDirName, languages, resourceName, types, 1, NULL, _CFBundleLayoutVersion(bundle)); if (types) CFRelease(types); if (array) { if (CFArrayGetCount(array) > 0) result = (CFURLRef)CFRetain(CFArrayGetValueAtIndex(array, 0)); @@ -697,9 +1022,9 @@ CF_EXPORT CFURLRef CFBundleCopyResourceURL(CFBundleRef bundle, CFStringRef resou CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfType(CFBundleRef bundle, CFStringRef resourceType, CFStringRef subDirName) { CFArrayRef languages = _CFBundleGetLanguageSearchList(bundle), types = NULL, array; - if (resourceType) types = CFArrayCreate(CFGetAllocator(bundle), (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); + if (resourceType) types = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); // MF:!!! Better "limit" than 1,000,000? - array = _CFFindBundleResources(bundle, NULL, subDirName, languages, NULL, types, 1000000, _CFBundleLayoutVersion(bundle)); + array = _CFFindBundleResources(bundle, NULL, subDirName, languages, NULL, types, 1000000, NULL, _CFBundleLayoutVersion(bundle)); if (types) CFRelease(types); return array; @@ -713,9 +1038,9 @@ CF_EXPORT CFURLRef CFBundleCopyResourceURLForLocalization(CFBundleRef bundle, CF CFURLRef result = NULL; CFArrayRef languages = NULL, types = NULL, array; - if (localizationName) languages = CFArrayCreate(CFGetAllocator(bundle), (const void **)&localizationName, 1, &kCFTypeArrayCallBacks); - if (resourceType) types = CFArrayCreate(CFGetAllocator(bundle), (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); - array = _CFFindBundleResources(bundle, NULL, subDirName, languages, resourceName, types, 1, _CFBundleLayoutVersion(bundle)); + if (localizationName) languages = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&localizationName, 1, &kCFTypeArrayCallBacks); + if (resourceType) types = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); + array = _CFFindBundleResources(bundle, NULL, subDirName, languages, resourceName, types, 1, NULL, _CFBundleLayoutVersion(bundle)); if (array) { if (CFArrayGetCount(array) > 0) result = (CFURLRef)CFRetain(CFArrayGetValueAtIndex(array, 0)); CFRelease(array); @@ -732,15 +1057,16 @@ CF_EXPORT CFArrayRef _CFBundleCopyResourceURLsOfTypeForLanguage(CFBundleRef bund CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfTypeForLocalization(CFBundleRef bundle, CFStringRef resourceType, CFStringRef subDirName, CFStringRef localizationName) { CFArrayRef languages = NULL, types = NULL, array; - if (localizationName) languages = CFArrayCreate(CFGetAllocator(bundle), (const void **)&localizationName, 1, &kCFTypeArrayCallBacks); - if (resourceType) types = CFArrayCreate(CFGetAllocator(bundle), (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); + if (localizationName) languages = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&localizationName, 1, &kCFTypeArrayCallBacks); + if (resourceType) types = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); // MF:!!! Better "limit" than 1,000,000? - array = _CFFindBundleResources(bundle, NULL, subDirName, languages, NULL, types, 1000000, _CFBundleLayoutVersion(bundle)); + array = _CFFindBundleResources(bundle, NULL, subDirName, languages, NULL, types, 1000000, NULL, _CFBundleLayoutVersion(bundle)); if (types) CFRelease(types); if (languages) CFRelease(languages); return array; } + CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName) { CFStringRef result = NULL; CFDictionaryRef stringTable = NULL; @@ -766,7 +1092,7 @@ CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRe CFDataRef tableData = NULL; SInt32 errCode; CFStringRef errStr; - if (CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(bundle), tableURL, &tableData, NULL, NULL, &errCode)) { + if (CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, tableURL, &tableData, NULL, NULL, &errCode)) { stringTable = (CFDictionaryRef)CFPropertyListCreateFromXMLData(CFGetAllocator(bundle), tableData, kCFPropertyListImmutable, &errStr); if (errStr) { CFRelease(errStr); @@ -777,10 +1103,11 @@ CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRe stringTable = NULL; } CFRelease(tableData); + } } if (nameForSharing) CFRelease(nameForSharing); - CFRelease(tableURL); + if (tableURL) CFRelease(tableURL); } if (!stringTable) stringTable = CFDictionaryCreate(CFGetAllocator(bundle), NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); @@ -804,7 +1131,7 @@ CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRe } if (capitalize != 0) { if (capitalize != 0) { - CFMutableStringRef capitalizedResult = CFStringCreateMutableCopy(CFGetAllocator(bundle), 0, result); + 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); @@ -831,7 +1158,7 @@ CF_EXPORT CFURLRef CFBundleCopyResourceURLInDirectory(CFURLRef bundleURL, CFStri uint8_t version = 0; CFArrayRef languages = _CFBundleCopyLanguageSearchListInDirectory(kCFAllocatorSystemDefault, newURL, &version), types = NULL, array; if (resourceType) types = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); - array = _CFFindBundleResources(NULL, newURL, subDirName, languages, resourceName, types, 1, version); + array = _CFFindBundleResources(NULL, newURL, subDirName, languages, resourceName, types, 1, NULL, version); if (types) CFRelease(types); if (languages) CFRelease(languages); if (array) { @@ -857,7 +1184,7 @@ CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfTypeInDirectory(CFURLRef bundleUR CFArrayRef languages = _CFBundleCopyLanguageSearchListInDirectory(kCFAllocatorSystemDefault, newURL, &version), types = NULL; if (resourceType) types = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); // MF:!!! Better "limit" than 1,000,000? - array = _CFFindBundleResources(NULL, newURL, subDirName, languages, NULL, types, 1000000, version); + array = _CFFindBundleResources(NULL, newURL, subDirName, languages, NULL, types, 1000000, NULL, version); if (types) CFRelease(types); if (languages) CFRelease(languages); } @@ -1333,14 +1660,14 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc // both of these used for temp string operations, for slightly // different purposes, where each type is appropriate - cheapStr = CFStringCreateMutable(alloc, 0); + cheapStr = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); _CFStrSetDesiredCapacity(cheapStr, CFMaxPathSize); tmpString = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, kCFAllocatorNull); #if READ_DIRECTORIES CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); - contents = _CFBundleCopyDirectoryContentsAtPath(cheapStr, _CFBundleAllContents); + contents = _CFBundleCopySortedDirectoryContentsAtPath(cheapStr, _CFBundleAllContents); contentsRange = CFRangeMake(0, CFArrayGetCount(contents)); #endif /* READ_DIRECTORIES */ @@ -1360,7 +1687,7 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc #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 && CFArrayContainsValue(contents, contentsRange, cheapStr))) { + if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, curLangStr)) || (version != 4 && _CFBundleSortedArrayContains(contents, cheapStr))) { #else /* READ_DIRECTORIES */ CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); @@ -1404,7 +1731,7 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc #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 && CFArrayContainsValue(contents, contentsRange, cheapStr))) { + if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, altLangStr)) || (version != 4 && _CFBundleSortedArrayContains(contents, cheapStr))) { #else /* READ_DIRECTORIES */ CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); @@ -1446,7 +1773,7 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc #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 && CFArrayContainsValue(contents, contentsRange, cheapStr))) { + if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, modifiedLangStr)) || (version != 4 && _CFBundleSortedArrayContains(contents, cheapStr))) { #else /* READ_DIRECTORIES */ CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); @@ -1466,7 +1793,7 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc #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 && CFArrayContainsValue(contents, contentsRange, cheapStr))) { + if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageAbbreviation)) || (version != 4 && _CFBundleSortedArrayContains(contents, cheapStr))) { #else /* READ_DIRECTORIES */ CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); @@ -1486,7 +1813,7 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc #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 && CFArrayContainsValue(contents, contentsRange, cheapStr))) { + if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageName)) || (version != 4 && _CFBundleSortedArrayContains(contents, cheapStr))) { #else /* READ_DIRECTORIES */ CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); @@ -1555,7 +1882,7 @@ __private_extern__ void _CFBundleAddPreferredLprojNamesInDirectory(CFAllocatorRe // This function will add zero, one or two elements to the lprojNames array. // It examines the users preferred language list and the lproj directories inside the bundle directory. It picks the lproj directory that is highest on the users list. // The users list can contain region names (like "en_US" for US English). In this case, if the region lproj exists, it will be added, and, if the region's associated language lproj exists that will be added. - CFURLRef resourcesURL = _CFBundleCopyResourcesDirectoryURLInDirectory(alloc, bundleURL, version); + CFURLRef resourcesURL = _CFBundleCopyResourcesDirectoryURLInDirectory(bundleURL, version); CFURLRef absoluteURL; CFIndex idx, startIdx; CFIndex count; @@ -1590,7 +1917,7 @@ __private_extern__ void _CFBundleAddPreferredLprojNamesInDirectory(CFAllocatorRe CFArrayRef mainBundleLangs = _CFBundleGetLanguageSearchList(mainBundle); if (mainBundleLangs && (CFArrayGetCount(mainBundleLangs) > 0)) { curLangStr = (CFStringRef)CFArrayGetValueAtIndex(mainBundleLangs, 0); - foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames, true); + foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(kCFAllocatorSystemDefault, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames, true); } } CFRelease(mainBundleURL); @@ -1606,23 +1933,23 @@ __private_extern__ void _CFBundleAddPreferredLprojNamesInDirectory(CFAllocatorRe curLangStr = (CFStringRef)CFArrayGetValueAtIndex(userLanguages, idx); nextLangStr = (idx + 1 < count) ? (CFStringRef)CFArrayGetValueAtIndex(userLanguages, idx + 1) : NULL; if (nextLangStr && _CFBundleLocalizationsHaveCommonPrefix(curLangStr, nextLangStr)) { - foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames, false); + foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(kCFAllocatorSystemDefault, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames, false); if (startIdx < 0) startIdx = idx; } else if (startIdx >= 0 && startIdx <= idx) { - foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames, false); + foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(kCFAllocatorSystemDefault, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames, false); for (; !foundOne && startIdx <= idx; startIdx++) { curLangStr = (CFStringRef)CFArrayGetValueAtIndex(userLanguages, startIdx); - foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames, true); + foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(kCFAllocatorSystemDefault, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames, true); } startIdx = -1; } else { - foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames, true); + foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(kCFAllocatorSystemDefault, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames, true); startIdx = -1; } } // use development region and U.S. English as backstops - if (!foundOne && devLang) foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, devLang, lprojNames, true); - if (!foundOne) foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, CFSTR("en_US"), lprojNames, true); + if (!foundOne && devLang) foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(kCFAllocatorSystemDefault, pathUniChars, pathLen, version, infoDict, devLang, lprojNames, true); + if (!foundOne) foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(kCFAllocatorSystemDefault, pathUniChars, pathLen, version, infoDict, CFSTR("en_US"), lprojNames, true); if (userLanguages) CFRelease(userLanguages); } } @@ -1747,7 +2074,7 @@ CF_EXPORT CFArrayRef CFBundleCopyPreferredLocalizationsFromArray(CFArrayRef locA __private_extern__ CFArrayRef _CFBundleCopyLanguageSearchListInDirectory(CFAllocatorRef alloc, CFURLRef url, uint8_t *version) { CFMutableArrayRef langs = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks); uint8_t localVersion = 0; - CFDictionaryRef infoDict = _CFBundleCopyInfoDictionaryInDirectory(alloc, url, &localVersion); + CFDictionaryRef infoDict = _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefaultGCRefZero, url, &localVersion); CFStringRef devLang = NULL; if (infoDict) devLang = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey); if (devLang && (CFGetTypeID(devLang) != CFStringGetTypeID() || CFStringGetLength(devLang) == 0)) devLang = NULL; @@ -1759,7 +2086,7 @@ __private_extern__ CFArrayRef _CFBundleCopyLanguageSearchListInDirectory(CFAlloc // Total backstop behavior to avoid having an empty array. if (CFArrayGetCount(langs) == 0) CFArrayAppendValue(langs, CFSTR("en")); - if (infoDict) CFRelease(infoDict); + if (infoDict && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(infoDict); if (version) *version = localVersion; return langs; } @@ -1797,16 +2124,15 @@ __private_extern__ Boolean _CFBundleURLLooksLikeBundleVersion(CFURLRef url, uint #if READ_DIRECTORIES CFURLRef absoluteURL = CFURLCopyAbsoluteURL(url); CFStringRef directoryPath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); - CFArrayRef contents = _CFBundleCopyDirectoryContentsAtPath(directoryPath, _CFBundleAllContents); - CFRange contentsRange = CFRangeMake(0, CFArrayGetCount(contents)); + CFArrayRef contents = _CFBundleCopySortedDirectoryContentsAtPath(directoryPath, _CFBundleAllContents); if (CFStringHasSuffix(CFURLGetString(url), CFSTR(".framework/"))) { - if (CFArrayContainsValue(contents, contentsRange, _CFBundleResourcesDirectoryName)) localVersion = 0; - else if (CFArrayContainsValue(contents, contentsRange, _CFBundleSupportFilesDirectoryName2)) localVersion = 2; - else if (CFArrayContainsValue(contents, contentsRange, _CFBundleSupportFilesDirectoryName1)) localVersion = 1; + if (_CFBundleSortedArrayContains(contents, _CFBundleResourcesDirectoryName)) localVersion = 0; + else if (_CFBundleSortedArrayContains(contents, _CFBundleSupportFilesDirectoryName2)) localVersion = 2; + else if (_CFBundleSortedArrayContains(contents, _CFBundleSupportFilesDirectoryName1)) localVersion = 1; } else { - if (CFArrayContainsValue(contents, contentsRange, _CFBundleSupportFilesDirectoryName2)) localVersion = 2; - else if (CFArrayContainsValue(contents, contentsRange, _CFBundleResourcesDirectoryName)) localVersion = 0; - else if (CFArrayContainsValue(contents, contentsRange, _CFBundleSupportFilesDirectoryName1)) localVersion = 1; + if (_CFBundleSortedArrayContains(contents, _CFBundleSupportFilesDirectoryName2)) localVersion = 2; + else if (_CFBundleSortedArrayContains(contents, _CFBundleResourcesDirectoryName)) localVersion = 0; + else if (_CFBundleSortedArrayContains(contents, _CFBundleSupportFilesDirectoryName1)) localVersion = 1; } CFRelease(contents); CFRelease(directoryPath); @@ -1814,8 +2140,12 @@ __private_extern__ Boolean _CFBundleURLLooksLikeBundleVersion(CFURLRef url, uint #endif /* READ_DIRECTORIES */ if (localVersion == 3) { #if DEPLOYMENT_TARGET_EMBEDDED -#elif DEPLOYMENT_TARGET_MACOSX +#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 (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) localVersion = 0; else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase2)) localVersion = 2; else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase1)) localVersion = 1; @@ -1824,31 +2154,239 @@ __private_extern__ Boolean _CFBundleURLLooksLikeBundleVersion(CFURLRef url, uint else if (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) localVersion = 0; else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase1)) localVersion = 1; } -#elif DEPLOYMENT_TARGET_WINDOWS - if (CFStringHasSuffix(CFURLGetString(url), CFSTR(".framework\\"))) { - if (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) localVersion = 0; - else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase2)) localVersion = 2; - else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase1)) localVersion = 1; - } else { - if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase2)) localVersion = 2; - else if (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) localVersion = 0; - else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase1)) localVersion = 1; - } -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif } if (version) *version = localVersion; return (localVersion != 3); } +static Boolean _isValidPlatformSuffix(CFStringRef suffix) { + for (CFIndex idx = 0; idx < _CFBundleNumberOfPlatforms; idx++) { + if (CFEqual(suffix, _CFBundleSupportedPlatforms[idx])) return true; + } + return false; +} + +static Boolean _isValidProductSuffix(CFStringRef suffix) { + for (CFIndex idx = 0; idx < _CFBundleNumberOfProducts; idx++) { + if (CFEqual(suffix, _CFBundleSupportedProducts[idx])) return true; + } + return false; +} + +static Boolean _isValidiPhoneOSPlatformProductSuffix(CFStringRef suffix) { + for (CFIndex idx = 0; idx < _CFBundleNumberOfiPhoneOSPlatformProducts; idx++) { + if (CFEqual(suffix, _CFBundleSupportediPhoneOSPlatformProducts[idx])) return true; + } + return false; +} + +static Boolean _isValidPlatformAndProductSuffixPair(CFStringRef platform, CFStringRef product) { + if (!platform && !product) return true; + if (!platform) { + return _isValidProductSuffix(product); + } + if (!product) { + return _isValidPlatformSuffix(platform); + } + if (CFEqual(platform, _CFBundleiPhoneOSPlatformName)) { + return _isValidiPhoneOSPlatformProductSuffix(product); + } + return false; +} + +static Boolean _isBlacklistedKey(CFStringRef keyName) { +#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; + } + return false; +} + +static Boolean _isOverrideKey(CFStringRef fullKey, CFStringRef *outBaseKey, CFStringRef *outPlatformSuffix, CFStringRef *outProductSuffix) { + if (outBaseKey) { + *outBaseKey = NULL; + } + if (outPlatformSuffix) { + *outPlatformSuffix = NULL; + } + if (outProductSuffix) { + *outProductSuffix = NULL; + } + if (!fullKey) + return false; + CFRange minusRange = CFStringFind(fullKey, CFSTR("-"), kCFCompareBackwards); + CFRange tildeRange = CFStringFind(fullKey, CFSTR("~"), kCFCompareBackwards); + if (minusRange.location == kCFNotFound && tildeRange.location == kCFNotFound) return false; + // minus must come before tilde if both are present + if (minusRange.location != kCFNotFound && tildeRange.location != kCFNotFound && tildeRange.location <= minusRange.location) return false; + + CFIndex strLen = CFStringGetLength(fullKey); + CFRange baseKeyRange = (minusRange.location != kCFNotFound) ? CFRangeMake(0, minusRange.location) : CFRangeMake(0, tildeRange.location); + CFRange platformRange = CFRangeMake(kCFNotFound, 0); + CFRange productRange = CFRangeMake(kCFNotFound, 0); + if (minusRange.location != kCFNotFound) { + platformRange.location = minusRange.location + minusRange.length; + platformRange.length = ((tildeRange.location != kCFNotFound) ? tildeRange.location : strLen) - platformRange.location; + } + if (tildeRange.location != kCFNotFound) { + productRange.location = tildeRange.location + tildeRange.length; + productRange.length = strLen - productRange.location; + } + if (baseKeyRange.length < 1) return false; + if (platformRange.location != kCFNotFound && platformRange.length < 1) return false; + if (productRange.location != kCFNotFound && productRange.length < 1) return false; + + CFStringRef platform = (platformRange.location != kCFNotFound) ? CFStringCreateWithSubstring(kCFAllocatorSystemDefaultGCRefZero, fullKey, platformRange) : NULL; + CFStringRef product = (productRange.location != kCFNotFound) ? CFStringCreateWithSubstring(kCFAllocatorSystemDefaultGCRefZero, fullKey, productRange) : NULL; + Boolean result = _isValidPlatformAndProductSuffixPair(platform, product); + + if (result) { + if (outBaseKey) { + *outBaseKey = CFStringCreateWithSubstring(kCFAllocatorSystemDefaultGCRefZero, fullKey, baseKeyRange); + } + if (outPlatformSuffix) { + *outPlatformSuffix = platform; + } else { + if (platform && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(platform); + } + if (outProductSuffix) { + *outProductSuffix = product; + } else { + if (product && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(product); + } + } else { + if (platform && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(platform); + if (product && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(product); + } + return result; +} + +static Boolean _isCurrentPlatformAndProduct(CFStringRef platform, CFStringRef product) { + if (!platform && !product) return true; + if (!platform) { + return CFEqual(_CFGetProductName(), product); + } + if (!product) { + return CFEqual(_CFGetPlatformName(), platform); + } + + return CFEqual(_CFGetProductName(), product) && CFEqual(_CFGetPlatformName(), platform); +} + +static CFArrayRef _CopySortedOverridesForBaseKey(CFStringRef keyName, CFDictionaryRef dict) { + CFMutableArrayRef overrides = CFArrayCreateMutable(kCFAllocatorSystemDefaultGCRefZero, 0, &kCFTypeArrayCallBacks); + CFStringRef keyNameWithBoth = CFStringCreateWithFormat(kCFAllocatorSystemDefaultGCRefZero, NULL, CFSTR("%@-%@~%@"), keyName, _CFGetPlatformName(), _CFGetProductName()); + CFStringRef keyNameWithProduct = CFStringCreateWithFormat(kCFAllocatorSystemDefaultGCRefZero, NULL, CFSTR("%@~%@"), keyName, _CFGetProductName()); + CFStringRef keyNameWithPlatform = CFStringCreateWithFormat(kCFAllocatorSystemDefaultGCRefZero, NULL, CFSTR("%@-%@"), keyName, _CFGetPlatformName()); + + CFIndex count = CFDictionaryGetCount(dict); + + if (count > 0) { + CFTypeRef *keys = (CFTypeRef *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, 2 * count * sizeof(CFTypeRef), 0); + CFTypeRef *values = &(keys[count]); + + CFDictionaryGetKeysAndValues(dict, keys, values); + for (CFIndex idx = 0; idx < count; idx++) { + if (CFEqual(keys[idx], keyNameWithBoth)) { + CFArrayAppendValue(overrides, keys[idx]); + break; + } + } + for (CFIndex idx = 0; idx < count; idx++) { + if (CFEqual(keys[idx], keyNameWithProduct)) { + CFArrayAppendValue(overrides, keys[idx]); + break; + } + } + for (CFIndex idx = 0; idx < count; idx++) { + if (CFEqual(keys[idx], keyNameWithPlatform)) { + CFArrayAppendValue(overrides, keys[idx]); + break; + } + } + for (CFIndex idx = 0; idx < count; idx++) { + if (CFEqual(keys[idx], keyName)) { + CFArrayAppendValue(overrides, keys[idx]); + break; + } + } + + if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) { + CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, keys); + } + } + + if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) { + CFRelease(keyNameWithProduct); + CFRelease(keyNameWithPlatform); + CFRelease(keyNameWithBoth); + } + + return overrides; +} + +__private_extern__ void _processInfoDictionary(CFMutableDictionaryRef dict, CFStringRef platformSuffix, CFStringRef productSuffix) { + CFIndex count = CFDictionaryGetCount(dict); + + if (count > 0) { + CFTypeRef *keys = (CFTypeRef *)CFAllocatorAllocate(kCFAllocatorSystemDefaultGCRefZero, 2 * count * sizeof(CFTypeRef), 0); + CFTypeRef *values = &(keys[count]); + CFMutableArrayRef guard = CFArrayCreateMutable(kCFAllocatorSystemDefaultGCRefZero, 0, &kCFTypeArrayCallBacks); + + CFDictionaryGetKeysAndValues(dict, keys, values); + for (CFIndex idx = 0; idx < count; idx++) { + CFStringRef keyPlatformSuffix, keyProductSuffix, keyName; + if (_isOverrideKey((CFStringRef)keys[idx], &keyName, &keyPlatformSuffix, &keyProductSuffix)) { + CFArrayRef keysForBaseKey = NULL; + if (_isCurrentPlatformAndProduct(keyPlatformSuffix, keyProductSuffix) && !_isBlacklistedKey(keyName) && CFDictionaryContainsKey(dict, keys[idx])) { + keysForBaseKey = _CopySortedOverridesForBaseKey(keyName, dict); + CFIndex keysForBaseKeyCount = CFArrayGetCount(keysForBaseKey); + + //make sure the other keys for this base key don't get released out from under us until we're done + CFArrayAppendValue(guard, keysForBaseKey); + + //the winner for this base key will be sorted to the front, do the override with it + CFTypeRef highestPriorityKey = CFArrayGetValueAtIndex(keysForBaseKey, 0); + CFDictionarySetValue(dict, keyName, CFDictionaryGetValue(dict, highestPriorityKey)); + + //remove everything except the now-overridden key; this will cause them to fail the CFDictionaryContainsKey(dict, keys[idx]) check in the enclosing if() and not be reprocessed + for (CFIndex presentKeysIdx = 0; presentKeysIdx < keysForBaseKeyCount; presentKeysIdx++) { + CFStringRef currentKey = (CFStringRef)CFArrayGetValueAtIndex(keysForBaseKey, presentKeysIdx); + if (!CFEqual(currentKey, keyName)) + CFDictionaryRemoveValue(dict, currentKey); + } + } else { + CFDictionaryRemoveValue(dict, keys[idx]); + } + + + if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) { + if (keyPlatformSuffix) CFRelease(keyPlatformSuffix); + if (keyProductSuffix) CFRelease(keyProductSuffix); + CFRelease(keyName); + if (keysForBaseKey) CFRelease(keysForBaseKey); + } + } + } + + if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) { + CFAllocatorDeallocate(kCFAllocatorSystemDefaultGCRefZero, keys); + CFRelease(guard); + } + } +} + +// returns zero-ref dictionary under GC if given kCFAllocatorSystemDefaultGCRefZero __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectory(CFAllocatorRef alloc, CFURLRef url, uint8_t *version) { CFDictionaryRef dict = NULL; unsigned char buff[CFMaxPathSize]; uint8_t localVersion = 0; if (CFURLGetFileSystemRepresentation(url, true, buff, CFMaxPathSize)) { - CFURLRef newURL = CFURLCreateFromFileSystemRepresentation(alloc, buff, strlen((char *)buff), true); + CFURLRef newURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, buff, strlen((char *)buff), true); if (!newURL) newURL = (CFURLRef)CFRetain(url); // version 3 is for flattened pseudo-bundles with no Contents, Support Files, or Resources directories @@ -1861,6 +2399,7 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectory(CFAllo return dict; } +// returns zero-ref dictionary under GC if given kCFAllocatorSystemDefaultGCRefZero __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFAllocatorRef alloc, CFURLRef url, uint8_t version) { CFDictionaryRef result = NULL; if (url) { @@ -1882,19 +2421,19 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer if (0 == version) { #if READ_DIRECTORIES - directoryURL = CFURLCreateWithString(alloc, _CFBundleResourcesURLFromBase0, url); + directoryURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleResourcesURLFromBase0, url); #endif /* READ_DIRECTORIES */ infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension0; infoURLFromBase = _CFBundleInfoURLFromBase0; } else if (1 == version) { #if READ_DIRECTORIES - directoryURL = CFURLCreateWithString(alloc, _CFBundleSupportFilesURLFromBase1, url); + directoryURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleSupportFilesURLFromBase1, url); #endif /* READ_DIRECTORIES */ infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension1; infoURLFromBase = _CFBundleInfoURLFromBase1; } else if (2 == version) { #if READ_DIRECTORIES - directoryURL = CFURLCreateWithString(alloc, _CFBundleSupportFilesURLFromBase2, url); + directoryURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundleSupportFilesURLFromBase2, url); #endif /* READ_DIRECTORIES */ infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension2; infoURLFromBase = _CFBundleInfoURLFromBase2; @@ -1916,7 +2455,7 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer if (directoryURL) { absoluteURL = CFURLCopyAbsoluteURL(directoryURL); directoryPath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); - contents = _CFBundleCopyDirectoryContentsAtPath(directoryPath, _CFBundleAllContents); + contents = _CFBundleCopySortedDirectoryContentsAtPath(directoryPath, _CFBundleAllContents); contentsRange = CFRangeMake(0, CFArrayGetCount(contents)); CFRelease(directoryPath); CFRelease(absoluteURL); @@ -1930,9 +2469,9 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer memmove(buff + len, _PlatformUniChars, _PlatformLen * sizeof(UniChar)); len += _PlatformLen; _CFAppendPathExtension(buff, &len, CFMaxPathSize, _InfoExtensionUniChars, _InfoExtensionLen); - cheapStr = CFStringCreateMutable(alloc, 0); + cheapStr = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); CFStringAppendCharacters(cheapStr, buff, len); - infoURL = CFURLCreateWithString(alloc, cheapStr, url); + infoURL = CFURLCreateWithString(kCFAllocatorSystemDefault, cheapStr, url); #if READ_DIRECTORIES if (contents) { CFIndex resourcesLen, idx; @@ -1945,13 +2484,13 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer } } #endif /* READ_DIRECTORIES */ - if (tryPlatformSpecific) CFURLCreateDataAndPropertiesFromResource(alloc, infoURL, &infoData, NULL, NULL, NULL); + 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); if (!infoData) { // Check for global Info.plist CFRelease(infoURL); - infoURL = CFURLCreateWithString(alloc, infoURLFromBase, url); + infoURL = CFURLCreateWithString(kCFAllocatorSystemDefault, infoURLFromBase, url); #if READ_DIRECTORIES if (contents) { CFIndex idx; @@ -1961,7 +2500,7 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer } } #endif /* READ_DIRECTORIES */ - if (tryGlobal) CFURLCreateDataAndPropertiesFromResource(alloc, infoURL, &infoData, NULL, NULL, NULL); + 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")); } @@ -1971,7 +2510,7 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer if (CFDictionaryGetTypeID() == CFGetTypeID(result)) { CFDictionarySetValue((CFMutableDictionaryRef)result, _kCFBundleInfoPlistURLKey, infoURL); } else { - CFRelease(result); + if (!_CFAllocatorIsGCRefZero(alloc)) CFRelease(result); result = NULL; } } @@ -1988,6 +2527,7 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer if (contents) CFRelease(contents); #endif /* READ_DIRECTORIES */ } + _processInfoDictionary((CFMutableDictionaryRef)result, _CFGetPlatformName(), _CFGetProductName()); return result; } @@ -1997,18 +2537,18 @@ static Boolean _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFAllocatorR CFDataRef pkgInfoData = NULL; // Check for a "real" new bundle - tempURL = CFURLCreateWithString(alloc, _CFBundlePkgInfoURLFromBase2, url); - CFURLCreateDataAndPropertiesFromResource(alloc, tempURL, &pkgInfoData, NULL, NULL, NULL); + tempURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundlePkgInfoURLFromBase2, url); + CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, tempURL, &pkgInfoData, NULL, NULL, NULL); CFRelease(tempURL); if (!pkgInfoData) { - tempURL = CFURLCreateWithString(alloc, _CFBundlePkgInfoURLFromBase1, url); - CFURLCreateDataAndPropertiesFromResource(alloc, tempURL, &pkgInfoData, NULL, NULL, NULL); + tempURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundlePkgInfoURLFromBase1, url); + CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, tempURL, &pkgInfoData, NULL, NULL, NULL); CFRelease(tempURL); } if (!pkgInfoData) { // Check for a "pseudo" new bundle - tempURL = CFURLCreateWithString(alloc, _CFBundlePseudoPkgInfoURLFromBase, url); - CFURLCreateDataAndPropertiesFromResource(alloc, tempURL, &pkgInfoData, NULL, NULL, NULL); + tempURL = CFURLCreateWithString(kCFAllocatorSystemDefault, _CFBundlePseudoPkgInfoURLFromBase, url); + CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, tempURL, &pkgInfoData, NULL, NULL, NULL); CFRelease(tempURL); } @@ -2025,7 +2565,7 @@ static Boolean _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFAllocatorR if (pkgInfoData) CFRelease(pkgInfoData); if (!retVal) { if (!infoDict) { - infoDict = _CFBundleCopyInfoDictionaryInDirectory(alloc, url, NULL); + infoDict = _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefaultGCRefZero, url, NULL); releaseInfoDict = true; } if (infoDict) { @@ -2040,7 +2580,7 @@ static Boolean _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFAllocatorR if (packageCreator) *packageCreator = CFSwapInt32BigToHost(tmp); retVal = hasCreator = true; } - if (releaseInfoDict) CFRelease(infoDict); + if (releaseInfoDict && !_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(infoDict); } } if (!hasType || !hasCreator) { @@ -2094,7 +2634,7 @@ CF_EXPORT Boolean _CFBundleGetPackageInfoInDirectory(CFAllocatorRef alloc, CFURL CF_EXPORT void CFBundleGetPackageInfo(CFBundleRef bundle, UInt32 *packageType, UInt32 *packageCreator) { CFURLRef bundleURL = CFBundleCopyBundleURL(bundle); - if (!_CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFGetAllocator(bundle), bundleURL, CFBundleGetInfoDictionary(bundle), packageType, packageCreator)) { + if (!_CFBundleGetPackageInfoInDirectoryWithInfoDictionary(kCFAllocatorSystemDefault, bundleURL, CFBundleGetInfoDictionary(bundle), packageType, packageCreator)) { if (packageType) *packageType = 0x424e444c; // 'BNDL' if (packageCreator) *packageCreator = 0x3f3f3f3f; // '????' } @@ -2135,7 +2675,7 @@ CF_EXPORT CFArrayRef _CFBundleGetSupportedPlatforms(CFBundleRef bundle) { UniChar buff[CFMaxPathSize]; CFIndex buffLen, infoLen = CFStringGetLength(_CFBundleInfoURLFromBaseNoExtension3), startLen, extLen = CFStringGetLength(_CFBundleInfoExtension); if (infoPlistURL) { - CFMutableArrayRef mutableArray = CFArrayCreateMutable(CFGetAllocator(bundle), 0, &kCFTypeArrayCallBacks); + CFMutableArrayRef mutableArray = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); absoluteURL = CFURLCopyAbsoluteURL(infoPlistURL); infoPlistPath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); CFRelease(absoluteURL); @@ -2294,7 +2834,7 @@ CF_EXPORT CFArrayRef CFBundleCopyBundleLocalizations(CFBundleRef bundle) { if (resourcesURL) { absoluteURL = CFURLCopyAbsoluteURL(resourcesURL); directoryPath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); - contents = _CFBundleCopyDirectoryContentsAtPath(directoryPath, _CFBundleAllContents); + contents = _CFBundleCopySortedDirectoryContentsAtPath(directoryPath, _CFBundleAllContents); contentsRange = CFRangeMake(0, CFArrayGetCount(contents)); for (idx = 0; idx < contentsRange.length; idx++) { CFStringRef name = CFArrayGetValueAtIndex(contents, idx); @@ -2355,11 +2895,12 @@ CF_EXPORT CFDictionaryRef CFBundleCopyInfoDictionaryForURL(CFURLRef url) { Boolean isDir = false; if (_CFIsResourceAtURL(url, &isDir)) { if (isDir) { - result = _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefault, url, NULL); + result = _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefaultGCRefZero, url, NULL); } else { - result = _CFBundleCopyInfoDictionaryInExecutable(url); + result = _CFBundleCopyInfoDictionaryInExecutable(url); // return zero-ref dictionary under GC } } + if (result && _CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRetain(result); // conditionally put on a retain for a Copy function return result; } @@ -2383,7 +2924,7 @@ CFArrayRef CFBundleCopyLocalizationsForURL(CFURLRef url) { result = CFBundleCopyBundleLocalizations(bundle); CFRelease(bundle); } else { - CFDictionaryRef infoDict = _CFBundleCopyInfoDictionaryInExecutable(url); + CFDictionaryRef infoDict = _CFBundleCopyInfoDictionaryInExecutable(url); // return zero-ref dictionary under GC if (infoDict) { CFArrayRef predefinedLocalizations = (CFArrayRef)CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey); if (predefinedLocalizations && CFGetTypeID(predefinedLocalizations) == CFArrayGetTypeID()) result = (CFArrayRef)CFRetain(predefinedLocalizations); @@ -2391,7 +2932,7 @@ CFArrayRef CFBundleCopyLocalizationsForURL(CFURLRef url) { devLang = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey); if (devLang && (CFGetTypeID(devLang) == CFStringGetTypeID() && CFStringGetLength(devLang) > 0)) result = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&devLang, 1, &kCFTypeArrayCallBacks); } - CFRelease(infoDict); + if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(infoDict); } } return result; diff --git a/CFByteOrder.h b/CFByteOrder.h index 209f201..ab2572b 100644 --- a/CFByteOrder.h +++ b/CFByteOrder.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFByteOrder.h - Copyright (c) 1995-2009, Apple Inc. All rights reserved. + Copyright (c) 1995-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBYTEORDER__) diff --git a/CFCalendar.c b/CFCalendar.c index 558a531..d115624 100644 --- a/CFCalendar.c +++ b/CFCalendar.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,12 +22,11 @@ */ /* CFCalendar.c - Copyright 2004-2004, Apple Computer, Inc. All rights reserved. + Copyright (c) 2004-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ - #include #include #include "CFInternal.h" @@ -84,7 +83,7 @@ static const CFRuntimeClass __CFCalendarClass = { __CFCalendarCopyDescription }; -static void __CFCalendarInitialize(void) { +__private_extern__ void __CFCalendarInitialize(void) { __kCFCalendarTypeID = _CFRuntimeRegisterClass(&__CFCalendarClass); } @@ -120,7 +119,7 @@ __private_extern__ UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID CFStringGetCharacters(tznam, CFRangeMake(0, cnt), (UniChar *)ubuffer); UErrorCode status = U_ZERO_ERROR; - UCalendar *cal = ucal_open(ubuffer, cnt, cstr, UCAL_TRADITIONAL, &status); + UCalendar *cal = ucal_open(ubuffer, cnt, cstr, UCAL_DEFAULT, &status); if (calendarID) CFRelease(localeID); return cal; } @@ -298,6 +297,9 @@ static UCalendarDateFields __CFCalendarGetICUFieldCode(CFCalendarUnit unit) { case kCFCalendarUnitMinute: return UCAL_MINUTE; case kCFCalendarUnitSecond: return UCAL_SECOND; case kCFCalendarUnitWeek: return UCAL_WEEK_OF_YEAR; + case kCFCalendarUnitWeekOfYear: return UCAL_WEEK_OF_YEAR; + case kCFCalendarUnitWeekOfMonth: return UCAL_WEEK_OF_MONTH; + case kCFCalendarUnitYearForWeekOfYear: return UCAL_YEAR_WOY; case kCFCalendarUnitWeekday: return UCAL_DAY_OF_WEEK; case kCFCalendarUnitWeekdayOrdinal: return UCAL_DAY_OF_WEEK_IN_MONTH; } @@ -317,6 +319,7 @@ static UCalendarDateFields __CFCalendarGetICUFieldCodeFromChar(char ch) { case 'S': return UCAL_MILLISECOND; case 'w': return UCAL_WEEK_OF_YEAR; case 'W': return UCAL_WEEK_OF_MONTH; + case 'Y': return UCAL_YEAR_WOY; case 'E': return UCAL_DAY_OF_WEEK; case 'D': return UCAL_DAY_OF_YEAR; case 'F': return UCAL_DAY_OF_WEEK_IN_MONTH; @@ -326,18 +329,20 @@ static UCalendarDateFields __CFCalendarGetICUFieldCodeFromChar(char ch) { return (UCalendarDateFields)-1; } -static UCalendarDateFields __CFCalendarGetCalendarUnitFromChar(char ch) { +static CFCalendarUnit __CFCalendarGetCalendarUnitFromChar(char ch) { switch (ch) { - case 'G': return (UCalendarDateFields)kCFCalendarUnitEra; - case 'y': return (UCalendarDateFields)kCFCalendarUnitYear; - case 'M': return (UCalendarDateFields)kCFCalendarUnitMonth; - case 'd': return (UCalendarDateFields)kCFCalendarUnitDay; - case 'H': return (UCalendarDateFields)kCFCalendarUnitHour; - case 'm': return (UCalendarDateFields)kCFCalendarUnitMinute; - case 's': return (UCalendarDateFields)kCFCalendarUnitSecond; - case 'w': return (UCalendarDateFields)kCFCalendarUnitWeek; - case 'E': return (UCalendarDateFields)kCFCalendarUnitWeekday; - case 'F': return (UCalendarDateFields)kCFCalendarUnitWeekdayOrdinal; + case 'G': return kCFCalendarUnitEra; + case 'y': return kCFCalendarUnitYear; + case 'M': return kCFCalendarUnitMonth; + case 'd': return kCFCalendarUnitDay; + case 'H': return kCFCalendarUnitHour; + case 'm': return kCFCalendarUnitMinute; + case 's': return kCFCalendarUnitSecond; + case 'w': return kCFCalendarUnitWeekOfYear; + case 'W': return kCFCalendarUnitWeekOfMonth; + case 'Y': return kCFCalendarUnitYearForWeekOfYear; + case 'E': return kCFCalendarUnitWeekday; + case 'F': return kCFCalendarUnitWeekdayOrdinal; } return (UCalendarDateFields)-1; } @@ -383,7 +388,11 @@ static void __CFCalendarSetToFirstInstant(CFCalendarRef calendar, CFCalendarUnit ucal_setMillis(calendar->_cal, udate, &status); int target_era = INT_MIN; switch (unit) { // largest to smallest, we set the fields to their minimum value + case kCFCalendarUnitYearForWeekOfYear:; + ucal_set(calendar->_cal, UCAL_WEEK_OF_YEAR, ucal_getLimit(calendar->_cal, UCAL_WEEK_OF_YEAR, UCAL_ACTUAL_MINIMUM, &status)); case kCFCalendarUnitWeek: + case kCFCalendarUnitWeekOfMonth:; + case kCFCalendarUnitWeekOfYear:; { // reduce to first day of week, then reduce the rest of the day int32_t goal = ucal_getAttribute(calendar->_cal, UCAL_FIRST_DAY_OF_WEEK); @@ -451,9 +460,11 @@ static Boolean __validUnits(CFCalendarUnit smaller, CFCalendarUnit bigger) { if (kCFCalendarUnitMinute == smaller) return false; // this causes CFIndex overflow in range.length if (kCFCalendarUnitSecond == smaller) return false; // this causes CFIndex overflow in range.length return true; + case kCFCalendarUnitYearForWeekOfYear: case kCFCalendarUnitYear: if (kCFCalendarUnitEra == smaller) return false; if (kCFCalendarUnitYear == smaller) return false; + if (kCFCalendarUnitYearForWeekOfYear == smaller) return false; if (kCFCalendarUnitWeekday == smaller) return false; return true; case kCFCalendarUnitMonth: @@ -475,6 +486,8 @@ static Boolean __validUnits(CFCalendarUnit smaller, CFCalendarUnit bigger) { if (kCFCalendarUnitSecond == smaller) return true; return false; case kCFCalendarUnitWeek: + case kCFCalendarUnitWeekOfMonth: + case kCFCalendarUnitWeekOfYear: if (kCFCalendarUnitWeekday == smaller) return true; if (kCFCalendarUnitDay == smaller) return true; if (kCFCalendarUnitHour == smaller) return true; diff --git a/CFCalendar.h b/CFCalendar.h index 438e02d..2f09050 100644 --- a/CFCalendar.h +++ b/CFCalendar.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFCalendar.h - Copyright (c) 2004-2009, Apple Inc. All rights reserved. + Copyright (c) 2004-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFCALENDAR__) @@ -33,50 +33,48 @@ #include #include -#if MAC_OS_X_VERSION_10_4 <= MAC_OS_X_VERSION_MAX_ALLOWED - CF_EXTERN_C_BEGIN typedef struct __CFCalendar * CFCalendarRef; CF_EXPORT -CFTypeID CFCalendarGetTypeID(void) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFTypeID CFCalendarGetTypeID(void); CF_EXPORT -CFCalendarRef CFCalendarCopyCurrent(void) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFCalendarRef CFCalendarCopyCurrent(void); CF_EXPORT -CFCalendarRef CFCalendarCreateWithIdentifier(CFAllocatorRef allocator, CFStringRef identifier) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFCalendarRef CFCalendarCreateWithIdentifier(CFAllocatorRef allocator, CFStringRef identifier); // Create a calendar. The identifiers are the kCF*Calendar // constants in CFLocale.h. CF_EXPORT -CFStringRef CFCalendarGetIdentifier(CFCalendarRef calendar) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFStringRef CFCalendarGetIdentifier(CFCalendarRef calendar); // Returns the calendar's identifier. CF_EXPORT -CFLocaleRef CFCalendarCopyLocale(CFCalendarRef calendar) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFLocaleRef CFCalendarCopyLocale(CFCalendarRef calendar); CF_EXPORT -void CFCalendarSetLocale(CFCalendarRef calendar, CFLocaleRef locale) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +void CFCalendarSetLocale(CFCalendarRef calendar, CFLocaleRef locale); CF_EXPORT -CFTimeZoneRef CFCalendarCopyTimeZone(CFCalendarRef calendar) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFTimeZoneRef CFCalendarCopyTimeZone(CFCalendarRef calendar); CF_EXPORT -void CFCalendarSetTimeZone(CFCalendarRef calendar, CFTimeZoneRef tz) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +void CFCalendarSetTimeZone(CFCalendarRef calendar, CFTimeZoneRef tz); CF_EXPORT -CFIndex CFCalendarGetFirstWeekday(CFCalendarRef calendar) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFIndex CFCalendarGetFirstWeekday(CFCalendarRef calendar); CF_EXPORT -void CFCalendarSetFirstWeekday(CFCalendarRef calendar, CFIndex wkdy) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +void CFCalendarSetFirstWeekday(CFCalendarRef calendar, CFIndex wkdy); CF_EXPORT -CFIndex CFCalendarGetMinimumDaysInFirstWeek(CFCalendarRef calendar) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFIndex CFCalendarGetMinimumDaysInFirstWeek(CFCalendarRef calendar); CF_EXPORT -void CFCalendarSetMinimumDaysInFirstWeek(CFCalendarRef calendar, CFIndex mwd) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +void CFCalendarSetMinimumDaysInFirstWeek(CFCalendarRef calendar, CFIndex mwd); enum { @@ -87,35 +85,40 @@ enum { kCFCalendarUnitHour = (1UL << 5), kCFCalendarUnitMinute = (1UL << 6), kCFCalendarUnitSecond = (1UL << 7), - kCFCalendarUnitWeek = (1UL << 8), + 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 +#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 }; typedef CFOptionFlags CFCalendarUnit; CF_EXPORT -CFRange CFCalendarGetMinimumRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFRange CFCalendarGetMinimumRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit); CF_EXPORT -CFRange CFCalendarGetMaximumRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFRange CFCalendarGetMaximumRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit); CF_EXPORT -CFRange CFCalendarGetRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFRange CFCalendarGetRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at); CF_EXPORT -CFIndex CFCalendarGetOrdinalityOfUnit(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFIndex CFCalendarGetOrdinalityOfUnit(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at); CF_EXPORT -Boolean CFCalendarGetTimeRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit, CFAbsoluteTime at, CFAbsoluteTime *startp, CFTimeInterval *tip) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +Boolean CFCalendarGetTimeRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit, CFAbsoluteTime at, CFAbsoluteTime *startp, CFTimeInterval *tip) CF_AVAILABLE(10_5, 2_0); CF_EXPORT -Boolean CFCalendarComposeAbsoluteTime(CFCalendarRef calendar, /* out */ CFAbsoluteTime *at, const char *componentDesc, ...) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +Boolean CFCalendarComposeAbsoluteTime(CFCalendarRef calendar, /* out */ CFAbsoluteTime *at, const char *componentDesc, ...); CF_EXPORT -Boolean CFCalendarDecomposeAbsoluteTime(CFCalendarRef calendar, CFAbsoluteTime at, const char *componentDesc, ...) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +Boolean CFCalendarDecomposeAbsoluteTime(CFCalendarRef calendar, CFAbsoluteTime at, const char *componentDesc, ...); enum { @@ -123,15 +126,13 @@ enum { }; CF_EXPORT -Boolean CFCalendarAddComponents(CFCalendarRef calendar, /* inout */ CFAbsoluteTime *at, CFOptionFlags options, const char *componentDesc, ...) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +Boolean CFCalendarAddComponents(CFCalendarRef calendar, /* inout */ CFAbsoluteTime *at, CFOptionFlags options, const char *componentDesc, ...); CF_EXPORT -Boolean CFCalendarGetComponentDifference(CFCalendarRef calendar, CFAbsoluteTime startingAT, CFAbsoluteTime resultAT, CFOptionFlags options, const char *componentDesc, ...) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +Boolean CFCalendarGetComponentDifference(CFCalendarRef calendar, CFAbsoluteTime startingAT, CFAbsoluteTime resultAT, CFOptionFlags options, const char *componentDesc, ...); CF_EXTERN_C_END -#endif - #endif /* ! __COREFOUNDATION_CFCALENDAR__ */ diff --git a/CFCharacterSet.c b/CFCharacterSet.c index 51416aa..6e8efe4 100644 --- a/CFCharacterSet.c +++ b/CFCharacterSet.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFCharacterSet.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. Responsibility: Aki Inoue */ @@ -145,6 +145,7 @@ CF_INLINE void __CFCSetPutIsInverted(CFMutableCharacterSetRef cset, Boolean isIn CF_INLINE void __CFCSetPutHasHashValue(CFMutableCharacterSetRef cset, Boolean hasHash) {(hasHash ? (cset->_base._cfinfo[CF_INFO_BITS] |= __kCFCharSetHasHashValue) : (cset->_base._cfinfo[CF_INFO_BITS] &= ~__kCFCharSetHasHashValue));} CF_INLINE void __CFCSetPutClassType(CFMutableCharacterSetRef cset, UInt32 classType) {cset->_base._cfinfo[CF_INFO_BITS] &= ~__kCFCharSetClassTypeMask; cset->_base._cfinfo[CF_INFO_BITS] |= classType;} +__private_extern__ Boolean __CFCharacterSetIsMutable(CFCharacterSetRef cset) {return __CFCSetIsMutable(cset);} /* Inline contents accessor macros */ diff --git a/CFCharacterSet.h b/CFCharacterSet.h index 0d1ccce..29739b3 100644 --- a/CFCharacterSet.h +++ b/CFCharacterSet.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFCharacterSet.h - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. */ /*! @@ -88,12 +88,8 @@ enum { kCFCharacterSetDecomposable, /* Canonically decomposable character set */ kCFCharacterSetAlphaNumeric, /* Alpha Numeric character set (Unicode General Category L*, M*, & N*) */ kCFCharacterSetPunctuation, /* Punctuation character set (Unicode General Category P*) */ -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED kCFCharacterSetCapitalizedLetter = 13, /* Titlecase character set (Unicode General Category Lt) */ -#endif -#if MAC_OS_X_VERSION_10_3 <= MAC_OS_X_VERSION_MAX_ALLOWED kCFCharacterSetSymbol = 14, /* Symbol character set (Unicode General Category S*) */ -#endif #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 @@ -185,7 +181,6 @@ CFCharacterSetRef CFCharacterSetCreateWithCharactersInString(CFAllocatorRef allo CF_EXPORT CFCharacterSetRef CFCharacterSetCreateWithBitmapRepresentation(CFAllocatorRef alloc, CFDataRef theData); -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED /*! @function CFCharacterSetCreateInvertedSet Creates a new immutable character set that is the invert of the specified character set. @@ -221,7 +216,6 @@ CF_EXPORT Boolean CFCharacterSetIsSupersetOfSet(CFCharacterSetRef theSet, CFChar plane number range, the behavior is undefined. */ CF_EXPORT Boolean CFCharacterSetHasMemberInPlane(CFCharacterSetRef theSet, CFIndex thePlane); -#endif /*! @function CFCharacterSetCreateMutable @@ -236,7 +230,6 @@ CF_EXPORT Boolean CFCharacterSetHasMemberInPlane(CFCharacterSetRef theSet, CFInd CF_EXPORT CFMutableCharacterSetRef CFCharacterSetCreateMutable(CFAllocatorRef alloc); -#if MAC_OS_X_VERSION_10_3 <= MAC_OS_X_VERSION_MAX_ALLOWED /*! @function CFCharacterSetCreateCopy Creates a new character set with the values from the given character set. This function tries to compact the backing store where applicable. @@ -251,8 +244,7 @@ CFMutableCharacterSetRef CFCharacterSetCreateMutable(CFAllocatorRef alloc); @result A reference to the new CFCharacterSet. */ CF_EXPORT -CFCharacterSetRef CFCharacterSetCreateCopy(CFAllocatorRef alloc, CFCharacterSetRef theSet) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; -#endif +CFCharacterSetRef CFCharacterSetCreateCopy(CFAllocatorRef alloc, CFCharacterSetRef theSet); /*! @function CFCharacterSetCreateMutableCopy @@ -284,7 +276,6 @@ CFMutableCharacterSetRef CFCharacterSetCreateMutableCopy(CFAllocatorRef alloc, C CF_EXPORT Boolean CFCharacterSetIsCharacterMember(CFCharacterSetRef theSet, UniChar theChar); -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED /*! @function CFCharacterSetIsLongCharacterMember Reports whether or not the UTF-32 character is in the character set. @@ -295,7 +286,6 @@ Boolean CFCharacterSetIsCharacterMember(CFCharacterSetRef theSet, UniChar theCha @result true, if the value is in the character set, otherwise false. */ CF_EXPORT Boolean CFCharacterSetIsLongCharacterMember(CFCharacterSetRef theSet, UTF32Char theChar); -#endif /*! @function CFCharacterSetCreateBitmapRepresentation diff --git a/CFCharacterSetBitmaps.bitmap b/CFCharacterSetBitmaps.bitmap index f2c9794335515e5afdb5f54c155f82cd1237005d..cd0af97b1f1f211aecbc1f7fde28ec011ef8611f 100644 GIT binary patch delta 5106 zcmd5=dvH|M8NcV8d+$CHb~j`b^4teaA}S4`A}9#Ec^E4d%S?$*WvU5^)v;o6s#B3> zZwzXmW7cc<+EPuRRcFw);8t$M2YUgb)@qjNP%K*5C=Z>nCX`ZR1AF_Ob9Xln@HOKf z{W5#+d3@(P=X{Uf{k|M9D-M_ybZ)~|s>*s)uF$uT!bH8iy9gUTeMxu@zUL%-8yno% z2tYDPdc{a`c?;3gY${H@Sq57aDkrurcv2yjetl!G%*v9K%(eJ?s88>0tWm{KWW7u) zAgz%?*(+r-`g@J5id5{Cr)a+&^G(=`44Xh5gU z)5&qYws{4$Ed58#tq~y<9}x*3LCb65a^4N{r-gmXVv?Y2kB`Ri*T)AneP6$SE-sNq zy!L{H3D225JQpueGcpFk>(E_=6)% z$P>rni#6Qq*477!BXOcNIR#!CWlq?8gx;?AEUs|{bE08YR4&tpqh5VYTfrRMWDBmf z4<=5)ucBG}GYNXKa6nkFl*=?iJrv{MdcD>BgWQBS|>wv8>!VZH#kWId?ETsVnh3R z1XdrzdmQYTDWljRq%>0M;;P_32MlPW0#3?wc|29cg*%-w`%DtFKhB;?B$r=KxY*mF zp_Ue7R}=yxs}N`sp{2@9zwT=F@0A<>zAEuw((AIC1a0sHD|1PN}DMx?O>N8(`+|1M3o0&x2WkD+OZEjEo3H3T3%S#LMmm9f-soG4rf_L z8xF_K>+IXS)k0zfc6HII(6fR~G1jz_>0WN8>F`n;sk$r|l}YqIjmIpK{T#8zpIFMo zBxi$|c8aI;s0n78)X4G09YPV@_7ivm6qb-E=0J zZV(ie!)e#agJV~;L62D)_)U_RuKPO643_H4{=Yl>=6g%d+u~Nb63|TD0^<>twpw zUe3`zo|?hU>3}wcj^=?a#2I)bi?dG$jbHL`{Jh1o}`03_ATPaMHXhs80moFiB>$ALLq%^U_fwBw42FlZnQ>Yo_` z4TQjdGx%AH>VUs=(=g)VA4y`nHt7GHC@6=FS2RiqwPIjyA~kTLiw+PKUTei@d))~= zo0u=2S_red@p>3~OW@&dx+

u3tx;;9EysBnDgiak73LEd}3t>U50=k3%GagAdR< zjlJvW)1-GmnJS=*#PqG?qIk+-y!-&|^W?--zyrOs8VHRodM5uDP<%RH~W2B zWV~4E4Sqh7 z2r4+_ur=#A-RS~J2*F|Al^`L9L80c4BOl&5mt}VX$1kn#Jx;{Xqc2#jAX2D z-4&TNWDSblZToPh2$(@uV(b`YQ$G*58klzWHnONhA>E>sAz1PRCQ1tn<7NOl2Negz zRxlTbQ{VdMl_Jo>N+>_xg6Y}pb+jypVWD_xHfL2~!Hw({QH_DWOZ_rjd=uMDEe3-( zv6U17=c_B(GK_*L)gp$nm$YwWhj`xsaV3jf1Rt$r^U;`Jft5G2r!g5ZioeZX@Q|d9 z&3>NL)gzL==gJ?;O-^&`^R)Y$PhhgwtFbEs6Ralm7R&DYe_^#cVjSvc8HQyW9Qq9_ zwX0JLl4(+6cpqnsQcHr+URolM1C=Km8I7#+7^v?%MOH5x^-1<(z&+-Y(71_|x+l0G z|6FV!#vA?QU1q#`g!uz!WtsbxcU|gF(LEOi(wfLa2O#6hi+g zrHC+i=9IEGDQRhF7ZYL_Cjuc&Dunx*R1TlqfUx425{Ref=L=jvyxOcT zQ*8@EZHpS3#t(ZAU5x qxe|ArjIyCUCTrQ)*Gjf~(A$^040^A+zxIEvfy-L} delta 3849 zcmcIndu&tZ6~Ev4?!9<3v`vg>Oz9v!41h({3&Y$qW=HyE8rw^h>!udZ}!3YFG% z6xC+QmQCAKF1O*VV}j5Px&aeVcU%odYx4-8K63d3b!rib#bd41@+daTDXCsm|^6?Vg@{v3(*_>JBAt8vV z6zk~k>8;eQhjG6Ga`NEpR}|(oz8ljja<)_AQYtUxzgK&Vj@VcnlaWX3Rw1s9F{RM9 zZ`cvd_DX8j_%PN|B1s?hd}`aD+827}BqXmS;W_}n(ONfwOz)`+Gs$?nu6%UsfL+&s zVB6fdRX2&X8{_I%KwL6@QQtUG8Z0!8R-ttyk|LV;l7{%@r{ICZEQGxYR`4a7BW1n$ z87Bt~zf)|rpn@`4|^(5AggHiPMdq?BdSrFAN=inY(G#j2uCZGGD(p)?NeyApwlvmQu5}iWVA1=az)DFl&yT7v83#_IGSvp1@;X0 zj+L5*6oo8I@_t$LEFCS0pcl-^hYqy?YG4-oye$1Iwo( zl9a%d9|B4)F1c%yv9d}J&TLjU=~j{0e$>o0v$VMC>I&x(>9Jl^Oxot+2y>amDb@uv zSW#hq^d4J3{w@&P$A)^^)gIi&;NB?iw$&_t!eA}~oB}X;#85Qj4*=#fFTMs4X8b>) z7;88P7~^IRjRgZIl`zAhtkA)29=UgLi<4yVy835gOa?#p0#n7s4MS-)S~AF$0+gbN zvoWdd_T;%sj@UPP>$Aq370ZQ^3!4<^`z(}0LgOwdFTrTNDr1)lQ<-G`ONB2&^=gd_ zz~n?HN8EuWy8I ze5+9n=^o@|4? zOz$2kUPxhagSE^uPy7tF6H>>BM<`-$3^%g~`nEtJp6>t^i`zhDDg5(BWt`~sk*9yn zBi8W~hsowIJ7FFntP-sq6t+Iz0rw}BmIybO?u4=c`Rn)7ps^fkCn12Zkc^M-Ol1<)G&_IkHQSaVKZEN6y|%pw&2DdyGO%x3Mw9O zu+{HPn)7n`PwRkuH^CLO(}+etZah%`ZEh1pwj6`T8poNPk26kGcb$acR5ys^Zap0k zH&}p^kArvQfUZ!WlC>{jx{u=1-Ow40M~;J^pd$b<0G+&!qlYzh@;5|S60NwXU6>vV z3&%yMtqEQg<@^n5iCfq=KQ5~LadL5jD@-B^Yy?fy)1#diHs&@K)C^}++a)<#{g-A7 zHWjPI`^%OZD8-i^hZ;qu?^zJuuBfROlK` z#BR;mn;plr#;c150qea+{a6xXe%uxUb*6Ks{3q*Z^v@*OSzGjJsUgtJPfF-%he%a5 zPVlsE=;>(!o(aV`*BPYUO&G$=QX(ib+fLU95wdLR) z)()FZm*8pk`{s>H3{w$Y~$NxG=EybtMqiGz}^_$ zdQePOarR1n8hZ%MNbFXP(^v7`5TQW7imwKu#s#bS(uol|>An5Oxp*H9=i=MT$t^K$ zv#EG%HJ`=EiKgJ{$M|0GO6I8V@xK+DO*>(k$Jvl>EyRyop~&n=@P)y_3pi(<@8mg7 zi5#B)122QDje4V6X?k~Z4hScq-0>cfIGMQwYbiFZX60!oMUl;#6h9KAxR_<;-#gg{ z+sdv&UKM9nur(}~vIPDnEYC15M1#Uq2Alw7o*65zypK@ulIU~?2U8Ih zFEz`*x<}e`X@&g%PkY)mv5{(2cgSAV*S7n8PXPup@;9B7t`Bs}Yd(KbzH;xJZrnZ6 zxJN?&6EpshZh6ehA%*{h?zz0;;9+Ik_|N2KHtx$P<8f?89z}mV3e`MXeYtQDa~VY> zXeaB`FnV{fJ1JTzp1z#X-NidOUm9IKaY!hCj_usZ%u( zpCv90T*m8RNuqp>PT>@*IFxb(Ip2=5P$Dnozp3<`=ArFP4YkdVet&1Qc=&utYWq&& zj>0Fd1a7NS?=P1eCeWgHhUgF03Bc40SUH$3m*SiC>fl@W@R%PK0CCH*4w#@@Apzt{ zK^L+JA@c}rT diff --git a/CFCharacterSetPriv.h b/CFCharacterSetPriv.h index dc2ddae..8fe60e6 100644 --- a/CFCharacterSetPriv.h +++ b/CFCharacterSetPriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFCharacterSetPriv.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFCHARACTERSETPRIV__) @@ -32,7 +32,6 @@ CF_EXTERN_C_BEGIN -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED /*! @function CFCharacterSetIsSurrogateHighCharacter Reports whether or not the character is a high surrogate. @@ -65,7 +64,6 @@ CF_INLINE Boolean CFCharacterSetIsSurrogateLowCharacter(UniChar character) { CF_INLINE UTF32Char CFCharacterSetGetLongCharacterForSurrogatePair(UniChar surrogateHigh, UniChar surrogateLow) { return ((surrogateHigh - 0xD800UL) << 10) + (surrogateLow - 0xDC00UL) + 0x0010000UL; } -#endif /* Check to see if the character represented by the surrogate pair surrogateHigh & surrogateLow is in the chraracter set */ CF_EXPORT Boolean CFCharacterSetIsSurrogatePairMember(CFCharacterSetRef theSet, UniChar surrogateHigh, UniChar surrogateLow) ; diff --git a/CFConcreteStreams.c b/CFConcreteStreams.c index b492996..a72f14d 100644 --- a/CFConcreteStreams.c +++ b/CFConcreteStreams.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFConcreteStreams.c - Copyright (c) 2000-2009, Apple Inc. All rights reserved. - Responsibility: Becky Willrich + Copyright (c) 2000-2011, Apple Inc. All rights reserved. + Responsibility: John Iarocci */ #include "CFStreamInternal.h" @@ -35,6 +35,7 @@ #include #include #include +#include #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED #include #include @@ -43,15 +44,6 @@ #error Unknown or unspecified DEPLOYMENT_TARGET #endif -// On Unix, you can schedule an fd with the RunLoop by creating a CFSocket around it. On Win32 -// files and sockets are not interchangeable, and we do cheapo scheduling, where the file is -// always readable and writable until we hit EOF (similar to the way CFData streams are scheduled). -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -#define REAL_FILE_SCHEDULING (1) -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif #define SCHEDULE_AFTER_WRITE (0) #define SCHEDULE_AFTER_READ (1) @@ -66,9 +58,9 @@ typedef struct { int fd; #ifdef REAL_FILE_SCHEDULING union { - CFSocketRef sock; // socket created once we open and have an fd + CFFileDescriptorRef cffd; // ref created once we open and have an fd CFMutableArrayRef rlArray; // scheduling information prior to open - } rlInfo; // If fd > 0, sock exists. Otherwise, rlArray. + } rlInfo; // If fd > 0, cffd exists. Otherwise, rlArray. #else uint16_t scheduled; // ref count of how many times we've been scheduled #endif @@ -81,15 +73,16 @@ CONST_STRING_DECL(kCFStreamPropertyFileCurrentOffset, "kCFStreamPropertyFileCurr #ifdef REAL_FILE_SCHEDULING -static void fileCallBack(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info); +extern void _CFFileDescriptorInduceFakeReadCallBack(CFFileDescriptorRef); +static void fileCallBack(CFFileDescriptorRef f, CFOptionFlags callBackTypes, void *info); -static void constructCFSocket(_CFFileStreamContext *fileStream, Boolean forRead, struct _CFStream *stream) { - CFSocketContext context = {0, stream, NULL, NULL, CFCopyDescription}; - CFSocketRef sock = CFSocketCreateWithNative(CFGetAllocator(stream), fileStream->fd, forRead ? kCFSocketReadCallBack : kCFSocketWriteCallBack, fileCallBack, &context); - CFSocketSetSocketFlags(sock, 0); +static void constructCFFD(_CFFileStreamContext *fileStream, Boolean forRead, struct _CFStream *stream) { + CFFileDescriptorContext context = {0, stream, NULL, NULL, (void *)CFCopyDescription}; + CFFileDescriptorRef cffd = CFFileDescriptorCreate(CFGetAllocator(stream), fileStream->fd, false, fileCallBack, &context); + CFFileDescriptorEnableCallBacks(cffd, forRead ? kCFFileDescriptorReadCallBack : kCFFileDescriptorWriteCallBack); if (fileStream->rlInfo.rlArray) { CFIndex i, c = CFArrayGetCount(fileStream->rlInfo.rlArray); - CFRunLoopSourceRef src = CFSocketCreateRunLoopSource(CFGetAllocator(stream), sock, 0); + CFRunLoopSourceRef src = CFFileDescriptorCreateRunLoopSource(CFGetAllocator(stream), cffd, 0); for (i = 0; i+1 < c; i += 2) { CFRunLoopRef rl = (CFRunLoopRef)CFArrayGetValueAtIndex(fileStream->rlInfo.rlArray, i); CFStringRef mode = CFArrayGetValueAtIndex(fileStream->rlInfo.rlArray, i+1); @@ -98,7 +91,7 @@ static void constructCFSocket(_CFFileStreamContext *fileStream, Boolean forRead, CFRelease(fileStream->rlInfo.rlArray); CFRelease(src); } - fileStream->rlInfo.sock = sock; + fileStream->rlInfo.cffd = cffd; } #endif @@ -121,7 +114,7 @@ static Boolean constructFD(_CFFileStreamContext *fileStream, CFStreamError *erro } if (__CFBitIsSet(fileStream->flags, APPEND)) { flags |= O_APPEND; - if(_CFExecutableLinkedOnOrAfter(CFSystemVersionPanther)) flags &= ~O_TRUNC; + flags &= ~O_TRUNC; } do { @@ -138,7 +131,7 @@ static Boolean constructFD(_CFFileStreamContext *fileStream, CFStreamError *erro #ifdef REAL_FILE_SCHEDULING if (fileStream->rlInfo.rlArray != NULL) { - constructCFSocket(fileStream, forRead, stream); + constructCFFD(fileStream, forRead, stream); } #endif @@ -172,7 +165,7 @@ static Boolean fileOpen(struct _CFStream *stream, CFStreamError *errorCode, Bool } #ifdef REAL_FILE_SCHEDULING } else if (ctxt->rlInfo.rlArray != NULL) { - constructCFSocket(ctxt, forRead, stream); + constructCFFD(ctxt, forRead, stream); #endif } return TRUE; @@ -198,8 +191,18 @@ static CFIndex fileRead(CFReadStreamRef stream, UInt8 *buffer, CFIndex bufferLen #ifdef REAL_FILE_SCHEDULING if (__CFBitIsSet(ctxt->flags, SCHEDULE_AFTER_READ)) { __CFBitClear(ctxt->flags, SCHEDULE_AFTER_READ); - if (ctxt->rlInfo.sock) { - CFSocketEnableCallBacks(ctxt->rlInfo.sock, kCFSocketReadCallBack); + if (!*atEOF && ctxt->rlInfo.cffd) { + struct stat statbuf; + int ret = fstat(ctxt->fd, &statbuf); + if (0 <= ret && (S_IFREG == (statbuf.st_mode & S_IFMT))) { + off_t offset = lseek(ctxt->fd, 0, SEEK_CUR); + if (statbuf.st_size == offset) { + _CFFileDescriptorInduceFakeReadCallBack(ctxt->rlInfo.cffd); + } + } + } + if (ctxt->rlInfo.cffd) { + CFFileDescriptorEnableCallBacks(ctxt->rlInfo.cffd, kCFFileDescriptorReadCallBack); } } #else @@ -264,8 +267,8 @@ static CFIndex fileWrite(CFWriteStreamRef stream, const UInt8 *buffer, CFIndex b #ifdef REAL_FILE_SCHEDULING if (__CFBitIsSet(fileStream->flags, SCHEDULE_AFTER_WRITE)) { __CFBitClear(fileStream->flags, SCHEDULE_AFTER_WRITE); - if (fileStream->rlInfo.sock) { - CFSocketEnableCallBacks(fileStream->rlInfo.sock, kCFSocketWriteCallBack); + if (fileStream->rlInfo.cffd) { + CFFileDescriptorEnableCallBacks(fileStream->rlInfo.cffd, kCFFileDescriptorWriteCallBack); } } #else @@ -314,10 +317,10 @@ static void fileClose(struct _CFStream *stream, void *info) { close(ctxt->fd); ctxt->fd = -1; #ifdef REAL_FILE_SCHEDULING - if (ctxt->rlInfo.sock) { - CFSocketInvalidate(ctxt->rlInfo.sock); - CFRelease(ctxt->rlInfo.sock); - ctxt->rlInfo.sock = NULL; + if (ctxt->rlInfo.cffd) { + CFFileDescriptorInvalidate(ctxt->rlInfo.cffd); + CFRelease(ctxt->rlInfo.cffd); + ctxt->rlInfo.cffd = NULL; } } else if (ctxt->rlInfo.rlArray) { CFRelease(ctxt->rlInfo.rlArray); @@ -327,15 +330,14 @@ static void fileClose(struct _CFStream *stream, void *info) { } #ifdef REAL_FILE_SCHEDULING -static void fileCallBack(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) { +static void fileCallBack(CFFileDescriptorRef f, CFOptionFlags type, void *info) { struct _CFStream *stream = (struct _CFStream *)info; Boolean isReadStream = (CFGetTypeID(stream) == CFReadStreamGetTypeID()); _CFFileStreamContext *fileStream = isReadStream ? CFReadStreamGetInfoPointer((CFReadStreamRef)stream) : CFWriteStreamGetInfoPointer((CFWriteStreamRef)stream); - if (type == kCFSocketWriteCallBack) { + if (type == kCFFileDescriptorWriteCallBack) { __CFBitSet(fileStream->flags, SCHEDULE_AFTER_WRITE); CFWriteStreamSignalEvent((CFWriteStreamRef)stream, kCFStreamEventCanAcceptBytes, NULL); } else { - // type == kCFSocketReadCallBack __CFBitSet(fileStream->flags, SCHEDULE_AFTER_READ); CFReadStreamSignalEvent((CFReadStreamRef)stream, kCFStreamEventHasBytesAvailable, NULL); } @@ -359,10 +361,10 @@ static void fileSchedule(struct _CFStream *stream, CFRunLoopRef runLoop, CFStrin CFArrayAppendValue(fileStream->rlInfo.rlArray, runLoopMode); } else { CFRunLoopSourceRef rlSrc; - if (!fileStream->rlInfo.sock) { - constructCFSocket(fileStream, isReadStream, stream); + if (!fileStream->rlInfo.cffd) { + constructCFFD(fileStream, isReadStream, stream); } - rlSrc = CFSocketCreateRunLoopSource(CFGetAllocator(stream), fileStream->rlInfo.sock, 0); + rlSrc = CFFileDescriptorCreateRunLoopSource(CFGetAllocator(stream), fileStream->rlInfo.cffd, 0); CFRunLoopAddSource(runLoop, rlSrc, runLoopMode); CFRelease(rlSrc); } @@ -395,9 +397,9 @@ static void fileUnschedule(struct _CFStream *stream, CFRunLoopRef runLoop, CFStr } } } - } else if (fileStream->rlInfo.sock) { + } else if (fileStream->rlInfo.cffd) { if (__CFBitIsSet(fileStream->flags, USE_RUNLOOP_ARRAY)) { - // we know that fileStream->rlInfo.rlArray is non-NULL because it is in a union with fileStream->rlInfo.sock + // we know that fileStream->rlInfo.rlArray is non-NULL because it is in a union with fileStream->rlInfo.cffd CFMutableArrayRef runloops = fileStream->rlInfo.rlArray; CFIndex i, c; for (i = 0, c = CFArrayGetCount(runloops); i+1 < c; i += 2) { @@ -408,9 +410,9 @@ static void fileUnschedule(struct _CFStream *stream, CFRunLoopRef runLoop, CFStr } } } else { - CFRunLoopSourceRef sockSource = CFSocketCreateRunLoopSource(CFGetAllocator(stream), fileStream->rlInfo.sock, 0); - CFRunLoopRemoveSource(runLoop, sockSource, runLoopMode); - CFRelease(sockSource); + CFRunLoopSourceRef rlSrc = CFFileDescriptorCreateRunLoopSource(CFGetAllocator(stream), fileStream->rlInfo.cffd, 0); + CFRunLoopRemoveSource(runLoop, rlSrc, runLoopMode); + CFRelease(rlSrc); } } #else @@ -483,7 +485,7 @@ static void *fileCreate(struct _CFStream *stream, void *info) { } newCtxt->fd = ctxt->fd; #ifdef REAL_FILE_SCHEDULING - newCtxt->rlInfo.sock = NULL; + newCtxt->rlInfo.cffd = NULL; #else newCtxt->scheduled = 0; #endif @@ -496,9 +498,10 @@ static void fileFinalize(struct _CFStream *stream, void *info) { _CFFileStreamContext *ctxt = (_CFFileStreamContext *)info; if (ctxt->fd > 0) { #ifdef REAL_FILE_SCHEDULING - if (ctxt->rlInfo.sock) { - CFSocketInvalidate(ctxt->rlInfo.sock); - CFRelease(ctxt->rlInfo.sock); + if (ctxt->rlInfo.cffd) { + CFFileDescriptorInvalidate(ctxt->rlInfo.cffd); + CFRelease(ctxt->rlInfo.cffd); + ctxt->rlInfo.cffd = NULL; } #endif close(ctxt->fd); @@ -805,6 +808,7 @@ CF_EXPORT CFWriteStreamRef CFWriteStreamCreateWithFile(CFAllocatorRef alloc, CFU return (CFWriteStreamRef)_CFStreamCreateWithFile(alloc, fileURL, FALSE); } +// CFReadStreamRef takes ownership of the fd, and will close() it CFReadStreamRef _CFReadStreamCreateFromFileDescriptor(CFAllocatorRef alloc, int fd) { _CFFileStreamContext fileContext; fileContext.url = NULL; @@ -812,6 +816,7 @@ CFReadStreamRef _CFReadStreamCreateFromFileDescriptor(CFAllocatorRef alloc, int return (CFReadStreamRef)_CFStreamCreateWithConstantCallbacks(alloc, &fileContext, (struct _CFStreamCallBacks *)(&fileCallBacks), TRUE); } +// CFWriteStreamRef takes ownership of the fd, and will close() it CFWriteStreamRef _CFWriteStreamCreateFromFileDescriptor(CFAllocatorRef alloc, int fd) { _CFFileStreamContext fileContext; fileContext.url = NULL; @@ -858,6 +863,13 @@ CFWriteStreamRef CFWriteStreamCreateWithBuffer(CFAllocatorRef alloc, UInt8 *buff } CF_EXPORT CFWriteStreamRef CFWriteStreamCreateWithAllocatedBuffers(CFAllocatorRef alloc, CFAllocatorRef bufferAllocator) { + if (!(bufferAllocator == NULL || bufferAllocator == kCFAllocatorNull)) { + // If there is a real bufferAllocator, then we don't allow the + // CFStream or the contents to be allocated with one of the special + // *GCRefZero allocators for now. + bufferAllocator = _CFConvertAllocatorToNonGCRefZeroEquivalent(bufferAllocator); + alloc = _CFConvertAllocatorToNonGCRefZeroEquivalent(alloc); + } _CFWriteDataStreamContext ctxt; ctxt.firstBuf = NULL; ctxt.currentBuf = NULL; diff --git a/CFData.c b/CFData.c index 9c16c27..45d938d 100644 --- a/CFData.c +++ b/CFData.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFData.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Kevin Perry */ @@ -50,6 +50,11 @@ CF_INLINE unsigned long __CFPageSize() { GetSystemInfo(&sysInfo); return sysInfo.dwPageSize; } +#elif DEPLOYMENT_TARGET_LINUX +#include +CF_INLINE unsigned long __CFPageSize() { + return (unsigned long)getpagesize(); +} #endif #define INLINE_BYTES_THRESHOLD ((4 * __CFPageSize()) - sizeof(struct __CFData) - 15) @@ -59,7 +64,7 @@ struct __CFData { CFIndex _length; /* number of bytes */ CFIndex _capacity; /* maximum number of bytes */ CFAllocatorRef _bytesDeallocator; /* used only for immutable; if NULL, no deallocation */ - uint8_t *_bytes; + uint8_t *_bytes; /* compaction: direct access to _bytes is only valid when data is not inline */ }; /* @@ -111,6 +116,10 @@ CF_INLINE UInt32 __CFMutableVarietyFromFlags(UInt32 flags) { #define __CFGenericValidateMutabilityFlags(flags) \ CFAssert2(__CFMutableVarietyFromFlags(flags) != 0x2, __kCFLogAssertion, "%s(): flags 0x%x do not correctly specify the mutable variety", __PRETTY_FUNCTION__, flags); + +CF_INLINE void __CFDataSetInline(CFDataRef data, Boolean flag) { + __CFBitfieldSetValue(((CFRuntimeBase *)data)->_cfinfo[CF_INFO_BITS], 2, 2, (flag ? 1 : 0)); +} CF_INLINE Boolean __CFDataNeedsToZero(CFDataRef data) { return __CFBitfieldGetValue(((CFRuntimeBase *)data)->_cfinfo[CF_INFO_BITS], 6, 6); @@ -213,12 +222,14 @@ static Boolean __CFDataEqual(CFTypeRef cf1, CFTypeRef cf2) { CFIndex length; length = __CFDataLength(data1); if (length != __CFDataLength(data2)) return false; - return 0 == memcmp(data1->_bytes, data2->_bytes, length); + const uint8_t *bytePtr1 = CFDataGetBytePtr(data1); + const uint8_t *bytePtr2 = CFDataGetBytePtr(data2); + return 0 == memcmp(bytePtr1, bytePtr2, length); } static CFHashCode __CFDataHash(CFTypeRef cf) { CFDataRef data = (CFDataRef)cf; - return CFHashBytes(data->_bytes, __CFMin(__CFDataLength(data), 80)); + return CFHashBytes((uint8_t *)CFDataGetBytePtr(data), __CFMin(__CFDataLength(data), 80)); } static CFStringRef __CFDataCopyDescription(CFTypeRef cf) { @@ -228,7 +239,7 @@ static CFStringRef __CFDataCopyDescription(CFTypeRef cf) { CFIndex len; const uint8_t *bytes; len = __CFDataLength(data); - bytes = data->_bytes; + bytes = CFDataGetBytePtr(data); result = CFStringCreateMutable(CFGetAllocator(data), 0); CFStringAppendFormat(result, NULL, CFSTR("{length = %u, capacity = %u, bytes = 0x"), cf, CFGetAllocator(data), len, __CFDataCapacity(data)); if (24 < len) { @@ -280,12 +291,12 @@ static void *__CFDataAllocate(CFDataRef data, CFIndex size, Boolean clear) { if (clear) memset((uint8_t *)bytes, 0, size); } else { if (__CFDataAllocatesCollectable(data)) { - bytes = auto_zone_allocate_object(auto_zone(), size, AUTO_MEMORY_UNSCANNED, 0, clear); + bytes = auto_zone_allocate_object(objc_collectableZone(), size, AUTO_MEMORY_UNSCANNED, 0, clear); } else { if (clear) { - bytes = malloc_zone_calloc(malloc_default_zone(), 1, size); + bytes = calloc(1, size); } else { - bytes = malloc_zone_malloc(malloc_default_zone(), size); + bytes = malloc(size); } } } @@ -298,13 +309,13 @@ static void __CFDataDeallocate(CFTypeRef cf) { CFAllocatorRef deallocator = data->_bytesDeallocator; if (deallocator != NULL) { _CFAllocatorDeallocateGC(deallocator, data->_bytes); - CFRelease(deallocator); + if (!_CFAllocatorIsGCRefZero(deallocator)) CFRelease(deallocator); data->_bytes = NULL; } else { if (__CFDataUseAllocator(data)) { _CFAllocatorDeallocateGC(__CFGetAllocator(data), data->_bytes); - } else if (!__CFDataAllocatesCollectable(data)) { - malloc_zone_free(malloc_default_zone(), data->_bytes); + } else if (!__CFDataAllocatesCollectable(data) && data->_bytes) { + free(data->_bytes); } data->_bytes = NULL; } @@ -342,6 +353,7 @@ static CFMutableDataRef __CFDataInit(CFAllocatorRef allocator, CFOptionFlags fla CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%d) cannot be less than zero", __PRETTY_FUNCTION__, capacity); CFAssert3(kCFFixedMutable != __CFMutableVarietyFromFlags(flags) || length <= capacity, __kCFLogAssertion, "%s(): for kCFFixedMutable type, capacity (%d) must be greater than or equal to number of initial elements (%d)", __PRETTY_FUNCTION__, capacity, length); CFAssert2(0 <= length, __kCFLogAssertion, "%s(): length (%d) cannot be less than zero", __PRETTY_FUNCTION__, length); + Boolean collectableMemory = CF_IS_COLLECTABLE_ALLOCATOR(allocator); Boolean noCopy = bytesDeallocator != NULL; Boolean isMutable = ((flags & __kCFMutable) != 0); @@ -385,8 +397,8 @@ static CFMutableDataRef __CFDataInit(CFAllocatorRef allocator, CFOptionFlags fla scan = NO; } } - if (!scan) auto_zone_set_unscanned(auto_zone(), memory); - if (!finalize) auto_zone_set_nofinalize(auto_zone(), memory); + if (!scan) auto_zone_set_unscanned(objc_collectableZone(), memory); + if (!finalize) auto_zone_set_nofinalize(objc_collectableZone(), memory); } if (isMutable && isGrowable) { __CFDataSetCapacity(memory, __CFDataRoundUpCapacity(1)); @@ -401,11 +413,15 @@ static CFMutableDataRef __CFDataInit(CFAllocatorRef allocator, CFOptionFlags fla if (noCopy) { __CFAssignWithWriteBarrier((void **)&memory->_bytes, (uint8_t *)bytes); if (finalize) { - memory->_bytesDeallocator = (CFAllocatorRef)CFRetain(bytesDeallocator); + if (_CFAllocatorIsGCRefZero(bytesDeallocator)) { + memory->_bytesDeallocator = bytesDeallocator; + } else { + memory->_bytesDeallocator = (CFAllocatorRef)CFRetain(_CFConvertAllocatorToNonGCRefZeroEquivalent(bytesDeallocator)); + } } - if (CF_IS_COLLECTABLE_ALLOCATOR(bytesDeallocator)) { - // When given a GC allocator as the deallocator, we can assume that the no-copy memory is GC-allocated with a retain count of (at least) 1 and we should release it now instead of waiting until __CFDataDeallocate. - auto_zone_release(auto_zone(), memory->_bytes); + if (CF_IS_COLLECTABLE_ALLOCATOR(bytesDeallocator) && !_CFAllocatorIsGCRefZero(bytesDeallocator)) { + // When given a GC allocator which is not one of the GCRefZero ones as the deallocator, we assume that the no-copy memory is GC-allocated with a retain count of (at least) 1 and we should release it now instead of waiting until __CFDataDeallocate. + auto_zone_release(objc_collectableZone(), memory->_bytes); } __CFDataSetNumBytesUsed(memory, length); __CFDataSetLength(memory, length); @@ -421,7 +437,12 @@ static CFMutableDataRef __CFDataInit(CFAllocatorRef allocator, CFOptionFlags fla return NULL; } } else { - memory->_bytes = (uint8_t *)__CFDataInlineBytesPtr(memory); + if (length == 0 && !isMutable) { + // NSData sets its bytes pointer to NULL when its length is zero. Starting in 10.7 we do the same for CFData. + memory->_bytes = NULL; + // It is important to set this data as not inlined, so we do not recalculate a bytes pointer from null. + __CFDataSetInline(memory, false); + } cleared = true; } __CFDataSetNeedsToZero(memory, !cleared); @@ -448,11 +469,25 @@ CFDataRef CFDataCreateCopy(CFAllocatorRef allocator, CFDataRef data) { } CFMutableDataRef CFDataCreateMutable(CFAllocatorRef allocator, CFIndex capacity) { - return __CFDataInit(allocator, (0 == capacity) ? kCFMutable : kCFFixedMutable, capacity, NULL, 0, NULL); + // Do not allow magic allocator for now for mutable datas, because it + // isn't remembered for proper handling later when growth of the buffer + // has to occur. + Boolean wasMagic = _CFAllocatorIsGCRefZero(allocator); + if (0 == capacity) allocator = _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator); + CFMutableDataRef r = (CFMutableDataRef)__CFDataInit(allocator, (0 == capacity) ? kCFMutable : kCFFixedMutable, capacity, NULL, 0, NULL); + if (wasMagic) CFMakeCollectable(r); + return r; } CFMutableDataRef CFDataCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFDataRef data) { - return __CFDataInit(allocator, (0 == capacity) ? kCFMutable : kCFFixedMutable, capacity, CFDataGetBytePtr(data), CFDataGetLength(data), NULL); + // Do not allow magic allocator for now for mutable datas, because it + // isn't remembered for proper handling later when growth of the buffer + // has to occur. + Boolean wasMagic = _CFAllocatorIsGCRefZero(allocator); + if (0 == capacity) allocator = _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator); + CFMutableDataRef r = (CFMutableDataRef) __CFDataInit(allocator, (0 == capacity) ? kCFMutable : kCFFixedMutable, capacity, CFDataGetBytePtr(data), CFDataGetLength(data), NULL); + if (wasMagic) CFMakeCollectable(r); + return r; } CFIndex CFDataGetLength(CFDataRef data) { @@ -464,19 +499,21 @@ CFIndex CFDataGetLength(CFDataRef data) { const uint8_t *CFDataGetBytePtr(CFDataRef data) { CF_OBJC_FUNCDISPATCH0(__kCFDataTypeID, const uint8_t *, data, "bytes"); __CFGenericValidateType(data, __kCFDataTypeID); - return data->_bytes; + // 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"); CFAssert1(__CFDataIsMutable(data), __kCFLogAssertion, "%s(): data is immutable", __PRETTY_FUNCTION__); - return data->_bytes; + // 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); __CFDataValidateRange(data, range, __PRETTY_FUNCTION__); - memmove(buffer, data->_bytes + range.location, range.length); + memmove(buffer, CFDataGetBytePtr(data) + range.location, range.length); } /* Allocates new block of data with at least numNewValues more bytes than the current length. If clear is true, the new bytes up to at least the new length with be zeroed. */ @@ -504,7 +541,7 @@ static void __CFDataGrow(CFMutableDataRef data, CFIndex numNewValues, Boolean cl if (__CFDataUseAllocator(data)) { bytes = CFAllocatorReallocate(allocator, oldBytes, numBytes * sizeof(uint8_t), 0); } else { - bytes = malloc_zone_realloc(__CFDataAllocatesCollectable(data) ? auto_zone() : malloc_default_zone(), oldBytes, numBytes * sizeof(uint8_t)); + bytes = realloc(oldBytes, numBytes * sizeof(uint8_t)); } } if (NULL == bytes) __CFDataHandleOutOfMemory(data, numBytes * sizeof(uint8_t)); @@ -538,7 +575,7 @@ void CFDataSetLength(CFMutableDataRef data, CFIndex newLength) { CFAssert1(newLength <= __CFDataCapacity(data), __kCFLogAssertion, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__); } } else if (oldLength < newLength && __CFDataNeedsToZero(data)) { - memset(data->_bytes + oldLength, 0, newLength - oldLength); + memset(CFDataGetMutableBytePtr(data) + oldLength, 0, newLength - oldLength); } else if (newLength < oldLength) { __CFDataSetNeedsToZero(data, true); } @@ -550,6 +587,7 @@ void CFDataSetLength(CFMutableDataRef data, CFIndex newLength) { void CFDataIncreaseLength(CFMutableDataRef data, CFIndex extraLength) { CF_OBJC_FUNCDISPATCH1(__kCFDataTypeID, void, data, "increaseLengthBy:", extraLength); CFAssert1(__CFDataIsMutable(data), __kCFLogAssertion, "%s(): data is immutable", __PRETTY_FUNCTION__); + if (extraLength < 0) HALT; // Avoid integer overflow. CFDataSetLength(data, __CFDataLength(data) + extraLength); } @@ -577,22 +615,32 @@ void CFDataReplaceBytes(CFMutableDataRef data, CFRange range, const uint8_t *new CFIndex newCount = len - range.length + newLength; if (newCount < 0) HALT; + uint8_t *bytePtr = (uint8_t *)CFDataGetMutableBytePtr(data); + uint8_t *srcBuf = (uint8_t *)newBytes; switch (__CFMutableVariety(data)) { case kCFMutable: if (__CFDataNumBytes(data) < newCount) { + if (bytePtr && newBytes && newBytes < bytePtr + __CFDataCapacity(data) && bytePtr < newBytes + newLength) { + srcBuf = (uint8_t *)malloc(newLength * sizeof(uint8_t)); + memmove(srcBuf, newBytes, newLength * sizeof(uint8_t)); + } __CFDataGrow(data, newLength - range.length, false); + bytePtr = (uint8_t *)CFDataGetMutableBytePtr(data); } break; case kCFFixedMutable: CFAssert1(newCount <= __CFDataCapacity(data), __kCFLogAssertion, "%s(): fixed-capacity data is full", __PRETTY_FUNCTION__); + // Continuing after this could cause buffer overruns. + if (newCount > __CFDataCapacity(data)) HALT; break; } if (newLength != range.length && range.location + range.length < len) { - memmove(data->_bytes + range.location + newLength, data->_bytes + range.location + range.length, (len - range.location - range.length) * sizeof(uint8_t)); + memmove(bytePtr + range.location + newLength, bytePtr + range.location + range.length, (len - range.location - range.length) * sizeof(uint8_t)); } if (0 < newLength) { - memmove(data->_bytes + range.location, newBytes, newLength * sizeof(uint8_t)); + memmove(bytePtr + range.location, srcBuf, newLength * sizeof(uint8_t)); } + if (srcBuf != newBytes) free(srcBuf); __CFDataSetNumBytesUsed(data, newCount); __CFDataSetLength(data, newCount); } @@ -612,7 +660,7 @@ static void _computeGoodSubstringShift(const uint8_t *needle, int needleLength, // Compute suffix lengths suff[needleLength - 1] = needleLength; - g = needleLength - 1; + f = g = needleLength - 1; for (i = needleLength - 2; i >= 0; --i) { if (i > g && suff[i + needleLength - 1 - f] < i - g) suff[i] = suff[i + needleLength - 1 - f]; diff --git a/CFData.h b/CFData.h index 55a8961..3da7fc5 100644 --- a/CFData.h +++ b/CFData.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFData.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFDATA__) @@ -81,7 +81,7 @@ 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 +#if MAC_OS_X_VERSION_10_6 <= MAC_OS_X_VERSION_MAX_ALLOWED || __IPHONE_4_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED enum { kCFDataSearchBackwards = 1UL << 0, kCFDataSearchAnchored = 1UL << 1 @@ -90,7 +90,7 @@ enum { typedef CFOptionFlags CFDataSearchFlags; CF_EXPORT -CFRange CFDataFind(CFDataRef theData, CFDataRef dataToFind, CFRange searchRange, CFDataSearchFlags compareOptions) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CFRange CFDataFind(CFDataRef theData, CFDataRef dataToFind, CFRange searchRange, CFDataSearchFlags compareOptions) CF_AVAILABLE(10_6, 4_0); CF_EXTERN_C_END diff --git a/CFDate.c b/CFDate.c index 438f2e4..13db24b 100644 --- a/CFDate.c +++ b/CFDate.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFDate.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ @@ -34,7 +34,7 @@ #include #include "CFInternal.h" #include -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX #include #elif DEPLOYMENT_TARGET_WINDOWS #else @@ -45,6 +45,9 @@ /* 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; const CFTimeInterval kCFAbsoluteTimeIntervalSince1904 = 3061152000.0L; @@ -63,12 +66,12 @@ __private_extern__ CFTimeInterval __CFTSRToTimeInterval(int64_t tsr) { CFAbsoluteTime CFAbsoluteTimeGetCurrent(void) { CFAbsoluteTime ret; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_IPHONE +#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_SYNC || DEPLOYMENT_TARGET_CODE011 +#elif DEPLOYMENT_TARGET_WINDOWS FILETIME ft; GetSystemTimeAsFileTime(&ft); ret = _CFAbsoluteTimeFromFileTime(&ft); @@ -79,18 +82,25 @@ CFAbsoluteTime CFAbsoluteTimeGetCurrent(void) { } __private_extern__ void __CFDateInitialize(void) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_IPHONE +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED struct mach_timebase_info info; mach_timebase_info(&info); __CFTSRRate = (1.0E9 / (double)info.numer) * (double)info.denom; __CF1_TSRRate = 1.0 / __CFTSRRate; -#elif DEPLOYMENT_TARGET_WINDOWS_SYNC || DEPLOYMENT_TARGET_CODE011 +#elif DEPLOYMENT_TARGET_WINDOWS LARGE_INTEGER freq; if (!QueryPerformanceFrequency(&freq)) { HALT; } __CFTSRRate = (double)freq.QuadPart; __CF1_TSRRate = 1.0 / __CFTSRRate; +#elif DEPLOYMENT_TARGET_LINUX + struct timespec res; + if (!clock_getres(CLOCK_MONOTONIC, &res)) { + HALT; + } + __CFTSRRate = res.tv_sec + (1000000000 * res.tv_nsec); + __CF1_TSRRate = 1.0 / __CFTSRRate; #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif @@ -174,6 +184,7 @@ CFComparisonResult CFDateCompare(CFDateRef date, CFDateRef otherDate, void *cont } #endif +#endif CF_INLINE int32_t __CFDoubleModToInt(double d, int32_t modulus) { int32_t result = (int32_t)(float)floor(d - floor(d / modulus) * modulus); diff --git a/CFDate.h b/CFDate.h index 77a41f9..6292777 100644 --- a/CFDate.h +++ b/CFDate.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFDate.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFDATE__) diff --git a/CFDateFormatter.c b/CFDateFormatter.c index 53af35f..1329496 100644 --- a/CFDateFormatter.c +++ b/CFDateFormatter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,15 +22,18 @@ */ /* CFDateFormatter.c - Copyright (c) 2002-2009, Apple Inc. All rights reserved. - Responsibility: Christopher Kane + Copyright (c) 2002-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ +#define U_SHOW_INTERNAL_API 1 + #include #include #include #include #include +#include "CFPriv.h" #include "CFInternal.h" #include "CFLocaleInternal.h" #include @@ -48,10 +51,22 @@ CF_EXPORT const CFStringRef kCFDateFormatterCalendarIdentifierKey; #define BUFFER_SIZE 768 +static CFStringRef __CFDateFormatterCreateForcedTemplate(CFLocaleRef locale, CFStringRef inString); + +// If you pass in a string in tmplate, you get back NULL (failure) or a CFStringRef. +// If you pass in an array in tmplate, you get back NULL (global failure) or a CFArrayRef with CFStringRefs or kCFNulls (per-template failure) at each corresponding index. + +CFArrayRef CFDateFormatterCreateDateFormatsFromTemplates(CFAllocatorRef allocator, CFArrayRef tmplates, CFOptionFlags options, CFLocaleRef locale) { + return (CFArrayRef)CFDateFormatterCreateDateFormatFromTemplate(allocator, (CFStringRef)tmplates, options, locale); +} + CFStringRef CFDateFormatterCreateDateFormatFromTemplate(CFAllocatorRef allocator, CFStringRef tmplate, CFOptionFlags options, CFLocaleRef locale) { if (allocator) __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); if (locale) __CFGenericValidateType(locale, CFLocaleGetTypeID()); - __CFGenericValidateType(tmplate, CFStringGetTypeID()); + Boolean tmplateIsString = (CFStringGetTypeID() == CFGetTypeID(tmplate)); + if (!tmplateIsString) { + __CFGenericValidateType(tmplate, CFArrayGetTypeID()); + } CFStringRef localeName = locale ? CFLocaleGetIdentifier(locale) : CFSTR(""); char buffer[BUFFER_SIZE]; @@ -69,40 +84,56 @@ CFStringRef CFDateFormatterCreateDateFormatFromTemplate(CFAllocatorRef allocator return NULL; } - CFIndex jCount = 0; // the only interesting cases are 0, 1, and 2 (adjacent) - CFRange r = CFStringFind(tmplate, CFSTR("j"), 0); - if (kCFNotFound != r.location) { - jCount++; - if ((r.location + 1 < CFStringGetLength(tmplate)) && ('j' == CFStringGetCharacterAtIndex(tmplate, r.location + 1))) { + CFTypeRef result = tmplateIsString ? NULL : (CFTypeRef)CFArrayCreateMutable(allocator, 0, &kCFTypeArrayCallBacks); + + for (CFIndex idx = 0, cnt = tmplateIsString ? 1 : CFArrayGetCount((CFArrayRef)tmplate); idx < cnt; idx++) { + CFStringRef tmplateString = tmplateIsString ? (CFStringRef)tmplate : (CFStringRef)CFArrayGetValueAtIndex((CFArrayRef)tmplate, idx); + CFStringRef resultString = NULL; + + tmplateString = __CFDateFormatterCreateForcedTemplate(locale ? locale : CFLocaleGetSystem(), tmplateString); + + CFIndex jCount = 0; // the only interesting cases are 0, 1, and 2 (adjacent) + CFRange r = CFStringFind(tmplateString, CFSTR("j"), 0); + if (kCFNotFound != r.location) { jCount++; + if ((r.location + 1 < CFStringGetLength(tmplateString)) && ('j' == CFStringGetCharacterAtIndex(tmplateString, r.location + 1))) { + jCount++; + } } - } - UChar pattern[BUFFER_SIZE], skel[BUFFER_SIZE], bpat[BUFFER_SIZE]; - CFIndex cnt = CFStringGetLength(tmplate); - if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; - CFStringGetCharacters(tmplate, CFRangeMake(0, cnt), (UniChar *)pattern); - int32_t patlen = cnt; + UChar pattern[BUFFER_SIZE], skel[BUFFER_SIZE], bpat[BUFFER_SIZE]; + CFIndex tmpltLen = CFStringGetLength(tmplateString); + if (BUFFER_SIZE < tmpltLen) tmpltLen = BUFFER_SIZE; + CFStringGetCharacters(tmplateString, CFRangeMake(0, tmpltLen), (UniChar *)pattern); + CFRelease(tmplateString); - status = U_ZERO_ERROR; - int32_t skellen = udatpg_getSkeleton(ptg, pattern, patlen, skel, sizeof(skel) / sizeof(skel[0]), &status); - if (U_FAILURE(status)) { - return NULL; - } + int32_t patlen = tmpltLen; + status = U_ZERO_ERROR; + int32_t skellen = udatpg_getSkeleton(ptg, pattern, patlen, skel, sizeof(skel) / sizeof(skel[0]), &status); + if (!U_FAILURE(status)) { + if ((0 < jCount) && (skellen + jCount < (sizeof(skel) / sizeof(skel[0])))) { + skel[skellen++] = 'j'; + if (1 < jCount) skel[skellen++] = 'j'; + } - if ((0 < jCount) && (skellen + jCount < (sizeof(skel) / sizeof(skel[0])))) { - skel[skellen++] = 'j'; - if (1 < jCount) skel[skellen++] = 'j'; - } + status = U_ZERO_ERROR; + int32_t bpatlen = udatpg_getBestPattern(ptg, skel, skellen, bpat, sizeof(bpat) / sizeof(bpat[0]), &status); + if (!U_FAILURE(status)) { + resultString = CFStringCreateWithCharacters(allocator, (const UniChar *)bpat, bpatlen); + } + } - status = U_ZERO_ERROR; - int32_t bpatlen = udatpg_getBestPattern(ptg, skel, skellen, bpat, sizeof(bpat) / sizeof(bpat[0]), &status); - if (U_FAILURE(status)) { - return NULL; + if (tmplateIsString) { + result = (CFTypeRef)resultString; + } else { + CFArrayAppendValue((CFMutableArrayRef)result, resultString ? (CFTypeRef)resultString : (CFTypeRef)kCFNull); + if (resultString) CFRelease(resultString); + } } + udatpg_close(ptg); - return CFStringCreateWithCharacters(allocator, (const UniChar *)bpat, bpatlen); + return (CFStringRef)result; } struct __CFDateFormatter { @@ -194,6 +225,8 @@ static void __CFDateFormatterSetProperty(CFDateFormatterRef formatter, CFStringR #define RESET_PROPERTY(C, K) \ if (df->_property. C) __CFDateFormatterSetProperty(df, K, df->_property. C, true); +// This blows away any custom format string the client may have set +// on the date formatter with CFDateFormatterSetFormat(). static void __ResetUDateFormat(CFDateFormatterRef df, Boolean goingToHaveCustomFormat) { if (df->_df) udat_close(df->_df); df->_df = NULL; @@ -209,7 +242,7 @@ static void __ResetUDateFormat(CFDateFormatterRef df, Boolean goingToHaveCustomF CFStringRef tmpTZName = df->_property._TimeZone ? CFTimeZoneGetName(df->_property._TimeZone) : CFSTR("GMT"); CFStringGetCharacters(tmpTZName, CFRangeMake(0, CFStringGetLength(tmpTZName)), (UniChar *)tz_buffer); - df->_property._HasCustomFormat = kCFBooleanFalse; + df->_property._HasCustomFormat = NULL; int32_t udstyle = 0, utstyle = 0; switch (df->_dateStyle) { @@ -569,8 +602,50 @@ static void __CFDateFormatterApplySymbolPrefs(const void *key, const void *value } } +static CFStringRef __CFDateFormatterCreateForcedTemplate(CFLocaleRef locale, CFStringRef inString) { + if (!inString) return NULL; + + Boolean doForce24 = false, doForce12 = false; + CFDictionaryRef prefs = __CFLocaleGetPrefs(locale); + CFPropertyListRef pref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUForce24HourTime")) : NULL; + if (NULL != pref && CFGetTypeID(pref) == CFBooleanGetTypeID()) { + doForce24 = CFBooleanGetValue((CFBooleanRef)pref); + } + pref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUForce12HourTime")) : NULL; + if (NULL != pref && CFGetTypeID(pref) == CFBooleanGetTypeID()) { + doForce12 = CFBooleanGetValue((CFBooleanRef)pref); + } + if (doForce24) doForce12 = false; // if both are set, Force24 wins, period + if (!doForce24 && !doForce12) return (CFStringRef)CFRetain(inString); + + CFMutableStringRef outString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); + CFIndex cnt = CFStringGetLength(inString); + CFIndex lastSecond = -1, lastMinute = -1, firstHour = -1; + Boolean isInQuote = false, hasA = false, had12Hour = false, had24Hour = false; + for (CFIndex idx = 0; idx < cnt; idx++) { + Boolean emit = true; + UniChar ch = CFStringGetCharacterAtIndex(inString, idx); + switch (ch) { + case '\'': isInQuote = !isInQuote; break; + case 'j': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); if (doForce24) ch = 'H'; else ch = 'h';} break; + case 'h': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); had12Hour = true; if (doForce24) ch = 'H';} break; // switch 12-hour to 24-hour + case 'K': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); had12Hour = true; if (doForce24) ch = 'k';} break; // switch 12-hour to 24-hour + case 'H': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); had24Hour = true; if (doForce12) ch = 'h';} break; // switch 24-hour to 12-hour + case 'k': if (!isInQuote) {if (-1 == firstHour) firstHour = CFStringGetLength(outString); had24Hour = true; if (doForce12) ch = 'K';} break; // switch 24-hour to 12-hour + case 'm': if (!isInQuote) lastMinute = CFStringGetLength(outString); break; + case 's': if (!isInQuote) lastSecond = CFStringGetLength(outString); break; + case 'a': if (!isInQuote) {hasA = true; if (doForce24) emit = false;} break; + break; + } + if (emit) CFStringAppendCharacters(outString, &ch, 1); + } + + return outString; +} + static CFStringRef __CFDateFormatterCreateForcedString(CFDateFormatterRef formatter, CFStringRef inString) { if (!inString) return NULL; + Boolean doForce24 = false, doForce12 = false; CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale); CFPropertyListRef pref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUForce24HourTime")) : NULL; @@ -581,8 +656,9 @@ static CFStringRef __CFDateFormatterCreateForcedString(CFDateFormatterRef format if (NULL != pref && CFGetTypeID(pref) == CFBooleanGetTypeID()) { doForce12 = CFBooleanGetValue((CFBooleanRef)pref); } - if (!doForce24 && !doForce12) return (CFStringRef)CFRetain(inString); if (doForce24) doForce12 = false; // if both are set, Force24 wins, period + if (!doForce24 && !doForce12) return (CFStringRef)CFRetain(inString); + CFMutableStringRef outString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); CFIndex cnt = CFStringGetLength(inString); CFIndex lastSecond = -1, lastMinute = -1, firstHour = -1; @@ -715,7 +791,12 @@ void CFDateFormatterSetFormat(CFDateFormatterRef formatter, CFStringRef formatSt CFIndex cnt = CFStringGetLength(formatString); CFAssert1(cnt <= 1024, __kCFLogAssertion, "%s(): format string too long", __PRETTY_FUNCTION__); if (formatter->_format != formatString && cnt <= 1024) { - __ResetUDateFormat(formatter, true); + // When going from a situation where there is no custom format already, + // and the "relative date formatting" property is set, we need to reset + // the whole UDateFormat. + if (formatter->_property._HasCustomFormat != kCFBooleanTrue && formatter->_property._DoesRelativeDateFormatting == kCFBooleanTrue) { + __ResetUDateFormat(formatter, true); + } STACK_BUFFER_DECL(UChar, ubuffer, cnt); const UChar *ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)formatString); if (NULL == ustr) { @@ -728,6 +809,7 @@ void CFDateFormatterSetFormat(CFDateFormatterRef formatter, CFStringRef formatSt if (U_SUCCESS(status)) { if (formatter->_format) CFRelease(formatter->_format); formatter->_format = (CFStringRef)CFStringCreateCopy(CFGetAllocator(formatter), formatString); + formatter->_property._HasCustomFormat = kCFBooleanTrue; } } if (formatString) CFRelease(formatString); @@ -842,7 +924,9 @@ static void __CFDateFormatterSetSymbolsArray(UDateFormat *icudf, int32_t icucode static CFArrayRef __CFDateFormatterGetSymbolsArray(UDateFormat *icudf, int32_t icucode, int index_base) { UErrorCode status = U_ZERO_ERROR; - CFIndex idx, cnt = udat_countSymbols(icudf, (UDateFormatSymbolType)icucode) - index_base; + CFIndex idx, cnt = udat_countSymbols(icudf, (UDateFormatSymbolType)icucode); + if (cnt <= index_base) return CFArrayCreate(kCFAllocatorSystemDefault, NULL, 0, &kCFTypeArrayCallBacks); + cnt = cnt - index_base; STACK_BUFFER_DECL(CFStringRef, strings, cnt); for (idx = 0; idx < cnt; idx++) { UChar ubuffer[BUFFER_SIZE]; diff --git a/CFDateFormatter.h b/CFDateFormatter.h index cbc87df..c212e88 100644 --- a/CFDateFormatter.h +++ b/CFDateFormatter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFDateFormatter.h - Copyright (c) 2003-2009, Apple Inc. All rights reserved. + Copyright (c) 2003-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFDATEFORMATTER__) @@ -32,8 +32,6 @@ #include #include -#if MAC_OS_X_VERSION_10_3 <= MAC_OS_X_VERSION_MAX_ALLOWED - CF_EXTERN_C_BEGIN typedef struct __CFDateFormatter *CFDateFormatterRef; @@ -41,11 +39,11 @@ typedef struct __CFDateFormatter *CFDateFormatterRef; // CFDateFormatters are not thread-safe. Do not use one from multiple threads! CF_EXPORT -CFStringRef CFDateFormatterCreateDateFormatFromTemplate(CFAllocatorRef allocator, CFStringRef tmplate, CFOptionFlags options, CFLocaleRef locale) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CFStringRef CFDateFormatterCreateDateFormatFromTemplate(CFAllocatorRef allocator, CFStringRef tmplate, CFOptionFlags options, CFLocaleRef locale) CF_AVAILABLE(10_6, 4_0); // no options defined, pass 0 for now CF_EXPORT -CFTypeID CFDateFormatterGetTypeID(void) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFTypeID CFDateFormatterGetTypeID(void); enum { // date and time format styles kCFDateFormatterNoStyle = 0, @@ -69,25 +67,25 @@ typedef CFIndex CFDateFormatterStyle; // use nothing but numbers. CF_EXPORT -CFDateFormatterRef CFDateFormatterCreate(CFAllocatorRef allocator, CFLocaleRef locale, CFDateFormatterStyle dateStyle, CFDateFormatterStyle timeStyle) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFDateFormatterRef CFDateFormatterCreate(CFAllocatorRef allocator, CFLocaleRef locale, CFDateFormatterStyle dateStyle, CFDateFormatterStyle timeStyle); // Returns a CFDateFormatter, localized to the given locale, which // will format dates to the given date and time styles. CF_EXPORT -CFLocaleRef CFDateFormatterGetLocale(CFDateFormatterRef formatter) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFLocaleRef CFDateFormatterGetLocale(CFDateFormatterRef formatter); CF_EXPORT -CFDateFormatterStyle CFDateFormatterGetDateStyle(CFDateFormatterRef formatter) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFDateFormatterStyle CFDateFormatterGetDateStyle(CFDateFormatterRef formatter); CF_EXPORT -CFDateFormatterStyle CFDateFormatterGetTimeStyle(CFDateFormatterRef formatter) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFDateFormatterStyle CFDateFormatterGetTimeStyle(CFDateFormatterRef formatter); // Get the properties with which the date formatter was created. CF_EXPORT -CFStringRef CFDateFormatterGetFormat(CFDateFormatterRef formatter) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFStringRef CFDateFormatterGetFormat(CFDateFormatterRef formatter); CF_EXPORT -void CFDateFormatterSetFormat(CFDateFormatterRef formatter, CFStringRef formatString) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +void CFDateFormatterSetFormat(CFDateFormatterRef formatter, CFStringRef formatString); // Set the format description string of the date formatter. This // overrides the style settings. The format of the format string // is as defined by the ICU library. The date formatter starts with a @@ -96,19 +94,19 @@ void CFDateFormatterSetFormat(CFDateFormatterRef formatter, CFStringRef formatSt CF_EXPORT -CFStringRef CFDateFormatterCreateStringWithDate(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFDateRef date) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFStringRef CFDateFormatterCreateStringWithDate(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFDateRef date); CF_EXPORT -CFStringRef CFDateFormatterCreateStringWithAbsoluteTime(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFAbsoluteTime at) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFStringRef CFDateFormatterCreateStringWithAbsoluteTime(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFAbsoluteTime at); // Create a string representation of the given date or CFAbsoluteTime // using the current state of the date formatter. CF_EXPORT -CFDateRef CFDateFormatterCreateDateFromString(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFStringRef string, CFRange *rangep) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFDateRef CFDateFormatterCreateDateFromString(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFStringRef string, CFRange *rangep); CF_EXPORT -Boolean CFDateFormatterGetAbsoluteTimeFromString(CFDateFormatterRef formatter, CFStringRef string, CFRange *rangep, CFAbsoluteTime *atp) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +Boolean CFDateFormatterGetAbsoluteTimeFromString(CFDateFormatterRef formatter, CFStringRef string, CFRange *rangep, CFAbsoluteTime *atp); // Parse a string representation of a date using the current state // of the date formatter. The range parameter specifies the range // of the string in which the parsing should occur in input, and on @@ -119,42 +117,42 @@ Boolean CFDateFormatterGetAbsoluteTimeFromString(CFDateFormatterRef formatter, C CF_EXPORT -void CFDateFormatterSetProperty(CFDateFormatterRef formatter, CFStringRef key, CFTypeRef value) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +void CFDateFormatterSetProperty(CFDateFormatterRef formatter, CFStringRef key, CFTypeRef value); CF_EXPORT -CFTypeRef CFDateFormatterCopyProperty(CFDateFormatterRef formatter, CFStringRef key) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFTypeRef CFDateFormatterCopyProperty(CFDateFormatterRef formatter, CFStringRef key); // Set and get various properties of the date formatter, the set of // which may be expanded in the future. -CF_EXPORT const CFStringRef kCFDateFormatterIsLenient AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFBoolean -CF_EXPORT const CFStringRef kCFDateFormatterTimeZone AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFTimeZone -CF_EXPORT const CFStringRef kCFDateFormatterCalendarName AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFDateFormatterDefaultFormat AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFDateFormatterTwoDigitStartDate AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFDate -CF_EXPORT const CFStringRef kCFDateFormatterDefaultDate AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFDate -CF_EXPORT const CFStringRef kCFDateFormatterCalendar AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFCalendar -CF_EXPORT const CFStringRef kCFDateFormatterEraSymbols AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterMonthSymbols AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterShortMonthSymbols AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterWeekdaySymbols AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterShortWeekdaySymbols AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterAMSymbol AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFDateFormatterPMSymbol AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFDateFormatterLongEraSymbols AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterVeryShortMonthSymbols AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterStandaloneMonthSymbols AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterShortStandaloneMonthSymbols AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterVeryShortStandaloneMonthSymbols AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterVeryShortWeekdaySymbols AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterStandaloneWeekdaySymbols AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterShortStandaloneWeekdaySymbols AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterVeryShortStandaloneWeekdaySymbols AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterQuarterSymbols AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterShortQuarterSymbols AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterStandaloneQuarterSymbols AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterShortStandaloneQuarterSymbols AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFArray of CFString -CF_EXPORT const CFStringRef kCFDateFormatterGregorianStartDate AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFDate -CF_EXPORT const CFStringRef kCFDateFormatterDoesRelativeDateFormattingKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; // CFBoolean +CF_EXPORT const CFStringRef kCFDateFormatterIsLenient; // CFBoolean +CF_EXPORT const CFStringRef kCFDateFormatterTimeZone; // CFTimeZone +CF_EXPORT const CFStringRef kCFDateFormatterCalendarName; // CFString +CF_EXPORT const CFStringRef kCFDateFormatterDefaultFormat; // CFString +CF_EXPORT const CFStringRef kCFDateFormatterTwoDigitStartDate; // CFDate +CF_EXPORT const CFStringRef kCFDateFormatterDefaultDate; // CFDate +CF_EXPORT const CFStringRef kCFDateFormatterCalendar; // CFCalendar +CF_EXPORT const CFStringRef kCFDateFormatterEraSymbols; // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterMonthSymbols; // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterShortMonthSymbols; // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterWeekdaySymbols; // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterShortWeekdaySymbols; // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterAMSymbol; // CFString +CF_EXPORT const CFStringRef kCFDateFormatterPMSymbol; // CFString +CF_EXPORT const CFStringRef kCFDateFormatterLongEraSymbols CF_AVAILABLE(10_5, 2_0); // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterVeryShortMonthSymbols CF_AVAILABLE(10_5, 2_0); // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterStandaloneMonthSymbols CF_AVAILABLE(10_5, 2_0); // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterShortStandaloneMonthSymbols CF_AVAILABLE(10_5, 2_0); // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterVeryShortStandaloneMonthSymbols CF_AVAILABLE(10_5, 2_0); // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterVeryShortWeekdaySymbols CF_AVAILABLE(10_5, 2_0); // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterStandaloneWeekdaySymbols CF_AVAILABLE(10_5, 2_0); // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterShortStandaloneWeekdaySymbols CF_AVAILABLE(10_5, 2_0); // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterVeryShortStandaloneWeekdaySymbols CF_AVAILABLE(10_5, 2_0); // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterQuarterSymbols CF_AVAILABLE(10_5, 2_0); // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterShortQuarterSymbols CF_AVAILABLE(10_5, 2_0); // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterStandaloneQuarterSymbols CF_AVAILABLE(10_5, 2_0); // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterShortStandaloneQuarterSymbols CF_AVAILABLE(10_5, 2_0); // CFArray of CFString +CF_EXPORT const CFStringRef kCFDateFormatterGregorianStartDate CF_AVAILABLE(10_5, 2_0); // CFDate +CF_EXPORT const CFStringRef kCFDateFormatterDoesRelativeDateFormattingKey CF_AVAILABLE(10_6, 4_0); // CFBoolean // See CFLocale.h for these calendar constants: // const CFStringRef kCFGregorianCalendar; @@ -171,7 +169,5 @@ CF_EXPORT const CFStringRef kCFDateFormatterDoesRelativeDateFormattingKey AVAILA CF_EXTERN_C_END -#endif - #endif /* ! __COREFOUNDATION_CFDATEFORMATTER__ */ diff --git a/CFDictionary.c b/CFDictionary.c index fb47630..2821fe7 100644 --- a/CFDictionary.c +++ b/CFDictionary.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFDictionary.c - Copyright 1998-2008, Apple, Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane Machine generated from Notes/HashingCode.template */ @@ -46,6 +46,7 @@ const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; const CFDictionaryKeyCallBacks kCFCopyStringDictionaryKeyCallBacks = {0, __CFStringCollectionCopy, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual}; +__private_extern__ const CFDictionaryValueCallBacks kCFTypeDictionaryValueCompactableCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual}; static const CFDictionaryKeyCallBacks __kCFNullDictionaryKeyCallBacks = {0, NULL, NULL, NULL, NULL, NULL}; static const CFDictionaryValueCallBacks __kCFNullDictionaryValueCallBacks = {0, NULL, NULL, NULL, NULL}; @@ -131,95 +132,232 @@ CFTypeID CFDictionaryGetTypeID(void) { return __kCFDictionaryTypeID; } -static uintptr_t __CFDictionaryCallback(CFBasicHashRef ht, uint8_t op, uintptr_t a1, uintptr_t a2, CFBasicHashCallbacks *cb) { - switch (op) { - case kCFBasicHashCallbackOpCopyCallbacks: { - CFBasicHashCallbacks *newcb = NULL; - if (CF_IS_COLLECTABLE_ALLOCATOR((CFAllocatorRef)a1)) { - newcb = (CFBasicHashCallbacks *)auto_zone_allocate_object(auto_zone(), 10 * sizeof(void *), AUTO_MEMORY_UNSCANNED, true, false); - } else { - newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate((CFAllocatorRef)a1, 10 * sizeof(void *), 0); - } - if (!newcb) HALT; - memmove(newcb, (void *)cb, 10 * sizeof(void *)); - return (uintptr_t)newcb; - } - case kCFBasicHashCallbackOpFreeCallbacks: { - if (CF_IS_COLLECTABLE_ALLOCATOR((CFAllocatorRef)a1)) { - auto_zone_release(auto_zone(), cb); - } else { - CFAllocatorDeallocate((CFAllocatorRef)a1, cb); - } - return 0; - } - case kCFBasicHashCallbackOpRetainValue: { - const_any_pointer_t (*value_retain)(CFAllocatorRef, const_any_pointer_t) = (const_any_pointer_t (*)(CFAllocatorRef, const_any_pointer_t))cb->context[0]; - if (NULL == value_retain) return a1; - return (uintptr_t)INVOKE_CALLBACK2(value_retain, CFGetAllocator(ht), (const_any_pointer_t)a1); - } - case kCFBasicHashCallbackOpRetainKey: { - const_any_pointer_t (*key_retain)(CFAllocatorRef, const_any_pointer_t) = (const_any_pointer_t (*)(CFAllocatorRef, const_any_pointer_t))cb->context[1]; - if (NULL == key_retain) return a1; - return (uintptr_t)INVOKE_CALLBACK2(key_retain, CFGetAllocator(ht), (const_any_pointer_t)a1); - } - case kCFBasicHashCallbackOpReleaseValue: { - void (*value_release)(CFAllocatorRef, const_any_pointer_t) = (void (*)(CFAllocatorRef, const_any_pointer_t))cb->context[2]; - if (NULL != value_release) INVOKE_CALLBACK2(value_release, CFGetAllocator(ht), (const_any_pointer_t)a1); - return 0; - } - case kCFBasicHashCallbackOpReleaseKey: { - void (*key_release)(CFAllocatorRef, const_any_pointer_t) = (void (*)(CFAllocatorRef, const_any_pointer_t))cb->context[3]; - if (NULL != key_release) INVOKE_CALLBACK2(key_release, CFGetAllocator(ht), (const_any_pointer_t)a1); - return 0; - } - case kCFBasicHashCallbackOpValueEqual: { - Boolean (*value_equal)(const_any_pointer_t, const_any_pointer_t) = (Boolean (*)(const_any_pointer_t, const_any_pointer_t))cb->context[4]; - if (NULL == value_equal) return (a1 == a2); - return INVOKE_CALLBACK2(value_equal, (const_any_pointer_t)a1, (const_any_pointer_t)a2) ? 1 : 0; - } - case kCFBasicHashCallbackOpKeyEqual: { - Boolean (*key_equal)(const_any_pointer_t, const_any_pointer_t) = (Boolean (*)(const_any_pointer_t, const_any_pointer_t))cb->context[5]; - if (NULL == key_equal) return (a1 == a2); - return INVOKE_CALLBACK2(key_equal, (const_any_pointer_t)a1, (const_any_pointer_t)a2) ? 1 : 0; - } - case kCFBasicHashCallbackOpHashKey: { - CFHashCode (*hash)(const_any_pointer_t) = (CFHashCode (*)(const_any_pointer_t))cb->context[6]; - if (NULL == hash) return a1; - return (uintptr_t)INVOKE_CALLBACK1(hash, (const_any_pointer_t)a1); - } - case kCFBasicHashCallbackOpDescribeValue: { - CFStringRef (*value_describe)(const_any_pointer_t) = (CFStringRef (*)(const_any_pointer_t))cb->context[7]; - if (NULL == value_describe) return (uintptr_t)CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (const_any_pointer_t)a1); - return (uintptr_t)INVOKE_CALLBACK1(value_describe, (const_any_pointer_t)a1); - } - case kCFBasicHashCallbackOpDescribeKey: { - CFStringRef (*key_describe)(const_any_pointer_t) = (CFStringRef (*)(const_any_pointer_t))cb->context[8]; - if (NULL == key_describe) return (uintptr_t)CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (const_any_pointer_t)a1); - return (uintptr_t)INVOKE_CALLBACK1(key_describe, (const_any_pointer_t)a1); +#define GCRETAIN(A, B) kCFTypeSetCallBacks.retain(A, B) +#define GCRELEASE(A, B) kCFTypeSetCallBacks.release(A, B) + +static uintptr_t __CFDictionaryStandardRetainValue(CFConstBasicHashRef ht, uintptr_t stack_value) { + if (CFBasicHashGetSpecialBits(ht) & 0x0100) return stack_value; + return (CFBasicHashHasStrongValues(ht)) ? (uintptr_t)GCRETAIN(kCFAllocatorSystemDefault, (CFTypeRef)stack_value) : (uintptr_t)CFRetain((CFTypeRef)stack_value); +} + +static uintptr_t __CFDictionaryStandardRetainKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + if (CFBasicHashGetSpecialBits(ht) & 0x0001) return stack_key; + return (CFBasicHashHasStrongKeys(ht)) ? (uintptr_t)GCRETAIN(kCFAllocatorSystemDefault, (CFTypeRef)stack_key) : (uintptr_t)CFRetain((CFTypeRef)stack_key); +} + +static void __CFDictionaryStandardReleaseValue(CFConstBasicHashRef ht, uintptr_t stack_value) { + if (CFBasicHashGetSpecialBits(ht) & 0x0200) return; + if (CFBasicHashHasStrongValues(ht)) GCRELEASE(kCFAllocatorSystemDefault, (CFTypeRef)stack_value); else CFRelease((CFTypeRef)stack_value); +} + +static void __CFDictionaryStandardReleaseKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + if (CFBasicHashGetSpecialBits(ht) & 0x0002) return; + if (CFBasicHashHasStrongKeys(ht)) GCRELEASE(kCFAllocatorSystemDefault, (CFTypeRef)stack_key); else CFRelease((CFTypeRef)stack_key); +} + +static Boolean __CFDictionaryStandardEquateValues(CFConstBasicHashRef ht, uintptr_t coll_value1, uintptr_t stack_value2) { + if (CFBasicHashGetSpecialBits(ht) & 0x0400) return coll_value1 == stack_value2; + return CFEqual((CFTypeRef)coll_value1, (CFTypeRef)stack_value2); +} + +static Boolean __CFDictionaryStandardEquateKeys(CFConstBasicHashRef ht, uintptr_t coll_key1, uintptr_t stack_key2) { + if (CFBasicHashGetSpecialBits(ht) & 0x0004) return coll_key1 == stack_key2; + return CFEqual((CFTypeRef)coll_key1, (CFTypeRef)stack_key2); +} + +static uintptr_t __CFDictionaryStandardHashKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + if (CFBasicHashGetSpecialBits(ht) & 0x0008) return stack_key; + return (uintptr_t)CFHash((CFTypeRef)stack_key); +} + +static uintptr_t __CFDictionaryStandardGetIndirectKey(CFConstBasicHashRef ht, uintptr_t coll_value) { + return 0; +} + +static CFStringRef __CFDictionaryStandardCopyValueDescription(CFConstBasicHashRef ht, uintptr_t stack_value) { + if (CFBasicHashGetSpecialBits(ht) & 0x0800) return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)stack_value); + return CFCopyDescription((CFTypeRef)stack_value); +} + +static CFStringRef __CFDictionaryStandardCopyKeyDescription(CFConstBasicHashRef ht, uintptr_t stack_key) { + if (CFBasicHashGetSpecialBits(ht) & 0x0010) return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)stack_key); + return CFCopyDescription((CFTypeRef)stack_key); +} + +static CFBasicHashCallbacks *__CFDictionaryStandardCopyCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb); +static void __CFDictionaryStandardFreeCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb); + +static const CFBasicHashCallbacks CFDictionaryStandardCallbacks = { + __CFDictionaryStandardCopyCallbacks, + __CFDictionaryStandardFreeCallbacks, + __CFDictionaryStandardRetainValue, + __CFDictionaryStandardRetainKey, + __CFDictionaryStandardReleaseValue, + __CFDictionaryStandardReleaseKey, + __CFDictionaryStandardEquateValues, + __CFDictionaryStandardEquateKeys, + __CFDictionaryStandardHashKey, + __CFDictionaryStandardGetIndirectKey, + __CFDictionaryStandardCopyValueDescription, + __CFDictionaryStandardCopyKeyDescription +}; + +static CFBasicHashCallbacks *__CFDictionaryStandardCopyCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) { + return (CFBasicHashCallbacks *)&CFDictionaryStandardCallbacks; +} + +static void __CFDictionaryStandardFreeCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) { +} + + +static CFBasicHashCallbacks *__CFDictionaryCopyCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) { + CFBasicHashCallbacks *newcb = NULL; + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + newcb = (CFBasicHashCallbacks *)auto_zone_allocate_object(objc_collectableZone(), sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), AUTO_MEMORY_UNSCANNED, false, false); + } else { + newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), 0); } + if (!newcb) HALT; + memmove(newcb, (void *)cb, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *)); + return newcb; +} + +static void __CFDictionaryFreeCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) { + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + } else { + CFAllocatorDeallocate(allocator, cb); } +} + +static uintptr_t __CFDictionaryRetainValue(CFConstBasicHashRef ht, uintptr_t stack_value) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + const_any_pointer_t (*value_retain)(CFAllocatorRef, const_any_pointer_t) = (const_any_pointer_t (*)(CFAllocatorRef, const_any_pointer_t))cb->context[0]; + if (NULL == value_retain) return stack_value; + return (uintptr_t)INVOKE_CALLBACK2(value_retain, CFGetAllocator(ht), (const_any_pointer_t)stack_value); +} + +static uintptr_t __CFDictionaryRetainKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + const_any_pointer_t (*key_retain)(CFAllocatorRef, const_any_pointer_t) = (const_any_pointer_t (*)(CFAllocatorRef, const_any_pointer_t))cb->context[1]; + if (NULL == key_retain) return stack_key; + return (uintptr_t)INVOKE_CALLBACK2(key_retain, CFGetAllocator(ht), (const_any_pointer_t)stack_key); +} + +static void __CFDictionaryReleaseValue(CFConstBasicHashRef ht, uintptr_t stack_value) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + void (*value_release)(CFAllocatorRef, const_any_pointer_t) = (void (*)(CFAllocatorRef, const_any_pointer_t))cb->context[2]; + if (NULL != value_release) INVOKE_CALLBACK2(value_release, CFGetAllocator(ht), (const_any_pointer_t) stack_value); +} + +static void __CFDictionaryReleaseKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + void (*key_release)(CFAllocatorRef, const_any_pointer_t) = (void (*)(CFAllocatorRef, const_any_pointer_t))cb->context[3]; + if (NULL != key_release) INVOKE_CALLBACK2(key_release, CFGetAllocator(ht), (const_any_pointer_t) stack_key); +} + +static Boolean __CFDictionaryEquateValues(CFConstBasicHashRef ht, uintptr_t coll_value1, uintptr_t stack_value2) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + Boolean (*value_equal)(const_any_pointer_t, const_any_pointer_t) = (Boolean (*)(const_any_pointer_t, const_any_pointer_t))cb->context[4]; + if (NULL == value_equal) return (coll_value1 == stack_value2); + return INVOKE_CALLBACK2(value_equal, (const_any_pointer_t) coll_value1, (const_any_pointer_t) stack_value2) ? 1 : 0; +} + +static Boolean __CFDictionaryEquateKeys(CFConstBasicHashRef ht, uintptr_t coll_key1, uintptr_t stack_key2) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + Boolean (*key_equal)(const_any_pointer_t, const_any_pointer_t) = (Boolean (*)(const_any_pointer_t, const_any_pointer_t))cb->context[5]; + if (NULL == key_equal) return (coll_key1 == stack_key2); + return INVOKE_CALLBACK2(key_equal, (const_any_pointer_t) coll_key1, (const_any_pointer_t) stack_key2) ? 1 : 0; +} + +static uintptr_t __CFDictionaryHashKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + CFHashCode (*hash)(const_any_pointer_t) = (CFHashCode (*)(const_any_pointer_t))cb->context[6]; + if (NULL == hash) return stack_key; + return (uintptr_t)INVOKE_CALLBACK1(hash, (const_any_pointer_t) stack_key); +} + +static uintptr_t __CFDictionaryGetIndirectKey(CFConstBasicHashRef ht, uintptr_t coll_value) { return 0; } -static CFBasicHashRef __CFDictionaryCreateGeneric(CFAllocatorRef allocator, const CFHashKeyCallBacks *keyCallBacks, const CFHashValueCallBacks *valueCallBacks, Boolean useValueCB) { +static CFStringRef __CFDictionaryCopyValueDescription(CFConstBasicHashRef ht, uintptr_t stack_value) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + CFStringRef (*value_describe)(const_any_pointer_t) = (CFStringRef (*)(const_any_pointer_t))cb->context[8]; + if (NULL == value_describe) return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (const_any_pointer_t) stack_value); + return (CFStringRef)INVOKE_CALLBACK1(value_describe, (const_any_pointer_t) stack_value); +} - CFBasicHashCallbacks *cb = NULL; +static CFStringRef __CFDictionaryCopyKeyDescription(CFConstBasicHashRef ht, uintptr_t stack_key) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + CFStringRef (*key_describe)(const_any_pointer_t) = (CFStringRef (*)(const_any_pointer_t))cb->context[9]; + if (NULL == key_describe) return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (const_any_pointer_t) stack_key); + return (CFStringRef)INVOKE_CALLBACK1(key_describe, (const_any_pointer_t) stack_key); +} + +static CFBasicHashRef __CFDictionaryCreateGeneric(CFAllocatorRef allocator, const CFHashKeyCallBacks *keyCallBacks, const CFHashValueCallBacks *valueCallBacks, Boolean useValueCB) { CFOptionFlags flags = kCFBasicHashLinearHashing; // kCFBasicHashExponentialHashing flags |= (CFDictionary ? kCFBasicHashHasKeys : 0) | (CFBag ? kCFBasicHashHasCounts : 0); + CFBasicHashCallbacks *cb = NULL; + Boolean std_cb = false; + uint16_t specialBits = 0; const_any_pointer_t (*key_retain)(CFAllocatorRef, const_any_pointer_t) = NULL; void (*key_release)(CFAllocatorRef, const_any_pointer_t) = NULL; const_any_pointer_t (*value_retain)(CFAllocatorRef, const_any_pointer_t) = NULL; void (*value_release)(CFAllocatorRef, const_any_pointer_t) = NULL; - Boolean std_cb = false; - if ((NULL == keyCallBacks || (keyCallBacks && 0 == memcmp(&__kCFNullDictionaryKeyCallBacks, keyCallBacks, sizeof(__kCFNullDictionaryKeyCallBacks)))) - && (!useValueCB || (NULL == valueCallBacks || (valueCallBacks && 0 == memcmp(&__kCFNullDictionaryValueCallBacks, valueCallBacks, sizeof(__kCFNullDictionaryValueCallBacks)))))) { - cb = (CFBasicHashCallbacks *)& CFBasicHashNullCallbacks; - } else if ((&kCFTypeDictionaryKeyCallBacks == keyCallBacks || (keyCallBacks && 0 == memcmp(&kCFTypeDictionaryKeyCallBacks, keyCallBacks, sizeof(kCFTypeDictionaryKeyCallBacks)))) - && (!useValueCB || (&kCFTypeDictionaryValueCallBacks == valueCallBacks || (valueCallBacks && 0 == memcmp(&kCFTypeDictionaryValueCallBacks, valueCallBacks, sizeof(kCFTypeDictionaryValueCallBacks)))))) { - std_cb = true; - cb = (CFBasicHashCallbacks *)& CFBasicHashStandardCallbacks; - } else { + + if ((NULL == keyCallBacks || 0 == keyCallBacks->version) && (!useValueCB || NULL == valueCallBacks || 0 == valueCallBacks->version)) { + Boolean keyRetainNull = NULL == keyCallBacks || NULL == keyCallBacks->retain; + Boolean keyReleaseNull = NULL == keyCallBacks || NULL == keyCallBacks->release; + Boolean keyEquateNull = NULL == keyCallBacks || NULL == keyCallBacks->equal; + Boolean keyHashNull = NULL == keyCallBacks || NULL == keyCallBacks->hash; + Boolean keyDescribeNull = NULL == keyCallBacks || NULL == keyCallBacks->copyDescription; + + Boolean valueRetainNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->retain)) || (!useValueCB && keyRetainNull); + Boolean valueReleaseNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->release)) || (!useValueCB && keyReleaseNull); + Boolean valueEquateNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->equal)) || (!useValueCB && keyEquateNull); + Boolean valueDescribeNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->copyDescription)) || (!useValueCB && keyDescribeNull); + + Boolean keyRetainStd = keyRetainNull || __CFTypeCollectionRetain == keyCallBacks->retain; + Boolean keyReleaseStd = keyReleaseNull || __CFTypeCollectionRelease == keyCallBacks->release; + Boolean keyEquateStd = keyEquateNull || CFEqual == keyCallBacks->equal; + Boolean keyHashStd = keyHashNull || CFHash == keyCallBacks->hash; + Boolean keyDescribeStd = keyDescribeNull || CFCopyDescription == keyCallBacks->copyDescription; + + Boolean valueRetainStd = (useValueCB && (valueRetainNull || __CFTypeCollectionRetain == valueCallBacks->retain)) || (!useValueCB && keyRetainStd); + Boolean valueReleaseStd = (useValueCB && (valueReleaseNull || __CFTypeCollectionRelease == valueCallBacks->release)) || (!useValueCB && keyReleaseStd); + Boolean valueEquateStd = (useValueCB && (valueEquateNull || CFEqual == valueCallBacks->equal)) || (!useValueCB && keyEquateStd); + Boolean valueDescribeStd = (useValueCB && (valueDescribeNull || CFCopyDescription == valueCallBacks->copyDescription)) || (!useValueCB && keyDescribeStd); + + if (keyRetainStd && keyReleaseStd && keyEquateStd && keyHashStd && keyDescribeStd && valueRetainStd && valueReleaseStd && valueEquateStd && valueDescribeStd) { + cb = (CFBasicHashCallbacks *)&CFDictionaryStandardCallbacks; + if (!(keyRetainNull || keyReleaseNull || keyEquateNull || keyHashNull || keyDescribeNull || valueRetainNull || valueReleaseNull || valueEquateNull || valueDescribeNull)) { + std_cb = true; + } else { + // just set these to tickle the GC Strong logic below in a way that mimics past practice + key_retain = keyCallBacks ? keyCallBacks->retain : NULL; + key_release = keyCallBacks ? keyCallBacks->release : NULL; + if (useValueCB) { + value_retain = valueCallBacks ? valueCallBacks->retain : NULL; + value_release = valueCallBacks ? valueCallBacks->release : NULL; + } else { + value_retain = key_retain; + value_release = key_release; + } + } + if (keyRetainNull) specialBits |= 0x0001; + if (keyReleaseNull) specialBits |= 0x0002; + if (keyEquateNull) specialBits |= 0x0004; + if (keyHashNull) specialBits |= 0x0008; + if (keyDescribeNull) specialBits |= 0x0010; + if (valueRetainNull) specialBits |= 0x0100; + if (valueReleaseNull) specialBits |= 0x0200; + if (valueEquateNull) specialBits |= 0x0400; + if (valueDescribeNull) specialBits |= 0x0800; + } + } + + if (!cb) { Boolean (*key_equal)(const_any_pointer_t, const_any_pointer_t) = NULL; Boolean (*value_equal)(const_any_pointer_t, const_any_pointer_t) = NULL; CFStringRef (*key_describe)(const_any_pointer_t) = NULL; @@ -241,24 +379,26 @@ static CFBasicHashRef __CFDictionaryCreateGeneric(CFAllocatorRef allocator, cons value_describe = key_describe; } hash_key = keyCallBacks ? keyCallBacks->hash : NULL; - FAULT_CALLBACK((void **)&key_retain); - FAULT_CALLBACK((void **)&key_release); - FAULT_CALLBACK((void **)&value_retain); - FAULT_CALLBACK((void **)&value_release); - FAULT_CALLBACK((void **)&key_equal); - FAULT_CALLBACK((void **)&value_equal); - FAULT_CALLBACK((void **)&key_describe); - FAULT_CALLBACK((void **)&value_describe); - FAULT_CALLBACK((void **)&hash_key); CFBasicHashCallbacks *newcb = NULL; if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - newcb = (CFBasicHashCallbacks *)auto_zone_allocate_object(auto_zone(), 10 * sizeof(void *), AUTO_MEMORY_UNSCANNED, true, false); + newcb = (CFBasicHashCallbacks *)auto_zone_allocate_object(objc_collectableZone(), sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), AUTO_MEMORY_UNSCANNED, false, false); } else { - newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, 10 * sizeof(void *), 0); + newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), 0); } if (!newcb) HALT; - newcb->func = (CFBasicHashCallbackType)__CFDictionaryCallback; + newcb->copyCallbacks = __CFDictionaryCopyCallbacks; + newcb->freeCallbacks = __CFDictionaryFreeCallbacks; + newcb->retainValue = __CFDictionaryRetainValue; + newcb->retainKey = __CFDictionaryRetainKey; + newcb->releaseValue = __CFDictionaryReleaseValue; + newcb->releaseKey = __CFDictionaryReleaseKey; + newcb->equateValues = __CFDictionaryEquateValues; + newcb->equateKeys = __CFDictionaryEquateKeys; + newcb->hashKey = __CFDictionaryHashKey; + newcb->getIndirectKey = __CFDictionaryGetIndirectKey; + newcb->copyValueDescription = __CFDictionaryCopyValueDescription; + newcb->copyKeyDescription = __CFDictionaryCopyKeyDescription; newcb->context[0] = (uintptr_t)value_retain; newcb->context[1] = (uintptr_t)key_retain; newcb->context[2] = (uintptr_t)value_release; @@ -266,8 +406,8 @@ static CFBasicHashRef __CFDictionaryCreateGeneric(CFAllocatorRef allocator, cons newcb->context[4] = (uintptr_t)value_equal; newcb->context[5] = (uintptr_t)key_equal; newcb->context[6] = (uintptr_t)hash_key; - newcb->context[7] = (uintptr_t)value_describe; - newcb->context[8] = (uintptr_t)key_describe; + newcb->context[8] = (uintptr_t)value_describe; + newcb->context[9] = (uintptr_t)key_describe; cb = newcb; } @@ -278,9 +418,43 @@ static CFBasicHashRef __CFDictionaryCreateGeneric(CFAllocatorRef allocator, cons if (std_cb || key_retain != NULL || key_release != NULL) { flags |= kCFBasicHashStrongKeys; } +#if CFDictionary + if (valueCallBacks == &kCFTypeDictionaryValueCompactableCallBacks) { + // Foundation allocated collections will have compactable values + flags |= kCFBasicHashCompactableValues; + } +#endif } - return CFBasicHashCreate(allocator, flags, cb); + CFBasicHashRef ht = CFBasicHashCreate(allocator, flags, cb); + CFBasicHashSetSpecialBits(ht, specialBits); + return ht; +} + +#if CFDictionary +__private_extern__ CFHashRef __CFDictionaryCreateTransfer(CFAllocatorRef allocator, const_any_pointer_t *klist, const_any_pointer_t *vlist, CFIndex numValues) { +#endif +#if CFSet || CFBag +__private_extern__ CFHashRef __CFDictionaryCreateTransfer(CFAllocatorRef allocator, const_any_pointer_t *klist, CFIndex numValues) { + const_any_pointer_t *vlist = klist; +#endif + CFTypeID typeID = CFDictionaryGetTypeID(); + CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__, numValues); + CFOptionFlags flags = kCFBasicHashLinearHashing; // kCFBasicHashExponentialHashing + flags |= (CFDictionary ? kCFBasicHashHasKeys : 0) | (CFBag ? kCFBasicHashHasCounts : 0); + CFBasicHashCallbacks *cb = (CFBasicHashCallbacks *)&CFDictionaryStandardCallbacks; + CFBasicHashRef ht = CFBasicHashCreate(allocator, flags, cb); + CFBasicHashSetSpecialBits(ht, 0x0303); + if (0 < numValues) CFBasicHashSetCapacity(ht, numValues); + for (CFIndex idx = 0; idx < numValues; idx++) { + CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]); + } + CFBasicHashSetSpecialBits(ht, 0x0000); + CFBasicHashMakeImmutable(ht); + *(uintptr_t *)ht = __CFISAForTypeID(typeID); + _CFRuntimeSetInstanceTypeID(ht, typeID); + if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFDictionary (immutable)"); + return (CFHashRef)ht; } #if CFDictionary @@ -429,8 +603,8 @@ const_any_pointer_t CFDictionaryGetValue(CFHashRef hc, const_any_pointer_t key) } 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_FUNCDISPATCH2(__kCFDictionaryTypeID, Boolean, hc, "__getValue:forKey:", (any_t *)value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, Boolean, hc, "__getValue:forObj:", (any_t *)value, key); __CFGenericValidateType(hc, __kCFDictionaryTypeID); CFBasicHashBucket bkt = CFBasicHashFindBucket((CFBasicHashRef)hc, (uintptr_t)key); if (0 < bkt.count) { @@ -489,7 +663,8 @@ void CFDictionaryGetValues(CFHashRef hc, const_any_pointer_t *keybuf) { __CFGenericValidateType(hc, __kCFDictionaryTypeID); if (kCFUseCollectableAllocator) { CFOptionFlags flags = CFBasicHashGetFlags((CFBasicHashRef)hc); - __block const_any_pointer_t *keys = keybuf, *values = valuebuf; + __block const_any_pointer_t *keys = keybuf; + __block const_any_pointer_t *values = valuebuf; CFBasicHashApply((CFBasicHashRef)hc, ^(CFBasicHashBucket bkt) { for (CFIndex cnt = bkt.count; cnt--;) { if (keybuf && (flags & kCFBasicHashStrongKeys)) { __CFAssignWithWriteBarrier((void **)keys, (void *)bkt.weak_key); keys++; } @@ -500,14 +675,14 @@ void CFDictionaryGetValues(CFHashRef hc, const_any_pointer_t *keybuf) { return (Boolean)true; }); } else { - CFBasicHashGetElements((CFBasicHashRef)hc, CFDictionaryGetCount(hc), (uintptr_t *)valuebuf, NULL, (uintptr_t *)keybuf, NULL); + CFBasicHashGetElements((CFBasicHashRef)hc, CFDictionaryGetCount(hc), (uintptr_t *)valuebuf, (uintptr_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_FUNCDISPATCH2(__kCFDictionaryTypeID, void, hc, "__apply:context:", applier, context); + if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, void, hc, "__applyValues:context:", applier, context); __CFGenericValidateType(hc, __kCFDictionaryTypeID); CFBasicHashApply((CFBasicHashRef)hc, ^(CFBasicHashBucket bkt) { #if CFDictionary @@ -620,7 +795,7 @@ 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 (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, void, hc, "setObject:", key); __CFGenericValidateType(hc, __kCFDictionaryTypeID); CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { @@ -638,6 +813,7 @@ void CFDictionaryRemoveValue(CFMutableHashRef hc, const_any_pointer_t key) { __CFGenericValidateType(hc, __kCFDictionaryTypeID); CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { + CFLog(3, CFSTR("%s(): immutable collection %p given to mutating function"), __PRETTY_FUNCTION__, hc); } CF_OBJC_KVO_WILLCHANGE(hc, key); CFBasicHashRemoveValue((CFBasicHashRef)hc, (uintptr_t)key); diff --git a/CFDictionary.h b/CFDictionary.h index 6c3bbab..2cdcabf 100644 --- a/CFDictionary.h +++ b/CFDictionary.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFDictionary.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ /*! diff --git a/CFError.c b/CFError.c index ca1e908..86053e7 100644 --- a/CFError.c +++ b/CFError.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFError.c - Copyright 2006-2009, Apple Inc. All rights reserved. + Copyright (c) 2006-2011, Apple Inc. All rights reserved. Responsibility: Ali Ozer */ @@ -31,11 +31,7 @@ #include "CFInternal.h" #include #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -#include #include -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif /* Pre-defined userInfo keys @@ -46,6 +42,8 @@ CONST_STRING_DECL(kCFErrorLocalizedRecoverySuggestionKey, "NSLocalizedRecovery CONST_STRING_DECL(kCFErrorDescriptionKey, "NSDescription"); CONST_STRING_DECL(kCFErrorDebugDescriptionKey, "NSDebugDescription"); CONST_STRING_DECL(kCFErrorUnderlyingErrorKey, "NSUnderlyingError"); +CONST_STRING_DECL(kCFErrorURLKey, "NSURL"); +CONST_STRING_DECL(kCFErrorFilePathKey, "NSFilePath"); /* Pre-defined error domains */ @@ -178,7 +176,7 @@ CFTypeID CFErrorGetTypeID(void) { */ static CFDictionaryRef _CFErrorCreateEmptyDictionary(CFAllocatorRef allocator) { if (allocator == NULL) allocator = __CFGetDefaultAllocator(); - if (allocator == kCFAllocatorSystemDefault) { + if (_CFAllocatorIsSystemDefault(allocator)) { static CFDictionaryRef emptyErrorDictionary = NULL; if (emptyErrorDictionary == NULL) { CFDictionaryRef tmp = CFDictionaryCreate(allocator, NULL, NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); @@ -229,10 +227,13 @@ CFStringRef _CFErrorCreateLocalizedDescription(CFErrorRef err) { CFStringRef localizedDesc = _CFErrorCopyUserInfoKey(err, kCFErrorLocalizedDescriptionKey); if (localizedDesc) return localizedDesc; + +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS // Cache the CF bundle since we will be using it for localized strings. CFBundleRef cfBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreFoundation")); - + if (!cfBundle) { // This should be rare, but has been observed in the wild, due to running out of file descriptors. Normally we might not go to such extremes, but since we want to be able to present reasonable errors even in the case of errors such as running out of file descriptors, why not. This is CFError after all. !!! Be sure to have the same logic here as below for going through various options for fetching the strings. +#endif CFStringRef result = NULL, reasonOrDesc; @@ -245,8 +246,11 @@ CFStringRef _CFErrorCreateLocalizedDescription(CFErrorRef err) { } if (reasonOrDesc) CFRelease(reasonOrDesc); return result; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS } +#endif +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS // Then look for kCFErrorLocalizedFailureReasonKey; if there, create a full sentence from that. CFStringRef reason = _CFErrorCopyUserInfoKey(err, kCFErrorLocalizedFailureReasonKey); if (reason) { @@ -273,6 +277,7 @@ CFStringRef _CFErrorCreateLocalizedDescription(CFErrorRef err) { } CFRelease(localizedDomain); return result; +#endif } /* The real guts of the failure reason creation functionality. This function can take a CF or NSError. It's called by NSError for the localizedFailureReason computation. @@ -291,23 +296,29 @@ CFStringRef _CFErrorCreateLocalizedRecoverySuggestion(CFErrorRef err) { /* The "debug" description, used by CFCopyDescription and -[NSObject description]. */ +static void userInfoKeyValueShow(const void *key, const void *value, void *context) { + CFStringRef desc; + if (CFEqual(key, kCFErrorUnderlyingErrorKey) && (desc = CFErrorCopyDescription((CFErrorRef)value))) { // We check desc, see + CFStringAppendFormat((CFMutableStringRef)context, NULL, CFSTR("%@=%p \"%@\", "), key, value, desc); + CFRelease(desc); + } else { + CFStringAppendFormat((CFMutableStringRef)context, NULL, CFSTR("%@=%@, "), key, value); + } +} + CFStringRef _CFErrorCreateDebugDescription(CFErrorRef err) { CFStringRef desc = CFErrorCopyDescription(err); CFStringRef debugDesc = _CFErrorCopyUserInfoKey(err, kCFErrorDebugDescriptionKey); CFDictionaryRef userInfo = _CFErrorGetUserInfo(err); - CFErrorRef underlyingError = NULL; CFMutableStringRef result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); CFStringAppendFormat(result, NULL, CFSTR("Error Domain=%@ Code=%d"), CFErrorGetDomain(err), (long)CFErrorGetCode(err)); - if (userInfo) { - CFStringAppendFormat(result, NULL, CFSTR(" UserInfo=%p"), userInfo); - underlyingError = (CFErrorRef)CFDictionaryGetValue(userInfo, kCFErrorUnderlyingErrorKey); - } CFStringAppendFormat(result, NULL, CFSTR(" \"%@\""), desc); if (debugDesc && CFStringGetLength(debugDesc) > 0) CFStringAppendFormat(result, NULL, CFSTR(" (%@)"), debugDesc); - if (underlyingError) { - CFStringRef underlyingErrorDesc = _CFErrorCreateDebugDescription(underlyingError); - CFStringAppendFormat(result, NULL, CFSTR(" Underlying Error=(%@)"), underlyingErrorDesc); - CFRelease(underlyingErrorDesc); + if (userInfo) { + CFStringAppendFormat(result, NULL, CFSTR(" UserInfo=%p {"), userInfo); + CFDictionaryApplyFunction(userInfo, userInfoKeyValueShow, (void *)result); + CFIndex commaLength = (CFStringHasSuffix(result, CFSTR(", "))) ? 2 : 0; + CFStringReplace(result, CFRangeMake(CFStringGetLength(result)-commaLength, commaLength), CFSTR("}")); } if (debugDesc) CFRelease(debugDesc); if (desc) CFRelease(desc); @@ -418,6 +429,7 @@ static CFTypeRef _CFErrorPOSIXCallBack(CFErrorRef err, CFStringRef key) { if (!errStr) return NULL; if (CFEqual(key, kCFErrorDescriptionKey)) return errStr; // If all we wanted was the non-localized description, we're done +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS // We need a kCFErrorLocalizedFailureReasonKey, so look up a possible localization for the error message // Look for the bundle in /System/Library/CoreServices/CoreTypes.bundle CFArrayRef paths = CFCopySearchPathForDirectoriesInDomains(kCFLibraryDirectory, kCFSystemDomainMask, false); @@ -446,6 +458,7 @@ static CFTypeRef _CFErrorPOSIXCallBack(CFErrorRef err, CFStringRef key) { } CFRelease(paths); } +#endif return errStr; } @@ -460,9 +473,6 @@ static CFTypeRef _CFErrorMachCallBack(CFErrorRef err, CFStringRef key) { } return NULL; } -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif @@ -483,9 +493,6 @@ static void _CFErrorInitializeCallBackTable(void) { CFErrorSetCallBackForDomain(kCFErrorDomainPOSIX, _CFErrorPOSIXCallBack); #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED CFErrorSetCallBackForDomain(kCFErrorDomainMach, _CFErrorMachCallBack); -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif } diff --git a/CFError.h b/CFError.h index 47cef6a..12958d6 100644 --- a/CFError.h +++ b/CFError.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFError.h - Copyright (c) 2006-2009, Apple Inc. All rights reserved. + Copyright (c) 2006-2011, Apple Inc. All rights reserved. */ /*! @@ -69,25 +69,27 @@ typedef struct __CFError * CFErrorRef; Returns the type identifier of all CFError instances. */ CF_EXPORT -CFTypeID CFErrorGetTypeID(void) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFTypeID CFErrorGetTypeID(void) CF_AVAILABLE(10_5, 2_0); // Predefined domains; value of "code" will correspond to preexisting values in these domains. -CF_EXPORT const CFStringRef kCFErrorDomainPOSIX AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; -CF_EXPORT const CFStringRef kCFErrorDomainOSStatus AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; -CF_EXPORT const CFStringRef kCFErrorDomainMach AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; -CF_EXPORT const CFStringRef kCFErrorDomainCocoa AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CF_EXPORT const CFStringRef kCFErrorDomainPOSIX CF_AVAILABLE(10_5, 2_0); +CF_EXPORT const CFStringRef kCFErrorDomainOSStatus CF_AVAILABLE(10_5, 2_0); +CF_EXPORT const CFStringRef kCFErrorDomainMach CF_AVAILABLE(10_5, 2_0); +CF_EXPORT const CFStringRef kCFErrorDomainCocoa CF_AVAILABLE(10_5, 2_0); // Keys in userInfo for localizable, end-user presentable error messages. At minimum provide one of first two; ideally provide all three. -CF_EXPORT const CFStringRef kCFErrorLocalizedDescriptionKey AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // Key to identify the end user-presentable description in userInfo. -CF_EXPORT const CFStringRef kCFErrorLocalizedFailureReasonKey AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // Key to identify the end user-presentable failure reason in userInfo. -CF_EXPORT const CFStringRef kCFErrorLocalizedRecoverySuggestionKey AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // Key to identify the end user-presentable recovery suggestion in userInfo. +CF_EXPORT const CFStringRef kCFErrorLocalizedDescriptionKey CF_AVAILABLE(10_5, 2_0); // Key to identify the end user-presentable description in userInfo. +CF_EXPORT const CFStringRef kCFErrorLocalizedFailureReasonKey CF_AVAILABLE(10_5, 2_0); // Key to identify the end user-presentable failure reason in userInfo. +CF_EXPORT const CFStringRef kCFErrorLocalizedRecoverySuggestionKey CF_AVAILABLE(10_5, 2_0); // Key to identify the end user-presentable recovery suggestion in userInfo. // If you do not have localizable error strings, you can provide a value for this key instead. -CF_EXPORT const CFStringRef kCFErrorDescriptionKey AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // Key to identify the description in the userInfo dictionary. Should be a complete sentence if possible. Should not contain domain name or error code. +CF_EXPORT const CFStringRef kCFErrorDescriptionKey CF_AVAILABLE(10_5, 2_0); // Key to identify the description in the userInfo dictionary. Should be a complete sentence if possible. Should not contain domain name or error code. // Other keys in userInfo. -CF_EXPORT const CFStringRef kCFErrorUnderlyingErrorKey AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // Key to identify the underlying error in userInfo. +CF_EXPORT const CFStringRef kCFErrorUnderlyingErrorKey CF_AVAILABLE(10_5, 2_0); // Key to identify the underlying error in userInfo. +CF_EXPORT const CFStringRef kCFErrorURLKey CF_AVAILABLE(10_7, 5_0); // Key to identify associated URL in userInfo. Typically one of this or kCFErrorFilePathKey is provided. +CF_EXPORT const CFStringRef kCFErrorFilePathKey CF_AVAILABLE(10_7, 5_0); // Key to identify associated file path in userInfo. Typically one of this or kCFErrorURLKey is provided. /*! @@ -102,7 +104,7 @@ CF_EXPORT const CFStringRef kCFErrorUnderlyingErrorKey AVAILABLE_MA @result A reference to the new CFError. */ CF_EXPORT -CFErrorRef CFErrorCreate(CFAllocatorRef allocator, CFStringRef domain, CFIndex code, CFDictionaryRef userInfo) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFErrorRef CFErrorCreate(CFAllocatorRef allocator, CFStringRef domain, CFIndex code, CFDictionaryRef userInfo) CF_AVAILABLE(10_5, 2_0); /*! @function CFErrorCreateWithUserInfoKeysAndValues @@ -117,7 +119,7 @@ CFErrorRef CFErrorCreate(CFAllocatorRef allocator, CFStringRef domain, CFIndex c @result A reference to the new CFError. numUserInfoValues CF types are gathered from each of userInfoKeys and userInfoValues to create the userInfo dictionary. */ CF_EXPORT -CFErrorRef CFErrorCreateWithUserInfoKeysAndValues(CFAllocatorRef allocator, CFStringRef domain, CFIndex code, const void *const *userInfoKeys, const void *const *userInfoValues, CFIndex numUserInfoValues) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFErrorRef CFErrorCreateWithUserInfoKeysAndValues(CFAllocatorRef allocator, CFStringRef domain, CFIndex code, const void *const *userInfoKeys, const void *const *userInfoValues, CFIndex numUserInfoValues) CF_AVAILABLE(10_5, 2_0); /*! @function CFErrorGetDomain @@ -126,7 +128,7 @@ CFErrorRef CFErrorCreateWithUserInfoKeysAndValues(CFAllocatorRef allocator, CFSt @result The error domain of the CFError. Since this is a "Get" function, the caller shouldn't CFRelease the return value. */ CF_EXPORT -CFStringRef CFErrorGetDomain(CFErrorRef err) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFStringRef CFErrorGetDomain(CFErrorRef err) CF_AVAILABLE(10_5, 2_0); /*! @function CFErrorGetCode @@ -135,7 +137,7 @@ CFStringRef CFErrorGetDomain(CFErrorRef err) AVAILABLE_MAC_OS_X_VERSION_10_5_AND @result The error code of the CFError (not an error return for the current call). */ CF_EXPORT -CFIndex CFErrorGetCode(CFErrorRef err) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFIndex CFErrorGetCode(CFErrorRef err) CF_AVAILABLE(10_5, 2_0); /*! @function CFErrorCopyUserInfo @@ -145,7 +147,7 @@ CFIndex CFErrorGetCode(CFErrorRef err) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER @result The user info of the CFError. */ CF_EXPORT -CFDictionaryRef CFErrorCopyUserInfo(CFErrorRef err) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFDictionaryRef CFErrorCopyUserInfo(CFErrorRef err) CF_AVAILABLE(10_5, 2_0); /*! @function CFErrorCopyDescription @@ -159,7 +161,7 @@ CFDictionaryRef CFErrorCopyUserInfo(CFErrorRef err) AVAILABLE_MAC_OS_X_VERSION_1 @result A CFString with human-presentable description of the CFError. Never NULL. */ CF_EXPORT -CFStringRef CFErrorCopyDescription(CFErrorRef err) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFStringRef CFErrorCopyDescription(CFErrorRef err) CF_AVAILABLE(10_5, 2_0); /*! @function CFErrorCopyFailureReason @@ -171,7 +173,7 @@ CFStringRef CFErrorCopyDescription(CFErrorRef err) AVAILABLE_MAC_OS_X_VERSION_10 @result A CFString with the localized, end-user presentable failure reason of the CFError, or NULL. */ CF_EXPORT -CFStringRef CFErrorCopyFailureReason(CFErrorRef err) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFStringRef CFErrorCopyFailureReason(CFErrorRef err) CF_AVAILABLE(10_5, 2_0); /*! @function CFErrorCopyRecoverySuggestion @@ -183,7 +185,7 @@ CFStringRef CFErrorCopyFailureReason(CFErrorRef err) AVAILABLE_MAC_OS_X_VERSION_ @result A CFString with the localized, end-user presentable recovery suggestion of the CFError, or NULL. */ CF_EXPORT -CFStringRef CFErrorCopyRecoverySuggestion(CFErrorRef err) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFStringRef CFErrorCopyRecoverySuggestion(CFErrorRef err) CF_AVAILABLE(10_5, 2_0); diff --git a/CFError_Private.h b/CFError_Private.h index f3e7ae0..24b19b3 100644 --- a/CFError_Private.h +++ b/CFError_Private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFError_Private.h - Copyright (c) 2006-2009, Apple Inc. All rights reserved. + Copyright (c) 2006-2011, Apple Inc. All rights reserved. This is Apple-internal SPI for CFError. */ @@ -37,13 +37,13 @@ CF_EXTERN_C_BEGIN /* This callback function is consulted if a key is not present in the userInfo dictionary. Note that setting a callback for the same domain again simply replaces the previous callback. Set NULL as the callback to remove it. */ typedef CFTypeRef (*CFErrorUserInfoKeyCallBack)(CFErrorRef err, CFStringRef key); -CF_EXPORT void CFErrorSetCallBackForDomain(CFStringRef domainName, CFErrorUserInfoKeyCallBack callBack) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; -CF_EXPORT CFErrorUserInfoKeyCallBack CFErrorGetCallBackForDomain(CFStringRef domainName) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CF_EXPORT void CFErrorSetCallBackForDomain(CFStringRef domainName, CFErrorUserInfoKeyCallBack callBack) CF_AVAILABLE(10_5, 2_0); +CF_EXPORT CFErrorUserInfoKeyCallBack CFErrorGetCallBackForDomain(CFStringRef domainName) CF_AVAILABLE(10_5, 2_0); /* A key for "true" debugging descriptions which should never be shown to the user. It's only used when the CFError is shown to the console, and nothing else is available. For instance the rather terse and techie OSStatus descriptions are in this boat. */ -CF_EXPORT const CFStringRef kCFErrorDebugDescriptionKey AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CF_EXPORT const CFStringRef kCFErrorDebugDescriptionKey CF_AVAILABLE(10_5, 2_0); CF_EXTERN_C_END diff --git a/CFFileUtilities.c b/CFFileUtilities.c index f16d0a5..6d7c7bb 100644 --- a/CFFileUtilities.c +++ b/CFFileUtilities.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFFileUtilities.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. - Responsibility: Christopher Kane + Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Responsibility: Tony Parker */ #include "CFInternal.h" @@ -61,7 +61,6 @@ #endif - CF_INLINE int openAutoFSNoWait() { #if DEPLOYMENT_TARGET_WINDOWS return -1; @@ -218,16 +217,27 @@ __private_extern__ CFMutableArrayRef _CFContentsOfDirectory(CFAllocatorRef alloc CFIndex pathLength = dirPath ? strlen(dirPath) : 0; // MF:!!! Need to use four-letter type codes where appropriate. CFStringRef extension = (matchingAbstractType ? _CFCopyExtensionForAbstractType(matchingAbstractType) : NULL); - CFIndex extLen = (extension ? CFStringGetLength(extension) : 0); - + CFIndex targetExtLen = (extension ? CFStringGetLength(extension) : 0); #if DEPLOYMENT_TARGET_WINDOWS // This is a replacement for 'dirent' below, and also uses wchar_t to support unicode paths wchar_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 :( - if (extLen > 0) { - CFStringGetBytes(extension, CFRangeMake(0, extLen), kCFStringEncodingUTF16, 0, false, (uint8_t *)extBuff, CFMaxPathLength, &extLen); - extBuff[extLen] = '\0'; + if (targetExtLen > 0) { + CFIndex usedBytes = 0; + CFStringGetBytes(extension, CFRangeMake(0, targetExtLen), kCFStringEncodingUTF16, 0, false, (uint8_t *)extBuff, CFMaxPathLength, &usedBytes); + targetExtLen = usedBytes / sizeof(wchar_t); + extBuff[targetExtLen] = '\0'; + wchar_t *extBuffStr = (wchar_t *)extBuff; + if (extBuffStr[0] == '.') + extBuffStr++; //skip the first dot, it's legitimate to have ".plist" for example + + wchar_t *extBuffDotPtr = extBuffStr; + while ((extBuffDotPtr = wcschr(extBuffStr, '.'))) { //find the next . in the extension... + extBuffInteriorDotCount++; + extBuffStr = extBuffDotPtr + 1; + } } wchar_t pathBuf[CFMaxPathSize]; @@ -284,22 +294,52 @@ __private_extern__ CFMutableArrayRef _CFContentsOfDirectory(CFAllocatorRef alloc continue; } - if (extLen > namelen) continue; // if the extension is the same length or longer than the name, it can't possibly match. - - if (extLen > 0) { + if (targetExtLen > namelen) continue; // if the extension is the same length or longer than the name, it can't possibly match. + + if (targetExtLen > 0) { + if (file.cFileName[namelen - 1] == '.') continue; //filename ends with a dot, no extension + + wchar_t *fileExt = NULL; + + if (extBuffInteriorDotCount == 0) { + fileExt = wcsrchr(file.cFileName, '.'); + } else { //find the Nth occurrence of . from the end of the string, to handle ".foo.bar" + wchar_t *save = file.cFileName; + while ((save = wcschr(save, '.')) && !fileExt) { + wchar_t *temp = save; + int moreDots = 0; + while ((temp = wcschr(temp, '.'))) { + if (++moreDots == extBuffInteriorDotCount) break; + } + if (moreDots == extBuffInteriorDotCount) { + fileExt = save; + } + } + } + + if (!fileExt) continue; //no extension + + if (((const wchar_t *)extBuff)[0] != '.') + fileExt++; //omit the dot if the target file extension omits the dot + + CFIndex fileExtLen = wcslen(fileExt); + + //if the extensions are different lengths, they can't possibly match + if (fileExtLen != targetExtLen) continue; + // Check to see if it matches the extension we're looking for. - if (_wcsicmp(&(file.cFileName[namelen - extLen]), (const wchar_t *)extBuff) != 0) { + if (_wcsicmp(fileExt, (const wchar_t *)extBuff) != 0) { continue; } } if (dirURL == NULL) { - CFStringRef dirURLStr = CFStringCreateWithBytes(alloc, (const uint8_t *)pathBuf, pathLength, kCFStringEncodingUTF16, NO); + CFStringRef dirURLStr = CFStringCreateWithBytes(alloc, (const uint8_t *)pathBuf, pathLength * sizeof(wchar_t), kCFStringEncodingUTF16, NO); dirURL = CFURLCreateWithFileSystemPath(alloc, dirURLStr, kCFURLWindowsPathStyle, true); CFRelease(dirURLStr); releaseBase = true; } // MF:!!! What about the trailing slash? - CFStringRef fileURLStr = CFStringCreateWithBytes(alloc, (const uint8_t *)file.cFileName, namelen, kCFStringEncodingUTF16, NO); + CFStringRef fileURLStr = CFStringCreateWithBytes(alloc, (const uint8_t *)file.cFileName, namelen * sizeof(wchar_t), kCFStringEncodingUTF16, NO); fileURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, fileURLStr, kCFURLWindowsPathStyle, (file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? true : false, dirURL); CFArrayAppendValue(files, fileURL); CFRelease(fileURL); @@ -310,10 +350,20 @@ __private_extern__ CFMutableArrayRef _CFContentsOfDirectory(CFAllocatorRef alloc #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || 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 :( - if (extLen > 0) { - CFStringGetBytes(extension, CFRangeMake(0, extLen), CFStringFileSystemEncoding(), 0, false, extBuff, CFMaxPathLength, &extLen); - extBuff[extLen] = '\0'; + if (targetExtLen > 0) { + CFStringGetBytes(extension, CFRangeMake(0, targetExtLen), CFStringFileSystemEncoding(), 0, false, extBuff, CFMaxPathLength, &targetExtLen); + extBuff[targetExtLen] = '\0'; + char *extBuffStr = (char *)extBuff; + if (extBuffStr[0] == '.') + extBuffStr++; //skip the first dot, it's legitimate to have ".plist" for example + + char *extBuffDotPtr = extBuffStr; + while ((extBuffDotPtr = strchr(extBuffStr, '.'))) { //find the next . in the extension... + extBuffInteriorDotCount++; + extBuffStr = extBuffDotPtr + 1; + } } uint8_t pathBuf[CFMaxPathSize]; @@ -354,11 +404,40 @@ __private_extern__ CFMutableArrayRef _CFContentsOfDirectory(CFAllocatorRef alloc continue; } - if (extLen > namelen) continue; // if the extension is the same length or longer than the name, it can't possibly match. - - if (extLen > 0) { - // Check to see if it matches the extension we're looking for. - if (strncmp(&(dp->d_name[namelen - extLen]), (char *)extBuff, extLen) != 0) { + if (targetExtLen > namelen) continue; // if the extension is the same length or longer than the name, it can't possibly match. + + if (targetExtLen > 0) { + if (dp->d_name[namelen - 1] == '.') continue; //filename ends with a dot, no extension + + char *fileExt = NULL; + if (extBuffInteriorDotCount == 0) { + fileExt = strrchr(dp->d_name, '.'); + } else { //find the Nth occurrence of . from the end of the string, to handle ".foo.bar" + char *save = dp->d_name; + while ((save = strchr(save, '.')) && !fileExt) { + char *temp = save; + int moreDots = 0; + while ((temp = strchr(temp, '.'))) { + if (++moreDots == extBuffInteriorDotCount) break; + } + if (moreDots == extBuffInteriorDotCount) { + fileExt = save; + } + } + } + + if (!fileExt) continue; //no extension + + if (((char *)extBuff)[0] != '.') + fileExt++; //omit the dot if the target extension omits the dot; safe, because we checked to make sure it isn't the last character just before + + size_t fileExtLen = strlen(fileExt); + + //if the extensions are different lengths, they can't possibly match + if (fileExtLen != targetExtLen) continue; + + // Check to see if it matches the extension we're looking for. + if (strncmp(fileExt, (char *)extBuff, fileExtLen) != 0) { continue; } } @@ -379,9 +458,17 @@ __private_extern__ CFMutableArrayRef _CFContentsOfDirectory(CFAllocatorRef alloc isDir = ((statBuf.st_mode & S_IFMT) == S_IFDIR); } } +#if DEPLOYMENT_TARGET_LINUX + fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc, (uint8_t *)dp->d_name, namelen, isDir, dirURL); +#else fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc, (uint8_t *)dp->d_name, dp->d_namlen, isDir, dirURL); +#endif } else { +#if DEPLOYMENT_TARGET_LINUX + fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase (alloc, (uint8_t *)dp->d_name, namelen, false, dirURL); +#else fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase (alloc, (uint8_t *)dp->d_name, dp->d_namlen, false, dirURL); +#endif } CFArrayAppendValue(files, fileURL); CFRelease(fileURL); @@ -414,22 +501,17 @@ __private_extern__ CFMutableArrayRef _CFContentsOfDirectory(CFAllocatorRef alloc return files; } -__private_extern__ SInt32 _CFGetFileProperties(CFAllocatorRef alloc, CFURLRef pathURL, Boolean *exists, SInt32 *posixMode, int64_t *size, CFDateRef *modTime, SInt32 *ownerID, CFArrayRef *dirContents) { +__private_extern__ SInt32 _CFGetPathProperties(CFAllocatorRef alloc, char *path, Boolean *exists, SInt32 *posixMode, int64_t *size, CFDateRef *modTime, SInt32 *ownerID, CFArrayRef *dirContents) { Boolean fileExists; Boolean isDirectory = false; - + if ((exists == NULL) && (posixMode == NULL) && (size == NULL) && (modTime == NULL) && (ownerID == NULL) && (dirContents == NULL)) { // Nothing to do. return 0; } - + struct statinfo statBuf; - char path[CFMaxPathSize]; - - if (!CFURLGetFileSystemRepresentation(pathURL, true, (uint8_t *)path, CFMaxPathLength)) { - return -1; - } - + if (stat(path, &statBuf) != 0) { // stat failed, but why? if (thread_errno() == ENOENT) { @@ -441,35 +523,35 @@ __private_extern__ SInt32 _CFGetFileProperties(CFAllocatorRef alloc, CFURLRef pa fileExists = true; isDirectory = ((statBuf.st_mode & S_IFMT) == S_IFDIR); } - - + + if (exists != NULL) { *exists = fileExists; } - + if (posixMode != NULL) { if (fileExists) { - + *posixMode = statBuf.st_mode; - + } else { *posixMode = 0; } } - + if (size != NULL) { if (fileExists) { - + *size = statBuf.st_size; - + } else { *size = 0; } } - + if (modTime != NULL) { if (fileExists) { -#if DEPLOYMENT_TARGET_WINDOWS +#if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX struct timespec ts = {statBuf.st_mtime, 0}; #else struct timespec ts = statBuf.st_mtimespec; @@ -479,12 +561,12 @@ __private_extern__ SInt32 _CFGetFileProperties(CFAllocatorRef alloc, CFURLRef pa *modTime = NULL; } } - + if (ownerID != NULL) { if (fileExists) { - + *ownerID = statBuf.st_uid; - + } else { *ownerID = -1; } @@ -492,9 +574,9 @@ __private_extern__ SInt32 _CFGetFileProperties(CFAllocatorRef alloc, CFURLRef pa if (dirContents != NULL) { if (fileExists && isDirectory) { - - CFMutableArrayRef contents = _CFContentsOfDirectory(alloc, (char *)path, NULL, pathURL, NULL); - + + CFMutableArrayRef contents = _CFContentsOfDirectory(alloc, (char *)path, NULL, NULL, NULL); + if (contents) { *dirContents = contents; } else { @@ -507,6 +589,17 @@ __private_extern__ SInt32 _CFGetFileProperties(CFAllocatorRef alloc, CFURLRef pa return 0; } +__private_extern__ SInt32 _CFGetFileProperties(CFAllocatorRef alloc, CFURLRef pathURL, Boolean *exists, SInt32 *posixMode, int64_t *size, CFDateRef *modTime, SInt32 *ownerID, CFArrayRef *dirContents) { + + char path[CFMaxPathSize]; + + if (!CFURLGetFileSystemRepresentation(pathURL, true, (uint8_t *)path, CFMaxPathLength)) { + return -1; + } + + return _CFGetPathProperties(alloc, path, exists, posixMode, size, modTime, ownerID, dirContents); +} + // 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 @@ -585,6 +678,30 @@ __private_extern__ Boolean _CFStripTrailingPathSlashes(UniChar *unichars, CFInde return (oldLength != *length); } +__private_extern__ Boolean _CFAppendTrailingPathSlash(UniChar *unichars, CFIndex *length, CFIndex maxLength) { + if (maxLength < *length + 1) { + return false; + } + switch (*length) { + case 0: + break; + case 1: + if (!IS_SLASH(unichars[0])) { + unichars[(*length)++] = CFPreferredSlash; + } + break; + case 2: + if (!HAS_DRIVE(unichars) && !HAS_NET(unichars)) { + unichars[(*length)++] = CFPreferredSlash; + } + break; + default: + unichars[(*length)++] = CFPreferredSlash; + break; + } + return true; +} + __private_extern__ Boolean _CFAppendPathComponent(UniChar *unichars, CFIndex *length, CFIndex maxLength, UniChar *component, CFIndex componentLength) { if (0 == componentLength) { return true; @@ -592,23 +709,7 @@ __private_extern__ Boolean _CFAppendPathComponent(UniChar *unichars, CFIndex *le if (maxLength < *length + 1 + componentLength) { return false; } - switch (*length) { - case 0: - break; - case 1: - if (!IS_SLASH(unichars[0])) { - unichars[(*length)++] = CFPreferredSlash; - } - break; - case 2: - if (!HAS_DRIVE(unichars) && !HAS_NET(unichars)) { - unichars[(*length)++] = CFPreferredSlash; - } - break; - default: - unichars[(*length)++] = CFPreferredSlash; - break; - } + _CFAppendTrailingPathSlash(unichars, length, maxLength); memmove(unichars + *length, component, componentLength * sizeof(UniChar)); *length += componentLength; return true; diff --git a/CFICUConverters.c b/CFICUConverters.c index da91618..27cce6a 100644 --- a/CFICUConverters.c +++ b/CFICUConverters.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,29 +21,21 @@ * @APPLE_LICENSE_HEADER_END@ */ -/* - * CFICUConverters.c - * CoreFoundation - * - * Created by Aki Inoue on 07/12/04. - * Copyright 2007-2009, Apple Inc. All rights reserved. - * - */ +/* CFICUConverters.c + Copyright (c) 2004-2011, Apple Inc. All rights reserved. + Responsibility: Aki Inoue +*/ #include "CFStringEncodingDatabase.h" #include "CFStringEncodingConverterPriv.h" #include "CFICUConverters.h" #include +#include #include #include #include "CFInternal.h" #include -#if DEPLOYMENT_TARGET_WINDOWS -#define strncasecmp_l(a, b, c, d) _strnicmp(a, b, c) -#define snprintf _snprintf -#endif - // Thread data support typedef struct { uint8_t _numSlots; @@ -68,39 +60,19 @@ static void __CFICUThreadDataDestructor(void *context) { CFAllocatorDeallocate(NULL, data); } -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -#import - CF_INLINE __CFICUThreadData *__CFStringEncodingICUGetThreadData() { __CFICUThreadData * data; - pthread_key_init_np(__CFTSDKeyICUConverter, __CFICUThreadDataDestructor); - data = (__CFICUThreadData *)pthread_getspecific(__CFTSDKeyICUConverter); + data = (__CFICUThreadData *)_CFGetTSD(__CFTSDKeyICUConverter); if (NULL == data) { data = (__CFICUThreadData *)CFAllocatorAllocate(NULL, sizeof(__CFICUThreadData), 0); memset(data, 0, sizeof(__CFICUThreadData)); - pthread_setspecific(__CFTSDKeyICUConverter, (const void *)data); + _CFSetTSD(__CFTSDKeyICUConverter, (void *)data, __CFICUThreadDataDestructor); } return data; } -#elif DEPLOYMENT_TARGET_WINDOWS -__private_extern__ void __CFStringEncodingICUThreadDataCleaner(void *context) { __CFICUThreadDataDestructor(context); } - -CF_INLINE __CFICUThreadData *__CFStringEncodingICUGetThreadData() { - __CFThreadSpecificData *threadData = __CFGetThreadSpecificData_inline(); - - if (NULL == threadData->_icuThreadData) { - threadData->_icuThreadData = (__CFICUThreadData *)CFAllocatorAllocate(NULL, sizeof(__CFICUThreadData), 0); - memset(threadData->_icuThreadData, 0, sizeof(__CFICUThreadData)); - } - - return (__CFICUThreadData *)threadData->_icuThreadData; -} -#else -#error Need implementation for thread data -#endif __private_extern__ const char *__CFStringEncodingGetICUName(CFStringEncoding encoding) { #define STACK_BUFFER_SIZE (60) @@ -265,9 +237,11 @@ static CFIndex __CFStringEncodingConverterReleaseICUConverter(UConverter *conver #define MAX_BUFFER_SIZE (1000) -#if (U_ICU_VERSION_MAJOR_NUM > 4) || ((U_ICU_VERSION_MAJOR_NUM == 4) && (U_ICU_VERSION_MINOR_NUM > 0)) +#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)) #warning Unknown ICU version. Check binary compatibility issues for rdar://problem/6024743 #endif +#endif #define HAS_ICU_BUG_6024743 (1) #define HAS_ICU_BUG_6025527 (1) @@ -301,7 +275,43 @@ __private_extern__ CFIndex __CFStringEncodingICUToBytes(const char *icuName, uin if (NULL != usedByteLen) *usedByteLen = totalLength; } else { ucnv_fromUnicode(converter, &destination, destinationLimit, (const UChar **)&source, (const UChar *)sourceLimit, NULL, flush, &errorCode); - + +#if HAS_ICU_BUG_6024743 +/* Another critical ICU design issue. Similar to conversion error, source pointer returned from U_BUFFER_OVERFLOW_ERROR is already beyond the last valid character position. It renders the returned value from source entirely unusable. We have to manually back up until succeeding Intrestingly, this issue doesn't apply to ucnv_toUnicode. The asynmmetric nature makes this more dangerous */ + if (U_BUFFER_OVERFLOW_ERROR == errorCode) { + const uint8_t *bitmap = CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, 0); + const uint8_t *nonBase; + UTF32Char character; + + do { + // Since the output buffer is filled, we can assume no invalid chars (including stray surrogates) + do { + sourceLimit = (source - 1); + character = *sourceLimit; + nonBase = bitmap; + + if (CFUniCharIsSurrogateLowCharacter(character)) { + --sourceLimit; + character = CFUniCharGetLongCharacterForSurrogatePair(*sourceLimit, character); + nonBase = CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, (character >> 16) & 0x000F); + character &= 0xFFFF; + } + } while ((sourceLimit > characters) && CFUniCharIsMemberOfBitmap(character, nonBase)); + + if (sourceLimit > characters) { + source = characters; + destination = (char *)bytes; + errorCode = U_ZERO_ERROR; + + ucnv_resetFromUnicode(converter); + + ucnv_fromUnicode(converter, &destination, destinationLimit, (const UChar **)&source, (const UChar *)sourceLimit, NULL, flush, &errorCode); + } + } while (U_BUFFER_OVERFLOW_ERROR == errorCode); + + errorCode = U_BUFFER_OVERFLOW_ERROR; + } +#endif if (NULL != usedByteLen) *usedByteLen = destination - (const char *)bytes; } diff --git a/CFICUConverters.h b/CFICUConverters.h index 47fe65f..097e51b 100644 --- a/CFICUConverters.h +++ b/CFICUConverters.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,7 +26,7 @@ * CoreFoundation * * Created by Aki Inoue on 07/12/04. - * Copyright (c) 2007-2009, Apple Inc. All rights reserved. + * Copyright (c) 2007-2011, Apple Inc. All rights reserved. * */ @@ -45,7 +45,4 @@ __private_extern__ CFIndex __CFStringEncodingICUByteLength(const char *icuName, // The caller is responsible for freeing the memory (use CFAllocatorDeallocate) __private_extern__ CFStringEncoding *__CFStringEncodingCreateICUEncodings(CFAllocatorRef allocator, CFIndex *numberOfIndex); -#if DEPLOYMENT_TARGET_WINDOWS -__private_extern__ void __CFStringEncodingICUThreadDataCleaner(void *context); -#endif diff --git a/CFInternal.h b/CFInternal.h index 7f8d9a6..c573ea8 100644 --- a/CFInternal.h +++ b/CFInternal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFInternal.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ /* @@ -36,6 +36,47 @@ #if !defined(__COREFOUNDATION_CFINTERNAL__) #define __COREFOUNDATION_CFINTERNAL__ 1 +#define __CF_COMPILE_YEAR__ (__DATE__[7] * 1000 + __DATE__[8] * 100 + __DATE__[9] * 10 + __DATE__[10] - 53328) +#define __CF_COMPILE_MONTH__ ((__DATE__[1] + __DATE__[2] == 207) ? 1 : \ + (__DATE__[1] + __DATE__[2] == 199) ? 2 : \ + (__DATE__[1] + __DATE__[2] == 211) ? 3 : \ + (__DATE__[1] + __DATE__[2] == 226) ? 4 : \ + (__DATE__[1] + __DATE__[2] == 218) ? 5 : \ + (__DATE__[1] + __DATE__[2] == 227) ? 6 : \ + (__DATE__[1] + __DATE__[2] == 225) ? 7 : \ + (__DATE__[1] + __DATE__[2] == 220) ? 8 : \ + (__DATE__[1] + __DATE__[2] == 213) ? 9 : \ + (__DATE__[1] + __DATE__[2] == 215) ? 10 : \ + (__DATE__[1] + __DATE__[2] == 229) ? 11 : \ + (__DATE__[1] + __DATE__[2] == 200) ? 12 : 0) +#define __CF_COMPILE_DAY__ (__DATE__[4] * 10 + __DATE__[5] - (__DATE__[4] == ' ' ? 368 : 528)) +#define __CF_COMPILE_DATE__ (__CF_COMPILE_YEAR__ * 10000 + __CF_COMPILE_MONTH__ * 100 + __CF_COMPILE_DAY__) + +#define __CF_COMPILE_HOUR__ (__TIME__[0] * 10 + __TIME__[1] - 528) +#define __CF_COMPILE_MINUTE__ (__TIME__[3] * 10 + __TIME__[4] - 528) +#define __CF_COMPILE_SECOND__ (__TIME__[6] * 10 + __TIME__[7] - 528) +#define __CF_COMPILE_TIME__ (__CF_COMPILE_HOUR__ * 10000 + __CF_COMPILE_MINUTE__ * 100 + __CF_COMPILE_SECOND__) + +#define __CF_COMPILE_SECOND_OF_DAY__ (__CF_COMPILE_HOUR__ * 3600 + __CF_COMPILE_MINUTE__ * 60 + __CF_COMPILE_SECOND__) + +// __CF_COMPILE_DAY_OF_EPOCH__ works within Gregorian years 2001 - 2099; the epoch is of course CF's epoch +#define __CF_COMPILE_DAY_OF_EPOCH__ ((__CF_COMPILE_YEAR__ - 2001) * 365 + (__CF_COMPILE_YEAR__ - 2001) / 4 \ + + ((__DATE__[1] + __DATE__[2] == 207) ? 0 : \ + (__DATE__[1] + __DATE__[2] == 199) ? 31 : \ + (__DATE__[1] + __DATE__[2] == 211) ? 59 + (__CF_COMPILE_YEAR__ % 4 == 0) : \ + (__DATE__[1] + __DATE__[2] == 226) ? 90 + (__CF_COMPILE_YEAR__ % 4 == 0) : \ + (__DATE__[1] + __DATE__[2] == 218) ? 120 + (__CF_COMPILE_YEAR__ % 4 == 0) : \ + (__DATE__[1] + __DATE__[2] == 227) ? 151 + (__CF_COMPILE_YEAR__ % 4 == 0) : \ + (__DATE__[1] + __DATE__[2] == 225) ? 181 + (__CF_COMPILE_YEAR__ % 4 == 0) : \ + (__DATE__[1] + __DATE__[2] == 220) ? 212 + (__CF_COMPILE_YEAR__ % 4 == 0) : \ + (__DATE__[1] + __DATE__[2] == 213) ? 243 + (__CF_COMPILE_YEAR__ % 4 == 0) : \ + (__DATE__[1] + __DATE__[2] == 215) ? 273 + (__CF_COMPILE_YEAR__ % 4 == 0) : \ + (__DATE__[1] + __DATE__[2] == 229) ? 304 + (__CF_COMPILE_YEAR__ % 4 == 0) : \ + (__DATE__[1] + __DATE__[2] == 200) ? 334 + (__CF_COMPILE_YEAR__ % 4 == 0) : \ + 365 + (__CF_COMPILE_YEAR__ % 4 == 0)) \ + + __CF_COMPILE_DAY__) + + CF_EXTERN_C_BEGIN #include @@ -43,16 +84,11 @@ CF_EXTERN_C_BEGIN #include #include #include -#include -#include #include #include #include -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX #include -#include -#include -#include #include #endif #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD @@ -81,17 +117,18 @@ CF_EXTERN_C_BEGIN CF_EXPORT const char *_CFProcessName(void); CF_EXPORT CFStringRef _CFProcessNameString(void); -CF_EXPORT Boolean _CFIsCFM(void); - CF_EXPORT Boolean _CFGetCurrentDirectory(char *path, int maxlen); -CF_EXPORT CFStringRef _CFGetUserName(void); - CF_EXPORT CFArrayRef _CFGetWindowsBinaryDirectories(void); CF_EXPORT CFStringRef _CFStringCreateHostName(void); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#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) @@ -134,6 +171,9 @@ CF_EXPORT void _CFMachPortInstallNotifyPort(CFRunLoopRef rl, CFStringRef mode); #define __kCFLogAssertion 3 +// This CF-only log function uses no CF functionality, so it may be called anywhere within CF - including thread teardown or prior to full CF setup +__private_extern__ void _CFLogSimple(int32_t lev, char *format, ...); + #if defined(DEBUG) extern void __CFGenericValidateType_(CFTypeRef cf, CFTypeID type, const char *func); #define __CFGenericValidateType(cf, type) __CFGenericValidateType_(cf, type, __PRETTY_FUNCTION__) @@ -157,83 +197,34 @@ extern void __CFGenericValidateType_(CFTypeRef cf, CFTypeID type, const char *fu #define __CFBitSet(V, N) ((V) |= (1UL << (N))) #define __CFBitClear(V, N) ((V) &= ~(1UL << (N))) - -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -// The fixed range 50 - 59 of pthread_specific keys is reserved -// for CoreFoundation; see . -// 60 - 69 are reserved for Foundation; Foundation uses 64 - 69 -// and reserves 60-63 for CoreFoundation. +// Foundation uses 20-40 // Foundation knows about the value of __CFTSDKeyAutoreleaseData1 enum { - __CFTSDKeyUnused50 = 50, - __CFTSDKeyAllocator = 51, - __CFTSDKeyExceptionData = 52, - __CFTSDKeyRunLoopCntr = 53, - __CFTSDKeyRunLoop = 54, - __CFTSDKeyICUConverter = 55, - __CFTSDKeyCollatorLocale = 56, - __CFTSDKeyCollatorUCollator = 57, - __CFTSDKeyIsInNSCache = 58, - __CFTSDKeyIsInCFLog = 59, - __CFTSDKeyIsInGCDMainQ = 60, - __CFTSDKeyUnused61 = 61, + __CFTSDKeyAllocator = 1, + __CFTSDKeyIsInCFLog = 2, + __CFTSDKeyIsInNSCache = 3, + __CFTSDKeyIsInGCDMainQ = 4, + __CFTSDKeyICUConverter = 7, + __CFTSDKeyCollatorLocale = 8, + __CFTSDKeyCollatorUCollator = 9, + __CFTSDKeyRunLoop = 10, + __CFTSDKeyRunLoopCntr = 11, + // autorelease pool stuff must be higher than run loop constants + __CFTSDKeyAutoreleaseData2 = 61, __CFTSDKeyAutoreleaseData1 = 62, - __CFTSDKeyAutoreleaseData2 = 63, // autorelease pool stuff must be higher than run loop constants + __CFTSDKeyExceptionData = 63, }; -extern int pthread_key_init_np(int, void (*)(void *)); -#endif - -#if DEPLOYMENT_TARGET_WINDOWS -typedef struct ___CFThreadSpecificData { - void *_unused1; - void *_allocator; - void *_runLoop; - int _runLoop_pid; - HHOOK _messageHook; - void *_icuThreadData; - -// If you add things to this struct, add cleanup to __CFFinalizeThreadData() -} __CFThreadSpecificData; - -extern __CFThreadSpecificData *__CFGetThreadSpecificData(void); -__private_extern__ void __CFFinalizeThreadData(void *arg); -extern DWORD __CFTSDKey; - -// implemented in windowsSyncHelper.c -__private_extern__ __CFThreadSpecificData *__CFGetThreadSpecificData_inline(void); - -#endif - #define __kCFAllocatorTypeID_CONST 2 CF_INLINE CFAllocatorRef __CFGetDefaultAllocator(void) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - CFAllocatorRef allocator = pthread_getspecific(__CFTSDKeyAllocator); -#else - CFAllocatorRef allocator = (CFAllocatorRef)__CFGetThreadSpecificData_inline()->_allocator; -#endif + CFAllocatorRef allocator = (CFAllocatorRef)_CFGetTSD(__CFTSDKeyAllocator); if (NULL == allocator) { allocator = kCFAllocatorSystemDefault; } return allocator; } -extern CFTypeID __CFGenericTypeID(const void *cf); - -// This should only be used in CF types, not toll-free bridged objects! -// It should not be used with CFAllocator arguments! -// Use CFGetAllocator() in the general case, and this inline function in a few limited (but often called) situations. -CF_INLINE CFAllocatorRef __CFGetAllocator(CFTypeRef cf) { // !!! Use with CF types only, and NOT WITH CFAllocator! - CFAssert1(__kCFAllocatorTypeID_CONST != __CFGenericTypeID(cf), __kCFLogAssertion, "__CFGetAllocator(): CFAllocator argument", cf); - if (__builtin_expect(__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 7, 7), 1)) { - return kCFAllocatorSystemDefault; - } - return *(CFAllocatorRef *)((char *)cf - sizeof(CFAllocatorRef)); -} - -// Don't define a __CFGetCurrentRunLoop(), because even internal clients should go through the real one - #if !defined(LLONG_MAX) #if defined(_I64_MAX) @@ -293,6 +284,7 @@ extern CFTimeInterval __CFTSRToTimeInterval(SInt64 tsr); extern CFStringRef __CFCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions); + /* result is long long or int, depending on doLonglong */ extern Boolean __CFStringScanInteger(CFStringInlineBuffer *buf, CFTypeRef locale, SInt32 *indexPtr, Boolean doLonglong, void *result); @@ -301,7 +293,7 @@ extern Boolean __CFStringScanHex(CFStringInlineBuffer *buf, SInt32 *indexPtr, un extern const char *__CFgetenv(const char *n); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX #define STACK_BUFFER_DECL(T, N, C) T N[C] #elif DEPLOYMENT_TARGET_WINDOWS #define STACK_BUFFER_DECL(T, N, C) T *N = (T *)_alloca((C) * sizeof(T)) @@ -310,9 +302,17 @@ extern const char *__CFgetenv(const char *n); #endif +CF_EXPORT CFTypeRef _CFTryRetain(CFTypeRef cf); +CF_EXPORT Boolean _CFIsDeallocating(CFTypeRef cf); + + +CF_EXPORT void * __CFConstantStringClassReferencePtr; + #ifdef __CONSTANT_CFSTRINGS__ + #define CONST_STRING_DECL(S, V) const CFStringRef S = (const CFStringRef)__builtin___CFStringMakeConstantString(V); #define PE_CONST_STRING_DECL(S, V) __private_extern__ const CFStringRef S = (const CFStringRef)__builtin___CFStringMakeConstantString(V); + #else struct CF_CONST_STRING { @@ -325,19 +325,19 @@ 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) +#if __CF_BIG_ENDIAN__ && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX) #define CONST_STRING_DECL(S, V) \ -static struct CF_CONST_STRING __ ## S ## __ = {{&__CFConstantStringClassReference, {0x0000, 0x07c8}}, V, sizeof(V) - 1}; \ +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 ## __ = {{&__CFConstantStringClassReference, {0x0000, 0x07c8}}, V, sizeof(V) - 1}; \ +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) +#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 ## __ = {{&__CFConstantStringClassReference, {0x07c8, 0x0000}}, V, sizeof(V) - 1}; \ +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 ## __ = {{&__CFConstantStringClassReference, {0x07c8, 0x0000}}, V, sizeof(V) - 1}; \ +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 #define CONST_STRING_DECL(S, V) \ @@ -346,8 +346,8 @@ 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 #endif // __BIG_ENDIAN__ +#endif // __CONSTANT_CFSTRINGS__ /* Buffer size for file pathname */ @@ -359,13 +359,8 @@ __private_extern__ const CFStringRef S = (CFStringRef) & __ ## S ## __; #define CFMaxPathLength ((CFIndex)1024) #endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -extern bool __CFOASafe; -extern void __CFSetLastAllocationEventName(void *ptr, const char *classname); -#else -#define __CFOASafe 0 -#define __CFSetLastAllocationEventName(a, b) ((void) 0) -#endif +CF_EXPORT bool __CFOASafe; +CF_EXPORT void __CFSetLastAllocationEventName(void *ptr, const char *classname); @@ -389,7 +384,7 @@ __private_extern__ void _CFRaiseMemoryException(CFStringRef reason); __private_extern__ Boolean __CFProphylacticAutofsAccess; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX typedef OSSpinLock CFSpinLock_t; @@ -414,6 +409,34 @@ typedef OSSpinLock CFSpinLock_t; } \ OSSpinLockUnlock(__lockp__); }) +#define __CFSpinLockTry(LP) ({ \ + OSSpinLock *__lockp__ = (LP); \ + OSSpinLock __lockv__ = *__lockp__; \ + if (0 != __lockv__ && ~0 != __lockv__ && (uintptr_t)__lockp__ != (uintptr_t)__lockv__) { \ + CFLog(3, CFSTR("In '%s', file %s, line %d, during lock, spin lock %p has value 0x%x, which is neither locked nor unlocked. The memory has been smashed."), __PRETTY_FUNCTION__, __FILE__, __LINE__, __lockp__, __lockv__); \ + /* HALT; */ \ + } \ + OSSpinLockTry(__lockp__); }) + +#elif DEPLOYMENT_TARGET_EMBEDDED + +typedef OSSpinLock CFSpinLock_t; + +#define CFSpinLockInit OS_SPINLOCK_INIT +#define CF_SPINLOCK_INIT_FOR_STRUCTS(X) (X = CFSpinLockInit) + +#define __CFSpinLock(LP) ({ \ + OSSpinLock *__lockp__ = (LP); \ + OSSpinLockLock(__lockp__); }) + +#define __CFSpinUnlock(LP) ({ \ + OSSpinLock *__lockp__ = (LP); \ + OSSpinLockUnlock(__lockp__); }) + +#define __CFSpinLockTry(LP) ({ \ + OSSpinLock *__lockp__ = (LP); \ + OSSpinLockTry(__lockp__); }) + #elif DEPLOYMENT_TARGET_WINDOWS typedef int32_t CFSpinLock_t; @@ -431,6 +454,30 @@ CF_INLINE void __CFSpinUnlock(volatile CFSpinLock_t *lock) { *lock = 0; } +CF_INLINE Boolean __CFSpinLockTry(volatile CFSpinLock_t *lock) { + return (InterlockedCompareExchange((LONG volatile *)lock, ~0, 0) == 0); +} + +#elif DEPLOYMENT_TARGET_LINUX + +typedef int32_t CFSpinLock_t; +#define CFSpinLockInit 0 +#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) { + sleep(0); + } +} + +CF_INLINE void __CFSpinUnlock(volatile CFSpinLock_t *lock) { + __sync_synchronize(); + *lock = 0; +} + +CF_INLINE Boolean __CFSpinLockTry(volatile CFSpinLock_t *lock) { + return (__sync_val_compare_and_swap(lock, ~0, 0) == 0); +} #else @@ -464,7 +511,7 @@ extern void __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNC #if DEPLOYMENT_TARGET_WINDOWS #include -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD +#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX #include #endif @@ -504,6 +551,10 @@ CF_EXPORT CFMutableArrayRef _CFContentsOfDirectory(CFAllocatorRef alloc, char *d /* alloc may be NULL */ /* return value is CFArray of CFURLs */ +CF_EXPORT SInt32 _CFGetPathProperties(CFAllocatorRef alloc, char *path, Boolean *exists, SInt32 *posixMode, SInt64 *size, CFDateRef *modTime, SInt32 *ownerID, CFArrayRef *dirContents); + /* alloc may be NULL */ + /* any of exists, posixMode, size, modTime, and dirContents can be NULL. Usually it is not a good idea to pass NULL for exists, since interpretting the other values sometimes requires that you know whether the file existed or not. Except for dirContents, it is pretty cheap to compute any of these things as loing as one of them must be computed. */ + CF_EXPORT SInt32 _CFGetFileProperties(CFAllocatorRef alloc, CFURLRef pathURL, Boolean *exists, SInt32 *posixMode, SInt64 *size, CFDateRef *modTime, SInt32 *ownerID, CFArrayRef *dirContents); /* alloc may be NULL */ /* any of exists, posixMode, size, modTime, and dirContents can be NULL. Usually it is not a good idea to pass NULL for exists, since interpretting the other values sometimes requires that you know whether the file existed or not. Except for dirContents, it is pretty cheap to compute any of these things as loing as one of them must be computed. */ @@ -514,6 +565,7 @@ CF_EXPORT SInt32 _CFGetFileProperties(CFAllocatorRef alloc, CFURLRef pathURL, Bo 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); CF_EXPORT Boolean _CFAppendPathComponent(UniChar *unichars, CFIndex *length, CFIndex maxLength, UniChar *component, CFIndex componentLength); CF_EXPORT Boolean _CFAppendPathExtension(UniChar *unichars, CFIndex *length, CFIndex maxLength, UniChar *extension, CFIndex extensionLength); CF_EXPORT Boolean _CFTransmutePathSlashes(UniChar *unichars, CFIndex *length, UniChar replSlash); @@ -524,99 +576,97 @@ CF_EXPORT CFIndex _CFLengthAfterDeletingPathExtension(UniChar *unichars, CFIndex #define __CFMaxRuntimeTypes 65535 -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC +// Tagged pointer support +// Low-bit set means tagged object, next 3 bits (currently) +// define the tagged object class, next 4 bits are for type +// information for the specific tagged object class. Thus, +// the low byte is for type info, and the rest of a pointer +// (32 or 64-bit) is for payload, whatever the tagged class. +// +// Note that the specific integers used to identify the +// specific tagged classes can and will change from release +// 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__) +#define CF_IS_TAGGED_OBJ(PTR) ((uintptr_t)(PTR) & 0x1) +#define CF_TAGGED_OBJ_TYPE(PTR) ((uintptr_t)(PTR) & 0xF) +#else +#define CF_IS_TAGGED_OBJ(PTR) 0 +#define CF_TAGGED_OBJ_TYPE(PTR) 0 +#endif + +enum { + kCFTaggedObjectID_Invalid = 0, + kCFTaggedObjectID_Undefined0 = (0 << 1) + 1, + kCFTaggedObjectID_Integer = (1 << 1) + 1, + kCFTaggedObjectID_Undefined2 = (2 << 1) + 1, + kCFTaggedObjectID_Undefined3 = (3 << 1) + 1, + kCFTaggedObjectID_Undefined4 = (4 << 1) + 1, + kCFTaggedObjectID_ManagedObjectID = (5 << 1) + 1, // Core Data + kCFTaggedObjectID_Date = (6 << 1) + 1, + kCFTaggedObjectID_DateTS = (7 << 1) + 1, +}; -#include -extern int32_t __CFRuntimeClassTableSize; +#define __CFRuntimeClassTableSize 1024 -extern uintptr_t *__CFRuntimeObjCClassTable; +extern uintptr_t __CFRuntimeObjCClassTable[]; CF_INLINE uintptr_t __CFISAForTypeID(CFTypeID typeID) { return (typeID < __CFRuntimeClassTableSize) ? __CFRuntimeObjCClassTable[typeID] : 0; } -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -extern id objc_msgSend(id, SEL, ...); -#elif DEPLOYMENT_TARGET_WINDOWS && defined(__cplusplus) -extern "C" __declspec(dllimport) id objc_msgSend(id, SEL, ...); -#elif DEPLOYMENT_TARGET_WINDOWS -extern __declspec(dllimport) id objc_msgSend(id, SEL, ...); +CF_INLINE Boolean CF_IS_OBJC(CFTypeID typeID, const void *obj) { + if (CF_IS_TAGGED_OBJ(obj)) return true; + uintptr_t cfisa = ((CFRuntimeBase *)obj)->_cfisa; + if (cfisa == 0) return false; +#if 0 + // Temporarily disabled +#if __LP64__ + if (cfisa < 0x10000000UL) { + CFLog(kCFLogLevelWarning, CFSTR("*** Warning: CF tested pointer %p for objectness and found its isa pointer to be bogus (%p)"), obj, cfisa); + return false; + } +#else + if (cfisa < 0x1000UL) { + CFLog(kCFLogLevelWarning, CFSTR("*** Warning: CF tested pointer %p for objectness and found its isa pointer to be bogus (%p)"), obj, cfisa); + return false; + } +#endif #endif + if (cfisa == (uintptr_t)__CFConstantStringClassReferencePtr) return false; + uintptr_t type_isa = (uintptr_t)(typeID < __CFRuntimeClassTableSize ? __CFRuntimeObjCClassTable[typeID] : 0); + if (cfisa == type_isa) return false; + return true; +} -extern void * (*__CFSendObjCMsg)(const void *, SEL, ...); +#define STUB_CF_OBJC 1 -CF_INLINE Boolean CF_IS_OBJC(CFTypeID typeID, const void *obj) { - return (typeID >= __CFRuntimeClassTableSize) || (((CFRuntimeBase *)obj)->_cfisa != __CFISAForTypeID(typeID) && ((CFRuntimeBase *)obj)->_cfisa > (uintptr_t)0xFFF); -} +#if STUB_CF_OBJC -// Invoke an ObjC method that returns void. -// Assumes CF_IS_OBJC has already been checked. -#define CF_OBJC_VOIDCALL0(obj, sel) \ - {void (*func)(const void *, SEL) = (void (*)(const void *, SEL))objc_msgSend; \ - static SEL s = NULL; if (!s) s = sel_registerName(sel); \ - func((const void *)obj, s);} -#define CF_OBJC_VOIDCALL1(obj, sel, a1) \ - {void (*func)(const void *, SEL, ...) = (void (*)(const void *, SEL, ...))objc_msgSend; \ - static SEL s = NULL; if (!s) s = sel_registerName(sel); \ - func((const void *)obj, s, (a1));} -#define CF_OBJC_VOIDCALL2(obj, sel, a1, a2) \ - {void (*func)(const void *, SEL, ...) = (void (*)(const void *, SEL, ...))objc_msgSend; \ - static SEL s = NULL; if (!s) s = sel_registerName(sel); \ - func((const void *)obj, s, (a1), (a2));} - - -// Invoke an ObjC method, leaving the result in "retvar". -// Assumes CF_IS_OBJC has already been checked. -#define CF_OBJC_CALL0(rettype, retvar, obj, sel) \ - {rettype (*func)(const void *, SEL) = (rettype (*)(const void *, SEL))objc_msgSend; \ - static SEL s = NULL; if (!s) s = sel_registerName(sel); \ - retvar = func((const void *)obj, s);} -#define CF_OBJC_CALL1(rettype, retvar, obj, sel, a1) \ - {rettype (*func)(const void *, SEL, ...) = (rettype (*)(const void *, SEL, ...))objc_msgSend; \ - static SEL s = NULL; if (!s) s = sel_registerName(sel); \ - retvar = func((const void *)obj, s, (a1));} -#define CF_OBJC_CALL2(rettype, retvar, obj, sel, a1, a2) \ - {rettype (*func)(const void *, SEL, ...) = (rettype (*)(const void *, SEL, ...))objc_msgSend; \ - static SEL s = NULL; if (!s) s = sel_registerName(sel); \ - retvar = func((const void *)obj, s, (a1), (a2));} - -// Invoke an ObjC method, return the result -#define CF_OBJC_FUNCDISPATCH0(typeID, rettype, obj, sel) \ - if (__builtin_expect(CF_IS_OBJC(typeID, obj), 0)) \ - {rettype (*func)(const void *, SEL) = (rettype (*)(const void *, SEL))objc_msgSend; \ - static SEL s = NULL; if (!s) s = sel_registerName(sel); \ - return func((const void *)obj, s);} -#define CF_OBJC_FUNCDISPATCH1(typeID, rettype, obj, sel, a1) \ - if (__builtin_expect(CF_IS_OBJC(typeID, obj), 0)) \ - {rettype (*func)(const void *, SEL, ...) = (rettype (*)(const void *, SEL,...))objc_msgSend; \ - static SEL s = NULL; if (!s) s = sel_registerName(sel); \ - return func((const void *)obj, s, (a1));} -#define CF_OBJC_FUNCDISPATCH2(typeID, rettype, obj, sel, a1, a2) \ - if (__builtin_expect(CF_IS_OBJC(typeID, obj), 0)) \ - {rettype (*func)(const void *, SEL, ...) = (rettype (*)(const void *, SEL,...))objc_msgSend; \ - static SEL s = NULL; if (!s) s = sel_registerName(sel); \ - return func((const void *)obj, s, (a1), (a2));} -#define CF_OBJC_FUNCDISPATCH3(typeID, rettype, obj, sel, a1, a2, a3) \ - if (__builtin_expect(CF_IS_OBJC(typeID, obj), 0)) \ - {rettype (*func)(const void *, SEL, ...) = (rettype (*)(const void *, SEL,...))objc_msgSend; \ - static SEL s = NULL; if (!s) s = sel_registerName(sel); \ - return func((const void *)obj, s, (a1), (a2), (a3));} -#define CF_OBJC_FUNCDISPATCH4(typeID, rettype, obj, sel, a1, a2, a3, a4) \ - if (__builtin_expect(CF_IS_OBJC(typeID, obj), 0)) \ - {rettype (*func)(const void *, SEL, ...) = (rettype (*)(const void *, SEL,...))objc_msgSend; \ - static SEL s = NULL; if (!s) s = sel_registerName(sel); \ - return func((const void *)obj, s, (a1), (a2), (a3), (a4));} -#define CF_OBJC_FUNCDISPATCH5(typeID, rettype, obj, sel, a1, a2, a3, a4, a5) \ - if (__builtin_expect(CF_IS_OBJC(typeID, obj), 0)) \ - {rettype (*func)(const void *, SEL, ...) = (rettype (*)(const void *, SEL,...))objc_msgSend; \ - static SEL s = NULL; if (!s) s = sel_registerName(sel); \ - return func((const void *)obj, s, (a1), (a2), (a3), (a4), (a5));} +#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 -#endif /* See comments in CFBase.c */ -#if DEPLOYMENT_TARGET_MACOSX && defined(__ppc__) +#if SUPPORT_CFM extern void __CF_FAULT_CALLBACK(void **ptr); extern void *__CF_INVOKE_CALLBACK(void *, ...); #define FAULT_CALLBACK(V) __CF_FAULT_CALLBACK(V) @@ -643,6 +693,8 @@ extern void *__CF_INVOKE_CALLBACK(void *, ...); // N : the name of the function (in the other library) // P : the parenthesized parameter list of the function // A : the parenthesized actual argument list to be passed +// FAILACTION: (only for the _FAIL macros) additional code to be +// run when the function cannot be found. // opt: a fifth optional argument can be passed in which is the // return value of the wrapper when the function cannot be // found; should be of type R, & can be a function call @@ -658,23 +710,24 @@ extern void *__CF_INVOKE_CALLBACK(void *, ...); extern void *__CFLookupCFNetworkFunction(const char *name); -#define DEFINE_WEAK_CFNETWORK_FUNC(R, N, P, A, ...) \ -static R __CFNetwork_ ## N P { \ - static R (*dyfunc) P = (void *)(~(uintptr_t)0); \ - if ((void *)(~(uintptr_t)0) == dyfunc) { \ - dyfunc = __CFLookupCFNetworkFunction(#N); } \ - if (dyfunc) { return dyfunc A ; } \ - return __VA_ARGS__ ; \ +#define DEFINE_WEAK_CFNETWORK_FUNC(R, N, P, A, ...) \ + typedef R (*dyfuncptr)P; \ + static dyfuncptr dyfunc = (dyfuncptr)(~(uintptr_t)0); \ + if ((dyfuncptr)(~(uintptr_t)0) == dyfunc) { \ + dyfunc = (dyfuncptr)__CFLookupCFNetworkFunction(#N); } \ + if (dyfunc) { return dyfunc A ; } \ + return __VA_ARGS__ ; \ } #define DEFINE_WEAK_CFNETWORK_FUNC_FAIL(R, N, P, A, FAILACTION, ...) \ -static R __CFNetwork_ ## N P { \ - static R (*dyfunc) P = (void *)(~(uintptr_t)0); \ - if ((void *)(~(uintptr_t)0) == dyfunc) { \ - dyfunc = __CFLookupCFNetworkFunction(#N); } \ - if (dyfunc) { return dyfunc A ; } \ - FAILACTION ; \ - return __VA_ARGS__ ; \ +static R __CFNetwork_ ## N P { \ + typedef R (*dyfuncptr)P; \ + static dyfuncptr dyfunc = (dyfuncptr)(~(uintptr_t)0); \ + if ((dyfuncptr)(~(uintptr_t)0) == dyfunc) { \ + dyfunc = (dyfuncptr)__CFLookupCFNetworkFunction(#N); } \ + if (dyfunc) { return dyfunc A ; } \ + FAILACTION ; \ + return __VA_ARGS__ ; \ } #else @@ -688,15 +741,30 @@ static R __CFNetwork_ ## N P { \ #if !defined(DEFINE_WEAK_CARBONCORE_FUNC) #define DEFINE_WEAK_CARBONCORE_FUNC(R, N, P, A, ...) #endif +#if !defined(DEFINE_WEAK_CORESERVICESINTERNAL_FUNC) +#define DEFINE_WEAK_CORESERVICESINTERNAL_FUNC(R, N, P, A, ...) +#endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS __private_extern__ CFComparisonResult _CFCompareStringsWithLocale(CFStringInlineBuffer *str1, CFRange str1Range, CFStringInlineBuffer *str2, CFRange str2Range, CFOptionFlags options, const void *compareLocale); -#endif __private_extern__ CFArrayRef _CFBundleCopyUserLanguages(Boolean useBackstops); +// This should only be used in CF types, not toll-free bridged objects! +// It should not be used with CFAllocator arguments! +// Use CFGetAllocator() in the general case, and this inline function in a few limited (but often called) situations. +CF_INLINE CFAllocatorRef __CFGetAllocator(CFTypeRef cf) { // !!! Use with CF types only, and NOT WITH CFAllocator! + if (CF_IS_TAGGED_OBJ(cf)) { + return kCFAllocatorSystemDefault; + } + if (__builtin_expect(__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 7, 7), 1)) { + return kCFAllocatorSystemDefault; + } + return *(CFAllocatorRef *)((char *)cf - sizeof(CFAllocatorRef)); +} + + #if DEPLOYMENT_TARGET_WINDOWS __private_extern__ const wchar_t *_CFDLLPath(void); __private_extern__ void __CFStringCleanup(void); @@ -713,8 +781,6 @@ struct __objcFastEnumerationStateEquivalent { unsigned long extra[5]; }; -unsigned long _CFStorageFastEnumeration(CFStorageRef storage, struct __objcFastEnumerationStateEquivalent *state, void *stackbuffer, unsigned long count); - CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFINTERNAL__ */ diff --git a/CFLocale.c b/CFLocale.c index fbec52e..cf8c7b6 100644 --- a/CFLocale.c +++ b/CFLocale.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFLocale.c - Copyright (c) 2002-2009, Apple Inc. All rights reserved. - Responsibility: Christopher Kane + Copyright (c) 2002-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ // Note the header file is in the OpenSource set (stripped to almost nothing), but not the .c file @@ -39,21 +39,20 @@ #include "CFLocaleInternal.h" #include // ICU locales #include // ICU locale data +#include #include // ICU currency functions #include // ICU Unicode sets #include // ICU low-level utilities #include // ICU message formatting -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX #include -#include #include #include #include #elif DEPLOYMENT_TARGET_WINDOWS #include -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif +#include CONST_STRING_DECL(kCFLocaleCurrentLocaleDidChangeNotification, "kCFLocaleCurrentLocaleDidChangeNotification") @@ -195,7 +194,7 @@ static Boolean __CFLocaleEqual(CFTypeRef cf1, CFTypeRef cf2) { if (NULL != locale1->_overrides && NULL == locale2->_overrides) return false; if (NULL != locale1->_overrides && !CFEqual(locale1->_overrides, locale2->_overrides)) return false; if (__kCFLocaleUser == __CFLocaleGetType(locale1)) { - return CFEqual(locale1->_prefs, locale2->_prefs); + return CFEqual(locale1->_prefs, locale2->_prefs); } return true; } @@ -285,7 +284,7 @@ static CFLocaleRef __CFLocaleCurrent = NULL; #define FALLBACK_LOCALE_NAME CFSTR("") #elif DEPLOYMENT_TARGET_EMBEDDED #define FALLBACK_LOCALE_NAME CFSTR("en_US") -#elif DEPLOYMENT_TARGET_WINDOWS +#elif DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX #define FALLBACK_LOCALE_NAME CFSTR("en_US") #else #error Unknown or unspecified DEPLOYMENT_TARGET @@ -308,6 +307,8 @@ CFLocaleRef CFLocaleCopyCurrent(void) { uint32_t size = sizeof(struct __CFLocale) - sizeof(CFRuntimeBase); locale = (struct __CFLocale *)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, CFLocaleGetTypeID(), size, NULL); if (NULL == locale) { + if (prefs) CFRelease(prefs); + if (identifier) CFRelease(identifier); return NULL; } __CFLocaleSetType(locale, __kCFLocaleUser); @@ -331,6 +332,7 @@ CFLocaleRef CFLocaleCopyCurrent(void) { } __private_extern__ CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale) { + CF_OBJC_FUNCDISPATCH0(CFLocaleGetTypeID(), CFDictionaryRef, locale, "_prefs"); return locale->_prefs; } @@ -351,7 +353,7 @@ CFLocaleRef CFLocaleCreate(CFAllocatorRef allocator, CFStringRef identifier) { // We only use cached objects if the allocator is the system // default allocator. if (!allocator) allocator = __CFGetDefaultAllocator(); - Boolean canCache = (kCFAllocatorSystemDefault == allocator); + Boolean canCache = _CFAllocatorIsSystemDefault(allocator); if (canCache && __CFLocaleCache) { CFLocaleRef locale = (CFLocaleRef)CFDictionaryGetValue(__CFLocaleCache, localeIdentifier); if (locale) { @@ -393,6 +395,7 @@ CFStringRef CFLocaleGetIdentifier(CFLocaleRef locale) { } CFTypeRef CFLocaleGetValue(CFLocaleRef locale, CFStringRef key) { +#if DEPLOYMENT_TARGET_MACOSX if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard)) { // Hack for Opera, which is using the hard-coded string value below instead of // the perfectly good public kCFLocaleCountryCode constant, for whatever reason. @@ -400,6 +403,7 @@ CFTypeRef CFLocaleGetValue(CFLocaleRef locale, CFStringRef key) { key = kCFLocaleCountryCodeKey; } } +#endif CF_OBJC_FUNCDISPATCH1(CFLocaleGetTypeID(), CFTypeRef, locale, "objectForKey:", key); CFIndex idx, slot = -1; for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { @@ -507,11 +511,9 @@ CFArrayRef CFLocaleCopyAvailableLocaleIdentifiers(void) { for (locale = 0; locale < localeCount; ++locale) { const char *localeID = uloc_getAvailable(locale); CFStringRef string1 = CFStringCreateWithCString(kCFAllocatorSystemDefault, localeID, kCFStringEncodingASCII); - CFStringRef string2 = CFLocaleCreateCanonicalLocaleIdentifierFromString(kCFAllocatorSystemDefault, string1); - CFSetAddValue(working, string1); // do not include canonicalized version as IntlFormats cannot cope with that in its popup + CFSetAddValue(working, string1); CFRelease(string1); - CFRelease(string2); } CFIndex cnt = CFSetGetCount(working); STACK_BUFFER_DECL(const void *, buffer, cnt); @@ -773,8 +775,29 @@ static bool __CFLocaleCopyICUKeyword(CFLocaleRef locale, bool user, CFTypeRef *c return false; } +static bool __CFLocaleCopyICUCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context, const char *keyword) { + 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; + UEnumeration *en = ucal_getKeywordValuesForLocale(keyword, localeID, TRUE, &icuStatus); + int32_t len; + const char *value = uenum_next(en, &len, &icuStatus); + if (U_SUCCESS(icuStatus)) { + *cf = (CFTypeRef) CFStringCreateWithCString(kCFAllocatorSystemDefault, value, kCFStringEncodingASCII); + uenum_close(en); + return true; + } + uenum_close(en); + } + *cf = NULL; + return false; +} + static bool __CFLocaleCopyCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { bool succeeded = __CFLocaleCopyICUKeyword(locale, user, cf, context, kCalendarKeyword); + if (!succeeded) { + succeeded = __CFLocaleCopyICUCalendarID(locale, user, cf, context, kCalendarKeyword); + } if (succeeded) { if (CFEqual(*cf, kCFCalendarIdentifierGregorian)) { CFRelease(*cf); @@ -941,9 +964,6 @@ static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale, bool user, CFTypeRef *c } } } -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif if (!done) { char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; @@ -975,7 +995,7 @@ 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 +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale, kCFNumberFormatterDecimalStyle); str = nf ? CFNumberFormatterCopyProperty(nf, context) : NULL; if (nf) CFRelease(nf); @@ -994,7 +1014,7 @@ 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 +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale, kCFNumberFormatterCurrencyStyle); str = nf ? CFNumberFormatterCopyProperty(nf, context) : NULL; if (nf) CFRelease(nf); diff --git a/CFLocale.h b/CFLocale.h index 03b7918..a085801 100644 --- a/CFLocale.h +++ b/CFLocale.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFLocale.h - Copyright (c) 2002-2009, Apple Inc. All rights reserved. + Copyright (c) 2002-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFLOCALE__) @@ -32,21 +32,19 @@ #include #include -#if MAC_OS_X_VERSION_10_3 <= MAC_OS_X_VERSION_MAX_ALLOWED - CF_EXTERN_C_BEGIN typedef const struct __CFLocale *CFLocaleRef; CF_EXPORT -CFTypeID CFLocaleGetTypeID(void) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFTypeID CFLocaleGetTypeID(void); CF_EXPORT -CFLocaleRef CFLocaleGetSystem(void) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFLocaleRef CFLocaleGetSystem(void); // Returns the "root", canonical locale. Contains fixed "backstop" settings. CF_EXPORT -CFLocaleRef CFLocaleCopyCurrent(void) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFLocaleRef CFLocaleCopyCurrent(void); // Returns the logical "user" locale for the current user. // [This is Copy in the sense that you get a retain you have to release, // but we may return the same cached object over and over.] Settings @@ -57,57 +55,57 @@ CFLocaleRef CFLocaleCopyCurrent(void) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // ensures that all the results of your operations are consistent.) CF_EXPORT -CFArrayRef CFLocaleCopyAvailableLocaleIdentifiers(void) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFArrayRef CFLocaleCopyAvailableLocaleIdentifiers(void); // Returns an array of CFStrings that represents all locales for // which locale data is available. CF_EXPORT -CFArrayRef CFLocaleCopyISOLanguageCodes(void) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFArrayRef CFLocaleCopyISOLanguageCodes(void); // Returns an array of CFStrings that represents all known legal ISO // language codes. Note: many of these will not have any supporting // locale data in Mac OS X. CF_EXPORT -CFArrayRef CFLocaleCopyISOCountryCodes(void) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFArrayRef CFLocaleCopyISOCountryCodes(void); // Returns an array of CFStrings that represents all known legal ISO // country codes. Note: many of these will not have any supporting // locale data in Mac OS X. CF_EXPORT -CFArrayRef CFLocaleCopyISOCurrencyCodes(void) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFArrayRef CFLocaleCopyISOCurrencyCodes(void); // Returns an array of CFStrings that represents all known legal ISO // currency codes. Note: some of these currencies may be obsolete, or // represent other financial instruments. CF_EXPORT -CFArrayRef CFLocaleCopyCommonISOCurrencyCodes(void) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFArrayRef CFLocaleCopyCommonISOCurrencyCodes(void) CF_AVAILABLE(10_5, 2_0); // Returns an array of CFStrings that represents ISO currency codes for // currencies in common use. CF_EXPORT -CFArrayRef CFLocaleCopyPreferredLanguages(void) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFArrayRef CFLocaleCopyPreferredLanguages(void) CF_AVAILABLE(10_5, 2_0); // Returns the array of canonicalized CFString locale IDs that the user prefers. CF_EXPORT -CFStringRef CFLocaleCreateCanonicalLanguageIdentifierFromString(CFAllocatorRef allocator, CFStringRef localeIdentifier) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFStringRef CFLocaleCreateCanonicalLanguageIdentifierFromString(CFAllocatorRef allocator, CFStringRef localeIdentifier); // Map an arbitrary language identification string (something close at // least) to a canonical language identifier. CF_EXPORT -CFStringRef CFLocaleCreateCanonicalLocaleIdentifierFromString(CFAllocatorRef allocator, CFStringRef localeIdentifier) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFStringRef CFLocaleCreateCanonicalLocaleIdentifierFromString(CFAllocatorRef allocator, CFStringRef localeIdentifier); // Map an arbitrary locale identification string (something close at // least) to the canonical identifier. CF_EXPORT -CFStringRef CFLocaleCreateCanonicalLocaleIdentifierFromScriptManagerCodes(CFAllocatorRef allocator, LangCode lcode, RegionCode rcode) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFStringRef CFLocaleCreateCanonicalLocaleIdentifierFromScriptManagerCodes(CFAllocatorRef allocator, LangCode lcode, RegionCode rcode); // Map a Mac OS LangCode and RegionCode to the canonical locale identifier. CF_EXPORT -CFStringRef CFLocaleCreateLocaleIdentifierFromWindowsLocaleCode(CFAllocatorRef allocator, uint32_t lcid) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CFStringRef CFLocaleCreateLocaleIdentifierFromWindowsLocaleCode(CFAllocatorRef allocator, uint32_t lcid) CF_AVAILABLE(10_6, 4_0); // Map a Windows LCID to the canonical locale identifier. CF_EXPORT -uint32_t CFLocaleGetWindowsLocaleCodeFromLocaleIdentifier(CFStringRef localeIdentifier) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +uint32_t CFLocaleGetWindowsLocaleCodeFromLocaleIdentifier(CFStringRef localeIdentifier) CF_AVAILABLE(10_6, 4_0); // Map a locale identifier to a Windows LCID. enum { @@ -120,13 +118,13 @@ enum { typedef CFIndex CFLocaleLanguageDirection; CF_EXPORT -CFLocaleLanguageDirection CFLocaleGetLanguageCharacterDirection(CFStringRef isoLangCode) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CFLocaleLanguageDirection CFLocaleGetLanguageCharacterDirection(CFStringRef isoLangCode) CF_AVAILABLE(10_6, 4_0); CF_EXPORT -CFLocaleLanguageDirection CFLocaleGetLanguageLineDirection(CFStringRef isoLangCode) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CFLocaleLanguageDirection CFLocaleGetLanguageLineDirection(CFStringRef isoLangCode) CF_AVAILABLE(10_6, 4_0); CF_EXPORT -CFDictionaryRef CFLocaleCreateComponentsFromLocaleIdentifier(CFAllocatorRef allocator, CFStringRef localeID) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFDictionaryRef CFLocaleCreateComponentsFromLocaleIdentifier(CFAllocatorRef allocator, CFStringRef localeID); // Parses a locale ID consisting of language, script, country, variant, // and keyword/value pairs into a dictionary. The keys are the constant // CFStrings corresponding to the locale ID components, and the values @@ -136,7 +134,7 @@ CFDictionaryRef CFLocaleCreateComponentsFromLocaleIdentifier(CFAllocatorRef allo // kCFLocaleCalendarIdentifier=kCFJapaneseCalendar. CF_EXPORT -CFStringRef CFLocaleCreateLocaleIdentifierFromComponents(CFAllocatorRef allocator, CFDictionaryRef dictionary) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFStringRef CFLocaleCreateLocaleIdentifierFromComponents(CFAllocatorRef allocator, CFDictionaryRef dictionary); // Reverses the actions of CFLocaleCreateDictionaryFromLocaleIdentifier, // creating a single string from the data in the dictionary. The // dictionary {kCFLocaleLanguageCode=en, kCFLocaleCountryCode=US, @@ -144,74 +142,72 @@ CFStringRef CFLocaleCreateLocaleIdentifierFromComponents(CFAllocatorRef allocato // "en_US@calendar=japanese". CF_EXPORT -CFLocaleRef CFLocaleCreate(CFAllocatorRef allocator, CFStringRef localeIdentifier) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFLocaleRef CFLocaleCreate(CFAllocatorRef allocator, CFStringRef localeIdentifier); // Returns a CFLocaleRef for the locale named by the "arbitrary" locale identifier. CF_EXPORT -CFLocaleRef CFLocaleCreateCopy(CFAllocatorRef allocator, CFLocaleRef locale) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFLocaleRef CFLocaleCreateCopy(CFAllocatorRef allocator, CFLocaleRef locale); // Having gotten a CFLocale from somebody, code should make a copy // if it is going to use it for several operations // or hold onto it. In the future, there may be mutable locales. CF_EXPORT -CFStringRef CFLocaleGetIdentifier(CFLocaleRef locale) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFStringRef CFLocaleGetIdentifier(CFLocaleRef locale); // Returns the locale's identifier. This may not be the same string // that the locale was created with (CFLocale may canonicalize it). CF_EXPORT -CFTypeRef CFLocaleGetValue(CFLocaleRef locale, CFStringRef key) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFTypeRef CFLocaleGetValue(CFLocaleRef locale, CFStringRef key); // Returns the value for the given key. This is how settings and state // are accessed via a CFLocale. Values might be of any CF type. CF_EXPORT -CFStringRef CFLocaleCopyDisplayNameForPropertyValue(CFLocaleRef displayLocale, CFStringRef key, CFStringRef value) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFStringRef CFLocaleCopyDisplayNameForPropertyValue(CFLocaleRef displayLocale, CFStringRef key, CFStringRef value); // Returns the display name for the given value. The key tells what // the value is, and is one of the usual locale property keys, though // not all locale property keys have values with display name values. -CF_EXPORT const CFStringRef kCFLocaleCurrentLocaleDidChangeNotification AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CF_EXPORT const CFStringRef kCFLocaleCurrentLocaleDidChangeNotification CF_AVAILABLE(10_5, 2_0); // Locale Keys -CF_EXPORT const CFStringRef kCFLocaleIdentifier AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFLocaleLanguageCode AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFLocaleCountryCode AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFLocaleScriptCode AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFLocaleVariantCode AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; - -CF_EXPORT const CFStringRef kCFLocaleExemplarCharacterSet AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFLocaleCalendarIdentifier AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFLocaleCalendar AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFLocaleCollationIdentifier AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFLocaleUsesMetricSystem AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFLocaleMeasurementSystem AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // "Metric" or "U.S." -CF_EXPORT const CFStringRef kCFLocaleDecimalSeparator AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; -CF_EXPORT const CFStringRef kCFLocaleGroupingSeparator AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; -CF_EXPORT const CFStringRef kCFLocaleCurrencySymbol AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; -CF_EXPORT const CFStringRef kCFLocaleCurrencyCode AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // ISO 3-letter currency code -CF_EXPORT const CFStringRef kCFLocaleCollatorIdentifier AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; -CF_EXPORT const CFStringRef kCFLocaleQuotationBeginDelimiterKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; -CF_EXPORT const CFStringRef kCFLocaleQuotationEndDelimiterKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; -CF_EXPORT const CFStringRef kCFLocaleAlternateQuotationBeginDelimiterKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; -CF_EXPORT const CFStringRef kCFLocaleAlternateQuotationEndDelimiterKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CF_EXPORT const CFStringRef kCFLocaleIdentifier; +CF_EXPORT const CFStringRef kCFLocaleLanguageCode; +CF_EXPORT const CFStringRef kCFLocaleCountryCode; +CF_EXPORT const CFStringRef kCFLocaleScriptCode; +CF_EXPORT const CFStringRef kCFLocaleVariantCode; + +CF_EXPORT const CFStringRef kCFLocaleExemplarCharacterSet; +CF_EXPORT const CFStringRef kCFLocaleCalendarIdentifier; +CF_EXPORT const CFStringRef kCFLocaleCalendar; +CF_EXPORT const CFStringRef kCFLocaleCollationIdentifier; +CF_EXPORT const CFStringRef kCFLocaleUsesMetricSystem; +CF_EXPORT const CFStringRef kCFLocaleMeasurementSystem; // "Metric" or "U.S." +CF_EXPORT const CFStringRef kCFLocaleDecimalSeparator; +CF_EXPORT const CFStringRef kCFLocaleGroupingSeparator; +CF_EXPORT const CFStringRef kCFLocaleCurrencySymbol; +CF_EXPORT const CFStringRef kCFLocaleCurrencyCode; // ISO 3-letter currency code +CF_EXPORT const CFStringRef kCFLocaleCollatorIdentifier CF_AVAILABLE(10_6, 4_0); +CF_EXPORT const CFStringRef kCFLocaleQuotationBeginDelimiterKey CF_AVAILABLE(10_6, 4_0); +CF_EXPORT const CFStringRef kCFLocaleQuotationEndDelimiterKey CF_AVAILABLE(10_6, 4_0); +CF_EXPORT const CFStringRef kCFLocaleAlternateQuotationBeginDelimiterKey CF_AVAILABLE(10_6, 4_0); +CF_EXPORT const CFStringRef kCFLocaleAlternateQuotationEndDelimiterKey CF_AVAILABLE(10_6, 4_0); // Values for kCFLocaleCalendarIdentifier -CF_EXPORT const CFStringRef kCFGregorianCalendar AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; -CF_EXPORT const CFStringRef kCFBuddhistCalendar AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFChineseCalendar AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFHebrewCalendar AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFIslamicCalendar AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFIslamicCivilCalendar AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFJapaneseCalendar AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFRepublicOfChinaCalendar AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; -CF_EXPORT const CFStringRef kCFPersianCalendar AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; -CF_EXPORT const CFStringRef kCFIndianCalendar AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; -CF_EXPORT const CFStringRef kCFISO8601Calendar AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CF_EXPORT const CFStringRef kCFGregorianCalendar; +CF_EXPORT const CFStringRef kCFBuddhistCalendar; +CF_EXPORT const CFStringRef kCFChineseCalendar; +CF_EXPORT const CFStringRef kCFHebrewCalendar; +CF_EXPORT const CFStringRef kCFIslamicCalendar; +CF_EXPORT const CFStringRef kCFIslamicCivilCalendar; +CF_EXPORT const CFStringRef kCFJapaneseCalendar; +CF_EXPORT const CFStringRef kCFRepublicOfChinaCalendar CF_AVAILABLE(10_6, 4_0); +CF_EXPORT const CFStringRef kCFPersianCalendar CF_AVAILABLE(10_6, 4_0); +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 -#endif - #endif /* ! __COREFOUNDATION_CFLOCALE__ */ diff --git a/CFLocaleIdentifier.c b/CFLocaleIdentifier.c index f014d32..6391835 100644 --- a/CFLocaleIdentifier.c +++ b/CFLocaleIdentifier.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -23,8 +23,8 @@ /* CFLocaleIdentifier.c - Copyright (c) 2002-2009, Apple Inc. All rights reserved. - Responsibility: Christopher Kane + Copyright (c) 2002-2011, Apple Inc. All rights reserved. + Responsibility: David Smith CFLocaleIdentifier.c defines - enum value kLocaleIdentifierCStringMax @@ -71,9 +71,11 @@ */ #include +#include #include #include #include +#include #include #include "CFInternal.h" #include "CFLocaleInternal.h" @@ -1921,7 +1923,20 @@ CFStringRef CFLocaleCreateLocaleIdentifierFromComponents(CFAllocatorRef allocato for (CFIndex idx = 0; idx < cnt; idx++) { if (keys[idx]) { char *key = __CStringFromString(keys[idx]); - char *value = __CStringFromString(values[idx]); + char *value; + if (0 == strcmp(key, "kCFLocaleCalendarKey")) { + // For interchangeability convenience, we alternatively allow a + // calendar object to be passed in, with the alternate key, and + // we'll extract the identifier. + CFCalendarRef cal = (CFCalendarRef)values[idx]; + CFStringRef ident = CFCalendarGetIdentifier(cal); + value = __CStringFromString(ident); + char *oldkey = key; + key = strdup("calendar"); + free(oldkey); + } else { + value = __CStringFromString(values[idx]); + } UErrorCode status = U_ZERO_ERROR; uloc_setKeywordValue(key, value, cLocaleID, sizeof(cLocaleID), &status); free(key); diff --git a/CFLocaleInternal.h b/CFLocaleInternal.h index 68d58ba..085c412 100644 --- a/CFLocaleInternal.h +++ b/CFLocaleInternal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -23,7 +23,7 @@ /* CFLocaleInternal.h - Copyright (c) 2008-2009, Apple Inc. All rights reserved. + Copyright (c) 2008-2011, Apple Inc. All rights reserved. */ /* diff --git a/CFLocaleKeys.c b/CFLocaleKeys.c new file mode 100644 index 0000000..7bffe9b --- /dev/null +++ b/CFLocaleKeys.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2011 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@ + */ + +/* CFLocaleKeys.c + Copyright (c) 2008-2011, Apple Inc. All rights reserved. + Responsibility: Christopher Kane +*/ + +#include + +CONST_STRING_DECL(kCFLocaleAlternateQuotationBeginDelimiterKey, "kCFLocaleAlternateQuotationBeginDelimiterKey"); +CONST_STRING_DECL(kCFLocaleAlternateQuotationEndDelimiterKey, "kCFLocaleAlternateQuotationEndDelimiterKey"); +CONST_STRING_DECL(kCFLocaleQuotationBeginDelimiterKey, "kCFLocaleQuotationBeginDelimiterKey"); +CONST_STRING_DECL(kCFLocaleQuotationEndDelimiterKey, "kCFLocaleQuotationEndDelimiterKey"); +CONST_STRING_DECL(kCFLocaleCalendarIdentifierKey, "calendar"); // *** +CONST_STRING_DECL(kCFLocaleCalendarKey, "kCFLocaleCalendarKey"); + +CONST_STRING_DECL(kCFLocaleCollationIdentifierKey, "collation"); // *** +CONST_STRING_DECL(kCFLocaleCollatorIdentifierKey, "kCFLocaleCollatorIdentifierKey"); +CONST_STRING_DECL(kCFLocaleCountryCodeKey, "kCFLocaleCountryCodeKey"); +CONST_STRING_DECL(kCFLocaleCurrencyCodeKey, "currency"); // *** +CONST_STRING_DECL(kCFLocaleCurrencySymbolKey, "kCFLocaleCurrencySymbolKey"); +CONST_STRING_DECL(kCFLocaleDecimalSeparatorKey, "kCFLocaleDecimalSeparatorKey"); +CONST_STRING_DECL(kCFLocaleExemplarCharacterSetKey, "kCFLocaleExemplarCharacterSetKey"); +CONST_STRING_DECL(kCFLocaleGroupingSeparatorKey, "kCFLocaleGroupingSeparatorKey"); +CONST_STRING_DECL(kCFLocaleIdentifierKey, "kCFLocaleIdentifierKey"); +CONST_STRING_DECL(kCFLocaleLanguageCodeKey, "kCFLocaleLanguageCodeKey"); +CONST_STRING_DECL(kCFLocaleMeasurementSystemKey, "kCFLocaleMeasurementSystemKey"); +CONST_STRING_DECL(kCFLocaleScriptCodeKey, "kCFLocaleScriptCodeKey"); +CONST_STRING_DECL(kCFLocaleUsesMetricSystemKey, "kCFLocaleUsesMetricSystemKey"); +CONST_STRING_DECL(kCFLocaleVariantCodeKey, "kCFLocaleVariantCodeKey"); + +CONST_STRING_DECL(kCFDateFormatterAMSymbolKey, "kCFDateFormatterAMSymbolKey"); +CONST_STRING_DECL(kCFDateFormatterCalendarKey, "kCFDateFormatterCalendarKey"); +CONST_STRING_DECL(kCFDateFormatterCalendarIdentifierKey, "kCFDateFormatterCalendarIdentifierKey"); +CONST_STRING_DECL(kCFDateFormatterDefaultDateKey, "kCFDateFormatterDefaultDateKey"); +CONST_STRING_DECL(kCFDateFormatterDefaultFormatKey, "kCFDateFormatterDefaultFormatKey"); +CONST_STRING_DECL(kCFDateFormatterDoesRelativeDateFormattingKey, "kCFDateFormatterDoesRelativeDateFormattingKey"); +CONST_STRING_DECL(kCFDateFormatterEraSymbolsKey, "kCFDateFormatterEraSymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterGregorianStartDateKey, "kCFDateFormatterGregorianStartDateKey"); +CONST_STRING_DECL(kCFDateFormatterIsLenientKey, "kCFDateFormatterIsLenientKey"); +CONST_STRING_DECL(kCFDateFormatterLongEraSymbolsKey, "kCFDateFormatterLongEraSymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterMonthSymbolsKey, "kCFDateFormatterMonthSymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterPMSymbolKey, "kCFDateFormatterPMSymbolKey"); +CONST_STRING_DECL(kCFDateFormatterQuarterSymbolsKey, "kCFDateFormatterQuarterSymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterShortMonthSymbolsKey, "kCFDateFormatterShortMonthSymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterShortQuarterSymbolsKey, "kCFDateFormatterShortQuarterSymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterShortStandaloneMonthSymbolsKey, "kCFDateFormatterShortStandaloneMonthSymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterShortStandaloneQuarterSymbolsKey, "kCFDateFormatterShortStandaloneQuarterSymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterShortStandaloneWeekdaySymbolsKey, "kCFDateFormatterShortStandaloneWeekdaySymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterShortWeekdaySymbolsKey, "kCFDateFormatterShortWeekdaySymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterStandaloneMonthSymbolsKey, "kCFDateFormatterStandaloneMonthSymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterStandaloneQuarterSymbolsKey, "kCFDateFormatterStandaloneQuarterSymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterStandaloneWeekdaySymbolsKey, "kCFDateFormatterStandaloneWeekdaySymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterTimeZoneKey, "kCFDateFormatterTimeZoneKey"); +CONST_STRING_DECL(kCFDateFormatterTwoDigitStartDateKey, "kCFDateFormatterTwoDigitStartDateKey"); +CONST_STRING_DECL(kCFDateFormatterVeryShortMonthSymbolsKey, "kCFDateFormatterVeryShortMonthSymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterVeryShortStandaloneMonthSymbolsKey, "kCFDateFormatterVeryShortStandaloneMonthSymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey, "kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterVeryShortWeekdaySymbolsKey, "kCFDateFormatterVeryShortWeekdaySymbolsKey"); +CONST_STRING_DECL(kCFDateFormatterWeekdaySymbolsKey, "kCFDateFormatterWeekdaySymbolsKey"); + +CONST_STRING_DECL(kCFNumberFormatterAlwaysShowDecimalSeparatorKey, "kCFNumberFormatterAlwaysShowDecimalSeparatorKey"); +CONST_STRING_DECL(kCFNumberFormatterCurrencyCodeKey, "kCFNumberFormatterCurrencyCodeKey"); +CONST_STRING_DECL(kCFNumberFormatterCurrencyDecimalSeparatorKey, "kCFNumberFormatterCurrencyDecimalSeparatorKey"); +CONST_STRING_DECL(kCFNumberFormatterCurrencyGroupingSeparatorKey, "kCFNumberFormatterCurrencyGroupingSeparatorKey"); +CONST_STRING_DECL(kCFNumberFormatterCurrencySymbolKey, "kCFNumberFormatterCurrencySymbolKey"); +CONST_STRING_DECL(kCFNumberFormatterDecimalSeparatorKey, "kCFNumberFormatterDecimalSeparatorKey"); +CONST_STRING_DECL(kCFNumberFormatterDefaultFormatKey, "kCFNumberFormatterDefaultFormatKey"); +CONST_STRING_DECL(kCFNumberFormatterExponentSymbolKey, "kCFNumberFormatterExponentSymbolKey"); +CONST_STRING_DECL(kCFNumberFormatterFormatWidthKey, "kCFNumberFormatterFormatWidthKey"); +CONST_STRING_DECL(kCFNumberFormatterGroupingSeparatorKey, "kCFNumberFormatterGroupingSeparatorKey"); +CONST_STRING_DECL(kCFNumberFormatterGroupingSizeKey, "kCFNumberFormatterGroupingSizeKey"); +CONST_STRING_DECL(kCFNumberFormatterInfinitySymbolKey, "kCFNumberFormatterInfinitySymbolKey"); +CONST_STRING_DECL(kCFNumberFormatterInternationalCurrencySymbolKey, "kCFNumberFormatterInternationalCurrencySymbolKey"); +CONST_STRING_DECL(kCFNumberFormatterIsLenientKey, "kCFNumberFormatterIsLenientKey"); +CONST_STRING_DECL(kCFNumberFormatterMaxFractionDigitsKey, "kCFNumberFormatterMaxFractionDigitsKey"); +CONST_STRING_DECL(kCFNumberFormatterMaxIntegerDigitsKey, "kCFNumberFormatterMaxIntegerDigitsKey"); +CONST_STRING_DECL(kCFNumberFormatterMaxSignificantDigitsKey, "kCFNumberFormatterMaxSignificantDigitsKey"); +CONST_STRING_DECL(kCFNumberFormatterMinFractionDigitsKey, "kCFNumberFormatterMinFractionDigitsKey"); +CONST_STRING_DECL(kCFNumberFormatterMinIntegerDigitsKey, "kCFNumberFormatterMinIntegerDigitsKey"); +CONST_STRING_DECL(kCFNumberFormatterMinSignificantDigitsKey, "kCFNumberFormatterMinSignificantDigitsKey"); +CONST_STRING_DECL(kCFNumberFormatterMinusSignKey, "kCFNumberFormatterMinusSignKey"); +CONST_STRING_DECL(kCFNumberFormatterMultiplierKey, "kCFNumberFormatterMultiplierKey"); +CONST_STRING_DECL(kCFNumberFormatterNaNSymbolKey, "kCFNumberFormatterNaNSymbolKey"); +CONST_STRING_DECL(kCFNumberFormatterNegativePrefixKey, "kCFNumberFormatterNegativePrefixKey"); +CONST_STRING_DECL(kCFNumberFormatterNegativeSuffixKey, "kCFNumberFormatterNegativeSuffixKey"); +CONST_STRING_DECL(kCFNumberFormatterPaddingCharacterKey, "kCFNumberFormatterPaddingCharacterKey"); +CONST_STRING_DECL(kCFNumberFormatterPaddingPositionKey, "kCFNumberFormatterPaddingPositionKey"); +CONST_STRING_DECL(kCFNumberFormatterPerMillSymbolKey, "kCFNumberFormatterPerMillSymbolKey"); +CONST_STRING_DECL(kCFNumberFormatterPercentSymbolKey, "kCFNumberFormatterPercentSymbolKey"); +CONST_STRING_DECL(kCFNumberFormatterPlusSignKey, "kCFNumberFormatterPlusSignKey"); +CONST_STRING_DECL(kCFNumberFormatterPositivePrefixKey, "kCFNumberFormatterPositivePrefixKey"); +CONST_STRING_DECL(kCFNumberFormatterPositiveSuffixKey, "kCFNumberFormatterPositiveSuffixKey"); +CONST_STRING_DECL(kCFNumberFormatterRoundingIncrementKey, "kCFNumberFormatterRoundingIncrementKey"); +CONST_STRING_DECL(kCFNumberFormatterRoundingModeKey, "kCFNumberFormatterRoundingModeKey"); +CONST_STRING_DECL(kCFNumberFormatterSecondaryGroupingSizeKey, "kCFNumberFormatterSecondaryGroupingSizeKey"); +CONST_STRING_DECL(kCFNumberFormatterUseGroupingSeparatorKey, "kCFNumberFormatterUseGroupingSeparatorKey"); +CONST_STRING_DECL(kCFNumberFormatterUseSignificantDigitsKey, "kCFNumberFormatterUseSignificantDigitsKey"); +CONST_STRING_DECL(kCFNumberFormatterZeroSymbolKey, "kCFNumberFormatterZeroSymbolKey"); + +CONST_STRING_DECL(kCFCalendarIdentifierGregorian, "gregorian"); +CONST_STRING_DECL(kCFCalendarIdentifierBuddhist, "buddhist"); +CONST_STRING_DECL(kCFCalendarIdentifierJapanese, "japanese"); +CONST_STRING_DECL(kCFCalendarIdentifierIslamic, "islamic"); +CONST_STRING_DECL(kCFCalendarIdentifierIslamicCivil, "islamic-civil"); +CONST_STRING_DECL(kCFCalendarIdentifierHebrew, "hebrew"); +CONST_STRING_DECL(kCFCalendarIdentifierChinese, "chinese"); +CONST_STRING_DECL(kCFCalendarIdentifierRepublicOfChina, "roc"); +CONST_STRING_DECL(kCFCalendarIdentifierPersian, "persian"); +CONST_STRING_DECL(kCFCalendarIdentifierIndian, "indian"); +CONST_STRING_DECL(kCFCalendarIdentifierISO8601, ""); +CONST_STRING_DECL(kCFCalendarIdentifierCoptic, "coptic"); +CONST_STRING_DECL(kCFCalendarIdentifierEthiopicAmeteMihret, "ethiopic"); +CONST_STRING_DECL(kCFCalendarIdentifierEthiopicAmeteAlem, "ethiopic-amete-alem"); + +// Aliases for Linux +#if DEPLOYMENT_TARGET_LINUX + +CF_EXPORT CFStringRef const kCFBuddhistCalendar __attribute__((alias ("kCFCalendarIdentifierBuddhist"))); +CF_EXPORT CFStringRef const kCFChineseCalendar __attribute__((alias ("kCFCalendarIdentifierChinese"))); +CF_EXPORT CFStringRef const kCFGregorianCalendar __attribute__((alias ("kCFCalendarIdentifierGregorian"))); +CF_EXPORT CFStringRef const kCFHebrewCalendar __attribute__((alias ("kCFCalendarIdentifierHebrew"))); +CF_EXPORT CFStringRef const kCFISO8601Calendar __attribute__((alias ("kCFCalendarIdentifierISO8601"))); +CF_EXPORT CFStringRef const kCFIndianCalendar __attribute__((alias ("kCFCalendarIdentifierIndian"))); +CF_EXPORT CFStringRef const kCFIslamicCalendar __attribute__((alias ("kCFCalendarIdentifierIslamic"))); +CF_EXPORT CFStringRef const kCFIslamicCivilCalendar __attribute__((alias ("kCFCalendarIdentifierIslamicCivil"))); +CF_EXPORT CFStringRef const kCFJapaneseCalendar __attribute__((alias ("kCFCalendarIdentifierJapanese"))); +CF_EXPORT CFStringRef const kCFPersianCalendar __attribute__((alias ("kCFCalendarIdentifierPersian"))); +CF_EXPORT CFStringRef const kCFRepublicOfChinaCalendar __attribute__((alias ("kCFCalendarIdentifierRepublicOfChina"))); + + +CF_EXPORT CFStringRef const kCFLocaleCalendarIdentifier __attribute__((alias ("kCFLocaleCalendarIdentifierKey"))); +CF_EXPORT CFStringRef const kCFLocaleCalendar __attribute__((alias ("kCFLocaleCalendarKey"))); +CF_EXPORT CFStringRef const kCFLocaleCollationIdentifier __attribute__((alias ("kCFLocaleCollationIdentifierKey"))); +CF_EXPORT CFStringRef const kCFLocaleCollatorIdentifier __attribute__((alias ("kCFLocaleCollatorIdentifierKey"))); +CF_EXPORT CFStringRef const kCFLocaleCountryCode __attribute__((alias ("kCFLocaleCountryCodeKey"))); +CF_EXPORT CFStringRef const kCFLocaleCurrencyCode __attribute__((alias ("kCFLocaleCurrencyCodeKey"))); +CF_EXPORT CFStringRef const kCFLocaleCurrencySymbol __attribute__((alias ("kCFLocaleCurrencySymbolKey"))); +CF_EXPORT CFStringRef const kCFLocaleDecimalSeparator __attribute__((alias ("kCFLocaleDecimalSeparatorKey"))); +CF_EXPORT CFStringRef const kCFLocaleExemplarCharacterSet __attribute__((alias ("kCFLocaleExemplarCharacterSetKey"))); +CF_EXPORT CFStringRef const kCFLocaleGroupingSeparator __attribute__((alias ("kCFLocaleGroupingSeparatorKey"))); +CF_EXPORT CFStringRef const kCFLocaleIdentifier __attribute__((alias ("kCFLocaleIdentifierKey"))); +CF_EXPORT CFStringRef const kCFLocaleLanguageCode __attribute__((alias ("kCFLocaleLanguageCodeKey"))); +CF_EXPORT CFStringRef const kCFLocaleMeasurementSystem __attribute__((alias ("kCFLocaleMeasurementSystemKey"))); +CF_EXPORT CFStringRef const kCFLocaleScriptCode __attribute__((alias ("kCFLocaleScriptCodeKey"))); +CF_EXPORT CFStringRef const kCFLocaleUsesMetricSystem __attribute__((alias ("kCFLocaleUsesMetricSystemKey"))); +CF_EXPORT CFStringRef const kCFLocaleVariantCode __attribute__((alias ("kCFLocaleVariantCodeKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterAMSymbol __attribute__((alias ("kCFDateFormatterAMSymbolKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterCalendar __attribute__((alias ("kCFDateFormatterCalendarKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterCalendarIdentifier __attribute__((alias ("kCFDateFormatterCalendarIdentifierKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterDefaultDate __attribute__((alias ("kCFDateFormatterDefaultDateKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterDefaultFormat __attribute__((alias ("kCFDateFormatterDefaultFormatKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterEraSymbols __attribute__((alias ("kCFDateFormatterEraSymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterGregorianStartDate __attribute__((alias ("kCFDateFormatterGregorianStartDateKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterIsLenient __attribute__((alias ("kCFDateFormatterIsLenientKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterLongEraSymbols __attribute__((alias ("kCFDateFormatterLongEraSymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterMonthSymbols __attribute__((alias ("kCFDateFormatterMonthSymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterPMSymbol __attribute__((alias ("kCFDateFormatterPMSymbolKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterQuarterSymbols __attribute__((alias ("kCFDateFormatterQuarterSymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterShortMonthSymbols __attribute__((alias ("kCFDateFormatterShortMonthSymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterShortQuarterSymbols __attribute__((alias ("kCFDateFormatterShortQuarterSymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterShortStandaloneMonthSymbols __attribute__((alias ("kCFDateFormatterShortStandaloneMonthSymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterShortStandaloneQuarterSymbols __attribute__((alias ("kCFDateFormatterShortStandaloneQuarterSymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterShortStandaloneWeekdaySymbols __attribute__((alias ("kCFDateFormatterShortStandaloneWeekdaySymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterShortWeekdaySymbols __attribute__((alias ("kCFDateFormatterShortWeekdaySymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterStandaloneMonthSymbols __attribute__((alias ("kCFDateFormatterStandaloneMonthSymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterStandaloneQuarterSymbols __attribute__((alias ("kCFDateFormatterStandaloneQuarterSymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterStandaloneWeekdaySymbols __attribute__((alias ("kCFDateFormatterStandaloneWeekdaySymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterTimeZone __attribute__((alias ("kCFDateFormatterTimeZoneKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterTwoDigitStartDate __attribute__((alias ("kCFDateFormatterTwoDigitStartDateKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterVeryShortMonthSymbols __attribute__((alias ("kCFDateFormatterVeryShortMonthSymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterVeryShortStandaloneMonthSymbols __attribute__((alias ("kCFDateFormatterVeryShortStandaloneMonthSymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterVeryShortStandaloneWeekdaySymbols __attribute__((alias ("kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterVeryShortWeekdaySymbols __attribute__((alias ("kCFDateFormatterVeryShortWeekdaySymbolsKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterWeekdaySymbols __attribute__((alias ("kCFDateFormatterWeekdaySymbolsKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterAlwaysShowDecimalSeparator __attribute__((alias ("kCFNumberFormatterAlwaysShowDecimalSeparatorKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterCurrencyCode __attribute__((alias ("kCFNumberFormatterCurrencyCodeKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterCurrencyDecimalSeparator __attribute__((alias ("kCFNumberFormatterCurrencyDecimalSeparatorKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterCurrencyGroupingSeparator __attribute__((alias ("kCFNumberFormatterCurrencyGroupingSeparatorKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterCurrencySymbol __attribute__((alias ("kCFNumberFormatterCurrencySymbolKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterDecimalSeparator __attribute__((alias ("kCFNumberFormatterDecimalSeparatorKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterDefaultFormat __attribute__((alias ("kCFNumberFormatterDefaultFormatKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterExponentSymbol __attribute__((alias ("kCFNumberFormatterExponentSymbolKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterFormatWidth __attribute__((alias ("kCFNumberFormatterFormatWidthKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterGroupingSeparator __attribute__((alias ("kCFNumberFormatterGroupingSeparatorKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterGroupingSize __attribute__((alias ("kCFNumberFormatterGroupingSizeKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterInfinitySymbol __attribute__((alias ("kCFNumberFormatterInfinitySymbolKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterInternationalCurrencySymbol __attribute__((alias ("kCFNumberFormatterInternationalCurrencySymbolKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterIsLenient __attribute__((alias ("kCFNumberFormatterIsLenientKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterMaxFractionDigits __attribute__((alias ("kCFNumberFormatterMaxFractionDigitsKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterMaxIntegerDigits __attribute__((alias ("kCFNumberFormatterMaxIntegerDigitsKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterMaxSignificantDigits __attribute__((alias ("kCFNumberFormatterMaxSignificantDigitsKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterMinFractionDigits __attribute__((alias ("kCFNumberFormatterMinFractionDigitsKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterMinIntegerDigits __attribute__((alias ("kCFNumberFormatterMinIntegerDigitsKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterMinSignificantDigits __attribute__((alias ("kCFNumberFormatterMinSignificantDigitsKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterMinusSign __attribute__((alias ("kCFNumberFormatterMinusSignKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterMultiplier __attribute__((alias ("kCFNumberFormatterMultiplierKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterNaNSymbol __attribute__((alias ("kCFNumberFormatterNaNSymbolKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterNegativePrefix __attribute__((alias ("kCFNumberFormatterNegativePrefixKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterNegativeSuffix __attribute__((alias ("kCFNumberFormatterNegativeSuffixKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterPaddingCharacter __attribute__((alias ("kCFNumberFormatterPaddingCharacterKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterPaddingPosition __attribute__((alias ("kCFNumberFormatterPaddingPositionKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterPerMillSymbol __attribute__((alias ("kCFNumberFormatterPerMillSymbolKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterPercentSymbol __attribute__((alias ("kCFNumberFormatterPercentSymbolKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterPlusSign __attribute__((alias ("kCFNumberFormatterPlusSignKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterPositivePrefix __attribute__((alias ("kCFNumberFormatterPositivePrefixKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterPositiveSuffix __attribute__((alias ("kCFNumberFormatterPositiveSuffixKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterRoundingIncrement __attribute__((alias ("kCFNumberFormatterRoundingIncrementKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterRoundingMode __attribute__((alias ("kCFNumberFormatterRoundingModeKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterSecondaryGroupingSize __attribute__((alias ("kCFNumberFormatterSecondaryGroupingSizeKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterUseGroupingSeparator __attribute__((alias ("kCFNumberFormatterUseGroupingSeparatorKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterUseSignificantDigits __attribute__((alias ("kCFNumberFormatterUseSignificantDigitsKey"))); +CF_EXPORT CFStringRef const kCFNumberFormatterZeroSymbol __attribute__((alias ("kCFNumberFormatterZeroSymbolKey"))); +CF_EXPORT CFStringRef const kCFDateFormatterCalendarName __attribute__((alias ("kCFDateFormatterCalendarIdentifierKey"))); + +#endif diff --git a/CFLocaleKeys.m b/CFLocaleKeys.m deleted file mode 100644 index ac19d7a..0000000 --- a/CFLocaleKeys.m +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (c) 2010 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@ - */ - - -@class NSString; - -NSString * const kCFLocaleAlternateQuotationBeginDelimiterKey = @"kCFLocaleAlternateQuotationBeginDelimiterKey"; -NSString * const kCFLocaleAlternateQuotationEndDelimiterKey = @"kCFLocaleAlternateQuotationEndDelimiterKey"; -NSString * const kCFLocaleQuotationBeginDelimiterKey = @"kCFLocaleQuotationBeginDelimiterKey"; -NSString * const kCFLocaleQuotationEndDelimiterKey = @"kCFLocaleQuotationEndDelimiterKey"; -NSString * const kCFLocaleCalendarIdentifierKey = @"calendar"; // *** -NSString * const kCFLocaleCalendarIdentifier = @"calendar"; // *** -NSString * const kCFLocaleCalendarKey = @"kCFLocaleCalendarKey"; -NSString * const kCFLocaleCollationIdentifierKey = @"collation"; // *** -NSString * const kCFLocaleCollatorIdentifierKey = @"kCFLocaleCollatorIdentifierKey"; -NSString * const kCFLocaleCountryCodeKey = @"kCFLocaleCountryCodeKey"; -NSString * const kCFLocaleCurrencyCodeKey = @"currency"; // *** -NSString * const kCFLocaleCurrencySymbolKey = @"kCFLocaleCurrencySymbolKey"; -NSString * const kCFLocaleDecimalSeparatorKey = @"kCFLocaleDecimalSeparatorKey"; -NSString * const kCFLocaleExemplarCharacterSetKey = @"kCFLocaleExemplarCharacterSetKey"; -NSString * const kCFLocaleGroupingSeparatorKey = @"kCFLocaleGroupingSeparatorKey"; -NSString * const kCFLocaleIdentifierKey = @"kCFLocaleIdentifierKey"; -NSString * const kCFLocaleLanguageCodeKey = @"kCFLocaleLanguageCodeKey"; -NSString * const kCFLocaleMeasurementSystemKey = @"kCFLocaleMeasurementSystemKey"; -NSString * const kCFLocaleScriptCodeKey = @"kCFLocaleScriptCodeKey"; -NSString * const kCFLocaleUsesMetricSystemKey = @"kCFLocaleUsesMetricSystemKey"; -NSString * const kCFLocaleVariantCodeKey = @"kCFLocaleVariantCodeKey"; - -NSString * const kCFDateFormatterAMSymbolKey = @"kCFDateFormatterAMSymbolKey"; -NSString * const kCFDateFormatterCalendarKey = @"kCFDateFormatterCalendarKey"; -NSString * const kCFDateFormatterCalendarIdentifierKey = @"kCFDateFormatterCalendarIdentifierKey"; -NSString * const kCFDateFormatterDefaultDateKey = @"kCFDateFormatterDefaultDateKey"; -NSString * const kCFDateFormatterDefaultFormatKey = @"kCFDateFormatterDefaultFormatKey"; -NSString * const kCFDateFormatterDoesRelativeDateFormattingKey = @"kCFDateFormatterDoesRelativeDateFormattingKey"; -NSString * const kCFDateFormatterEraSymbolsKey = @"kCFDateFormatterEraSymbolsKey"; -NSString * const kCFDateFormatterGregorianStartDateKey = @"kCFDateFormatterGregorianStartDateKey"; -NSString * const kCFDateFormatterIsLenientKey = @"kCFDateFormatterIsLenientKey"; -NSString * const kCFDateFormatterLongEraSymbolsKey = @"kCFDateFormatterLongEraSymbolsKey"; -NSString * const kCFDateFormatterMonthSymbolsKey = @"kCFDateFormatterMonthSymbolsKey"; -NSString * const kCFDateFormatterPMSymbolKey = @"kCFDateFormatterPMSymbolKey"; -NSString * const kCFDateFormatterQuarterSymbolsKey = @"kCFDateFormatterQuarterSymbolsKey"; -NSString * const kCFDateFormatterShortMonthSymbolsKey = @"kCFDateFormatterShortMonthSymbolsKey"; -NSString * const kCFDateFormatterShortQuarterSymbolsKey = @"kCFDateFormatterShortQuarterSymbolsKey"; -NSString * const kCFDateFormatterShortStandaloneMonthSymbolsKey = @"kCFDateFormatterShortStandaloneMonthSymbolsKey"; -NSString * const kCFDateFormatterShortStandaloneQuarterSymbolsKey = @"kCFDateFormatterShortStandaloneQuarterSymbolsKey"; -NSString * const kCFDateFormatterShortStandaloneWeekdaySymbolsKey = @"kCFDateFormatterShortStandaloneWeekdaySymbolsKey"; -NSString * const kCFDateFormatterShortWeekdaySymbolsKey = @"kCFDateFormatterShortWeekdaySymbolsKey"; -NSString * const kCFDateFormatterStandaloneMonthSymbolsKey = @"kCFDateFormatterStandaloneMonthSymbolsKey"; -NSString * const kCFDateFormatterStandaloneQuarterSymbolsKey = @"kCFDateFormatterStandaloneQuarterSymbolsKey"; -NSString * const kCFDateFormatterStandaloneWeekdaySymbolsKey = @"kCFDateFormatterStandaloneWeekdaySymbolsKey"; -NSString * const kCFDateFormatterTimeZoneKey = @"kCFDateFormatterTimeZoneKey"; -NSString * const kCFDateFormatterTimeZone = @"kCFDateFormatterTimeZoneKey"; -NSString * const kCFDateFormatterTwoDigitStartDateKey = @"kCFDateFormatterTwoDigitStartDateKey"; -NSString * const kCFDateFormatterVeryShortMonthSymbolsKey = @"kCFDateFormatterVeryShortMonthSymbolsKey"; -NSString * const kCFDateFormatterVeryShortStandaloneMonthSymbolsKey = @"kCFDateFormatterVeryShortStandaloneMonthSymbolsKey"; -NSString * const kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey = @"kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey"; -NSString * const kCFDateFormatterVeryShortWeekdaySymbolsKey = @"kCFDateFormatterVeryShortWeekdaySymbolsKey"; -NSString * const kCFDateFormatterWeekdaySymbolsKey = @"kCFDateFormatterWeekdaySymbolsKey"; - -NSString * const kCFNumberFormatterAlwaysShowDecimalSeparatorKey = @"kCFNumberFormatterAlwaysShowDecimalSeparatorKey"; -NSString * const kCFNumberFormatterCurrencyCodeKey = @"kCFNumberFormatterCurrencyCodeKey"; -NSString * const kCFNumberFormatterCurrencyDecimalSeparatorKey = @"kCFNumberFormatterCurrencyDecimalSeparatorKey"; -NSString * const kCFNumberFormatterCurrencyGroupingSeparatorKey = @"kCFNumberFormatterCurrencyGroupingSeparatorKey"; -NSString * const kCFNumberFormatterCurrencySymbolKey = @"kCFNumberFormatterCurrencySymbolKey"; -NSString * const kCFNumberFormatterDecimalSeparatorKey = @"kCFNumberFormatterDecimalSeparatorKey"; -NSString * const kCFNumberFormatterDefaultFormatKey = @"kCFNumberFormatterDefaultFormatKey"; -NSString * const kCFNumberFormatterExponentSymbolKey = @"kCFNumberFormatterExponentSymbolKey"; -NSString * const kCFNumberFormatterFormatWidthKey = @"kCFNumberFormatterFormatWidthKey"; -NSString * const kCFNumberFormatterGroupingSeparatorKey = @"kCFNumberFormatterGroupingSeparatorKey"; -NSString * const kCFNumberFormatterGroupingSizeKey = @"kCFNumberFormatterGroupingSizeKey"; -NSString * const kCFNumberFormatterInfinitySymbolKey = @"kCFNumberFormatterInfinitySymbolKey"; -NSString * const kCFNumberFormatterInternationalCurrencySymbolKey = @"kCFNumberFormatterInternationalCurrencySymbolKey"; -NSString * const kCFNumberFormatterIsLenientKey = @"kCFNumberFormatterIsLenientKey"; -NSString * const kCFNumberFormatterMaxFractionDigitsKey = @"kCFNumberFormatterMaxFractionDigitsKey"; -NSString * const kCFNumberFormatterMaxIntegerDigitsKey = @"kCFNumberFormatterMaxIntegerDigitsKey"; -NSString * const kCFNumberFormatterMaxSignificantDigitsKey = @"kCFNumberFormatterMaxSignificantDigitsKey"; -NSString * const kCFNumberFormatterMinFractionDigitsKey = @"kCFNumberFormatterMinFractionDigitsKey"; -NSString * const kCFNumberFormatterMinIntegerDigitsKey = @"kCFNumberFormatterMinIntegerDigitsKey"; -NSString * const kCFNumberFormatterMinSignificantDigitsKey = @"kCFNumberFormatterMinSignificantDigitsKey"; -NSString * const kCFNumberFormatterMinusSignKey = @"kCFNumberFormatterMinusSignKey"; -NSString * const kCFNumberFormatterMultiplierKey = @"kCFNumberFormatterMultiplierKey"; -NSString * const kCFNumberFormatterNaNSymbolKey = @"kCFNumberFormatterNaNSymbolKey"; -NSString * const kCFNumberFormatterNegativePrefixKey = @"kCFNumberFormatterNegativePrefixKey"; -NSString * const kCFNumberFormatterNegativeSuffixKey = @"kCFNumberFormatterNegativeSuffixKey"; -NSString * const kCFNumberFormatterPaddingCharacterKey = @"kCFNumberFormatterPaddingCharacterKey"; -NSString * const kCFNumberFormatterPaddingPositionKey = @"kCFNumberFormatterPaddingPositionKey"; -NSString * const kCFNumberFormatterPerMillSymbolKey = @"kCFNumberFormatterPerMillSymbolKey"; -NSString * const kCFNumberFormatterPercentSymbolKey = @"kCFNumberFormatterPercentSymbolKey"; -NSString * const kCFNumberFormatterPlusSignKey = @"kCFNumberFormatterPlusSignKey"; -NSString * const kCFNumberFormatterPositivePrefixKey = @"kCFNumberFormatterPositivePrefixKey"; -NSString * const kCFNumberFormatterPositiveSuffixKey = @"kCFNumberFormatterPositiveSuffixKey"; -NSString * const kCFNumberFormatterRoundingIncrementKey = @"kCFNumberFormatterRoundingIncrementKey"; -NSString * const kCFNumberFormatterRoundingModeKey = @"kCFNumberFormatterRoundingModeKey"; -NSString * const kCFNumberFormatterSecondaryGroupingSizeKey = @"kCFNumberFormatterSecondaryGroupingSizeKey"; -NSString * const kCFNumberFormatterUseGroupingSeparatorKey = @"kCFNumberFormatterUseGroupingSeparatorKey"; -NSString * const kCFNumberFormatterUseSignificantDigitsKey = @"kCFNumberFormatterUseSignificantDigitsKey"; -NSString * const kCFNumberFormatterZeroSymbolKey = @"kCFNumberFormatterZeroSymbolKey"; - -NSString * const kCFCalendarIdentifierGregorian = @"gregorian"; -NSString * const kCFCalendarIdentifierBuddhist = @"buddhist"; -NSString * const kCFCalendarIdentifierJapanese = @"japanese"; -NSString * const kCFCalendarIdentifierIslamic = @"islamic"; -NSString * const kCFCalendarIdentifierIslamicCivil = @"islamic-civil"; -NSString * const kCFCalendarIdentifierHebrew = @"hebrew"; -NSString * const kCFCalendarIdentifierChinese = @"chinese"; -NSString * const kCFCalendarIdentifierRepublicOfChina = @"roc"; -NSString * const kCFCalendarIdentifierPersian = @"persian"; -NSString * const kCFCalendarIdentifierIndian = @"indian"; -NSString * const kCFCalendarIdentifierISO8601 = @""; -NSString * const kCFCalendarIdentifierCoptic = @"coptic"; -NSString * const kCFCalendarIdentifierEthiopicAmeteMihret = @"ethiopic"; -NSString * const kCFCalendarIdentifierEthiopicAmeteAlem = @"ethiopic-amete-alem"; - -NSString * const kCFGregorianCalendar = @"gregorian"; -NSString * const kCFBuddhistCalendar = @"buddhist"; -NSString * const kCFChineseCalendar = @"chinese"; -NSString * const kCFHebrewCalendar = @"hebrew"; -NSString * const kCFIslamicCalendar = @"islamic"; -NSString * const kCFIslamicCivilCalendar = @"islamic-civil"; -NSString * const kCFJapaneseCalendar = @"japanese"; -NSString * const kCFRepublicOfChinaCalendar = @"roc"; -NSString * const kCFPersianCalendar = @"persian"; -NSString * const kCFIndianCalendar = @"indian"; -NSString * const kCFISO8601Calendar = @""; diff --git a/CFLogUtilities.h b/CFLogUtilities.h index 12ff4b8..09e87e2 100644 --- a/CFLogUtilities.h +++ b/CFLogUtilities.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFLogUtilities.h - Copyright (c) 2004-2009, Apple Inc. All rights reserved. + Copyright (c) 2004-2011, Apple Inc. All rights reserved. */ /* diff --git a/CFMachPort.c b/CFMachPort.c index 5f9cbb5..4a60872 100644 --- a/CFMachPort.c +++ b/CFMachPort.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFMachPort.c - Copyright (c) 1998-2010, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include "CFInternal.h" @@ -225,7 +224,7 @@ static __CFPointerArray *__CFAllMachPorts = nil; static Boolean __CFMachPortCheck(mach_port_t port) { mach_port_type_t type = 0; kern_return_t ret = mach_port_type(mach_task_self(), port, &type); - return (KERN_SUCCESS != ret || (type & MACH_PORT_TYPE_DEAD_NAME)) ? false : true; + return (KERN_SUCCESS != ret || (0 == (type & MACH_PORT_TYPE_PORT_RIGHTS))) ? false : true; } static void __CFMachPortChecker(Boolean fromTimer) { // only call on __portQueue() @@ -322,7 +321,7 @@ CFMachPortRef _CFMachPortCreateWithPort2(CFAllocatorRef allocator, mach_port_t p mach_port_type_t type = 0; kern_return_t ret = mach_port_type(mach_task_self(), port, &type); - if (KERN_SUCCESS != ret || (type & ~(MACH_PORT_TYPE_SEND|MACH_PORT_TYPE_SEND_ONCE|MACH_PORT_TYPE_RECEIVE|MACH_PORT_TYPE_DNREQUEST))) { + if (KERN_SUCCESS != ret || (0 == (type & MACH_PORT_TYPE_PORT_RIGHTS))) { if (type & ~MACH_PORT_TYPE_DEAD_NAME) { CFLog(kCFLogLevelError, CFSTR("*** CFMachPortCreateWithPort(): bad Mach port parameter (0x%lx) or unsupported mysterious kind of Mach port (%d, %ld)"), (unsigned long)port, ret, (unsigned long)type); } @@ -331,17 +330,16 @@ CFMachPortRef _CFMachPortCreateWithPort2(CFAllocatorRef allocator, mach_port_t p __block CFMachPortRef mp = NULL; dispatch_sync(__portQueue(), ^{ - static Boolean portCheckerGoing = false; - if (!portCheckerGoing) { + static dispatch_source_t timerSource = NULL; + if (timerSource == NULL) { uint64_t nanos = 63 * 1000 * 1000 * 1000ULL; uint64_t leeway = 9 * 1000ULL; - dispatch_source_t timerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, __portQueue()); + 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); - portCheckerGoing = true; } #if defined(AVOID_WEAK_COLLECTIONS) @@ -535,11 +533,6 @@ Boolean CFMachPortIsValid(CFMachPortRef mp) { mach_port_type_t type = 0; kern_return_t ret = mach_port_type(mach_task_self(), mp->_port, &type); if (KERN_SUCCESS != ret || (type & ~(MACH_PORT_TYPE_SEND|MACH_PORT_TYPE_SEND_ONCE|MACH_PORT_TYPE_RECEIVE|MACH_PORT_TYPE_DNREQUEST))) { - CFRetain(mp); - dispatch_async(dispatch_get_global_queue(0, 0), ^{ - CFMachPortInvalidate(mp); - CFRelease(mp); - }); return false; } return true; @@ -583,20 +576,20 @@ static void *__CFMachPortPerform(void *msg, CFIndex size, CFAllocatorRef allocat 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; + } }); if (!isValid) return NULL; - void *context_info = NULL; - void (*context_release)(const void *) = NULL; - if (mp->_context.retain) { - context_info = (void *)mp->_context.retain(mp->_context.info); - context_release = mp->_context.release; - } else { - context_info = mp->_context.info; - } - mp->_callout(mp, msg, size, context_info); if (context_release) { diff --git a/CFMachPort.h b/CFMachPort.h index 35c9bc4..5114750 100644 --- a/CFMachPort.h +++ b/CFMachPort.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFMachPort.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFMACHPORT__) diff --git a/CFMessagePort.c b/CFMessagePort.c index 40afce5..2caf0a6 100644 --- a/CFMessagePort.c +++ b/CFMessagePort.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFMessagePort.c - Copyright (c) 1998-2010, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ @@ -44,7 +44,6 @@ extern pid_t getpid(void); - #define __kCFMessagePortMaxNameLengthMax 255 #if defined(BOOTSTRAP_MAX_NAME_LEN) @@ -60,8 +59,10 @@ 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; @@ -82,6 +83,7 @@ struct __CFMessagePort { dispatch_queue_t _dispatchQ; /* only used by local port */ CFMessagePortInvalidationCallBack _icallout; CFMessagePortCallBack _callout; /* only used by local port; immutable */ + CFMessagePortCallBackEx _calloutEx; /* only used by local port; immutable */ CFMessagePortContext _context; /* not part of remote port; immutable; invalidated */ }; @@ -230,7 +232,7 @@ static CFStringRef __CFMessagePortCopyDescription(CFTypeRef cf) { if (NULL == contextDesc) { contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR(""), ms->_context.info); } - void *addr = ms->_callout; + void *addr = ms->_callout ? (void *)ms->_callout : (void *)ms->_calloutEx; Dl_info info; const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{locked = %s, valid = %s, remote = %s, name = %@, source = %p, callout = %s (%p), context = %@}"), cf, CFGetAllocator(ms), locked, (__CFMessagePortIsValid(ms) ? "Yes" : "No"), (__CFMessagePortIsRemote(ms) ? "Yes" : "No"), ms->_name, ms->_source, name, addr, (NULL != contextDesc ? contextDesc : CFSTR(""))); @@ -315,18 +317,25 @@ CFTypeID CFMessagePortGetTypeID(void) { static CFStringRef __CFMessagePortSanitizeStringName(CFStringRef name, uint8_t **utfnamep, CFIndex *utfnamelenp) { uint8_t *utfname; CFIndex utflen; - CFStringRef result; + CFStringRef result = NULL; utfname = CFAllocatorAllocate(kCFAllocatorSystemDefault, __kCFMessagePortMaxNameLength + 1, 0); CFStringGetBytes(name, CFRangeMake(0, CFStringGetLength(name)), kCFStringEncodingUTF8, 0, false, utfname, __kCFMessagePortMaxNameLength, &utflen); utfname[utflen] = '\0'; - /* A new string is created, because the original string may have been - truncated to the max length, and we want the string name to definitely - match the raw UTF-8 chunk that has been created. Also, this is useful - to get a constant string in case the original name string was mutable. */ - result = CFStringCreateWithBytes(kCFAllocatorSystemDefault, utfname, utflen, kCFStringEncodingUTF8, false); + if (strlen(utfname) != utflen) { + /* PCA 9194709: refuse to sanitize a string with an embedded nul character */ + CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); + utfname = NULL; + utfnamelenp = 0; + } else { + /* A new string is created, because the original string may have been + truncated to the max length, and we want the string name to definitely + match the raw UTF-8 chunk that has been created. Also, this is useful + to get a constant string in case the original name string was mutable. */ + result = CFStringCreateWithBytes(kCFAllocatorSystemDefault, utfname, utflen, kCFStringEncodingUTF8, false); + } if (NULL != utfnamep) { *utfnamep = utfname; - } else { + } else if (NULL != utfname) { CFAllocatorDeallocate(kCFAllocatorSystemDefault, utfname); } if (NULL != utfnamelenp) { @@ -344,7 +353,7 @@ static void __CFMessagePortInvalidationCallBack(CFMachPortRef port, void *info) if (info) CFMessagePortInvalidate(info); } -static CFMessagePortRef __CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo, Boolean perPID) { +static CFMessagePortRef __CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo, Boolean perPID, CFMessagePortCallBackEx calloutEx) { CFMessagePortRef memory; uint8_t *utfname = NULL; @@ -392,6 +401,7 @@ static CFMessagePortRef __CFMessagePortCreateLocal(CFAllocatorRef allocator, CFS memory->_dispatchQ = NULL; memory->_icallout = NULL; memory->_callout = callout; + memory->_calloutEx = calloutEx; memory->_context.info = NULL; memory->_context.retain = NULL; memory->_context.release = NULL; @@ -471,11 +481,15 @@ static CFMessagePortRef __CFMessagePortCreateLocal(CFAllocatorRef allocator, CFS } CFMessagePortRef CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) { - return __CFMessagePortCreateLocal(allocator, name, callout, context, shouldFreeInfo, false); + return __CFMessagePortCreateLocal(allocator, name, callout, context, shouldFreeInfo, false, NULL); } CFMessagePortRef CFMessagePortCreatePerProcessLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) { - return __CFMessagePortCreateLocal(allocator, name, callout, context, shouldFreeInfo, true); + return __CFMessagePortCreateLocal(allocator, name, callout, context, shouldFreeInfo, true, NULL); +} + +CFMessagePortRef _CFMessagePortCreateLocalEx(CFAllocatorRef allocator, CFStringRef name, Boolean perPID, uintptr_t unused, CFMessagePortCallBackEx calloutEx, CFMessagePortContext *context, Boolean *shouldFreeInfo) { + return __CFMessagePortCreateLocal(allocator, name, NULL, context, shouldFreeInfo, perPID, calloutEx); } static CFMessagePortRef __CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef name, Boolean perPID, CFIndex pid) { @@ -531,6 +545,7 @@ static CFMessagePortRef __CFMessagePortCreateRemote(CFAllocatorRef allocator, CF memory->_dispatchQ = NULL; memory->_icallout = NULL; memory->_callout = NULL; + memory->_calloutEx = NULL; ctx.version = 0; ctx.info = memory; ctx.retain = NULL; @@ -721,6 +736,7 @@ void CFMessagePortInvalidate(CFMessagePortRef ms) { } ms->_source = NULL; ms->_replyPort = NULL; + ms->_port = NULL; __CFMessagePortUnlock(ms); __CFSpinLock(&__CFAllMessagePortsLock); @@ -731,13 +747,6 @@ void CFMessagePortInvalidate(CFMessagePortRef ms) { if (NULL != callout) { callout(ms, info); } - // We already know we're going invalid, don't need this callback - // anymore; plus, this solves a reentrancy deadlock; also, this - // must be done before the deallocate of the Mach port, to - // avoid a race between the notification message which could be - // handled in another thread, and this NULL'ing out. - CFMachPortSetInvalidationCallBack(port, NULL); - // For hashing and equality purposes, cannot get rid of _port here if (!__CFMessagePortIsRemote(ms) && NULL != ms->_context.release) { ms->_context.release(info); } @@ -753,6 +762,20 @@ void CFMessagePortInvalidate(CFMessagePortRef ms) { // Get rid of our extra ref on the Mach port gotten from bs server mach_port_deallocate(mach_task_self(), CFMachPortGetPort(port)); } + if (NULL != port) { + // We already know we're going invalid, don't need this callback + // anymore; plus, this solves a reentrancy deadlock; also, this + // must be done before the deallocate of the Mach port, to + // avoid a race between the notification message which could be + // handled in another thread, and this NULL'ing out. + CFMachPortSetInvalidationCallBack(port, NULL); + if (__CFMessagePortExtraMachRef(ms)) { + mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(port), MACH_PORT_RIGHT_SEND, -1); + mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(port), MACH_PORT_RIGHT_RECEIVE, -1); + } + CFMachPortInvalidate(port); + CFRelease(port); + } } else { __CFMessagePortUnlock(ms); } @@ -959,7 +982,7 @@ SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CFDataRef static mach_port_t __CFMessagePortGetPort(void *info) { CFMessagePortRef ms = info; - if (!ms->_port) CFLog(kCFLogLevelWarning, CFSTR("*** Warning: A local CFMessagePort (%p) is being put in a run loop or dispatch queue, but it has not been named yet, so this will be a no-op and no messages are going to be received, even if named later."), info); + if (!ms->_port && __CFMessagePortIsValid(ms)) CFLog(kCFLogLevelWarning, CFSTR("*** Warning: A local CFMessagePort (%p) is being put in a run loop or dispatch queue, but it has not been named yet, so this will be a no-op and no messages are going to be received, even if named later."), info); return ms->_port ? CFMachPortGetPort(ms->_port) : MACH_PORT_NULL; } @@ -1024,7 +1047,12 @@ static void *__CFMessagePortPerform(void *msg, CFIndex size, CFAllocatorRef allo msgid = CFSwapInt32LittleToHost(MSGP_GET(msgp, msgid)); data = CFDataCreateWithBytesNoCopy(allocator, MSGP1_FIELD(msgp, ool).address, MSGP1_FIELD(msgp, ool).size, kCFAllocatorNull); } - returnData = ms->_callout(ms, msgid, data, context_info); + if (ms->_callout) { + returnData = ms->_callout(ms, msgid, data, context_info); + } else { + mach_msg_trailer_t *trailer = (mach_msg_trailer_t *)(((uintptr_t)&(msgp->header) + msgp->header.msgh_size + sizeof(natural_t) - 1) & ~(sizeof(natural_t) - 1)); + returnData = ms->_calloutEx(ms, msgid, data, context_info, trailer, 0); + } /* Now, returnData could be (1) NULL, (2) an ordinary data < MAX_INLINE, (3) ordinary data >= MAX_INLINE, (4) a no-copy data < MAX_INLINE, (5) a no-copy data >= MAX_INLINE. In cases (2) and (4), we send the return diff --git a/CFMessagePort.h b/CFMessagePort.h index 5bf900c..a7d6d92 100644 --- a/CFMessagePort.h +++ b/CFMessagePort.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFMessagePort.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFMESSAGEPORT__) @@ -31,9 +31,7 @@ #include #include #include -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) #include -#endif CF_EXTERN_C_BEGIN @@ -79,9 +77,7 @@ CF_EXPORT SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CF_EXPORT CFRunLoopSourceRef CFMessagePortCreateRunLoopSource(CFAllocatorRef allocator, CFMessagePortRef local, CFIndex order); -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) -CF_EXPORT void CFMessagePortSetDispatchQueue(CFMessagePortRef ms, dispatch_queue_t queue) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; -#endif +CF_EXPORT void CFMessagePortSetDispatchQueue(CFMessagePortRef ms, dispatch_queue_t queue) CF_AVAILABLE(10_6, 4_0); CF_EXTERN_C_END diff --git a/CFNumber.c b/CFNumber.c index d4b3bfa..8484b27 100644 --- a/CFNumber.c +++ b/CFNumber.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFNumber.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. Responsibility: Ali Ozer */ @@ -36,9 +36,6 @@ #define isnan(A) _isnan(A) #define isinf(A) !_finite(A) #define copysign(A, B) _copysign(A, B) -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif #define __CFAssertIsBoolean(cf) __CFGenericValidateType(cf, __kCFBooleanTypeID) @@ -62,7 +59,7 @@ static CFStringRef __CFBooleanCopyDescription(CFTypeRef cf) { return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{value = %s}"), cf, CFGetAllocator(cf), (boolean == kCFBooleanTrue) ? "true" : "false"); } -static CFStringRef __CFBooleanCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { +__private_extern__ CFStringRef __CFBooleanCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { CFBooleanRef boolean = (CFBooleanRef)cf; return (CFStringRef)CFRetain((boolean == kCFBooleanTrue) ? CFSTR("true") : CFSTR("false")); } @@ -153,7 +150,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 +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || 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 @@ -425,7 +422,14 @@ static const struct { /* kCFNumberSInt128Type */ {kCFNumberSInt128Type, 0, 1, 4, 0}, }; +#define CF_IS_TAGGED_INT(OBJ) (CF_TAGGED_OBJ_TYPE(OBJ) == kCFTaggedObjectID_Integer) + CF_INLINE CFNumberType __CFNumberGetType(CFNumberRef num) { + if (CF_IS_TAGGED_INT(num)) { + uintptr_t type_bits = ((uintptr_t)num >> 6) & 0x3; // top 2 bits of low byte + const CFNumberType canonical_types[4] = {kCFNumberSInt8Type, kCFNumberSInt16Type, kCFNumberSInt32Type, kCFNumberSInt64Type}; + return canonical_types[type_bits]; + } return __CFBitfieldGetValue(num->_base._cfinfo[CF_INFO_BITS], 4, 0); } @@ -457,6 +461,12 @@ static Boolean __CFNumberGetValue(CFNumberRef number, CFNumberType type, void *v type = __CFNumberTypeTable[type].canonicalType; CFNumberType ntype = __CFNumberGetType(number); const void *data = &(number->_pad); + intptr_t taggedInteger; + if (CF_IS_TAGGED_INT(number)) { + taggedInteger = (intptr_t)number; + taggedInteger = taggedInteger >> 8; + data = &taggedInteger; + } switch (type) { case kCFNumberSInt8Type: if (__CFNumberTypeTable[ntype].floatBit) { @@ -647,6 +657,12 @@ static Boolean __CFNumberGetValueCompat(CFNumberRef number, CFNumberType type, v type = __CFNumberTypeTable[type].canonicalType; CFNumberType ntype = __CFNumberGetType(number); const void *data = &(number->_pad); + intptr_t taggedInteger; + if (CF_IS_TAGGED_INT(number)) { + taggedInteger = (intptr_t)number; + taggedInteger = taggedInteger >> 8; + data = &taggedInteger; + } switch (type) { case kCFNumberSInt8Type: if (__CFNumberTypeTable[ntype].floatBit) { @@ -862,7 +878,7 @@ CFLog(kCFLogLevelWarning, CFSTR("*** TEST FAIL in __CFNumberCopyDescription: '%@ // This function separated out from __CFNumberCopyFormattingDescription() so the plist creation can use it as well. -static CFStringRef __CFNumberCopyFormattingDescriptionAsFloat64_new(CFTypeRef cf) { +static CFStringRef __CFNumberCreateFormattingDescriptionAsFloat64(CFAllocatorRef allocator, CFTypeRef cf) { Float64 d; CFNumberGetValue((CFNumberRef)cf, kCFNumberFloat64Type, &d); if (isnan(d)) { @@ -875,11 +891,11 @@ static CFStringRef __CFNumberCopyFormattingDescriptionAsFloat64_new(CFTypeRef cf return (CFStringRef)CFRetain(CFSTR("0.0")); } // if %g is used here, need to use DBL_DIG + 2 on Mac OS X, but %f needs +1 - return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%.*g"), DBL_DIG + 2, d); + return CFStringCreateWithFormat(allocator, NULL, CFSTR("%.*g"), DBL_DIG + 2, d); } __private_extern__ CFStringRef __CFNumberCopyFormattingDescriptionAsFloat64(CFTypeRef cf) { - CFStringRef result = __CFNumberCopyFormattingDescriptionAsFloat64_new(cf); + CFStringRef result = __CFNumberCreateFormattingDescriptionAsFloat64(kCFAllocatorSystemDefault, cf); #if OLD_CRAP_TOO CFNumberRef number = (CFNumberRef)cf; if (! number->__old__) { @@ -894,6 +910,19 @@ CFLog(kCFLogLevelWarning, CFSTR("*** TEST FAIL in __CFNumberCopyFormattingDescri return result; } +__private_extern__ CFStringRef __CFNumberCreateFormattingDescription(CFAllocatorRef allocator, CFTypeRef cf, CFDictionaryRef formatOptions) { + CFNumberRef number = (CFNumberRef)cf; + CFNumberType type = __CFNumberGetType(number); + if (__CFNumberTypeTable[type].floatBit) { + return __CFNumberCreateFormattingDescriptionAsFloat64(allocator, number); + } + CFSInt128Struct i; + __CFNumberGetValue(number, kCFNumberSInt128Type, &i); + char buffer[128]; + emit128(buffer, &i, false); + return CFStringCreateWithFormat(allocator, NULL, CFSTR("%s"), buffer); +} + static CFStringRef __CFNumberCopyFormattingDescription_new(CFTypeRef cf, CFDictionaryRef formatOptions) { CFNumberRef number = (CFNumberRef)cf; CFNumberType type = __CFNumberGetType(number); @@ -907,7 +936,7 @@ static CFStringRef __CFNumberCopyFormattingDescription_new(CFTypeRef cf, CFDicti return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%s"), buffer); } -static CFStringRef __CFNumberCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { +__private_extern__ CFStringRef __CFNumberCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { CFStringRef result = __CFNumberCopyFormattingDescription_new(cf, formatOptions); #if OLD_CRAP_TOO CFNumberRef number = (CFNumberRef)cf; @@ -975,6 +1004,14 @@ CFLog(kCFLogLevelWarning, CFSTR("*** TEST FAIL in __CFNumberHash: '%d' '%d'"), h } static CFTypeID __kCFNumberTypeID = _kCFRuntimeNotATypeID; +static void *__CFTaggedNumberClass = 0; + +enum { + kCFNumberCachingEnabled = 0, + kCFNumberCachingDisabled = 1, + kCFNumberCachingFullyDisabled = 2 +}; +static char __CFNumberCaching = kCFNumberCachingEnabled; static const CFRuntimeClass __CFNumberClass = { 0, @@ -1005,6 +1042,10 @@ __private_extern__ void __CFNumberInitialize(void) { __kCFNumberPositiveInfinity._base._cfisa = __CFISAForTypeID(__kCFNumberTypeID); __CFBitfieldSetValue(__kCFNumberPositiveInfinity._base._cfinfo[CF_INFO_BITS], 4, 0, kCFNumberFloat64Type); __kCFNumberPositiveInfinity._pad = BITSFORDOUBLEPOSINF; + + + const char *caching = __CFgetenv("CFNumberDisableCache"); // "all" to disable caching and tagging; anything else to disable caching; nothing to leave both enabled + if (caching) __CFNumberCaching = (!strcmp(caching, "all")) ? kCFNumberCachingFullyDisabled : kCFNumberCachingDisabled; // initial state above is kCFNumberCachingEnabled } CFTypeID CFNumberGetTypeID(void) { @@ -1020,13 +1061,46 @@ CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType type, const vo __CFAssertIsValidNumberType(type); //printf("+ [%p] CFNumberCreate(%p, %d, %p)\n", pthread_self(), allocator, type, valuePtr); + if (!allocator) allocator = __CFGetDefaultAllocator(); + + if (__CFTaggedNumberClass && _CFAllocatorIsSystemDefault(allocator) && (__CFNumberCaching != kCFNumberCachingFullyDisabled)) { + switch (__CFNumberTypeTable[type].canonicalType) { // canonicalized client-desired type + case kCFNumberSInt8Type: { + int8_t value = *(int8_t *)valuePtr; + return (CFNumberRef)((uintptr_t)((intptr_t)value << 8) | (0 << 6) | kCFTaggedObjectID_Integer); + } + case kCFNumberSInt16Type: { + int16_t value = *(int16_t *)valuePtr; + return (CFNumberRef)((uintptr_t)((intptr_t)value << 8) | (1 << 6) | kCFTaggedObjectID_Integer); + } + 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; + // tell anybody that complains about that to go ... hang. + if ((1L << 23) <= -value || (1L << 23) <= value) break; +#endif + return (CFNumberRef)((uintptr_t)((intptr_t)value << 8) | (2 << 6) | kCFTaggedObjectID_Integer); + } +#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; + // 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); + return (CFNumberRef)ptr_val; + } +#endif + } + } + // Look for cases where we can return a cached instance. // We only use cached objects if the allocator is the system // default allocator, except for the special floating point // constant objects, where we return the cached object // regardless of allocator, since that is what has always // been done (and now must for compatibility). - if (!allocator) allocator = __CFGetDefaultAllocator(); int64_t valToBeCached = NotToBeCached; if (__CFNumberTypeTable[type].floatBit) { @@ -1041,7 +1115,7 @@ CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType type, const vo if (isinf(d)) cached = (d < 0.0) ? kCFNumberNegativeInfinity : kCFNumberPositiveInfinity; } if (cached) return (CFNumberRef)CFRetain(cached); - } else if (kCFAllocatorSystemDefault == allocator) { + } else if (_CFAllocatorIsSystemDefault(allocator) && (__CFNumberCaching == kCFNumberCachingEnabled)) { switch (__CFNumberTypeTable[type].canonicalType) { case kCFNumberSInt8Type: {int8_t val = *(int8_t *)valuePtr; if (MinCachedInt <= val && val <= MaxCachedInt) valToBeCached = (int64_t)val; break;} case kCFNumberSInt16Type: {int16_t val = *(int16_t *)valuePtr; if (MinCachedInt <= val && val <= MaxCachedInt) valToBeCached = (int64_t)val; break;} @@ -1108,6 +1182,9 @@ CFLog(kCFLogLevelWarning, CFSTR("+++ Create old number '%@'"), __CFNumberCopyDes CFNumberType CFNumberGetType(CFNumberRef number) { //printf("+ [%p] CFNumberGetType(%p)\n", pthread_self(), number); + if (CF_IS_TAGGED_INT(number)) { + return __CFNumberGetType(number); + } CF_OBJC_FUNCDISPATCH0(__kCFNumberTypeID, CFNumberType, number, "_cfNumberType"); __CFAssertIsNumber(number); CFNumberType type = __CFNumberGetType(number); @@ -1167,8 +1244,63 @@ CFLog(kCFLogLevelWarning, CFSTR("*** TEST FAIL in CFNumberIsFloatType: '%d' '%d' return r; } -Boolean CFNumberGetValue(CFNumberRef number, CFNumberType type, void *valuePtr) { +Boolean CFNumberGetValue(CFNumberRef number, CFNumberType type, void *valuePtr) { //printf("+ [%p] CFNumberGetValue(%p, %d, %p)\n", pthread_self(), number, type, valuePtr); + if (CF_IS_TAGGED_INT(number)) { + __CFAssertIsValidNumberType(type); + uint8_t localMemory[128]; + if (!valuePtr) valuePtr = localMemory; + intptr_t taggedInteger = (intptr_t)number; + taggedInteger = taggedInteger >> 8; + switch (__CFNumberTypeTable[type].canonicalType) { // canonicalized client-desired type + case kCFNumberSInt8Type: +#if 0 + if (taggedInteger < INT8_MIN) { + *(int8_t *)valuePtr = INT8_MIN; + return false; + } + if (INT8_MAX < taggedInteger) { + *(int8_t *)valuePtr = INT8_MAX; + return false; + } +#endif + *(int8_t *)valuePtr = (int8_t)taggedInteger; + return true; + case kCFNumberSInt16Type: +#if 0 + if (taggedInteger < INT16_MIN) { + *(int16_t *)valuePtr = INT16_MIN; + return false; + } + if (INT16_MAX < taggedInteger) { + *(int16_t *)valuePtr = INT16_MAX; + return false; + } +#endif + *(int16_t *)valuePtr = (int16_t)taggedInteger; + return true; + case kCFNumberSInt32Type: +#if 0 && __LP64__ + if (taggedInteger < INT32_MIN) { + *(int32_t *)valuePtr = INT32_MIN; + return false; + } + if (INT32_MAX < taggedInteger) { + *(int32_t *)valuePtr = INT32_MAX; + return false; + } +#endif + *(int32_t *)valuePtr = (int32_t)taggedInteger; + return true; +#if __LP64__ + case kCFNumberSInt64Type: + *(int64_t *)valuePtr = (int64_t)taggedInteger; + return true; +#endif + } + Boolean r = __CFNumberGetValueCompat(number, type, valuePtr); + return r; + } CF_OBJC_FUNCDISPATCH2(__kCFNumberTypeID, Boolean, number, "_getValue:forType:", valuePtr, __CFNumberTypeTable[type].canonicalType); __CFAssertIsNumber(number); __CFAssertIsValidNumberType(type); diff --git a/CFNumber.h b/CFNumber.h index 070e83a..5f51f2e 100644 --- a/CFNumber.h +++ b/CFNumber.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFNumber.h - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFNUMBER__) diff --git a/CFNumberFormatter.c b/CFNumberFormatter.c index 617a6ad..97573c7 100644 --- a/CFNumberFormatter.c +++ b/CFNumberFormatter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,11 +22,12 @@ */ /* CFNumberFormatter.c - Copyright (c) 2002-2009, Apple Inc. All rights reserved. - Responsibility: Christopher Kane + Copyright (c) 2002-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ #include +#include #include "CFInternal.h" #include "CFLocaleInternal.h" #include @@ -122,6 +123,8 @@ CFNumberFormatterRef CFNumberFormatterCreate(CFAllocatorRef allocator, CFLocaleR case kCFNumberFormatterPercentStyle: ustyle = UNUM_PERCENT; break; case kCFNumberFormatterScientificStyle: ustyle = UNUM_SCIENTIFIC; break; case kCFNumberFormatterSpellOutStyle: ustyle = UNUM_SPELLOUT; break; + case kCFNumberFormatterOrdinalStyle: ustyle = UNUM_ORDINAL; break; + case kCFNumberFormatterDurationStyle: ustyle = UNUM_DURATION; break; default: CFAssert2(0, __kCFLogAssertion, "%s(): unknown style %d", __PRETTY_FUNCTION__, style); ustyle = UNUM_DECIMAL; @@ -155,7 +158,7 @@ CFNumberFormatterRef CFNumberFormatterCreate(CFAllocatorRef allocator, CFLocaleR } memory->_locale = locale ? CFLocaleCreateCopy(allocator, locale) : CFLocaleGetSystem(); __CFNumberFormatterCustomize(memory); - if (kCFNumberFormatterSpellOutStyle != memory->_style) { + if (kCFNumberFormatterSpellOutStyle != memory->_style && kCFNumberFormatterOrdinalStyle != memory->_style && kCFNumberFormatterDurationStyle != memory->_style) { UChar ubuffer[BUFFER_SIZE]; status = U_ZERO_ERROR; int32_t ret = unum_toPattern(memory->_nf, false, ubuffer, BUFFER_SIZE, &status); @@ -165,7 +168,7 @@ CFNumberFormatterRef CFNumberFormatterCreate(CFAllocatorRef allocator, CFLocaleR } memory->_defformat = memory->_format ? (CFStringRef)CFRetain(memory->_format) : NULL; memory->_compformat = memory->_format ? __CFNumberFormatterCreateCompressedString(memory->_format, true, NULL) : NULL; - if (kCFNumberFormatterSpellOutStyle != memory->_style) { + if (kCFNumberFormatterSpellOutStyle != memory->_style && kCFNumberFormatterOrdinalStyle != memory->_style && kCFNumberFormatterDurationStyle != memory->_style) { int32_t n = unum_getAttribute(memory->_nf, UNUM_MULTIPLIER); if (1 != n) { memory->_multiplier = CFNumberCreate(allocator, kCFNumberSInt32Type, &n); @@ -181,6 +184,8 @@ extern CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale); static void __substituteFormatStringFromPrefsNF(CFNumberFormatterRef formatter) { CFIndex formatStyle = formatter->_style; if (kCFNumberFormatterSpellOutStyle == formatStyle) return; + if (kCFNumberFormatterOrdinalStyle == formatStyle) return; + if (kCFNumberFormatterDurationStyle == formatStyle) return; CFStringRef prefName = CFSTR("AppleICUNumberFormatStrings"); if (kCFNumberFormatterNoStyle != formatStyle) { CFStringRef pref = NULL; @@ -194,6 +199,8 @@ static void __substituteFormatStringFromPrefsNF(CFNumberFormatterRef formatter) case kCFNumberFormatterPercentStyle: key = CFSTR("3"); break; case kCFNumberFormatterScientificStyle: key = CFSTR("4"); break; case kCFNumberFormatterSpellOutStyle: key = CFSTR("5"); break; + case kCFNumberFormatterOrdinalStyle: key = CFSTR("6"); break; + case kCFNumberFormatterDurationStyle: key = CFSTR("7"); break; default: key = CFSTR("0"); break; } pref = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)metapref, key); @@ -206,6 +213,8 @@ static void __substituteFormatStringFromPrefsNF(CFNumberFormatterRef formatter) case kCFNumberFormatterPercentStyle: icustyle = UNUM_PERCENT; break; case kCFNumberFormatterScientificStyle: icustyle = UNUM_SCIENTIFIC; break; case kCFNumberFormatterSpellOutStyle: icustyle = UNUM_SPELLOUT; break; + case kCFNumberFormatterOrdinalStyle: icustyle = UNUM_ORDINAL; break; + case kCFNumberFormatterDurationStyle: icustyle = UNUM_DURATION; break; } CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale); char buffer[BUFFER_SIZE]; @@ -276,6 +285,7 @@ static CFStringRef __CFNumberFormatterCreateCompressedString(CFStringRef inStrin return outString; } +// Should not be called for rule-based ICU formatters; not supported static void __CFNumberFormatterApplySymbolPrefs(const void *key, const void *value, void *context) { if (CFGetTypeID(key) == CFStringGetTypeID() && CFGetTypeID(value) == CFStringGetTypeID()) { CFNumberFormatterRef formatter = (CFNumberFormatterRef)context; @@ -293,7 +303,11 @@ static void __CFNumberFormatterApplySymbolPrefs(const void *key, const void *val } } +// Should not be called for rule-based ICU formatters static UErrorCode __CFNumberFormatterApplyPattern(CFNumberFormatterRef formatter, CFStringRef pattern) { + if (kCFNumberFormatterSpellOutStyle == formatter->_style) return U_UNSUPPORTED_ERROR; + if (kCFNumberFormatterOrdinalStyle == formatter->_style) return U_UNSUPPORTED_ERROR; + if (kCFNumberFormatterDurationStyle == formatter->_style) return U_UNSUPPORTED_ERROR; CFIndex cnt = CFStringGetLength(pattern); STACK_BUFFER_DECL(UChar, ubuffer, cnt); const UChar *ustr = (const UChar *)CFStringGetCharactersPtr(pattern); @@ -344,6 +358,8 @@ CFNumberFormatterStyle CFNumberFormatterGetStyle(CFNumberFormatterRef formatter) CFStringRef CFNumberFormatterGetFormat(CFNumberFormatterRef formatter) { __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID()); if (kCFNumberFormatterSpellOutStyle == formatter->_style) return NULL; + if (kCFNumberFormatterOrdinalStyle == formatter->_style) return NULL; + if (kCFNumberFormatterDurationStyle == formatter->_style) return NULL; UChar ubuffer[BUFFER_SIZE]; CFStringRef newString = NULL; UErrorCode status = U_ZERO_ERROR; @@ -370,6 +386,8 @@ void CFNumberFormatterSetFormat(CFNumberFormatterRef formatter, CFStringRef form __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID()); __CFGenericValidateType(formatString, CFStringGetTypeID()); if (kCFNumberFormatterSpellOutStyle == formatter->_style) return; + if (kCFNumberFormatterOrdinalStyle == formatter->_style) return; + if (kCFNumberFormatterDurationStyle == formatter->_style) return; CFIndex cnt = CFStringGetLength(formatString); CFAssert1(cnt <= 1024, __kCFLogAssertion, "%s(): format string too long", __PRETTY_FUNCTION__); if ((!formatter->_format || !CFEqual(formatter->_format, formatString)) && cnt <= 1024) { @@ -522,10 +540,10 @@ Boolean CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter, CFSt case kCFNumberSInt32Type: case kCFNumberIntType: case kCFNumberLongType: case kCFNumberCFIndexType: case kCFNumberSInt64Type: case kCFNumberLongLongType: - unum_setAttribute(formatter->_nf, UNUM_PARSE_INT_ONLY, 1); + unum_setAttribute(formatter->_nf, UNUM_PARSE_INT_ONLY, 1); // ignored by ICU for rule-based formatters break; default: - unum_setAttribute(formatter->_nf, UNUM_PARSE_INT_ONLY, 0); + unum_setAttribute(formatter->_nf, UNUM_PARSE_INT_ONLY, 0); // ignored by ICU for rule-based formatters integerOnly = 0; break; } @@ -622,6 +640,10 @@ void CFNumberFormatterSetProperty(CFNumberFormatterRef formatter, CFStringRef ke CFIndex cnt; __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID()); __CFGenericValidateType(key, CFStringGetTypeID()); + // rule-based formatters don't do attributes and symbols, except for one + if (kCFNumberFormatterSpellOutStyle == formatter->_style && kCFNumberFormatterIsLenientKey != key) return; + if (kCFNumberFormatterOrdinalStyle == formatter->_style && kCFNumberFormatterIsLenientKey != key) return; + if (kCFNumberFormatterDurationStyle == formatter->_style && kCFNumberFormatterIsLenientKey != key) return; if (kCFNumberFormatterCurrencyCodeKey == key) { __CFGenericValidateType(value, CFStringGetTypeID()); cnt = CFStringGetLength((CFStringRef)value); @@ -829,6 +851,10 @@ CFTypeRef CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter, CFString CFIndex cnt; __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID()); __CFGenericValidateType(key, CFStringGetTypeID()); + // rule-based formatters don't do attributes and symbols, except for one + if (kCFNumberFormatterSpellOutStyle == formatter->_style && kCFNumberFormatterIsLenientKey != key) return NULL; + if (kCFNumberFormatterOrdinalStyle == formatter->_style && kCFNumberFormatterIsLenientKey != key) return NULL; + if (kCFNumberFormatterDurationStyle == formatter->_style && kCFNumberFormatterIsLenientKey != key) return NULL; if (kCFNumberFormatterCurrencyCodeKey == key) { cnt = unum_getTextAttribute(formatter->_nf, UNUM_CURRENCY_CODE, ubuffer, BUFFER_SIZE, &status); if (U_SUCCESS(status) && cnt == 0) { diff --git a/CFNumberFormatter.h b/CFNumberFormatter.h index 970354b..4e43941 100644 --- a/CFNumberFormatter.h +++ b/CFNumberFormatter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFNumberFormatter.h - Copyright (c) 2003-2009, Apple Inc. All rights reserved. + Copyright (c) 2003-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFNUMBERFORMATTER__) @@ -32,8 +32,6 @@ #include #include -#if MAC_OS_X_VERSION_10_3 <= MAC_OS_X_VERSION_MAX_ALLOWED - CF_EXTERN_C_BEGIN typedef struct __CFNumberFormatter *CFNumberFormatterRef; @@ -41,7 +39,7 @@ typedef struct __CFNumberFormatter *CFNumberFormatterRef; // CFNumberFormatters are not thread-safe. Do not use one from multiple threads! CF_EXPORT -CFTypeID CFNumberFormatterGetTypeID(void) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFTypeID CFNumberFormatterGetTypeID(void); enum { // number format styles kCFNumberFormatterNoStyle = 0, @@ -55,22 +53,22 @@ typedef CFIndex CFNumberFormatterStyle; CF_EXPORT -CFNumberFormatterRef CFNumberFormatterCreate(CFAllocatorRef allocator, CFLocaleRef locale, CFNumberFormatterStyle style) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFNumberFormatterRef CFNumberFormatterCreate(CFAllocatorRef allocator, CFLocaleRef locale, CFNumberFormatterStyle style); // Returns a CFNumberFormatter, localized to the given locale, which // will format numbers to the given style. CF_EXPORT -CFLocaleRef CFNumberFormatterGetLocale(CFNumberFormatterRef formatter) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFLocaleRef CFNumberFormatterGetLocale(CFNumberFormatterRef formatter); CF_EXPORT -CFNumberFormatterStyle CFNumberFormatterGetStyle(CFNumberFormatterRef formatter) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFNumberFormatterStyle CFNumberFormatterGetStyle(CFNumberFormatterRef formatter); // Get the properties with which the number formatter was created. CF_EXPORT -CFStringRef CFNumberFormatterGetFormat(CFNumberFormatterRef formatter) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFStringRef CFNumberFormatterGetFormat(CFNumberFormatterRef formatter); CF_EXPORT -void CFNumberFormatterSetFormat(CFNumberFormatterRef formatter, CFStringRef formatString) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +void CFNumberFormatterSetFormat(CFNumberFormatterRef formatter, CFStringRef formatString); // 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 @@ -80,10 +78,10 @@ void CFNumberFormatterSetFormat(CFNumberFormatterRef formatter, CFStringRef form CF_EXPORT -CFStringRef CFNumberFormatterCreateStringWithNumber(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberRef number) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFStringRef CFNumberFormatterCreateStringWithNumber(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberRef number); CF_EXPORT -CFStringRef CFNumberFormatterCreateStringWithValue(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberType numberType, const void *valuePtr) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFStringRef CFNumberFormatterCreateStringWithValue(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberType numberType, const void *valuePtr); // Create a string representation of the given number or value // using the current state of the number formatter. @@ -94,10 +92,10 @@ enum { typedef CFOptionFlags CFNumberFormatterOptionFlags; CF_EXPORT -CFNumberRef CFNumberFormatterCreateNumberFromString(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFStringRef string, CFRange *rangep, CFOptionFlags options) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFNumberRef CFNumberFormatterCreateNumberFromString(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFStringRef string, CFRange *rangep, CFOptionFlags options); CF_EXPORT -Boolean CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter, CFStringRef string, CFRange *rangep, CFNumberType numberType, void *valuePtr) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +Boolean CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter, CFStringRef string, CFRange *rangep, CFNumberType numberType, void *valuePtr); // Parse a string representation of a number using the current state // of the number formatter. The range parameter specifies the range // of the string in which the parsing should occur in input, and on @@ -110,51 +108,51 @@ Boolean CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter, CFSt CF_EXPORT -void CFNumberFormatterSetProperty(CFNumberFormatterRef formatter, CFStringRef key, CFTypeRef value) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +void CFNumberFormatterSetProperty(CFNumberFormatterRef formatter, CFStringRef key, CFTypeRef value); CF_EXPORT -CFTypeRef CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter, CFStringRef key) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFTypeRef CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter, CFStringRef key); // Set and get various properties of the number formatter, the set of // which may be expanded in the future. -CF_EXPORT const CFStringRef kCFNumberFormatterCurrencyCode AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterDecimalSeparator AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterCurrencyDecimalSeparator AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterAlwaysShowDecimalSeparator AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFBoolean -CF_EXPORT const CFStringRef kCFNumberFormatterGroupingSeparator AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterUseGroupingSeparator AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFBoolean -CF_EXPORT const CFStringRef kCFNumberFormatterPercentSymbol AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterZeroSymbol AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterNaNSymbol AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterInfinitySymbol AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterMinusSign AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterPlusSign AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterCurrencySymbol AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterExponentSymbol AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterMinIntegerDigits AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFNumber -CF_EXPORT const CFStringRef kCFNumberFormatterMaxIntegerDigits AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFNumber -CF_EXPORT const CFStringRef kCFNumberFormatterMinFractionDigits AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFNumber -CF_EXPORT const CFStringRef kCFNumberFormatterMaxFractionDigits AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFNumber -CF_EXPORT const CFStringRef kCFNumberFormatterGroupingSize AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFNumber -CF_EXPORT const CFStringRef kCFNumberFormatterSecondaryGroupingSize AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFNumber -CF_EXPORT const CFStringRef kCFNumberFormatterRoundingMode AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFNumber -CF_EXPORT const CFStringRef kCFNumberFormatterRoundingIncrement AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFNumber -CF_EXPORT const CFStringRef kCFNumberFormatterFormatWidth AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFNumber -CF_EXPORT const CFStringRef kCFNumberFormatterPaddingPosition AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFNumber -CF_EXPORT const CFStringRef kCFNumberFormatterPaddingCharacter AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterDefaultFormat AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterMultiplier AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFNumber -CF_EXPORT const CFStringRef kCFNumberFormatterPositivePrefix AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterPositiveSuffix AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterNegativePrefix AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterNegativeSuffix AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterPerMillSymbol AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterInternationalCurrencySymbol AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterCurrencyGroupingSeparator AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFString -CF_EXPORT const CFStringRef kCFNumberFormatterIsLenient AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFBoolean -CF_EXPORT const CFStringRef kCFNumberFormatterUseSignificantDigits AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFBoolean -CF_EXPORT const CFStringRef kCFNumberFormatterMinSignificantDigits AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFNumber -CF_EXPORT const CFStringRef kCFNumberFormatterMaxSignificantDigits AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; // CFNumber +CF_EXPORT const CFStringRef kCFNumberFormatterCurrencyCode; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterDecimalSeparator; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterCurrencyDecimalSeparator; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterAlwaysShowDecimalSeparator; // CFBoolean +CF_EXPORT const CFStringRef kCFNumberFormatterGroupingSeparator; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterUseGroupingSeparator; // CFBoolean +CF_EXPORT const CFStringRef kCFNumberFormatterPercentSymbol; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterZeroSymbol; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterNaNSymbol; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterInfinitySymbol; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterMinusSign; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterPlusSign; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterCurrencySymbol; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterExponentSymbol; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterMinIntegerDigits; // CFNumber +CF_EXPORT const CFStringRef kCFNumberFormatterMaxIntegerDigits; // CFNumber +CF_EXPORT const CFStringRef kCFNumberFormatterMinFractionDigits; // CFNumber +CF_EXPORT const CFStringRef kCFNumberFormatterMaxFractionDigits; // CFNumber +CF_EXPORT const CFStringRef kCFNumberFormatterGroupingSize; // CFNumber +CF_EXPORT const CFStringRef kCFNumberFormatterSecondaryGroupingSize; // CFNumber +CF_EXPORT const CFStringRef kCFNumberFormatterRoundingMode; // CFNumber +CF_EXPORT const CFStringRef kCFNumberFormatterRoundingIncrement; // CFNumber +CF_EXPORT const CFStringRef kCFNumberFormatterFormatWidth; // CFNumber +CF_EXPORT const CFStringRef kCFNumberFormatterPaddingPosition; // CFNumber +CF_EXPORT const CFStringRef kCFNumberFormatterPaddingCharacter; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterDefaultFormat; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterMultiplier; // CFNumber +CF_EXPORT const CFStringRef kCFNumberFormatterPositivePrefix; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterPositiveSuffix; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterNegativePrefix; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterNegativeSuffix; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterPerMillSymbol; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterInternationalCurrencySymbol; // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterCurrencyGroupingSeparator CF_AVAILABLE(10_5, 2_0); // CFString +CF_EXPORT const CFStringRef kCFNumberFormatterIsLenient CF_AVAILABLE(10_5, 2_0); // CFBoolean +CF_EXPORT const CFStringRef kCFNumberFormatterUseSignificantDigits CF_AVAILABLE(10_5, 2_0); // CFBoolean +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 { kCFNumberFormatterRoundCeiling = 0, @@ -177,7 +175,7 @@ typedef CFIndex CFNumberFormatterPadPosition; CF_EXPORT -Boolean CFNumberFormatterGetDecimalInfoForCurrencyCode(CFStringRef currencyCode, int32_t *defaultFractionDigits, double *roundingIncrement) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +Boolean CFNumberFormatterGetDecimalInfoForCurrencyCode(CFStringRef currencyCode, int32_t *defaultFractionDigits, double *roundingIncrement); // Returns the number of fraction digits that should be displayed, and // the rounding increment (or 0.0 if no rounding is done by the currency) // for the given currency. Returns false if the currency code is unknown @@ -186,7 +184,5 @@ Boolean CFNumberFormatterGetDecimalInfoForCurrencyCode(CFStringRef currencyCode, CF_EXTERN_C_END -#endif - #endif /* ! __COREFOUNDATION_CFNUMBERFORMATTER__ */ diff --git a/CFPlatform.c b/CFPlatform.c index e6d0219..9785888 100644 --- a/CFPlatform.c +++ b/CFPlatform.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFPlatform.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. - Responsibility: Christopher Kane + Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Responsibility: Tony Parker */ #include "CFInternal.h" @@ -42,12 +42,13 @@ #if DEPLOYMENT_TARGET_WINDOWS #include #include +#include #define getcwd _NS_getcwd #endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS #define kCFPlatformInterfaceStringEncoding kCFStringEncodingUTF8 #else #define kCFPlatformInterfaceStringEncoding CFStringGetSystemEncoding() @@ -66,12 +67,14 @@ __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 '\\' @@ -169,7 +172,7 @@ const char *_CFProcessPath(void) { uint32_t size = CFMaxPathSize; char buffer[size]; if (0 == _NSGetExecutablePath(buffer, &size)) { -#if DEPLOYMENT_TARGET_MACOSX && defined(__ppc__) +#if SUPPORT_CFM size_t len = strlen(buffer); if (12 <= len && 0 == strcmp("LaunchCFMApp", buffer + len - 12)) { struct stat exec, lcfm; @@ -195,6 +198,28 @@ const char *_CFProcessPath(void) { } #endif +#if DEPLOYMENT_TARGET_LINUX +#include + +const char *_CFProcessPath(void) { + if (__CFProcessPath) return __CFProcessPath; + char buf[CFMaxPathSize + 1]; + + ssize_t res = readlink("/proc/self/exe", buf, CFMaxPathSize); + if (res > 0) { + // null terminate, readlink does not + buf[res] = 0; + __CFProcessPath = strdup(buf); + __CFprogname = strrchr(__CFProcessPath, PATH_SEP); + __CFprogname = (__CFprogname ? __CFprogname + 1 : __CFProcessPath); + } else { + __CFProcessPath = ""; + __CFprogname = __CFProcessPath; + } + return __CFProcessPath; +} +#endif + __private_extern__ CFStringRef _CFProcessNameString(void) { static CFStringRef __CFProcessNameString = NULL; if (!__CFProcessNameString) { @@ -209,13 +234,17 @@ __private_extern__ CFStringRef _CFProcessNameString(void) { } static CFStringRef __CFUserName = NULL; +static CFSpinLock_t __CFPlatformCacheLock = CFSpinLockInit; #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD + +#include + static CFURLRef __CFHomeDirectory = NULL; static uint32_t __CFEUID = -1; static uint32_t __CFUID = -1; -static CFURLRef _CFCopyHomeDirURLForUser(struct passwd *upwd) { +static CFURLRef _CFCopyHomeDirURLForUser(struct passwd *upwd) { // __CFPlatformCacheLock must be locked on entry and will be on exit CFURLRef home = NULL; if (!issetugid()) { const char *path = __CFgetenv("CFFIXED_USER_HOME"); @@ -231,7 +260,7 @@ static CFURLRef _CFCopyHomeDirURLForUser(struct passwd *upwd) { return home; } -static void _CFUpdateUserInfo(void) { +static void _CFUpdateUserInfo(void) { // __CFPlatformCacheLock must be locked on entry and will be on exit struct passwd *upwd; __CFEUID = geteuid(); @@ -264,11 +293,7 @@ static void _CFUpdateUserInfo(void) { } #endif -#if DEPLOYMENT_TARGET_WINDOWS -typedef DWORD (*NetUserGetInfoCall)(wchar_t *, wchar_t *, DWORD, char* *); -#endif - -static CFURLRef _CFCreateHomeDirectoryURLForUser(CFStringRef uName) { +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) @@ -296,12 +321,26 @@ static CFURLRef _CFCreateHomeDirectoryURLForUser(CFStringRef uName) { return _CFCopyHomeDirURLForUser(upwd); } #elif DEPLOYMENT_TARGET_WINDOWS - CFStringRef user = !uName ? _CFUserName() : uName; + // 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; - - if (!uName || CFEqual(user, _CFUserName())) { + + UniChar pathChars[MAX_PATH]; + if (S_OK == SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, (wchar_t *)pathChars)) { + len = (CFIndex)wcslen((wchar_t *)pathChars); + str = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, pathChars, len); + 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"); const char *cdrive = __CFgetenv("HOMEDRIVE"); if (cdrive && cpath) { @@ -311,98 +350,36 @@ static CFURLRef _CFCreateHomeDirectoryURLForUser(CFStringRef uName) { str = CFStringCreateWithCString(kCFAllocatorSystemDefault, fullPath, kCFPlatformInterfaceStringEncoding); retVal = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, kCFURLWindowsPathStyle, true); CFRelease(str); - } - } - if (retVal == NULL) { - UniChar pathChars[MAX_PATH]; - if (S_OK == SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, (wchar_t *) pathChars)) { - UniChar* p = pathChars; - while (*p++ != 0) - ++len; - str = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, pathChars, len); - retVal = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, kCFURLWindowsPathStyle, true); - } else { - // We have to get "some" directory location, so fall-back to the - // processes current directory. - UniChar currDir[MAX_PATH]; - DWORD dwChars = GetCurrentDirectoryW(MAX_PATH + 1, (wchar_t *)currDir); - if (dwChars > 0) { - UniChar* p = currDir; - while (*p++ != 0) - ++len; - str = CFStringCreateWithCharacters(kCFAllocatorDefault, currDir, len); - retVal = CFURLCreateWithFileSystemPath(NULL, str, kCFURLWindowsPathStyle, true); - } - CFRelease(str); - } - } -#if 0 - char fullPath[CFMaxPathSize]; - HRESULT hr = SHGetFolderPathA(NULL, CSIDL_PROFILE, NULL, 0 /* SHGFP_TYPE_CURRENT */, fullPath); - if (SUCCEEDED(hr)) { - CFStringRef str = CFStringCreateWithCString(NULL, fullPath, kCFPlatformInterfaceStringEncoding); - retVal = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, kCFURLWindowsPathStyle, true); - CFRelease(str); } } + if (!retVal) { - struct _USER_INFO_2 *userInfo; - HINSTANCE hinstDll = GetModuleHandleA("NETAPI32"); - if (!hinstDll) - hinstDll = LoadLibraryExA("NETAPI32", NULL, 0); - if (hinstDll) { - NetUserGetInfoCall lpfn = (NetUserGetInfoCall)GetProcAddress(hinstDll, "NetUserGetInfo"); - if (lpfn) { - unsigned namelen = CFStringGetLength(user); - UniChar *username; - username = (UniChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UniChar) * (namelen + 1), 0); - CFStringGetCharacters(user, CFRangeMake(0, namelen), username); - if (!(*lpfn)(NULL, (wchar_t *)username, 2, (char * *)&userInfo)) { - UInt32 len = 0; - CFMutableStringRef str; - while (userInfo->usri2_home_dir[len] != 0) len ++; - str = CFStringCreateMutable(kCFAllocatorSystemDefault, len+1); - CFStringAppendCharacters(str, (const UniChar *)userInfo->usri2_home_dir, len); - retVal = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, kCFURLWindowsPathStyle, true); + // Last resort: We have to get "some" directory location, so fall-back to the processes current directory. + UniChar currDir[MAX_PATH]; + DWORD dwChars = GetCurrentDirectoryW(MAX_PATH + 1, (wchar_t *)currDir); + if (dwChars > 0) { + len = (CFIndex)wcslen((wchar_t *)currDir); + str = CFStringCreateWithCharacters(kCFAllocatorDefault, currDir, len); + retVal = CFURLCreateWithFileSystemPath(NULL, str, kCFURLWindowsPathStyle, true); CFRelease(str); } - CFAllocatorDeallocate(kCFAllocatorSystemDefault, username); } - } else { - } - } -#endif - - // 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. -#if DEPLOYMENT_TARGET_WINDOWS_SAFARI - if (retVal) { - CFStringRef str = CFURLCopyFileSystemPath(retVal, kCFURLWindowsPathStyle); - if (str && CFStringGetLength(str) == 0) { - CFRelease(retVal); - retVal=NULL; - } - if (str) CFRelease(str); - } -#else - CFStringRef testPath = CFURLCopyPath(retVal); + + // 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) { CFRelease(retVal); - retVal=NULL; - } - if (testPath) { - CFRelease(testPath); + retVal = NULL; } -#endif + if (testPath) CFRelease(testPath); + return retVal; - #else #error Dont know how to compute users home directories on this platform #endif } -static CFStringRef _CFUserName(void) { +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(); @@ -428,10 +405,6 @@ static CFStringRef _CFUserName(void) { return __CFUserName; } -__private_extern__ CFStringRef _CFGetUserName(void) { - return CFStringCreateCopy(kCFAllocatorSystemDefault, _CFUserName()); -} - #define CFMaxHostNameLength 256 #define CFMaxHostNameSize (CFMaxHostNameLength+1) @@ -447,11 +420,27 @@ __private_extern__ CFStringRef _CFStringCreateHostName(void) { These can return NULL. */ CF_EXPORT CFStringRef CFGetUserName(void) { - return _CFUserName(); + 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) { - return _CFCreateHomeDirectoryURLForUser(uName); + CFURLRef result = NULL; + __CFSpinLock(&__CFPlatformCacheLock); + result = _CFCreateHomeDirectoryURLForUser(uName); + __CFSpinUnlock(&__CFPlatformCacheLock); + return result; } #undef CFMaxHostNameLength @@ -526,6 +515,243 @@ CF_EXPORT CFMutableStringRef _CFCreateApplicationRepositoryPath(CFAllocatorRef a } #endif +#pragma mark - +#pragma mark Thread Functions + +#if DEPLOYMENT_TARGET_WINDOWS + +// This code from here: +// http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx + +const DWORD MS_VC_EXCEPTION=0x406D1388; +#pragma pack(push,8) +typedef struct tagTHREADNAME_INFO +{ + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. +} THREADNAME_INFO; +#pragma pack(pop) + +CF_EXPORT void _NS_pthread_setname_np(const char *name) { + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = name; + info.dwThreadID = GetCurrentThreadId(); + info.dwFlags = 0; + + __try + { + RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info ); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + } +} + +static pthread_t __initialPthread = { NULL, 0 }; + +CF_EXPORT int _NS_pthread_main_np() { + pthread_t me = pthread_self(); + if (NULL == __initialPthread.p) { + __initialPthread.p = me.p; + __initialPthread.x = me.x; + } + return (pthread_equal(__initialPthread, me)); +} + +#endif + +#pragma mark - +#pragma mark Thread Local Data + +// If slot >= CF_TSD_MAX_SLOTS, the SPI functions will crash at NULL + slot address. +// 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 +#define CF_TSD_KEY 55 +#endif + +// Windows and Linux, not sure how many times the destructor could get called; CF_TSD_MAX_DESTRUCTOR_CALLS could be 1 + +#define CF_TSD_BAD_PTR ((void *)0x1000) + +typedef void (*tsdDestructor)(void *); + +// Data structure to hold TSD data, cleanup functions for each +typedef struct __CFTSDTable { + uint32_t destructorCount; + uintptr_t data[CF_TSD_MAX_SLOTS]; + tsdDestructor destructors[CF_TSD_MAX_SLOTS]; +} __CFTSDTable; + +static void __CFTSDFinalize(void *arg); + +#if DEPLOYMENT_TARGET_WINDOWS + +#include "CFVersionCheck.h" + +static DWORD __CFTSDIndexKey = 0xFFFFFFFF; + +// Called from CFRuntime's startup code, on Windows only +__private_extern__ void __CFTSDWindowsInitialize() { + __CFTSDIndexKey = TlsAlloc(); +} + +// Called from CFRuntime's cleanup code, on Windows only +__private_extern__ void __CFTSDWindowsCleanup() { + TlsFree(__CFTSDIndexKey); +} + +// Called for each thread as it exits, on Windows only +__private_extern__ void __CFFinalizeWindowsThreadData() { + // Normally, this should call the finalizer several times to emulate the behavior of pthreads on Windows. However, a few bugs keep us from doing this: + // REGRESSION(CF-610-CF-611): Crash closing Safari in BonjourDB destructor (Windows) + // SyncUIHandler crashes after conflict is resolved and we do SyncNow + // and a bug in dispatch keeps us from using pthreadsWin32 directly, because it does not deal with the case of a dispatch_async happening during process exit (it attempts to create a thread, but that is illegal on Win32 and causes a hang). + // So instead we just finalize once, which is the behavior pre-Airwolf anyway + __CFTSDFinalize(TlsGetValue(__CFTSDIndexKey)); +} + +#endif + +#if DEPLOYMENT_TARGET_LINUX + +static pthread_key_t __CFTSDIndexKey; + +// Called from CFRuntime's startup code, on Linux only +__private_extern__ void __CFTSDLinuxInitialize() { + (void)pthread_key_create(&__CFTSDIndexKey, __CFTSDFinalize); +} + +#endif + +static void __CFTSDSetSpecific(void *arg) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + pthread_setspecific(CF_TSD_KEY, arg); +#elif DEPLOYMENT_TARGET_LINUX + pthread_setspecific(__CFTSDIndexKey, arg); +#elif DEPLOYMENT_TARGET_WINDOWS + TlsSetValue(__CFTSDIndexKey, arg); +#endif +} + +static void *__CFTSDGetSpecific() { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + return pthread_getspecific(CF_TSD_KEY); +#elif DEPLOYMENT_TARGET_LINUX + return pthread_getspecific(__CFTSDIndexKey); +#elif DEPLOYMENT_TARGET_WINDOWS + return TlsGetValue(__CFTSDIndexKey); +#endif +} + +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. + __CFTSDSetSpecific(arg); + + if (!arg || arg == CF_TSD_BAD_PTR) { + // We've already been destroyed. The call above set the bad pointer again. Now we just return. + return; + } + + __CFTSDTable *table = (__CFTSDTable *)arg; + table->destructorCount++; + + // On 1st, 2nd, 3rd, 4th calls, invoke destructor + // 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]; + table->data[i] = (uintptr_t)NULL; + table->destructors[i]((void *)(old)); + } + } +#if COCOA_ARR0 + _CFAutoreleasePoolPop(pool); +#endif + + if (table->destructorCount == PTHREAD_DESTRUCTOR_ITERATIONS - 1) { // On 4th call, destroy our data + free(table); + + // Now if the destructor is called again we will take the shortcut at the beginning of this function. + __CFTSDSetSpecific(CF_TSD_BAD_PTR); + return; + } +} + +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +extern int pthread_key_init_np(int, void (*)(void *)); +#endif + +// Get or initialize a thread local storage. It is created on demand. +static __CFTSDTable *__CFTSDGetTable() { + __CFTSDTable *table = (__CFTSDTable *)__CFTSDGetSpecific(); + // Make sure we're not setting data again after destruction. + if (table == CF_TSD_BAD_PTR) { + return NULL; + } + // Create table on demand + if (!table) { + // 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 + pthread_key_init_np(CF_TSD_KEY, __CFTSDFinalize); +#endif + __CFTSDSetSpecific(table); + } + + return table; +} + + +// For the use of CF and Foundation only +CF_EXPORT void *_CFGetTSD(uint32_t slot) { + if (slot > CF_TSD_MAX_SLOTS) { + _CFLogSimple(kCFLogLevelError, "Error: TSD slot %d out of range (get)", slot); + HALT; + } + __CFTSDTable *table = __CFTSDGetTable(); + if (!table) { + // Someone is getting TSD during thread destruction. The table is gone, so we can't get any data anymore. + _CFLogSimple(kCFLogLevelWarning, "Warning: TSD slot %d retrieved but the thread data has already been torn down.", slot); + return NULL; + } + uintptr_t *slots = (uintptr_t *)(table->data); + return (void *)slots[slot]; +} + +// For the use of CF and Foundation only +CF_EXPORT void *_CFSetTSD(uint32_t slot, void *newVal, tsdDestructor destructor) { + if (slot > CF_TSD_MAX_SLOTS) { + _CFLogSimple(kCFLogLevelError, "Error: TSD slot %d out of range (set)", slot); + HALT; + } + __CFTSDTable *table = __CFTSDGetTable(); + if (!table) { + // Someone is setting TSD during thread destruction. The table is gone, so we can't get any data anymore. + _CFLogSimple(kCFLogLevelWarning, "Warning: TSD slot %d set but the thread data has already been torn down.", slot); + return NULL; + } + + void *oldVal = (void *)table->data[slot]; + + table->data[slot] = (uintptr_t)newVal; + table->destructors[slot] = destructor; + + return oldVal; +} + +#pragma mark - +#pragma mark Windows Wide to UTF8 and UTF8 to Wide + #if DEPLOYMENT_TARGET_WINDOWS /* On Windows, we want to use UTF-16LE for path names to get full unicode support. Internally, however, everything remains in UTF-8 representation. These helper functions stand between CF and the Microsoft CRT to ensure that we are using the right representation on both sides. */ @@ -587,7 +813,14 @@ CF_EXPORT int _NS_rmdir(const char *name) { CF_EXPORT int _NS_chmod(const char *name, int mode) { wchar_t *wide = createWideFileSystemRepresentation(name, NULL); - int res = _wchmod(wide, mode); + + // Convert mode + int newMode = 0; + if (mode | 0400) newMode |= _S_IREAD; + if (mode | 0200) newMode |= _S_IWRITE; + if (mode | 0100) newMode |= _S_IEXEC; + + int res = _wchmod(wide, newMode); free(wide); return res; } @@ -618,7 +851,8 @@ CF_EXPORT char *_NS_getcwd(char *dstbuf, size_t size) { } CF_EXPORT char *_NS_getenv(const char *name) { - // todo: wide env variables + // todo: wide getenv + // We have to be careful what happens here, because getenv is called during cf initialization, and things like cfstring may not be working yet return getenv(name); } @@ -722,3 +956,224 @@ CF_EXPORT int _NS_mkstemp(char *name, int bufSize) { #endif +#if DEPLOYMENT_TARGET_WINDOWS +// Utilities to convert from a volume name to a drive letter + +Boolean _isAFloppy(char driveLetter) +{ + HANDLE h; + TCHAR tsz[8]; + Boolean retval = false; + int iDrive; + + if (driveLetter >= 'a' && driveLetter <= 'z') { + driveLetter = driveLetter - 'a' + 'A'; + } + + if ((driveLetter < 'A') || (driveLetter > 'Z')) { + // invalid driveLetter; I guess it's not a floppy... + return false; + } + + iDrive = driveLetter - 'A' + 1; + + // On Windows NT, use the technique described in the Knowledge Base article Q115828 and in the "FLOPPY" SDK sample. + wsprintf(tsz, TEXT("\\\\.\\%c:"), TEXT('@') + iDrive); + h = CreateFile(tsz, 0, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); + if (h != INVALID_HANDLE_VALUE) + { + DISK_GEOMETRY Geom[20]; + DWORD cb; + + if (DeviceIoControl (h, IOCTL_DISK_GET_MEDIA_TYPES, 0, 0, + Geom, sizeof(Geom), &cb, 0) + && cb > 0) + { + switch (Geom[0].MediaType) + { + case F5_1Pt2_512: // 5.25 1.2MB floppy + case F5_360_512: // 5.25 360K floppy + case F5_320_512: // 5.25 320K floppy + case F5_320_1024: // 5.25 320K floppy + case F5_180_512: // 5.25 180K floppy + case F5_160_512: // 5.25 160K floppy + case F3_1Pt44_512: // 3.5 1.44MB floppy + case F3_2Pt88_512: // 3.5 2.88MB floppy + case F3_20Pt8_512: // 3.5 20.8MB floppy + case F3_720_512: // 3.5 720K floppy + retval = true; + break; + } + } + + CloseHandle(h); + } + + return retval; +} + + +extern CFStringRef CFCreateWindowsDrivePathFromVolumeName(CFStringRef volNameStr) { + if (!volNameStr) return NULL; + + // This code is designed to match as closely as possible code from QuickTime's library + CFIndex strLen = CFStringGetLength(volNameStr); + if (strLen == 0) { + return NULL; + } + + // Get drive names + long length, result; + wchar_t *driveNames = NULL; + + // Get the size of the buffer to store the list of drives + length = GetLogicalDriveStringsW(0, 0); + if (!length) { + return NULL; + } + + driveNames = (wchar_t *)malloc((length + 1) * sizeof(wchar_t)); + result = GetLogicalDriveStringsW(length, driveNames); + + if (!result || result > length) { + free(driveNames); + return NULL; + } + + // Get the volume name string into a wide buffer + wchar_t *theVolumeName = (wchar_t *)malloc((strLen + 1) * sizeof(wchar_t)); + CFStringGetCharacters(volNameStr, CFRangeMake(0, strLen), (UniChar *)theVolumeName); + theVolumeName[strLen] = 0; + + // lowercase volume name + _wcslwr(theVolumeName); + + // Iterate through the drive names, looking for something that matches + wchar_t *drivePtr = driveNames; + CFStringRef drivePathResult = NULL; + + while (*drivePtr) { + _wcslwr(drivePtr); + + if (!_isAFloppy((char)*drivePtr)) { + UINT oldErrorMode; + DWORD whoCares1, whoCares2; + BOOL getVolInfoSucceeded; + UniChar thisVolumeName[MAX_PATH]; + + // Convert this drive string into a volume name + oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS); + getVolInfoSucceeded = GetVolumeInformationW(drivePtr, (LPWSTR)thisVolumeName, sizeof(thisVolumeName), NULL, &whoCares1, &whoCares2, NULL, 0); + SetErrorMode(oldErrorMode); + + if (getVolInfoSucceeded) { + _wcslwr((wchar_t *)thisVolumeName); + + // If the volume corresponding to this drive matches the input volume + // then this drive is the winner. + if (!wcscmp((const wchar_t *)thisVolumeName, theVolumeName) || + (*thisVolumeName == 0x00 && (CFStringCompare(volNameStr, CFSTR("NONAME"), 0) == kCFCompareEqualTo))) { + drivePathResult = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)drivePtr, wcslen(drivePtr)); + break; + } + } + } + + drivePtr += wcslen(drivePtr) + 1; + } + + + free(driveNames); + free(theVolumeName); + return drivePathResult; +} + +#endif // DEPLOYMENT_TARGET_WINDOWS + +#pragma mark - +#pragma mark Linux OSAtomic + +#if DEPLOYMENT_TARGET_LINUX + +bool OSAtomicCompareAndSwapPtr(void *oldp, void *newp, void *volatile *dst) +{ + return __sync_bool_compare_and_swap(dst, oldp, newp); +} + +bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) +{ + return __sync_val_compare_and_swap(dst, oldl, newl); +} + +bool OSAtomicCompareAndSwapPtrBarrier(void *oldp, void *newp, void *volatile *dst) +{ + return __sync_bool_compare_and_swap(dst, oldp, newp); +} + +int32_t OSAtomicAdd32Barrier( int32_t theAmount, volatile int32_t *theValue ) { + return __sync_fetch_and_add(theValue, theAmount) + theAmount; +} + +bool OSAtomicCompareAndSwap32Barrier(int32_t oldValue, int32_t newValue, volatile int32_t *theValue) { + return __sync_bool_compare_and_swap(theValue, oldValue, newValue); +} + +int32_t OSAtomicDecrement32Barrier(volatile int32_t *dst) +{ + return OSAtomicAdd32Barrier(-1, dst); +} + +int32_t OSAtomicIncrement32Barrier(volatile int32_t *dst) +{ + return OSAtomicAdd32Barrier(1, dst); +} + +int32_t OSAtomicAdd32( int32_t theAmount, volatile int32_t *theValue ) { + return OSAtomicAdd32Barrier(theAmount, theValue); +} + +int32_t OSAtomicIncrement32(volatile int32_t *theValue) { + return OSAtomicIncrement32Barrier(theValue); +} + +int32_t OSAtomicDecrement32(volatile int32_t *theValue) { + return OSAtomicDecrement32Barrier(theValue); +} + +void OSMemoryBarrier() { + __sync_synchronize(); +} + +#endif // DEPLOYMENT_TARGET_LINUX + +#pragma mark - +#pragma mark Windows and Linux Helpers + +#if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX + +#include + +__private_extern__ int asprintf(char **ret, const char *format, ...) { + va_list args; + size_t sz = 1024; + *ret = (char *) malloc(sz * sizeof(char)); + if (!*ret) return -1; + va_start(args, format); + int cnt = vsnprintf(*ret, sz, format, args); + va_end(args); + if (cnt < sz - 1) return cnt; + sz = cnt + 8; + char *oldret = *ret; + *ret = (char *) realloc(*ret, sz * sizeof(char)); + if (!*ret && oldret) free(oldret); + if (!*ret) return -1; + va_start(args, format); + cnt = vsnprintf(*ret, sz, format, args); + va_end(args); + if (cnt < sz - 1) return cnt; + free(*ret); + *ret = NULL; + return -1; +} + +#endif diff --git a/CFPlatformConverters.c b/CFPlatformConverters.c index 25b22b9..2948714 100644 --- a/CFPlatformConverters.c +++ b/CFPlatformConverters.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFPlatformConverters.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Aki Inoue */ @@ -62,9 +62,7 @@ static const CFStringEncodingConverter __CFPlatformBootstrap = { __private_extern__ const CFStringEncodingConverter *__CFStringEncodingGetExternalConverter(uint32_t encoding) { - if (NULL != __CFStringEncodingGetICUName(encoding)) return &__CFICUBootstrap; - - return (__CFIsPlatformConverterAvailable(encoding) ? &__CFPlatformBootstrap : NULL); + return (__CFIsPlatformConverterAvailable(encoding) ? &__CFPlatformBootstrap : (__CFStringEncodingGetICUName(encoding) ? &__CFICUBootstrap : NULL)); // we prefer Text Encoding Converter ICU since it's more reliable } #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED @@ -119,9 +117,11 @@ __private_extern__ CFIndex __CFStringEncodingPlatformUnicodeToBytes(uint32_t enc WORD dwFlags = 0; CFIndex usedLen; - dwFlags |= (flags & (kCFStringEncodingAllowLossyConversion|kCFStringEncodingSubstituteCombinings) ? WC_DEFAULTCHAR : 0); - dwFlags |= (flags & kCFStringEncodingComposeCombinings ? WC_COMPOSITECHECK : 0); - dwFlags |= (flags & kCFStringEncodingIgnoreCombinings ? WC_DISCARDNS : 0); + if ((kCFStringEncodingUTF7 != encoding) && (kCFStringEncodingGB_18030_2000 != encoding) && (0x0800 != (encoding & 0x0F00))) { // not UTF-7/GB18030/ISO-2022-* + dwFlags |= (flags & (kCFStringEncodingAllowLossyConversion|kCFStringEncodingSubstituteCombinings) ? WC_DEFAULTCHAR : 0); + dwFlags |= (flags & kCFStringEncodingComposeCombinings ? WC_COMPOSITECHECK : 0); + dwFlags |= (flags & kCFStringEncodingIgnoreCombinings ? WC_DISCARDNS : 0); + } if ((usedLen = WideCharToMultiByte(CFStringConvertEncodingToWindowsCodepage(encoding), dwFlags, (LPCWSTR)characters, numChars, (LPSTR)bytes, maxByteLen, NULL, NULL)) == 0) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { @@ -168,8 +168,10 @@ __private_extern__ CFIndex __CFStringEncodingPlatformBytesToUnicode(uint32_t enc WORD dwFlags = 0; CFIndex usedLen; - dwFlags |= (flags & (kCFStringEncodingAllowLossyConversion|kCFStringEncodingSubstituteCombinings) ? 0 : MB_ERR_INVALID_CHARS); - dwFlags |= (flags & (kCFStringEncodingUseCanonical|kCFStringEncodingUseHFSPlusCanonical) ? MB_COMPOSITE : MB_PRECOMPOSED); + if ((kCFStringEncodingUTF7 != encoding) && (kCFStringEncodingGB_18030_2000 != encoding) && (0x0800 != (encoding & 0x0F00))) { // not UTF-7/GB18030/ISO-2022-* + dwFlags |= (flags & (kCFStringEncodingAllowLossyConversion|kCFStringEncodingSubstituteCombinings) ? 0 : MB_ERR_INVALID_CHARS); + dwFlags |= (flags & (kCFStringEncodingUseCanonical|kCFStringEncodingUseHFSPlusCanonical) ? MB_COMPOSITE : MB_PRECOMPOSED); + } if ((usedLen = MultiByteToWideChar(CFStringConvertEncodingToWindowsCodepage(encoding), dwFlags, (LPCSTR)bytes, numBytes, (LPWSTR)characters, maxCharLen) == 0)) { if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { diff --git a/CFPlugIn.c b/CFPlugIn.c index a12881d..c97870f 100644 --- a/CFPlugIn.c +++ b/CFPlugIn.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFPlugIn.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. - Responsibility: Doug Davidson + Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ #include "CFBundle_Internal.h" diff --git a/CFPlugIn.h b/CFPlugIn.h index 9d4813d..57bc90e 100644 --- a/CFPlugIn.h +++ b/CFPlugIn.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFPlugIn.h - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFPLUGIN__) diff --git a/CFPlugInCOM.h b/CFPlugInCOM.h index e826b16..5ee1347 100644 --- a/CFPlugInCOM.h +++ b/CFPlugInCOM.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFPlugInCOM.h - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFPLUGINCOM__) diff --git a/CFPlugIn_Factory.c b/CFPlugIn_Factory.c index c0232d5..1777b47 100644 --- a/CFPlugIn_Factory.c +++ b/CFPlugIn_Factory.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFPlugIn_Factory.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. - Responsibility: Doug Davidson + Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ #include "CFBundle_Internal.h" @@ -139,12 +139,6 @@ __private_extern__ void *_CFPFactoryCreateInstance(CFAllocatorRef allocator, _CF if (!factory->_func) { factory->_func = (CFPlugInFactoryFunction)CFBundleGetFunctionPointerForName(factory->_plugIn, factory->_funcName); if (!factory->_func) CFLog(__kCFLogPlugIn, CFSTR("Cannot find function pointer %@ for factory %@ in %@"), factory->_funcName, factory->_uuid, factory->_plugIn); -#if BINARY_SUPPORT_CFM - if (factory->_func) { - // return values from CFBundleGetFunctionPointerForName will always be dyld, but we must force-fault them because pointers to glue code do not fault correctly - factory->_func = (void *)((uint32_t)(factory->_func) | 0x1); - } -#endif /* BINARY_SUPPORT_CFM */ } if (factory->_func) { // UPPGOOP diff --git a/CFPlugIn_Factory.h b/CFPlugIn_Factory.h index 36aa70f..a680406 100644 --- a/CFPlugIn_Factory.h +++ b/CFPlugIn_Factory.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFPlugIn_Factory.h - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFPLUGIN_FACTORY__) diff --git a/CFPlugIn_Instance.c b/CFPlugIn_Instance.c index 8923155..617e970 100644 --- a/CFPlugIn_Instance.c +++ b/CFPlugIn_Instance.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFPlugIn_Instance.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. - Responsibility: Doug Davidson + Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ #include "CFBundle_Internal.h" diff --git a/CFPlugIn_PlugIn.c b/CFPlugIn_PlugIn.c index d24a6be..71ecb04 100644 --- a/CFPlugIn_PlugIn.c +++ b/CFPlugIn_PlugIn.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFPlugIn_PlugIn.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. - Responsibility: Doug Davidson + Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ #include "CFBundle_Internal.h" diff --git a/CFPreferences.c b/CFPreferences.c index ed005b5..065c40c 100644 --- a/CFPreferences.c +++ b/CFPreferences.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFPreferences.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. - Responsibility: Chris Parker + Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ #include @@ -32,10 +32,11 @@ #include #endif #include +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS #include +#endif #include #include -#include #include "CFInternal.h" #include #if DEPLOYMENT_TARGET_MACOSX @@ -435,8 +436,9 @@ static CFStringRef _CFPreferencesCachePrefixForUserHost(CFStringRef userName, } CFMutableStringRef result = CFStringCreateMutable(__CFPreferencesAllocator(), 0); if (userName == kCFPreferencesCurrentUser) { - userName = CFGetUserName(); + userName = CFCopyUserName(); CFStringAppend(result, userName); + CFRelease(userName); CFStringAppend(result, CFSTR("/")); } else if (userName == kCFPreferencesAnyUser) { CFStringAppend(result, CFSTR("*/")); diff --git a/CFPreferences.h b/CFPreferences.h index 43c04d4..2525c01 100644 --- a/CFPreferences.h +++ b/CFPreferences.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFPreferences.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFPREFERENCES__) diff --git a/CFPriv.h b/CFPriv.h index 1a160dc..d1694fe 100644 --- a/CFPriv.h +++ b/CFPriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFPriv.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ /* @@ -37,19 +37,20 @@ #include #include #include -#include -#include +#include +#include #include -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) +#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_OS_LINUX)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) #include #endif #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) || TARGET_OS_WIN32 #include #include +#include #endif CF_EXTERN_C_BEGIN @@ -63,15 +64,12 @@ CF_EXPORT const char **_CFGetProcessPath(void); CF_EXPORT const char **_CFGetProgname(void); -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) +#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 Boolean _CFRunLoopModeContainsMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef candidateContainedName); -CF_EXPORT void _CFRunLoopAddModeToMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef toModeName); -CF_EXPORT void _CFRunLoopRemoveModeFromMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef fromModeName); CF_EXPORT void _CFRunLoopStopMode(CFRunLoopRef rl, CFStringRef modeName); CF_EXPORT CFIndex CFMachPortGetQueuedMessageCount(CFMachPortRef mp); @@ -98,7 +96,6 @@ CFURLRef _CFCreateURLFromFSSpec(CFAllocatorRef alloc, const struct FSSpec *voids #endif #endif -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED enum { kCFURLComponentDecompositionNonHierarchical, kCFURLComponentDecompositionRFC1808, /* use this for RFC 1738 decompositions as well */ @@ -147,7 +144,7 @@ CF_EXPORT CFURLRef _CFURLCreateFromComponents(CFAllocatorRef alloc, CFURLComponentDecomposition decompositionType, const void *components); #define CFURLCopyComponents _CFURLCopyComponents #define CFURLCreateFromComponents _CFURLCreateFromComponents -#endif + CF_EXPORT Boolean _CFStringGetFileSystemRepresentation(CFStringRef string, UInt8 *buffer, CFIndex maxBufLen); @@ -156,9 +153,14 @@ CF_EXPORT Boolean _CFStringGetFileSystemRepresentation(CFStringRef string, UInt8 CF_EXPORT CFStringRef _CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const UInt8 *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean externalFormat, CFAllocatorRef contentsDeallocator); /* These return NULL on MacOS 8 */ +// This one leaks the returned string in order to be thread-safe. +// CF cannot help you in this matter if you continue to use this SPI. CF_EXPORT CFStringRef CFGetUserName(void); +CF_EXPORT +CFStringRef CFCopyUserName(void); + CF_EXPORT CFURLRef CFCopyHomeDirectoryURLForUser(CFStringRef uName); /* Pass NULL for the current user's home directory */ @@ -168,7 +170,7 @@ CFURLRef CFCopyHomeDirectoryURLForUser(CFStringRef uName); /* Pass NULL for the standard system directories where apps, resources, etc get installed. Because queries can return multiple directories, you get back a CFArray (which you should free when done) of - CFStrings. The directories are returned in search path order; + CFURLs. The directories are returned in search path order; that is, the first place to look is returned first. This API may return directories that do not exist yet. If NSUserDomain is included in a query, then the results will contain "~" to @@ -241,12 +243,10 @@ enum { CFSystemVersionPuma = 1, /* 10.1 */ CFSystemVersionJaguar = 2, /* 10.2 */ CFSystemVersionPanther = 3, /* 10.3 */ - CFSystemVersionPinot = 3, /* Deprecated name for Panther */ CFSystemVersionTiger = 4, /* 10.4 */ - CFSystemVersionMerlot = 4, /* Deprecated name for Tiger */ CFSystemVersionLeopard = 5, /* 10.5 */ - CFSystemVersionChablis = 5, /* Deprecated name for Leopard */ CFSystemVersionSnowLeopard = 6, /* 10.6 */ + CFSystemVersionLion = 7, /* 10.7 */ CFSystemVersionMax, /* This should bump up when new entries are added */ }; @@ -445,19 +445,33 @@ CF_EXPORT CFMessagePortRef CFMessagePortCreateUber(CFAllocatorRef allocator, CFS CF_EXPORT void CFMessagePortSetCloneCallout(CFMessagePortRef ms, CFMessagePortCallBack cloneCallout); #endif -#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) +#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_OS_LINUX)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) #include -CFMessagePortRef CFMessagePortCreatePerProcessLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo); -CFMessagePortRef CFMessagePortCreatePerProcessRemote(CFAllocatorRef allocator, CFStringRef name, CFIndex pid); +CF_EXPORT CFMessagePortRef CFMessagePortCreatePerProcessLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo); +CF_EXPORT CFMessagePortRef CFMessagePortCreatePerProcessRemote(CFAllocatorRef allocator, CFStringRef name, CFIndex pid); + + +typedef CFDataRef (*CFMessagePortCallBackEx)(CFMessagePortRef local, SInt32 msgid, CFDataRef data, void *info, void *trailer, uintptr_t); + +CF_EXPORT CFMessagePortRef _CFMessagePortCreateLocalEx(CFAllocatorRef allocator, CFStringRef name, Boolean perPID, uintptr_t unused, CFMessagePortCallBackEx callout2, CFMessagePortContext *context, Boolean *shouldFreeInfo); + #endif +#if TARGET_OS_MAC || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_OS_LINUX +#include +#else +// Avoid including the pthread header +#ifndef HAVE_STRUCT_TIMESPEC +#define HAVE_STRUCT_TIMESPEC 1 +struct timespec { long tv_sec; long tv_nsec; }; +#endif +#endif CF_INLINE CFAbsoluteTime _CFAbsoluteTimeFromFileTimeSpec(struct timespec ts) { return (CFAbsoluteTime)((CFTimeInterval)ts.tv_sec - kCFAbsoluteTimeIntervalSince1970) + (1.0e-9 * (CFTimeInterval)ts.tv_nsec); } -#if 0 CF_INLINE struct timespec _CFFileTimeSpecFromAbsoluteTime(CFAbsoluteTime at) { struct timespec ts; double sec = 0.0; @@ -466,18 +480,45 @@ CF_INLINE struct timespec _CFFileTimeSpecFromAbsoluteTime(CFAbsoluteTime at) { frac += 1.0; sec -= 1.0; } +#if TARGET_OS_WIN32 + ts.tv_sec = (long)(sec + kCFAbsoluteTimeIntervalSince1970); +#else ts.tv_sec = (time_t)(sec + kCFAbsoluteTimeIntervalSince1970); - ts.tv_nsec = (long)(NSEC_PER_SEC * frac + 0.5); +#endif + ts.tv_nsec = (long)(1000000000UL * frac + 0.5); return ts; } -#endif + +CF_EXPORT bool _CFPropertyListCreateSingleValue(CFAllocatorRef allocator, CFDataRef data, CFOptionFlags option, CFStringRef keyPath, CFPropertyListRef *value, CFErrorRef *error); + #if TARGET_OS_WIN32 +#include + CF_EXPORT CFStringRef _CFGetWindowsAppleAppDataDirectory(void); CF_EXPORT CFArrayRef _CFGetWindowsBinaryDirectories(void); CF_EXPORT CFStringRef _CFGetWindowsAppleSystemLibraryDirectory(void); + +// If your Windows application does not use a CFRunLoop on the main thread (perhaps because it is reserved for handling UI events via Windows API), then call this function to make distributed notifications arrive using a different run loop. +CF_EXPORT void _CFNotificationCenterSetRunLoop(CFNotificationCenterRef nc, CFRunLoopRef rl); + +CF_EXPORT uint32_t /*DWORD*/ _CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef modeName); +CF_EXPORT void _CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, uint32_t /*DWORD*/ mask, CFStringRef modeName); + +CF_EXPORT uint32_t /*DWORD*/ _CFRunLoopGetWindowsThreadID(CFRunLoopRef rl); + +typedef void (*CFWindowsMessageQueueHandler)(void); + +// Run Loop parameter must be the current thread's run loop for the next two functions; you cannot use another thread's run loop +CF_EXPORT CFWindowsMessageQueueHandler _CFRunLoopGetWindowsMessageQueueHandler(CFRunLoopRef rl, CFStringRef modeName); +CF_EXPORT void _CFRunLoopSetWindowsMessageQueueHandler(CFRunLoopRef rl, CFStringRef modeName, CFWindowsMessageQueueHandler func); + #endif + +CF_EXPORT CFArrayRef CFDateFormatterCreateDateFormatsFromTemplates(CFAllocatorRef allocator, CFArrayRef tmplates, CFOptionFlags options, CFLocaleRef locale); + + CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFPRIV__ */ diff --git a/CFPropertyList.c b/CFPropertyList.c index adb164f..a2c9100 100644 --- a/CFPropertyList.c +++ b/CFPropertyList.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFPropertyList.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. Responsibility: Tony Parker */ @@ -35,7 +35,9 @@ #include #include #include +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS #include +#endif #include #include "CFLocaleInternal.h" #include @@ -44,24 +46,6 @@ #include #include #include -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -#include -#include -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif - - -__private_extern__ bool allowMissingSemi = false; - -// Should move this somewhere else -intptr_t _CFDoOperation(intptr_t code, intptr_t subcode1, intptr_t subcode2) { - switch (code) { - case 15317: allowMissingSemi = subcode1 ? true : false; break; - } - return code; -} #define PLIST_IX 0 #define ARRAY_IX 1 @@ -91,13 +75,52 @@ intptr_t _CFDoOperation(intptr_t code, intptr_t subcode1, intptr_t subcode2) { #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(); \ + HALT; \ + } \ + Boolean N ## _is_stack__ = (N ## _count__ <= 256); \ + if (N ## _count__ == 0) N ## _count__ = 1; \ + STACK_BUFFER_DECL(CFTypeRef, N ## _buffer__, N ## _is_stack__ ? N ## _count__ : 1); \ + 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(); \ + HALT; \ + } \ + do {} while (0) +#endif + +#if !defined(free_cftype_array) +#define free_cftype_array(N) \ + if (! N ## _is_stack__) { \ + if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFAllocatorDeallocate(kCFAllocatorSystemDefault, N); \ + } \ + do {} while (0) +#endif + // 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); +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; @@ -132,25 +155,25 @@ static void initStatics() { } } -__private_extern__ CFErrorRef __CFPropertyListCreateError(CFAllocatorRef allocator, CFIndex code, CFStringRef debugString, ...) { +__private_extern__ CFErrorRef __CFPropertyListCreateError(CFIndex code, CFStringRef debugString, ...) { va_list argList; CFErrorRef error = NULL; if (debugString != NULL) { CFStringRef debugMessage = NULL; va_start(argList, debugString); - debugMessage = CFStringCreateWithFormatAndArguments(allocator, NULL, debugString, argList); + debugMessage = CFStringCreateWithFormatAndArguments(kCFAllocatorSystemDefault, NULL, debugString, argList); va_end(argList); - CFMutableDictionaryRef userInfo = CFDictionaryCreateMutable(allocator, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFMutableDictionaryRef userInfo = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(userInfo, kCFErrorDebugDescriptionKey, debugMessage); - error = CFErrorCreate(allocator, kCFErrorDomainCocoa, code, userInfo); + error = CFErrorCreate(kCFAllocatorSystemDefault, kCFErrorDomainCocoa, code, userInfo); CFRelease(debugMessage); CFRelease(userInfo); } else { - error = CFErrorCreate(allocator, kCFErrorDomainCocoa, code, NULL); + error = CFErrorCreate(kCFAllocatorSystemDefault, kCFErrorDomainCocoa, code, NULL); } return error; @@ -160,7 +183,7 @@ CFStringRef __CFPropertyListCopyErrorDebugDescription(CFErrorRef error) { CFStringRef result = NULL; if (error) { CFDictionaryRef userInfo = CFErrorCopyUserInfo(error); - result = CFStringCreateCopy(kCFAllocatorDefault, (CFStringRef)CFDictionaryGetValue(userInfo, kCFErrorDebugDescriptionKey)); + result = CFStringCreateCopy(kCFAllocatorSystemDefault, (CFStringRef)CFDictionaryGetValue(userInfo, kCFErrorDebugDescriptionKey)); CFRelease(userInfo); } return result; @@ -171,89 +194,97 @@ struct context { bool answer; CFMutableSetRef set; CFPropertyListFormat format; + CFStringRef *error; }; static void __CFPropertyListIsArrayPlistAux(const void *value, void *context) { struct context *ctx = (struct context *)context; if (!ctx->answer) return; -#if defined(DEBUG) - if (!value) CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListIsValid(): property list arrays cannot contain NULL")); -#endif - ctx->answer = value && __CFPropertyListIsValidAux(value, true, ctx->set, ctx->format); + if (!value && !*(ctx->error)) { + *(ctx->error) = (CFStringRef)CFRetain(CFSTR("property list arrays cannot contain NULL")); + } + ctx->answer = value && __CFPropertyListIsValidAux(value, true, ctx->set, ctx->format, ctx->error); } static void __CFPropertyListIsDictPlistAux(const void *key, const void *value, void *context) { struct context *ctx = (struct context *)context; if (!ctx->answer) return; -#if defined(DEBUG) - if (!key) CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListIsValid(): property list dictionaries cannot contain NULL keys")); - if (!value) CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListIsValid(): property list dictionaries cannot contain NULL values")); - if (stringtype != CFGetTypeID(key)) { + if (!key && !*(ctx->error)) *(ctx->error) = (CFStringRef)CFRetain(CFSTR("property list dictionaries cannot contain NULL keys")); + if (!value && !*(ctx->error)) *(ctx->error) = (CFStringRef)CFRetain(CFSTR("property list dictionaries cannot contain NULL values")); + if (stringtype != CFGetTypeID(key) && !*(ctx->error)) { CFStringRef desc = CFCopyTypeIDDescription(CFGetTypeID(key)); - CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListIsValid(): property list dictionaries may only have keys which are CFStrings, not '%@'"), desc); + *(ctx->error) = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("property list dictionaries may only have keys which are CFStrings, not '%@'"), desc); CFRelease(desc); } -#endif - ctx->answer = key && value && (stringtype == CFGetTypeID(key)) && __CFPropertyListIsValidAux(value, true, ctx->set, ctx->format); + ctx->answer = key && value && (stringtype == CFGetTypeID(key)) && __CFPropertyListIsValidAux(value, true, ctx->set, ctx->format, ctx->error); } -static bool __CFPropertyListIsValidAux(CFPropertyListRef plist, bool recursive, CFMutableSetRef set, CFPropertyListFormat format) { +static bool __CFPropertyListIsValidAux(CFPropertyListRef plist, bool recursive, CFMutableSetRef set, CFPropertyListFormat format, CFStringRef *error) { CFTypeID type; -#if defined(DEBUG) - if (!plist) CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListIsValid(): property lists cannot contain NULL")); -#endif - if (!plist) return false; + if (!plist) { + *error = (CFStringRef)CFRetain(CFSTR("property lists cannot contain NULL")); + return false; + } type = CFGetTypeID(plist); if (stringtype == type) return true; if (datatype == type) return true; if (kCFPropertyListOpenStepFormat != format) { if (booltype == type) return true; if (numbertype == type) return true; - if (datetype == type) return true; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC + if (datetype == type) return true; if (_CFKeyedArchiverUIDGetTypeID() == type) return true; -#elif DEPLOYMENT_TARGET_WINDOWS_SAFARI -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif } if (!recursive && arraytype == type) return true; if (!recursive && dicttype == type) return true; // at any one invocation of this function, set should contain the objects in the "path" down to this object -#if defined(DEBUG) - if (CFSetContainsValue(set, plist)) CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListIsValid(): property lists cannot contain recursive container references")); -#endif - if (CFSetContainsValue(set, plist)) return false; + if (CFSetContainsValue(set, plist)) { + *error = (CFStringRef)CFRetain(CFSTR("property lists cannot contain recursive container references")); + return false; + } if (arraytype == type) { - struct context ctx = {true, set, format}; + struct context ctx = {true, set, format, error}; CFSetAddValue(set, plist); CFArrayApplyFunction((CFArrayRef)plist, CFRangeMake(0, CFArrayGetCount((CFArrayRef)plist)), __CFPropertyListIsArrayPlistAux, &ctx); CFSetRemoveValue(set, plist); return ctx.answer; } if (dicttype == type) { - struct context ctx = {true, set, format}; + struct context ctx = {true, set, format, error}; CFSetAddValue(set, plist); CFDictionaryApplyFunction((CFDictionaryRef)plist, __CFPropertyListIsDictPlistAux, &ctx); CFSetRemoveValue(set, plist); return ctx.answer; } -#if defined(DEBUG) - { - CFStringRef desc = CFCopyTypeIDDescription(type); - CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListIsValid(): property lists cannot contain objects of type '%@'"), desc); - CFRelease(desc); - } -#endif + + CFStringRef desc = CFCopyTypeIDDescription(type); + *error = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("property lists cannot contain objects of type '%@'"), desc); + CFRelease(desc); + 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(kCFAllocatorSystemDefault, 0, NULL); - bool result = __CFPropertyListIsValidAux(plist, true, set, format); - CFRelease(set); + 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__); + CFMutableSetRef set = CFSetCreateMutable(kCFAllocatorSystemDefaultGCRefZero, 0, NULL); + bool result = __CFPropertyListIsValidAux(plist, true, set, format, error); + if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(set); return result; } @@ -287,6 +318,9 @@ typedef struct { static CFTypeRef parseOldStylePropertyListOrStringsFile(_CFXMLPlistParseInfo *pInfo); +CF_INLINE void __CFPListRelease(CFTypeRef cf, _CFXMLPlistParseInfo *pInfo) { + if (cf && !_CFAllocatorIsGCRefZero(pInfo->allocator)) CFRelease(cf); +} // The following set of _plist... functions append various things to a mutable data which is in UTF8 encoding. These are pretty general. Assumption is call characters and CFStrings can be converted to UTF8 and appeneded. @@ -382,6 +416,12 @@ static void _appendEscapedString(CFStringRef origStr, CFMutableDataRef mStr) { for (i = 0; i < length; i ++) { UniChar ch = __CFStringGetCharacterFromInlineBufferQuick(&inlineBuffer, i); + if (CFStringIsSurrogateHighCharacter(ch) && (bufCnt + 2 >= BUFSIZE)) { + // flush the buffer first so we have room for a low/high pair and do not split them + _plistAppendCharacters(mStr, buf, bufCnt); + bufCnt = 0; + } + switch(ch) { case '<': if (bufCnt) _plistAppendCharacters(mStr, buf, bufCnt); @@ -502,40 +542,6 @@ static void _CFAppendXML0(CFTypeRef object, UInt32 indentation, CFMutableDataRef _plistAppendUTF8CString(xmlString, "\n"); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC - } else if (typeID == _CFKeyedArchiverUIDGetTypeID()) { - _plistAppendUTF8CString(xmlString, "<"); - _plistAppendCharacters(xmlString, CFXMLPlistTags[DICT_IX], DICT_TAG_LENGTH); - _plistAppendUTF8CString(xmlString, ">\n"); - _appendIndents(indentation+1, xmlString); - _plistAppendUTF8CString(xmlString, "<"); - _plistAppendCharacters(xmlString, CFXMLPlistTags[KEY_IX], KEY_TAG_LENGTH); - _plistAppendUTF8CString(xmlString, ">"); - _appendEscapedString(CFSTR("CF$UID"), xmlString); - _plistAppendUTF8CString(xmlString, "\n"); - _appendIndents(indentation + 1, xmlString); - _plistAppendUTF8CString(xmlString, "<"); - _plistAppendCharacters(xmlString, CFXMLPlistTags[INTEGER_IX], INTEGER_TAG_LENGTH); - _plistAppendUTF8CString(xmlString, ">"); - - uint64_t v = _CFKeyedArchiverUIDGetValue((CFKeyedArchiverUIDRef)object); - CFNumberRef num = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt64Type, &v); - _plistAppendFormat(xmlString, CFSTR("%@"), num); - CFRelease(num); - - _plistAppendUTF8CString(xmlString, "\n"); - _appendIndents(indentation, xmlString); - _plistAppendUTF8CString(xmlString, "\n"); -#elif DEPLOYMENT_TARGET_WINDOWS_SAFARI -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif } else if (typeID == arraytype) { UInt32 i, count = CFArrayGetCount((CFArrayRef)object); if (count == 0) { @@ -557,7 +563,6 @@ static void _CFAppendXML0(CFTypeRef object, UInt32 indentation, CFMutableDataRef } else if (typeID == dicttype) { UInt32 i, count = CFDictionaryGetCount((CFDictionaryRef)object); CFMutableArrayRef keyArray; - CFTypeRef *keys; if (count == 0) { _plistAppendUTF8CString(xmlString, "<"); _plistAppendCharacters(xmlString, CFXMLPlistTags[DICT_IX], DICT_TAG_LENGTH); @@ -567,7 +572,7 @@ static void _CFAppendXML0(CFTypeRef object, UInt32 indentation, CFMutableDataRef _plistAppendUTF8CString(xmlString, "<"); _plistAppendCharacters(xmlString, CFXMLPlistTags[DICT_IX], DICT_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">\n"); - keys = (CFTypeRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, count * sizeof(CFTypeRef), 0); + new_cftype_array(keys, count); CFDictionaryGetKeysAndValues((CFDictionaryRef)object, keys, NULL); keyArray = CFArrayCreateMutable(kCFAllocatorSystemDefault, count, &kCFTypeArrayCallBacks); CFArrayReplaceValues(keyArray, CFRangeMake(0, 0), keys, count); @@ -586,7 +591,7 @@ static void _CFAppendXML0(CFTypeRef object, UInt32 indentation, CFMutableDataRef _plistAppendUTF8CString(xmlString, ">\n"); _CFAppendXML0(CFDictionaryGetValue((CFDictionaryRef)object, key), indentation+1, xmlString); } - CFAllocatorDeallocate(kCFAllocatorSystemDefault, keys); + free_cftype_array(keys); _appendIndents(indentation, xmlString); _plistAppendUTF8CString(xmlString, "error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Unterminated comment started on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Unterminated comment started on line %d"), lineNumber(pInfo)); } // stringToMatch and buf must both be of at least len @@ -783,14 +788,14 @@ static void skipXMLProcessingInstruction(_CFXMLPlistParseInfo *pInfo) { pInfo->curr ++; } pInfo->curr = begin; - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF while parsing the processing instruction begun on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF while parsing the processing instruction begun on line %d"), lineNumber(pInfo)); } // first character should be immediately after the "end - pInfo->curr < DOCTYPE_TAG_LENGTH || !matchString(pInfo->curr, CFXMLPlistTags[DOCTYPE_IX], DOCTYPE_TAG_LENGTH)) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Malformed DTD on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Malformed DTD on line %d"), lineNumber(pInfo)); return; } pInfo->curr += DOCTYPE_TAG_LENGTH; @@ -807,7 +812,7 @@ static void skipDTD(_CFXMLPlistParseInfo *pInfo) { pInfo->curr ++; } if (pInfo->curr == pInfo->end) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF while parsing DTD")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF while parsing DTD")); return; } @@ -820,10 +825,10 @@ static void skipDTD(_CFXMLPlistParseInfo *pInfo) { if (*(pInfo->curr) == '>') { pInfo->curr ++; } else { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected character %c on line %d while parsing DTD"), *(pInfo->curr), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected character %c on line %d while parsing DTD"), *(pInfo->curr), lineNumber(pInfo)); } } else { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF while parsing DTD")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF while parsing DTD")); } } @@ -836,7 +841,7 @@ static void skipPERef(_CFXMLPlistParseInfo *pInfo) { } p ++; } - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF while parsing percent-escape sequence begun on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF while parsing percent-escape sequence begun on line %d"), lineNumber(pInfo)); } // First character should be just past '[' @@ -851,7 +856,7 @@ static void skipInlineDTD(_CFXMLPlistParseInfo *pInfo) { } else if (ch == '<') { pInfo->curr ++; if (pInfo->curr >= pInfo->end) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF while parsing inline DTD")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF while parsing inline DTD")); return; } ch = *(pInfo->curr); @@ -870,25 +875,25 @@ static void skipInlineDTD(_CFXMLPlistParseInfo *pInfo) { pInfo->curr ++; } if (*(pInfo->curr) != '>') { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF while parsing inline DTD")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF while parsing inline DTD")); return; } pInfo->curr ++; } } else { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected character %c on line %d while parsing inline DTD"), ch, lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected character %c on line %d while parsing inline DTD"), ch, lineNumber(pInfo)); return; } } else if (ch == ']') { pInfo->curr ++; return; } else { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected character %c on line %d while parsing inline DTD"), ch, lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected character %c on line %d while parsing inline DTD"), ch, lineNumber(pInfo)); return; } } if (!pInfo->error) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF while parsing inline DTD")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF while parsing inline DTD")); } } @@ -975,16 +980,16 @@ static CFTypeRef getContentObject(_CFXMLPlistParseInfo *pInfo, Boolean *isKey) { while (!pInfo->error && pInfo->curr < pInfo->end) { skipWhitespace(pInfo); if (pInfo->curr >= pInfo->end) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); return NULL; } if (*(pInfo->curr) != '<') { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected character %c on line %d"), *(pInfo->curr), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected character %c on line %d"), *(pInfo->curr), lineNumber(pInfo)); return NULL; } pInfo->curr ++; if (pInfo->curr >= pInfo->end) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); return NULL; } switch (*(pInfo->curr)) { @@ -995,14 +1000,14 @@ static CFTypeRef getContentObject(_CFXMLPlistParseInfo *pInfo, Boolean *isKey) { case '!': // Could be a comment if (pInfo->curr+2 >= pInfo->end) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); return NULL; } if (*(pInfo->curr+1) == '-' && *(pInfo->curr+2) == '-') { pInfo->curr += 2; skipXMLComment(pInfo); } else { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); return NULL; } break; @@ -1019,9 +1024,9 @@ static CFTypeRef getContentObject(_CFXMLPlistParseInfo *pInfo, Boolean *isKey) { return NULL; } -static void _catFromMarkToBuf(const UniChar *mark, const UniChar *buf, CFMutableStringRef *string, CFAllocatorRef allocator ) { +static void _catFromMarkToBuf(const UniChar *mark, const UniChar *buf, CFMutableStringRef *string, _CFXMLPlistParseInfo *pInfo) { if (!(*string)) { - *string = CFStringCreateMutable(allocator, 0); + *string = CFStringCreateMutable(pInfo->allocator, 0); } CFStringAppendCharacters(*string, mark, buf-mark); } @@ -1029,11 +1034,11 @@ static void _catFromMarkToBuf(const UniChar *mark, const UniChar *buf, CFMutable static void parseCDSect_pl(_CFXMLPlistParseInfo *pInfo, CFMutableStringRef string) { const UniChar *end, *begin; if (pInfo->end - pInfo->curr < CDSECT_TAG_LENGTH) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); return; } if (!matchString(pInfo->curr, CFXMLPlistTags[CDSECT_IX], CDSECT_TAG_LENGTH)) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered improper CDATA opening at line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered improper CDATA opening at line %d"), lineNumber(pInfo)); return; } pInfo->curr += CDSECT_TAG_LENGTH; @@ -1050,7 +1055,7 @@ static void parseCDSect_pl(_CFXMLPlistParseInfo *pInfo, CFMutableStringRef strin } // Never found the end mark pInfo->curr = begin; - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Could not find end of CDATA started on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Could not find end of CDATA started on line %d"), lineNumber(pInfo)); } // Only legal references are {lt, gt, amp, apos, quote, #ddd, #xAAA} @@ -1060,7 +1065,7 @@ static void parseEntityReference_pl(_CFXMLPlistParseInfo *pInfo, CFMutableString pInfo->curr ++; // move past the '&'; len = pInfo->end - pInfo->curr; // how many characters we can safely scan if (len < 1) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); return; } switch (*(pInfo->curr)) { @@ -1070,7 +1075,7 @@ static void parseEntityReference_pl(_CFXMLPlistParseInfo *pInfo, CFMutableString pInfo->curr += 3; break; } - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unknown ampersand-escape sequence at line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unknown ampersand-escape sequence at line %d"), lineNumber(pInfo)); return; case 'g': // "gt" if (len >= 3 && *(pInfo->curr+1) == 't' && *(pInfo->curr+2) == ';') { @@ -1078,11 +1083,11 @@ static void parseEntityReference_pl(_CFXMLPlistParseInfo *pInfo, CFMutableString pInfo->curr += 3; break; } - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unknown ampersand-escape sequence at line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unknown ampersand-escape sequence at line %d"), lineNumber(pInfo)); return; case 'a': // "apos" or "amp" if (len < 4) { // Not enough characters for either conversion - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); return; } if (*(pInfo->curr+1) == 'm') { @@ -1100,7 +1105,7 @@ static void parseEntityReference_pl(_CFXMLPlistParseInfo *pInfo, CFMutableString break; } } - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unknown ampersand-escape sequence at line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unknown ampersand-escape sequence at line %d"), lineNumber(pInfo)); return; case 'q': // "quote" if (len >= 5 && *(pInfo->curr+1) == 'u' && *(pInfo->curr+2) == 'o' && *(pInfo->curr+3) == 't' && *(pInfo->curr+4) == ';') { @@ -1108,14 +1113,14 @@ static void parseEntityReference_pl(_CFXMLPlistParseInfo *pInfo, CFMutableString pInfo->curr += 5; break; } - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unknown ampersand-escape sequence at line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unknown ampersand-escape sequence at line %d"), lineNumber(pInfo)); return; case '#': { uint16_t num = 0; Boolean isHex = false; if ( len < 4) { // Not enough characters to make it all fit! Need at least "&#d;" - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); return; } pInfo->curr ++; @@ -1135,22 +1140,22 @@ static void parseEntityReference_pl(_CFXMLPlistParseInfo *pInfo, CFMutableString if (ch <= '9' && ch >= '0') { num += (ch - '0'); } else if (!isHex) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected character %c at line %d"), ch, lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected character %c at line %d"), ch, lineNumber(pInfo)); return; } else if (ch >= 'a' && ch <= 'f') { num += 10 + (ch - 'a'); } else if (ch >= 'A' && ch <= 'F') { num += 10 + (ch - 'A'); } else { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected character %c at line %d"), ch, lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected character %c at line %d"), ch, lineNumber(pInfo)); return; } } - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); return; } default: - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unknown ampersand-escape sequence at line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unknown ampersand-escape sequence at line %d"), lineNumber(pInfo)); return; } CFStringAppendCharacters(string, &ch, 1); @@ -1165,11 +1170,12 @@ static CFStringRef _uniqueStringForString(_CFXMLPlistParseInfo *pInfo, CFStringR CFSetAddValue(pInfo->stringSet, uniqued); __CFTypeCollectionRelease(pInfo->allocator, uniqued); } + if (uniqued && !_CFAllocatorIsGCRefZero(pInfo->allocator)) CFRetain(uniqued); return uniqued; } static CFStringRef _uniqueStringForCharacters(_CFXMLPlistParseInfo *pInfo, const UniChar *base, CFIndex length) { - if (0 == length) return CFSTR(""); + 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; @@ -1195,7 +1201,8 @@ static CFStringRef _uniqueStringForCharacters(_CFXMLPlistParseInfo *pInfo, const CFSetAddValue(pInfo->stringSet, stringToUnique); uniqued = stringToUnique; } - CFRelease(stringToUnique); + __CFPListRelease(stringToUnique, pInfo); + if (uniqued && !_CFAllocatorIsGCRefZero(pInfo->allocator)) CFRetain(uniqued); return uniqued; } @@ -1210,11 +1217,11 @@ static CFStringRef getString(_CFXMLPlistParseInfo *pInfo) { if (pInfo->curr + 1 >= pInfo->end) break; // Could be a CDSect; could be the end of the string if (*(pInfo->curr+1) != '!') break; // End of the string - _catFromMarkToBuf(mark, pInfo->curr, &string, pInfo->allocator); + _catFromMarkToBuf(mark, pInfo->curr, &string, pInfo); parseCDSect_pl(pInfo, string); mark = pInfo->curr; } else if (ch == '&') { - _catFromMarkToBuf(mark, pInfo->curr, &string, pInfo->allocator); + _catFromMarkToBuf(mark, pInfo->curr, &string, pInfo); parseEntityReference_pl(pInfo, string); mark = pInfo->curr; } else { @@ -1223,13 +1230,12 @@ static CFStringRef getString(_CFXMLPlistParseInfo *pInfo) { } if (pInfo->error) { - if (string) CFRelease(string); + __CFPListRelease(string, pInfo); return NULL; } if (!string) { if (pInfo->mutabilityOption != kCFPropertyListMutableContainersAndLeaves) { CFStringRef uniqueString = _uniqueStringForCharacters(pInfo, mark, pInfo->curr-mark); - if (uniqueString) CFRetain(uniqueString); return uniqueString; } else { string = CFStringCreateMutable(pInfo->allocator, 0); @@ -1237,11 +1243,10 @@ static CFStringRef getString(_CFXMLPlistParseInfo *pInfo) { return string; } } - _catFromMarkToBuf(mark, pInfo->curr, &string, pInfo->allocator); + _catFromMarkToBuf(mark, pInfo->curr, &string, pInfo); if (pInfo->mutabilityOption != kCFPropertyListMutableContainersAndLeaves) { CFStringRef uniqueString = _uniqueStringForString(pInfo, string); - if (uniqueString) CFRetain(uniqueString); - CFRelease(string); + __CFPListRelease(string, pInfo); return uniqueString; } return string; @@ -1250,21 +1255,21 @@ static CFStringRef getString(_CFXMLPlistParseInfo *pInfo) { static Boolean checkForCloseTag(_CFXMLPlistParseInfo *pInfo, const UniChar *tag, CFIndex tagLen) { if (pInfo->end - pInfo->curr < tagLen + 3) { if (!pInfo->error) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); } return false; } if (*(pInfo->curr) != '<' || *(++pInfo->curr) != '/') { if (!pInfo->error) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected character %c on line %d"), *(pInfo->curr), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected character %c on line %d"), *(pInfo->curr), lineNumber(pInfo)); } return false; } pInfo->curr ++; if (!matchString(pInfo->curr, tag, tagLen)) { - CFStringRef str = CFStringCreateWithCharactersNoCopy(pInfo->allocator, tag, tagLen, kCFAllocatorNull); + CFStringRef str = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, tag, tagLen, kCFAllocatorNull); if (!pInfo->error) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Close tag on line %d does not match open tag %@"), lineNumber(pInfo), str); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Close tag on line %d does not match open tag %@"), lineNumber(pInfo), str); } CFRelease(str); return false; @@ -1273,13 +1278,13 @@ static Boolean checkForCloseTag(_CFXMLPlistParseInfo *pInfo, const UniChar *tag, skipWhitespace(pInfo); if (pInfo->curr == pInfo->end) { if (!pInfo->error) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); } return false; } if (*(pInfo->curr) != '>') { if (!pInfo->error) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected character %c on line %d"), *(pInfo->curr), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected character %c on line %d"), *(pInfo->curr), lineNumber(pInfo)); } return false; } @@ -1293,28 +1298,28 @@ static CFTypeRef parsePListTag(_CFXMLPlistParseInfo *pInfo) { const UniChar *save; result = getContentObject(pInfo, NULL); if (!result) { - if (!pInfo->error) pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered empty plist tag")); + if (!pInfo->error) pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered empty plist tag")); return NULL; } save = pInfo->curr; // Save this in case the next step fails tmp = getContentObject(pInfo, NULL); if (tmp) { // Got an extra object - CFRelease(tmp); - CFRelease(result); + __CFPListRelease(tmp, pInfo); + __CFPListRelease(result, pInfo); pInfo->curr = save; - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected element at line %d (plist can only include one object)"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected element at line %d (plist can only include one object)"), lineNumber(pInfo)); return NULL; } if (pInfo->error) { // Parse failed catastrophically - CFRelease(result); + __CFPListRelease(result, pInfo); return NULL; } if (checkForCloseTag(pInfo, CFXMLPlistTags[PLIST_IX], PLIST_TAG_LENGTH)) { return result; } - CFRelease(result); + __CFPListRelease(result, pInfo); return NULL; } @@ -1329,11 +1334,11 @@ static CFTypeRef parseArrayTag(_CFXMLPlistParseInfo *pInfo) { CFTypeRef tmp = getContentObject(pInfo, NULL); while (tmp) { CFArrayAppendValue(array, tmp); - CFRelease(tmp); + __CFPListRelease(tmp, pInfo); tmp = getContentObject(pInfo, NULL); } if (pInfo->error) { // getContentObject encountered a parse error - CFRelease(array); + __CFPListRelease(array, pInfo); return NULL; } if (checkForCloseTag(pInfo, CFXMLPlistTags[ARRAY_IX], ARRAY_TAG_LENGTH)) { @@ -1341,13 +1346,13 @@ static CFTypeRef parseArrayTag(_CFXMLPlistParseInfo *pInfo) { if (1 == allowImmutableCollections) { if (pInfo->mutabilityOption == kCFPropertyListImmutable) { CFArrayRef newArray = CFArrayCreateCopy(pInfo->allocator, array); - CFRelease(array); + __CFPListRelease(array, pInfo); array = (CFMutableArrayRef)newArray; } } return array; } - CFRelease(array); + __CFPListRelease(array, pInfo); return NULL; } @@ -1359,20 +1364,20 @@ static CFTypeRef parseDictTag(_CFXMLPlistParseInfo *pInfo) { key = getContentObject(pInfo, &gotKey); while (key) { if (!gotKey) { - if (key) CFRelease(key); - if (dict) CFRelease(dict); + __CFPListRelease(key, pInfo); + __CFPListRelease(dict, pInfo); pInfo->curr = base; if (!pInfo->error) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Found non-key inside at line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Found non-key inside at line %d"), lineNumber(pInfo)); } return NULL; } value = getContentObject(pInfo, NULL); if (!value) { - if (key) CFRelease(key); - if (dict) CFRelease(dict); + __CFPListRelease(key, pInfo); + __CFPListRelease(dict, pInfo); if (!pInfo->error) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Value missing for key inside at line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Value missing for key inside at line %d"), lineNumber(pInfo)); } return NULL; } @@ -1381,9 +1386,9 @@ static CFTypeRef parseDictTag(_CFXMLPlistParseInfo *pInfo) { _CFDictionarySetCapacity(dict, 10); } CFDictionarySetValue(dict, key, value); - CFRelease(key); + __CFPListRelease(key, pInfo); key = NULL; - CFRelease(value); + __CFPListRelease(value, pInfo); value = NULL; base = pInfo->curr; key = getContentObject(pInfo, &gotKey); @@ -1404,7 +1409,7 @@ static CFTypeRef parseDictTag(_CFXMLPlistParseInfo *pInfo) { uint32_t v; CFNumberGetValue((CFNumberRef)val, kCFNumberSInt32Type, &v); uid = (CFTypeRef)_CFKeyedArchiverUIDCreate(pInfo->allocator, v); - CFRelease(dict); + __CFPListRelease(dict, pInfo); return uid; } } @@ -1412,14 +1417,14 @@ static CFTypeRef parseDictTag(_CFXMLPlistParseInfo *pInfo) { if (1 == allowImmutableCollections) { if (pInfo->mutabilityOption == kCFPropertyListImmutable) { CFDictionaryRef newDict = CFDictionaryCreateCopy(pInfo->allocator, dict); - CFRelease(dict); + __CFPListRelease(dict, pInfo); dict = (CFMutableDictionaryRef)newDict; } } } return dict; } - if (dict) CFRelease(dict); + __CFPListRelease(dict, pInfo); return NULL; } @@ -1429,11 +1434,11 @@ static CFTypeRef parseDataTag(_CFXMLPlistParseInfo *pInfo) { result = __CFPLDataDecode(pInfo, pInfo->mutabilityOption == kCFPropertyListMutableContainersAndLeaves); if (!result) { pInfo->curr = base; - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Could not interpret at line %d (should be base64-encoded)"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Could not interpret at line %d (should be base64-encoded)"), lineNumber(pInfo)); return NULL; } if (checkForCloseTag(pInfo, CFXMLPlistTags[DATA_IX], DATA_TAG_LENGTH)) return result; - CFRelease(result); + __CFPListRelease(result, pInfo); return NULL; } @@ -1453,7 +1458,13 @@ static CFTypeRef parseDateTag(_CFXMLPlistParseInfo *pInfo) { int32_t year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0; int32_t num = 0; Boolean badForm = false; - + Boolean yearIsNegative = false; + + if (pInfo->curr < pInfo->end && *pInfo->curr == '-') { + yearIsNegative = true; + pInfo->curr++; + } + while (pInfo->curr < pInfo->end && isdigit(*pInfo->curr)) { year = 10*year + (*pInfo->curr) - '0'; pInfo->curr ++; @@ -1496,14 +1507,14 @@ static CFTypeRef parseDateTag(_CFXMLPlistParseInfo *pInfo) { } if (badForm) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Could not interpret at line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Could not interpret at line %d"), lineNumber(pInfo)); return NULL; } if (!checkForCloseTag(pInfo, CFXMLPlistTags[DATE_IX], DATE_TAG_LENGTH)) return NULL; CFAbsoluteTime at = 0.0; #if 1 - CFGregorianDate date = {year, month, day, hour, minute, second}; + CFGregorianDate date = {yearIsNegative ? -year : year, month, day, hour, minute, second}; at = CFGregorianDateGetAbsoluteTime(date, NULL); #else CFCalendarRef calendar = CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault, kCFCalendarIdentifierGregorian); @@ -1524,37 +1535,37 @@ static CFTypeRef parseRealTag(_CFXMLPlistParseInfo *pInfo) { CFStringInlineBuffer buf; if (!str) { if (!pInfo->error) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered empty on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered empty on line %d"), lineNumber(pInfo)); } return NULL; } if (kCFCompareEqualTo == CFStringCompare(str, CFSTR("nan"), kCFCompareCaseInsensitive)) { - CFRelease(str); + __CFPListRelease(str, pInfo); return (checkForCloseTag(pInfo, CFXMLPlistTags[REAL_IX], REAL_TAG_LENGTH)) ? CFRetain(kCFNumberNaN) : NULL; } if (kCFCompareEqualTo == CFStringCompare(str, CFSTR("+infinity"), kCFCompareCaseInsensitive)) { - CFRelease(str); + __CFPListRelease(str, pInfo); return (checkForCloseTag(pInfo, CFXMLPlistTags[REAL_IX], REAL_TAG_LENGTH)) ? CFRetain(kCFNumberPositiveInfinity) : NULL; } if (kCFCompareEqualTo == CFStringCompare(str, CFSTR("-infinity"), kCFCompareCaseInsensitive)) { - CFRelease(str); + __CFPListRelease(str, pInfo); return (checkForCloseTag(pInfo, CFXMLPlistTags[REAL_IX], REAL_TAG_LENGTH)) ? CFRetain(kCFNumberNegativeInfinity) : NULL; } if (kCFCompareEqualTo == CFStringCompare(str, CFSTR("infinity"), kCFCompareCaseInsensitive)) { - CFRelease(str); + __CFPListRelease(str, pInfo); return (checkForCloseTag(pInfo, CFXMLPlistTags[REAL_IX], REAL_TAG_LENGTH)) ? CFRetain(kCFNumberPositiveInfinity) : NULL; } if (kCFCompareEqualTo == CFStringCompare(str, CFSTR("-inf"), kCFCompareCaseInsensitive)) { - CFRelease(str); + __CFPListRelease(str, pInfo); return (checkForCloseTag(pInfo, CFXMLPlistTags[REAL_IX], REAL_TAG_LENGTH)) ? CFRetain(kCFNumberNegativeInfinity) : NULL; } if (kCFCompareEqualTo == CFStringCompare(str, CFSTR("inf"), kCFCompareCaseInsensitive)) { - CFRelease(str); + __CFPListRelease(str, pInfo); return (checkForCloseTag(pInfo, CFXMLPlistTags[REAL_IX], REAL_TAG_LENGTH)) ? CFRetain(kCFNumberPositiveInfinity) : NULL; } if (kCFCompareEqualTo == CFStringCompare(str, CFSTR("+inf"), kCFCompareCaseInsensitive)) { - CFRelease(str); + __CFPListRelease(str, pInfo); return (checkForCloseTag(pInfo, CFXMLPlistTags[REAL_IX], REAL_TAG_LENGTH)) ? CFRetain(kCFNumberPositiveInfinity) : NULL; } @@ -1562,19 +1573,19 @@ static CFTypeRef parseRealTag(_CFXMLPlistParseInfo *pInfo) { CFStringInitInlineBuffer(str, &buf, CFRangeMake(0, len)); idx = 0; if (!__CFStringScanDouble(&buf, NULL, &idx, &val) || idx != len) { - CFRelease(str); - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered misformatted real on line %d"), lineNumber(pInfo)); + __CFPListRelease(str, pInfo); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered misformatted real on line %d"), lineNumber(pInfo)); return NULL; } - CFRelease(str); + __CFPListRelease(str, pInfo); result = CFNumberCreate(pInfo->allocator, kCFNumberDoubleType, &val); if (checkForCloseTag(pInfo, CFXMLPlistTags[REAL_IX], REAL_TAG_LENGTH)) return result; - CFRelease(result); + __CFPListRelease(result, pInfo); return NULL; } #define GET_CH if (pInfo->curr == pInfo->end) { \ - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Premature end of file after on line %d"), lineNumber(pInfo)); \ + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Premature end of file after on line %d"), lineNumber(pInfo)); \ return NULL; \ } \ ch = *(pInfo->curr) @@ -1598,7 +1609,7 @@ static CFTypeRef parseIntegerTag(_CFXMLPlistParseInfo *pInfo) { while (pInfo->curr < pInfo->end && __CFIsWhitespace(*(pInfo->curr))) pInfo->curr++; GET_CH; if ('<' == ch) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered empty on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered empty on line %d"), lineNumber(pInfo)); return NULL; } if ('-' == ch || '+' == ch) { @@ -1631,7 +1642,7 @@ static CFTypeRef parseIntegerTag(_CFXMLPlistParseInfo *pInfo) { return CFNumberCreate(pInfo->allocator, kCFNumberSInt32Type, &val); } if ('<' == ch) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Incomplete on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Incomplete on line %d"), lineNumber(pInfo)); return NULL; } uint64_t value = 0; @@ -1649,25 +1660,25 @@ static CFTypeRef parseIntegerTag(_CFXMLPlistParseInfo *pInfo) { new_digit = (ch - 'A' + 10); break; default: // other character - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Unknown character '%c' (0x%x) in on line %d"), ch, ch, lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Unknown character '%c' (0x%x) in on line %d"), ch, ch, lineNumber(pInfo)); return NULL; } if (!isHex && new_digit > 9) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Hex digit in non-hex on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Hex digit in non-hex on line %d"), lineNumber(pInfo)); return NULL; } if (UINT64_MAX / multiplier < value) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Integer overflow in on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Integer overflow in on line %d"), lineNumber(pInfo)); return NULL; } value = multiplier * value; if (UINT64_MAX - new_digit < value) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Integer overflow in on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Integer overflow in on line %d"), lineNumber(pInfo)); return NULL; } value = value + new_digit; if (isNeg && (uint64_t)INT64_MAX + 1 < value) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Integer underflow in on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Integer underflow in on line %d"), lineNumber(pInfo)); return NULL; } pInfo->curr++; @@ -1715,7 +1726,7 @@ static CFTypeRef parseXMLElement(_CFXMLPlistParseInfo *pInfo, Boolean *isKey) { if (markerLength == 0) { // Back up to the beginning of the marker pInfo->curr = marker; - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Malformed tag on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Malformed tag on line %d"), lineNumber(pInfo)); return NULL; } switch (*marker) { @@ -1767,14 +1778,14 @@ static CFTypeRef parseXMLElement(_CFXMLPlistParseInfo *pInfo, Boolean *isKey) { } if (!pInfo->allowNewTypes && markerIx != PLIST_IX && markerIx != ARRAY_IX && markerIx != DICT_IX && markerIx != STRING_IX && markerIx != KEY_IX && markerIx != DATA_IX) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered new tag when expecting only old-style property list objects")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered new tag when expecting only old-style property list objects")); return NULL; } switch (markerIx) { case PLIST_IX: if (isEmpty) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered empty plist tag")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered empty plist tag")); return NULL; } return parsePListTag(pInfo); @@ -1805,21 +1816,21 @@ static CFTypeRef parseXMLElement(_CFXMLPlistParseInfo *pInfo, Boolean *isKey) { str = getString(pInfo); if (!str) return NULL; // getString will already have set the error string if (!checkForCloseTag(pInfo, CFXMLPlistTags[markerIx], tagLen)) { - CFRelease(str); + __CFPListRelease(str, pInfo); return NULL; } return str; } case DATA_IX: if (isEmpty) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered empty on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered empty on line %d"), lineNumber(pInfo)); return NULL; } else { return parseDataTag(pInfo); } case DATE_IX: if (isEmpty) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered empty on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered empty on line %d"), lineNumber(pInfo)); return NULL; } else { return parseDateTag(pInfo); @@ -1836,14 +1847,14 @@ static CFTypeRef parseXMLElement(_CFXMLPlistParseInfo *pInfo, Boolean *isKey) { return CFRetain(kCFBooleanFalse); case REAL_IX: if (isEmpty) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered empty on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered empty on line %d"), lineNumber(pInfo)); return NULL; } else { return parseRealTag(pInfo); } case INTEGER_IX: if (isEmpty) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered empty on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered empty on line %d"), lineNumber(pInfo)); return NULL; } else { return parseIntegerTag(pInfo); @@ -1851,8 +1862,8 @@ static CFTypeRef parseXMLElement(_CFXMLPlistParseInfo *pInfo, Boolean *isKey) { default: { CFStringRef markerStr = CFStringCreateWithCharacters(pInfo->allocator, marker, markerLength); pInfo->curr = marker; - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unknown tag %@ on line %d"), markerStr, lineNumber(pInfo)); - CFRelease(markerStr); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unknown tag %@ on line %d"), markerStr, lineNumber(pInfo)); + __CFPListRelease(markerStr, pInfo); return NULL; } } @@ -1863,11 +1874,11 @@ static CFTypeRef parseXMLPropertyList(_CFXMLPlistParseInfo *pInfo) { UniChar ch; skipWhitespace(pInfo); if (pInfo->curr+1 >= pInfo->end) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("No XML content found")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("No XML content found")); return NULL; } if (*(pInfo->curr) != '<') { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Unexpected character %c at line %d"), *(pInfo->curr), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Unexpected character %c at line %d"), *(pInfo->curr), lineNumber(pInfo)); return NULL; } ch = *(++ pInfo->curr); @@ -1893,7 +1904,7 @@ static CFTypeRef parseXMLPropertyList(_CFXMLPlistParseInfo *pInfo) { } // Should never get here if (!(pInfo->error)) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unexpected EOF")); } return NULL; } @@ -1922,6 +1933,10 @@ static CFStringEncoding encodingForXMLData(CFDataRef data, CFErrorRef *error) { if ( ch == '?' || ch == '>') return kCFStringEncodingUTF8; idx ++; scan = idx; + if (idx + 8 >= end) { + if (error) *error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("End of buffer while looking for encoding name")); + return 0; + } if (ch == 'e' && *scan++ == 'n' && *scan++ == 'c' && *scan++ == 'o' && *scan++ == 'd' && *scan++ == 'i' && *scan++ == 'n' && *scan++ == 'g' && *scan++ == '=') { idx = scan; @@ -1950,7 +1965,7 @@ static CFStringEncoding encodingForXMLData(CFDataRef data, CFErrorRef *error) { } if (error) { - *error = __CFPropertyListCreateError(kCFAllocatorSystemDefault, kCFPropertyListReadCorruptError, CFSTR("Encountered unknown encoding (%@)"), encodingName); + *error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Encountered unknown encoding (%@)"), encodingName); CFRelease(encodingName); } return 0; @@ -2008,7 +2023,7 @@ CFTypeRef _CFPropertyListCreateFromXMLStringError(CFAllocatorRef allocator, CFSt if (!length) { if (error) { - *error = __CFPropertyListCreateError(allocator, kCFPropertyListReadCorruptError, CFSTR("Conversion of string failed. The string is empty.")); + *error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Conversion of string failed. The string is empty.")); } return NULL; } @@ -2021,11 +2036,12 @@ CFTypeRef _CFPropertyListCreateFromXMLStringError(CFAllocatorRef allocator, CFSt CFRetain(xmlString); UniChar *buf = (UniChar *)CFStringGetCharactersPtr(xmlString); - allocator = allocator ? allocator : __CFGetDefaultAllocator(); - CFRetain(allocator); - if (!buf) { - buf = (UniChar *)CFAllocatorAllocate(allocator, length * sizeof(UniChar), 0); + buf = (UniChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, length * sizeof(UniChar), 0); + if (!buf) { + out_of_memory_warning(); + return NULL; + } CFStringGetCharacters(xmlString, CFRangeMake(0, length), buf); createdBuffer = true; } @@ -2075,11 +2091,10 @@ CFTypeRef _CFPropertyListCreateFromXMLStringError(CFAllocatorRef allocator, CFSt } if (createdBuffer) { - CFAllocatorDeallocate(allocator, (void *)pInfo->begin); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, (void *)pInfo->begin); } - if (pInfo->stringSet) CFRelease(pInfo->stringSet); + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(pInfo->stringSet); if (pInfo->error) CFRelease(pInfo->error); - CFRelease(allocator); CFRelease(xmlString); return result; } @@ -2128,20 +2143,23 @@ CFTypeRef _CFPropertyListCreateFromXMLString(CFAllocatorRef allocator, CFStringR return result; } - /* Get a single value for a given key in a top-level dictionary in a property list. @param allocator The allocator to use. @param data The property list data. @param option Currently unused, set to 0. - @param key The key to search for in the top-level dictionary. If the top-level data structure is not a dictionary, the return value will be false. + @param keyPath The keyPath to search for in the property list. Keys are colon-separated. Indexes into arrays are specified with an integer (zero-based). @param value If the key is found and the parameter is non-NULL, this will be set to a reference to the value. It is the caller's responsibility to release the object. If no object is found, will be set to NULL. If this parameter is NULL, this function can be used to check for the existence of a key without creating it by just checking the return value. @param error If an error occurs, will be set to a valid CFErrorRef. It is the caller's responsibility to release this value. @return True if the key is found, false otherwise. */ -bool _CFPropertyListCreateSingleValue(CFAllocatorRef allocator, CFDataRef data, CFOptionFlags option, CFStringRef key, CFPropertyListRef *value, CFErrorRef *error) { +bool _CFPropertyListCreateSingleValue(CFAllocatorRef allocator, CFDataRef data, CFOptionFlags option, CFStringRef keyPath, CFPropertyListRef *value, CFErrorRef *error) { initStatics(); + if (!keyPath || CFStringGetLength(keyPath) == 0) { + return false; + } + uint8_t marker; CFBinaryPlistTrailer trailer; uint64_t offset; @@ -2151,39 +2169,76 @@ bool _CFPropertyListCreateSingleValue(CFAllocatorRef allocator, CFDataRef data, // First check to see if it is a binary property list if (8 <= datalen && __CFBinaryPlistGetTopLevelInfo(databytes, datalen, &marker, &offset, &trailer)) { - // Create a dictionary to cache objects in - CFMutableDictionaryRef objects = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); - _CFDictionarySetCapacity(objects, 1); - - // Look for the value in the top-level dictionary - uint64_t keyOffset, valueOffset; - result = __CFBinaryPlistGetOffsetForValueFromDictionary3(databytes, datalen, offset, &trailer, (CFTypeRef)key, &keyOffset, &valueOffset, false, objects); - - // value could be null if the caller wanted to check for the existence of a key but not bother creating it - if (result && value) { - CFPropertyListRef pl; + // Split up the key path + CFArrayRef keyPathArray = CFStringCreateArrayBySeparatingStrings(kCFAllocatorSystemDefaultGCRefZero, keyPath, CFSTR(":")); + uint64_t keyOffset, valueOffset = offset; + + // Create a dictionary to cache objects in + CFMutableDictionaryRef objects = CFDictionaryCreateMutable(kCFAllocatorSystemDefaultGCRefZero, 0, NULL, &kCFTypeDictionaryValueCallBacks); + CFIndex keyPathCount = CFArrayGetCount(keyPathArray); + _CFDictionarySetCapacity(objects, keyPathCount + 1); + + for (CFIndex i = 0; i < keyPathCount; i++) { + CFStringRef oneKey = (CFStringRef)CFArrayGetValueAtIndex(keyPathArray, i); + SInt32 intValue = CFStringGetIntValue(oneKey); + if ((intValue == 0 && CFStringCompare(CFSTR("0"), oneKey, 0) != kCFCompareEqualTo) || intValue == INT_MAX || intValue == INT_MIN) { + // Treat as a string key into a dictionary + result = __CFBinaryPlistGetOffsetForValueFromDictionary3(databytes, datalen, valueOffset, &trailer, (CFTypeRef)oneKey, &keyOffset, &valueOffset, false, objects); + } else { + // Treat as integer index into an array + result = __CFBinaryPlistGetOffsetForValueFromArray2(databytes, datalen, valueOffset, &trailer, intValue, &valueOffset, objects); + } + + if (!result) { + break; + } + } + + // value could be null if the caller wanted to check for the existence of a key but not bother creating it + if (result && value) { + CFPropertyListRef pl; result = __CFBinaryPlistCreateObject2(databytes, datalen, valueOffset, &trailer, allocator, option, objects, NULL, 0, &pl); if (result) { // caller's responsibility to release the created object *value = pl; } } - - CFRelease(objects); + + if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(keyPathArray); + if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(objects); } else { // Try an XML property list // Note: This is currently not any more efficient than grabbing the whole thing. This could be improved in the future. CFPropertyListRef plist = CFPropertyListCreateWithData(allocator, data, option, NULL, error); - if (!(*error) && plist && CFGetTypeID((CFTypeRef)plist) == dicttype) { - CFPropertyListRef pl = (CFPropertyListRef)CFDictionaryGetValue((CFDictionaryRef)plist, key); - if (pl) { - *value = pl; - // caller's responsibility to release the created object - CFRetain(*value); - result = true; - } + CFPropertyListRef nextObject = plist; + result = true; + + if (!(*error) && plist) { + CFArrayRef keyPathArray = CFStringCreateArrayBySeparatingStrings(kCFAllocatorSystemDefaultGCRefZero, keyPath, CFSTR(":")); + for (CFIndex i = 0; i < CFArrayGetCount(keyPathArray); i++) { + CFStringRef oneKey = (CFStringRef)CFArrayGetValueAtIndex(keyPathArray, i); + SInt32 intValue = CFStringGetIntValue(oneKey); + if (((intValue == 0 && CFStringCompare(CFSTR("0"), oneKey, 0) != kCFCompareEqualTo) || intValue == INT_MAX || intValue == INT_MIN) && CFGetTypeID((CFTypeRef)nextObject) == dicttype) { + // Treat as a string key into a dictionary + nextObject = (CFPropertyListRef)CFDictionaryGetValue((CFDictionaryRef)nextObject, oneKey); + } else if (CFGetTypeID((CFTypeRef)nextObject) == arraytype) { + // Treat as integer index into an array + nextObject = (CFPropertyListRef)CFArrayGetValueAtIndex((CFArrayRef)nextObject, intValue); + } else { + result = false; + break; + } + } + + if (result && nextObject && value) { + *value = nextObject; + // caller's responsibility to release the created object + CFRetain(*value); + } + + if (!_CFAllocatorIsGCRefZero(kCFAllocatorSystemDefaultGCRefZero)) CFRelease(keyPathArray); } - if (plist) CFRelease(plist); + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(plist); } return result; @@ -2196,7 +2251,7 @@ CFTypeRef _CFPropertyListCreateWithData(CFAllocatorRef allocator, CFDataRef data if (!data || CFDataGetLength(data) == 0) { if (error) { - *error = __CFPropertyListCreateError(allocator, kCFPropertyListReadCorruptError, CFSTR("Cannot parse a NULL or zero-length data")); + *error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Cannot parse a NULL or zero-length data")); } return NULL; } @@ -2211,9 +2266,6 @@ CFTypeRef _CFPropertyListCreateWithData(CFAllocatorRef allocator, CFDataRef data return plist; } - allocator = allocator ? allocator : __CFGetDefaultAllocator(); - CFRetain(allocator); - // Use our own error variable here so we can check it against NULL later CFErrorRef subError = NULL; encoding = encodingForXMLData(data, &subError); // 0 is an error return, NOT MacRoman. @@ -2223,10 +2275,13 @@ CFTypeRef _CFPropertyListCreateWithData(CFAllocatorRef allocator, CFDataRef data // Note that encodingForXMLData() will give us the right values for a standard plist, too. if (error && subError == NULL) { // encodingForXMLData didn't set an error, so we create a new one here - *error = __CFPropertyListCreateError(allocator, kCFPropertyListReadCorruptError, CFSTR("Could not determine the encoding of the XML data")); + *error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Could not determine the encoding of the XML data")); } else if (error && subError) { // give the caller the subError, they will release *error = subError; + } else if (!error && subError) { + // Release the error + CFRelease(subError); } return NULL; } @@ -2241,7 +2296,7 @@ CFTypeRef _CFPropertyListCreateWithData(CFAllocatorRef allocator, CFDataRef data plist = _CFPropertyListCreateFromXMLStringError(allocator, xmlString, option, error, allowNewTypes, format); if (xmlString) { - CFRelease(xmlString); + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(xmlString); xmlString = NULL; } @@ -2291,23 +2346,22 @@ CFDataRef CFPropertyListCreateData(CFAllocatorRef allocator, CFPropertyListRef p CFDataRef data = NULL; - allocator = allocator ? allocator : __CFGetDefaultAllocator(); - CFRetain(allocator); - - if (!CFPropertyListIsValid(propertyList, format)) { - CFLog(kCFLogLevelError, CFSTR("Property list invalid for format: %d"), format); - CFRelease(allocator); + CFStringRef validErr = NULL; + if (!_CFPropertyListIsValidWithErrorString(propertyList, format, &validErr)) { + CFLog(kCFLogLevelError, CFSTR("Property list invalid for format: %d (%@)"), format, validErr); + if (validErr) CFRelease(validErr); return NULL; } if (format == kCFPropertyListOpenStepFormat) { CFLog(kCFLogLevelError, CFSTR("Property list format kCFPropertyListOpenStepFormat not supported for writing")); - CFRelease(allocator); return NULL; } else if (format == kCFPropertyListXMLFormat_v1_0) { - data = _CFPropertyListCreateXMLData(kCFAllocatorSystemDefault, propertyList, true); + data = _CFPropertyListCreateXMLData(allocator, propertyList, true); } else if (format == kCFPropertyListBinaryFormat_v1_0) { - CFWriteStreamRef stream = CFWriteStreamCreateWithAllocatedBuffers(allocator, allocator); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS + // TODO: Is it more efficient to create a stream here or just use a mutable data? + CFWriteStreamRef stream = CFWriteStreamCreateWithAllocatedBuffers(kCFAllocatorSystemDefault, allocator); CFWriteStreamOpen(stream); CFIndex len = CFPropertyListWrite(propertyList, stream, format, options, error); if (0 < len) { @@ -2315,14 +2369,20 @@ CFDataRef CFPropertyListCreateData(CFAllocatorRef allocator, CFPropertyListRef p } CFWriteStreamClose(stream); CFRelease(stream); +#else + CFMutableDataRef dataForPlist = CFDataCreateMutable(allocator, 0); + __CFBinaryPlistWrite(propertyList, dataForPlist, 0, options, error); + return dataForPlist; +#endif } else { CFLog(kCFLogLevelError, CFSTR("Unknown format option")); } - CFRelease(allocator); return data; } +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS + CFIndex CFPropertyListWrite(CFPropertyListRef propertyList, CFWriteStreamRef stream, CFPropertyListFormat format, CFOptionFlags options, CFErrorRef *error) { initStatics(); CFAssert1(stream != NULL, __kCFLogAssertion, "%s(): NULL stream not allowed", __PRETTY_FUNCTION__); @@ -2333,8 +2393,10 @@ CFIndex CFPropertyListWrite(CFPropertyListRef propertyList, CFWriteStreamRef str CFAssert1(CFWriteStreamGetTypeID() == CFGetTypeID(stream), __kCFLogAssertion, "%s(): stream argument is not a write stream", __PRETTY_FUNCTION__); CFAssert1(kCFStreamStatusOpen == CFWriteStreamGetStatus(stream) || kCFStreamStatusWriting == CFWriteStreamGetStatus(stream), __kCFLogAssertion, "%s(): stream is not open", __PRETTY_FUNCTION__); - if (!CFPropertyListIsValid(propertyList, format)) { - CFLog(kCFLogLevelError, CFSTR("Property list invalid for format: %d"), format); + CFStringRef validErr = NULL; + if (!_CFPropertyListIsValidWithErrorString(propertyList, format, &validErr)) { + CFLog(kCFLogLevelError, CFSTR("Property list invalid for format: %d (%@)"), format, validErr); + if (validErr) CFRelease(validErr); return 0; } if (format == kCFPropertyListOpenStepFormat) { @@ -2348,7 +2410,8 @@ CFIndex CFPropertyListWrite(CFPropertyListRef propertyList, CFWriteStreamRef str while (0 < len) { CFIndex ret = CFWriteStreamWrite(stream, ptr, len); if (ret == 0) { - if (error) *error = __CFPropertyListCreateError(kCFAllocatorSystemDefault, kCFPropertyListWriteStreamError, CFSTR("Property list writing could not be completed because stream is full.")); + if (error) *error = __CFPropertyListCreateError(kCFPropertyListWriteStreamError, CFSTR("Property list writing could not be completed because stream is full.")); + CFRelease(data); return 0; } if (ret < 0) { @@ -2364,6 +2427,7 @@ CFIndex CFPropertyListWrite(CFPropertyListRef propertyList, CFWriteStreamRef str } CFRelease(underlyingError); } + CFRelease(data); return 0; } ptr += ret; @@ -2387,8 +2451,10 @@ CFIndex CFPropertyListWriteToStream(CFPropertyListRef propertyList, CFWriteStrea CFErrorRef error = NULL; // For backwards compatibility, we check the format parameter up front since these do not have CFError counterparts in the newer API - if (!CFPropertyListIsValid(propertyList, format)) { - if (errorString) *errorString = (CFStringRef)CFRetain(CFSTR("Property list invalid for format")); + CFStringRef validErr = NULL; + if (!_CFPropertyListIsValidWithErrorString(propertyList, format, &validErr)) { + if (errorString) *errorString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("Property list invalid for format (%@)"), validErr); + if (validErr) CFRelease(validErr); return 0; } if (format == kCFPropertyListOpenStepFormat) { @@ -2460,7 +2526,7 @@ CFPropertyListRef CFPropertyListCreateWithStream(CFAllocatorRef allocator, CFRea CFAssert1(kCFStreamStatusOpen == CFReadStreamGetStatus(stream) || kCFStreamStatusReading == CFReadStreamGetStatus(stream), __kCFLogAssertion, "%s(): stream is not open", __PRETTY_FUNCTION__); CFAssert2(mutabilityOption == kCFPropertyListImmutable || mutabilityOption == kCFPropertyListMutableContainers || mutabilityOption == kCFPropertyListMutableContainersAndLeaves, __kCFLogAssertion, "%s(): Unrecognized option %d", __PRETTY_FUNCTION__, mutabilityOption); - if (0 == streamLength) streamLength = INT_MAX; + if (0 == streamLength) streamLength = LONG_MAX; CFErrorRef underlyingError = NULL; __CFConvertReadStreamToBytes(stream, streamLength, &buffer, &buflen, &underlyingError); if (underlyingError) { @@ -2478,7 +2544,7 @@ CFPropertyListRef CFPropertyListCreateWithStream(CFAllocatorRef allocator, CFRea if (!buffer || buflen < 6) { if (buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, buffer); - if (error) *error = __CFPropertyListCreateError(allocator, kCFPropertyListReadCorruptError, CFSTR("stream had too few bytes")); + if (error) *error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("stream had too few bytes")); return NULL; } data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, buffer, buflen, kCFAllocatorSystemDefault); @@ -2499,6 +2565,8 @@ CFPropertyListRef CFPropertyListCreateFromStream(CFAllocatorRef allocator, CFRea return result; } +#endif //DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS + // ======================================================================== // @@ -2609,7 +2677,7 @@ static CFStringRef parseQuotedPlistString(_CFXMLPlistParseInfo *pInfo, UniChar q UniChar ch = *(pInfo->curr); if (ch == quote) break; if (ch == '\\') { - _catFromMarkToBuf(mark, pInfo->curr, &str, pInfo->allocator); + _catFromMarkToBuf(mark, pInfo->curr, &str, pInfo); pInfo->curr ++; ch = getSlashedChar(pInfo); CFStringAppendCharacters(str, &ch, 1); @@ -2620,26 +2688,24 @@ static CFStringRef parseQuotedPlistString(_CFXMLPlistParseInfo *pInfo, UniChar q } } if (pInfo->end <= pInfo->curr) { - if (str) CFRelease(str); + __CFPListRelease(str, pInfo); pInfo->curr = startMark; - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Unterminated quoted string starting on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Unterminated quoted string starting on line %d"), lineNumber(pInfo)); return NULL; } if (!str) { if (pInfo->mutabilityOption == kCFPropertyListMutableContainersAndLeaves) { - _catFromMarkToBuf(mark, pInfo->curr, &str, pInfo->allocator); + _catFromMarkToBuf(mark, pInfo->curr, &str, pInfo); } else { str = (CFMutableStringRef)_uniqueStringForCharacters(pInfo, mark, pInfo->curr-mark); - CFRetain(str); } } else { if (mark != pInfo->curr) { - _catFromMarkToBuf(mark, pInfo->curr, &str, pInfo->allocator); + _catFromMarkToBuf(mark, pInfo->curr, &str, pInfo); } if (pInfo->mutabilityOption != kCFPropertyListMutableContainersAndLeaves) { CFStringRef uniqueString = _uniqueStringForString(pInfo, str); - CFRetain(uniqueString); - CFRelease(str); + __CFPListRelease(str, pInfo); str = (CFMutableStringRef)uniqueString; } } @@ -2662,7 +2728,6 @@ static CFStringRef parseUnquotedPlistString(_CFXMLPlistParseInfo *pInfo) { if (pInfo->curr != mark) { if (pInfo->mutabilityOption != kCFPropertyListMutableContainersAndLeaves) { CFStringRef str = _uniqueStringForCharacters(pInfo, mark, pInfo->curr-mark); - CFRetain(str); return str; } else { CFMutableStringRef str = CFStringCreateMutable(pInfo->allocator, 0); @@ -2670,7 +2735,7 @@ static CFStringRef parseUnquotedPlistString(_CFXMLPlistParseInfo *pInfo) { return str; } } - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Unexpected EOF")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Unexpected EOF")); return NULL; } @@ -2679,7 +2744,7 @@ static CFStringRef parsePlistString(_CFXMLPlistParseInfo *pInfo, bool requireObj Boolean foundChar = advanceToNonSpace(pInfo); if (!foundChar) { if (requireObject) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Unexpected EOF while parsing string")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Unexpected EOF while parsing string")); } return NULL; } @@ -2691,7 +2756,7 @@ static CFStringRef parsePlistString(_CFXMLPlistParseInfo *pInfo, bool requireObj return parseUnquotedPlistString(pInfo); } else { if (requireObject) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Invalid string character at line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Invalid string character at line %d"), lineNumber(pInfo)); } return NULL; } @@ -2703,11 +2768,11 @@ static CFTypeRef parsePlistArray(_CFXMLPlistParseInfo *pInfo) { Boolean foundChar; while (tmp) { CFArrayAppendValue(array, tmp); - CFRelease(tmp); + __CFPListRelease(tmp, pInfo); foundChar = advanceToNonSpace(pInfo); if (!foundChar) { - CFRelease(array); - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Expected ',' for array at line %d"), lineNumber(pInfo)); + __CFPListRelease(array, pInfo); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Expected ',' for array at line %d"), lineNumber(pInfo)); return NULL; } if (*pInfo->curr != ',') { @@ -2719,8 +2784,8 @@ static CFTypeRef parsePlistArray(_CFXMLPlistParseInfo *pInfo) { } foundChar = advanceToNonSpace(pInfo); if (!foundChar || *pInfo->curr != ')') { - CFRelease(array); - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Expected terminating ')' for array at line %d"), lineNumber(pInfo)); + __CFPListRelease(array, pInfo); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Expected terminating ')' for array at line %d"), lineNumber(pInfo)); return NULL; } if (pInfo->error) { @@ -2742,7 +2807,7 @@ static CFDictionaryRef parsePlistDictContent(_CFXMLPlistParseInfo *pInfo) { if (!foundChar) { CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListCreateFromXMLData(): Unexpected end of file. Missing semicolon or value in dictionary.")); failedParse = true; - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Missing ';' on line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Missing ';' on line %d"), lineNumber(pInfo)); break; } @@ -2758,32 +2823,29 @@ static CFDictionaryRef parsePlistDictContent(_CFXMLPlistParseInfo *pInfo) { break; } } else { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Unexpected ';' or '=' after key at line %d"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Unexpected ';' or '=' after key at line %d"), lineNumber(pInfo)); failedParse = true; break; } CFDictionarySetValue(dict, key, value); - CFRelease(key); + __CFPListRelease(key, pInfo); key = NULL; - CFRelease(value); + __CFPListRelease(value, pInfo); value = NULL; foundChar = advanceToNonSpace(pInfo); if (foundChar && *pInfo->curr == ';') { pInfo->curr ++; key = parsePlistString(pInfo, false); - } else if ((!allowMissingSemi && _CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) || !foundChar) { + } else if (true || !foundChar) { CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListCreateFromXMLData(): Old-style plist parser: missing semicolon in dictionary.")); failedParse = true; - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Missing ';' on line %d"), lineNumber(pInfo)); - } else { - // on pre-Jaguar systems, do nothing except silently ignore the rest - // of the dictionary, which is what happened on those systems. + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Missing ';' on line %d"), lineNumber(pInfo)); } } if (failedParse) { - if (key) CFRelease(key); - CFRelease(dict); + __CFPListRelease(key, pInfo); + __CFPListRelease(dict, pInfo); return NULL; } if (pInfo->error) { @@ -2798,8 +2860,8 @@ static CFTypeRef parsePlistDict(_CFXMLPlistParseInfo *pInfo) { if (!dict) return NULL; Boolean foundChar = advanceToNonSpace(pInfo); if (!foundChar || *pInfo->curr != '}') { - CFRelease(dict); - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Expected terminating '}' for dictionary at line %d"), lineNumber(pInfo)); + __CFPListRelease(dict, pInfo); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Expected terminating '}' for dictionary at line %d"), lineNumber(pInfo)); return NULL; } pInfo->curr ++; @@ -2849,13 +2911,13 @@ static CFTypeRef parsePlistData(_CFXMLPlistParseInfo *pInfo) { unsigned char bytes[numBytes]; int numBytesRead = getDataBytes(pInfo, bytes, numBytes); if (numBytesRead < 0) { - CFRelease(result); + __CFPListRelease(result, pInfo); switch (numBytesRead) { case -2: - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Malformed data byte group at line %d; uneven length"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Malformed data byte group at line %d; uneven length"), lineNumber(pInfo)); break; default: - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Malformed data byte group at line %d; invalid hex"), lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Malformed data byte group at line %d; invalid hex"), lineNumber(pInfo)); break; } return NULL; @@ -2873,8 +2935,8 @@ static CFTypeRef parsePlistData(_CFXMLPlistParseInfo *pInfo) { pInfo->curr ++; // Move past '>' return result; } else { - CFRelease(result); - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Expected terminating '>' for data at line %d"), lineNumber(pInfo)); + __CFPListRelease(result, pInfo); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Expected terminating '>' for data at line %d"), lineNumber(pInfo)); return NULL; } } @@ -2886,7 +2948,7 @@ static CFTypeRef parsePlistObject(_CFXMLPlistParseInfo *pInfo, bool requireObjec Boolean foundChar = advanceToNonSpace(pInfo); if (!foundChar) { if (requireObject) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Unexpected EOF while parsing plist")); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Unexpected EOF while parsing plist")); } return NULL; } @@ -2906,7 +2968,7 @@ static CFTypeRef parsePlistObject(_CFXMLPlistParseInfo *pInfo, bool requireObjec } else { pInfo->curr --; // Must back off the charcter we just read if (requireObject) { - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Unexpected character '0x%x' at line %d"), ch, lineNumber(pInfo)); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Unexpected character '0x%x' at line %d"), ch, lineNumber(pInfo)); } return NULL; } @@ -2923,11 +2985,11 @@ static CFTypeRef parseOldStylePropertyListOrStringsFile(_CFXMLPlistParseInfo *pI if (!foundChar) return result; if (!result) return NULL; if (CFGetTypeID(result) != stringtype) { - CFRelease(result); - pInfo->error = __CFPropertyListCreateError(pInfo->allocator, kCFPropertyListReadCorruptError, CFSTR("Junk after plist at line %d"), lineNumber(pInfo)); + __CFPListRelease(result, pInfo); + pInfo->error = __CFPropertyListCreateError(kCFPropertyListReadCorruptError, CFSTR("Junk after plist at line %d"), lineNumber(pInfo)); return NULL; } - CFRelease(result); + __CFPListRelease(result, pInfo); // Check for a strings file (looks like a dictionary without the opening/closing curly braces) pInfo->curr = begin; return parsePlistDictContent(pInfo); @@ -2938,23 +3000,24 @@ static CFTypeRef parseOldStylePropertyListOrStringsFile(_CFXMLPlistParseInfo *pI static CFArrayRef _arrayDeepImmutableCopy(CFAllocatorRef allocator, CFArrayRef array, CFOptionFlags mutabilityOption) { CFArrayRef result = NULL; CFIndex i, c = CFArrayGetCount(array); - CFTypeRef *values; if (c == 0) { result = CFArrayCreate(allocator, NULL, 0, &kCFTypeArrayCallBacks); - } else if ((values = (CFTypeRef *)CFAllocatorAllocate(allocator, c*sizeof(CFTypeRef), 0)) != NULL) { + } else { + new_cftype_array(values, c); CFArrayGetValues(array, CFRangeMake(0, c), values); for (i = 0; i < c; i ++) { - values[i] = CFPropertyListCreateDeepCopy(allocator, values[i], mutabilityOption); - if (values[i] == NULL) { + CFTypeRef newValue = CFPropertyListCreateDeepCopy(allocator, values[i], mutabilityOption); + if (newValue == NULL) { break; } + __CFAssignWithWriteBarrier((void **)values + i, (void *)newValue); } result = (i == c) ? CFArrayCreate(allocator, values, c, &kCFTypeArrayCallBacks) : NULL; c = i; - for (i = 0; i < c; i ++) { - CFRelease(values[i]); + if (!_CFAllocatorIsGCRefZero(allocator)) { + for (i = 0; i < c; i ++) CFRelease(values[i]); } - CFAllocatorDeallocate(allocator, values); + free_cftype_array(values); } return result; } @@ -2967,10 +3030,10 @@ static CFMutableArrayRef _arrayDeepMutableCopy(CFAllocatorRef allocator, CFArray CFTypeRef newValue = CFPropertyListCreateDeepCopy(allocator, CFArrayGetValueAtIndex(array, i), mutabilityOption); if (!newValue) break; CFArrayAppendValue(result, newValue); - CFRelease(newValue); + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(newValue); } if (i != c) { - CFRelease(result); + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(result); result = NULL; } } @@ -2979,41 +3042,37 @@ static CFMutableArrayRef _arrayDeepMutableCopy(CFAllocatorRef allocator, CFArray CFPropertyListRef CFPropertyListCreateDeepCopy(CFAllocatorRef allocator, CFPropertyListRef propertyList, CFOptionFlags mutabilityOption) { initStatics(); - CFTypeID typeID; CFPropertyListRef result = NULL; CFAssert1(propertyList != NULL, __kCFLogAssertion, "%s(): cannot copy a NULL property list", __PRETTY_FUNCTION__); __CFAssertIsPList(propertyList); CFAssert2(mutabilityOption == kCFPropertyListImmutable || mutabilityOption == kCFPropertyListMutableContainers || mutabilityOption == kCFPropertyListMutableContainersAndLeaves, __kCFLogAssertion, "%s(): Unrecognized option %d", __PRETTY_FUNCTION__, mutabilityOption); if (!CFPropertyListIsValid(propertyList, kCFPropertyListBinaryFormat_v1_0)) return NULL; - if (allocator == NULL) { - allocator = (CFAllocatorRef)CFRetain(__CFGetDefaultAllocator()); - } else { - CFRetain(allocator); - } - - typeID = CFGetTypeID(propertyList); + CFTypeID typeID = CFGetTypeID(propertyList); if (typeID == dicttype) { CFDictionaryRef dict = (CFDictionaryRef)propertyList; Boolean isMutable = (mutabilityOption != kCFPropertyListImmutable); CFIndex count = CFDictionaryGetCount(dict); - CFTypeRef *keys, *values; if (count == 0) { result = isMutable ? CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks): CFDictionaryCreate(allocator, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - } else if ((keys = (CFTypeRef *)CFAllocatorAllocate(allocator, 2 * count * sizeof(CFTypeRef), 0)) != NULL) { + } else { + new_cftype_array(keys, 2 * count); + CFTypeRef *values; CFIndex i; values = keys+count; CFDictionaryGetKeysAndValues(dict, keys, values); for (i = 0; i < count; i ++) { - keys[i] = CFStringCreateCopy(allocator, (CFStringRef)keys[i]); - if (keys[i] == NULL) { + CFTypeRef newKey = CFStringCreateCopy(allocator, (CFStringRef)keys[i]); + if (newKey == NULL) { break; } - values[i] = CFPropertyListCreateDeepCopy(allocator, values[i], mutabilityOption); - if (values[i] == NULL) { - CFRelease(keys[i]); + __CFAssignWithWriteBarrier((void **)keys + i, (void *)newKey); + CFTypeRef newValue = CFPropertyListCreateDeepCopy(allocator, values[i], mutabilityOption); + if (newValue == NULL) { + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(keys[i]); break; } + __CFAssignWithWriteBarrier((void **)values + i, (void *)newValue); } if (i == count) { result = isMutable ? CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) : CFDictionaryCreate(allocator, keys, values, count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); @@ -3021,20 +3080,18 @@ CFPropertyListRef CFPropertyListCreateDeepCopy(CFAllocatorRef allocator, CFPrope if (isMutable) { CFDictionarySetValue((CFMutableDictionaryRef)result, keys[i], values[i]); } - CFRelease(keys[i]); - CFRelease(values[i]); + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(keys[i]); + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(values[i]); } } else { result = NULL; count = i; for (i = 0; i < count; i ++) { - CFRelease(keys[i]); - CFRelease(values[i]); + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(keys[i]); + if (!_CFAllocatorIsGCRefZero(allocator)) CFRelease(values[i]); } } - CFAllocatorDeallocate(allocator, keys); - } else { - result = NULL; + free_cftype_array(keys); } } else if (typeID == arraytype) { if (mutabilityOption == kCFPropertyListImmutable) { @@ -3071,7 +3128,6 @@ CFPropertyListRef CFPropertyListCreateDeepCopy(CFAllocatorRef allocator, CFPrope CFAssert2(false, __kCFLogAssertion, "%s(): %p is not a property list type", __PRETTY_FUNCTION__, propertyList); result = NULL; } - CFRelease(allocator); return result; } diff --git a/CFPropertyList.h b/CFPropertyList.h index 219dc7a..3d138da 100644 --- a/CFPropertyList.h +++ b/CFPropertyList.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFPropertyList.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFPROPERTYLIST__) @@ -31,7 +31,10 @@ #include #include #include +#include +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_EMBEDDED #include +#endif CF_EXTERN_C_BEGIN @@ -79,8 +82,6 @@ CFDataRef CFPropertyListCreateXMLData(CFAllocatorRef allocator, CFPropertyListRe CF_EXPORT CFPropertyListRef CFPropertyListCreateDeepCopy(CFAllocatorRef allocator, CFPropertyListRef propertyList, CFOptionFlags mutabilityOption); -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED - enum { kCFPropertyListOpenStepFormat = 1, kCFPropertyListXMLFormat_v1_0 = 100, @@ -96,6 +97,8 @@ typedef CFIndex CFPropertyListFormat; CF_EXPORT Boolean CFPropertyListIsValid(CFPropertyListRef plist, CFPropertyListFormat format); +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_EMBEDDED + /* Writes the bytes of a plist serialization out to the stream. The * stream must be opened and configured -- the function simply writes * a bunch of bytes to the stream. The output plist format can be chosen. @@ -126,7 +129,7 @@ CFPropertyListRef CFPropertyListCreateFromStream(CFAllocatorRef allocator, CFRea #endif -#if MAC_OS_X_VERSION_10_6 <= MAC_OS_X_VERSION_MAX_ALLOWED +#if MAC_OS_X_VERSION_10_6 <= MAC_OS_X_VERSION_MAX_ALLOWED || __IPHONE_4_0 <= __IPHONE_OS_VERSION_MAX_ALLOWED enum { kCFPropertyListReadCorruptError = 3840, // Error parsing a property list kCFPropertyListReadUnknownVersionError = 3841, // The version number in the property list is unknown @@ -138,22 +141,26 @@ enum { /* Create a property list with a CFData input. If the format parameter is non-NULL, it will be set to the format of the data after parsing is complete. The options parameter is used to specify CFPropertyListMutabilityOptions. If an error occurs while parsing the data, the return value will be NULL. Additionally, if an error occurs and the error parameter is non-NULL, the error parameter will be set to a CFError describing the problem, which the caller must release. If the parse succeeds, the returned value is a reference to the new property list. It is the responsibility of the caller to release this value. */ CF_EXPORT -CFPropertyListRef CFPropertyListCreateWithData(CFAllocatorRef allocator, CFDataRef data, CFOptionFlags options, CFPropertyListFormat *format, CFErrorRef *error) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CFPropertyListRef CFPropertyListCreateWithData(CFAllocatorRef allocator, CFDataRef data, CFOptionFlags options, CFPropertyListFormat *format, CFErrorRef *error) CF_AVAILABLE(10_6, 4_0); + +#if TARGET_OS_MAC || TARGET_OS_WIN32 || TARGET_OS_EMBEDDED /* Create and return a property list with a CFReadStream input. TIf the format parameter is non-NULL, it will be set to the format of the data after parsing is complete. The options parameter is used to specify CFPropertyListMutabilityOptions. The streamLength parameter specifies the number of bytes to read from the stream. Set streamLength to 0 to read until the end of the stream is detected. If an error occurs while parsing the data, the return value will be NULL. Additionally, if an error occurs and the error parameter is non-NULL, the error parameter will be set to a CFError describing the problem, which the caller must release. If the parse succeeds, the returned value is a reference to the new property list. It is the responsibility of the caller to release this value. */ CF_EXPORT -CFPropertyListRef CFPropertyListCreateWithStream(CFAllocatorRef allocator, CFReadStreamRef stream, CFIndex streamLength, CFOptionFlags options, CFPropertyListFormat *format, CFErrorRef *error) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CFPropertyListRef CFPropertyListCreateWithStream(CFAllocatorRef allocator, CFReadStreamRef stream, CFIndex streamLength, CFOptionFlags options, CFPropertyListFormat *format, CFErrorRef *error) CF_AVAILABLE(10_6, 4_0); /* Write the bytes of a serialized property list out to a stream. The stream must be opened and configured. The format of the property list can be chosen with the format parameter. The options parameter is currently unused and should be set to 0. The return value is the number of bytes written or 0 in the case of an error. If an error occurs and the error parameter is non-NULL, the error parameter will be set to a CFError describing the problem, which the caller must release. */ CF_EXPORT -CFIndex CFPropertyListWrite(CFPropertyListRef propertyList, CFWriteStreamRef stream, CFPropertyListFormat format, CFOptionFlags options, CFErrorRef *error) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CFIndex CFPropertyListWrite(CFPropertyListRef propertyList, CFWriteStreamRef stream, CFPropertyListFormat format, CFOptionFlags options, CFErrorRef *error) CF_AVAILABLE(10_6, 4_0); + +#endif /* Create a CFData with the bytes of a serialized property list. The format of the property list can be chosen with the format parameter. The options parameter is currently unused and should be set to 0. If an error occurs while parsing the data, the return value will be NULL. Additionally, if an error occurs and the error parameter is non-NULL, the error parameter will be set to a CFError describing the problem, which the caller must release. If the conversion succeeds, the returned value is a reference to the created data. It is the responsibility of the caller to release this value. */ CF_EXPORT -CFDataRef CFPropertyListCreateData(CFAllocatorRef allocator, CFPropertyListRef propertyList, CFPropertyListFormat format, CFOptionFlags options, CFErrorRef *error) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CFDataRef CFPropertyListCreateData(CFAllocatorRef allocator, CFPropertyListRef propertyList, CFPropertyListFormat format, CFOptionFlags options, CFErrorRef *error) CF_AVAILABLE(10_6, 4_0); CF_EXTERN_C_END diff --git a/CFRunLoop.c b/CFRunLoop.c index d38b717..f035f51 100644 --- a/CFRunLoop.c +++ b/CFRunLoop.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFRunLoop.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. - Responsibility: Christopher Kane + Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Responsibility: Tony Parker */ #include @@ -33,8 +33,10 @@ #include #include #include -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#include #include +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#include #include #include #include @@ -44,7 +46,9 @@ extern mach_port_t _dispatch_get_main_queue_port_4CF(void); extern void _dispatch_main_queue_callback_4CF(mach_msg_header_t *msg); #else #include -#define __CFReadTSR() mach_absolute_time() +__private_extern__ LONGLONG __CFTSRToFiletime(int64_t tsr); +DISPATCH_EXPORT HANDLE _dispatch_get_main_queue_handle_4CF(void); +DISPATCH_EXPORT void _dispatch_main_queue_callback_4CF(void); #endif #include @@ -57,26 +61,10 @@ static int _LogCFRunLoop = 0; #define HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY 0 #if DEPLOYMENT_TARGET_WINDOWS + static pthread_t kNilPthreadT = { nil, nil }; #define pthreadPointer(a) a.p -static DWORD __CFTSDKeyRunLoopKey = ~0; - -// See function below. -bool gMARRY_MESSAGE_QUEUE = FALSE; -// -// vod __CFSetNonMachRunLoopMarryMsgQueueMode(bool bEnabled) -// -// This function will exist for a while until code is written -// by the WebKit folks to handle the new RunLoop message-queue -// model. -CF_EXPORT void __CFSetNonMachRunLoopMarryMsgQueueMode(bool bEnabled) { - gMARRY_MESSAGE_QUEUE = bEnabled; -} -bool __CFIsNonMachRunLoopMarryMsgQueueEnabled(void) { - return gMARRY_MESSAGE_QUEUE; -} - #else static pthread_t kNilPthreadT = (pthread_t)0; @@ -84,29 +72,6 @@ static pthread_t kNilPthreadT = (pthread_t)0; #define lockCount(a) a #endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -#include -#include - -typedef struct { - CFIndex version; - void * info; - const void *(*retain)(const void *info); - void (*release)(const void *info); - CFStringRef (*copyDescription)(const void *info); - Boolean (*equal)(const void *info1, const void *info2); - CFHashCode (*hash)(const void *info); - void (*perform)(const struct kevent *kev, void *info); - struct kevent event; -} CFRunLoopSourceContext2; - -// The bits in the flags field in the kevent structure are cleared except for EV_ONESHOT and EV_CLEAR. -// Do not use the udata field of the kevent structure -- that field is smashed by CFRunLoop. -// There is no way to EV_ENABLE or EV_DISABLE a kevent. -// The "autoinvalidation" of EV_ONESHOT is not handled properly by CFRunLoop yet. -// The "autoinvalidation" of EV_DELETE on the last close of a file descriptor is not handled properly by CFRunLoop yet. -// There is no way to reset the state in a kevent (such as clearing the EV_EOF state for fifos). -#endif CF_EXPORT bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict, const void *key, const void **actualkey); @@ -114,6 +79,93 @@ CF_EXPORT bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict, const void *key // simple abstraction layer spanning Mach ports and Windows HANDLES #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +__private_extern__ uint32_t __CFGetProcessPortCount(void) { + ipc_info_space_t info; + ipc_info_name_array_t table = 0; + mach_msg_type_number_t tableCount = 0; + ipc_info_tree_name_array_t tree = 0; + mach_msg_type_number_t treeCount = 0; + + kern_return_t ret = mach_port_space_info(mach_task_self(), &info, &table, &tableCount, &tree, &treeCount); + if (ret != KERN_SUCCESS) { + return (uint32_t)0; + } + if (table != NULL) { + ret = vm_deallocate(mach_task_self(), (vm_address_t)table, tableCount * sizeof(*table)); + } + if (tree != NULL) { + ret = vm_deallocate(mach_task_self(), (vm_address_t)tree, treeCount * sizeof(*tree)); + } + return (uint32_t)tableCount; +} + +__private_extern__ CFArrayRef __CFStopAllThreads(void) { + CFMutableArrayRef suspended_list = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, NULL); + mach_port_t my_task = mach_task_self(); + mach_port_t my_thread = mach_thread_self(); + thread_act_array_t thr_list = 0; + mach_msg_type_number_t thr_cnt = 0; + + // really, should loop doing the stopping until no more threads get added to the list N times in a row + kern_return_t ret = task_threads(my_task, &thr_list, &thr_cnt); + if (ret == KERN_SUCCESS) { + for (CFIndex idx = 0; idx < thr_cnt; idx++) { + thread_act_t thread = thr_list[idx]; + if (thread == my_thread) continue; + if (CFArrayContainsValue(suspended_list, CFRangeMake(0, CFArrayGetCount(suspended_list)), (const void *)(uintptr_t)thread)) continue; + ret = thread_suspend(thread); + if (ret == KERN_SUCCESS) { + CFArrayAppendValue(suspended_list, (const void *)(uintptr_t)thread); + } else { + mach_port_deallocate(my_task, thread); + } + } + vm_deallocate(my_task, (vm_address_t)thr_list, sizeof(thread_t) * thr_cnt); + } + mach_port_deallocate(my_task, my_thread); + return suspended_list; +} + +__private_extern__ void __CFRestartAllThreads(CFArrayRef threads) { + for (CFIndex idx = 0; idx < CFArrayGetCount(threads); idx++) { + thread_act_t thread = (thread_act_t)(uintptr_t)CFArrayGetValueAtIndex(threads, idx); + kern_return_t ret = thread_resume(thread); + if (ret != KERN_SUCCESS) HALT; + mach_port_deallocate(mach_task_self(), thread); + } +} + +static uint32_t __CF_last_warned_port_count = 0; + +static void foo() __attribute__((unused)); +static void foo() { + uint32_t pcnt = __CFGetProcessPortCount(); + if (__CF_last_warned_port_count + 1000 < pcnt) { + CFArrayRef threads = __CFStopAllThreads(); + + +// do stuff here +CFOptionFlags responseFlags = 0; +SInt32 result = CFUserNotificationDisplayAlert(0.0, kCFUserNotificationCautionAlertLevel, NULL, NULL, NULL, CFSTR("High Mach Port Usage"), CFSTR("This application is using a lot of Mach ports."), CFSTR("Default"), CFSTR("Altern"), CFSTR("Other b"), &responseFlags); +if (0 != result) { + CFLog(3, CFSTR("ERROR")); +} else { + switch (responseFlags) { + case kCFUserNotificationDefaultResponse: CFLog(3, CFSTR("DefaultR")); break; + case kCFUserNotificationAlternateResponse: CFLog(3, CFSTR("AltR")); break; + case kCFUserNotificationOtherResponse: CFLog(3, CFSTR("OtherR")); break; + case kCFUserNotificationCancelResponse: CFLog(3, CFSTR("CancelR")); break; + } +} + + + __CFRestartAllThreads(threads); + CFRelease(threads); + __CF_last_warned_port_count = pcnt; + } +} + + typedef mach_port_t __CFPort; #define CFPORT_NULL MACH_PORT_NULL typedef mach_port_t __CFPortSet; @@ -154,11 +206,17 @@ CF_INLINE __CFPortSet __CFPortSetAllocate(void) { } CF_INLINE Boolean __CFPortSetInsert(__CFPort port, __CFPortSet portSet) { + if (MACH_PORT_NULL == port) { + return false; + } kern_return_t ret = mach_port_insert_member(mach_task_self(), port, portSet); return (KERN_SUCCESS == ret); } CF_INLINE Boolean __CFPortSetRemove(__CFPort port, __CFPortSet portSet) { + if (MACH_PORT_NULL == port) { + return false; + } kern_return_t ret = mach_port_extract_member(mach_task_self(), port, portSet); return (KERN_SUCCESS == ret); } @@ -233,13 +291,17 @@ static __CFPort *__CFPortSetGetPorts(__CFPortSet portSet, __CFPort *portBuf, uin } static Boolean __CFPortSetInsert(__CFPort port, __CFPortSet portSet) { + if (NULL == port) { + return false; + } __CFSpinLock(&(portSet->lock)); if (portSet->used >= portSet->size) { portSet->size += 4; portSet->handles = (HANDLE *)CFAllocatorReallocate(kCFAllocatorSystemDefault, portSet->handles, portSet->size * sizeof(HANDLE), 0); } - if (portSet->used >= MAXIMUM_WAIT_OBJECTS) + if (portSet->used >= MAXIMUM_WAIT_OBJECTS) { CFLog(kCFLogLevelWarning, CFSTR("*** More than MAXIMUM_WAIT_OBJECTS (%d) ports add to a port set. The last ones will be ignored."), MAXIMUM_WAIT_OBJECTS); + } portSet->handles[portSet->used++] = port; __CFSpinUnlock(&(portSet->lock)); return true; @@ -247,6 +309,9 @@ static Boolean __CFPortSetInsert(__CFPort port, __CFPortSet portSet) { static Boolean __CFPortSetRemove(__CFPort port, __CFPortSet portSet) { int i, j; + if (NULL == port) { + return false; + } __CFSpinLock(&(portSet->lock)); for (i = 0; i < portSet->used; i++) { if (portSet->handles[i] == port) { @@ -264,6 +329,21 @@ static Boolean __CFPortSetRemove(__CFPort port, __CFPortSet portSet) { #endif +#if !defined(__MACTYPES__) && !defined(_OS_OSTYPES_H) +#if defined(__BIG_ENDIAN__) +typedef struct UnsignedWide { + UInt32 hi; + UInt32 lo; +} UnsignedWide; +#elif defined(__LITTLE_ENDIAN__) +typedef struct UnsignedWide { + UInt32 lo; + UInt32 hi; +} UnsignedWide; +#endif +typedef UnsignedWide AbsoluteTime; +#endif + #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED extern mach_port_name_t mk_timer_create(void); extern kern_return_t mk_timer_destroy(mach_port_name_t name); @@ -302,41 +382,39 @@ static CFTypeID __kCFRunLoopSourceTypeID = _kCFRuntimeNotATypeID; static CFTypeID __kCFRunLoopObserverTypeID = _kCFRuntimeNotATypeID; static CFTypeID __kCFRunLoopTimerTypeID = _kCFRuntimeNotATypeID; -#if DEPLOYMENT_TARGET_WINDOWS -// The MSG identifier for the Windows message injected in the message queue to wake the run loop -static unsigned int __kCFRunLoopWakeUpMessage = 0; -static unsigned int __kCFRunLoopV1SourceReadyMessage = 0; -#endif - typedef struct __CFRunLoopMode *CFRunLoopModeRef; struct __CFRunLoopMode { CFRuntimeBase _base; - CFSpinLock_t _lock; /* must have the run loop locked before locking this */ + pthread_mutex_t _lock; /* must have the run loop locked before locking this */ CFStringRef _name; Boolean _stopped; char _padding[3]; - CFMutableSetRef _sources; - CFMutableSetRef _observers; - CFMutableSetRef _timers; + CFMutableSetRef _sources0; + CFMutableSetRef _sources1; + CFMutableArrayRef _observers; + CFMutableArrayRef _timers; CFMutableDictionaryRef _portToV1SourceMap; - CFMutableArrayRef _submodes; // names of the submodes __CFPortSet _portSet; CFIndex _observerMask; #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - int _kq; + mach_port_t _timerPort; #endif #if DEPLOYMENT_TARGET_WINDOWS + HANDLE _timerPort; DWORD _msgQMask; + void (*_msgPump)(void); #endif }; CF_INLINE void __CFRunLoopModeLock(CFRunLoopModeRef rlm) { - __CFSpinLock(&(rlm->_lock)); + pthread_mutex_lock(&(rlm->_lock)); +// CFLog(6, CFSTR("__CFRunLoopModeLock locked %p"), rlm); } CF_INLINE void __CFRunLoopModeUnlock(CFRunLoopModeRef rlm) { - __CFSpinUnlock(&(rlm->_lock)); +// CFLog(6, CFSTR("__CFRunLoopModeLock unlocking %p"), rlm); + pthread_mutex_unlock(&(rlm->_lock)); } static Boolean __CFRunLoopModeEqual(CFTypeRef cf1, CFTypeRef cf2) { @@ -354,64 +432,59 @@ static CFStringRef __CFRunLoopModeCopyDescription(CFTypeRef cf) { CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf; CFMutableStringRef result; result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); + CFStringAppendFormat(result, NULL, CFSTR("{name = %@, "), rlm, CFGetAllocator(rlm), rlm->_name); + CFStringAppendFormat(result, NULL, CFSTR("port set = %p, "), rlm->_portSet); + CFStringAppendFormat(result, NULL, CFSTR("timer port = %p, "), rlm->_timerPort); #if DEPLOYMENT_TARGET_WINDOWS - CFStringAppendFormat(result, NULL, CFSTR("{name = %@, locked = %s, "), rlm, CFGetAllocator(rlm), rlm->_name, "unknown"); -#else - CFStringAppendFormat(result, NULL, CFSTR("{name = %@, locked = %s, "), rlm, CFGetAllocator(rlm), rlm->_name, lockCount(rlm->_lock) ? "true" : "false"); -#endif - CFStringAppendFormat(result, NULL, CFSTR("port set = %p,"), rlm->_portSet); -#if DEPLOYMENT_TARGET_WINDOWS - CFStringAppendFormat(result, NULL, CFSTR("MSGQ mask = %p,"), rlm->_msgQMask); + CFStringAppendFormat(result, NULL, CFSTR("MSGQ mask = %p, "), rlm->_msgQMask); #endif - CFStringAppendFormat(result, NULL, CFSTR("\n\tsources = %@,\n\tobservers = %@,\n\ttimers = %@\n},\n"), rlm->_sources, rlm->_observers, rlm->_timers); + CFStringAppendFormat(result, NULL, CFSTR("\n\tsources0 = %@,\n\tsources1 = %@,\n\tobservers = %@,\n\ttimers = %@\n},\n"), rlm->_sources0, rlm->_sources1, rlm->_observers, rlm->_timers); return result; } static void __CFRunLoopModeDeallocate(CFTypeRef cf) { CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf; - if (NULL != rlm->_sources) CFRelease(rlm->_sources); + if (NULL != rlm->_sources0) CFRelease(rlm->_sources0); + if (NULL != rlm->_sources1) CFRelease(rlm->_sources1); if (NULL != rlm->_observers) CFRelease(rlm->_observers); if (NULL != rlm->_timers) CFRelease(rlm->_timers); - if (NULL != rlm->_submodes) CFRelease(rlm->_submodes); if (NULL != rlm->_portToV1SourceMap) CFRelease(rlm->_portToV1SourceMap); CFRelease(rlm->_name); __CFPortSetFree(rlm->_portSet); #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - if (-1 != rlm->_kq) close(rlm->_kq); + if (MACH_PORT_NULL != rlm->_timerPort) mk_timer_destroy(rlm->_timerPort); +#elif DEPLOYMENT_TARGET_WINDOWS + if (NULL != rlm->_timerPort) CloseHandle(rlm->_timerPort); #endif + pthread_mutex_destroy(&rlm->_lock); memset((char *)cf + sizeof(CFRuntimeBase), 0x7C, sizeof(struct __CFRunLoopMode) - sizeof(CFRuntimeBase)); } struct _block_item { struct _block_item *_next; - CFTypeRef _mode; // CFString or CFSet or CFRunLoopTimer + CFTypeRef _mode; // CFString or CFSet void (^_block)(void); }; struct __CFRunLoop { CFRuntimeBase _base; - CFSpinLock_t _lock; /* locked for accessing mode list */ + pthread_mutex_t _lock; /* locked for accessing mode list */ __CFPort _wakeUpPort; // used for CFRunLoopWakeUp + Boolean _ignoreWakeUps; volatile uint32_t *_stopped; pthread_t _pthread; + uint32_t _winthread; CFMutableSetRef _commonModes; CFMutableSetRef _commonModeItems; CFRunLoopModeRef _currentMode; CFMutableSetRef _modes; struct _block_item *_blocks_head; struct _block_item *_blocks_tail; -#if DEPLOYMENT_TARGET_WINDOWS - DWORD _threadID; - __CFPort _msgUpdatePort; -#endif CFTypeRef _counterpart; }; #if DEPLOYMENT_TARGET_WINDOWS -void __CFRunLoopUpdateMsgWait(CFRunLoopRef rl); -void __CFRunLoopUpdateMsgWaitMarryMsgQueue(CFRunLoopRef rl); static Boolean __CFRunLoopDoSource1(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopSourceRef rls); -CF_EXPORT LRESULT CALLBACK pumpRunLoopFromMessageQueue(int nCode, WPARAM wParam, LPARAM lParam); #endif /* Bit 0 of the base reserved bits is used for stopped state */ @@ -458,11 +531,13 @@ CF_INLINE void __CFRunLoopSetDeallocating(CFRunLoopRef rl) { } CF_INLINE void __CFRunLoopLock(CFRunLoopRef rl) { - __CFSpinLock(&(((CFRunLoopRef)rl)->_lock)); + pthread_mutex_lock(&(((CFRunLoopRef)rl)->_lock)); +// CFLog(6, CFSTR("__CFRunLoopLock locked %p"), rl); } CF_INLINE void __CFRunLoopUnlock(CFRunLoopRef rl) { - __CFSpinUnlock(&(((CFRunLoopRef)rl)->_lock)); +// CFLog(6, CFSTR("__CFRunLoopLock unlocking %p"), rl); + pthread_mutex_unlock(&(((CFRunLoopRef)rl)->_lock)); } static CFStringRef __CFRunLoopCopyDescription(CFTypeRef cf) { @@ -470,9 +545,9 @@ static CFStringRef __CFRunLoopCopyDescription(CFTypeRef cf) { CFMutableStringRef result; result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); #if DEPLOYMENT_TARGET_WINDOWS - CFStringAppendFormat(result, NULL, CFSTR("{locked = %s, wakeup port = 0x%x, stopped = %s,\ncurrent mode = %@,\n"), cf, CFGetAllocator(cf), "unknown", rl->_wakeUpPort, (rl->_stopped && *(rl->_stopped)) ? "true" : "false", rl->_currentMode ? rl->_currentMode->_name : CFSTR("(none)")); + CFStringAppendFormat(result, NULL, CFSTR("{wakeup port = 0x%x, stopped = %s,\ncurrent mode = %@,\n"), cf, CFGetAllocator(cf), rl->_wakeUpPort, (rl->_stopped && *(rl->_stopped)) ? "true" : "false", rl->_currentMode ? rl->_currentMode->_name : CFSTR("(none)")); #else - CFStringAppendFormat(result, NULL, CFSTR("{locked = %s, wakeup port = 0x%x, stopped = %s,\ncurrent mode = %@,\n"), cf, CFGetAllocator(cf), lockCount(rl->_lock) ? "true" : "false", rl->_wakeUpPort, (rl->_stopped && (rl->_stopped[2] == 0x53544F50)) ? "true" : "false", rl->_currentMode ? rl->_currentMode->_name : CFSTR("(none)")); + CFStringAppendFormat(result, NULL, CFSTR("{wakeup port = 0x%x, stopped = %s,\ncurrent mode = %@,\n"), cf, CFGetAllocator(cf), rl->_wakeUpPort, (rl->_stopped && (rl->_stopped[2] == 0x53544F50)) ? "true" : "false", rl->_currentMode ? rl->_currentMode->_name : CFSTR("(none)")); #endif CFStringAppendFormat(result, NULL, CFSTR("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl->_commonModes, rl->_commonModeItems, rl->_modes); return result; @@ -482,6 +557,16 @@ __private_extern__ void __CFRunLoopDump() { // __private_extern__ to keep the co CFShow(CFCopyDescription(CFRunLoopGetCurrent())); } +CF_INLINE void __CFRunLoopLockInit(pthread_mutex_t *lock) { + pthread_mutexattr_t mattr; + pthread_mutexattr_init(&mattr); + pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE); + int32_t mret = pthread_mutex_init(lock, &mattr); + pthread_mutexattr_destroy(&mattr); + if (0 != mret) { + } +} + /* call with rl locked */ static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeName, Boolean create) { CHECK_FOR_FORK(); @@ -503,22 +588,27 @@ static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeNam if (NULL == rlm) { return NULL; } - CF_SPINLOCK_INIT_FOR_STRUCTS(rlm->_lock); + __CFRunLoopLockInit(&rlm->_lock); rlm->_name = CFStringCreateCopy(kCFAllocatorSystemDefault, modeName); rlm->_stopped = false; rlm->_portToV1SourceMap = NULL; - rlm->_sources = NULL; + rlm->_sources0 = NULL; + rlm->_sources1 = NULL; rlm->_observers = NULL; rlm->_timers = NULL; - rlm->_submodes = NULL; rlm->_observerMask = 0; rlm->_portSet = __CFPortSetAllocate(); - if (!__CFPortSetInsert(rl->_wakeUpPort, rlm->_portSet)) HALT; #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - rlm->_kq = -1; + rlm->_timerPort = mk_timer_create(); +#elif DEPLOYMENT_TARGET_WINDOWS + // We use a manual reset timer because it is possible that we will WaitForMultipleObjectsEx on the timer port but not service it on that run loop iteration. The event is reset when we handle the timers. + rlm->_timerPort = CreateWaitableTimer(NULL, TRUE, NULL); #endif -#if DEPLOYMENT_TARGET_WINDOWS + if (!__CFPortSetInsert(rlm->_timerPort, rlm->_portSet)) HALT; + if (!__CFPortSetInsert(rl->_wakeUpPort, rlm->_portSet)) HALT; +#if DEPLOYMENT_TARGET_WINDOWS rlm->_msgQMask = 0; + rlm->_msgPump = NULL; #endif CFSetAddValue(rl->_modes, rlm); CFRelease(rlm); @@ -534,13 +624,11 @@ static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFR #if DEPLOYMENT_TARGET_WINDOWS if (0 != rlm->_msgQMask) return false; #endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - Boolean libdispatchQSafe = pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == pthread_getspecific(__CFTSDKeyIsInGCDMainQ))); + Boolean libdispatchQSafe = pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ))); if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name)) return false; // represents the libdispatch main queue -#endif - if (NULL != rlm->_sources && 0 < CFSetGetCount(rlm->_sources)) return false; - if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) return false; -#if 1 + if (NULL != rlm->_sources0 && 0 < CFSetGetCount(rlm->_sources0)) return false; + if (NULL != rlm->_sources1 && 0 < CFSetGetCount(rlm->_sources1)) return false; + if (NULL != rlm->_timers && 0 < CFArrayGetCount(rlm->_timers)) return false; struct _block_item *item = rl->_blocks_head; while (item) { struct _block_item *curr = item; @@ -553,44 +641,79 @@ static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFR } if (doit) return false; } -#endif - if (NULL != rlm->_submodes) { - CFIndex idx, cnt; - for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) { - CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); - CFRunLoopModeRef subrlm; - Boolean subIsEmpty; - subrlm = __CFRunLoopFindMode(rl, modeName, false); - subIsEmpty = (NULL != subrlm) ? __CFRunLoopModeIsEmpty(rl, subrlm, previousMode) : true; - if (NULL != subrlm) __CFRunLoopModeUnlock(subrlm); - if (!subIsEmpty) return false; - } - } return true; } #if DEPLOYMENT_TARGET_WINDOWS -DWORD __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef modeName) { - CFRunLoopModeRef rlm; + +uint32_t _CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef modeName) { + if (modeName == kCFRunLoopCommonModes) { + CFLog(kCFLogLevelError, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported")); + HALT; + } DWORD result = 0; __CFRunLoopLock(rl); - rlm = __CFRunLoopFindMode(rl, modeName, false); + CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false); if (rlm) { result = rlm->_msgQMask; __CFRunLoopModeUnlock(rlm); } __CFRunLoopUnlock(rl); + return (uint32_t)result; +} + +void _CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, uint32_t mask, CFStringRef modeName) { + if (modeName == kCFRunLoopCommonModes) { + CFLog(kCFLogLevelError, CFSTR("_CFRunLoopSetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported")); + HALT; + } + __CFRunLoopLock(rl); + CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true); + rlm->_msgQMask = (DWORD)mask; + __CFRunLoopModeUnlock(rlm); + __CFRunLoopUnlock(rl); +} + +uint32_t _CFRunLoopGetWindowsThreadID(CFRunLoopRef rl) { + return rl->_winthread; +} + +CFWindowsMessageQueueHandler _CFRunLoopGetWindowsMessageQueueHandler(CFRunLoopRef rl, CFStringRef modeName) { + if (modeName == kCFRunLoopCommonModes) { + CFLog(kCFLogLevelError, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported")); + HALT; + } + if (rl != CFRunLoopGetCurrent()) { + CFLog(kCFLogLevelError, CFSTR("_CFRunLoopGetWindowsMessageQueueHandler: run loop parameter must be the current run loop")); + HALT; + } + void (*result)(void) = NULL; + __CFRunLoopLock(rl); + CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false); + if (rlm) { + result = rlm->_msgPump; + __CFRunLoopModeUnlock(rlm); + } + __CFRunLoopUnlock(rl); return result; } -void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, DWORD mask, CFStringRef modeName) { - CFRunLoopModeRef rlm; +void _CFRunLoopSetWindowsMessageQueueHandler(CFRunLoopRef rl, CFStringRef modeName, CFWindowsMessageQueueHandler func) { + if (modeName == kCFRunLoopCommonModes) { + CFLog(kCFLogLevelError, CFSTR("_CFRunLoopGetWindowsMessageQueueMask: kCFRunLoopCommonModes unsupported")); + HALT; + } + if (rl != CFRunLoopGetCurrent()) { + CFLog(kCFLogLevelError, CFSTR("_CFRunLoopGetWindowsMessageQueueHandler: run loop parameter must be the current run loop")); + HALT; + } __CFRunLoopLock(rl); - rlm = __CFRunLoopFindMode(rl, modeName, true); - rlm->_msgQMask = mask; + CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true); + rlm->_msgPump = func; __CFRunLoopModeUnlock(rlm); __CFRunLoopUnlock(rl); } + #endif /* Bit 3 in the base reserved bits is used for invalid state in run loop objects */ @@ -610,7 +733,7 @@ CF_INLINE void __CFUnsetValid(void *cf) { struct __CFRunLoopSource { CFRuntimeBase _base; uint32_t _bits; - CFSpinLock_t _lock; + pthread_mutex_t _lock; CFIndex _order; /* immutable */ CFMutableBagRef _runLoops; union { @@ -634,79 +757,19 @@ CF_INLINE void __CFRunLoopSourceUnsetSignaled(CFRunLoopSourceRef rls) { } CF_INLINE void __CFRunLoopSourceLock(CFRunLoopSourceRef rls) { - __CFSpinLock(&(rls->_lock)); + pthread_mutex_lock(&(rls->_lock)); +// CFLog(6, CFSTR("__CFRunLoopSourceLock locked %p"), rls); } CF_INLINE void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls) { - __CFSpinUnlock(&(rls->_lock)); -} - -/* rlm is not locked */ -static void __CFRunLoopSourceSchedule(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) { /* DOES CALLOUT */ -//printf("Scheduling source %p with mode %s in loop %p\n", rls, CFStringGetCStringPtr(rlm->_name, 0), rl); - __CFRunLoopSourceLock(rls); - if (NULL == rls->_runLoops) { - rls->_runLoops = CFBagCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeBagCallBacks); // sources retain run loops! - } - CFBagAddValue(rls->_runLoops, rl); - __CFRunLoopSourceUnlock(rls); // have to unlock before the callout -- cannot help clients with safety - if (0 == rls->_context.version0.version) { - if (NULL != rls->_context.version0.schedule) { - rls->_context.version0.schedule(rls->_context.version0.info, rl, rlm->_name); - } - } else if (1 == rls->_context.version0.version) { - __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */ - if (CFPORT_NULL != port) { - __CFPortSetInsert(port, rlm->_portSet); - } -#if DEPLOYMENT_TARGET_WINDOWS - __CFRunLoopLock(rl); - //#warning Bug here - if rl->_currentMode is NULL and rlm == the default mode, we should also update - if (rl->_currentMode == rlm) { - if (__CFIsNonMachRunLoopMarryMsgQueueEnabled()) - __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl); - else - __CFRunLoopUpdateMsgWait(rl); - } - __CFRunLoopUnlock(rl); -#endif - } +// CFLog(6, CFSTR("__CFRunLoopSourceLock unlocking %p"), rls); + pthread_mutex_unlock(&(rls->_lock)); } -/* rlm is not locked */ -static void __CFRunLoopSourceCancel(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) { /* DOES CALLOUT */ -//printf("Cancelling source %p from mode %s in loop %p\n", rls, CFStringGetCStringPtr(rlm->_name, 0), rl); - __CFRunLoopSourceLock(rls); - if (NULL != rls->_runLoops) { - CFBagRemoveValue(rls->_runLoops, rl); - } - __CFRunLoopSourceUnlock(rls); - if (0 == rls->_context.version0.version) { - if (NULL != rls->_context.version0.cancel) { - rls->_context.version0.cancel(rls->_context.version0.info, rl, rlm->_name); /* CALLOUT */ - } - } else if (1 == rls->_context.version0.version) { - __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */ - if (CFPORT_NULL != port) { - __CFPortSetRemove(port, rlm->_portSet); - } -#if DEPLOYMENT_TARGET_WINDOWS - __CFRunLoopLock(rl); - //#warning Bug here - must also update if rl->_currentMode == NULL and rlm == default mode - if (rl->_currentMode == rlm && rl->_msgUpdatePort != CFPORT_NULL) { - if (__CFIsNonMachRunLoopMarryMsgQueueEnabled()) - __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl); - else - __CFRunLoopUpdateMsgWait(rl); - } - __CFRunLoopUnlock(rl); -#endif - } -} struct __CFRunLoopObserver { CFRuntimeBase _base; - CFSpinLock_t _lock; + pthread_mutex_t _lock; CFRunLoopRef _runLoop; CFIndex _rlCount; CFOptionFlags _activities; /* immutable */ @@ -743,11 +806,13 @@ CF_INLINE void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo) { } CF_INLINE void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo) { - __CFSpinLock(&(rlo->_lock)); + pthread_mutex_lock(&(rlo->_lock)); +// CFLog(6, CFSTR("__CFRunLoopObserverLock locked %p"), rlo); } CF_INLINE void __CFRunLoopObserverUnlock(CFRunLoopObserverRef rlo) { - __CFSpinUnlock(&(rlo->_lock)); +// CFLog(6, CFSTR("__CFRunLoopObserverLock unlocking %p"), rlo); + pthread_mutex_unlock(&(rlo->_lock)); } static void __CFRunLoopObserverSchedule(CFRunLoopObserverRef rlo, CFRunLoopRef rl, CFRunLoopModeRef rlm) { @@ -770,20 +835,13 @@ static void __CFRunLoopObserverCancel(CFRunLoopObserverRef rlo, CFRunLoopRef rl, struct __CFRunLoopTimer { CFRuntimeBase _base; - CFSpinLock_t _lock; + uint16_t _bits; + pthread_mutex_t _lock; CFRunLoopRef _runLoop; CFMutableSetRef _rlModes; CFAbsoluteTime _nextFireDate; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - mach_port_name_t _port; - int64_t _fireTSR; /* TSR units */ - int64_t _intervalTSR; /* immutable; 0 means non-repeating; TSR units */ -#elif DEPLOYMENT_TARGET_WINDOWS - CFIndex _rlCount; - int64_t _fireTSR; /* TSR units */ - int64_t _intervalTSR; /* immutable; 0 means non-repeating; TSR units */ -#endif CFTimeInterval _interval; /* immutable */ + int64_t _fireTSR; /* TSR units */ CFIndex _order; /* immutable */ CFRunLoopTimerCallBack _callout; /* immutable */ CFRunLoopTimerContext _context; /* immutable, except invalidation */ @@ -793,43 +851,33 @@ struct __CFRunLoopTimer { /* Bit 1 of the base reserved bits is used for fired-during-callout state */ CF_INLINE Boolean __CFRunLoopTimerIsFiring(CFRunLoopTimerRef rlt) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0); + return (Boolean)__CFBitfieldGetValue(rlt->_bits, 0, 0); } CF_INLINE void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt) { - __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0, 1); + __CFBitfieldSetValue(rlt->_bits, 0, 0, 1); } CF_INLINE void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt) { - __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0, 0); -} - -CF_INLINE Boolean __CFRunLoopTimerDidFire(CFRunLoopTimerRef rlt) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1); -} - -CF_INLINE void __CFRunLoopTimerSetDidFire(CFRunLoopTimerRef rlt) { - __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1, 1); -} - -CF_INLINE void __CFRunLoopTimerUnsetDidFire(CFRunLoopTimerRef rlt) { - __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1, 0); + __CFBitfieldSetValue(rlt->_bits, 0, 0, 0); } CF_INLINE Boolean __CFRunLoopTimerIsDeallocating(CFRunLoopTimerRef rlt) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 2, 2); + return (Boolean)__CFBitfieldGetValue(rlt->_bits, 2, 2); } CF_INLINE void __CFRunLoopTimerSetDeallocating(CFRunLoopTimerRef rlt) { - __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 2, 2, 1); + __CFBitfieldSetValue(rlt->_bits, 2, 2, 1); } CF_INLINE void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt) { - __CFSpinLock(&(rlt->_lock)); + pthread_mutex_lock(&(rlt->_lock)); +// CFLog(6, CFSTR("__CFRunLoopTimerLock locked %p"), rlt); } CF_INLINE void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt) { - __CFSpinUnlock(&(rlt->_lock)); +// CFLog(6, CFSTR("__CFRunLoopTimerLock unlocking %p"), rlt); + pthread_mutex_unlock(&(rlt->_lock)); } static CFSpinLock_t __CFRLTFireTSRLock = CFSpinLockInit; @@ -842,77 +890,6 @@ CF_INLINE void __CFRunLoopTimerFireTSRUnlock(void) { __CFSpinUnlock(&__CFRLTFireTSRLock); } -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -static CFMutableDictionaryRef __CFRLTPortMap = NULL; -static CFSpinLock_t __CFRLTPortMapLock = CFSpinLockInit; - -CF_INLINE void __CFRunLoopTimerPortMapLock(void) { - __CFSpinLock(&__CFRLTPortMapLock); -} - -CF_INLINE void __CFRunLoopTimerPortMapUnlock(void) { - __CFSpinUnlock(&__CFRLTPortMapLock); -} -#endif - -static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt); - -// called with timer locked in libdispatch mode -static void __CFRunLoopTimerRescheduleWithAllModes(CFRunLoopTimerRef rlt) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - mk_timer_arm(rlt->_port, __CFUInt64ToAbsoluteTime(rlt->_fireTSR)); -#endif -} - -static void __CFRunLoopTimerSchedule(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRunLoopModeRef rlm) { -//CFLog(4, CFSTR("__CFRunLoopTimerSchedule(%p, loop %p, mode %@) [%p, %p]"), rlt, rl, rlm->_name, rlt->_runLoop, rlt->_port); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - __CFRunLoopTimerLock(rlt); - if (NULL == rlt->_runLoop) { - rlt->_runLoop = rl; - if (MACH_PORT_NULL == rlt->_port) { - rlt->_port = mk_timer_create(); - } - __CFRunLoopTimerPortMapLock(); - if (NULL == __CFRLTPortMap) { - __CFRLTPortMap = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); - } - CFDictionarySetValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port, rlt); - __CFRunLoopTimerPortMapUnlock(); - __CFRunLoopTimerRescheduleWithAllModes(rlt); - } - mach_port_insert_member(mach_task_self(), rlt->_port, rlm->_portSet); - CFSetAddValue(rlt->_rlModes, rlm->_name); - __CFRunLoopTimerUnlock(rlt); -#elif DEPLOYMENT_TARGET_WINDOWS - if (0 == rlt->_rlCount) { - rlt->_runLoop = rl; - } - rlt->_rlCount++; -#endif -} - -static void __CFRunLoopTimerCancel(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRunLoopModeRef rlm) { -//CFLog(6, CFSTR("__CFRunLoopTimerCancel(rlt %p, rl %p, rlm %@)"), rlt, rl, rlm->_name); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - __CFRunLoopTimerLock(rlt); - CFSetRemoveValue(rlt->_rlModes, rlm->_name); - __CFPortSetRemove(rlt->_port, rlm->_portSet); - if (0 == CFSetGetCount(rlt->_rlModes)) { - __CFRunLoopTimerPortMapLock(); - if (NULL != __CFRLTPortMap) { - CFDictionaryRemoveValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port); - } - __CFRunLoopTimerPortMapUnlock(); - mk_timer_cancel(rlt->_port, NULL); - rlt->_runLoop = NULL; - } - __CFRunLoopTimerUnlock(rlt); -#elif DEPLOYMENT_TARGET_WINDOWS - CFRunLoopWakeUp(rl); -#endif -} - #if DEPLOYMENT_TARGET_WINDOWS struct _collectTimersContext { @@ -932,31 +909,20 @@ static void __CFRunLoopCollectTimers(const void *value, void *ctx) { // RunLoop and RunLoopMode must be locked static void __CFRunLoopTimersToFireRecursive(CFRunLoopRef rl, CFRunLoopModeRef rlm, struct _collectTimersContext *ctxt) { - if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) { - __CFRunLoopTimerFireTSRLock(); - CFSetApplyFunction(rlm->_timers, __CFRunLoopCollectTimers, ctxt); - __CFRunLoopTimerFireTSRUnlock(); - } - if (NULL != rlm->_submodes) { - CFIndex idx, cnt; - for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) { - CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); - CFRunLoopModeRef subrlm; - subrlm = __CFRunLoopFindMode(rl, modeName, false); - if (NULL != subrlm) { - __CFRunLoopTimersToFireRecursive(rl, subrlm, ctxt); - __CFRunLoopModeUnlock(subrlm); - } - } + __CFRunLoopTimerFireTSRLock(); + if (NULL != rlm->_timers && 0 < CFArrayGetCount(rlm->_timers)) { + CFArrayApplyFunction(rlm->_timers, CFRangeMake(0, CFArrayGetCount(rlm->_timers)), __CFRunLoopCollectTimers, ctxt); } + __CFRunLoopTimerFireTSRUnlock(); } // RunLoop and RunLoopMode must be locked static CFArrayRef __CFRunLoopTimersToFire(CFRunLoopRef rl, CFRunLoopModeRef rlm) { - struct _collectTimersContext ctxt = {NULL, __CFReadTSR()}; + struct _collectTimersContext ctxt = {NULL, mach_absolute_time()}; __CFRunLoopTimersToFireRecursive(rl, rlm, &ctxt); return ctxt.results; } + #endif /* CFRunLoop */ @@ -968,38 +934,9 @@ CONST_STRING_DECL(kCFRunLoopCommonModes, "kCFRunLoopCommonModes") static CFRunLoopSourceRef __CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl, CFRunLoopModeRef rlm, __CFPort port) { /* DOES CALLOUT */ CHECK_FOR_FORK(); CFRunLoopSourceRef found = rlm->_portToV1SourceMap ? (CFRunLoopSourceRef)CFDictionaryGetValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)port) : NULL; - if (NULL == found && NULL != rlm->_submodes) { - CFIndex idx, cnt; - for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) { - CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); - CFRunLoopModeRef subrlm; - subrlm = __CFRunLoopFindMode(rl, modeName, false); - if (NULL != subrlm) { - found = __CFRunLoopModeFindSourceForMachPort(rl, subrlm, port); - __CFRunLoopModeUnlock(subrlm); - } - if (NULL != found) { - break; - } - } - } return found; } -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -// call with rl and rlm locked -static CFRunLoopTimerRef __CFRunLoopModeFindTimerForMachPort(CFRunLoopModeRef rlm, __CFPort port) { - CHECK_FOR_FORK(); - CFRunLoopTimerRef result = NULL; - __CFRunLoopTimerPortMapLock(); - if (NULL != __CFRLTPortMap) { - result = (CFRunLoopTimerRef)CFDictionaryGetValue(__CFRLTPortMap, (void *)(uintptr_t)port); - } - __CFRunLoopTimerPortMapUnlock(); - return result; -} -#endif - // Remove backreferences the mode's sources have to the rl (context); // the primary purpose of rls->_runLoops is so that Invalidation can remove // the source from the run loops it is in, but during deallocation of a @@ -1011,10 +948,12 @@ static void __CFRunLoopCleanseSources(const void *value, void *context) { CFRunLoopRef rl = (CFRunLoopRef)context; CFIndex idx, cnt; const void **list, *buffer[256]; - if (NULL == rlm->_sources) return; - cnt = CFSetGetCount(rlm->_sources); + if (NULL == rlm->_sources0 && NULL == rlm->_sources1) return; + + cnt = (rlm->_sources0 ? CFSetGetCount(rlm->_sources0) : 0) + (rlm->_sources1 ? CFSetGetCount(rlm->_sources1) : 0); list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0)); - CFSetGetValues(rlm->_sources, list); + if (rlm->_sources0) CFSetGetValues(rlm->_sources0, list); + if (rlm->_sources1) CFSetGetValues(rlm->_sources1, list + (rlm->_sources0 ? CFSetGetCount(rlm->_sources0) : 0)); for (idx = 0; idx < cnt; idx++) { CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx]; __CFRunLoopSourceLock(rls); @@ -1031,17 +970,35 @@ static void __CFRunLoopDeallocateSources(const void *value, void *context) { CFRunLoopRef rl = (CFRunLoopRef)context; CFIndex idx, cnt; const void **list, *buffer[256]; - if (NULL == rlm->_sources) return; - cnt = CFSetGetCount(rlm->_sources); + if (NULL == rlm->_sources0 && NULL == rlm->_sources1) return; + + cnt = (rlm->_sources0 ? CFSetGetCount(rlm->_sources0) : 0) + (rlm->_sources1 ? CFSetGetCount(rlm->_sources1) : 0); list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0)); - CFSetGetValues(rlm->_sources, list); + if (rlm->_sources0) CFSetGetValues(rlm->_sources0, list); + if (rlm->_sources1) CFSetGetValues(rlm->_sources1, list + (rlm->_sources0 ? CFSetGetCount(rlm->_sources0) : 0)); for (idx = 0; idx < cnt; idx++) { CFRetain(list[idx]); } - CFSetRemoveAllValues(rlm->_sources); + if (rlm->_sources0) CFSetRemoveAllValues(rlm->_sources0); + if (rlm->_sources1) CFSetRemoveAllValues(rlm->_sources1); for (idx = 0; idx < cnt; idx++) { - __CFRunLoopSourceCancel((CFRunLoopSourceRef)list[idx], rl, rlm); - CFRelease(list[idx]); + CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx]; + __CFRunLoopSourceLock(rls); + if (NULL != rls->_runLoops) { + CFBagRemoveValue(rls->_runLoops, rl); + } + __CFRunLoopSourceUnlock(rls); + if (0 == rls->_context.version0.version) { + if (NULL != rls->_context.version0.cancel) { + rls->_context.version0.cancel(rls->_context.version0.info, rl, rlm->_name); /* CALLOUT */ + } + } else if (1 == rls->_context.version0.version) { + __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */ + if (CFPORT_NULL != port) { + __CFPortSetRemove(port, rlm->_portSet); + } + } + CFRelease(rls); } if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); } @@ -1052,13 +1009,13 @@ static void __CFRunLoopDeallocateObservers(const void *value, void *context) { CFIndex idx, cnt; const void **list, *buffer[256]; if (NULL == rlm->_observers) return; - cnt = CFSetGetCount(rlm->_observers); + cnt = CFArrayGetCount(rlm->_observers); list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0)); - CFSetGetValues(rlm->_observers, list); + CFArrayGetValues(rlm->_observers, CFRangeMake(0, cnt), list); for (idx = 0; idx < cnt; idx++) { CFRetain(list[idx]); } - CFSetRemoveAllValues(rlm->_observers); + CFArrayRemoveAllValues(rlm->_observers); for (idx = 0; idx < cnt; idx++) { __CFRunLoopObserverCancel((CFRunLoopObserverRef)list[idx], rl, rlm); CFRelease(list[idx]); @@ -1068,19 +1025,25 @@ static void __CFRunLoopDeallocateObservers(const void *value, void *context) { static void __CFRunLoopDeallocateTimers(const void *value, void *context) { CFRunLoopModeRef rlm = (CFRunLoopModeRef)value; - CFRunLoopRef rl = (CFRunLoopRef)context; CFIndex idx, cnt; const void **list, *buffer[256]; if (NULL == rlm->_timers) return; - cnt = CFSetGetCount(rlm->_timers); + cnt = CFArrayGetCount(rlm->_timers); list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0)); - CFSetGetValues(rlm->_timers, list); + CFArrayGetValues(rlm->_timers, CFRangeMake(0, CFArrayGetCount(rlm->_timers)), list); for (idx = 0; idx < cnt; idx++) { CFRetain(list[idx]); } - CFSetRemoveAllValues(rlm->_timers); + CFArrayRemoveAllValues(rlm->_timers); for (idx = 0; idx < cnt; idx++) { - __CFRunLoopTimerCancel((CFRunLoopTimerRef)list[idx], rl, rlm); + CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)list[idx]; + __CFRunLoopTimerLock(rlt); + // if the run loop is deallocating, and since a timer can only be in one + // run loop, we're going to be removing the timer from all modes, so be + // a little heavy-handed and direct + CFSetRemoveAllValues(rlt->_rlModes); + rlt->_runLoop = NULL; + __CFRunLoopTimerUnlock(rlt); CFRelease(list[idx]); } if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); @@ -1129,11 +1092,8 @@ static void __CFRunLoopDeallocate(CFTypeRef cf) { } __CFPortFree(rl->_wakeUpPort); rl->_wakeUpPort = CFPORT_NULL; -#if DEPLOYMENT_TARGET_WINDOWS - __CFPortFree(rl->_msgUpdatePort); - rl->_msgUpdatePort = CFPORT_NULL; -#endif __CFRunLoopUnlock(rl); + pthread_mutex_destroy(&rl->_lock); memset((char *)cf + sizeof(CFRuntimeBase), 0x8C, sizeof(struct __CFRunLoop) - sizeof(CFRuntimeBase)); } @@ -1161,21 +1121,14 @@ static const CFRuntimeClass __CFRunLoopClass = { __CFRunLoopCopyDescription }; -static void __CFFinalizeRunLoop(uintptr_t data); +__private_extern__ void __CFFinalizeRunLoop(uintptr_t data); + +static int64_t tenus = 0LL; __private_extern__ void __CFRunLoopInitialize(void) { + tenus = __CFTimeIntervalToTSR(0.000010000); __kCFRunLoopTypeID = _CFRuntimeRegisterClass(&__CFRunLoopClass); __kCFRunLoopModeTypeID = _CFRuntimeRegisterClass(&__CFRunLoopModeClass); -#if DEPLOYMENT_TARGET_WINDOWS - __kCFRunLoopWakeUpMessage = RegisterWindowMessageW((LPCWSTR)L"CFRunLoopWakeup"); - __kCFRunLoopV1SourceReadyMessage = RegisterWindowMessageW((LPCWSTR)L"CFRunLoopV1Ready"); -#endif -#if DEPLOYMENT_TARGET_WINDOWS - if (~0 == __CFTSDKeyRunLoopKey) __CFTSDKeyRunLoopKey = TlsAlloc(); -#else - pthread_key_init_np(__CFTSDKeyRunLoop, NULL); - pthread_key_init_np(__CFTSDKeyRunLoopCntr, (void *)__CFFinalizeRunLoop); -#endif } CFTypeID CFRunLoopGetTypeID(void) { @@ -1191,22 +1144,24 @@ static CFRunLoopRef __CFRunLoopCreate(pthread_t t) { return NULL; } loop->_stopped = NULL; - CF_SPINLOCK_INIT_FOR_STRUCTS(loop->_lock); + __CFRunLoopLockInit(&loop->_lock); loop->_wakeUpPort = __CFPortAllocate(); if (CFPORT_NULL == loop->_wakeUpPort) HALT; -#if DEPLOYMENT_TARGET_WINDOWS - loop->_msgUpdatePort = CFPORT_NULL; -#endif + loop->_ignoreWakeUps = true; loop->_commonModes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); CFSetAddValue(loop->_commonModes, kCFRunLoopDefaultMode); loop->_commonModeItems = NULL; loop->_currentMode = NULL; loop->_modes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); - _CFSetSetCapacity(loop->_modes, 10); loop->_blocks_head = NULL; loop->_blocks_tail = NULL; loop->_counterpart = NULL; loop->_pthread = t; +#if DEPLOYMENT_TARGET_WINDOWS + loop->_winthread = GetCurrentThreadId(); +#else + loop->_winthread = 0; +#endif rlm = __CFRunLoopFindMode(loop, kCFRunLoopDefaultMode, true); if (NULL != rlm) __CFRunLoopModeUnlock(rlm); return loop; @@ -1246,27 +1201,10 @@ CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) { CFRelease(newLoop); } if (pthread_equal(t, pthread_self())) { -#if DEPLOYMENT_TARGET_WINDOWS - TlsSetValue(__CFTSDKeyRunLoopKey, (LPVOID)(PTHREAD_DESTRUCTOR_ITERATIONS-1)); -#else - pthread_setspecific(__CFTSDKeyRunLoop, (void *)loop); - if (0 == pthread_getspecific(__CFTSDKeyRunLoopCntr)) { - pthread_setspecific(__CFTSDKeyRunLoopCntr, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS-1)); - } -#endif -#if DEPLOYMENT_TARGET_WINDOWS - // Install our message hook so we can spin the runloop - loop->_threadID = GetCurrentThreadId(); - //#if MARRY_MESSAGE_QUEUE - if (__CFIsNonMachRunLoopMarryMsgQueueEnabled()) { -#ifdef _DEBUG - __CFGetThreadSpecificData_inline()->_messageHook = SetWindowsHookExW(WH_GETMESSAGE, (HOOKPROC)pumpRunLoopFromMessageQueue, GetModuleHandleW((LPCWSTR)L"CoreFoundation_debug.dll"), loop->_threadID); -#else - __CFGetThreadSpecificData_inline()->_messageHook = SetWindowsHookExW(WH_GETMESSAGE, (HOOKPROC)pumpRunLoopFromMessageQueue, GetModuleHandleW((LPCWSTR)L"CoreFoundation.dll"), loop->_threadID); -#endif + _CFSetTSD(__CFTSDKeyRunLoop, (void *)loop, NULL); + if (0 == _CFGetTSD(__CFTSDKeyRunLoopCntr)) { + _CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS-1), (void (*)(void *))__CFFinalizeRunLoop); } - //#endif -#endif } __CFSpinUnlock(&loopsLock); return loop; @@ -1289,7 +1227,7 @@ CFRunLoopRef _CFRunLoopGet0b(pthread_t t) { static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName); // Called for each thread as it exits -static void __CFFinalizeRunLoop(uintptr_t data) { +__private_extern__ void __CFFinalizeRunLoop(uintptr_t data) { CFRunLoopRef rl = NULL; if (data <= 1) { __CFSpinLock(&loopsLock); @@ -1300,11 +1238,7 @@ static void __CFFinalizeRunLoop(uintptr_t data) { } __CFSpinUnlock(&loopsLock); } else { -#if DEPLOYMENT_TARGET_WINDOWS - TlsSetValue(__CFTSDKeyRunLoopKey, (LPVOID)(data - 1)); -#else - pthread_setspecific(__CFTSDKeyRunLoopCntr, (void *)(data - 1)); -#endif + _CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(data - 1), (void (*)(void *))__CFFinalizeRunLoop); } if (rl && CFRunLoopGetMain() != rl) { // protect against cooperative threads if (NULL != rl->_counterpart) { @@ -1331,18 +1265,6 @@ pthread_t _CFRunLoopGet1(CFRunLoopRef rl) { CF_EXPORT CFTypeRef _CFRunLoopGet2(CFRunLoopRef rl) { CFTypeRef ret = NULL; __CFSpinLock(&loopsLock); - if (NULL == rl->_counterpart) { - Class cls = (Class)objc_lookUpClass("NSRunLoop"); - if (cls) { - char hasMethod; - CF_OBJC_CALL1(char, hasMethod, cls, "respondsToSelector:", sel_registerName("_new:")); - if (hasMethod) { - void *ns; - CF_OBJC_CALL1(void *, ns, cls, "_new:", rl); - rl->_counterpart = ns ? CFRetain(ns) : NULL; - } - } - } ret = rl->_counterpart; __CFSpinUnlock(&loopsLock); return ret; @@ -1367,8 +1289,8 @@ void _CFRunLoopSetCurrent(CFRunLoopRef rl) { } __CFSpinUnlock(&loopsLock); CFRelease(currentLoop); - pthread_setspecific(__CFTSDKeyRunLoop, NULL); - pthread_setspecific(__CFTSDKeyRunLoopCntr, 0); + _CFSetTSD(__CFTSDKeyRunLoop, NULL, NULL); + _CFSetTSD(__CFTSDKeyRunLoopCntr, 0, (void (*)(void *))__CFFinalizeRunLoop); } } #endif @@ -1382,10 +1304,8 @@ CFRunLoopRef CFRunLoopGetMain(void) { CFRunLoopRef CFRunLoopGetCurrent(void) { CHECK_FOR_FORK(); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - CFRunLoopRef rl = (CFRunLoopRef)pthread_getspecific(__CFTSDKeyRunLoop); + CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop); if (rl) return rl; -#endif return _CFRunLoopGet0(pthread_self()); } @@ -1469,7 +1389,6 @@ void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef modeName) { if (!CFSetContainsValue(rl->_commonModes, modeName)) { CFSetRef set = rl->_commonModeItems ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModeItems) : NULL; CFSetAddValue(rl->_commonModes, modeName); - __CFRunLoopUnlock(rl); if (NULL != set) { CFTypeRef context[2] = {rl, modeName}; /* add all common-modes items to new mode */ @@ -1477,24 +1396,50 @@ void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef modeName) { CFRelease(set); } } else { - __CFRunLoopUnlock(rl); } + __CFRunLoopUnlock(rl); +} + + +static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__() __attribute__((noinline)); +static void __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(CFRunLoopObserverCallBack func, CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info) { + if (func) { + func(observer, activity, info); + } + getpid(); // thwart tail-call optimization +} + +static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__() __attribute__((noinline)); +static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(CFRunLoopTimerCallBack func, CFRunLoopTimerRef timer, void *info) { + if (func) { + func(timer, info); + } + getpid(); // thwart tail-call optimization +} + +static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__() __attribute__((noinline)); +static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(void (^block)(void)) { + if (block) { + block(); + } + getpid(); // thwart tail-call optimization } -static Boolean __CFRunLoopDoBlocks(CFRunLoopRef rl, CFStringRef curMode) { // Call with rl locked +static Boolean __CFRunLoopDoBlocks(CFRunLoopRef rl, CFRunLoopModeRef rlm) { // Call with rl and rlm locked if (!rl->_blocks_head) return false; - if (!curMode) return false; + if (!rlm || !rlm->_name) return false; Boolean did = false; - CFAbsoluteTime deadline = CFAbsoluteTimeGetCurrent() + 0.0009765625; struct _block_item *head = rl->_blocks_head; struct _block_item *tail = rl->_blocks_tail; rl->_blocks_head = NULL; rl->_blocks_tail = NULL; CFSetRef commonModes = rl->_commonModes; + CFStringRef curMode = rlm->_name; + __CFRunLoopModeUnlock(rlm); __CFRunLoopUnlock(rl); struct _block_item *prev = NULL; struct _block_item *item = head; - while (item && CFAbsoluteTimeGetCurrent() < deadline) { + while (item) { struct _block_item *curr = item; item = item->_next; Boolean doit = false; @@ -1512,13 +1457,14 @@ static Boolean __CFRunLoopDoBlocks(CFRunLoopRef rl, CFStringRef curMode) { // Ca CFRelease(curr->_mode); free(curr); if (doit) { - block(); // rl is not locked, mode is not locked + __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__(block); did = true; } Block_release(block); // do this before relocking to prevent deadlocks where some yahoo wants to run the run loop reentrantly from their dealloc } } __CFRunLoopLock(rl); + __CFRunLoopModeLock(rlm); if (head) { tail->_next = rl->_blocks_head; rl->_blocks_head = head; @@ -1527,92 +1473,52 @@ static Boolean __CFRunLoopDoBlocks(CFRunLoopRef rl, CFStringRef curMode) { // Ca return did; } -static CFComparisonResult __CFRunLoopObserverQSortComparator(const void *val1, const void *val2, void *context) { - CFRunLoopObserverRef o1 = *((CFRunLoopObserverRef *)val1); - CFRunLoopObserverRef o2 = *((CFRunLoopObserverRef *)val2); - if (!o1) { - return (!o2) ? kCFCompareEqualTo : kCFCompareLessThan; +/* rl is locked, rlm is locked on entrance and exit */ +static void __CFRunLoopDoObservers() __attribute__((noinline)); +static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity) { /* DOES CALLOUT */ + CHECK_FOR_FORK(); + + CFIndex cnt = rlm->_observers ? CFArrayGetCount(rlm->_observers) : 0; + if (cnt < 1) return; + + /* Fire the observers */ + STACK_BUFFER_DECL(CFRunLoopObserverRef, buffer, (cnt <= 1024) ? cnt : 1); + CFRunLoopObserverRef *collectedObservers = (cnt <= 1024) ? buffer : (CFRunLoopObserverRef *)malloc(cnt * sizeof(CFRunLoopObserverRef)); + CFIndex obs_cnt = 0; + for (CFIndex idx = 0; idx < cnt; idx++) { + CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)CFArrayGetValueAtIndex(rlm->_observers, idx); + if (0 != (rlo->_activities & activity) && __CFIsValid(rlo) && !__CFRunLoopObserverIsFiring(rlo)) { + collectedObservers[obs_cnt++] = (CFRunLoopObserverRef)CFRetain(rlo); + } } - if (!o2) { - return kCFCompareGreaterThan; + __CFRunLoopModeUnlock(rlm); + __CFRunLoopUnlock(rl); + for (CFIndex idx = 0; idx < obs_cnt; idx++) { + CFRunLoopObserverRef rlo = collectedObservers[idx]; + __CFRunLoopObserverLock(rlo); + if (__CFIsValid(rlo)) { + Boolean doInvalidate = !__CFRunLoopObserverRepeats(rlo); + __CFRunLoopObserverSetFiring(rlo); + __CFRunLoopObserverUnlock(rlo); + __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__(rlo->_callout, rlo, activity, rlo->_context.info); + if (doInvalidate) { + CFRunLoopObserverInvalidate(rlo); + } + __CFRunLoopObserverUnsetFiring(rlo); + } else { + __CFRunLoopObserverUnlock(rlo); + } + CFRelease(rlo); } - if (o1->_order < o2->_order) return kCFCompareLessThan; - if (o2->_order < o1->_order) return kCFCompareGreaterThan; - return kCFCompareEqualTo; -} - - -/* rl is unlocked, rlm is locked on entrance and exit */ -/* ALERT: this should collect all the candidate observers from the top level - * and all submodes, recursively, THEN start calling them, in order to obey - * the ordering parameter. */ -static void __CFRunLoopDoObservers(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopActivity activity) { /* DOES CALLOUT */ - CHECK_FOR_FORK(); - CFIndex idx, cnt; - CFArrayRef submodes; - - /* Fire the observers */ - submodes = (NULL != rlm->_submodes && 0 < CFArrayGetCount(rlm->_submodes)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault, rlm->_submodes) : NULL; - if (NULL != rlm->_observers) { - cnt = CFSetGetCount(rlm->_observers); - if (0 < cnt) { - STACK_BUFFER_DECL(CFRunLoopObserverRef, buffer, (cnt <= 1024) ? cnt : 1); - CFRunLoopObserverRef *collectedObservers = (CFRunLoopObserverRef *)((cnt <= 1024) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(CFRunLoopObserverRef), 0)); - CFSetGetValues(rlm->_observers, (const void **)collectedObservers); - for (idx = 0; idx < cnt; idx++) { - CFRunLoopObserverRef rlo = collectedObservers[idx]; - if (0 != (rlo->_activities & activity) && __CFIsValid(rlo) && !__CFRunLoopObserverIsFiring(rlo)) { - CFRetain(rlo); - } else { - /* We're not interested in this one - set it to NULL so we don't process it later */ - collectedObservers[idx] = NULL; - } - } - __CFRunLoopModeUnlock(rlm); - CFQSortArray(collectedObservers, cnt, sizeof(CFRunLoopObserverRef), __CFRunLoopObserverQSortComparator, NULL); - for (idx = 0; idx < cnt; idx++) { - CFRunLoopObserverRef rlo = collectedObservers[idx]; - if (rlo) { - __CFRunLoopObserverLock(rlo); - if (__CFIsValid(rlo)) { - __CFRunLoopObserverUnlock(rlo); - __CFRunLoopObserverSetFiring(rlo); - rlo->_callout(rlo, activity, rlo->_context.info); /* CALLOUT */ - __CFRunLoopObserverUnsetFiring(rlo); - if (!__CFRunLoopObserverRepeats(rlo)) { - CFRunLoopObserverInvalidate(rlo); - } - } else { - __CFRunLoopObserverUnlock(rlo); - } - CFRelease(rlo); - } - } - __CFRunLoopModeLock(rlm); - if (collectedObservers != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, collectedObservers); - } - } - if (NULL != submodes) { - __CFRunLoopModeUnlock(rlm); - for (idx = 0, cnt = CFArrayGetCount(submodes); idx < cnt; idx++) { - CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(submodes, idx); - CFRunLoopModeRef subrlm; - __CFRunLoopLock(rl); - subrlm = __CFRunLoopFindMode(rl, modeName, false); - __CFRunLoopUnlock(rl); - if (NULL != subrlm) { - __CFRunLoopDoObservers(rl, subrlm, activity); - __CFRunLoopModeUnlock(subrlm); - } - } - CFRelease(submodes); - __CFRunLoopModeLock(rlm); - } -} - -static CFComparisonResult __CFRunLoopSourceComparator(const void *val1, const void *val2, void *context) { - CFRunLoopSourceRef o1 = (CFRunLoopSourceRef)val1; - CFRunLoopSourceRef o2 = (CFRunLoopSourceRef)val2; + __CFRunLoopLock(rl); + __CFRunLoopModeLock(rlm); + + if (collectedObservers != buffer) free(collectedObservers); +} + +static CFComparisonResult __CFRunLoopSourceComparator(const void *val1, const void *val2, void *context) { + CFRunLoopSourceRef o1 = (CFRunLoopSourceRef)val1; + CFRunLoopSourceRef o2 = (CFRunLoopSourceRef)val2; if (o1->_order < o2->_order) return kCFCompareLessThan; if (o2->_order < o1->_order) return kCFCompareGreaterThan; return kCFCompareEqualTo; @@ -1636,94 +1542,97 @@ static void __CFRunLoopCollectSources0(const void *value, void *context) { } } -/* rl is unlocked, rlm is locked on entrance and exit */ +static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__() __attribute__((noinline)); +static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(void (*perform)(void *), void *info) { + if (perform) { + perform(info); + } + getpid(); // thwart tail-call optimization +} + +static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__() __attribute__((noinline)); +static void __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__( +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + void *(*perform)(void *msg, CFIndex size, CFAllocatorRef allocator, void *info), + mach_msg_header_t *msg, CFIndex size, mach_msg_header_t **reply, +#else + void (*perform)(void *), +#endif + void *info) { + if (perform) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + *reply = perform(msg, size, kCFAllocatorSystemDefault, info); +#else + perform(info); +#endif + } + getpid(); // thwart tail-call optimization +} + +/* rl is locked, rlm is locked on entrance and exit */ +static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) __attribute__((noinline)); static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) { /* DOES CALLOUT */ CHECK_FOR_FORK(); CFTypeRef sources = NULL; Boolean sourceHandled = false; - CFIndex idx, cnt; - __CFRunLoopModeUnlock(rlm); // locks have to be taken in order - __CFRunLoopLock(rl); - __CFRunLoopModeLock(rlm); /* Fire the version 0 sources */ - if (NULL != rlm->_sources && 0 < CFSetGetCount(rlm->_sources)) { - CFSetApplyFunction(rlm->_sources, (__CFRunLoopCollectSources0), &sources); - } - for (idx = 0, cnt = (NULL != rlm->_submodes) ? CFArrayGetCount(rlm->_submodes) : 0; idx < cnt; idx++) { - CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); - CFRunLoopModeRef subrlm; - subrlm = __CFRunLoopFindMode(rl, modeName, false); - if (NULL != subrlm) { - if (NULL != subrlm->_sources && 0 < CFSetGetCount(subrlm->_sources)) { - CFSetApplyFunction(subrlm->_sources, (__CFRunLoopCollectSources0), &sources); - } - __CFRunLoopModeUnlock(subrlm); - } + if (NULL != rlm->_sources0 && 0 < CFSetGetCount(rlm->_sources0)) { + CFSetApplyFunction(rlm->_sources0, (__CFRunLoopCollectSources0), &sources); } - __CFRunLoopUnlock(rl); if (NULL != sources) { - // sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef __CFRunLoopModeUnlock(rlm); + __CFRunLoopUnlock(rl); + // sources is either a single (retained) CFRunLoopSourceRef or an array of (retained) CFRunLoopSourceRef if (CFGetTypeID(sources) == __kCFRunLoopSourceTypeID) { CFRunLoopSourceRef rls = (CFRunLoopSourceRef)sources; __CFRunLoopSourceLock(rls); -#if DEPLOYMENT_TARGET_WINDOWS if (__CFRunLoopSourceIsSignaled(rls)) { -#endif - __CFRunLoopSourceUnsetSignaled(rls); - if (__CFIsValid(rls)) { - __CFRunLoopSourceUnlock(rls); - if (NULL != rls->_context.version0.perform) { - rls->_context.version0.perform(rls->_context.version0.info); /* CALLOUT */ - CHECK_FOR_FORK(); - } - sourceHandled = true; - } else { - __CFRunLoopSourceUnlock(rls); - } -#if DEPLOYMENT_TARGET_WINDOWS + __CFRunLoopSourceUnsetSignaled(rls); + if (__CFIsValid(rls)) { + __CFRunLoopSourceUnlock(rls); + __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(rls->_context.version0.perform, rls->_context.version0.info); + CHECK_FOR_FORK(); + sourceHandled = true; + } else { + __CFRunLoopSourceUnlock(rls); + } } else { __CFRunLoopSourceUnlock(rls); } -#endif } else { - cnt = CFArrayGetCount((CFArrayRef)sources); + CFIndex cnt = CFArrayGetCount((CFArrayRef)sources); CFArraySortValues((CFMutableArrayRef)sources, CFRangeMake(0, cnt), (__CFRunLoopSourceComparator), NULL); - for (idx = 0; idx < cnt; idx++) { + for (CFIndex idx = 0; idx < cnt; idx++) { CFRunLoopSourceRef rls = (CFRunLoopSourceRef)CFArrayGetValueAtIndex((CFArrayRef)sources, idx); __CFRunLoopSourceLock(rls); -#if DEPLOYMENT_TARGET_WINDOWS if (__CFRunLoopSourceIsSignaled(rls)) { -#endif - __CFRunLoopSourceUnsetSignaled(rls); - if (__CFIsValid(rls)) { - __CFRunLoopSourceUnlock(rls); - if (NULL != rls->_context.version0.perform) { - rls->_context.version0.perform(rls->_context.version0.info); /* CALLOUT */ + __CFRunLoopSourceUnsetSignaled(rls); + if (__CFIsValid(rls)) { + __CFRunLoopSourceUnlock(rls); + __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__(rls->_context.version0.perform, rls->_context.version0.info); CHECK_FOR_FORK(); + sourceHandled = true; + } else { + __CFRunLoopSourceUnlock(rls); } - sourceHandled = true; - } else { - __CFRunLoopSourceUnlock(rls); - } -#if DEPLOYMENT_TARGET_WINDOWS } else { __CFRunLoopSourceUnlock(rls); } -#endif if (stopAfterHandle && sourceHandled) { break; } } } CFRelease(sources); + __CFRunLoopLock(rl); __CFRunLoopModeLock(rlm); } return sourceHandled; } // msg, size and reply are unused on Windows +static Boolean __CFRunLoopDoSource1() __attribute__((noinline)); static Boolean __CFRunLoopDoSource1(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopSourceRef rls #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED , mach_msg_header_t *msg, CFIndex size, mach_msg_header_t **reply @@ -1735,41 +1644,112 @@ static Boolean __CFRunLoopDoSource1(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRun /* Fire a version 1 source */ CFRetain(rls); __CFRunLoopModeUnlock(rlm); + __CFRunLoopUnlock(rl); __CFRunLoopSourceLock(rls); if (__CFIsValid(rls)) { __CFRunLoopSourceUnsetSignaled(rls); __CFRunLoopSourceUnlock(rls); - if (NULL != rls->_context.version1.perform) { + __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__(rls->_context.version1.perform, #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - *reply = rls->_context.version1.perform(msg, size, kCFAllocatorSystemDefault, rls->_context.version1.info); /* CALLOUT */ - CHECK_FOR_FORK(); -#else - if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 performing rls %p"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls); } - rls->_context.version1.perform(rls->_context.version1.info); /* CALLOUT */ - CHECK_FOR_FORK(); + msg, size, reply, #endif - } else { - if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 perform is NULL"), CFRunLoopGetCurrent(), *_CFGetProgname()); } - } + rls->_context.version1.info); + CHECK_FOR_FORK(); sourceHandled = true; } else { if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 rls %p is invalid"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls); } __CFRunLoopSourceUnlock(rls); } CFRelease(rls); + __CFRunLoopLock(rl); __CFRunLoopModeLock(rlm); return sourceHandled; } -// mode is locked on entry and exit +static CFIndex __CFRunLoopInsertionIndexInTimerArray(CFArrayRef array, CFRunLoopTimerRef rlt) __attribute__((noinline)); +static CFIndex __CFRunLoopInsertionIndexInTimerArray(CFArrayRef array, CFRunLoopTimerRef rlt) { + CFIndex cnt = CFArrayGetCount(array); + if (cnt <= 0) { + return 0; + } + if (256 < cnt) { + CFRunLoopTimerRef item = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(array, cnt - 1); + if (item->_fireTSR <= rlt->_fireTSR) { + return cnt; + } + item = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(array, 0); + if (rlt->_fireTSR < item->_fireTSR) { + return 0; + } + } + + CFIndex add = (1 << flsl(cnt)) * 2; + CFIndex idx = 0; + Boolean lastTestLEQ; + do { + add = add / 2; + lastTestLEQ = false; + CFIndex testIdx = idx + add; + if (testIdx < cnt) { + CFRunLoopTimerRef item = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(array, testIdx); + if (item->_fireTSR <= rlt->_fireTSR) { + idx = testIdx; + lastTestLEQ = true; + } + } + } while (0 < add); + + return lastTestLEQ ? idx + 1 : idx; +} + +// call with rlm and its run loop locked, and the TSRLock locked; rlt not locked; returns with same state +static void __CFRepositionTimerInMode(CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt, Boolean isInArray) __attribute__((noinline)); +static void __CFRepositionTimerInMode(CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt, Boolean isInArray) { + if (!rlt || !rlm->_timers) return; + Boolean found = false; + if (isInArray) { + CFIndex idx = CFArrayGetFirstIndexOfValue(rlm->_timers, CFRangeMake(0, CFArrayGetCount(rlm->_timers)), rlt); + if (kCFNotFound != idx) { + CFRetain(rlt); + CFArrayRemoveValueAtIndex(rlm->_timers, idx); + found = true; + } + } + if (!found && isInArray) return; + CFIndex newIdx = __CFRunLoopInsertionIndexInTimerArray(rlm->_timers, rlt); + CFArrayInsertValueAtIndex(rlm->_timers, newIdx, rlt); + CFRunLoopTimerRef nextTimer = NULL; + for (CFIndex idx = 0, cnt = CFArrayGetCount(rlm->_timers); idx < cnt; idx++) { + CFRunLoopTimerRef t = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(rlm->_timers, idx); + if (!__CFRunLoopTimerIsFiring(t)) { + nextTimer = t; + break; + } + } + if (nextTimer) { + int64_t fireTSR = nextTimer->_fireTSR; + fireTSR = (fireTSR / tenus + 1) * tenus; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + mk_timer_arm(rlm->_timerPort, __CFUInt64ToAbsoluteTime(fireTSR)); +#elif DEPLOYMENT_TARGET_WINDOWS + LARGE_INTEGER dueTime; + dueTime.QuadPart = __CFTSRToFiletime(fireTSR); + SetWaitableTimer(rlm->_timerPort, &dueTime, 0, NULL, NULL, FALSE); +#endif + } + if (isInArray) CFRelease(rlt); +} + +// mode and rl are locked on entry and exit static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopTimerRef rlt) { /* DOES CALLOUT */ - Boolean timerHandled = false, timerEarly = false; + Boolean timerHandled = false; int64_t oldFireTSR = 0; /* Fire a timer */ CFRetain(rlt); - __CFRunLoopModeUnlock(rlm); - if (__CFIsValid(rlt) && !__CFRunLoopTimerIsFiring(rlt)) { + __CFRunLoopTimerLock(rlt); + + if (__CFIsValid(rlt) && rlt->_fireTSR <= (int64_t)mach_absolute_time() && !__CFRunLoopTimerIsFiring(rlt) && rlt->_runLoop == rl) { void *context_info = NULL; void (*context_release)(const void *) = NULL; if (rlt->_context.retain) { @@ -1778,85 +1758,169 @@ static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLo } else { context_info = rlt->_context.info; } - __CFRunLoopTimerUnsetDidFire(rlt); + Boolean doInvalidate = (0.0 == rlt->_interval); __CFRunLoopTimerSetFiring(rlt); -//CFLog(4, CFSTR("Firing timer %p from loop %p in mode %@"), rlt, rl, rlm->_name); + __CFRunLoopTimerUnlock(rlt); __CFRunLoopTimerFireTSRLock(); oldFireTSR = rlt->_fireTSR; __CFRunLoopTimerFireTSRUnlock(); - if (0 && CFAbsoluteTimeGetCurrent() < rlt->_nextFireDate) { // not enabled at this time -- causes trouble when clock goes backwards - timerEarly = true; - } else { - rlt->_callout(rlt, context_info); /* CALLOUT */ - CHECK_FOR_FORK(); - timerHandled = true; + + CFRunLoopTimerRef nextTimer = NULL; + for (CFIndex idx = 0, cnt = CFArrayGetCount(rlm->_timers); idx < cnt; idx++) { + CFRunLoopTimerRef t = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(rlm->_timers, idx); + if (!__CFRunLoopTimerIsFiring(t)) { + nextTimer = t; + break; + } + } + if (nextTimer) { + int64_t fireTSR = nextTimer->_fireTSR; + fireTSR = (fireTSR / tenus + 1) * tenus; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + mk_timer_arm(rlm->_timerPort, __CFUInt64ToAbsoluteTime(fireTSR)); +#elif DEPLOYMENT_TARGET_WINDOWS + LARGE_INTEGER dueTime; + dueTime.QuadPart = __CFTSRToFiletime(fireTSR); + SetWaitableTimer(rlm->_timerPort, &dueTime, 0, NULL, NULL, FALSE); +#endif + } + + __CFRunLoopModeUnlock(rlm); + __CFRunLoopUnlock(rl); + __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__(rlt->_callout, rlt, context_info); + CHECK_FOR_FORK(); + if (doInvalidate) { + CFRunLoopTimerInvalidate(rlt); /* DOES CALLOUT */ } -//CFLog(4, CFSTR("Done firing timer %p from loop %p in mode %@"), rlt, rl, rlm->_name); - __CFRunLoopTimerUnsetFiring(rlt); if (context_release) { context_release(context_info); } - } else { - // If the timer fires while it is firing in a higher activiation, - // it is not allowed to fire, but we have to remember that fact. - // Later, if the timer's fire date is being handled manually, we - // need to re-arm the kernel timer, since it has possibly already - // fired (this firing which is being skipped, say) and the timer - // will permanently stop if we completely drop this firing. - if (__CFRunLoopTimerIsFiring(rlt)) __CFRunLoopTimerSetDidFire(rlt); + __CFRunLoopLock(rl); + __CFRunLoopModeLock(rlm); + __CFRunLoopTimerLock(rlt); + timerHandled = true; + __CFRunLoopTimerUnsetFiring(rlt); } if (__CFIsValid(rlt) && timerHandled) { - if (0.0 == rlt->_interval) { - CFRunLoopTimerInvalidate(rlt); /* DOES CALLOUT */ - } else { - /* This is just a little bit tricky: we want to support calling - * CFRunLoopTimerSetNextFireDate() from within the callout and - * honor that new time here if it is a later date, otherwise - * it is completely ignored. */ - __CFRunLoopTimerFireTSRLock(); - int64_t currentFireTSR = rlt->_fireTSR; - if (oldFireTSR < currentFireTSR) { - /* Next fire TSR was set, and set to a date after the previous - * fire date, so we honor it. */ - if (__CFRunLoopTimerDidFire(rlt)) { - __CFRunLoopTimerRescheduleWithAllModes(rlt); - __CFRunLoopTimerUnsetDidFire(rlt); + /* This is just a little bit tricky: we want to support calling + * CFRunLoopTimerSetNextFireDate() from within the callout and + * honor that new time here if it is a later date, otherwise + * it is completely ignored. */ + if (oldFireTSR < rlt->_fireTSR) { + /* Next fire TSR was set, and set to a date after the previous + * fire date, so we honor it. */ + __CFRunLoopTimerUnlock(rlt); + // The timer was adjusted and repositioned, during the + // callout, but if it was still the min timer, it was + // skipped because it was firing. Need to redo the + // min timer calculation in case rlt should now be that + // timer instead of whatever was chosen. + CFRunLoopTimerRef nextTimer = NULL; + for (CFIndex idx = 0, cnt = CFArrayGetCount(rlm->_timers); idx < cnt; idx++) { + CFRunLoopTimerRef t = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(rlm->_timers, idx); + if (!__CFRunLoopTimerIsFiring(t)) { + nextTimer = t; + break; + } + } + if (nextTimer) { + int64_t fireTSR = nextTimer->_fireTSR; + fireTSR = (fireTSR / tenus + 1) * tenus; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + mk_timer_arm(rlm->_timerPort, __CFUInt64ToAbsoluteTime(fireTSR)); +#else + LARGE_INTEGER dueTime; + dueTime.QuadPart = __CFTSRToFiletime(fireTSR); + SetWaitableTimer(rlm->_timerPort, &dueTime, 0, NULL, NULL, FALSE); +#endif + } + } else { + int64_t nextFireTSR = 0LL; + int64_t intervalTSR = 0LL; + if (rlt->_interval <= 0.0) { + } else if (TIMER_INTERVAL_LIMIT < rlt->_interval) { + intervalTSR = __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT); + } else { + intervalTSR = __CFTimeIntervalToTSR(rlt->_interval); + } + if (LLONG_MAX - intervalTSR <= oldFireTSR) { + nextFireTSR = LLONG_MAX; + } else { + int64_t currentTSR = (int64_t)mach_absolute_time(); + nextFireTSR = oldFireTSR; + while (nextFireTSR <= currentTSR) { + nextFireTSR += intervalTSR; + } + } + CFRunLoopRef rlt_rl = rlt->_runLoop; + if (rlt_rl) { + CFRetain(rlt_rl); + CFIndex cnt = CFSetGetCount(rlt->_rlModes); + STACK_BUFFER_DECL(CFTypeRef, modes, cnt); + CFSetGetValues(rlt->_rlModes, (const void **)modes); + // To avoid A->B, B->A lock ordering issues when coming up + // towards the run loop from a source, the timer has to be + // unlocked, which means we have to protect from object + // invalidation, although that's somewhat expensive. + for (CFIndex idx = 0; idx < cnt; idx++) { + CFRetain(modes[idx]); } - } else { - if ((uint64_t)LLONG_MAX <= (uint64_t)oldFireTSR + (uint64_t)rlt->_intervalTSR) { - currentFireTSR = LLONG_MAX; - } else { - int64_t currentTSR = (int64_t)__CFReadTSR(); - currentFireTSR = oldFireTSR; - while (currentFireTSR <= currentTSR) { - currentFireTSR += rlt->_intervalTSR; + __CFRunLoopTimerUnlock(rlt); + for (CFIndex idx = 0; idx < cnt; idx++) { + CFStringRef name = (CFStringRef)modes[idx]; + modes[idx] = (CFTypeRef)__CFRunLoopFindMode(rlt_rl, name, false); + CFRelease(name); + } + __CFRunLoopTimerFireTSRLock(); + rlt->_fireTSR = nextFireTSR; + rlt->_nextFireDate = CFAbsoluteTimeGetCurrent() + __CFTSRToTimeInterval(nextFireTSR - (int64_t)mach_absolute_time()); + for (CFIndex idx = 0; idx < cnt; idx++) { + CFRunLoopModeRef rlm = (CFRunLoopModeRef)modes[idx]; + if (rlm) { + __CFRepositionTimerInMode(rlm, rlt, true); } } - rlt->_fireTSR = currentFireTSR; - __CFRunLoopTimerRescheduleWithAllModes(rlt); - } - __CFRunLoopTimerFireTSRUnlock(); - } - } - if (__CFIsValid(rlt) && timerEarly) { - int64_t now2 = (int64_t)mach_absolute_time(); - CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); - __CFRunLoopTimerFireTSRLock(); - if (rlt->_nextFireDate < now1) { - rlt->_fireTSR = now2; - } else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < rlt->_nextFireDate) { - rlt->_fireTSR = LLONG_MAX; - } else { - rlt->_fireTSR = now2 + __CFTimeIntervalToTSR(rlt->_nextFireDate - now1); - } - __CFRunLoopTimerRescheduleWithAllModes(rlt); - __CFRunLoopTimerFireTSRUnlock(); + __CFRunLoopTimerFireTSRUnlock(); + for (CFIndex idx = 0; idx < cnt; idx++) { + __CFRunLoopModeUnlock((CFRunLoopModeRef)modes[idx]); + } + CFRelease(rlt_rl); + } else { + __CFRunLoopTimerUnlock(rlt); + __CFRunLoopTimerFireTSRLock(); + rlt->_fireTSR = nextFireTSR; + rlt->_nextFireDate = CFAbsoluteTimeGetCurrent() + __CFTSRToTimeInterval(nextFireTSR - (int64_t)mach_absolute_time()); + __CFRunLoopTimerFireTSRUnlock(); + } + } + } else { + __CFRunLoopTimerUnlock(rlt); } CFRelease(rlt); - __CFRunLoopModeLock(rlm); return timerHandled; } +// rl and rlm are locked on entry and exit +static Boolean __CFRunLoopDoTimers(CFRunLoopRef rl, CFRunLoopModeRef rlm, int64_t limitTSR) { /* DOES CALLOUT */ + Boolean timerHandled = false; + CFMutableArrayRef timers = NULL; + for (CFIndex idx = 0, cnt = rlm->_timers ? CFArrayGetCount(rlm->_timers) : 0; idx < cnt; idx++) { + CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(rlm->_timers, idx); + if (__CFIsValid(rlt) && rlt->_fireTSR <= limitTSR && !__CFRunLoopTimerIsFiring(rlt)) { + if (!timers) timers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + CFArrayAppendValue(timers, rlt); + } + } + for (CFIndex idx = 0, cnt = timers ? CFArrayGetCount(timers) : 0; idx < cnt; idx++) { + CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(timers, idx); + Boolean did = __CFRunLoopDoTimer(rl, rlm, rlt); + timerHandled = timerHandled || did; + } + if (timers) CFRelease(timers); + return timerHandled; +} + + CF_EXPORT Boolean _CFRunLoopFinished(CFRunLoopRef rl, CFStringRef modeName) { CHECK_FOR_FORK(); CFRunLoopModeRef rlm; @@ -1866,160 +1930,132 @@ CF_EXPORT Boolean _CFRunLoopFinished(CFRunLoopRef rl, CFStringRef modeName) { if (NULL == rlm || __CFRunLoopModeIsEmpty(rl, rlm, NULL)) { result = true; } - __CFRunLoopUnlock(rl); if (rlm) __CFRunLoopModeUnlock(rlm); + __CFRunLoopUnlock(rl); return result; } -// rl is locked, rlm is locked on entry and exit -static void __CFRunLoopModeAddPortsToPortSet(CFRunLoopRef rl, CFRunLoopModeRef rlm, __CFPortSet portSet) { - CFIndex idx, cnt; - const void **list, *buffer[256]; +static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) __attribute__((noinline)); - // Timers and version 1 sources go into the portSet currently - if (NULL != rlm->_sources) { - cnt = CFSetGetCount(rlm->_sources); - list = (const void **)((cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0)); - CFSetGetValues(rlm->_sources, list); - for (idx = 0; idx < cnt; idx++) { - CFRunLoopSourceRef rls = (CFRunLoopSourceRef)list[idx]; - if (1 == rls->_context.version0.version) { - __CFPort port = rls->_context.version1.getPort(rls->_context.version1.info); /* CALLOUT */ - if (CFPORT_NULL != port) { - __CFPortSetInsert(port, portSet); - } - } - } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); - } #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - if (NULL != rlm->_timers) { - cnt = CFSetGetCount(rlm->_timers); - list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0); - CFSetGetValues(rlm->_timers, list); - for (idx = 0; idx < cnt; idx++) { - CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)list[idx]; - if (MACH_PORT_NULL != rlt->_port) { - mach_port_insert_member(mach_task_self(), rlt->_port, portSet); - } - } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); - } -#endif - // iterate over submodes - for (idx = 0, cnt = NULL != rlm->_submodes ? CFArrayGetCount(rlm->_submodes) : 0; idx < cnt; idx++) { - CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); - CFRunLoopModeRef subrlm; - subrlm = __CFRunLoopFindMode(rl, modeName, false); - if (NULL != subrlm) { - __CFRunLoopModeAddPortsToPortSet(rl, subrlm, portSet); - __CFRunLoopModeUnlock(subrlm); - } + +#define TIMEOUT_INFINITY (~(mach_msg_timeout_t)0) + +static Boolean __CFRunLoopServiceMachPort(mach_port_name_t port, mach_msg_header_t **buffer, size_t buffer_size, mach_msg_timeout_t timeout) { + Boolean originalBuffer = true; + for (;;) { /* In that sleep of death what nightmares may come ... */ + mach_msg_header_t *msg = (mach_msg_header_t *)*buffer; + msg->msgh_bits = 0; + msg->msgh_local_port = port; + msg->msgh_remote_port = MACH_PORT_NULL; + msg->msgh_size = buffer_size; + msg->msgh_id = 0; + kern_return_t ret = mach_msg(msg, MACH_RCV_MSG|MACH_RCV_LARGE|((TIMEOUT_INFINITY != timeout) ? MACH_RCV_TIMEOUT : 0)|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV), 0, msg->msgh_size, port, timeout, MACH_PORT_NULL); + if (MACH_MSG_SUCCESS == ret) return true; + if (MACH_RCV_TIMED_OUT == ret) { + if (!originalBuffer) free(msg); + *buffer = NULL; + return false; + } + if (MACH_RCV_TOO_LARGE != ret) break; + buffer_size = round_msg(msg->msgh_size + MAX_TRAILER_SIZE); + if (originalBuffer) *buffer = NULL; + originalBuffer = false; + *buffer = realloc(*buffer, buffer_size); } + HALT; + return false; } -static __CFPortSet _LastMainWaitSet = 0; +#elif DEPLOYMENT_TARGET_WINDOWS -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -// return NO if we're the main runloop and there are no messages waiting on the port set -int _CFRunLoopInputsReady(void) { - CHECK_FOR_FORK(); - if (!pthread_main_np()) return true; +#define TIMEOUT_INFINITY INFINITE - // XXX_PCB: can't be any messages waiting if the wait set is NULL. - if (_LastMainWaitSet == MACH_PORT_NULL) return false; - - // prepare a message header with no space for any data, nor a trailer - mach_msg_header_t msg; - msg.msgh_size = sizeof(msg); // just the header, ma'am - // need the waitset, actually XXX - msg.msgh_local_port = _LastMainWaitSet; - msg.msgh_remote_port = MACH_PORT_NULL; - msg.msgh_id = 0; +// pass in either a portSet or onePort +static Boolean __CFRunLoopWaitForMultipleObjects(__CFPortSet portSet, HANDLE *onePort, DWORD timeout, DWORD mask, HANDLE *livePort, Boolean *msgReceived) { + DWORD waitResult = WAIT_TIMEOUT; + HANDLE handleBuf[MAXIMUM_WAIT_OBJECTS]; + HANDLE *handles = NULL; + uint32_t handleCount = 0; + Boolean freeHandles = false; + Boolean result = false; + + if (portSet) { + // copy out the handles to be safe from other threads at work + handles = __CFPortSetGetPorts(portSet, handleBuf, MAXIMUM_WAIT_OBJECTS, &handleCount); + freeHandles = (handles != handleBuf); + } else { + handles = onePort; + handleCount = 1; + freeHandles = FALSE; + } - kern_return_t ret = mach_msg(&msg, MACH_RCV_MSG | MACH_RCV_TIMEOUT | MACH_RCV_LARGE, 0, msg.msgh_size, _LastMainWaitSet, 0, MACH_PORT_NULL); + // The run loop mode and loop are already in proper unlocked state from caller + waitResult = MsgWaitForMultipleObjectsEx(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, timeout, mask, MWMO_INPUTAVAILABLE); - return (MACH_RCV_TOO_LARGE == ret); - return true; -} -#endif - -#if 0 -static void print_msg_scan_header(void) { - printf("======== ======== ======== ========\n"); - printf("description\tport\tport type\t\treferences\n"); -} - -static void print_one_port_info(const char *desc, mach_port_t port, mach_msg_type_name_t type) { - mach_port_urefs_t refs; - kern_return_t ret = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, &refs); - if (ret != KERN_SUCCESS) refs = 0; - const char *type_name = "???"; - switch (type) { - case MACH_MSG_TYPE_MOVE_SEND: type_name = "MACH_MSG_TYPE_MOVE_SEND"; break; - case MACH_MSG_TYPE_MOVE_SEND_ONCE: type_name = "MACH_MSG_TYPE_MOVE_SEND_ONCE"; break; - case MACH_MSG_TYPE_MOVE_RECEIVE: type_name = "MACH_MSG_TYPE_MOVE_RECEIVE"; break; - case MACH_MSG_TYPE_MAKE_SEND: type_name = "MACH_MSG_TYPE_MAKE_SEND"; break; - case MACH_MSG_TYPE_MAKE_SEND_ONCE: type_name = "MACH_MSG_TYPE_MAKE_SEND_ONCE"; break; - } - printf("%s\t%p\t%-20s\t%u\n", desc, port, type_name, refs); -} - -static void mach_msg_scan(mach_msg_header_t *msg, int clean) { - Boolean printed_header = false; - /* - * The msgh_local_port field doesn't hold a port right. - * The receive operation consumes the destination port right. - */ - if (MACH_PORT_NULL != msg->msgh_remote_port) { - if (! printed_header) print_msg_scan_header(); - printed_header = true; - print_one_port_info("msg->msgh_remote_port", msg->msgh_remote_port, MACH_MSGH_BITS_REMOTE(msg->msgh_bits)); - } - if (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) { - mach_msg_body_t *body = (mach_msg_body_t *) (msg + 1); - mach_msg_descriptor_t *saddr = (mach_msg_descriptor_t *) ((mach_msg_base_t *) msg + 1); - mach_msg_descriptor_t *eaddr = saddr + body->msgh_descriptor_count; - for ( ; saddr < eaddr; saddr++) { - switch (saddr->type.type) { - case MACH_MSG_PORT_DESCRIPTOR:; - mach_msg_port_descriptor_t *dsc = &saddr->port; - if (! printed_header) print_msg_scan_header(); - printed_header = true; - print_one_port_info("port in body", dsc->name, dsc->disposition); -// if (clean) mach_port_deallocate(mach_task_self(), dsc->name); - break; - case MACH_MSG_OOL_PORTS_DESCRIPTOR:; - mach_msg_ool_ports_descriptor_t *dsc2 = &saddr->ool_ports; - mach_port_t *ports = (mach_port_t *) dsc2->address; - for (mach_msg_type_number_t j = 0; j < dsc2->count; j++, ports++) { - if (! printed_header) print_msg_scan_header(); - printed_header = true; - print_one_port_info("port in OOL ports", *ports, dsc2->disposition); - } - break; - } - } + CFAssert2(waitResult != WAIT_FAILED, __kCFLogAssertion, "%s(): error %d from MsgWaitForMultipleObjects", __PRETTY_FUNCTION__, GetLastError()); + + if (waitResult == WAIT_TIMEOUT) { + // do nothing, just return to caller + result = false; + } else if (waitResult >= WAIT_OBJECT_0 && waitResult < WAIT_OBJECT_0+handleCount) { + // a handle was signaled + if (livePort) *livePort = handles[waitResult-WAIT_OBJECT_0]; + result = true; + } else if (waitResult == WAIT_OBJECT_0+handleCount) { + // windows message received + if (msgReceived) *msgReceived = true; + result = true; + } else if (waitResult >= WAIT_ABANDONED_0 && waitResult < WAIT_ABANDONED_0+handleCount) { + // an "abandoned mutex object" + if (livePort) *livePort = handles[waitResult-WAIT_ABANDONED_0]; + result = true; + } else { + CFAssert2(waitResult == WAIT_FAILED, __kCFLogAssertion, "%s(): unexpected result from MsgWaitForMultipleObjects: %d", __PRETTY_FUNCTION__, waitResult); + result = false; + } + + if (freeHandles) { + CFAllocatorDeallocate(kCFAllocatorSystemDefault, handles); } + + return result; } -#endif -static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode, Boolean waitIfEmpty) __attribute__((noinline)); -#if DEPLOYMENT_TARGET_WINDOWS -static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl, CFRunLoopModeRef rlm); #endif -/* rl is unlocked, rlm locked on entrance and exit */ -static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode, Boolean waitIfEmpty) { /* DOES CALLOUT */ +struct __timeout_context { + dispatch_source_t ds; + CFRunLoopRef rl; int64_t termTSR; +}; + +static void __CFRunLoopTimeoutCancel(void *arg) { + struct __timeout_context *context = (struct __timeout_context *)arg; + CFRelease(context->rl); + dispatch_release(context->ds); + free(context); +} + +static void __CFRunLoopTimeout(void *arg) { + struct __timeout_context *context = (struct __timeout_context *)arg; + context->termTSR = 0LL; + CFRunLoopWakeUp(context->rl); + // The interval is DISPATCH_TIME_FOREVER, so this won't fire again +} + #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - mach_port_name_t timeoutPort = MACH_PORT_NULL; - mach_port_name_t dispatchPort = MACH_PORT_NULL; - Boolean libdispatchQSafe = pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == pthread_getspecific(__CFTSDKeyIsInGCDMainQ))); - if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name)) dispatchPort = _dispatch_get_main_queue_port_4CF(); +#elif DEPLOYMENT_TARGET_WINDOWS +#define MACH_PORT_NULL 0 +#define mach_port_name_t HANDLE +#define _dispatch_get_main_queue_port_4CF _dispatch_get_main_queue_handle_4CF +#else +#error Unknown deployment target - CFRunLoop not functional #endif - Boolean poll = false; - Boolean firstPass = true; + +/* rl, rlm are locked on entrance and exit */ +static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, CFRunLoopModeRef previousMode) { + int64_t startTSR = (int64_t)mach_absolute_time(); if (__CFRunLoopIsStopped(rl)) { __CFRunLoopUnsetStopped(rl); @@ -2028,347 +2064,220 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter rlm->_stopped = false; return kCFRunLoopRunStopped; } - if (seconds <= 0.0) { - termTSR = 0; - } else if (TIMER_INTERVAL_LIMIT < seconds) { - termTSR = LLONG_MAX; - } else { - termTSR = (int64_t)__CFReadTSR() + __CFTimeIntervalToTSR(seconds); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - timeoutPort = mk_timer_create(); - mk_timer_arm(timeoutPort, __CFUInt64ToAbsoluteTime(termTSR)); -#endif - } - if (seconds <= 0.0) { - poll = true; - } - if (rl == CFRunLoopGetMain()) _LastMainWaitSet = CFPORT_NULL; - for (;;) { - __CFPortSet waitSet = CFPORT_NULL; - Boolean destroyWaitSet = false; - CFRunLoopSourceRef rls; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - mach_msg_header_t *msg; - kern_return_t ret; - uint8_t buffer[2048]; -#else - CFArrayRef timersToCall = NULL; -#endif - int32_t returnValue = 0; - Boolean sourceHandledThisLoop = false; - - // Do not handle blocks here, as there is already a handling at - // the end of this loop, and that just makes for two handlings - // in a row when the loop cycles. - if (rlm->_observerMask & kCFRunLoopBeforeTimers || rlm->_submodes) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers); - if (rlm->_observerMask & kCFRunLoopBeforeSources || rlm->_submodes) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources); - if (rl->_blocks_head) { - __CFRunLoopModeUnlock(rlm); - __CFRunLoopLock(rl); - __CFRunLoopDoBlocks(rl, rlm->_name); - __CFRunLoopModeLock(rlm); - __CFRunLoopUnlock(rl); - } - sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle) || sourceHandledThisLoop; + mach_port_name_t dispatchPort = MACH_PORT_NULL; + Boolean libdispatchQSafe = pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ))); + if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name)) dispatchPort = _dispatch_get_main_queue_port_4CF(); + dispatch_source_t timeout_timer = NULL; + struct __timeout_context *timeout_context = (struct __timeout_context *)malloc(sizeof(*timeout_context)); + if (seconds <= 0.0) { // instant timeout + seconds = 0.0; + timeout_context->termTSR = 0LL; + } else if (seconds <= TIMER_INTERVAL_LIMIT) { + dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, DISPATCH_QUEUE_OVERCOMMIT); + timeout_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); + dispatch_retain(timeout_timer); + timeout_context->ds = timeout_timer; + timeout_context->rl = (CFRunLoopRef)CFRetain(rl); + timeout_context->termTSR = startTSR + __CFTimeIntervalToTSR(seconds); + dispatch_set_context(timeout_timer, timeout_context); // source gets ownership of context + dispatch_source_set_event_handler_f(timeout_timer, __CFRunLoopTimeout); + dispatch_source_set_cancel_handler_f(timeout_timer, __CFRunLoopTimeoutCancel); + uint64_t nanos = (uint64_t)(seconds * 1000 * 1000 + 1) * 1000; + dispatch_source_set_timer(timeout_timer, dispatch_time(DISPATCH_TIME_NOW, nanos), DISPATCH_TIME_FOREVER, 0); + dispatch_resume(timeout_timer); + } else { // infinite timeout + seconds = 9999999999.0; + timeout_context->termTSR = INT64_MAX; + } + + Boolean didDispatchPortLastTime = true; + int32_t retVal = 0; + do { + uint8_t msg_buffer[3 * 1024]; #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - if (MACH_PORT_NULL != dispatchPort) { - msg = (mach_msg_header_t *)buffer; - msg->msgh_size = sizeof(buffer); - msg->msgh_bits = 0; - msg->msgh_local_port = dispatchPort; - msg->msgh_remote_port = MACH_PORT_NULL; - msg->msgh_id = 0; - ret = mach_msg(msg, MACH_RCV_MSG|MACH_RCV_LARGE|MACH_RCV_TIMEOUT|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV), 0, msg->msgh_size, dispatchPort, 0, MACH_PORT_NULL); - - if (MACH_MSG_SUCCESS == ret) { - __CFRunLoopModeUnlock(rlm); - pthread_setspecific(__CFTSDKeyIsInGCDMainQ, (void *)3); - _dispatch_main_queue_callback_4CF(msg); - sourceHandledThisLoop = true; - pthread_setspecific(__CFTSDKeyIsInGCDMainQ, (void *)0); - __CFRunLoopLock(rl); - __CFRunLoopModeLock(rlm); - __CFRunLoopUnlock(rl); - } else if (MACH_RCV_TIMED_OUT == ret) { - msg = NULL; - } else { - HALT; - } - } + mach_msg_header_t *msg = NULL; +#elif DEPLOYMENT_TARGET_WINDOWS + HANDLE livePort = NULL; + Boolean windowsMessageReceived = false; #endif + __CFPortSet waitSet = rlm->_portSet; - if (sourceHandledThisLoop) { - poll = true; - if (rl->_blocks_head) { - __CFRunLoopModeUnlock(rlm); - __CFRunLoopLock(rl); - __CFRunLoopDoBlocks(rl, rlm->_name); - __CFRunLoopModeLock(rlm); - __CFRunLoopUnlock(rl); - } - } + rl->_ignoreWakeUps = false; - if (!poll) { - if (rlm->_observerMask & kCFRunLoopBeforeWaiting || rlm->_submodes) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting); - // do not do any user callouts after this point (after notifying of sleeping) - __CFRunLoopSetSleeping(rl); - } - if (NULL != rlm->_submodes) { - // !!! what do we do if this doesn't succeed? - waitSet = __CFPortSetAllocate(); - if (CFPORT_NULL == waitSet) HALT; - __CFRunLoopModeUnlock(rlm); - __CFRunLoopLock(rl); - __CFRunLoopModeLock(rlm); - __CFRunLoopModeAddPortsToPortSet(rl, rlm, waitSet); - __CFRunLoopUnlock(rl); - destroyWaitSet = true; - } else { - waitSet = rlm->_portSet; - } -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - if (CFPORT_NULL != timeoutPort) { - __CFPortSetInsert(timeoutPort, waitSet); - } - if (CFPORT_NULL != dispatchPort) { - __CFPortSetInsert(dispatchPort, waitSet); + if (rlm->_observerMask & kCFRunLoopBeforeTimers) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers); + if (rlm->_observerMask & kCFRunLoopBeforeSources) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources); + + __CFRunLoopDoBlocks(rl, rlm); + + Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle); + if (sourceHandledThisLoop) { + __CFRunLoopDoBlocks(rl, rlm); } -#endif - if (rl == CFRunLoopGetMain()) _LastMainWaitSet = waitSet; - __CFRunLoopModeUnlock(rlm); + Boolean poll = sourceHandledThisLoop || (0LL == timeout_context->termTSR); + + if (MACH_PORT_NULL != dispatchPort && !didDispatchPortLastTime) { #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - if (kCFUseCollectableAllocator && !poll) { - memset(buffer, 0, sizeof(buffer)); - objc_clear_stack(0); - } - - msg = (mach_msg_header_t *)buffer; - msg->msgh_size = sizeof(buffer); - -//static uint64_t _last_value = 0; -//uint64_t new_val = mach_absolute_time(); -//printf(". %d before %qd (%qd)\n", getpid(), new_val, new_val - _last_value); -//_last_value = new_val; - - /* In that sleep of death what nightmares may come ... */ - try_receive:; - msg->msgh_bits = 0; - msg->msgh_local_port = waitSet; - msg->msgh_remote_port = MACH_PORT_NULL; - msg->msgh_id = 0; - ret = mach_msg(msg, MACH_RCV_MSG|MACH_RCV_LARGE|(poll ? MACH_RCV_TIMEOUT : 0)|MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV), 0, msg->msgh_size, waitSet, 0, MACH_PORT_NULL); - - if (MACH_RCV_TOO_LARGE == ret) { - uint32_t newSize = round_msg(msg->msgh_size + MAX_TRAILER_SIZE); - if (msg == (mach_msg_header_t *)buffer) msg = NULL; - msg = CFAllocatorReallocate(kCFAllocatorSystemDefault, msg, newSize, 0); - msg->msgh_size = newSize; - goto try_receive; - } else if (MACH_RCV_TIMED_OUT == ret) { - // timeout, for poll - if (msg != (mach_msg_header_t *)buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg); - msg = NULL; - } else if (MACH_MSG_SUCCESS != ret) { - HALT; - } -//new_val = mach_absolute_time(); -//printf(". %d after %qd (%qd)\n", getpid(), new_val, new_val - _last_value); -//_last_value = new_val; + msg = (mach_msg_header_t *)msg_buffer; + if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), 0)) { + goto handle_msg; + } #elif DEPLOYMENT_TARGET_WINDOWS - DWORD waitResult = WAIT_TIMEOUT; - HANDLE handleBuf[MAXIMUM_WAIT_OBJECTS]; - HANDLE *handles; - uint32_t handleCount; - Boolean freeHandles; - if (destroyWaitSet) { - // wait set is a local, no one else could modify it, no need to copy handles - handles = waitSet->handles; - handleCount = waitSet->used; - freeHandles = FALSE; - } else { - // copy out the handles to be safe from other threads at work - handles = __CFPortSetGetPorts(waitSet, handleBuf, MAXIMUM_WAIT_OBJECTS, &handleCount); - freeHandles = (handles != handleBuf); - } - // should msgQMask be an OR'ing of this and all submodes' masks? - if (0 == GetQueueStatus(rlm->_msgQMask)) { - DWORD timeout; - if (poll) - timeout = 0; - else { - int64_t nextStop; - __CFRunLoopModeLock(rlm); - nextStop = __CFRunLoopGetNextTimerFireTSR(rl, rlm); - if (nextStop <= 0) - nextStop = termTSR; - else if (nextStop > termTSR) - nextStop = termTSR; - // else the next stop is dictated by the next timer - int64_t timeoutTSR = nextStop - __CFReadTSR(); - if (timeoutTSR < 0) - timeout = 0; - else { - CFTimeInterval timeoutCF = __CFTSRToTimeInterval(timeoutTSR) * 1000; - if (timeoutCF > MAXDWORD) - timeout = INFINITE; - else - timeout = (DWORD)timeoutCF; - } - } - waitResult = WaitForMultipleObjects(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, false, timeout); - } - ResetEvent(rl->_wakeUpPort); -#endif - __CFRunLoopLock(rl); - __CFRunLoopModeLock(rlm); - __CFRunLoopUnlock(rl); - if (destroyWaitSet) { - __CFPortSetFree(waitSet); - if (rl == CFRunLoopGetMain()) _LastMainWaitSet = 0; - } else { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - if (CFPORT_NULL != timeoutPort) { - __CFPortSetRemove(timeoutPort, waitSet); - } - if (CFPORT_NULL != dispatchPort) { - __CFPortSetRemove(dispatchPort, waitSet); - } + if (__CFRunLoopWaitForMultipleObjects(NULL, &dispatchPort, 0, 0, &livePort, NULL)) { + goto handle_msg; + } #endif - } + } + + didDispatchPortLastTime = false; + + if (!poll && (rlm->_observerMask & kCFRunLoopBeforeWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting); + __CFRunLoopSetSleeping(rl); + // do not do any user callouts after this point (after notifying of sleeping) + + // Must push the local-to-this-activation ports in on every loop + // iteration, as this mode could be run re-entrantly and we don't + // want these ports to get serviced. + + __CFPortSetInsert(dispatchPort, waitSet); - if (!poll) { - __CFRunLoopUnsetSleeping(rl); - if (rlm->_observerMask & kCFRunLoopAfterWaiting || rlm->_submodes) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting); - } - poll = false; __CFRunLoopModeUnlock(rlm); - __CFRunLoopLock(rl); - __CFRunLoopModeLock(rlm); + __CFRunLoopUnlock(rl); - __CFPort livePort = CFPORT_NULL; #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - if (NULL != msg) { - livePort = msg->msgh_local_port; + if (kCFUseCollectableAllocator) { + objc_clear_stack(0); + memset(msg_buffer, 0, sizeof(msg_buffer)); } + msg = (mach_msg_header_t *)msg_buffer; + __CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), poll ? 0 : TIMEOUT_INFINITY); #elif DEPLOYMENT_TARGET_WINDOWS - CFAssert2(waitResult != WAIT_FAILED, __kCFLogAssertion, "%s(): error %d from MsgWaitForMultipleObjects", __PRETTY_FUNCTION__, GetLastError()); - if (waitResult == WAIT_TIMEOUT) { - // do nothing, just return to caller - } else if (waitResult >= WAIT_OBJECT_0 && waitResult < WAIT_OBJECT_0+handleCount) { - // a handle was signaled - livePort = handles[waitResult-WAIT_OBJECT_0]; - } else if (waitResult == WAIT_OBJECT_0+handleCount) { - // windows message received - the CFWindowsMessageQueue will pick this up when - // the v0 RunLoopSources get their chance - } else if (waitResult >= WAIT_ABANDONED_0 && waitResult < WAIT_ABANDONED_0+handleCount) { - // an "abandoned mutex object" - livePort = handles[waitResult-WAIT_ABANDONED_0]; - } else { - CFAssert2(waitResult == WAIT_FAILED, __kCFLogAssertion, "%s(): unexpected result from MsgWaitForMultipleObjects: %d", __PRETTY_FUNCTION__, waitResult); - } - if (freeHandles) - CFAllocatorDeallocate(kCFAllocatorSystemDefault, handles); - timersToCall = __CFRunLoopTimersToFire(rl, rlm); + // Here, use the app-supplied message queue mask. They will set this if they are interested in having this run loop receive windows messages. + // Note: don't pass 0 for polling, or this thread will never yield the CPU. + __CFRunLoopWaitForMultipleObjects(waitSet, NULL, poll ? 0 : TIMEOUT_INFINITY, rlm->_msgQMask, &livePort, &windowsMessageReceived); #endif + + __CFRunLoopLock(rl); + __CFRunLoopModeLock(rlm); + + // Must remove the local-to-this-activation ports in on every loop + // iteration, as this mode could be run re-entrantly and we don't + // want these ports to get serviced. Also, we don't want them left + // in there if this function returns. + + __CFPortSetRemove(dispatchPort, waitSet); + + rl->_ignoreWakeUps = true; + + // user callouts now OK again + __CFRunLoopUnsetSleeping(rl); + if (!poll && (rlm->_observerMask & kCFRunLoopAfterWaiting)) __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting); + + handle_msg:; + rl->_ignoreWakeUps = true; - if (CFPORT_NULL == livePort) { - __CFRunLoopUnlock(rl); - } else if (livePort == rl->_wakeUpPort) { - // wakeup - if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("wakeupPort was signalled")); } - __CFRunLoopUnlock(rl); // leave run loop unlocked - } #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - else if (livePort == timeoutPort) { - returnValue = kCFRunLoopRunTimedOut; + mach_port_t livePort = msg ? msg->msgh_local_port : MACH_PORT_NULL; +#endif +#if DEPLOYMENT_TARGET_WINDOWS + if (windowsMessageReceived) { + // These Win32 APIs cause a callout, so make sure we're unlocked first and relocked after + __CFRunLoopModeUnlock(rlm); __CFRunLoopUnlock(rl); - } else if (dispatchPort == livePort) { + + if (rlm->_msgPump) { + rlm->_msgPump(); + } else { + MSG msg; + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_NOYIELD)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + __CFRunLoopLock(rl); + __CFRunLoopModeLock(rlm); + sourceHandledThisLoop = true; + } else +#endif + if (MACH_PORT_NULL == livePort) { + // handle nothing + } else if (livePort == rl->_wakeUpPort) { + // do nothing on Mac OS +#if DEPLOYMENT_TARGET_WINDOWS + // Always reset the wake up port, or risk spinning forever + ResetEvent(rl->_wakeUpPort); +#endif + } else if (livePort == rlm->_timerPort) { +#if DEPLOYMENT_TARGET_WINDOWS + // We use a manual reset timer to ensure that we don't miss timers firing because the run loop did the wakeUpPort this time + // The only way to reset a timer is to reset the timer using SetWaitableTimer. We don't want it to fire again though, so we set the timeout to a large negative value. The timer may be reset again inside the timer handling code. + LARGE_INTEGER dueTime; + dueTime.QuadPart = LONG_MIN; + SetWaitableTimer(rlm->_timerPort, &dueTime, 0, NULL, NULL, FALSE); +#endif + __CFRunLoopDoTimers(rl, rlm, mach_absolute_time()); + } else if (livePort == dispatchPort) { __CFRunLoopModeUnlock(rlm); __CFRunLoopUnlock(rl); - pthread_setspecific(__CFTSDKeyIsInGCDMainQ, (void *)3); + _CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)6, NULL); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED _dispatch_main_queue_callback_4CF(msg); - sourceHandledThisLoop = true; - pthread_setspecific(__CFTSDKeyIsInGCDMainQ, (void *)0); +#elif DEPLOYMENT_TARGET_WINDOWS + _dispatch_main_queue_callback_4CF(); +#endif + _CFSetTSD(__CFTSDKeyIsInGCDMainQ, (void *)0, NULL); __CFRunLoopLock(rl); __CFRunLoopModeLock(rlm); - __CFRunLoopUnlock(rl); // leave run loop unlocked - } else if (NULL != (rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort))) { - mach_msg_header_t *reply = NULL; - __CFRunLoopUnlock(rl); -// mach_msg_scan(msg, 0); - if (__CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply)) { - sourceHandledThisLoop = true; - } -// mach_msg_scan(msg, 1); - if (NULL != reply) { - ret = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL); -//#warning CF: what should be done with the return value? - CFAllocatorDeallocate(kCFAllocatorSystemDefault, reply); - } - } else { - CFRunLoopTimerRef rlt; - rlt = __CFRunLoopModeFindTimerForMachPort(rlm, livePort); - __CFRunLoopUnlock(rl); - if (NULL != rlt) { - __CFRunLoopDoTimer(rl, rlm, rlt); - } - } - if (msg != (mach_msg_header_t *)buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg); -#else - else if (NULL != (rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort))) { - __CFRunLoopUnlock(rl); - if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("Source %@ was signalled"), rls); } - if (__CFRunLoopDoSource1(rl, rlm, rls)) { - sourceHandledThisLoop = true; - } - } + sourceHandledThisLoop = true; + didDispatchPortLastTime = true; + } else { + // Despite the name, this works for windows handles as well + CFRunLoopSourceRef rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, livePort); + if (rls) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + mach_msg_header_t *reply = NULL; + sourceHandledThisLoop = __CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply) || sourceHandledThisLoop; + if (NULL != reply) { + (void)mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, reply); + } +#elif DEPLOYMENT_TARGET_WINDOWS + sourceHandledThisLoop = __CFRunLoopDoSource1(rl, rlm, rls) || sourceHandledThisLoop; #endif - -#if DEPLOYMENT_TARGET_WINDOWS - if (NULL != timersToCall) { - int i; - for (i = CFArrayGetCount(timersToCall)-1; i >= 0; i--) - __CFRunLoopDoTimer(rl, rlm, (CFRunLoopTimerRef)CFArrayGetValueAtIndex(timersToCall, i)); - CFRelease(timersToCall); - } + } + } +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + if (msg && msg != (mach_msg_header_t *)msg_buffer) free(msg); #endif - if (rl->_blocks_head) { - __CFRunLoopModeUnlock(rlm); // locks must be taken in order - __CFRunLoopLock(rl); - __CFRunLoopDoBlocks(rl, rlm->_name); - __CFRunLoopModeLock(rlm); - __CFRunLoopUnlock(rl); - } + __CFRunLoopDoBlocks(rl, rlm); + if (sourceHandledThisLoop && stopAfterHandle) { - returnValue = kCFRunLoopRunHandledSource; - // If we're about to timeout, but we just did a zero-timeout poll that only found our own - // internal wakeup signal on the first look at the portset, we'll go around the loop one - // more time, so as not to starve a v1 source that was just added along with a runloop wakeup. - } else if (0 != returnValue || (uint64_t)termTSR <= __CFReadTSR()) { - returnValue = kCFRunLoopRunTimedOut; + retVal = kCFRunLoopRunHandledSource; + } else if (timeout_context->termTSR < (int64_t)mach_absolute_time()) { + retVal = kCFRunLoopRunTimedOut; } else if (__CFRunLoopIsStopped(rl)) { __CFRunLoopUnsetStopped(rl); - returnValue = kCFRunLoopRunStopped; + retVal = kCFRunLoopRunStopped; } else if (rlm->_stopped) { rlm->_stopped = false; - returnValue = kCFRunLoopRunStopped; - } else if (!waitIfEmpty && __CFRunLoopModeIsEmpty(rl, rlm, previousMode)) { - returnValue = kCFRunLoopRunFinished; + retVal = kCFRunLoopRunStopped; + } else if (__CFRunLoopModeIsEmpty(rl, rlm, previousMode)) { + retVal = kCFRunLoopRunFinished; } - if (0 != returnValue) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - if (MACH_PORT_NULL != timeoutPort) { - mk_timer_destroy(timeoutPort); - } -#endif - return returnValue; - } - firstPass = false; + } while (0 == retVal); + + if (timeout_timer) { + dispatch_source_cancel(timeout_timer); + dispatch_release(timeout_timer); + } else { + free(timeout_context); } + + return retVal; } SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */ @@ -2379,11 +2288,6 @@ SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterva if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode, rl->_currentMode)) { Boolean did = false; if (currentMode) __CFRunLoopModeUnlock(currentMode); -#if 0 - if (rl->_blocks_head) { - __CFRunLoopDoBlocks(rl, modeName); - } -#endif __CFRunLoopUnlock(rl); return did ? kCFRunLoopRunHandledSource : kCFRunLoopRunFinished; } @@ -2391,39 +2295,15 @@ SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterva rl->_stopped = NULL; CFRunLoopModeRef previousMode = rl->_currentMode; rl->_currentMode = currentMode; -#if DEPLOYMENT_TARGET_WINDOWS - if (previousMode && currentMode != previousMode) { - if (__CFIsNonMachRunLoopMarryMsgQueueEnabled()) - __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl); - else - __CFRunLoopUpdateMsgWait(rl); - } -#endif - __CFRunLoopUnlock(rl); int32_t result; - @try { - if (currentMode->_observerMask & kCFRunLoopEntry || currentMode->_submodes) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry); - result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode, false); - if (currentMode->_observerMask & kCFRunLoopExit || currentMode->_submodes) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit); - } @finally { - // this kvetches if an exception was raised during a run loop callout, because the mode is not locked - if (0 != currentMode->_lock) { - __CFRunLoopModeUnlock(currentMode); - } - __CFRunLoopLock(rl); + if (currentMode->_observerMask & kCFRunLoopEntry ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry); + result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, previousMode); + if (currentMode->_observerMask & kCFRunLoopExit ) __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit); + __CFRunLoopModeUnlock(currentMode); if (rl->_stopped) CFAllocatorDeallocate(kCFAllocatorSystemDefault, (uint32_t *)rl->_stopped); rl->_stopped = previousStopped; rl->_currentMode = previousMode; -#if DEPLOYMENT_TARGET_WINDOWS - if (previousMode && currentMode != previousMode) { - if (__CFIsNonMachRunLoopMarryMsgQueueEnabled()) - __CFRunLoopUpdateMsgWaitMarryMsgQueue(rl); - else - __CFRunLoopUpdateMsgWait(rl); - } -#endif - __CFRunLoopUnlock(rl); - } + __CFRunLoopUnlock(rl); return result; } @@ -2440,89 +2320,16 @@ SInt32 CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled); } -static void __CFRunLoopFindMinTimer(const void *value, void *ctx) { - CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)value; - if (__CFIsValid(rlt)) { - CFRunLoopTimerRef *result = (CFRunLoopTimerRef *)ctx; - if (NULL == *result || rlt->_fireTSR < (*result)->_fireTSR) { - *result = rlt; - } - } -} - -#if DEPLOYMENT_TARGET_WINDOWS -static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl, CFRunLoopModeRef rlm) { - CFRunLoopTimerRef result = NULL; - int64_t fireTime = 0; - if (rlm) { - if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) { - __CFRunLoopTimerFireTSRLock(); - CFSetApplyFunction(rlm->_timers, (__CFRunLoopFindMinTimer), &result); - if (result) - fireTime = result->_fireTSR; - __CFRunLoopTimerFireTSRUnlock(); - } - if (NULL != rlm->_submodes) { - CFIndex idx, cnt; - for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) { - CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); - CFRunLoopModeRef subrlm; - subrlm = __CFRunLoopFindMode(rl, modeName, false); - if (NULL != subrlm) { - int64_t newFireTime = __CFRunLoopGetNextTimerFireTSR(rl, subrlm); - __CFRunLoopModeUnlock(subrlm); - if (fireTime == 0 || (newFireTime != 0 && newFireTime < fireTime)) - fireTime = newFireTime; - } - } - } - __CFRunLoopModeUnlock(rlm); - } - return fireTime; -} -#endif - -// called with rlm locked, if not NULL -static CFAbsoluteTime __CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFRunLoopModeRef rlm) { - CFRunLoopTimerRef result = NULL; - CFAbsoluteTime fireDate = 0.0; - int64_t now2 = (int64_t)mach_absolute_time(); - CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); - if (rlm) { - if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) { - __CFRunLoopTimerFireTSRLock(); - CFSetApplyFunction(rlm->_timers, (__CFRunLoopFindMinTimer), &result); - if (result) { - fireDate = (0 == result->_fireTSR) ? 0.0 : (now1 + __CFTSRToTimeInterval(result->_fireTSR - now2)); - } - __CFRunLoopTimerFireTSRUnlock(); - } - if (NULL != rlm->_submodes) { - CFIndex idx, cnt; - for (idx = 0, cnt = CFArrayGetCount(rlm->_submodes); idx < cnt; idx++) { - CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(rlm->_submodes, idx); - CFRunLoopModeRef subrlm; - subrlm = __CFRunLoopFindMode(rl, modeName, false); - if (NULL != subrlm) { - CFAbsoluteTime newFireDate = __CFRunLoopGetNextTimerFireDate(rl, subrlm); - __CFRunLoopModeUnlock(subrlm); - if (fireDate == 0 || (newFireDate != 0.0 && newFireDate < fireDate)) - fireDate = newFireDate; - } - } - } - __CFRunLoopModeUnlock(rlm); - } - return fireDate; -} - CFAbsoluteTime CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFStringRef modeName) { CHECK_FOR_FORK(); - CFRunLoopModeRef rlm; __CFRunLoopLock(rl); - rlm = __CFRunLoopFindMode(rl, modeName, false); + CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false); + CFAbsoluteTime at = 0.0; + CFRunLoopTimerRef timer = (rlm && rlm->_timers && 0 < CFArrayGetCount(rlm->_timers)) ? (CFRunLoopTimerRef)CFArrayGetValueAtIndex(rlm->_timers, 0) : NULL; + if (timer) at = CFRunLoopTimerGetNextFireDate(timer); + if (rlm) __CFRunLoopModeUnlock(rlm); __CFRunLoopUnlock(rl); - return __CFRunLoopGetNextTimerFireDate(rl, rlm); + return at; } Boolean CFRunLoopIsWaiting(CFRunLoopRef rl) { @@ -2532,6 +2339,12 @@ Boolean CFRunLoopIsWaiting(CFRunLoopRef rl) { void CFRunLoopWakeUp(CFRunLoopRef rl) { CHECK_FOR_FORK(); + // This lock is crucial to ignorable wakeups, do not remove it. + __CFRunLoopLock(rl); + if (rl->_ignoreWakeUps) { + __CFRunLoopUnlock(rl); + return; + } #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED kern_return_t ret; /* We unconditionally try to send the message, since we don't want @@ -2543,14 +2356,8 @@ void CFRunLoopWakeUp(CFRunLoopRef rl) { } #else SetEvent(rl->_wakeUpPort); - __CFRunLoopLock(rl); - if (rl->_threadID == GetCurrentThreadId()) { - PostMessageW(NULL, __kCFRunLoopWakeUpMessage, NULL, NULL); - } else { - PostThreadMessageW(rl->_threadID, __kCFRunLoopWakeUpMessage, NULL, NULL); - } - __CFRunLoopUnlock(rl); #endif + __CFRunLoopUnlock(rl); } void CFRunLoopStop(CFRunLoopRef rl) { @@ -2572,96 +2379,17 @@ CF_EXPORT void _CFRunLoopStopMode(CFRunLoopRef rl, CFStringRef modeName) { CFRunLoopModeRef rlm; __CFRunLoopLock(rl); rlm = __CFRunLoopFindMode(rl, modeName, true); - __CFRunLoopUnlock(rl); if (NULL != rlm) { rlm->_stopped = true; __CFRunLoopModeUnlock(rlm); } - CFRunLoopWakeUp(rl); -} - -CF_EXPORT Boolean _CFRunLoopModeContainsMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef candidateContainedName) { - CHECK_FOR_FORK(); - CFRunLoopModeRef rlm; - if (modeName == kCFRunLoopCommonModes || candidateContainedName == kCFRunLoopCommonModes) { - return false; - } else if (CFEqual(modeName, candidateContainedName)) { - return true; - } - __CFRunLoopLock(rl); - rlm = __CFRunLoopFindMode(rl, modeName, true); __CFRunLoopUnlock(rl); - if (NULL != rlm) { - CFArrayRef submodes; - if (NULL == rlm->_submodes) { - __CFRunLoopModeUnlock(rlm); - return false; - } - if (CFArrayContainsValue(rlm->_submodes, CFRangeMake(0, CFArrayGetCount(rlm->_submodes)), candidateContainedName)) { - __CFRunLoopModeUnlock(rlm); - return true; - } - submodes = (NULL != rlm->_submodes && 0 < CFArrayGetCount(rlm->_submodes)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault, rlm->_submodes) : NULL; - __CFRunLoopModeUnlock(rlm); - if (NULL != submodes) { - CFIndex idx, cnt; - for (idx = 0, cnt = CFArrayGetCount(submodes); idx < cnt; idx++) { - CFStringRef subname = (CFStringRef)CFArrayGetValueAtIndex(submodes, idx); - if (_CFRunLoopModeContainsMode(rl, subname, candidateContainedName)) { - CFRelease(submodes); - return true; - } - } - CFRelease(submodes); - } - } - return false; -} - -CF_EXPORT void _CFRunLoopAddModeToMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef toModeName) { - CHECK_FOR_FORK(); - CFRunLoopModeRef rlm; - if (__CFRunLoopIsDeallocating(rl)) return; - // should really do a recursive check here, to make sure that a cycle isn't - // introduced; of course, if that happens, you aren't going to get very far. - if (modeName == kCFRunLoopCommonModes || toModeName == kCFRunLoopCommonModes || CFEqual(modeName, toModeName)) { - return; - } else { - __CFRunLoopLock(rl); - rlm = __CFRunLoopFindMode(rl, toModeName, true); - __CFRunLoopUnlock(rl); - if (NULL != rlm) { - if (NULL == rlm->_submodes) { - rlm->_submodes = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); - } - if (!CFArrayContainsValue(rlm->_submodes, CFRangeMake(0, CFArrayGetCount(rlm->_submodes)), modeName)) { - CFArrayAppendValue(rlm->_submodes, modeName); - } - __CFRunLoopModeUnlock(rlm); - } - } + CFRunLoopWakeUp(rl); } -CF_EXPORT void _CFRunLoopRemoveModeFromMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef fromModeName) { +CF_EXPORT Boolean _CFRunLoopModeContainsMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef candidateContainedName) { CHECK_FOR_FORK(); - CFRunLoopModeRef rlm; - // should really do a recursive check here, to make sure that a cycle isn't - // introduced; of course, if that happens, you aren't going to get very far. - if (modeName == kCFRunLoopCommonModes || fromModeName == kCFRunLoopCommonModes || CFEqual(modeName, fromModeName)) { - return; - } else { - __CFRunLoopLock(rl); - rlm = __CFRunLoopFindMode(rl, fromModeName, true); - __CFRunLoopUnlock(rl); - if (NULL != rlm) { - if (NULL != rlm->_submodes) { - CFIndex idx, cnt = CFArrayGetCount(rlm->_submodes); - idx = CFArrayGetFirstIndexOfValue(rlm->_submodes, CFRangeMake(0, cnt), modeName); - if (0 <= idx) CFArrayRemoveValueAtIndex(rlm->_submodes, idx); - } - __CFRunLoopModeUnlock(rlm); - } - } + return false; } void CFRunLoopPerformBlock(CFRunLoopRef rl, CFTypeRef mode, void (^block)(void)) { @@ -2703,7 +2431,7 @@ void CFRunLoopPerformBlock(CFRunLoopRef rl, CFTypeRef mode, void (^block)(void)) mode = NULL; } #if DEPLOYMENT_TARGET_WINDOWS - // Block.h uses "typeof", which is not available when using Visual Studio on Windows + // clang ObjC rewriter: __typeof(block) not rewritten correctly block = (void (^)(void))_Block_copy(block); #else block = Block_copy(block); @@ -2736,34 +2464,29 @@ Boolean CFRunLoopContainsSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStrin if (NULL != rl->_commonModeItems) { hasValue = CFSetContainsValue(rl->_commonModeItems, rls); } - __CFRunLoopUnlock(rl); } else { rlm = __CFRunLoopFindMode(rl, modeName, false); - __CFRunLoopUnlock(rl); - if (NULL != rlm && NULL != rlm->_sources) { - hasValue = CFSetContainsValue(rlm->_sources, rls); - __CFRunLoopModeUnlock(rlm); - } else if (NULL != rlm) { + if (NULL != rlm) { + hasValue = (rlm->_sources0 ? CFSetContainsValue(rlm->_sources0, rls) : false) || (rlm->_sources1 ? CFSetContainsValue(rlm->_sources1, rls) : false); __CFRunLoopModeUnlock(rlm); } } + __CFRunLoopUnlock(rl); return hasValue; } void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { /* DOES CALLOUT */ CHECK_FOR_FORK(); - CFRunLoopModeRef rlm; if (__CFRunLoopIsDeallocating(rl)) return; if (!__CFIsValid(rls)) return; + Boolean doVer0Callout = false; __CFRunLoopLock(rl); if (modeName == kCFRunLoopCommonModes) { CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; if (NULL == rl->_commonModeItems) { rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); - _CFSetSetCapacity(rl->_commonModeItems, 20); } CFSetAddValue(rl->_commonModeItems, rls); - __CFRunLoopUnlock(rl); if (NULL != set) { CFTypeRef context[2] = {rl, rls}; /* add new item to all common-modes */ @@ -2771,36 +2494,57 @@ void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef mod CFRelease(set); } } else { - rlm = __CFRunLoopFindMode(rl, modeName, true); - __CFRunLoopUnlock(rl); - if (NULL != rlm && NULL == rlm->_sources) { - rlm->_sources = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); + CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true); + if (NULL != rlm && NULL == rlm->_sources0) { + rlm->_sources0 = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); + rlm->_sources1 = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); rlm->_portToV1SourceMap = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); - _CFSetSetCapacity(rlm->_sources, 10); } - if (NULL != rlm && !CFSetContainsValue(rlm->_sources, rls)) { - CFSetAddValue(rlm->_sources, rls); - if (1 == rls->_context.version0.version) { + if (NULL != rlm && !CFSetContainsValue(rlm->_sources0, rls) && !CFSetContainsValue(rlm->_sources1, rls)) { + if (0 == rls->_context.version0.version) { + CFSetAddValue(rlm->_sources0, rls); + } else if (1 == rls->_context.version0.version) { + CFSetAddValue(rlm->_sources1, rls); __CFPort src_port = rls->_context.version1.getPort(rls->_context.version1.info); - CFDictionarySetValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)src_port, rls); + if (CFPORT_NULL != src_port) { + CFDictionarySetValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)src_port, rls); + __CFPortSetInsert(src_port, rlm->_portSet); + } } - __CFRunLoopModeUnlock(rlm); - __CFRunLoopSourceSchedule(rls, rl, rlm); /* DOES CALLOUT */ - } else if (NULL != rlm) { + __CFRunLoopSourceLock(rls); + if (NULL == rls->_runLoops) { + rls->_runLoops = CFBagCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeBagCallBacks); // sources retain run loops! + } + CFBagAddValue(rls->_runLoops, rl); + __CFRunLoopSourceUnlock(rls); + if (0 == rls->_context.version0.version) { + if (NULL != rls->_context.version0.schedule) { + doVer0Callout = true; + } + } + } + if (NULL != rlm) { __CFRunLoopModeUnlock(rlm); } } + __CFRunLoopUnlock(rl); + if (doVer0Callout) { + // although it looses some protection for the source, we have no choice but + // to do this after unlocking the run loop and mode locks, to avoid deadlocks + // where the source wants to take a lock which is already held in another + // thread which is itself waiting for a run loop/mode lock + rls->_context.version0.schedule(rls->_context.version0.info, rl, modeName); /* CALLOUT */ + } } void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { /* DOES CALLOUT */ CHECK_FOR_FORK(); - CFRunLoopModeRef rlm; + Boolean doVer0Callout = false, doRLSRelease = false; __CFRunLoopLock(rl); if (modeName == kCFRunLoopCommonModes) { if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rls)) { CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; CFSetRemoveValue(rl->_commonModeItems, rls); - __CFRunLoopUnlock(rl); if (NULL != set) { CFTypeRef context[2] = {rl, rls}; /* remove new item from all common-modes */ @@ -2808,25 +2552,45 @@ void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef CFRelease(set); } } else { - __CFRunLoopUnlock(rl); } } else { - rlm = __CFRunLoopFindMode(rl, modeName, false); - __CFRunLoopUnlock(rl); - if (NULL != rlm && NULL != rlm->_sources && CFSetContainsValue(rlm->_sources, rls)) { + CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false); + if (NULL != rlm && ((NULL != rlm->_sources0 && CFSetContainsValue(rlm->_sources0, rls)) || (NULL != rlm->_sources1 && CFSetContainsValue(rlm->_sources1, rls)))) { CFRetain(rls); if (1 == rls->_context.version0.version) { __CFPort src_port = rls->_context.version1.getPort(rls->_context.version1.info); - CFDictionaryRemoveValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)src_port); + if (CFPORT_NULL != src_port) { + CFDictionaryRemoveValue(rlm->_portToV1SourceMap, (const void *)(uintptr_t)src_port); + __CFPortSetRemove(src_port, rlm->_portSet); + } } - CFSetRemoveValue(rlm->_sources, rls); - __CFRunLoopModeUnlock(rlm); - __CFRunLoopSourceCancel(rls, rl, rlm); /* DOES CALLOUT */ - CFRelease(rls); - } else if (NULL != rlm) { + CFSetRemoveValue(rlm->_sources0, rls); + CFSetRemoveValue(rlm->_sources1, rls); + __CFRunLoopSourceLock(rls); + if (NULL != rls->_runLoops) { + CFBagRemoveValue(rls->_runLoops, rl); + } + __CFRunLoopSourceUnlock(rls); + if (0 == rls->_context.version0.version) { + if (NULL != rls->_context.version0.schedule) { + doVer0Callout = true; + } + } + doRLSRelease = true; + } + if (NULL != rlm) { __CFRunLoopModeUnlock(rlm); } } + __CFRunLoopUnlock(rl); + if (doVer0Callout) { + // although it looses some protection for the source, we have no choice but + // to do this after unlocking the run loop and mode locks, to avoid deadlocks + // where the source wants to take a lock which is already held in another + // thread which is itself waiting for a run loop/mode lock + rls->_context.version0.cancel(rls->_context.version0.info, rl, modeName); /* CALLOUT */ + } + if (doRLSRelease) CFRelease(rls); } static void __CFRunLoopRemoveSourcesFromCommonMode(const void *value, void *ctx) { @@ -2849,27 +2613,31 @@ static void __CFRunLoopRemoveAllSources(CFRunLoopRef rl, CFStringRef modeName) { if (modeName == kCFRunLoopCommonModes) { if (NULL != rl->_commonModeItems) { CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; - __CFRunLoopUnlock(rl); if (NULL != set) { CFSetApplyFunction(set, (__CFRunLoopRemoveSourcesFromCommonMode), (void *)rl); CFRelease(set); } } else { - __CFRunLoopUnlock(rl); } } else { rlm = __CFRunLoopFindMode(rl, modeName, false); - __CFRunLoopUnlock(rl); - if (NULL != rlm && NULL != rlm->_sources) { - CFSetRef set = CFSetCreateCopy(kCFAllocatorSystemDefault, rlm->_sources); - __CFRunLoopModeUnlock(rlm); + if (NULL != rlm && NULL != rlm->_sources0) { + CFSetRef set = CFSetCreateCopy(kCFAllocatorSystemDefault, rlm->_sources0); + CFTypeRef context[2] = {rl, modeName}; + CFSetApplyFunction(set, (__CFRunLoopRemoveSourceFromMode), (void *)context); + CFRelease(set); + } + if (NULL != rlm && NULL != rlm->_sources1) { + CFSetRef set = CFSetCreateCopy(kCFAllocatorSystemDefault, rlm->_sources1); CFTypeRef context[2] = {rl, modeName}; CFSetApplyFunction(set, (__CFRunLoopRemoveSourceFromMode), (void *)context); CFRelease(set); - } else if (NULL != rlm) { + } + if (NULL != rlm) { __CFRunLoopModeUnlock(rlm); } } + __CFRunLoopUnlock(rl); } Boolean CFRunLoopContainsObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) { @@ -2881,17 +2649,16 @@ Boolean CFRunLoopContainsObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFS if (NULL != rl->_commonModeItems) { hasValue = CFSetContainsValue(rl->_commonModeItems, rlo); } - __CFRunLoopUnlock(rl); } else { rlm = __CFRunLoopFindMode(rl, modeName, false); - __CFRunLoopUnlock(rl); if (NULL != rlm && NULL != rlm->_observers) { - hasValue = CFSetContainsValue(rlm->_observers, rlo); - __CFRunLoopModeUnlock(rlm); - } else if (NULL != rlm) { + hasValue = CFArrayContainsValue(rlm->_observers, CFRangeMake(0, CFArrayGetCount(rlm->_observers)), rlo); + } + if (NULL != rlm) { __CFRunLoopModeUnlock(rlm); } } + __CFRunLoopUnlock(rl); return hasValue; } @@ -2907,7 +2674,6 @@ void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); } CFSetAddValue(rl->_commonModeItems, rlo); - __CFRunLoopUnlock(rl); if (NULL != set) { CFTypeRef context[2] = {rl, rlo}; /* add new item to all common-modes */ @@ -2916,19 +2682,30 @@ void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef } } else { rlm = __CFRunLoopFindMode(rl, modeName, true); - __CFRunLoopUnlock(rl); if (NULL != rlm && NULL == rlm->_observers) { - rlm->_observers = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); - } - if (NULL != rlm && !CFSetContainsValue(rlm->_observers, rlo)) { - CFSetAddValue(rlm->_observers, rlo); + rlm->_observers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + } + if (NULL != rlm && !CFArrayContainsValue(rlm->_observers, CFRangeMake(0, CFArrayGetCount(rlm->_observers)), rlo)) { + Boolean inserted = false; + for (CFIndex idx = CFArrayGetCount(rlm->_observers); idx--; ) { + CFRunLoopObserverRef obs = (CFRunLoopObserverRef)CFArrayGetValueAtIndex(rlm->_observers, idx); + if (obs->_order <= rlo->_order) { + CFArrayInsertValueAtIndex(rlm->_observers, idx + 1, rlo); + inserted = true; + break; + } + } + if (!inserted) { + CFArrayInsertValueAtIndex(rlm->_observers, 0, rlo); + } rlm->_observerMask |= rlo->_activities; - __CFRunLoopModeUnlock(rlm); __CFRunLoopObserverSchedule(rlo, rl, rlm); - } else if (NULL != rlm) { + } + if (NULL != rlm) { __CFRunLoopModeUnlock(rlm); } } + __CFRunLoopUnlock(rl); } void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) { @@ -2939,7 +2716,6 @@ void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFString if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rlo)) { CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; CFSetRemoveValue(rl->_commonModeItems, rlo); - __CFRunLoopUnlock(rl); if (NULL != set) { CFTypeRef context[2] = {rl, rlo}; /* remove new item from all common-modes */ @@ -2947,50 +2723,50 @@ void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFString CFRelease(set); } } else { - __CFRunLoopUnlock(rl); } } else { rlm = __CFRunLoopFindMode(rl, modeName, false); - __CFRunLoopUnlock(rl); - if (NULL != rlm && NULL != rlm->_observers && CFSetContainsValue(rlm->_observers, rlo)) { + if (NULL != rlm && NULL != rlm->_observers) { CFRetain(rlo); - CFSetRemoveValue(rlm->_observers, rlo); - __CFRunLoopModeUnlock(rlm); - __CFRunLoopObserverCancel(rlo, rl, rlm); + CFIndex idx = CFArrayGetFirstIndexOfValue(rlm->_observers, CFRangeMake(0, CFArrayGetCount(rlm->_observers)), rlo); + if (kCFNotFound != idx) { + CFArrayRemoveValueAtIndex(rlm->_observers, idx); + __CFRunLoopObserverCancel(rlo, rl, rlm); + } CFRelease(rlo); - } else if (NULL != rlm) { + } + if (NULL != rlm) { __CFRunLoopModeUnlock(rlm); } } + __CFRunLoopUnlock(rl); } Boolean CFRunLoopContainsTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) { CHECK_FOR_FORK(); - CFRunLoopModeRef rlm; + if (NULL == rlt->_runLoop || rl != rlt->_runLoop) return false; Boolean hasValue = false; __CFRunLoopLock(rl); if (modeName == kCFRunLoopCommonModes) { if (NULL != rl->_commonModeItems) { hasValue = CFSetContainsValue(rl->_commonModeItems, rlt); } - __CFRunLoopUnlock(rl); } else { - rlm = __CFRunLoopFindMode(rl, modeName, false); - __CFRunLoopUnlock(rl); + CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false); if (NULL != rlm && NULL != rlm->_timers) { - hasValue = CFSetContainsValue(rlm->_timers, rlt); - __CFRunLoopModeUnlock(rlm); - } else if (NULL != rlm) { + CFIndex idx = CFArrayGetFirstIndexOfValue(rlm->_timers, CFRangeMake(0, CFArrayGetCount(rlm->_timers)), rlt); + hasValue = (kCFNotFound != idx); + } + if (NULL != rlm) { __CFRunLoopModeUnlock(rlm); } } + __CFRunLoopUnlock(rl); return hasValue; } void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) { CHECK_FOR_FORK(); -//CFLog(4, CFSTR("CFRunLoopAddTimer(%p, timer %p, %@)"), rl, rlt, modeName); - CFRunLoopModeRef rlm; if (__CFRunLoopIsDeallocating(rl)) return; if (!__CFIsValid(rlt) || (NULL != rlt->_runLoop && rlt->_runLoop != rl)) return; __CFRunLoopLock(rl); @@ -3000,7 +2776,6 @@ void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeN rl->_commonModeItems = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); } CFSetAddValue(rl->_commonModeItems, rlt); - __CFRunLoopUnlock(rl); if (NULL != set) { CFTypeRef context[2] = {rl, rlt}; /* add new item to all common-modes */ @@ -3008,31 +2783,47 @@ void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeN CFRelease(set); } } else { - rlm = __CFRunLoopFindMode(rl, modeName, true); - __CFRunLoopUnlock(rl); + CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, true); if (NULL != rlm && NULL == rlm->_timers) { - rlm->_timers = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); + CFArrayCallBacks cb = kCFTypeArrayCallBacks; + cb.equal = NULL; + rlm->_timers = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &cb); + } + if (NULL != rlm && !CFSetContainsValue(rlt->_rlModes, rlm->_name)) { + __CFRunLoopTimerLock(rlt); + if (NULL == rlt->_runLoop) { + rlt->_runLoop = rl; + } else if (rl != rlt->_runLoop) { + __CFRunLoopTimerUnlock(rlt); + __CFRunLoopModeUnlock(rlm); + __CFRunLoopUnlock(rl); + return; + } + CFSetAddValue(rlt->_rlModes, rlm->_name); + __CFRunLoopTimerUnlock(rlt); + __CFRunLoopTimerFireTSRLock(); + __CFRepositionTimerInMode(rlm, rlt, false); + __CFRunLoopTimerFireTSRUnlock(); + if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionLion)) { + // Normally we don't do this on behalf of clients, but for + // backwards compatibility due to the change in timer handling... + if (rl != CFRunLoopGetCurrent()) CFRunLoopWakeUp(rl); + } } - if (NULL != rlm && !CFSetContainsValue(rlm->_timers, rlt)) { - CFSetAddValue(rlm->_timers, rlt); - __CFRunLoopModeUnlock(rlm); - __CFRunLoopTimerSchedule(rlt, rl, rlm); - } else if (NULL != rlm) { + if (NULL != rlm) { __CFRunLoopModeUnlock(rlm); } } + __CFRunLoopUnlock(rl); } void CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) { CHECK_FOR_FORK(); -//CFLog(4, CFSTR("CFRunLoopRemoveTimer(%p, timer %p, %@)"), rl, rlt, modeName); - CFRunLoopModeRef rlm; __CFRunLoopLock(rl); if (modeName == kCFRunLoopCommonModes) { if (NULL != rl->_commonModeItems && CFSetContainsValue(rl->_commonModeItems, rlt)) { CFSetRef set = rl->_commonModes ? CFSetCreateCopy(kCFAllocatorSystemDefault, rl->_commonModes) : NULL; CFSetRemoveValue(rl->_commonModeItems, rlt); - __CFRunLoopUnlock(rl); if (NULL != set) { CFTypeRef context[2] = {rl, rlt}; /* remove new item from all common-modes */ @@ -3040,24 +2831,57 @@ void CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef mo CFRelease(set); } } else { - __CFRunLoopUnlock(rl); } } else { - rlm = __CFRunLoopFindMode(rl, modeName, false); - __CFRunLoopUnlock(rl); - if (NULL != rlm && NULL != rlm->_timers && CFSetContainsValue(rlm->_timers, rlt)) { - CFRetain(rlt); - CFSetRemoveValue(rlm->_timers, rlt); - __CFRunLoopModeUnlock(rlm); - __CFRunLoopTimerCancel(rlt, rl, rlm); - CFRelease(rlt); - } else if (NULL != rlm) { + CFRunLoopModeRef rlm = __CFRunLoopFindMode(rl, modeName, false); + CFIndex idx = kCFNotFound; + if (NULL != rlm && NULL != rlm->_timers) { + idx = CFArrayGetFirstIndexOfValue(rlm->_timers, CFRangeMake(0, CFArrayGetCount(rlm->_timers)), rlt); + } + if (kCFNotFound != idx) { + __CFRunLoopTimerLock(rlt); + CFSetRemoveValue(rlt->_rlModes, rlm->_name); + if (0 == CFSetGetCount(rlt->_rlModes)) { + rlt->_runLoop = NULL; + } + __CFRunLoopTimerUnlock(rlt); + CFArrayRemoveValueAtIndex(rlm->_timers, idx); + if (0 == CFArrayGetCount(rlm->_timers)) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + AbsoluteTime dummy; + mk_timer_cancel(rlm->_timerPort, &dummy); +#elif DEPLOYMENT_TARGET_WINDOWS + CancelWaitableTimer(rlm->_timerPort); +#endif + } else if (0 == idx) { + CFRunLoopTimerRef nextTimer = NULL; + for (CFIndex idx = 0, cnt = CFArrayGetCount(rlm->_timers); idx < cnt; idx++) { + CFRunLoopTimerRef t = (CFRunLoopTimerRef)CFArrayGetValueAtIndex(rlm->_timers, idx); + if (!__CFRunLoopTimerIsFiring(t)) { + nextTimer = t; + break; + } + } + if (nextTimer) { + int64_t fireTSR = nextTimer->_fireTSR; + fireTSR = (fireTSR / tenus + 1) * tenus; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + mk_timer_arm(rlm->_timerPort, __CFUInt64ToAbsoluteTime(fireTSR)); +#elif DEPLOYMENT_TARGET_WINDOWS + LARGE_INTEGER dueTime; + dueTime.QuadPart = __CFTSRToFiletime(fireTSR); + SetWaitableTimer(rlm->_timerPort, &dueTime, 0, NULL, NULL, FALSE); +#endif + } + } + } + if (NULL != rlm) { __CFRunLoopModeUnlock(rlm); } } + __CFRunLoopUnlock(rl); } - /* CFRunLoopSource */ static Boolean __CFRunLoopSourceEqual(CFTypeRef cf1, CFTypeRef cf2) { /* DOES CALLOUT */ @@ -3103,9 +2927,9 @@ static CFStringRef __CFRunLoopSourceCopyDescription(CFTypeRef cf) { /* DOES CALL #endif } #if DEPLOYMENT_TARGET_WINDOWS - result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{locked = %s, signalled = %s, valid = %s, order = %d, context = %@}"), cf, CFGetAllocator(rls), "unknown", __CFRunLoopSourceIsSignaled(rls) ? "Yes" : "No", __CFIsValid(rls) ? "Yes" : "No", rls->_order, contextDesc); + result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{signalled = %s, valid = %s, order = %d, context = %@}"), cf, CFGetAllocator(rls), __CFRunLoopSourceIsSignaled(rls) ? "Yes" : "No", __CFIsValid(rls) ? "Yes" : "No", rls->_order, contextDesc); #else - result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{locked = %s, signalled = %s, valid = %s, order = %d, context = %@}"), cf, CFGetAllocator(rls), lockCount(rls->_lock) ? "Yes" : "No", __CFRunLoopSourceIsSignaled(rls) ? "Yes" : "No", __CFIsValid(rls) ? "Yes" : "No", rls->_order, contextDesc); + result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{signalled = %s, valid = %s, order = %d, context = %@}"), cf, CFGetAllocator(rls), __CFRunLoopSourceIsSignaled(rls) ? "Yes" : "No", __CFIsValid(rls) ? "Yes" : "No", rls->_order, contextDesc); #endif CFRelease(contextDesc); return result; @@ -3117,6 +2941,7 @@ static void __CFRunLoopSourceDeallocate(CFTypeRef cf) { /* DOES CALLOUT */ if (rls->_context.version0.release) { rls->_context.version0.release(rls->_context.version0.info); } + pthread_mutex_destroy(&rls->_lock); memset((char *)cf + sizeof(CFRuntimeBase), 0, sizeof(struct __CFRunLoopSource) - sizeof(CFRuntimeBase)); } @@ -3152,7 +2977,7 @@ CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order } __CFSetValid(memory); __CFRunLoopSourceUnsetSignaled(memory); - CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock); + __CFRunLoopLockInit(&memory->_lock); memory->_bits = 0; memory->_order = order; memory->_runLoops = NULL; @@ -3164,11 +2989,6 @@ CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order case 1: size = sizeof(CFRunLoopSourceContext1); break; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - case 2: - size = sizeof(CFRunLoopSourceContext2); - break; -#endif } objc_memmove_collectable(&memory->_context, context, size); if (context->retain) { @@ -3191,15 +3011,20 @@ static void __CFRunLoopSourceRemoveFromRunLoop(const void *value, void *context) CFRunLoopRef rl = (CFRunLoopRef)value; CFTypeRef *params = (CFTypeRef *)context; CFRunLoopSourceRef rls = (CFRunLoopSourceRef)params[0]; - CFArrayRef array; CFIndex idx; if (rl == params[1]) return; - array = CFRunLoopCopyAllModes(rl); + + // CFRunLoopRemoveSource will lock the run loop while it + // needs that, but we also lock it out here to keep + // changes from occurring for this whole sequence. + __CFRunLoopLock(rl); + CFArrayRef array = CFRunLoopCopyAllModes(rl); for (idx = CFArrayGetCount(array); idx--;) { CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(array, idx); CFRunLoopRemoveSource(rl, rls, modeName); } CFRunLoopRemoveSource(rl, rls, kCFRunLoopCommonModes); + __CFRunLoopUnlock(rl); CFRelease(array); params[1] = rl; } @@ -3207,25 +3032,27 @@ static void __CFRunLoopSourceRemoveFromRunLoop(const void *value, void *context) void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls) { CHECK_FOR_FORK(); __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID); - CFRetain(rls); __CFRunLoopSourceLock(rls); + CFRetain(rls); if (__CFIsValid(rls)) { - __CFUnsetValid(rls); + CFBagRef rloops = rls->_runLoops; + __CFUnsetValid(rls); __CFRunLoopSourceUnsetSignaled(rls); - if (NULL != rls->_runLoops) { - CFTypeRef params[2] = {rls, NULL}; - CFBagRef bag = rls->_runLoops; - rls->_runLoops = NULL; - __CFRunLoopSourceUnlock(rls); - CFBagApplyFunction(bag, (__CFRunLoopSourceRemoveFromRunLoop), params); - CFRelease(bag); - } else { - __CFRunLoopSourceUnlock(rls); - } - /* for hashing- and equality-use purposes, can't actually release the context here */ - } else { - __CFRunLoopSourceUnlock(rls); + if (NULL != rloops) { + // To avoid A->B, B->A lock ordering issues when coming up + // towards the run loop from a source, the source has to be + // unlocked, which means we have to protect from object + // invalidation. + rls->_runLoops = NULL; // transfer ownership to local stack + __CFRunLoopSourceUnlock(rls); + CFTypeRef params[2] = {rls, NULL}; + CFBagApplyFunction(rloops, (__CFRunLoopSourceRemoveFromRunLoop), params); + CFRelease(rloops); + __CFRunLoopSourceLock(rls); + } + /* for hashing- and equality-use purposes, can't actually release the context here */ } + __CFRunLoopSourceUnlock(rls); CFRelease(rls); } @@ -3247,11 +3074,6 @@ void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls, CFRunLoopSourceContext *c case 1: size = sizeof(CFRunLoopSourceContext1); break; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - case 2: - size = sizeof(CFRunLoopSourceContext2); - break; -#endif } memmove(context, &rls->_context, size); } @@ -3274,11 +3096,16 @@ Boolean CFRunLoopSourceIsSignalled(CFRunLoopSourceRef rls) { } __private_extern__ void _CFRunLoopSourceWakeUpRunLoops(CFRunLoopSourceRef rls) { + CFBagRef loops = NULL; __CFRunLoopSourceLock(rls); if (__CFIsValid(rls) && NULL != rls->_runLoops) { - CFBagApplyFunction(rls->_runLoops, __CFRunLoopSourceWakeUpLoop, NULL); + loops = CFBagCreateCopy(kCFAllocatorSystemDefault, rls->_runLoops); } __CFRunLoopSourceUnlock(rls); + if (loops) { + CFBagApplyFunction(loops, __CFRunLoopSourceWakeUpLoop, NULL); + CFRelease(loops); + } } /* CFRunLoopObserver */ @@ -3294,12 +3121,12 @@ static CFStringRef __CFRunLoopObserverCopyDescription(CFTypeRef cf) { /* DOES CA contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR(""), rlo->_context.info); } #if DEPLOYMENT_TARGET_WINDOWS - result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{locked = %s, valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %p, context = %@}"), cf, CFGetAllocator(rlo), "unknown", __CFIsValid(rlo) ? "Yes" : "No", rlo->_activities, __CFRunLoopObserverRepeats(rlo) ? "Yes" : "No", rlo->_order, rlo->_callout, contextDesc); + result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %p, context = %@}"), cf, CFGetAllocator(rlo), __CFIsValid(rlo) ? "Yes" : "No", rlo->_activities, __CFRunLoopObserverRepeats(rlo) ? "Yes" : "No", rlo->_order, rlo->_callout, contextDesc); #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED void *addr = rlo->_callout; Dl_info info; const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; - result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{locked = %s, valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %s (%p), context = %@}"), cf, CFGetAllocator(rlo), lockCount(rlo->_lock) ? "Yes" : "No", __CFIsValid(rlo) ? "Yes" : "No", rlo->_activities, __CFRunLoopObserverRepeats(rlo) ? "Yes" : "No", rlo->_order, name, addr, contextDesc); + result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %s (%p), context = %@}"), cf, CFGetAllocator(rlo), __CFIsValid(rlo) ? "Yes" : "No", rlo->_activities, __CFRunLoopObserverRepeats(rlo) ? "Yes" : "No", rlo->_order, name, addr, contextDesc); #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif @@ -3310,6 +3137,7 @@ static CFStringRef __CFRunLoopObserverCopyDescription(CFTypeRef cf) { /* DOES CA static void __CFRunLoopObserverDeallocate(CFTypeRef cf) { /* DOES CALLOUT */ CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)cf; CFRunLoopObserverInvalidate(rlo); + pthread_mutex_destroy(&rlo->_lock); } static const CFRuntimeClass __CFRunLoopObserverClass = { @@ -3348,7 +3176,7 @@ CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionF } else { __CFRunLoopObserverUnsetRepeats(memory); } - CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock); + __CFRunLoopLockInit(&memory->_lock); memory->_runLoop = NULL; memory->_rlCount = 0; memory->_activities = activities; @@ -3372,6 +3200,23 @@ CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionF return memory; } +static void _runLoopObserverWithBlockContext(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *opaqueBlock) { + typedef void (^observer_block_t) (CFRunLoopObserverRef observer, CFRunLoopActivity activity); + observer_block_t block = (observer_block_t)opaqueBlock; + block(observer, activity); +} + +CFRunLoopObserverRef CFRunLoopObserverCreateWithHandler(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, + void (^block) (CFRunLoopObserverRef observer, CFRunLoopActivity activity)) { + CFRunLoopObserverContext blockContext; + blockContext.version = 0; + blockContext.info = (void *)block; + blockContext.retain = (const void *(*)(const void *info))_Block_copy; + blockContext.release = (void (*)(const void *info))_Block_release; + blockContext.copyDescription = NULL; + return CFRunLoopObserverCreate(allocator, activities, repeats, order, _runLoopObserverWithBlockContext, &blockContext); +} + CFOptionFlags CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo) { CHECK_FOR_FORK(); __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); @@ -3390,32 +3235,43 @@ Boolean CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo) { return __CFRunLoopObserverRepeats(rlo); } -void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo) { /* DOES CALLOUT */ +void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo) { /* DOES CALLOUT */ CHECK_FOR_FORK(); __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); - CFRetain(rlo); __CFRunLoopObserverLock(rlo); + CFRetain(rlo); if (__CFIsValid(rlo)) { - CFRunLoopRef rl = rlo->_runLoop; - __CFUnsetValid(rlo); - __CFRunLoopObserverUnlock(rlo); - if (NULL != rl) { - CFArrayRef array; - CFIndex idx; - array = CFRunLoopCopyAllModes(rl); - for (idx = CFArrayGetCount(array); idx--;) { - CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(array, idx); - CFRunLoopRemoveObserver(rl, rlo, modeName); - } - CFRunLoopRemoveObserver(rl, rlo, kCFRunLoopCommonModes); - CFRelease(array); - } - if (rlo->_context.release) - rlo->_context.release(rlo->_context.info); /* CALLOUT */ - rlo->_context.info = NULL; - } else { - __CFRunLoopObserverUnlock(rlo); + CFRunLoopRef rl = rlo->_runLoop; + void *info = rlo->_context.info; + rlo->_context.info = NULL; + __CFUnsetValid(rlo); + if (NULL != rl) { + // To avoid A->B, B->A lock ordering issues when coming up + // towards the run loop from an observer, it has to be + // unlocked, which means we have to protect from object + // invalidation. + CFRetain(rl); + __CFRunLoopObserverUnlock(rlo); + // CFRunLoopRemoveObserver will lock the run loop while it + // needs that, but we also lock it out here to keep + // changes from occurring for this whole sequence. + __CFRunLoopLock(rl); + CFArrayRef array = CFRunLoopCopyAllModes(rl); + for (CFIndex idx = CFArrayGetCount(array); idx--;) { + CFStringRef modeName = (CFStringRef)CFArrayGetValueAtIndex(array, idx); + CFRunLoopRemoveObserver(rl, rlo, modeName); + } + CFRunLoopRemoveObserver(rl, rlo, kCFRunLoopCommonModes); + __CFRunLoopUnlock(rl); + CFRelease(array); + CFRelease(rl); + __CFRunLoopObserverLock(rlo); + } + if (NULL != rlo->_context.release) { + rlo->_context.release(info); /* CALLOUT */ + } } + __CFRunLoopObserverUnlock(rlo); CFRelease(rlo); } @@ -3435,13 +3291,6 @@ void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo, CFRunLoopObserverCont static CFStringRef __CFRunLoopTimerCopyDescription(CFTypeRef cf) { /* DOES CALLOUT */ CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)cf; - CFStringRef result; - int64_t now2 = (int64_t)mach_absolute_time(); - CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); - __CFRunLoopTimerFireTSRLock(); - int64_t fireTime = rlt->_fireTSR; - __CFRunLoopTimerFireTSRUnlock(); - CFAbsoluteTime fireDate = now1 + __CFTSRToTimeInterval(fireTime - now2); CFStringRef contextDesc = NULL; if (NULL != rlt->_context.copyDescription) { contextDesc = rlt->_context.copyDescription(rlt->_context.info); @@ -3449,16 +3298,16 @@ static CFStringRef __CFRunLoopTimerCopyDescription(CFTypeRef cf) { /* DOES CALLO if (NULL == contextDesc) { contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR(""), rlt->_context.info); } + void *addr = (void *)rlt->_callout; + const char *name = "???"; #if DEPLOYMENT_TARGET_WINDOWS - result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{locked = %s, valid = %s, interval = %0.09g, next fire date = %0.09g, order = %d, callout = %p, context = %@}"), cf, CFGetAllocator(rlt), "unknown", __CFIsValid(rlt) ? "Yes" : "No", __CFTSRToTimeInterval(rlt->_intervalTSR), now1 + __CFTSRToTimeInterval(fireTime - now2), rlt->_order, rlt->_callout, contextDesc); #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - void *addr = rlt->_callout; Dl_info info; - const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; - result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{locked = %s, valid = %s, interval = %0.09g, next fire date = %0.09g, order = %d, callout = %s (%p), context = %@}"), cf, CFGetAllocator(rlt), lockCount(rlt->_lock) ? "Yes" : "No", __CFIsValid(rlt) ? "Yes" : "No", rlt->_interval, fireDate, rlt->_order, name, addr, contextDesc); + name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif + CFStringRef result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{valid = %s, interval = %0.09g, next fire date = %0.09g, callout = %s (%p), context = %@}"), cf, CFGetAllocator(rlt), __CFIsValid(rlt) ? "Yes" : "No", rlt->_interval, rlt->_nextFireDate, name, addr, contextDesc); CFRelease(contextDesc); return result; } @@ -3470,6 +3319,7 @@ static void __CFRunLoopTimerDeallocate(CFTypeRef cf) { /* DOES CALLOUT */ CFRunLoopTimerInvalidate(rlt); /* DOES CALLOUT */ CFRelease(rlt->_rlModes); rlt->_rlModes = NULL; + pthread_mutex_destroy(&rlt->_lock); } static const CFRuntimeClass __CFRunLoopTimerClass = { @@ -3493,7 +3343,7 @@ CFTypeID CFRunLoopTimerGetTypeID(void) { } CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context) { - CHECK_FOR_FORK(); + CHECK_FOR_FORK(); CFRunLoopTimerRef memory; UInt32 size; size = sizeof(struct __CFRunLoopTimer) - sizeof(CFRuntimeBase); @@ -3503,35 +3353,24 @@ CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime } __CFSetValid(memory); __CFRunLoopTimerUnsetFiring(memory); - __CFRunLoopTimerUnsetDidFire(memory); - CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock); + __CFRunLoopLockInit(&memory->_lock); memory->_runLoop = NULL; memory->_rlModes = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - memory->_port = MACH_PORT_NULL; -#endif memory->_order = order; if (interval < 0.0) interval = 0.0; memory->_interval = interval; if (TIMER_DATE_LIMIT < fireDate) fireDate = TIMER_DATE_LIMIT; - if (TIMER_INTERVAL_LIMIT < interval) interval = TIMER_INTERVAL_LIMIT; memory->_nextFireDate = fireDate; + memory->_fireTSR = 0LL; int64_t now2 = (int64_t)mach_absolute_time(); CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); if (fireDate < now1) { memory->_fireTSR = now2; - } else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < fireDate) { - memory->_fireTSR = LLONG_MAX; + } else if (TIMER_INTERVAL_LIMIT < fireDate - now1) { + memory->_fireTSR = now2 + __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT); } else { memory->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1); } - if (interval <= 0.0) { - memory->_intervalTSR = 0; - } else if (__CFTSRToTimeInterval(LLONG_MAX) < interval) { - memory->_intervalTSR = LLONG_MAX; - } else { - memory->_intervalTSR = __CFTimeIntervalToTSR(interval); - } memory->_callout = callout; if (NULL != context) { if (context->retain) { @@ -3548,48 +3387,104 @@ CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime memory->_context.release = 0; memory->_context.copyDescription = 0; } -//CFLog(4, CFSTR("CFRunLoopTimerCreate(%p, %f, %f, 0x%lx, %ld, %p, %p) => %p"), allocator, fireDate, interval, flags, order, callout, context, memory); return memory; } +static void _runLoopTimerWithBlockContext(CFRunLoopTimerRef timer, void *opaqueBlock) { + typedef void (^timer_block_t) (CFRunLoopTimerRef timer); + timer_block_t block = (timer_block_t)opaqueBlock; + block(timer); +} + +CFRunLoopTimerRef CFRunLoopTimerCreateWithHandler(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, + void (^block) (CFRunLoopTimerRef timer)) { + + CFRunLoopTimerContext blockContext; + blockContext.version = 0; + blockContext.info = (void *)block; + blockContext.retain = (const void *(*)(const void *info))_Block_copy; + blockContext.release = (void (*)(const void *info))_Block_release; + blockContext.copyDescription = NULL; + return CFRunLoopTimerCreate(allocator, fireDate, interval, flags, order, _runLoopTimerWithBlockContext, &blockContext); +} + CFAbsoluteTime CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt) { CHECK_FOR_FORK(); CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFAbsoluteTime, rlt, "_cffireTime"); __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); - int64_t fireTime, result = 0; - __CFRunLoopTimerFireTSRLock(); - fireTime = rlt->_fireTSR; - __CFRunLoopTimerFireTSRUnlock(); + CFAbsoluteTime at = 0.0; __CFRunLoopTimerLock(rlt); + __CFRunLoopTimerFireTSRLock(); if (__CFIsValid(rlt)) { - result = fireTime; + at = rlt->_nextFireDate; } + __CFRunLoopTimerFireTSRUnlock(); __CFRunLoopTimerUnlock(rlt); - int64_t now2 = (int64_t)mach_absolute_time(); - CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); - return (0 == result) ? 0.0 : now1 + __CFTSRToTimeInterval(result - now2); + return at; } void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt, CFAbsoluteTime fireDate) { -//CFLog(6, CFSTR("CFRunLoopTimerSetNextFireDate(rlt %p, fireDate %f)"), rlt, fireDate); CHECK_FOR_FORK(); -//CFLog(4, CFSTR("CFRunLoopTimerSetNextFireDate(%p, %f) [limit: %f]"), rlt, fireDate, TIMER_DATE_LIMIT); + if (!__CFIsValid(rlt)) return; if (TIMER_DATE_LIMIT < fireDate) fireDate = TIMER_DATE_LIMIT; - rlt->_nextFireDate = fireDate; + int64_t nextFireTSR = 0LL; int64_t now2 = (int64_t)mach_absolute_time(); CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); - __CFRunLoopTimerFireTSRLock(); if (fireDate < now1) { - rlt->_fireTSR = now2; - } else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < fireDate) { - rlt->_fireTSR = LLONG_MAX; + nextFireTSR = now2; + } else if (TIMER_INTERVAL_LIMIT < fireDate - now1) { + nextFireTSR = now2 + __CFTimeIntervalToTSR(TIMER_INTERVAL_LIMIT); } else { - rlt->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1); + nextFireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1); } - if (rlt->_runLoop != NULL) { - __CFRunLoopTimerRescheduleWithAllModes(rlt); - } - __CFRunLoopTimerFireTSRUnlock(); + __CFRunLoopTimerLock(rlt); + if (NULL != rlt->_runLoop) { + CFIndex cnt = CFSetGetCount(rlt->_rlModes); + STACK_BUFFER_DECL(CFTypeRef, modes, cnt); + CFSetGetValues(rlt->_rlModes, (const void **)modes); + // To avoid A->B, B->A lock ordering issues when coming up + // towards the run loop from a source, the timer has to be + // unlocked, which means we have to protect from object + // invalidation, although that's somewhat expensive. + for (CFIndex idx = 0; idx < cnt; idx++) { + CFRetain(modes[idx]); + } + CFRunLoopRef rl = (CFRunLoopRef)CFRetain(rlt->_runLoop); + __CFRunLoopTimerUnlock(rlt); + __CFRunLoopLock(rl); + for (CFIndex idx = 0; idx < cnt; idx++) { + CFStringRef name = (CFStringRef)modes[idx]; + modes[idx] = __CFRunLoopFindMode(rl, name, false); + CFRelease(name); + } + __CFRunLoopTimerFireTSRLock(); + rlt->_fireTSR = nextFireTSR; + rlt->_nextFireDate = fireDate; + for (CFIndex idx = 0; idx < cnt; idx++) { + CFRunLoopModeRef rlm = (CFRunLoopModeRef)modes[idx]; + if (rlm) { + __CFRepositionTimerInMode(rlm, rlt, true); + } + } + __CFRunLoopTimerFireTSRUnlock(); + for (CFIndex idx = 0; idx < cnt; idx++) { + __CFRunLoopModeUnlock((CFRunLoopModeRef)modes[idx]); + } + __CFRunLoopUnlock(rl); + // This is setting the date of a timer, not a direct + // interaction with a run loop, so we'll do a wakeup + // (which may be costly) for the caller, just in case. + // (And useful for binary compatibility with older + // code used to the older timer implementation.) + if (rl != CFRunLoopGetCurrent()) CFRunLoopWakeUp(rl); + CFRelease(rl); + } else { + __CFRunLoopTimerFireTSRLock(); + rlt->_fireTSR = nextFireTSR; + rlt->_nextFireDate = fireDate; + __CFRunLoopTimerFireTSRUnlock(); + __CFRunLoopTimerUnlock(rlt); + } } CFTimeInterval CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt) { @@ -3607,50 +3502,56 @@ Boolean CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt) { CFIndex CFRunLoopTimerGetOrder(CFRunLoopTimerRef rlt) { CHECK_FOR_FORK(); - CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFIndex, rlt, "order"); __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); return rlt->_order; } void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt) { /* DOES CALLOUT */ CHECK_FOR_FORK(); -//CFLog(4, CFSTR("CFRunLoopTimerInvalidate(%p)"), rlt); CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, void, rlt, "invalidate"); __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); + __CFRunLoopTimerLock(rlt); if (!__CFRunLoopTimerIsDeallocating(rlt)) { CFRetain(rlt); } - __CFRunLoopTimerLock(rlt); if (__CFIsValid(rlt)) { CFRunLoopRef rl = rlt->_runLoop; void *info = rlt->_context.info; - __CFUnsetValid(rlt); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - __CFRunLoopTimerPortMapLock(); - if (NULL != __CFRLTPortMap) { - CFDictionaryRemoveValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port); - } - __CFRunLoopTimerPortMapUnlock(); - mk_timer_destroy(rlt->_port); - rlt->_port = MACH_PORT_NULL; -#endif rlt->_context.info = NULL; - __CFRunLoopTimerUnlock(rlt); + __CFUnsetValid(rlt); if (NULL != rl) { CFIndex cnt = CFSetGetCount(rlt->_rlModes); STACK_BUFFER_DECL(CFStringRef, modes, cnt); CFSetGetValues(rlt->_rlModes, (const void **)modes); + // To avoid A->B, B->A lock ordering issues when coming up + // towards the run loop from a source, the timer has to be + // unlocked, which means we have to protect from object + // invalidation, although that's somewhat expensive. + for (CFIndex idx = 0; idx < cnt; idx++) { + CFRetain(modes[idx]); + } + CFRetain(rl); + __CFRunLoopTimerUnlock(rlt); + // CFRunLoopRemoveTimer will lock the run loop while it + // needs that, but we also lock it out here to keep + // changes from occurring for this whole sequence. + __CFRunLoopLock(rl); for (CFIndex idx = 0; idx < cnt; idx++) { CFRunLoopRemoveTimer(rl, rlt, modes[idx]); } CFRunLoopRemoveTimer(rl, rlt, kCFRunLoopCommonModes); + __CFRunLoopUnlock(rl); + for (CFIndex idx = 0; idx < cnt; idx++) { + CFRelease(modes[idx]); + } + CFRelease(rl); + __CFRunLoopTimerLock(rlt); } if (NULL != rlt->_context.release) { rlt->_context.release(info); /* CALLOUT */ } - } else { - __CFRunLoopTimerUnlock(rlt); } + __CFRunLoopTimerUnlock(rlt); if (!__CFRunLoopTimerIsDeallocating(rlt)) { CFRelease(rlt); } @@ -3670,164 +3571,3 @@ void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt, CFRunLoopTimerContext *cont *context = rlt->_context; } - -#if DEPLOYMENT_TARGET_WINDOWS - -//#if MARRY_MESSAGE_QUEUE - -// Do we need to make sure it's not CFRunLoopRun processing the message queue? -CF_EXPORT LRESULT CALLBACK pumpRunLoopFromMessageQueue(int nCode, WPARAM wParam, LPARAM lParam) { - //if nCode < 0, we're supposed to blindly call CallNexthookEx instead of processing the message ourselves - if (nCode >= 0) { - MSG *msgPtr = (MSG *)lParam; - CFRunLoopRef rl = CFRunLoopGetCurrent(); - CFStringRef currMode; - - if (msgPtr->message == __kCFRunLoopV1SourceReadyMessage) { - CFRunLoopModeRef rlm; - CFRunLoopSourceRef rls; - __CFRunLoopLock(rl); - rlm = rl->_currentMode; - if (!rlm) { - rlm = __CFRunLoopFindMode(rl, kCFRunLoopDefaultMode, true); // returns the mode locked - } else { - __CFRunLoopModeLock(rlm); - } - rls = __CFRunLoopModeFindSourceForMachPort(rl, rlm, (__CFPort)msgPtr->lParam); - __CFRunLoopUnlock(rl); - if (rls) { - // Must still hold the mode lock when calling DoSource1 - __CFRunLoopDoSource1(rl, rlm, rls); - } - __CFRunLoopModeUnlock(rlm); - } - if (msgPtr->message == __kCFRunLoopV1SourceReadyMessage || msgPtr->message == __kCFRunLoopWakeUpMessage) { - // Must always pump the RL regardless of whether we received the wakeup message because whomever processed the v1 source may be assuming that the RL is running and will see further callouts. - currMode = CFRunLoopCopyCurrentMode(rl); - if (!currMode) { - currMode = kCFRunLoopDefaultMode; - CFRetain(currMode); - } - while (CFRunLoopRunInMode(currMode, 0.0, true) == kCFRunLoopRunHandledSource) { - ; - } - CFRelease(currMode); - } - } - return CallNextHookEx(__CFGetThreadSpecificData_inline()->_messageHook, nCode, wParam, lParam); -} - -void __CFRunLoopMsgWaitThread(void *theRL) { - CFRunLoopRef rl = (CFRunLoopRef)theRL; - Boolean allDone = FALSE; - - while (!allDone) { - - CFRunLoopModeRef rlm; - __CFPortSet waitSet; - DWORD waitResult = WAIT_TIMEOUT; - DWORD qMask; - HANDLE handleBuf[MAXIMUM_WAIT_OBJECTS]; - HANDLE *handles, *currHandle; - uint32_t handleCount, handleIndex; - Boolean freeHandles; - - __CFRunLoopLock(rl); - rlm = rl->_currentMode; - if (!rlm) { - rlm = __CFRunLoopFindMode(rl, kCFRunLoopDefaultMode, true); // Returns a locked mode - } else { - __CFRunLoopModeLock(rlm); - } - CFRetain(rlm); - waitSet = rlm->_portSet; - - // copy out the handles to be safe from other threads at work - handles = __CFPortSetGetPorts(waitSet, handleBuf, MAXIMUM_WAIT_OBJECTS, &handleCount); - freeHandles = (handles != handleBuf); - // Replace the wakeup port with our own update port - for (handleIndex = 0, currHandle = handles; handleIndex < handleCount; handleIndex ++, currHandle++) { - if (*currHandle == rl->_wakeUpPort) { - *currHandle = rl->_msgUpdatePort; - break; - } - } - - // Not sure what to do with this.... - // handles[handleCount] = rl->_msgShutdownPort; - // handleCount ++; - - qMask = rlm->_msgQMask; - - while (1) { - Boolean shuttingDown = false; - __CFRunLoopModeUnlock(rlm); - __CFRunLoopUnlock(rl); - - // What do we do if there are more than MAXIMUM_WAIT_OBJECTS - //waitResult = MsgWaitForMultipleObjects(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, false, INFINITE, qMask); - waitResult = WaitForMultipleObjects(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, false, INFINITE); - // Need to poll here to see if we've been told to die; if so, we must not touch rl. I think. - __CFRunLoopLock(rl); - __CFRunLoopModeLock(rlm); - ResetEvent(rl->_msgUpdatePort); - - __CFPort livePort = CFPORT_NULL; - if (waitResult == WAIT_FAILED) { - DWORD error = GetLastError(); - if (error == ERROR_INVALID_HANDLE) { - // A handle got freed out from underneath us. Force an update of our handle watch list. - livePort = rl->_msgUpdatePort; - } else { - CFAssert2(true, __kCFLogAssertion, "%s(): error %d from MsgWaitForMultipleObjects\n", __PRETTY_FUNCTION__,error); - } - } - if (waitResult >= WAIT_OBJECT_0 && waitResult < WAIT_OBJECT_0+handleCount) { - // a handle was signaled - livePort = handles[waitResult-WAIT_OBJECT_0]; - } else if (waitResult >= WAIT_ABANDONED_0 && waitResult < WAIT_ABANDONED_0+handleCount) { - // an "abandoned mutex object" - livePort = handles[waitResult-WAIT_ABANDONED_0]; - } - if (freeHandles){ - CFAllocatorDeallocate(kCFAllocatorSystemDefault, handles); - } - - if (livePort == rl->_msgUpdatePort) { - break; - // } else if (livePort == rl->_msgShutdownPort) { - // allDone = true; - // break; - } else { - // OutputDebugStr(L"Posting v1 source ready msg\n"); - ResetEvent(livePort); - PostThreadMessageW(rl->_threadID, __kCFRunLoopV1SourceReadyMessage, NULL, (LPARAM)livePort); - } - } - __CFRunLoopModeUnlock(rlm); - CFRelease(rlm); - __CFRunLoopUnlock(rl); - } -} - -// #endif - -// Called while holding the run loop lock - -//#if MARRY_MESSAGE_QUEUE - -void __CFRunLoopUpdateMsgWaitMarryMsgQueue(CFRunLoopRef rl) { - if (rl->_msgUpdatePort == CFPORT_NULL) { - rl->_msgUpdatePort = __CFPortAllocate(); - if (CFPORT_NULL == rl->_msgUpdatePort) HALT; - - // Kick off the MsgWaitThread - _beginthread(__CFRunLoopMsgWaitThread, 0, rl); - } - SetEvent(rl->_msgUpdatePort); -} -//#else -CF_INLINE void __CFRunLoopUpdateMsgWait(CFRunLoopRef rl) {} -//#endif - -#endif diff --git a/CFRunLoop.h b/CFRunLoop.h index cc9f923..6762f23 100644 --- a/CFRunLoop.h +++ b/CFRunLoop.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFRunLoop.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFRUNLOOP__) @@ -72,7 +72,7 @@ CF_EXPORT const CFStringRef kCFRunLoopCommonModes; CF_EXPORT CFTypeID CFRunLoopGetTypeID(void); CF_EXPORT CFRunLoopRef CFRunLoopGetCurrent(void); -CF_EXPORT CFRunLoopRef CFRunLoopGetMain(void) AVAILABLE_MAC_OS_X_VERSION_10_1_AND_LATER; +CF_EXPORT CFRunLoopRef CFRunLoopGetMain(void); CF_EXPORT CFStringRef CFRunLoopCopyCurrentMode(CFRunLoopRef rl); @@ -88,8 +88,8 @@ CF_EXPORT Boolean CFRunLoopIsWaiting(CFRunLoopRef rl); CF_EXPORT void CFRunLoopWakeUp(CFRunLoopRef rl); CF_EXPORT void CFRunLoopStop(CFRunLoopRef rl); -#if __BLOCKS__ && MAC_OS_X_VERSION_10_6 <= MAC_OS_X_VERSION_MAX_ALLOWED -CF_EXPORT void CFRunLoopPerformBlock(CFRunLoopRef rl, CFTypeRef mode, void (^block)(void)) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +#if __BLOCKS__ +CF_EXPORT void CFRunLoopPerformBlock(CFRunLoopRef rl, CFTypeRef mode, void (^block)(void)) CF_AVAILABLE(10_6, 4_0); #endif CF_EXPORT Boolean CFRunLoopContainsSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef mode); @@ -157,6 +157,9 @@ typedef void (*CFRunLoopObserverCallBack)(CFRunLoopObserverRef observer, CFRunLo CF_EXPORT CFTypeID CFRunLoopObserverGetTypeID(void); CF_EXPORT CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context); +#if __BLOCKS__ +CF_EXPORT CFRunLoopObserverRef CFRunLoopObserverCreateWithHandler(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, void (^block) (CFRunLoopObserverRef observer, CFRunLoopActivity activity)) CF_AVAILABLE(10_7, 5_0); +#endif CF_EXPORT CFOptionFlags CFRunLoopObserverGetActivities(CFRunLoopObserverRef observer); CF_EXPORT Boolean CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef observer); @@ -178,6 +181,10 @@ typedef void (*CFRunLoopTimerCallBack)(CFRunLoopTimerRef timer, void *info); CF_EXPORT CFTypeID CFRunLoopTimerGetTypeID(void); CF_EXPORT CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context); +#if __BLOCKS__ +CF_EXPORT CFRunLoopTimerRef CFRunLoopTimerCreateWithHandler(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, void (^block) (CFRunLoopTimerRef timer)) CF_AVAILABLE(10_7, 5_0); +#endif + CF_EXPORT CFAbsoluteTime CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef timer); CF_EXPORT void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef timer, CFAbsoluteTime fireDate); CF_EXPORT CFTimeInterval CFRunLoopTimerGetInterval(CFRunLoopTimerRef timer); diff --git a/CFRuntime.c b/CFRuntime.c index 92a8193..602ed94 100644 --- a/CFRuntime.c +++ b/CFRuntime.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFRuntime.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ @@ -40,30 +40,11 @@ #include #include #include -#include #include #include -#define objc_isAuto (0) -#else -#include #endif -#if DEPLOYMENT_TARGET_WINDOWS -#define _objc_getFreedObjectClass() 0 -#else -extern Class _objc_getFreedObjectClass(void); -#endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -extern void __CFRecordAllocationEvent(int eventnum, void *ptr, int64_t size, uint64_t data, const char *classname); -#else -#define __CFRecordAllocationEvent(a, b, c, d, e) ((void)0) -#endif - - -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -extern void instrumentObjcMessageSends(BOOL flag); -#endif #if DEPLOYMENT_TARGET_WINDOWS #include @@ -76,12 +57,14 @@ __kCFRetainEvent = 28, __kCFReleaseEvent = 29 }; -#if DEPLOYMENT_TARGET_WINDOWS +#if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX #include #else #include #endif +#define FAKE_INSTRUMENTS 0 + #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED bool __CFOASafe = false; @@ -113,6 +96,46 @@ void __CFSetLastAllocationEventName(void *ptr, const char *classname) { __CFObjectAllocSetLastAllocEventNameFunction(ptr, classname); } +#elif FAKE_INSTRUMENTS + +CF_EXPORT bool __CFOASafe = true; + +void __CFOAInitialize(void) { } + +void __CFRecordAllocationEvent(int eventnum, void *ptr, int64_t size, uint64_t data, const char *classname) { + if (!__CFOASafe) return; + if (!classname) classname = "(no class)"; + const char *event = "unknown event"; + switch (eventnum) { + case 21: + event = "zombie"; + break; + case 13: + case __kCFReleaseEvent: + event = "release"; + break; + case 12: + case __kCFRetainEvent: + event = "retain"; + break; + } + fprintf(stdout, "event,%d,%s,%p,%ld,%lu,%s\n", eventnum, event, ptr, (long)size, (unsigned long)data, classname); +} + +void __CFSetLastAllocationEventName(void *ptr, const char *classname) { + if (!__CFOASafe) return; + if (!classname) classname = "(no class)"; + fprintf(stdout, "name,%p,%s\n", ptr, classname ? classname : "(no class)"); +} + +#else + +bool __CFOASafe = false; + +void __CFOAInitialize(void) { } +void __CFRecordAllocationEvent(int eventnum, void *ptr, int64_t size, uint64_t data, const char *classname) { } +void __CFSetLastAllocationEventName(void *ptr, const char *classname) { } + #endif extern void __HALT(void); @@ -182,15 +205,14 @@ static const CFRuntimeClass __CFTypeClass = { // the lock does not protect most reading of these; we just leak the old table to allow read-only accesses to continue to work static CFSpinLock_t __CFBigRuntimeFunnel = CFSpinLockInit; -static CFRuntimeClass ** __CFRuntimeClassTable = NULL; -int32_t __CFRuntimeClassTableSize = 0; +static CFRuntimeClass * __CFRuntimeClassTable[__CFRuntimeClassTableSize] = {0}; static int32_t __CFRuntimeClassTableCount = 0; -uintptr_t *__CFRuntimeObjCClassTable = NULL; - -__private_extern__ void * (*__CFSendObjCMsg)(const void *, SEL, ...) = NULL; +__private_extern__ uintptr_t __CFRuntimeObjCClassTable[__CFRuntimeClassTableSize] = {0}; +#if !defined(__CFObjCIsCollectable) bool (*__CFObjCIsCollectable)(void *) = NULL; +#endif // Compiler uses this symbol name; must match compiler built-in decl, so we use 'int' #if __LP64__ @@ -198,18 +220,18 @@ int __CFConstantStringClassReference[24] = {0}; #else int __CFConstantStringClassReference[12] = {0}; #endif - +void *__CFConstantStringClassReferencePtr = &__CFConstantStringClassReference; Boolean _CFIsObjC(CFTypeID typeID, void *obj) { - __CFSpinLock(&__CFBigRuntimeFunnel); - Boolean b = ((typeID >= (CFTypeID)__CFRuntimeClassTableSize) || (((CFRuntimeBase *)obj)->_cfisa != (uintptr_t)__CFRuntimeObjCClassTable[typeID] && ((CFRuntimeBase *)obj)->_cfisa > (uintptr_t)0xFFF)); - __CFSpinUnlock(&__CFBigRuntimeFunnel); - return b; + return CF_IS_OBJC(typeID, obj); } CFTypeID _CFRuntimeRegisterClass(const CFRuntimeClass * const cls) { -// version field must be 0 // className must be pure ASCII string, non-null + if ((cls->version & _kCFRuntimeCustomRefCount) && !cls->refcount) { + CFLog(kCFLogLevelWarning, CFSTR("*** _CFRuntimeRegisterClass() given inconsistent class '%s'. Program will crash soon."), cls->className); + return _kCFRuntimeNotATypeID; + } __CFSpinLock(&__CFBigRuntimeFunnel); if (__CFMaxRuntimeTypes <= __CFRuntimeClassTableCount) { CFLog(kCFLogLevelWarning, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls->className); @@ -217,32 +239,9 @@ CFTypeID _CFRuntimeRegisterClass(const CFRuntimeClass * const cls) { return _kCFRuntimeNotATypeID; } if (__CFRuntimeClassTableSize <= __CFRuntimeClassTableCount) { - int32_t old_size = __CFRuntimeClassTableSize; - int32_t new_size = __CFRuntimeClassTableSize * 4; - - void *new_table1 = calloc(new_size, sizeof(CFRuntimeClass *)); - memmove(new_table1, __CFRuntimeClassTable, old_size * sizeof(CFRuntimeClass *)); - __CFRuntimeClassTable = (CFRuntimeClass**)new_table1; - - void *new_table2 = calloc(new_size, sizeof(uintptr_t)); - memmove(new_table2, __CFRuntimeObjCClassTable, old_size * sizeof(uintptr_t)); - for (CFIndex idx = old_size; idx < new_size; idx++) { - ((uintptr_t *)new_table2)[idx] = __CFRuntimeObjCClassTable[0]; - } - __CFRuntimeObjCClassTable = (uintptr_t *)new_table2; - - __CFRuntimeClassTableSize = new_size; - // The old value of __CFRuntimeClassTable is intentionally leaked - // for thread-safety reasons: - // other threads might have loaded the value of that, in functions here - // in this file executing in other threads, and may attempt to use it after - // this thread gets done reallocating here, so freeing is unsafe. We - // don't want to pay the expense of locking around all uses of these variables. - // The old value of __CFRuntimeObjCClassTable is intentionally leaked - // for thread-safety reasons: - // other threads might have loaded the value of that, since it is - // accessible via CFBridgingPriv.h, and may attempt to use it after - // this thread gets done reallocating here, so freeing is unsafe. + CFLog(kCFLogLevelWarning, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls->className); + __CFSpinUnlock(&__CFBigRuntimeFunnel); + return _kCFRuntimeNotATypeID; } __CFRuntimeClassTable[__CFRuntimeClassTableCount++] = (CFRuntimeClass *)cls; CFTypeID typeID = __CFRuntimeClassTableCount - 1; @@ -250,11 +249,6 @@ CFTypeID _CFRuntimeRegisterClass(const CFRuntimeClass * const cls) { return typeID; } -void _CFRuntimeBridgeClasses(CFTypeID cf_typeID, const char *objc_classname) { - __CFSpinLock(&__CFBigRuntimeFunnel); - __CFRuntimeObjCClassTable[cf_typeID] = (uintptr_t)objc_getFutureClass(objc_classname); - __CFSpinUnlock(&__CFBigRuntimeFunnel); -} const CFRuntimeClass * _CFRuntimeGetClassWithTypeID(CFTypeID typeID) { return __CFRuntimeClassTable[typeID]; // hopelessly unthreadsafe @@ -269,19 +263,8 @@ void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID) { #if defined(DEBUG) || defined(ENABLE_ZOMBIES) -/* CFZombieLevel levels: - * bit 0: scribble deallocated CF object memory - * bit 1: do not scribble on CFRuntimeBase header (when bit 0) - * bit 4: do not free CF objects - * bit 7: use 3rd-order byte as scribble byte for dealloc (otherwise 0xFC) - */ - -static uint32_t __CFZombieLevel = 0x0; __private_extern__ uint8_t __CFZombieEnabled = 0; __private_extern__ uint8_t __CFDeallocateZombies = 0; -#if !__OBJC2__ -static void *_original_objc_dealloc = 0; -#endif void _CFEnableZombies(void) { __CFZombieEnabled = 0xFF; @@ -301,28 +284,32 @@ CF_INLINE CFOptionFlags CF_GET_COLLECTABLE_MEMORY_TYPE(const CFRuntimeClass *cls #endif CFTypeRef _CFRuntimeCreateInstance(CFAllocatorRef allocator, CFTypeID typeID, CFIndex extraBytes, unsigned char *category) { + if (__CFRuntimeClassTableSize <= typeID) HALT; CFAssert1(typeID != _kCFRuntimeNotATypeID, __kCFLogAssertion, "%s(): Uninitialized type id", __PRETTY_FUNCTION__); CFRuntimeClass *cls = __CFRuntimeClassTable[typeID]; if (NULL == cls) { return NULL; } - allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; - if (kCFAllocatorNull == allocator) { + Boolean customRC = !!(cls->version & _kCFRuntimeCustomRefCount); + if (customRC && !cls->refcount) { + CFLog(kCFLogLevelWarning, CFSTR("*** _CFRuntimeCreateInstance() found inconsistent class '%s'."), cls->className); + return NULL; + } + if (customRC && kCFUseCollectableAllocator && (kCFAllocatorSystemDefaultGCRefZero == allocator || kCFAllocatorDefaultGCRefZero == allocator)) { + CFLog(kCFLogLevelWarning, CFSTR("*** _CFRuntimeCreateInstance(): special zero-ref allocators cannot be used with class '%s' with custom ref counting."), cls->className); + return NULL; + } + CFAllocatorRef realAllocator = _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator); + if (kCFAllocatorNull == realAllocator) { return NULL; } - Boolean usesSystemDefaultAllocator = (allocator == kCFAllocatorSystemDefault); + Boolean usesSystemDefaultAllocator = _CFAllocatorIsSystemDefault(realAllocator); CFIndex size = sizeof(CFRuntimeBase) + extraBytes + (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef)); size = (size + 0xF) & ~0xF; // CF objects are multiples of 16 in size // CFType version 0 objects are unscanned by default since they don't have write-barriers and hard retain their innards // CFType version 1 objects are scanned and use hand coded write-barriers to store collectable storage within CFRuntimeBase *memory = (CFRuntimeBase *)CFAllocatorAllocate(allocator, size, CF_GET_COLLECTABLE_MEMORY_TYPE(cls)); if (NULL == memory) { - CFStringRef msg = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("Attempt to allocate %ld bytes for %s failed"), size, category ? (char *)category : (char *)cls->className); - { - CFLog(kCFLogLevelCritical, CFSTR("%@"), msg); - HALT; - } - CFRelease(msg); return NULL; } if (!kCFUseCollectableAllocator || !CF_IS_COLLECTABLE_ALLOCATOR(allocator) || !(CF_GET_COLLECTABLE_MEMORY_TYPE(cls) & __kCFAllocatorGCScannedMemory)) { @@ -336,16 +323,29 @@ CFTypeRef _CFRuntimeCreateInstance(CFAllocatorRef allocator, CFTypeID typeID, CF if (!usesSystemDefaultAllocator) { // add space to hold allocator ref for non-standard allocators. // (this screws up 8 byte alignment but seems to work) - *(CFAllocatorRef *)((char *)memory) = (CFAllocatorRef)CFRetain(allocator); + *(CFAllocatorRef *)((char *)memory) = (CFAllocatorRef)CFRetain(realAllocator); memory = (CFRuntimeBase *)((char *)memory + sizeof(CFAllocatorRef)); } memory->_cfisa = __CFISAForTypeID(typeID); + uint32_t rc = 0; #if __LP64__ - *(uint32_t *)(memory->_cfinfo) = (uint32_t)((0 << 24) + ((typeID & 0xFFFF) << 8) + (usesSystemDefaultAllocator ? 0x80 : 0x00)); - memory->_rc = 1; + if (!kCFUseCollectableAllocator || (kCFAllocatorSystemDefaultGCRefZero != allocator && kCFAllocatorDefaultGCRefZero != allocator)) { + memory->_rc = 1; + } + if (customRC) { + memory->_rc = 0xFFFFFFFFU; + rc = 0xFF; + } #else - *(uint32_t *)(memory->_cfinfo) = (uint32_t)((1 << 24) + ((typeID & 0xFFFF) << 8) + (usesSystemDefaultAllocator ? 0x80 : 0x00)); + if (!kCFUseCollectableAllocator || (kCFAllocatorSystemDefaultGCRefZero != allocator && kCFAllocatorDefaultGCRefZero != allocator)) { + rc = 1; + } + if (customRC) { + rc = 0xFF; + } #endif + uint32_t *cfinfop = (uint32_t *)&(memory->_cfinfo); + *cfinfop = (uint32_t)((rc << 24) | (customRC ? 0x800000 : 0x0) | ((uint32_t)typeID << 8) | (usesSystemDefaultAllocator ? 0x80 : 0x00)); if (NULL != cls->init) { (cls->init)(memory); } @@ -354,36 +354,43 @@ CFTypeRef _CFRuntimeCreateInstance(CFAllocatorRef allocator, CFTypeID typeID, CF void _CFRuntimeInitStaticInstance(void *ptr, CFTypeID typeID) { CFAssert1(typeID != _kCFRuntimeNotATypeID, __kCFLogAssertion, "%s(): Uninitialized type id", __PRETTY_FUNCTION__); - if (NULL == __CFRuntimeClassTable[typeID]) { - return; + if (__CFRuntimeClassTableSize <= typeID) HALT; + CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; + Boolean customRC = !!(cfClass->version & _kCFRuntimeCustomRefCount); + if (customRC) { + CFLog(kCFLogLevelError, CFSTR("*** Cannot initialize a static instance to a class (%s) with custom ref counting"), cfClass->className); + return; } CFRuntimeBase *memory = (CFRuntimeBase *)ptr; memory->_cfisa = __CFISAForTypeID(typeID); - *(uint32_t *)(memory->_cfinfo) = (uint32_t)((0 << 24) + ((typeID & 0xFFFF) << 8) + 0x80); + uint32_t *cfinfop = (uint32_t *)&(memory->_cfinfo); + *cfinfop = (uint32_t)(((customRC ? 0xFF : 0) << 24) | (customRC ? 0x800000 : 0x0) | ((uint32_t)typeID << 8) | 0x80); #if __LP64__ - memory->_rc = 0; + memory->_rc = customRC ? 0xFFFFFFFFU : 0x0; #endif - if (NULL != __CFRuntimeClassTable[typeID]->init) { - (__CFRuntimeClassTable[typeID]->init)(memory); + if (NULL != cfClass->init) { + (cfClass->init)(memory); } } -void _CFRuntimeSetInstanceTypeID(CFTypeRef cf, CFTypeID typeID) { - *(uint16_t *)(((CFRuntimeBase *)cf)->_cfinfo + 1) = (uint16_t)(typeID & 0xFFFF); -} - -__private_extern__ Boolean __CFRuntimeIsFreedObject(id anObject) { - if (!anObject) return false; - static Class freedClass = Nil; - if (!freedClass) freedClass = _objc_getFreedObjectClass(); - Class cls = object_getClass(anObject); - if (cls == freedClass) return true; - // in 64-bit, a future class has nil isa, and calling class_getName() on - // such will crash so we do this test; zombie classes are not future classes - if (object_getClass((id)cls) == nil) return false; - const char *cname = class_getName(cls); - if (cname && 0 == strncmp(cname, "_NSZombie_", 10)) return true; - return false; +void _CFRuntimeSetInstanceTypeID(CFTypeRef cf, CFTypeID newTypeID) { + if (__CFRuntimeClassTableSize <= newTypeID) HALT; + uint32_t *cfinfop = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); + CFTypeID currTypeID = (*cfinfop >> 8) & 0x03FF; // mask up to 0x0FFF + CFRuntimeClass *newcfClass = __CFRuntimeClassTable[newTypeID]; + Boolean newCustomRC = (newcfClass->version & _kCFRuntimeCustomRefCount); + CFRuntimeClass *currcfClass = __CFRuntimeClassTable[currTypeID]; + Boolean currCustomRC = (currcfClass->version & _kCFRuntimeCustomRefCount); + if (currCustomRC || (0 != currTypeID && newCustomRC)) { + CFLog(kCFLogLevelError, CFSTR("*** Cannot change the CFTypeID of a %s to a %s due to custom ref counting"), currcfClass->className, newcfClass->className); + return; + } + // Going from current type ID of 0 to anything is allowed, but if + // the object has somehow already been retained and the transition + // is to a class doing custom ref counting, the ref count isn't + // transferred and there will probably be a crash later when the + // object is freed too early. + *cfinfop = (*cfinfop & 0xFFF000FFU) | ((uint32_t)newTypeID << 8); } @@ -395,7 +402,7 @@ enum { #if DEPLOYMENT_TARGET_MACOSX #define NUM_EXTERN_TABLES 8 #define EXTERN_TABLE_IDX(O) (((uintptr_t)(O) >> 8) & 0x7) -#elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS +#elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX #define NUM_EXTERN_TABLES 1 #define EXTERN_TABLE_IDX(O) 0 #else @@ -415,46 +422,106 @@ CF_EXPORT uintptr_t __CFDoExternRefOperation(uintptr_t op, id obj) { if (nil == obj) HALT; uintptr_t idx = EXTERN_TABLE_IDX(obj); uintptr_t disguised = DISGUISE(obj); -#if DEPLOYMENT_TARGET_WINDOWS - // assume threaded on windows for now - int thr = 1; -#else - int thr = pthread_is_threaded_np(); -#endif CFSpinLock_t *lock = &__NSRetainCounters[idx].lock; CFBasicHashRef table = __NSRetainCounters[idx].table; uintptr_t count; switch (op) { case 300: // increment case 350: // increment, no event - if (thr) __CFSpinLock(lock); + __CFSpinLock(lock); CFBasicHashAddValue(table, disguised, disguised); - if (thr) __CFSpinUnlock(lock); + __CFSpinUnlock(lock); if (__CFOASafe && op != 350) __CFRecordAllocationEvent(__kCFObjectRetainedEvent, obj, 0, 0, NULL); return (uintptr_t)obj; case 400: // decrement if (__CFOASafe) __CFRecordAllocationEvent(__kCFObjectReleasedEvent, obj, 0, 0, NULL); case 450: // decrement, no event - if (thr) __CFSpinLock(lock); + __CFSpinLock(lock); count = (uintptr_t)CFBasicHashRemoveValue(table, disguised); - if (thr) __CFSpinUnlock(lock); + __CFSpinUnlock(lock); return 0 == count; case 500: - if (thr) __CFSpinLock(lock); + __CFSpinLock(lock); count = (uintptr_t)CFBasicHashGetCountOfKey(table, disguised); - if (thr) __CFSpinUnlock(lock); + __CFSpinUnlock(lock); return count; } return 0; } +static void __CFExternRefNullFreeCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) { +} + +static uintptr_t __CFExternRefNullRetainValue(CFConstBasicHashRef ht, uintptr_t stack_value) { + return stack_value; +} + +static uintptr_t __CFExternRefNullRetainKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + return stack_key; +} -CFTypeID __CFGenericTypeID(const void *cf) { - return (*(uint32_t *)(((CFRuntimeBase *)cf)->_cfinfo) >> 8) & 0xFFFF; +static void __CFExternRefNullReleaseValue(CFConstBasicHashRef ht, uintptr_t stack_value) { +} + +static void __CFExternRefNullReleaseKey(CFConstBasicHashRef ht, uintptr_t stack_key) { +} + +static Boolean __CFExternRefNullEquateValues(CFConstBasicHashRef ht, uintptr_t coll_value1, uintptr_t stack_value2) { + return coll_value1 == stack_value2; +} + +static Boolean __CFExternRefNullEquateKeys(CFConstBasicHashRef ht, uintptr_t coll_key1, uintptr_t stack_key2) { + return coll_key1 == stack_key2; +} + +static uintptr_t __CFExternRefNullHashKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + return stack_key; +} + +static uintptr_t __CFExternRefNullGetIndirectKey(CFConstBasicHashRef ht, uintptr_t coll_value) { + return 0; +} + +static CFStringRef __CFExternRefNullCopyValueDescription(CFConstBasicHashRef ht, uintptr_t stack_value) { + return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)stack_value); +} + +static CFStringRef __CFExternRefNullCopyKeyDescription(CFConstBasicHashRef ht, uintptr_t stack_key) { + return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)stack_key); } +static CFBasicHashCallbacks *__CFExternRefNullCopyCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb); + +static const CFBasicHashCallbacks CFExternRefCallbacks = { + __CFExternRefNullCopyCallbacks, + __CFExternRefNullFreeCallbacks, + __CFExternRefNullRetainValue, + __CFExternRefNullRetainKey, + __CFExternRefNullReleaseValue, + __CFExternRefNullReleaseKey, + __CFExternRefNullEquateValues, + __CFExternRefNullEquateKeys, + __CFExternRefNullHashKey, + __CFExternRefNullGetIndirectKey, + __CFExternRefNullCopyValueDescription, + __CFExternRefNullCopyKeyDescription +}; + +static CFBasicHashCallbacks *__CFExternRefNullCopyCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) { + return (CFBasicHashCallbacks *)&CFExternRefCallbacks; +} + +CF_EXPORT CFTypeID CFNumberGetTypeID(void); + CF_INLINE CFTypeID __CFGenericTypeID_inline(const void *cf) { - return (*(uint32_t *)(((CFRuntimeBase *)cf)->_cfinfo) >> 8) & 0xFFFF; + // yes, 10 bits masked off, though 12 bits are there for the type field; __CFRuntimeClassTableSize is 1024 + uint32_t *cfinfop = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); + CFTypeID typeID = (*cfinfop >> 8) & 0x03FF; // mask up to 0x0FFF + return typeID; +} + +CFTypeID __CFGenericTypeID(const void *cf) { + return __CFGenericTypeID_inline(cf); } CFTypeID CFTypeGetTypeID(void) { @@ -470,37 +537,17 @@ __private_extern__ void __CFGenericValidateType_(CFTypeRef cf, CFTypeID type, co #define __CFGenericAssertIsCF(cf) \ CFAssert2(cf != NULL && (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]) && (__kCFNotATypeTypeID != __CFGenericTypeID_inline(cf)) && (__kCFTypeTypeID != __CFGenericTypeID_inline(cf)), __kCFLogAssertion, "%s(): pointer %p is not a CF object", __PRETTY_FUNCTION__, cf); -#if 0 #define CFTYPE_IS_OBJC(obj) (false) #define CFTYPE_OBJC_FUNCDISPATCH0(rettype, obj, sel) do {} while (0) #define CFTYPE_OBJC_FUNCDISPATCH1(rettype, obj, sel, a1) do {} while (0) -#else - -CF_INLINE int CFTYPE_IS_OBJC(const void *obj) { - CFTypeID typeID = __CFGenericTypeID_inline(obj); - return CF_IS_OBJC(typeID, obj); -} - -#define CFTYPE_OBJC_FUNCDISPATCH0(rettype, obj, sel) \ - if (CFTYPE_IS_OBJC(obj)) \ - {rettype (*func)(void *, SEL) = (rettype (*)(void *, SEL))objc_msgSend; \ - static SEL s = NULL; if (!s) s = sel_registerName(sel); \ - return func((void *)obj, s);} -#define CFTYPE_OBJC_FUNCDISPATCH1(rettype, obj, sel, a1) \ - if (CFTYPE_IS_OBJC(obj)) \ - {rettype (*func)(void *, SEL, ...) = (rettype (*)(void *, SEL, ...))objc_msgSend; \ - static SEL s = NULL; if (!s) s = sel_registerName(sel); \ - return func((void *)obj, s, (a1));} - -#endif CFTypeID CFGetTypeID(CFTypeRef cf) { #if defined(DEBUG) if (NULL == cf) HALT; #endif - CFTYPE_OBJC_FUNCDISPATCH0(CFTypeID, cf, "_cfTypeID"); + CFTYPE_OBJC_FUNCDISPATCH0(CFTypeID, cf, _cfTypeID); __CFGenericAssertIsCF(cf); return __CFGenericTypeID_inline(cf); } @@ -512,42 +559,18 @@ CFStringRef CFCopyTypeIDDescription(CFTypeID type) { // Bit 31 (highest bit) in second word of cf instance indicates external ref count -CF_EXPORT void _CFRelease(CFTypeRef cf); -CF_EXPORT CFTypeRef _CFRetain(CFTypeRef cf); +static CFTypeRef _CFRetain(CFTypeRef cf, Boolean tryR); CFTypeRef CFRetain(CFTypeRef cf) { if (NULL == cf) HALT; - if (CF_IS_COLLECTABLE(cf)) { - if (CFTYPE_IS_OBJC(cf)) { - // always honor CFRetain's with a GC-visible retain. - auto_zone_retain(auto_zone(), (void*)cf); - return cf; - } else { - // special case CF objects for performance. - return _CFRetain(cf); - } - } - CFTYPE_OBJC_FUNCDISPATCH0(CFTypeRef, cf, "retain"); if (cf) __CFGenericAssertIsCF(cf); - return _CFRetain(cf); + return _CFRetain(cf, false); } -__private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf); +static void _CFRelease(CFTypeRef cf); void CFRelease(CFTypeRef cf) { if (NULL == cf) HALT; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - if (CF_IS_COLLECTABLE(cf)) { - if (CFTYPE_IS_OBJC(cf)) { - // release the GC-visible reference. - auto_zone_release(auto_zone(), (void*)cf); - } else { - // special-case CF objects for better performance. - _CFRelease(cf); - } - return; - } -#endif #if 0 void **addrs[2] = {&&start, &&end}; start:; @@ -556,7 +579,6 @@ void CFRelease(CFTypeRef cf) { HALT; } #endif - CFTYPE_OBJC_FUNCDISPATCH0(void, cf, "release"); if (cf) __CFGenericAssertIsCF(cf); _CFRelease(cf); #if 0 @@ -565,13 +587,12 @@ void CFRelease(CFTypeRef cf) { } +__private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf); + __private_extern__ const void *__CFStringCollectionCopy(CFAllocatorRef allocator, const void *ptr) { if (NULL == ptr) HALT; CFStringRef theString = (CFStringRef)ptr; - CFStringRef result = CFStringCreateCopy(allocator, theString); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - result = (CFStringRef)CFMakeCollectable(result); - } + CFStringRef result = CFStringCreateCopy(_CFConvertAllocatorToGCRefZeroEquivalent(allocator), theString); return (const void *)result; } @@ -583,13 +604,12 @@ __private_extern__ const void *__CFTypeCollectionRetain(CFAllocatorRef allocator // only collections allocated in the GC zone can opt-out of reference counting. if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { if (CFTYPE_IS_OBJC(cf)) return cf; // do nothing for OBJC objects. - if (auto_zone_is_valid_pointer(auto_zone(), ptr)) { + if (auto_zone_is_valid_pointer(objc_collectableZone(), ptr)) { CFRuntimeClass *cfClass = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]; if (cfClass->version & _kCFRuntimeResourcefulObject) { // GC: If this a CF object in the GC heap that is marked resourceful, then // it must be retained keep it alive in a CF collection. - // We're basically inlining CFRetain() here, to avoid extra heap membership tests. - _CFRetain(cf); + CFRetain(cf); } else ; // don't retain normal CF objects @@ -619,16 +639,15 @@ __private_extern__ void __CFTypeCollectionRelease(CFAllocatorRef allocator, cons // only collections allocated in the GC zone can opt-out of reference counting. if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { if (CFTYPE_IS_OBJC(cf)) return; // do nothing for OBJC objects. - if (auto_zone_is_valid_pointer(auto_zone(), cf)) { + if (auto_zone_is_valid_pointer(objc_collectableZone(), cf)) { #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED // GC: If this a CF object in the GC heap that is marked uncollectable, then // must balance the retain done in __CFTypeCollectionRetain(). - // We're basically inlining CFRelease() here, to avoid extra heap membership tests. CFRuntimeClass *cfClass = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]; if (cfClass->version & _kCFRuntimeResourcefulObject) { // reclaim is called by _CFRelease(), which must be called to keep the // CF and GC retain counts in sync. - _CFRelease(cf); + CFRelease(cf); } else { // avoid releasing normal CF objects. Like other collections, for example } @@ -649,7 +668,6 @@ __private_extern__ void __CFTypeCollectionRelease(CFAllocatorRef allocator, cons #if !__LP64__ static CFSpinLock_t __CFRuntimeExternRefCountTableLock = CFSpinLockInit; -static CFMutableBagRef __CFRuntimeExternRefCountTable = NULL; #endif static uint64_t __CFGetFullRetainCount(CFTypeRef cf) { @@ -674,33 +692,27 @@ static uint64_t __CFGetFullRetainCount(CFTypeRef cf) { #endif } -CFTypeRef _CFRetainGC(CFTypeRef cf) { -#if defined(DEBUG) - if (kCFUseCollectableAllocator && !CF_IS_COLLECTABLE(cf)) { - fprintf(stderr, "non-auto object %p passed to _CFRetainGC.\n", cf); - HALT; - } -#endif - return kCFUseCollectableAllocator ? cf : CFRetain(cf); -} - -void _CFReleaseGC(CFTypeRef cf) { -#if defined(DEBUG) - if (kCFUseCollectableAllocator && !CF_IS_COLLECTABLE(cf)) { - fprintf(stderr, "non-auto object %p passed to _CFReleaseGC.\n", cf); - HALT; - } -#endif - if (!kCFUseCollectableAllocator) CFRelease(cf); -} - CFIndex CFGetRetainCount(CFTypeRef cf) { if (NULL == cf) HALT; - if (CF_IS_COLLECTABLE(cf)) { - if (CFTYPE_IS_OBJC(cf)) return auto_zone_retain_count(auto_zone(), cf); - } else { - CFTYPE_OBJC_FUNCDISPATCH0(CFIndex, cf, "retainCount"); - __CFGenericAssertIsCF(cf); + uint32_t cfinfo = *(uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); + if (cfinfo & 0x800000) { // custom ref counting for object + CFTypeID typeID = (cfinfo >> 8) & 0x03FF; // mask up to 0x0FFF + CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; + uint32_t (*refcount)(intptr_t, CFTypeRef) = cfClass->refcount; + if (!refcount || !(cfClass->version & _kCFRuntimeCustomRefCount) || (((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS] != 0xFF)) { + HALT; // bogus object + } +#if __LP64__ + if (((CFRuntimeBase *)cf)->_rc != 0xFFFFFFFFU) { + HALT; // bogus object + } +#endif + uint32_t rc = refcount(0, cf); +#if __LP64__ + return (CFIndex)rc; +#else + return (rc < LONG_MAX) ? (CFIndex)rc : (CFIndex)LONG_MAX; +#endif } uint64_t rc = __CFGetFullRetainCount(cf); return (rc < (uint64_t)LONG_MAX) ? (CFIndex)rc : (CFIndex)LONG_MAX; @@ -708,29 +720,6 @@ CFIndex CFGetRetainCount(CFTypeRef cf) { CFTypeRef CFMakeCollectable(CFTypeRef cf) { if (NULL == cf) return NULL; - if (CF_IS_COLLECTABLE(cf)) { - objc_assertRegisteredThreadWithCollector(); -#if defined(DEBUG) - CFAllocatorRef allocator = CFGetAllocator(cf); - if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - CFLog(kCFLogLevelWarning, CFSTR("object %p with non-GC allocator %p passed to CFMakeCollectable."), cf, allocator); - HALT; - } -#endif - if (!CFTYPE_IS_OBJC(cf)) { - CFRuntimeClass *cfClass = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]; - if (cfClass->version & (_kCFRuntimeResourcefulObject)) { - // don't allow the collector to manage uncollectable objects. - CFLog(kCFLogLevelWarning, CFSTR("uncollectable object %p passed to CFMakeCollectable."), cf); - HALT; - } - } - if (CFGetRetainCount(cf) == 0) { - CFLog(kCFLogLevelWarning, CFSTR("object %p with 0 retain-count passed to CFMakeCollectable."), cf); - return cf; - } - CFRelease(cf); - } return cf; } @@ -746,8 +735,8 @@ Boolean CFEqual(CFTypeRef cf1, CFTypeRef cf2) { if (NULL == cf1) HALT; if (NULL == cf2) HALT; if (cf1 == cf2) return true; - CFTYPE_OBJC_FUNCDISPATCH1(Boolean, cf1, "isEqual:", cf2); - CFTYPE_OBJC_FUNCDISPATCH1(Boolean, cf2, "isEqual:", cf1); + CFTYPE_OBJC_FUNCDISPATCH1(Boolean, cf1, isEqual:, cf2); + CFTYPE_OBJC_FUNCDISPATCH1(Boolean, cf2, isEqual:, cf1); __CFGenericAssertIsCF(cf1); __CFGenericAssertIsCF(cf2); if (__CFGenericTypeID_inline(cf1) != __CFGenericTypeID_inline(cf2)) return false; @@ -759,29 +748,23 @@ Boolean CFEqual(CFTypeRef cf1, CFTypeRef cf2) { CFHashCode CFHash(CFTypeRef cf) { if (NULL == cf) HALT; - CFTYPE_OBJC_FUNCDISPATCH0(CFHashCode, cf, "hash"); + CFTYPE_OBJC_FUNCDISPATCH0(CFHashCode, cf, hash); __CFGenericAssertIsCF(cf); - if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->hash) { - return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->hash(cf); + CFHashCode (*hash)(CFTypeRef cf) = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->hash; + if (NULL != hash) { + return hash(cf); } + if (CF_IS_COLLECTABLE(cf)) return (CFHashCode)_object_getExternalHash((id)cf); return (CFHashCode)cf; } // definition: produces a normally non-NULL debugging description of the object CFStringRef CFCopyDescription(CFTypeRef cf) { - if (NULL == cf) HALT; - if (CFTYPE_IS_OBJC(cf)) { - static SEL s = NULL; - CFStringRef (*func)(void *, SEL) = (CFStringRef (*)(void *, SEL))objc_msgSend; - if (!s) s = sel_registerName("_copyDescription"); - CFStringRef result = func((void *)cf, s); - return result; - } - // CFTYPE_OBJC_FUNCDISPATCH0(CFStringRef, cf, "_copyDescription"); // XXX returns 0 refcounted item under GC + if (NULL == cf) return NULL; + // CFTYPE_OBJC_FUNCDISPATCH0(CFStringRef, cf, _copyDescription); // XXX returns 0 refcounted item under GC __CFGenericAssertIsCF(cf); if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyDebugDesc) { - CFStringRef result; - result = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyDebugDesc(cf); + CFStringRef result = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyDebugDesc(cf); if (NULL != result) return result; } return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%s %p [%p]>"), __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->className, cf, CFGetAllocator(cf)); @@ -789,16 +772,7 @@ CFStringRef CFCopyDescription(CFTypeRef cf) { // Definition: if type produces a formatting description, return that string, otherwise NULL __private_extern__ CFStringRef __CFCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { - if (NULL == cf) HALT; - if (CFTYPE_IS_OBJC(cf)) { - static SEL s = NULL, r = NULL; - CFStringRef (*func)(void *, SEL, CFDictionaryRef) = (CFStringRef (*)(void *, SEL, CFDictionaryRef))objc_msgSend; - BOOL (*rfunc)(void *, SEL, SEL) = (BOOL (*)(void *, SEL, SEL))objc_msgSend; - if (!s) s = sel_registerName("_copyFormattingDescription:"); - if (!r) r = sel_registerName("respondsToSelector:"); - if (s && rfunc((void *)cf, r, s)) return func((void *)cf, s, formatOptions); - return NULL; - } + if (NULL == cf) return NULL; __CFGenericAssertIsCF(cf); if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyFormattingDesc) { return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyFormattingDesc(cf, formatOptions); @@ -810,16 +784,12 @@ extern CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef); CFAllocatorRef CFGetAllocator(CFTypeRef cf) { if (NULL == cf) return kCFAllocatorSystemDefault; -// CF: need to get allocator from objc objects in better way...how? -// -> bridging of CFAllocators and malloc_zone_t will help this - if (CFTYPE_IS_OBJC(cf)) return __CFGetDefaultAllocator(); if (__kCFAllocatorTypeID_CONST == __CFGenericTypeID_inline(cf)) { return __CFAllocatorGetAllocator(cf); } return __CFGetAllocator(cf); } -extern void __CFBaseInitialize(void); extern void __CFNullInitialize(void); extern void __CFAllocatorInitialize(void); extern void __CFStringInitialize(void); @@ -846,12 +816,22 @@ extern void __CFPlugInInstanceInitialize(void); extern void __CFUUIDInitialize(void); extern void __CFBinaryHeapInitialize(void); extern void __CFBitVectorInitialize(void); +#if DEPLOYMENT_TARGET_LINUX +__private_extern__ void __CFTSDLinuxInitialize(); +#endif #if DEPLOYMENT_TARGET_WINDOWS -extern void __CFWindowsMessageQueueInitialize(void); -extern void __CFWindowsNamedPipeInitialize(void); -extern void __CFBaseCleanup(void); +// From CFPlatform.c +__private_extern__ void __CFTSDWindowsInitialize(void); +__private_extern__ void __CFTSDWindowsCleanup(void); +__private_extern__ void __CFFinalizeWindowsThreadData(); #endif extern void __CFStreamInitialize(void); +extern void __CFCalendarInitialize(); +extern void __CFTimeZoneInitialize(); +#if DEPLOYMENT_TARGET_LINUX +extern void __CFCalendarInitialize(); +extern void __CFTimeZoneInitialize(); +#endif #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED __private_extern__ uint8_t __CF120290 = false; @@ -921,6 +901,9 @@ static struct { {"CFStringDisableROM", NULL}, {"CF_CHARSET_PATH", NULL}, {"__CF_USER_TEXT_ENCODING", NULL}, + {"__CFPREFERENCES_AUTOSYNC_INTERVAL", NULL}, + {"__CFPREFERENCES_USE_OLD_UID_BEHAVIOR", NULL}, + {"CFNumberDisableCache", NULL}, {NULL, NULL}, // the last one is for optional "COMMAND_MODE" "legacy", do not use this slot, insert before }; @@ -941,9 +924,13 @@ __private_extern__ const char *__CFgetenv(const char *n) { CF_EXPORT pthread_t _CFMainPThread; pthread_t _CFMainPThread = kNilPthreadT; -CF_EXPORT bool kCFUseCollectableAllocator = false; +#undef kCFUseCollectableAllocator +CF_EXPORT bool kCFUseCollectableAllocator; +bool kCFUseCollectableAllocator = false; __private_extern__ Boolean __CFProphylacticAutofsAccess = false; +__private_extern__ Boolean __CFInitializing = 0; +__private_extern__ Boolean __CFInitialized = 0; #if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD static void __CFInitialize(void) __attribute__ ((constructor)); @@ -953,33 +940,41 @@ static CF_EXPORT #endif void __CFInitialize(void) { - static int __done = 0; - if (!__done) { - __done = 1; + if (!__CFInitialized && !__CFInitializing) { + __CFInitializing = 1; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS if (!pthread_main_np()) HALT; // CoreFoundation must be initialized on the main thread +#endif _CFMainPThread = pthread_self(); +#if DEPLOYMENT_TARGET_WINDOWS + // Must not call any CF functions + __CFTSDWindowsInitialize(); +#elif DEPLOYMENT_TARGET_LINUX + __CFTSDLinuxInitialize(); +#endif + __CFProphylacticAutofsAccess = true; for (CFIndex idx = 0; idx < sizeof(__CFEnv) / sizeof(__CFEnv[0]); idx++) { __CFEnv[idx].value = __CFEnv[idx].name ? getenv(__CFEnv[idx].name) : NULL; } +#if !defined(kCFUseCollectableAllocator) kCFUseCollectableAllocator = objc_collectingEnabled(); +#endif if (kCFUseCollectableAllocator) { +#if !defined(__CFObjCIsCollectable) __CFObjCIsCollectable = (bool (*)(void *))objc_isAuto; +#endif } #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED UInt32 s, r; __CFStringGetUserDefaultEncoding(&s, &r); // force the potential setenv to occur early pthread_atfork(__01121__, NULL, __01123__); - const char *value2 = __CFgetenv("NSObjCMessageLoggingEnabled"); - if (value2 && (*value2 == 'Y' || *value2 == 'y')) instrumentObjcMessageSends(1); -#elif DEPLOYMENT_TARGET_WINDOWS -#else #endif #if defined(DEBUG) || defined(ENABLE_ZOMBIES) @@ -987,27 +982,12 @@ void __CFInitialize(void) { if (value && (*value == 'Y' || *value == 'y')) __CFZombieEnabled = 0xff; value = __CFgetenv("NSDeallocateZombies"); if (value && (*value == 'Y' || *value == 'y')) __CFDeallocateZombies = 0xff; -#if !__OBJC2__ - _original_objc_dealloc = (void *)_dealloc; -#endif - - value = __CFgetenv("CFZombieLevel"); - if (NULL != value) { - __CFZombieLevel = (uint32_t)strtoul_l(value, NULL, 0, NULL); - } - if (0x0 == __CFZombieLevel) __CFZombieLevel = 0x0000FC00; // default #endif - __CFRuntimeClassTableSize = 1024; - __CFRuntimeClassTable = (CFRuntimeClass **)calloc(__CFRuntimeClassTableSize, sizeof(CFRuntimeClass *)); - __CFRuntimeObjCClassTable = (uintptr_t *)calloc(__CFRuntimeClassTableSize, sizeof(uintptr_t)); - __CFBaseInitialize(); + memset(__CFRuntimeClassTable, 0, sizeof(__CFRuntimeClassTable)); + memset(__CFRuntimeObjCClassTable, 0, sizeof(__CFRuntimeObjCClassTable)); - _CFRuntimeBridgeClasses(0, "__NSCFType"); - for (CFIndex idx = 1; idx < __CFRuntimeClassTableSize; idx++) { - __CFRuntimeObjCClassTable[idx] = __CFRuntimeObjCClassTable[0]; - } /* Here so that two runtime classes get indices 0, 1. */ __kCFNotATypeTypeID = _CFRuntimeRegisterClass(&__CFNotATypeClass); @@ -1036,27 +1016,24 @@ void __CFInitialize(void) { CFBasicHashGetTypeID(); CFBagGetTypeID(); -#if !__LP64__ - // Creating this lazily in CFRetain causes recursive call to CFRetain - __CFRuntimeExternRefCountTable = CFBagCreateMutable(kCFAllocatorSystemDefault, 0, NULL); -#endif for (CFIndex idx = 0; idx < NUM_EXTERN_TABLES; idx++) { - __NSRetainCounters[idx].table = CFBasicHashCreate(kCFAllocatorSystemDefault, kCFBasicHashHasCounts | kCFBasicHashLinearHashing | kCFBasicHashAggressiveGrowth, &CFBasicHashNullCallbacks); + __NSRetainCounters[idx].table = CFBasicHashCreate(kCFAllocatorSystemDefault, kCFBasicHashHasCounts | kCFBasicHashLinearHashing | kCFBasicHashAggressiveGrowth, &CFExternRefCallbacks); CFBasicHashSetCapacity(__NSRetainCounters[idx].table, 40); __NSRetainCounters[idx].lock = CFSpinLockInit; } /*** _CFRuntimeCreateInstance() can finally be called generally after this line. ***/ - __CFRuntimeClassTableCount = 7; - __CFStringInitialize(); // CFString's TypeID must be 0x7, now and forever - __CFRuntimeClassTableCount = 16; + __CFRuntimeClassTableCount = 7; + __CFStringInitialize(); // CFString's TypeID must be 0x7, now and forever + + __CFRuntimeClassTableCount = 16; + __CFNullInitialize(); // See above for hard-coding of this position CFSetGetTypeID(); // See above for hard-coding of this position CFDictionaryGetTypeID(); // See above for hard-coding of this position __CFArrayInitialize(); // See above for hard-coding of this position __CFDataInitialize(); // See above for hard-coding of this position - __CFNullInitialize(); // See above for hard-coding of this position __CFBooleanInitialize(); // See above for hard-coding of this position __CFNumberInitialize(); // See above for hard-coding of this position @@ -1067,47 +1044,57 @@ void __CFInitialize(void) { __CFErrorInitialize(); __CFTreeInitialize(); __CFURLInitialize(); + +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS __CFBundleInitialize(); +#endif #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED __CFPlugInInitialize(); __CFPlugInInstanceInitialize(); #endif __CFUUIDInitialize(); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS __CFMessagePortInitialize(); +#endif #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED __CFMachPortInitialize(); #endif +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS __CFStreamInitialize(); +#endif +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS __CFRunLoopInitialize(); __CFRunLoopObserverInitialize(); __CFRunLoopSourceInitialize(); __CFRunLoopTimerInitialize(); - +#endif + __CFTimeZoneInitialize(); + __CFCalendarInitialize(); +#if DEPLOYMENT_TARGET_LINUX + __CFTimeZoneInitialize(); + __CFCalendarInitialize(); +#endif + { CFIndex idx, cnt; - char **args; + char **args; #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED args = *_NSGetArgv(); cnt = *_NSGetArgc(); #elif DEPLOYMENT_TARGET_WINDOWS wchar_t *commandLine = GetCommandLineW(); - wchar_t **wideArgs = CommandLineToArgvW(commandLine, (int *)&cnt); - args = (char **)malloc(sizeof(char *) * cnt); - for (int y=0; y < cnt; y++) { - int bufSize = lstrlenW(wideArgs[y]) + 20; - char *arg = (char *)malloc(sizeof(char) * bufSize); - int res = WideCharToMultiByte(CP_ACP, 1024 /*WC_NO_BEST_FIT_CHARS*/, wideArgs[y], -1, arg, bufSize, NULL, NULL); - if (!res) - printf("CF - Error converting command line arg string to ascii: %x\n", (unsigned int)wideArgs[y]); - args[y] = arg; - } + // result is actually pointer to wchar_t *, make sure to account for that below + args = (char **)CommandLineToArgvW(commandLine, (int *)&cnt); #endif CFIndex count; CFStringRef *list, buffer[256]; list = (cnt <= 256) ? buffer : (CFStringRef *)malloc(cnt * sizeof(CFStringRef)); for (idx = 0, count = 0; idx < cnt; idx++) { if (NULL == args[idx]) continue; +#if DEPLOYMENT_TARGET_WINDOWS + list[count] = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)args[idx], wcslen((wchar_t *)args[idx])); +#else list[count] = CFStringCreateWithCString(kCFAllocatorSystemDefault, args[idx], kCFStringEncodingUTF8); if (NULL == list[count]) { list[count] = CFStringCreateWithCString(kCFAllocatorSystemDefault, args[idx], kCFStringEncodingISOLatin1); @@ -1118,9 +1105,14 @@ void __CFInitialize(void) { // conversion fails, but out of charity we try once // more with ISO Latin1, a standard unix encoding. } +#endif if (NULL != list[count]) count++; } __CFArgStuff = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)list, count, &kCFTypeArrayCallBacks); + if (list != buffer) free(list); +#if DEPLOYMENT_TARGET_WINDOWS + LocalFree(args); +#endif } _CFProcessPath(); // cache this early @@ -1131,30 +1123,15 @@ void __CFInitialize(void) { #endif if (__CFRuntimeClassTableCount < 256) __CFRuntimeClassTableCount = 256; - __CFSendObjCMsg = (void *(*)(const void *, SEL, ...))objc_msgSend; - -#if DEPLOYMENT_TARGET_MACOSX -#elif DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_EMBEDDED -#else -#error -#endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard)) { - setenv("COMMAND_MODE", "legacy", 1); - __CFEnv[sizeof(__CFEnv) / sizeof(__CFEnv[0]) - 1].name = "COMMAND_MODE"; - __CFEnv[sizeof(__CFEnv) / sizeof(__CFEnv[0]) - 1].value = "legacy"; - } -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error -#endif #if defined(DEBUG) && (DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) CFLog(kCFLogLevelWarning, CFSTR("Assertions enabled")); #endif __CFProphylacticAutofsAccess = false; + __CFInitializing = 0; + __CFInitialized = 1; } } @@ -1212,46 +1189,105 @@ int DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID pReserved ) { if (dwReason == DLL_PROCESS_ATTACH) { __CFInitialize(); cfBundle = RegisterCoreFoundationBundle(); - } else if (dwReason == DLL_PROCESS_DETACH) { + } else if (dwReason == DLL_PROCESS_DETACH && pReserved == 0) { + // Only cleanup if we are being unloaded dynamically (pReserved == 0) __CFStreamCleanup(); __CFSocketCleanup(); __CFUniCharCleanup(); - __CFBaseCleanup(); + +#if DEPLOYMENT_TARGET_WINDOWS + // No CF functions should access TSD after this is called + __CFTSDWindowsCleanup(); +#endif + // do these last if (cfBundle) CFRelease(cfBundle); __CFStringCleanup(); } else if (dwReason == DLL_THREAD_DETACH) { - __CFFinalizeThreadData(NULL); + __CFFinalizeWindowsThreadData(); } return TRUE; } #endif -CF_EXPORT CFTypeRef _CFRetain(CFTypeRef cf) { - if (NULL == cf) return NULL; +#if __CF_BIG_ENDIAN__ +#define RC_INCREMENT (1ULL) +#define RC_MASK (0xFFFFFFFFULL) +#define RC_GET(V) ((V) & RC_MASK) +#define RC_DEALLOCATING_BIT (0x400000ULL << 32) +#else +#define RC_INCREMENT (1ULL << 32) +#define RC_MASK (0xFFFFFFFFULL << 32) +#define RC_GET(V) (((V) & RC_MASK) >> 32) +#define RC_DEALLOCATING_BIT (0x400000ULL) +#endif + +#if COCOA_ARR1 && __LP64__ +static bool (*CAS64)(int64_t, int64_t, volatile int64_t *) = OSAtomicCompareAndSwap64Barrier; +#else +static bool (*CAS32)(int32_t, int32_t, volatile int32_t *) = OSAtomicCompareAndSwap32Barrier; +#endif + +// For "tryR==true", a return of NULL means "failed". +static CFTypeRef _CFRetain(CFTypeRef cf, Boolean tryR) { + uint32_t cfinfo = *(uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); + if (cfinfo & 0x800000) { // custom ref counting for object + if (tryR) return NULL; + CFTypeID typeID = (cfinfo >> 8) & 0x03FF; // mask up to 0x0FFF + CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; + uint32_t (*refcount)(intptr_t, CFTypeRef) = cfClass->refcount; + if (!refcount || !(cfClass->version & _kCFRuntimeCustomRefCount) || (((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS] != 0xFF)) { + HALT; // bogus object + } +#if __LP64__ + if (((CFRuntimeBase *)cf)->_rc != 0xFFFFFFFFU) { + HALT; // bogus object + } +#endif + refcount(+1, cf); + return cf; + } + Boolean didAuto = false; #if __LP64__ - if (0 == ((CFRuntimeBase *)cf)->_rc && !CF_IS_COLLECTABLE(cf)) return cf; // Constant CFTypeRef + if (0 == ((CFRuntimeBase *)cf)->_rc && !CF_IS_COLLECTABLE(cf)) return cf; // Constant CFTypeRef +#if COCOA_ARR1 + uint64_t allBits; + do { + allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo); + if (tryR && (allBits & RC_DEALLOCATING_BIT)) return NULL; + } while (!CAS64(allBits, allBits + RC_INCREMENT, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo)); + // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition. + if (RC_GET(allBits) == 0 && CF_IS_COLLECTABLE(cf)) { + auto_zone_retain(objc_collectableZone(), (void*)cf); + didAuto = true; + } +#else uint32_t lowBits; do { lowBits = ((CFRuntimeBase *)cf)->_rc; - } while (!OSAtomicCompareAndSwap32Barrier(lowBits, lowBits + 1, (int32_t *)&((CFRuntimeBase *)cf)->_rc)); + } while (!CAS32(lowBits, lowBits + 1, (int32_t *)&((CFRuntimeBase *)cf)->_rc)); // GC: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition. if (lowBits == 0 && CF_IS_COLLECTABLE(cf)) { - auto_zone_retain(auto_zone(), (void*)cf); + auto_zone_retain(objc_collectableZone(), (void*)cf); didAuto = true; } +#endif #else #define RC_START 24 #define RC_END 31 - volatile UInt32 *infoLocation = (UInt32 *)&(((CFRuntimeBase *)cf)->_cfinfo); - CFIndex rcLowBits = __CFBitfieldGetValue(*infoLocation, RC_END, RC_START); + volatile uint32_t *infoLocation = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); + CFIndex rcLowBits = __CFBitfieldGetValue(cfinfo, RC_END, RC_START); if (__builtin_expect(0 == rcLowBits, 0) && !CF_IS_COLLECTABLE(cf)) return cf; // Constant CFTypeRef bool success = 0; do { - UInt32 initialCheckInfo = *infoLocation; - UInt32 prospectiveNewInfo = initialCheckInfo; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory. + cfinfo = *infoLocation; +#if COCOA_ARR1 + // if already deallocating, don't allow new retain + if (tryR && (cfinfo & 0x400000)) return NULL; +#endif + uint32_t prospectiveNewInfo = cfinfo; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory. prospectiveNewInfo += (1 << RC_START); rcLowBits = __CFBitfieldGetValue(prospectiveNewInfo, RC_END, RC_START); if (__builtin_expect((rcLowBits & 0x7f) == 0, 0)) { @@ -1263,19 +1299,19 @@ CF_EXPORT CFTypeRef _CFRetain(CFTypeRef cf) { This prevents needing to access the external ref count for successive retains and releases when the composite retain count is right around a multiple of 1 << 7. */ - prospectiveNewInfo = initialCheckInfo; + prospectiveNewInfo = cfinfo; __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, ((1 << 7) | (1 << 6))); __CFSpinLock(&__CFRuntimeExternRefCountTableLock); - success = OSAtomicCompareAndSwap32Barrier(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); + success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); if (__builtin_expect(success, 1)) { __CFDoExternRefOperation(350, (id)cf); } __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock); } else { - success = OSAtomicCompareAndSwap32Barrier(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); + success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); // XXX_PCB: 0 --> 1 transition? then add a GC retain count, to root the object. we'll remove it on the 1 --> 0 transition. - if (success && __CFBitfieldGetValue(initialCheckInfo, RC_END, RC_START) == 0 && CF_IS_COLLECTABLE(cf)) { - auto_zone_retain(auto_zone(), (void*)cf); + if (success && __CFBitfieldGetValue(cfinfo, RC_END, RC_START) == 0 && CF_IS_COLLECTABLE(cf)) { + auto_zone_retain(objc_collectableZone(), (void*)cf); didAuto = true; } } @@ -1287,22 +1323,101 @@ CF_EXPORT CFTypeRef _CFRetain(CFTypeRef cf) { return cf; } -CF_EXPORT void _CFRelease(CFTypeRef cf) { - CFTypeID typeID = __CFGenericTypeID_inline(cf); +// Never called under GC, only called via ARR weak subsystem; a return of NULL is failure +CFTypeRef _CFTryRetain(CFTypeRef cf) { + if (NULL == cf) return NULL; + return _CFRetain(cf, true); +} + +Boolean _CFIsDeallocating(CFTypeRef cf) { + if (NULL == cf) return false; + uint32_t cfinfo = *(uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); + if (cfinfo & 0x800000) { // custom ref counting for object + return true; // lie for now; this weak references to these objects cannot be formed + } + return (cfinfo & 0x400000) ? true : false; +} + +static void _CFRelease(CFTypeRef cf) { + + uint32_t cfinfo = *(uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); + CFTypeID typeID = (cfinfo >> 8) & 0x03FF; // mask up to 0x0FFF + if (cfinfo & 0x800000) { // custom ref counting for object + CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; + uint32_t (*refcount)(intptr_t, CFTypeRef) = cfClass->refcount; + if (!refcount || !(cfClass->version & _kCFRuntimeCustomRefCount) || (((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS] != 0xFF)) { + HALT; // bogus object + } +#if __LP64__ + if (((CFRuntimeBase *)cf)->_rc != 0xFFFFFFFFU) { + HALT; // bogus object + } +#endif + refcount(-1, cf); + return; + } + Boolean isAllocator = (__kCFAllocatorTypeID_CONST == typeID); Boolean didAuto = false; #if __LP64__ +#if COCOA_ARR1 + uint32_t lowBits; + uint64_t allBits; + again:; + do { + allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo); + lowBits = RC_GET(allBits); + if (0 == lowBits) { + if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf); + return; // Constant CFTypeRef + } + if (1 == lowBits) { + CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; + if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) { + cfClass->reclaim(cf); + } + if (!CF_IS_COLLECTABLE(cf)) { + uint64_t newAllBits = allBits | RC_DEALLOCATING_BIT; + if (!CAS64(allBits, newAllBits, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo)) { + goto again; + } + allBits = newAllBits; + void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize; + if (NULL != func) { + func(cf); + } + allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo); + lowBits = RC_GET(allBits); + if (isAllocator || ((1 == lowBits) && CAS64(allBits, allBits - RC_INCREMENT, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo))) { + goto really_free; + } + Boolean success = false; + do { // drop the deallocating bit; racey, but this resurrection stuff isn't thread-safe anyway + allBits = *(uint64_t *)&(((CFRuntimeBase *)cf)->_cfinfo); + uint64_t newAllBits = allBits & ~RC_DEALLOCATING_BIT; + success = CAS64(allBits, newAllBits, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo); + } while (!success); + goto again; // still need to have the effect of a CFRelease + } + } + } while (!CAS64(allBits, allBits - RC_INCREMENT, (int64_t *)&((CFRuntimeBase *)cf)->_cfinfo)); + if (lowBits == 1 && CF_IS_COLLECTABLE(cf)) { + // GC: release the collector's hold over the object, which will call the finalize function later on. + auto_zone_release(objc_collectableZone(), (void*)cf); + didAuto = true; + } +#else uint32_t lowBits; do { lowBits = ((CFRuntimeBase *)cf)->_rc; if (0 == lowBits) { - if (CF_IS_COLLECTABLE(cf)) auto_zone_release(auto_zone(), (void*)cf); + if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf); return; // Constant CFTypeRef } if (1 == lowBits) { // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; - if (cfClass->version & _kCFRuntimeResourcefulObject && cfClass->reclaim != NULL) { + if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) { cfClass->reclaim(cf); } if (!CF_IS_COLLECTABLE(cf)) { @@ -1310,47 +1425,118 @@ CF_EXPORT void _CFRelease(CFTypeRef cf) { if (NULL != func) { func(cf); } - // We recheck lowBits to see if the object has been retained again during - // the finalization process. This allows for the finalizer to resurrect, - // but the main point is to allow finalizers to be able to manage the - // removal of objects from uniquing caches, which may race with other threads - // which are allocating (looking up and finding) objects from those caches, - // which (that thread) would be the thing doing the extra retain in that case. - if (isAllocator || OSAtomicCompareAndSwap32Barrier(1, 0, (int32_t *)&((CFRuntimeBase *)cf)->_rc)) { + if (isAllocator || CAS32(1, 0, (int32_t *)&((CFRuntimeBase *)cf)->_rc)) { goto really_free; } } } - } while (!OSAtomicCompareAndSwap32Barrier(lowBits, lowBits - 1, (int32_t *)&((CFRuntimeBase *)cf)->_rc)); + } while (!CAS32(lowBits, lowBits - 1, (int32_t *)&((CFRuntimeBase *)cf)->_rc)); if (lowBits == 1 && CF_IS_COLLECTABLE(cf)) { // GC: release the collector's hold over the object, which will call the finalize function later on. - auto_zone_release(auto_zone(), (void*)cf); + auto_zone_release(objc_collectableZone(), (void*)cf); didAuto = true; } +#endif +#else +#if COCOA_ARR1 + again:; + volatile uint32_t *infoLocation = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); + CFIndex rcLowBits = __CFBitfieldGetValue(cfinfo, RC_END, RC_START); + if (__builtin_expect(0 == rcLowBits, 0)) { + if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf); + return; // Constant CFTypeRef + } + bool success = 0; + Boolean whack = false; + do { + cfinfo = *infoLocation; + rcLowBits = __CFBitfieldGetValue(cfinfo, RC_END, RC_START); + if (__builtin_expect(1 == rcLowBits, 0)) { + // we think cf should be deallocated + uint32_t prospectiveNewInfo = cfinfo | (0x400000); + if (CF_IS_COLLECTABLE(cf)) { + prospectiveNewInfo -= (1 << RC_START); + } + success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); + if (success) whack = true; + } else { + // not yet junk + uint32_t prospectiveNewInfo = cfinfo; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory. + if (__builtin_expect((1 << 7) == rcLowBits, 0)) { + // Time to remove a bit from the external ref count + __CFSpinLock(&__CFRuntimeExternRefCountTableLock); + CFIndex rcHighBitsCnt = __CFDoExternRefOperation(500, (id)cf); + if (1 == rcHighBitsCnt) { + __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, (1 << 6) - 1); + } else { + __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, ((1 << 6) | (1 << 7)) - 1); + } + success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); + if (__builtin_expect(success, 1)) { + __CFDoExternRefOperation(450, (id)cf); + } + __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock); + } else { + prospectiveNewInfo -= (1 << RC_START); + success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); + } + } + } while (__builtin_expect(!success, 0)); + + if (whack) { + CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; + if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) { + cfClass->reclaim(cf); + } + if (CF_IS_COLLECTABLE(cf)) { + // GC: release the collector's hold over the object, which will call the finalize function later on. + auto_zone_release(objc_collectableZone(), (void*)cf); + didAuto = true; + } else { + if (isAllocator) { + goto really_free; + } else { + void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize; + if (NULL != func) { + func(cf); + } + rcLowBits = __CFBitfieldGetValue(*infoLocation, RC_END, RC_START); + if (1 == rcLowBits) { + goto really_free; + } + do { // drop the deallocating bit; racey, but this resurrection stuff isn't thread-safe anyway + cfinfo = *infoLocation; + uint32_t prospectiveNewInfo = (cfinfo & ~(0x400000)); + success = CAS32(*(int32_t *)& cfinfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); + } while (!success); + goto again; + } + } + } #else - volatile UInt32 *infoLocation = (UInt32 *)&(((CFRuntimeBase *)cf)->_cfinfo); + volatile uint32_t *infoLocation = (uint32_t *)&(((CFRuntimeBase *)cf)->_cfinfo); CFIndex rcLowBits = __CFBitfieldGetValue(*infoLocation, RC_END, RC_START); if (__builtin_expect(0 == rcLowBits, 0)) { - if (CF_IS_COLLECTABLE(cf)) auto_zone_release(auto_zone(), (void*)cf); + if (CF_IS_COLLECTABLE(cf)) auto_zone_release(objc_collectableZone(), (void*)cf); return; // Constant CFTypeRef } bool success = 0; do { - UInt32 initialCheckInfo = *infoLocation; + uint32_t initialCheckInfo = *infoLocation; rcLowBits = __CFBitfieldGetValue(initialCheckInfo, RC_END, RC_START); if (__builtin_expect(1 == rcLowBits, 0)) { // we think cf should be deallocated // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; - if (cfClass->version & _kCFRuntimeResourcefulObject && cfClass->reclaim != NULL) { + if ((cfClass->version & _kCFRuntimeResourcefulObject) && cfClass->reclaim != NULL) { cfClass->reclaim(cf); } if (CF_IS_COLLECTABLE(cf)) { - UInt32 prospectiveNewInfo = initialCheckInfo - (1 << RC_START); - success = OSAtomicCompareAndSwap32Barrier(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); + uint32_t prospectiveNewInfo = initialCheckInfo - (1 << RC_START); + success = CAS32(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); // GC: release the collector's hold over the object, which will call the finalize function later on. if (success) { - auto_zone_release(auto_zone(), (void*)cf); + auto_zone_release(objc_collectableZone(), (void*)cf); didAuto = true; } } else { @@ -1360,7 +1546,7 @@ CF_EXPORT void _CFRelease(CFTypeRef cf) { void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize; if (NULL != func) { func(cf); - } + } // We recheck rcLowBits to see if the object has been retained again during // the finalization process. This allows for the finalizer to resurrect, // but the main point is to allow finalizers to be able to manage the @@ -1376,7 +1562,7 @@ CF_EXPORT void _CFRelease(CFTypeRef cf) { } } else { // not yet junk - UInt32 prospectiveNewInfo = initialCheckInfo; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory. + uint32_t prospectiveNewInfo = initialCheckInfo; // don't want compiler to generate prospectiveNewInfo = *infoLocation. This is why infoLocation is declared as a pointer to volatile memory. if (__builtin_expect((1 << 7) == rcLowBits, 0)) { // Time to remove a bit from the external ref count __CFSpinLock(&__CFRuntimeExternRefCountTableLock); @@ -1386,18 +1572,18 @@ CF_EXPORT void _CFRelease(CFTypeRef cf) { } else { __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, ((1 << 6) | (1 << 7)) - 1); } - success = OSAtomicCompareAndSwap32Barrier(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); + success = CAS32(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); if (__builtin_expect(success, 1)) { __CFDoExternRefOperation(450, (id)cf); } __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock); } else { prospectiveNewInfo -= (1 << RC_START); - success = OSAtomicCompareAndSwap32Barrier(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); + success = CAS32(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); } } } while (__builtin_expect(!success, 0)); - +#endif #endif if (!didAuto && __builtin_expect(__CFOASafe, 0)) { __CFRecordAllocationEvent(__kCFReleaseEvent, (void *)cf, 0, CFGetRetainCount(cf), NULL); @@ -1412,96 +1598,17 @@ CF_EXPORT void _CFRelease(CFTypeRef cf) { // cannot zombify allocators, which get deallocated by __CFAllocatorDeallocate (finalize) if (isAllocator) { __CFAllocatorDeallocate((void *)cf); - } else { + } else { CFAllocatorRef allocator = kCFAllocatorSystemDefault; Boolean usesSystemDefaultAllocator = true; if (!__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 7, 7)) { allocator = CFGetAllocator(cf); - usesSystemDefaultAllocator = (allocator == kCFAllocatorSystemDefault); + usesSystemDefaultAllocator = _CFAllocatorIsSystemDefault(allocator); } - if (__CFZombieEnabled && !kCFUseCollectableAllocator) { - Class cls = object_getClass((id)cf); - const char *name = NULL; - __CFSpinLock(&__CFBigRuntimeFunnel); - for (CFIndex idx = 0; !name && idx < __CFRuntimeClassTableCount; idx++) { - if ((uintptr_t)cls == __CFRuntimeObjCClassTable[idx]) { - CFRuntimeClass *c = __CFRuntimeClassTable[idx]; - if (c) name = c->className; - } - } - __CFSpinUnlock(&__CFBigRuntimeFunnel); - // in 64-bit, a future class has nil isa, and calling class_getName() - // on such will crash so we do this test - if (!name && object_getClass((id)cls)) { - name = class_getName(cls); - } - if (!name) name = "$class-unknown$"; - char *cname = NULL; - asprintf(&cname, "_NSZombie_%s", name); - Class zclass = (Class)objc_lookUpClass(cname); - if (!zclass) { - zclass = objc_duplicateClass((Class)objc_lookUpClass("_NSZombie_"), cname, 0); - } - free(cname); - -#if DEPLOYMENT_TARGET_MACOSX - if (object_getClass((id)cls)) { - objc_destructInstance((id)cf); - } -#endif - if (__CFDeallocateZombies) { -#if __OBJC2__ - object_setClass((id)cf, zclass); -#else - // Set 'isa' pointer only if using standard deallocator - // However, _internal_object_dispose is not exported from libobjc - if (_dealloc == _original_objc_dealloc) { - object_setClass((id)cf, zclass); - } -#endif - CFAllocatorDeallocate(allocator, (uint8_t *)cf - (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef))); - } else { - object_setClass((id)cf, zclass); - } - -#if 0 - extern uintptr_t __CFFindPointer(uintptr_t ptr, uintptr_t start); - uintptr_t res = __CFFindPointer((uintptr_t)cf, 0); - while (0 != res) { - if (res < (uintptr_t)&cf - 4 * 4096 || (uintptr_t)&cf + 4096 < res) { - printf("*** NSZombie warning: object %p deallocated, but reference still found at %p (%p %p)\n", cf, res); - } - res = __CFFindPointer((uintptr_t)cf, res + 1); - } -#endif - - } else { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - if (kCFUseCollectableAllocator || !(__CFZombieLevel & (1 << 4))) { - Class cls = object_getClass((id)cf); - if (object_getClass((id)cls)) { - objc_removeAssociatedObjects((id)cf); - } - } -#endif - if ((__CFZombieLevel & (1 << 0)) && !kCFUseCollectableAllocator) { - uint8_t *ptr = (uint8_t *)cf - (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef)); - size_t size = malloc_size(ptr); - uint8_t byte = 0xFC; - if (__CFZombieLevel & (1 << 1)) { - ptr = (uint8_t *)cf + sizeof(CFRuntimeBase); - size = size - sizeof(CFRuntimeBase) - (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef)); - } - if (__CFZombieLevel & (1 << 7)) { - byte = (__CFZombieLevel >> 8) & 0xFF; - } - memset(ptr, byte, size); - } - if (kCFUseCollectableAllocator || !(__CFZombieLevel & (1 << 4))) { - CFAllocatorDeallocate(allocator, (uint8_t *)cf - (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef))); - } + { + CFAllocatorDeallocate(allocator, (uint8_t *)cf - (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef))); } if (kCFAllocatorSystemDefault != allocator) { @@ -1513,3 +1620,4 @@ CF_EXPORT void _CFRelease(CFTypeRef cf) { #undef __kCFAllocatorTypeID_CONST #undef __CFGenericAssertIsCF + diff --git a/CFRuntime.h b/CFRuntime.h index 66c8306..a257be3 100644 --- a/CFRuntime.h +++ b/CFRuntime.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFRuntime.h - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFRUNTIME__) @@ -34,44 +34,122 @@ CF_EXTERN_C_BEGIN +#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) + // GC: until we link against ObjC must use indirect functions. Overridden in CFSetupFoundationBridging CF_EXPORT bool kCFUseCollectableAllocator; CF_EXPORT bool (*__CFObjCIsCollectable)(void *); -// GC: primitives. +// Only CoreFoundation and Foundation should use these *GCRefZero constants; +// do not listen to anyone who tells you otherwise. + +CF_EXPORT +const CFAllocatorRef kCFAllocatorSystemDefaultGCRefZero; // DO NOT USE THIS +CF_EXPORT +const CFAllocatorRef kCFAllocatorDefaultGCRefZero; // DO NOT USE THIS + +CF_INLINE CFAllocatorRef _CFConvertAllocatorToNonGCRefZeroEquivalent(CFAllocatorRef allocator) { + if (kCFAllocatorSystemDefaultGCRefZero == allocator) { + allocator = kCFAllocatorSystemDefault; + } else if (kCFAllocatorDefaultGCRefZero == allocator || NULL == allocator || kCFAllocatorDefault == allocator) { + allocator = CFAllocatorGetDefault(); + } + return allocator; +} + +CF_INLINE CFAllocatorRef _CFConvertAllocatorToGCRefZeroEquivalent(CFAllocatorRef allocator) { // DO NOT USE THIS + if (!kCFUseCollectableAllocator) return allocator; + if (kCFAllocatorDefault == allocator || NULL == allocator) { + allocator = CFAllocatorGetDefault(); + } + if (kCFAllocatorSystemDefault == allocator) { + allocator = kCFAllocatorSystemDefaultGCRefZero; + } else if (CFAllocatorGetDefault() == allocator) { + allocator = kCFAllocatorDefaultGCRefZero; + } + return allocator; +} + +CF_INLINE Boolean _CFAllocatorIsSystemDefault(CFAllocatorRef allocator) { + if (allocator == kCFAllocatorSystemDefaultGCRefZero || allocator == kCFAllocatorSystemDefault) return true; + if (kCFAllocatorDefaultGCRefZero == allocator || NULL == allocator || kCFAllocatorDefault == allocator) { + return (kCFAllocatorSystemDefault == CFAllocatorGetDefault()); + } + return false; +} + +CF_INLINE Boolean _CFAllocatorIsGCRefZero(CFAllocatorRef allocator) { + // not intended as a literal test, but as a behavioral test + if (!kCFUseCollectableAllocator) return false; + return (kCFAllocatorSystemDefaultGCRefZero == allocator || kCFAllocatorDefaultGCRefZero == allocator); +} + // is GC on? #define CF_USING_COLLECTABLE_MEMORY (kCFUseCollectableAllocator) // is GC on and is this the GC allocator? -#define CF_IS_COLLECTABLE_ALLOCATOR(allocator) (kCFUseCollectableAllocator && (NULL == (allocator) || kCFAllocatorSystemDefault == (allocator))) +#define CF_IS_COLLECTABLE_ALLOCATOR(allocator) (kCFUseCollectableAllocator && (NULL == (allocator) || kCFAllocatorSystemDefault == (allocator) || _CFAllocatorIsGCRefZero(allocator))) // is this allocated by the collector? #define CF_IS_COLLECTABLE(obj) (__CFObjCIsCollectable ? __CFObjCIsCollectable((void*)obj) : false) +#else + +#define kCFUseCollectableAllocator 0 +#define __CFObjCIsCollectable 0 +#define kCFAllocatorSystemDefaultGCRefZero kCFAllocatorSystemDefault +#define kCFAllocatorDefaultGCRefZero kCFAllocatorDefault + +#define _CFConvertAllocatorToNonGCRefZeroEquivalent(A) (A) +#define _CFConvertAllocatorToGCRefZeroEquivalent(A) (A) + +CF_INLINE Boolean _CFAllocatorIsSystemDefault(CFAllocatorRef allocator) { + if (allocator == kCFAllocatorSystemDefault) return true; + if (NULL == allocator || kCFAllocatorDefault == allocator) { + return (kCFAllocatorSystemDefault == CFAllocatorGetDefault()); + } + return false; +} + +#define _CFAllocatorIsGCRefZero(A) (0) +#define CF_USING_COLLECTABLE_MEMORY 0 +#define CF_IS_COLLECTABLE_ALLOCATOR(allocator) 0 +#define CF_IS_COLLECTABLE(obj) 0 +#endif enum { - _kCFRuntimeNotATypeID = 0, - _kCFRuntimeScannedObject = (1UL << 0), - /* _kCFRuntimeUncollectableObject = (1UL << 1), No longer used; obsolete. */ - _kCFRuntimeResourcefulObject = (1UL << 2) + _kCFRuntimeNotATypeID = 0 }; -typedef struct __CFRuntimeClass { // Version 0 struct +enum { // Version field constants + _kCFRuntimeScannedObject = (1UL << 0), + _kCFRuntimeResourcefulObject = (1UL << 2), // tells CFRuntime to make use of the reclaim field + _kCFRuntimeCustomRefCount = (1UL << 3), // tells CFRuntime to make use of the refcount field +}; + +typedef struct __CFRuntimeClass { CFIndex version; - const char *className; + const char *className; // must be a pure ASCII string, nul-terminated void (*init)(CFTypeRef cf); CFTypeRef (*copy)(CFAllocatorRef allocator, CFTypeRef cf); -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED void (*finalize)(CFTypeRef cf); -#else - void (*dealloc)(CFTypeRef cf); -#endif Boolean (*equal)(CFTypeRef cf1, CFTypeRef cf2); CFHashCode (*hash)(CFTypeRef cf); - CFStringRef (*copyFormattingDesc)(CFTypeRef cf, CFDictionaryRef formatOptions); // str with retain - CFStringRef (*copyDebugDesc)(CFTypeRef cf); // str with retain -#if MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED + CFStringRef (*copyFormattingDesc)(CFTypeRef cf, CFDictionaryRef formatOptions); // return str with retain + CFStringRef (*copyDebugDesc)(CFTypeRef cf); // return str with retain + #define CF_RECLAIM_AVAILABLE 1 - void (*reclaim)(CFTypeRef cf); -#endif + void (*reclaim)(CFTypeRef cf); // Set _kCFRuntimeResourcefulObject in the .version to indicate this field should be used + +#define CF_REFCOUNT_AVAILABLE 1 + uint32_t (*refcount)(intptr_t op, CFTypeRef cf); // Set _kCFRuntimeCustomRefCount in the .version to indicate this field should be used + // this field must be non-NULL when _kCFRuntimeCustomRefCount is in the .version field + // - if the callback is passed 1 in 'op' it should increment the 'cf's reference count and return 0 + // - if the callback is passed 0 in 'op' it should return the 'cf's reference count, up to 32 bits + // - if the callback is passed -1 in 'op' it should decrement the 'cf's reference count; if it is now zero, 'cf' should be cleaned up and deallocated (the finalize callback above will NOT be called unless the process is running under GC, and CF does not deallocate the memory for you; if running under GC, finalize should do the object tear-down and free the object memory); then return 0 + // remember to use saturation arithmetic logic and stop incrementing and decrementing when the ref count hits UINT32_MAX, or you will have a security bug + // remember that reference count incrementing/decrementing must be done thread-safely/atomically + // objects should be created/initialized with a custom ref-count of 1 by the class creation functions + // do not attempt to use any bits within the CFRuntimeBase for your reference count; store that in some additional field in your CF object + } CFRuntimeClass; #define RADAR_5115468_FIXED 1 @@ -212,7 +290,9 @@ CF_EXPORT void _CFRuntimeSetInstanceTypeID(CFTypeRef cf, CFTypeID typeID); * If the specified CFTypeID is unknown to the CF runtime, * this function does nothing. This function CANNOT be used * to initialize an instance. It is for advanced usages such - * as faulting. + * as faulting. You cannot change the CFTypeID of an object + * of a _kCFRuntimeCustomRefCount class, or to a + * _kCFRuntimeCustomRefCount class. */ CF_EXPORT void _CFRuntimeInitStaticInstance(void *memory, CFTypeID typeID); @@ -224,7 +304,8 @@ CF_EXPORT void _CFRuntimeInitStaticInstance(void *memory, CFTypeID typeID); * least as large as sizeof(CFRuntimeBase) on the platform * the code is being compiled for. The init function of the * CFRuntimeClass is invoked on the memory as well, if the - * class has one. + * class has one. Static instances cannot be initialized to + * _kCFRuntimeCustomRefCount classes. */ #define CF_HAS_INIT_STATIC_INSTANCE 1 diff --git a/CFSet.c b/CFSet.c index f23f4f9..8a016e9 100644 --- a/CFSet.c +++ b/CFSet.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFSet.c - Copyright 1998-2008, Apple, Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane Machine generated from Notes/HashingCode.template */ @@ -46,6 +46,7 @@ const CFSetKeyCallBacks kCFTypeSetKeyCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; const CFSetKeyCallBacks kCFCopyStringSetKeyCallBacks = {0, __CFStringCollectionCopy, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; const CFSetValueCallBacks kCFTypeSetValueCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual}; +__private_extern__ const CFSetValueCallBacks kCFTypeSetValueCompactableCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual}; static const CFSetKeyCallBacks __kCFNullSetKeyCallBacks = {0, NULL, NULL, NULL, NULL, NULL}; static const CFSetValueCallBacks __kCFNullSetValueCallBacks = {0, NULL, NULL, NULL, NULL}; @@ -131,95 +132,232 @@ CFTypeID CFSetGetTypeID(void) { return __kCFSetTypeID; } -static uintptr_t __CFSetCallback(CFBasicHashRef ht, uint8_t op, uintptr_t a1, uintptr_t a2, CFBasicHashCallbacks *cb) { - switch (op) { - case kCFBasicHashCallbackOpCopyCallbacks: { - CFBasicHashCallbacks *newcb = NULL; - if (CF_IS_COLLECTABLE_ALLOCATOR((CFAllocatorRef)a1)) { - newcb = (CFBasicHashCallbacks *)auto_zone_allocate_object(auto_zone(), 10 * sizeof(void *), AUTO_MEMORY_UNSCANNED, true, false); - } else { - newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate((CFAllocatorRef)a1, 10 * sizeof(void *), 0); - } - if (!newcb) HALT; - memmove(newcb, (void *)cb, 10 * sizeof(void *)); - return (uintptr_t)newcb; - } - case kCFBasicHashCallbackOpFreeCallbacks: { - if (CF_IS_COLLECTABLE_ALLOCATOR((CFAllocatorRef)a1)) { - auto_zone_release(auto_zone(), cb); - } else { - CFAllocatorDeallocate((CFAllocatorRef)a1, cb); - } - return 0; - } - case kCFBasicHashCallbackOpRetainValue: { - const_any_pointer_t (*value_retain)(CFAllocatorRef, const_any_pointer_t) = (const_any_pointer_t (*)(CFAllocatorRef, const_any_pointer_t))cb->context[0]; - if (NULL == value_retain) return a1; - return (uintptr_t)INVOKE_CALLBACK2(value_retain, CFGetAllocator(ht), (const_any_pointer_t)a1); - } - case kCFBasicHashCallbackOpRetainKey: { - const_any_pointer_t (*key_retain)(CFAllocatorRef, const_any_pointer_t) = (const_any_pointer_t (*)(CFAllocatorRef, const_any_pointer_t))cb->context[1]; - if (NULL == key_retain) return a1; - return (uintptr_t)INVOKE_CALLBACK2(key_retain, CFGetAllocator(ht), (const_any_pointer_t)a1); - } - case kCFBasicHashCallbackOpReleaseValue: { - void (*value_release)(CFAllocatorRef, const_any_pointer_t) = (void (*)(CFAllocatorRef, const_any_pointer_t))cb->context[2]; - if (NULL != value_release) INVOKE_CALLBACK2(value_release, CFGetAllocator(ht), (const_any_pointer_t)a1); - return 0; - } - case kCFBasicHashCallbackOpReleaseKey: { - void (*key_release)(CFAllocatorRef, const_any_pointer_t) = (void (*)(CFAllocatorRef, const_any_pointer_t))cb->context[3]; - if (NULL != key_release) INVOKE_CALLBACK2(key_release, CFGetAllocator(ht), (const_any_pointer_t)a1); - return 0; - } - case kCFBasicHashCallbackOpValueEqual: { - Boolean (*value_equal)(const_any_pointer_t, const_any_pointer_t) = (Boolean (*)(const_any_pointer_t, const_any_pointer_t))cb->context[4]; - if (NULL == value_equal) return (a1 == a2); - return INVOKE_CALLBACK2(value_equal, (const_any_pointer_t)a1, (const_any_pointer_t)a2) ? 1 : 0; - } - case kCFBasicHashCallbackOpKeyEqual: { - Boolean (*key_equal)(const_any_pointer_t, const_any_pointer_t) = (Boolean (*)(const_any_pointer_t, const_any_pointer_t))cb->context[5]; - if (NULL == key_equal) return (a1 == a2); - return INVOKE_CALLBACK2(key_equal, (const_any_pointer_t)a1, (const_any_pointer_t)a2) ? 1 : 0; - } - case kCFBasicHashCallbackOpHashKey: { - CFHashCode (*hash)(const_any_pointer_t) = (CFHashCode (*)(const_any_pointer_t))cb->context[6]; - if (NULL == hash) return a1; - return (uintptr_t)INVOKE_CALLBACK1(hash, (const_any_pointer_t)a1); - } - case kCFBasicHashCallbackOpDescribeValue: { - CFStringRef (*value_describe)(const_any_pointer_t) = (CFStringRef (*)(const_any_pointer_t))cb->context[7]; - if (NULL == value_describe) return (uintptr_t)CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (const_any_pointer_t)a1); - return (uintptr_t)INVOKE_CALLBACK1(value_describe, (const_any_pointer_t)a1); - } - case kCFBasicHashCallbackOpDescribeKey: { - CFStringRef (*key_describe)(const_any_pointer_t) = (CFStringRef (*)(const_any_pointer_t))cb->context[8]; - if (NULL == key_describe) return (uintptr_t)CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (const_any_pointer_t)a1); - return (uintptr_t)INVOKE_CALLBACK1(key_describe, (const_any_pointer_t)a1); +#define GCRETAIN(A, B) kCFTypeSetCallBacks.retain(A, B) +#define GCRELEASE(A, B) kCFTypeSetCallBacks.release(A, B) + +static uintptr_t __CFSetStandardRetainValue(CFConstBasicHashRef ht, uintptr_t stack_value) { + if (CFBasicHashGetSpecialBits(ht) & 0x0100) return stack_value; + return (CFBasicHashHasStrongValues(ht)) ? (uintptr_t)GCRETAIN(kCFAllocatorSystemDefault, (CFTypeRef)stack_value) : (uintptr_t)CFRetain((CFTypeRef)stack_value); +} + +static uintptr_t __CFSetStandardRetainKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + if (CFBasicHashGetSpecialBits(ht) & 0x0001) return stack_key; + return (CFBasicHashHasStrongKeys(ht)) ? (uintptr_t)GCRETAIN(kCFAllocatorSystemDefault, (CFTypeRef)stack_key) : (uintptr_t)CFRetain((CFTypeRef)stack_key); +} + +static void __CFSetStandardReleaseValue(CFConstBasicHashRef ht, uintptr_t stack_value) { + if (CFBasicHashGetSpecialBits(ht) & 0x0200) return; + if (CFBasicHashHasStrongValues(ht)) GCRELEASE(kCFAllocatorSystemDefault, (CFTypeRef)stack_value); else CFRelease((CFTypeRef)stack_value); +} + +static void __CFSetStandardReleaseKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + if (CFBasicHashGetSpecialBits(ht) & 0x0002) return; + if (CFBasicHashHasStrongKeys(ht)) GCRELEASE(kCFAllocatorSystemDefault, (CFTypeRef)stack_key); else CFRelease((CFTypeRef)stack_key); +} + +static Boolean __CFSetStandardEquateValues(CFConstBasicHashRef ht, uintptr_t coll_value1, uintptr_t stack_value2) { + if (CFBasicHashGetSpecialBits(ht) & 0x0400) return coll_value1 == stack_value2; + return CFEqual((CFTypeRef)coll_value1, (CFTypeRef)stack_value2); +} + +static Boolean __CFSetStandardEquateKeys(CFConstBasicHashRef ht, uintptr_t coll_key1, uintptr_t stack_key2) { + if (CFBasicHashGetSpecialBits(ht) & 0x0004) return coll_key1 == stack_key2; + return CFEqual((CFTypeRef)coll_key1, (CFTypeRef)stack_key2); +} + +static uintptr_t __CFSetStandardHashKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + if (CFBasicHashGetSpecialBits(ht) & 0x0008) return stack_key; + return (uintptr_t)CFHash((CFTypeRef)stack_key); +} + +static uintptr_t __CFSetStandardGetIndirectKey(CFConstBasicHashRef ht, uintptr_t coll_value) { + return 0; +} + +static CFStringRef __CFSetStandardCopyValueDescription(CFConstBasicHashRef ht, uintptr_t stack_value) { + if (CFBasicHashGetSpecialBits(ht) & 0x0800) return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)stack_value); + return CFCopyDescription((CFTypeRef)stack_value); +} + +static CFStringRef __CFSetStandardCopyKeyDescription(CFConstBasicHashRef ht, uintptr_t stack_key) { + if (CFBasicHashGetSpecialBits(ht) & 0x0010) return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (void *)stack_key); + return CFCopyDescription((CFTypeRef)stack_key); +} + +static CFBasicHashCallbacks *__CFSetStandardCopyCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb); +static void __CFSetStandardFreeCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb); + +static const CFBasicHashCallbacks CFSetStandardCallbacks = { + __CFSetStandardCopyCallbacks, + __CFSetStandardFreeCallbacks, + __CFSetStandardRetainValue, + __CFSetStandardRetainKey, + __CFSetStandardReleaseValue, + __CFSetStandardReleaseKey, + __CFSetStandardEquateValues, + __CFSetStandardEquateKeys, + __CFSetStandardHashKey, + __CFSetStandardGetIndirectKey, + __CFSetStandardCopyValueDescription, + __CFSetStandardCopyKeyDescription +}; + +static CFBasicHashCallbacks *__CFSetStandardCopyCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) { + return (CFBasicHashCallbacks *)&CFSetStandardCallbacks; +} + +static void __CFSetStandardFreeCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) { +} + + +static CFBasicHashCallbacks *__CFSetCopyCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) { + CFBasicHashCallbacks *newcb = NULL; + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + newcb = (CFBasicHashCallbacks *)auto_zone_allocate_object(objc_collectableZone(), sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), AUTO_MEMORY_UNSCANNED, false, false); + } else { + newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), 0); } + if (!newcb) HALT; + memmove(newcb, (void *)cb, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *)); + return newcb; +} + +static void __CFSetFreeCallbacks(CFConstBasicHashRef ht, CFAllocatorRef allocator, CFBasicHashCallbacks *cb) { + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + } else { + CFAllocatorDeallocate(allocator, cb); } +} + +static uintptr_t __CFSetRetainValue(CFConstBasicHashRef ht, uintptr_t stack_value) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + const_any_pointer_t (*value_retain)(CFAllocatorRef, const_any_pointer_t) = (const_any_pointer_t (*)(CFAllocatorRef, const_any_pointer_t))cb->context[0]; + if (NULL == value_retain) return stack_value; + return (uintptr_t)INVOKE_CALLBACK2(value_retain, CFGetAllocator(ht), (const_any_pointer_t)stack_value); +} + +static uintptr_t __CFSetRetainKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + const_any_pointer_t (*key_retain)(CFAllocatorRef, const_any_pointer_t) = (const_any_pointer_t (*)(CFAllocatorRef, const_any_pointer_t))cb->context[1]; + if (NULL == key_retain) return stack_key; + return (uintptr_t)INVOKE_CALLBACK2(key_retain, CFGetAllocator(ht), (const_any_pointer_t)stack_key); +} + +static void __CFSetReleaseValue(CFConstBasicHashRef ht, uintptr_t stack_value) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + void (*value_release)(CFAllocatorRef, const_any_pointer_t) = (void (*)(CFAllocatorRef, const_any_pointer_t))cb->context[2]; + if (NULL != value_release) INVOKE_CALLBACK2(value_release, CFGetAllocator(ht), (const_any_pointer_t) stack_value); +} + +static void __CFSetReleaseKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + void (*key_release)(CFAllocatorRef, const_any_pointer_t) = (void (*)(CFAllocatorRef, const_any_pointer_t))cb->context[3]; + if (NULL != key_release) INVOKE_CALLBACK2(key_release, CFGetAllocator(ht), (const_any_pointer_t) stack_key); +} + +static Boolean __CFSetEquateValues(CFConstBasicHashRef ht, uintptr_t coll_value1, uintptr_t stack_value2) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + Boolean (*value_equal)(const_any_pointer_t, const_any_pointer_t) = (Boolean (*)(const_any_pointer_t, const_any_pointer_t))cb->context[4]; + if (NULL == value_equal) return (coll_value1 == stack_value2); + return INVOKE_CALLBACK2(value_equal, (const_any_pointer_t) coll_value1, (const_any_pointer_t) stack_value2) ? 1 : 0; +} + +static Boolean __CFSetEquateKeys(CFConstBasicHashRef ht, uintptr_t coll_key1, uintptr_t stack_key2) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + Boolean (*key_equal)(const_any_pointer_t, const_any_pointer_t) = (Boolean (*)(const_any_pointer_t, const_any_pointer_t))cb->context[5]; + if (NULL == key_equal) return (coll_key1 == stack_key2); + return INVOKE_CALLBACK2(key_equal, (const_any_pointer_t) coll_key1, (const_any_pointer_t) stack_key2) ? 1 : 0; +} + +static uintptr_t __CFSetHashKey(CFConstBasicHashRef ht, uintptr_t stack_key) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + CFHashCode (*hash)(const_any_pointer_t) = (CFHashCode (*)(const_any_pointer_t))cb->context[6]; + if (NULL == hash) return stack_key; + return (uintptr_t)INVOKE_CALLBACK1(hash, (const_any_pointer_t) stack_key); +} + +static uintptr_t __CFSetGetIndirectKey(CFConstBasicHashRef ht, uintptr_t coll_value) { return 0; } -static CFBasicHashRef __CFSetCreateGeneric(CFAllocatorRef allocator, const CFHashKeyCallBacks *keyCallBacks, const CFHashValueCallBacks *valueCallBacks, Boolean useValueCB) { +static CFStringRef __CFSetCopyValueDescription(CFConstBasicHashRef ht, uintptr_t stack_value) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + CFStringRef (*value_describe)(const_any_pointer_t) = (CFStringRef (*)(const_any_pointer_t))cb->context[8]; + if (NULL == value_describe) return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (const_any_pointer_t) stack_value); + return (CFStringRef)INVOKE_CALLBACK1(value_describe, (const_any_pointer_t) stack_value); +} - CFBasicHashCallbacks *cb = NULL; +static CFStringRef __CFSetCopyKeyDescription(CFConstBasicHashRef ht, uintptr_t stack_key) { + const CFBasicHashCallbacks *cb = CFBasicHashGetCallbacks(ht); + CFStringRef (*key_describe)(const_any_pointer_t) = (CFStringRef (*)(const_any_pointer_t))cb->context[9]; + if (NULL == key_describe) return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<%p>"), (const_any_pointer_t) stack_key); + return (CFStringRef)INVOKE_CALLBACK1(key_describe, (const_any_pointer_t) stack_key); +} + +static CFBasicHashRef __CFSetCreateGeneric(CFAllocatorRef allocator, const CFHashKeyCallBacks *keyCallBacks, const CFHashValueCallBacks *valueCallBacks, Boolean useValueCB) { CFOptionFlags flags = kCFBasicHashLinearHashing; // kCFBasicHashExponentialHashing flags |= (CFDictionary ? kCFBasicHashHasKeys : 0) | (CFBag ? kCFBasicHashHasCounts : 0); + CFBasicHashCallbacks *cb = NULL; + Boolean std_cb = false; + uint16_t specialBits = 0; const_any_pointer_t (*key_retain)(CFAllocatorRef, const_any_pointer_t) = NULL; void (*key_release)(CFAllocatorRef, const_any_pointer_t) = NULL; const_any_pointer_t (*value_retain)(CFAllocatorRef, const_any_pointer_t) = NULL; void (*value_release)(CFAllocatorRef, const_any_pointer_t) = NULL; - Boolean std_cb = false; - if ((NULL == keyCallBacks || (keyCallBacks && 0 == memcmp(&__kCFNullSetKeyCallBacks, keyCallBacks, sizeof(__kCFNullSetKeyCallBacks)))) - && (!useValueCB || (NULL == valueCallBacks || (valueCallBacks && 0 == memcmp(&__kCFNullSetValueCallBacks, valueCallBacks, sizeof(__kCFNullSetValueCallBacks)))))) { - cb = (CFBasicHashCallbacks *)& CFBasicHashNullCallbacks; - } else if ((&kCFTypeSetKeyCallBacks == keyCallBacks || (keyCallBacks && 0 == memcmp(&kCFTypeSetKeyCallBacks, keyCallBacks, sizeof(kCFTypeSetKeyCallBacks)))) - && (!useValueCB || (&kCFTypeSetValueCallBacks == valueCallBacks || (valueCallBacks && 0 == memcmp(&kCFTypeSetValueCallBacks, valueCallBacks, sizeof(kCFTypeSetValueCallBacks)))))) { - std_cb = true; - cb = (CFBasicHashCallbacks *)& CFBasicHashStandardCallbacks; - } else { + + if ((NULL == keyCallBacks || 0 == keyCallBacks->version) && (!useValueCB || NULL == valueCallBacks || 0 == valueCallBacks->version)) { + Boolean keyRetainNull = NULL == keyCallBacks || NULL == keyCallBacks->retain; + Boolean keyReleaseNull = NULL == keyCallBacks || NULL == keyCallBacks->release; + Boolean keyEquateNull = NULL == keyCallBacks || NULL == keyCallBacks->equal; + Boolean keyHashNull = NULL == keyCallBacks || NULL == keyCallBacks->hash; + Boolean keyDescribeNull = NULL == keyCallBacks || NULL == keyCallBacks->copyDescription; + + Boolean valueRetainNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->retain)) || (!useValueCB && keyRetainNull); + Boolean valueReleaseNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->release)) || (!useValueCB && keyReleaseNull); + Boolean valueEquateNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->equal)) || (!useValueCB && keyEquateNull); + Boolean valueDescribeNull = (useValueCB && (NULL == valueCallBacks || NULL == valueCallBacks->copyDescription)) || (!useValueCB && keyDescribeNull); + + Boolean keyRetainStd = keyRetainNull || __CFTypeCollectionRetain == keyCallBacks->retain; + Boolean keyReleaseStd = keyReleaseNull || __CFTypeCollectionRelease == keyCallBacks->release; + Boolean keyEquateStd = keyEquateNull || CFEqual == keyCallBacks->equal; + Boolean keyHashStd = keyHashNull || CFHash == keyCallBacks->hash; + Boolean keyDescribeStd = keyDescribeNull || CFCopyDescription == keyCallBacks->copyDescription; + + Boolean valueRetainStd = (useValueCB && (valueRetainNull || __CFTypeCollectionRetain == valueCallBacks->retain)) || (!useValueCB && keyRetainStd); + Boolean valueReleaseStd = (useValueCB && (valueReleaseNull || __CFTypeCollectionRelease == valueCallBacks->release)) || (!useValueCB && keyReleaseStd); + Boolean valueEquateStd = (useValueCB && (valueEquateNull || CFEqual == valueCallBacks->equal)) || (!useValueCB && keyEquateStd); + Boolean valueDescribeStd = (useValueCB && (valueDescribeNull || CFCopyDescription == valueCallBacks->copyDescription)) || (!useValueCB && keyDescribeStd); + + if (keyRetainStd && keyReleaseStd && keyEquateStd && keyHashStd && keyDescribeStd && valueRetainStd && valueReleaseStd && valueEquateStd && valueDescribeStd) { + cb = (CFBasicHashCallbacks *)&CFSetStandardCallbacks; + if (!(keyRetainNull || keyReleaseNull || keyEquateNull || keyHashNull || keyDescribeNull || valueRetainNull || valueReleaseNull || valueEquateNull || valueDescribeNull)) { + std_cb = true; + } else { + // just set these to tickle the GC Strong logic below in a way that mimics past practice + key_retain = keyCallBacks ? keyCallBacks->retain : NULL; + key_release = keyCallBacks ? keyCallBacks->release : NULL; + if (useValueCB) { + value_retain = valueCallBacks ? valueCallBacks->retain : NULL; + value_release = valueCallBacks ? valueCallBacks->release : NULL; + } else { + value_retain = key_retain; + value_release = key_release; + } + } + if (keyRetainNull) specialBits |= 0x0001; + if (keyReleaseNull) specialBits |= 0x0002; + if (keyEquateNull) specialBits |= 0x0004; + if (keyHashNull) specialBits |= 0x0008; + if (keyDescribeNull) specialBits |= 0x0010; + if (valueRetainNull) specialBits |= 0x0100; + if (valueReleaseNull) specialBits |= 0x0200; + if (valueEquateNull) specialBits |= 0x0400; + if (valueDescribeNull) specialBits |= 0x0800; + } + } + + if (!cb) { Boolean (*key_equal)(const_any_pointer_t, const_any_pointer_t) = NULL; Boolean (*value_equal)(const_any_pointer_t, const_any_pointer_t) = NULL; CFStringRef (*key_describe)(const_any_pointer_t) = NULL; @@ -241,24 +379,26 @@ static CFBasicHashRef __CFSetCreateGeneric(CFAllocatorRef allocator, const CFHas value_describe = key_describe; } hash_key = keyCallBacks ? keyCallBacks->hash : NULL; - FAULT_CALLBACK((void **)&key_retain); - FAULT_CALLBACK((void **)&key_release); - FAULT_CALLBACK((void **)&value_retain); - FAULT_CALLBACK((void **)&value_release); - FAULT_CALLBACK((void **)&key_equal); - FAULT_CALLBACK((void **)&value_equal); - FAULT_CALLBACK((void **)&key_describe); - FAULT_CALLBACK((void **)&value_describe); - FAULT_CALLBACK((void **)&hash_key); CFBasicHashCallbacks *newcb = NULL; if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - newcb = (CFBasicHashCallbacks *)auto_zone_allocate_object(auto_zone(), 10 * sizeof(void *), AUTO_MEMORY_UNSCANNED, true, false); + newcb = (CFBasicHashCallbacks *)auto_zone_allocate_object(objc_collectableZone(), sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), AUTO_MEMORY_UNSCANNED, false, false); } else { - newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, 10 * sizeof(void *), 0); + newcb = (CFBasicHashCallbacks *)CFAllocatorAllocate(allocator, sizeof(CFBasicHashCallbacks) + 10 * sizeof(void *), 0); } if (!newcb) HALT; - newcb->func = (CFBasicHashCallbackType)__CFSetCallback; + newcb->copyCallbacks = __CFSetCopyCallbacks; + newcb->freeCallbacks = __CFSetFreeCallbacks; + newcb->retainValue = __CFSetRetainValue; + newcb->retainKey = __CFSetRetainKey; + newcb->releaseValue = __CFSetReleaseValue; + newcb->releaseKey = __CFSetReleaseKey; + newcb->equateValues = __CFSetEquateValues; + newcb->equateKeys = __CFSetEquateKeys; + newcb->hashKey = __CFSetHashKey; + newcb->getIndirectKey = __CFSetGetIndirectKey; + newcb->copyValueDescription = __CFSetCopyValueDescription; + newcb->copyKeyDescription = __CFSetCopyKeyDescription; newcb->context[0] = (uintptr_t)value_retain; newcb->context[1] = (uintptr_t)key_retain; newcb->context[2] = (uintptr_t)value_release; @@ -266,8 +406,8 @@ static CFBasicHashRef __CFSetCreateGeneric(CFAllocatorRef allocator, const CFHas newcb->context[4] = (uintptr_t)value_equal; newcb->context[5] = (uintptr_t)key_equal; newcb->context[6] = (uintptr_t)hash_key; - newcb->context[7] = (uintptr_t)value_describe; - newcb->context[8] = (uintptr_t)key_describe; + newcb->context[8] = (uintptr_t)value_describe; + newcb->context[9] = (uintptr_t)key_describe; cb = newcb; } @@ -278,9 +418,43 @@ static CFBasicHashRef __CFSetCreateGeneric(CFAllocatorRef allocator, const CFHas if (std_cb || key_retain != NULL || key_release != NULL) { flags |= kCFBasicHashStrongKeys; } +#if CFDictionary + if (valueCallBacks == &kCFTypeDictionaryValueCompactableCallBacks) { + // Foundation allocated collections will have compactable values + flags |= kCFBasicHashCompactableValues; + } +#endif } - return CFBasicHashCreate(allocator, flags, cb); + CFBasicHashRef ht = CFBasicHashCreate(allocator, flags, cb); + CFBasicHashSetSpecialBits(ht, specialBits); + return ht; +} + +#if CFDictionary +__private_extern__ CFHashRef __CFSetCreateTransfer(CFAllocatorRef allocator, const_any_pointer_t *klist, const_any_pointer_t *vlist, CFIndex numValues) { +#endif +#if CFSet || CFBag +__private_extern__ CFHashRef __CFSetCreateTransfer(CFAllocatorRef allocator, const_any_pointer_t *klist, CFIndex numValues) { + const_any_pointer_t *vlist = klist; +#endif + CFTypeID typeID = CFSetGetTypeID(); + CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__, numValues); + CFOptionFlags flags = kCFBasicHashLinearHashing; // kCFBasicHashExponentialHashing + flags |= (CFDictionary ? kCFBasicHashHasKeys : 0) | (CFBag ? kCFBasicHashHasCounts : 0); + CFBasicHashCallbacks *cb = (CFBasicHashCallbacks *)&CFSetStandardCallbacks; + CFBasicHashRef ht = CFBasicHashCreate(allocator, flags, cb); + CFBasicHashSetSpecialBits(ht, 0x0303); + if (0 < numValues) CFBasicHashSetCapacity(ht, numValues); + for (CFIndex idx = 0; idx < numValues; idx++) { + CFBasicHashAddValue(ht, (uintptr_t)klist[idx], (uintptr_t)vlist[idx]); + } + CFBasicHashSetSpecialBits(ht, 0x0000); + CFBasicHashMakeImmutable(ht); + *(uintptr_t *)ht = __CFISAForTypeID(typeID); + _CFRuntimeSetInstanceTypeID(ht, typeID); + if (__CFOASafe) __CFSetLastAllocationEventName(ht, "CFSet (immutable)"); + return (CFHashRef)ht; } #if CFDictionary @@ -429,8 +603,8 @@ const_any_pointer_t CFSetGetValue(CFHashRef hc, const_any_pointer_t key) { } Boolean CFSetGetValueIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *value) { - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, Boolean, hc, "_getValue:forKey:", (any_t *)value, key); - if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, Boolean, hc, "_getValue:forObj:", (any_t *)value, key); + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, Boolean, hc, "__getValue:forKey:", (any_t *)value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, Boolean, hc, "__getValue:forObj:", (any_t *)value, key); __CFGenericValidateType(hc, __kCFSetTypeID); CFBasicHashBucket bkt = CFBasicHashFindBucket((CFBasicHashRef)hc, (uintptr_t)key); if (0 < bkt.count) { @@ -489,7 +663,8 @@ void CFSetGetValues(CFHashRef hc, const_any_pointer_t *keybuf) { __CFGenericValidateType(hc, __kCFSetTypeID); if (kCFUseCollectableAllocator) { CFOptionFlags flags = CFBasicHashGetFlags((CFBasicHashRef)hc); - __block const_any_pointer_t *keys = keybuf, *values = valuebuf; + __block const_any_pointer_t *keys = keybuf; + __block const_any_pointer_t *values = valuebuf; CFBasicHashApply((CFBasicHashRef)hc, ^(CFBasicHashBucket bkt) { for (CFIndex cnt = bkt.count; cnt--;) { if (keybuf && (flags & kCFBasicHashStrongKeys)) { __CFAssignWithWriteBarrier((void **)keys, (void *)bkt.weak_key); keys++; } @@ -500,14 +675,14 @@ void CFSetGetValues(CFHashRef hc, const_any_pointer_t *keybuf) { return (Boolean)true; }); } else { - CFBasicHashGetElements((CFBasicHashRef)hc, CFSetGetCount(hc), (uintptr_t *)valuebuf, NULL, (uintptr_t *)keybuf, NULL); + CFBasicHashGetElements((CFBasicHashRef)hc, CFSetGetCount(hc), (uintptr_t *)valuebuf, (uintptr_t *)keybuf); } } void CFSetApplyFunction(CFHashRef hc, CFSetApplierFunction applier, any_pointer_t context) { FAULT_CALLBACK((void **)&(applier)); - if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, void, hc, "_apply:context:", applier, context); - if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, void, hc, "_applyValues:context:", applier, context); + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, void, hc, "__apply:context:", applier, context); + if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, void, hc, "__applyValues:context:", applier, context); __CFGenericValidateType(hc, __kCFSetTypeID); CFBasicHashApply((CFBasicHashRef)hc, ^(CFBasicHashBucket bkt) { #if CFDictionary @@ -620,7 +795,7 @@ void CFSetSetValue(CFMutableHashRef hc, const_any_pointer_t key) { const_any_pointer_t value = key; #endif if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, void, hc, "setObject:forKey:", value, key); - if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, void, hc, "_setObject:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, void, hc, "setObject:", key); __CFGenericValidateType(hc, __kCFSetTypeID); CFAssert2(CFBasicHashIsMutable((CFBasicHashRef)hc), __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); if (!CFBasicHashIsMutable((CFBasicHashRef)hc)) { diff --git a/CFSet.h b/CFSet.h index a638d7e..3d9e0ff 100644 --- a/CFSet.h +++ b/CFSet.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFSet.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ /*! @header CFSet @@ -319,7 +319,7 @@ CFIndex CFSetGetCount(CFSetRef theSet); @function CFSetGetCountOfValue Counts the number of times the given value occurs in the set. Since sets by definition contain only one instance of a value, this function - is synomous to SFSetContainsValue. + is synonymous to CFSetContainsValue. @param theSet The set to be searched. If this parameter is not a valid CFSet, the behavior is undefined. @param value The value for which to find matches in the set. The @@ -365,7 +365,7 @@ CF_EXPORT const void *CFSetGetValue(CFSetRef theSet, const void *value); /*! - @function CFSetGetValue + @function CFSetGetValueIfPresent Retrieves a value in the set which hashes the same as the specified value, if present. @param theSet The set to be queried. If this parameter is not a diff --git a/CFSocket.c b/CFSocket.c index 7a6e472..1fc9d11 100644 --- a/CFSocket.c +++ b/CFSocket.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,14 +22,14 @@ */ /* CFSocket.c - Copyright (c) 1999-2010, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ #define NEW_SOCKET 0 #if NEW_SOCKET - +/* #include #include "CFInternal.h" @@ -103,14 +103,14 @@ struct __shared_blob { struct __CFSocket { CFRuntimeBase _base; - struct __shared_blob *_shared; /* non-NULL when valid, NULL when invalid */ + struct __shared_blob *_shared; // non-NULL when valid, NULL when invalid - uint8_t _state:2; /* mutable, not written safely */ - uint8_t _isSaneFD:1; /* immutable */ - uint8_t _connOriented:1; /* immutable */ - uint8_t _wantConnect:1; /* immutable */ - uint8_t _wantWrite:1; /* immutable */ - uint8_t _wantReadType:2; /* immutable */ + uint8_t _state:2; // mutable, not written safely + uint8_t _isSaneFD:1; // immutable + uint8_t _connOriented:1; // immutable + uint8_t _wantConnect:1; // immutable + uint8_t _wantWrite:1; // immutable + uint8_t _wantReadType:2; // immutable uint8_t _error; @@ -131,10 +131,10 @@ struct __CFSocket { int32_t _runLoopCounter; - CFDataRef _address; /* immutable, once created */ - CFDataRef _peerAddress; /* immutable, once created */ - CFSocketCallBack _callout; /* immutable */ - CFSocketContext _context; /* immutable */ + CFDataRef _address; // immutable, once created + CFDataRef _peerAddress; // immutable, once created + CFSocketCallBack _callout; // immutable + CFSocketContext _context; // immutable }; @@ -155,7 +155,7 @@ static CFStringRef __CFSocketCopyDescription(CFTypeRef cf) { void *addr = sock->_callout; const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; int avail = -1; - ioctl(sock->_shared ? sock->_shared->_socket : -1, FIONREAD, &avail); + ioctlsocket(sock->_shared ? sock->_shared->_socket : -1, FIONREAD, &avail); CFStringRef result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR( "{valid = %s, socket = %d, " "want connect = %s, connect disabled = %s, " @@ -180,7 +180,7 @@ static CFStringRef __CFSocketCopyDescription(CFTypeRef cf) { static void __CFSocketDeallocate(CFTypeRef cf) { CHECK_FOR_FORK_RET(); CFSocketRef sock = (CFSocketRef)cf; - /* Since CFSockets are cached, we can only get here sometime after being invalidated */ + // Since CFSockets are cached, we can only get here sometime after being invalidated sock->_state = kCFSocketStateDeallocating; if (sock->_peerAddress) { CFRelease(sock->_peerAddress); @@ -533,6 +533,7 @@ void CFSocketEnableCallBacks(CFSocketRef sock, CFOptionFlags callBackTypes) { dispatch_suspend(sock->_shared->_rdsrc); sock->_rsuspended = true; } + // If the source exists, but is now invalid, this next stuff is relatively harmless. if (sock->_shared->_source) { CFRunLoopSourceSignal(sock->_shared->_source); _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source); @@ -550,6 +551,7 @@ void CFSocketEnableCallBacks(CFSocketRef sock, CFOptionFlags callBackTypes) { dispatch_suspend(sock->_shared->_wrsrc); sock->_wsuspended = true; } + // If the source exists, but is now invalid, this next stuff is relatively harmless. if (sock->_shared->_source) { CFRunLoopSourceSignal(sock->_shared->_source); _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source); @@ -567,6 +569,7 @@ void CFSocketEnableCallBacks(CFSocketRef sock, CFOptionFlags callBackTypes) { dispatch_suspend(sock->_shared->_wrsrc); sock->_wsuspended = true; } + // If the source exists, but is now invalid, this next stuff is relatively harmless. if (sock->_shared->_source) { CFRunLoopSourceSignal(sock->_shared->_source); _CFRunLoopSourceWakeUpRunLoops(sock->_shared->_source); @@ -703,6 +706,8 @@ static void __CFSocketPerform(void *info) { // CFRunLoop should only call this o __block int new_fd = INVALID_SOCKET; __block CFDataRef address = NULL; __block CFMutableDataRef data = NULL; + __block void *context_info = NULL; + __block void (*context_release)(const void *) = NULL; dispatch_sync(__sockQueue(), ^{ isValid = __CFSocketIsValid(sock); if (!isValid) return; @@ -745,7 +750,7 @@ static void __CFSocketPerform(void *info) { // CFRunLoop should only call this o uint8_t name[MAX_SOCKADDR_LEN]; socklen_t namelen = sizeof(name); int avail = 0; - int ret = ioctl(fd, FIONREAD, &avail); + int ret = ioctlsocket(fd, FIONREAD, &avail); if (ret < 0 || avail < 256) avail = 256; if ((1 << 20) < avail) avail = (1 << 20); data = CFDataCreateMutable(CFGetAllocator(sock), 0); @@ -787,19 +792,16 @@ static void __CFSocketPerform(void *info) { // CFRunLoop should only call this o dispatch_resume(sock->_shared->_wrsrc); } } + if (sock->_context.retain && (doConnect || doRead || doWrite)) { + context_info = (void *)sock->_context.retain(sock->_context.info); + context_release = sock->_context.release; + } else { + context_info = sock->_context.info; + } }); // CFLog(5, CFSTR("__CFSocketPerform(%p) isValid:%d, doRead:%d, doWrite:%d, doConnect:%d error:%d"), sock, isValid, doRead, doWrite, doConnect, errorCode); if (!isValid || !(doConnect || doRead || doWrite)) return; - void *context_info = NULL; - void (*context_release)(const void *) = NULL; - if (sock->_context.retain) { - context_info = (void *)sock->_context.retain(sock->_context.info); - context_release = sock->_context.release; - } else { - context_info = sock->_context.info; - } - Boolean calledOut = false; if (doConnect) { if (sock->_callout) sock->_callout(sock, kCFSocketConnectCallBack, NULL, (0 != errorCode) ? &errorCode : NULL, context_info); @@ -937,13 +939,13 @@ CFIndex __CFSocketRead(CFSocketRef s, UInt8* buffer, CFIndex length, int* error) Boolean __CFSocketGetBytesAvailable(CFSocketRef s, CFIndex* ctBytesAvailable) { int bytesAvailable; - int ret = ioctl(CFSocketGetNative(s), FIONREAD, &bytesAvailable); + int ret = ioctlsocket(CFSocketGetNative(s), FIONREAD, &bytesAvailable); if (ret < 0) return false; *ctBytesAvailable = (CFIndex)bytesAvailable; return true; } - +*/ #else /* not NEW_SOCKET */ @@ -951,8 +953,12 @@ Boolean __CFSocketGetBytesAvailable(CFSocketRef s, CFIndex* ctBytesAvailable) { #include #include #include -#include +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED #include +#include +#include +#include +#endif #include #include #include @@ -960,21 +966,59 @@ Boolean __CFSocketGetBytesAvailable(CFSocketRef s, CFIndex* ctBytesAvailable) { #include #include #include "CFInternal.h" -#include -#include + +#if DEPLOYMENT_TARGET_WINDOWS + +#define EINPROGRESS WSAEINPROGRESS + +// redefine this to the winsock error in this file +#undef EBADF +#define EBADF WSAENOTSOCK + +#define NBBY 8 +#define NFDBITS (sizeof(int32_t) * NBBY) + +typedef int32_t fd_mask; +typedef int socklen_t; + +// not entirely correct, but good enough for what it's used for here +void gettimeofday(struct timeval *tp, void *tzp) { + tp->tv_sec = 0; + tp->tv_usec = 0; +} + +// although this is only used for debug info, we define it for compatibility +#define timersub(tvp, uvp, vvp) \ + do { \ + (vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \ + (vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \ + if ((vvp)->tv_usec < 0) { \ + (vvp)->tv_sec--; \ + (vvp)->tv_usec += 1000000; \ + } \ + } while (0) + + +#endif // DEPLOYMENT_TARGET_WINDOWS + // On Mach we use a v0 RunLoopSource to make client callbacks. That source is signalled by a // separate SocketManager thread who uses select() to watch the sockets' fds. //#define LOG_CFSOCKET +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED #define INVALID_SOCKET (CFSocketNativeHandle)(-1) - #define closesocket(a) close((a)) #define ioctlsocket(a,b,c) ioctl((a),(b),(c)) +#endif CF_INLINE int __CFSocketLastError(void) { +#if DEPLOYMENT_TARGET_WINDOWS + return WSAGetLastError(); +#else return thread_errno(); +#endif } CF_INLINE CFIndex __CFSocketFdGetSize(CFDataRef fdSet) { @@ -1154,8 +1198,14 @@ CF_INLINE void __CFSocketEstablishPeerAddress(CFSocketRef s) { } static Boolean __CFNativeSocketIsValid(CFSocketNativeHandle sock) { +#if DEPLOYMENT_TARGET_WINDOWS + SInt32 errorCode = 0; + int errorSize = sizeof(errorCode); + return !(0 != getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&errorCode, &errorSize) && __CFSocketLastError() == WSAENOTSOCK); +#else SInt32 flags = fcntl(sock, F_GETFL, 0); - return !(0 > flags && EBADF == thread_errno()); + return !(0 > flags && EBADF == __CFSocketLastError()); +#endif } CF_INLINE Boolean __CFSocketFdClr(CFSocketNativeHandle sock, CFMutableDataRef fdSet) { @@ -1176,7 +1226,45 @@ CF_INLINE Boolean __CFSocketFdClr(CFSocketNativeHandle sock, CFMutableDataRef fd } static SInt32 __CFSocketCreateWakeupSocketPair(void) { - return socketpair(PF_LOCAL, SOCK_DGRAM, 0, __CFWakeupSocketPair); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + SInt32 error; + + error = socketpair(PF_LOCAL, SOCK_DGRAM, 0, __CFWakeupSocketPair); + if (0 <= error) error = fcntl(__CFWakeupSocketPair[0], F_SETFD, FD_CLOEXEC); + if (0 <= error) error = fcntl(__CFWakeupSocketPair[1], F_SETFD, FD_CLOEXEC); + if (0 > error) { + closesocket(__CFWakeupSocketPair[0]); + closesocket(__CFWakeupSocketPair[1]); + __CFWakeupSocketPair[0] = INVALID_SOCKET; + __CFWakeupSocketPair[1] = INVALID_SOCKET; + } +#else + UInt32 i; + SInt32 error = 0; + struct sockaddr_in address[2]; + int namelen = sizeof(struct sockaddr_in); + for (i = 0; i < 2; i++) { + __CFWakeupSocketPair[i] = socket(PF_INET, SOCK_DGRAM, 0); + memset(&(address[i]), 0, sizeof(struct sockaddr_in)); + address[i].sin_family = AF_INET; + address[i].sin_addr.s_addr = htonl(INADDR_LOOPBACK); + if (0 <= error) error = bind(__CFWakeupSocketPair[i], (struct sockaddr *)&(address[i]), sizeof(struct sockaddr_in)); + if (0 <= error) error = getsockname(__CFWakeupSocketPair[i], (struct sockaddr *)&(address[i]), &namelen); + if (sizeof(struct sockaddr_in) != namelen) error = -1; + } + if (0 <= error) error = connect(__CFWakeupSocketPair[0], (struct sockaddr *)&(address[1]), sizeof(struct sockaddr_in)); + if (0 <= error) error = connect(__CFWakeupSocketPair[1], (struct sockaddr *)&(address[0]), sizeof(struct sockaddr_in)); + if (0 > error) { + closesocket(__CFWakeupSocketPair[0]); + closesocket(__CFWakeupSocketPair[1]); + __CFWakeupSocketPair[0] = INVALID_SOCKET; + __CFWakeupSocketPair[1] = INVALID_SOCKET; + } +#endif +#if defined(LOG_CFSOCKET) + fprintf(stdout, "wakeup socket pair is %d / %d\n", __CFWakeupSocketPair[0], __CFWakeupSocketPair[1]); +#endif + return error; } @@ -1187,7 +1275,7 @@ CF_INLINE Boolean __CFSocketSetFDForRead(CFSocketRef s) { Boolean b = __CFSocketFdSet(s->_socket, __CFReadSocketsFds); if (b && INVALID_SOCKET != __CFWakeupSocketPair[0]) { uint8_t c = 'r'; - send(__CFWakeupSocketPair[0], &c, sizeof(c), 0); + send(__CFWakeupSocketPair[0], (const char *)&c, sizeof(c), 0); } return b; } @@ -1197,7 +1285,7 @@ CF_INLINE Boolean __CFSocketClearFDForRead(CFSocketRef s) { Boolean b = __CFSocketFdClr(s->_socket, __CFReadSocketsFds); if (b && INVALID_SOCKET != __CFWakeupSocketPair[0]) { uint8_t c = 's'; - send(__CFWakeupSocketPair[0], &c, sizeof(c), 0); + send(__CFWakeupSocketPair[0], (const char *)&c, sizeof(c), 0); } return b; } @@ -1207,7 +1295,7 @@ CF_INLINE Boolean __CFSocketSetFDForWrite(CFSocketRef s) { Boolean b = __CFSocketFdSet(s->_socket, __CFWriteSocketsFds); if (b && INVALID_SOCKET != __CFWakeupSocketPair[0]) { uint8_t c = 'w'; - send(__CFWakeupSocketPair[0], &c, sizeof(c), 0); + send(__CFWakeupSocketPair[0], (const char *)&c, sizeof(c), 0); } return b; } @@ -1217,11 +1305,49 @@ CF_INLINE Boolean __CFSocketClearFDForWrite(CFSocketRef s) { Boolean b = __CFSocketFdClr(s->_socket, __CFWriteSocketsFds); if (b && INVALID_SOCKET != __CFWakeupSocketPair[0]) { uint8_t c = 'x'; - send(__CFWakeupSocketPair[0], &c, sizeof(c), 0); + send(__CFWakeupSocketPair[0], (const char *)&c, sizeof(c), 0); } return b; } +#if DEPLOYMENT_TARGET_WINDOWS +static Boolean WinSockUsed = FALSE; + +static void __CFSocketInitializeWinSock_Guts(void) { + if (!WinSockUsed) { + WinSockUsed = TRUE; + WORD versionRequested = MAKEWORD(2, 2); + WSADATA wsaData; + int errorStatus = WSAStartup(versionRequested, &wsaData); + if (errorStatus != 0 || LOBYTE(wsaData.wVersion) != LOBYTE(versionRequested) || HIBYTE(wsaData.wVersion) != HIBYTE(versionRequested)) { + WSACleanup(); + CFLog(kCFLogLevelWarning, CFSTR("*** Could not initialize WinSock subsystem!!!")); + } + } +} + +CF_EXPORT void __CFSocketInitializeWinSock(void) { + __CFSpinLock(&__CFActiveSocketsLock); + __CFSocketInitializeWinSock_Guts(); + __CFSpinUnlock(&__CFActiveSocketsLock); +} + +__private_extern__ void __CFSocketCleanup(void) { + if (INVALID_SOCKET != __CFWakeupSocketPair[0]) { + closesocket(__CFWakeupSocketPair[0]); + __CFWakeupSocketPair[0] = INVALID_SOCKET; + } + if (INVALID_SOCKET != __CFWakeupSocketPair[1]) { + closesocket(__CFWakeupSocketPair[1]); + __CFWakeupSocketPair[1] = INVALID_SOCKET; + } + if (WinSockUsed) { + // technically this is not supposed to be called here since it will be called from dllmain, but I don't know where else to put it + WSACleanup(); + } +} + +#endif // CFNetwork needs to call this, especially for Win32 to get WSAStartup static void __CFSocketInitializeSockets(void) { @@ -1230,18 +1356,22 @@ static void __CFSocketInitializeSockets(void) { __CFWriteSocketsFds = CFDataCreateMutable(kCFAllocatorSystemDefault, 0); __CFReadSocketsFds = CFDataCreateMutable(kCFAllocatorSystemDefault, 0); zeroLengthData = CFDataCreateMutable(kCFAllocatorSystemDefault, 0); +#if DEPLOYMENT_TARGET_WINDOWS + __CFSocketInitializeWinSock_Guts(); +#endif if (0 > __CFSocketCreateWakeupSocketPair()) { CFLog(kCFLogLevelWarning, CFSTR("*** Could not create wakeup socket pair for CFSocket!!!")); } else { UInt32 yes = 1; /* wakeup sockets must be non-blocking */ - ioctlsocket(__CFWakeupSocketPair[0], FIONBIO, &yes); - ioctlsocket(__CFWakeupSocketPair[1], FIONBIO, &yes); + ioctlsocket(__CFWakeupSocketPair[0], FIONBIO, (u_long *)&yes); + ioctlsocket(__CFWakeupSocketPair[1], FIONBIO, (u_long *)&yes); __CFSocketFdSet(__CFWakeupSocketPair[1], __CFReadSocketsFds); } } static CFRunLoopRef __CFSocketCopyRunLoopToWakeUp(CFRunLoopSourceRef src, CFMutableArrayRef runLoops) { + if (!src) return NULL; CFRunLoopRef rl = NULL; SInt32 idx, cnt = CFArrayGetCount(runLoops); if (0 < cnt) { @@ -1294,9 +1424,10 @@ static void __CFSocketHandleWrite(CFSocketRef s, Boolean callBackNow) { CFOptionFlags writeCallBacksAvailable; if (!CFSocketIsValid(s)) return; - if (0 != (s->_f.client & kCFSocketLeaveErrors) || 0 != getsockopt(s->_socket, SOL_SOCKET, SO_ERROR, (void *)&errorCode, (socklen_t *)&errorSize)) errorCode = 0; // cast for WinSock bad API + if (0 != (s->_f.client & kCFSocketLeaveErrors) || 0 != getsockopt(s->_socket, SOL_SOCKET, SO_ERROR, (char *)&errorCode, (socklen_t *)&errorSize)) errorCode = 0; + // cast for WinSock bad API #if defined(LOG_CFSOCKET) - if (errorCode) fprintf(stdout, "error %ld on socket %d\n", errorCode, s->_socket); + if (errorCode) fprintf(stdout, "error %ld on socket %d\n", (long)errorCode, s->_socket); #endif __CFSocketLock(s); writeCallBacksAvailable = __CFSocketCallBackTypes(s) & (kCFSocketWriteCallBack | kCFSocketConnectCallBack); @@ -1353,18 +1484,18 @@ static void __CFSocketHandleRead(CFSocketRef s, Boolean causedByTimeout) SInt32 recvlen = 0; if (__CFSocketIsConnectionOriented(s)) { buffer = bufferArray; - recvlen = recvfrom(s->_socket, buffer, MAX_CONNECTION_ORIENTED_DATA_SIZE, 0, (struct sockaddr *)name, (socklen_t *)&namelen); + recvlen = recvfrom(s->_socket, (char *)buffer, MAX_CONNECTION_ORIENTED_DATA_SIZE, 0, (struct sockaddr *)name, (socklen_t *)&namelen); } else { - buffer = malloc(MAX_DATA_SIZE); - if (buffer) recvlen = recvfrom(s->_socket, buffer, MAX_DATA_SIZE, 0, (struct sockaddr *)name, (socklen_t *)&namelen); + buffer = (uint8_t *)malloc(MAX_DATA_SIZE); + if (buffer) recvlen = recvfrom(s->_socket, (char *)buffer, MAX_DATA_SIZE, 0, (struct sockaddr *)name, (socklen_t *)&namelen); } #if defined(LOG_CFSOCKET) - fprintf(stdout, "read %ld bytes on socket %d\n", recvlen, s->_socket); + fprintf(stdout, "read %ld bytes on socket %d\n", (long)recvlen, s->_socket); #endif if (0 >= recvlen) { //??? should return error if <0 /* zero-length data is the signal for perform to invalidate */ - data = CFRetain(zeroLengthData); + data = (CFDataRef)CFRetain(zeroLengthData); } else { data = CFDataCreate(CFGetAllocator(s), buffer, recvlen); } @@ -1381,10 +1512,10 @@ static void __CFSocketHandleRead(CFSocketRef s, Boolean causedByTimeout) address = CFDataCreate(CFGetAllocator(s), name, namelen); } else if (__CFSocketIsConnectionOriented(s)) { if (NULL == s->_peerAddress) __CFSocketEstablishPeerAddress(s); - if (NULL != s->_peerAddress) address = CFRetain(s->_peerAddress); + if (NULL != s->_peerAddress) address = (CFDataRef)CFRetain(s->_peerAddress); } if (NULL == address) { - address = CFRetain(zeroLengthData); + address = (CFDataRef)CFRetain(zeroLengthData); } if (NULL == s->_dataQueue) { s->_dataQueue = CFArrayCreateMutable(CFGetAllocator(s), 0, &kCFTypeArrayCallBacks); @@ -1416,7 +1547,7 @@ static void __CFSocketHandleRead(CFSocketRef s, Boolean causedByTimeout) if (NULL != name && 0 < namelen) { address = CFDataCreate(CFGetAllocator(s), name, namelen); } else { - address = CFRetain(zeroLengthData); + address = (CFDataRef)CFRetain(zeroLengthData); } __CFSocketLock(s); if (!__CFSocketIsValid(s)) { @@ -1452,7 +1583,7 @@ static void __CFSocketHandleRead(CFSocketRef s, Boolean causedByTimeout) if (causedByTimeout) { #if defined(LOG_CFSOCKET) - fprintf(stdout, "TIMEOUT RECEIVED - WILL SIGNAL IMMEDIATELY TO FLUSH (%d buffered)\n", s->_bytesToBufferPos); + fprintf(stdout, "TIMEOUT RECEIVED - WILL SIGNAL IMMEDIATELY TO FLUSH (%ld buffered)\n", s->_bytesToBufferPos); #endif /* we've got a timeout, but no bytes read. Ignore the timeout. */ if (s->_bytesToBufferPos == 0) { @@ -1501,7 +1632,7 @@ static void __CFSocketHandleRead(CFSocketRef s, Boolean causedByTimeout) s->_bytesToBufferPos += ctRead; if (s->_bytesToBuffer != s->_bytesToBufferPos) { #if defined(LOG_CFSOCKET) - fprintf(stdout, "READ %d - need %d MORE - GOING BACK FOR MORE\n", ctRead, s->_bytesToBuffer - s->_bytesToBufferPos); + fprintf(stdout, "READ %ld - need %ld MORE - GOING BACK FOR MORE\n", ctRead, s->_bytesToBuffer - s->_bytesToBufferPos); #endif __CFSpinLock(&__CFActiveSocketsLock); /* restore socket to fds */ @@ -1511,7 +1642,7 @@ static void __CFSocketHandleRead(CFSocketRef s, Boolean causedByTimeout) return; } else { #if defined(LOG_CFSOCKET) - fprintf(stdout, "DONE READING (read %d bytes) - GOING TO SIGNAL\n", ctRead); + fprintf(stdout, "DONE READING (read %ld bytes) - GOING TO SIGNAL\n", ctRead); #endif } } @@ -1597,7 +1728,7 @@ void __CFSocketSetSocketReadBufferAttrs(CFSocketRef s, CFTimeInterval timeout, C * aside and use them to satisfy any subsequent reads. */ #if defined(LOG_CFSOCKET) - __socketLog("%s(%d): WARNING: shouldn't set read buffer length while data (%d bytes) is still in the read buffer (leftover total %d)", __FUNCTION__, __LINE__, ctBuffer, s->_leftoverBytes? CFDataGetLength(s->_leftoverBytes) : 0); + fprintf(stdout, "%s(%d): WARNING: shouldn't set read buffer length while data (%ld bytes) is still in the read buffer (leftover total %ld)", __FUNCTION__, __LINE__, ctBuffer, s->_leftoverBytes? CFDataGetLength(s->_leftoverBytes) : 0); #endif if (s->_leftoverBytes == NULL) @@ -1621,7 +1752,8 @@ void __CFSocketSetSocketReadBufferAttrs(CFSocketRef s, CFTimeInterval timeout, C s->_readBuffer = NULL; } // Zero length buffer, smash the timeout - timeoutVal = (struct timeval) { 0, 0 }; + timeoutVal.tv_sec = 0; + timeoutVal.tv_usec = 0; } else { /* if the buffer shrank, we can re-use the old one */ if (length > s->_bytesToBuffer) { @@ -1653,7 +1785,7 @@ void __CFSocketSetSocketReadBufferAttrs(CFSocketRef s, CFTimeInterval timeout, C CFIndex __CFSocketRead(CFSocketRef s, UInt8* buffer, CFIndex length, int* error) { #if defined(LOG_CFSOCKET) - fprintf(stdout, "READING BYTES FOR SOCKET %d (%d buffered, out of %d desired, eof = %d, err = %d)\n", s->_socket, s->_bytesToBufferPos, s->_bytesToBuffer, s->_atEOF, s->_bufferedReadError); + fprintf(stdout, "READING BYTES FOR SOCKET %d (%ld buffered, out of %ld desired, eof = %d, err = %d)\n", s->_socket, s->_bytesToBufferPos, s->_bytesToBuffer, s->_atEOF, s->_bufferedReadError); #endif CFIndex result = -1; @@ -1699,7 +1831,7 @@ CFIndex __CFSocketRead(CFSocketRef s, UInt8* buffer, CFIndex length, int* error) } #if defined(LOG_CFSOCKET) - fprintf(stdout, "SLURPED %d BYTES FROM BUFFER %d LEFT TO READ!\n", ctBuffer, length); + fprintf(stdout, "SLURPED %ld BYTES FROM BUFFER %ld LEFT TO READ!\n", ctBuffer, length); #endif result = ctBuffer; @@ -1730,7 +1862,7 @@ CFIndex __CFSocketRead(CFSocketRef s, UInt8* buffer, CFIndex length, int* error) /* normal read */ result = read(CFSocketGetNative(s), buffer, length); #if defined(LOG_CFSOCKET) - fprintf(stdout, "READ %d bytes", result); + fprintf(stdout, "READ %ld bytes", result); #endif if (result == 0) { @@ -1759,13 +1891,8 @@ Boolean __CFSocketGetBytesAvailable(CFSocketRef s, CFIndex* ctBytesAvailable) return true; } else { int result; -#if DEPLOYMENT_TARGET_WINDOWS - int bytesAvailable, intLen = sizeof(bytesAvailable); - result = getsockopt(CFSocketGetNative(s), SOL_SOCKET, SO_NREAD, &bytesAvailable, (void *)&intLen); -#else unsigned long bytesAvailable; result = ioctlsocket(CFSocketGetNative(s), FIONREAD, &bytesAvailable); -#endif if (result < 0) return false; *ctBytesAvailable = (CFIndex) bytesAvailable; @@ -1815,7 +1942,7 @@ static void __CFSocketManager(void * arg) __CFSpinLock(&__CFActiveSocketsLock); __CFSocketManagerIteration++; #if defined(LOG_CFSOCKET) - fprintf(stdout, "socket manager iteration %lu looking at read sockets ", __CFSocketManagerIteration); + fprintf(stdout, "socket manager iteration %lu looking at read sockets ", (unsigned long)__CFSocketManagerIteration); __CFSocketWriteSocketList(__CFReadSockets, __CFReadSocketsFds, FALSE); if (0 < CFArrayGetCount(__CFWriteSockets)) { fprintf(stdout, " and write sockets "); @@ -1851,7 +1978,7 @@ static void __CFSocketManager(void * arg) pTimeout = NULL; } else { #if defined(LOG_CFSOCKET) - fprintf(stdout, "timeout will be %d, %d!\n", minTimeout->tv_sec, minTimeout->tv_usec); + fprintf(stdout, "timeout will be %ld, %d!\n", minTimeout->tv_sec, minTimeout->tv_usec); #endif tv = *minTimeout; pTimeout = &tv; @@ -1860,17 +1987,21 @@ static void __CFSocketManager(void * arg) if (pTimeout) { #if defined(LOG_CFSOCKET) - fprintf(stdout, "select will have a %d, %d timeout\n", pTimeout->tv_sec, pTimeout->tv_usec); + fprintf(stdout, "select will have a %ld, %d timeout\n", pTimeout->tv_sec, pTimeout->tv_usec); #endif gettimeofday(&timeBeforeSelect, NULL); } __CFSpinUnlock(&__CFActiveSocketsLock); +#if DEPLOYMENT_TARGET_WINDOWS + // On Windows, select checks connection failed sockets via the exceptfds parameter. connection succeeded is checked via writefds. We need both. + exceptfds = writefds; +#endif nrfds = select(maxnrfds, readfds, writefds, exceptfds, pTimeout); #if defined(LOG_CFSOCKET) - fprintf(stdout, "socket manager woke from select, ret=%ld\n", nrfds); + fprintf(stdout, "socket manager woke from select, ret=%ld\n", (long)nrfds); #endif /* @@ -1884,7 +2015,7 @@ static void __CFSocketManager(void * arg) timersub(&timeAfterSelect, &timeBeforeSelect, &deltaTime); #if defined(LOG_CFSOCKET) - fprintf(stdout, "Socket manager received timeout - kicking off expired reads (expired delta %d, %d)\n", deltaTime.tv_sec, deltaTime.tv_usec); + fprintf(stdout, "Socket manager received timeout - kicking off expired reads (expired delta %ld, %d)\n", deltaTime.tv_sec, deltaTime.tv_usec); #endif __CFSpinLock(&__CFActiveSocketsLock); @@ -1902,7 +2033,7 @@ static void __CFSocketManager(void * arg) /* if this sockets timeout is less than or equal elapsed time, then signal it */ if (INVALID_SOCKET != sock && sockInBounds) { #if defined(LOG_CFSOCKET) - fprintf(stdout, "Expiring socket %d (delta %d, %d)\n", sock, s->_readBufferTimeout.tv_sec, s->_readBufferTimeout.tv_usec); + fprintf(stdout, "Expiring socket %d (delta %ld, %d)\n", sock, s->_readBufferTimeout.tv_sec, s->_readBufferTimeout.tv_usec); #endif CFArraySetValueAtIndex(selectedReadSockets, selectedReadSocketsIndex, s); selectedReadSocketsIndex++; @@ -1921,7 +2052,7 @@ static void __CFSocketManager(void * arg) if (0 > nrfds) { SInt32 selectError = __CFSocketLastError(); #if defined(LOG_CFSOCKET) - fprintf(stdout, "socket manager received error %ld from select\n", selectError); + fprintf(stdout, "socket manager received error %ld from select\n", (long)selectError); #endif if (EBADF == selectError) { CFMutableArrayRef invalidSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); @@ -1957,7 +2088,7 @@ static void __CFSocketManager(void * arg) continue; } if (FD_ISSET(__CFWakeupSocketPair[1], readfds)) { - recv(__CFWakeupSocketPair[1], buffer, sizeof(buffer), 0); + recv(__CFWakeupSocketPair[1], (char *)buffer, sizeof(buffer), 0); #if defined(LOG_CFSOCKET) fprintf(stdout, "socket manager received %c on wakeup socket\n", buffer[0]); #endif @@ -2035,8 +2166,13 @@ static CFStringRef __CFSocketCopyDescription(CFTypeRef cf) { result = CFStringCreateMutable(CFGetAllocator(s), 0); __CFSocketLock(s); void *addr = s->_callout; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED Dl_info info; const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; +#else + // don't bother trying to figure out callout names + const char *name = ""; +#endif CFStringAppendFormat(result, NULL, CFSTR("{valid = %s, type = %d, socket = %d, socket set count = %ld,\n callback types = 0x%x, callout = %s (%p), source = %p,\n run loops = %@,\n context = "), cf, CFGetAllocator(s), (__CFSocketIsValid(s) ? "Yes" : "No"), s->_socketType, s->_socket, s->_socketSetCount, __CFSocketCallBackTypes(s), name, addr, s->_source0, s->_runLoops); contextInfo = s->_context.info; contextCopyDescription = s->_context.copyDescription; @@ -2093,6 +2229,7 @@ static const CFRuntimeClass __CFSocketClass = { CFTypeID CFSocketGetTypeID(void) { if (_kCFRuntimeNotATypeID == __kCFSocketTypeID) { __kCFSocketTypeID = _CFRuntimeRegisterClass(&__CFSocketClass); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED struct rlimit lim1; int ret1 = getrlimit(RLIMIT_NOFILE, &lim1); int mib[] = {CTL_KERN, KERN_MAXFILESPERPROC}; @@ -2107,6 +2244,7 @@ CFTypeID CFSocketGetTypeID(void) { setrlimit(RLIMIT_NOFILE, &lim2); // we try, but do not go to extraordinary measures } +#endif } return __kCFSocketTypeID; } @@ -2129,7 +2267,7 @@ static CFSocketRef _CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketN return memory; } else { #if defined(LOG_CFSOCKET) - fprintf(stdout, "useExistingInstance is FALSE, removing existing instance %d from __CFAllSockets\n", (int)memory); + fprintf(stdout, "useExistingInstance is FALSE, removing existing instance %p from __CFAllSockets\n", memory); #endif __CFSpinUnlock(&__CFAllSocketsLock); CFSocketInvalidate(memory); @@ -2153,7 +2291,7 @@ static CFSocketRef _CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketN memory->_lock = CFSpinLockInit; memory->_writeLock = CFSpinLockInit; memory->_socket = sock; - if (INVALID_SOCKET == sock || 0 != getsockopt(sock, SOL_SOCKET, SO_TYPE, (void *)&(memory->_socketType), (socklen_t *)&typeSize)) memory->_socketType = 0; // cast for WinSock bad API + if (INVALID_SOCKET == sock || 0 != getsockopt(sock, SOL_SOCKET, SO_TYPE, (char *)&(memory->_socketType), (socklen_t *)&typeSize)) memory->_socketType = 0; // cast for WinSock bad API memory->_errorCode = 0; memory->_address = NULL; memory->_peerAddress = NULL; @@ -2192,7 +2330,9 @@ static CFSocketRef _CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketN memory->_context.info = contextInfo; __CFSocketUnlock(memory); } -// CFLog(5, CFSTR("CFSocketCreateWithNative(): created socket %p with callbacks 0x%x"), memory, callBackTypes); +#if defined(LOG_CFSOCKET) + CFLog(5, CFSTR("CFSocketCreateWithNative(): created socket %p (%d) with callbacks 0x%x"), memory, memory->_socket, callBackTypes); +#endif return memory; } @@ -2275,7 +2415,9 @@ void CFSocketInvalidate(CFSocketRef s) { } __CFSpinUnlock(&__CFAllSocketsLock); CFRelease(s); -// CFLog(5, CFSTR("CFSocketInvalidate(%p) done"), s); +#if defined(LOG_CFSOCKET) + CFLog(5, CFSTR("CFSocketInvalidate(%p) done"), s); +#endif } Boolean CFSocketIsValid(CFSocketRef s) { @@ -2297,10 +2439,12 @@ CFDataRef CFSocketCopyAddress(CFSocketRef s) { __CFSocketLock(s); __CFSocketEstablishAddress(s); if (NULL != s->_address) { - result = CFRetain(s->_address); + result = (CFDataRef)CFRetain(s->_address); } __CFSocketUnlock(s); -// CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p address %@"), s, result); +#if defined(LOG_CFSOCKET) + CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p address %@"), s, result); +#endif return result; } @@ -2311,10 +2455,12 @@ CFDataRef CFSocketCopyPeerAddress(CFSocketRef s) { __CFSocketLock(s); __CFSocketEstablishPeerAddress(s); if (NULL != s->_peerAddress) { - result = CFRetain(s->_peerAddress); + result = (CFDataRef)CFRetain(s->_peerAddress); } __CFSocketUnlock(s); -// CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p peer address %@"), s, result); +#if defined(LOG_CFSOCKET) + CFLog(5, CFSTR("CFSocketCopyAddress(): created socket %p peer address %@"), s, result); +#endif return result; } @@ -2445,7 +2591,7 @@ void CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes) { } static void __CFSocketSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) { - CFSocketRef s = info; + CFSocketRef s = (CFSocketRef)info; __CFSocketLock(s); //??? also need to arrange delivery of all pending data if (__CFSocketIsValid(s)) { @@ -2471,7 +2617,7 @@ static void __CFSocketSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) { } static void __CFSocketCancel(void *info, CFRunLoopRef rl, CFStringRef mode) { - CFSocketRef s = info; + CFSocketRef s = (CFSocketRef)info; SInt32 idx; __CFSocketLock(s); s->_socketSetCount--; @@ -2532,7 +2678,7 @@ static void __CFSocketDoCallback(CFSocketRef s, CFDataRef data, CFDataRef addres // CFLog(5, CFSTR("__CFSocketPerformV0(%p) doing connect callback, error: %d"), s, errorCode); if (errorCode) { #if defined(LOG_CFSOCKET) - fprintf(stdout, "perform calling out error %ld to socket %d\n", errorCode, s->_socket); + fprintf(stdout, "perform calling out error %ld to socket %d\n", (long)errorCode, s->_socket); #endif if (callout) callout(s, kCFSocketConnectCallBack, NULL, &errorCode, contextInfo); calledOut = true; @@ -2549,7 +2695,7 @@ static void __CFSocketDoCallback(CFSocketRef s, CFDataRef data, CFDataRef addres if (NULL != data && (!calledOut || CFSocketIsValid(s))) { SInt32 datalen = CFDataGetLength(data); #if defined(LOG_CFSOCKET) - fprintf(stdout, "perform calling out data of length %ld to socket %d\n", datalen, s->_socket); + fprintf(stdout, "perform calling out data of length %ld to socket %d\n", (long)datalen, s->_socket); #endif if (callout) callout(s, kCFSocketDataCallBack, address, data, contextInfo); calledOut = true; @@ -2586,7 +2732,7 @@ static void __CFSocketDoCallback(CFSocketRef s, CFDataRef data, CFDataRef addres } static void __CFSocketPerformV0(void *info) { - CFSocketRef s = info; + CFSocketRef s = (CFSocketRef)info; CFDataRef data = NULL; CFDataRef address = NULL; CFSocketNativeHandle sock = INVALID_SOCKET; @@ -2607,10 +2753,10 @@ static void __CFSocketPerformV0(void *info) { if (kCFSocketDataCallBack == readCallBackType) { if (NULL != s->_dataQueue && 0 < CFArrayGetCount(s->_dataQueue)) { - data = CFArrayGetValueAtIndex(s->_dataQueue, 0); + data = (CFDataRef)CFArrayGetValueAtIndex(s->_dataQueue, 0); CFRetain(data); CFArrayRemoveValueAtIndex(s->_dataQueue, 0); - address = CFArrayGetValueAtIndex(s->_addressQueue, 0); + address = (CFDataRef)CFArrayGetValueAtIndex(s->_addressQueue, 0); CFRetain(address); CFArrayRemoveValueAtIndex(s->_addressQueue, 0); } @@ -2618,7 +2764,7 @@ static void __CFSocketPerformV0(void *info) { if (NULL != s->_dataQueue && 0 < CFArrayGetCount(s->_dataQueue)) { sock = (CFSocketNativeHandle)(uintptr_t)CFArrayGetValueAtIndex(s->_dataQueue, 0); CFArrayRemoveValueAtIndex(s->_dataQueue, 0); - address = CFArrayGetValueAtIndex(s->_addressQueue, 0); + address = (CFDataRef)CFArrayGetValueAtIndex(s->_addressQueue, 0); CFRetain(address); CFArrayRemoveValueAtIndex(s->_addressQueue, 0); } @@ -2773,14 +2919,14 @@ CFSocketError CFSocketSendData(CFSocketRef s, CFDataRef address, CFDataRef data, __CFSocketWriteLock(s); tv.tv_sec = (timeout <= 0.0 || (CFTimeInterval)INT_MAX <= timeout) ? INT_MAX : (int)floor(timeout); tv.tv_usec = (int)floor(1.0e+6 * (timeout - floor(timeout))); - setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (void *)&tv, sizeof(tv)); // cast for WinSock bad API + setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)); // cast for WinSock bad API if (NULL != addrptr && 0 < addrlen) { - size = sendto(sock, dataptr, datalen, 0, (struct sockaddr *)addrptr, addrlen); + size = sendto(sock, (char *)dataptr, datalen, 0, (struct sockaddr *)addrptr, addrlen); } else { - size = send(sock, dataptr, datalen, 0); + size = send(sock, (char *)dataptr, datalen, 0); } #if defined(LOG_CFSOCKET) - fprintf(stdout, "wrote %ld bytes to socket %d\n", size, sock); + fprintf(stdout, "wrote %ld bytes to socket %d\n", (long)size, sock); #endif __CFSocketWriteUnlock(s); CFRelease(s); @@ -2790,21 +2936,45 @@ CFSocketError CFSocketSendData(CFSocketRef s, CFDataRef address, CFDataRef data, CFSocketError CFSocketSetAddress(CFSocketRef s, CFDataRef address) { CHECK_FOR_FORK(); - const uint8_t *name; - SInt32 namelen, result = 0; + struct sockaddr *name; + socklen_t namelen; __CFGenericValidateType(s, CFSocketGetTypeID()); if (NULL == address) return kCFSocketError; if (!CFSocketIsValid(s)) return kCFSocketError; - name = CFDataGetBytePtr(address); - namelen = CFDataGetLength(address); + + name = (struct sockaddr *)CFDataGetBytePtr(address); + namelen = (socklen_t)CFDataGetLength(address); if (!name || namelen <= 0) return kCFSocketError; + CFSocketNativeHandle sock = CFSocketGetNative(s); - result = bind(sock, (struct sockaddr *)name, namelen); - if (0 == result) { - listen(sock, 256); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + // Verify that the namelen is correct. If not, we have to fix it up. Developers will often incorrectly use 0 or strlen(path). See 9217961 and the second half of 9098274. + // Max size is a size byte, plus family byte, plus path of 255, plus a null byte. + char newName[255]; + if (namelen > 2 && name->sa_family == AF_UNIX) { + // Don't use the SUN_LEN macro, because strnlen is safer and we know the max length of the string (from CFData, minus 2 bytes for len and addr) + socklen_t realLength = (sizeof(*((struct sockaddr_un *)name)) - sizeof(((struct sockaddr_un *)name)->sun_path) + strnlen(((struct sockaddr_un *)name)->sun_path, namelen - 2)); + if (realLength > 255) return kCFSocketError; + + // For a UNIX domain socket, we must pass the value of name.sun_len to bind in order for getsockname() to return a result that makes sense. + namelen = (socklen_t)(((struct sockaddr_un *)name)->sun_len); + + if (realLength != namelen) { + // We got a different answer for length than was supplied by the caller. Fix it up so we don't end up truncating the path. + CFLog(kCFLogLevelWarning, CFSTR("WARNING: The sun_len field of a sockaddr_un structure passed to CFSocketSetAddress was not set correctly using the SUN_LEN macro.")); + memcpy(newName, name, realLength); + namelen = realLength; + ((struct sockaddr_un *)newName)->sun_len = realLength; + name = (struct sockaddr *)newName; } + } +#endif + int result = bind(sock, name, namelen); + if (0 == result) { + listen(sock, 256); + } //??? should return errno - return result; + return (CFIndex)result; } CFSocketError CFSocketConnectToAddress(CFSocketRef s, CFDataRef address, CFTimeInterval timeout) { @@ -2822,15 +2992,27 @@ CFSocketError CFSocketConnectToAddress(CFSocketRef s, CFDataRef address, CFTimeI if (!name || namelen <= 0) return kCFSocketError; CFSocketNativeHandle sock = CFSocketGetNative(s); { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED SInt32 flags = fcntl(sock, F_GETFL, 0); if (flags >= 0) wasBlocking = ((flags & O_NONBLOCK) == 0); - if (wasBlocking && (timeout > 0.0 || timeout < 0.0)) ioctl(sock, FIONBIO, &yes); + if (wasBlocking && (timeout > 0.0 || timeout < 0.0)) ioctlsocket(sock, FIONBIO, (u_long *)&yes); +#else + // You can set but not get this flag in WIN32, so assume it was in non-blocking mode. + // The downside is that when we leave this routine we'll leave it non-blocking, + // whether it started that way or not. + SInt32 flags = 0; + if (timeout > 0.0 || timeout < 0.0) ioctlsocket(sock, FIONBIO, (u_long *)&yes); + wasBlocking = false; +#endif result = connect(sock, (struct sockaddr *)name, namelen); if (result != 0) { - connect_err = thread_errno(); + connect_err = __CFSocketLastError(); +#if DEPLOYMENT_TARGET_WINDOWS + if (connect_err == WSAEWOULDBLOCK) connect_err = EINPROGRESS; +#endif } #if defined(LOG_CFSOCKET) - fprintf(stdout, "connection attempt returns %ld error %ld on socket %d (flags 0x%lx blocking %d)\n", result, connect_err, sock, flags, wasBlocking); + fprintf(stdout, "connection attempt returns %d error %d on socket %d (flags 0x%x blocking %d)\n", result, connect_err, sock, flags, wasBlocking); #endif if (EINPROGRESS == connect_err && timeout >= 0.0) { /* select on socket */ @@ -2843,20 +3025,20 @@ CFSocketError CFSocketConnectToAddress(CFSocketRef s, CFDataRef address, CFTimeI tv.tv_usec = (int)floor(1.0e+6 * (timeout - floor(timeout))); nrfds = select(__CFSocketFdGetSize(fds), NULL, (fd_set *)CFDataGetMutableBytePtr(fds), NULL, &tv); if (nrfds < 0) { - select_err = thread_errno(); + select_err = __CFSocketLastError(); result = -1; } else if (nrfds == 0) { result = -2; } else { - if (0 != getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&select_err, (socklen_t *)&error_size)) select_err = 0; + if (0 != getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&select_err, (socklen_t *)&error_size)) select_err = 0; result = (select_err == 0) ? 0 : -1; } CFRelease(fds); #if defined(LOG_CFSOCKET) - fprintf(stdout, "timed connection attempt %s on socket %d, result %ld, select returns %ld error %ld\n", (result == 0) ? "succeeds" : "fails", sock, result, nrfds, select_err); + fprintf(stdout, "timed connection attempt %s on socket %d, result %d, select returns %d error %d\n", (result == 0) ? "succeeds" : "fails", sock, result, nrfds, select_err); #endif } - if (wasBlocking && (timeout > 0.0 || timeout < 0.0)) ioctl(sock, FIONBIO, &no); + if (wasBlocking && (timeout > 0.0 || timeout < 0.0)) ioctlsocket(sock, FIONBIO, (u_long *)&no); if (EINPROGRESS == connect_err && timeout < 0.0) { result = 0; #if defined(LOG_CFSOCKET) @@ -2878,7 +3060,13 @@ CFSocketRef CFSocketCreate(CFAllocatorRef allocator, SInt32 protocolFamily, SInt if (0 >= protocol && SOCK_STREAM == socketType) protocol = IPPROTO_TCP; if (0 >= protocol && SOCK_DGRAM == socketType) protocol = IPPROTO_UDP; } +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED if (PF_LOCAL == protocolFamily && 0 >= socketType) socketType = SOCK_STREAM; +#endif +#if DEPLOYMENT_TARGET_WINDOWS + // make sure we've called proper Win32 startup facilities before socket() + __CFSocketInitializeWinSock(); +#endif sock = socket(protocolFamily, socketType, protocol); if (INVALID_SOCKET != sock) { s = CFSocketCreateWithNative(allocator, sock, callBackTypes, callout, context); @@ -2919,7 +3107,7 @@ static void __CFSocketHandleNameRegistryReply(CFSocketRef s, CFSocketCallBackTyp __CFSocketNameRegistryResponse *response = (__CFSocketNameRegistryResponse *)info; CFDictionaryRef replyDictionary = NULL; CFPropertyListRef value; - replyDictionary = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, replyData, kCFPropertyListImmutable, NULL); + replyDictionary = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, replyData, kCFPropertyListImmutable, NULL); if (NULL != response->error) *(response->error) = kCFSocketError; if (NULL != replyDictionary) { if (CFGetTypeID((CFTypeRef)replyDictionary) == CFDictionaryGetTypeID() && NULL != (value = CFDictionaryGetValue(replyDictionary, kCFSocketResultKey))) { @@ -2959,7 +3147,9 @@ static void __CFSocketSendNameRegistryRequest(CFSocketSignature *signature, CFDi static void __CFSocketValidateSignature(const CFSocketSignature *providedSignature, CFSocketSignature *signature, uint16_t defaultPortNumber) { struct sockaddr_in sain, *sainp; memset(&sain, 0, sizeof(sain)); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED sain.sin_len = sizeof(sain); +#endif sain.sin_family = AF_INET; sain.sin_port = htons(__CFSocketDefaultNameRegistryPortNumber); sain.sin_addr.s_addr = htonl(INADDR_LOOPBACK); @@ -2983,7 +3173,9 @@ static void __CFSocketValidateSignature(const CFSocketSignature *providedSignatu } else { sainp = (struct sockaddr_in *)CFDataGetBytePtr(providedSignature->address); if ((int)sizeof(struct sockaddr_in) <= CFDataGetLength(providedSignature->address) && (AF_INET == sainp->sin_family || 0 == sainp->sin_family)) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED sain.sin_len = sizeof(sain); +#endif sain.sin_family = AF_INET; sain.sin_port = sainp->sin_port; if (0 == sain.sin_port) sain.sin_port = htons(defaultPortNumber); @@ -2991,7 +3183,7 @@ static void __CFSocketValidateSignature(const CFSocketSignature *providedSignatu if (htonl(INADDR_ANY) == sain.sin_addr.s_addr) sain.sin_addr.s_addr = htonl(INADDR_LOOPBACK); signature->address = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)&sain, sizeof(sain)); } else { - signature->address = CFRetain(providedSignature->address); + signature->address = (CFDataRef)CFRetain(providedSignature->address); } } } @@ -3079,7 +3271,7 @@ CFSocketError CFSocketCopyRegisteredSocketSignature(const CFSocketSignature *nam CFRelease(signature->address); signature->address = address; } - if (NULL != nameServerAddress) *nameServerAddress = serverAddress ? CFRetain(serverAddress) : NULL; + if (NULL != nameServerAddress) *nameServerAddress = serverAddress ? (CFDataRef)CFRetain(serverAddress) : NULL; } if (NULL != data) CFRelease(data); if (NULL != serverAddress) CFRelease(serverAddress); diff --git a/CFSocket.h b/CFSocket.h index 3653bf5..8de2647 100644 --- a/CFSocket.h +++ b/CFSocket.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,20 +22,12 @@ */ /* CFSocket.h - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSOCKET__) #define __COREFOUNDATION_CFSOCKET__ 1 -#include - -#if TARGET_OS_WIN32 -typedef uintptr_t CFSocketNativeHandle; -#else -typedef int CFSocketNativeHandle; -#endif - #include #include @@ -141,15 +133,11 @@ enum { kCFSocketReadCallBack = 1, kCFSocketAcceptCallBack = 2, kCFSocketDataCallBack = 3, - kCFSocketConnectCallBack = 4 -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED - , + kCFSocketConnectCallBack = 4, kCFSocketWriteCallBack = 8 -#endif }; typedef CFOptionFlags CFSocketCallBackType; -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED /* Socket flags */ enum { kCFSocketAutomaticallyReenableReadCallBack = 1, @@ -161,7 +149,6 @@ enum { #endif kCFSocketCloseOnInvalidate = 128 }; -#endif typedef void (*CFSocketCallBack)(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info); /* If the callback wishes to keep hold of address or data after the point that it returns, then it must copy them. */ @@ -174,6 +161,12 @@ typedef struct { CFStringRef (*copyDescription)(const void *info); } CFSocketContext; +#if TARGET_OS_WIN32 +typedef uintptr_t CFSocketNativeHandle; +#else +typedef int CFSocketNativeHandle; +#endif + CF_EXPORT CFTypeID CFSocketGetTypeID(void); CF_EXPORT CFSocketRef CFSocketCreate(CFAllocatorRef allocator, SInt32 protocolFamily, SInt32 socketType, SInt32 protocol, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context); @@ -194,12 +187,11 @@ CF_EXPORT CFSocketNativeHandle CFSocketGetNative(CFSocketRef s); CF_EXPORT CFRunLoopSourceRef CFSocketCreateRunLoopSource(CFAllocatorRef allocator, CFSocketRef s, CFIndex order); -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED CF_EXPORT CFOptionFlags CFSocketGetSocketFlags(CFSocketRef s); CF_EXPORT void CFSocketSetSocketFlags(CFSocketRef s, CFOptionFlags flags); CF_EXPORT void CFSocketDisableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes); CF_EXPORT void CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes); -#endif + /* For convenience, a function is provided to send data using the socket with a timeout. The timeout will be used only if the specified value is positive. The address should be left NULL if the socket is already connected. */ CF_EXPORT CFSocketError CFSocketSendData(CFSocketRef s, CFDataRef address, CFDataRef data, CFTimeInterval timeout); diff --git a/CFSocketStream.c b/CFSocketStream.c index 88326a4..99440af 100644 --- a/CFSocketStream.c +++ b/CFSocketStream.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFSocketStream.c - Copyright (c) 2000-2009, Apple Inc. All rights reserved. + Copyright (c) 2000-2011, Apple Inc. All rights reserved. Responsibility: Jeremy Wyld */ // Original Author: Becky Willrich diff --git a/CFSortFunctions.c b/CFSortFunctions.c index f4c5b5a..4018a3c 100644 --- a/CFSortFunctions.c +++ b/CFSortFunctions.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,18 +22,16 @@ */ /* CFSortFunctions.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ #include #include "CFInternal.h" -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS #include -#include #endif - enum { kCFSortConcurrent = (1 << 0), kCFSortStable = (1 << 4), @@ -132,7 +130,9 @@ static void __CFSimpleMergeSort(VALUE_TYPE listp[], INDEX_TYPE cnt, VALUE_TYPE t } } -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS +// Excluded from linux for dispatch dependency + // if !right, put the cnt1 smallest values in tmp, else put the cnt2 largest values in tmp static void __CFSortIndexesNMerge(VALUE_TYPE listp1[], INDEX_TYPE cnt1, VALUE_TYPE listp2[], INDEX_TYPE cnt2, VALUE_TYPE tmp[], size_t right, COMPARATOR_BLOCK cmp) { // if the last element of listp1 <= the first of listp2, lists are already ordered @@ -206,11 +206,11 @@ static void __CFSortIndexesN(VALUE_TYPE listp[], INDEX_TYPE count, int32_t ncore STACK_BUFFER_DECL(VALUE_TYPE *, stack_tmps, num_sect); for (INDEX_TYPE idx = 0; idx < num_sect; idx++) { - stack_tmps[idx] = malloc(sz * sizeof(VALUE_TYPE)); + stack_tmps[idx] = (VALUE_TYPE *)malloc(sz * sizeof(VALUE_TYPE)); } VALUE_TYPE **tmps = stack_tmps; - dispatch_queue_t q = dispatch_get_concurrent_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT); + dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, DISPATCH_QUEUE_OVERCOMMIT); dispatch_apply(num_sect, q, ^(size_t sect) { INDEX_TYPE sect_len = (sect < num_sect - 1) ? sz : last_sect_len; __CFSimpleMergeSort(listp + sect * sz, sect_len, tmps[sect], cmp); // naturally stable @@ -248,16 +248,13 @@ static void __CFSortIndexesN(VALUE_TYPE listp[], INDEX_TYPE count, int32_t ncore } #endif -// returns an array of indexes (of length count) giving the indexes 0 - count-1, as sorted by the comparator block -CFIndex *CFSortIndexes(CFIndex count, CFOptionFlags opts, CFComparisonResult (^cmp)(CFIndex, CFIndex)) { - if (count < 1) return NULL; - if (INTPTR_MAX / sizeof(CFIndex) < count) return NULL; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +// fills an array of indexes (of length count) giving the indexes 0 - count-1, as sorted by the comparator block +void CFSortIndexes(CFIndex *indexBuffer, CFIndex count, CFOptionFlags opts, CFComparisonResult (^cmp)(CFIndex, CFIndex)) { + if (count < 1) return; + if (INTPTR_MAX / sizeof(CFIndex) < count) return; int32_t ncores = 0; if (opts & kCFSortConcurrent) { - int32_t mib[2] = {CTL_HW, HW_AVAILCPU}; - size_t len = sizeof(ncores); - sysctl(mib, 2, &ncores, &len, NULL, 0); + ncores = __CFActiveProcessorCount(); if (count < 160 || ncores < 2) { opts = (opts & ~kCFSortConcurrent); } else if (count < 640 && 2 < ncores) { @@ -271,39 +268,40 @@ CFIndex *CFSortIndexes(CFIndex count, CFOptionFlags opts, CFComparisonResult (^c ncores = 16; } } - CFIndex *idxs = malloc_zone_memalign(malloc_default_zone(), 64, count * sizeof(CFIndex)); - if (!idxs) return NULL; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS if (count <= 65536) { - for (CFIndex idx = 0; idx < count; idx++) idxs[idx] = idx; + for (CFIndex idx = 0; idx < count; idx++) indexBuffer[idx] = idx; } else { /* Specifically hard-coded to 8; the count has to be very large before more chunks and/or cores is worthwhile. */ CFIndex sz = ((((size_t)count + 15) / 16) * 16) / 8; - dispatch_apply(8, dispatch_get_concurrent_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT), ^(size_t n) { + dispatch_apply(8, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, DISPATCH_QUEUE_OVERCOMMIT), ^(size_t n) { CFIndex idx = n * sz, lim = __CFMin(idx + sz, count); - for (; idx < lim; idx++) idxs[idx] = idx; + for (; idx < lim; idx++) indexBuffer[idx] = idx; }); } +#else + for (CFIndex idx = 0; idx < count; idx++) indexBuffer[idx] = idx; +#endif +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS if (opts & kCFSortConcurrent) { - __CFSortIndexesN(idxs, count, ncores, cmp); // naturally stable - return idxs; + __CFSortIndexesN(indexBuffer, count, ncores, cmp); // naturally stable + return; } -#else - CFIndex *idxs = (CFIndex *)malloc(count * sizeof(CFIndex)); - if (!idxs) return NULL; - for (CFIndex idx = 0; idx < count; idx++) idxs[idx] = idx; #endif - STACK_BUFFER_DECL(VALUE_TYPE, local, count <= 16384 ? count : 1); - VALUE_TYPE *tmp = (count <= 16384) ? local : (VALUE_TYPE *)malloc(count * sizeof(VALUE_TYPE)); - __CFSimpleMergeSort(idxs, count, tmp, cmp); // naturally stable + STACK_BUFFER_DECL(VALUE_TYPE, local, count <= 4096 ? count : 1); + VALUE_TYPE *tmp = (count <= 4096) ? local : (VALUE_TYPE *)malloc(count * sizeof(VALUE_TYPE)); + __CFSimpleMergeSort(indexBuffer, count, tmp, cmp); // naturally stable if (local != tmp) free(tmp); - return idxs; } /* Comparator is passed the address of the values. */ void CFQSortArray(void *list, CFIndex count, CFIndex elementSize, CFComparatorFunction comparator, void *context) { - if (count < 1 || elementSize < 1) return; - CFIndex *indexes = CFSortIndexes(count, 0, ^(CFIndex a, CFIndex b) { return comparator((char *)list + a * elementSize, (char *)list + b * elementSize, context); }); // naturally stable - void *store = malloc(count * elementSize); + if (count < 2 || elementSize < 1) return; + STACK_BUFFER_DECL(CFIndex, locali, count <= 4096 ? count : 1); + CFIndex *indexes = (count <= 4096) ? locali : (CFIndex *)malloc(count * sizeof(CFIndex)); + CFSortIndexes(indexes, count, 0, ^(CFIndex a, CFIndex b) { return comparator((char *)list + a * elementSize, (char *)list + b * elementSize, context); }); + STACK_BUFFER_DECL(uint8_t, locals, count <= (16 * 1024 / elementSize) ? count * elementSize : 1); + void *store = (count <= (16 * 1024 / elementSize)) ? locals : malloc(count * elementSize); for (CFIndex idx = 0; idx < count; idx++) { if (sizeof(uintptr_t) == elementSize) { uintptr_t *a = (uintptr_t *)list + indexes[idx]; @@ -315,15 +313,18 @@ void CFQSortArray(void *list, CFIndex count, CFIndex elementSize, CFComparatorFu } // no swapping or modification of the original list has occurred until this point objc_memmove_collectable(list, store, count * elementSize); - free(store); - free(indexes); + if (locals != store) free(store); + if (locali != indexes) free(indexes); } /* Comparator is passed the address of the values. */ void CFMergeSortArray(void *list, CFIndex count, CFIndex elementSize, CFComparatorFunction comparator, void *context) { - if (count < 1 || elementSize < 1) return; - CFIndex *indexes = CFSortIndexes(count, kCFSortStable, ^(CFIndex a, CFIndex b) { return comparator((char *)list + a * elementSize, (char *)list + b * elementSize, context); }); // naturally stable - void *store = malloc(count * elementSize); + if (count < 2 || elementSize < 1) return; + STACK_BUFFER_DECL(CFIndex, locali, count <= 4096 ? count : 1); + CFIndex *indexes = (count <= 4096) ? locali : (CFIndex *)malloc(count * sizeof(CFIndex)); + CFSortIndexes(indexes, count, kCFSortStable, ^(CFIndex a, CFIndex b) { return comparator((char *)list + a * elementSize, (char *)list + b * elementSize, context); }); + STACK_BUFFER_DECL(uint8_t, locals, count <= (16 * 1024 / elementSize) ? count * elementSize : 1); + void *store = (count <= (16 * 1024 / elementSize)) ? locals : malloc(count * elementSize); for (CFIndex idx = 0; idx < count; idx++) { if (sizeof(uintptr_t) == elementSize) { uintptr_t *a = (uintptr_t *)list + indexes[idx]; @@ -335,8 +336,8 @@ void CFMergeSortArray(void *list, CFIndex count, CFIndex elementSize, CFComparat } // no swapping or modification of the original list has occurred until this point objc_memmove_collectable(list, store, count * elementSize); - free(store); - free(indexes); + if (locals != store) free(store); + if (locali != indexes) free(indexes); } diff --git a/CFStorage.c b/CFStorage.c index 37073c2..f5d1193 100644 --- a/CFStorage.c +++ b/CFStorage.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,20 +22,46 @@ */ /* CFStorage.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. - Responsibility: Ali Ozer -*/ + Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Responsibility: Ali Ozer + */ /* -2-3 tree storing arbitrary sized values. + 2-3 tree storing arbitrary sized values. + + ??? Currently elementSize cannot be greater than storage->maxLeafCapacity, which is less than or equal to __CFStorageMaxLeafCapacity + + CFStorage is thread-safe for multiple readers, but not thread safe for simultaneous reading and writing. + */ + -??? Currently elementSize cannot be greater than storage->maxLeafCapacity, which is less than or equal to __CFStorageMaxLeafCapacity +/* pammon notes on FrozenStorage + A CFStorage can be frozen, or more specifically, some or all of the nodes can be frozen. Frozen nodes can be safely shared between CFStorage instances. CFStorages containing frozen nodes are still considered mutable: frozen nodes are discarded and recreated on demand. It is a form of copy-on-write. + + Freezing is usually one-way: there is no going back. However, if a node's reference count is 1, we know that no other CFStorage can reference it; and if we are in a mutating function, we know that it can be safely unfrozen. + + If a node is frozen, all of its descendants should be considered frozen. + + The root node, which is defined inline within the CFStorage struct itself, can never be frozen. + + */ -CFStorage is thread-safe for multiple readers, but not thread safe for simultaneous reading and writing. -*/ +#define NO_SHIFTER ((uint32_t)(-1)) -#include "CFStorage.h" +#include #include "CFInternal.h" +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS +#include +#endif + +#if DEPLOYMENT_TARGET_WINDOWS +// No C99 support +#define restrict + +// Replace bzero +#define bzero(dst, size) ZeroMemory(dst, size) + +#endif #if !defined(PAGE_SIZE) #define PAGE_SIZE 4096 @@ -45,17 +71,6 @@ CFStorage is thread-safe for multiple readers, but not thread safe for simultane // Also, tests with StorageTimer.c done in 4/07 indicate that 4096 * 3 is better than smaller or larger node sizes. #define __CFStorageMaxLeafCapacity (4096 * 3) -// If the max length of a node is less than can fit in a half-word (half of a long), we can get away without ever caching the high half-word the cachedRange -#if __LP64__ -#if __CFStorageMaxLeafCapacity > 0xFFFFFFFFULL -#define POSSIBLE_TO_HAVE_LENGTH_MORE_THAN_HALFWORD 1 -#endif -#else -#if __CFStorageMaxLeafCapacity > 0xFFFFUL -#define POSSIBLE_TO_HAVE_LENGTH_MORE_THAN_HALFWORD 1 -#endif -#endif - #define COPYMEM(src,dst,n) objc_memmove_collectable((dst), (src), (n)) #define PAGE_LIMIT ((CFIndex)PAGE_SIZE / 2) @@ -63,17 +78,20 @@ CF_INLINE int32_t roundToPage(int32_t num) { return (num + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); } - +typedef const struct __CFStorage *ConstCFStorageRef; /* Each node in the storage. isLeaf determines whether the node is a leaf node or a node inside the tree. If latter, number of children are determined by the number of non-NULL entries in child[]. (NULL entries are at the end.) -*/ + */ typedef struct __CFStorageNode { CFIndex numBytes; /* Number of actual bytes in this node and all its children */ + uint32_t refCount; /* Refcount of the node. Is always at least 1 for a normal node. For root nodes, which are stored directly in the CFStorage, this is 0. CFStorageRetain/ReleaseNode checks for a refcount of 0 and does not retain/release such nodes. */ + bool isFrozen; /* Indicates that the node is frozen, i.e. may be shared. */ bool isLeaf; union { struct { CFIndex capacityInBytes; // capacityInBytes is capacity of memory; this is either 0, or >= numBytes uint8_t *memory; + CFRange cachedRange; //the absolute range of this node, in "value" units. This is valid only if this node is referenced by storage->cacheNode, and used by the cache. In general this is not valid, and the offset needs to be passed down from the tree } leaf; struct { struct __CFStorageNode *child[3]; @@ -81,45 +99,48 @@ typedef struct __CFStorageNode { } info; } CFStorageNode; -/* This is the struct used to store the cache in the CFStorage; it enables us to make the cache thread-safe for multiple readers (which update the cache). The values in this cache store half the desired value in the top half, and the genCount of the writer in the low half. This cache is consistent only if all of the genCounts are the same. Note that the cache does not provide thread-safety for readers in the presence of a writer. -The cached range (location, length) is in terms of values; if the cached range is not (0,0), then the cached node needs to be non-NULL and pointing at a leaf node. -*/ +/* A struct used for insertion into frozen nodes, which may need to return a new version of themselves, and a new friend! The child field is a replacement for the child that was inserted into; if the child does not need to be replaced (i.e. it was unfrozen and there was space to perform the insertion) then the child that was inserted into is returned here. The sibling field is a new child that should also be inserted (or NULL if none). */ typedef struct { - unsigned long locationHi, locationLo; // cachedRange.location -#if POSSIBLE_TO_HAVE_LENGTH_MORE_THAN_HALFWORD - unsigned long lengthHi; -#endif - unsigned long lengthLo; // cachedRange.length; note that we actually do not bother with lengthHi if __CFStorageMaxLeafCapacity is less than half-word - unsigned long cachedNodeHi, cachedNodeLo; // cachedNode -} CFStorageAccessCacheParts; + CFStorageNode *child; + CFStorageNode *sibling; +} CFStorageDoubleNodeReturn; + +CF_INLINE CFStorageDoubleNodeReturn CFStorageDoubleNodeReturnMake(CFStorageNode *child, CFStorageNode *sibling) { + CFStorageDoubleNodeReturn v; + v.child = child; + v.sibling = sibling; + return v; +} /* The CFStorage object. -*/ + */ struct __CFStorage { CFRuntimeBase base; CFIndex valueSize; + uint32_t byteToValueShifter; CFSpinLock_t cacheReaderMemoryAllocationLock; - int cacheGenerationCount; - CFStorageAccessCacheParts cacheParts; + bool alwaysFrozen; + CFStorageNode * volatile cacheNode; CFIndex maxLeafCapacity; // In terms of bytes CFStorageNode rootNode; CFOptionFlags nodeHint; // __kCFAllocatorGCScannedMemory or 0. }; - - - -/* Allocates the memory and initializes the capacity in a leaf. __CFStorageAllocLeafNodeMemory() is the entry point; __CFStorageAllocLeafNodeMemoryAux is called if actual reallocation is needed. __CFStorageAllocLeafNodeMemoryAux() locks not for mutations (mutations are not thread-safe in general), but for lazy allocation of storage during reading. -*/ -static void __CFStorageAllocLeafNodeMemoryAux(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFIndex cap) { - __CFSpinLock(&(storage->cacheReaderMemoryAllocationLock)); - __CFAssignWithWriteBarrier((void **)&node->info.leaf.memory, _CFAllocatorReallocateGC(allocator, node->info.leaf.memory, cap, storage->nodeHint)); // This will free... - if (__CFOASafe) __CFSetLastAllocationEventName(node->info.leaf.memory, "CFStorage (node bytes)"); - node->info.leaf.capacityInBytes = cap; - __CFSpinUnlock(&(storage->cacheReaderMemoryAllocationLock)); +/* Helper function to return the intersection of two ranges */ +static inline CFRange intersectionRange(CFRange a, CFRange b) { + CFIndex start = __CFMax(a.location, b.location); + CFIndex end = __CFMin(a.location + a.length, b.location + b.length); + if (end <= start) { + return CFRangeMake(0, 0); + } + else { + return CFRangeMake(start, end - start); + } } +/* Allocates the memory and initializes the capacity in a leaf. This locks not for mutations (mutations are not thread-safe in general), but for lazy allocation of storage during reading. + */ CF_INLINE void __CFStorageAllocLeafNodeMemory(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFIndex cap, bool compact) { if (cap > PAGE_LIMIT) { cap = roundToPage(cap); @@ -127,157 +148,272 @@ CF_INLINE void __CFStorageAllocLeafNodeMemory(CFAllocatorRef allocator, CFStorag } else { cap = (((cap + 63) / 64) * 64); } - if (compact ? (cap != node->info.leaf.capacityInBytes) : (cap > node->info.leaf.capacityInBytes)) __CFStorageAllocLeafNodeMemoryAux(allocator, storage, node, cap); + /* We must be careful here, because another thread may be trying to allocate this memory at the same time (8203146). This may happen if two threads both attempt to read from a lazily-allocated node. */ + if ((compact ? (cap != node->info.leaf.capacityInBytes) : (cap > node->info.leaf.capacityInBytes))) { + __CFSpinLock(&(storage->cacheReaderMemoryAllocationLock)); + /* Check again now that we've acquired the lock. We know that we can do this because two simulaneous readers will always pass the same capacity. This is the fix for 8203146. This probably needs a memory barrier. */ + if ((compact ? (cap != node->info.leaf.capacityInBytes) : (cap > node->info.leaf.capacityInBytes))) { + __CFAssignWithWriteBarrier((void **)&node->info.leaf.memory, _CFAllocatorReallocateGC(allocator, node->info.leaf.memory, cap, storage->nodeHint)); // This will free... + if (__CFOASafe) __CFSetLastAllocationEventName(node->info.leaf.memory, "CFStorage (node bytes)"); + node->info.leaf.capacityInBytes = cap; + } + __CFSpinUnlock(&(storage->cacheReaderMemoryAllocationLock)); + } } +#if 0 +#define ASSERT(x) do { if (! (x)) { fprintf(stderr, "Assertion %s failed on line %d\n", #x, __LINE__); abort(); } } while (0) +#else +#define ASSERT(x) do { if (0 && ! (x)) { } } while(0) +#endif +static void __CFStorageCheckIntegrity(CFStorageRef storage); +#define CHECK_INTEGRITY() do { if (0) __CFStorageCheckIntegrity(storage); } while (0) +static void __CFStorageCheckNodeIntegrity(ConstCFStorageRef storage, const CFStorageNode *node); +#define CHECK_NODE_INTEGRITY(X) do { if (0) __CFStorageCheckNodeIntegrity(storage, X); } while (0) -#if __LP64__ -#define genCountMask 0x00000000FFFFFFFFUL -#define dataMask 0xFFFFFFFF00000000UL -#define shiftLowWordBy 32 -#else -#define genCountMask 0x0000FFFFUL -#define dataMask 0xFFFF0000UL -#define shiftLowWordBy 16 -#endif +#pragma mark Byte <-> Value Functions -/* Sets the cache to point at the specified node. loc and len are in terms of values, not bytes. To clear the cache set these two to 0. - At least one of node or memory should be non-NULL. memory is consulted first when using the cache. -*/ -CF_INLINE void __CFStorageSetCache(CFStorageRef storage, CFStorageNode *node, CFIndex loc, CFIndex len) { - unsigned int genCount = ((unsigned int)OSAtomicIncrement32(&storage->cacheGenerationCount)) & genCountMask; - CFStorageAccessCacheParts cacheParts; - cacheParts.locationHi = (loc & dataMask) | genCount; - cacheParts.locationLo = (loc << shiftLowWordBy) | genCount; -#if POSSIBLE_TO_HAVE_LENGTH_MORE_THAN_HALFWORD - cacheParts.lengthHi = (len & dataMask) | genCount; -#endif - cacheParts.lengthLo = (len << shiftLowWordBy) | genCount; - cacheParts.cachedNodeHi = ((unsigned long)node & dataMask) | genCount; - cacheParts.cachedNodeLo = ((unsigned long)node << shiftLowWordBy) | genCount; - storage->cacheParts = cacheParts; +CF_INLINE CFIndex __CFStorageConvertByteToValue(ConstCFStorageRef storage, CFIndex byte) { + if (storage->byteToValueShifter != NO_SHIFTER) { + return byte >> storage->byteToValueShifter; + } + return byte / storage->valueSize; } -/* Thread-safely get the cached range and node info. -*/ -CF_INLINE Boolean __CFStorageGetCache(CFStorageRef storage, CFRange *cachedRangePtr, CFStorageNode **cachedNodePtr) { - CFStorageAccessCacheParts cacheParts = storage->cacheParts; +CF_INLINE CFRange __CFStorageConvertBytesToValueRange(ConstCFStorageRef storage, CFIndex offset, CFIndex length) { + if (storage->byteToValueShifter != NO_SHIFTER) { + return CFRangeMake(offset >> storage->byteToValueShifter, length >> storage->byteToValueShifter); + } + return CFRangeMake(offset / storage->valueSize, length / storage->valueSize); +} - unsigned int genCount = cacheParts.locationHi & genCountMask; - - // Check to make sure the genCounts of all the items are the same; if not, the cache was inconsistent - if ((cacheParts.locationLo & genCountMask) == genCount && -#if POSSIBLE_TO_HAVE_LENGTH_MORE_THAN_HALFWORD - (cacheParts.lengthHi & genCountMask) == genCount && -#endif - (cacheParts.lengthLo & genCountMask) == genCount && - (cacheParts.cachedNodeHi & genCountMask) == genCount && - (cacheParts.cachedNodeLo & genCountMask) == genCount) { - - *cachedNodePtr = (CFStorageNode *)((cacheParts.cachedNodeHi & dataMask) | ((cacheParts.cachedNodeLo & dataMask) >> shiftLowWordBy)); - cachedRangePtr->location = (cacheParts.locationHi & dataMask) | ((cacheParts.locationLo & dataMask) >> shiftLowWordBy); - cachedRangePtr->length = (cacheParts.lengthLo & dataMask) >> shiftLowWordBy; -#if POSSIBLE_TO_HAVE_LENGTH_MORE_THAN_HALFWORD - cachedRangePtr->length |= (cacheParts.lengthHi & dataMask); -#endif +CF_INLINE CFIndex __CFStorageConvertValueToByte(ConstCFStorageRef storage, CFIndex value) { + if (storage->byteToValueShifter != NO_SHIFTER) { + return value << storage->byteToValueShifter; + } + return value * storage->valueSize; +} + +CF_INLINE CFRange __CFStorageConvertValuesToByteRange(ConstCFStorageRef storage, CFIndex offset, CFIndex length) { + if (storage->byteToValueShifter != NO_SHIFTER) { + return CFRangeMake(offset << storage->byteToValueShifter, length << storage->byteToValueShifter); + } + return CFRangeMake(offset * storage->valueSize, length * storage->valueSize); +} + + +#pragma mark Node reference counting and freezing + +CF_INLINE CFStorageNode *__CFStorageRetainNode(CFStorageNode *node) { + if (node->refCount > 0) OSAtomicIncrement32((int32_t *)&node->refCount); + return node; +} + +/* A faster version of __CFStorageRetainNode that is not thread safe. This can be used from the Unfrozen (aka unshared) calls, or when a node was just allocated and there's no opportunity for it to have escaped yet */ +CF_INLINE CFStorageNode *__CFStorageRetainNodeThreadUnsafe(CFStorageNode *node) { + if (node->refCount > 0) node->refCount++; + return node; +} + +static void __CFStorageDeallocateNode(CFStorageRef storage, CFStorageNode *node); + +CF_INLINE void __CFStorageReleaseNode(CFStorageRef storage, CFStorageNode *node) { + if (node->refCount > 0) { + uint32_t newRefCount = OSAtomicDecrement32((int32_t *)&node->refCount); + if (newRefCount == 0) { + __CFStorageDeallocateNode(storage, node); + } + } +} + +CF_INLINE void __CFStorageReleaseNodeWithNullCheck(CFStorageRef storage, CFStorageNode *node) { + if (node) __CFStorageReleaseNode(storage, node); +} + +static void __CFStorageDeallocateNode(CFStorageRef storage, CFStorageNode *node) { + CFAllocatorRef allocator = CFGetAllocator(storage); + if (node->isLeaf) { + if (node->info.leaf.memory) _CFAllocatorDeallocateGC(allocator, node->info.leaf.memory); + } else { + __CFStorageReleaseNodeWithNullCheck(storage, node->info.notLeaf.child[0]); + __CFStorageReleaseNodeWithNullCheck(storage, node->info.notLeaf.child[1]); + __CFStorageReleaseNodeWithNullCheck(storage, node->info.notLeaf.child[2]); + } + _CFAllocatorDeallocateGC(allocator, node); +} + +static inline void __CFStorageFreezeNode(CFStorageNode *node) { + node->isFrozen = true; +} +/* If a node is frozen, but its reference count is 1, then we are the only reference to it and we can unfreeze it. In general, it's unsafe to do this because it may race with other threads that depend on it being frozen (e.g. we are about to copy the node). However, we do not support concurrent access while mutating a CFStorage, so if we are in a mutation function, know we have exclusive access and we can unfreeze the node. */ +static inline bool __CFStorageThawNodeDuringMutation(CFStorageRef storage, CFStorageNode *node) { + if (node->refCount == 1) { + node->isFrozen = false; return true; } return false; } -/* Gets the location for the specified absolute loc from the cached info. - Returns NULL if the location is not in the cache. -*/ -CF_INLINE uint8_t *__CFStorageGetFromCache(CFStorageRef storage, CFIndex loc, CFRange *validConsecutiveValueRange) { - CFRange cachedRange = {0, 0}; - CFStorageNode *cachedNode = 0; +static inline void __CFStorageSetChild(CFStorageNode *parentNode, CFIndex childIndex, CFStorageNode *newChild) { + ASSERT(! parentNode->isLeaf); + ASSERT(childIndex < 3); + __CFAssignWithWriteBarrier((void **)&parentNode->info.notLeaf.child[childIndex], newChild); +} - // If we can't get values from the cache, return NULL - if (!__CFStorageGetCache(storage, &cachedRange, &cachedNode)) return NULL; +static inline void __CFStorageGetChildren(const CFStorageNode *parent, CFStorageNode ** restrict resultArray, bool shouldRetain, bool shouldFreeze) { + ASSERT(! parent->isLeaf); + CFIndex i; + for (i=0; i < 3; i++) { + CFStorageNode *node = parent->info.notLeaf.child[i]; + if (node != NULL && shouldRetain) __CFStorageRetainNode(node); + if (node != NULL && shouldFreeze) __CFStorageFreezeNode(node); + resultArray[i] = node; + } +} + +#pragma mark Storage cache handling - // Check to see if the index is in the cache - if (loc < cachedRange.location || loc >= cachedRange.location + cachedRange.length) return NULL; - // If the cached node has no memory, return here; it will be allocated as a result of the non-cached lookup. - if (!cachedNode->info.leaf.memory) return NULL; +/* Sets the cache to point at the specified node. loc and len are in terms of values, not bytes. To clear the cache set these two to 0. + At least one of node or memory should be non-NULL. memory is consulted first when using the cache. + */ +CF_INLINE void __CFStorageSetCache(CFStorageRef storage, CFStorageNode *node, CFIndex locInBytes) { + if (node) { + ASSERT(node->isLeaf); + node->info.leaf.cachedRange = __CFStorageConvertBytesToValueRange(storage, locInBytes, node->numBytes); + } + storage->cacheNode = node; +} + +/* Gets the location for the specified absolute loc from the cached info. + Returns NULL if the location is not in the cache. + */ +CF_INLINE uint8_t *__CFStorageGetFromCache(CFStorageRef storage, CFIndex loc, CFRange * restrict validConsecutiveValueRange, bool requireUnfrozenNode) { + CFStorageNode * const cachedNode = storage->cacheNode; /* It's important we read from this field no more than once, for thread safety with other concurrent reads; that is why the field is marked volatile. */ + if (! cachedNode) return NULL; /* No cache */ - // The cache has consistent values, and in fact, the values we're looking for! - uint8_t *result = cachedNode->info.leaf.memory + (loc - cachedRange.location) * storage->valueSize; - *validConsecutiveValueRange = cachedRange; + /* We only allow caching leaf nodes. */ + ASSERT(cachedNode->isLeaf); + + /* If the node is frozen, and we require an unfrozen node, then return NULL */ + if (requireUnfrozenNode && cachedNode->isFrozen) return NULL; + + /* If there's no memory allocated yet, then allocate it now*/ + if (! cachedNode->info.leaf.memory) { + __CFStorageAllocLeafNodeMemory(CFGetAllocator(storage), storage, cachedNode, cachedNode->numBytes, false); + } + + /* If the node's range starts after loc, or ends before or at loc, return NULL */ + CFIndex nodeOffset = cachedNode->info.leaf.cachedRange.location; + CFIndex nodeLength = cachedNode->info.leaf.cachedRange.length; + if (loc < nodeOffset || loc >= nodeOffset + nodeLength) { + return NULL; + } + /* The cache is valid, so return it */ + validConsecutiveValueRange->location = nodeOffset; + validConsecutiveValueRange->length = nodeLength; + uint8_t *result = cachedNode->info.leaf.memory + __CFStorageConvertValueToByte(storage, loc - nodeOffset); return result; } - - /* Returns the number of the child containing the desired value and the relative index of the value in that child. - forInsertion = true means that we are looking for the child in which to insert; this changes the behavior when the index is at the end of a child - relativeByteNum (not optional, for performance reasons) returns the relative byte number of the specified byte in the child. - Don't call with leaf nodes! -*/ -CF_INLINE void __CFStorageFindChild(CFStorageNode *node, CFIndex byteNum, bool forInsertion, CFIndex *childNum, CFIndex *relativeByteNum) { - if (forInsertion) byteNum--; /* If for insertion, we do <= checks, not <, so this accomplishes the same thing */ - if (byteNum < node->info.notLeaf.child[0]->numBytes) *childNum = 0; + forInsertion = true means that we are looking for the child in which to insert or delete; this changes the behavior when the index is at the end of a child + relativeByteNum (not optional, for performance reasons) returns the relative byte number of the specified byte in the child. + Don't call with leaf nodes! + */ +CF_INLINE CFStorageNode *__CFStorageFindChild(const CFStorageNode * restrict node, CFIndex byteNum, bool forInsertionOrDeletion, CFIndex * restrict childNum, CFIndex * restrict relativeByteNum) { + if (forInsertionOrDeletion) byteNum--; /* If for insertion, we do <= checks, not <, so this accomplishes the same thing */ + CFStorageNode *result; + result = node->info.notLeaf.child[0]; + if (byteNum < result->numBytes) *childNum = 0; else { - byteNum -= node->info.notLeaf.child[0]->numBytes; - if (byteNum < node->info.notLeaf.child[1]->numBytes) *childNum = 1; + byteNum -= result->numBytes; + result = node->info.notLeaf.child[1]; + if (byteNum < result->numBytes) *childNum = 1; else { - byteNum -= node->info.notLeaf.child[1]->numBytes; + byteNum -= result->numBytes; *childNum = 2; + result = node->info.notLeaf.child[2]; } } - if (forInsertion) byteNum++; + if (forInsertionOrDeletion) byteNum++; *relativeByteNum = byteNum; + return result; } +static CFStorageNode *__CFStorageCopyNode(CFStorageRef storage, const CFStorageNode *node); + /* Finds the location where the specified byte is stored. If validConsecutiveByteRange is not NULL, returns - the range of bytes that are consecutive with this one. - !!! Assumes the byteNum is within the range of this node. -*/ -static void *__CFStorageFindByte(CFStorageRef storage, CFStorageNode *node, CFIndex byteNum, CFStorageNode **resultNode, CFRange *validConsecutiveByteRange) { + the range of bytes that are consecutive with this one. + !!! Assumes the byteNum is within the range of this node. + */ +static void *__CFStorageFindByte(CFStorageRef storage, CFStorageNode *node, CFIndex byteNum, CFIndex absoluteByteOffsetOfNode, CFStorageNode **resultNode, CFRange *validConsecutiveByteRange, bool requireUnfreezing) { if (node->isLeaf) { - if (validConsecutiveByteRange) *validConsecutiveByteRange = CFRangeMake(0, node->numBytes); + *validConsecutiveByteRange = CFRangeMake(absoluteByteOffsetOfNode, node->numBytes); + *resultNode = node; __CFStorageAllocLeafNodeMemory(CFGetAllocator(storage), storage, node, node->numBytes, false); - if (resultNode) *resultNode = node; - return node->info.leaf.memory + byteNum; + return node->info.leaf.memory + byteNum; } else { - void *result; CFIndex childNum; CFIndex relativeByteNum; - __CFStorageFindChild(node, byteNum, false, &childNum, &relativeByteNum); - result = __CFStorageFindByte(storage, node->info.notLeaf.child[childNum], relativeByteNum, resultNode, validConsecutiveByteRange); - if (validConsecutiveByteRange) { - if (childNum > 0) validConsecutiveByteRange->location += node->info.notLeaf.child[0]->numBytes; - if (childNum > 1) validConsecutiveByteRange->location += node->info.notLeaf.child[1]->numBytes; - } - return result; + CFStorageNode *child = __CFStorageFindChild(node, byteNum, false, &childNum, &relativeByteNum); + if (requireUnfreezing && child->isFrozen && ! __CFStorageThawNodeDuringMutation(storage, child)) { + /* Replace the child with an unfrozen variant */ + CFStorageNode *unfrozenReplacement = __CFStorageCopyNode(storage, child); + /* Release the old node, set the new one */ + __CFStorageSetChild(node, childNum, unfrozenReplacement); + __CFStorageReleaseNode(storage, child); + child = unfrozenReplacement; + } + return __CFStorageFindByte(storage, child, relativeByteNum, absoluteByteOffsetOfNode + (byteNum - relativeByteNum), resultNode, validConsecutiveByteRange, requireUnfreezing); } } /* Guts of CFStorageGetValueAtIndex(); note that validConsecutiveValueRange is not optional. - Consults and updates cache. -*/ -CF_INLINE void *__CFStorageGetValueAtIndex(CFStorageRef storage, CFIndex idx, CFRange *validConsecutiveValueRange) { + Consults and updates cache. + */ +CF_INLINE void *__CFStorageGetValueAtIndex(CFStorageRef storage, CFIndex idx, CFRange *validConsecutiveValueRange, bool requireUnfreezing) { uint8_t *result; - if (!(result = __CFStorageGetFromCache(storage, idx, validConsecutiveValueRange))) { - CFRange rangeInBytes; + if (!(result = __CFStorageGetFromCache(storage, idx, validConsecutiveValueRange, requireUnfreezing))) { CFStorageNode *resultNode; - result = (uint8_t *)__CFStorageFindByte(storage, &storage->rootNode, idx * storage->valueSize, &resultNode, &rangeInBytes); - CFRange rangeInValues = CFRangeMake(rangeInBytes.location / storage->valueSize, rangeInBytes.length / storage->valueSize); - __CFStorageSetCache(storage, resultNode, rangeInValues.location, rangeInValues.length); - *validConsecutiveValueRange = rangeInValues; + CFRange rangeInBytes; + result = (uint8_t *)__CFStorageFindByte(storage, &storage->rootNode, __CFStorageConvertValueToByte(storage, idx), 0, &resultNode, &rangeInBytes, requireUnfreezing); + __CFStorageSetCache(storage, resultNode, rangeInBytes.location); + *validConsecutiveValueRange = __CFStorageConvertBytesToValueRange(storage, rangeInBytes.location, rangeInBytes.length); } return result; } -// returns refcount==1 node under GC -static CFStorageNode *__CFStorageCreateNode(CFAllocatorRef allocator, bool isLeaf, CFIndex numBytes) { +/* Copies data in the range srcRange from srcLeaf to index dstLocation in dstLeaf. Both srcLeaf and dstLeaf must be leaf nodes, and dstLeaf must not be frozen. If srcRange has a nonzero length, then both must have their memory properly allocated. This does not modify the numBytes of srcLeaf or dstLeaf. + */ +static void __CFLeafCopyRangeToOffset(const CFStorageNode *srcLeaf, CFRange srcRange, CFStorageNode *dstLeaf, CFIndex dstLocation) { + ASSERT(srcLeaf->isLeaf); + ASSERT(dstLeaf->isLeaf); + if (srcRange.length > 0) { + ASSERT(srcLeaf->info.leaf.memory != NULL); + ASSERT(dstLeaf->info.leaf.memory != NULL); + ASSERT(srcRange.location + srcRange.length <= srcLeaf->numBytes); + ASSERT(dstLocation + srcRange.length <= dstLeaf->info.leaf.capacityInBytes); + COPYMEM(srcLeaf->info.leaf.memory + srcRange.location, dstLeaf->info.leaf.memory + dstLocation, srcRange.length); + } +} + +#pragma mark Node creation and destruction + +// returns a node with a refCount of 1, and an auto_zone_retain() under GC +static CFStorageNode *__CFStorageCreateNode(CFAllocatorRef allocator, CFStorageRef storage, bool isLeaf, CFIndex numBytes) { CFStorageNode *newNode = (CFStorageNode *)CFAllocatorAllocate(allocator, sizeof(CFStorageNode), __kCFAllocatorGCScannedMemory); if (__CFOASafe) __CFSetLastAllocationEventName(newNode, "CFStorage (node)"); + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + auto_zone_release(objc_collectableZone(), newNode); //remove the implicit retain so we can be collected + } + newNode->refCount = 1; + newNode->isFrozen = storage->alwaysFrozen; newNode->isLeaf = isLeaf; newNode->numBytes = numBytes; if (isLeaf) { @@ -289,223 +425,488 @@ static CFStorageNode *__CFStorageCreateNode(CFAllocatorRef allocator, bool isLea return newNode; } -static void __CFStorageNodeDealloc(CFAllocatorRef allocator, CFStorageNode *node, bool freeNodeItself) { +/* Creates an (unfrozen) copy of the given node. This is shallow in the sense that it shares children for branches, but deep in that it copies memory for leaves. */ +static CFStorageNode *__CFStorageCopyNode(CFStorageRef storage, const CFStorageNode *node) { + CFAllocatorRef allocator = CFGetAllocator(storage); + CFStorageNode *result = __CFStorageCreateNode(allocator, storage, node->isLeaf, node->numBytes); if (node->isLeaf) { - _CFAllocatorDeallocateGC(allocator, node->info.leaf.memory); - } else { - int cnt; - for (cnt = 0; cnt < 3; cnt++) if (node->info.notLeaf.child[cnt]) __CFStorageNodeDealloc(allocator, node->info.notLeaf.child[cnt], true); + if (node->info.leaf.memory != NULL) { + __CFStorageAllocLeafNodeMemory(allocator, storage, result, result->numBytes, false); + COPYMEM(node->info.leaf.memory, result->info.leaf.memory, result->numBytes); + } + } + else { + CFStorageNode *child = node->info.notLeaf.child[0]; + __CFStorageSetChild(result, 0, __CFStorageRetainNode(child)); + if ((child = node->info.notLeaf.child[1])) __CFStorageSetChild(result, 1, __CFStorageRetainNode(child)); + if ((child = node->info.notLeaf.child[2])) __CFStorageSetChild(result, 2, __CFStorageRetainNode(child)); + + /* If we are copying children from a frozen node to an unfrozen node, we need to freeze the children */ + if (node->isFrozen) { + __CFStorageFreezeNode(result->info.notLeaf.child[0]); + if ((child = result->info.notLeaf.child[1])) __CFStorageFreezeNode(child); + if ((child = result->info.notLeaf.child[2])) __CFStorageFreezeNode(child); + } + } + return result; +} + + +static void __CFStorageDeallocateNode(CFStorageRef storage, CFStorageNode *node); + + +#pragma mark Insertion and Deletion prototypes +/* Prototypes for deletion and insertion. The *Frozen and *Unfrozen variants should only be called for nodes that we know are frozen or unfrozen. Frozen nodes may only have frozen children, so it makes sense for the Frozen functions to call other Frozen functions. Unfrozen nodes may have frozen or unfrozen children, so they should call the non-suffixed variants (which dispatch on whether the node is frozen or not). + + The only acceptable time to directly call the Unfrozen variant is for the root node of a CFStorage, because root nodes may never be frozen. The isRootNode parameter determines whether we are in this case. + + The Insertion functions return two nodes. As an awful performance hack, if the first node returned from __CFStorageInsert* is the same as the node passed in, that node is *not* retained, so should not be relased. If it is a different node, it is retained. + */ +static CFStorageDoubleNodeReturn __CFStorageInsert(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFIndex byteNum, CFIndex size, CFIndex absoluteByteNum); +static CFStorageNode *__CFStorageDelete(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFRange range, bool compact); + +static CFStorageDoubleNodeReturn __CFStorageInsertFrozen(CFAllocatorRef allocator, CFStorageRef storage, const CFStorageNode *node, CFIndex byteNum, CFIndex size, CFIndex absoluteByteNum); +static CFStorageNode *__CFStorageDeleteFrozen(CFAllocatorRef allocator, CFStorageRef storage, const CFStorageNode *node, CFRange range); + +static CFStorageDoubleNodeReturn __CFStorageInsertUnfrozen(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFIndex byteNum, CFIndex size, CFIndex absoluteByteNum); +static CFStorageNode *__CFStorageDeleteUnfrozen(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFRange range, bool compact, bool isRootNode); + +#pragma mark Frozen Deletion + +static CFStorageNode *__CFStorageDeleteLeafFrozen(CFAllocatorRef allocator, CFStorageRef storage, const CFStorageNode *node, CFRange range) { + ASSERT(node->isLeaf); + const CFIndex rangeToDeleteEnd = range.location + range.length; + ASSERT(rangeToDeleteEnd <= node->numBytes); + CFIndex remainingBytes = node->numBytes - range.length; + if (remainingBytes == 0) { + /* The range to delete encompasses our entire range of bytes. Return NULL to indicate that we should be deleted. */ + return NULL; + } + else { + /* Need to create a new node */ + CFStorageNode *newNode = __CFStorageCreateNode(allocator, storage, true, remainingBytes); + if (node->info.leaf.memory) { + /* Our node had memory allocated, so copy in the non-deleted portion */ + CFRange nonDeletedPrefix = CFRangeMake(0, range.location); + CFRange nonDeletedSuffix = CFRangeMake(rangeToDeleteEnd, node->numBytes - rangeToDeleteEnd); + ASSERT(nonDeletedPrefix.length + nonDeletedSuffix.length == remainingBytes); + __CFStorageAllocLeafNodeMemory(allocator, storage, newNode, remainingBytes, false); // no point in compacting since we're freshly allocated + __CFLeafCopyRangeToOffset(node, nonDeletedPrefix, newNode, 0); + __CFLeafCopyRangeToOffset(node, nonDeletedSuffix, newNode, nonDeletedPrefix.length); + } + return newNode; + } +} + +/* Helper function for both frozen and unfrozen branch deletion. Walks the children of the node, calling __CFStorageDelete (or __CFStorageDeleteFrozen if childrenAreDefinitelyFrozen is YES), and assigning the results back to newChildren. Returns the number of new children. The newChildren nodes all acquire a reference count! + */ +static inline CFIndex __CFStoragePopulateBranchChildrenAfterDeletion(CFAllocatorRef allocator, CFStorageRef storage, const CFStorageNode *node, CFRange range, CFStorageNode *newChildren[3], bool childrenAreDefinitelyFrozen, bool compact) { + CFIndex newChildIndex = 0; + CFIndex childByteOffset = 0; //will track the current start byte of this child + for (CFIndex existingChildIndex = 0; existingChildIndex < 3; existingChildIndex++) { + CFStorageNode *existingChild = node->info.notLeaf.child[existingChildIndex]; + if (! existingChild) break; //no more children + const CFIndex existingChildLength = existingChild->numBytes; + /* The child's range is {byteOffset, existingChildLength}. Figure out what part of the range to delete is intersected by this child's range */ + CFRange deletionRangeIntersectedByChild = intersectionRange(range, CFRangeMake(childByteOffset, existingChildLength)); + if (! deletionRangeIntersectedByChild.length) { + /* The range to delete does not overlap this child's range, so preserve the child */ + newChildren[newChildIndex++] = __CFStorageRetainNode(existingChild); //bump the refcount like we promised we would + if (childrenAreDefinitelyFrozen) { + /* Because we are about to add this child from a frozen node to a possibly unfrozen node, mark the child as frozen */ + __CFStorageFreezeNode(existingChild); + } + } + else { + /* We have something from this child to delete */ + CFRange rangeOfChildToDelete = CFRangeMake(deletionRangeIntersectedByChild.location - childByteOffset, deletionRangeIntersectedByChild.length); + CFStorageNode *newChild; + if (childrenAreDefinitelyFrozen) { + newChild = __CFStorageDeleteFrozen(allocator, storage, existingChild, rangeOfChildToDelete); + } + else { + newChild = __CFStorageDelete(allocator, storage, existingChild, rangeOfChildToDelete, compact); + } + /* We may get null back if we deleted the entire child */ + if (newChild != NULL) { + newChildren[newChildIndex++] = newChild; // Transfers the reference count + } + + if (rangeOfChildToDelete.length == existingChildLength) { + ASSERT(newChild == NULL); //should have deleted everything + } + else { + ASSERT(newChild != NULL); + ASSERT(newChild->numBytes == existingChildLength - rangeOfChildToDelete.length); + } + } + childByteOffset += existingChildLength; + } + return newChildIndex; +} + +static CFStorageNode *__CFStorageDeleteBranchFrozen(CFAllocatorRef allocator, CFStorageRef storage, const CFStorageNode *node, CFRange range) { + ASSERT(! node->isLeaf); + ASSERT(range.location + range.length <= node->numBytes); + if (range.length == node->numBytes) { + /* They're deleting everything, so return NULL to indicate that this node should be deleted. */ + return NULL; + } + + /* Construct our new children in this array. */ + CFStorageNode *newChildren[3]; + CFIndex newChildIndex = __CFStoragePopulateBranchChildrenAfterDeletion(allocator, storage, node, range, newChildren, true/*childrenAreDefinitelyFrozen*/, false/*compact*/); + + /* We do not have to freeze anything in newChildren. __CFStoragePopulateBranchChildrenAfterDeletion() will properly freeze any existing children, and new children we get should not be marked frozen. */ + + /* Now we have the children of the new node in newChildren. We expect to have at least one child (if we got no children, we should have returned NULL up above because they deleted everything. */ + ASSERT(newChildIndex >= 1); + if (newChildIndex == 1) { + /* Only one child, so just return it, transferring its retain count */ + return newChildren[0]; + } + else { + CFStorageNode *result = __CFStorageCreateNode(allocator, storage, false, 0); + while (newChildIndex--) { + __CFStorageSetChild(result, newChildIndex, newChildren[newChildIndex]); //transfers the reference count + } + result->numBytes = node->numBytes - range.length; + return result; } - if (freeNodeItself) _CFAllocatorDeallocateGC(allocator, node); } -static CFIndex __CFStorageGetNumChildren(CFStorageNode *node) { - if (!node || node->isLeaf) return 0; - if (node->info.notLeaf.child[2]) return 3; - if (node->info.notLeaf.child[1]) return 2; - if (node->info.notLeaf.child[0]) return 1; - return 0; +/* Returns a new node, or NULL if the entire thing was deleted. + */ +static CFStorageNode *__CFStorageDeleteFrozen(CFAllocatorRef allocator, CFStorageRef storage, const CFStorageNode *node, CFRange range) { + if (node->isLeaf) { + return __CFStorageDeleteLeafFrozen(allocator, storage, node, range); + } + else { + return __CFStorageDeleteBranchFrozen(allocator, storage, node, range); + } } +#pragma mark Unfrozen Deletion + /* The boolean compact indicates whether leaf nodes that get smaller should be realloced. -*/ -static void __CFStorageDelete(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFRange range, bool compact) { + */ +static CFStorageNode *__CFStorageDeleteUnfrozen(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFRange range, bool compact, bool isRootNode) { + ASSERT(! node->isFrozen); + ASSERT(range.location + range.length <= node->numBytes); + CHECK_NODE_INTEGRITY(node); + + if (range.length == node->numBytes) { + /* We are deleting everything, so return NULL */ + return NULL; + } + if (node->isLeaf) { node->numBytes -= range.length; - // If this node had memory allocated, readjust the bytes... + // If this node had memory allocated, readjust the bytes... if (node->info.leaf.memory) { - COPYMEM(node->info.leaf.memory + range.location + range.length, node->info.leaf.memory + range.location, node->numBytes - range.location); + COPYMEM(node->info.leaf.memory + range.location + range.length, node->info.leaf.memory + range.location, node->numBytes - range.location); if (compact) __CFStorageAllocLeafNodeMemory(allocator, storage, node, node->numBytes, true); } - } else { - bool childrenAreLeaves = node->info.notLeaf.child[0]->isLeaf; + CHECK_NODE_INTEGRITY(node); + return __CFStorageRetainNodeThreadUnsafe(node); //we can use the ThreadUnsafe calls because this is the Unfrozen variant, so we are not shared + } else { + CFStorageNode *newChildren[3] = {NULL, NULL, NULL}; + CFIndex newChildIndex = __CFStoragePopulateBranchChildrenAfterDeletion(allocator, storage, node, range, newChildren, false/*childrenAreDefinitelyFrozen*/, compact); node->numBytes -= range.length; - while (range.length > 0) { - CFRange rangeToDelete; - CFIndex relativeByteNum; - CFIndex childNum; - __CFStorageFindChild(node, range.location + range.length, true, &childNum, &relativeByteNum); - if (range.length > relativeByteNum) { - rangeToDelete.length = relativeByteNum; - rangeToDelete.location = 0; - } else { - rangeToDelete.length = range.length; - rangeToDelete.location = relativeByteNum - range.length; - } - __CFStorageDelete(allocator, storage, node->info.notLeaf.child[childNum], rangeToDelete, compact); - if (node->info.notLeaf.child[childNum]->numBytes == 0) { // Delete empty node and compact - int cnt; - _CFAllocatorDeallocateGC(allocator, node->info.notLeaf.child[childNum]); - for (cnt = childNum; cnt < 2; cnt++) { - __CFAssignWithWriteBarrier((void **)&node->info.notLeaf.child[cnt], node->info.notLeaf.child[cnt+1]); - } - node->info.notLeaf.child[2] = NULL; - } - range.length -= rangeToDelete.length; + ASSERT(newChildIndex >= 1); //we expect to have at least one child; else we would have deleted everything up above + + /* Release all of our existing children. Either we are about to return a new child in place of us; or we are about to set our children to the new ones */ + __CFStorageReleaseNode(storage, node->info.notLeaf.child[0]); + __CFStorageReleaseNodeWithNullCheck(storage, node->info.notLeaf.child[1]); + __CFStorageReleaseNodeWithNullCheck(storage, node->info.notLeaf.child[2]); + node->info.notLeaf.child[0] = node->info.notLeaf.child[1] = node->info.notLeaf.child[2] = NULL; + + if (newChildIndex == 1) { + /* We have only one child, so return it, transferring the refcount that __CFStoragePopulate gives it */ + return newChildren[0]; } - // At this point the remaining children are packed - if (childrenAreLeaves) { - // Children are leaves; if their total bytes is smaller than a leaf's worth, collapse into one... - if (node->numBytes > 0 && node->numBytes <= storage->maxLeafCapacity) { - __CFStorageAllocLeafNodeMemory(allocator, storage, node->info.notLeaf.child[0], node->numBytes, false); - if (node->info.notLeaf.child[1] && node->info.notLeaf.child[1]->numBytes) { - COPYMEM(node->info.notLeaf.child[1]->info.leaf.memory, node->info.notLeaf.child[0]->info.leaf.memory + node->info.notLeaf.child[0]->numBytes, node->info.notLeaf.child[1]->numBytes); - if (node->info.notLeaf.child[2] && node->info.notLeaf.child[2]->numBytes) { - COPYMEM(node->info.notLeaf.child[2]->info.leaf.memory, node->info.notLeaf.child[0]->info.leaf.memory + node->info.notLeaf.child[0]->numBytes + node->info.notLeaf.child[1]->numBytes, node->info.notLeaf.child[2]->numBytes); - __CFStorageNodeDealloc(allocator, node->info.notLeaf.child[2], true); - node->info.notLeaf.child[2] = NULL; - } - __CFStorageNodeDealloc(allocator, node->info.notLeaf.child[1], true); - node->info.notLeaf.child[1] = NULL; - } - node->info.notLeaf.child[0]->numBytes = node->numBytes; - } - } else { - // Children are not leaves; combine their children to assure each node has 2 or 3 children... - // (Could try to bypass all this by noting up above whether the number of grandchildren changed...) - CFStorageNode *gChildren[9]; - CFIndex cCnt, gCnt, cnt; - CFIndex totalG = 0; // Total number of grandchildren - for (cCnt = 0; cCnt < 3; cCnt++) { - CFStorageNode *child = node->info.notLeaf.child[cCnt]; - if (child) { - for (gCnt = 0; gCnt < 3; gCnt++) if (child->info.notLeaf.child[gCnt]) { - gChildren[totalG++] = child->info.notLeaf.child[gCnt]; - child->info.notLeaf.child[gCnt] = NULL; - } - child->numBytes = 0; - } - } - gCnt = 0; // Total number of grandchildren placed - for (cCnt = 0; cCnt < 3; cCnt++) { - // These tables indicate how many children each child should have, given the total number of grandchildren (last child gets remainder) - static const unsigned char forChild0[10] = {0, 1, 2, 3, 2, 3, 3, 3, 3, 3}; - static const unsigned char forChild1[10] = {0, 0, 0, 0, 2, 2, 3, 2, 3, 3}; - // sCnt is the number of grandchildren to be placed into child cCnt - // Depending on child number, pick the right number - CFIndex sCnt = (cCnt == 0) ? forChild0[totalG] : ((cCnt == 1) ? forChild1[totalG] : totalG); - // Assure we have that many grandchildren... - if (sCnt > totalG - gCnt) sCnt = totalG - gCnt; - if (sCnt) { - if (!node->info.notLeaf.child[cCnt]) { - CFStorageNode *newNode = __CFStorageCreateNode(allocator, false, 0); - __CFAssignWithWriteBarrier((void **)&node->info.notLeaf.child[cCnt], newNode); - Boolean GC = CF_IS_COLLECTABLE_ALLOCATOR(allocator); - if (GC) auto_zone_release(auto_zone(), newNode); - } - for (cnt = 0; cnt < sCnt; cnt++) { - node->info.notLeaf.child[cCnt]->numBytes += gChildren[gCnt]->numBytes; - __CFAssignWithWriteBarrier((void **)&node->info.notLeaf.child[cCnt]->info.notLeaf.child[cnt], gChildren[gCnt++]); - } - } else { - if (node->info.notLeaf.child[cCnt]) { - _CFAllocatorDeallocateGC(allocator, node->info.notLeaf.child[cCnt]); - node->info.notLeaf.child[cCnt] = NULL; - } - } + else { + CFIndex i; + for (i=0; i < 3; i++) { + __CFStorageSetChild(node, i, newChildren[i]); //set the new child, transferring the refcount to us (or set NULL) } - } + CHECK_NODE_INTEGRITY(node); + return __CFStorageRetainNodeThreadUnsafe(node); + } } } +#pragma mark Frozen Insertion + +/* Insertion into an frozen leaf. We return two nodes, either of which may be 'node', or possibly two new nodes. This always sets the cache. */ +static CFStorageDoubleNodeReturn __CFStorageInsertLeafFrozen(CFAllocatorRef allocator, CFStorageRef storage, const CFStorageNode *node, CFIndex byteNum, CFIndex size, CFIndex absoluteByteNum) { + /* Inserting into a frozen leaf. If we can fit the new data along with our existing data into a single node, then do so (i.e. if we can return one node, do it). Otherwise, all of the data would have to fit into a second node (we are never called with more data than storage->maxLeafCapacity) so just make a new node with the data and return that. */ + CFStorageNode *leftResult, *rightResult; + CHECK_NODE_INTEGRITY(node); + ASSERT(byteNum <= node->numBytes); + CFIndex newTotalSize = size + node->numBytes; + if (newTotalSize <= storage->maxLeafCapacity) { + /* We can fit into a single node */ + rightResult = NULL; + leftResult = __CFStorageCreateNode(allocator, storage, true, newTotalSize); + if (node->info.leaf.memory != NULL) { // Beware lazy memory allocation + __CFStorageAllocLeafNodeMemory(allocator, storage, leftResult, newTotalSize, false); + COPYMEM(node->info.leaf.memory, leftResult->info.leaf.memory, byteNum); //copy first byteNum bytes from existing node + //middle we don't touch + COPYMEM(node->info.leaf.memory + byteNum, leftResult->info.leaf.memory + byteNum + size, node->numBytes - byteNum); //copy last part from existing node + } + __CFStorageSetCache(storage, leftResult, absoluteByteNum - byteNum); + } + else { + /* We cannot fit into a single node. See if we can preserve self (i.e. we're inserting at beginning or end). */ + if (byteNum == node->numBytes) { + /* Inserting at end, so left is our existing node and right is the new node. Do not retain left node, because it is the same as the given node */ + leftResult = (CFStorageNode *)node; + rightResult = __CFStorageCreateNode(allocator, storage, true, size); + __CFStorageSetCache(storage, rightResult, absoluteByteNum); + } + else if (byteNum == 0) { + /* Inserting at beginning, so right is our existing node and left is the new node. Do retain left node, because it is different than the given node. */ + rightResult = __CFStorageRetainNode((CFStorageNode *)node); + leftResult = __CFStorageCreateNode(allocator, storage, true, size); + __CFStorageSetCache(storage, leftResult, absoluteByteNum); + } + else { + /* Inserting in middle. We will need to create two nodes because we overflow one. We could be lazy and only allocate up to byteNum, but since it's likely that they're about to insert into us and we'd have to reallocate, just allocate everything requested up front. */ + CFIndex leftAmount = storage->maxLeafCapacity, rightAmount = newTotalSize - storage->maxLeafCapacity; + leftResult = __CFStorageCreateNode(allocator, storage, true, leftAmount); + rightResult = __CFStorageCreateNode(allocator, storage, true, rightAmount); + __CFStorageAllocLeafNodeMemory(allocator, storage, leftResult, leftAmount, false); + __CFStorageAllocLeafNodeMemory(allocator, storage, rightResult, rightAmount, false); + ASSERT(node->info.leaf.capacityInBytes >= node->numBytes); + + /* The existing node has length node->numBytes, so it has the following range: {0, node->numBytes} + + We are inserting (garbage) data of length 'size' into offset 'byteNum'. Therefore we end up with the following two logical ranges, expressed as {start, length}: + {0, byteNum}, {byteNum + size, node->numBytes - byteNum} + + We need to divide these among our new nodes with the following logical ranges: + {0, leftAmount}, {leftAmount, rightAmount} + + The first range must be fit entirely within the left node (byteNum <= leftAmount). The second range may or may be divided between the left and right nodes. + */ + + ASSERT(byteNum <= leftAmount); + COPYMEM(node->info.leaf.memory, leftResult->info.leaf.memory, byteNum); + + const CFRange leftNodeRange = {0, leftAmount}, rightNodeRange = {leftAmount, rightAmount}; + const CFRange preservedData = {byteNum + size, node->numBytes - byteNum}; + CFRange overlap; + if ((overlap = intersectionRange(leftNodeRange, preservedData)).length > 0) COPYMEM(node->info.leaf.memory + overlap.location - size, leftResult->info.leaf.memory + overlap.location, overlap.length); + if ((overlap = intersectionRange(rightNodeRange, preservedData)).length > 0) COPYMEM(node->info.leaf.memory + overlap.location - size, rightResult->info.leaf.memory + overlap.location - leftAmount, overlap.length); + __CFStorageSetCache(storage, leftResult, absoluteByteNum - byteNum); + } + } + return CFStorageDoubleNodeReturnMake(leftResult, rightResult); +} + +static CFStorageDoubleNodeReturn __CFStorageInsertBranchFrozen(CFAllocatorRef allocator, CFStorageRef storage, const CFStorageNode *node, CFIndex byteNum, CFIndex size, CFIndex absoluteByteNum) { + /* Inserting into a frozen branch. We definitely will need to make a new copy of us, so make that up front. We may or may not need to make a new sibling. Note that in some cases, we may be able to get away with not creating a new copy of us, e.g. inserting at the very end of the tree. In that case, we could preserve us and make a sibling containing exactly one node. However, we do not really want to have branches with exactly one child; because then why not just return the child? And then the whole tree can become unbalanced. So then instead, always distribute the children equally among our nodes. */ + CHECK_NODE_INTEGRITY(node); + CFStorageNode *copyOfMe = __CFStorageCreateNode(allocator, storage, false, 0); + CFStorageNode *siblingOfMe = NULL; + CFIndex relativeByteNum; + CFIndex childNum; + CFStorageNode *child = __CFStorageFindChild(node, byteNum, true, &childNum, &relativeByteNum); + ASSERT(childNum >= 0 && childNum <= 2); + CFStorageDoubleNodeReturn childReturn = __CFStorageInsertFrozen(allocator, storage, child, relativeByteNum, size, absoluteByteNum); + ASSERT(childReturn.child); //we always get at least one back + + /* Make a local array of all new children (retained). We'll then move them to the new nodes. */ + CFStorageNode *newChildren[4] = {NULL}; + __CFStorageGetChildren(node, newChildren, true/*retain*/, true/*freeze*/); + if (newChildren[childNum] != childReturn.child) { + __CFStorageReleaseNode(storage, newChildren[childNum]); + newChildren[childNum] = childReturn.child; // Transfers the retain + } + if (childReturn.sibling != NULL) { + if (childNum < 2) newChildren[3] = newChildren[2]; + if (childNum < 1) newChildren[2] = newChildren[1]; + newChildren[childNum + 1] = childReturn.sibling; // Transfers the retain + } + + /* First two always go to our clone */ + __CFStorageSetChild(copyOfMe, 0, newChildren[0]); + __CFStorageSetChild(copyOfMe, 1, newChildren[1]); + if (newChildren[3] == NULL) { + /* We have three or fewer children to distribute, i.e. we don't need a sibling. Put them all into copy of me. Our clone's byte count is larger than our own by 'size'. */ + __CFStorageSetChild(copyOfMe, 2, newChildren[2]); + copyOfMe->numBytes = node->numBytes + size; + } + else { + /* We have four children to distribute. The first two go to us, the last two go to our new sibling. */ + siblingOfMe = __CFStorageCreateNode(allocator, storage, false, 0); + __CFStorageSetChild(siblingOfMe, 0, newChildren[2]); + __CFStorageSetChild(siblingOfMe, 1, newChildren[3]); + copyOfMe->numBytes = newChildren[0]->numBytes + newChildren[1]->numBytes; + siblingOfMe->numBytes = newChildren[2]->numBytes + newChildren[3]->numBytes; + } + CHECK_NODE_INTEGRITY(node); + CHECK_NODE_INTEGRITY(copyOfMe); + if (siblingOfMe) CHECK_NODE_INTEGRITY(siblingOfMe); + return CFStorageDoubleNodeReturnMake(copyOfMe, siblingOfMe); +} + +static CFStorageDoubleNodeReturn __CFStorageInsertFrozen(CFAllocatorRef allocator, CFStorageRef storage, const CFStorageNode *node, CFIndex byteNum, CFIndex size, CFIndex absoluteByteNum) { + if (node->isLeaf) { + return __CFStorageInsertLeafFrozen(allocator, storage, node, byteNum, size, absoluteByteNum); + } + else { + return __CFStorageInsertBranchFrozen(allocator, storage, node, byteNum, size, absoluteByteNum); + } +} + + +#pragma mark Unfrozen Insertion + +/* Insertion into an unfrozen leaf. We return two nodes, one of which is 'node'. This always sets the cache. */ +static CFStorageDoubleNodeReturn __CFStorageInsertLeafUnfrozen(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFIndex byteNum, CFIndex size, CFIndex absoluteByteNum) { + if (size + node->numBytes > storage->maxLeafCapacity) { // Need to create more child nodes + CFStorageNode *newNode; + if (byteNum == node->numBytes) { // Inserting at end; easy... + newNode = __CFStorageCreateNode(allocator, storage, true, size); + __CFStorageSetCache(storage, newNode, absoluteByteNum); + } else if (byteNum == 0) { // Inserting at front; also easy, but we need to swap node and newNode + newNode = __CFStorageCreateNode(allocator, storage, true, 0); + + /* Transfer our memory to the new node */ + newNode->numBytes = node->numBytes; + newNode->info.leaf.capacityInBytes = node->info.leaf.capacityInBytes; + __CFAssignWithWriteBarrier((void **)&newNode->info.leaf.memory, node->info.leaf.memory); + + /* Stomp on our existing node */ + node->numBytes = size; + node->info.leaf.capacityInBytes = 0; + node->info.leaf.memory = NULL; + + /* Cache our existing node */ + __CFStorageSetCache(storage, node, absoluteByteNum); + } else if (byteNum + size <= storage->maxLeafCapacity) { // Inserting at middle; inserted region will fit into existing child + // Create new node to hold the overflow + newNode = __CFStorageCreateNode(allocator, storage, true, node->numBytes - byteNum); + if (node->info.leaf.memory) { // We allocate memory lazily... + __CFStorageAllocLeafNodeMemory(allocator, storage, newNode, node->numBytes - byteNum, false); + COPYMEM(node->info.leaf.memory + byteNum, newNode->info.leaf.memory, node->numBytes - byteNum); + __CFStorageAllocLeafNodeMemory(allocator, storage, node, byteNum + size, false); + } + node->numBytes = byteNum + size; + __CFStorageSetCache(storage, node, absoluteByteNum - byteNum); + } else { // Inserting some of new into one node, rest into another; remember that the assumption is size <= storage->maxLeafCapacity + newNode = __CFStorageCreateNode(allocator, storage, true, node->numBytes + size - storage->maxLeafCapacity); // New stuff + if (node->info.leaf.memory) { // We allocate memory lazily... + __CFStorageAllocLeafNodeMemory(allocator, storage, newNode, node->numBytes + size - storage->maxLeafCapacity, false); + COPYMEM(node->info.leaf.memory + byteNum, newNode->info.leaf.memory + byteNum + size - storage->maxLeafCapacity, node->numBytes - byteNum); + __CFStorageAllocLeafNodeMemory(allocator, storage, node, storage->maxLeafCapacity, false); + } + __CFStorageSetCache(storage, node, absoluteByteNum - byteNum); + node->numBytes = storage->maxLeafCapacity; + } + return CFStorageDoubleNodeReturnMake(node, newNode); // We do not retain 'node' because it is the given node. + } else { // No need to create new nodes! + if (node->info.leaf.memory) { + __CFStorageAllocLeafNodeMemory(allocator, storage, node, node->numBytes + size, false); + COPYMEM(node->info.leaf.memory + byteNum, node->info.leaf.memory + byteNum + size, node->numBytes - byteNum); + } + node->numBytes += size; + __CFStorageSetCache(storage, node, absoluteByteNum - byteNum); + return CFStorageDoubleNodeReturnMake(node, NULL); //return the existing node, meaning the parent does not have to do anything. Do not retain it because it is the given node. + } +} + +static CFStorageDoubleNodeReturn __CFStorageInsertBranchUnfrozen(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFIndex byteNum, CFIndex size, CFIndex absoluteByteNum) { + CFIndex relativeByteNum; + CFIndex childNum; // we will insert after childNum, i.e. if childNum is 0, any new node becomes index 1. This can have value 0, 1, or 2. + CFStorageNode *childNode = __CFStorageFindChild(node, byteNum, true, &childNum, &relativeByteNum); + CFStorageDoubleNodeReturn newNodes = __CFStorageInsert(allocator, storage, childNode, relativeByteNum, size, absoluteByteNum); + CFStorageDoubleNodeReturn result = {node, NULL}; // the default return value meaning we did all of the work ourselves and our parent does not need to do anything + ASSERT(childNode != NULL); + ASSERT(newNodes.child != NULL); + + if (newNodes.child != childNode) { + /* We got back a replacement for the current child, so replace it. */ + __CFStorageReleaseNode(storage, childNode); + __CFStorageSetChild(node, childNum, newNodes.child); + } + + if (newNodes.sibling == NULL) { + /* The insertion happened successfully without requiring us to add any new nodes. */ + node->numBytes += size; + } else { + /* We got back an additional node to insert. */ + CFStorageNode *newChild = newNodes.sibling; + if (node->info.notLeaf.child[2] == NULL) { // There's an empty slot for the new node, cool + if (childNum == 0) __CFStorageSetChild(node, 2, node->info.notLeaf.child[1]); // Make room + __CFStorageSetChild(node, childNum+1, newChild); + node->numBytes += size; + } else { + CFStorageNode *anotherNode = __CFStorageCreateNode(allocator, storage, false, 0); // Create another node + if (childNum == 0) { // Last two children go to new node + __CFStorageSetChild(anotherNode, 0, node->info.notLeaf.child[1]); + __CFStorageSetChild(anotherNode, 1, node->info.notLeaf.child[2]); + __CFStorageSetChild(node, 1, newChild); + node->info.notLeaf.child[2] = NULL; + } else if (childNum == 1) { // Last child goes to new node + __CFStorageSetChild(anotherNode, 0, newChild); + __CFStorageSetChild(anotherNode, 1, node->info.notLeaf.child[2]); + node->info.notLeaf.child[2] = NULL; + } else { // New node contains the new comers... + __CFStorageSetChild(anotherNode, 0, node->info.notLeaf.child[2]); + __CFStorageSetChild(anotherNode, 1, newChild); + node->info.notLeaf.child[2] = NULL; + } + node->numBytes = node->info.notLeaf.child[0]->numBytes + node->info.notLeaf.child[1]->numBytes; + anotherNode->numBytes = anotherNode->info.notLeaf.child[0]->numBytes + anotherNode->info.notLeaf.child[1]->numBytes; + /* node should not be retained because it is the passed in node. anotherNode was created so we transfer its retain count */ + result.sibling = anotherNode; + } + } + return result; +} + + /* Returns NULL or additional node to come after this node - Assumption: size is never > storage->maxLeafCapacity - Under GC node has a retain count to keep it alive in unregistered pthreads -*/ -static CFStorageNode *__CFStorageInsert(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFIndex byteNum, CFIndex size, CFIndex absoluteByteNum) { + Assumption: size is never > storage->maxLeafCapacity + */ +static CFStorageDoubleNodeReturn __CFStorageInsertUnfrozen(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFIndex byteNum, CFIndex size, CFIndex absoluteByteNum) { + ASSERT(! node->isFrozen); if (node->isLeaf) { - if (size + node->numBytes > storage->maxLeafCapacity) { // Need to create more child nodes - if (byteNum == node->numBytes) { // Inserting at end; easy... - CFStorageNode *newNode = __CFStorageCreateNode(allocator, true, size); - __CFStorageSetCache(storage, newNode, absoluteByteNum / storage->valueSize, size / storage->valueSize); - return newNode; - } else if (byteNum == 0) { // Inserting at front; also easy, but we need to swap node and newNode - CFStorageNode *newNode = __CFStorageCreateNode(allocator, true, 0); - objc_memmove_collectable(newNode, node, sizeof(CFStorageNode)); - node->isLeaf = true; - node->numBytes = size; - node->info.leaf.capacityInBytes = 0; - node->info.leaf.memory = NULL; - __CFStorageSetCache(storage, node, absoluteByteNum / storage->valueSize, size / storage->valueSize); - return newNode; - } else if (byteNum + size <= storage->maxLeafCapacity) { // Inserting at middle; inserted region will fit into existing child - // Create new node to hold the overflow - CFStorageNode *newNode = __CFStorageCreateNode(allocator, true, node->numBytes - byteNum); - if (node->info.leaf.memory) { // We allocate memory lazily... - __CFStorageAllocLeafNodeMemory(allocator, storage, newNode, node->numBytes - byteNum, false); - COPYMEM(node->info.leaf.memory + byteNum, newNode->info.leaf.memory, node->numBytes - byteNum); - __CFStorageAllocLeafNodeMemory(allocator, storage, node, byteNum + size, false); - } - node->numBytes = byteNum + size; - __CFStorageSetCache(storage, node, (absoluteByteNum - byteNum) / storage->valueSize, node->numBytes / storage->valueSize); - return newNode; - } else { // Inserting some of new into one node, rest into another; remember that the assumption is size <= storage->maxLeafCapacity - CFStorageNode *newNode = __CFStorageCreateNode(allocator, true, node->numBytes + size - storage->maxLeafCapacity); // New stuff - if (node->info.leaf.memory) { // We allocate memory lazily... - __CFStorageAllocLeafNodeMemory(allocator, storage, newNode, node->numBytes + size - storage->maxLeafCapacity, false); - COPYMEM(node->info.leaf.memory + byteNum, newNode->info.leaf.memory + byteNum + size - storage->maxLeafCapacity, node->numBytes - byteNum); - __CFStorageAllocLeafNodeMemory(allocator, storage, node, storage->maxLeafCapacity, false); - } - node->numBytes = storage->maxLeafCapacity; - __CFStorageSetCache(storage, node, (absoluteByteNum - byteNum) / storage->valueSize, node->numBytes / storage->valueSize); - return newNode; - } - } else { // No need to create new nodes! - if (node->info.leaf.memory) { - __CFStorageAllocLeafNodeMemory(allocator, storage, node, node->numBytes + size, false); - COPYMEM(node->info.leaf.memory + byteNum, node->info.leaf.memory + byteNum + size, node->numBytes - byteNum); - } - node->numBytes += size; - __CFStorageSetCache(storage, node, (absoluteByteNum - byteNum) / storage->valueSize, node->numBytes / storage->valueSize); - return NULL; - } + return __CFStorageInsertLeafUnfrozen(allocator, storage, node, byteNum, size, absoluteByteNum); } else { - CFIndex relativeByteNum; - CFIndex childNum; - CFStorageNode *newNode; - __CFStorageFindChild(node, byteNum, true, &childNum, &relativeByteNum); - newNode = __CFStorageInsert(allocator, storage, node->info.notLeaf.child[childNum], relativeByteNum, size, absoluteByteNum); - if (newNode) { - if (node->info.notLeaf.child[2] == NULL) { // There's an empty slot for the new node, cool - if (childNum == 0) __CFAssignWithWriteBarrier((void **)&node->info.notLeaf.child[2], node->info.notLeaf.child[1]); // Make room - __CFAssignWithWriteBarrier((void **)&node->info.notLeaf.child[childNum + 1], newNode); - Boolean GC = CF_IS_COLLECTABLE_ALLOCATOR(allocator); - if (GC) auto_zone_release(auto_zone(), newNode); - node->numBytes += size; - return NULL; - } else { - CFStorageNode *anotherNode = __CFStorageCreateNode(allocator, false, 0); // Create another node - if (childNum == 0) { // Last two children go to new node - __CFAssignWithWriteBarrier((void **)&anotherNode->info.notLeaf.child[0], node->info.notLeaf.child[1]); - __CFAssignWithWriteBarrier((void **)&anotherNode->info.notLeaf.child[1], node->info.notLeaf.child[2]); - __CFAssignWithWriteBarrier((void **)&node->info.notLeaf.child[1], newNode); - node->info.notLeaf.child[2] = NULL; - } else if (childNum == 1) { // Last child goes to new node - __CFAssignWithWriteBarrier((void **)&anotherNode->info.notLeaf.child[0], newNode); - __CFAssignWithWriteBarrier((void **)&anotherNode->info.notLeaf.child[1], node->info.notLeaf.child[2]); - node->info.notLeaf.child[2] = NULL; - } else { // New node contains the new comers... - __CFAssignWithWriteBarrier((void **)&anotherNode->info.notLeaf.child[0], node->info.notLeaf.child[2]); - __CFAssignWithWriteBarrier((void **)&anotherNode->info.notLeaf.child[1], newNode); - node->info.notLeaf.child[2] = NULL; - } - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - auto_zone_release(auto_zone(), newNode); - } - node->numBytes = node->info.notLeaf.child[0]->numBytes + node->info.notLeaf.child[1]->numBytes; - anotherNode->numBytes = anotherNode->info.notLeaf.child[0]->numBytes + anotherNode->info.notLeaf.child[1]->numBytes; - return anotherNode; - } - } else { - node->numBytes += size; - } + return __CFStorageInsertBranchUnfrozen(allocator, storage, node, byteNum, size, absoluteByteNum); } - return NULL; } +#pragma mark Frozen or Unfrozen Dispatch Functions + +static CFStorageDoubleNodeReturn __CFStorageInsert(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFIndex byteNum, CFIndex size, CFIndex absoluteByteNum) { + if (node->isFrozen && ! __CFStorageThawNodeDuringMutation(storage, node)) { + return __CFStorageInsertFrozen(allocator, storage, node, byteNum, size, absoluteByteNum); + } + else { + return __CFStorageInsertUnfrozen(allocator, storage, node, byteNum, size, absoluteByteNum); + } +} + +static CFStorageNode *__CFStorageDelete(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFRange range, bool compact) { + if (node->isFrozen && ! __CFStorageThawNodeDuringMutation(storage, node)) { + return __CFStorageDeleteFrozen(allocator, storage, node, range); + } + else { + return __CFStorageDeleteUnfrozen(allocator, storage, node, range, compact, false/*isRootNode*/); + } +} + + +#pragma mark Utility functions + CF_INLINE CFIndex __CFStorageGetCount(CFStorageRef storage) { - return storage->rootNode.numBytes / storage->valueSize; + return __CFStorageConvertByteToValue(storage, storage->rootNode.numBytes); } static Boolean __CFStorageEqual(CFTypeRef cf1, CFTypeRef cf2) { @@ -514,16 +915,16 @@ static Boolean __CFStorageEqual(CFTypeRef cf1, CFTypeRef cf2) { CFIndex loc, count, valueSize; CFRange range1, range2; uint8_t *ptr1, *ptr2; - + count = __CFStorageGetCount(storage1); if (count != __CFStorageGetCount(storage2)) return false; - + valueSize = __CFStorageGetValueSize(storage1); if (valueSize != __CFStorageGetValueSize(storage2)) return false; - + loc = range1.location = range1.length = range2.location = range2.length = 0; ptr1 = ptr2 = NULL; - + while (loc < count) { CFIndex cntThisTime; if (loc >= range1.location + range1.length) ptr1 = (uint8_t *)CFStorageGetValueAtIndex(storage1, loc, &range1); @@ -547,11 +948,11 @@ static CFHashCode __CFStorageHash(CFTypeRef cf) { static void __CFStorageDescribeNode(CFStorageNode *node, CFMutableStringRef str, CFIndex level) { int cnt; for (cnt = 0; cnt < level; cnt++) CFStringAppendCString(str, " ", CFStringGetSystemEncoding()); - + if (node->isLeaf) { - CFStringAppendFormat(str, NULL, CFSTR("Leaf %d/%d\n"), node->numBytes, node->info.leaf.capacityInBytes); + CFStringAppendFormat(str, NULL, CFSTR("Leaf %ld/%ld (%p) refcount: %u frozen: %s\n"), node->numBytes, node->info.leaf.capacityInBytes, node, node->refCount, node->isFrozen ? "yes" : "no"); } else { - CFStringAppendFormat(str, NULL, CFSTR("Node %d\n"), node->numBytes); + CFStringAppendFormat(str, NULL, CFSTR("Node %ld (%p) refcount: %u frozen: %s\n"), node->numBytes, node, node->refCount, node->isFrozen ? "yes" : "no"); for (cnt = 0; cnt < 3; cnt++) if (node->info.notLeaf.child[cnt]) __CFStorageDescribeNode(node->info.notLeaf.child[cnt], str, level+1); } } @@ -563,7 +964,7 @@ static CFIndex __CFStorageGetNodeCapacity(CFStorageNode *node) { } CFIndex __CFStorageGetCapacity(CFStorageRef storage) { - return __CFStorageGetNodeCapacity(&storage->rootNode) / storage->valueSize; + return __CFStorageConvertByteToValue(storage, __CFStorageGetNodeCapacity(&storage->rootNode)); } CFIndex __CFStorageGetValueSize(CFStorageRef storage) { @@ -580,11 +981,114 @@ static CFStringRef __CFStorageCopyDescription(CFTypeRef cf) { return result; } +/* Returns true if enumeration should stop, false if it should continue. */ +static bool __CFStorageEnumerateNodesInByteRangeWithBlock(CFStorageRef storage, CFStorageNode *node, CFIndex globalOffsetOfNode, CFRange range, CFIndex concurrencyToken, CFStorageApplierBlock applier) { + bool stop = false; + if (node->isLeaf) { + CFIndex start = range.location; + CFIndex length = __CFMin(range.length, node->numBytes - start); + if (! node->info.leaf.memory) { + __CFStorageAllocLeafNodeMemory(CFGetAllocator(storage), storage, node, node->numBytes, false); + } + applier(node->info.leaf.memory + start, __CFStorageConvertBytesToValueRange(storage, globalOffsetOfNode + start, length), &stop); + } + else { + CFStorageNode *children[3] = {node->info.notLeaf.child[0], node->info.notLeaf.child[1], node->info.notLeaf.child[2]}; + const CFIndex lengths[3] = {children[0]->numBytes, children[1] ? children[1]->numBytes : 0, children[2] ? children[2]->numBytes : 0}; + const CFIndex offsets[3] = {0, lengths[0], lengths[0] + lengths[1]}; + const CFRange overlaps[3] = {intersectionRange(CFRangeMake(offsets[0], lengths[0]), range), intersectionRange(CFRangeMake(offsets[1], lengths[1]), range), intersectionRange(CFRangeMake(offsets[2], lengths[2]), range)}; + CFIndex numOverlappingChildren = (!! overlaps[0].length + !! overlaps[1].length + !! overlaps[2].length); + if (numOverlappingChildren > 1) concurrencyToken--; + + if (concurrencyToken >= 0 && numOverlappingChildren > 1) { + CFIndex numChildren = 1 + !!children[1] + !!children[2]; + const CFRange * overlapsPtr = overlaps; //blocks don't let us reference arrays :( + const CFIndex * offsetsPtr = offsets; + CFStorageNode ** childrenPtr = children; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS + __block bool blockStop = false; + dispatch_apply(numChildren, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(size_t ind) { + if (! blockStop && overlapsPtr[ind].length > 0) { + if (__CFStorageEnumerateNodesInByteRangeWithBlock(storage, childrenPtr[ind], globalOffsetOfNode + offsetsPtr[ind], CFRangeMake(overlapsPtr[ind].location - offsetsPtr[ind], overlapsPtr[ind].length), concurrencyToken, applier)) { + blockStop = true; + } + } + }); + stop = blockStop; +#else + for (CFIndex ind = 0; ind < numChildren; ind++) { + if (overlapsPtr[ind].length > 0) { + if (__CFStorageEnumerateNodesInByteRangeWithBlock(storage, childrenPtr[ind], globalOffsetOfNode + offsetsPtr[ind], CFRangeMake(overlapsPtr[ind].location - offsetsPtr[ind], overlapsPtr[ind].length), concurrencyToken, applier)) { + stop = true; + break; + } + } + } +#endif + } else { + if (overlaps[0].length > 0) { + stop = stop || __CFStorageEnumerateNodesInByteRangeWithBlock(storage, children[0], globalOffsetOfNode + offsets[0], CFRangeMake(overlaps[0].location - offsets[0], overlaps[0].length), concurrencyToken, applier); + } + if (overlaps[1].length > 0) { + stop = stop || __CFStorageEnumerateNodesInByteRangeWithBlock(storage, children[1], globalOffsetOfNode + offsets[1], CFRangeMake(overlaps[1].location - offsets[1], overlaps[1].length), concurrencyToken, applier); + } + if (overlaps[2].length > 0) { + stop = stop || __CFStorageEnumerateNodesInByteRangeWithBlock(storage, children[2], globalOffsetOfNode + offsets[2], CFRangeMake(overlaps[2].location - offsets[2], overlaps[2].length), concurrencyToken, applier); + } + } + } + return stop; +} + +static CFStorageNode *_CFStorageFindNodeContainingByteRange(ConstCFStorageRef storage, const CFStorageNode *node, CFRange nodeRange, CFIndex globalOffsetOfNode, CFRange *outGlobalByteRangeOfResult) { + if (! node->isLeaf) { + /* See how many children are overlapped by this range. If it's only 1, call us recursively on that node; otherwise we're it! */ + CFStorageNode *children[3] = {node->info.notLeaf.child[0], node->info.notLeaf.child[1], node->info.notLeaf.child[2]}; + const CFIndex lengths[3] = {children[0]->numBytes, children[1] ? children[1]->numBytes : 0, children[2] ? children[2]->numBytes : 0}; + const CFIndex offsets[3] = {0, lengths[0], lengths[0] + lengths[1]}; + const CFRange overlaps[3] = {intersectionRange(CFRangeMake(offsets[0], lengths[0]), nodeRange), intersectionRange(CFRangeMake(offsets[1], lengths[1]), nodeRange), intersectionRange(CFRangeMake(offsets[2], lengths[2]), nodeRange)}; + CFIndex numOverlappingChildren = (!! overlaps[0].length + !! overlaps[1].length + !! overlaps[2].length); + ASSERT(numOverlappingChildren > 0); + if (numOverlappingChildren == 1) { + CFIndex overlappingChild = (overlaps[0].length ? 0 : (overlaps[1].length ? 1 : 2)); + return _CFStorageFindNodeContainingByteRange(storage, children[overlappingChild], CFRangeMake(nodeRange.location - offsets[overlappingChild], nodeRange.length), globalOffsetOfNode + offsets[overlappingChild], outGlobalByteRangeOfResult); + } + } + + /* Either we are a leaf, in which case we contain the range, or we are a branch with multiple overlapping children. Either way, we are the minimum node containing the range in question. */ + *outGlobalByteRangeOfResult = CFRangeMake(globalOffsetOfNode, node->numBytes); + return (CFStorageNode *)node; + + +} + +/* Frees all memory associated with the root node, effectively emptying the CFStorage */ +static void __CFStorageClearRootNode(CFStorageRef storage) { + CFAllocatorRef allocator = CFGetAllocator(storage); + /* Have to release our children if we are a branch, or free our memory if we are a leaf */ + if (storage->rootNode.isLeaf) { + _CFAllocatorDeallocateGC(allocator, storage->rootNode.info.leaf.memory); + } + else { + __CFStorageReleaseNodeWithNullCheck(storage, storage->rootNode.info.notLeaf.child[0]); + __CFStorageReleaseNodeWithNullCheck(storage, storage->rootNode.info.notLeaf.child[1]); + __CFStorageReleaseNodeWithNullCheck(storage, storage->rootNode.info.notLeaf.child[2]); + } + storage->rootNode.isLeaf = true; + storage->rootNode.numBytes = 0; + storage->rootNode.info.leaf.capacityInBytes = 0; + storage->rootNode.info.leaf.memory = NULL; +} + static void __CFStorageDeallocate(CFTypeRef cf) { + /* CFStorage is used in CFArray. Under GC, CFArray references us strongly, but not retained. Thus we may be finalized before the array. When the array itself is finalized, it will call any custom deallocate callback on all of its contents, which means it has to walk the array. Thus CFStorage must be careful to not perturb its structure in Deallocate under GC. + + CFStorage nodes have a reference count, and if a node has a reference count of one, and we are in a mutating function, we conclude that this CFStorage has exclusive ownership of the node, and we can treat it as mutable even if it's marked as frozen (see __CFStorageThawNodeDuringMutation). Therefore it would be nice if we could decrement our nodes' refcounts in Deallocate. However, if we did so, then another CFStorage might treat a node that we reference as mutable and modify it, which must not happen, because we must not perturb the structure of a CFStorage in Deallocate. Thus we just "leak" a reference count under GC. Of course, these reference counts don't actually keep the memory alive in GC, so it's not a real leak. + */ CFStorageRef storage = (CFStorageRef)cf; - CFAllocatorRef allocator = CFGetAllocator(storage); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) return; // XXX_PCB GC will take care of us. - __CFStorageNodeDealloc(allocator, &storage->rootNode, false); + if (! CF_IS_COLLECTABLE_ALLOCATOR(CFGetAllocator(storage))) { + __CFStorageClearRootNode(storage); + } } static CFTypeID __kCFStorageTypeID = _kCFRuntimeNotATypeID; @@ -615,27 +1119,91 @@ CFStorageRef CFStorageCreate(CFAllocatorRef allocator, CFIndex valueSize) { return NULL; } storage->valueSize = valueSize; - CF_SPINLOCK_INIT_FOR_STRUCTS(storage->cacheReaderMemoryAllocationLock); - storage->cacheGenerationCount = 0; - storage->cacheParts.locationHi = 0; - storage->cacheParts.locationLo = 0; -#if POSSIBLE_TO_HAVE_LENGTH_MORE_THAN_HALFWORD - storage->cacheParts.lengthHi = 0; + /* if valueSize is a power of 2, then set the shifter to the log base 2 of valueSize. Otherwise set it to NO_SHIFTER */ + if (valueSize > 0 && !(valueSize & (valueSize - 1))) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + storage->byteToValueShifter = __builtin_ctzl(valueSize); +#else + CFIndex tempSize = valueSize; + storage->byteToValueShifter = 0; + while (tempSize > 1) { + storage->byteToValueShifter++; + tempSize >>= 1; + } #endif - storage->cacheParts.lengthLo = 0; - storage->cacheParts.cachedNodeHi = 0; - storage->cacheParts.cachedNodeLo = 0; + } + else { + storage->byteToValueShifter = NO_SHIFTER; + } + + CF_SPINLOCK_INIT_FOR_STRUCTS(storage->cacheReaderMemoryAllocationLock); storage->maxLeafCapacity = __CFStorageMaxLeafCapacity; if (valueSize && ((storage->maxLeafCapacity % valueSize) != 0)) { storage->maxLeafCapacity = (storage->maxLeafCapacity / valueSize) * valueSize; // Make it fit perfectly (3406853) } memset(&(storage->rootNode), 0, sizeof(CFStorageNode)); storage->rootNode.isLeaf = true; - storage->nodeHint = __kCFAllocatorGCScannedMemory; + storage->rootNode.refCount = 0; + if (valueSize >= sizeof(void *)) { + storage->nodeHint = __kCFAllocatorGCScannedMemory; + } + else { + // Don't scan nodes if the value size is smaller than a pointer (8198596) + storage->nodeHint = 0; + } if (__CFOASafe) __CFSetLastAllocationEventName(storage, "CFStorage"); return storage; } +CFStorageRef CFStorageCreateWithSubrange(CFStorageRef mutStorage, CFRange range) { + const ConstCFStorageRef storage = mutStorage; //we expect this to never modify the storage, so use a const variable to help enforce that + CFStorageRef result = CFStorageCreate(CFGetAllocator(storage), storage->valueSize); + + if (range.length > 0) { + /* Start by finding the node that contains the entire range. Bump the reference count of its children and add them to the root of our new copy. */ + const CFRange byteRange = __CFStorageConvertValuesToByteRange(storage, range.location, range.length); + CFRange byteRangeOfContainingNode; + CFStorageNode *nodeContainingEntireRange = _CFStorageFindNodeContainingByteRange(storage, &storage->rootNode, byteRange, 0, &byteRangeOfContainingNode); + ASSERT(nodeContainingEntireRange != NULL); + + /* If the result is a leaf, insert the portion we care about */ + if (nodeContainingEntireRange->isLeaf) { + CFStorageInsertValues(result, CFRangeMake(0, range.length)); + if (nodeContainingEntireRange->info.leaf.memory) { + CFIndex offsetIntoNode = byteRange.location - byteRangeOfContainingNode.location; + ASSERT(offsetIntoNode >= 0); + CFStorageReplaceValues(result, CFRangeMake(0, range.length), nodeContainingEntireRange->info.leaf.memory + offsetIntoNode); + } + } + else { + /* The result is not a leaf. Insert all of its children into our root. */ + ASSERT(byteRangeOfContainingNode.length == nodeContainingEntireRange->numBytes); + result->rootNode.isLeaf = false; + result->rootNode.numBytes = byteRangeOfContainingNode.length; + result->rootNode.info.notLeaf.child[0] = result->rootNode.info.notLeaf.child[1] = result->rootNode.info.notLeaf.child[2] = NULL; + for (CFIndex i=0; i < 3; i++) { + CFStorageNode *newNode = nodeContainingEntireRange->info.notLeaf.child[i]; + if (! newNode) break; + __CFStorageFreezeNode(newNode); + __CFStorageSetChild(&result->rootNode, i, __CFStorageRetainNode(newNode)); + } + + /* Now delete from the beginning or end to trim this to the right size */ + CFRange rangeOfContainingNode = __CFStorageConvertBytesToValueRange(result, byteRangeOfContainingNode.location, byteRangeOfContainingNode.length); + CFIndex prefixToTrim = range.location - rangeOfContainingNode.location; + CFIndex suffixToTrim = (rangeOfContainingNode.location + rangeOfContainingNode.length) - (range.location + range.length); + ASSERT(prefixToTrim >= 0); + ASSERT(suffixToTrim >= 0); + ASSERT(CFStorageGetCount(result) == rangeOfContainingNode.length); + if (suffixToTrim > 0) CFStorageDeleteValues(result, CFRangeMake(rangeOfContainingNode.length - suffixToTrim, suffixToTrim)); + if (prefixToTrim > 0) CFStorageDeleteValues(result, CFRangeMake(0, prefixToTrim)); + } + } + + ASSERT(CFStorageGetCount(result) == range.length); + return result; +} + CFTypeID CFStorageGetTypeID(void) { return __kCFStorageTypeID; } @@ -645,81 +1213,127 @@ CFIndex CFStorageGetCount(CFStorageRef storage) { } /* Returns pointer to the specified value - index and validConsecutiveValueRange are in terms of values -*/ + index and validConsecutiveValueRange are in terms of values + */ void *CFStorageGetValueAtIndex(CFStorageRef storage, CFIndex idx, CFRange *validConsecutiveValueRange) { - CFRange range; - return __CFStorageGetValueAtIndex(storage, idx, validConsecutiveValueRange ? validConsecutiveValueRange : &range); + CFRange dummy; + return __CFStorageGetValueAtIndex(storage, idx, validConsecutiveValueRange ? validConsecutiveValueRange : &dummy, true/*requireUnfreezing*/); +} + +const void *CFStorageGetConstValueAtIndex(CFStorageRef storage, CFIndex idx, CFRange *validConsecutiveValueRange) { + CFRange dummy; + return __CFStorageGetValueAtIndex(storage, idx, validConsecutiveValueRange ? validConsecutiveValueRange : &dummy, false/*requireUnfreezing*/); } + /* Makes space for range.length values at location range.location - This function deepens the tree if necessary... -*/ + This function deepens the tree if necessary... + */ void CFStorageInsertValues(CFStorageRef storage, CFRange range) { - CFIndex numBytesToInsert = range.length * storage->valueSize; - CFIndex byteNum = range.location * storage->valueSize; + CFIndex numBytesToInsert = __CFStorageConvertValueToByte(storage, range.length); + CFIndex byteNum = __CFStorageConvertValueToByte(storage, range.location); + const CFIndex expectedByteCount = storage->rootNode.numBytes + numBytesToInsert; + const CFAllocatorRef allocator = CFGetAllocator(storage); + const CFIndex insertionChunkSize = storage->maxLeafCapacity; while (numBytesToInsert > 0) { - CFStorageNode *newNode; - CFAllocatorRef allocator = CFGetAllocator(storage); - CFIndex insertThisTime = numBytesToInsert; - if (insertThisTime > storage->maxLeafCapacity) { - insertThisTime = (storage->maxLeafCapacity / storage->valueSize) * storage->valueSize; - } - newNode = __CFStorageInsert(allocator, storage, &storage->rootNode, byteNum, insertThisTime, byteNum); - if (newNode) { - CFStorageNode *tempRootNode = __CFStorageCreateNode(allocator, false, 0); // Will copy the (static) rootNode over to this - objc_memmove_collectable(tempRootNode, &storage->rootNode, sizeof(CFStorageNode)); - storage->rootNode.isLeaf = false; - __CFAssignWithWriteBarrier((void **)&storage->rootNode.info.notLeaf.child[0], tempRootNode); - __CFAssignWithWriteBarrier((void **)&storage->rootNode.info.notLeaf.child[1], newNode); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - auto_zone_release(auto_zone(), tempRootNode); - auto_zone_release(auto_zone(), newNode); - } + CHECK_INTEGRITY(); + const CFIndex insertThisTime = __CFMin(numBytesToInsert, insertionChunkSize); + CFStorageDoubleNodeReturn newNodes = __CFStorageInsertUnfrozen(allocator, storage, &storage->rootNode, byteNum, insertThisTime, byteNum); //we don't have to call the frozen variant because the root node is never frozen + ASSERT(newNodes.child == &storage->rootNode);// unfrozen variant should always give us our node back. We may have another node to insert in newNodes.sibling + if (newNodes.sibling != NULL) { + CFStorageNode *newNode = newNodes.sibling; + /* Need to create a new root node. Copy our existing root node's contents to a new heap node. */ + CFStorageNode *heapRoot = __CFStorageCreateNode(allocator, storage, storage->rootNode.isLeaf, storage->rootNode.numBytes); // Will copy the (static) rootNode over to this + objc_memmove_collectable(&heapRoot->info, &storage->rootNode.info, sizeof heapRoot->info); + + /* Our root is about to become a branch. If our root node is currently a leaf, we need to clear the cache, because if the cache points at the root then the cache is about to start pointing at a branch node (which is not allowed) */ + if (storage->rootNode.isLeaf) { + __CFStorageSetCache(storage, NULL, 0); + storage->rootNode.isLeaf = false; + } + + /* Set the new children in our root. Note that it's important that we overwrite the root node's info, because we wanted to transfer the refcounts of our children (or our allocated memory, if we are a leaf) to the new heap root */ + __CFStorageSetChild(&storage->rootNode, 0, heapRoot); + __CFStorageSetChild(&storage->rootNode, 1, newNode); storage->rootNode.info.notLeaf.child[2] = NULL; - storage->rootNode.numBytes = tempRootNode->numBytes + newNode->numBytes; -#if 1 - // ??? - __CFStorageSetCache(storage, NULL, 0, 0); -#else - if (storage->cache.cachedNode == &(storage->rootNode)) __CFAssignWithWriteBarrier((void **)&storage->cache.cachedNode, tempRootNode); // The cache should follow the node -#endif + storage->rootNode.numBytes = heapRoot->numBytes + newNode->numBytes; } numBytesToInsert -= insertThisTime; byteNum += insertThisTime; + ASSERT(storage->rootNode.numBytes + numBytesToInsert == expectedByteCount); } + ASSERT(expectedByteCount == storage->rootNode.numBytes); + CHECK_INTEGRITY(); } /* Deletes the values in the specified range - This function gets rid of levels if necessary... -*/ + This function gets rid of levels if necessary... + */ void CFStorageDeleteValues(CFStorageRef storage, CFRange range) { + CHECK_INTEGRITY(); CFAllocatorRef allocator = CFGetAllocator(storage); - range.location *= storage->valueSize; - range.length *= storage->valueSize; - __CFStorageDelete(allocator, storage, &storage->rootNode, range, true); - while (__CFStorageGetNumChildren(&storage->rootNode) == 1) { - CFStorageNode *child = storage->rootNode.info.notLeaf.child[0]; // The single child - objc_memmove_collectable(&storage->rootNode, child, sizeof(CFStorageNode)); - _CFAllocatorDeallocateGC(allocator, child); + CFRange byteRange = __CFStorageConvertValuesToByteRange(storage, range.location, range.length); + const CFIndex expectedByteCount = storage->rootNode.numBytes - byteRange.length; + + /* We don't try to mantain the cache across deletion */ + __CFStorageSetCache(storage, NULL, 0); + + /* The root node can never be frozen, so it's always OK to modify it */ + ASSERT(! storage->rootNode.isFrozen); + CFStorageNode *newRoot = __CFStorageDeleteUnfrozen(allocator, storage, &storage->rootNode, byteRange, true/*compact*/, true/*isRootNode*/); + + /* There are three return values we can get: + NULL -> everything was deleted + the root node -> something was deleted, but no nodes became empty, so we don't have to replace any children + a different node -> represents the new root + */ + if (newRoot == NULL) { + __CFStorageClearRootNode(storage); } - if (__CFStorageGetNumChildren(&storage->rootNode) == 0 && !storage->rootNode.isLeaf) { - storage->rootNode.isLeaf = true; - storage->rootNode.info.leaf.capacityInBytes = 0; - storage->rootNode.info.leaf.memory = NULL; + else if (newRoot == &storage->rootNode) { + /* No need to replace any children, nothing to do for this case */ } - // !!! Need to update the cache - __CFStorageSetCache(storage, NULL, 0, 0); + else { + /* Got a legitimately new root back. If it is unfrozen, we can just acquire its guts. If it is frozen, we have more work to do. Note that we do not have to worry about releasing any existing children of the root, beacuse __CFStorageDeleteUnfrozen already did that. Also note that if we got a legitimately new root back, we must be a branch node, because if we were a leaf node, we would have been unfrozen and gotten ourself back. */ + storage->rootNode.numBytes = newRoot->numBytes; + storage->rootNode.isLeaf = newRoot->isLeaf; + bzero(&storage->rootNode.info, sizeof storage->rootNode.info); //be a little paranoid here + if (newRoot->isLeaf) { + if (! newRoot->isFrozen) { + /* If the leaf is not frozen, we can just steal its memory (if any)! If it is frozen, we must copy it. */ + __CFAssignWithWriteBarrier((void **)&storage->rootNode.info.leaf.memory, newRoot->info.leaf.memory); + /* Clear out the old node, because we stole its memory and we don't want it to deallocate it when teh node is destroyed below. */ + bzero(&newRoot->info, sizeof newRoot->info); + } + else { + /* The leaf is frozen, so we have to copy its memory. */ + if (newRoot->info.leaf.memory) { + __CFStorageAllocLeafNodeMemory(allocator, storage, &storage->rootNode, storage->rootNode.numBytes, false); + COPYMEM(newRoot->info.leaf.memory, storage->rootNode.info.leaf.memory, newRoot->numBytes); + } + } + } else { + /* New root is a branch. */ + ASSERT(newRoot->info.notLeaf.child[0] && newRoot->info.notLeaf.child[1]); //never expect to get back a node with only one child + __CFStorageSetChild(&storage->rootNode, 0, __CFStorageRetainNode(newRoot->info.notLeaf.child[0])); + __CFStorageSetChild(&storage->rootNode, 1, __CFStorageRetainNode(newRoot->info.notLeaf.child[1])); + if (newRoot->info.notLeaf.child[2]) __CFStorageSetChild(&storage->rootNode, 2, __CFStorageRetainNode(newRoot->info.notLeaf.child[2])); + } + } + __CFStorageReleaseNodeWithNullCheck(storage, newRoot); //balance the retain from __CFStorageDeleteUnfrozen + ASSERT(expectedByteCount == storage->rootNode.numBytes); + CHECK_INTEGRITY(); } void CFStorageGetValues(CFStorageRef storage, CFRange range, void *values) { + CHECK_INTEGRITY(); while (range.length > 0) { CFRange leafRange; - void *storagePtr = __CFStorageGetValueAtIndex(storage, range.location, &leafRange); - CFIndex cntThisTime = range.length; - if (cntThisTime > leafRange.length - (range.location - leafRange.location)) cntThisTime = leafRange.length - (range.location - leafRange.location); - COPYMEM(storagePtr, values, cntThisTime * storage->valueSize); - values = (uint8_t *)values + (cntThisTime * storage->valueSize); + void *storagePtr = __CFStorageGetValueAtIndex(storage, range.location, &leafRange, false/*requireUnfreezing*/); + CFIndex cntThisTime = __CFMin(range.length, leafRange.length - (range.location - leafRange.location)); + CFIndex byteCntThisTime = __CFStorageConvertValueToByte(storage, cntThisTime); + COPYMEM(storagePtr, values, byteCntThisTime); + values = (uint8_t *)values + byteCntThisTime; range.location += cntThisTime; range.length -= cntThisTime; } @@ -738,34 +1352,112 @@ unsigned long _CFStorageFastEnumeration(CFStorageRef storage, struct __objcFastE } void CFStorageApplyFunction(CFStorageRef storage, CFRange range, CFStorageApplierFunction applier, void *context) { - while (0 < range.length) { - CFRange leafRange; - const void *storagePtr; - CFIndex idx, cnt; - storagePtr = CFStorageGetValueAtIndex(storage, range.location, &leafRange); - cnt = __CFMin(range.length, leafRange.location + leafRange.length - range.location); - for (idx = 0; idx < cnt; idx++) { - applier(storagePtr, context); - storagePtr = (const char *)storagePtr + storage->valueSize; - } - range.length -= cnt; - range.location += cnt; + CHECK_INTEGRITY(); + CFIndex valueSize = storage->valueSize; + CFStorageApplyBlock(storage, range, 0, ^(const void *storagePtr, CFRange subrange, bool *stop){ + while (subrange.length--) { + applier(storagePtr, context); + storagePtr = valueSize + (const char *)storagePtr; + } + }); +} + +void CFStorageApplyBlock(CFStorageRef storage, CFRange range, CFStorageEnumerationOptionFlags options, CFStorageApplierBlock applier) { + if (! range.length) return; + CFRange byteRange = __CFStorageConvertValuesToByteRange(storage, range.location, range.length); + /* As we descend the tree, if we find we need to go down two or more children, and the concurrency token is not zero, then we decrement the concurrency token and do it concurrently. Since we have 3 children, a concurrency token of 3 yields up to 3**3 == 27 threads, which is a lot! Concurrency benefits start to kick in around one million elements */ + CFIndex concurrencyToken = 0; + if ((options & kCFStorageEnumerationConcurrent) && (range.length >= 1024 * 1024)) { + concurrencyToken = 3; } + __CFStorageEnumerateNodesInByteRangeWithBlock(storage, &storage->rootNode, 0/*globalOffsetOfNode*/, byteRange, concurrencyToken, applier); } void CFStorageReplaceValues(CFStorageRef storage, CFRange range, const void *values) { + CHECK_INTEGRITY(); while (range.length > 0) { CFRange leafRange; - void *storagePtr = __CFStorageGetValueAtIndex(storage, range.location, &leafRange); - CFIndex cntThisTime = range.length; - if (cntThisTime > leafRange.length - (range.location - leafRange.location)) cntThisTime = leafRange.length - (range.location - leafRange.location); - COPYMEM(values, storagePtr, cntThisTime * storage->valueSize); - values = (const uint8_t *)values + (cntThisTime * storage->valueSize); + void *storagePtr = __CFStorageGetValueAtIndex(storage, range.location, &leafRange, true/*requireUnfreezing*/); + ASSERT(range.location >= leafRange.location); + ASSERT(range.location < leafRange.location + leafRange.length); + CFIndex cntThisTime = __CFMin(range.length, leafRange.length - (range.location - leafRange.location)); + CFIndex byteCntThisTime = __CFStorageConvertValueToByte(storage, cntThisTime); + COPYMEM(values, storagePtr, byteCntThisTime); + values = (const uint8_t *)values + byteCntThisTime; range.location += cntThisTime; range.length -= cntThisTime; } } +static void __CFStorageApplyNodeBlockInterior(CFStorageRef storage, CFStorageNode *node, void (^block)(CFStorageRef storage, CFStorageNode *node)) { + block(storage, node); + if (! node->isLeaf) { + CFStorageNode *childNode; + if ((childNode = node->info.notLeaf.child[0])) __CFStorageApplyNodeBlockInterior(storage, childNode, block); + if ((childNode = node->info.notLeaf.child[1])) __CFStorageApplyNodeBlockInterior(storage, childNode, block); + if ((childNode = node->info.notLeaf.child[2])) __CFStorageApplyNodeBlockInterior(storage, childNode, block); + } +} + +static void __CFStorageApplyNodeBlock(CFStorageRef storage, void (^block)(CFStorageRef storage, CFStorageNode *node)) { + __CFStorageApplyNodeBlockInterior(storage, &storage->rootNode, block); +} + +static CFIndex __CFStorageEstimateTotalAllocatedSize(CFStorageRef storage) __attribute__((unused)); +static CFIndex __CFStorageEstimateTotalAllocatedSize(CFStorageRef storage) { + __block CFIndex nodeResult = 0; + __block CFIndex contentsResult = 0; + __CFStorageApplyNodeBlock(storage, ^(CFStorageRef storage, CFStorageNode *node) { + if (node != &storage->rootNode) { + nodeResult += malloc_size(node); + if (node->isLeaf && node->info.leaf.memory != NULL) { + contentsResult += malloc_size(node->info.leaf.memory); + } + } + }); + return nodeResult + contentsResult; +} + +void __CFStorageSetAlwaysFrozen(CFStorageRef storage, bool alwaysFrozen) { + storage->alwaysFrozen = alwaysFrozen; +} + +static CFIndex __CFStorageCheckNodeCachedLengthIntegrity(ConstCFStorageRef storage, const CFStorageNode *node) { + if (node->isLeaf) { + ASSERT(node->numBytes > 0 || node == &storage->rootNode); + return node->numBytes; + } else { + /* Branch */ + CFStorageNode *childNode; + CFIndex expectedResult = __CFStorageCheckNodeCachedLengthIntegrity(storage, node->info.notLeaf.child[0]); + if ((childNode = node->info.notLeaf.child[1])) { + expectedResult += __CFStorageCheckNodeCachedLengthIntegrity(storage, childNode); + if ((childNode = node->info.notLeaf.child[2])) { + expectedResult += __CFStorageCheckNodeCachedLengthIntegrity(storage, childNode); + } + } + ASSERT(expectedResult == node->numBytes); + return expectedResult; + } +} + +static void __CFStorageCheckNodeIntegrity(ConstCFStorageRef storage, const CFStorageNode *node) { + ASSERT(node->isFrozen == 0 || node->isFrozen == 1); + + __CFStorageCheckNodeCachedLengthIntegrity(storage, node); + /* If we are a branch, make sure that we have at least one child, and that there is not a non-NULL child after a NULL child */ + if (! node->isLeaf) { + ASSERT(node->info.notLeaf.child[0] != NULL); + if (node->info.notLeaf.child[1] == NULL) ASSERT(node->info.notLeaf.child[2] == NULL); + } +} + +static void __CFStorageCheckIntegrity(CFStorageRef storage) { + __CFStorageApplyNodeBlock(storage, ^(CFStorageRef storage, CFStorageNode *node) { + __CFStorageCheckNodeIntegrity(storage, node); + }); +} + /* Used by CFArray.c */ static void __CFStorageNodeSetUnscanned(CFStorageNode *node, auto_zone_t *zone) { @@ -781,7 +1473,7 @@ static void __CFStorageNodeSetUnscanned(CFStorageNode *node, auto_zone_t *zone) __private_extern__ void _CFStorageSetWeak(CFStorageRef storage) { storage->nodeHint = 0; - __CFStorageNodeSetUnscanned(&storage->rootNode, (auto_zone_t *)auto_zone()); + __CFStorageNodeSetUnscanned(&storage->rootNode, (auto_zone_t *)objc_collectableZone()); } #undef COPYMEM diff --git a/CFStorage.h b/CFStorage.h index 86db40f..fef9800 100644 --- a/CFStorage.h +++ b/CFStorage.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFStorage.h - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. */ /*! @header CFStorage @@ -52,6 +52,11 @@ storage was a single block. #include +enum { + kCFStorageEnumerationConcurrent = (1UL << 0) /* Allow enumeration to proceed concurrently */ +}; +typedef CFOptionFlags CFStorageEnumerationOptionFlags; + CF_EXTERN_C_BEGIN /*! @@ -70,6 +75,21 @@ typedef struct __CFStorage *CFStorageRef; */ typedef void (*CFStorageApplierFunction)(const void *val, void *context); +/*! + @typedef CFStorageRangeApplierBlock + Type of the callback block used by the apply functions of + CFStorage + @param val A pointer to a range of values, numbering range.length + @param range The range of values. This will always be a subrange of the range + passed to the apply function. Do not try to modify the contents of the vals pointer, because + there is no guarantee it points into the contents of the CFStorage object. + @param stop An "out" parameter that, if set to true from within the block, indicates that the enumeration may stop. + +*/ +#if __BLOCKS__ +typedef void (^CFStorageApplierBlock)(const void *vals, CFRange range, bool *stop); +#endif + /*! @function CFStorageGetTypeID Returns the type identifier of all CFStorage instances. @@ -85,8 +105,8 @@ CF_EXPORT CFTypeID CFStorageGetTypeID(void); CFAllocator is used. If this reference is not a valid CFAllocator, the behavior is undefined. @param valueSizeInBytes The size in bytes of each of the elements - to be stored in the storage. If this value is zero or - negative, the result is undefined. + to be stored in the storage. If this value is zero or + negative, the result is undefined. @result A reference to the new CFStorage instance. */ CF_EXPORT CFStorageRef CFStorageCreate(CFAllocatorRef alloc, CFIndex valueSizeInBytes); @@ -94,16 +114,17 @@ CF_EXPORT CFStorageRef CFStorageCreate(CFAllocatorRef alloc, CFIndex valueSizeIn /*! @function CFStorageInsertValues Allocates space for range.length values at location range.location. Use - CFStorageReplaceValues() to set those values. + CFStorageReplaceValues() to set those values. @param storage The storage to which the values are to be inserted. - If this parameter is not a valid CFStorage, the behavior is undefined. - @param range The range of values within the storage to delete. If the - range location or end point (defined by the location plus - length minus 1) are outside the index space of the storage (0 - to N inclusive, where N is the count of the storage), the - behavior is undefined. If the range length is negative, the - behavior is undefined. The range may be empty (length 0), - in which case the no values are inserted. + If this parameter is not a valid CFStorage, the behavior is undefined. + @param range The range of values within the storage to insert. The + range location must be at least zero and not exceed the count of the storage. + Values at indexes equal to or greater than the range location have their indexes + increased by the length of the range. Thus this creates a gap in the storage + equal to the length of the given range. If the range length is negative, the + behavior is undefined. The range may be empty (length 0), + in which case there is no effect. + */ CF_EXPORT void CFStorageInsertValues(CFStorageRef storage, CFRange range); @@ -111,14 +132,14 @@ CF_EXPORT void CFStorageInsertValues(CFStorageRef storage, CFRange range); @function CFStorageDeleteValues Deletes the values of the storage in the specified range. @param storage The storage from which the values are to be deleted. - If this parameter is not a valid CFStorage, the behavior is undefined. + If this parameter is not a valid CFStorage, the behavior is undefined. @param range The range of values within the storage to delete. If the range location or end point (defined by the location plus length minus 1) are outside the index space of the storage (0 to N inclusive, where N is the count of the storage), the behavior is undefined. If the range length is negative, the behavior is undefined. The range may be empty (length 0), - in which case the no values are deleted. + in which case no values are deleted. */ CF_EXPORT void CFStorageDeleteValues(CFStorageRef storage, CFRange range); @@ -132,24 +153,49 @@ CF_EXPORT void CFStorageDeleteValues(CFStorageRef storage, CFRange range); CF_EXPORT CFIndex CFStorageGetCount(CFStorageRef storage); /*! - @function CFStorageGetValueAtIndex - Returns a pointer to the specified value. The pointer is mutable and may be used to - get or set the value. + @function CFStorageGetValueAtIndex + Returns a pointer to the specified value. The pointer is mutable and may be used to + get or set the value. This is considered to be a mutating function, and so calling this + while accessing the CFStorage from another thread is undefined behavior, + even if you do not set a value. To access the CFStorage in a non-mutating + manner, use the more efficient CFStorageGetConstValueAtIndex(). @param storage The storage to be queried. If this parameter is not a valid CFStorage, the behavior is undefined. @param idx The index of the value to retrieve. If the index is outside the index space of the storage (0 to N-1 inclusive, where N is the count of the storage), the behavior is undefined. - @param validConsecutiveValueRange This parameter is a C pointer to a CFRange. - If NULL is specified, this argument is ignored; otherwise, the range - is set to the range of values that may be accessed via an offset from the result pointer. - The range location is set to the index of the lowest consecutive - value and the range length is set to the count of consecutive values. + @param validConsecutiveValueRange This parameter is a C pointer to a CFRange. + If NULL is specified, this argument is ignored; otherwise, the range + is set to the range of values that may be accessed via an offset from the result pointer. + The range location is set to the index of the lowest consecutive + value and the range length is set to the count of consecutive values. @result The value with the given index in the storage. */ CF_EXPORT void *CFStorageGetValueAtIndex(CFStorageRef storage, CFIndex idx, CFRange *validConsecutiveValueRange); +/*! + @function CFStorageGetConstValueAtIndex + Returns a pointer to the specified value. The pointer is immutable and may + only be used to get the value. This is not considered to be a mutating function, + so it is safe to call this concurrently with other non-mutating functions. Furthermore, + this is often more efficient than CFStorageGetValueAtIndex(), so it should be used + in preference to that function when possible. + @param storage The storage to be queried. If this parameter is not a + valid CFStorage, the behavior is undefined. + @param idx The index of the value to retrieve. If the index is + outside the index space of the storage (0 to N-1 inclusive, + where N is the count of the storage), the behavior is + undefined. + @param validConsecutiveValueRange This parameter is a C pointer to a CFRange. + If NULL is specified, this argument is ignored; otherwise, the range + is set to the range of values that may be accessed via an offset from the result pointer. + The range location is set to the index of the lowest consecutive + value and the range length is set to the count of consecutive values. + @result The value with the given index in the storage. +*/ +CF_EXPORT const void *CFStorageGetConstValueAtIndex(CFStorageRef storage, CFIndex idx, CFRange *validConsecutiveValueRange); + /*! @function CFStorageGetValues Fills the buffer with values from the storage. @@ -196,6 +242,43 @@ CF_EXPORT void CFStorageGetValues(CFStorageRef storage, CFRange range, void *val */ CF_EXPORT void CFStorageApplyFunction(CFStorageRef storage, CFRange range, CFStorageApplierFunction applier, void *context); +/*! + @function CFStorageApplyBlock + Enumerates ranges of stored objects with a block. + @param storage The storage to be operated upon. If this parameter is not + a valid CFStorage, the behavior is undefined. + @param range The range of values within the storage to operate on. If the + sum of the range location and length is larger than the + count of the storage, the behavior is undefined. If the + range location or length is negative, the behavior is undefined. + @param options Options controlling how the enumeration may proceed. + @param applier The callback block. The block is passed a pointer to + a buffer of contiguous objects in the storage, and the range of stored + values represented by the buffer. If the block modifies the + contents of the buffer, the behavior is undefined. If the block modifies + the contents of the CFStorage, the behavior is undefined. + + */ +#if __BLOCKS__ +CF_EXPORT void CFStorageApplyBlock(CFStorageRef storage, CFRange range, CFStorageEnumerationOptionFlags options, CFStorageApplierBlock applier); +#endif + + +/*! + @function CFStorageCreateWithSubrange + Returns a new CFStorage that contains a portion of an existing CFStorage. + @param storage The storage to be operated upon. If this parameter is not + a valid CFStorage, the behavior is undefined. + @param range The range of values within the storage to operate on. If the + sum of the range location and length is larger than the + count of the storage, the behavior is undefined. If the + range location or length is negative, the behavior is undefined. + @result A reference to a new CFStorage containing a byte-for-byte copy of + the objects in the range. This may use copy-on-write techniques + to allow efficient implementation. + */ +CF_EXPORT CFStorageRef CFStorageCreateWithSubrange(CFStorageRef storage, CFRange range); + /*! @function CFStorageReplaceValues Replaces a range of values in the storage. @@ -211,10 +294,10 @@ CF_EXPORT void CFStorageApplyFunction(CFStorageRef storage, CFRange range, CFSto in which case the new values are merely inserted at the range location. @param values A C array of the values to be copied into the storage. - The new values in the storage are ordered in the same order - in which they appear in this C array. This parameter may be NULL - if the range length is 0. This C array is not changed or freed by - this function. If this parameter is not a valid pointer to a C array of at least + The new values in the storage are ordered in the same order + in which they appear in this C array. This parameter may be NULL + if the range length is 0. This C array is not changed or freed by + this function. If this parameter is not a valid pointer to a C array of at least range length pointers, the behavior is undefined. */ CF_EXPORT void CFStorageReplaceValues(CFStorageRef storage, CFRange range, const void *values); @@ -223,6 +306,7 @@ CF_EXPORT void CFStorageReplaceValues(CFStorageRef storage, CFRange range, const */ CF_EXPORT CFIndex __CFStorageGetCapacity(CFStorageRef storage); CF_EXPORT CFIndex __CFStorageGetValueSize(CFStorageRef storage); +CF_EXPORT void __CFStorageSetAlwaysFrozen(CFStorageRef storage, bool alwaysFrozen); CF_EXTERN_C_END diff --git a/CFStream.c b/CFStream.c index 0a2ba5e..e1468b3 100644 --- a/CFStream.c +++ b/CFStream.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFStream.c - Copyright (c) 2000-2009, Apple Inc. All rights reserved. - Responsibility: Becky Willrich + Copyright (c) 2000-2011, Apple Inc. All rights reserved. + Responsibility: John Iarocci */ #include @@ -33,8 +33,13 @@ #include "CFInternal.h" #include +#if defined(DEBUG) +#include +#endif + struct CFStreamAux { CFSpinLock_t streamLock; + CFArrayRef previousRunloopsAndModes; }; enum { @@ -76,15 +81,26 @@ __private_extern__ CFStreamStatus _CFStreamGetStatus(struct _CFStream *stream); static Boolean _CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndModes, CFRunLoopRef rl, CFStringRef mode); static void _wakeUpRunLoop(struct _CFStream *stream); +CF_INLINE void checkRLMArray(CFArrayRef arr) +{ +#if defined(DEBUG) + assert(arr == NULL || (CFArrayGetCount(arr) % 2) == 0); +#endif +} + CF_INLINE void* _CFStreamCreateReserved(CFAllocatorRef alloc) { struct CFStreamAux* aux = (struct CFStreamAux*) CFAllocatorAllocate(alloc, sizeof(struct CFStreamAux), 0); if (aux) { aux->streamLock = CFSpinLockInit; + aux->previousRunloopsAndModes = NULL; } return aux; } CF_INLINE void _CFStreamDestroyReserved(CFAllocatorRef alloc, void* aux) { + struct CFStreamAux* paux = (struct CFStreamAux*) aux; + if (paux->previousRunloopsAndModes) + CFRelease(paux->previousRunloopsAndModes); CFAllocatorDeallocate(alloc, aux); } @@ -665,41 +681,76 @@ static void _cfstream_shared_signalEventSync(void* info) } } -// Largely cribbed from CFSocket.c; find a run loop where our source is scheduled and wake it up. We skip the runloop cycling, so we -// are likely to signal the same run loop over and over again. Don't know if we should worry about that. -static void _wakeUpRunLoop(struct _CFStream *stream) { - CFRunLoopRef rl = NULL; - SInt32 idx, cnt; - CFArrayRef rlArray; - if (!stream->client || !stream->client->runLoopsAndModes) return; - rlArray = stream->client->runLoopsAndModes; - cnt = CFArrayGetCount(rlArray); - if (cnt == 0) return; - if (cnt == 2) { - rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, 0); - } else { - rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, 0); - for (idx = 2; NULL != rl && idx < cnt; idx+=2) { - CFRunLoopRef value = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, idx); - if (value != rl) rl = NULL; +/* This routine is to be considered unsafe... */ +static CFArrayRef _CFStreamGetRunLoopsAndModes(struct _CFStream *stream) +{ + CFArrayRef result = NULL; + if (stream && stream->client) { + _CFStreamLock(stream); + struct CFStreamAux* aux = _CFStreamGetAuxRecord(stream); + if (aux->previousRunloopsAndModes) { + CFRelease(aux->previousRunloopsAndModes); + aux->previousRunloopsAndModes = NULL; } - if (NULL == rl) { /* more than one different rl, so we must pick one */ - for (idx = 0; idx < cnt; idx+=2) { + if (stream->client->runLoopsAndModes) { + aux->previousRunloopsAndModes = CFArrayCreateCopy(CFGetAllocator(stream), stream->client->runLoopsAndModes); + } + result = aux->previousRunloopsAndModes; + checkRLMArray(result); + _CFStreamUnlock(stream); + } + return result; +} + +static CFArrayRef _CFStreamCopyRunLoopsAndModes(struct _CFStream *stream) +{ + CFArrayRef result = NULL; + if (stream && stream->client) { + _CFStreamLock(stream); + if (stream->client->runLoopsAndModes) { + result = CFArrayCreateCopy(CFGetAllocator(stream), stream->client->runLoopsAndModes); + } + checkRLMArray(result); + _CFStreamUnlock(stream); + } + return result; +} + +static void _wakeUpRunLoop(struct _CFStream *stream) { + CFArrayRef rlArray = _CFStreamCopyRunLoopsAndModes(stream); + if (rlArray) { + CFIndex cnt = CFArrayGetCount(rlArray); + CFRunLoopRef rl; + + if (cnt == 2) { + rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, 0); + } else if (cnt > 2) { + CFIndex idx; + rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, 0); + for (idx = 2; NULL != rl && idx < cnt; idx+=2) { CFRunLoopRef value = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, idx); - CFStringRef currentMode = CFRunLoopCopyCurrentMode(value); - if (NULL != currentMode && CFEqual(currentMode, CFArrayGetValueAtIndex(rlArray, idx+1)) && CFRunLoopIsWaiting(value)) { - CFRelease(currentMode); - rl = value; - break; - } - if (NULL != currentMode) CFRelease(currentMode); + if (value != rl) rl = NULL; } - if (NULL == rl) { /* didn't choose one above, so choose first */ - rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, 0); + if (NULL == rl) { /* more than one different rl, so we must pick one */ + for (idx = 0; idx < cnt; idx+=2) { + CFRunLoopRef value = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, idx); + CFStringRef currentMode = CFRunLoopCopyCurrentMode(value); + if (NULL != currentMode && CFEqual(currentMode, CFArrayGetValueAtIndex(rlArray, idx+1)) && CFRunLoopIsWaiting(value)) { + CFRelease(currentMode); + rl = value; + break; + } + if (NULL != currentMode) CFRelease(currentMode); + } + if (NULL == rl) { /* didn't choose one above, so choose first */ + rl = (CFRunLoopRef)CFArrayGetValueAtIndex(rlArray, 0); + } } } + if (NULL != rl && CFRunLoopIsWaiting(rl)) + CFRunLoopWakeUp(rl); } - if (NULL != rl && CFRunLoopIsWaiting(rl)) CFRunLoopWakeUp(rl); + CFRelease(rlArray); } __private_extern__ void _CFStreamSignalEvent(struct _CFStream *stream, CFStreamEventType event, CFErrorRef error, Boolean synchronousAllowed) { @@ -1398,12 +1449,15 @@ __private_extern__ void _CFStreamScheduleWithRunLoop(struct _CFStream *stream, C } } + _CFStreamLock(stream); if (!stream->client->runLoopsAndModes) { stream->client->runLoopsAndModes = CFArrayCreateMutable(CFGetAllocator(stream), 0, &kCFTypeArrayCallBacks); } CFArrayAppendValue(stream->client->runLoopsAndModes, runLoop); CFArrayAppendValue(stream->client->runLoopsAndModes, runLoopMode); - + checkRLMArray(stream->client->runLoopsAndModes); + _CFStreamUnlock(stream); + if (cb->schedule) { __CFBitSet(stream->flags, CALLING_CLIENT); cb->schedule(stream, runLoop, runLoopMode, _CFStreamGetInfoPointer(stream)); @@ -1480,7 +1534,10 @@ __private_extern__ void _CFStreamUnscheduleFromRunLoop(struct _CFStream *stream, __CFSpinUnlock(&sSourceLock); } + _CFStreamLock(stream); _CFStreamRemoveRunLoopAndModeFromArray(stream->client->runLoopsAndModes, runLoop, runLoopMode); + checkRLMArray(stream->client->runLoopsAndModes); + _CFStreamUnlock(stream); if (cb->unschedule) { cb->unschedule(stream, runLoop, runLoopMode, _CFStreamGetInfoPointer(stream)); @@ -1508,11 +1565,6 @@ static void waitForOpen(struct _CFStream *stream) { _CFStreamUnscheduleFromRunLoop(stream, runLoop, privateMode); } -CF_INLINE CFArrayRef _CFStreamGetRunLoopsAndModes(struct _CFStream *stream) { - if (stream->client) return stream->client->runLoopsAndModes; - else return NULL; -} - CF_EXPORT CFArrayRef _CFReadStreamGetRunLoopsAndModes(CFReadStreamRef readStream) { return _CFStreamGetRunLoopsAndModes((struct _CFStream *)readStream); } @@ -1521,6 +1573,14 @@ CF_EXPORT CFArrayRef _CFWriteStreamGetRunLoopsAndModes(CFWriteStreamRef writeStr return _CFStreamGetRunLoopsAndModes((struct _CFStream *)writeStream); } +CF_EXPORT CFArrayRef _CFReadStreamCopyRunLoopsAndModes(CFReadStreamRef readStream) { + return _CFStreamCopyRunLoopsAndModes((struct _CFStream *)readStream); +} + +CF_EXPORT CFArrayRef _CFWriteStreamCopyRunLoopsAndModes(CFWriteStreamRef writeStream) { + return _CFStreamCopyRunLoopsAndModes((struct _CFStream *)writeStream); +} + CF_EXPORT void CFReadStreamSignalEvent(CFReadStreamRef stream, CFStreamEventType event, const void *error) { _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, TRUE); } @@ -1558,6 +1618,8 @@ void _CFStreamSourceScheduleWithRunLoop(CFRunLoopSourceRef source, CFMutableArra CFIndex count; CFRange range; + checkRLMArray(runLoopsAndModes); + count = CFArrayGetCount(runLoopsAndModes); range = CFRangeMake(0, count); @@ -1594,6 +1656,8 @@ void _CFStreamSourceUnscheduleFromRunLoop(CFRunLoopSourceRef source, CFMutableAr count = CFArrayGetCount(runLoopsAndModes); range = CFRangeMake(0, count); + checkRLMArray(runLoopsAndModes); + while (range.length) { CFIndex i = CFArrayGetFirstIndexOfValue(runLoopsAndModes, range, runLoop); @@ -1629,6 +1693,8 @@ void _CFStreamSourceScheduleWithAllRunLoops(CFRunLoopSourceRef source, CFArrayRe if (!source) return; + checkRLMArray(runLoopsAndModes); + for (i = 0; i < count; i += 2) { // Make sure it's scheduled on all the right loops and modes. @@ -1648,6 +1714,8 @@ void _CFStreamSourceUncheduleFromAllRunLoops(CFRunLoopSourceRef source, CFArrayR if (!source) return; + checkRLMArray(runLoopsAndModes); + for (i = 0; i < count; i += 2) { // Go through the array removing the source from all loops and modes. @@ -1663,6 +1731,8 @@ Boolean _CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndMode if (!runLoopsAndModes) return FALSE; + checkRLMArray(runLoopsAndModes); + cnt = CFArrayGetCount(runLoopsAndModes); for (idx = 0; idx + 1 < cnt; idx += 2) { if (CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes, idx), rl) && CFEqual(CFArrayGetValueAtIndex(runLoopsAndModes, idx + 1), mode)) { diff --git a/CFStream.h b/CFStream.h index e22f496..8084ae1 100644 --- a/CFStream.h +++ b/CFStream.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFStream.h - Copyright (c) 2000-2009, Apple Inc. All rights reserved. + Copyright (c) 2000-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSTREAM__) @@ -105,17 +105,13 @@ CFWriteStreamRef CFWriteStreamCreateWithFile(CFAllocatorRef alloc, CFURLRef file CF_EXPORT void CFStreamCreateBoundPair(CFAllocatorRef alloc, CFReadStreamRef *readStream, CFWriteStreamRef *writeStream, CFIndex transferBufferSize); -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED /* Property for file write streams; value should be a CFBoolean. Set to TRUE to append to a file, rather than to replace its contents */ CF_EXPORT const CFStringRef kCFStreamPropertyAppendToFile; -#endif -#if MAC_OS_X_VERSION_10_3 <= MAC_OS_X_VERSION_MAX_ALLOWED - -CF_EXPORT const CFStringRef kCFStreamPropertyFileCurrentOffset AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; // Value is a CFNumber +CF_EXPORT +const CFStringRef kCFStreamPropertyFileCurrentOffset; // Value is a CFNumber -#endif /* Socket stream properties */ @@ -136,10 +132,8 @@ CF_EXPORT void CFStreamCreatePairWithSocket(CFAllocatorRef alloc, CFSocketNativeHandle sock, CFReadStreamRef *readStream, CFWriteStreamRef *writeStream); CF_EXPORT void CFStreamCreatePairWithSocketToHost(CFAllocatorRef alloc, CFStringRef host, UInt32 port, CFReadStreamRef *readStream, CFWriteStreamRef *writeStream); -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED CF_EXPORT void CFStreamCreatePairWithPeerSocketSignature(CFAllocatorRef alloc, const CFSocketSignature *signature, CFReadStreamRef *readStream, CFWriteStreamRef *writeStream); -#endif /* Returns the current state of the stream */ @@ -150,9 +144,9 @@ CFStreamStatus CFWriteStreamGetStatus(CFWriteStreamRef stream); /* Returns NULL if no error has occurred; otherwise returns the error. */ CF_EXPORT -CFErrorRef CFReadStreamCopyError(CFReadStreamRef stream) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFErrorRef CFReadStreamCopyError(CFReadStreamRef stream) CF_AVAILABLE(10_5, 2_0); CF_EXPORT -CFErrorRef CFWriteStreamCopyError(CFWriteStreamRef stream) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFErrorRef CFWriteStreamCopyError(CFWriteStreamRef stream) CF_AVAILABLE(10_5, 2_0); /* Returns success/failure. Opening a stream causes it to reserve all the system resources it requires. If the stream can open non-blocking, this will always @@ -225,14 +219,12 @@ CFTypeRef CFReadStreamCopyProperty(CFReadStreamRef stream, CFStringRef propertyN CF_EXPORT CFTypeRef CFWriteStreamCopyProperty(CFWriteStreamRef stream, CFStringRef propertyName); -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED /* Returns TRUE if the stream recognizes and accepts the given property-value pair; FALSE otherwise. */ CF_EXPORT Boolean CFReadStreamSetProperty(CFReadStreamRef stream, CFStringRef propertyName, CFTypeRef propertyValue); CF_EXPORT Boolean CFWriteStreamSetProperty(CFWriteStreamRef stream, CFStringRef propertyName, CFTypeRef propertyValue); -#endif /* Asynchronous processing - If you wish to neither poll nor block, you may register a client to hear about interesting events that occur on a stream. Only one client diff --git a/CFStreamAbstract.h b/CFStreamAbstract.h index bf12c92..28c9412 100644 --- a/CFStreamAbstract.h +++ b/CFStreamAbstract.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFStreamAbstract.h - Copyright (c) 2000-2009, Apple Inc. All rights reserved. + Copyright (c) 2000-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSTREAMABSTRACT__) @@ -134,11 +134,18 @@ CF_EXPORT void *_CFWriteStreamGetClient(CFWriteStreamRef writeStream); // Returns an array of the runloops and modes on which the stream is currently scheduled +// Note that these are unretained mutable arrays - use the copy variant instead. CF_EXPORT CFArrayRef _CFReadStreamGetRunLoopsAndModes(CFReadStreamRef readStream); CF_EXPORT CFArrayRef _CFWriteStreamGetRunLoopsAndModes(CFWriteStreamRef writeStream); +// Returns an array of the runloops and modes on which the stream is currently scheduled +CF_EXPORT +CFArrayRef _CFReadStreamCopyRunLoopsAndModes(CFReadStreamRef readStream); +CF_EXPORT +CFArrayRef _CFWriteStreamCopyRunLoopsAndModes(CFWriteStreamRef writeStream); + /* Deprecated versions; here for backwards compatibility. */ typedef struct { CFIndex version; /* == 1 */ diff --git a/CFStreamInternal.h b/CFStreamInternal.h index e657b26..8b37ba9 100644 --- a/CFStreamInternal.h +++ b/CFStreamInternal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/CFStreamPriv.h b/CFStreamPriv.h index b7827ca..dcbb262 100644 --- a/CFStreamPriv.h +++ b/CFStreamPriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFStreamPriv.h - Copyright (c) 2000-2009, Apple Inc. All rights reserved. + Copyright (c) 2000-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSTREAMPRIV__) diff --git a/CFString.c b/CFString.c index 69c9db7..5bf618e 100644 --- a/CFString.c +++ b/CFString.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFString.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Ali Ozer !!! For performance reasons, it's important that all functions marked CF_INLINE in this file are inlined. @@ -36,6 +36,7 @@ #include #include #include +#include #include "CFInternal.h" #include "CFLocaleInternal.h" #include @@ -44,9 +45,6 @@ #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD #include #endif -#if DEPLOYMENT_TARGET_WINDOWS -#define strncasecmp_l(a, b, c, d) _strnicmp(a, b, c) -#endif #if defined(__GNUC__) #define LONG_DOUBLE_SUPPORT 1 @@ -111,6 +109,8 @@ extern size_t malloc_good_size(size_t size); #endif extern void __CFStrConvertBytesToUnicode(const uint8_t *bytes, UniChar *buffer, CFIndex numChars); +static void __CFStringAppendFormatCore(CFMutableStringRef outputString, CFStringRef (*copyDescFunc)(void *, const void *), CFDictionaryRef formatOptions, CFStringRef formatString, CFIndex initialArgPosition, const void *origValues, CFIndex originalValuesSize, va_list args); + #if defined(DEBUG) // We put this into C & Pascal strings if we can't convert @@ -127,8 +127,6 @@ static Boolean __CFConstantStringTableBeingFreed = false; static CFOptionFlags _CFStringCompatibilityMask = 0; -#define Bug2967272 1 - void _CFStringSetCompatibility(CFOptionFlags mask) { _CFStringCompatibilityMask |= mask; } @@ -282,8 +280,10 @@ CF_INLINE CFAllocatorRef __CFStrContentsDeallocator(CFStringRef str) { } // Assumption: Called with immutable strings only, and on strings that are known to have a contentsDeallocator -CF_INLINE void __CFStrSetContentsDeallocator(CFStringRef str, CFAllocatorRef contentsAllocator) { - *__CFStrContentsDeallocatorPtr(str) = contentsAllocator; +CF_INLINE void __CFStrSetContentsDeallocator(CFStringRef str, CFAllocatorRef allocator) { + allocator = kCFUseCollectableAllocator ? allocator : _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator); + if (!(kCFAllocatorSystemDefaultGCRefZero == allocator || kCFAllocatorDefaultGCRefZero == allocator)) CFRetain(allocator); + *__CFStrContentsDeallocatorPtr(str) = allocator; } static CFAllocatorRef *__CFStrContentsAllocatorPtr(CFStringRef str) { @@ -298,8 +298,10 @@ CF_INLINE CFAllocatorRef __CFStrContentsAllocator(CFMutableStringRef str) { } // Assumption: Called with strings that have a contents allocator; also, contents allocator follows custom -CF_INLINE void __CFStrSetContentsAllocator(CFMutableStringRef str, CFAllocatorRef alloc) { - *(__CFStrContentsAllocatorPtr(str)) = alloc; +CF_INLINE void __CFStrSetContentsAllocator(CFMutableStringRef str, CFAllocatorRef allocator) { + allocator = kCFUseCollectableAllocator ? allocator : _CFConvertAllocatorToNonGCRefZeroEquivalent(allocator); + if (!(kCFAllocatorSystemDefaultGCRefZero == allocator || kCFAllocatorDefaultGCRefZero == allocator)) CFRetain(allocator); + *(__CFStrContentsAllocatorPtr(str)) = allocator; } /* Returns length; use __CFStrLength2 if contents buffer pointer has already been computed. @@ -387,9 +389,11 @@ static void *__CFStrAllocateMutableContents(CFMutableStringRef str, CFIndex size static void __CFStrDeallocateMutableContents(CFMutableStringRef str, void *buffer) { CFAllocatorRef alloc = (__CFStrHasContentsAllocator(str)) ? __CFStrContentsAllocator(str) : __CFGetAllocator(str); - if (CF_IS_COLLECTABLE_ALLOCATOR(alloc)) { + if (__CFStrIsMutable(str) && __CFStrHasContentsAllocator(str) && _CFAllocatorIsGCRefZero(alloc)) { + // do nothing + } else if (CF_IS_COLLECTABLE_ALLOCATOR(alloc)) { // GC: for finalization safety, let collector reclaim the buffer in the next GC cycle. - auto_zone_release(auto_zone(), buffer); + auto_zone_release(objc_collectableZone(), buffer); } else { CFAllocatorDeallocate(alloc, buffer); } @@ -416,7 +420,7 @@ static CFStringEncoding __CFDefaultFileSystemEncoding = kCFStringEncodingInvalid CFStringEncoding __CFDefaultEightBitStringEncoding = kCFStringEncodingInvalidId; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX #define __defaultEncoding kCFStringEncodingMacRoman #elif DEPLOYMENT_TARGET_WINDOWS #define __defaultEncoding kCFStringEncodingWindowsLatin1 @@ -458,11 +462,7 @@ CFStringEncoding CFStringFileSystemEncoding(void) { */ CFIndex CFStringGetMaximumSizeForEncoding(CFIndex length, CFStringEncoding encoding) { if (encoding == kCFStringEncodingUTF8) { - if (_CFExecutableLinkedOnOrAfter(CFSystemVersionPanther)) { // 1 Unichar can expand to 3 bytes; we return 6 for older apps for compatibility return (length > (LONG_MAX / 3)) ? kCFNotFound : (length * 3); - } else { - return (length > (LONG_MAX / 6)) ? kCFNotFound : (length * 6); - } } else if ((encoding == kCFStringEncodingUTF32) || (encoding == kCFStringEncodingUTF32BE) || (encoding == kCFStringEncodingUTF32LE)) { // UTF-32 return (length > (LONG_MAX / sizeof(UTF32Char))) ? kCFNotFound : (length * sizeof(UTF32Char)); } else { @@ -529,7 +529,27 @@ CFStringEncoding __CFStringComputeEightBitStringEncoding(void) { /* Returns whether the provided bytes can be stored in ASCII */ CF_INLINE Boolean __CFBytesInASCII(const uint8_t *bytes, CFIndex len) { - while (len--) if ((uint8_t)(*bytes++) >= 128) return false; +#if __LP64__ + /* Go by 8s in 64 bit */ + while (len >= 8) { + uint64_t val = *(const uint64_t *)bytes; + if (val & 0x8080808080808080ULL) return false; + bytes += 8; + len -= 8; + } +#endif + /* Go by 4s */ + while (len >= 4) { + uint32_t val = *(const uint32_t *)bytes; + if (val & 0x80808080U) return false; + bytes += 4; + len -= 4; + } + /* Handle the rest one byte at a time */ + while (len--) { + if (*bytes++ & 0x80) return false; + } + return true; } @@ -900,16 +920,19 @@ static void __CFStringDeallocate(CFTypeRef cf) { __CFStrDeallocateMutableContents((CFMutableStringRef)str, contents); } else { if (__CFStrHasContentsDeallocator(str)) { - CFAllocatorRef contentsDeallocator = __CFStrContentsDeallocator(str); - CFAllocatorDeallocate(contentsDeallocator, contents); - CFRelease(contentsDeallocator); + CFAllocatorRef allocator = __CFStrContentsDeallocator(str); + CFAllocatorDeallocate(allocator, contents); + if (!(kCFAllocatorSystemDefaultGCRefZero == allocator || kCFAllocatorDefaultGCRefZero == allocator)) CFRelease(allocator); } else { CFAllocatorRef alloc = __CFGetAllocator(str); CFAllocatorDeallocate(alloc, contents); } } } - if (isMutable && __CFStrHasContentsAllocator(str)) CFRelease(__CFStrContentsAllocator((CFMutableStringRef)str)); + if (isMutable && __CFStrHasContentsAllocator(str)) { + CFAllocatorRef allocator = __CFStrContentsAllocator((CFMutableStringRef)str); + if (!(kCFAllocatorSystemDefaultGCRefZero == allocator || kCFAllocatorDefaultGCRefZero == allocator)) CFRelease(allocator); + } } } @@ -1132,7 +1155,7 @@ static CFTypeID __kCFStringTypeID = _kCFRuntimeNotATypeID; typedef CFTypeRef (*CF_STRING_CREATE_COPY)(CFAllocatorRef alloc, CFTypeRef theString); static const CFRuntimeClass __CFStringClass = { - 0, + _kCFRuntimeScannedObject, "CFString", NULL, // init (CF_STRING_CREATE_COPY)CFStringCreateCopy, @@ -1208,7 +1231,7 @@ __private_extern__ CFStringRef __CFStringCreateImmutableFunnel3( contentsDeallocator = __CFGetDefaultAllocator(); } - if ((NULL != kCFEmptyString) && (numBytes == 0) && (alloc == kCFAllocatorSystemDefault)) { // If we are using the system default allocator, and the string is empty, then use the empty string! + if ((NULL != kCFEmptyString) && (numBytes == 0) && _CFAllocatorIsSystemDefault(alloc)) { // If we are using the system default allocator, and the string is empty, then use the empty string! if (noCopy && (contentsDeallocator != kCFAllocatorNull)) { // See 2365208... This change was done after Sonata; before we didn't free the bytes at all (leak). CFAllocatorDeallocate(contentsDeallocator, (void *)bytes); } @@ -1233,7 +1256,7 @@ __private_extern__ CFStringRef __CFStringCreateImmutableFunnel3( CFIndex realNumBytes = numBytes - (hasLengthByte ? 1 : 0); Boolean usingPassedInMemory = false; - vBuf.allocator = __CFGetDefaultAllocator(); // We don't want to use client's allocator for temp stuff + vBuf.allocator = kCFAllocatorSystemDefault; // We don't want to use client's allocator for temp stuff vBuf.chars.unicode = NULL; // This will cause the decode function to allocate memory if necessary if (!__CFStringDecodeByteStream3((const uint8_t *)realBytes, realNumBytes, encoding, false, &vBuf, &usingPassedInMemory, converterFlags)) { @@ -1379,7 +1402,8 @@ __private_extern__ CFStringRef __CFStringCreateImmutableFunnel3( if (noCopy) { size = sizeof(void *); // Pointer to the buffer - if (contentsDeallocator != alloc && contentsDeallocator != kCFAllocatorNull) { + // special GCRefZero allocator usage always needs saving + if (_CFAllocatorIsGCRefZero(contentsDeallocator) || (contentsDeallocator != alloc && contentsDeallocator != kCFAllocatorNull)) { size += sizeof(void *); // The contentsDeallocator } if (!hasLengthByte) size += sizeof(CFIndex); // Explicit length @@ -1421,8 +1445,9 @@ __private_extern__ CFStringRef __CFStringCreateImmutableFunnel3( if (str) { if (__CFOASafe) __CFSetLastAllocationEventName(str, "CFString (immutable)"); + CFOptionFlags allocBits = _CFAllocatorIsGCRefZero(contentsDeallocator) ? __kCFHasContentsDeallocator : (contentsDeallocator == alloc ? __kCFNotInlineContentsDefaultFree : (contentsDeallocator == kCFAllocatorNull ? __kCFNotInlineContentsNoFree : __kCFNotInlineContentsCustomFree)); __CFStrSetInfoBits(str, - (useInlineData ? __kCFHasInlineContents : (contentsDeallocator == alloc ? __kCFNotInlineContentsDefaultFree : (contentsDeallocator == kCFAllocatorNull ? __kCFNotInlineContentsNoFree : __kCFNotInlineContentsCustomFree))) | + (useInlineData ? __kCFHasInlineContents : allocBits) | ((encoding == kCFStringEncodingUnicode) ? __kCFIsUnicode : 0) | (useNullByte ? __kCFHasNullByte : 0) | (useLengthByte ? __kCFHasLengthByte : 0)); @@ -1440,7 +1465,7 @@ __private_extern__ CFStringRef __CFStringCreateImmutableFunnel3( if (useNullByte) contents[numBytes] = 0; } else { __CFStrSetContentPtr(str, bytes); - if (contentsDeallocator != alloc && contentsDeallocator != kCFAllocatorNull) __CFStrSetContentsDeallocator(str, (CFAllocatorRef)CFRetain(contentsDeallocator)); + if (__CFStrHasContentsDeallocator(str)) __CFStrSetContentsDeallocator(str, contentsDeallocator); } } else { if (noCopy && (contentsDeallocator != kCFAllocatorNull)) { @@ -1515,9 +1540,9 @@ CFStringRef CFStringCreateWithFormatAndArguments(CFAllocatorRef alloc, CFDictio CFStringRef _CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc, CFStringRef (*copyDescFunc)(void *, const void *), CFDictionaryRef formatOptions, CFStringRef format, va_list arguments) { CFStringRef str; - CFMutableStringRef outputString = CFStringCreateMutable(__CFGetDefaultAllocator(), 0); //should use alloc if no copy/release + CFMutableStringRef outputString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); //should use alloc if no copy/release __CFStrSetDesiredCapacity(outputString, 120); // Given this will be tightened later, choosing a larger working string is fine - _CFStringAppendFormatAndArgumentsAux(outputString, copyDescFunc, formatOptions, format, arguments); + __CFStringAppendFormatCore(outputString, copyDescFunc, formatOptions, format, 0, NULL, 0, arguments); // ??? copy/release should not be necessary here -- just make immutable, compress if possible // (However, this does make the string inline, and cause the supplied allocator to be used...) str = (CFStringRef)CFStringCreateCopy(alloc, outputString); @@ -1558,9 +1583,9 @@ CFStringRef CFStringCreateCopy(CFAllocatorRef alloc, CFStringRef str) { __CFAssertIsString(str); if (!__CFStrIsMutable((CFStringRef)str) && // If the string is not mutable - ((alloc ? alloc : __CFGetDefaultAllocator()) == __CFGetAllocator(str)) && // and it has the same allocator as the one we're using + ((alloc ? _CFConvertAllocatorToNonGCRefZeroEquivalent(alloc) : __CFGetDefaultAllocator()) == __CFGetAllocator(str)) && // and it has the same allocator as the one we're using (__CFStrIsInline((CFStringRef)str) || __CFStrFreeContentsWhenDone((CFStringRef)str) || __CFStrIsConstant((CFStringRef)str))) { // and the characters are inline, or are owned by the string, or the string is constant - CFRetain(str); // Then just retain instead of making a true copy + if (!(kCFUseCollectableAllocator && _CFAllocatorIsGCRefZero(alloc))) CFRetain(str); // Then just retain instead of making a true copy return str; } if (__CFStrIsEightBit((CFStringRef)str)) { @@ -1784,6 +1809,7 @@ CF_INLINE void __CFStringReplace(CFMutableStringRef str, CFRange range, CFString CF_INLINE CFMutableStringRef __CFStringCreateMutableFunnel(CFAllocatorRef alloc, CFIndex maxLength, UInt32 additionalInfoBits) { CFMutableStringRef str; + if (_CFAllocatorIsGCRefZero(alloc)) additionalInfoBits |= __kCFHasContentsAllocator; Boolean hasExternalContentsAllocator = (additionalInfoBits & __kCFHasContentsAllocator) ? true : false; if (alloc == NULL) alloc = __CFGetDefaultAllocator(); @@ -1800,6 +1826,10 @@ CF_INLINE CFMutableStringRef __CFStringCreateMutableFunnel(CFAllocatorRef alloc, if (maxLength != 0) __CFStrSetIsFixed(str); __CFStrSetDesiredCapacity(str, (maxLength == 0) ? DEFAULTMINCAPACITY : maxLength); __CFStrSetCapacity(str, 0); + if (__CFStrHasContentsAllocator(str)) { + // contents allocator starts out as the string's own allocator + __CFStrSetContentsAllocator(str, alloc); + } } return str; } @@ -1809,7 +1839,11 @@ CFMutableStringRef CFStringCreateMutableWithExternalCharactersNoCopy(CFAllocator CFMutableStringRef string = __CFStringCreateMutableFunnel(alloc, 0, contentsAllocationBits | __kCFIsUnicode); if (string) { __CFStrSetIsExternalMutable(string); - if (contentsAllocationBits == __kCFHasContentsAllocator) __CFStrSetContentsAllocator(string, (CFAllocatorRef)CFRetain(externalCharactersAllocator)); + if (__CFStrHasContentsAllocator(string)) { + CFAllocatorRef allocator = __CFStrContentsAllocator((CFMutableStringRef)string); + if (!(kCFAllocatorSystemDefaultGCRefZero == allocator || kCFAllocatorDefaultGCRefZero == allocator)) CFRelease(allocator); + __CFStrSetContentsAllocator(string, externalCharactersAllocator); + } CFStringSetExternalCharactersNoCopy(string, chars, numChars, capacity); } return string; @@ -1906,7 +1940,7 @@ CF_INLINE void __CFStringGetCharactersGuts(CFStringRef str, CFRange range, UniCh /* This one is for the CF API */ void CFStringGetCharacters(CFStringRef str, CFRange range, UniChar *buffer) { - CF_OBJC_FUNCDISPATCH2(__kCFStringTypeID, void, str, "getCharacters:range:", buffer, CFRangeMake(range.location, range.length)); + CF_OBJC_FUNCDISPATCH2(__kCFStringTypeID, void, str, "getCharacters:range:", buffer, range); __CFAssertIsString(str); __CFAssertRangeIsInStringBounds(str, range.location, range.length); @@ -2130,6 +2164,8 @@ static const char *_CFStrGetLanguageIdentifierForLocale(CFLocaleRef locale) { langID = "lt"; } else if (!strncmp(string, "tr", 2)) { // Turkish langID = "tr"; + } else if (!strncmp(string, "nl", 2)) { // Dutch + langID = "nl"; } } @@ -2144,12 +2180,9 @@ static const char *_CFStrGetLanguageIdentifierForLocale(CFLocaleRef locale) { return langID; } -static int8_t __CFCheckLocaleCFType = -1; - CF_INLINE bool _CFCanUseLocale(CFLocaleRef locale) { if (locale) { - if (__CFCheckLocaleCFType < 0) __CFCheckLocaleCFType = !_CFExecutableLinkedOnOrAfter(CFSystemVersionPanther); - if (!__CFCheckLocaleCFType || (CFGetTypeID(locale) == CFLocaleGetTypeID())) return true; + return true; } return false; } @@ -2384,7 +2417,7 @@ static bool __CFStringFillCharacterSetInlineBuffer(CFCharacterSetInlineBuffer *b static CFCharacterSetRef nonAlnumChars = NULL; if (NULL == nonAlnumChars) { - CFMutableCharacterSetRef cset = CFCharacterSetCreateMutableCopy(NULL, CFCharacterSetGetPredefined(kCFCharacterSetAlphaNumeric)); + CFMutableCharacterSetRef cset = CFCharacterSetCreateMutableCopy(kCFAllocatorSystemDefault, CFCharacterSetGetPredefined(kCFCharacterSetAlphaNumeric)); CFCharacterSetInvert(cset); if (!OSAtomicCompareAndSwapPtrBarrier(NULL, cset, (void **)&nonAlnumChars)) CFRelease(cset); } @@ -2422,6 +2455,7 @@ CFComparisonResult CFStringCompareWithOptionsAndLocale(CFStringRef string, CFStr Boolean freeLocale = false; CFCharacterSetInlineBuffer *ignoredChars = NULL; CFCharacterSetInlineBuffer csetBuffer; + bool numericEquivalence = false; if ((compareOptions & kCFCompareLocalized) && (NULL == locale)) { locale = CFLocaleCopyCurrent(); @@ -2464,8 +2498,10 @@ CFComparisonResult CFStringCompareWithOptionsAndLocale(CFStringRef string, CFStr if (str1Char != str2Char) { if ((str1Char < 0x80) && (str2Char < 0x80)) { if (forceOrdering && (kCFCompareEqualTo == compareResult) && (str1Char != str2Char)) compareResult = ((str1Char < str2Char) ? kCFCompareLessThan : kCFCompareGreaterThan); - if ((str1Char >= 'A') && (str1Char <= 'Z')) str1Char += ('a' - 'A'); - if ((str2Char >= 'A') && (str2Char <= 'Z')) str2Char += ('a' - 'A'); + if (caseInsensitive) { + if ((str1Char >= 'A') && (str1Char <= 'Z')) str1Char += ('a' - 'A'); + if ((str2Char >= 'A') && (str2Char <= 'Z')) str2Char += ('a' - 'A'); + } if (str1Char != str2Char) return ((str1Char < str2Char) ? kCFCompareLessThan : kCFCompareGreaterThan); } else { @@ -2543,12 +2579,8 @@ CFComparisonResult CFStringCompareWithOptionsAndLocale(CFStringRef string, CFStr if (numerically && ((0 == strBuf1Len) && (str1Char <= '9') && (str1Char >= '0')) && ((0 == strBuf2Len) && (str2Char <= '9') && (str2Char >= '0'))) { // If both are not ASCII digits, then don't do numerical comparison here uint64_t intValue1 = 0, intValue2 = 0; // !!! Doesn't work if numbers are > max uint64_t - - if (forceOrdering && (kCFCompareEqualTo == compareResult) && (str1Char != str2Char)) { - compareResult = ((str1Char < str2Char) ? kCFCompareLessThan : kCFCompareGreaterThan); - forcedIndex1 = str1Index; - forcedIndex2 = str2Index; - } + CFIndex str1NumRangeIndex = str1Index; + CFIndex str2NumRangeIndex = str2Index; do { intValue1 = (intValue1 * 10) + (str1Char - '0'); @@ -2561,6 +2593,13 @@ CFComparisonResult CFStringCompareWithOptionsAndLocale(CFStringRef string, CFStr } while ((str2Char <= '9') && (str2Char >= '0')); if (intValue1 == intValue2) { + if (forceOrdering && (kCFCompareEqualTo == compareResult) && ((str1Index - str1NumRangeIndex) != (str2Index - str2NumRangeIndex))) { + compareResult = (((str1Index - str1NumRangeIndex) < (str2Index - str2NumRangeIndex)) ? kCFCompareLessThan : kCFCompareGreaterThan); + numericEquivalence = true; + forcedIndex1 = str1NumRangeIndex; + forcedIndex2 = str2NumRangeIndex; + } + continue; } else if (intValue1 < intValue2) { if (freeLocale && locale) { @@ -2731,8 +2770,8 @@ CFComparisonResult CFStringCompareWithOptionsAndLocale(CFStringRef string, CFStr str2Index += ((str2Char < 0x10000) ? 1 : 2); } } - // Need to recalc localized result here for forced ordering - if ((NULL != locale) && (kCFCompareEqualTo != compareResult) && (str1Index == rangeToCompare.length) && (str2Index == str2Len)) compareResult = _CFCompareStringsWithLocale(&inlineBuf1, CFRangeMake(forcedIndex1, rangeToCompare.length - forcedIndex1), &inlineBuf2, CFRangeMake(forcedIndex2, str2Len - forcedIndex2), compareOptions, locale); + // Need to recalc localized result here for forced ordering, ICU cannot do numericEquivalence + if (!numericEquivalence && (NULL != locale) && (kCFCompareEqualTo != compareResult) && (str1Index == rangeToCompare.length) && (str2Index == str2Len)) compareResult = _CFCompareStringsWithLocale(&inlineBuf1, CFRangeMake(forcedIndex1, rangeToCompare.length - forcedIndex1), &inlineBuf2, CFRangeMake(forcedIndex2, str2Len - forcedIndex2), compareOptions, locale); if (freeLocale && locale) { CFRelease(locale); @@ -3054,7 +3093,7 @@ Boolean CFStringFindWithOptionsAndLocale(CFStringRef string, CFStringRef stringT if (strBuf1Len > 0) { match = false; - if ((compareOptions & kCFCompareDiacriticInsensitive) && (strBuf1[0] < 0x0510)) { + if (diacriticsInsensitive && (strBuf1[0] < 0x0510)) { while (strBuf1Index < strBuf1Len) { if (!CFUniCharIsMemberOfBitmap(strBuf1[strBuf1Index], ((strBuf1[strBuf1Index] < 0x10000) ? graphemeBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet, (strBuf1[strBuf1Index] >> 16))))) break; ++strBuf1Index; @@ -3204,7 +3243,8 @@ CFArrayRef CFStringCreateArrayWithFindResults(CFAllocatorRef alloc, CFStringRef // If necessary, grow the data and squirrel away the found range if (foundCount >= capacity) { - if (rangeStorage == NULL) rangeStorage = CFDataCreateMutable(alloc, 0); + // Note that rangeStorage is not allowed to be allocated from one of the GCRefZero allocators + if (rangeStorage == NULL) rangeStorage = CFDataCreateMutable(_CFConvertAllocatorToNonGCRefZeroEquivalent(alloc), 0); capacity = (capacity + 4) * 2; CFDataSetLength(rangeStorage, capacity * (sizeof(CFRange) + sizeof(CFDataRef))); rangeStorageBytes = (uint8_t *)CFDataGetMutableBytePtr(rangeStorage) + foundCount * (sizeof(CFRange) + sizeof(CFDataRef)); @@ -3301,7 +3341,7 @@ static CFRange _CFStringInlineBufferGetComposedRange(CFStringInlineBuffer *buffe if (CFUniCharIsSurrogateLowCharacter(character) && CFUniCharIsSurrogateHighCharacter((otherSurrogate = CFStringGetCharacterFromInlineBuffer(buffer, start - 1)))) { character = CFUniCharGetLongCharacterForSurrogatePair(otherSurrogate, character); bitmap = CFUniCharGetBitmapPtrForPlane(csetType, (character >> 16)); - --start; + if (--start == 0) break; // starting with non-BMP combining mark } else { bitmap = bmpBitmap; } @@ -3432,7 +3472,7 @@ CFRange CFStringGetRangeOfCharacterClusterAtIndex(CFStringRef string, CFIndex ch CFStringInlineBuffer stringBuffer; const uint8_t *bmpBitmap; const uint8_t *letterBMP; - const uint8_t *combClassBMP; + static const uint8_t *combClassBMP = NULL; UTF32Char character; UTF16Char otherSurrogate; @@ -3444,7 +3484,7 @@ CFRange CFStringGetRangeOfCharacterClusterAtIndex(CFStringRef string, CFIndex ch bmpBitmap = CFUniCharGetBitmapPtrForPlane(csetType, 0); letterBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharLetterCharacterSet, 0); - combClassBMP = (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, 0); + if (NULL == combClassBMP) combClassBMP = (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, 0); CFStringInitInlineBuffer(string, &stringBuffer, CFRangeMake(0, length)); @@ -3749,12 +3789,12 @@ static void __CFStringGetLineOrParagraphBounds(CFStringRef string, CFRange range } void CFStringGetLineBounds(CFStringRef string, CFRange range, CFIndex *lineBeginIndex, CFIndex *lineEndIndex, CFIndex *contentsEndIndex) { - CF_OBJC_FUNCDISPATCH4(__kCFStringTypeID, void, string, "getLineStart:end:contentsEnd:forRange:", lineBeginIndex, lineEndIndex, contentsEndIndex, CFRangeMake(range.location, range.length)); + CF_OBJC_FUNCDISPATCH4(__kCFStringTypeID, void, string, "getLineStart:end:contentsEnd:forRange:", lineBeginIndex, lineEndIndex, contentsEndIndex, range); __CFStringGetLineOrParagraphBounds(string, range, lineBeginIndex, lineEndIndex, contentsEndIndex, true); } void CFStringGetParagraphBounds(CFStringRef string, CFRange range, CFIndex *parBeginIndex, CFIndex *parEndIndex, CFIndex *contentsEndIndex) { - CF_OBJC_FUNCDISPATCH4(__kCFStringTypeID, void, string, "getParagraphStart:end:contentsEnd:forRange:", parBeginIndex, parEndIndex, contentsEndIndex, CFRangeMake(range.location, range.length)); + CF_OBJC_FUNCDISPATCH4(__kCFStringTypeID, void, string, "getParagraphStart:end:contentsEnd:forRange:", parBeginIndex, parEndIndex, contentsEndIndex, range); __CFStringGetLineOrParagraphBounds(string, range, parBeginIndex, parEndIndex, contentsEndIndex, false); } @@ -3784,7 +3824,7 @@ CFStringRef CFStringCreateByCombiningStrings(CFAllocatorRef alloc, CFArrayRef ar otherString = (CFStringRef)CFArrayGetValueAtIndex(array, idx); numChars += CFStringGetLength(otherString); // canBeEightbit is already false if the separator is an NSString... - if (!CF_IS_OBJC(__kCFStringTypeID, otherString) && __CFStrIsUnicode(otherString)) canBeEightbit = false; + if (CF_IS_OBJC(__kCFStringTypeID, otherString) || ! __CFStrIsEightBit(otherString)) canBeEightbit = false; } buffer = (uint8_t *)CFAllocatorAllocate(alloc, canBeEightbit ? ((numChars + 1) * sizeof(uint8_t)) : (numChars * sizeof(UniChar)), 0); @@ -3799,7 +3839,7 @@ CFStringRef CFStringCreateByCombiningStrings(CFAllocatorRef alloc, CFArrayRef ar } else { if (!isSepCFString) { // NSString CFStringGetCharacters(separatorString, CFRangeMake(0, CFStringGetLength(separatorString)), (UniChar *)bufPtr); - } else if (canBeEightbit || __CFStrIsUnicode(separatorString)) { + } else if (canBeEightbit) { memmove(bufPtr, (const uint8_t *)__CFStrContents(separatorString) + __CFStrSkipAnyLengthByte(separatorString), separatorNumByte); } else { __CFStrConvertBytesToUnicode((uint8_t *)__CFStrContents(separatorString) + __CFStrSkipAnyLengthByte(separatorString), (UniChar *)bufPtr, __CFStrLength(separatorString)); @@ -3854,14 +3894,14 @@ CFArrayRef CFStringCreateArrayBySeparatingStrings(CFAllocatorRef alloc, CFString numChars = currentRange->location - startIndex; substring = CFStringCreateWithSubstring(alloc, string, CFRangeMake(startIndex, numChars)); CFArrayAppendValue(array, substring); - CFRelease(substring); + if (!_CFAllocatorIsGCRefZero(alloc)) CFRelease(substring); startIndex = currentRange->location + currentRange->length; } substring = CFStringCreateWithSubstring(alloc, string, CFRangeMake(startIndex, length - startIndex)); CFArrayAppendValue(array, substring); - CFRelease(substring); + if (!_CFAllocatorIsGCRefZero(alloc)) CFRelease(substring); - CFRelease(separatorRanges); + if (!_CFAllocatorIsGCRefZero(alloc)) CFRelease(separatorRanges); return array; } @@ -4030,7 +4070,7 @@ void CFStringAppendCharacters(CFMutableStringRef str, const UniChar *chars, CFIn __CFAssertIsStringAndMutable(str); strLength = __CFStrLength(str); - if (__CFStringGetCompatibility(Bug2967272) || __CFStrIsUnicode(str)) { + if (__CFStrIsUnicode(str)) { __CFStringChangeSize(str, CFRangeMake(strLength, 0), appendedLength, true); memmove((UniChar *)__CFStrContents(str) + strLength, chars, appendedLength * sizeof(UniChar)); } else { @@ -4048,7 +4088,7 @@ void CFStringAppendCharacters(CFMutableStringRef str, const UniChar *chars, CFIn } -static void __CFStringAppendBytes(CFMutableStringRef str, const char *cStr, CFIndex appendedLength, CFStringEncoding encoding) { +void __CFStringAppendBytes(CFMutableStringRef str, const char *cStr, CFIndex appendedLength, CFStringEncoding encoding) { Boolean appendedIsUnicode = false; Boolean freeCStrWhenDone = false; Boolean demoteAppendedUnicode = false; @@ -4142,6 +4182,7 @@ void CFStringAppendFormat(CFMutableStringRef str, CFDictionaryRef formatOptions, CFIndex CFStringFindAndReplace(CFMutableStringRef string, CFStringRef stringToFind, CFStringRef replacementString, CFRange rangeToSearch, CFStringCompareFlags compareOptions) { + CF_OBJC_FUNCDISPATCH4(__kCFStringTypeID, CFIndex, string, "replaceOccurrencesOfString:withString:options:range:", stringToFind, replacementString, compareOptions, rangeToSearch); CFRange foundRange; Boolean backwards = ((compareOptions & kCFCompareBackwards) != 0); UInt32 endIndex = rangeToSearch.location + rangeToSearch.length; @@ -4202,8 +4243,10 @@ CFIndex CFStringFindAndReplace(CFMutableStringRef string, CFStringRef stringToFi int __CFStringCheckAndReplace(CFMutableStringRef str, CFRange range, CFStringRef replacement) { if (!__CFStrIsMutable(str)) return _CFStringErrNotMutable; // These three ifs are always here, for NSString usage if (!replacement && __CFStringNoteErrors()) return _CFStringErrNilArg; - // We use unsigneds as that is what NSRanges do; we use uint64_t do make sure the sum doesn't wrap (otherwise we'd need to do 3 separate checks). This allows catching bad ranges as described in 3375535. (-1,1) - if (((uint64_t)((unsigned)range.location)) + ((uint64_t)((unsigned)range.length)) > (uint64_t)__CFStrLength(str) && __CFStringNoteErrors()) return _CFStringErrBounds; + // This attempts to catch bad ranges including those described in 3375535 (-1,1) + unsigned long endOfRange = (unsigned long)(range.location) + (unsigned long)(range.length); // NSRange uses unsigned quantities, hence the casting + if (((endOfRange > (unsigned long)__CFStrLength(str)) || (endOfRange < (unsigned long)(range.location))) && __CFStringNoteErrors()) return _CFStringErrBounds; + __CFAssertIsStringAndMutable(str); __CFAssertRangeIsInStringBounds(str, range.location, range.length); __CFStringReplace(str, range, replacement); @@ -5127,7 +5170,8 @@ enum { kCFStringFormatZeroFlag = (1 << 0), // if not, padding is space char kCFStringFormatMinusFlag = (1 << 1), // if not, no flag implied kCFStringFormatPlusFlag = (1 << 2), // if not, no flag implied, overrides space - kCFStringFormatSpaceFlag = (1 << 3) // if not, no flag implied + kCFStringFormatSpaceFlag = (1 << 3), // if not, no flag implied + kCFStringFormatExternalSpecFlag = (1 << 4) // using config dict }; typedef struct { @@ -5141,7 +5185,7 @@ typedef struct { int8_t mainArgNum; int8_t precArgNum; int8_t widthArgNum; - int8_t unused1; + int8_t configDictIndex; } CFFormatSpec; typedef struct { @@ -5189,14 +5233,42 @@ enum { CFFormatDummyPointerType = 42 /* special case for %n */ }; -CF_INLINE void __CFParseFormatSpec(const UniChar *uformat, const uint8_t *cformat, SInt32 *fmtIdx, SInt32 fmtLen, CFFormatSpec *spec) { +CF_INLINE void __CFParseFormatSpec(const UniChar *uformat, const uint8_t *cformat, SInt32 *fmtIdx, SInt32 fmtLen, CFFormatSpec *spec, CFStringRef *configKeyPointer) { Boolean seenDot = false; + Boolean seenSharp = false; + CFIndex keyIndex = kCFNotFound; + for (;;) { UniChar ch; if (fmtLen <= *fmtIdx) return; /* no type */ if (cformat) ch = (UniChar)cformat[(*fmtIdx)++]; else ch = uformat[(*fmtIdx)++]; + + if (keyIndex >= 0) { + if ((ch < '0') || ((ch > '9') && (ch < 'A')) || ((ch > 'Z') && (ch < 'a') && (ch != '_')) || (ch > 'z')) { + if (ch == '@') { // found the key + CFIndex length = (*fmtIdx) - 1 - keyIndex; + + spec->flags |= kCFStringFormatExternalSpecFlag; + spec->type = CFFormatCFType; + spec->size = CFFormatSizePointer; // 4 or 8 depending on LP64 + + if ((NULL != configKeyPointer) && (length > 0)) { + if (cformat) { + *configKeyPointer = CFStringCreateWithBytes(NULL, cformat + keyIndex, length, __CFStringGetEightBitStringEncoding(), FALSE); + } else { + *configKeyPointer = CFStringCreateWithCharactersNoCopy(NULL, uformat + keyIndex, length, kCFAllocatorNull); + } + } + return; + } + keyIndex = kCFNotFound; + } + continue; + } + reswtch:switch (ch) { case '#': // ignored for now + seenSharp = true; break; case 0x20: if (!(spec->flags & kCFStringFormatPlusFlag)) spec->flags |= kCFStringFormatSpaceFlag; @@ -5213,6 +5285,15 @@ reswtch:switch (ch) { if (!(spec->flags & kCFStringFormatMinusFlag)) spec->flags |= kCFStringFormatZeroFlag; break; case 'h': + if (*fmtIdx < fmtLen) { + // fetch next character, don't increment fmtIdx + if (cformat) ch = (UniChar)cformat[(*fmtIdx)]; else ch = uformat[(*fmtIdx)]; + if ('h' == ch) { // 'hh' for char, like 'c' + (*fmtIdx)++; + spec->size = CFFormatSize1; + break; + } + } spec->size = CFFormatSize2; break; case 'l': @@ -5278,9 +5359,15 @@ reswtch:switch (ch) { spec->size = CFFormatSizePointer; // 4 or 8 depending on LP64 return; case '@': - spec->type = CFFormatCFType; - spec->size = CFFormatSizePointer; // 4 or 8 depending on LP64 - return; + if (seenSharp) { + seenSharp = false; + keyIndex = *fmtIdx; + break; + } else { + spec->type = CFFormatCFType; + spec->size = CFFormatSizePointer; // 4 or 8 depending on LP64 + return; + } case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { int64_t number = 0; do { @@ -5325,7 +5412,7 @@ reswtch:switch (ch) { ??? %s depends on handling of encodings by __CFStringAppendBytes */ void CFStringAppendFormatAndArguments(CFMutableStringRef outputString, CFDictionaryRef formatOptions, CFStringRef formatString, va_list args) { - _CFStringAppendFormatAndArgumentsAux(outputString, NULL, formatOptions, formatString, args); + __CFStringAppendFormatCore(outputString, NULL, formatOptions, formatString, 0, NULL, 0, args); } #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED @@ -5362,7 +5449,9 @@ void CFStringAppendFormatAndArguments(CFMutableStringRef outputString, CFDiction }} #endif -void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStringRef (*copyDescFunc)(void *, const void *), CFDictionaryRef formatOptions, CFStringRef formatString, va_list args) { +void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStringRef (*copyDescFunc)(void *, const void *), CFDictionaryRef formatOptions, CFStringRef formatString, va_list args) { __CFStringAppendFormatCore(outputString, copyDescFunc, formatOptions, formatString, 0, NULL, 0, args); } + +static void __CFStringAppendFormatCore(CFMutableStringRef outputString, CFStringRef (*copyDescFunc)(void *, const void *), CFDictionaryRef formatOptions, CFStringRef formatString, CFIndex initialArgPosition, const void *origValues, CFIndex originalValuesSize, va_list args) { SInt32 numSpecs, sizeSpecs, sizeArgNum, formatIdx, curSpec, argNum; CFIndex formatLen; #define FORMAT_BUFFER_LEN 400 @@ -5376,16 +5465,23 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr CFFormatSpec *specs; CFPrintValue localValuesBuffer[VPRINTF_BUFFER_LEN]; CFPrintValue *values; + const CFPrintValue *originalValues = (const CFPrintValue *)origValues; + CFDictionaryRef localConfigs[VPRINTF_BUFFER_LEN]; + CFDictionaryRef *configs; + CFIndex numConfigs; CFAllocatorRef tmpAlloc = NULL; - intmax_t dummyLocation; // A place for %n to do its thing in; should be the widest possible int value + va_list copiedArgs; numSpecs = 0; sizeSpecs = 0; sizeArgNum = 0; + numConfigs = 0; specs = NULL; values = NULL; - + configs = NULL; + + formatLen = CFStringGetLength(formatString); if (!CF_IS_OBJC(__kCFStringTypeID, formatString)) { __CFAssertIsString(formatString); @@ -5413,6 +5509,8 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr specs = ((2 * sizeSpecs + 1) > VPRINTF_BUFFER_LEN) ? (CFFormatSpec *)CFAllocatorAllocate(tmpAlloc, (2 * sizeSpecs + 1) * sizeof(CFFormatSpec), 0) : localSpecsBuffer; if (specs != localSpecsBuffer && __CFOASafe) __CFSetLastAllocationEventName(specs, "CFString (temp)"); + configs = ((sizeSpecs < VPRINTF_BUFFER_LEN) ? localConfigs : (CFDictionaryRef *)CFAllocatorAllocate(tmpAlloc, sizeof(CFStringRef) * sizeSpecs, 0)); + /* Collect format specification information from the format string */ for (curSpec = 0, formatIdx = 0; formatIdx < formatLen; curSpec++) { SInt32 newFmtIdx; @@ -5426,6 +5524,7 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr specs[curSpec].mainArgNum = -1; specs[curSpec].precArgNum = -1; specs[curSpec].widthArgNum = -1; + specs[curSpec].configDictIndex = -1; if (cformat) { for (newFmtIdx = formatIdx; newFmtIdx < formatLen && '%' != cformat[newFmtIdx]; newFmtIdx++); } else { @@ -5435,8 +5534,9 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr specs[curSpec].type = CFFormatLiteralType; specs[curSpec].len = newFmtIdx - formatIdx; } else { + CFStringRef configKey = NULL; newFmtIdx++; /* Skip % */ - __CFParseFormatSpec(uformat, cformat, &newFmtIdx, formatLen, &(specs[curSpec])); + __CFParseFormatSpec(uformat, cformat, &newFmtIdx, formatLen, &(specs[curSpec]), &configKey); if (CFFormatLiteralType == specs[curSpec].type) { specs[curSpec].loc = formatIdx + 1; specs[curSpec].len = 1; @@ -5450,14 +5550,21 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr } numSpecs = curSpec; + // Max of three args per spec, reasoning thus: 1 width, 1 prec, 1 value - values = ((3 * sizeSpecs + 1) > VPRINTF_BUFFER_LEN) ? (CFPrintValue *)CFAllocatorAllocate(tmpAlloc, (3 * sizeSpecs + 1) * sizeof(CFPrintValue), 0) : localValuesBuffer; + sizeArgNum = ((NULL == originalValues) ? (3 * sizeSpecs + 1) : originalValuesSize); + + values = (sizeArgNum > VPRINTF_BUFFER_LEN) ? (CFPrintValue *)CFAllocatorAllocate(tmpAlloc, sizeArgNum * sizeof(CFPrintValue), 0) : localValuesBuffer; if (values != localValuesBuffer && __CFOASafe) __CFSetLastAllocationEventName(values, "CFString (temp)"); - memset(values, 0, (3 * sizeSpecs + 1) * sizeof(CFPrintValue)); - sizeArgNum = (3 * sizeSpecs + 1); + memset(values, 0, sizeArgNum * sizeof(CFPrintValue)); + +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD + // va_copy is a C99 extension. No support on Windows + if (numConfigs > 0) va_copy(copiedArgs, args); // we need to preserve the original state for passing down +#endif /* DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD */ /* Compute values array */ - argNum = 0; + argNum = initialArgPosition; for (curSpec = 0; curSpec < numSpecs; curSpec++) { SInt32 newMaxArgNum; if (0 == specs[curSpec].type) continue; @@ -5488,8 +5595,11 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr if (-1 == specs[curSpec].mainArgNum) { specs[curSpec].mainArgNum = argNum++; } + values[specs[curSpec].mainArgNum].size = specs[curSpec].size; values[specs[curSpec].mainArgNum].type = specs[curSpec].type; + + if (-1 != specs[curSpec].widthArgNum) { values[specs[curSpec].widthArgNum].size = 0; values[specs[curSpec].widthArgNum].type = CFFormatLongType; @@ -5502,6 +5612,7 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr /* Collect the arguments in correct type from vararg list */ for (argNum = 0; argNum < sizeArgNum; argNum++) { + if ((NULL != originalValues) && (0 == values[argNum].type)) values[argNum] = originalValues[argNum]; switch (values[argNum].type) { case 0: case CFFormatLiteralType: @@ -5547,6 +5658,12 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr va_end(args); /* Format the pieces together */ + + if (NULL == originalValues) { + originalValues = values; + originalValuesSize = sizeArgNum; + } + for (curSpec = 0; curSpec < numSpecs; curSpec++) { SInt32 width = 0, precision = 0; UniChar *up, ch; @@ -5739,7 +5856,117 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr break; case CFFormatCFType: case CFFormatObjectType: - if (NULL != values[specs[curSpec].mainArgNum].value.pointerValue) { + if (specs[curSpec].configDictIndex != -1) { // config dict + CFTypeRef object = NULL; + CFStringRef innerFormat = NULL; + + switch (values[specs[curSpec].mainArgNum].type) { + case CFFormatLongType: + object = CFNumberCreate(tmpAlloc, kCFNumberSInt64Type, &(values[specs[curSpec].mainArgNum].value.int64Value)); + break; + + case CFFormatDoubleType: +#if LONG_DOUBLE_SUPPORT + if (CFFormatSize16 == values[specs[curSpec].mainArgNum].size) { + double aValue = values[specs[curSpec].mainArgNum].value.longDoubleValue; // losing precision + + object = CFNumberCreate(tmpAlloc, kCFNumberDoubleType, &aValue); + } else +#endif + { + object = CFNumberCreate(tmpAlloc, kCFNumberDoubleType, &(values[specs[curSpec].mainArgNum].value.doubleValue)); + } + break; + + case CFFormatPointerType: + object = CFNumberCreate(tmpAlloc, kCFNumberCFIndexType, &(values[specs[curSpec].mainArgNum].value.pointerValue)); + break; + + case CFFormatPascalCharsType: + case CFFormatCharsType: + if (NULL != values[specs[curSpec].mainArgNum].value.pointerValue) { + CFMutableStringRef aString = CFStringCreateMutable(tmpAlloc, 0); + int len; + const char *str = (const char *)values[specs[curSpec].mainArgNum].value.pointerValue; + if (specs[curSpec].type == CFFormatPascalCharsType) { // Pascal string case + len = ((unsigned char *)str)[0]; + str++; + if (hasPrecision && precision < len) len = precision; + } else { // C-string case + if (!hasPrecision) { // No precision, so rely on the terminating null character + len = strlen(str); + } else { // Don't blindly call strlen() if there is a precision; the string might not have a terminating null (3131988) + const char *terminatingNull = (const char *)memchr(str, 0, precision); // Basically strlen() on only the first precision characters of str + if (terminatingNull) { // There was a null in the first precision characters + len = terminatingNull - str; + } else { + len = precision; + } + } + } + // Since the spec says the behavior of the ' ', '0', '#', and '+' flags is undefined for + // '%s', and since we have ignored them in the past, the behavior is hereby cast in stone + // to ignore those flags (and, say, never pad with '0' instead of space). + if (specs[curSpec].flags & kCFStringFormatMinusFlag) { + __CFStringAppendBytes(aString, str, len, __CFStringGetSystemEncoding()); + if (hasWidth && width > len) { + int w = width - len; // We need this many spaces; do it ten at a time + do {__CFStringAppendBytes(aString, " ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0); + } + } else { + if (hasWidth && width > len) { + int w = width - len; // We need this many spaces; do it ten at a time + do {__CFStringAppendBytes(aString, " ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0); + } + __CFStringAppendBytes(aString, str, len, __CFStringGetSystemEncoding()); + } + + object = aString; + } + break; + + case CFFormatSingleUnicharType: + ch = (UniChar)values[specs[curSpec].mainArgNum].value.int64Value; + object = CFStringCreateWithCharactersNoCopy(tmpAlloc, &ch, 1, kCFAllocatorNull); + break; + + case CFFormatUnicharsType: + //??? need to handle width, precision, and padding arguments + up = (UniChar *)values[specs[curSpec].mainArgNum].value.pointerValue; + if (NULL != up) { + CFMutableStringRef aString = CFStringCreateMutable(tmpAlloc, 0); + int len; + for (len = 0; 0 != up[len]; len++); + // Since the spec says the behavior of the ' ', '0', '#', and '+' flags is undefined for + // '%s', and since we have ignored them in the past, the behavior is hereby cast in stone + // to ignore those flags (and, say, never pad with '0' instead of space). + if (hasPrecision && precision < len) len = precision; + if (specs[curSpec].flags & kCFStringFormatMinusFlag) { + CFStringAppendCharacters(aString, up, len); + if (hasWidth && width > len) { + int w = width - len; // We need this many spaces; do it ten at a time + do {__CFStringAppendBytes(aString, " ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0); + } + } else { + if (hasWidth && width > len) { + int w = width - len; // We need this many spaces; do it ten at a time + do {__CFStringAppendBytes(aString, " ", (w > 10 ? 10 : w), kCFStringEncodingASCII);} while ((w -= 10) > 0); + } + CFStringAppendCharacters(aString, up, len); + } + object = aString; + } + break; + + case CFFormatCFType: + case CFFormatObjectType: + if (NULL != values[specs[curSpec].mainArgNum].value.pointerValue) object = CFRetain(values[specs[curSpec].mainArgNum].value.pointerValue); + break; + } + + if (NULL != object) CFRelease(object); + + } else if (NULL != values[specs[curSpec].mainArgNum].value.pointerValue) { CFStringRef str = NULL; if (copyDescFunc) { str = copyDescFunc(values[specs[curSpec].mainArgNum].value.pointerValue, formatOptions); @@ -5762,10 +5989,14 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr } } +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD + // va_copy is a C99 extension. No support on Windows + if (numConfigs > 0) va_end(copiedArgs); +#endif /* DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD */ if (specs != localSpecsBuffer) CFAllocatorDeallocate(tmpAlloc, specs); if (values != localValuesBuffer) CFAllocatorDeallocate(tmpAlloc, values); if (formatChars && (formatChars != localFormatBuffer)) CFAllocatorDeallocate(tmpAlloc, formatChars); - + if (configs != localConfigs) CFAllocatorDeallocate(tmpAlloc, configs); } #undef SNPRINTF diff --git a/CFString.h b/CFString.h index 99333cb..9ee6af1 100644 --- a/CFString.h +++ b/CFString.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFString.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSTRING__) @@ -126,9 +126,8 @@ enum { kCFStringEncodingASCII = 0x0600, /* 0..127 (in creating CFString, values greater than 0x7F are treated as corresponding Unicode value) */ kCFStringEncodingUnicode = 0x0100, /* kTextEncodingUnicodeDefault + kTextEncodingDefaultFormat (aka kUnicode16BitFormat) */ kCFStringEncodingUTF8 = 0x08000100, /* kTextEncodingUnicodeDefault + kUnicodeUTF8Format */ - kCFStringEncodingNonLossyASCII = 0x0BFF /* 7bit Unicode variants used by Cocoa & Java */ -#if MAC_OS_X_VERSION_10_4 <= MAC_OS_X_VERSION_MAX_ALLOWED - , + kCFStringEncodingNonLossyASCII = 0x0BFF, /* 7bit Unicode variants used by Cocoa & Java */ + kCFStringEncodingUTF16 = 0x0100, /* kTextEncodingUnicodeDefault + kUnicodeUTF16Format (alias of kCFStringEncodingUnicode) */ kCFStringEncodingUTF16BE = 0x10000100, /* kTextEncodingUnicodeDefault + kUnicodeUTF16BEFormat */ kCFStringEncodingUTF16LE = 0x14000100, /* kTextEncodingUnicodeDefault + kUnicodeUTF16LEFormat */ @@ -136,7 +135,6 @@ enum { kCFStringEncodingUTF32 = 0x0c000100, /* kTextEncodingUnicodeDefault + kUnicodeUTF32Format */ kCFStringEncodingUTF32BE = 0x18000100, /* kTextEncodingUnicodeDefault + kUnicodeUTF32BEFormat */ kCFStringEncodingUTF32LE = 0x1c000100 /* kTextEncodingUnicodeDefault + kUnicodeUTF32LEFormat */ -#endif /* MAC_OS_X_VERSION_10_4 <= MAC_OS_X_VERSION_MAX_ALLOWED */ }; typedef CFStringEncoding CFStringBuiltInEncodings; @@ -166,7 +164,7 @@ equivalents in the encoding the compiler will use to interpret them (for instanc O-umlaut is \303\226 in UTF-8). UTF-8 is the recommended encoding here, since it is the default choice with Mac OS X developer tools. */ -#if TARGET_OS_WIN32 +#if TARGET_OS_WIN32 || TARGET_OS_LINUX #undef __CONSTANT_CFSTRINGS__ #endif @@ -176,7 +174,7 @@ since it is the default choice with Mac OS X developer tools. #define CFSTR(cStr) __CFStringMakeConstantString("" cStr "") #endif -#if defined(__GNUC__) && (__GNUC__*10+__GNUC_MINOR__ >= 42) && !defined(__INTEL_COMPILER) && (TARGET_OS_MAC || TARGET_OS_EMBEDDED) +#if defined(__GNUC__) && (__GNUC__*10+__GNUC_MINOR__ >= 42) && defined(__APPLE_CC__) && (__APPLE_CC__ > 1) && !defined(__INTEL_COMPILER) && (TARGET_OS_MAC || TARGET_OS_EMBEDDED) #define CF_FORMAT_FUNCTION(F,A) __attribute__((format(CFString, F, A))) #define CF_FORMAT_ARGUMENT(A) __attribute__((format_arg(A))) #else @@ -227,12 +225,10 @@ CFStringRef CFStringCreateWithPascalStringNoCopy(CFAllocatorRef alloc, ConstStr2 CF_EXPORT CFStringRef CFStringCreateWithCStringNoCopy(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding, CFAllocatorRef contentsDeallocator); -#if MAC_OS_X_VERSION_10_4 <= MAC_OS_X_VERSION_MAX_ALLOWED /* The following takes an explicit length, and allows you to specify whether the data is an external format --- that is, whether to pay attention to the BOM character (if any) and do byte swapping if necessary */ CF_EXPORT -CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const UInt8 *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean isExternalRepresentation, CFAllocatorRef contentsDeallocator) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -#endif +CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const UInt8 *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean isExternalRepresentation, CFAllocatorRef contentsDeallocator); CF_EXPORT CFStringRef CFStringCreateWithCharactersNoCopy(CFAllocatorRef alloc, const UniChar *chars, CFIndex numChars, CFAllocatorRef contentsDeallocator); @@ -372,17 +368,17 @@ CFIndex CFStringGetMaximumSizeForEncoding(CFIndex length, CFStringEncoding encod /* Extract the contents of the string as a NULL-terminated 8-bit string appropriate for passing to POSIX APIs (for example, normalized for HFS+). The string is zero-terminated. false will be returned if the conversion results don't fit into the buffer. Use CFStringGetMaximumSizeOfFileSystemRepresentation() if you want to make sure the buffer is of sufficient length. */ CF_EXPORT -Boolean CFStringGetFileSystemRepresentation(CFStringRef string, char *buffer, CFIndex maxBufLen) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +Boolean CFStringGetFileSystemRepresentation(CFStringRef string, char *buffer, CFIndex maxBufLen); /* Get the upper bound on the number of bytes required to hold the file system representation for the string. This result is returned quickly as a very rough approximation, and could be much larger than the actual space required. The result includes space for the zero termination. If you are allocating a buffer for long-term keeping, it's recommended that you reallocate it smaller (to be the right size) after calling CFStringGetFileSystemRepresentation(). */ CF_EXPORT -CFIndex CFStringGetMaximumSizeOfFileSystemRepresentation(CFStringRef string) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFIndex CFStringGetMaximumSizeOfFileSystemRepresentation(CFStringRef string); /* Create a CFString from the specified zero-terminated POSIX file system representation. If the conversion fails (possible due to bytes in the buffer not being a valid sequence of bytes for the appropriate character encoding), NULL is returned. */ CF_EXPORT -CFStringRef CFStringCreateWithFileSystemRepresentation(CFAllocatorRef alloc, const char *buffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +CFStringRef CFStringCreateWithFileSystemRepresentation(CFAllocatorRef alloc, const char *buffer); /*** Comparison functions. ***/ @@ -410,10 +406,8 @@ locale == NULL indicates canonical locale (the return value from CFLocaleGetSyst kCFCompareNumerically, added in 10.2, does not work if kCFCompareLocalized is specified on systems before 10.3 kCFCompareBackwards and kCFCompareAnchored are not applicable. */ -#if MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED CF_EXPORT -CFComparisonResult CFStringCompareWithOptionsAndLocale(CFStringRef theString1, CFStringRef theString2, CFRange rangeToCompare, CFStringCompareFlags compareOptions, CFLocaleRef locale) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; -#endif /* MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED */ +CFComparisonResult CFStringCompareWithOptionsAndLocale(CFStringRef theString1, CFStringRef theString2, CFRange rangeToCompare, CFStringCompareFlags compareOptions, CFLocaleRef locale) CF_AVAILABLE(10_5, 2_0); /* Comparison convenience. Uses the current user locale (the return value from CFLocaleCopyCurrent()) if kCFCompareLocalized. */ @@ -432,10 +426,8 @@ CFComparisonResult CFStringCompare(CFStringRef theString1, CFStringRef theString If stringToFind is the empty string (zero length), nothing is found. Ignores the kCFCompareNumerically option. */ -#if MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED CF_EXPORT -Boolean CFStringFindWithOptionsAndLocale(CFStringRef theString, CFStringRef stringToFind, CFRange rangeToSearch, CFStringCompareFlags searchOptions, CFLocaleRef locale, CFRange *result) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; -#endif /* MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED */ +Boolean CFStringFindWithOptionsAndLocale(CFStringRef theString, CFStringRef stringToFind, CFRange rangeToSearch, CFStringCompareFlags searchOptions, CFLocaleRef locale, CFRange *result) CF_AVAILABLE(10_5, 2_0); /* Find convenience. Uses the current user locale (the return value from CFLocaleCopyCurrent()) if kCFCompareLocalized. */ @@ -464,7 +456,6 @@ Boolean CFStringHasPrefix(CFStringRef theString, CFStringRef prefix); CF_EXPORT Boolean CFStringHasSuffix(CFStringRef theString, CFStringRef suffix); -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED /*! @function CFStringGetRangeOfComposedCharactersAtIndex Returns the range of the composed character sequence at the specified index. @@ -510,7 +501,6 @@ CF_EXPORT CFRange CFStringGetRangeOfComposedCharactersAtIndex(CFStringRef theStr set is found and result is filled, otherwise, false. */ CF_EXPORT Boolean CFStringFindCharacterFromSet(CFStringRef theString, CFCharacterSetRef theSet, CFRange rangeToSearch, CFStringCompareFlags searchOptions, CFRange *result); -#endif /* Find range of bounds of the line(s) that span the indicated range (startIndex, numChars), taking into account various possible line separator sequences (CR, CRLF, LF, and Unicode NextLine, LineSeparator, ParagraphSeparator). @@ -527,7 +517,38 @@ void CFStringGetLineBounds(CFStringRef theString, CFRange range, CFIndex *lineBe /* Same as CFStringGetLineBounds(), however, will only look for paragraphs. Won't stop at Unicode NextLine or LineSeparator characters. */ CF_EXPORT -void CFStringGetParagraphBounds(CFStringRef string, CFRange range, CFIndex *parBeginIndex, CFIndex *parEndIndex, CFIndex *contentsEndIndex) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +void CFStringGetParagraphBounds(CFStringRef string, CFRange range, CFIndex *parBeginIndex, CFIndex *parEndIndex, CFIndex *contentsEndIndex) CF_AVAILABLE(10_5, 2_0); + +/*! + @function CFStringGetHyphenationLocationBeforeIndex + Retrieve the first potential hyphenation location found before the specified location. + @param string The CFString which is to be hyphenated. If this + parameter is not a valid CFString, the behavior is + undefined. + @param location An index in the string. If a valid hyphen index is returned, it + will be before this index. + @param limitRange The range of characters within the string to search. If + the range location or end point (defined by the location + plus length minus 1) are outside the index space of the + string (0 to N-1 inclusive, where N is the length of the + string), the behavior is undefined. If the range length is + negative, the behavior is undefined. The range may be empty + (length 0), in which case no hyphen location is generated. + @param options Reserved for future use. + @param locale Specifies which language's hyphenation conventions to use. + This must be a valid locale. Hyphenation data is not available + for all locales. You can use CFStringIsHyphenationAvailableForLocale + to test for availability of hyphenation data. + @param character The suggested hyphen character to insert. Pass NULL if you + do not need this information. + @result an index in the string where it is appropriate to insert a hyphen, if + one exists; else kCFNotFound +*/ +CF_EXPORT +CFIndex CFStringGetHyphenationLocationBeforeIndex(CFStringRef string, CFIndex location, CFRange limitRange, CFOptionFlags options, CFLocaleRef locale, UTF32Char *character) CF_AVAILABLE(10_7, 4_2); + +CF_EXPORT +Boolean CFStringIsHyphenationAvailableForLocale(CFLocaleRef locale) CF_AVAILABLE(10_7, 4_3); /*** Exploding and joining strings with a separator string ***/ @@ -584,7 +605,6 @@ void CFStringReplace(CFMutableStringRef theString, CFRange range, CFStringRef re CF_EXPORT void CFStringReplaceAll(CFMutableStringRef theString, CFStringRef replacement); /* Replaces whole string */ -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED /* Replace all occurrences of target in rangeToSearch of theString with replacement. Pays attention to kCFCompareCaseInsensitive, kCFCompareBackwards, kCFCompareNonliteral, and kCFCompareAnchored. kCFCompareBackwards can be used to do the replacement starting from the end, which could give a different result. @@ -596,7 +616,6 @@ void CFStringReplaceAll(CFMutableStringRef theString, CFStringRef replacement); CF_EXPORT CFIndex CFStringFindAndReplace(CFMutableStringRef theString, CFStringRef stringToFind, CFStringRef replacementString, CFRange rangeToSearch, CFStringCompareFlags compareOptions); -#endif /* This function will make the contents of a mutable CFString point directly at the specified UniChar array. It works only with CFStrings created with CFStringCreateMutableWithExternalCharactersNoCopy(). @@ -628,7 +647,6 @@ void CFStringTrim(CFMutableStringRef theString, CFStringRef trimString); CF_EXPORT void CFStringTrimWhitespace(CFMutableStringRef theString); -#if MAC_OS_X_VERSION_10_3 <= MAC_OS_X_VERSION_MAX_ALLOWED CF_EXPORT void CFStringLowercase(CFMutableStringRef theString, CFLocaleRef locale); @@ -637,18 +655,7 @@ void CFStringUppercase(CFMutableStringRef theString, CFLocaleRef locale); CF_EXPORT void CFStringCapitalize(CFMutableStringRef theString, CFLocaleRef locale); -#else -CF_EXPORT -void CFStringLowercase(CFMutableStringRef theString, const void *localeTBD); // localeTBD must be NULL on pre-10.3 - -CF_EXPORT -void CFStringUppercase(CFMutableStringRef theString, const void *localeTBD); // localeTBD must be NULL on pre-10.3 - -CF_EXPORT -void CFStringCapitalize(CFMutableStringRef theString, const void *localeTBD); // localeTBD must be NULL on pre-10.3 -#endif -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED /*! @typedef CFStringNormalizationForm This is the type of Unicode normalization forms as described in @@ -675,9 +682,8 @@ typedef CFIndex CFStringNormalizationForm; the behavior is undefined. */ CF_EXPORT void CFStringNormalize(CFMutableStringRef theString, CFStringNormalizationForm theForm); -#endif -#if MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED + /*! @function CFStringFold Folds the string into the form specified by the flags. @@ -703,34 +709,33 @@ CF_EXPORT void CFStringNormalize(CFMutableStringRef theString, CFStringNormaliza */ CF_EXPORT -void CFStringFold(CFMutableStringRef theString, CFOptionFlags theFlags, CFLocaleRef theLocale) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; -#endif /* MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED */ +void CFStringFold(CFMutableStringRef theString, CFOptionFlags theFlags, CFLocaleRef theLocale) CF_AVAILABLE(10_5, 2_0); /* Perform string transliteration. The transformation represented by transform is applied to the given range of string, modifying it in place. Only the specified range will be modified, but the transform may look at portions of the string outside that range for context. NULL range pointer causes the whole string to be transformed. On return, range is modified to reflect the new range corresponding to the original range. reverse indicates that the inverse transform should be used instead, if it exists. If the transform is successful, true is returned; if unsuccessful, false. Reasons for the transform being unsuccessful include an invalid transform identifier, or attempting to reverse an irreversible transform. You can pass one of the predefined transforms below, or any valid ICU transform ID as defined in the ICU User Guide. Note that we do not support arbitrary set of ICU transform rules. */ CF_EXPORT -Boolean CFStringTransform(CFMutableStringRef string, CFRange *range, CFStringRef transform, Boolean reverse) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; +Boolean CFStringTransform(CFMutableStringRef string, CFRange *range, CFStringRef transform, Boolean reverse); /* Transform identifiers for CFStringTransform() */ -CF_EXPORT const CFStringRef kCFStringTransformStripCombiningMarks AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFStringTransformToLatin AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFStringTransformFullwidthHalfwidth AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFStringTransformLatinKatakana AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFStringTransformLatinHiragana AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFStringTransformHiraganaKatakana AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFStringTransformMandarinLatin AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFStringTransformLatinHangul AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFStringTransformLatinArabic AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFStringTransformLatinHebrew AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFStringTransformLatinThai AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFStringTransformLatinCyrillic AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFStringTransformLatinGreek AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFStringTransformToXMLHex AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFStringTransformToUnicodeName AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; -CF_EXPORT const CFStringRef kCFStringTransformStripDiacritics AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CF_EXPORT const CFStringRef kCFStringTransformStripCombiningMarks; +CF_EXPORT const CFStringRef kCFStringTransformToLatin; +CF_EXPORT const CFStringRef kCFStringTransformFullwidthHalfwidth; +CF_EXPORT const CFStringRef kCFStringTransformLatinKatakana; +CF_EXPORT const CFStringRef kCFStringTransformLatinHiragana; +CF_EXPORT const CFStringRef kCFStringTransformHiraganaKatakana; +CF_EXPORT const CFStringRef kCFStringTransformMandarinLatin; +CF_EXPORT const CFStringRef kCFStringTransformLatinHangul; +CF_EXPORT const CFStringRef kCFStringTransformLatinArabic; +CF_EXPORT const CFStringRef kCFStringTransformLatinHebrew; +CF_EXPORT const CFStringRef kCFStringTransformLatinThai; +CF_EXPORT const CFStringRef kCFStringTransformLatinCyrillic; +CF_EXPORT const CFStringRef kCFStringTransformLatinGreek; +CF_EXPORT const CFStringRef kCFStringTransformToXMLHex; +CF_EXPORT const CFStringRef kCFStringTransformToUnicodeName; +CF_EXPORT const CFStringRef kCFStringTransformStripDiacritics CF_AVAILABLE(10_5, 2_0); /*** General encoding related functionality ***/ @@ -849,7 +854,7 @@ CF_INLINE Boolean CFStringIsSurrogateLowCharacter(UniChar character) { } CF_INLINE UTF32Char CFStringGetLongCharacterForSurrogatePair(UniChar surrogateHigh, UniChar surrogateLow) { - return ((surrogateHigh - 0xD800UL) << 10) + (surrogateLow - 0xDC00UL) + 0x0010000UL; + return (UTF32Char)(((surrogateHigh - 0xD800UL) << 10) + (surrogateLow - 0xDC00UL) + 0x0010000UL); } // Maps a UTF-32 character to a pair of UTF-16 surrogate characters. The buffer pointed by surrogates has to have space for at least 2 UTF-16 characters. Returns true if mapped to a surrogate pair. diff --git a/CFStringDefaultEncoding.h b/CFStringDefaultEncoding.h index 439b23a..500e1eb 100644 --- a/CFStringDefaultEncoding.h +++ b/CFStringDefaultEncoding.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFStringDefaultEncoding.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSTRINGDEFAULTENCODING__) diff --git a/CFStringEncodingConverter.c b/CFStringEncodingConverter.c index 094ba57..4f70b85 100644 --- a/CFStringEncodingConverter.c +++ b/CFStringEncodingConverter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFStringEncodingConverter.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Aki Inoue */ @@ -605,7 +605,7 @@ static const _CFEncodingConverter *__CFGetConverter(uint32_t encoding) { case kCFStringEncodingUTF8: commonConverterSlot = (const _CFEncodingConverter **)&(commonConverters[0]); break; /* the swith here should avoid possible bootstrap issues in the default: case below when invoked from CFStringGetSystemEncoding() */ -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX case kCFStringEncodingMacRoman: commonConverterSlot = (const _CFEncodingConverter **)&(commonConverters[1]); break; #elif DEPLOYMENT_TARGET_WINDOWS case kCFStringEncodingWindowsLatin1: commonConverterSlot = (const _CFEncodingConverter **)(&(commonConverters[1])); break; @@ -907,9 +907,9 @@ __private_extern__ CFIndex CFStringEncodingByteLengthForCharacters(uint32_t enco if (1 == converter->definition->maxBytesPerChar) return numChars; if (NULL == converter->definition->toBytesLen) { - CFIndex usedCharLen; + CFIndex usedByteLen; - return ((kCFStringEncodingConversionSuccess == CFStringEncodingUnicodeToBytes(encoding, flags, characters, numChars, &usedCharLen, NULL, 0, NULL)) ? usedCharLen : 0); + return ((kCFStringEncodingConversionSuccess == CFStringEncodingUnicodeToBytes(encoding, flags, characters, numChars, NULL, NULL, 0, &usedByteLen)) ? usedByteLen : 0); } else { return converter->definition->toBytesLen(flags, characters, numChars); } diff --git a/CFStringEncodingConverter.h b/CFStringEncodingConverter.h index d1372a0..d754a22 100644 --- a/CFStringEncodingConverter.h +++ b/CFStringEncodingConverter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFStringEncodingConverter.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSTRINGENCODINGCONVERTER__) diff --git a/CFStringEncodingConverterExt.h b/CFStringEncodingConverterExt.h index a4b6492..7ead197 100644 --- a/CFStringEncodingConverterExt.h +++ b/CFStringEncodingConverterExt.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFStringEncodingConverterExt.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSTRINGENCODINGCONVERETEREXT__) diff --git a/CFStringEncodingConverterPriv.h b/CFStringEncodingConverterPriv.h index 33fa73e..2fc9fc7 100644 --- a/CFStringEncodingConverterPriv.h +++ b/CFStringEncodingConverterPriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFStringEncodingConverterPriv.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSTRINGENCODINGCONVERTERPRIV__) diff --git a/CFStringEncodingDatabase.c b/CFStringEncodingDatabase.c index d3e8021..bd05f28 100644 --- a/CFStringEncodingDatabase.c +++ b/CFStringEncodingDatabase.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,14 +21,10 @@ * @APPLE_LICENSE_HEADER_END@ */ -/* - * CFStringEncodingDatabase.c - * CoreFoundation - * - * Created by Aki Inoue on 07/12/05. - * Copyright 2007-2009, Apple Inc. All rights reserved. - * - */ +/* CFStringEncodingDatabase.c + Copyright (c) 2005-2011, Apple Inc. All rights reserved. + Responsibility: Aki Inoue +*/ #include "CFInternal.h" #include @@ -36,11 +32,6 @@ #include "CFStringEncodingDatabase.h" #include -#if DEPLOYMENT_TARGET_WINDOWS -#define strncasecmp_l(a, b, c, d) _strnicmp(a, b, c) -#define snprintf _snprintf -#endif - #define ISO8859CODEPAGE_BASE (28590) static const uint16_t __CFKnownEncodingList[] = { diff --git a/CFStringEncodingDatabase.h b/CFStringEncodingDatabase.h index e982afe..606c217 100644 --- a/CFStringEncodingDatabase.h +++ b/CFStringEncodingDatabase.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,7 +26,7 @@ * CoreFoundation * * Created by Aki Inoue on 07/12/05. - * Copyright (c) 2007-2009, Apple Inc. All rights reserved. + * Copyright (c) 2007-2011, Apple Inc. All rights reserved. * */ diff --git a/CFStringEncodingExt.h b/CFStringEncodingExt.h index e1e223e..5b8bc5d 100644 --- a/CFStringEncodingExt.h +++ b/CFStringEncodingExt.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFStringEncodingExt.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSTRINGENCODINGEXT__) @@ -101,9 +101,7 @@ enum { kCFStringEncodingISOLatin7 = 0x020D, /* ISO 8859-13 */ kCFStringEncodingISOLatin8 = 0x020E, /* ISO 8859-14 */ kCFStringEncodingISOLatin9 = 0x020F, /* ISO 8859-15 */ -#if MAC_OS_X_VERSION_10_4 <= MAC_OS_X_VERSION_MAX_ALLOWED kCFStringEncodingISOLatin10 = 0x0210, /* ISO 8859-16 */ -#endif /* MS-DOS & Windows encodings begin at 0x400 */ kCFStringEncodingDOSLatinUS = 0x0400, /* code page 437 */ @@ -140,9 +138,7 @@ enum { /* Various national standards begin at 0x600 */ /* kCFStringEncodingASCII = 0x0600, defined in CoreFoundation/CFString.h */ -#if MAC_OS_X_VERSION_10_4 <= MAC_OS_X_VERSION_MAX_ALLOWED kCFStringEncodingANSEL = 0x0601, /* ANSEL (ANSI Z39.47) */ -#endif kCFStringEncodingJIS_X0201_76 = 0x0620, kCFStringEncodingJIS_X0208_83 = 0x0621, kCFStringEncodingJIS_X0208_90 = 0x0622, @@ -151,9 +147,7 @@ enum { #if MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED kCFStringEncodingShiftJIS_X0213 = 0x0628, /* Shift-JIS format encoding of JIS X0213 planes 1 and 2*/ #endif -#if MAC_OS_X_VERSION_10_4 <= MAC_OS_X_VERSION_MAX_ALLOWED kCFStringEncodingShiftJIS_X0213_MenKuTen = 0x0629, /* JIS X0213 in plane-row-column notation */ -#endif kCFStringEncodingGB_2312_80 = 0x0630, kCFStringEncodingGBK_95 = 0x0631, /* annex to GB 13000-93; for Windows 95 */ kCFStringEncodingGB_18030_2000 = 0x0632, @@ -185,17 +179,13 @@ enum { kCFStringEncodingMacRomanLatin1 = 0x0A04, /* Mac OS Roman permuted to align with ISO Latin-1 */ kCFStringEncodingHZ_GB_2312 = 0x0A05, /* HZ (RFC 1842, for Chinese mail & news) */ kCFStringEncodingBig5_HKSCS_1999 = 0x0A06, /* Big-5 with Hong Kong special char set supplement*/ -#if MAC_OS_X_VERSION_10_4 <= MAC_OS_X_VERSION_MAX_ALLOWED kCFStringEncodingVISCII = 0x0A07, /* RFC 1456, Vietnamese */ kCFStringEncodingKOI8_U = 0x0A08, /* RFC 2319, Ukrainian */ kCFStringEncodingBig5_E = 0x0A09, /* Taiwan Big-5E standard */ -#endif /* Other platform encodings*/ /* kCFStringEncodingNextStepLatin = 0x0B01, defined in CoreFoundation/CFString.h */ -#if MAC_OS_X_VERSION_10_4 <= MAC_OS_X_VERSION_MAX_ALLOWED kCFStringEncodingNextStepJapanese = 0x0B02, /* NextStep Japanese encoding */ -#endif /* EBCDIC & IBM host encodings begin at 0xC00 */ kCFStringEncodingEBCDIC_US = 0x0C01, /* basic EBCDIC-US */ diff --git a/CFStringEncodings.c b/CFStringEncodings.c index 4710f68..c39ce46 100644 --- a/CFStringEncodings.c +++ b/CFStringEncodings.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFStringEncodings.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. Responsibility: Aki Inoue */ @@ -148,7 +148,7 @@ Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, CFIndex len, CFStringE if ((encoding == kCFStringEncodingUTF16) || (encoding == kCFStringEncodingUTF16BE) || (encoding == kCFStringEncodingUTF16LE)) { // UTF-16 const UTF16Char *src = (const UTF16Char *)bytes; - const UTF16Char *limit = src + (len / sizeof(UTF16Char)); + const UTF16Char *limit = src + (len / sizeof(UTF16Char)); // avoiding odd len issue bool swap = false; if (kCFStringEncodingUTF16 == encoding) { @@ -228,7 +228,7 @@ Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, CFIndex len, CFStringE } } else if ((encoding == kCFStringEncodingUTF32) || (encoding == kCFStringEncodingUTF32BE) || (encoding == kCFStringEncodingUTF32LE)) { const UTF32Char *src = (const UTF32Char *)bytes; - const UTF32Char *limit = src + (len / sizeof(UTF32Char)); + const UTF32Char *limit = src + (len / sizeof(UTF32Char)); // avoiding odd len issue bool swap = false; static bool strictUTF32 = (bool)-1; @@ -474,7 +474,7 @@ Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, CFIndex len, CFStringE buffer->chars.unicode = (buffer->chars.unicode ? buffer->chars.unicode : (guessedLength <= MAX_LOCAL_UNICHARS) ? (UniChar *)buffer->localBuffer : (UniChar *)CFAllocatorAllocate(buffer->allocator, guessedLength * sizeof(UniChar), 0)); if (!buffer->chars.unicode) goto memoryErrorExit; - if (lossyFlag == (UInt32)-1) lossyFlag = (_CFExecutableLinkedOnOrAfter(CFSystemVersionPanther) ? 0 : kCFStringEncodingAllowLossyConversion); + if (lossyFlag == (UInt32)-1) lossyFlag = 0; if (CFStringEncodingBytesToUnicode(encoding, lossyFlag|__CFGetASCIICompatibleFlag(), bytes, len, NULL, buffer->chars.unicode, (guessedLength > MAX_LOCAL_UNICHARS ? guessedLength : MAX_LOCAL_UNICHARS), &(buffer->numChars))) result = FALSE; } @@ -834,6 +834,7 @@ Boolean CFStringGetFileSystemRepresentation(CFStringRef string, char *buffer, CF #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED #define MAX_STACK_BUFFER_LEN (255) const UTF16Char *characters = CFStringGetCharactersPtr(string); + const char *origBuffer = buffer; const char *bufferLimit = buffer + maxBufLen; CFIndex length = CFStringGetLength(string); CFIndex usedBufLen; @@ -872,6 +873,11 @@ Boolean CFStringGetFileSystemRepresentation(CFStringRef string, char *buffer, CF if (buffer < bufferLimit) { // Since the filename has its own limit, this is ok for now *buffer = '\0'; + if (_CFExecutableLinkedOnOrAfter(CFSystemVersionLion)) { + while (origBuffer < buffer) if (*origBuffer++ == 0) { // There's a zero in there. Now see if the rest are all zeroes. + while (origBuffer < buffer) if (*origBuffer++ != 0) return false; // Embedded NULLs should cause failure: + } + } return true; } else { return false; @@ -896,7 +902,7 @@ void _CFStringGetUserDefaultEncoding(UInt32 *oScriptValue, UInt32 *oRegionValue) char buffer[__kCFMaxDefaultEncodingFileLength]; int uid = getuid(); - if ((stringValue = getenv(__kCFUserEncodingEnvVariableName)) != NULL) { + if ((stringValue = (char *)__CFgetenv(__kCFUserEncodingEnvVariableName)) != NULL) { if ((uid == strtol_l(stringValue, &stringValue, 0, NULL)) && (':' == *stringValue)) { ++stringValue; } else { @@ -904,7 +910,7 @@ void _CFStringGetUserDefaultEncoding(UInt32 *oScriptValue, UInt32 *oRegionValue) } } - if ((stringValue == NULL) && ((uid > 0) || getenv("HOME"))) { + if ((stringValue == NULL) && ((uid > 0) || __CFgetenv("HOME"))) { char passwdExtraBuf[1000 + MAXPATHLEN]; // Extra memory buffer for getpwuid_r(); no clue as to how large this should be... struct passwd passwdBuf, *passwdp = NULL; @@ -922,7 +928,7 @@ void _CFStringGetUserDefaultEncoding(UInt32 *oScriptValue, UInt32 *oRegionValue) const char *path = NULL; if (!issetugid()) { - path = getenv("CFFIXED_USER_HOME"); + path = __CFgetenv("CFFIXED_USER_HOME"); } if (!path) { path = passwdp->pw_dir; @@ -938,7 +944,7 @@ void _CFStringGetUserDefaultEncoding(UInt32 *oScriptValue, UInt32 *oRegionValue) snprintf(filename, sizeof(filename), "0x%X:0:0", uid); setenv(__kCFUserEncodingEnvVariableName, filename, 1); } else { - int readSize; + ssize_t readSize; readSize = read(fd, buffer, __kCFMaxDefaultEncodingFileLength - 1); buffer[(readSize < 0 ? 0 : readSize)] = '\0'; close(fd); @@ -983,7 +989,7 @@ void _CFStringGetInstallationEncodingAndRegion(uint32_t *encoding, uint32_t *reg int no_hang_fd = __CFProphylacticAutofsAccess ? open("/dev/autofs_nowait", 0) : -1; int fd = open(filename, O_RDONLY, 0); if (0 <= fd) { - size_t size = read(fd, buffer, __kCFMaxDefaultEncodingFileLength - 1); + ssize_t size = read(fd, buffer, __kCFMaxDefaultEncodingFileLength - 1); buffer[(size < 0 ? 0 : size)] = '\0'; close(fd); stringValue = buffer; @@ -1003,7 +1009,7 @@ Boolean _CFStringSaveUserDefaultEncoding(UInt32 iScriptValue, UInt32 iRegionValu if (passwdp) { const char *path = passwdp->pw_dir; if (!issetugid()) { - char *value = getenv("CFFIXED_USER_HOME"); + const char *value = __CFgetenv("CFFIXED_USER_HOME"); if (value) path = value; // override } diff --git a/CFStringScanner.c b/CFStringScanner.c index 4de445c..7852c7f 100644 --- a/CFStringScanner.c +++ b/CFStringScanner.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFStringScanner.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. Responsibility: Ali Ozer */ @@ -227,7 +227,7 @@ __private_extern__ Boolean __CFStringScanDouble(CFStringInlineBuffer *buf, CFTyp return true; } } -#endif 0 +#endif // 0 // Get characters until one not in __CFNumberSet[] is encountered while ((ch < 128) && (__CFNumberSet[ch >> 3] & (1 << (ch & 7)))) { if (numChars >= capacity - 1) { diff --git a/CFStringUtilities.c b/CFStringUtilities.c index 3744aa3..eb5a95b 100644 --- a/CFStringUtilities.c +++ b/CFStringUtilities.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFStringUtilities.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. Responsibility: Aki Inoue */ @@ -385,14 +385,16 @@ static UCollator *__CFStringCopyDefaultCollator(CFLocaleRef compareLocale) { if (compareLocale != __CFDefaultCollatorLocale) { currentLocale = CFLocaleCopyCurrent(); - CFRelease(currentLocale); - if (compareLocale != currentLocale) return NULL; + if (compareLocale != currentLocale) { + CFRelease(currentLocale); + return NULL; + } } __CFSpinLock(&__CFDefaultCollatorLock); if ((NULL != currentLocale) && (__CFDefaultCollatorLocale != currentLocale)) { while (__CFDefaultCollatorsCount > 0) ucol_close(__CFDefaultCollators[--__CFDefaultCollatorsCount]); - __CFDefaultCollatorLocale = currentLocale; + __CFDefaultCollatorLocale = CFRetain(currentLocale); } if (__CFDefaultCollatorsCount > 0) collator = __CFDefaultCollators[--__CFDefaultCollatorsCount]; @@ -402,14 +404,16 @@ static UCollator *__CFStringCopyDefaultCollator(CFLocaleRef compareLocale) { collator = __CFStringCreateCollator(compareLocale); } + if (NULL != currentLocale) CFRelease(currentLocale); + return collator; } #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED static void __collatorFinalize(UCollator *collator) { - CFLocaleRef locale = pthread_getspecific(__CFTSDKeyCollatorLocale); - pthread_setspecific(__CFTSDKeyCollatorUCollator, NULL); - pthread_setspecific(__CFTSDKeyCollatorLocale, NULL); + CFLocaleRef locale = _CFGetTSD(__CFTSDKeyCollatorLocale); + _CFSetTSD(__CFTSDKeyCollatorUCollator, NULL, NULL); + _CFSetTSD(__CFTSDKeyCollatorLocale, NULL, NULL); __CFSpinLock(&__CFDefaultCollatorLock); if ((__CFDefaultCollatorLocale == locale) && (__CFDefaultCollatorsCount < kCFMaxCachedDefaultCollators)) { __CFDefaultCollators[__CFDefaultCollatorsCount++] = collator; @@ -588,8 +592,8 @@ __private_extern__ CFComparisonResult _CFCompareStringsWithLocale(CFStringInline #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED // First we try to use the last one used on this thread, if the locale is the same, // otherwise we try to check out a default one, or then we create one. - UCollator *threadCollator = pthread_getspecific(__CFTSDKeyCollatorUCollator); - CFLocaleRef threadLocale = pthread_getspecific(__CFTSDKeyCollatorLocale); + UCollator *threadCollator = _CFGetTSD(__CFTSDKeyCollatorUCollator); + CFLocaleRef threadLocale = _CFGetTSD(__CFTSDKeyCollatorLocale); if (compareLocale == threadLocale) { collator = threadCollator; } else { @@ -716,11 +720,10 @@ __private_extern__ CFComparisonResult _CFCompareStringsWithLocale(CFStringInline if (collator == threadCollator) { // do nothing, already cached } else { - if (threadLocale) __collatorFinalize((UCollator *)pthread_getspecific(__CFTSDKeyCollatorUCollator)); // need to dealloc collators + if (threadLocale) __collatorFinalize((UCollator *)_CFGetTSD(__CFTSDKeyCollatorUCollator)); // need to dealloc collators - pthread_key_init_np(__CFTSDKeyCollatorUCollator, (void *)__collatorFinalize); - pthread_setspecific(__CFTSDKeyCollatorUCollator, collator); - pthread_setspecific(__CFTSDKeyCollatorLocale, CFRetain(compareLocale)); + _CFSetTSD(__CFTSDKeyCollatorUCollator, collator, (void *)__collatorFinalize); + _CFSetTSD(__CFTSDKeyCollatorLocale, (void *)CFRetain(compareLocale), NULL); } #endif diff --git a/CFSystemDirectories.c b/CFSystemDirectories.c index 10cfdbd..94f954f 100644 --- a/CFSystemDirectories.c +++ b/CFSystemDirectories.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFSystemDirectories.c - Copyright (c) 1997-2009, Apple Inc. All rights reserved. - Responsibility: Ali Ozer + Copyright (c) 1997-2011, Apple Inc. All rights reserved. + Responsibility: Kevin Perry */ /* @@ -65,7 +65,7 @@ CFSearchPathEnumerationState __CFGetNextSearchPathEnumeration(CFSearchPathEnumer #endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS CFArrayRef CFCopySearchPathForDirectoriesInDomains(CFSearchPathDirectory directory, CFSearchPathDomainMask domainMask, Boolean expandTilde) { CFMutableArrayRef array; diff --git a/CFTimeZone.c b/CFTimeZone.c index 3e0a7bb..2ed391b 100644 --- a/CFTimeZone.c +++ b/CFTimeZone.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,12 +22,11 @@ */ /* CFTimeZone.c - Copyright 1998-2002, Apple, Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ - #include #include #include @@ -41,18 +40,35 @@ #include #include #include -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX #include #include #include +#endif +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED #include -#else -#error Unknown or unspecified DEPLOYMENT_TARGET +#elif DEPLOYMENT_TARGET_LINUX +#ifndef TZDIR +#define TZDIR "/usr/share/zoneinfo" /* Time zone object file directory */ +#endif /* !defined TZDIR */ + +#ifndef TZDEFAULT +#define TZDEFAULT "/etc/localtime" +#endif /* !defined TZDEFAULT */ + +struct tzhead { + char tzh_magic[4]; /* TZ_MAGIC */ + char tzh_reserved[16]; /* reserved for future use */ + char tzh_ttisgmtcnt[4]; /* coded number of trans. time flags */ + char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */ + char tzh_leapcnt[4]; /* coded number of leap seconds */ + char tzh_timecnt[4]; /* coded number of transition times */ + char tzh_typecnt[4]; /* coded number of local time types */ + char tzh_charcnt[4]; /* coded number of abbr. chars */ +}; #endif -#import - -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX #define TZZONELINK TZDEFAULT #define TZZONEINFO TZDIR "/" #elif DEPLOYMENT_TARGET_WINDOWS @@ -63,6 +79,11 @@ static void __InitTZStrings(void); #error Unknown or unspecified DEPLOYMENT_TARGET #endif +#if DEPLOYMENT_TARGET_LINUX +// Symbol aliases +CF_EXPORT CFStringRef const kCFDateFormatterTimeZone __attribute__((weak, alias ("kCFDateFormatterTimeZoneKey"))); +#endif + CONST_STRING_DECL(kCFTimeZoneSystemTimeZoneDidChangeNotification, "kCFTimeZoneSystemTimeZoneDidChangeNotification") static CFTimeZoneRef __CFTimeZoneSystem = NULL; @@ -140,7 +161,7 @@ static CFMutableArrayRef __CFCopyWindowsTimeZoneList() { RegCloseKey(hkResult); return result; } -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS +#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX static CFMutableArrayRef __CFCopyRecursiveDirectoryList() { CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); #if DEPLOYMENT_TARGET_WINDOWS @@ -291,7 +312,6 @@ CF_INLINE void __CFEntzcode(int32_t value, unsigned char *bufp) { bufp[3] = (value >> 0) & 0xff; } -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC static Boolean __CFParseTimeZoneData(CFAllocatorRef allocator, CFDataRef data, CFTZPeriod **tzpp, CFIndex *cntp) { int32_t len, timecnt, typecnt, charcnt, idx, cnt; const uint8_t *p, *timep, *typep, *ttisp, *charp; @@ -408,20 +428,6 @@ static Boolean __CFParseTimeZoneData(CFAllocatorRef allocator, CFDataRef data, C } return result; } -#elif DEPLOYMENT_TARGET_WINDOWS_SAFARI -static Boolean __CFParseTimeZoneData(CFAllocatorRef allocator, CFDataRef data, CFTZPeriod **tzpp, CFIndex *cntp) { -/* We use Win32 function to find TimeZone - * (Aleksey Dukhnyakov) - */ - *tzpp = (CFTZPeriod *)CFAllocatorAllocate(allocator, sizeof(CFTZPeriod), 0); - memset(*tzpp, 0, sizeof(CFTZPeriod)); - __CFTZPeriodInit(*tzpp, 0, NULL, 0, false); - *cntp = 1; - return TRUE; -} -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif static Boolean __CFTimeZoneEqual(CFTypeRef cf1, CFTypeRef cf2) { CFTimeZoneRef tz1 = (CFTimeZoneRef)cf1; @@ -481,8 +487,7 @@ CFTypeID CFTimeZoneGetTypeID(void) { return __kCFTimeZoneTypeID; } - -#if DEPLOYMENT_TARGET_WINDOWS_SYNC +#if DEPLOYMENT_TARGET_WINDOWS static const char *__CFTimeZoneWinToOlsonDefaults = /* Mappings to time zones in Windows Registry are best-guess */ "" @@ -720,11 +725,10 @@ void __InitTZStrings(void) { } #endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC static CFTimeZoneRef __CFTimeZoneCreateSystem(void) { CFTimeZoneRef result = NULL; -#if DEPLOYMENT_TARGET_WINDOWS_SYNC +#if DEPLOYMENT_TARGET_WINDOWS CFStringRef name = NULL; TIME_ZONE_INFORMATION tzi = { 0 }; DWORD rval = GetTimeZoneInformation(&tzi); @@ -780,32 +784,6 @@ static CFTimeZoneRef __CFTimeZoneCreateSystem(void) { } return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault, 0.0); } -#elif DEPLOYMENT_TARGET_WINDOWS_SAFARI -static CFTimeZoneRef __CFTimeZoneCreateSystem(void) { - CFTimeZoneRef result = NULL; -/* The GetTimeZoneInformation function retrieves the current - * time-zone parameters for Win32 - * (Aleksey Dukhnyakov) - */ - CFDataRef data; - TIME_ZONE_INFORMATION tz; - DWORD dw_result; - dw_result=GetTimeZoneInformation(&tz); - - if ( dw_result == TIME_ZONE_ID_STANDARD || - dw_result == TIME_ZONE_ID_DAYLIGHT ) { - CFStringRef name = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)tz.StandardName, wcslen(tz.StandardName)); - data = CFDataCreate(kCFAllocatorSystemDefault, (UInt8 *)&tz, sizeof(tz)); - result = CFTimeZoneCreate(kCFAllocatorSystemDefault, name, data); - CFRelease(name); - CFRelease(data); - if (result) return result; - } - return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault, 0.0); -} -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif CFTimeZoneRef CFTimeZoneCopySystem(void) { CFTimeZoneRef tz; @@ -882,13 +860,7 @@ CFArrayRef CFTimeZoneCopyKnownNames(void) { /* TimeZone information locate in the registry for Win32 * (Aleksey Dukhnyakov) */ -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC list = __CFCopyRecursiveDirectoryList(); -#elif DEPLOYMENT_TARGET_WINDOWS_SAFARI - list = __CFCopyWindowsTimeZoneList(); -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif // Remove undesirable ancient cruft CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary(); CFIndex idx; @@ -906,7 +878,6 @@ CFArrayRef CFTimeZoneCopyKnownNames(void) { return tzs; } -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC /* The criteria here are sort of: coverage for the U.S. and Europe, * large cities, abbreviation uniqueness, and perhaps a few others. * But do not make the list too large with obscure information. @@ -966,66 +937,6 @@ static const char *__CFTimeZoneAbbreviationDefaults = " WIT Asia/Jakarta" " " " "; -#elif DEPLOYMENT_TARGET_WINDOWS_SAFARI -static const char *__CFTimeZoneAbbreviationDefaults = -/* Mappings to time zones in Windows Registry are best-guess */ -"" -" " -" " -" " -" ADT Atlantic Standard Time" -" AKDT Alaskan Standard Time" -" AKST Alaskan Standard Time" -" ART SA Eastern Standard Time" -" AST Atlantic Standard Time" -" BDT Central Asia Standard Time" -" BRST SA Eastern Standard Time" -" BRT SA Eastern Standard Time" -" BST GMT Standard Time" -" CAT South Africa Standard Time" -" CDT Central Standard Time" -" CEST Central Europe Standard Time" -" CET Central Europe Standard Time" -" CLST SA Western Standard Time" -" CLT SA Western Standard Time" -" COT Central Standard Time" -" CST Central Standard Time" -" EAT E. Africa Standard Time" -" EDT Eastern Standard Time" -" EEST E. Europe Standard Time" -" EET E. Europe Standard Time" -" EST Eastern Standard Time" -" GMT Greenwich Standard Time" -" GST Arabian Standard Time" -" HKT China Standard Time" -" HST Hawaiian Standard Time" -" ICT SE Asia Standard Time" -" IRST Iran Standard Time" -" IST India Standard Time" -" JST Tokyo Standard Time" -" KST Korea Standard Time" -" MDT Mountain Standard Time" -" MSD E. Europe Standard Time" -" MSK E. Europe Standard Time" -" MST Mountain Standard Time" -" NZDT New Zealand Standard Time" -" NZST New Zealand Standard Time" -" PDT Pacific Standard Time" -" PET SA Pacific Standard Time" -" PHT Taipei Standard Time" -" PKT West Asia Standard Time" -" PST Pacific Standard Time" -" SGT Singapore Standard Time" -" UTC Greenwich Standard Time" -" WAT W. Central Africa Standard Time" -" WEST W. Europe Standard Time" -" WET W. Europe Standard Time" -" WIT SE Asia Standard Time" -" " -" "; -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif CFDictionaryRef CFTimeZoneCopyAbbreviationDictionary(void) { CFDictionaryRef dict; @@ -1043,15 +954,17 @@ CFDictionaryRef CFTimeZoneCopyAbbreviationDictionary(void) { return dict; } +void _removeFromCache(const void *key, const void *value, void *context) { + CFDictionaryRemoveValue(__CFTimeZoneCache, (CFStringRef)key); +} + void CFTimeZoneSetAbbreviationDictionary(CFDictionaryRef dict) { __CFGenericValidateType(dict, CFDictionaryGetTypeID()); __CFTimeZoneLockGlobal(); if (dict != __CFTimeZoneAbbreviationDict) { if (dict) CFRetain(dict); if (__CFTimeZoneAbbreviationDict) { - for (id key in (id)__CFTimeZoneAbbreviationDict) { - CFDictionaryRemoveValue(__CFTimeZoneCache, (CFStringRef)key); - } + CFDictionaryApplyFunction(__CFTimeZoneAbbreviationDict, _removeFromCache, NULL); CFRelease(__CFTimeZoneAbbreviationDict); } __CFTimeZoneAbbreviationDict = dict; @@ -1101,7 +1014,6 @@ CFTimeZoneRef CFTimeZoneCreate(CFAllocatorRef allocator, CFStringRef name, CFDat return memory; } -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC static CFTimeZoneRef __CFTimeZoneCreateFixed(CFAllocatorRef allocator, int32_t seconds, CFStringRef name, int isDST) { CFTimeZoneRef result; CFDataRef data; @@ -1127,28 +1039,7 @@ static CFTimeZoneRef __CFTimeZoneCreateFixed(CFAllocatorRef allocator, int32_t s CFRelease(data); return result; } -#elif DEPLOYMENT_TARGET_WINDOWS_SAFARI -static CFTimeZoneRef __CFTimeZoneCreateFixed(CFAllocatorRef allocator, int32_t seconds, CFStringRef name, int isDST) { -/* CFTimeZoneRef->_data will contain TIME_ZONE_INFORMATION structure - * to find current timezone - * (Aleksey Dukhnyakov) - */ - CFTimeZoneRef result; - TIME_ZONE_INFORMATION tzi; - CFDataRef data; - CFIndex length = CFStringGetLength(name); - memset(&tzi,0,sizeof(tzi)); - tzi.Bias=(long)(-seconds/60); - CFStringGetCharacters(name, CFRangeMake(0, length < 31 ? length : 31 ), (UniChar *)tzi.StandardName); - data = CFDataCreate(allocator,(UInt8 *)&tzi, sizeof(tzi)); - result = CFTimeZoneCreate(allocator, name, data); - CFRelease(data); - return result; -} -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif // rounds offset to nearest minute CFTimeZoneRef CFTimeZoneCreateWithTimeIntervalFromGMT(CFAllocatorRef allocator, CFTimeInterval ti) { @@ -1164,13 +1055,7 @@ CFTimeZoneRef CFTimeZoneCreateWithTimeIntervalFromGMT(CFAllocatorRef allocator, seconds -= ((ti < 0) ? -hour : hour) * 3600; minute = (ti < 0) ? (-seconds / 60) : (seconds / 60); if (fabs(ti) < 1.0) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC name = (CFStringRef)CFRetain(CFSTR("GMT")); -#elif DEPLOYMENT_TARGET_WINDOWS_SAFARI - name = (CFStringRef)CFRetain(CFSTR("Greenwich Standard Time")); -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif } else { name = CFStringCreateWithFormat(allocator, NULL, CFSTR("GMT%c%02d%02d"), (ti < 0.0 ? '-' : '+'), hour, minute); } @@ -1222,12 +1107,11 @@ CFTimeZoneRef CFTimeZoneCreateWithName(CFAllocatorRef allocator, CFStringRef nam } } } -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC CFURLRef baseURL, tempURL; void *bytes; CFIndex length; -#if DEPLOYMENT_TARGET_WINDOWS_SYNC +#if DEPLOYMENT_TARGET_WINDOWS if (!__tzZoneInfo) __InitTZStrings(); if (!__tzZoneInfo) return NULL; baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, __tzZoneInfo, kCFURLWindowsPathStyle, true); @@ -1253,7 +1137,7 @@ CFTimeZoneRef CFTimeZoneCreateWithName(CFAllocatorRef allocator, CFStringRef nam CFStringRef mapping = CFDictionaryGetValue(dict, name); if (mapping) { name = mapping; -#if DEPLOYMENT_TARGET_WINDOWS_SYNC +#if DEPLOYMENT_TARGET_WINDOWS } else if (CFStringHasPrefix(name, __tzZoneInfo)) { CFMutableStringRef unprefixed = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, CFStringGetLength(name), name); CFStringDelete(unprefixed, CFRangeMake(0, CFStringGetLength(__tzZoneInfo))); @@ -1297,112 +1181,6 @@ CFTimeZoneRef CFTimeZoneCreateWithName(CFAllocatorRef allocator, CFStringRef nam } return result; } -#elif DEPLOYMENT_TARGET_WINDOWS_SAFARI -/* Reading GMT offset and daylight flag from the registry - * for TimeZone name - * (Aleksey Dukhnyakov) - */ - { - CFStringRef safeName = name; - struct { - LONG Bias; - LONG StandardBias; - LONG DaylightBias; - SYSTEMTIME StandardDate; - SYSTEMTIME DaylightDate; - } tzi; - TIME_ZONE_INFORMATION tzi_system; - - HKEY hkResult; - DWORD dwType, dwSize=sizeof(tzi), - dwSize_name1=sizeof(tzi_system.StandardName), - dwSize_name2=sizeof(tzi_system.DaylightName); - - if (tryAbbrev) { - CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary(); - tzName = (CFStringRef)CFDictionaryGetValue(abbrevs, name); - if (NULL == tzName) { - CFRelease(abbrevs); - return NULL; - } - name = tzName; - CFRelease(abbrevs); - } - -/* Open regestry and move down to the TimeZone information - */ - if (RegOpenKey(HKEY_LOCAL_MACHINE,_T(TZZONEINFO),&hkResult) != - ERROR_SUCCESS ) { - return NULL; - } -/* Move down to specific TimeZone name - */ -#if defined(UNICODE) - UniChar *uniTimeZone = (UniChar*)CFStringGetCharactersPtr(name); - if (uniTimeZone == NULL) { - // We need to extract the bytes out of the CFStringRef and create our own - // UNICODE string to pass to the Win32 API - RegOpenKey. - UInt8 uniBuff[MAX_PATH+2]; // adding +2 to handle Unicode-null termination /0/0. - CFIndex usedBuff = 0; - CFIndex numChars = CFStringGetBytes(name, CFRangeMake(0, CFStringGetLength(name)), kCFStringEncodingUnicode, 0, FALSE, uniBuff, MAX_PATH, &usedBuff); - if (numChars == 0) { - return NULL; - } else { - // NULL-terminate the newly created Unicode string. - uniBuff[usedBuff] = '\0'; - uniBuff[usedBuff+1] = '\0'; - } - - if (RegOpenKey(hkResult, (LPCWSTR)uniBuff ,&hkResult) != ERROR_SUCCESS ) { - return NULL; - } - } else { - if (RegOpenKey(hkResult, (LPCWSTR)uniTimeZone ,&hkResult) != ERROR_SUCCESS ) { - return NULL; - } - } -#else - if (RegOpenKey(hkResult,CFStringGetCStringPtr(name, CFStringGetSystemEncoding()),&hkResult) != ERROR_SUCCESS ) { - return NULL; - } -#endif - -/* TimeZone information(offsets, daylight flag, ...) assign to tzi structure - */ - if ( RegQueryValueEx(hkResult,_T("TZI"),NULL,&dwType,(LPBYTE)&tzi,&dwSize) != ERROR_SUCCESS && - RegQueryValueEx(hkResult,_T("Std"),NULL,&dwType,(LPBYTE)&tzi_system.StandardName,&dwSize_name1) != ERROR_SUCCESS && - RegQueryValueEx(hkResult,_T("Dlt"),NULL,&dwType,(LPBYTE)&tzi_system.DaylightName,&dwSize_name2) != ERROR_SUCCESS ) - { - return NULL; - } - - tzi_system.Bias=tzi.Bias; - tzi_system.StandardBias=tzi.StandardBias; - tzi_system.DaylightBias=tzi.DaylightBias; - tzi_system.StandardDate=tzi.StandardDate; - tzi_system.DaylightDate=tzi.DaylightDate; - -/* CFTimeZoneRef->_data will contain TIME_ZONE_INFORMATION structure - * to find current timezone - * (Aleksey Dukhnyakov) - */ - data = CFDataCreate(allocator,(UInt8 *)&tzi_system, sizeof(tzi_system)); - - RegCloseKey(hkResult); - result = CFTimeZoneCreate(allocator, name, data); - if (result) { - if (tryAbbrev) - result->_periods->abbrev = (CFStringRef)CFStringCreateCopy(allocator,safeName); - else { - } - } - CFRelease(data); - } - return result; -} -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif CFStringRef CFTimeZoneGetName(CFTimeZoneRef tz) { CF_OBJC_FUNCDISPATCH0(CFTimeZoneGetTypeID(), CFStringRef, tz, "name"); @@ -1435,169 +1213,29 @@ BOOL __CFTimeZoneGetWin32SystemTime(SYSTEMTIME * sys_time, CFAbsoluteTime time) else return FALSE; } -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif CFTimeInterval CFTimeZoneGetSecondsFromGMT(CFTimeZoneRef tz, CFAbsoluteTime at) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC CFIndex idx; - CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval, tz, "_secondsFromGMTForAbsoluteTime:", at); __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); idx = __CFBSearchTZPeriods(tz, at); return __CFTZPeriodGMTOffset(&(tz->_periods[idx])); -#elif DEPLOYMENT_TARGET_WINDOWS_SAFARI -/* To calculate seconds from GMT, calculate current timezone time and - * subtract GMT timnezone time - * (Aleksey Dukhnyakov) - */ - TIME_ZONE_INFORMATION tzi; - FILETIME ftime1,ftime2; - SYSTEMTIME stime0,stime1,stime2; - LONGLONG * l1= (LONGLONG*)&ftime1; - LONGLONG * l2= (LONGLONG*)&ftime2; - CFRange range={0,sizeof(TIME_ZONE_INFORMATION)}; - double result; - - CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval, tz, "_secondsFromGMTForAbsoluteTime:", at); - - CFDataGetBytes(tz->_data,range,(UInt8 *)&tzi); - - if (!__CFTimeZoneGetWin32SystemTime(&stime0,at) || - !SystemTimeToTzSpecificLocalTime(&tzi,&stime0,&stime1) || - !SystemTimeToFileTime(&stime1,&ftime1) ) - { - CFAssert(0, __kCFLogAssertion, "Win32 system time/timezone failed !\n"); - return 0; - } - - tzi.DaylightDate.wMonth=0; - tzi.StandardDate.wMonth=0; - tzi.StandardBias=0; - tzi.DaylightBias=0; - tzi.Bias=0; - - if ( !SystemTimeToTzSpecificLocalTime(&tzi,&stime0,&stime2) || - !SystemTimeToFileTime(&stime2,&ftime2)) - { - CFAssert(0, __kCFLogAssertion, "Win32 system time/timezone failed !\n"); - return 0; - } - result=(double)((*l1-*l2)/10000000); - return result; -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif } -#if DEPLOYMENT_TARGET_WINDOWS_SAFARI -/* - * Get abbreviation for name for WIN32 platform - * (Aleksey Dukhnyakov) - */ - -typedef struct { - CFStringRef tzName; - CFStringRef tzAbbr; -} _CFAbbrFind; - -static void _CFFindKeyForValue(const void *key, const void *value, void *context) { - if ( ((_CFAbbrFind *)context)->tzAbbr != NULL ) { - if ( ((_CFAbbrFind *)context)->tzName == (CFStringRef) value ) { - ((_CFAbbrFind *)context)->tzAbbr = (CFStringRef)key ; - } - } -} - -CFIndex __CFTimeZoneInitAbbrev(CFTimeZoneRef tz) { - - if ( tz->_periods->abbrev == NULL ) { - _CFAbbrFind abbr = { NULL, NULL }; - CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary(); - - CFDictionaryApplyFunction(abbrevs, _CFFindKeyForValue, &abbr); - - if ( abbr.tzAbbr != NULL) - tz->_periods->abbrev = (CFStringRef)CFStringCreateCopy(kCFAllocatorSystemDefault, abbr.tzAbbr); - else - tz->_periods->abbrev = (CFStringRef)CFStringCreateCopy(kCFAllocatorSystemDefault, tz->_name); -/* We should return name of TimeZone if couldn't find abbrevation. - * (Ala on MACOSX) - * - * (Aleksey Dukhnyakov) -*/ - CFRelease( abbrevs ); - } - - return 0; -} -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif - CFStringRef CFTimeZoneCopyAbbreviation(CFTimeZoneRef tz, CFAbsoluteTime at) { CFStringRef result; CFIndex idx; - CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFStringRef, tz, "_abbreviationForAbsoluteTime:", at); __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC idx = __CFBSearchTZPeriods(tz, at); -#elif DEPLOYMENT_TARGET_WINDOWS_SAFARI -/* - * Initialize abbreviation for this TimeZone - * (Aleksey Dukhnyakov) - */ - idx = __CFTimeZoneInitAbbrev(tz); -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif result = __CFTZPeriodAbbreviation(&(tz->_periods[idx])); return result ? (CFStringRef)CFRetain(result) : NULL; } Boolean CFTimeZoneIsDaylightSavingTime(CFTimeZoneRef tz, CFAbsoluteTime at) { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS_SYNC CFIndex idx; - CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), Boolean, tz, "_isDaylightSavingTimeForAbsoluteTime:", at); __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); idx = __CFBSearchTZPeriods(tz, at); return __CFTZPeriodIsDST(&(tz->_periods[idx])); -#elif DEPLOYMENT_TARGET_WINDOWS_SAFARI -/* Compare current timezone time and current timezone time without - * transition to day light saving time - * (Aleskey Dukhnyakov) - */ - TIME_ZONE_INFORMATION tzi; - SYSTEMTIME stime0,stime1,stime2; - CFRange range={0,sizeof(TIME_ZONE_INFORMATION)}; - - CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), Boolean, tz, "_isDaylightSavingTimeForAbsoluteTime:", at); - - CFDataGetBytes(tz->_data,range,(UInt8 *)&tzi); - - if ( !__CFTimeZoneGetWin32SystemTime(&stime0,at) || - !SystemTimeToTzSpecificLocalTime(&tzi,&stime0,&stime1)) { - CFAssert(0, __kCFLogAssertion, "Win32 system time/timezone failed !\n"); - return FALSE; - } - - tzi.DaylightDate.wMonth=0; - tzi.StandardDate.wMonth=0; - - if ( !SystemTimeToTzSpecificLocalTime(&tzi,&stime0,&stime2)) { - CFAssert(0, __kCFLogAssertion, "Win32 system time/timezone failed !\n"); - return FALSE; - } - - if ( !memcmp(&stime1,&stime2,sizeof(stime1)) ) - return FALSE; - - return TRUE; -#else -#error Unknown or unspecified DEPLOYMENT_TARGET -#endif } CFTimeInterval CFTimeZoneGetDaylightSavingTimeOffset(CFTimeZoneRef tz, CFAbsoluteTime at) { diff --git a/CFTimeZone.h b/CFTimeZone.h index 824b1ea..e7fe9e2 100644 --- a/CFTimeZone.h +++ b/CFTimeZone.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFTimeZone.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFTIMEZONE__) @@ -86,10 +86,10 @@ CF_EXPORT Boolean CFTimeZoneIsDaylightSavingTime(CFTimeZoneRef tz, CFAbsoluteTime at); CF_EXPORT -CFTimeInterval CFTimeZoneGetDaylightSavingTimeOffset(CFTimeZoneRef tz, CFAbsoluteTime at) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFTimeInterval CFTimeZoneGetDaylightSavingTimeOffset(CFTimeZoneRef tz, CFAbsoluteTime at) CF_AVAILABLE(10_5, 2_0); CF_EXPORT -CFAbsoluteTime CFTimeZoneGetNextDaylightSavingTimeTransition(CFTimeZoneRef tz, CFAbsoluteTime at) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +CFAbsoluteTime CFTimeZoneGetNextDaylightSavingTimeTransition(CFTimeZoneRef tz, CFAbsoluteTime at) CF_AVAILABLE(10_5, 2_0); #if MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED enum { @@ -100,14 +100,14 @@ enum { kCFTimeZoneNameStyleGeneric, kCFTimeZoneNameStyleShortGeneric }; +#endif typedef CFIndex CFTimeZoneNameStyle; CF_EXPORT -CFStringRef CFTimeZoneCopyLocalizedName(CFTimeZoneRef tz, CFTimeZoneNameStyle style, CFLocaleRef locale) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; -#endif +CFStringRef CFTimeZoneCopyLocalizedName(CFTimeZoneRef tz, CFTimeZoneNameStyle style, CFLocaleRef locale) CF_AVAILABLE(10_5, 2_0); CF_EXPORT -const CFStringRef kCFTimeZoneSystemTimeZoneDidChangeNotification AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +const CFStringRef kCFTimeZoneSystemTimeZoneDidChangeNotification CF_AVAILABLE(10_5, 2_0); CF_EXTERN_C_END diff --git a/CFTree.c b/CFTree.c index ee37e29..56ba469 100644 --- a/CFTree.c +++ b/CFTree.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFTree.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. Responsibility: Christopher Kane */ @@ -86,7 +86,6 @@ static CFStringRef __CFTreeCopyDescription(CFTypeRef cf) { CFTreeRef tree = (CFTreeRef)cf; CFMutableStringRef result; CFStringRef contextDesc = NULL; - Boolean safeToReleaseContextDesc = true; const struct __CFTreeCallBacks *cb; CFAllocatorRef allocator; allocator = CFGetAllocator(tree); @@ -94,13 +93,12 @@ static CFStringRef __CFTreeCopyDescription(CFTypeRef cf) { cb = __CFTreeGetCallBacks(tree); if (NULL != cb->copyDescription) { contextDesc = (CFStringRef)INVOKE_CALLBACK1(cb->copyDescription, tree->_info); - safeToReleaseContextDesc = _CFExecutableLinkedOnOrAfter(CFSystemVersionTiger); // Because it came from elsewhere, only free it compatibly (3593254) } if (NULL == contextDesc) { contextDesc = CFStringCreateWithFormat(allocator, NULL, CFSTR(""), tree->_info); } CFStringAppendFormat(result, NULL, CFSTR("{children = %u, context = %@}"), cf, allocator, CFTreeGetChildCount(tree), contextDesc); - if (contextDesc && safeToReleaseContextDesc) CFRelease(contextDesc); + if (contextDesc) CFRelease(contextDesc); return result; } @@ -329,7 +327,7 @@ void CFTreePrependChild(CFTreeRef tree, CFTreeRef newChild) { __CFGenericValidateType(newChild, __kCFTreeTypeID); CFAssert1(NULL == newChild->_parent, __kCFLogAssertion, "%s(): must remove newChild from previous parent first", __PRETTY_FUNCTION__); CFAssert1(NULL == newChild->_sibling, __kCFLogAssertion, "%s(): must remove newChild from previous parent first", __PRETTY_FUNCTION__); - _CFRetainGC(newChild); + if (!kCFUseCollectableAllocator) CFRetain(newChild); __CFAssignWithWriteBarrier((void **)&newChild->_parent, tree); __CFAssignWithWriteBarrier((void **)&newChild->_sibling, tree->_child); if (!tree->_child) { @@ -347,7 +345,7 @@ void CFTreeAppendChild(CFTreeRef tree, CFTreeRef newChild) { if (newChild->_parent) { HALT; } - _CFRetainGC(newChild); + if (!kCFUseCollectableAllocator) CFRetain(newChild); allocator = CFGetAllocator(tree); __CFAssignWithWriteBarrier((void **)&newChild->_parent, tree); newChild->_sibling = NULL; @@ -366,7 +364,7 @@ void CFTreeInsertSibling(CFTreeRef tree, CFTreeRef newSibling) { CFAssert1(NULL != tree->_parent, __kCFLogAssertion, "%s(): tree must have a parent", __PRETTY_FUNCTION__); CFAssert1(NULL == newSibling->_parent, __kCFLogAssertion, "%s(): must remove newSibling from previous parent first", __PRETTY_FUNCTION__); CFAssert1(NULL == newSibling->_sibling, __kCFLogAssertion, "%s(): must remove newSibling from previous parent first", __PRETTY_FUNCTION__); - _CFRetainGC(newSibling); + if (!kCFUseCollectableAllocator) CFRetain(newSibling); allocator = CFGetAllocator(tree); __CFAssignWithWriteBarrier((void **)&newSibling->_parent, tree->_parent); __CFAssignWithWriteBarrier((void **)&newSibling->_sibling, tree->_sibling); @@ -400,7 +398,7 @@ void CFTreeRemove(CFTreeRef tree) { } tree->_parent = NULL; tree->_sibling = NULL; - _CFReleaseGC(tree); + if (!kCFUseCollectableAllocator) CFRelease(tree); } } @@ -414,7 +412,7 @@ void CFTreeRemoveAllChildren(CFTreeRef tree) { CFTreeRef nextSibling = nextChild->_sibling; nextChild->_parent = NULL; nextChild->_sibling = NULL; - _CFReleaseGC(nextChild); + if (!kCFUseCollectableAllocator) CFRelease(nextChild); nextChild = nextSibling; } } diff --git a/CFTree.h b/CFTree.h index 2b55e03..4fbd09c 100644 --- a/CFTree.h +++ b/CFTree.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFTree.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ /*! @header CFTree diff --git a/CFURL.c b/CFURL.c index fb6ec7c..786c5ba 100644 --- a/CFURL.c +++ b/CFURL.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFURL.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. - Responsibility: Becky Willrich + Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Responsibility: John Iarocci */ #include @@ -32,23 +32,18 @@ #include #include "CFInternal.h" #include -#include #include #include #include #include +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX #if DEPLOYMENT_TARGET_MACOSX #include +#endif #include #include #include -#elif DEPLOYMENT_TARGET_EMBEDDED -#include -#include -#include -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET +#include #endif #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED @@ -61,9 +56,6 @@ CFStringRef CFURLCreateStringWithFileSystemPath(CFAllocatorRef allocator, CFURLR CF_EXPORT CFURLRef _CFURLCreateCurrentDirectoryURL(CFAllocatorRef allocator); #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED static CFStringRef HFSPathToURLPath(CFStringRef path, CFAllocatorRef alloc, Boolean isDir); -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif @@ -137,6 +129,8 @@ static UInt32 numNonUTF8EncodedURLs = 0; #define FILE_ID_PREFIX ".file" #define FILE_ID_KEY "id" +#define FILE_ID_PREAMBLE "/.file/id=" +#define FILE_ID_PREAMBLE_LENGTH 10 #define ASSERT_CHECK_PATHSTYLE(x) 0 @@ -461,7 +455,7 @@ CF_INLINE CFStringRef _replacePathIllegalCharacters(CFStringRef str, CFAllocator return CFURLCreateStringByAddingPercentEscapes(alloc, str, NULL, CFSTR(";?"), kCFStringEncodingUTF8); } else { return CFURLCreateStringByAddingPercentEscapes(alloc, str, NULL, CFSTR(";?/"), kCFStringEncodingUTF8); - } + } } #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED @@ -576,7 +570,7 @@ CFStringRef CFURLCreateStringByReplacingPercentEscapes(CFAllocatorRef alloc, CF if (!strForEscapedChar) { strForEscapedChar = CFStringCreateMutableWithExternalCharactersNoCopy(alloc, &escapedChar, 1, 1, kCFAllocatorNull); } - escapedStr = strForEscapedChar; + escapedStr = (CFStringRef)CFRetain(strForEscapedChar); } else { CFIndex j; // Make sure up front that we have enough characters @@ -599,7 +593,7 @@ CFStringRef CFURLCreateStringByReplacingPercentEscapes(CFAllocatorRef alloc, CF strForEscapedChar = CFStringCreateMutableWithExternalCharactersNoCopy(alloc, &escapedChar, 1, 1, kCFAllocatorNull); } CFRelease(escapedStr); - escapedStr = strForEscapedChar; + escapedStr = (CFStringRef)CFRetain(strForEscapedChar); } if (failed) break; } @@ -610,7 +604,7 @@ CFStringRef CFURLCreateStringByReplacingPercentEscapes(CFAllocatorRef alloc, CF if (!escapeAll) { if (CFStringFind(charactersToLeaveEscaped, escapedStr, 0).location != kCFNotFound) { - if (escapedStr != strForEscapedChar) { + if (escapedStr) { CFRelease(escapedStr); escapedStr = NULL; } @@ -628,14 +622,14 @@ CFStringRef CFURLCreateStringByReplacingPercentEscapes(CFAllocatorRef alloc, CF CFRelease(substring); } CFStringAppend(newStr, escapedStr); - if (escapedStr != strForEscapedChar) { + if (escapedStr) { CFRelease(escapedStr); escapedStr = NULL; } mark = searchRange.location;// We need mark to be the index of the first character beyond the escape sequence } - if (escapedStr && escapedStr != strForEscapedChar) CFRelease(escapedStr); + if (escapedStr) CFRelease(escapedStr); if (strForEscapedChar) CFRelease(strForEscapedChar); if (failed) { if (newStr) CFRelease(newStr); @@ -731,7 +725,6 @@ CFStringRef CFURLCreateStringByReplacingPercentEscapesUsingEncoding(CFAllocatorR if (escapeAll) { CFStringAppend(newStr, convertedString); - CFRelease(convertedString); } else { CFIndex i, c = CFStringGetLength(convertedString); if (!escapedStr) { @@ -747,6 +740,7 @@ CFStringRef CFURLCreateStringByReplacingPercentEscapesUsingEncoding(CFAllocatorR } } } + CFRelease(convertedString); mark = searchRange.location;// We need mark to be the index of the first character beyond the escape sequence } @@ -1430,13 +1424,13 @@ static void _parseComponents(CFAllocatorRef alloc, CFStringRef string, CFURLRef break; } } -#if DEPLOYMENT_TARGET_MACOSX +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED if (pathRg.length > 6 && STRING_CHAR(pathRg.location) == '/' && STRING_CHAR(pathRg.location + 1) == '.' && STRING_CHAR(pathRg.location + 2) == 'f' && STRING_CHAR(pathRg.location + 3) == 'i' && STRING_CHAR(pathRg.location + 4) == 'l' && STRING_CHAR(pathRg.location + 5) == 'e' && STRING_CHAR(pathRg.location + 6) == '/') { flags |= PATH_HAS_FILE_ID; } else if (!sawPercent) { flags |= POSIX_AND_URL_PATHS_MATCH; } -#elif DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS +#elif DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_WINDOWS if (!sawPercent) { flags |= POSIX_AND_URL_PATHS_MATCH; } @@ -1628,18 +1622,19 @@ CF_EXPORT CFURLRef _CFURLAlloc(CFAllocatorRef allocator) { #endif url = (struct __CFURL *)_CFRuntimeCreateInstance(allocator, __kCFURLTypeID, sizeof(struct __CFURL) - sizeof(CFRuntimeBase), NULL); if (url) { - url->_flags = 0; - if (createOldUTF8StyleURLs()) { - url->_flags |= IS_OLD_UTF8_STYLE; - } - url->_string = NULL; - url->_base = NULL; - url->ranges = NULL; - // url->_reserved = NULL; - url->_encoding = kCFStringEncodingUTF8; - // url->_sanatizedString = NULL; - url->extra = NULL; - } + url->_flags = 0; + if (createOldUTF8StyleURLs()) { + url->_flags |= IS_OLD_UTF8_STYLE; + } + url->_encoding = kCFStringEncodingUTF8; + url->_string = NULL; + url->_base = NULL; + url->ranges = NULL; + url->extra = NULL; + url->_resourceInfo = NULL; + // url->_reserved = NULL; + // url->_sanatizedString = NULL; + } return url; } @@ -1650,19 +1645,19 @@ static void _CFURLInit(struct __CFURL *url, CFStringRef URLString, UInt32 fsType // Coming in, the url has its allocator flag properly set, and its base initialized, and nothing else. url->_string = (CFStringRef)CFStringCreateCopy(CFGetAllocator(url), URLString); url->_flags |= (fsType << 16); - - url->_base = base ? CFURLCopyAbsoluteURL(base) : NULL; - - #if DEBUG_URL_MEMORY_USAGE + + url->_base = base ? CFURLCopyAbsoluteURL(base) : NULL; + +#if DEBUG_URL_MEMORY_USAGE if (fsType != FULL_URL_REPRESENTATION) { numFileURLsCreated ++; } if ( url->_base ) - numURLsWithBaseURL ++; - #endif + numURLsWithBaseURL ++; +#endif } -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX CF_EXPORT void _CFURLInitFSPath(CFURLRef url, CFStringRef path) { CFIndex len = CFStringGetLength(path); if (len && CFStringGetCharacterAtIndex(path, 0) == '/') { @@ -1680,14 +1675,21 @@ CF_EXPORT void _CFURLInitFSPath(CFURLRef url, CFStringRef path) { #elif DEPLOYMENT_TARGET_WINDOWS CF_EXPORT void _CFURLInitFSPath(CFURLRef url, CFStringRef path) { CFIndex len = CFStringGetLength(path); + // be sure to use the windows path separator when checking the path to see if it's a directory here + if (!len || '\\' == CFStringGetCharacterAtIndex(path, len - 1)) + ((struct __CFURL *)url)->_flags |= IS_DIRECTORY; UniChar firstChar = 0 < len ? CFStringGetCharacterAtIndex(path, 0) : 0; UniChar secondChar = 1 < len ? CFStringGetCharacterAtIndex(path, 1) : 0; Boolean isDrive = ('A' <= firstChar && firstChar <= 'Z') || ('a' <= firstChar && firstChar <= 'z'); + if (!len || '/' == CFStringGetCharacterAtIndex(path, len - 1)) + ((struct __CFURL *)url)->_flags |= IS_DIRECTORY; isDrive = isDrive && (secondChar == ':' || secondChar == '|'); if (isDrive || (firstChar == '\\' && secondChar == '\\')) { _CFURLInit((struct __CFURL *)url, path, kCFURLWindowsPathStyle, NULL); ((struct __CFURL *)url)->_flags |= IS_ABSOLUTE; } else if (firstChar == '/') { + if (!len || '/' == CFStringGetCharacterAtIndex(path, len - 1)) + ((struct __CFURL *)url)->_flags |= IS_DIRECTORY; _CFURLInit((struct __CFURL *)url, path, kCFURLPOSIXPathStyle, NULL); ((struct __CFURL *)url)->_flags |= IS_ABSOLUTE; } else { @@ -1696,8 +1698,6 @@ CF_EXPORT void _CFURLInitFSPath(CFURLRef url, CFStringRef path) { if ( cwdURL ) CFRelease(cwdURL); } - if (!len || '/' == CFStringGetCharacterAtIndex(path, len - 1)) - ((struct __CFURL *)url)->_flags |= IS_DIRECTORY; } #else #error Unknown or unspecified DEPLOYMENT_TARGET @@ -1752,7 +1752,12 @@ CF_EXPORT Boolean _CFStringIsLegalURLString(CFStringRef string) { sawHash = true; continue; } +#if DEPLOYMENT_TARGET_WINDOWS + // CF on Windows: CFURLCreateWithString should work with | in path on Windows + if (isURLLegalCharacter(ch) || ch == '|') +#else if ( isURLLegalCharacter( ch ) ) +#endif continue; break; } @@ -1834,6 +1839,7 @@ static CFIndex _convertEscapeSequence(CFIndex percentIndex, CFStringRef urlStrin i += 3; } if (!sawNonASCIICharacter && info->agreesOverASCII) { + CFRelease(newData); return i; } else { CFStringRef tmp = CFStringCreateWithBytes(CFGetAllocator(urlString), CFDataGetBytePtr(newData), CFDataGetLength(newData), info->fromEnc, false); @@ -1883,6 +1889,11 @@ CFURLRef CFURLCreateWithBytes(CFAllocatorRef allocator, const uint8_t *URLBytes, if (urlString) CFRelease(urlString); return NULL; } +#if DEPLOYMENT_TARGET_MACOSX + if ( !baseURL && *URLBytes == '/' ) { + CFLog(kCFLogLevelWarning, CFSTR("CFURLCreateWithBytes was passed these invalid URLBytes: '%@' (a file system path instead of an URL string). The URL created will not work with most file URL functions. CFURLCreateFromFileSystemRepresentation should be used instead."), urlString); + } +#endif if (createOldUTF8StyleURLs()) { if (encoding != kCFStringEncodingUTF8) { CFStringRef tmp = _convertPercentEscapes(urlString, encoding, kCFStringEncodingUTF8, false, false, NULL, 0); @@ -1929,6 +1940,11 @@ CFURLRef CFURLCreateWithString(CFAllocatorRef allocator, CFStringRef URLString, CFURLRef url; if (!URLString || CFStringGetLength(URLString) == 0) return NULL; if (!_CFStringIsLegalURLString(URLString)) return NULL; +#if DEPLOYMENT_TARGET_MACOSX + if ( !baseURL && CFStringGetCharacterAtIndex(URLString, 0) == '/' ) { + CFLog(kCFLogLevelWarning, CFSTR("CFURLCreateWithString was passed this invalid URL string: '%@' (a file system path instead of an URL string). The URL created will not work with most file URL functions. CFURLCreateWithFileSystemPath or CFURLCreateWithFileSystemPathRelativeToBase should be used instead."), URLString); + } +#endif url = _CFURLAlloc(allocator); if (url) { _CFURLInitWithString(url, URLString, baseURL); @@ -1951,6 +1967,11 @@ CFURLRef CFURLCreateAbsoluteURLWithBytes(CFAllocatorRef alloc, const UInt8 *rela if (!relativeString) { return NULL; } +#if DEPLOYMENT_TARGET_MACOSX + if ( !baseURL && *relativeURLBytes == '/' ) { + CFLog(kCFLogLevelWarning, CFSTR("CFURLCreateAbsoluteURLWithBytes was passed these invalid relativeURLBytes (and no baseURL): '%@' (a file system path instead of an URL string). The URL created will not work with most file URL functions. CFURLCreateFromFileSystemRepresentationRelativeToBase should be used instead."), relativeString); + } +#endif if (!useCompatibilityMode) { CFURLRef url = _CFURLCreateWithArbitraryString(alloc, relativeString, baseURL); CFRelease(relativeString); @@ -3159,9 +3180,6 @@ static CFStringRef schemeSpecificString(CFURLRef url) { #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED case kCFURLHFSPathStyle: return HFSPathToURLPath(url->_string, CFGetAllocator(url), isDir); -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif case kCFURLWindowsPathStyle: return WindowsPathToURLPath(url->_string, CFGetAllocator(url), isDir); @@ -3259,9 +3277,6 @@ static Boolean decomposeToRFC1808(CFURLRef url, CFURLComponentsRFC1808 *componen case kCFURLHFSPathStyle: components->pathComponents = HFSPathToURLComponents(url->_string, alloc, ((url->_flags & IS_DIRECTORY) != 0)); break; -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif case kCFURLWindowsPathStyle: components->pathComponents = WindowsPathToURLComponents(url->_string, alloc, ((url->_flags & IS_DIRECTORY) != 0)); @@ -3545,10 +3560,14 @@ static CFStringRef URLPathToPOSIXPath(CFStringRef path, CFAllocatorRef allocator CFRelease(result); result = tmp; } - } + } return result; -} - + } + +#if DEPLOYMENT_TARGET_WINDOWS +// From CFPlatform.c +extern CFStringRef CFCreateWindowsDrivePathFromVolumeName(CFStringRef volNameStr); +#endif static CFStringRef URLPathToWindowsPath(CFStringRef path, CFAllocatorRef allocator, CFStringEncoding encoding) { // Check for a drive letter, then flip all the slashes @@ -3582,9 +3601,34 @@ static CFStringRef URLPathToWindowsPath(CFStringRef path, CFAllocatorRef allocat CFRelease(driveStr); } } - CFRelease(firstComponent); +#if DEPLOYMENT_TARGET_WINDOWS + else { + // From [DEFECT] CFURL returns a Windows path that contains volume name instead of a drive letter + // we need to replace the volume name (it is not valid on Windows) with the drive mounting point path + // remove the first component and set the component with the drive letter to be the first component + CFStringRef driveRootPath = CFCreateWindowsDrivePathFromVolumeName(firstComponent); + + if (driveRootPath) { + // remove trailing slash + if (CFStringHasSuffix(driveRootPath, CFSTR("\\"))) { + CFStringRef newDriveRootPath = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, driveRootPath, CFRangeMake(0, CFStringGetLength(driveRootPath) - 1)); + CFRelease(driveRootPath); + driveRootPath = newDriveRootPath; + } + + // replace the first component of the path with the drive path + CFArrayRemoveValueAtIndex(components, 0); + CFArraySetValueAtIndex(components, 0, driveRootPath); + + CFRelease(driveRootPath); + } + } +#endif } } + if ( firstComponent ) { + CFRelease(firstComponent); + } } newPath = CFStringCreateByCombiningStrings(allocator, components, CFSTR("\\")); CFRelease(components); @@ -3619,24 +3663,27 @@ static void _convertToURLRepresentation(struct __CFURL *url) { break; } CFAssert2(path != NULL, __kCFLogAssertion, "%s(): Encountered malformed file system URL %@", __PRETTY_FUNCTION__, url); - if (!url->_base) { - CFMutableStringRef str = CFStringCreateMutable(alloc, 0); - CFStringAppend(str, isFileReferencePath ? CFSTR("file://") : CFSTR("file://localhost")); - CFStringAppend(str, path); - url->_flags = (url->_flags & (IS_DIRECTORY)) | (FULL_URL_REPRESENTATION << 16) | IS_DECOMPOSABLE | IS_ABSOLUTE | IS_PARSED | HAS_SCHEME | HAS_FILE_SCHEME | HAS_HOST | HAS_PATH | ORIGINAL_AND_URL_STRINGS_MATCH | ( isFileReferencePath ? PATH_HAS_FILE_ID : 0 ); - CFRelease(url->_string); - url->_string = str; - url->ranges = (CFRange *)CFAllocatorAllocate(alloc, sizeof(CFRange) * 3, 0); - url->ranges[0] = CFRangeMake(0, 4); - url->ranges[1] = CFRangeMake(7, isFileReferencePath ? 0 : 9); - url->ranges[2] = CFRangeMake(url->ranges[1].location + url->ranges[1].length, CFStringGetLength(path)); - CFRelease(path); - } else { - CFRelease(url->_string); - url->_flags = (url->_flags & (IS_DIRECTORY)) | (FULL_URL_REPRESENTATION << 16) | IS_DECOMPOSABLE | IS_PARSED | HAS_PATH | ORIGINAL_AND_URL_STRINGS_MATCH; - url->_string = path; - url->ranges = (CFRange *)CFAllocatorAllocate(alloc, sizeof(CFRange), 0); - *(url->ranges) = CFRangeMake(0, CFStringGetLength(path)); + if ( path ) + { + if (!url->_base) { + CFMutableStringRef str = CFStringCreateMutable(alloc, 0); + CFStringAppend(str, isFileReferencePath ? CFSTR("file://") : CFSTR("file://localhost")); + CFStringAppend(str, path); + url->_flags = (url->_flags & (IS_DIRECTORY)) | (FULL_URL_REPRESENTATION << 16) | IS_DECOMPOSABLE | IS_ABSOLUTE | IS_PARSED | HAS_SCHEME | HAS_FILE_SCHEME | HAS_HOST | HAS_PATH | ORIGINAL_AND_URL_STRINGS_MATCH | ( isFileReferencePath ? PATH_HAS_FILE_ID : 0 ); + CFRelease(url->_string); + url->_string = str; + url->ranges = (CFRange *)CFAllocatorAllocate(alloc, sizeof(CFRange) * 3, 0); + url->ranges[0] = CFRangeMake(0, 4); + url->ranges[1] = CFRangeMake(7, isFileReferencePath ? 0 : 9); + url->ranges[2] = CFRangeMake(url->ranges[1].location + url->ranges[1].length, CFStringGetLength(path)); + CFRelease(path); + } else { + CFRelease(url->_string); + url->_flags = (url->_flags & (IS_DIRECTORY)) | (FULL_URL_REPRESENTATION << 16) | IS_DECOMPOSABLE | IS_PARSED | HAS_PATH | ORIGINAL_AND_URL_STRINGS_MATCH; + url->_string = path; + url->ranges = (CFRange *)CFAllocatorAllocate(alloc, sizeof(CFRange), 0); + *(url->ranges) = CFRangeMake(0, CFStringGetLength(path)); + } } } @@ -3726,7 +3773,7 @@ CFURLRef CFURLCreateWithFileSystemPath(CFAllocatorRef allocator, CFStringRef fil CF_EXPORT CFURLRef CFURLCreateWithFileSystemPathRelativeToBase(CFAllocatorRef allocator, CFStringRef filePath, CFURLPathStyle fsType, Boolean isDirectory, CFURLRef baseURL) { CFURLRef url; - Boolean isAbsolute = true, releaseFilePath = false; + Boolean isAbsolute = true, releaseFilePath = false, releaseBaseURL = false; UniChar pathDelim = '\0'; CFIndex len; @@ -3756,8 +3803,7 @@ CF_EXPORT CFURLRef CFURLCreateWithFileSystemPathRelativeToBase(CFAllocatorRef al isAbsolute = (len > 0 && CFStringGetCharacterAtIndex(filePath, 0) != ':'); pathDelim = ':'; - if ( _CFExecutableLinkedOnOrAfter( CFSystemVersionTiger ) && - filePath && CFStringFindWithOptions( filePath, CFSTR("::"), fullStrRange, 0, NULL ) ) { + if ( filePath && CFStringFindWithOptions( filePath, CFSTR("::"), fullStrRange, 0, NULL ) ) { UniChar * chars = (UniChar *) malloc( fullStrRange.length * sizeof( UniChar ) ); CFIndex index, writeIndex, firstColonOffset = -1; @@ -3801,7 +3847,12 @@ CF_EXPORT CFURLRef CFURLCreateWithFileSystemPathRelativeToBase(CFAllocatorRef al } if (isAbsolute) { baseURL = NULL; - } + } + else if ( baseURL == NULL ) { + baseURL = _CFURLCreateCurrentDirectoryURL(allocator); + releaseBaseURL = true; + } + if (isDirectory && len > 0 && CFStringGetCharacterAtIndex(filePath, len-1) != pathDelim) { CFMutableStringRef tempRef = CFStringCreateMutable(allocator, 0); @@ -3824,11 +3875,13 @@ CF_EXPORT CFURLRef CFURLCreateWithFileSystemPathRelativeToBase(CFAllocatorRef al } if (!filePath || CFStringGetLength(filePath) == 0) { if (releaseFilePath && filePath) CFRelease(filePath); + if (releaseBaseURL && baseURL) CFRelease(baseURL); return NULL; } url = _CFURLAlloc(allocator); _CFURLInit((struct __CFURL *)url, filePath, fsType, baseURL); if (releaseFilePath) CFRelease(filePath); + if (releaseBaseURL && baseURL) CFRelease(baseURL); if (isDirectory) ((struct __CFURL *)url)->_flags |= IS_DIRECTORY; if (fsType == kCFURLPOSIXPathStyle) { // Check if relative path is equivalent to URL representation; this will be true if url->_string contains only characters from the unreserved character set, plus '/' to delimit the path, plus ';', '@', '&', '=', '+', '$', ',' (according to RFC 2396) -- REW, 12/1/2000 @@ -3866,7 +3919,7 @@ CF_EXPORT CFURLRef CFURLCreateWithFileSystemPathRelativeToBase(CFAllocatorRef al static Boolean _pathHasFileIDPrefix( CFStringRef path ) { // path is not NULL, path has prefix "/.file/" and has at least one character following the prefix. - static const CFStringRef fileIDPrefix = CFSTR( "/" FILE_ID_PREFIX "/" ); + CFStringRef fileIDPrefix = CFSTR( "/" FILE_ID_PREFIX "/" ); return path && CFStringHasPrefix( path, fileIDPrefix ) && CFStringGetLength( path ) > CFStringGetLength( fileIDPrefix ); } @@ -3928,18 +3981,21 @@ CFStringRef CFURLCreateStringWithFileSystemPath(CFAllocatorRef allocator, CFURLR } } - // For Tiger, leave this behavior in for all path types. For Leopard, it would be nice to remove this entirely - // and do a linked-on-or-later check so we don't break third parties. - // See Converting volume name from POSIX to HFS form fails and - // CF needs to back out 4003028 for icky details. - if ( relPath && CFURLHasDirectoryPath(anURL) && CFStringGetLength(relPath) > 1 && CFStringGetCharacterAtIndex(relPath, CFStringGetLength(relPath)-1) == PATH_DELIM_FOR_TYPE(fsType)) { + // For Tiger, leave this behavior in for all path types. For Leopard, it would be nice to remove this entirely + // and do a linked-on-or-later check so we don't break third parties. + // See Converting volume name from POSIX to HFS form fails and + // CF needs to back out 4003028 for icky details. + if ( relPath && CFURLHasDirectoryPath(anURL) && CFStringGetLength(relPath) > 1 && CFStringGetCharacterAtIndex(relPath, CFStringGetLength(relPath)-1) == PATH_DELIM_FOR_TYPE(fsType)) { CFStringRef tmp = CFStringCreateWithSubstring(allocator, relPath, CFRangeMake(0, CFStringGetLength(relPath)-1)); CFRelease(relPath); relPath = tmp; } - + // Note that !resolveAgainstBase implies !base if (!basePath || !relPath) { + if ( basePath ) { + CFRelease(basePath); + } return relPath; } else { CFStringRef result = _resolveFileSystemPaths(relPath, basePath, CFURLHasDirectoryPath(base), fsType, allocator); @@ -3954,7 +4010,7 @@ Boolean CFURLGetFileSystemRepresentation(CFURLRef url, Boolean resolveAgainstBas CFAllocatorRef alloc = CFGetAllocator(url); if (!url) return false; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX path = CFURLCreateStringWithFileSystemPath(alloc, url, kCFURLPOSIXPathStyle, resolveAgainstBase); if (path) { Boolean convResult = _CFStringGetFileSystemRepresentation(path, buffer, bufLen); @@ -4002,14 +4058,40 @@ CF_EXPORT Boolean _CFURLGetWideFileSystemRepresentation(CFURLRef url, Boolean re } #endif +static CFStringRef _createPathFromFileSystemRepresentation(CFAllocatorRef allocator, const uint8_t *buffer, CFIndex bufLen, Boolean isDirectory) { + char pathDelim = PATH_SEP; + CFStringRef path; + if ( isDirectory ) { + // it is a directory: if it doesn't end with pathDelim, append a pathDelim. Limit stack buffer to PATH_MAX+1 in case a large bogus value is passed. + if ( (bufLen > 0) && (bufLen <= PATH_MAX) && (buffer[bufLen-1] != pathDelim) ) { + STACK_BUFFER_DECL(uint8_t, tempBuf, bufLen + 1); + memcpy(tempBuf, buffer, bufLen); + tempBuf[bufLen] = pathDelim; + path = CFStringCreateWithBytes(allocator, tempBuf, bufLen + 1, CFStringFileSystemEncoding(), false); + } + else { + // already had pathDelim at end of buffer or bufLen is really large + path = CFStringCreateWithBytes(allocator, buffer, bufLen, CFStringFileSystemEncoding(), false); + } + } + else { + // it is not a directory: remove any pathDelim characters at end (leaving at least one character) + while ( (bufLen > 1) && (buffer[bufLen-1] == pathDelim) ) { + --bufLen; + } + path = CFStringCreateWithBytes(allocator, buffer, bufLen, CFStringFileSystemEncoding(), false); + } + return path; +} + CFURLRef CFURLCreateFromFileSystemRepresentation(CFAllocatorRef allocator, const uint8_t *buffer, CFIndex bufLen, Boolean isDirectory) { - CFStringRef path = CFStringCreateWithBytes(allocator, buffer, bufLen, CFStringFileSystemEncoding(), false); + CFStringRef path = _createPathFromFileSystemRepresentation(allocator, buffer, bufLen, isDirectory); CFURLRef newURL; if (!path) return NULL; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - newURL = CFURLCreateWithFileSystemPath(allocator, path, kCFURLPOSIXPathStyle, isDirectory); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX + newURL = CFURLCreateWithFileSystemPath(allocator, path, kCFURLPOSIXPathStyle, isDirectory); #elif DEPLOYMENT_TARGET_WINDOWS - newURL = CFURLCreateWithFileSystemPath(allocator, path, kCFURLWindowsPathStyle, isDirectory); + newURL = CFURLCreateWithFileSystemPath(allocator, path, kCFURLWindowsPathStyle, isDirectory); #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif @@ -4018,10 +4100,10 @@ CFURLRef CFURLCreateFromFileSystemRepresentation(CFAllocatorRef allocator, const } CF_EXPORT CFURLRef CFURLCreateFromFileSystemRepresentationRelativeToBase(CFAllocatorRef allocator, const uint8_t *buffer, CFIndex bufLen, Boolean isDirectory, CFURLRef baseURL) { - CFStringRef path = CFStringCreateWithBytes(allocator, buffer, bufLen, CFStringFileSystemEncoding(), false); + CFStringRef path = _createPathFromFileSystemRepresentation(allocator, buffer, bufLen, isDirectory); CFURLRef newURL; if (!path) return NULL; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX newURL = CFURLCreateWithFileSystemPathRelativeToBase(allocator, path, kCFURLPOSIXPathStyle, isDirectory, baseURL); #elif DEPLOYMENT_TARGET_WINDOWS newURL = CFURLCreateWithFileSystemPathRelativeToBase(allocator, path, kCFURLWindowsPathStyle, isDirectory, baseURL); @@ -4100,12 +4182,38 @@ CFStringRef CFURLCopyLastPathComponent(CFURLRef url) { CFRelease(path); } } else { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + Boolean filePathURLCreated = false; + + if ( _CFURLIsFileReferenceURL(url) ) { + // use a file path URL or fail + CFURLRef filePathURL = CFURLCreateFilePathURL(CFGetAllocator(url), url, NULL); + if ( filePathURL ) { + filePathURLCreated = TRUE; + url = filePathURL; + } + else { + return NULL; + } + } +#endif + CFRange rg = _rangeOfLastPathComponent(url); if (rg.location == kCFNotFound || rg.length == 0) { // No path +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + if ( filePathURLCreated ) { + CFRelease(url); + } +#endif return (CFStringRef)CFRetain(CFSTR("")); } if (rg.length == 1 && CFStringGetCharacterAtIndex(url->_string, rg.location) == PATH_DELIM_FOR_TYPE(URL_PATH_TYPE(url))) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + if ( filePathURLCreated ) { + CFRelease(url); + } +#endif return (CFStringRef)CFRetain(CFSTR("/")); } result = CFStringCreateWithSubstring(CFGetAllocator(url), url->_string, rg); @@ -4119,6 +4227,11 @@ CFStringRef CFURLCopyLastPathComponent(CFURLRef url) { CFRelease(result); result = tmp; } +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + if ( filePathURLCreated ) { + CFRelease(url); + } +#endif } return result; } @@ -4150,6 +4263,19 @@ CFURLRef CFURLCreateCopyAppendingPathComponent(CFAllocatorRef allocator, CFURLRe __CFGenericValidateType(url, __kCFURLTypeID); CFAssert1(pathComponent != NULL, __kCFLogAssertion, "%s(): Cannot be called with a NULL component to append", __PRETTY_FUNCTION__); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + Boolean filePathURLCreated = false; + + if ( _CFURLIsFileReferenceURL(url) ) { + // use a file path URL if possible (only because this is appending a path component) + CFURLRef filePathURL = CFURLCreateFilePathURL(allocator, url, NULL); + if ( filePathURL ) { + filePathURLCreated = TRUE; + url = filePathURL; + } + } +#endif + fsType = URL_PATH_TYPE(url); if (fsType != FULL_URL_REPRESENTATION && CFStringFindWithOptions(pathComponent, PATH_DELIM_AS_STRING_FOR_TYPE(fsType), CFRangeMake(0, CFStringGetLength(pathComponent)), 0, NULL)) { // Must convert to full representation, and then work with it @@ -4162,22 +4288,25 @@ CFURLRef CFURLCreateCopyAppendingPathComponent(CFAllocatorRef allocator, CFURLRe CFStringRef newComp; CFRange pathRg; if (!(url->_flags & IS_PARSED)) _parseComponentsOfURL(url); - if (!(url->_flags & HAS_PATH)) return NULL; - - newString = CFStringCreateMutableCopy(allocator, 0, url->_string); - newComp = CFURLCreateStringByAddingPercentEscapes(allocator, pathComponent, NULL, CFSTR(";?"), (url->_flags & IS_OLD_UTF8_STYLE) ? kCFStringEncodingUTF8 : url->_encoding); - pathRg = _rangeForComponent(url->_flags, url->ranges, HAS_PATH); - if (!pathRg.length || CFStringGetCharacterAtIndex(url->_string, pathRg.location + pathRg.length - 1) != '/') { - CFStringInsert(newString, pathRg.location + pathRg.length, CFSTR("/")); - pathRg.length ++; - } - CFStringInsert(newString, pathRg.location + pathRg.length, newComp); - if (isDirectory) { - CFStringInsert(newString, pathRg.location + pathRg.length + CFStringGetLength(newComp), CFSTR("/")); + if (!(url->_flags & HAS_PATH)) { + result = NULL; + } + else { + newString = CFStringCreateMutableCopy(allocator, 0, url->_string); + newComp = CFURLCreateStringByAddingPercentEscapes(allocator, pathComponent, NULL, CFSTR(";?"), (url->_flags & IS_OLD_UTF8_STYLE) ? kCFStringEncodingUTF8 : url->_encoding); + pathRg = _rangeForComponent(url->_flags, url->ranges, HAS_PATH); + if (!pathRg.length || CFStringGetCharacterAtIndex(url->_string, pathRg.location + pathRg.length - 1) != '/') { + CFStringInsert(newString, pathRg.location + pathRg.length, CFSTR("/")); + pathRg.length ++; + } + CFStringInsert(newString, pathRg.location + pathRg.length, newComp); + if (isDirectory) { + CFStringInsert(newString, pathRg.location + pathRg.length + CFStringGetLength(newComp), CFSTR("/")); + } + CFRelease(newComp); + result = _CFURLCreateWithArbitraryString(allocator, newString, url->_base); + CFRelease(newString); } - CFRelease(newComp); - result = _CFURLCreateWithArbitraryString(allocator, newString, url->_base); - CFRelease(newString); } else { UniChar pathDelim = PATH_DELIM_FOR_TYPE(fsType); CFStringRef newString; @@ -4197,6 +4326,11 @@ CFURLRef CFURLCreateCopyAppendingPathComponent(CFAllocatorRef allocator, CFURLRe result = CFURLCreateWithFileSystemPathRelativeToBase(allocator, newString, fsType, isDirectory, url->_base); CFRelease(newString); } +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + if ( filePathURLCreated ) { + CFRelease(url); + } +#endif return result; } @@ -4211,10 +4345,33 @@ CFURLRef CFURLCreateCopyDeletingLastPathComponent(CFAllocatorRef allocator, CFUR CFAssert1(url != NULL, __kCFLogAssertion, "%s(): NULL argument not allowed", __PRETTY_FUNCTION__); __CFGenericValidateType(url, __kCFURLTypeID); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + Boolean filePathURLCreated = false; + + if ( _CFURLIsFileReferenceURL(url) ) { + // use a file path URL or fail + CFURLRef filePathURL = CFURLCreateFilePathURL(allocator, url, NULL); + if ( filePathURL ) { + filePathURLCreated = TRUE; + url = filePathURL; + } + else { + return NULL; + } + } +#endif + fsType = URL_PATH_TYPE(url); if (fsType == FULL_URL_REPRESENTATION) { if (!(url->_flags & IS_PARSED)) _parseComponentsOfURL(url); - if (!(url->_flags & HAS_PATH)) return NULL; + if (!(url->_flags & HAS_PATH)) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + if ( filePathURLCreated ) { + CFRelease(url); + } +#endif + return NULL; + } pathRg = _rangeForComponent(url->_flags, url->ranges, HAS_PATH); } else { pathRg = CFRangeMake(0, CFStringGetLength(url->_string)); @@ -4262,6 +4419,11 @@ CFURLRef CFURLCreateCopyDeletingLastPathComponent(CFAllocatorRef allocator, CFUR result = CFURLCreateWithFileSystemPathRelativeToBase(allocator, newString, fsType, true, url->_base); } CFRelease(newString); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + if ( filePathURLCreated ) { + CFRelease(url); + } +#endif return result; } @@ -4276,8 +4438,31 @@ CFURLRef CFURLCreateCopyAppendingPathExtension(CFAllocatorRef allocator, CFURLRe __CFGenericValidateType(url, __kCFURLTypeID); __CFGenericValidateType(extension, CFStringGetTypeID()); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + Boolean filePathURLCreated = false; + + if ( _CFURLIsFileReferenceURL(url) ) { + // use a file path URL or fail + CFURLRef filePathURL = CFURLCreateFilePathURL(allocator, url, NULL); + if ( filePathURL ) { + filePathURLCreated = TRUE; + url = filePathURL; + } + else { + return NULL; + } + } +#endif + rg = _rangeOfLastPathComponent(url); - if (rg.location < 0) return NULL; // No path + if (rg.location < 0) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + if ( filePathURLCreated ) { + CFRelease(url); + } +#endif + return NULL; // No path + } fsType = URL_PATH_TYPE(url); if (fsType != FULL_URL_REPRESENTATION && CFStringFindWithOptions(extension, PATH_DELIM_AS_STRING_FOR_TYPE(fsType), CFRangeMake(0, CFStringGetLength(extension)), 0, NULL)) { _convertToURLRepresentation((struct __CFURL *)url); @@ -4297,6 +4482,11 @@ CFURLRef CFURLCreateCopyAppendingPathExtension(CFAllocatorRef allocator, CFURLRe result = CFURLCreateWithFileSystemPathRelativeToBase(allocator, newString, fsType, (url->_flags & IS_DIRECTORY) != 0 ? true : false, url->_base); } CFRelease(newString); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + if ( filePathURLCreated ) { + CFRelease(url); + } +#endif return result; } @@ -4307,6 +4497,23 @@ CFURLRef CFURLCreateCopyDeletingPathExtension(CFAllocatorRef allocator, CFURLRef CFAssert1(url != NULL, __kCFLogAssertion, "%s(): NULL argument not allowed", __PRETTY_FUNCTION__); url = _CFURLFromNSURL(url); __CFGenericValidateType(url, __kCFURLTypeID); + +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + Boolean filePathURLCreated = false; + + if ( _CFURLIsFileReferenceURL(url) ) { + // use a file path URL or fail + CFURLRef filePathURL = CFURLCreateFilePathURL(allocator, url, NULL); + if ( filePathURL ) { + filePathURLCreated = TRUE; + url = filePathURL; + } + else { + return NULL; + } + } +#endif + rg = _rangeOfLastPathComponent(url); if (rg.location < 0) { result = NULL; @@ -4323,6 +4530,11 @@ CFURLRef CFURLCreateCopyDeletingPathExtension(CFAllocatorRef allocator, CFURLRef } else { result = (CFURLRef)CFRetain(url); } +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED + if ( filePathURLCreated ) { + CFRelease(url); + } +#endif return result; } @@ -4403,9 +4615,6 @@ static CFStringRef HFSPathToURLPath(CFStringRef path, CFAllocatorRef alloc, Bool CFRelease(newComponents); return result; } -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif @@ -4525,3 +4734,91 @@ CFURLRef _CFURLCreateFromPropertyListRepresentation(CFAllocatorRef alloc, CFProp return url; } +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +Boolean _CFURLIsFileReferenceURL(CFURLRef url) +{ + // returns TRUE if url is is a file URL whose path starts with a file ID reference + if ( url->_base ) { + return _CFURLIsFileReferenceURL( url->_base ); + } + if (URL_PATH_TYPE(url) == kCFURLFileReferencePathStyle) { + return true; + } else if (URL_PATH_TYPE(url) == FULL_URL_REPRESENTATION ) { + if (!(url->_flags & IS_PARSED)) { + _parseComponentsOfURL(url); + } + return ((url->_flags & HAS_FILE_SCHEME) && (url->_flags & PATH_HAS_FILE_ID)); + } + // Otherwise, the path type is some other non-ID path type + return false; +} + +Boolean _CFURLIsFileURL(CFURLRef url) +{ + if ( url->_base ) { + return _CFURLIsFileURL( url->_base ); + } + if (URL_PATH_TYPE(url) != FULL_URL_REPRESENTATION) { + return true; + } else if (!(url->_flags & IS_PARSED)) { + _parseComponentsOfURL(url); + } + return (url->_flags & HAS_FILE_SCHEME) != 0; +} + + +CFURLRef CFURLCreateFilePathURL(CFAllocatorRef alloc, CFURLRef url, CFErrorRef *error) +{ + CFURLRef result = NULL; + if (!_CFURLIsFileURL(url)) { + if ( error ) { + *error = CFErrorCreate( kCFAllocatorDefault, kCFErrorDomainCocoa, kCFURLReadUnsupportedSchemeError, NULL ); + } + result = NULL; + } else { + // File URL. Form of the path is unknown. Make a new URL. + CFStringRef newURLString; + CFStringRef netLoc; + CFStringRef fsPath; + CFStringRef rSpec; + + if ( CFURLGetBaseURL( url )) { + CFURLRef absURL = CFURLCopyAbsoluteURL( url ); + fsPath = CFURLCopyFileSystemPath( absURL, kCFURLPOSIXPathStyle ); + netLoc = CFURLCopyNetLocation( absURL ); + rSpec = CFURLCopyResourceSpecifier( absURL ); + CFRelease( absURL ); + } else { + fsPath = CFURLCopyFileSystemPath( url, kCFURLPOSIXPathStyle ); + netLoc = CFURLCopyNetLocation( url ); + rSpec = CFURLCopyResourceSpecifier( url ); + } + if ( fsPath ) { + CFStringRef urlPath = _replacePathIllegalCharacters( fsPath, alloc, true ); + newURLString = CFStringCreateWithFormat( alloc, NULL, CFSTR("file://%@%@%@%@"), (netLoc ? netLoc : CFSTR("")), urlPath, ((CFStringCompare(urlPath, CFSTR("/"), 0) != kCFCompareEqualTo) ? (CFURLHasDirectoryPath( url ) ? CFSTR("/") : CFSTR("")) : CFSTR("")), (rSpec ? rSpec : CFSTR(""))); + result = CFURLCreateWithString( alloc, newURLString, NULL ); + CFRelease( newURLString ); + CFRelease( urlPath ); + CFRelease( fsPath ); + } else { + if ( error ) { + // Would be better here to get an underlying error back from CFURLCopyFileSystemPath + *error = CFErrorCreate( kCFAllocatorDefault, kCFErrorDomainCocoa, kCFURLNoSuchResourceError, NULL ); + } + result = NULL; + } + if ( netLoc ) { + CFRelease( netLoc ); + } + if ( rSpec ) { + CFRelease( rSpec ); + } + } + return result; +} + +#endif + +CFURLRef CFURLCreateFileReferenceURL(CFAllocatorRef alloc, CFURLRef url, CFErrorRef *error) { + return NULL; +} diff --git a/CFURL.h b/CFURL.h index 6195043..377c452 100644 --- a/CFURL.h +++ b/CFURL.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFURL.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFURL__) @@ -32,6 +32,7 @@ #include #include #include +#include CF_EXTERN_C_BEGIN @@ -77,8 +78,6 @@ CFDataRef CFURLCreateData(CFAllocatorRef allocator, CFURLRef url, CFStringEncodi CF_EXPORT CFURLRef CFURLCreateWithString(CFAllocatorRef allocator, CFStringRef URLString, CFURLRef baseURL); -#if MAC_OS_X_VERSION_10_3 <= MAC_OS_X_VERSION_MAX_ALLOWED - /* Create an absolute URL directly, without requiring the extra step */ /* of calling CFURLCopyAbsoluteURL(). If useCompatibilityMode is */ /* true, the rules historically used on the web are used to resolve */ @@ -91,8 +90,7 @@ CFURLRef CFURLCreateWithString(CFAllocatorRef allocator, CFStringRef URLString, /* resource specifier pieces (query, parameters, and fragment), then */ /* the last path component of the base URL will not be deleted */ CF_EXPORT -CFURLRef CFURLCreateAbsoluteURLWithBytes(CFAllocatorRef alloc, const UInt8 *relativeURLBytes, CFIndex length, CFStringEncoding encoding, CFURLRef baseURL, Boolean useCompatibilityMode) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; -#endif +CFURLRef CFURLCreateAbsoluteURLWithBytes(CFAllocatorRef alloc, const UInt8 *relativeURLBytes, CFIndex length, CFStringEncoding encoding, CFURLRef baseURL, Boolean useCompatibilityMode); /* filePath should be the URL's path expressed as a path of the type */ /* fsType. If filePath is not absolute, the resulting URL will be */ @@ -290,7 +288,6 @@ CFURLRef CFURLCreateCopyAppendingPathExtension(CFAllocatorRef allocator, CFURLRe CF_EXPORT CFURLRef CFURLCreateCopyDeletingPathExtension(CFAllocatorRef allocator, CFURLRef url); -#if MAC_OS_X_VERSION_10_3 <= MAC_OS_X_VERSION_MAX_ALLOWED /* Fills buffer with the bytes for url, returning the number of bytes */ /* filled. If buffer is of insufficient size, returns -1 and no bytes */ /* are placed in buffer. If buffer is NULL, the needed length is */ @@ -298,7 +295,7 @@ CFURLRef CFURLCreateCopyDeletingPathExtension(CFAllocatorRef allocator, CFURLRef /* from which the URL was created; if the URL was created from a */ /* string, the bytes will be the bytes of the string encoded via UTF-8 */ CF_EXPORT -CFIndex CFURLGetBytes(CFURLRef url, UInt8 *buffer, CFIndex bufferLength) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFIndex CFURLGetBytes(CFURLRef url, UInt8 *buffer, CFIndex bufferLength); enum { kCFURLComponentScheme = 1, @@ -381,8 +378,7 @@ query (54, 5) (53, 7) fragment (60, 8) (59, 9) */ CF_EXPORT -CFRange CFURLGetByteRangeForComponent(CFURLRef url, CFURLComponentType component, CFRange *rangeIncludingSeparators) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; -#endif +CFRange CFURLGetByteRangeForComponent(CFURLRef url, CFURLComponentType component, CFRange *rangeIncludingSeparators); /* Returns a string with any percent escape sequences that do NOT */ /* correspond to characters in charactersToLeaveEscaped with their */ @@ -394,11 +390,9 @@ CFRange CFURLGetByteRangeForComponent(CFURLRef url, CFURLComponentType component CF_EXPORT CFStringRef CFURLCreateStringByReplacingPercentEscapes(CFAllocatorRef allocator, CFStringRef originalString, CFStringRef charactersToLeaveEscaped); -#if MAC_OS_X_VERSION_10_3 <= MAC_OS_X_VERSION_MAX_ALLOWED /* As above, but allows you to specify the encoding to use when interpreting percent escapes */ CF_EXPORT -CFStringRef CFURLCreateStringByReplacingPercentEscapesUsingEncoding(CFAllocatorRef allocator, CFStringRef origString, CFStringRef charsToLeaveEscaped, CFStringEncoding encoding) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; -#endif +CFStringRef CFURLCreateStringByReplacingPercentEscapesUsingEncoding(CFAllocatorRef allocator, CFStringRef origString, CFStringRef charsToLeaveEscaped, CFStringEncoding encoding); /* Creates a copy or originalString, replacing certain characters with */ /* the equivalent percent escape sequence based on the encoding specified. */ @@ -417,13 +411,15 @@ CF_EXPORT CFStringRef CFURLCreateStringByAddingPercentEscapes(CFAllocatorRef allocator, CFStringRef originalString, CFStringRef charactersToLeaveUnescaped, CFStringRef legalURLCharactersToBeEscaped, CFStringEncoding encoding); +#if (TARGET_OS_MAC || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) || CF_BUILDING_CF || NSBUILDINGFOUNDATION + /* Returns a file reference URL, a path-idependent form of file URL. */ /* Converts a file path URL if necessary. For non-file URLs, returns NULL. */ /* Also returns NULL when the conversion fails because the target resource doesn't exist. */ /* Optional output error: The error is set to a valid CFErrorRef when the function */ /* result is NULL. A valid output error must be released by the caller. */ CF_EXPORT -CFURLRef CFURLCreateFileReferenceURL(CFAllocatorRef allocator, CFURLRef url, CFErrorRef *error) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CFURLRef CFURLCreateFileReferenceURL(CFAllocatorRef allocator, CFURLRef url, CFErrorRef *error) CF_AVAILABLE(10_6, 4_0); /* Returns a file path URL, converting a file reference URL if necessary. */ @@ -432,12 +428,13 @@ CFURLRef CFURLCreateFileReferenceURL(CFAllocatorRef allocator, CFURLRef url, CFE /* Optional output error: The error is set to a valid CFErrorRef when the function */ /* result is NULL. A valid output error must be released by the caller. */ CF_EXPORT -CFURLRef CFURLCreateFilePathURL(CFAllocatorRef allocator, CFURLRef url, CFErrorRef *error) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CFURLRef CFURLCreateFilePathURL(CFAllocatorRef allocator, CFURLRef url, CFErrorRef *error) CF_AVAILABLE(10_6, 4_0); +#endif -#if TARGET_OS_MAC +#if (TARGET_OS_MAC || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) || CF_BUILDING_CF || NSBUILDINGFOUNDATION /* The following APIs provide efficient access to resource properties. Properties are identified by keys, and values are represented as Core Foundation objects. The @@ -460,7 +457,7 @@ When a resource property value is set, the change is written to backing store sy /* a valid CFErrorRef when the function returns false. A valid output error must be */ /* released by the caller. */ CF_EXPORT -Boolean CFURLCopyResourcePropertyForKey(CFURLRef url, CFStringRef key, void *propertyValueTypeRefPtr, CFErrorRef *error) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +Boolean CFURLCopyResourcePropertyForKey(CFURLRef url, CFStringRef key, void *propertyValueTypeRefPtr, CFErrorRef *error) CF_AVAILABLE(10_6, 4_0); /* Returns any number of resource property values as a dictionary of keyed values. */ @@ -471,7 +468,7 @@ Boolean CFURLCopyResourcePropertyForKey(CFURLRef url, CFStringRef key, void *pro /* Optional output error: the error is set to a valid CFErrorRef when the */ /* function returns NULL. A valid output error must be released by the caller. */ CF_EXPORT -CFDictionaryRef CFURLCopyResourcePropertiesForKeys(CFURLRef url, CFArrayRef keys, CFErrorRef *error) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CFDictionaryRef CFURLCopyResourcePropertiesForKeys(CFURLRef url, CFArrayRef keys, CFErrorRef *error) CF_AVAILABLE(10_6, 4_0); /* Changes a resource property value. Synchronously writes the value to the resource backing */ @@ -482,7 +479,7 @@ CFDictionaryRef CFURLCopyResourcePropertiesForKeys(CFURLRef url, CFArrayRef keys /* Note that some values are read-only. Attempting to set a read-only property */ /* results in an error. */ CF_EXPORT -Boolean CFURLSetResourcePropertyForKey(CFURLRef url, CFStringRef key, CFTypeRef propertValue, CFErrorRef *error) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +Boolean CFURLSetResourcePropertyForKey(CFURLRef url, CFStringRef key, CFTypeRef propertyValue, CFErrorRef *error) CF_AVAILABLE(10_6, 4_0); /* Changes any number of resource property values, specified as a dictionary of keyed values. */ @@ -490,21 +487,26 @@ Boolean CFURLSetResourcePropertyForKey(CFURLRef url, CFStringRef key, CFTypeRef /* to the type required for its key (see key definitions). Returns true when all values are set successfully, */ /* and false if an error occurs. Optional output error: the error is set to a valid CFErrorRef when the function returns */ /* false. A valid output error must be released by the caller. When an error occurs after some properties have been */ -/* successfully changed, the user dictionary in the error contains an array of keys that */ -/* were not set. Note that some values are read-only. Attempting to set a read-only value */ -/* results in an error. */ +/* successfully changed, the userInfo dictionary in the error contains an array of keys that */ +/* were not set with the dictionary key kCFURLKeysOfUnsetValuesKey. */ +/* Note that some values are read-only. Attempting to set a read-only value results in an error. */ CF_EXPORT -Boolean CFURLSetResourcePropertiesForKeys(CFURLRef url, CFDictionaryRef keyedPropertyValues, CFErrorRef *error) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +Boolean CFURLSetResourcePropertiesForKeys(CFURLRef url, CFDictionaryRef keyedPropertyValues, CFErrorRef *error) CF_AVAILABLE(10_6, 4_0); + + +CF_EXPORT +const CFStringRef kCFURLKeysOfUnsetValuesKey CF_AVAILABLE(10_7, 5_0); + /* If CFURLSetResourcePropertiesForKeys returns an error, this is key in the error's userInfo dictionary to the array of keys of unset values. */ /* Discards a cached property value for a specific key */ CF_EXPORT -void CFURLClearResourcePropertyCacheForKey(CFURLRef url, CFStringRef key) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +void CFURLClearResourcePropertyCacheForKey(CFURLRef url, CFStringRef key) CF_AVAILABLE(10_6, 4_0); /* Discards all cached property values */ CF_EXPORT -void CFURLClearResourcePropertyCache(CFURLRef url) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +void CFURLClearResourcePropertyCache(CFURLRef url) CF_AVAILABLE(10_6, 4_0); /* Sets a temporary property value. Temporary properties exist only in memory and are never */ @@ -513,7 +515,7 @@ void CFURLClearResourcePropertyCache(CFURLRef url) AVAILABLE_MAC_OS_X_VERSION_10 /* values are for client use. Values must be valid Core Foundation types, and will be retained. */ /* To remove a temporary property value, use CFURLClearResourcePropertyCacheForKey. */ CF_EXPORT -void CFURLSetTemporaryResourcePropertyForKey(CFURLRef url, CFStringRef key, CFTypeRef propertyValue) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +void CFURLSetTemporaryResourcePropertyForKey(CFURLRef url, CFStringRef key, CFTypeRef propertyValue) CF_AVAILABLE(10_6, 4_0); /* Synchronously checks if the resource's backing store is reachable and the resource exists, */ @@ -526,125 +528,186 @@ void CFURLSetTemporaryResourcePropertyForKey(CFURLRef url, CFStringRef key, CFTy /* When performing an operation such as opening a file, it is more efficient to */ /* simply try the operation and handle failures than to check first for reachability. */ CF_EXPORT -Boolean CFURLResourceIsReachable(CFURLRef url, CFErrorRef *error) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +Boolean CFURLResourceIsReachable(CFURLRef url, CFErrorRef *error) CF_AVAILABLE(10_6, 4_0); /* Properties of File System Resources */ CF_EXPORT -const CFStringRef kCFURLNameKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLNameKey CF_AVAILABLE(10_6, 4_0); /* The resource name provided by the file system (value type CFString) */ CF_EXPORT -const CFStringRef kCFURLLocalizedNameKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLLocalizedNameKey CF_AVAILABLE(10_6, 4_0); /* Localized or extension-hidden name as displayed to users (Read-only, value type CFString) */ CF_EXPORT -const CFStringRef kCFURLIsRegularFileKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLIsRegularFileKey CF_AVAILABLE(10_6, 4_0); /* True for regular files (Read-only, value type CFBoolean) */ CF_EXPORT -const CFStringRef kCFURLIsDirectoryKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLIsDirectoryKey CF_AVAILABLE(10_6, 4_0); /* True for directories (Read-only, CFBoolean) */ CF_EXPORT -const CFStringRef kCFURLIsSymbolicLinkKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLIsSymbolicLinkKey CF_AVAILABLE(10_6, 4_0); /* True for symlinks (Read-only, value type CFBoolean) */ CF_EXPORT -const CFStringRef kCFURLIsVolumeKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLIsVolumeKey CF_AVAILABLE(10_6, 4_0); /* True for the root directory of a volume (Read-only, value type CFBoolean) */ CF_EXPORT -const CFStringRef kCFURLIsPackageKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLIsPackageKey CF_AVAILABLE(10_6, 4_0); /* True for packaged directories (value type CFBoolean) */ CF_EXPORT -const CFStringRef kCFURLIsSystemImmutableKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLIsSystemImmutableKey CF_AVAILABLE(10_6, 4_0); /* True for system-immutable resources (value type CFBoolean) */ CF_EXPORT -const CFStringRef kCFURLIsUserImmutableKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLIsUserImmutableKey CF_AVAILABLE(10_6, 4_0); /* True for user-immutable resources (value type CFBoolean) */ CF_EXPORT -const CFStringRef kCFURLIsHiddenKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLIsHiddenKey CF_AVAILABLE(10_6, 4_0); /* True for resources normally hidden from users (value type CFBoolean) */ CF_EXPORT -const CFStringRef kCFURLHasHiddenExtensionKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; - /* True for resources whose filename extension is hiden (value type CFBoolean) */ +const CFStringRef kCFURLHasHiddenExtensionKey CF_AVAILABLE(10_6, 4_0); + /* True for resources whose filename extension is hidden (value type CFBoolean) */ CF_EXPORT -const CFStringRef kCFURLCreationDateKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; - /* Value type CFDate */ +const CFStringRef kCFURLCreationDateKey CF_AVAILABLE(10_6, 4_0); + /* The date the resource was created (value type CFDate) */ CF_EXPORT -const CFStringRef kCFURLContentAccessDateKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; - /* Value type CFDate */ +const CFStringRef kCFURLContentAccessDateKey CF_AVAILABLE(10_6, 4_0); + /* The date the resource was last accessed (Read-only, value type CFDate) */ CF_EXPORT -const CFStringRef kCFURLContentModificationDateKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; - /* Value type CFDate */ +const CFStringRef kCFURLContentModificationDateKey CF_AVAILABLE(10_6, 4_0); + /* The time the resource content was last modified (value type CFDate) */ CF_EXPORT -const CFStringRef kCFURLAttributeModificationDateKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; - /* Value type CFDate */ +const CFStringRef kCFURLAttributeModificationDateKey CF_AVAILABLE(10_6, 4_0); + /* The time the resource's attributes were last modified (value type CFDate) */ CF_EXPORT -const CFStringRef kCFURLLinkCountKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLLinkCountKey CF_AVAILABLE(10_6, 4_0); /* Number of hard links to the resource (Read-only, CFNumber) */ CF_EXPORT -const CFStringRef kCFURLParentDirectoryURLKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLParentDirectoryURLKey CF_AVAILABLE(10_6, 4_0); /* URL of the parent directory, if any (Read-only, value type CFURL) */ CF_EXPORT -const CFStringRef kCFURLVolumeURLKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLVolumeURLKey CF_AVAILABLE(10_6, 4_0); /* URL of the volume on which the resource is stored (Read-only, value type CFURL) */ CF_EXPORT -const CFStringRef kCFURLTypeIdentifierKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLTypeIdentifierKey CF_AVAILABLE(10_6, 4_0); /* Uniform type identifier for the resource (Read-only, value type CFString) */ CF_EXPORT -const CFStringRef kCFURLLocalizedTypeDescriptionKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLLocalizedTypeDescriptionKey CF_AVAILABLE(10_6, 4_0); /* User-visible type or "kind" descriptiopn (Read-only, value type CFString) */ CF_EXPORT -const CFStringRef kCFURLLabelNumberKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLLabelNumberKey CF_AVAILABLE(10_6, 4_0); /* The label number assigned to the resource (value type CFNumber) */ CF_EXPORT -const CFStringRef kCFURLLabelColorKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLLabelColorKey CF_AVAILABLE(10_6, 4_0); /* The color of the assigned label (Read-only, value type CGColorRef, must link with Application Services) */ CF_EXPORT -const CFStringRef kCFURLLocalizedLabelKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLLocalizedLabelKey CF_AVAILABLE(10_6, 4_0); /* The user-visible label text (Read-only, value type CFString) */ CF_EXPORT -const CFStringRef kCFURLEffectiveIconKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLEffectiveIconKey CF_AVAILABLE(10_6, 4_0); /* The icon normally displayed for the resource (Read-only, value type CGImageRef, must link with Application Services) */ CF_EXPORT -const CFStringRef kCFURLCustomIconKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLCustomIconKey CF_AVAILABLE(10_6, 4_0); /* The custom icon assigned to the resource, if any (value type CGImageRef, must link with Application Services) */ +CF_EXPORT +const CFStringRef kCFURLFileResourceIdentifierKey CF_AVAILABLE(10_7, 5_0); + /* An identifier which can be used to compare two file system objects for equality using CFEqual (i.e, two object identifiers are equal if they have the same file system path or if the paths are linked to same inode on the same file system). This identifier is not persistent across system restarts. (Read-only, value type CFType) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeIdentifierKey CF_AVAILABLE(10_7, 5_0); + /* An identifier that can be used to identify the volume the file system object is on. Other objects on the same volume will have the same volume identifier and can be compared using for equality using CFEqual. This identifier is not persistent across system restarts. (Read-only, value type CFType) */ + +CF_EXPORT +const CFStringRef kCFURLPreferredIOBlockSizeKey CF_AVAILABLE(10_7, 5_0); + /* The optimal block size when reading or writing this file's data, or NULL if not available. (Read-only, value type CFNumber) */ + +CF_EXPORT +const CFStringRef kCFURLIsReadableKey CF_AVAILABLE(10_7, 5_0); + /* true if this process (as determined by EUID) can read the resource. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLIsWritableKey CF_AVAILABLE(10_7, 5_0); + /* true if this process (as determined by EUID) can write to the resource. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLIsExecutableKey CF_AVAILABLE(10_7, 5_0); + /* true if this process (as determined by EUID) can execute a file resource or search a directory resource. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLFileSecurityKey CF_AVAILABLE(10_7, 5_0); + /* The file system object's security information encapsulated in a CFFileSecurity object. (Value type CFFileSecurity) */ + +CF_EXPORT +const CFStringRef kCFURLFileResourceTypeKey CF_AVAILABLE(10_7, 5_0); + /* Returns the file system object type. (Read-only, value type CFString) */ + +/* The file system object type values returned for the kCFURLFileResourceTypeKey */ +CF_EXPORT +const CFStringRef kCFURLFileResourceTypeNamedPipe CF_AVAILABLE(10_7, 5_0); +CF_EXPORT +const CFStringRef kCFURLFileResourceTypeCharacterSpecial CF_AVAILABLE(10_7, 5_0); +CF_EXPORT +const CFStringRef kCFURLFileResourceTypeDirectory CF_AVAILABLE(10_7, 5_0); +CF_EXPORT +const CFStringRef kCFURLFileResourceTypeBlockSpecial CF_AVAILABLE(10_7, 5_0); +CF_EXPORT +const CFStringRef kCFURLFileResourceTypeRegular CF_AVAILABLE(10_7, 5_0); +CF_EXPORT +const CFStringRef kCFURLFileResourceTypeSymbolicLink CF_AVAILABLE(10_7, 5_0); +CF_EXPORT +const CFStringRef kCFURLFileResourceTypeSocket CF_AVAILABLE(10_7, 5_0); +CF_EXPORT +const CFStringRef kCFURLFileResourceTypeUnknown CF_AVAILABLE(10_7, 5_0); /* File Properties */ CF_EXPORT -const CFStringRef kCFURLFileSizeKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLFileSizeKey CF_AVAILABLE(10_6, 4_0); /* Total file size, in bytes (Read-only, value type CFNumber) */ CF_EXPORT -const CFStringRef kCFURLFileAllocatedSizeKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLFileAllocatedSizeKey CF_AVAILABLE(10_6, 4_0); /* Total size of blocks allocated (Read-only, value type CFNumber) */ CF_EXPORT -const CFStringRef kCFURLIsAliasFileKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; -/* true if the url is a Finder alias file, false otherwise ( Read-only, value type CFBooleanRef) */ +const CFStringRef kCFURLTotalFileSizeKey CF_AVAILABLE(10_7, 5_0); + /* Total displayable size of the file, in bytes (this may include space used by metadata), or NULL if not available. (Read-only, value type CFNumber) */ + +CF_EXPORT +const CFStringRef kCFURLTotalFileAllocatedSizeKey CF_AVAILABLE(10_7, 5_0); + /* Total allocated size of the file, in bytes (this may include space used by metadata), or NULL if not available. This can be less than the value returned by kCFURLTotalFileSizeKey if the resource is compressed. (Read-only, value type CFNumber) */ + +CF_EXPORT +const CFStringRef kCFURLIsAliasFileKey CF_AVAILABLE(10_6, 4_0); + /* true if the url is a Finder alias file, false otherwise ( Read-only, value type CFBooleanRef) */ + +CF_EXPORT +const CFStringRef kCFURLIsMountTriggerKey CF_AVAILABLE(10_7, 4_0); + /* true if this URL is a file system trigger directory. Traversing or opening a file system trigger will cause an attempt to mount a file system on the trigger directory. (Read-only, value type CFBoolean) */ /* Volume Properties */ @@ -652,57 +715,163 @@ const CFStringRef kCFURLIsAliasFileKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER /* For convenience, volume properties may be requested from any resource on a volume. */ CF_EXPORT -const CFStringRef kCFURLVolumeLocalizedFormatDescriptionKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLVolumeLocalizedFormatDescriptionKey CF_AVAILABLE(10_6, 4_0); /* The user-visible volume format (Read-only, value type CFString) */ CF_EXPORT -const CFStringRef kCFURLVolumeTotalCapacityKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLVolumeTotalCapacityKey CF_AVAILABLE(10_6, 4_0); /* Total volume capacity in bytes (Read-only, value type CFNumber) */ CF_EXPORT -const CFStringRef kCFURLVolumeAvailableCapacityKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLVolumeAvailableCapacityKey CF_AVAILABLE(10_6, 4_0); /* Total free space, in bytes (Read-only, value type CFNumber) */ CF_EXPORT -const CFStringRef kCFURLVolumeResourceCountKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLVolumeResourceCountKey CF_AVAILABLE(10_6, 4_0); /* Total number of resources on the volume (Read-only, value type CFNumber) */ CF_EXPORT -const CFStringRef kCFURLVolumeSupportsPersistentIDsKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLVolumeSupportsPersistentIDsKey CF_AVAILABLE(10_6, 4_0); /* Read-only, value type CFBoolean */ CF_EXPORT -const CFStringRef kCFURLVolumeSupportsSymbolicLinksKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLVolumeSupportsSymbolicLinksKey CF_AVAILABLE(10_6, 4_0); /* Read-only, value type CFBoolean */ CF_EXPORT -const CFStringRef kCFURLVolumeSupportsHardLinksKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLVolumeSupportsHardLinksKey CF_AVAILABLE(10_6, 4_0); /* Read-only, value type CFBoolean */ CF_EXPORT -const CFStringRef kCFURLVolumeSupportsJournalingKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLVolumeSupportsJournalingKey CF_AVAILABLE(10_6, 4_0); /* Read-only, value type CFBoolean */ CF_EXPORT -const CFStringRef kCFURLVolumeIsJournalingKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLVolumeIsJournalingKey CF_AVAILABLE(10_6, 4_0); /* Read-only, value type CFBoolean */ CF_EXPORT -const CFStringRef kCFURLVolumeSupportsSparseFilesKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLVolumeSupportsSparseFilesKey CF_AVAILABLE(10_6, 4_0); /* Read-only, value type CFBoolean */ CF_EXPORT -const CFStringRef kCFURLVolumeSupportsZeroRunsKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLVolumeSupportsZeroRunsKey CF_AVAILABLE(10_6, 4_0); /* Read-only, value type CFBoolean */ CF_EXPORT -const CFStringRef kCFURLVolumeSupportsCaseSensitiveNamesKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLVolumeSupportsCaseSensitiveNamesKey CF_AVAILABLE(10_6, 4_0); /* Read-only, value type CFBoolean */ CF_EXPORT -const CFStringRef kCFURLVolumeSupportsCasePreservedNamesKey AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +const CFStringRef kCFURLVolumeSupportsCasePreservedNamesKey CF_AVAILABLE(10_6, 4_0); /* Read-only, value type CFBoolean */ +CF_EXPORT +const CFStringRef kCFURLVolumeSupportsRootDirectoryDatesKey CF_AVAILABLE(10_7, 5_0); + /* true if the volume supports reliable storage of times for the root directory. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeSupportsVolumeSizesKey CF_AVAILABLE(10_7, 5_0); + /* true if the volume supports returning volume size values (kCFURLVolumeTotalCapacityKey and kCFURLVolumeAvailableCapacityKey). (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeSupportsRenamingKey CF_AVAILABLE(10_7, 5_0); + /* true if the volume can be renamed. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeSupportsAdvisoryFileLockingKey CF_AVAILABLE(10_7, 5_0); + /* true if the volume implements whole-file flock(2) style advisory locks, and the O_EXLOCK and O_SHLOCK flags of the open(2) call. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeSupportsExtendedSecurityKey CF_AVAILABLE(10_7, 5_0); + /* true if the volume implements extended security (ACLs). (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeIsBrowsableKey CF_AVAILABLE(10_7, 5_0); + /* true if the volume should be visible via the GUI (i.e., appear on the Desktop as a separate volume). (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeMaximumFileSizeKey CF_AVAILABLE(10_7, 5_0); + /* The largest file size (in bytes) supported by this file system, or NULL if this cannot be determined. (Read-only, value type CFNumber) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeIsEjectableKey CF_AVAILABLE(10_7, 5_0); + /* true if the volume's media is ejectable from the drive mechanism under software control. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeIsRemovableKey CF_AVAILABLE(10_7, 5_0); + /* true if the volume's media is removable from the drive mechanism. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeIsInternalKey CF_AVAILABLE(10_7, 5_0); + /* true if the volume's device is connected to an internal bus, false if connected to an external bus, or NULL if not available. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeIsAutomountedKey CF_AVAILABLE(10_7, 5_0); + /* true if the volume is automounted. Note: do not mistake this with the functionality provided by kCFURLVolumeSupportsBrowsingKey. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeIsLocalKey CF_AVAILABLE(10_7, 5_0); + /* true if the volume is stored on a local device. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeIsReadOnlyKey CF_AVAILABLE(10_7, 5_0); + /* true if the volume is read-only. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeCreationDateKey CF_AVAILABLE(10_7, 5_0); + /* The volume's creation date, or NULL if this cannot be determined. (Read-only, value type CFDate) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeURLForRemountingKey CF_AVAILABLE(10_7, 5_0); + /* The CFURL needed to remount a network volume, or NULL if not available. (Read-only, value type CFURL) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeUUIDStringKey CF_AVAILABLE(10_7, 5_0); + /* The volume's persistent UUID as a string, or NULL if a persistent UUID is not available for the volume. (Read-only, value type CFString) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeNameKey CF_AVAILABLE(10_7, 5_0); + /* The name of the volume (settable if kCFURLVolumeSupportsRenamingKey is true, value type CFString) */ + +CF_EXPORT +const CFStringRef kCFURLVolumeLocalizedNameKey CF_AVAILABLE(10_7, 5_0); + /* The user-presentable name of the volume (Read-only, value type CFString) */ + +/* UbiquitousItem Properties */ + +CF_EXPORT +const CFStringRef kCFURLIsUbiquitousItemKey CF_AVAILABLE(10_7, 5_0); + /* true if this item is synced to the cloud, false if it is only a local file. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLUbiquitousItemHasUnresolvedConflictsKey CF_AVAILABLE(10_7, 5_0); + /* true if this item has conflicts outstanding. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLUbiquitousItemIsDownloadedKey CF_AVAILABLE(10_7, 5_0); + /* true if there is local data present for this item. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLUbiquitousItemIsDownloadingKey CF_AVAILABLE(10_7, 5_0); + /* true if data is being downloaded for this item. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLUbiquitousItemIsUploadedKey CF_AVAILABLE(10_7, 5_0); + /* true if there is data present in the cloud for this item. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLUbiquitousItemIsUploadingKey CF_AVAILABLE(10_7, 5_0); + /* true if data is being uploaded for this item. (Read-only, value type CFBoolean) */ + +CF_EXPORT +const CFStringRef kCFURLUbiquitousItemPercentDownloadedKey CF_AVAILABLE(10_7, 5_0); + /* [0-100] percent of data downloaded. (Read-only, value type double CFNumber) */ + +CF_EXPORT +const CFStringRef kCFURLUbiquitousItemPercentUploadedKey CF_AVAILABLE(10_7, 5_0); + /* [0-100] percent of data downloaded. (Read-only, value type double CFNumber) */ + enum { kCFURLBookmarkCreationPreferFileIDResolutionMask = ( 1UL << 8 ), // At resolution time, this alias will prefer resolving by the embedded fileID to the path kCFURLBookmarkCreationMinimalBookmarkMask = ( 1UL << 9 ), // Creates a bookmark with "less" information, which may be smaller but still be able to resolve in certain ways @@ -728,7 +897,8 @@ typedef CFOptionFlags CFURLBookmarkFileCreationOptions; @param relativeToURL If non-NULL, the created bookmark will be relative to the given url @param error If non-NULL, on exit will be filled in with a CFErrorRef representing any error which occured during creation of the bookmark data @result A CFDataRef containing an data, which can be later be passed to CFURLCreateByResolvingBookmarkData() or to CFURLCopyPropertiesForKeysFromBookmarkData() / CFURLCopyPropertyForKeyFromBookmarkData() */ -CFDataRef CFURLCreateBookmarkData ( CFAllocatorRef allocator, CFURLRef url, CFURLBookmarkCreationOptions options, CFArrayRef resourcePropertiesToInclude, CFURLRef relativeToURL, CFErrorRef* error ) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CF_EXPORT +CFDataRef CFURLCreateBookmarkData ( CFAllocatorRef allocator, CFURLRef url, CFURLBookmarkCreationOptions options, CFArrayRef resourcePropertiesToInclude, CFURLRef relativeToURL, CFErrorRef* error ) CF_AVAILABLE(10_6, 4_0); /* @function CFURLCreateByResolvingBookmarkData @discussion Given a CFDataRef created with CFURLCreateBookmarkRepresentation(), return a CFURLRef of the item it was a bookmark to, and @@ -746,7 +916,8 @@ CFDataRef CFURLCreateBookmarkData ( CFAllocatorRef allocator, CFURLRef url, CFUR have saved and create a new one. @param error If non-NULL, on exit will be filled in with a CFErrorRef representing any error which occured during resolution of the bookmark data @result A CFURLRef of a file which is the closest match to the file the bookmark data */ -CFURLRef CFURLCreateByResolvingBookmarkData ( CFAllocatorRef allocator, CFDataRef bookmark, CFURLBookmarkResolutionOptions options, CFURLRef relativeToURL, CFArrayRef resourcePropertiesToInclude, Boolean* isStale, CFErrorRef* error ) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CF_EXPORT +CFURLRef CFURLCreateByResolvingBookmarkData ( CFAllocatorRef allocator, CFDataRef bookmark, CFURLBookmarkResolutionOptions options, CFURLRef relativeToURL, CFArrayRef resourcePropertiesToInclude, Boolean* isStale, CFErrorRef* error ) CF_AVAILABLE(10_6, 4_0); /* @function CFURLCreatePropertiesForKeysFromBookmarkData @discussion Given a bookmark, return a dictionary of properties ( all properties if propertiesToReturn == NULL ). @@ -755,7 +926,8 @@ CFURLRef CFURLCreateByResolvingBookmarkData ( CFAllocatorRef allocator, CFDataRe @param bookmark a CFDataRef containing a bookmark data, created with CFURLCreateBookmarkData @param propertiesToReturn a CFArrayRef of the properties of the bookmark data which the client would like returned. @result a CFDictionaryRef containing the values for the properties passed in obtained from the bookmark data ( not by attempting to resolve it or do i/o in any way ) */ -CFDictionaryRef CFURLCreateResourcePropertiesForKeysFromBookmarkData ( CFAllocatorRef allocator, CFArrayRef resourcePropertiesToReturn, CFDataRef bookmark ) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CF_EXPORT +CFDictionaryRef CFURLCreateResourcePropertiesForKeysFromBookmarkData ( CFAllocatorRef allocator, CFArrayRef resourcePropertiesToReturn, CFDataRef bookmark ) CF_AVAILABLE(10_6, 4_0); /* @function CFURLCreatePropertyForKeyFromBookmarkData @discussion Given a bookmark, return the value for a given property from the bookmark data @@ -764,7 +936,8 @@ CFDictionaryRef CFURLCreateResourcePropertiesForKeysFromBookmarkData ( CFAllocat @param bookmark a CFDataRef containing a bookmark data, created with CFURLCreateBookmarkData @param propertyKey the property key to return. @result a CFTypeRef value for the property passed in obtained from the bookmark data ( not by attempting to resolve it or do i/o in any way ) */ -CFTypeRef CFURLCreateResourcePropertyForKeyFromBookmarkData( CFAllocatorRef allocator, CFStringRef resourcePropertyKey, CFDataRef bookmark ) AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER; +CF_EXPORT +CFTypeRef CFURLCreateResourcePropertyForKeyFromBookmarkData( CFAllocatorRef allocator, CFStringRef resourcePropertyKey, CFDataRef bookmark ) CF_AVAILABLE(10_6, 4_0); /*! @function CFURLCreateBookmarkDataFromFile @description Given a fileURL of a file which is a Finder "alias" file, return a CFDataRef with the bookmark data from the file. If urlRef points to an alias file @@ -776,7 +949,8 @@ CFTypeRef CFURLCreateResourcePropertyForKeyFromBookmarkData( CFAllocatorRef all @param errorRef if non-NULL, on exit will be filled in with a CFErrorRef representing any error which occurred during the creation of the bookmark data from the file @result A CFDataRef containing bookmark data, or NULL if there was an error creating bookmark data from the file, such as if the file is not an alias file. */ -CFDataRef CFURLCreateBookmarkDataFromFile(CFAllocatorRef allocator, CFURLRef fileURL, CFErrorRef *errorRef ); +CF_EXPORT +CFDataRef CFURLCreateBookmarkDataFromFile(CFAllocatorRef allocator, CFURLRef fileURL, CFErrorRef *errorRef ) CF_AVAILABLE(10_6, 5_0); /*! @function CFURLWriteBookmarkDataToFile @description Given a created bookmarkData object, create a new Finder "alias" file at fileURL which contains the bookmark data. If fileURL is a url to a directory, an alias file @@ -789,7 +963,8 @@ CFDataRef CFURLCreateBookmarkDataFromFile(CFAllocatorRef allocator, CFURLRef fil @param options options flags @param errorRef if non-NULL, on exit will be filled in with a CFErrorRef representing any error which occurred during the creation of the alias file */ -Boolean CFURLWriteBookmarkDataToFile( CFDataRef bookmarkRef, CFURLRef fileURL, CFURLBookmarkFileCreationOptions options, CFErrorRef *errorRef ); +CF_EXPORT +Boolean CFURLWriteBookmarkDataToFile( CFDataRef bookmarkRef, CFURLRef fileURL, CFURLBookmarkFileCreationOptions options, CFErrorRef *errorRef ) CF_AVAILABLE(10_6, 5_0); /*! @function CFURLCreateBookmarkDataFromAliasRecord @discussion Create a CFDataRef containing bookmarkdata by converting the alias data in aliasRecordDataRef, which should be the contents of an AliasRecord copied into a CFDataRef object. @@ -799,9 +974,10 @@ Boolean CFURLWriteBookmarkDataToFile( CFDataRef bookmarkRef, CFURLRef fileURL, C @param aliasRecordDataRef the contents of an AliasRecord to create bookmark data for @result A CFDataRef containing an data, which can be later be passed to CFURLCreateByResolvingBookmarkData() or to CFURLCopyPropertiesForKeysFromBookmarkData() / CFURLCopyPropertyForKeyFromBookmarkData() */ -CFDataRef CFURLCreateBookmarkDataFromAliasRecord ( CFAllocatorRef allocatorRef, CFDataRef aliasRecordDataRef ); +CF_EXPORT +CFDataRef CFURLCreateBookmarkDataFromAliasRecord ( CFAllocatorRef allocatorRef, CFDataRef aliasRecordDataRef ) CF_AVAILABLE_MAC(10_6); -#endif /* TARGET_OS_MAC */ +#endif /* TARGET_OS_MAC || TARGET_OS_EMBEDDED || TARGET_OS_IPHONE */ CF_EXTERN_C_END diff --git a/CFURLAccess.c b/CFURLAccess.c index b79777e..e8d0c07 100644 --- a/CFURLAccess.c +++ b/CFURLAccess.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFURLAccess.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. Responsibility: Chris Linn */ @@ -39,7 +39,7 @@ CFData read/write routines #include #include #include -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX #include #include #include @@ -47,7 +47,6 @@ CFData read/write routines #include #include #include -#include #elif DEPLOYMENT_TARGET_WINDOWS //#include #include @@ -59,7 +58,9 @@ CFData read/write routines #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif - +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#include +#endif #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED @@ -69,9 +70,6 @@ DEFINE_WEAK_CFNETWORK_FUNC_FAIL(Boolean, _CFURLWriteDataAndPropertiesToResource, DEFINE_WEAK_CFNETWORK_FUNC_FAIL(Boolean, _CFURLDestroyResource, (CFURLRef A, SInt32 *B), (A, B), if(B) *B = kCFURLImproperArgumentsError, false) -#elif DEPLOYMENT_TARGET_WINDOWS -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif typedef struct __NSString__ *NSString; @@ -252,7 +250,7 @@ static Boolean _CFFileURLWritePropertiesToResource(CFURLRef url, CFDictionaryRef CFNumberRef modeNum = (CFNumberRef)value; CFNumberGetValue(modeNum, kCFNumberSInt32Type, &mode); } else { -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX #define MODE_TYPE mode_t #elif DEPLOYMENT_TARGET_WINDOWS #define MODE_TYPE uint16_t @@ -733,13 +731,11 @@ Boolean CFURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef } else { #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED result = __CFNetwork__CFURLCreateDataAndPropertiesFromResource(alloc, url, fetchedData, fetchedProperties, desiredProperties, errorCode); -#elif DEPLOYMENT_TARGET_WINDOWS +#else if (fetchedData) *fetchedData = NULL; if (fetchedProperties) *fetchedProperties = NULL; if (errorCode) *errorCode = kCFURLUnknownSchemeError; result = false; -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif } CFRelease(scheme); @@ -815,11 +811,9 @@ Boolean CFURLWriteDataAndPropertiesToResource(CFURLRef url, CFDataRef data, CFDi if (errorCode) *errorCode = kCFURLUnknownSchemeError; } return result; -#elif DEPLOYMENT_TARGET_WINDOWS +#else if (errorCode) *errorCode = kCFURLUnknownSchemeError; return false; -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif } } @@ -863,11 +857,9 @@ Boolean CFURLDestroyResource(CFURLRef url, SInt32 *errorCode) { if (errorCode) *errorCode = kCFURLUnknownSchemeError; } return result; -#elif DEPLOYMENT_TARGET_WINDOWS +#else if (errorCode) *errorCode = kCFURLUnknownSchemeError; return false; -#else -#error Unknown or unspecified DEPLOYMENT_TARGET #endif } } diff --git a/CFURLAccess.h b/CFURLAccess.h index 14b7ef1..c05ec23 100644 --- a/CFURLAccess.h +++ b/CFURLAccess.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFURLAccess.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFURLACCESS__) @@ -63,7 +63,7 @@ large files. */ CF_EXPORT -Boolean CFURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFDataRef *resourceData, CFDictionaryRef *properties, CFArrayRef desiredProperties, SInt32 *errorCode) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER; +Boolean CFURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFDataRef *resourceData, CFDictionaryRef *properties, CFArrayRef desiredProperties, SInt32 *errorCode) CF_AVAILABLE(10_0, 2_0); /* Attempts to write the given data and properties to the given URL. If dataToWrite is NULL, only properties are written out (use @@ -74,17 +74,17 @@ Returns success or failure; errorCode is set as for CFURLCreateDataAndPropertiesFromResource(), above. */ CF_EXPORT -Boolean CFURLWriteDataAndPropertiesToResource(CFURLRef url, CFDataRef dataToWrite, CFDictionaryRef propertiesToWrite, SInt32 *errorCode) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER; +Boolean CFURLWriteDataAndPropertiesToResource(CFURLRef url, CFDataRef dataToWrite, CFDictionaryRef propertiesToWrite, SInt32 *errorCode) CF_AVAILABLE(10_0, 2_0); /* Destroys the resource indicated by url. */ /* Returns success or failure; errorCode set as above. */ CF_EXPORT -Boolean CFURLDestroyResource(CFURLRef url, SInt32 *errorCode) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER; +Boolean CFURLDestroyResource(CFURLRef url, SInt32 *errorCode) CF_AVAILABLE(10_0, 2_0); /* Convenience method which calls through to CFURLCreateDataAndPropertiesFromResource(). */ /* Returns NULL on error and sets errorCode accordingly. */ CF_EXPORT -CFTypeRef CFURLCreatePropertyFromResource(CFAllocatorRef alloc, CFURLRef url, CFStringRef property, SInt32 *errorCode) AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER; +CFTypeRef CFURLCreatePropertyFromResource(CFAllocatorRef alloc, CFURLRef url, CFStringRef property, SInt32 *errorCode) CF_AVAILABLE(10_0, 2_0); /* Common error codes (returned only by the older APIs that predate CFError) */ @@ -104,21 +104,21 @@ typedef CFIndex CFURLError; /* Older property keys */ CF_EXPORT -const CFStringRef kCFURLFileExists AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER; +const CFStringRef kCFURLFileExists CF_AVAILABLE(10_0, 2_0); CF_EXPORT -const CFStringRef kCFURLFileDirectoryContents AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER; +const CFStringRef kCFURLFileDirectoryContents CF_AVAILABLE(10_0, 2_0); CF_EXPORT -const CFStringRef kCFURLFileLength AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER; +const CFStringRef kCFURLFileLength CF_AVAILABLE(10_0, 2_0); CF_EXPORT -const CFStringRef kCFURLFileLastModificationTime AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER; +const CFStringRef kCFURLFileLastModificationTime CF_AVAILABLE(10_0, 2_0); CF_EXPORT -const CFStringRef kCFURLFilePOSIXMode AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER; +const CFStringRef kCFURLFilePOSIXMode CF_AVAILABLE(10_0, 2_0); CF_EXPORT -const CFStringRef kCFURLFileOwnerID AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER; +const CFStringRef kCFURLFileOwnerID CF_AVAILABLE(10_0, 2_0); CF_EXPORT -const CFStringRef kCFURLHTTPStatusCode AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER; +const CFStringRef kCFURLHTTPStatusCode CF_AVAILABLE(10_0, 2_0); CF_EXPORT -const CFStringRef kCFURLHTTPStatusLine AVAILABLE_MAC_OS_X_VERSION_10_0_AND_LATER; +const CFStringRef kCFURLHTTPStatusLine CF_AVAILABLE(10_0, 2_0); /* The value of kCFURLFileExists is a CFBoolean */ /* The value of kCFURLFileDirectoryContents is a CFArray containing CFURLs. An empty array means the directory exists, but is empty */ diff --git a/CFURLPriv.h b/CFURLPriv.h new file mode 100644 index 0000000..c17faf3 --- /dev/null +++ b/CFURLPriv.h @@ -0,0 +1,608 @@ +/* + * Copyright (c) 2011 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@ + */ + +/* CFURLPriv.h + Copyright (c) 2008-2011, Apple Inc. All rights reserved. + */ + +#if !defined(__COREFOUNDATION_CFURLPRIV__) +#define __COREFOUNDATION_CFURLPRIV__ 1 + +#include +#include +#include +#include +#include +#include +#if TARGET_OS_MAC +#include +#include +#include +#include +#include +#endif + +CF_EXTERN_C_BEGIN + +#if TARGET_OS_MAC + +#if MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED +enum { + // Resource I/O related errors, with kCFErrorURLKey containing URL + kCFURLNoSuchResourceError = 4, // Attempt to do a file system operation on a non-existent file + kCFURLResourceLockingError = 255, // Couldn't get a lock on file + kCFURLReadUnknownError = 256, // Read error (reason unknown) + kCFURLReadNoPermissionError = 257, // Read error (permission problem) + kCFURLReadInvalidResourceNameError = 258, // Read error (invalid file name) + kCFURLReadCorruptResourceError = 259, // Read error (file corrupt, bad format, etc) + kCFURLReadNoSuchResourceError = 260, // Read error (no such file) + kCFURLReadInapplicableStringEncodingError = 261, // Read error (string encoding not applicable) also kCFStringEncodingErrorKey + kCFURLReadUnsupportedSchemeError = 262, // Read error (unsupported URL scheme) + kCFURLReadTooLargeError = 263, // Read error (file too large) + kCFURLReadUnknownStringEncodingError = 264, // Read error (string encoding of file contents could not be determined) + kCFURLWriteUnknownError = 512, // Write error (reason unknown) + kCFURLWriteNoPermissionError = 513, // Write error (permission problem) + kCFURLWriteInvalidResourceNameError = 514, // Write error (invalid file name) + kCFURLWriteInapplicableStringEncodingError = 517, // Write error (string encoding not applicable) also kCFStringEncodingErrorKey + kCFURLWriteUnsupportedSchemeError = 518, // Write error (unsupported URL scheme) + kCFURLWriteOutOfSpaceError = 640, // Write error (out of storage space) + kCFURLWriteVolumeReadOnlyError = 642, // Write error (readonly volume) +}; +#endif + + +enum { + kCFURLFileReferencePathStyle = 14, +}; + + +/* + Error user dictionary keys +*/ +CF_EXPORT +const CFStringRef kCFURLKeyArrayErrorKey CF_AVAILABLE(10_6, 4_0); + + +/* + Private File System Property Keys +*/ +CF_EXPORT const CFStringRef _kCFURLPathKey CF_AVAILABLE(10_6, 4_0); + /* File system path (CFString) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIDKey CF_AVAILABLE(10_6, 4_0); + /* Volume ID (CFNumber) */ + +CF_EXPORT const CFStringRef _kCFURLInodeNumberKey CF_AVAILABLE(10_6, 4_0); + /* 64-bit inode number (the inode number from the file system) (CFNumber) */ + +CF_EXPORT const CFStringRef _kCFURLFileIDKey CF_AVAILABLE(10_6, 4_0); + /* 64-bit file ID (for tracking a file by ID. This may or may not be the inode number) (CFNumber) */ + +CF_EXPORT const CFStringRef _kCFURLParentDirectoryIDKey CF_AVAILABLE(10_6, 4_0); + /* 64-bit file ID (for tracking a parent directory by ID. This may or may not be the inode number) (CFNumber) */ + +/* OBSOLETE */CF_EXPORT const CFStringRef _kCFURLFilePathKey CF_DEPRECATED(10_0, 10_6, 2_0, 4_0); + /* _kCFURLFilePathKey was never implemented. Use _kCFURLPathKey instead. */ + +CF_EXPORT const CFStringRef _kCFURLDistinctLocalizedNameKey CF_AVAILABLE(10_6, 4_0); + /* The localized name, if it is disnct from the real name. Otherwise, NULL (CFString) */ + +CF_EXPORT const CFStringRef _kCFURLNameExtensionKey CF_AVAILABLE(10_6, 4_0); + /* The name extenison (CFString) */ + +CF_EXPORT const CFStringRef _kCFURLFinderInfoKey CF_AVAILABLE(10_6, 4_0); + /* A 16-byte Finder Info structure immediately followed by a 16-byte Extended Finder Info structure (CFData) */ + +CF_EXPORT const CFStringRef _kCFURLIsCompressedKey CF_AVAILABLE(10_6, 4_0); + /* True if resource's data is transparently compressed by the system on its storage device (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLIsApplicationKey CF_AVAILABLE(10_6, 4_0); + /* True if resource is an application (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLCanSetHiddenExtensionKey CF_AVAILABLE(10_6, 4_0); + /* True if the filename extension can be hidden or unhidden (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLIsReadableKey CF_AVAILABLE(10_6, 4_0); +/* OBSOLETE */CF_EXPORT const CFStringRef _kCFURLUserCanReadKey CF_DEPRECATED(10_0, 10_6, 2_0, 4_0); + /* True if current user can read the resource (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLIsWriteableKey CF_AVAILABLE(10_6, 4_0); +/* OBSOLETE */CF_EXPORT const CFStringRef _kCFURLUserCanWriteKey CF_DEPRECATED(10_0, 10_6, 2_0, 4_0); + /* True if current user can write to the resource (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLIsExecutableKey CF_AVAILABLE(10_6, 4_0); +/* OBSOLETE */CF_EXPORT const CFStringRef _kCFURLUserCanExecuteKey CF_DEPRECATED(10_0, 10_6, 2_0, 4_0); + /* True if current user can execute a file resource or search a directory resource (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLParentDirectoryIsVolumeRootKey CF_AVAILABLE(10_6, 4_0); + /* True if the parent directory is the root of a volume (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLFileSecurityKey CF_AVAILABLE(10_6, 4_0); + /* The file's security settings (FSFileSecurity, CarbonCore/Files.h) */ + +CF_EXPORT const CFStringRef _kCFURLFileSizeOfResourceForkKey CF_AVAILABLE(10_6, 4_0); + /* Size in bytes of the resource fork (CFNumber) */ + +CF_EXPORT const CFStringRef _kCFURLFileAllocatedSizeOfResourceForkKey CF_AVAILABLE(10_6, 4_0); + /* Size in bytes of the blocks allocated for the resource fork (CFNumber) */ + +CF_EXPORT const CFStringRef _kCFURLEffectiveIconImageDataKey CF_AVAILABLE(10_6, 4_0); + /* Icon image data, i.e. raw pixel data (CFData) */ + +CF_EXPORT const CFStringRef _kCFURLCustomIconImageDataKey CF_AVAILABLE(10_6, 4_0); + /* Icon image data of the item's custom icon, if any (CFData) */ + +CF_EXPORT const CFStringRef _kCFURLEffectiveIconFlattenedReferenceDataKey CF_AVAILABLE(10_6, 4_0); + /* Icon flattened reference, suitable for cheaply sharing the effective icon reference across processess (CFData) */ + +CF_EXPORT const CFStringRef _kCFURLBundleIdentifierKey CF_AVAILABLE(10_6, 4_0); + /* If resource is a bundle, the bundle identifier (CFString) */ + +CF_EXPORT const CFStringRef _kCFURLVersionKey CF_AVAILABLE(10_6, 4_0); + /* If resource is a bundle, the bundle version (CFBundleVersion) as a string (CFString) */ + +CF_EXPORT const CFStringRef _kCFURLShortVersionStringKey CF_AVAILABLE(10_6, 4_0); + /* If resource is a bundle, the bundle short version (CFBundleShortVersionString) as a string (CFString) */ + +CF_EXPORT const CFStringRef _kCFURLOwnerIDKey CF_AVAILABLE(10_6, 4_0); + /* 32-bit owner ID (uid_t) (CFNumber) */ + +CF_EXPORT const CFStringRef _kCFURLGroupIDKey CF_AVAILABLE(10_6, 4_0); + /* 32-bit group ID (gid_t) (CFNumber) */ + +CF_EXPORT const CFStringRef _kCFURLStatModeKey CF_AVAILABLE(10_6, 4_0); + /* 32-bit group ID (mode_t) (CFNumber) */ + +CF_EXPORT const CFStringRef _kCFURLLocalizedNameDictionaryKey CF_AVAILABLE(10_7, NA); + /* For items with localized display names, the dictionary of all available localizations. The keys are the cannonical locale strings for the available localizations. (CFDictionary) */ + +CF_EXPORT const CFStringRef _kCFURLLocalizedTypeDescriptionDictionaryKey CF_AVAILABLE(10_7, NA); + /* The dictionary of all available localizations of the item kind string. The keys are the cannonical locale strings for the available localizations. (CFDictionary) */ + +CF_EXPORT const CFStringRef _kCFURLApplicationCategoriesKey CF_AVAILABLE(10_7, NA); + /* The array of category UTI strings associated with the url. (CFArray) */ + +/* Additional volume properties */ + +CF_EXPORT const CFStringRef _kCFURLVolumeRefNumKey CF_AVAILABLE(10_6, 4_0); + /* The Carbon File Manager's FSVolumeRefNum for the resource volume (CFNumber) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeUUIDStringKey CF_AVAILABLE(10_6, 4_0); + /* The volume's persistent unique ID as a string, or NULL if not available (CFString) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeCreationDateKey CF_AVAILABLE(10_6, 4_0); + /* Value type CFDate */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsLocalKey CF_AVAILABLE(10_6, 4_0); + /* Volume is on a locally connected device -- not a network volume (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsAutomountKey CF_AVAILABLE(10_6, 4_0); + /* Volume was mounted by the automounter (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeDontBrowseKey CF_AVAILABLE(10_6, 4_0); + /* Don't browse: generally, not shown to users (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsReadOnlyKey CF_AVAILABLE(10_6, 4_0); + /* Mounted read-only (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsQuarantinedKey CF_AVAILABLE(10_6, 4_0); + /* Mounted quarantined (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsEjectableKey CF_AVAILABLE(10_6, 4_0); + /* Volume is ejectable media (CD, DVD, etc) (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsRemovableKey CF_AVAILABLE(10_6, 4_0); + /* Volume can be disconnected (USB, FireWire) (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsInternalKey CF_AVAILABLE(10_6, 4_0); + /* Device is on an internal bus/channel (Note: this has different behavior than the public VolumeIsInternal key) (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsExternalKey CF_AVAILABLE(10_6, 4_0); + /* Device is on an external bus/channel (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsDiskImageKey CF_AVAILABLE(10_6, 4_0); + /* Volume is a mounted disk image (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLDiskImageBackingURLKey CF_AVAILABLE(10_6, 4_0); + /* If volume is a mounted disk image, the URL of the backing disk image (CFURL) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsFileVaultKey CF_AVAILABLE(10_6, 4_0); + /* Volume uses File Vault encryption (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsiDiskKey CF_AVAILABLE(10_6, 4_0); + /* Volume is an iDisk (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeiDiskUserNameKey CF_AVAILABLE(10_6, 4_0); + /* If volume is an iDisk, the base member name of the iDisk owner (CFString) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsLocaliDiskMirrorKey CF_AVAILABLE(10_6, 4_0); + /* Volume is a local mirror of an iDisk (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsiPodKey CF_AVAILABLE(10_6, 4_0); + /* Volume is on an iPod (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsCDKey CF_AVAILABLE(10_6, 4_0); + /* Volume is a CD (audio or CD-ROM). (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsDVDKey CF_AVAILABLE(10_6, 4_0); + /* Volume is a DVD (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsDeviceFileSystemKey CF_AVAILABLE(10_7, 5_0); + /* Volume is devfs (CFBoolean) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeIsHFSStandardKey CF_AVAILABLE(10_6, 4_0); + /* Volume is HFS standard (which includes AFP volumes). Directory IDs, but not file IDs, can be looked up. (CFBoolean) */ + +/* Keys specific to bookmarks at this time */ +CF_EXPORT const CFStringRef _kCFURLPropertyKeyFullPathString CF_AVAILABLE(10_6, 4_0); + /* the full filesystem path of the item the bookmark was create against */ + +CF_EXPORT const CFStringRef _kCFURLURLString CF_AVAILABLE(10_6, 4_0); + /* the url string ( possibly relative to a base url ) of the url this bookmark was created against. */ + +CF_EXPORT const CFStringRef _kCFURLFileIDData CF_AVAILABLE(10_6, 4_0); + /* the url string ( possibly relative to a base url ) of the url this bookmark was created against. */ + +CF_EXPORT const CFStringRef _kCFURLResolvedFromBookmarkDataKey CF_AVAILABLE(10_6, 4_0); + /* the bookmark data that was resolved to produce the URL, if any (CFData) */ + +CF_EXPORT const CFStringRef _kCFURLVolumeMountPointStringKey CF_AVAILABLE(10_6, 4_0); + /* the volume mountpoint string (Read-only, value type CFString) */ + +CF_EXPORT const CFStringRef _kCFURLCompleteMountURLKey CF_AVAILABLE(10_6, 4_0); + /* the URL to mount the volume on which the resource is stored, if any (Read-only, value type CFURL) */ + + + +/* + Some common boolean properties can be accessed as a bitfield + for better performance -- see _CFURLGetResourcePropertyFlags() and + _CFURLCopyResourcePropertyValuesAndFlags(), below. + */ +enum { + kCFURLResourceIsRegularFile = 0x00000001, + kCFURLResourceIsDirectory = 0x00000002, + kCFURLResourceIsSymbolicLink = 0x00000004, + kCFURLResourceIsVolume = 0x00000008, + kCFURLResourceIsPackage = 0x00000010, + kCFURLResourceIsSystemImmutable = 0x00000020, + kCFURLResourceIsUserImmutable = 0x00000040, + kCFURLResourceIsHidden = 0x00000080, + kCFURLResourceHasHiddenExtension = 0x00000100, + kCFURLResourceIsApplication = 0x00000200, + kCFURLResourceIsCompressed = 0x00000400, + /* OBSOLETE */ kCFURLResourceIsSystemCompressed = 0x00000400, /* -> kCFURLResourceIsCompressed */ + kCFURLCanSetHiddenExtension = 0x00000800, + kCFURLResourceIsReadable = 0x00001000, + kCFURLResourceIsWriteable = 0x00002000, + kCFURLResourceIsExecutable = 0x00004000, /* execute files or search directories */ + kCFURLIsAliasFile = 0x00008000, + kCFURLIsMountTrigger = 0x00010000, +}; +typedef unsigned long long CFURLResourcePropertyFlags; + + +/* + _CFURLGetResourceFlags - Returns a bit array of resource flags in the "flags" + output parameter. Only flags whose corresponding bits are set in the "mask" parameter + are valid in the output bit array. Returns true on success, false if an error occurs. + Optional output error: the error is set to a valid CFErrorRef if and only if the function + returns false. A valid output error must be released by the caller. + */ +CF_EXPORT +Boolean _CFURLGetResourcePropertyFlags(CFURLRef url, CFURLResourcePropertyFlags mask, CFURLResourcePropertyFlags *flags, CFErrorRef *error) CF_AVAILABLE(10_6, 4_0); + + +/* + File resource properties which can be obtained with _CFURLCopyFilePropertyValuesAndFlags(). + */ +enum { + kCFURLName = 0x0000000000000001, + kCFURLLinkCount = 0x0000000000000002, + kCFURLVolumeIdentifier = 0x0000000000000004, + kCFURLObjectIdentifier = 0x0000000000000008, + kCFURLCreationDate = 0x0000000000000010, + kCFURLContentModificationDate = 0x0000000000000020, + kCFURLAttributeModificationDate = 0x0000000000000040, + kCFURLFileSize = 0x0000000000000080, + kCFURLFileAllocatedSize = 0x0000000000000100, + kCFURLFileSizeOfResourceFork = 0x0000000000000200, + kCFURLFileAllocatedSizeOfResourceFork = 0x0000000000000400, + kCFURLFinderInfo = 0x0000000000000800, + kCFURLFileSecurity = 0x0000000000001000, +}; +typedef unsigned long long CFURLFilePropertyBitmap; + +/* + The structure where _CFURLCopyFilePropertyValuesAndFlags() returns file resource properties. + */ +struct _CFURLFilePropertyValues { + CFStringRef name; /* you are responsible for releasing this if you ask for it and get it */ + uint32_t linkCount; + uint64_t volumeIdentifier; + uint64_t objectIdentifier; + CFAbsoluteTime creationDate; + CFAbsoluteTime contentModificationDate; + CFAbsoluteTime attributeModificationDate; + uint64_t fileSize; + uint64_t fileAllocatedSize; + uint64_t fileSizeOfResourceFork; + uint64_t fileAllocatedSizeOfResourceFork; + uint8_t finderInfo[32]; + CFFileSecurityRef fileSecurity; /* you are responsible for releasing this if you ask for it and get it */ +}; +typedef struct _CFURLFilePropertyValues _CFURLFilePropertyValues; + +/* + _CFURLCopyResourcePropertyValuesAndFlags - Returns property values as simple types + whenever possible. Returns a bit array of resource flags in the "flags" + output parameter. Only flags whose corresponding bits are set in the "mask" parameter + are valid in the output bit array. Returns true on success, false if an error occurs. + Optional output error: the error is set to a valid CFErrorRef if and only if the function + returns false. A valid output error must be released by the caller. + */ +CF_EXPORT +Boolean _CFURLCopyResourcePropertyValuesAndFlags( CFURLRef url, CFURLFilePropertyBitmap requestProperties, CFURLFilePropertyBitmap *actualProperties, struct _CFURLFilePropertyValues *properties, CFURLResourcePropertyFlags propertyFlagsMask, CFURLResourcePropertyFlags *propertyFlags, CFErrorRef *error) CF_AVAILABLE(10_7, 4_0); + +/* + Volume property flags + */ +enum { + kCFURLVolumeIsLocal = 0x1LL, // Local device (vs. network device) + kCFURLVolumeIsAutomount = 0x2LL, // Mounted by the automounter + kCFURLVolumeDontBrowse = 0x4LL, // Hidden from user browsing + kCFURLVolumeIsReadOnly = 0x8LL, // Mounted read-only + kCFURLVolumeIsQuarantined = 0x10LL, // Mounted with quarantine bit + kCFURLVolumeIsEjectable = 0x20LL, + kCFURLVolumeIsRemovable = 0x40LL, + kCFURLVolumeIsInternal = 0x80LL, + kCFURLVolumeIsExternal = 0x100LL, + kCFURLVolumeIsDiskImage = 0x200LL, + kCFURLVolumeIsFileVault = 0x400LL, + kCFURLVolumeIsLocaliDiskMirror = 0x800LL, + kCFURLVolumeIsiPod = 0x1000LL, + kCFURLVolumeIsiDisk = 0x2000LL, + kCFURLVolumeIsCD = 0x4000LL, + kCFURLVolumeIsDVD = 0x8000LL, + kCFURLVolumeIsDeviceFileSystem = 0x10000LL, +// IMPORTANT: The values of the following flags must stay in sync with the +// VolumeCapabilities flags in CarbonCore (FileIDTreeStorage.h) + kCFURLVolumeSupportsPersistentIDs = 0x100000000LL, + kCFURLVolumeSupportsSearchFS = 0x200000000LL, + kCFURLVolumeSupportsExchange = 0x400000000LL, + // reserved 0x800000000LL, + kCFURLVolumeSupportsSymbolicLinks = 0x1000000000LL, + kCFURLVolumeSupportsDenyModes = 0x2000000000LL, + kCFURLVolumeSupportsCopyFile = 0x4000000000LL, + kCFURLVolumeSupportsReadDirAttr = 0x8000000000LL, + kCFURLVolumeSupportsJournaling = 0x10000000000LL, + kCFURLVolumeSupportsRename = 0x20000000000LL, + kCFURLVolumeSupportsFastStatFS = 0x40000000000LL, + kCFURLVolumeSupportsCaseSensitiveNames = 0x80000000000LL, + kCFURLVolumeSupportsCasePreservedNames = 0x100000000000LL, + kCFURLVolumeSupportsFLock = 0x200000000000LL, + kCFURLVolumeHasNoRootDirectoryTimes = 0x400000000000LL, + kCFURLVolumeSupportsExtendedSecurity = 0x800000000000LL, + kCFURLVolumeSupports2TBFileSize = 0x1000000000000LL, + kCFURLVolumeSupportsHardLinks = 0x2000000000000LL, + kCFURLVolumeSupportsMandatoryByteRangeLocks = 0x4000000000000LL, + kCFURLVolumeSupportsPathFromID = 0x8000000000000LL, + // reserved 0x10000000000000LL, + kCFURLVolumeIsJournaling = 0x20000000000000LL, + kCFURLVolumeSupportsSparseFiles = 0x40000000000000LL, + kCFURLVolumeSupportsZeroRuns = 0x80000000000000LL, + kCFURLVolumeSupportsVolumeSizes = 0x100000000000000LL, + kCFURLVolumeSupportsRemoteEvents = 0x200000000000000LL, + kCFURLVolumeSupportsHiddenFiles = 0x400000000000000LL, + kCFURLVolumeSupportsDecmpFSCompression = 0x800000000000000LL, + kCFURLVolumeHas64BitObjectIDs = 0x1000000000000000LL, + kCFURLVolumePropertyFlagsAll = 0xffffffffffffffffLL +}; +typedef unsigned long long CFURLVolumePropertyFlags; + + +/* + _CFURLGetVolumePropertyFlags - Returns a bit array of volume properties. + Only flags whose corresponding bits are set in the "mask" parameter are valid + in the output bit array. Returns true on success, false if an error occurs. + Optional output error: the error is set to a valid CFErrorRef if and only if the function + returns false. A valid output error must be released by the caller. + */ +CF_EXPORT +Boolean _CFURLGetVolumePropertyFlags(CFURLRef url, CFURLVolumePropertyFlags mask, CFURLVolumePropertyFlags *flags, CFErrorRef *error) CF_AVAILABLE(10_6, 4_0); + +/* + _CFURLSetResourcePropertyForKeyAndUpdateFileCache - Works mostly like CFURLSetResourcePropertyForKey + except that file system properties are updated in the URL's file cache (if it has a valid cache) + and dependant properties are not flushed. This means that values in the cache may not match what + is on the file system (see for details). + + Only for use by DesktopServices! + */ +CF_EXPORT +Boolean _CFURLSetResourcePropertyForKeyAndUpdateFileCache(CFURLRef url, CFStringRef key, CFTypeRef propertyValue, CFErrorRef *error) CF_AVAILABLE(10_7, NA); + +/* + _CFURLCreateDisplayPathComponentsArray() + + Summary: + _FileURLCreateDisplayPathComponentsArray creates a CFArray of + CFURLs for each component in the path leading up to the target + URL. This routine is suitable for clients who wish to show the + path leading up to a file system item. NOTE: This routine can be + I/O intensive, so use it sparingly, and cache the results if + possible. + + Discussion: + The CFURLs in the result CFArray are ordered from the target URL + to the root of the display path. For example, if the target URL + is file://localhost/System/Library/ the CFURLs in the array will + be ordered: file://localhost/System/Library/, + file://localhost/System/, and then file://localhost/ + + Parameters: + + targetURL: + The target URL. + + error: + A pointer to a CFErrorRef, or NULL. If error is non-NULL and + the function result is NULL, this will be filled in with a + CFErrorRef representing the error that occurred. + + Result: + A CFArray or NULL if an error occurred. + */ +CF_EXPORT +CFArrayRef _CFURLCreateDisplayPathComponentsArray(CFURLRef url, CFErrorRef *error) CF_AVAILABLE(10_7, 4_0); + +#if 0 +/* Not implemented */ +CF_EXPORT +CFURLRef _CFURLCreateFileIDURLFromFSRef(CFAllocatorRef allocator, const struct FSRef *fsRef); +#endif + +CF_EXPORT +CFURLRef _CFURLCreateAbsoluteURLWithDirectoryURLAndName(CFAllocatorRef allocator, CFURLRef directoryURL, CFStringRef name) CF_AVAILABLE(10_6, 4_0); + +/* Returns true for URLs that locate file system resources. */ +CF_EXPORT +Boolean _CFURLIsFileURL(CFURLRef url) CF_AVAILABLE(10_6, 4_0); + +/* Returns true for file URLs that use the file reference form */ +CF_EXPORT +Boolean _CFURLIsFileReferenceURL(CFURLRef url) CF_AVAILABLE(10_6, 4_0); + +/* For use by Core Services */ +CF_EXPORT +void *__CFURLResourceInfoPtr(CFURLRef url) CF_AVAILABLE(10_6, 4_0); + +CF_EXPORT +void __CFURLSetResourceInfoPtr(CFURLRef url, void *ptr) CF_AVAILABLE(10_6, 4_0); + +#if TARGET_OS_MAC + +CF_EXPORT +CFURLRef _CFURLCreateFileReferenceURLFromIDs( CFAllocatorRef allocator, fsid_t fsid, UInt64 inodeNumber ) CF_AVAILABLE(10_7, NA); + +/* _CFURLVolumeIdentifierGetVolumeRefNum is used by LaunchServices */ +CF_EXPORT +SInt16 _CFURLVolumeIdentifierGetVolumeRefNum(UInt64 volumeIdentifier) CF_AVAILABLE(10_7, NA); + +CF_EXPORT +CFURLRef _CFURLCreateFileReferenceURLFromFSRef(CFAllocatorRef allocator, const struct FSRef *ref) CF_AVAILABLE(10_7, NA); + +/* _CFURLGetFSRef is a very lightweight version of CFURLGetFSRef that assumes the CFURL is a file URL and the properties needed to create a FSRef are available in the file URL's cache. This is for use only by CarbonCore's FileOperations SPI and API. */ +CF_EXPORT +Boolean _CFURLGetFSRef(CFURLRef url, struct FSRef *fsRef) CF_AVAILABLE(10_7, NA); + +/* _CFURLGetObjectInformationNoIO is used by LaunchServices */ +CF_EXPORT +Boolean _CFURLGetObjectInformationNoIO(CFURLRef url, UInt64 * volumeIdentifier, UInt64 * objectIdentifier, UInt32 * statMode) CF_AVAILABLE(10_7, NA); + +#endif + +struct FSCatalogInfo; +struct HFSUniStr255; + +/* _CFURLGetCatalogInfo is used by LaunchServices */ +CF_EXPORT +SInt32 _CFURLGetCatalogInfo(CFURLRef url, UInt32 whichInfo, struct FSCatalogInfo *catalogInfo, struct HFSUniStr255 *name) CF_AVAILABLE(10_7, 5_0); + +/* _CFURLReplaceObject SPI */ + +/* options for _CFURLReplaceObject */ +enum { +// _CFURLItemReplacementUsingOriginalMetadataOnly = 1, // not used + _CFURLItemReplacementUsingNewMetadataOnly = 2, +// _CFURLItemReplacementByMergingMetadata = 3, // not used + _CFURLItemReplacementWithoutDeletingBackupItem = 1 << 4 +}; + +CF_EXPORT +Boolean _CFURLReplaceObject( CFAllocatorRef allocator, CFURLRef originalItemURL, CFURLRef newItemURL, CFStringRef newName, CFStringRef backupItemName, CFOptionFlags options, CFURLRef *resultingURL, CFErrorRef *error ) CF_AVAILABLE(10_7, 5_0); + + +#if (TARGET_OS_MAC) || CF_BUILDING_CF || NSBUILDINGFOUNDATION +CF_EXPORT +CFURLEnumeratorResult _CFURLEnumeratorGetURLsBulk(CFURLEnumeratorRef enumerator, CFIndex maximumURLs, CFIndex *actualURLs, CFURLRef *urls, CFErrorRef *error) CF_AVAILABLE(10_6, 4_0); +#endif + +#if TARGET_OS_MAC + +enum { + kCFBookmarkFileCreationWithoutOverwritingExistingFile = ( 1UL << 8 ), // if destination file already exists don't overwrite it and return an error + kCFBookmarkFileCreationWithoutAppendingAliasExtension = ( 1UL << 9 ), // don't add / change whatever extension is on the created alias file + kCFBookmarkFileCreationWithoutCreatingResourceFork = ( 1UL << 10 ), // don't create the resource-fork half of the alias file + + kCFURLBookmarkCreationAllowCreationIfResourceDoesNotExistMask = ( 1 << 28 ), // allow creation of a bookmark to a file: scheme with a CFURLRef of item which may not exist. If the filesystem item does not exist, the created bookmark contains essentially no properties beyond the url string. + + kCFURLBookmarkCreationDoNotIncludeSandboxExtensionsMask = ( 1 << 29 ), // If set, sandbox extensions are not included in created bookmarks. Ordinarily, bookmarks ( except those created suitable for putting into a bookmark file ) will have a sandbox extension added for the item +}; + +enum { + kCFBookmarkResolutionPerformRelativeResolutionFirstMask = ( 1 << 10 ), // perform relative resolution before absolute resolution. If this bit is set, for this to be useful a relative URL must also have been passed in and the bookmark when created must have been created relative to another url. +}; + +enum { + kCFURLBookmarkComparisonUnableToCompare = 0x00000000, /* the two bookmarks could not be compared for some reason */ + kCFURLBookmarkComparisonNoMatch = 0x00001000, /* Bookmarks do not refer to the same item */ + kCFURLBookmarkComparisonUnlikelyToMatch = 0x00002000, /* it is unlikely that the two items refer to the same filesystem item */ + kCFURLBookmarkComparisonLikelyToMatch = 0x00004000, /* it is likely that the two items refer to the same filesystem item ( but, they may not ) */ + kCFURLBookmarkComparisonMatch = 0x00008000, /* the two items refer to the same item, but other information in the bookmarks may not match */ + kCFURLBookmarkComparisonExactMatch = 0x0000f000 /* the two bookmarks are identical */ +}; +typedef CFIndex CFURLBookmarkMatchResult; + +/* Keys specific to bookmarks at this time */ +CF_EXPORT const CFStringRef _kCFURLPropertyKeyFullPathString; // the full filesystem path of the item the bookmark was create against +CF_EXPORT const CFStringRef _kCFURLURLString; // the url string ( possibly relative to a base url ) of the url this bookmark was created against. +CF_EXPORT const CFStringRef _kCFURLFileIDData; // the url string ( possibly relative to a base url ) of the url this bookmark was created against. + +CFURLBookmarkMatchResult _CFURLCompareBookmarkData( CFDataRef bookmark1Ref, CFDataRef bookmark2Ref, CFURLRef relativeToURL, CFArrayRef* matchingPropertyKeys ) CF_AVAILABLE(10_7, NA); + +CF_EXPORT +CFURLBookmarkMatchResult _CFURLBookmarkDataCompare(CFDataRef bookmark1Ref, CFDataRef bookmark2Ref, CFURLRef relativeToURL, CFArrayRef* matchingPropertyKeys) CF_AVAILABLE(10_7, NA); // Use _CFURLCompareBookmarkData() instead + +CF_EXPORT +OSStatus _CFURLBookmarkDataToAliasHandle(CFDataRef bookmarkRef, void* aliasHandleP) CF_AVAILABLE(10_7, NA); + +#endif + +/* + The following are properties that can be asked of bookmark data objects in addition to the resource properties + from CFURL itself. + */ + +extern const CFStringRef kCFURLBookmarkOriginalPathKey CF_AVAILABLE(10_7, 5_0); +extern const CFStringRef kCFURLBookmarkOriginalRelativePathKey CF_AVAILABLE(10_7, 5_0); +extern const CFStringRef kCFURLBookmarkOriginalRelativePathComponentsArrayKey CF_AVAILABLE(10_7, 5_0); +extern const CFStringRef kCFURLBookmarkOriginalVolumeNameKey CF_AVAILABLE(10_7, 5_0); +extern const CFStringRef kCFURLBookmarkOriginalVolumeCreationDateKey CF_AVAILABLE(10_7, 5_0); + +#endif /* TARGET_OS_MAC */ + +CF_EXTERN_C_END + +#endif /* ! __COREFOUNDATION_CFURLPRIV__ */ + diff --git a/CFUUID.c b/CFUUID.c index 937ff15..6f0a4a6 100644 --- a/CFUUID.c +++ b/CFUUID.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFUUID.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. - Responsibility: Doug Davidson + Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ #include @@ -32,14 +32,38 @@ #include #endif +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS +#include + +static CFMutableDictionaryRef _uniquedUUIDs = NULL; +CF_INLINE void LOCKED(dispatch_block_t work) { + static dispatch_once_t guard; + static dispatch_queue_t CFUUIDGlobalDataLock; + dispatch_once(&guard, ^{ CFUUIDGlobalDataLock = dispatch_queue_create("CFUUID global uniquing table lock", 0); }); + dispatch_sync(CFUUIDGlobalDataLock, work); +} + +#else +// Platforms without dispatch + static CFMutableDictionaryRef _uniquedUUIDs = NULL; -static CFSpinLock_t CFUUIDGlobalDataLock = CFSpinLockInit; +static CFSpinLock_t _uniquedUUIDsLock = CFSpinLockInit; + +CF_INLINE void LOCKED(void (^work)(void)) { + __CFSpinLock(&_uniquedUUIDsLock); + work(); + __CFSpinUnlock(&_uniquedUUIDsLock); +} + +#endif struct __CFUUID { CFRuntimeBase _base; CFUUIDBytes _bytes; }; +typedef struct __CFUUID __CFUUID_t; + static Boolean __CFisEqualUUIDBytes(const void *ptr1, const void *ptr2) { CFUUIDBytes *p1 = (CFUUIDBytes *)ptr1; CFUUIDBytes *p2 = (CFUUIDBytes *)ptr2; @@ -54,20 +78,17 @@ static CFHashCode __CFhashUUIDBytes(const void *ptr) { /* * GC implementation of a weak set specifically designed for UUID */ - -#define LOCK() __CFSpinLock(&CFUUIDGlobalDataLock) -#define UNLOCK() __CFSpinUnlock(&CFUUIDGlobalDataLock) #define MALLOC(x) CFAllocatorAllocate(kCFAllocatorSystemDefault, x, 0) #define FREE(x) CFAllocatorDeallocate(kCFAllocatorSystemDefault, x) #define HASH(x) CFHashBytes((uint8_t *)x, 16) -#define READWEAK(location) auto_read_weak_reference(auto_zone(), (void**)location) -#define WRITEWEAK(location, value) auto_assign_weak_reference(auto_zone(), value, (void **)location, NULL) +#define READWEAK(location) objc_read_weak((id *)location) +#define WRITEWEAK(location, value) objc_assign_weak((id)value, (id *)location) typedef struct { unsigned long count, size; - struct __CFUUID **weakPtrs; + __CFUUID_t **weakPtrs; } _UUIDWeakSet_t; static _UUIDWeakSet_t _UUIDWeakSet; @@ -75,12 +96,12 @@ static _UUIDWeakSet_t _UUIDWeakSet; static void grow_has_lock(void); // enter if not already present -static void enter_has_lock(struct __CFUUID *candidate) { +static void enter_has_lock(__CFUUID_t *candidate) { if (!candidate) return; _UUIDWeakSet_t *table = &_UUIDWeakSet; if (!table->size) grow_has_lock(); unsigned long int hashValue = HASH(&candidate->_bytes) & (table->size-1); - struct __CFUUID *result = table->weakPtrs[hashValue]; + __CFUUID_t *result = table->weakPtrs[hashValue]; while (1) { if (result == (void *)0x1 || result == NULL) { table->weakPtrs[hashValue] = NULL; // so that we don't try to unregister 0x1 @@ -88,7 +109,7 @@ static void enter_has_lock(struct __CFUUID *candidate) { ++table->count; break; } - if (result) result = (struct __CFUUID *)READWEAK(&table->weakPtrs[hashValue]); + if (result) result = (__CFUUID_t *)READWEAK(&table->weakPtrs[hashValue]); if (result) { // see if it is equal to candidate if (__CFisEqualUUIDBytes(&result->_bytes, &candidate->_bytes)) { @@ -107,15 +128,15 @@ static void enter_has_lock(struct __CFUUID *candidate) { } } -static void *find_has_lock(CFUUIDBytes *bytes) { +static void *find_has_lock(const CFUUIDBytes *bytes) { if (!bytes) return NULL; _UUIDWeakSet_t *table = &_UUIDWeakSet; if (!table->size) return NULL; // no entries unsigned long int hashValue = HASH(bytes) & (table->size-1); - struct __CFUUID *result = table->weakPtrs[hashValue]; + __CFUUID_t *result = table->weakPtrs[hashValue]; while (1) { if (result == (void *)0x1) break; - if (result) result = (struct __CFUUID *)READWEAK(&table->weakPtrs[hashValue]); + if (result) result = (__CFUUID_t *)READWEAK(&table->weakPtrs[hashValue]); if (result) { // see if it is equal to bytes if (__CFisEqualUUIDBytes(&result->_bytes, bytes)) return result; @@ -132,20 +153,20 @@ static void grow_has_lock() { _UUIDWeakSet_t *table = &_UUIDWeakSet; if (table->size == 0) { table->size = 16; - table->weakPtrs = (struct __CFUUID **)MALLOC(sizeof(struct __CFUUID *)*table->size); - for (int i = 0; i < table->size; ++i) table->weakPtrs[i] = (struct __CFUUID *)0x1; + table->weakPtrs = (__CFUUID_t **)MALLOC(sizeof(__CFUUID_t *)*table->size); + for (int i = 0; i < table->size; ++i) table->weakPtrs[i] = (__CFUUID_t *)0x1; table->count = 0; return; } table->count = 0; table->size = table->size*2; - struct __CFUUID **oldPtrs = table->weakPtrs; - table->weakPtrs = (struct __CFUUID **)MALLOC(sizeof(struct __CFUUID *)*table->size); - for (int i = 0; i < table->size; ++i) table->weakPtrs[i] = (struct __CFUUID *)0x1; + __CFUUID_t **oldPtrs = table->weakPtrs; + table->weakPtrs = (__CFUUID_t **)MALLOC(sizeof(__CFUUID_t *)*table->size); + for (int i = 0; i < table->size; ++i) table->weakPtrs[i] = (__CFUUID_t *)0x1; for (int i = 0; i < table->size / 2; ++i) { - if (oldPtrs[i] == (struct __CFUUID *)0x1) continue; // available field, ignore + if (oldPtrs[i] == (__CFUUID_t *)0x1) continue; // available field, ignore if (oldPtrs[i] == NULL) continue; // zero'ed by collector, ignore - enter_has_lock((struct __CFUUID *)READWEAK(&oldPtrs[i])); // read, then enter (but enter must check for NULL) + enter_has_lock((__CFUUID_t *)READWEAK(&oldPtrs[i])); // read, then enter (but enter must check for NULL) WRITEWEAK(&oldPtrs[i], NULL); // unregister } FREE(oldPtrs); @@ -153,45 +174,40 @@ static void grow_has_lock() { /***** end of weak set */ -static void __CFUUIDAddUniqueUUID(CFUUIDRef uuid) { +static void __CFUUIDAddUniqueUUIDHasLock(CFUUIDRef uuid) { CFDictionaryKeyCallBacks __CFUUIDBytesDictionaryKeyCallBacks = {0, NULL, NULL, NULL, __CFisEqualUUIDBytes, __CFhashUUIDBytes}; CFDictionaryValueCallBacks __CFnonRetainedUUIDDictionaryValueCallBacks = {0, NULL, NULL, CFCopyDescription, CFEqual}; - __CFSpinLock(&CFUUIDGlobalDataLock); if (kCFUseCollectableAllocator) { - enter_has_lock((struct __CFUUID *)uuid); + enter_has_lock((__CFUUID_t *)uuid); if (_UUIDWeakSet.count > (3 * _UUIDWeakSet.size / 4)) grow_has_lock(); - __CFSpinUnlock(&CFUUIDGlobalDataLock); - return; + } else { + if (!_uniquedUUIDs) _uniquedUUIDs = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &__CFUUIDBytesDictionaryKeyCallBacks, &__CFnonRetainedUUIDDictionaryValueCallBacks); + CFDictionarySetValue(_uniquedUUIDs, &(uuid->_bytes), uuid); } - if (!_uniquedUUIDs) _uniquedUUIDs = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &__CFUUIDBytesDictionaryKeyCallBacks, &__CFnonRetainedUUIDDictionaryValueCallBacks); - CFDictionarySetValue(_uniquedUUIDs, &(uuid->_bytes), uuid); - __CFSpinUnlock(&CFUUIDGlobalDataLock); } -static void __CFUUIDRemoveUniqueUUID(CFUUIDRef uuid) { - __CFSpinLock(&CFUUIDGlobalDataLock); +static void __CFUUIDRemoveUniqueUUIDHasLock(CFUUIDRef uuid) { if (_uniquedUUIDs) CFDictionaryRemoveValue(_uniquedUUIDs, &(uuid->_bytes)); - __CFSpinUnlock(&CFUUIDGlobalDataLock); } -static CFUUIDRef __CFUUIDGetUniquedUUID(CFUUIDBytes *bytes) { +static CFUUIDRef __CFUUIDGetUniquedUUIDHasLock(const CFUUIDBytes *bytes) { CFUUIDRef uuid = NULL; - __CFSpinLock(&CFUUIDGlobalDataLock); if (kCFUseCollectableAllocator) { uuid = (CFUUIDRef)find_has_lock(bytes); } else if (_uniquedUUIDs) { uuid = (CFUUIDRef)CFDictionaryGetValue(_uniquedUUIDs, bytes); } - __CFSpinUnlock(&CFUUIDGlobalDataLock); return uuid; } static void __CFUUIDDeallocate(CFTypeRef cf) { if (kCFUseCollectableAllocator) return; - struct __CFUUID *uuid = (struct __CFUUID *)cf; - __CFUUIDRemoveUniqueUUID(uuid); + __CFUUID_t *uuid = (__CFUUID_t *)cf; + LOCKED(^{ + __CFUUIDRemoveUniqueUUIDHasLock(uuid); + }); } static CFStringRef __CFUUIDCopyDescription(CFTypeRef cf) { @@ -228,19 +244,23 @@ CFTypeID CFUUIDGetTypeID(void) { } static CFUUIDRef __CFUUIDCreateWithBytesPrimitive(CFAllocatorRef allocator, CFUUIDBytes bytes, Boolean isConst) { - struct __CFUUID *uuid = (struct __CFUUID *)__CFUUIDGetUniquedUUID(&bytes); - if (!uuid) { - size_t size; - size = sizeof(struct __CFUUID) - sizeof(CFRuntimeBase); - uuid = (struct __CFUUID *)_CFRuntimeCreateInstance(kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : allocator, __kCFUUIDTypeID, size, NULL); - - if (!uuid) return NULL; - - uuid->_bytes = bytes; - __CFUUIDAddUniqueUUID(uuid); - } else if (!isConst) { - CFRetain(uuid); - } + __block __CFUUID_t *uuid = NULL; + LOCKED(^{ + uuid = (__CFUUID_t *)__CFUUIDGetUniquedUUIDHasLock(&bytes); + if (!uuid) { + size_t size; + size = sizeof(__CFUUID_t) - sizeof(CFRuntimeBase); + uuid = (__CFUUID_t *)_CFRuntimeCreateInstance(kCFUseCollectableAllocator ? kCFAllocatorSystemDefault : allocator, __kCFUUIDTypeID, size, NULL); + + if (!uuid) return; + + uuid->_bytes = bytes; + __CFUUIDAddUniqueUUIDHasLock(uuid); + } else if (!isConst) { + CFRetain(uuid); + } + }); + return (CFUUIDRef)uuid; } @@ -250,33 +270,31 @@ static CFUUIDRef __CFUUIDCreateWithBytesPrimitive(CFAllocatorRef allocator, CFUU CFUUIDRef CFUUIDCreate(CFAllocatorRef alloc) { /* Create a new bytes struct and then call the primitive. */ - CFUUIDBytes bytes; - uint32_t retval = 0; + __block CFUUIDBytes bytes; + __block uint32_t retval = 0; - __CFSpinLock(&CFUUIDGlobalDataLock); + LOCKED(^{ #if DEPLOYMENT_TARGET_WINDOWS - UUID u; - long rStatus = UuidCreate(&u); - if (RPC_S_OK != rStatus && RPC_S_UUID_LOCAL_ONLY != rStatus) retval = 1; - memmove(&bytes, &u, sizeof(bytes)); + UUID u; + long rStatus = UuidCreate(&u); + if (RPC_S_OK != rStatus && RPC_S_UUID_LOCAL_ONLY != rStatus) retval = 1; + memmove(&bytes, &u, sizeof(bytes)); #elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - static Boolean useV1UUIDs = false, checked = false; - uuid_t uuid; - if (!checked) { - const char *value = __CFgetenv("CFUUIDVersionNumber"); - if (value) { - if (1 == strtoul_l(value, NULL, 0, NULL)) useV1UUIDs = true; - } else { - if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionTiger)) useV1UUIDs = true; + static Boolean useV1UUIDs = false, checked = false; + uuid_t uuid; + if (!checked) { + const char *value = __CFgetenv("CFUUIDVersionNumber"); + if (value) { + if (1 == strtoul_l(value, NULL, 0, NULL)) useV1UUIDs = true; + } + checked = true; } - checked = true; - } - if (useV1UUIDs) uuid_generate_time(uuid); else uuid_generate_random(uuid); - memcpy(&bytes, uuid, sizeof(uuid)); + if (useV1UUIDs) uuid_generate_time(uuid); else uuid_generate_random(uuid); + memcpy((void *)&bytes, uuid, sizeof(uuid)); #else - retval = 1; + retval = 1; #endif - __CFSpinUnlock(&CFUUIDGlobalDataLock); + }); return (retval == 0) ? __CFUUIDCreateWithBytesPrimitive(alloc, bytes, false) : NULL; } diff --git a/CFUUID.h b/CFUUID.h index 7b000e9..0b3380c 100644 --- a/CFUUID.h +++ b/CFUUID.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFUUID.h - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFUUID__) diff --git a/CFUniChar.c b/CFUniChar.c index 10a00bf..bbda50d 100644 --- a/CFUniChar.c +++ b/CFUniChar.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,13 +22,12 @@ */ /* CFUniChar.c - Copyright (c) 2001-2009, Apple Inc. All rights reserved. + Copyright (c) 2001-2011, Apple Inc. All rights reserved. Responsibility: Aki Inoue */ #include #include "CFInternal.h" -#include "CFBundle_Internal.h" #include "CFUniChar.h" #include "CFStringEncodingConverterExt.h" #include "CFUnicodeDecomposition.h" @@ -41,7 +40,6 @@ #include #include #include -#include #endif #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED #include @@ -101,7 +99,7 @@ static const void *__CFGetSectDataPtr(const char *segname, const char *sectname, // Memory map the file -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX CF_INLINE void __CFUniCharCharacterSetPath(char *cpath) { #elif DEPLOYMENT_TARGET_WINDOWS CF_INLINE void __CFUniCharCharacterSetPath(wchar_t *wpath) { @@ -110,6 +108,8 @@ CF_INLINE void __CFUniCharCharacterSetPath(wchar_t *wpath) { #endif #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED strlcpy(cpath, __kCFCharacterSetDir, MAXPATHLEN); +#elif DEPLOYMENT_TARGET_LINUX + strlcpy(cpath, __kCFCharacterSetDir, MAXPATHLEN); #elif DEPLOYMENT_TARGET_WINDOWS wchar_t frameworkPath[MAXPATHLEN]; _CFGetFrameworkPath(frameworkPath, MAXPATHLEN); @@ -163,10 +163,10 @@ void __AddBitmapStateForName(const wchar_t *bitmapName) { } #endif -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -static bool __CFUniCharLoadBytesFromFile(const char *fileName, const void **bytes) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX +static bool __CFUniCharLoadBytesFromFile(const char *fileName, const void **bytes, int64_t *fileSize) { #elif DEPLOYMENT_TARGET_WINDOWS -static bool __CFUniCharLoadBytesFromFile(const wchar_t *fileName, const void **bytes) { +static bool __CFUniCharLoadBytesFromFile(const wchar_t *fileName, const void **bytes, int64_t *fileSize) { #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif @@ -191,14 +191,22 @@ static bool __CFUniCharLoadBytesFromFile(const wchar_t *fileName, const void **b mappingHandle = CreateFileMapping(bitmapFileHandle, NULL, PAGE_READONLY, 0, 0, NULL); CloseHandle(bitmapFileHandle); if (!mappingHandle) return false; + } - *bytes = MapViewOfFileEx(mappingHandle, FILE_MAP_READ, 0, 0, 0, 0); - CloseHandle(mappingHandle); - } else { - *bytes = MapViewOfFileEx(mappingHandle, FILE_MAP_READ, 0, 0, 0, 0); - CloseHandle(mappingHandle); + *bytes = MapViewOfFileEx(mappingHandle, FILE_MAP_READ, 0, 0, 0, 0); + + if (NULL != fileSize) { + MEMORY_BASIC_INFORMATION memoryInfo; + + if (0 == VirtualQueryEx(mappingHandle, *bytes, &memoryInfo, sizeof(memoryInfo))) { + *fileSize = 0; // This indicates no checking. Is it right ? + } else { + *fileSize = memoryInfo.RegionSize; + } } + CloseHandle(mappingHandle); + return (*bytes ? true : false); #else struct stat statBuf; @@ -213,33 +221,38 @@ static bool __CFUniCharLoadBytesFromFile(const wchar_t *fileName, const void **b } close(fd); + if (NULL != fileSize) *fileSize = statBuf.st_size; + return true; #endif } #endif // USE_MACHO_SEGMENT -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED -static bool __CFUniCharLoadFile(const char *bitmapName, const void **bytes) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX +static bool __CFUniCharLoadFile(const char *bitmapName, const void **bytes, int64_t *fileSize) { #elif DEPLOYMENT_TARGET_WINDOWS -static bool __CFUniCharLoadFile(const wchar_t *bitmapName, const void **bytes) { +static bool __CFUniCharLoadFile(const wchar_t *bitmapName, const void **bytes, int64_t *fileSize) { #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif #if USE_MACHO_SEGMENT *bytes = __CFGetSectDataPtr("__UNICODE", bitmapName, NULL); + + if (NULL != fileSize) *fileSize = 0; + return *bytes ? true : false; #else -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX char cpath[MAXPATHLEN]; __CFUniCharCharacterSetPath(cpath); - strlcat(cpath, bitmapName, MAXPATHLEN); - return __CFUniCharLoadBytesFromFile(cpath, bytes); + strlcat(cpath, bitmapName, MAXPATHLEN); + return __CFUniCharLoadBytesFromFile(cpath, bytes, fileSize); #elif DEPLOYMENT_TARGET_WINDOWS wchar_t wpath[MAXPATHLEN]; __CFUniCharCharacterSetPath(wpath); - wcsncat(wpath, bitmapName, MAXPATHLEN); - return __CFUniCharLoadBytesFromFile(wpath, bytes); + wcsncat(wpath, bitmapName, MAXPATHLEN); + return __CFUniCharLoadBytesFromFile(wpath, bytes, fileSize); #else #error Unknown or unspecified DEPLOYMENT_TARGET #endif @@ -263,6 +276,37 @@ CF_INLINE bool isWhitespaceAndNewline(UTF32Char theChar, uint16_t charset, const return ((isWhitespace(theChar, charset, data) || isNewline(theChar, charset, data)) ? true : false); } +#if USE_MACHO_SEGMENT +CF_INLINE bool __CFSimpleFileSizeVerification(const void *bytes, int64_t fileSize) { return true; } +#elif 1 +// __CFSimpleFileSizeVerification is broken +static bool __CFSimpleFileSizeVerification(const void *bytes, int64_t fileSize) { return true; } +#else +static bool __CFSimpleFileSizeVerification(const void *bytes, int64_t fileSize) { + bool result = true; + + if (fileSize > 0) { + if ((sizeof(uint32_t) * 2) > fileSize) { + result = false; + } else { + uint32_t headerSize = CFSwapInt32BigToHost(*((uint32_t *)((char *)bytes + 4))); + + if ((headerSize < (sizeof(uint32_t) * 4)) || (headerSize > fileSize)) { + result = false; + } else { + const uint32_t *lastElement = (uint32_t *)(((uint8_t *)bytes) + headerSize) - 2; + + if ((headerSize + CFSwapInt32BigToHost(lastElement[0]) + CFSwapInt32BigToHost(lastElement[1])) > headerSize) result = false; + } + } + } + + if (!result) CFLog(kCFLogLevelCritical, CFSTR("File size verification for Unicode database file failed.")); + + return result; +} +#endif // USE_MACHO_SEGMENT + typedef struct { uint32_t _numPlanes; const uint8_t **_planes; @@ -275,12 +319,12 @@ static __CFUniCharBitmapData *__CFUniCharBitmapDataArray = NULL; static CFSpinLock_t __CFUniCharBitmapLock = CFSpinLockInit; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX #if !defined(CF_UNICHAR_BITMAP_FILE) #if USE_MACHO_SEGMENT #define CF_UNICHAR_BITMAP_FILE "__csbitmaps" #else -#define CF_UNICHAR_BITMAP_FILE "CFCharacterSetBitmaps.bitmap" +#define CF_UNICHAR_BITMAP_FILE "/CFCharacterSetBitmaps.bitmap" #endif #endif #elif DEPLOYMENT_TARGET_WINDOWS @@ -301,10 +345,11 @@ static bool __CFUniCharLoadBitmapData(void) { const void *bitmapBase; const void *bitmap; int idx, bitmapIndex; + int64_t fileSize; __CFSpinLock(&__CFUniCharBitmapLock); - if (__CFUniCharBitmapDataArray || !__CFUniCharLoadFile(CF_UNICHAR_BITMAP_FILE, &bytes)) { + if (__CFUniCharBitmapDataArray || !__CFUniCharLoadFile(CF_UNICHAR_BITMAP_FILE, &bytes, &fileSize) || !__CFSimpleFileSizeVerification(bytes, fileSize)) { __CFSpinUnlock(&__CFUniCharBitmapLock); return false; } @@ -579,18 +624,18 @@ static const void **__CFUniCharMappingTables = NULL; static CFSpinLock_t __CFUniCharMappingTableLock = CFSpinLockInit; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX #if __CF_BIG_ENDIAN__ #if USE_MACHO_SEGMENT #define MAPPING_TABLE_FILE "__data" #else -#define MAPPING_TABLE_FILE "CFUnicodeData-B.mapping" +#define MAPPING_TABLE_FILE "/CFUnicodeData-B.mapping" #endif #else #if USE_MACHO_SEGMENT #define MAPPING_TABLE_FILE "__data" #else -#define MAPPING_TABLE_FILE "CFUnicodeData-L.mapping" +#define MAPPING_TABLE_FILE "/CFUnicodeData-L.mapping" #endif #endif #elif DEPLOYMENT_TARGET_WINDOWS @@ -620,8 +665,9 @@ __private_extern__ const void *CFUniCharGetMappingData(uint32_t type) { const void *bodyBase; int headerSize; int idx, count; + int64_t fileSize; - if (!__CFUniCharLoadFile(MAPPING_TABLE_FILE, &bytes)) { + if (!__CFUniCharLoadFile(MAPPING_TABLE_FILE, &bytes, &fileSize) || !__CFSimpleFileSizeVerification(bytes, fileSize)) { __CFSpinUnlock(&__CFUniCharMappingTableLock); return NULL; } @@ -720,10 +766,12 @@ static bool __CFUniCharLoadCaseMappingTable(void) { #define TURKISH_LANG_CODE (0x7472) // tr #define LITHUANIAN_LANG_CODE (0x6C74) // lt #define AZERI_LANG_CODE (0x617A) // az +#define DUTCH_LANG_CODE (0x6E6C) // nl #else #define TURKISH_LANG_CODE (0x7274) // tr #define LITHUANIAN_LANG_CODE (0x746C) // lt #define AZERI_LANG_CODE (0x7A61) // az +#define DUTCH_LANG_CODE (0x6C6E) // nl #endif CFIndex CFUniCharMapCaseTo(UTF32Char theChar, UTF16Char *convertedChar, CFIndex maxLength, uint32_t ctype, uint32_t flags, const uint8_t *langCode) { @@ -808,10 +856,17 @@ caseFoldRetry: } break; + case DUTCH_LANG_CODE: + if ((theChar == 0x004A) || (theChar == 0x006A)) { + *convertedChar = (((ctype == kCFUniCharToUppercase) || (ctype == kCFUniCharToTitlecase) || (kCFUniCharCaseMapDutchDigraph & flags)) ? 0x004A : 0x006A); + return 1; + } + break; + default: break; } } -#endif DO_SPECIAL_CASE_MAPPING +#endif // DO_SPECIAL_CASE_MAPPING if (NULL == __CFUniCharBitmapDataArray) __CFUniCharLoadBitmapData(); @@ -1018,7 +1073,15 @@ __private_extern__ uint32_t CFUniCharGetConditionalCaseMappingFlags(UTF32Char th return (((++currentIndex < length) && (buffer[currentIndex] == 0x0307)) ? kCFUniCharCaseMapMoreAbove : 0); } } - } + } else if (*((const uint16_t *)langCode) == DUTCH_LANG_CODE) { + if (kCFUniCharCaseMapDutchDigraph & lastFlags) { + return (((theChar == 0x006A) || (theChar == 0x004A)) ? kCFUniCharCaseMapDutchDigraph : 0); + } else { + if ((type == kCFUniCharToTitlecase) && ((theChar == 0x0069) || (theChar == 0x0049))) { + return (((++currentIndex < length) && ((buffer[currentIndex] == 0x006A) || (buffer[currentIndex] == 0x004A))) ? kCFUniCharCaseMapDutchDigraph : 0); + } + } + } } return 0; } @@ -1029,11 +1092,11 @@ static int __CFUniCharUnicodePropertyTableCount = 0; static CFSpinLock_t __CFUniCharPropTableLock = CFSpinLockInit; -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_LINUX #if USE_MACHO_SEGMENT #define PROP_DB_FILE "__properties" #else -#define PROP_DB_FILE "CFUniCharPropertyDatabase.data" +#define PROP_DB_FILE "/CFUniCharPropertyDatabase.data" #endif #elif DEPLOYMENT_TARGET_WINDOWS #if USE_MACHO_SEGMENT @@ -1058,8 +1121,9 @@ const void *CFUniCharGetUnicodePropertyDataForPlane(uint32_t propertyType, uint3 int idx, count; int planeIndex, planeCount; int planeSize; + int64_t fileSize; - if (!__CFUniCharLoadFile(PROP_DB_FILE, &bytes)) { + if (!__CFUniCharLoadFile(PROP_DB_FILE, &bytes, &fileSize) || !__CFSimpleFileSizeVerification(bytes, fileSize)) { __CFSpinUnlock(&__CFUniCharPropTableLock); return NULL; } diff --git a/CFUniChar.h b/CFUniChar.h index ddb0230..8fbf766 100644 --- a/CFUniChar.h +++ b/CFUniChar.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFUniChar.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFUNICHAR__) @@ -124,7 +124,8 @@ enum { enum { kCFUniCharCaseMapFinalSigma = (1UL << 0), kCFUniCharCaseMapAfter_i = (1UL << 1), - kCFUniCharCaseMapMoreAbove = (1UL << 2) + kCFUniCharCaseMapMoreAbove = (1UL << 2), + kCFUniCharCaseMapDutchDigraph = (1UL << 3) }; CF_EXPORT CFIndex CFUniCharMapCaseTo(UTF32Char theChar, UTF16Char *convertedChar, CFIndex maxLength, uint32_t ctype, uint32_t flags, const uint8_t *langCode); diff --git a/CFUniCharPriv.h b/CFUniCharPriv.h index 784d528..7580b36 100644 --- a/CFUniCharPriv.h +++ b/CFUniCharPriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFUniCharPriv.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFUNICHARPRIV__) diff --git a/CFUniCharPropertyDatabase.data b/CFUniCharPropertyDatabase.data index 785058ebb4efecea122992cc5575dc539ada1fff..37cf5a347939bed3ace307b539fd83fbf90f913a 100644 GIT binary patch delta 1739 zcmaJ>TWnNS6usv@=iNKZw9^-K+L`IJofhs)Y3Y zqcJ2TnsNR3BBWY>j331-5<{r{F)=27Af_g!A#GwNkr0FUiorzpxpO;+AMVLLXPGwcjuV5?v5FWI@=ii)|`jGf|QiRdcyLUY|c82sPX%xF!^?trLU@ z_i&`X0Y>wAwMl4RyRM})F|I@fp;Z8@4_QgJOJYmbIr&o-Dw7C&u!U;^rkH`@rVh-B zH>{%C>cWAx>$u~I(s#0C8Z>!vHgK(EMy#9qbw=x2{HkB(s8iubpkxbLs$$`I4E@d3H+z4R&41W!$g%nwXe$ zG;L*?A223iMqChO#hM6rF?{dSt=4FkXGO^>qFbZw53T1~-(@2Mq1Ed0Sqd?#dZfOg zv5D6>+SKz4P*y5=Z0`A*1)!)HF3Z-%<_e; zBio*!#kjIv86DeU#p6d6rs9>(7nuO5%a9~RMWJ&YPIZQnZ`W|D>l*&(s0*tkA|Gtw znyA7!+%1Wsi1gtU%*huJJRZVwEJ=VzQ;irq;KSfR6wB*%%=L9+CAEcmGrb{incde! zykrzn9F(nRH;jos2bWI_>Gn9hIXCX6zq1c7B}#m{q3OlQIrrHi=DHgGzR z&i-qKnba`Byh&az+}pg7XX3!^C;MTnK|TY$dC9jcSuIDpyB?LGVUfkwnKhL0OLg+QwMqSjU_W+eN?DpG-G~rAAOUA zaR#SHG(_47LOhAj2x`8!Ok6&|RNUj?+$(~s=2@aZom#KIk=c(^dolf<~{0vF5e(F6v$DS{S{eSRBFR zSS5ipPr$Mcoe}9qXEo>fVPf)ITJLI+{$I#%nlb!rY_fBcb8DO?tJS(hbA7ZYdZkKcmfy0HxkjP?7D2$u&JKJ&+Tg$i$i2Qw z%1B(Gs7k^1bP8xs+`yb4*D6MPCbKhFto8`A5U0{KRmgN#11!hdDyGS*$w-`gKYmR5 E2OK}~GXMYp delta 953 zcmXw1OKekD5WVxBpMSBF7veavi4z;UiQ|OCHcm{4A$~ZYwkh-(P>K)&!vZ5hAyB$# zkO-(OD!~GCHmI#swL~ls2*_1iK{vpv%Tghbx`>Q~SRg(DRY-^hj2$!5)qL+cGozV* zM)QBu*gzsKSac!679k8>Y1b+~DXK*iR-4`7taG`AsOMON-ngR4(=3FyQt?q*glNUD z%C{Du@UJZ8^IDq_0Ri$i$u9arB_WSl{-9E!Q<}Dr9WV7iu~--6cc@f|v#OJ?^zRj1 zSMI~K=^W_7oacC{kY~4XA>2ruD&oF3qYCi^^!x9EiTnoYj*Ih0btyNqSBDqWbifNl5&T~kgrw+ncs>3+`0@!hS=_q-*x^>xdF$=Au3vJB2TlorPZhSSGEP( zJAxsiRYc*)C!JlyR(`+q0Gk-=e7(S8JTF3hfR;o69!`XL^hL^)-bZwCG%7ZF)& zLP+#PP?vMyY5E~<_ul0yoe@I#Wx|OQlTYOQ@B!8T zs+U(j^^(G0uTBK25PQ1Yxu5Xz*fj&}?e?E)g<>xkyNd)0}tmXV^yTWb5g`;P2duj^1_PKf0jfiYc)S8*({IQyC$I=!H zX7}klz};HR%Xya!n*Uq5Eq%Fbdo8yY9r;<56Bfj_ClTM2!B1Pw>PF+SExa@*e#|;? zZiojr?6Burs~a~BE4J=9#S8pe8arR8no<$m=)Gg(d*caxd`7M0M??P03Lj<;rR2h% YqYB?rQJyIlRlJ`5m+1-@Bj2bW0H&-XumAu6 diff --git a/CFUnicodeData-B.mapping b/CFUnicodeData-B.mapping index 3212a19ea8876adc63104d89782ef309e8fcb20b..444a1e8d56cc02d2021114ca87967258bc19c30f 100644 GIT binary patch delta 10665 zcmYk?37k#k`vCBB=iWPG#!j*?!`Qbmw=AUyCDCF}5|UI>k|pc4RPsYANw(}s6q=;H zD5<1q-~8HFC8mX%x%z)ke?RH-(f2v;dGEdFoclb_d*;kMxjz2t)A0r^b8`d#<%ItW zf?AV;;Jl+jaKT+c(0yYNY`G-}w(m7Qa!Z4bB}?W+f_U8^h}UEN{A)_iC{cH0BuMKK z1WiUof+ja}499Yc@peqIeg4tP_e4rHIbh#U#(w6(`FB*E5g!x@9vqxstXfuD%XM?j z92x}c?urEK?&b=v`&7^Ov^GkHiN%xIy{d z&Q42fw(f4Pc1_l;z8ggLUBUM`kRNi;jv(V>4(6x4lKhY@kJgC^7kZL^_za__A8#=#e)9^^E z{A)IEjbzxI8V!Q{YL87TRWpB`2{BC&z+FTTWqnCfSKoc|NDH8>jOU z&R{RzN*6rmHeSx#IfyfP74LAMk~3#kQgEH%Ka`z0vneZc=5QqEauo06XwIYWCg(1? z_BnSu&%$u7cl_hzjFg1RrLE7 zAHJ25QTg{E$X#k!Zs#tioX-85h51L{9~Moff*?;4OZFfyjq*7!O8J}@V`u*NYuP?Y{l|C zlc&%+msf!uc`7@zBD=B@FJ@)-WEJ*hRrY5!4rKL=AZ-Y1qz7s8GOv~cl81TODkbe^ zL2UyPFs}~BGl!E{mr2&+bk^r>Y`{C%kh9r{cd{`puX#;)FLj8tg>1&fY|drWDbiN3 zMN+U@kjDp^;Ci0MjXa&3*piR26}PfApJW?8!!!6i&*XNt<;y&ayLdKVXFKj;d+ufO z9Kkz+4t$>-`4Kxsg5Ke!JvS0u5nhS&BEis^>>LRu&ZAW%?NfG73(`Jg4}QU({EEH! z4SVxD_MuG8>&pYYlrpwuUO&Mv1}@`a_UEs>oN_mB0OfAp6_mSq16er#(5K`6NnO1& z?Qf%cXEZ{+Q}zaVdS^6Fy)&A@(F{{rfkcaQEK716OH=oc>dkrMS)RIoG)(P@tjJ06 zAX=GPXEaRhDLyw^JOBIr^CHPGwI4ID9`o6NkFycCvI(DHGj3xppJX1N;%R)EE%^*v z^I4w3=h&9d^K8Dr_I!~YxIHaMMmq_17&wnF@qE6_3%HZr_zExLE?&Y{*@Le|gJ>_l z&aiZL^D@3+{{Zf>9hT6Wwy)${wy)yeNRYdV`y%;cJ|7iH4hw=r#KjrTG~P(xL{xPp zVzyORLLZ4vpgt0v%nTQGDvQ~#suKE0bQblI=p5=JQMr~VVgEfW$@^H!xN1t2rfN!* z2`_?jN|ZI=pc48>bS?FfsA@`_;@}@)1s}MHr=|zd$63+#)2!rmFR-%h9jwA#)JLLk zu$ujl6A(^e5JJAiuC4C3~Vi zC3~U)C3`|YiAwf_eiHqQjU7me`bjK}O=Ce!S|^&tgP3$q=qIsK%uS{RG5MQlLHV1= zGeQ0)5?)Y+r`eXb3H>Bihb?W(*F-Dx8&f}tHKl$Mlb;FwB$l9l5|ft+{Up|gXL&#Q zn9xsR@-WfP>pL>3p~TJ==qEAxm(WjQUD?qKxWM?;>}osAsc!a<;Dx-27kT{{Ud&s9AeqpRViOH?H(?4jq}X)2t&QEvUdCrq zLyFC2A0IH6Zfj#17n}iO+qY8Qav#CIrYF;n5=qW>}%d)f0(r6878eB z7z>kD4~!k;Bp%{q7Elk2{YJNsvE(0usRqKVoyHGm-huPSi=7_UzEkMWvx z{}``L_mAO^)`@$mJ0}*H7iRr^Y|4df&imPdix_7AVxG<=Y{jJvt6&+=c)vRypU_{*M$=g+77E?9eeX3XC79?diyWu!^W@R1`g&% zUd2Z^jE}~H_;uWrOb_BW3O0M;7;fP>T9@MEXq;)AinOhm=jCCnKjn<|33|g1s zx6!&3pGoUdd={-s@vv&FOYyn1F2(23x)i^gNefeazTibJpoJ+OmeCGpw20QF_%goC z<=n}zd|t7CHFr6qb+j(UALeTetLAk+%H7;d>rySDA zX;}ZC2|hFMxgB9yeZjD-zGPTdU-5f>%^&#vJs0IR!xezJjP^LE`JMJdQRi9)jG*o7^DU1%B3(uFJ?t{XDyGITNHD+8k6j`?^H==%Ry3)Q3J;jl zmp`!|e`bFk)Jj@|1;86a`Vf>BP@^=pB9~{9W3{UYWZ{nZ4nSZ4PS?LO} zu+YG``9}}dPb$Bn@CqouqVNh#W|Y3Nq8O(!PUTk=UIFD-l);%SM&(zON#$3R#knlb zc`QNYS5%U!uc#DNUr}kQzM?WZW4iJyDr;Z~%W)aQOT3)nC0@z!5-Y=^@Di_Oc!}4s z64$dbH?RsHVO4HoHEv;b=CcO3vL?5&mLH$epAuvnc!st49P97}=5RafQdt(&<4)G+ zF1j;He~k^fn~k`KjrkUva37oU9X8{8Y|alD-WjETBxu1;n8*E0@H3vqFL*k?VoQF* zR{V~w`2*YV0MFphJd?k$Ef4c7{>roYJKOOHlkEk63eI66J21tL{F|N9f{X~yWt8VJ z&d$u>`OIV&7Uu;l$*wHTZY;|SS)LcM0xxDoow4W=L1hEoS(QClojqBTy_n73tiwL6 z%f777OWBb9*qE2GDf_cIFJ}u5V1idfgN)NTkgavbqCtW)4GiYlbZ3-t4u`N4ukymq z9Lg@dnq4`J7xEfj%xl@5*Rdyuvp272Uyfiu-oXC6kpq%~k%ED|iGw+cLwGZXax{l= z46o%_4(B+I;4Qq7<9QP&@Mccr7*66iPUd({;Y7;4jO1j&)G**QPUCdW;0)fzTRD@r zaTagqY|i9d-obgC#k=_*&gX0{;2bXGTrT3BT*7(kKVzBTE(6PXH&^l=uI7BM<-J_T z1zgYjxPc4#2=C`6F5(t0Wh+z-PEz{bxKUSYhA=uH<&E;!9l3om|6R zT+7$^Aa`>e_wXUU#r53BhxraS@I7wi2YiGd@lk%lP2qR2U$B{kTA$nef6BPDo|e{*|UP%Oe7jPfPM z`7$%OlbL*l#kq?m`6^5EHJ0V;EYIDnz&BWtdsvxovT9iWZwaa!*vp#S$85gMI(&z9 z`7Z18JvQX~Y|IbXlpnG=KVl1h%mhE->HL(fxSwtKU!ED(|7U`;41CUZ{DSB3OLpW} zJeOayGrwUMe#@@>ju-NKUd$iZojUCZC?zn*{a1|H!^9_1+h$sSi}iTaT1R)IYscdU}_Mg0#0Xy zw=#{lGs-&{<9`_E9H#S5X7DZ+<2}sez0Bf$EYAB`f{R&_OIb?&7kfZZ+Q15y;VPEp z8kXaOEYF8{3f+FEDsUrDrQ7dRMQ&y#KE}#?oK^S)tMW-!c80Yf|>?i zWG(JsHeY6KzQQ_m8=lJH>#WN+SdVYAKKHT#-)2L;%SL>kjrk#)@MAXRr)-uK{8!MN zpEH+k8dEL!HS_o_6Lfo?I*mW_bpFJaJjhl&#MUfe8~(;K_y^DAQMTn@Jc~sPf8SQ@ zn4o(!$W-^K9*oh0iA?pL>cuSfraDjcVHtWbk*U5@m-1Bhqqhzxq#kFp+tM0S_iJ zm0fBSuj0)d#?icvV>p6iIg;aeGd-Bd97_)-GRJcQCvhT`cWM%+b24w^6yCukXNMD} z3hv}I-p%Q}movDKw{kIW<1*gPuv%tvH9eTf469@o*YiKz$l2V)ISi{}F1PYdhSe~S zNy}jB9zj?I^SPb(GR*!3+{ODCX8l6$;r$G=eG%W`Vuo41gdcG!!|Yzh&-ehtq+ZT% zxPoCauZ#xC%mac|2Er^}&BI*7FnibX2tA0%46}9}Q+y~I$jKnJo>4x`bZ%fKH?jmh zh{!6{aiCg?+nq?JAJ!YT=^O?=ZnZvED&nMW3+t`#(GM7&=!Kc}h&#(=j zWm`VSc6^>4_yVmZsTX-Zw@ZR7i%4n*FXBtIc%)utFYcs8BlQX|<1Sh&Qhtig8bm)u zXIUds1+gIOYW~VFS%2dV{GFrt2g4*i!U;UeDXjjdHwd%yuW~_Fn4N{if~+v}d3uyrhJAFX3q@6bAy^&YKbSs&0kmh};>V_BcjI+nGc*0HS5XdTP?g4VID zuUN*l`i5ocPb&_W;{lfEL7u|He!G3Rg5Wov$|J1EzgUSWR*nY616HBmg&wZTbXH>~ ztFr`aurzD39BZ)xvssC?S(SBIgE>rQ3+f7TSdaBtpN-gnP1%sSY{Uc`M}nXuo3ID1 zPsLlZ8Cx^g_&IFB4$M0~KfzA6Pvf~fJ))zYCunJ)Gh6X|wq_T$;RQT{U3n(Eu`Ms; zS-gm6^J4n5p5PL;XLp{%@BlloCp)qi{X#J4&2u9m;3i*X zK~=xn^k+H+)gnO;SE!(RBp4XJPmM^>eJ*R-znLC4^{CFI=S`Cxc|q++Fs3H!M1nc% znG*>vJ;b_^pjR8#iv%~G!upPU0UJbuAueG-LkA)`3mP$#a^o&vS%KUb;17!mni`iw z18md2L|<*exx756A1OFbFwj6}Udi)0l$W@4 z3)$U~|FUg!!^rHk>aDCJErOs{C+gfMVq-z>w%jI>9+9j-tN&+0V%yZFk=FI4SU40k zJ8lz(^F#BFYgPDX+pWw$o_<`b#6R2N=Z5oJA2z<2?kB}P zPKtY;6kFa-ytemAai5doz9+?Q+K$h6{rjER2+R4O9l58_2jp7eHM9S}Lg5>P`@^#j z-#9#z(C|RQD;OI73lBd07w!vR^S{@-I=K`5b7gY#kN-R6njjeFy9z%j{7_Z$Z#?JU gxc{tw&Cp|{Q7N+udm;B*7NoAv-6rvFPH6j!LmrUe4FEuZ0idr zRfx9Po88mCZli4Z;kU(meR%8WAb(d7`S3RGX7`Oj{vO`WPuPQdc?UmdPkzBSM+f=) zxRzh@E%W=ijtBTQ4{|+!$Q~M*YF6BGS?@^8?2KhABiU}*k>z4R?+V$Y8=lP1zO!v< zBy(dd2>kf9J8%|n;#_v*0(RmecIFax;c|B6O5V)XyoGPF8`tqxZs2XvAlSt25zm>o zJKoG5&TsYjYu{nweG@%h(2;jK-oaij*vY&6l6LcM^PjM{>pJru$9s9N>pm}Tx4mim zFCF!B^c5d+c0c>OdLRclKEQ#_ALJmP`XdLM|Aj+b=Qm$_sN>%_%yqvP@7i9cW}U{S z{tALRXPP>~rjGw*Gsh*xRd-yM363c#_v15yqI>CzqCWIZitb|`@26TTdVq!O%QAeB z<=BrE=*}Y***_LUDscd-(49xBa}aBAFl%v0EE7cP8Vog2k8VBEki*%S566Q@Q;uMo z8J^9NJddN;hNF2gAK~R3!>c)#*Yi={$j8`;kGs*E`9#K`o548V#wU3@pW+>Sns;(M z@8UD;%?Z4h&$`k3IFWr>Opz;^M8CVD=QxCuIh@Zk!zmoi%nJr%4W{yOzQ`vzjpO+e zpXJM(#OZvVGdPv6@FmXV49?;#&gNXs;R4R3EELV-63(YA^eS3lAPhwdDGWugQW%OB zQ5cF|;|4C~CNAL?F6Db%Mm1lwoV%FiM_fTQU$l~+Ww-8J5~=n@5Ht!)<7+DF$hQnj zO?36>O?pJcugTRC(59g?NyO)-gEIghEYKWFwx$ zCalC1Pi9M2W-C@M<*^WEeJ{m-K^9JtWjr@cisM)4&;^*v0m6+5lL@v6Hjwzj`K;2}^gm>#8x! zQ@DaPxRR&wb=Kx8*5zuR&No<}YuJ!)@(ix!nS6^)xsJ{GHq%_s7TgdGGO@D_Hkvq> z@9;cs;stz{ZMc~iatkl!R$j_&u^@Ii-(wh!_jxV1JKv5w9ETD4!0}Do>9`YjMS^Bw z;e8m%Uc0|vB-1qr(pIn7t&Fk<^@*7Dq~ngIC#_G!?xQ{t>&tu(^&u8GFEwd>A~u}* zgy02feIhoRWt<<&vV4MeBr$18m#4I(D})b0T+%0+c#ir+Yzp;>n6#uTx%nA9**A34 z>B@OQY#ysPevMUq-EvlQypq)^6={7U_BKy-UK-LhxS2I64C&LH7lw4LL?(#sGN^6h zW9k>N&!}I-RDD{%h<(M=-N=5{qiRpr=Rr20YESDIF~y$NFJiy&3^#I^`bF$-p6TL<3JbNH=F5Q;8t1e$(lA5HHKK9IM;3ei5(CmX6hH`fS(Nq<#^v zMg1bKKGXU|ydL$7xVlX17xBitz~`yQw0;p+hv_!Hz9lmnM*JKD{UWaZ()vZbH81uB z>MnhWWA&E4lvnUFUd_whh*q4w!gV+DN*}1c(pQ=9!mAyJHFb^i-FYp0@;YCCH?QZt zL6AvnNb&nkw0FUS)R5u>XuBF8#17_%QbUT5U`O9zByCsYVR30l@yDql#m7-Yia$jS zDL$SWQamg+{U|<>`cZrm^`rRYAQPm!8-zt?zZ##)9zHlMzB@RbJsB3?ot(p7oX@+c zRj2Q!R-Nw6WxR)4b^2beVjqS@c^|dv^!;4V2l!4Hm%avJbw0?jI`zPKSe<%c`~%tq z#KR)h1LGf24~&P!st3kD&6#osuZzw;6P$uSJ8cr5?nqx_eTv4oHN#yLI_4-x@w4-;Wg+a4yuqP9Iu6wvlC zp(&?r4-;i*dzeX-Gq68QRG|G~q9W}N6DQODFj1A0s5_^hb6r^VlUa+;vks@Qh%Yd# z{;6!h7ukr@7^dJQHsQ-`#_8HsB4secH)z3EoCwn}({U@#qHdg?&9-bX6 z;}x9mCl6Dx!1?RB(0qHo$_`w_PJE4Bxi}Fdx^YP+FG%z-Sn3P!<}%(x>r$c*txJjf zXTO+VkE6giP5w!CB`sgVM;t| zu%3@|1H%|?^br!F@txJh8KGvl~7@y6~Pv#as(NtQO5-)KZ!_>UTSNJ|>(Yllf z)3bwN3%4#M7KHiVX%NO}7sHk>fBGehdG{FjZgheSXOu+~>NTVgA1|*lpr#C&E~L!!TC+8OG{c{*MRvCBI`BuY(NZ z^*zIQ{lG9@Kl;2dUO(|C{>(64hj^I3Fih32JQC*rH-j)vhZ!yozwxaD@{`TN((uXCvY^&a16^*`bx`D`bx`F`bsP4jCtZ$dZLN(tjGxr zAMr$nk9ZQpM=XY=;Uk{H@DWdCRZe3yzRc>J!BaSsr*bxHa4u_dK2PI9){16=yhR4J zO)O>|E@fRVXAxKMbc$tZJ+5YbuA!Y#-dZ-~IyT~Zp23Z5%uPI#o7se0*_7`w+!^I< zH)zfenBp#`xtnKk4_ojPw&Y%(&Chubzu>vt$5#BB=W##J=K)^8gKW(o*oHqb)7IdS z!G-*l7x6GJ<{!L-fALZt;blC^%lRL#U@5QUF`Jc419+Wi8&!I=qEN?8bV$H5TMI;B7oZ zXDsb*(8R>;Y)(6){Ih6hlz%pR`odPcljpM+Tk|fq<=wo9y?F`m;bpv+SFjJS;(fe^ z_wzbFz;-%gX&FzaU>t-XgHf9LJ~m z6vuNspOOFk2?i5POyski#EG2DVou>CPUUl)#>sq{&vOQ+a3){iY)<7|zR3BU#)W)| zi}*4ZbGrQJFEyB9VmV*o3eM!~oW<3g%{83EwVca!oX7Q?&y8HbO|KJAx#f?0|cX*VW_#fY8DL3;Nw?u=2fLj^mHpclL^Y}hpP`aIk z+`%&ZfaSvc?=+}jVizm&LssH$R^~^n$~~;kk9jITVNHI@THMPz{ES8Xob~uWHsBX* z#4p*H``9GR|5pahOnl80zu{Tj&zAg_=kNeq@jIT+gKW+3*_J=>BL2ur_!BSV&%A<% zcol!)HT;#{wFjlY8MNbJ-oW44fp$g(9cgD&(1mtJ1-I~T=WpW?-p+q`2aobj{>!`g zAA7Te_p+4tF-IGq(qqg#XmH%%p&-Zw9KZ+%G0Gu~aTw!#mm>3o~@xPkTg z4jb@YHslsI;x?Ya_t}^`cqVtUNygwqgQon5&G<2!^HZky8Pl{q&z;3D*@9oOCBNa> z{FdkNJD$t$*@{2%JpRn{`3o=LZ_IcxQSiG#d&+(82L3}YCJN*|*MT|S6bq7ap6kdM zy_iVKcdj#?$aSGy=en{yZ>BisZsE!7MlsG=ev_xr@|zUjOwRI~tZl;bo0Qv}BU4+EOTB=B-_x7iKIB@yqHK{N-rjo zVwm${B6&5vm`GkH|2Z!vlI=}+F_9FzTt9Z=L+r}_?8X7?&VjsxgV>8+OeA~Li-}|( z4&?(J#(o^m0eqN)IfBEO;fRdENP|%v#W5Vs$M^`xaSWg4SWe)h4Ab%$C)10GWSEjC zIE~{tolkNmpJJGbr#YYF8K&VGW-Nobi3VW`in)T57*_vtT*Ju>tNwYe=M;w3{sK31 zD!1`PZs#=ain-_P#9KcNkLE;7G0?eCT5Qws}jwqv11SV%W(?(aVq;$tsNW4mpOuO!fbq>b>vZ^PK1NUB9*0-fQo(*S_bvXZzaZH(p52sGXS^lneg(H?dR@ z{LwrJ9=st4*0m3Uv73V6;GQ5DR%%m5yRy7DZM1pWQ zM^p{MQ5?<5Y^WY%qe%SsBJ;!CKgq}S{mc^!W)z#A+xaW&WQX|9duE>SEJ$x$|5xm1Ug%N;Lp+^`X2RTqrUXq;?n!LS88 zGMc2=cQAKN{Cq|vHMesJoJ&}N8S!(~R$iXlyaMwJPw?mX;s)_BxsS>9j<>ol8mVSN zfr*7C6qs0OLV<~eCKQ-hXhMOBg=_hAyj7z`S446&iXUrNrgFi-=YwEW?;yOBCmKhl z4q@SG@yLX}NwFnYgu%hoVA^ARpU?6`_Ixi44zU+MVQ+q#8obhnN7$GDVLyJs{yfH= z{Mz;}@>{;d@6~tlNABivzRVM;L41F#MrNVK4*G)E(tlm`j|(nrxFf6+AFy#-m?P00 z1kow+D>qNMyl7%TV&;hfiJ2z`Bxb&GNc{1a?@zsMp_}OTAP67fU@qdFe3V1Dn0Ijr zhjA%K@G*`I;u&vj4rA>~yU-5Vo-5gb-j1Y>d`7zy*RwM>@@B@_gL0^j?R6~As*mGX z+l}Wr?FqcFp!oi>8MCB6ji_2icNj#fF&YNZ>P*qjWR7q_&;2*Wa%m2-@^f=A^YBjQ z|bdSP%>n?pL^z zvw0Wia2V%uI3M6h&f{o4$gzBg<4trvCvgF%@L^8pLf*?qIE#xohmUd|7bnhWzOaM~ zxs;FcF)rmYKF-Ivg3I|7pWqs<;4^%Z>$#E}`4r<^#jRY;9bCf~`80QPz*^xI;Ti7b zvwVZ=xS#9!4xgh3Msx!|>z;Y361*Ud{@UASn;4@QRvl)apWBg)HV{9p-0!7N8$IN$G6D zf^5M;Y|X-K%OdQ^qU^$A?9MCMi^bV55~P;kph%EXio;B(bWJzv2%(I^XqM$Tmg7X0 zXN(z~#tNLlioB1NIGdIE0ITpJR^`L2#znk}OIV%Dn8_ztBPOgAYH~HRxRzIQ9cys| zYjZQ}a0}~lJL_>Lui-A%=N>lTYrK~GcpcwjLmprw9%Sr#;RB&D53vakvnktl4#H-f z*fR*5bLM~`Y{7XGg0LNr*seW4j|7np{E{8{6+7`8cIJ1ynLn@#e_~hu90_Vix(UB1 z+`?1r&R=;e&#(v2vM0~67cVUM`N){qC9R=ae{mSYsAngm9L{8pU@Av4jiZ>0qnVpy zn1^GTm*be9|zcjI$!2XJu|-Rc_@~ z+{R39XHD+l)qH`qxs!GIBCp{~Y`|T-j=R~2FS9ZCB$iN9;T47Ee3dQv8gJlU-pJQ^ z6Zf$l-(Uy6$xhKA`WCxzKX2jN?4kbvduhMJzS{4yzxF{snHhxd)r=4SVt5!E=%R#K zK9n%Rp^S2bZId`!JDKCPQ#gsKoZ_P9;0*m~oTZ+VbC`?scp2yG&&@}8IhUyC;WA#4 z*Xcy*gwD8p}UP?kTi9FMa+e=(5^o?-?5%8ES0N<3@3$~@01 zykx&s8AJFTs<=;^YjFhQX`C)=O{ry1Ch z_o#Q`O!dy3t$s7-IzSiB*WZ;3)w^*KZ{cEg=ThFvW$eM_?8z1E#g$31Akte{rO=0K z*q3YVxF6TCKR0jyH}f`b;XrQZ?cB*bxQm0hhlBYV@8muX;aj|m2RM`mW5O`u1K!O; z9L~cgGJ>CRB#)|(;uqSZd5mNDHOKN>{p0up$Md-Q1fJkTp5!E+=4AfH#Jv~$-KCu( zoL892i=4(kIh{dr5V?mD&R`PnWeR692k&Ffa%g_yCJ= zUSjkFXjSu{s}R4K8LDm#`L>vJM|(JuYK? zKF({oJhA>8+VK+#jk$u&bUeux+ADbjpJE%XVmtk-*+F{^JM(FFb>?e%tNv%$Q~g=? z;X3x`dJg1s9F!a+Z%DicLz9D)jT~j*CXV4|j$@n?_&g_Z3uD~Msocit+|C)?!I^x4 zv$&J9`6B1?CC=k6KE&8=VS(^67jh35@f9w1Mz3<2_G?_uyPDsz3PYf20!M0 z^-p-fgbwpP^-uYs`e!`EBm9I%`6>UyBgwHK`nmAA0blT#jxYH&kMUc6#qaqwf8;kj z&Tn~w-|-~B=V|`H-|X*4p5;$G&*QwrpBbbC(G!fugkOXdo@5$N@iLxf9{$RF{Eg{6 z!@~TX#dww__yNWLwJ@$`3LXjIga4@3qj6c zlyE^|%z`r~D#XTVg%>S9MmUL4ddnh7oXTWQX9{O9l{1-xvzW%&%*naT#d*Ap4>30v z@NzC>9xmb)7d;sl3wafmG9Q;QKbNxrS1_F`S&*w(h-+AwYgvTPvMATH7&q`rZenr9 zS%O$T6J6 zah%KvOx%01Ny3yw;8afKG*0Jq&fqV`&4rx9MV!mU ze1J>1c2~Q~O<_hlNlYEscxtC9IA6M~BuI7HO;Q>C)ce$4D@fm)=XZaD=@nf#% zVLr#txFPW#92GY5b8h07+{~{S=Qn(w-*F3n;8y;`ZTy+r`3raO6kp)4+{rV1k!Sf5 z&v6$oFt%H`B)rVOxQAg5pNtsgt4!u=Oyypt@pb0nKIY~d%)>XCmv1pY_cNVuvk(uk z2;X6`9EndxLUDzIEXns+n(wnLKVW%&$O`<3m3W9%_%W;T6ISP8*5Iei;%BVIBdo)t ztjGVbeh$AGeJ)(9@C6(4OJ2`oY{IYDj9;?_zhNtW%hvpkZTLOg@&~r(kL<{w*qO)K zg+H?!Pq2GT_(kZ!lkCM)?8DRSm%}F`-p1c}2hZ?M{lD`rp5-w9!Qni|kvz}Qyuh)% z$nm_yiTsnX$--a46b6_4Qp%9`Fv5Eo<$X-z{Y>T@rtkr#@sE|Hp+q3QzC~KFPd%iut&j`S~;p@EN9a9Sia~7UD)0=4KY*^DN4(EXM7; zk}t40Uu20(*8eV{q{7QA#aCFGudxhYXIZ|%a(s*B`8G574lD2=EAo9-;)krvL#)D2 zSe2i$8jtX*nD8H=I=^5hkFf^7W=(#}EPl_c`6FxbIBW9+>+mG&@-*x5H(tZvS)YHf z0nhVVUSzDD@TZ%qJ;Ssh+JQ;z$W(S>PIhK)-pni5h56Z)1=)>7cnhy&cb4R>EW;iw z&z`KvUaXSle@1!>S1I&i4ff^L?8iFn&uch<*YY+t;y^ax?QG6F*ouRABL}lB?_>uK zVQ1dOt{lqlX@33>6M8D#%|0B?{v5%99LYf(#UUKcVI0E|9Lv!h$8j9biJZU~CvqAm zaRw*zJ|^D!*@+FN2oG>7AL2AV%;{Xjd$@!%xQzGm3C`q7-pAFP#kIVj>o}VmIER}# zms|J%w{sq2JB9heE-v66KFrs+ko))u-{K-3;G;aq#r%Lvc!*1Rn2+%Ym+^Bx&SPB8 zZ}>_I!<|h?UmK$Jc5D8wxrb-@D*xbKp5s2A=bOC1 z{k+Hn+h#<=DjBihR2aOg7VniRtiTGa%!;hWO3Y+sX0ZyJc>Gso2UcV4Tz)#SE;D(( zdJQ&aO(wR_VpCqtW~{~LR#aG9Xu&#c$+}E@rJ^2h;5BT``n-`1*oN2gCSJ$3Y{+(O zMBhmYuV-R{joFb+*ojTqnavnWd^e-H(1k6S_zp%(c4I5v!W(#vGi%KTyph+j4IA+$ zHg;v&vYGaSY{B5P6Jf~KjBty;GhLBr_YK0lr^8s#rF#(OQ+T^$5a#DT8x-K2n}RT% zMY{!IL4GwW2n(^2c40oHzX(g+7KBAv`tBes#>M`yc_rI)2*To=(<=x|aBlk`EXj@f zOR>2A(x+o)J}C&xD3lx(gk`yQP7s#k$*w_Ip7lBfVFn8f4Z;dsXyz5!xnB@gqW2)I z%rsWv4G+3E_-zmO2CJ!G#b2FZb*37Z$zgNdBQc?)9oFR3ac&ZhAMYk%4hOEqDR;R? zm^RQolBlyTvrM=ihdYyNxYeI{8?lYI;(E4YV|HW{-pr=##%8>g8O?=WLJRg~OAcT= zE^_JG^Oug>o~snzA1PkP50V;QO-p%j|G%85Wp1lhHS8Fs`8vYi{aM>4RSWA^h$Y%r zCHlR5XYB9s3H{CS@3#ME{M)PlwbsAZ{@27Y6WiDQ*TiuX?TTKOSy1WUY^h~u%k96} zUsV6sNUXd6b_Bk@mz^!Y>}&~UXUi}6)$DA&W@l?QJ6pHe+0xCc+{~RdMutfeoXd+wR j*?Cs?|K%OS{+F$c>}@_C{l9$FrAkabv7asj{>lFba!g_Y delta 8536 zcmXBZd7Mr4{|E4M@2n;X*+sTSc8y4ODoG_#mLr(EJdV} zN|Yq|QYy)oe$RRQ{PTRhU!QZ%oO|y%*S#}`cEoL86_;H3k%~cy;Q#-{772pH`a!Vh znIPEJI0))&41&~*Ah_}1rsR6}MpN${lQr9bvOzGgY!DjEA!Vb53(O3qWfU9}ZSX*1 zI6Ap-zHoR(vFPF=P21#?X?iwZqXGb!TM{pQ;@_ z(WF@EXx5P(W4pEgJQN&H2*!2b33lX{3BgC5c#@rYie30EyYe)5@{H|w@dxhaIsG1< z=ZCz&3|@@>I;K*^v`07f2vvzL*pwcMwvCR-7S7%?dVTMdglNX$jiE@hq8@z^#5Cs; zzR2Zl!BuR@wQR)=Y|YJV!>xRY+u4>o*^YbIo_pDW`-33dk)GsGCmt|&=Aj^{AJawn zRMC|!Y|xEI&E0v-0bb^bAc*b3llq=)WxHNHWqyU?eNo>i< ze94KvULq0%?Sv_c4t#^1IF(&Ejomn%FY`_I}Z-?@q_L>YT9Rxqva4>)J)DGd#(P^J2B;>znoL?~rE^#3*^FRI;U3co` zn8;Oog;IjxFNS%YF}%rG-eDa7V?4v*ASQuvOk^Un@E#^H8}DHbW@Rqk%e>6S0^uO` zJ{D&76qj%@A%`NFIa!+bvpjP#g}GUUd035kS&R8tkNH`j1=x@U*@zFYDGRYhI7leW zcHtnt2)j6;qA4!n?m{s|PZnoymSA5#!~sm^V3uSmALa;_;%JuUSeD^%Qoi(|GwYZzL znZY{T$4Fh_fKZQz`2>%!F^{ncPlSVTQ+~;2Jjv!f#TWT4Tkten@(f$?2e#%pw&8ic z#0zZ8i{T(oxSeoG(Vmytfxo4Fd}e6ms;RH(Pxj+A_UCmD;0+GsEe_%x4(44BVGt99 zhce7m#&Q_rIh=_c!6c4k)|en}6m!IQ(@Y7%LGI}8vu}nXd982O=Vz1!xrK$el@D?o zi!zCVx z>+&F<;2}Q6!+bg>i1~yK`6-|05jM7dlugZ_@kR47wlp8-;)+4&^OR`Aa|1$=HlCDF zr66d}Fgr7b-EAAop5{3AF~_qX6FAV5n#fe^SvXRk#0c--X|?X5%#deVoDU zl{^V)PA-SyZADJbvEluk&s@8BY`^^6YA(PXEXWV-{{Z({ zFT?{Z%)@+;N30jA1EWxvUi07P0GS9OlFYsYrWGP;;;hDGR%a>JU|H5=1;?w!O6JKvd*oIU25~s5*XRsY-vOQ<9182uZf^bJ+j-nIi zu`}m8a2GCQS1x8ZE@OAD!+4s*c~(DyKXN30;wb*i(foy(*IwjTPwg1t ziefB(=Q#es*Z3F5^KVYzKb**$oW$Fl%zyph*BQhGu~Qfu=Yu2TIhBc=#w1Q>R=$~e z|7R0sD6;b{=8W^nk-3@1e4NFCe4B-BH=9NH4vTRPOK>ieIgbzXU6$s2mgNGL=Xl>@kqgP6`C+|E>fz~S7%k=)7A z+{H26&2ikr@r-;ZOcXLWnR_{fA91Qjw2w2)`#F;za~2P9w)KOY=Mf#^0{vkw|IgZl4yn5X$Ezvoe&;jy?#5OY>IVTT|1m4zSqHP7)I{>1Nip5OClp5+Dp$Y1yq zFY;&p%3mDs5-;(8yu!=8$}9YfzwvrR_+7ZktGvTM_#gjdI6jE^i*dZhME=ctc%9k! z4|DJabMYqg@)is5HVg3%i|}6-=UqmUh5v+7?6<3*WjRRd=L(?Jj1NW7^c`R zmX#UDs_{X+cviE1KWi`-YcV(LFc0f7FP~%)o{I}YMSa~abNQK2{pjG!$6_K4Ed9?? zLtf@{yuwEOjg9#`oAN4~^AEP*pKQgy*oN2GmVdK7ud^fnVQ1c8SKefI-ntzm1wDk@ zie70)ua=DTHihoE{TOCH#&7^*If!u_!g!`Kfy0@|k<7x;OyU^c!*R^Y@w}H4nT?Zq zAEz+;9q)`&g&d0M%*h$NpEH?@vzVK+nTKLTu>cpbAQ$riE@dGuXJM}7 zgIvubcf2#M6^bg>vlutBI5)Edx9}luV=}k1BzN#(?qVtKVQFTt3_oI7?q@k3V0j*5 z1%ASc5#fmN2tQ*AkFyd_@KJur$~?&`JjKWOEvxc0ALkiX;}5LPbF9JhtjP+}8|(2ZpWvT-lGpeYud_aH@M+#+1K!~?yvv3R5`yrv4D&h0@_ELy5fk|W zlM=i$HWsofnlKxiGCP|wCz~@DUt}J(U_Q2F0k+};Y|X-K!yLqZmhxXti_jEhdo%2J^3Viu|8j61NLS^_Th7U zm5tb!jUz%op(*>bIR~%>2eK6hu?+{aEr+l@hq5D6*_p%GmBZPcBiMr@*^8sto1^(E zGq1f!KVgh8fMYp`<2Zz`F_q&voD(>b6FHibIEIrsj<0h(r*II3M z!c`%Ie{wIc@grX6KHlJd-r~o+!vnm_gA5Xb@F9kIn6dnX@%)sDJi;U%WmbO1Y>Anl zjD+lpwuzaF# zMrVbJiXWK5ANeTHu?l};Ri0-x{>&P@z*_u;b$F5W_$!~}CD!Nv*npSWkXQH|e`BMF z@Vn5MSJ{+*usQ!^i$tG{*qYbamVdK@_3P}!f7pdL*o`;&GHzP!sw zf8jr2AcKE>DP@R58Rjs?a0FvHigC<5@pz790$*byCol^qF^RA99=^e>oW^_kCbRwP z{(nojPm#v#e49D=4s&uY@8`SB#RbgGh0MeEnU_nLkIR^!D_DT5SdeS@0N1e)H?Z)( z?*C1~gNi7Na4U;4oyGV8i*qMSa5o>~hfL;PmgGJ@%#T@$2U(hjS%#moERV7rkFk72 z_*|&KFIbUZ@ezK_6n?`>{EmR@vJLO!OU%i(%*}Sp$M!794lJC- zZ$>%_MHQV`f}L5CU09l3S&rRUk=Q@MIFV_b#Mzw8xqO}TIfV=P1{ZTGmvI_bayr-WO-9xW zGlfk|;}*_hI^X6F&gO2u!wk;hKF;L<&f{Ue%Ojl6V_d)!e2-soAy07;zvKIv_x~AT zvEoNA;dw6QFI>h;T+S<8!K+-!zqpFmxtce*hIhD@|8X6|Nq!N*IBsAfH}W2C%Dn%x z37Zu;7-cSQVP0-!0d8XyB9g?m_;AF?VlSe<(_FM?Xa zN36?ze3JY5G(ToT9^msl$i}?NX8eOK_$ON@1+jmz9j~zy|7JH{XHWjaKD@#HEOb*C z>;SizniS-`%_&Ji;vLS6{(U!ZI5IoQXH$PHp2Gp0$3dLWA$*TRxrnJ;%wb&0;atuU zT*;AK%~4#-(Ol2WKSpol7#58WLStEs?;C9~R4&LG} j-sT?OVMcnpxKNqo^pzDtlf&t)QbG+v>1!*6s+RmetQPni diff --git a/CFUnicodeDecomposition.c b/CFUnicodeDecomposition.c index adade11..592bb34 100644 --- a/CFUnicodeDecomposition.c +++ b/CFUnicodeDecomposition.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFUnicodeDecomposition.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. Responsibility: Aki Inoue */ diff --git a/CFUnicodeDecomposition.h b/CFUnicodeDecomposition.h index f6d9690..d68ffc8 100644 --- a/CFUnicodeDecomposition.h +++ b/CFUnicodeDecomposition.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,7 +26,7 @@ * CoreFoundation * * Created by aki on Wed Oct 03 2001. - * Copyright (c) 2001-2009, Apple Inc. All rights reserved. + * Copyright (c) 2001-2011, Apple Inc. All rights reserved. * */ diff --git a/CFUnicodePrecomposition.c b/CFUnicodePrecomposition.c index da37677..8e7688b 100644 --- a/CFUnicodePrecomposition.c +++ b/CFUnicodePrecomposition.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFUnicodePrecomposition.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. + Copyright (c) 1999-2011, Apple Inc. All rights reserved. Responsibility: Aki Inoue */ diff --git a/CFUnicodePrecomposition.h b/CFUnicodePrecomposition.h index 7e3877a..efd3038 100644 --- a/CFUnicodePrecomposition.h +++ b/CFUnicodePrecomposition.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,7 +26,7 @@ * CoreFoundation * * Created by aki on Wed Oct 03 2001. - * Copyright (c) 2001-2009, Apple Inc. All rights reserved. + * Copyright (c) 2001-2011, Apple Inc. All rights reserved. * */ diff --git a/CFUserNotification.c b/CFUserNotification.c index 901373c..afb75b1 100644 --- a/CFUserNotification.c +++ b/CFUserNotification.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,9 @@ */ /* CFUserNotification.c - Copyright (c) 2000-2009, Apple Inc. All rights reserved. - Responsibility: Doug Davidson + Copyright (c) 2000-2011, Apple Inc. All rights reserved. + Original Author: Doug Davidson + Responsibility: Kevin Perry */ #include @@ -42,7 +43,6 @@ #include #include - #define CFUserNotificationLog(alertHeader, alertMessage) CFLog(3, CFSTR("%@: %@"), alertHeader, alertMessage); enum { @@ -228,7 +228,7 @@ static SInt32 _CFUserNotificationSendRequest(CFAllocatorRef allocator, CFStringR data = CFPropertyListCreateXMLData(allocator, modifiedDictionary); if (data) { size = sizeof(mach_msg_base_t) + ((CFDataGetLength(data) + 3) & (~0x3)); - msg = (mach_msg_base_t *)CFAllocatorAllocate(allocator, size, 0); + msg = (mach_msg_base_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, size, 0); if (__CFOASafe) __CFSetLastAllocationEventName(msg, "CFUserNotification (temp)"); if (msg) { memset(msg, 0, size); @@ -241,7 +241,7 @@ static SInt32 _CFUserNotificationSendRequest(CFAllocatorRef allocator, CFStringR CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (uint8_t *)msg + sizeof(mach_msg_base_t)); //CFShow(CFStringCreateWithBytes(kCFAllocatorSystemDefault, (UInt8 *)msg + sizeof(mach_msg_base_t), CFDataGetLength(data), kCFStringEncodingUTF8, false)); retval = mach_msg((mach_msg_header_t *)msg, MACH_SEND_MSG|MACH_SEND_TIMEOUT, size, 0, MACH_PORT_NULL, MESSAGE_TIMEOUT, MACH_PORT_NULL); - CFAllocatorDeallocate(allocator, msg); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg); } else { retval = unix_err(ENOMEM); } @@ -321,7 +321,7 @@ SInt32 CFUserNotificationReceiveResponse(CFUserNotificationRef userNotification, CFDataRef responseData; if (userNotification && MACH_PORT_NULL != userNotification->_replyPort) { - msg = (mach_msg_base_t *)CFAllocatorAllocate(CFGetAllocator(userNotification), size, 0); + msg = (mach_msg_base_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, size, 0); if (__CFOASafe) __CFSetLastAllocationEventName(msg, "CFUserNotification (temp)"); if (msg) { memset(msg, 0, size); @@ -348,7 +348,7 @@ SInt32 CFUserNotificationReceiveResponse(CFUserNotificationRef userNotification, mach_port_destroy(mach_task_self(), userNotification->_replyPort); userNotification->_replyPort = MACH_PORT_NULL; } - CFAllocatorDeallocate(CFGetAllocator(userNotification), msg); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, msg); } else { retval = unix_err(ENOMEM); } diff --git a/CFUserNotification.h b/CFUserNotification.h index bc2fd0f..48f6f7b 100644 --- a/CFUserNotification.h +++ b/CFUserNotification.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFUserNotification.h - Copyright (c) 2000-2009, Apple Inc. All rights reserved. + Copyright (c) 2000-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFUSERNOTIFICATION__) @@ -186,10 +186,8 @@ const CFStringRef kCFUserNotificationCheckBoxTitlesKey; CF_EXPORT const CFStringRef kCFUserNotificationTextFieldValuesKey; -#if MAC_OS_X_VERSION_10_3 <= MAC_OS_X_VERSION_MAX_ALLOWED CF_EXPORT -const CFStringRef kCFUserNotificationPopUpSelectionKey AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; -#endif +const CFStringRef kCFUserNotificationPopUpSelectionKey CF_AVAILABLE(10_3, NA); #if (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) CF_EXPORT diff --git a/CFUtilities.c b/CFUtilities.c index f999bca..bdd840f 100644 --- a/CFUtilities.c +++ b/CFUtilities.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,24 +22,35 @@ */ /* CFUtilities.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. - Responsibility: Christopher Kane + Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Responsibility: Tony Parker */ #include #include "CFInternal.h" #include "CFLocaleInternal.h" #include +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS #include +#endif #include #include #include #include +#if DEPLOYMENT_TARGET_WINDOWS +#include +#endif #include #include #include #include +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS #include +#else +#define ASL_LEVEL_EMERG 0 +#define ASL_LEVEL_DEBUG 7 +#endif + #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED #include #include @@ -59,12 +70,11 @@ #include #include #include -#include #include #endif #if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD - #include - #include +#include +#include #endif /* Comparator is passed the address of the values. */ @@ -159,6 +169,14 @@ __private_extern__ uintptr_t __CFFindPointer(uintptr_t ptr, uintptr_t start) { } return 0; } + +__private_extern__ void __CFDumpAllPointerLocations(uintptr_t ptr) { + uintptr_t addr = 0; + do { + addr = __CFFindPointer(ptr, sizeof(void *) + addr); + printf("%p\n", (void *)addr); + } while (addr != 0); +} #endif #if DEPLOYMENT_TARGET_WINDOWS @@ -311,167 +329,37 @@ CONST_STRING_DECL(_kCFSystemVersionBuildVersionKey, "ProductBuildVersion") CONST_STRING_DECL(_kCFSystemVersionProductVersionStringKey, "Version") CONST_STRING_DECL(_kCFSystemVersionBuildStringKey, "Build") -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || TARGET_IPHONE_SIMULATOR - -typedef struct { - uint16_t primaryVersion; - uint8_t secondaryVersion; - uint8_t tertiaryVersion; -} CFLibraryVersion; - -CFLibraryVersion CFGetExecutableLinkedLibraryVersion(CFStringRef libraryName) { - CFLibraryVersion ret = {0xFFFF, 0xFF, 0xFF}; - char library[CFMaxPathSize]; // search specs larger than this are pointless - if (!CFStringGetCString(libraryName, library, sizeof(library), kCFStringEncodingUTF8)) return ret; - int32_t version = NSVersionOfLinkTimeLibrary(library); - if (-1 != version) { - ret.primaryVersion = version >> 16; - ret.secondaryVersion = (version >> 8) & 0xff; - ret.tertiaryVersion = version & 0xff; - } - return ret; -} - -CFLibraryVersion CFGetExecutingLibraryVersion(CFStringRef libraryName) { - CFLibraryVersion ret = {0xFFFF, 0xFF, 0xFF}; - char library[CFMaxPathSize]; // search specs larger than this are pointless - if (!CFStringGetCString(libraryName, library, sizeof(library), kCFStringEncodingUTF8)) return ret; - int32_t version = NSVersionOfRunTimeLibrary(library); - if (-1 != version) { - ret.primaryVersion = version >> 16; - ret.secondaryVersion = (version >> 8) & 0xff; - ret.tertiaryVersion = version & 0xff; - } - return ret; -} -static inline Boolean _CFLibraryVersionLessThan(CFLibraryVersion vers1, CFLibraryVersion vers2) { - if (vers1.primaryVersion < vers2.primaryVersion) { - return true; - } else if (vers1.primaryVersion == vers2.primaryVersion) { - if (vers1.secondaryVersion < vers2.secondaryVersion) { - return true; - } else if (vers1.secondaryVersion == vers2.secondaryVersion) { - return vers1.tertiaryVersion < vers2.tertiaryVersion; - } - } - return false; +CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) { + return true; } -/* -If - (vers != 0xFFFF): We know the version number of the library this app was linked against - and (versionInfo[version].VERSIONFIELD != 0xFFFF): And we know what version number started the specified release - and ((version == 0) || (versionInfo[version-1].VERSIONFIELD < versionInfo[version].VERSIONFIELD)): And it's distinct from the prev release -Then - If the version the app is linked against is less than the version recorded for the specified release - Then stop checking and return false - Else stop checking and return YES -Else - Continue checking (the next library) -*/ -#define resultIndex(VERSION) (VERSION) -#define checkLibrary(LIBNAME, VERSIONFIELD) { \ - uint16_t vers = (NSVersionOfLinkTimeLibrary(LIBNAME) >> 16); \ - if ((vers != 0xFFFF) && (versionInfo[version].VERSIONFIELD != 0xFFFF) && \ - ((version == 0) || (versionInfo[version-1].VERSIONFIELD < versionInfo[version].VERSIONFIELD))) \ - return (results[resultIndex(version)] = ((vers < versionInfo[version].VERSIONFIELD) ? false : true)); \ -} - - -CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) { - // The numbers in the below tables should be the numbers for any version of the framework in the release. - // When adding new entries to these tables for a new build train, it's simplest to use the versions of the - // first new versions of projects submitted to the new train. These can later be updated. One thing to watch for is that software updates - // for the previous release do not increase numbers beyond the number used for the next release! - // For a given train, don't ever use the last versions submitted to the previous train! (This to assure room for software updates.) - // If versions are the same as previous release, use 0xFFFF; this will assure the answer is a conservative NO. - // NOTE: Also update the CFM check below, perhaps to the previous release... (???) - static const struct { - uint16_t libSystemVersion; - uint16_t cocoaVersion; - uint16_t appkitVersion; - uint16_t fouVersion; - uint16_t cfVersion; - uint16_t carbonVersion; - uint16_t applicationServicesVersion; - uint16_t coreServicesVersion; - uint16_t iokitVersion; - } versionInfo[] = { - {50, 5, 577, 397, 196, 113, 16, 9, 52}, /* CFSystemVersionCheetah (used the last versions) */ - {55, 7, 620, 425, 226, 122, 16, 10, 67}, /* CFSystemVersionPuma (used the last versions) */ - {56, 8, 631, 431, 232, 122, 17, 11, 73}, /* CFSystemVersionJaguar */ - {67, 9, 704, 481, 281, 126, 19, 16, 159}, /* CFSystemVersionPanther */ - {73, 10, 750, 505, 305, 128, 22, 18, 271}, /* CFSystemVersionTiger */ - {89, 12, 840, 575, 375, 136, 34, 32, 0xFFFF}, /* CFSystemVersionLeopard */ - {112, 13, 960, 680, 480, 0xFFFF, 0xFFFF, 33, 0xFFFF}, /* CFSystemVersionSnowLeopard */ - }; - - - // !!! When a new release is added to the array, don't forget to bump the size of this array! - static char results[CFSystemVersionMax] = {-2, -2, -2, -2, -2, -2}; /* We cache the results per-release; there are only a few of these... */ - if (version >= CFSystemVersionMax) return false; /* Actually, we don't know the answer, and something scary is going on */ - - int versionIndex = resultIndex(version); - if (results[versionIndex] != -2) return results[versionIndex]; #if DEPLOYMENT_TARGET_MACOSX - if (_CFIsCFM()) { - results[versionIndex] = (version <= CFSystemVersionJaguar) ? true : false; - return results[versionIndex]; - } -#endif - - // Do a sanity check, since sometimes System framework is screwed up, which confuses everything. - // If the currently executing System framework has a version less than that of Leopard, warn. - static Boolean called = false; - if (!called) { // We do a check here in case CFLog() recursively calls this function. - called = true; - int32_t vers = NSVersionOfRunTimeLibrary("System"); - if ((vers != -1) && (((unsigned int)vers) >> 16) < 89) { // 89 is the version of libSystem for first version of Leopard - CFLog(__kCFLogAssertion, CFSTR("System.framework version (%x) is wrong, this will break CF and up"), vers); - } - if (results[versionIndex] != -2) return results[versionIndex]; // If there was a recursive call that figured this out, return +__private_extern__ void *__CFLookupCarbonCoreFunction(const char *name) { + static void *image = NULL; + if (NULL == image) { + image = dlopen("/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore", RTLD_LAZY | RTLD_LOCAL); } - -#if DEPLOYMENT_TARGET_MACOSX - if (version < CFSystemVersionMax) { - // Compare the linked library versions of a Mac OS X app to framework versions found on Mac OS X. - checkLibrary("System", libSystemVersion); // Pretty much everyone links with this - checkLibrary("Cocoa", cocoaVersion); - checkLibrary("AppKit", appkitVersion); - checkLibrary("Foundation", fouVersion); - checkLibrary("CoreFoundation", cfVersion); - checkLibrary("Carbon", carbonVersion); - checkLibrary("ApplicationServices", applicationServicesVersion); - checkLibrary("CoreServices", coreServicesVersion); - checkLibrary("IOKit", iokitVersion); - } else { + void *dyfunc = NULL; + if (image) { + dyfunc = dlsym(image, name); } -#else -#endif - - /* If not found, then simply return NO to indicate earlier --- compatibility by default, unfortunately */ - return false; -} -#else -CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) { - return true; + return dyfunc; } #endif - -#if DEPLOYMENT_TARGET_MACOSX -__private_extern__ void *__CFLookupCarbonCoreFunction(const char *name) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +__private_extern__ void *__CFLookupCoreServicesInternalFunction(const char *name) { static void *image = NULL; if (NULL == image) { - image = dlopen("/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore", RTLD_LAZY | RTLD_LOCAL); + image = dlopen("/System/Library/PrivateFrameworks/CoreServicesInternal.framework/CoreServicesInternal", RTLD_LAZY | RTLD_LOCAL); } void *dyfunc = NULL; if (image) { - dyfunc = dlsym(image, name); + dyfunc = dlsym(image, name); } return dyfunc; } @@ -523,13 +411,16 @@ __private_extern__ CFIndex __CFActiveProcessorCount() { v = (v & 0x3333333333333333ULL) + ((v >> 2) & 0x3333333333333333ULL); v = (v + (v >> 4)) & 0xf0f0f0f0f0f0f0fULL; pcnt = (v * 0x0101010101010101ULL) >> ((sizeof(v) - 1) * 8); -#else +#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED int32_t mib[] = {CTL_HW, HW_AVAILCPU}; size_t len = sizeof(pcnt); int32_t result = sysctl(mib, sizeof(mib) / sizeof(int32_t), &pcnt, &len, NULL, 0); if (result != 0) { pcnt = 0; } +#else + // Assume the worst + pcnt = 1; #endif return pcnt; } @@ -585,62 +476,42 @@ static void _CFShowToFile(FILE *file, Boolean flush, const void *obj) { } cnt = CFStringGetLength(str); - // iTunes used OutputDebugStringW(theString); - - CFStringInitInlineBuffer(str, &buffer, CFRangeMake(0, cnt)); #if DEPLOYMENT_TARGET_WINDOWS - wchar_t *accumulatedBuffer = (wchar_t *)malloc((cnt+1) * sizeof(wchar_t)); -#endif + UniChar *ptr = (UniChar *)CFStringGetCharactersPtr(str); + BOOL freePtr = false; + if (!ptr) { + CFIndex strLen = CFStringGetLength(str); + // +2, 1 for newline, 1 for null + CFIndex bufSize = sizeof(UniChar *) * (CFStringGetMaximumSizeForEncoding(strLen, kCFStringEncodingUnicode) + 2); + CFIndex bytesUsed = 0; + ptr = (UniChar *)malloc(bufSize); + CFStringGetCharacters(str, CFRangeMake(0, strLen), ptr); + ptr[strLen] = L'\n'; + ptr[strLen+1] = 0; + freePtr = true; + } + OutputDebugStringW((wchar_t *)ptr); + if (freePtr) free(ptr); +#else + CFStringInitInlineBuffer(str, &buffer, CFRangeMake(0, cnt)); for (idx = 0; idx < cnt; idx++) { UniChar ch = __CFStringGetCharacterFromInlineBufferQuick(&buffer, idx); -#if DEPLOYMENT_TARGET_WINDOWS - if (file == stderr || file == stdout) { - accumulatedBuffer[idx] = ch; - lastNL = (ch == L'\n'); - if (idx == (cnt - 1)) { - accumulatedBuffer[idx+1] = L'\0'; - OutputDebugStringW(accumulatedBuffer); - free(accumulatedBuffer); - } - } else { -#endif - -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - if (ch < 128) { + if (ch < 128) { fprintf_l(file, NULL, "%c", ch); - lastNL = (ch == '\n'); + lastNL = (ch == '\n'); } else { fprintf_l(file, NULL, "\\u%04x", ch); } -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - if (ch < 128) { - _fprintf_l(file, "%c", NULL, ch); - lastNL = (ch == '\n'); - } else { - _fprintf_l(file, "\\u%04x", NULL, ch); - } -#endif - } -#if DEPLOYMENT_TARGET_WINDOWS } -#endif if (!lastNL) { -#if DEPLOYMENT_TARGET_WINDOWS - if (file == stderr || file == stdout) { - char outStr[2]; - outStr[0] = '\n'; - outStr[1] = '\0'; - OutputDebugStringA(outStr); - } else { - _fprintf_l(file, "\n", NULL); -#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED fprintf_l(file, NULL, "\n"); -#endif -#if DEPLOYMENT_TARGET_WINDOWS - } +#else + fprintf(file, NULL, "\n"); #endif if (flush) fflush(file); } +#endif if (str) CFRelease(str); } @@ -673,6 +544,8 @@ static Boolean also_do_stderr() { return true; } +extern char *__CFBundleMainID; + static void __CFLogCString(int32_t lev, const char *message, size_t length, char withBanner) { char *banner = NULL; char *time = NULL; @@ -681,6 +554,7 @@ static void __CFLogCString(int32_t lev, const char *message, size_t length, char #if !(DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED) int bannerLen = 0; #endif + // The banner path may use CF functions, but the rest of this function should not. It may be called at times when CF is not fully setup or torn down. if (withBanner) { CFAbsoluteTime at = CFAbsoluteTimeGetCurrent(); CFCalendarRef calendar = CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault, kCFCalendarIdentifierGregorian); @@ -701,16 +575,20 @@ static void __CFLogCString(int32_t lev, const char *message, size_t length, char #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED asprintf(&banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s[%d:%x] ", year, month, day, hour, minute, second, ms, *_CFGetProgname(), getpid(), pthread_mach_thread_np(pthread_self())); asprintf(&thread, "%x", pthread_mach_thread_np(pthread_self())); -#else +#elif DEPLOYMENT_TARGET_WINDOWS bannerLen = asprintf(&banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s[%d:%x] ", year, month, day, hour, minute, second, ms, *_CFGetProgname(), getpid(), GetCurrentThreadId()); asprintf(&thread, "%x", GetCurrentThreadId()); +#else + bannerLen = asprintf(&banner, "%04d-%02d-%02d %02d:%02d:%02d.%03d %s[%d:%x] ", year, month, day, hour, minute, second, ms, *_CFGetProgname(), getpid(), (unsigned int)pthread_self()); + asprintf(&thread, "%x", pthread_self()); #endif asprintf(&time, "%04d-%02d-%02d %02d:%02d:%02d.%03d", year, month, day, hour, minute, second, ms); } after_banner:; +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS asprintf(&uid, "%d", geteuid()); - aslclient asl = asl_open(NULL, "com.apple.console", ASL_OPT_NO_DELAY); + aslclient asl = asl_open(NULL, __CFBundleMainID[0] ? __CFBundleMainID : "com.apple.console", ASL_OPT_NO_DELAY); aslmsg msg = asl_new(ASL_TYPE_MSG); asl_set(msg, "CFLog Local Time", time); // not to be documented, not public API asl_set(msg, "CFLog Thread", thread); // not to be documented, not public API @@ -721,6 +599,7 @@ static void __CFLogCString(int32_t lev, const char *message, size_t length, char asl_send(asl, msg); asl_free(msg); asl_close(asl); +#endif if (also_do_stderr()) { #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED @@ -736,7 +615,7 @@ static void __CFLogCString(int32_t lev, const char *message, size_t length, char __CFSpinLock(&lock); writev(STDERR_FILENO, v[0].iov_base ? v : v + 1, nv); __CFSpinUnlock(&lock); -#else +#elif DEPLOYMENT_TARGET_WINDOWS size_t bufLen = bannerLen + length + 1; char *buf = (char *)malloc(sizeof(char) * bufLen); if (banner) { @@ -753,6 +632,21 @@ static void __CFLogCString(int32_t lev, const char *message, size_t length, char // This Win32 API call only prints when a debugger is active // OutputDebugStringA(buf); free(buf); +#else + size_t bufLen = bannerLen + length + 1; + char *buf = (char *)malloc(sizeof(char) * bufLen); + if (banner) { + // Copy the banner into the debug string + memmove(buf, banner, bannerLen); + + // Copy the message into the debug string + strncpy(buf + bannerLen, message, bufLen - bannerLen); + } else { + strncpy(buf, message, bufLen); + } + buf[bufLen - 1] = '\0'; + fprintf(stderr, "%s\n", buf); + free(buf); #endif } @@ -764,8 +658,9 @@ static void __CFLogCString(int32_t lev, const char *message, size_t length, char CF_EXPORT void _CFLogvEx(CFLogFunc logit, CFStringRef (*copyDescFunc)(void *, const void *), CFDictionaryRef formatOptions, int32_t lev, CFStringRef format, va_list args) { #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - if (pthread_getspecific(__CFTSDKeyIsInCFLog)) return; - pthread_setspecific(__CFTSDKeyIsInCFLog, (void *)1); + uintptr_t val = (uintptr_t)_CFGetTSD(__CFTSDKeyIsInCFLog); + if (3 < val) return; // allow up to 4 nested invocations + _CFSetTSD(__CFTSDKeyIsInCFLog, (void *)(val + 1), NULL); #endif CFStringRef str = format ? _CFStringCreateWithFormatAndArgumentsAux(kCFAllocatorSystemDefault, copyDescFunc, formatOptions, (CFStringRef)format, args) : 0; CFIndex blen = str ? CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8) + 1 : 0; @@ -781,10 +676,22 @@ CF_EXPORT void _CFLogvEx(CFLogFunc logit, CFStringRef (*copyDescFunc)(void *, co if (buf) free(buf); if (str) CFRelease(str); #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - pthread_setspecific(__CFTSDKeyIsInCFLog, 0); + _CFSetTSD(__CFTSDKeyIsInCFLog, (void *)val, NULL); #endif } +// This CF-only log function uses no CF functionality, so it may be called anywhere within CF - including thread teardown or prior to full CF setup +__private_extern__ void _CFLogSimple(int32_t lev, char *format, ...) { + va_list args; + va_start(args, format); + char formattedMessage[1024]; + int length = vsnprintf(formattedMessage, 1024, format, args); + if (length > 0) { + __CFLogCString(lev, formattedMessage, length, 0); + } + va_end(args); +} + void CFLog(int32_t lev, CFStringRef format, ...) { va_list args; va_start(args, format); diff --git a/CFVersion.c b/CFVersion.c index da4dfa8..59cfa1c 100644 --- a/CFVersion.c +++ b/CFVersion.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,5 +21,9 @@ * @APPLE_LICENSE_HEADER_END@ */ -const unsigned char kCFCoreFoundationVersionString[] = "@(#)PROGRAM:CoreFoundation PROJECT:CoreFoundation-550 SYSTEM:Darwin DEVELOPER:unknown BUILT:" __DATE__ " " __TIME__ "\n"; -double kCFCoreFoundationVersionNumber = (double)550; +/* CFVersion.c + Copyright 2009-2011, Apple Inc. All rights reserved. + Responsibility: CFLite Team +*/ +const unsigned char kCFCoreFoundationVersionString[] = "@(#)PROGRAM:CoreFoundation PROJECT:CoreFoundation-635 SYSTEM:Darwin DEVELOPER:unknown BUILT:" __DATE__ " " __TIME__ "\n"; +double kCFCoreFoundationVersionNumber = (double)635; diff --git a/CFWindowsMessageQueue.c b/CFWindowsMessageQueue.c deleted file mode 100644 index bd1502d..0000000 --- a/CFWindowsMessageQueue.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (c) 2010 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@ - */ - -/* CFWindowsMessageQueue.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. - Responsibility: Christopher Kane -*/ - -#if DEPLOYMENT_TARGET_WINDOWS - -#include "CFWindowsMessageQueue.h" -#include "CFInternal.h" - -extern DWORD __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef mode); -extern void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, DWORD mask, CFStringRef mode); - -struct __CFWindowsMessageQueue { - CFRuntimeBase _base; - CFAllocatorRef _allocator; - CFSpinLock_t _lock; - DWORD _mask; - CFRunLoopSourceRef _source; - CFMutableArrayRef _runLoops; -}; - -/* Bit 3 in the base reserved bits is used for invalid state */ - -CF_INLINE Boolean __CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)wmq)->_cfinfo[CF_INFO_BITS], 3, 3); -} - -CF_INLINE void __CFWindowsMessageQueueSetValid(CFWindowsMessageQueueRef wmq) { - __CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_cfinfo[CF_INFO_BITS], 3, 3, 1); -} - -CF_INLINE void __CFWindowsMessageQueueUnsetValid(CFWindowsMessageQueueRef wmq) { - __CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_cfinfo[CF_INFO_BITS], 3, 3, 0); -} - -CF_INLINE void __CFWindowsMessageQueueLock(CFWindowsMessageQueueRef wmq) { - __CFSpinLock(&(wmq->_lock)); -} - -CF_INLINE void __CFWindowsMessageQueueUnlock(CFWindowsMessageQueueRef wmq) { - __CFSpinUnlock(&(wmq->_lock)); -} - -static Boolean __CFWindowsMessageQueueEqual(CFTypeRef cf1, CFTypeRef cf2) { - CFWindowsMessageQueueRef wmq1 = (CFWindowsMessageQueueRef)cf1; - CFWindowsMessageQueueRef wmq2 = (CFWindowsMessageQueueRef)cf2; - return (wmq1 == wmq2); -} - -static CFHashCode __CFWindowsMessageQueueHash(CFTypeRef cf) { - CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf; - return (CFHashCode)wmq; -} - -static CFStringRef __CFWindowsMessageQueueCopyDescription(CFTypeRef cf) { -/* Some commentary, possibly as out of date as much of the rest of the file was -#warning CF: this and many other CopyDescription functions are probably -#warning CF: broken, in that some of these fields being printed out can -#warning CF: be NULL, when the object is in the invalid state -*/ - CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf; - CFMutableStringRef result; - result = CFStringCreateMutable(CFGetAllocator(wmq), 0); - __CFWindowsMessageQueueLock(wmq); -/* More commentary, which we don't really need to see with every build -#warning CF: here, and probably everywhere with a per-instance lock, -#warning CF: the locked state will always be true because we lock, -#warning CF: and you cannot call description if the object is locked; -#warning CF: probably should not lock description, and call it unsafe -*/ - CFStringAppendFormat(result, NULL, CFSTR("{locked = %s, valid = %s, mask = 0x%x,\n run loops = %@}"), cf, CFGetAllocator(wmq), "unknown", (__CFWindowsMessageQueueIsValid(wmq) ? "Yes" : "No"), (UInt32)wmq->_mask, wmq->_runLoops); - __CFWindowsMessageQueueUnlock(wmq); - return result; -} - -CFAllocatorRef __CFWindowsMessageQueueGetAllocator(CFTypeRef cf) { - CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf; - return wmq->_allocator; -} - -static void __CFWindowsMessageQueueDeallocate(CFTypeRef cf) { - CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)cf; - CFAllocatorRef allocator = CFGetAllocator(wmq); - CFAllocatorDeallocate(allocator, wmq); - CFRelease(allocator); -} - -static CFTypeID __kCFWindowsMessageQueueTypeID = _kCFRuntimeNotATypeID; - -static const CFRuntimeClass __CFWindowsMessageQueueClass = { - 0, - "CFWindowsMessageQueue", - NULL, // init - NULL, // copy - __CFWindowsMessageQueueDeallocate, - __CFWindowsMessageQueueEqual, - __CFWindowsMessageQueueHash, - NULL, // - __CFWindowsMessageQueueCopyDescription -}; - -__private_extern__ void __CFWindowsMessageQueueInitialize(void) { - __kCFWindowsMessageQueueTypeID = _CFRuntimeRegisterClass(&__CFWindowsMessageQueueClass); -} - -CFTypeID CFWindowsMessageQueueGetTypeID(void) { - return __kCFWindowsMessageQueueTypeID; -} - -CFWindowsMessageQueueRef CFWindowsMessageQueueCreate(CFAllocatorRef allocator, uint32_t mask) { - CFWindowsMessageQueueRef memory; - UInt32 size = sizeof(struct __CFWindowsMessageQueue) - sizeof(CFRuntimeBase); - memory = (CFWindowsMessageQueueRef)_CFRuntimeCreateInstance(allocator, __kCFWindowsMessageQueueTypeID, size, NULL); - if (NULL == memory) { - return NULL; - } - __CFWindowsMessageQueueSetValid(memory); - - CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock); - memory->_mask = (DWORD)mask; - memory->_source = NULL; - memory->_runLoops = CFArrayCreateMutable(allocator, 0, NULL); - return memory; -} - -void CFWindowsMessageQueueInvalidate(CFWindowsMessageQueueRef wmq) { - __CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID); - CFRetain(wmq); - __CFWindowsMessageQueueLock(wmq); - if (__CFWindowsMessageQueueIsValid(wmq)) { - SInt32 idx; - __CFWindowsMessageQueueUnsetValid(wmq); - for (idx = CFArrayGetCount(wmq->_runLoops); idx--;) { - CFRunLoopWakeUp((CFRunLoopRef)CFArrayGetValueAtIndex(wmq->_runLoops, idx)); - } - CFRelease(wmq->_runLoops); - wmq->_runLoops = NULL; - if (NULL != wmq->_source) { - CFRunLoopSourceInvalidate(wmq->_source); - CFRelease(wmq->_source); - wmq->_source = NULL; - } - } - __CFWindowsMessageQueueUnlock(wmq); - CFRelease(wmq); -} - -Boolean CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq) { - __CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID); - return __CFWindowsMessageQueueIsValid(wmq); -} - -uint32_t CFWindowsMessageQueueGetMask(CFWindowsMessageQueueRef wmq) { - __CFGenericValidateType(wmq, __kCFWindowsMessageQueueTypeID); - return wmq->_mask; -} - -static void __CFWindowsMessageQueueSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) { - CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)info; - __CFWindowsMessageQueueLock(wmq); - if (__CFWindowsMessageQueueIsValid(wmq)) { - uint32_t mask; - CFArrayAppendValue(wmq->_runLoops, rl); - mask = __CFRunLoopGetWindowsMessageQueueMask(rl, mode); - mask |= wmq->_mask; - __CFRunLoopSetWindowsMessageQueueMask(rl, mask, mode); - } - __CFWindowsMessageQueueUnlock(wmq); -} - -static void __CFWindowsMessageQueueCancel(void *info, CFRunLoopRef rl, CFStringRef mode) { - CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)info; - __CFWindowsMessageQueueLock(wmq); -//#warning CF: should fix up run loop modes mask here, if not done -//#warning CF: previously by the invalidation, where it should also -//#warning CF: be done - if (NULL != wmq->_runLoops) { - SInt32 idx = CFArrayGetFirstIndexOfValue(wmq->_runLoops, CFRangeMake(0, CFArrayGetCount(wmq->_runLoops)), rl); - if (0 <= idx) CFArrayRemoveValueAtIndex(wmq->_runLoops, idx); - } - __CFWindowsMessageQueueUnlock(wmq); -} - -static void __CFWindowsMessageQueuePerform(void *info) { - CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)info; - __CFWindowsMessageQueueLock(wmq); - if (!__CFWindowsMessageQueueIsValid(wmq)) { - __CFWindowsMessageQueueUnlock(wmq); - return; - } - __CFWindowsMessageQueueUnlock(wmq); - extern void do_WIN32_MSG(); - do_WIN32_MSG(); -} - -CFRunLoopSourceRef CFWindowsMessageQueueCreateRunLoopSource(CFAllocatorRef allocator, CFWindowsMessageQueueRef wmq, CFIndex order) { - CFRunLoopSourceRef result = NULL; - __CFWindowsMessageQueueLock(wmq); - if (NULL == wmq->_source) { - CFRunLoopSourceContext context; - context.version = 0; - context.info = (void *)wmq; - context.retain = CFRetain; - context.release = CFRelease; - context.copyDescription = __CFWindowsMessageQueueCopyDescription; - context.equal = __CFWindowsMessageQueueEqual; - context.hash = __CFWindowsMessageQueueHash; - context.schedule = __CFWindowsMessageQueueSchedule; - context.cancel = __CFWindowsMessageQueueCancel; - context.perform = __CFWindowsMessageQueuePerform; - wmq->_source = CFRunLoopSourceCreate(allocator, order, &context); - } - CFRetain(wmq->_source); /* This retain is for the receiver */ - result = wmq->_source; - __CFWindowsMessageQueueUnlock(wmq); - return result; -} - -#endif - diff --git a/CFWindowsMessageQueue.h b/CFWindowsMessageQueue.h deleted file mode 100644 index bf094c9..0000000 --- a/CFWindowsMessageQueue.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2010 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@ - */ - -/* CFWindowsMessageQueue.h - Copyright (c) 1999-2009, Apple Inc. All rights reserved. -*/ - -#if !defined(__COREFOUNDATION_CFWINDOWSMESSAGEQUEUE__) -#define __COREFOUNDATION_CFWINDOWSMESSAGEQUEUE__ 1 - -#if DEPLOYMENT_TARGET_WINDOWS - -#include -#include - - -typedef struct __CFWindowsMessageQueue * CFWindowsMessageQueueRef; - -CF_EXPORT CFTypeID CFWindowsMessageQueueGetTypeID(void); - -CF_EXPORT CFWindowsMessageQueueRef CFWindowsMessageQueueCreate(CFAllocatorRef allocator, uint32_t /* DWORD */ mask); - -CF_EXPORT uint32_t CFWindowsMessageQueueGetMask(CFWindowsMessageQueueRef wmq); -CF_EXPORT void CFWindowsMessageQueueInvalidate(CFWindowsMessageQueueRef wmq); -CF_EXPORT Boolean CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq); - -CF_EXPORT CFRunLoopSourceRef CFWindowsMessageQueueCreateRunLoopSource(CFAllocatorRef allocator, CFWindowsMessageQueueRef wmq, CFIndex order); - -#endif - -#endif /* ! __COREFOUNDATION_CFWINDOWSMESSAGEQUEUE__ */ - diff --git a/CFXMLInputStream.c b/CFXMLInputStream.c index ef7a0c3..9279e58 100644 --- a/CFXMLInputStream.c +++ b/CFXMLInputStream.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFXMLInputStream.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. - Responsibility: Chris Parker + Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ #include "CFXMLInputStream.h" diff --git a/CFXMLInputStream.h b/CFXMLInputStream.h index 1e3d8fe..94571d1 100644 --- a/CFXMLInputStream.h +++ b/CFXMLInputStream.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CFXMLInputStream.h - Copyright (c) 2000-2009, Apple Inc. All rights reserved. + Copyright (c) 2000-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFXMLINPUTSTREAM__) diff --git a/CFXMLNode.c b/CFXMLNode.c index 8c04fd7..c40ac89 100644 --- a/CFXMLNode.c +++ b/CFXMLNode.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFXMLNode.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. - Responsibility: Chris Parker + Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ #include @@ -133,7 +133,7 @@ static CFHashCode __CFXMLNodeHash(CFTypeRef cf) { return url ? CFHash(url) : (CFHashCode)cf; } else { CFAssert2(false, __kCFLogAssertion, "%s(): Saw unexpected XML type code %d", __PRETTY_FUNCTION__, node->dataTypeID); - return (CFHashCode)cf; + return CFHash(cf); } } diff --git a/CFXMLNode.h b/CFXMLNode.h index df3f340..6e7d001 100644 --- a/CFXMLNode.h +++ b/CFXMLNode.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,13 +22,12 @@ */ /* CFXMLNode.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ -/* CFXMLParser (and thus CFXMLNode) will be officially deprecated in a future release of Mac OS X. - Clients should be aware of the fact that CFXMLParser has some serious deficiencies in terms of both - performance and standards compliance and should migrate their XML parsing to NSXMLParser, NSXMLDocument, or - other XML parsing technologies that will suit their needs better than CFXMLParser. +/* CFXMLParser (and thus CFXMLNode) are deprecated. Clients should be aware of the fact that CFXMLParser has + some serious deficiencies in terms of both performance and standards compliance and should migrate their + XML parsing to NSXMLParser, NSXMLDocument, or other XML parsing technologies. */ #if !defined(__COREFOUNDATION_CFXMLNODE__) diff --git a/CFXMLParser.c b/CFXMLParser.c index 4153ad4..5721ef3 100644 --- a/CFXMLParser.c +++ b/CFXMLParser.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFXMLParser.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. - Responsibility: Chris Parker + Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ #include @@ -1630,8 +1630,8 @@ Boolean parseAttributes(CFXMLParserRef parser) { break; } if (CFArrayGetFirstIndexOfValue(array, CFRangeMake(0, CFArrayGetCount(array)), key) != kCFNotFound) { - _CFReportError(parser, kCFXMLErrorMalformedStartTag, "Found repeated attribute"); - return false; + _CFReportError(parser, kCFXMLErrorMalformedStartTag, "Found repeated attribute"); + return false; } _inputStreamSkipWhitespace(&parser->input, NULL); if (!_inputStreamGetCharacter(&parser->input, &ch) || ch != '=') { diff --git a/CFXMLParser.h b/CFXMLParser.h index 1dc19d0..3d75276 100644 --- a/CFXMLParser.h +++ b/CFXMLParser.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,13 +22,12 @@ */ /* CFXMLParser.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ -/* CFXMLParser will be officially deprecated in a future release of Mac OS X. Clients should be - aware of the fact that CFXMLParser has some serious deficiencies in terms of both performance - and standards compliance and should migrate their XML parsing to NSXMLParser, NSXMLDocument, or - other XML parsing technologies that will suit their needs better than CFXMLParser. +/* CFXMLParser is deprecated. Clients should be aware of the fact that CFXMLParser has some serious + deficiencies in terms of both performance and standards compliance and should migrate their XML + parsing to NSXMLParser, NSXMLDocument, or other XML parsing technologies. */ #if !defined(__COREFOUNDATION_CFXMLPARSER__) @@ -253,7 +252,7 @@ CFXMLTreeRef CFXMLTreeCreateFromData(CFAllocatorRef allocator, CFDataRef xmlData various error information (see below). The caller is responsible for releasing the returned dictionary. If the error dictionary is not desired, pass NULL. */ CF_EXPORT -CFXMLTreeRef CFXMLTreeCreateFromDataWithError(CFAllocatorRef allocator, CFDataRef xmlData, CFURLRef dataSource, CFOptionFlags parseOptions, CFIndex versionOfNodes, CFDictionaryRef *errorDict) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFXMLTreeRef CFXMLTreeCreateFromDataWithError(CFAllocatorRef allocator, CFDataRef xmlData, CFURLRef dataSource, CFOptionFlags parseOptions, CFIndex versionOfNodes, CFDictionaryRef *errorDict); /* Loads the data to be parsed directly from dataSource. Arguments as above. */ CF_EXPORT @@ -274,22 +273,22 @@ CFDataRef CFXMLTreeCreateXMLData(CFAllocatorRef allocator, CFXMLTreeRef xmlTree) containing the expansion. Pass NULL for entitiesDictionary to indicate no entities other than the standard five. */ CF_EXPORT -CFStringRef CFXMLCreateStringByEscapingEntities(CFAllocatorRef allocator, CFStringRef string, CFDictionaryRef entitiesDictionary) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFStringRef CFXMLCreateStringByEscapingEntities(CFAllocatorRef allocator, CFStringRef string, CFDictionaryRef entitiesDictionary); CF_EXPORT -CFStringRef CFXMLCreateStringByUnescapingEntities(CFAllocatorRef allocator, CFStringRef string, CFDictionaryRef entitiesDictionary) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CFStringRef CFXMLCreateStringByUnescapingEntities(CFAllocatorRef allocator, CFStringRef string, CFDictionaryRef entitiesDictionary); /* CFXMLTreeCreateFromDataWithError error dictionary key constants. */ -CF_EXPORT const CFStringRef kCFXMLTreeErrorDescription AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CF_EXPORT const CFStringRef kCFXMLTreeErrorDescription; /* value is a CFString containing the readable error string. */ -CF_EXPORT const CFStringRef kCFXMLTreeErrorLineNumber AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CF_EXPORT const CFStringRef kCFXMLTreeErrorLineNumber; /* value is a CFNumber containing the line on which the error appears. */ -CF_EXPORT const CFStringRef kCFXMLTreeErrorLocation AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CF_EXPORT const CFStringRef kCFXMLTreeErrorLocation; /* value is a CFNumber containing the byte location at which the error occurred. */ -CF_EXPORT const CFStringRef kCFXMLTreeErrorStatusCode AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; +CF_EXPORT const CFStringRef kCFXMLTreeErrorStatusCode; /* value is a CFNumber containing the error status code. */ CF_EXTERN_C_END diff --git a/CFXMLPreferencesDomain.c b/CFXMLPreferencesDomain.c index cca7871..8f83032 100644 --- a/CFXMLPreferencesDomain.c +++ b/CFXMLPreferencesDomain.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,10 +22,11 @@ */ /* CFXMLPreferencesDomain.c - Copyright (c) 1998-2009, Apple Inc. All rights reserved. - Responsibility: Chris Parker + Copyright (c) 1998-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ + #include #include #include @@ -69,7 +70,7 @@ static void __CFMilliSleep(uint32_t msecs) { SleepEx(msecs, false); #elif defined(__svr4__) || defined(__hpux__) sleep((msecs + 900) / 1000); -#elif DEPLOYMENT_TARGET_MACOSX +#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX struct timespec input; input.tv_sec = msecs / 1000; input.tv_nsec = (msecs - input.tv_sec * 1000) * 1000000; @@ -320,12 +321,7 @@ static Boolean _writeXMLFile(CFURLRef url, CFMutableDictionaryRef dict, Boolean if (val) CFRelease(val); } else { CFPropertyListFormat desiredFormat = __CFPreferencesShouldWriteXML() ? kCFPropertyListXMLFormat_v1_0 : kCFPropertyListBinaryFormat_v1_0; - CFWriteStreamRef binStream = CFWriteStreamCreateWithAllocatedBuffers(alloc, alloc); - CFWriteStreamOpen(binStream); - CFPropertyListWriteToStream(dict, binStream, desiredFormat, NULL); - CFWriteStreamClose(binStream); - CFDataRef data = (CFDataRef) CFWriteStreamCopyProperty(binStream, kCFStreamPropertyDataWritten); - CFRelease(binStream); + CFDataRef data = CFPropertyListCreateData(alloc, dict, desiredFormat, 0, NULL); if (data) { SInt32 mode; #if DEPLOYMENT_TARGET_MACOSX @@ -528,7 +524,7 @@ static Boolean synchronizeXMLDomain(CFTypeRef context, void *xmlDomain) { } success = _writeXMLFile((CFURLRef )context, domain->_domainDict, domain->_isWorldReadable, &tryAgain); if (tryAgain) { - __CFMilliSleep((((uint32_t)__CFReadTSR() & 0xf) + 1) * 50); + __CFMilliSleep(50); } } while (tryAgain); CFRelease(cachedDict); @@ -540,4 +536,3 @@ static Boolean synchronizeXMLDomain(CFTypeRef context, void *xmlDomain) { return success; } - diff --git a/CFXMLTree.c b/CFXMLTree.c index 819a254..11c4a94 100644 --- a/CFXMLTree.c +++ b/CFXMLTree.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,8 +22,8 @@ */ /* CFXMLTree.c - Copyright (c) 1999-2009, Apple Inc. All rights reserved. - Responsibility: Chris Parker + Copyright (c) 1999-2011, Apple Inc. All rights reserved. + Responsibility: David Smith */ #include "CFInternal.h" diff --git a/CoreFoundation.h b/CoreFoundation.h index 943d037..1eaf0eb 100644 --- a/CoreFoundation.h +++ b/CoreFoundation.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CoreFoundation.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_COREFOUNDATION__) @@ -63,7 +63,6 @@ #include #include #include -#include #include #include #include @@ -73,16 +72,11 @@ #include #include #include -#include #include #include -#include #include #include -#include #include -#include -#include #include #include #include @@ -91,24 +85,26 @@ #include #include +#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) || TARGET_OS_WIN32 +#include +#include +#include +#include +#include +#include + -#if (TARGET_OS_MAC || TARGET_OS_WIN32) -#include #endif #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) || (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) -#include -#include #endif + #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) #include #include #include #endif -#if TARGET_OS_WIN32 -#include -#include -#endif + #endif /* ! __COREFOUNDATION_COREFOUNDATION__ */ diff --git a/CoreFoundation_Prefix.h b/CoreFoundation_Prefix.h index b734a38..44edab3 100644 --- a/CoreFoundation_Prefix.h +++ b/CoreFoundation_Prefix.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* CoreFoundation_Prefix.h - Copyright (c) 2005-2009, Apple Inc. All rights reserved. + Copyright (c) 2005-2011, Apple Inc. All rights reserved. */ @@ -38,20 +38,29 @@ #if DEPLOYMENT_TARGET_WINDOWS && defined(__cplusplus) extern "C" { #endif + +#define SystemIntegrityCheck(A, B) do {} while (0) + -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS +#if INCLUDE_OBJC #include +#else +typedef signed char BOOL; +typedef char * id; +typedef char * Class; +#define YES (BOOL)1 +#define NO (BOOL)0 +#define nil NULL #endif -#if DEPLOYMENT_TARGET_WINDOWS -#define DISPATCH_HELPER_FUNCTIONS(PREFIX, QNAME) +#if DEPLOYMENT_TARGET_MACOSX && defined(__ppc__) +#define SUPPORT_CFM 1 #endif #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED - -#import #import #import +#endif /* This macro creates 3 helper functions which are useful in dealing with libdispatch: * __ PREFIX SyncDispatchIsSafe -- returns bool indicating whether calling dispatch_sync() would be safe from self-deadlock @@ -79,7 +88,6 @@ static dispatch_queue_t __ ## PREFIX ## Queue(void) { \ return __ ## PREFIX ## dq; \ } \ -#endif #define LIBAUTO_STUB 1 @@ -103,15 +111,48 @@ typedef int boolean_t; #endif #endif -#if DEPLOYMENT_TARGET_WINDOWS +#if DEPLOYMENT_TARGET_LINUX + +#define __private_extern__ +#define __strong +#define __weak -#define MAXPATHLEN MAX_PATH -#undef MAX_PATH -#undef INVALID_HANDLE_VALUE +#define strtod_l(a,b,locale) strtod(a,b) +#define strtoul_l(a,b,c,locale) strtoul(a,b,c) +#define strtol_l(a,b,c,locale) strtol(a,b,c) +#define strncasecmp_l(a, b, c, d) strncasecmp(a, b, c) -// Define MIN/MAX macros from NSObjCRuntime.h, which are only defined for GNUC -#if !defined(__GNUC__) +#define fprintf_l(a,locale,b,...) fprintf(a, b, __VA_ARGS__) +#define strlcat(a,b,c) strncat(a,b,c) +#define strlcpy(a,b,c) strncpy(a,b,c) + +#define issetugid() 0 + +// Implemented in CFPlatform.c +bool OSAtomicCompareAndSwapPtr(void *oldp, void *newp, void *volatile *dst); +bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst); +bool OSAtomicCompareAndSwapPtrBarrier(void *oldp, void *newp, void *volatile *dst); + +int32_t OSAtomicDecrement32Barrier(volatile int32_t *dst); +int32_t OSAtomicIncrement32Barrier(volatile int32_t *dst); +int32_t OSAtomicIncrement32(volatile int32_t *theValue); +int32_t OSAtomicDecrement32(volatile int32_t *theValue); + +int32_t OSAtomicAdd32( int32_t theAmount, volatile int32_t *theValue ); +int32_t OSAtomicAdd32Barrier( int32_t theAmount, volatile int32_t *theValue ); +bool OSAtomicCompareAndSwap32Barrier( int32_t oldValue, int32_t newValue, volatile int32_t *theValue ); + +void OSMemoryBarrier(); + +#include +CF_INLINE size_t malloc_size(void *memblock) { + return malloc_usable_size(memblock); +} + +#endif + +#if DEPLOYMENT_TARGET_WINDOWS || DEPLOYMENT_TARGET_LINUX #if !defined(MIN) #define MIN(A,B) ((A) < (B) ? (A) : (B)) #endif @@ -122,9 +163,14 @@ typedef int boolean_t; #if !defined(ABS) #define ABS(A) ((A) < 0 ? (-(A)) : (A)) +#endif #endif - -#endif + +#if DEPLOYMENT_TARGET_WINDOWS + +#define MAXPATHLEN MAX_PATH +#undef MAX_PATH +#undef INVALID_HANDLE_VALUE // Defined for source compatibility #define ino_t _ino_t @@ -165,6 +211,7 @@ CF_EXPORT int _NS_access(const char *name, int amode); // The order of these includes is important #include #include +#include #undef BOOL @@ -181,6 +228,7 @@ struct timespec { #define malloc_default_zone() (void *)0 #define malloc_zone_from_ptr(a) (void *)0 #define malloc_zone_malloc(zone,size) malloc(size) +#define malloc_zone_memalign(zone,align,size) malloc(size) #define malloc_zone_calloc(zone,count,size) calloc(count,size) #define bcopy(b1,b2,len) memmove(b2, b1, (size_t)(len)) typedef int malloc_zone_t; @@ -206,25 +254,27 @@ typedef int32_t OSSpinLock; #include #include -//#include #include -#include #include + CF_INLINE size_t malloc_size(void *memblock) { return _msize(memblock); } #define mach_absolute_time() ((uint64_t)(CFAbsoluteTimeGetCurrent() * 1000000000.0)) -extern int pthread_main_np(); - #define strtod_l(a,b,locale) strtod(a,b) #define strtoul_l(a,b,c,locale) strtoul(a,b,c) #define strtol_l(a,b,c,locale) strtol(a,b,c) +#define strncasecmp_l(a, b, c, d) _strnicmp(a, b, c) +#define snprintf _snprintf -#define _fprintf_l(a,b,locale,...) fprintf(a, b, __VA_ARGS__) +#define fprintf_l(a,locale,b,...) fprintf(a, b, __VA_ARGS__) #define strlcat(a,b,c) strncat(a,b,c) +#define strlcpy(a,b,c) strncpy(a,b,c) + +#define sleep(x) Sleep(1000*x) #define issetugid() 0 @@ -238,6 +288,7 @@ CF_EXPORT int32_t OSAtomicIncrement32Barrier(volatile int32_t *dst); CF_EXPORT int32_t OSAtomicIncrement32(volatile int32_t *theValue); CF_EXPORT int32_t OSAtomicDecrement32(volatile int32_t *theValue); +CF_EXPORT int32_t OSAtomicAdd32( int32_t theAmount, volatile int32_t *theValue ); CF_EXPORT int32_t OSAtomicAdd32Barrier( int32_t theAmount, volatile int32_t *theValue ); CF_EXPORT bool OSAtomicCompareAndSwap32Barrier( int32_t oldValue, int32_t newValue, volatile int32_t *theValue ); @@ -248,10 +299,7 @@ CF_EXPORT bool OSAtomicCompareAndSwap64Barrier( int64_t __oldValue, int64_t __ne CF_EXPORT int64_t OSAtomicAdd64( int64_t __theAmount, volatile int64_t *__theValue ); CF_EXPORT int64_t OSAtomicAdd64Barrier( int64_t __theAmount, volatile int64_t *__theValue ); */ - -#define sleep(x) Sleep(1000*x) -#define strlcpy strncpy - + //#ifndef NTDDI_VERSION //#define NTDDI_VERSION NTDDI_WINXP //#endif @@ -259,45 +307,36 @@ CF_EXPORT int64_t OSAtomicAdd64Barrier( int64_t __theAmount, volatile int64_t *_ #include #include #include + +#endif + +#if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_WINDOWS + +#include -static __inline int flsl( long mask ) { +CF_INLINE int flsl( long mask ) { int idx = 0; - while (mask != 0) mask = (unsigned long)mask >> 1, idx++; - return idx; + while (mask != 0) mask = (unsigned long)mask >> 1, idx++; + return idx; } - -static __inline int asprintf(char **ret, const char *format, ...) { - va_list args; - size_t sz = 1024; - *ret = (char *) malloc(sz * sizeof(char)); - if (!*ret) return -1; - va_start(args, format); - int cnt = vsnprintf(*ret, sz, format, args); - va_end(args); - if (cnt < sz - 1) return cnt; - sz = cnt + 8; - char *oldret = *ret; - *ret = (char *) realloc(*ret, sz * sizeof(char)); - if (!*ret && oldret) free(oldret); - if (!*ret) return -1; - va_start(args, format); - cnt = vsnprintf(*ret, sz, format, args); - va_end(args); - if (cnt < sz - 1) return cnt; - free(*ret); - *ret = NULL; - return -1; + +CF_INLINE int popcountll(long long x) { + int count = 0; + while (x) { + count++; + x &= x - 1; // reset LS1B + } + return count; } -#define __unused +__private_extern__ int asprintf(char **ret, const char *format, ...); -#define __weak -#define __strong - #endif #ifdef LIBAUTO_STUB +#include + /* Stubs for functions in libauto. */ enum {OBJC_GENERATIONAL = (1 << 0)}; @@ -312,7 +351,19 @@ enum { }; -enum { AUTO_TYPE_UNKNOWN = -1, AUTO_UNSCANNED = 1, AUTO_OBJECT = 2, AUTO_MEMORY_SCANNED = 0, AUTO_MEMORY_UNSCANNED = AUTO_UNSCANNED, AUTO_OBJECT_SCANNED = AUTO_OBJECT, AUTO_OBJECT_UNSCANNED = AUTO_OBJECT | AUTO_UNSCANNED }; +enum { + AUTO_TYPE_UNKNOWN = -1, + AUTO_UNSCANNED = (1 << 0), + AUTO_OBJECT = (1 << 1), + AUTO_POINTERS_ONLY = (1 << 2), + AUTO_MEMORY_SCANNED = !AUTO_UNSCANNED, + AUTO_MEMORY_UNSCANNED = AUTO_UNSCANNED, + AUTO_MEMORY_ALL_POINTERS = AUTO_POINTERS_ONLY, + AUTO_MEMORY_ALL_WEAK_POINTERS = (AUTO_UNSCANNED | AUTO_POINTERS_ONLY), + AUTO_OBJECT_SCANNED = AUTO_OBJECT, + AUTO_OBJECT_UNSCANNED = AUTO_OBJECT | AUTO_UNSCANNED, + AUTO_OBJECT_ALL_POINTERS = AUTO_OBJECT | AUTO_POINTERS_ONLY +}; typedef unsigned long auto_memory_type_t; typedef struct _auto_zone_t auto_zone_t; typedef struct auto_weak_callback_block { @@ -323,76 +374,80 @@ typedef struct auto_weak_callback_block { } auto_weak_callback_block_t; CF_INLINE void *objc_memmove_collectable(void *a, const void *b, size_t c) { return memmove(a, b, c); } +CF_INLINE void *objc_collectableZone(void) { return 0; } -CF_INLINE auto_zone_t *auto_zone(void) { return 0; } CF_INLINE void *auto_zone_allocate_object(void *zone, size_t size, auto_memory_type_t type, int rc, int clear) { return 0; } CF_INLINE const void *auto_zone_base_pointer(void *zone, const void *ptr) { return 0; } +CF_INLINE void auto_zone_set_scan_exactly(void *zone, void *ptr) {} CF_INLINE void auto_zone_retain(void *zone, void *ptr) {} CF_INLINE unsigned int auto_zone_release(void *zone, void *ptr) { return 0; } CF_INLINE unsigned int auto_zone_retain_count(void *zone, const void *ptr) { return 0; } -CF_INLINE void auto_zone_set_unscanned(auto_zone_t *zone, void *ptr) {} -CF_INLINE void auto_zone_set_nofinalize(auto_zone_t *zone, void *ptr) {} +CF_INLINE void auto_zone_set_unscanned(void *zone, void *ptr) {} +CF_INLINE void auto_zone_set_nofinalize(void *zone, void *ptr) {} CF_INLINE int auto_zone_is_finalized(void *zone, const void *ptr) { return 0; } CF_INLINE size_t auto_zone_size(void *zone, const void *ptr) { return 0; } CF_INLINE void auto_register_weak_reference(void *zone, const void *referent, void **referrer, uintptr_t *counter, void **listHead, void **listElement) {} CF_INLINE void auto_unregister_weak_reference(void *zone, const void *referent, void **referrer) {} -CF_INLINE void auto_zone_register_thread(void *zone) {} -CF_INLINE void auto_zone_unregister_thread(void *zone) {} CF_INLINE int auto_zone_is_valid_pointer(void *zone, const void *ptr) { return 0; } CF_INLINE BOOL objc_isAuto(id object) { return 0; } CF_INLINE void* auto_read_weak_reference(void *zone, void **referrer) { void *result = *referrer; return result; } -CF_INLINE void auto_assign_weak_reference(void *zone, const void *referent, void **referrer, auto_weak_callback_block_t *block) { *referrer = (void *)referent; } +CF_INLINE void auto_assign_weak_reference(void *zone, const void *value, const void **location, auto_weak_callback_block_t *block) { *location = (void *)value; } CF_INLINE auto_memory_type_t auto_zone_get_layout_type(void *zone, void *ptr) { return AUTO_UNSCANNED; } -CF_INLINE boolean_t auto_zone_set_write_barrier(auto_zone_t *zone, const void *dest, const void *new_value) { return false; } +CF_INLINE int auto_zone_set_write_barrier(void *zone, const void *dest, const void *new_value) { return false; } CF_INLINE void objc_assertRegisteredThreadWithCollector(void) {} +CF_INLINE void objc_registerThreadWithCollector(void) {} +CF_INLINE uintptr_t _object_getExternalHash(id obj) { + return (uintptr_t)obj; +} + // from objc-auto.h -static OBJC_INLINE BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation) +CF_INLINE BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation) { return OSAtomicCompareAndSwapPtr((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); } -static OBJC_INLINE BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation) +CF_INLINE BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation) { return OSAtomicCompareAndSwapPtrBarrier((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); } -static OBJC_INLINE BOOL objc_atomicCompareAndSwapGlobal(id predicate, id replacement, volatile id *objectLocation) +CF_INLINE BOOL objc_atomicCompareAndSwapGlobal(id predicate, id replacement, volatile id *objectLocation) { return OSAtomicCompareAndSwapPtr((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); } -static OBJC_INLINE BOOL objc_atomicCompareAndSwapGlobalBarrier(id predicate, id replacement, volatile id *objectLocation) +CF_INLINE BOOL objc_atomicCompareAndSwapGlobalBarrier(id predicate, id replacement, volatile id *objectLocation) { return OSAtomicCompareAndSwapPtrBarrier((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); } -static OBJC_INLINE BOOL objc_atomicCompareAndSwapInstanceVariable(id predicate, id replacement, volatile id *objectLocation) +CF_INLINE BOOL objc_atomicCompareAndSwapInstanceVariable(id predicate, id replacement, volatile id *objectLocation) { return OSAtomicCompareAndSwapPtr((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); } -static OBJC_INLINE BOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate, id replacement, volatile id *objectLocation) +CF_INLINE BOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate, id replacement, volatile id *objectLocation) { return OSAtomicCompareAndSwapPtrBarrier((void *)predicate, (void *)replacement, (void * volatile *)objectLocation); } -static OBJC_INLINE id objc_assign_strongCast(id val, id *dest) +CF_INLINE id objc_assign_strongCast(id val, id *dest) { return (*dest = val); } -static OBJC_INLINE id objc_assign_global(id val, id *dest) +CF_INLINE id objc_assign_global(id val, id *dest) { return (*dest = val); } -static OBJC_INLINE id objc_assign_ivar(id val, id dest, ptrdiff_t offset) +CF_INLINE id objc_assign_ivar(id val, id dest, ptrdiff_t offset) { return (*(id*)((char *)dest+offset) = val); } -//static OBJC_INLINE void *objc_memmove_collectable(void *dst, const void *src, size_t size) { return memmove(dst, src, size); } +//CF_INLINE void *objc_memmove_collectable(void *dst, const void *src, size_t size) { return memmove(dst, src, size); } -static OBJC_INLINE id objc_read_weak(id *location) +CF_INLINE id objc_read_weak(id *location) { return *location; } -static OBJC_INLINE id objc_assign_weak(id value, id *location) +CF_INLINE id objc_assign_weak(id value, id *location) { return (*location = value); } -static OBJC_INLINE void objc_finalizeOnMainThread(Class cls) { } -static OBJC_INLINE BOOL objc_is_finalized(void *ptr) { return NO; } -static OBJC_INLINE void objc_clear_stack(unsigned long options) { } +CF_INLINE void objc_finalizeOnMainThread(Class cls) { } +CF_INLINE BOOL objc_is_finalized(void *ptr) { return NO; } +CF_INLINE void objc_clear_stack(unsigned long options) { } -static OBJC_INLINE BOOL objc_collectingEnabled(void) { return NO; } -static OBJC_INLINE void objc_start_collector_thread(void) { } +CF_INLINE BOOL objc_collectingEnabled(void) { return NO; } +CF_INLINE void objc_start_collector_thread(void) { } -static OBJC_INLINE void objc_collect(unsigned long options) { } +CF_INLINE void objc_collect(unsigned long options) { } #endif @@ -403,7 +458,29 @@ static OBJC_INLINE void objc_collect(unsigned long options) { } #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 && defined(__cplusplus) } // extern "C" #endif diff --git a/Examples/plconvert.c b/Examples/plconvert.c new file mode 100644 index 0000000..6a2b81e --- /dev/null +++ b/Examples/plconvert.c @@ -0,0 +1,110 @@ +// Mac OS X: llvm-gcc -F -framework CoreFoundation Examples/plconvert.c -o plconvert + +// Linux: clang -I/usr/local/include -L/usr/local/lib -lCoreFoundation plconvert.c -o plconvert + +/* + This example shows usage of CFString, CFData, and other CFPropertyList types. It takes two arguments: + 1. A property list file to read, in either binary or XML property list format. + 2. A file name to write a converted property list file to. + If the first input is binary, the output is XML and vice-versa. +*/ + +#include +#include +#include +#include +#include +#include + +#include + +static void logIt(CFStringRef format, ...) { + va_list args; + va_start(args, format); + CFStringRef str = CFStringCreateWithFormatAndArguments(kCFAllocatorSystemDefault, NULL, format, args); + if (!str) return; + + CFIndex blen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8); + char *buf = str ? (char *)malloc(blen + 1) : 0; + if (buf) { + Boolean converted = CFStringGetCString(str, buf, blen, kCFStringEncodingUTF8); + if (converted) { + // null-terminate + buf[blen] = 0; + printf("%s\n", buf); + } + } + if (buf) free(buf); + if (str) CFRelease(str); va_end(args); +} + +static CFMutableDataRef createDataFromFile(const char *fname) { + int fd = open(fname, O_RDONLY); + CFMutableDataRef res = CFDataCreateMutable(kCFAllocatorSystemDefault, 0); + char buf[4096]; + + ssize_t amountRead; + while ((amountRead = read(fd, buf, 4096)) > 0) { + CFDataAppendBytes(res, (const UInt8 *)buf, amountRead); + } + + close(fd); + return res; +} + +static bool writeDataToFile(CFDataRef data, const char *fname) { + int fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd < 0) { + printf("There was an error creating the file: %d", errno); + return false; + } + int dataLen = CFDataGetLength(data); + int w = write(fd, CFDataGetBytePtr(data), dataLen); + fsync(fd); + close(fd); + if (w != dataLen) return false; + return true; +} + +int main(int argc, char **argv) { + + if (argc != 3) { + printf("Usage: plconvert \nIf the in file is an XML property list, convert to binary property list in out file. If the in file is a binary property list, convert to XML property list in out file.\n"); + } else { + CFMutableDataRef plistData = createDataFromFile(argv[1]); + if (!plistData) { + printf("Unable to create data from file name: %s", argv[1]); + } else { + CFPropertyListFormat fmt; + CFErrorRef err; + CFPropertyListRef plist = CFPropertyListCreateWithData(kCFAllocatorSystemDefault, (CFDataRef)plistData, 0, &fmt, &err); + if (!plist) { + logIt(CFSTR("Unable to create property list from data: %@"), err); + } else { + logIt(CFSTR("Property list contents:\n%@"), plist); + if (fmt == kCFPropertyListBinaryFormat_v1_0) { + logIt(CFSTR("Converting to XML property list at: %s"), argv[2]); + fmt = kCFPropertyListXMLFormat_v1_0; + } else if (fmt == kCFPropertyListXMLFormat_v1_0) { + logIt(CFSTR("Converting to binary property list at: %s"), argv[2]); + fmt = kCFPropertyListBinaryFormat_v1_0; + } else { + logIt(CFSTR("Unknown property list format! Not converting output format.")); + } + + CFDataRef outputData = CFPropertyListCreateData(kCFAllocatorSystemDefault, plist, fmt, 0, &err); + if (!outputData) { + logIt(CFSTR("Unable to write property list to data: %@"), err); + } else { + bool success = writeDataToFile(outputData, argv[2]); + if (!success) { + logIt(CFSTR("Unable to write data to file")); + } + CFRelease(outputData); + } + CFRelease(plist); + } + CFRelease(plistData); + } + } +} diff --git a/ForFoundationOnly.h b/ForFoundationOnly.h index 263a9af..18be3cc 100644 --- a/ForFoundationOnly.h +++ b/ForFoundationOnly.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -22,7 +22,7 @@ */ /* ForFoundationOnly.h - Copyright (c) 1998-2009, Apple Inc. All rights reserved. + Copyright (c) 1998-2011, Apple Inc. All rights reserved. */ #if !CF_BUILDING_CF && !NSBUILDINGFOUNDATION @@ -51,7 +51,9 @@ CF_EXTERN_C_BEGIN -#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED +#if DEPLOYMENT_TARGET_LINUX +#include +#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED #include #endif @@ -59,6 +61,7 @@ CF_EXTERN_C_END // ---- CFBundle material ---------------------------------------- +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS #include CF_EXTERN_C_BEGIN @@ -68,13 +71,14 @@ CF_EXPORT const CFStringRef _kCFBundleInfoPlistURLKey; CF_EXPORT const CFStringRef _kCFBundleRawInfoPlistURLKey; CF_EXPORT const CFStringRef _kCFBundleNumericVersionKey; CF_EXPORT const CFStringRef _kCFBundleResourcesFileMappedKey; -CF_EXPORT const CFStringRef _kCFBundleCFMLoadAsBundleKey; CF_EXPORT const CFStringRef _kCFBundleAllowMixedLocalizationsKey; CF_EXPORT const CFStringRef _kCFBundleInitialPathKey; CF_EXPORT const CFStringRef _kCFBundleResolvedPathKey; CF_EXPORT const CFStringRef _kCFBundlePrincipalClassKey; -CF_EXPORT CFArrayRef _CFFindBundleResources(CFBundleRef bundle, CFURLRef bundleURL, CFStringRef subDirName, CFArrayRef searchLanguages, CFStringRef resName, CFArrayRef resTypes, CFIndex limit, UInt8 version); +#if __BLOCKS__ +CF_EXPORT CFArrayRef _CFFindBundleResources(CFBundleRef bundle, CFURLRef bundleURL, CFStringRef subDirName, CFArrayRef searchLanguages, CFStringRef resName, CFArrayRef resTypes, CFIndex limit, Boolean (^predicate)(CFStringRef filename, Boolean *stop), UInt8 version); +#endif CF_EXPORT UInt8 _CFBundleLayoutVersion(CFBundleRef bundle); @@ -86,6 +90,7 @@ CF_EXPORT CFErrorRef _CFBundleCreateError(CFAllocatorRef allocator, CFBundleRef CF_EXTERN_C_END +#endif // ---- CFPreferences material ---------------------------------------- @@ -188,6 +193,8 @@ CF_EXPORT CFIndex __CFStringEncodeByteStream(CFStringRef string, CFIndex rangeLo CF_EXPORT CFStringRef __CFStringCreateImmutableFunnel2(CFAllocatorRef alloc, const void *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean possiblyExternalFormat, Boolean tryToReduceUnicode, Boolean hasLengthByte, Boolean hasNullByte, Boolean noCopy, CFAllocatorRef contentsDeallocator); +CF_EXPORT void __CFStringAppendBytes(CFMutableStringRef str, const char *cStr, CFIndex appendedLength, CFStringEncoding encoding); + CF_INLINE Boolean __CFStringEncodingIsSupersetOfASCII(CFStringEncoding encoding) { switch (encoding & 0x0000FF00) { case 0x0: // MacOS Script range @@ -211,7 +218,7 @@ CF_INLINE Boolean __CFStringEncodingIsSupersetOfASCII(CFStringEncoding encoding) return false; // It's modal encoding case 0xA00: // Misc standard range - if ((encoding == kCFStringEncodingShiftJIS) || (encoding == kCFStringEncodingHZ_GB_2312)) return false; + if ((encoding == kCFStringEncodingShiftJIS) || (encoding == kCFStringEncodingHZ_GB_2312) || (encoding == kCFStringEncodingUTF7_IMAP)) return false; return true; case 0xB00: @@ -391,8 +398,6 @@ CF_EXPORT CFTypeRef _CFPropertyListCreateFromXMLData(CFAllocatorRef allocator, C CF_EXPORT CFTypeRef _CFPropertyListCreateFromXMLString(CFAllocatorRef allocator, CFStringRef xmlString, CFOptionFlags option, CFStringRef *errorString, Boolean allowNewTypes, CFPropertyListFormat *format); -CF_EXPORT bool _CFPropertyListCreateSingleValue(CFAllocatorRef allocator, CFDataRef data, CFOptionFlags option, CFStringRef key, CFPropertyListRef *value, CFErrorRef *error); - // ---- Sudden Termination material ---------------------------------------- #if DEPLOYMENT_TARGET_MACOSX @@ -405,6 +410,14 @@ CF_EXPORT size_t _CFSuddenTerminationDisablingCount(void); #endif +// ---- Thread-specific data -------------------------------------------- + +// Get some thread specific data from a pre-assigned slot. +CF_EXPORT void *_CFGetTSD(uint32_t slot); + +// Set some thread specific data in a pre-assigned slot. Don't pick a random value. Make sure you're using a slot that is unique. Pass in a destructor to free this data, or NULL if none is needed. Unlike pthread TSD, the destructor is per-thread. +CF_EXPORT void *_CFSetTSD(uint32_t slot, void *newVal, void (*destructor)(void *)); + #if DEPLOYMENT_TARGET_WINDOWS // ---- Windows-specific material --------------------------------------- @@ -431,9 +444,6 @@ CF_EXTERN_C_BEGIN CF_EXPORT CFTypeID CFTypeGetTypeID(void); -CF_EXPORT CFTypeRef _CFRetainGC(CFTypeRef cf); -CF_EXPORT void _CFReleaseGC(CFTypeRef cf); - CF_EXPORT void _CFArraySetCapacity(CFMutableArrayRef array, CFIndex cap); CF_EXPORT void _CFBagSetCapacity(CFMutableBagRef bag, CFIndex cap); CF_EXPORT void _CFDictionarySetCapacity(CFMutableDictionaryRef dict, CFIndex cap); @@ -495,7 +505,9 @@ CF_EXPORT void *__CFURLReservedPtr(CFURLRef url); CF_EXPORT void __CFURLSetReservedPtr(CFURLRef url, void *ptr); CF_EXPORT CFStringEncoding _CFURLGetEncoding(CFURLRef url); +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_WINDOWS CF_EXPORT Boolean _CFRunLoopFinished(CFRunLoopRef rl, CFStringRef mode); +#endif CF_EXPORT CFIndex _CFStreamInstanceSize(void); @@ -516,6 +528,11 @@ extern kern_return_t _CFDiscorporateMemoryDematerialize(CFDiscorporateMemory *hm extern kern_return_t _CFDiscorporateMemoryMaterialize(CFDiscorporateMemory *hm); #endif +enum { + kCFNumberFormatterOrdinalStyle = 6, + kCFNumberFormatterDurationStyle = 7, +}; + CF_EXPORT CFRange _CFDataFindBytes(CFDataRef data, CFDataRef dataToFind, CFRange searchRange, CFDataSearchFlags compareOptions); diff --git a/Info.plist b/Info.plist index d83c6eb..93f14c1 100644 --- a/Info.plist +++ b/Info.plist @@ -15,18 +15,18 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 6.6.4 + 6.7 CFBundleSignature ???? CFBundleVersion - 550.43 - CarbonLazyValues - - CodeFragmentManager - - CoreFoundation - CFMPriv_CoreFoundation - - + $(CURRENT_PROJECT_VERSION) + CarbonLazyValues + + CodeFragmentManager + + CoreFoundation + CFMPriv_CoreFoundation + + diff --git a/Makefile b/Makefile index f3f4b7b..db97d33 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,81 @@ -install: - DSTBASE="$(DSTROOT)/System/Library/Frameworks" ./BuildCFLite + +include MakefileVersion + +MIN_MACOSX_VERSION=10.7 +MAX_MACOSX_VERSION=MAC_OS_X_VERSION_10_7 + +OBJECTS = $(patsubst %.c,%.o,$(wildcard *.c)) +OBJECTS += CFBasicHash.o +HFILES = $(wildcard *.h) +INTERMEDIATE_HFILES = $(addprefix $(OBJBASE)/CoreFoundation/,$(HFILES)) + +PUBLIC_HEADERS=CFArray.h CFBag.h CFBase.h CFBinaryHeap.h CFBitVector.h CFBundle.h CFByteOrder.h CFCalendar.h CFCharacterSet.h CFData.h CFDate.h CFDateFormatter.h CFDictionary.h CFError.h CFLocale.h CFMessagePort.h CFNumber.h CFNumberFormatter.h CFPlugIn.h CFPlugInCOM.h CFPreferences.h CFPropertyList.h CFRunLoop.h CFSet.h CFSocket.h CFStream.h CFString.h CFStringEncodingExt.h CFTimeZone.h CFTree.h CFURL.h CFURLAccess.h CFUUID.h CFUserNotification.h CFXMLNode.h CFXMLParser.h CoreFoundation.h + +PRIVATE_HEADERS=CFBundlePriv.h CFCharacterSetPriv.h CFError_Private.h CFLogUtilities.h CFPriv.h CFRuntime.h CFStorage.h CFStreamAbstract.h CFStreamPriv.h CFStreamInternal.h CFStringDefaultEncoding.h CFStringEncodingConverter.h CFStringEncodingConverterExt.h CFUniChar.h CFUnicodeDecomposition.h CFUnicodePrecomposition.h ForFoundationOnly.h + +MACHINE_TYPE := $(shell uname -p) +unicode_data_file_name = $(if $(or $(findstring i386,$(1)),$(findstring i686,$(1)),$(findstring x86_64,$(1))),CFUnicodeData-L.mapping,CFUnicodeData-B.mapping) + +OBJBASE_ROOT = CF-Objects +OBJBASE = $(OBJBASE_ROOT)/$(STYLE) +DSTBASE = $(if $(DSTROOT),$(DSTROOT)/System/Library/Frameworks,../CF-Root) + +STYLE=normal +STYLE_CFLAGS=-O2 +STYLE_LFLAGS= +ARCHFLAGS=-arch i386 -arch x86_64 +INSTALLNAME=/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation_$(STYLE) + +CC = /usr/bin/llvm-gcc + +CFLAGS=-c -x c -pipe -std=gnu99 -Wmost -Wno-trigraphs -mmacosx-version-min=$(MIN_MACOSX_VERSION) -fconstant-cfstrings -fexceptions -DCF_BUILDING_CF=1 -DDEPLOYMENT_TARGET_MACOSX=1 -DMAC_OS_X_VERSION_MAX_ALLOWED=$(MAX_MACOSX_VERSION) -DU_SHOW_DRAFT_API=1 -DU_SHOW_CPLUSPLUS_API=0 -I$(OBJBASE) -DVERSION=$(VERSION) -include CoreFoundation_Prefix.h + +LFLAGS=-dynamiclib -mmacosx-version-min=$(MIN_MACOSX_VERSION) -twolevel_namespace -fexceptions -init ___CFInitialize -compatibility_version 150 -current_version $(VERSION) -Wl,-alias_list,SymbolAliases -sectcreate __UNICODE __csbitmaps CFCharacterSetBitmaps.bitmap -sectcreate __UNICODE __properties CFUniCharPropertyDatabase.data -sectcreate __UNICODE __data $(call unicode_data_file_name,$(MACHINE_TYPE)) -segprot __UNICODE r r + + +.PHONY: all install clean +.PRECIOUS: $(OBJBASE)/CoreFoundation/%.h + +all: install + +clean: + -/bin/rm -rf $(OBJBASE_ROOT) + +$(OBJBASE)/CoreFoundation: + /bin/mkdir -p $(OBJBASE)/CoreFoundation + +$(OBJBASE)/CoreFoundation/%.h: %.h $(OBJBASE)/CoreFoundation + /bin/cp $< $@ + +$(OBJBASE)/%.o: %.c $(INTERMEDIATE_HFILES) + $(CC) $(STYLE_CFLAGS) $(ARCHFLAGS) $(CFLAGS) $< -o $@ + +$(OBJBASE)/%.o: %.m $(INTERMEDIATE_HFILES) + $(CC) $(STYLE_CFLAGS) $(ARCHFLAGS) $(CFLAGS) $< -o $@ + +$(OBJBASE)/CoreFoundation_$(STYLE): $(addprefix $(OBJBASE)/,$(OBJECTS)) + $(CC) $(STYLE_LFLAGS) -install_name $(INSTALLNAME) $(ARCHFLAGS) $(LFLAGS) $^ -licucore.A -o $(OBJBASE)/CoreFoundation_$(STYLE) + +install: $(OBJBASE)/CoreFoundation_$(STYLE) + /bin/rm -rf $(DSTBASE)/CoreFoundation.framework + /bin/mkdir -p $(DSTBASE)/CoreFoundation.framework/Versions/A/Resources + /bin/mkdir -p $(DSTBASE)/CoreFoundation.framework/Versions/A/Headers + /bin/mkdir -p $(DSTBASE)/CoreFoundation.framework/Versions/A/PrivateHeaders + /bin/ln -sf A $(DSTBASE)/CoreFoundation.framework/Versions/Current + /bin/ln -sf Versions/Current/Resources $(DSTBASE)/CoreFoundation.framework/Resources + /bin/ln -sf Versions/Current/Headers $(DSTBASE)/CoreFoundation.framework/Headers + /bin/ln -sf Versions/Current/PrivateHeaders $(DSTBASE)/CoreFoundation.framework/PrivateHeaders + /bin/ln -sf Versions/Current/CoreFoundation $(DSTBASE)/CoreFoundation.framework/CoreFoundation + /bin/cp Info.plist $(DSTBASE)/CoreFoundation.framework/Versions/A/Resources + /bin/mkdir -p $(DSTBASE)/CoreFoundation.framework/Versions/A/Resources/en.lproj + /bin/cp $(PUBLIC_HEADERS) $(DSTBASE)/CoreFoundation.framework/Versions/A/Headers + /bin/cp $(PRIVATE_HEADERS) $(DSTBASE)/CoreFoundation.framework/Versions/A/PrivateHeaders + #/usr/bin/strip -S -o $(DSTBASE)/CoreFoundation.framework/Versions/A/CoreFoundation $(OBJBASE)/CoreFoundation_$(STYLE) + /bin/cp $(OBJBASE)/CoreFoundation_$(STYLE) $(DSTBASE)/CoreFoundation.framework/Versions/A/CoreFoundation + /usr/bin/dsymutil $(DSTBASE)/CoreFoundation.framework/Versions/A/CoreFoundation -o $(DSTBASE)/CoreFoundation.framework.dSYM + /usr/sbin/chown -RH -f root:wheel $(DSTBASE)/CoreFoundation.framework + /bin/chmod -RH a-w,a+rX $(DSTBASE)/CoreFoundation.framework + /bin/chmod -RH u+w $(DSTBASE) + install_name_tool -id /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation $(DSTBASE)/CoreFoundation.framework/Versions/A/CoreFoundation + @echo "Installing done. The framework is in $(DSTBASE)" + diff --git a/MakefileLinux b/MakefileLinux new file mode 100644 index 0000000..7070ab7 --- /dev/null +++ b/MakefileLinux @@ -0,0 +1,75 @@ + +include MakefileVersion + +MIN_MACOSX_VERSION=10.7 +MAX_MACOSX_VERSION=MAC_OS_X_VERSION_10_7 + +OBJECTS = CFCharacterSet.o CFPreferences.o CFApplicationPreferences.o CFXMLPreferencesDomain.o CFStringEncodingConverter.o CFUniChar.o CFArray.o CFPropertyList.o CFStringEncodingDatabase.o CFUnicodeDecomposition.o CFBag.o CFData.o CFStringEncodings.o CFUnicodePrecomposition.o CFBase.o CFDate.o CFNumber.o CFRuntime.o CFStringScanner.o CFBinaryHeap.o CFDateFormatter.o CFNumberFormatter.o CFSet.o CFStringUtilities.o CFUtilities.o CFBinaryPList.o CFDictionary.o CFPlatform.o CFSystemDirectories.o CFVersion.o CFBitVector.o CFError.o CFPlatformConverters.o CFTimeZone.o CFBuiltinConverters.o CFFileUtilities.o CFSortFunctions.o CFTree.o CFICUConverters.o CFURL.o CFLocale.o CFURLAccess.o CFCalendar.o CFLocaleIdentifier.o CFString.o CFUUID.o CFStorage.o CFLocaleKeys.o +OBJECTS += CFBasicHash.o +HFILES = $(wildcard *.h) +INTERMEDIATE_HFILES = $(addprefix $(OBJBASE)/CoreFoundation/,$(HFILES)) + +PUBLIC_HEADERS=CFArray.h CFBag.h CFBase.h CFBinaryHeap.h CFBitVector.h CFByteOrder.h CFCalendar.h CFCharacterSet.h CFData.h CFDate.h CFDateFormatter.h CFDictionary.h CFError.h CFLocale.h CFMachPort.h CFNumber.h CFNumberFormatter.h CFPreferences.h CFPropertyList.h CFSet.h CFString.h CFStringEncodingExt.h CFTimeZone.h CFTree.h CFURL.h CFURLAccess.h CFUUID.h CoreFoundation.h TargetConditionals.h + +PRIVATE_HEADERS= CFCharacterSetPriv.h CFError_Private.h CFLogUtilities.h CFPriv.h CFRuntime.h CFStorage.h CFStringDefaultEncoding.h CFStringEncodingConverter.h CFStringEncodingConverterExt.h CFUniChar.h CFUnicodeDecomposition.h CFUnicodePrecomposition.h ForFoundationOnly.h + +RESOURCES = CFCharacterSetBitmaps.bitmap CFUnicodeData-L.mapping CFUnicodeData-B.mapping + +OBJBASE_ROOT = CF-Objects +OBJBASE = $(OBJBASE_ROOT)/$(STYLE) +DSTBASE = /usr/local + +STYLE=normal +STYLE_CFLAGS=-O0 -g +STYLE_LFLAGS= + +CC = /usr/bin/clang + +CFLAGS=-c -x c -fblocks -fpic -pipe -std=gnu99 -Wno-trigraphs -fexceptions -DCF_BUILDING_CF=1 -DDEPLOYMENT_TARGET_LINUX=1 -DMAC_OS_X_VERSION_MAX_ALLOWED=$(MAX_MACOSX_VERSION) -DU_SHOW_DRAFT_API=1 -DU_SHOW_CPLUSPLUS_API=0 -I$(OBJBASE) -I$(OBJBASE)/CoreFoundation -DVERSION=$(VERSION) -include CoreFoundation_Prefix.h + +LFLAGS=-shared -fpic -init=___CFInitialize -Wl,--no-undefined,-soname,libCoreFoundation.so + +# Libs for open source version of ICU +#LIBS=-lc -lpthread -lm -lrt -licuuc -licudata -licui18n -lBlocksRuntime + +# Libs for Apple version of ICU +LIBS=-lc -lpthread -lm -lrt -licucore -lBlocksRuntime + +.PHONY: all install clean +.PRECIOUS: $(OBJBASE)/CoreFoundation/%.h + +all: $(OBJBASE)/libCoreFoundation.so + +clean: + -/bin/rm -rf $(OBJBASE_ROOT) + +$(OBJBASE)/CoreFoundation: + /bin/mkdir -p $(OBJBASE)/CoreFoundation + +$(OBJBASE)/CoreFoundation/%.h: %.h $(OBJBASE)/CoreFoundation + /bin/cp $< $@ + +$(OBJBASE)/%.o: %.c $(INTERMEDIATE_HFILES) + $(CC) $(STYLE_CFLAGS) $(CFLAGS) $< -o $@ + +$(OBJBASE)/%.o: %.m $(INTERMEDIATE_HFILES) + $(CC) $(STYLE_CFLAGS) $(CFLAGS) $< -o $@ + +$(OBJBASE)/libCoreFoundation.so: $(addprefix $(OBJBASE)/,$(OBJECTS)) + $(CC) $(STYLE_LFLAGS) $(LFLAGS) $^ -L/usr/local/lib $(LIBS) -o $(OBJBASE)/libCoreFoundation.so + @echo "Building done. 'sudo make install' to put the result into $(DSTBASE)/lib and $(DSTBASE)/include." + +install: $(OBJBASE)/libCoreFoundation.so + /bin/mkdir -p $(DSTBASE) + /bin/mkdir -p $(DSTBASE)/include/CoreFoundation + /bin/mkdir -p $(DSTBASE)/share/CoreFoundation + -/bin/rm $(DSTBASE)/include/CoreFoundation/*.h + /bin/mkdir -p $(DSTBASE)/lib + /bin/cp $(PRIVATE_HEADERS) $(DSTBASE)/include/CoreFoundation + /bin/cp $(PUBLIC_HEADERS) $(DSTBASE)/include/CoreFoundation + /bin/cp $(OBJBASE)/libCoreFoundation.so $(DSTBASE)/lib + /bin/cp $(RESOURCES) $(DSTBASE)/share/CoreFoundation + # this one goes outside the base directory + /bin/cp TargetConditionals.h $(DSTBASE)/include + /sbin/ldconfig -n $(DSTBASE)/lib + @echo "Installing done. The library is in $(DSTBASE)/lib and the headers are in $(DSTBASE)/include/CoreFoundation" diff --git a/MakefileVersion b/MakefileVersion new file mode 100644 index 0000000..0755f30 --- /dev/null +++ b/MakefileVersion @@ -0,0 +1 @@ +VERSION=635 diff --git a/README_CFLITE b/README_CFLITE new file mode 100644 index 0000000..b0b4b5b --- /dev/null +++ b/README_CFLITE @@ -0,0 +1,74 @@ +What is CFLite? +**** **** **** **** **** + +CFLite is an open source version of the CoreFoundation framework found on Mac OS X and iOS. It is designed to be simple and portable. For example, it can be used on other platforms to read and write property lists that may come from Mac OS X or iOS. + +It is important to note that this version is not the exact same version as is used on Mac OS X or iOS, but they do share a significant amount of code. + +How to Contact the CFLite Team +**** **** **** **** **** + +If you have patches, or enhancement requests, please file a bug report here: + https://bugreport.apple.com + +Please include as much detail as possible in your bug report, including platform, compiler, CFLite version, and a test case if appropriate. Mention that the bug should be sent to CoreFoundation in your descriptioon. + + +Building and Installing CFLite +**** **** **** **** **** + +On Mac OS X / Darwin +---- ---- ---- ---- ---- + +Use the default Makefile: + +% make + +This will create a CoreFoundation.framework, containing the shared library, header files, and resources. You can link to this library and use it at runtime by setting the DYLD_FRAMEWORK_PATH environment variable. 'man dyld' will give more information about this. + +An application must not link both this version of CFLite and the installed version of CoreFoundation. They are not compatible. CFLite will also not work with Foundation or any higher-level Cocoa framework that depends on the installed CoreFoundation. + +On Linux +---- ---- ---- ---- ---- + +First, you will need to fetch a few dependencies of CoreFoundation. + +* clang compiler 2.8 or later + http://clang.llvm.org/ + + CoreFoundation use the clang compiler to support modern features like Blocks. + +* libBlocksRuntime + http://compiler-rt.llvm.org/ + + This small shared library supports Blocks at runtime. You will need the 'cmake' utility (http://www.cmake.org/) to build this. It is recommended to install this library in /usr/local/lib and put the headers in /usr/local/include. + +* ICU 4.4 or later (ICU4C, the C version, not ICU4J, the Java version) + http://site.icu-project.org/download + + ICU is used for locales, time zones, calendars, and unicode support in CoreFoundation. Again, it is recommended to install this library in /usr/local/lib. + +Once you have the dependencies in place, build CFLite using the Linux Makefile: + +% sudo make -f MakefileLinux install + +This will create and install these files: + +/usr/local/lib/libCoreFoundation.so +/usr/local/include/CoreFoundation/

+/usr/local/include/TargetConditionals.h +/usr/local/share/CoreFoundation/ + +Make sure to set LD_LIBRARY_PATH environment variable to include /usr/local/lib when using an executable that has linked CFLite. + +On Windows +---- ---- ---- ---- ---- + +CFLite does not yet fully support Windows. The primary missing dependency is a version of clang that can build a dynamically linked library (.DLL) that supports the Windows executable format. + +Using CFLite +**** **** **** **** **** + +The Mac OS X version of CFLite supports most of the functionality of the full CoreFoundation. The Linux version of CFLite focuses on strings, dates, collections, and other property-list related items. + +There is an example of using CFLite on linux to process property lists in the 'plconvert.c' file. diff --git a/SymbolAliases b/SymbolAliases new file mode 100644 index 0000000..84b9421 --- /dev/null +++ b/SymbolAliases @@ -0,0 +1,96 @@ +_kCFCalendarIdentifierBuddhist _kCFBuddhistCalendar +_kCFCalendarIdentifierChinese _kCFChineseCalendar +_kCFCalendarIdentifierGregorian _kCFGregorianCalendar +_kCFCalendarIdentifierHebrew _kCFHebrewCalendar +_kCFCalendarIdentifierISO8601 _kCFISO8601Calendar +_kCFCalendarIdentifierIndian _kCFIndianCalendar +_kCFCalendarIdentifierIslamic _kCFIslamicCalendar +_kCFCalendarIdentifierIslamicCivil _kCFIslamicCivilCalendar +_kCFCalendarIdentifierJapanese _kCFJapaneseCalendar +_kCFCalendarIdentifierPersian _kCFPersianCalendar +_kCFCalendarIdentifierRepublicOfChina _kCFRepublicOfChinaCalendar + + +_kCFLocaleCalendarIdentifierKey _kCFLocaleCalendarIdentifier +_kCFLocaleCalendarKey _kCFLocaleCalendar +_kCFLocaleCollationIdentifierKey _kCFLocaleCollationIdentifier +_kCFLocaleCollatorIdentifierKey _kCFLocaleCollatorIdentifier +_kCFLocaleCountryCodeKey _kCFLocaleCountryCode +_kCFLocaleCurrencyCodeKey _kCFLocaleCurrencyCode +_kCFLocaleCurrencySymbolKey _kCFLocaleCurrencySymbol +_kCFLocaleDecimalSeparatorKey _kCFLocaleDecimalSeparator +_kCFLocaleExemplarCharacterSetKey _kCFLocaleExemplarCharacterSet +_kCFLocaleGroupingSeparatorKey _kCFLocaleGroupingSeparator +_kCFLocaleIdentifierKey _kCFLocaleIdentifier +_kCFLocaleLanguageCodeKey _kCFLocaleLanguageCode +_kCFLocaleMeasurementSystemKey _kCFLocaleMeasurementSystem +_kCFLocaleScriptCodeKey _kCFLocaleScriptCode +_kCFLocaleUsesMetricSystemKey _kCFLocaleUsesMetricSystem +_kCFLocaleVariantCodeKey _kCFLocaleVariantCode +_kCFDateFormatterAMSymbolKey _kCFDateFormatterAMSymbol +_kCFDateFormatterCalendarKey _kCFDateFormatterCalendar +_kCFDateFormatterCalendarIdentifierKey _kCFDateFormatterCalendarIdentifier +_kCFDateFormatterDefaultDateKey _kCFDateFormatterDefaultDate +_kCFDateFormatterDefaultFormatKey _kCFDateFormatterDefaultFormat +_kCFDateFormatterEraSymbolsKey _kCFDateFormatterEraSymbols +_kCFDateFormatterGregorianStartDateKey _kCFDateFormatterGregorianStartDate +_kCFDateFormatterIsLenientKey _kCFDateFormatterIsLenient +_kCFDateFormatterLongEraSymbolsKey _kCFDateFormatterLongEraSymbols +_kCFDateFormatterMonthSymbolsKey _kCFDateFormatterMonthSymbols +_kCFDateFormatterPMSymbolKey _kCFDateFormatterPMSymbol +_kCFDateFormatterQuarterSymbolsKey _kCFDateFormatterQuarterSymbols +_kCFDateFormatterShortMonthSymbolsKey _kCFDateFormatterShortMonthSymbols +_kCFDateFormatterShortQuarterSymbolsKey _kCFDateFormatterShortQuarterSymbols +_kCFDateFormatterShortStandaloneMonthSymbolsKey _kCFDateFormatterShortStandaloneMonthSymbols +_kCFDateFormatterShortStandaloneQuarterSymbolsKey _kCFDateFormatterShortStandaloneQuarterSymbols +_kCFDateFormatterShortStandaloneWeekdaySymbolsKey _kCFDateFormatterShortStandaloneWeekdaySymbols +_kCFDateFormatterShortWeekdaySymbolsKey _kCFDateFormatterShortWeekdaySymbols +_kCFDateFormatterStandaloneMonthSymbolsKey _kCFDateFormatterStandaloneMonthSymbols +_kCFDateFormatterStandaloneQuarterSymbolsKey _kCFDateFormatterStandaloneQuarterSymbols +_kCFDateFormatterStandaloneWeekdaySymbolsKey _kCFDateFormatterStandaloneWeekdaySymbols +_kCFDateFormatterTimeZoneKey _kCFDateFormatterTimeZone +_kCFDateFormatterTwoDigitStartDateKey _kCFDateFormatterTwoDigitStartDate +_kCFDateFormatterVeryShortMonthSymbolsKey _kCFDateFormatterVeryShortMonthSymbols +_kCFDateFormatterVeryShortStandaloneMonthSymbolsKey _kCFDateFormatterVeryShortStandaloneMonthSymbols +_kCFDateFormatterVeryShortStandaloneWeekdaySymbolsKey _kCFDateFormatterVeryShortStandaloneWeekdaySymbols +_kCFDateFormatterVeryShortWeekdaySymbolsKey _kCFDateFormatterVeryShortWeekdaySymbols +_kCFDateFormatterWeekdaySymbolsKey _kCFDateFormatterWeekdaySymbols +_kCFNumberFormatterAlwaysShowDecimalSeparatorKey _kCFNumberFormatterAlwaysShowDecimalSeparator +_kCFNumberFormatterCurrencyCodeKey _kCFNumberFormatterCurrencyCode +_kCFNumberFormatterCurrencyDecimalSeparatorKey _kCFNumberFormatterCurrencyDecimalSeparator +_kCFNumberFormatterCurrencyGroupingSeparatorKey _kCFNumberFormatterCurrencyGroupingSeparator +_kCFNumberFormatterCurrencySymbolKey _kCFNumberFormatterCurrencySymbol +_kCFNumberFormatterDecimalSeparatorKey _kCFNumberFormatterDecimalSeparator +_kCFNumberFormatterDefaultFormatKey _kCFNumberFormatterDefaultFormat +_kCFNumberFormatterExponentSymbolKey _kCFNumberFormatterExponentSymbol +_kCFNumberFormatterFormatWidthKey _kCFNumberFormatterFormatWidth +_kCFNumberFormatterGroupingSeparatorKey _kCFNumberFormatterGroupingSeparator +_kCFNumberFormatterGroupingSizeKey _kCFNumberFormatterGroupingSize +_kCFNumberFormatterInfinitySymbolKey _kCFNumberFormatterInfinitySymbol +_kCFNumberFormatterInternationalCurrencySymbolKey _kCFNumberFormatterInternationalCurrencySymbol +_kCFNumberFormatterIsLenientKey _kCFNumberFormatterIsLenient +_kCFNumberFormatterMaxFractionDigitsKey _kCFNumberFormatterMaxFractionDigits +_kCFNumberFormatterMaxIntegerDigitsKey _kCFNumberFormatterMaxIntegerDigits +_kCFNumberFormatterMaxSignificantDigitsKey _kCFNumberFormatterMaxSignificantDigits +_kCFNumberFormatterMinFractionDigitsKey _kCFNumberFormatterMinFractionDigits +_kCFNumberFormatterMinIntegerDigitsKey _kCFNumberFormatterMinIntegerDigits +_kCFNumberFormatterMinSignificantDigitsKey _kCFNumberFormatterMinSignificantDigits +_kCFNumberFormatterMinusSignKey _kCFNumberFormatterMinusSign +_kCFNumberFormatterMultiplierKey _kCFNumberFormatterMultiplier +_kCFNumberFormatterNaNSymbolKey _kCFNumberFormatterNaNSymbol +_kCFNumberFormatterNegativePrefixKey _kCFNumberFormatterNegativePrefix +_kCFNumberFormatterNegativeSuffixKey _kCFNumberFormatterNegativeSuffix +_kCFNumberFormatterPaddingCharacterKey _kCFNumberFormatterPaddingCharacter +_kCFNumberFormatterPaddingPositionKey _kCFNumberFormatterPaddingPosition +_kCFNumberFormatterPerMillSymbolKey _kCFNumberFormatterPerMillSymbol +_kCFNumberFormatterPercentSymbolKey _kCFNumberFormatterPercentSymbol +_kCFNumberFormatterPlusSignKey _kCFNumberFormatterPlusSign +_kCFNumberFormatterPositivePrefixKey _kCFNumberFormatterPositivePrefix +_kCFNumberFormatterPositiveSuffixKey _kCFNumberFormatterPositiveSuffix +_kCFNumberFormatterRoundingIncrementKey _kCFNumberFormatterRoundingIncrement +_kCFNumberFormatterRoundingModeKey _kCFNumberFormatterRoundingMode +_kCFNumberFormatterSecondaryGroupingSizeKey _kCFNumberFormatterSecondaryGroupingSize +_kCFNumberFormatterUseGroupingSeparatorKey _kCFNumberFormatterUseGroupingSeparator +_kCFNumberFormatterUseSignificantDigitsKey _kCFNumberFormatterUseSignificantDigits +_kCFNumberFormatterZeroSymbolKey _kCFNumberFormatterZeroSymbol +_kCFDateFormatterCalendarIdentifierKey _kCFDateFormatterCalendarName diff --git a/TargetConditionals.h b/TargetConditionals.h new file mode 100644 index 0000000..f02a187 --- /dev/null +++ b/TargetConditionals.h @@ -0,0 +1,17 @@ +/* TargetConditionals.h + Copyright (c) 2010-2011, Apple Inc. All rights reserved. + For CF on Linux ONLY +*/ + +#ifndef __TARGETCONDITIONALS__ +#define __TARGETCONDITIONALS__ + +#define TARGET_OS_MAC 0 +#define TARGET_OS_WIN32 0 +#define TARGET_OS_UNIX 0 +#define TARGET_OS_EMBEDDED 0 +#define TARGET_OS_IPHONE 0 +#define TARGET_IPHONE_SIMULATOR 0 +#define TARGET_OS_LINUX 1 + +#endif /* __TARGETCONDITIONALS__ */ diff --git a/plconvert.c b/plconvert.c new file mode 100644 index 0000000..4838d73 --- /dev/null +++ b/plconvert.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2011 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@ + */ + +// Mac OS X: llvm-gcc -F -framework CoreFoundation Examples/plconvert.c -o plconvert + +// Linux: clang -I/usr/local/include -L/usr/local/lib -lCoreFoundation plconvert.c -o plconvert + +/* + This example shows usage of CFString, CFData, and other CFPropertyList types. It takes two arguments: + 1. A property list file to read, in either binary or XML property list format. + 2. A file name to write a converted property list file to. + If the first input is binary, the output is XML and vice-versa. +*/ + +#include +#include +#include +#include +#include +#include + +#include + +static void logIt(CFStringRef format, ...) { + va_list args; + va_start(args, format); + CFStringRef str = CFStringCreateWithFormatAndArguments(kCFAllocatorSystemDefault, NULL, format, args); + if (!str) return; + + CFIndex blen = CFStringGetMaximumSizeForEncoding(CFStringGetLength(str), kCFStringEncodingUTF8); + char *buf = str ? (char *)malloc(blen + 1) : 0; + if (buf) { + Boolean converted = CFStringGetCString(str, buf, blen, kCFStringEncodingUTF8); + if (converted) { + // null-terminate + buf[blen] = 0; + printf("%s\n", buf); + } + } + if (buf) free(buf); + if (str) CFRelease(str); va_end(args); +} + +static CFMutableDataRef createDataFromFile(const char *fname) { + int fd = open(fname, O_RDONLY); + CFMutableDataRef res = CFDataCreateMutable(kCFAllocatorSystemDefault, 0); + char buf[4096]; + + ssize_t amountRead; + while ((amountRead = read(fd, buf, 4096)) > 0) { + CFDataAppendBytes(res, (const UInt8 *)buf, amountRead); + } + + close(fd); + return res; +} + +static bool writeDataToFile(CFDataRef data, const char *fname) { + int fd = open(fname, O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (fd < 0) { + printf("There was an error creating the file: %d", errno); + return false; + } + int dataLen = CFDataGetLength(data); + int w = write(fd, CFDataGetBytePtr(data), dataLen); + fsync(fd); + close(fd); + if (w != dataLen) return false; + return true; +} + +int main(int argc, char **argv) { + + if (argc != 3) { + printf("Usage: plconvert \nIf the in file is an XML property list, convert to binary property list in out file. If the in file is a binary property list, convert to XML property list in out file.\n"); + } else { + CFMutableDataRef plistData = createDataFromFile(argv[1]); + if (!plistData) { + printf("Unable to create data from file name: %s", argv[1]); + } else { + CFPropertyListFormat fmt; + CFErrorRef err; + CFPropertyListRef plist = CFPropertyListCreateWithData(kCFAllocatorSystemDefault, (CFDataRef)plistData, 0, &fmt, &err); + if (!plist) { + logIt(CFSTR("Unable to create property list from data: %@"), err); + } else { + logIt(CFSTR("Property list contents:\n%@"), plist); + if (fmt == kCFPropertyListBinaryFormat_v1_0) { + logIt(CFSTR("Converting to XML property list at: %s"), argv[2]); + fmt = kCFPropertyListXMLFormat_v1_0; + } else if (fmt == kCFPropertyListXMLFormat_v1_0) { + logIt(CFSTR("Converting to binary property list at: %s"), argv[2]); + fmt = kCFPropertyListBinaryFormat_v1_0; + } else { + logIt(CFSTR("Unknown property list format! Not converting output format.")); + } + + CFDataRef outputData = CFPropertyListCreateData(kCFAllocatorSystemDefault, plist, fmt, 0, &err); + if (!outputData) { + logIt(CFSTR("Unable to write property list to data: %@"), err); + } else { + bool success = writeDataToFile(outputData, argv[2]); + if (!success) { + logIt(CFSTR("Unable to write data to file")); + } + CFRelease(outputData); + } + CFRelease(plist); + } + CFRelease(plistData); + } + } +} -- 2.45.2