From bd5b749cf7786ae858ab372fc8f64179736c6515 Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 14 Feb 2008 23:13:42 +0000 Subject: [PATCH] CF-476.10.tar.gz --- AppServices.subproj/CFStreamPriv.h | 173 -- Base.subproj/CFRuntime.c | 986 ------- Base.subproj/CFSortFunctions.c | 831 ------ Base.subproj/CFUtilities.c | 550 ---- Base.subproj/CFUtilities.h | 87 - Base.subproj/CFUtilitiesPriv.h | 67 - Base.subproj/auto_stubs.h | 44 - Base.subproj/uuid.c | 1252 --------- BuildCFLite | 91 + ...references.c => CFApplicationPreferences.c | 223 +- Collections.subproj/CFArray.c => CFArray.c | 484 ++-- Collections.subproj/CFArray.h => CFArray.h | 65 +- CFBag.c | 1467 ++++++++++ Collections.subproj/CFBag.h => CFBag.h | 12 +- Base.subproj/CFBase.c => CFBase.c | 279 +- Base.subproj/CFBase.h => CFBase.h | 164 +- .../CFBinaryHeap.c => CFBinaryHeap.c | 87 +- .../CFBinaryHeap.h => CFBinaryHeap.h | 49 +- CFBinaryPList.c | 1278 +++++++++ .../CFBitVector.c => CFBitVector.c | 14 +- .../CFBitVector.h => CFBitVector.h | 12 +- ...iltinConverters.c => CFBuiltinConverters.c | 265 +- PlugIn.subproj/CFBundle.c => CFBundle.c | 2427 +++++++++++------ PlugIn.subproj/CFBundle.h => CFBundle.h | 120 +- .../CFBundlePriv.h => CFBundlePriv.h | 23 +- ...le_BinaryTypes.h => CFBundle_BinaryTypes.h | 27 +- ...CFBundle_Internal.h => CFBundle_Internal.h | 72 +- ...Bundle_Resources.c => CFBundle_Resources.c | 961 ++++--- Base.subproj/CFByteOrder.h => CFByteOrder.h | 136 +- CFCalendar.c | 1051 +++++++ CFCalendar.h | 133 + .../CFCharacterSet.c => CFCharacterSet.c | 676 ++--- .../CFCharacterSet.h => CFCharacterSet.h | 41 +- ...aps.bitmap => CFCharacterSetBitmaps.bitmap | Bin 352454 -> 434391 bytes ...CharacterSetPriv.h => CFCharacterSetPriv.h | 27 +- ...CFConcreteStreams.c => CFConcreteStreams.c | 173 +- Collections.subproj/CFData.c => CFData.c | 40 +- Collections.subproj/CFData.h => CFData.h | 12 +- NumberDate.subproj/CFDate.c => CFDate.c | 147 +- NumberDate.subproj/CFDate.h => CFDate.h | 21 +- CFDateFormatter.c | 713 +++++ CFDateFormatter.h | 167 ++ CFDictionary.c | 1467 ++++++++++ .../CFDictionary.h => CFDictionary.h | 61 +- CFError.c | 478 ++++ CFError.h | 192 ++ CFError_Private.h | 50 + .../CFFileUtilities.c => CFFileUtilities.c | 306 +-- Base.subproj/CFInternal.h => CFInternal.h | 393 ++- CFLocale.c | 983 +++++++ CFLocale.h | 185 ++ CFLocaleIdentifier.c | 1897 +++++++++++++ CFLogUtilities.h | 63 + RunLoop.subproj/CFMachPort.c => CFMachPort.c | 243 +- RunLoop.subproj/CFMachPort.h => CFMachPort.h | 16 +- .../CFMessagePort.c => CFMessagePort.c | 344 ++- .../CFMessagePort.h => CFMessagePort.h | 12 +- CFNumber.c | 1115 ++++++++ NumberDate.subproj/CFNumber.h => CFNumber.h | 25 +- CFNumberFormatter.c | 981 +++++++ CFNumberFormatter.h | 191 ++ Base.subproj/CFPlatform.c => CFPlatform.c | 281 +- PlugIn.subproj/CFPlugIn.c => CFPlugIn.c | 10 +- PlugIn.subproj/CFPlugIn.h => CFPlugIn.h | 18 +- PlugIn.subproj/CFPlugInCOM.h => CFPlugInCOM.h | 19 +- .../CFPlugIn_Factory.c => CFPlugIn_Factory.c | 34 +- .../CFPlugIn_Factory.h => CFPlugIn_Factory.h | 12 +- ...CFPlugIn_Instance.c => CFPlugIn_Instance.c | 13 +- .../CFPlugIn_PlugIn.c => CFPlugIn_PlugIn.c | 32 +- .../CFPreferences.c => CFPreferences.c | 360 +-- .../CFPreferences.h => CFPreferences.h | 12 +- Base.subproj/CFPriv.h => CFPriv.h | 178 +- .../CFPropertyList.c => CFPropertyList.c | 586 ++-- .../CFPropertyList.h => CFPropertyList.h | 22 +- RunLoop.subproj/CFRunLoop.c => CFRunLoop.c | 917 +++---- CFRunLoop.h | 188 ++ CFRunLoopPriv.h | 377 +++ CFRuntime.c | 1068 ++++++++ Base.subproj/CFRuntime.h => CFRuntime.h | 65 +- CFSet.c | 1467 ++++++++++ Collections.subproj/CFSet.h => CFSet.h | 45 +- RunLoop.subproj/CFSocket.c => CFSocket.c | 1635 ++++++----- RunLoop.subproj/CFSocket.h => CFSocket.h | 28 +- .../CFSocketStream.c => CFSocketStream.c | 170 +- CFSortFunctions.c | 1021 +++++++ .../CFStorage.c => CFStorage.c | 258 +- .../CFStorage.h => CFStorage.h | 12 +- Stream.subproj/CFStream.c => CFStream.c | 358 ++- AppServices.subproj/CFStream.h => CFStream.h | 71 +- .../CFStreamAbstract.h => CFStreamAbstract.h | 124 +- CFStreamInternal.h | 73 + .../CFStreamPriv.h => CFStreamPriv.h | 67 +- String.subproj/CFString.c => CFString.c | 2165 +++++++++------ String.subproj/CFString.h => CFString.h | 150 +- ...ultEncoding.h => CFStringDefaultEncoding.h | 125 +- ...Converter.c => CFStringEncodingConverter.c | 263 +- ...Converter.h => CFStringEncodingConverter.h | 44 +- ...terExt.h => CFStringEncodingConverterExt.h | 69 +- ...rPriv.h => CFStringEncodingConverterPriv.h | 18 +- ...ringEncodingExt.h => CFStringEncodingExt.h | 48 +- ...CFStringEncodings.c => CFStringEncodings.c | 142 +- .../CFStringScanner.c => CFStringScanner.c | 24 +- ...CFStringUtilities.c => CFStringUtilities.c | 65 +- ...stemDirectories.c => CFSystemDirectories.c | 24 +- CFTimeZone.c | 1169 ++++++++ .../CFTimeZone.h => CFTimeZone.h | 32 +- Collections.subproj/CFTree.c => CFTree.c | 23 +- Collections.subproj/CFTree.h => CFTree.h | 12 +- URL.subproj/CFURL.c => CFURL.c | 521 ++-- URL.subproj/CFURL.h => CFURL.h | 26 +- URL.subproj/CFURLAccess.c => CFURLAccess.c | 473 +++- URL.subproj/CFURLAccess.h => CFURLAccess.h | 19 +- Base.subproj/CFUUID.c => CFUUID.c | 58 +- Base.subproj/CFUUID.h => CFUUID.h | 12 +- .../CFUniChar.c => CFUniChar.c | 748 ++--- .../CFUniChar.h => CFUniChar.h | 29 +- .../CFUniCharPriv.h => CFUniCharPriv.h | 11 +- ...ase.data => CFUniCharPropertyDatabase.data | Bin 17688 -> 22820 bytes ...eData-B.mapping => CFUnicodeData-B.mapping | Bin 81316 -> 85576 bytes ...eData-L.mapping => CFUnicodeData-L.mapping | Bin 81316 -> 85576 bytes CFUnicodeDecomposition.c | 404 +++ ...ecomposition.h => CFUnicodeDecomposition.h | 20 +- ...composition.c => CFUnicodePrecomposition.c | 36 +- ...composition.h => CFUnicodePrecomposition.h | 16 +- ...UserNotification.c => CFUserNotification.c | 151 +- ...UserNotification.h => CFUserNotification.h | 12 +- CFUtilities.c | 453 +++ version.c => CFVersion.c | 17 +- ...sMessageQueue.c => CFWindowsMessageQueue.c | 32 +- ...sMessageQueue.h => CFWindowsMessageQueue.h | 13 +- .../CFXMLInputStream.c => CFXMLInputStream.c | 45 +- .../CFXMLInputStream.h => CFXMLInputStream.h | 4 +- Parsing.subproj/CFXMLNode.c => CFXMLNode.c | 49 +- Parsing.subproj/CFXMLNode.h => CFXMLNode.h | 22 +- .../CFXMLParser.c => CFXMLParser.c | 84 +- .../CFXMLParser.h => CFXMLParser.h | 22 +- ...rencesDomain.c => CFXMLPreferencesDomain.c | 173 +- Parsing.subproj/CFXMLTree.c => CFXMLTree.c | 12 +- Collections.subproj/CFBag.c | 848 ------ Collections.subproj/CFDictionary.c | 1337 --------- Collections.subproj/CFSet.c | 1054 ------- .../CoreFoundation.h => CoreFoundation.h | 51 +- ...ForFoundationOnly.h => ForFoundationOnly.h | 224 +- Info.plist | 32 + Locale.subproj/CFLocale.h | 51 - Makefile | 152 +- NumberDate.subproj/CFNumber.c | 620 ----- NumberDate.subproj/CFTimeZone.c | 1474 ---------- Parsing.subproj/CFBinaryPList.c | 930 ------- README | 3 + RunLoop.subproj/CFRunLoop.h | 435 --- RunLoop.subproj/CFRunLoopPriv.h | 48 - Stream.subproj/CFStream.h | 280 -- .../CFUnicodeDecomposition.c | 517 ---- auto_stubs.h | 70 + framework.make | 626 ----- 156 files changed, 29482 insertions(+), 21075 deletions(-) delete mode 100644 AppServices.subproj/CFStreamPriv.h delete mode 100644 Base.subproj/CFRuntime.c delete mode 100644 Base.subproj/CFSortFunctions.c delete mode 100644 Base.subproj/CFUtilities.c delete mode 100644 Base.subproj/CFUtilities.h delete mode 100644 Base.subproj/CFUtilitiesPriv.h delete mode 100644 Base.subproj/auto_stubs.h delete mode 100644 Base.subproj/uuid.c create mode 100755 BuildCFLite rename Preferences.subproj/CFApplicationPreferences.c => CFApplicationPreferences.c (81%) rename Collections.subproj/CFArray.c => CFArray.c (77%) rename Collections.subproj/CFArray.h => CFArray.h (93%) create mode 100644 CFBag.c rename Collections.subproj/CFBag.h => CFBag.h (94%) rename Base.subproj/CFBase.c => CFBase.c (81%) rename Base.subproj/CFBase.h => CFBase.h (72%) rename Collections.subproj/CFBinaryHeap.c => CFBinaryHeap.c (78%) rename Collections.subproj/CFBinaryHeap.h => CFBinaryHeap.h (90%) create mode 100644 CFBinaryPList.c rename Collections.subproj/CFBitVector.c => CFBitVector.c (98%) rename Collections.subproj/CFBitVector.h => CFBitVector.h (93%) rename StringEncodings.subproj/CFBuiltinConverters.c => CFBuiltinConverters.c (84%) rename PlugIn.subproj/CFBundle.c => CFBundle.c (51%) rename PlugIn.subproj/CFBundle.h => CFBundle.h (71%) rename PlugIn.subproj/CFBundlePriv.h => CFBundlePriv.h (92%) rename PlugIn.subproj/CFBundle_BinaryTypes.h => CFBundle_BinaryTypes.h (83%) rename PlugIn.subproj/CFBundle_Internal.h => CFBundle_Internal.h (84%) rename PlugIn.subproj/CFBundle_Resources.c => CFBundle_Resources.c (76%) rename Base.subproj/CFByteOrder.h => CFByteOrder.h (70%) create mode 100644 CFCalendar.c create mode 100644 CFCalendar.h rename String.subproj/CFCharacterSet.c => CFCharacterSet.c (81%) rename String.subproj/CFCharacterSet.h => CFCharacterSet.h (95%) rename CharacterSets/CFCharacterSetBitmaps.bitmap => CFCharacterSetBitmaps.bitmap (75%) rename String.subproj/CFCharacterSetPriv.h => CFCharacterSetPriv.h (88%) rename Stream.subproj/CFConcreteStreams.c => CFConcreteStreams.c (83%) rename Collections.subproj/CFData.c => CFData.c (93%) rename Collections.subproj/CFData.h => CFData.h (92%) rename NumberDate.subproj/CFDate.c => CFDate.c (83%) rename NumberDate.subproj/CFDate.h => CFDate.h (90%) create mode 100644 CFDateFormatter.c create mode 100644 CFDateFormatter.h create mode 100644 CFDictionary.c rename Collections.subproj/CFDictionary.h => CFDictionary.h (94%) create mode 100644 CFError.c create mode 100644 CFError.h create mode 100644 CFError_Private.h rename Base.subproj/CFFileUtilities.c => CFFileUtilities.c (68%) rename Base.subproj/CFInternal.h => CFInternal.h (63%) create mode 100644 CFLocale.c create mode 100644 CFLocale.h create mode 100644 CFLocaleIdentifier.c create mode 100644 CFLogUtilities.h rename RunLoop.subproj/CFMachPort.c => CFMachPort.c (72%) rename RunLoop.subproj/CFMachPort.h => CFMachPort.h (91%) rename RunLoop.subproj/CFMessagePort.c => CFMessagePort.c (68%) rename RunLoop.subproj/CFMessagePort.h => CFMessagePort.h (94%) create mode 100644 CFNumber.c rename NumberDate.subproj/CFNumber.h => CFNumber.h (92%) create mode 100644 CFNumberFormatter.c create mode 100644 CFNumberFormatter.h rename Base.subproj/CFPlatform.c => CFPlatform.c (59%) rename PlugIn.subproj/CFPlugIn.c => CFPlugIn.c (94%) rename PlugIn.subproj/CFPlugIn.h => CFPlugIn.h (95%) rename PlugIn.subproj/CFPlugInCOM.h => CFPlugInCOM.h (91%) rename PlugIn.subproj/CFPlugIn_Factory.c => CFPlugIn_Factory.c (87%) rename PlugIn.subproj/CFPlugIn_Factory.h => CFPlugIn_Factory.h (93%) rename PlugIn.subproj/CFPlugIn_Instance.c => CFPlugIn_Instance.c (94%) rename PlugIn.subproj/CFPlugIn_PlugIn.c => CFPlugIn_PlugIn.c (90%) rename Preferences.subproj/CFPreferences.c => CFPreferences.c (72%) rename Preferences.subproj/CFPreferences.h => CFPreferences.h (96%) rename Base.subproj/CFPriv.h => CFPriv.h (66%) rename Parsing.subproj/CFPropertyList.c => CFPropertyList.c (85%) rename Parsing.subproj/CFPropertyList.h => CFPropertyList.h (94%) rename RunLoop.subproj/CFRunLoop.c => CFRunLoop.c (82%) create mode 100644 CFRunLoop.h create mode 100644 CFRunLoopPriv.h create mode 100644 CFRuntime.c rename Base.subproj/CFRuntime.h => CFRuntime.h (90%) create mode 100644 CFSet.c rename Collections.subproj/CFSet.h => CFSet.h (94%) rename RunLoop.subproj/CFSocket.c => CFSocket.c (67%) rename RunLoop.subproj/CFSocket.h => CFSocket.h (96%) rename Stream.subproj/CFSocketStream.c => CFSocketStream.c (58%) create mode 100644 CFSortFunctions.c rename Collections.subproj/CFStorage.c => CFStorage.c (74%) rename Collections.subproj/CFStorage.h => CFStorage.h (98%) rename Stream.subproj/CFStream.c => CFStream.c (79%) rename AppServices.subproj/CFStream.h => CFStream.h (90%) rename Stream.subproj/CFStreamAbstract.h => CFStreamAbstract.h (74%) create mode 100644 CFStreamInternal.h rename Stream.subproj/CFStreamPriv.h => CFStreamPriv.h (78%) rename String.subproj/CFString.c => CFString.c (71%) rename String.subproj/CFString.h => CFString.h (83%) rename String.subproj/CFStringDefaultEncoding.h => CFStringDefaultEncoding.h (63%) rename StringEncodings.subproj/CFStringEncodingConverter.c => CFStringEncodingConverter.c (82%) rename StringEncodings.subproj/CFStringEncodingConverter.h => CFStringEncodingConverter.h (66%) rename StringEncodings.subproj/CFStringEncodingConverterExt.h => CFStringEncodingConverterExt.h (56%) rename StringEncodings.subproj/CFStringEncodingConverterPriv.h => CFStringEncodingConverterPriv.h (80%) rename String.subproj/CFStringEncodingExt.h => CFStringEncodingExt.h (89%) rename String.subproj/CFStringEncodings.c => CFStringEncodings.c (88%) rename String.subproj/CFStringScanner.c => CFStringScanner.c (93%) rename String.subproj/CFStringUtilities.c => CFStringUtilities.c (89%) rename Base.subproj/CFSystemDirectories.c => CFSystemDirectories.c (77%) create mode 100644 CFTimeZone.c rename NumberDate.subproj/CFTimeZone.h => CFTimeZone.h (71%) rename Collections.subproj/CFTree.c => CFTree.c (95%) rename Collections.subproj/CFTree.h => CFTree.h (98%) rename URL.subproj/CFURL.c => CFURL.c (91%) rename URL.subproj/CFURL.h => CFURL.h (97%) rename URL.subproj/CFURLAccess.c => CFURLAccess.c (53%) rename URL.subproj/CFURLAccess.h => CFURLAccess.h (95%) rename Base.subproj/CFUUID.c => CFUUID.c (85%) rename Base.subproj/CFUUID.h => CFUUID.h (94%) rename StringEncodings.subproj/CFUniChar.c => CFUniChar.c (62%) rename StringEncodings.subproj/CFUniChar.h => CFUniChar.h (91%) rename StringEncodings.subproj/CFUniCharPriv.h => CFUniCharPriv.h (85%) rename CharacterSets/CFUniCharPropertyDatabase.data => CFUniCharPropertyDatabase.data (64%) rename CharacterSets/CFUnicodeData-B.mapping => CFUnicodeData-B.mapping (59%) rename CharacterSets/CFUnicodeData-L.mapping => CFUnicodeData-L.mapping (60%) create mode 100644 CFUnicodeDecomposition.c rename StringEncodings.subproj/CFUnicodeDecomposition.h => CFUnicodeDecomposition.h (67%) rename StringEncodings.subproj/CFUnicodePrecomposition.c => CFUnicodePrecomposition.c (89%) rename StringEncodings.subproj/CFUnicodePrecomposition.h => CFUnicodePrecomposition.h (78%) rename AppServices.subproj/CFUserNotification.c => CFUserNotification.c (81%) rename AppServices.subproj/CFUserNotification.h => CFUserNotification.h (97%) create mode 100644 CFUtilities.c rename version.c => CFVersion.c (65%) rename RunLoop.subproj/CFWindowsMessageQueue.c => CFWindowsMessageQueue.c (87%) rename RunLoop.subproj/CFWindowsMessageQueue.h => CFWindowsMessageQueue.h (90%) rename Parsing.subproj/CFXMLInputStream.c => CFXMLInputStream.c (95%) rename Parsing.subproj/CFXMLInputStream.h => CFXMLInputStream.h (97%) rename Parsing.subproj/CFXMLNode.c => CFXMLNode.c (88%) rename Parsing.subproj/CFXMLNode.h => CFXMLNode.h (96%) rename Parsing.subproj/CFXMLParser.c => CFXMLParser.c (97%) rename Parsing.subproj/CFXMLParser.h => CFXMLParser.h (98%) rename Preferences.subproj/CFXMLPreferencesDomain.c => CFXMLPreferencesDomain.c (82%) rename Parsing.subproj/CFXMLTree.c => CFXMLTree.c (96%) delete mode 100644 Collections.subproj/CFBag.c delete mode 100644 Collections.subproj/CFDictionary.c delete mode 100644 Collections.subproj/CFSet.c rename Base.subproj/CoreFoundation.h => CoreFoundation.h (89%) rename Base.subproj/ForFoundationOnly.h => ForFoundationOnly.h (76%) create mode 100644 Info.plist delete mode 100644 Locale.subproj/CFLocale.h delete mode 100644 NumberDate.subproj/CFNumber.c delete mode 100644 NumberDate.subproj/CFTimeZone.c delete mode 100644 Parsing.subproj/CFBinaryPList.c delete mode 100644 RunLoop.subproj/CFRunLoop.h delete mode 100644 RunLoop.subproj/CFRunLoopPriv.h delete mode 100644 Stream.subproj/CFStream.h delete mode 100644 StringEncodings.subproj/CFUnicodeDecomposition.c create mode 100644 auto_stubs.h delete mode 100755 framework.make diff --git a/AppServices.subproj/CFStreamPriv.h b/AppServices.subproj/CFStreamPriv.h deleted file mode 100644 index 3106dc5..0000000 --- a/AppServices.subproj/CFStreamPriv.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFStreamPriv.h - Copyright (c) 2000-2005, Apple, Inc. All rights reserved. -*/ - -#if !defined(__COREFOUNDATION_CFSTREAMPRIV__) -#define __COREFOUNDATION_CFSTREAMPRIV__ 1 - -#include -#include -#include -#include -#include - -#if defined(__cplusplus) -extern "C" { -#endif - -struct _CFStream; -struct _CFStreamClient { - CFStreamClientContext cbContext; - void (*cb)(struct _CFStream *, CFStreamEventType, void *); - CFOptionFlags when; - CFRunLoopSourceRef rlSource; - CFMutableArrayRef runLoopsAndModes; - CFOptionFlags whatToSignal; -}; - -// A unified set of callbacks so we can use a single structure for all struct _CFStreams. -struct _CFStreamCallBacks { - CFIndex version; - void *(*create)(struct _CFStream *stream, void *info); - void (*finalize)(struct _CFStream *stream, void *info); - CFStringRef (*copyDescription)(struct _CFStream *stream, void *info); - Boolean (*open)(struct _CFStream *stream, CFStreamError *error, Boolean *openComplete, void *info); - Boolean (*openCompleted)(struct _CFStream *stream, CFStreamError *error, void *info); - CFIndex (*read)(CFReadStreamRef stream, UInt8 *buffer, CFIndex bufferLength, CFStreamError *error, Boolean *atEOF, void *info); - const UInt8 *(*getBuffer)(CFReadStreamRef sream, CFIndex maxBytesToRead, CFIndex *numBytesRead, CFStreamError *error, Boolean *atEOF, void *info); - Boolean (*canRead)(CFReadStreamRef, void *info); - CFIndex (*write)(CFWriteStreamRef, const UInt8 *buffer, CFIndex bufferLength, CFStreamError *error, void *info); - Boolean (*canWrite)(CFWriteStreamRef, void *info); - void (*close)(struct _CFStream *stream, void *info); - CFTypeRef (*copyProperty)(struct _CFStream *stream, CFStringRef propertyName, void *info); - Boolean (*setProperty)(struct _CFStream *stream, CFStringRef propertyName, CFTypeRef propertyValue, void *info); - void (*requestEvents)(struct _CFStream *stream, CFOptionFlags events, void *info); - void (*schedule)(struct _CFStream *stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info); - void (*unschedule)(struct _CFStream *stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info); -}; - -struct _CFStream { - CFRuntimeBase _cfBase; - CFOptionFlags flags; - CFStreamError error; - struct _CFStreamClient *client; - void *info; - const struct _CFStreamCallBacks *callBacks; // This will not exist (will not be allocated) if the callbacks are from our known, "blessed" set. - void *_reserved1; -}; - -CF_INLINE void *_CFStreamGetInfoPointer(struct _CFStream *stream) { - return stream->info; -} - -// cb version must be 1 -CF_EXPORT struct _CFStream *_CFStreamCreateWithConstantCallbacks(CFAllocatorRef alloc, void *info, const struct _CFStreamCallBacks *cb, Boolean isReading); - -// Only available for streams created with _CFStreamCreateWithConstantCallbacks, above. cb's version must be 1 -CF_EXPORT void _CFStreamSetInfoPointer(struct _CFStream *stream, void *info, const struct _CFStreamCallBacks *cb); - - -/* -** _CFStreamSourceScheduleWithRunLoop -** -** Schedules the given run loop source on the given run loop and mode. It then -** adds the loop and mode pair to the runLoopsAndModes list. The list is -** simply a linear list of a loop reference followed by a mode reference. -** -** source Run loop source to be scheduled -** -** runLoopsAndModes List of run loop/mode pairs on which the source is scheduled -** -** runLoop Run loop on which the source is being scheduled -** -** runLoopMode Run loop mode on which the source is being scheduled -*/ -CF_EXPORT -void _CFStreamSourceScheduleWithRunLoop(CFRunLoopSourceRef source, CFMutableArrayRef runLoopsAndModes, CFRunLoopRef runLoop, CFStringRef runLoopMode); - - -/* -** _CFStreamSourceUnscheduleFromRunLoop -** -** Unschedule the given source from the given run loop and mode. It then will -** guarantee that the source remains scheduled on the list of run loop and mode -** pairs in the runLoopsAndModes list. The list is simply a linear list of a -** loop reference followed by a mode reference. -** -** source Run loop source to be unscheduled -** -** runLoopsAndModes List of run loop/mode pairs on which the source is scheduled -** -** runLoop Run loop from which the source is being unscheduled -** -** runLoopMode Run loop mode from which the source is being unscheduled -*/ -CF_EXPORT -void _CFStreamSourceUnscheduleFromRunLoop(CFRunLoopSourceRef source, CFMutableArrayRef runLoopsAndModes, CFRunLoopRef runLoop, CFStringRef runLoopMode); - - -/* -** _CFStreamSourceScheduleWithAllRunLoops -** -** Schedules the given run loop source on all the run loops and modes in the list. -** The list is simply a linear list of a loop reference followed by a mode reference. -** -** source Run loop source to be unscheduled -** -** runLoopsAndModes List of run loop/mode pairs on which the source is scheduled -*/ -CF_EXPORT -void _CFStreamSourceScheduleWithAllRunLoops(CFRunLoopSourceRef source, CFArrayRef runLoopsAndModes); - - -/* -** _CFStreamSourceUnscheduleFromRunLoop -** -** Unschedule the given source from all the run loops and modes in the list. -** The list is simply a linear list of a loop reference followed by a mode -** reference. -** -** source Run loop source to be unscheduled -** -** runLoopsAndModes List of run loop/mode pairs on which the source is scheduled -*/ -CF_EXPORT -void _CFStreamSourceUncheduleFromAllRunLoops(CFRunLoopSourceRef source, CFArrayRef runLoopsAndModes); - - -#define SECURITY_NONE (0) -#define SECURITY_SSLv2 (1) -#define SECURITY_SSLv3 (2) -#define SECURITY_SSLv32 (3) -#define SECURITY_TLS (4) - -extern const int kCFStreamErrorDomainSSL; - -#if defined(__cplusplus) -} -#endif - -#endif /* ! __COREFOUNDATION_CFSTREAMPRIV__ */ - diff --git a/Base.subproj/CFRuntime.c b/Base.subproj/CFRuntime.c deleted file mode 100644 index 5f4491b..0000000 --- a/Base.subproj/CFRuntime.c +++ /dev/null @@ -1,986 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFRuntime.c - Copyright 1999-2002, Apple, Inc. All rights reserved. - Responsibility: Christopher Kane -*/ - -#define ENABLE_ZOMBIES 1 - -#include "CFRuntime.h" -#include "CFInternal.h" -#include -#include -#include -#if defined(__MACH__) -#include -#include -#include -#include -#include -#else -#endif - -#if defined(__MACH__) -extern void __CFRecordAllocationEvent(int eventnum, void *ptr, int size, int data, const char *classname); -#else -#define __CFRecordAllocationEvent(a, b, c, d, e) -#endif - -#if defined(__MACH__) -extern BOOL objc_isAuto(id object); -extern void* objc_assign_ivar_address_CF(void *value, void *base, void **slot); -extern void* objc_assign_strongCast_CF(void* value, void **slot); -#endif - -enum { -// retain/release recording constants -- must match values -// used by OA for now; probably will change in the future -__kCFRetainEvent = 28, -__kCFReleaseEvent = 29 -}; - -/* On Win32 we should use _msize instead of malloc_size - * (Aleksey Dukhnyakov) - */ -#if defined(__WIN32__) -#include -CF_INLINE size_t malloc_size(void *memblock) { - return _msize(memblock); -} -#else -#include -#endif - -#if defined(__MACH__) - -bool __CFOASafe = false; - -void __CFOAInitialize(void) { - static void (*dyfunc)(void) = (void *)0xFFFFFFFF; - if (NULL == getenv("OAKeepAllocationStatistics")) return; - if ((void *)0xFFFFFFFF == dyfunc) { - dyfunc = dlsym(RTLD_DEFAULT, "_OAInitialize"); - } - if (NULL != dyfunc) { - dyfunc(); - __CFOASafe = true; - } -} - -void __CFRecordAllocationEvent(int eventnum, void *ptr, int size, int data, const char *classname) { - static void (*dyfunc)(int, void *, int, int, const char *) = (void *)0xFFFFFFFF; - if (!__CFOASafe) return; - if ((void *)0xFFFFFFFF == dyfunc) { - dyfunc = dlsym(RTLD_DEFAULT, "_OARecordAllocationEvent"); - } - if (NULL != dyfunc) { - dyfunc(eventnum, ptr, size, data, classname); - } -} - -void __CFSetLastAllocationEventName(void *ptr, const char *classname) { - static void (*dyfunc)(void *, const char *) = (void *)0xFFFFFFFF; - if (!__CFOASafe) return; - if ((void *)0xFFFFFFFF == dyfunc) { - dyfunc = dlsym(RTLD_DEFAULT, "_OASetLastAllocationEventName"); - } - if (NULL != dyfunc) { - dyfunc(ptr, classname); - } -} -#endif - -extern void __HALT(void); - -static CFTypeID __kCFNotATypeTypeID = _kCFRuntimeNotATypeID; - -static const CFRuntimeClass __CFNotATypeClass = { - 0, - "Not A Type", - (void *)__HALT, - (void *)__HALT, - (void *)__HALT, - (void *)__HALT, - (void *)__HALT, - (void *)__HALT, - (void *)__HALT -}; - -static CFTypeID __kCFTypeTypeID = _kCFRuntimeNotATypeID; - -static const CFRuntimeClass __CFTypeClass = { - 0, - "CFType", - (void *)__HALT, - (void *)__HALT, - (void *)__HALT, - (void *)__HALT, - (void *)__HALT, - (void *)__HALT, - (void *)__HALT -}; - -/* bits 15-8 in the CFRuntimeBase _info are type */ -/* bits 7-0 in the CFRuntimeBase are reserved for CF's use */ - -static CFRuntimeClass * __CFRuntimeClassTable[__CFMaxRuntimeTypes] = {NULL}; -static int32_t __CFRuntimeClassTableCount = 0; - -#if defined(__MACH__) - -#if !defined(__ppc__) -__private_extern__ void * (*__CFSendObjCMsg)(const void *, SEL, ...) = NULL; -#endif - -__private_extern__ malloc_zone_t *__CFCollectableZone = NULL; - -static bool objc_isCollectable_nope(void* obj) { return false; } -bool (*__CFObjCIsCollectable)(void *) = NULL; - -static const void* objc_AssignIvar_none(const void *value, void *base, const void **slot) { return (*slot = value); } -const void* (*__CFObjCAssignIvar)(const void *value, const void *base, const void **slot) = objc_AssignIvar_none; - -static const void* objc_StrongAssign_none(const void *value, const void **slot) { return (*slot = value); } -const void* (*__CFObjCStrongAssign)(const void *value, const void **slot) = objc_StrongAssign_none; - -void* (*__CFObjCMemmoveCollectable)(void *dst, const void *, unsigned) = memmove; - -// GC: to be moved to objc if necessary. -static void objc_WriteBarrierRange_none(void *ptr, unsigned size) {} -static void objc_WriteBarrierRange_auto(void *ptr, unsigned size) { auto_zone_write_barrier_range(__CFCollectableZone, ptr, size); } -void (*__CFObjCWriteBarrierRange)(void *, unsigned) = objc_WriteBarrierRange_none; - -// Temporarily disabled __private_extern__ -#warning Ali, be sure to reexamine this -struct objc_class *__CFRuntimeObjCClassTable[__CFMaxRuntimeTypes] = {NULL}; - -#endif - -// Compiler uses this symbol name -int __CFConstantStringClassReference[10] = {0}; - -#if defined(__MACH__) -static struct objc_class __CFNSTypeClass = {{0, 0}, NULL, {0, 0, 0, 0, 0, 0, 0}}; -#endif - -//static CFSpinLock_t __CFRuntimeLock = 0; - -CFTypeID _CFRuntimeRegisterClass(const CFRuntimeClass * const cls) { -// version field must be 0 -// className must be pure ASCII string, non-null - if (__CFMaxRuntimeTypes <= __CFRuntimeClassTableCount) { - CFLog(0, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls->className); - return _kCFRuntimeNotATypeID; - } - __CFRuntimeClassTable[__CFRuntimeClassTableCount++] = (CFRuntimeClass *)cls; - return __CFRuntimeClassTableCount - 1; -} - -void _CFRuntimeInitializeClassForBridging(CFTypeID typeID) { - __CFRuntimeObjCClassTable[typeID] = (struct objc_class *)calloc(sizeof(struct objc_class), 1); -} - -Boolean _CFRuntimeSetupBridging(CFTypeID typeID, struct objc_class *mainClass, struct objc_class *subClass) { - void *isa = __CFISAForTypeID(typeID); - memmove(isa, subClass, sizeof(struct objc_class)); - class_poseAs(isa, mainClass); - return true; -} - -const CFRuntimeClass * _CFRuntimeGetClassWithTypeID(CFTypeID typeID) { - return __CFRuntimeClassTable[typeID]; -} - -void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID) { - __CFRuntimeClassTable[typeID] = NULL; -} - - -#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) - * bit 16: scribble allocated CF object memory - * bit 23: use 1st-order byte as scribble byte for alloc (otherwise 0xCF) - */ - -static uint32_t __CFZombieLevel = 0x0; - -static void __CFZombifyAllocatedMemory(void *cf) { - if (__CFZombieLevel & (1 << 16)) { - void *ptr = cf; - size_t size = malloc_size(cf); - uint8_t byte = 0xCF; - if (__CFZombieLevel & (1 << 23)) { - byte = (__CFZombieLevel >> 24) & 0xFF; - } - memset(ptr, byte, size); - } -} - -static void __CFZombifyDeallocatedMemory(void *cf) { - if (__CFZombieLevel & (1 << 0)) { - void *ptr = cf; - size_t size = malloc_size(cf); - uint8_t byte = 0xFC; - if (__CFZombieLevel & (1 << 1)) { - ptr += sizeof(CFRuntimeBase); - size -= sizeof(CFRuntimeBase); - } - if (__CFZombieLevel & (1 << 7)) { - byte = (__CFZombieLevel >> 8) & 0xFF; - } - memset(ptr, byte, size); - } -} - -#endif /* DEBUG */ - -// XXX_PCB: use the class version field as a bitmask, to allow classes to opt-in for GC scanning. - -CF_INLINE CFOptionFlags CF_GET_COLLECTABLE_MEMORY_TYPE(const CFRuntimeClass *cls) -{ - return (cls->version & _kCFRuntimeScannedObject) ? AUTO_OBJECT_SCANNED : AUTO_OBJECT_UNSCANNED; -} - -CFTypeRef _CFRuntimeCreateInstance(CFAllocatorRef allocator, CFTypeID typeID, uint32_t extraBytes, unsigned char *category) { - CFRuntimeBase *memory; - Boolean usesSystemDefaultAllocator; - int32_t size; - - CFAssert1(typeID != _kCFRuntimeNotATypeID, __kCFLogAssertion, "%s(): Uninitialized type id", __PRETTY_FUNCTION__); - - if (NULL == __CFRuntimeClassTable[typeID]) { - return NULL; - } - allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; - usesSystemDefaultAllocator = (allocator == kCFAllocatorSystemDefault); - extraBytes = (extraBytes + (sizeof(void *) - 1)) & ~(sizeof(void *) - 1); - size = sizeof(CFRuntimeBase) + extraBytes + (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef)); - // 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 - memory = CFAllocatorAllocate(allocator, size, CF_GET_COLLECTABLE_MEMORY_TYPE(__CFRuntimeClassTable[typeID])); - if (NULL == memory) { - return NULL; - } -#if defined(DEBUG) || defined(ENABLE_ZOMBIES) - __CFZombifyAllocatedMemory((void *)memory); -#endif - if (__CFOASafe && category) { - __CFSetLastAllocationEventName(memory, category); - } else if (__CFOASafe) { - __CFSetLastAllocationEventName(memory, __CFRuntimeClassTable[typeID]->className); - } - 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) = CFRetain(allocator); - memory = (CFRuntimeBase *)((char *)memory + sizeof(CFAllocatorRef)); - } - memory->_isa = __CFISAForTypeID(typeID); - memory->_rc = 1; - memory->_info = 0; - __CFBitfieldSetValue(memory->_info, 15, 8, typeID); - if (usesSystemDefaultAllocator) { - __CFBitfieldSetValue(memory->_info, 7, 7, 1); - } - if (NULL != __CFRuntimeClassTable[typeID]->init) { - (__CFRuntimeClassTable[typeID]->init)(memory); - } - return memory; -} - -void _CFRuntimeSetInstanceTypeID(CFTypeRef cf, CFTypeID typeID) { - __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_info, 15, 8, typeID); -} - -CFTypeID __CFGenericTypeID(const void *cf) { - return __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 15, 8); -} - -CF_INLINE CFTypeID __CFGenericTypeID_inline(const void *cf) { - return __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 15, 8); -} - -CFTypeID CFTypeGetTypeID(void) { - return __kCFTypeTypeID; -} - -__private_extern__ void __CFGenericValidateType_(CFTypeRef cf, CFTypeID type, const char *func) { - if (cf && CF_IS_OBJC(type, cf)) return; - CFAssert2((cf != NULL) && (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]) && (__kCFNotATypeTypeID != __CFGenericTypeID_inline(cf)) && (__kCFTypeTypeID != __CFGenericTypeID_inline(cf)), __kCFLogAssertion, "%s(): pointer 0x%x is not a CF object", func, cf); \ - CFAssert3(__CFGenericTypeID_inline(cf) == type, __kCFLogAssertion, "%s(): pointer 0x%x is not a %s", func, cf, __CFRuntimeClassTable[type]->className); \ -} - -#define __CFGenericAssertIsCF(cf) \ - CFAssert2(cf != NULL && (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]) && (__kCFNotATypeTypeID != __CFGenericTypeID_inline(cf)) && (__kCFTypeTypeID != __CFGenericTypeID_inline(cf)), __kCFLogAssertion, "%s(): pointer 0x%x is not a CF object", __PRETTY_FUNCTION__, cf); - -#if !defined(__MACH__) - -#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) - -#endif - -#if defined(__MACH__) - -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) = (void *)__CFSendObjCMsg; \ - 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, ...) = (void *)__CFSendObjCMsg; \ - 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"); - __CFGenericAssertIsCF(cf); - return __CFGenericTypeID_inline(cf); -} - -CFStringRef CFCopyTypeIDDescription(CFTypeID type) { - CFAssert2((NULL != __CFRuntimeClassTable[type]) && __kCFNotATypeTypeID != type && __kCFTypeTypeID != type, __kCFLogAssertion, "%s(): type %d is not a CF type ID", __PRETTY_FUNCTION__, type); - return CFStringCreateWithCString(kCFAllocatorDefault, __CFRuntimeClassTable[type]->className, kCFStringEncodingASCII); -} - -static CFSpinLock_t __CFGlobalRetainLock = 0; -static CFMutableDictionaryRef __CFRuntimeExternRefCountTable = NULL; - -#define DISGUISE(object) ((void *)(((unsigned)object) + 1)) -#define UNDISGUISE(disguised) ((id)(((unsigned)disguised) - 1)) - -extern void _CFDictionaryIncrementValue(CFMutableDictionaryRef dict, const void *key); -extern int _CFDictionaryDecrementValue(CFMutableDictionaryRef dict, const void *key); - -// Bit 31 (highest bit) in second word of cf instance indicates external ref count - -extern void _CFRelease(CFTypeRef cf); -extern CFTypeRef _CFRetain(CFTypeRef cf); -extern CFHashCode _CFHash(CFTypeRef cf); - -CFTypeRef CFRetain(CFTypeRef cf) { - // always honor CFRetain's with a hard reference - if (CF_IS_COLLECTABLE(cf)) { - auto_zone_retain(__CFCollectableZone, (void*)cf); - return cf; - } - // XXX_PCB some Objc objects aren't really reference counted, perhaps they should be able to make that distinction? - CFTYPE_OBJC_FUNCDISPATCH0(CFTypeRef, cf, "retain"); - __CFGenericAssertIsCF(cf); - return _CFRetain(cf); -} - -__private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf); - -void CFRelease(CFTypeRef cf) { - // make sure we get rid of the hard reference if called - if (CF_IS_COLLECTABLE(cf)) { - auto_zone_release(__CFCollectableZone, (void*)cf); - return; - } - // XXX_PCB some objects aren't really reference counted. - CFTYPE_OBJC_FUNCDISPATCH0(void, cf, "release"); - __CFGenericAssertIsCF(cf); - _CFRelease(cf); -} - -static uint64_t __CFGetFullRetainCount(CFTypeRef cf) { - uint32_t lowBits = 0; - uint64_t highBits = 0, compositeRC; - lowBits = ((CFRuntimeBase *)cf)->_rc; - if (0 == lowBits) { - return (uint64_t)0x00ffffffffffffffULL; - } - if ((lowBits & 0x08000) != 0) { - highBits = (uint64_t)(uintptr_t)CFDictionaryGetValue(__CFRuntimeExternRefCountTable, DISGUISE(cf)); - } - compositeRC = (lowBits & 0x7fff) + (highBits << 15); - return compositeRC; -} - -CFTypeRef _CFRetainGC(CFTypeRef cf) -{ -#if defined(DEBUG) - if (CF_USING_COLLECTABLE_MEMORY && !CF_IS_COLLECTABLE(cf)) { - fprintf(stderr, "non-auto object %p passed to _CFRetainGC.\n", cf); - HALT; - } -#endif - return CF_USING_COLLECTABLE_MEMORY ? cf : CFRetain(cf); -} - -void _CFReleaseGC(CFTypeRef cf) -{ -#if defined(DEBUG) - if (CF_USING_COLLECTABLE_MEMORY && !CF_IS_COLLECTABLE(cf)) { - fprintf(stderr, "non-auto object %p passed to _CFReleaseGC.\n", cf); - HALT; - } -#endif - if (!CF_USING_COLLECTABLE_MEMORY) CFRelease(cf); -} - -CFIndex CFGetRetainCount(CFTypeRef cf) { - uint64_t rc; - CFIndex result; -#if defined(DEBUG) - if (NULL == cf) HALT; -#endif - if (CF_IS_COLLECTABLE(cf)) { - return auto_zone_retain_count(__CFCollectableZone, cf); - } - CFTYPE_OBJC_FUNCDISPATCH0(CFIndex, cf, "retainCount"); - __CFGenericAssertIsCF(cf); - rc = __CFGetFullRetainCount(cf); - result = (rc < (uint64_t)0x7FFFFFFF) ? (CFIndex)rc : (CFIndex)0x7FFFFFFF; - return result; -} - -CFTypeRef CFMakeCollectable(CFTypeRef cf) -{ - if (!cf) return NULL; - if (CF_USING_COLLECTABLE_MEMORY) { -#if defined(DEBUG) - CFAllocatorRef allocator = CFGetAllocator(cf); - if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - CFLog(0, CFSTR("object %p with non-GC allocator %p passed to CFMakeCollected."), cf, allocator); - HALT; - } -#endif - if (CFGetRetainCount(cf) == 0) { - CFLog(0, CFSTR("object %p with 0 retain-count passed to CFMakeCollected."), cf); - return cf; - } - CFRelease(cf); - } - return cf; -} - -Boolean CFEqual(CFTypeRef cf1, CFTypeRef cf2) { -#if defined(DEBUG) - if (NULL == cf1) HALT; - if (NULL == cf2) HALT; -#endif - if (cf1 == cf2) return true; - 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; - if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal) { - return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal(cf1, cf2); - } - return false; -} - -CFHashCode CFHash(CFTypeRef cf) { - CFTYPE_OBJC_FUNCDISPATCH0(CFHashCode, cf, "hash"); - __CFGenericAssertIsCF(cf); - return _CFHash(cf); -} - -// definition: produces a normally non-NULL debugging description of the object -CFStringRef CFCopyDescription(CFTypeRef cf) { -#if defined(DEBUG) - if (NULL == cf) HALT; -#endif - if (CFTYPE_IS_OBJC(cf)) { - static SEL s = NULL; - CFStringRef (*func)(void *, SEL, ...) = (void *)__CFSendObjCMsg; - if (!s) s = sel_registerName("_copyDescription"); - CFStringRef result = func((void *)cf, s); - if (result && CF_USING_COLLECTABLE_MEMORY) CFRetain(result); // needs hard retain - return result; - } - // 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); - if (NULL != result) return result; - } - return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("<%s %p [%p]>"), __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->className, cf, CFGetAllocator(cf)); -} - -// Definition: if type produces a formatting description, return that string, otherwise NULL -__private_extern__ CFStringRef __CFCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { -#if defined(DEBUG) - if (NULL == cf) HALT; -#endif -#if defined(__MACH__) - if (CFTYPE_IS_OBJC(cf)) { - static SEL s = NULL, r = NULL; - CFStringRef (*func)(void *, SEL, ...) = (void *)__CFSendObjCMsg; - if (!s) s = sel_registerName("_copyFormattingDescription:"); - if (!r) r = sel_registerName("respondsToSelector:"); - if (s && func((void *)cf, r, s)) return func((void *)cf, s, formatOptions); - return NULL; - } -#endif - __CFGenericAssertIsCF(cf); - if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyFormattingDesc) { - return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyFormattingDesc(cf, formatOptions); - } - return NULL; -} - -extern CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef); - -CFAllocatorRef CFGetAllocator(CFTypeRef cf) { -#if defined(DEBUG) - if (NULL == cf) HALT; -#endif -// 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); -extern void __CFArrayInitialize(void); -extern void __CFBagInitialize(void); -extern void __CFBooleanInitialize(void); -extern void __CFCharacterSetInitialize(void); -extern void __CFDataInitialize(void); -extern void __CFDateInitialize(void); -extern void __CFDictionaryInitialize(void); -extern void __CFNumberInitialize(void); -extern void __CFSetInitialize(void); -extern void __CFStorageInitialize(void); -extern void __CFTimeZoneInitialize(void); -extern void __CFTreeInitialize(void); -extern void __CFURLInitialize(void); -extern void __CFXMLNodeInitialize(void); -extern void __CFXMLParserInitialize(void); -extern void __CFLocaleInitialize(void); -extern void __CFCalendarInitialize(void); -extern void __CFNumberFormatterInitialize(void); -extern void __CFDateFormatterInitialize(void); -#if defined(__MACH__) -extern void __CFMessagePortInitialize(void); -extern void __CFMachPortInitialize(void); -#endif -#if defined(__MACH__) || defined(__WIN32__) -extern void __CFRunLoopInitialize(void); -extern void __CFRunLoopObserverInitialize(void); -extern void __CFRunLoopSourceInitialize(void); -extern void __CFRunLoopTimerInitialize(void); -extern void __CFSocketInitialize(void); -#endif -extern void __CFBundleInitialize(void); -extern void __CFPlugInInitialize(void); -extern void __CFPlugInInstanceInitialize(void); -extern void __CFUUIDInitialize(void); -extern void __CFBinaryHeapInitialize(void); -extern void __CFBitVectorInitialize(void); -#if defined(__WIN32__) -extern void __CFWindowsMessageQueueInitialize(void); -extern void __CFBaseCleanup(void); -#endif -extern void __CFStreamInitialize(void); -#if defined(__MACH__) -extern void __CFPreferencesDomainInitialize(void); -extern void __CFUserNotificationInitialize(void); -#endif - -#if defined(DEBUG) -#define DO_SYSCALL_TRACE_HELPERS 1 -#endif -#if defined(DO_SYSCALL_TRACE_HELPERS) && defined(__MACH__) -extern void ptrace(int, int, int, int); -#define SYSCALL_TRACE(N) do ptrace(N, 0, 0, 0); while (0) -#else -#define SYSCALL_TRACE(N) do {} while (0) -#endif - -#if defined(__MACH__) && defined(PROFILE) -static void _CF_mcleanup(void) { - monitor(0,0,0,0,0); -} -#endif - -const void *__CFArgStuff = NULL; -__private_extern__ void *__CFAppleLanguages = NULL; -__private_extern__ void *__CFSessionID = NULL; - -#if defined(__LINUX__) || defined(__FREEBSD__) -static void __CFInitialize(void) __attribute__ ((constructor)); -static -#endif -#if defined(__WIN32__) -CF_EXPORT -#endif -void __CFInitialize(void) { - static int __done = 0; - if (sizeof(int) != sizeof(long) || 4 != sizeof(long)) __HALT(); - - if (!__done) { - __done = 1; - SYSCALL_TRACE(0xC000); - { - kCFUseCollectableAllocator = objc_collecting_enabled(); - if (kCFUseCollectableAllocator) { - __CFCollectableZone = auto_zone(); - __CFObjCIsCollectable = objc_isAuto; - __CFObjCAssignIvar = objc_assign_ivar_address_CF; - __CFObjCStrongAssign = objc_assign_strongCast_CF; - __CFObjCMemmoveCollectable = objc_memmove_collectable; - __CFObjCWriteBarrierRange = objc_WriteBarrierRange_auto; - } - } -#if defined(DEBUG) || defined(ENABLE_ZOMBIES) - { - const char *value = getenv("CFZombieLevel"); - if (NULL != value) { - __CFZombieLevel = strtoul(value, NULL, 0); - } - if (0x0 == __CFZombieLevel) __CFZombieLevel = 0xCF00FC00; // default - } -#endif -#if defined(__MACH__) && defined(PROFILE) - { - const char *v = getenv("DYLD_IMAGE_SUFFIX"); - const char *p = getenv("CFPROF_ENABLE"); - // ckane: People were upset that I added this feature to allow for the profiling of - // libraries using unprofiled apps/executables, so ensure they cannot get this accidentally. - if (v && p && 0 == strcmp("_profile", v) && 0 == strcmp(crypt(p + 2, p) + 2, "eQJhkVvMm.w")) { - // Unfortunately, no way to know if this has already been done, - // or I would not do it. Not much information will be lost. - atexit(_CF_mcleanup); - moninit(); - } - } -#endif - - __CFBaseInitialize(); - -#if defined(__MACH__) - { - CFIndex idx; - for (idx = 0; idx < __CFMaxRuntimeTypes; idx++) { - __CFRuntimeObjCClassTable[idx] = &__CFNSTypeClass; - } - } -#endif - - /* Here so that two runtime classes get indices 0, 1. */ - __kCFNotATypeTypeID = _CFRuntimeRegisterClass(&__CFNotATypeClass); - __kCFTypeTypeID = _CFRuntimeRegisterClass(&__CFTypeClass); - - /* Here so that __kCFAllocatorTypeID gets index 2. */ - __CFAllocatorInitialize(); - - /* Basic collections need to be up before CFString. */ - __CFDictionaryInitialize(); - __CFArrayInitialize(); - __CFDataInitialize(); - __CFSetInitialize(); - -#if defined(__MACH__) - { - CFIndex idx, cnt; - char **args = *_NSGetArgv(); - cnt = *_NSGetArgc(); - for (idx = 1; idx < cnt - 1; idx++) { - if (0 == strcmp(args[idx], "-AppleLanguages")) { - CFIndex length = strlen(args[idx + 1]); - __CFAppleLanguages = malloc(length + 1); - memmove(__CFAppleLanguages, args[idx + 1], length + 1); - break; - } - } - } -#endif - - - // Creating this lazily in CFRetain causes recursive call to CFRetain - __CFRuntimeExternRefCountTable = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); - - /*** _CFRuntimeCreateInstance() can finally be called generally after this line. ***/ - - __CFStringInitialize(); // CFString's TypeID must be 0x7, now and forever - __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 - __CFDateInitialize(); // See above for hard-coding of this position - __CFTimeZoneInitialize(); // See above for hard-coding of this position - - __CFBinaryHeapInitialize(); - __CFBitVectorInitialize(); - __CFBagInitialize(); - __CFCharacterSetInitialize(); - __CFStorageInitialize(); - __CFTreeInitialize(); - __CFURLInitialize(); - __CFXMLNodeInitialize(); - __CFXMLParserInitialize(); - __CFBundleInitialize(); - __CFPlugInInitialize(); - __CFPlugInInstanceInitialize(); - __CFUUIDInitialize(); -#if defined(__MACH__) - __CFMessagePortInitialize(); - __CFMachPortInitialize(); -#endif -#if defined(__MACH__) || defined(__WIN32__) - __CFRunLoopInitialize(); - __CFRunLoopObserverInitialize(); - __CFRunLoopSourceInitialize(); - __CFRunLoopTimerInitialize(); - __CFSocketInitialize(); -#endif - __CFStreamInitialize(); -#if defined(__MACH__) - __CFPreferencesDomainInitialize(); -#endif // __MACH__ - - - SYSCALL_TRACE(0xC001); - -#if defined(__MACH__) - { - CFIndex idx, cnt; - char **args = *_NSGetArgv(); - CFIndex count; - cnt = *_NSGetArgc(); - CFStringRef *list, buffer[256]; - list = (cnt <= 256) ? buffer : malloc(cnt * sizeof(CFStringRef)); - for (idx = 0, count = 0; idx < cnt && args[idx]; idx++) { - list[count] = CFStringCreateWithCString(kCFAllocatorSystemDefault, args[idx], kCFStringEncodingUTF8); - if (NULL == list[count]) { - list[count] = CFStringCreateWithCString(kCFAllocatorSystemDefault, args[idx], kCFStringEncodingISOLatin1); - // We CANNOT use the string SystemEncoding here; - // Do not argue: it is not initialized yet, but these - // arguments MUST be initialized before it is. - // We should just ignore the argument if the UTF-8 - // conversion fails, but out of charity we try once - // more with ISO Latin1, a standard unix encoding. - } - if (NULL != list[count]) count++; - } - __CFArgStuff = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)list, count, &kCFTypeArrayCallBacks); - } - - __CFSessionID = getenv("SECURITYSESSIONID"); -#endif - _CFProcessPath(); // cache this early - -#if defined(__MACH__) - __CFOAInitialize(); - SYSCALL_TRACE(0xC003); -#endif - - if (__CFRuntimeClassTableCount < 100) __CFRuntimeClassTableCount = 100; - -#if defined(DEBUG) && !defined(__WIN32__) - // Don't log on MacOS 8 as this will create a log file unnecessarily - CFLog (0, CFSTR("Assertions enabled")); -#endif - SYSCALL_TRACE(0xC0FF); - } -} - -#if defined(__WIN32__) - -/* We have to call __CFInitialize when library is attached to the process. - * (Sergey Zubarev) - */ -WINBOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID pReserved ) { - if (dwReason == DLL_PROCESS_ATTACH) { - __CFInitialize(); - } else if (dwReason == DLL_PROCESS_DETACH) { - __CFStringCleanup(); - __CFSocketCleanup(); - __CFUniCharCleanup(); - __CFStreamCleanup(); - __CFBaseCleanup(); - } else if (dwReason == DLL_THREAD_DETACH) { - __CFFinalizeThreadData(NULL); - } - return TRUE; -} - -#endif - - -// Functions that avoid ObC dispatch and CF type validation, for use by NSNotifyingCFArray, etc. -// Hopefully all of this will just go away. 3321464. M.P. To Do - 7/9/03 - -Boolean _CFEqual(CFTypeRef cf1, CFTypeRef cf2) { -#if defined(DEBUG) - if (NULL == cf1) HALT; - if (NULL == cf2) HALT; -#endif - if (cf1 == cf2) return true; - __CFGenericAssertIsCF(cf1); - __CFGenericAssertIsCF(cf2); - if (__CFGenericTypeID_inline(cf1) != __CFGenericTypeID_inline(cf2)) return false; - if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal) { - return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal(cf1, cf2); - } - return false; -} - -CFIndex _CFGetRetainCount(CFTypeRef cf) { - uint64_t rc; - CFIndex result; - rc = __CFGetFullRetainCount(cf); - result = (rc < (uint64_t)0x7FFFFFFF) ? (CFIndex)rc : (CFIndex)0x7FFFFFFF; - return result; -} - -CFHashCode _CFHash(CFTypeRef cf) { -#if defined(DEBUG) - if (NULL == cf) HALT; -#endif - if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->hash) { - return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->hash(cf); - } - return (CFHashCode)cf; -} - -CF_EXPORT CFTypeRef _CFRetain(CFTypeRef cf) { - CFIndex lowBits = 0; -#if defined(DEBUG) - if (NULL == cf) HALT; -#endif - __CFSpinLock(&__CFGlobalRetainLock); - lowBits = ((CFRuntimeBase *)cf)->_rc; - if (__builtin_expect(0 == lowBits, 0)) { // Constant CFTypeRef - __CFSpinUnlock(&__CFGlobalRetainLock); - return cf; - } - lowBits++; - if (__builtin_expect((lowBits & 0x07fff) == 0, 0)) { - // Roll over another bit to the external ref count - _CFDictionaryIncrementValue(__CFRuntimeExternRefCountTable, DISGUISE(cf)); - lowBits = 0x8000; // Bit 16 indicates external ref count - } - ((CFRuntimeBase *)cf)->_rc = lowBits; - __CFSpinUnlock(&__CFGlobalRetainLock); - if (__builtin_expect(__CFOASafe, 0)) { - uint64_t compositeRC; - compositeRC = (lowBits & 0x7fff) + ((uint64_t)(uintptr_t)CFDictionaryGetValue(__CFRuntimeExternRefCountTable, DISGUISE(cf)) << 15); - if (compositeRC > (uint64_t)0x7fffffff) compositeRC = (uint64_t)0x7fffffff; - __CFRecordAllocationEvent(__kCFRetainEvent, (void *)cf, 0, compositeRC, NULL); - } - return cf; -} - -CF_EXPORT void _CFRelease(CFTypeRef cf) { - CFIndex lowBits = 0; -#if defined(DEBUG) - if (NULL == cf) HALT; -#endif - __CFSpinLock(&__CFGlobalRetainLock); - lowBits = ((CFRuntimeBase *)cf)->_rc; - if (__builtin_expect(0 == lowBits, 0)) { // Constant CFTypeRef - __CFSpinUnlock(&__CFGlobalRetainLock); - return; - } - if (__builtin_expect(1 == lowBits, 0)) { - __CFSpinUnlock(&__CFGlobalRetainLock); - if (__builtin_expect(__CFOASafe, 0)) __CFRecordAllocationEvent(__kCFReleaseEvent, (void *)cf, 0, 0, NULL); - if (__builtin_expect(__kCFAllocatorTypeID_CONST == __CFGenericTypeID_inline(cf), 0)) { -#if defined(DEBUG) || defined(ENABLE_ZOMBIES) - __CFZombifyDeallocatedMemory((void *)cf); - if (!(__CFZombieLevel & (1 << 4))) { - __CFAllocatorDeallocate((void *)cf); - } -#else - __CFAllocatorDeallocate((void *)cf); -#endif - } else { - CFAllocatorRef allocator; -// ((CFRuntimeBase *)cf)->_rc = 0; - if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->finalize) { - __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->finalize(cf); - } - if (__builtin_expect(__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 7, 7), 1)) { - allocator = kCFAllocatorSystemDefault; - } else { - allocator = CFGetAllocator(cf); - (intptr_t)cf -= sizeof(CFAllocatorRef); - } -#if defined(DEBUG) || defined(ENABLE_ZOMBIES) - __CFZombifyDeallocatedMemory((void *)cf); - if (!(__CFZombieLevel & (1 << 4))) { - CFAllocatorDeallocate(allocator, (void *)cf); - } -#else - CFAllocatorDeallocate(allocator, (void *)cf); -#endif - if (kCFAllocatorSystemDefault != allocator) { - CFRelease(allocator); - } - } - } else { - if (__builtin_expect(0x8000 == lowBits, 0)) { - // Time to remove a bit from the external ref count - if (0 == _CFDictionaryDecrementValue(__CFRuntimeExternRefCountTable, DISGUISE(cf))) { - lowBits = 0x07fff; - } else { - lowBits = 0x0ffff; - } - } else { - lowBits--; - } - ((CFRuntimeBase *)cf)->_rc = lowBits; - __CFSpinUnlock(&__CFGlobalRetainLock); - if (__builtin_expect(__CFOASafe, 0)) { - uint64_t compositeRC; - compositeRC = (lowBits & 0x7fff) + ((uint64_t)(uintptr_t)CFDictionaryGetValue(__CFRuntimeExternRefCountTable, DISGUISE(cf)) << 15); - if (compositeRC > (uint64_t)0x7fffffff) compositeRC = (uint64_t)0x7fffffff; - __CFRecordAllocationEvent(__kCFReleaseEvent, (void *)cf, 0, compositeRC, NULL); - } - } -} - -#undef DO_SYSCALL_TRACE_HELPERS -#undef SYSCALL_TRACE -#undef __kCFAllocatorTypeID_CONST -#undef __CFGenericAssertIsCF diff --git a/Base.subproj/CFSortFunctions.c b/Base.subproj/CFSortFunctions.c deleted file mode 100644 index 5596ac1..0000000 --- a/Base.subproj/CFSortFunctions.c +++ /dev/null @@ -1,831 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFSortFunctions.c - Copyright 1999-2002, Apple, Inc. All rights reserved. - Responsibility: Christopher Kane -*/ - -/* This file contains code copied from the Libc project's files - qsort.c, merge.c, and heapsort.c, and modified to suit the - needs of CF, which needs the comparison callback to have an - additional parameter. The code is collected into this one - file so that the individual BSD sort routines can remain - private and static. We may not keep the bsd functions - separate eventually. -*/ - -#include -#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__) -#include -#else -#define EINVAL 22 -#endif -#include -#include -#include -#include -#include "CFInternal.h" - -static int bsd_mergesort(void *base, int nmemb, int size, CFComparatorFunction cmp, void *context); - -/* Comparator is passed the address of the values. */ -void CFMergeSortArray(void *list, CFIndex count, CFIndex elementSize, CFComparatorFunction comparator, void *context) { - bsd_mergesort(list, count, elementSize, comparator, context); -} - -#if 0 -// non-recursing qsort with side index list which is the actual thing sorted -// XXX kept here for possible later reference -void cjk_big_isort(char *list, int size, int *idx_list, int (*comp)(const void *, const void *, void *), void *context, int lo, int hi) { - int t, idx, idx2; - char *v1; - for (idx = lo + 1; idx < hi + 1; idx++) { - t = idx_list[idx]; - v1 = list + t * size; - for (idx2 = idx; lo < idx2 && (comp(v1, list + idx_list[idx2 - 1] * size, context) < 0); idx2--) - idx_list[idx2] = idx_list[idx2 - 1]; - idx_list[idx2] = t; - } -} - -void cjk_big_qsort(char *list, int size, int *idx_list, int (*comp)(const void *, const void *, void *), void *context, int lo, int hi, int *recurse) { - int p, idx, mid, g1, g2, g3, r1, r2; - char *v1, *v2, *v3; - g1 = lo; - g2 = (hi + lo) / 2; //random() % (hi - lo + 1) + lo; - g3 = hi; - v1 = list + idx_list[g1] * size; - v2 = list + idx_list[g2] * size; - v3 = list + idx_list[g3] * size; - if (comp(v1, v2, context) < 0) { - p = comp(v2, v3, context) < 0 ? g2 : (comp(v1, v3, context) < 0 ? g3 : g1); - } else { - p = comp(v2, v3, context) > 0 ? g2 : (comp(v1, v3, context) < 0 ? g1 : g3); - } - if (lo != p) {int t = idx_list[lo]; idx_list[lo] = idx_list[p]; idx_list[p] = t;} - r2 = 1; - v2 = list + idx_list[lo] * size; - for (mid = lo, idx = lo + 1; idx < hi + 1; idx++) { - v1 = list + idx_list[idx] * size; - r1 = comp(v1, v2, context); - r2 = r2 && (0 == r1); - if (r1 < 0) { - mid++; - if (idx != mid) {int t = idx_list[idx]; idx_list[idx] = idx_list[mid]; idx_list[mid] = t;} - } - } - if (lo != mid) {int t = idx_list[lo]; idx_list[lo] = idx_list[mid]; idx_list[mid] = t;} - *recurse = !r2 ? mid : -1; -} - -void cjk_big_sort(char *list, int n, int size, int (*comp)(const void *, const void *, void *), void *context) { - int len = 0, los[40], his[40]; - // 40 is big enough for 2^40 elements, in theory; in practice, much - // lower but still sufficient; should recurse if the 40 limit is hit - int *idx_list = malloc(sizeof(int) * n); - char *tmp_list = malloc(n * size); - int idx; - for (idx = 0; idx < n; idx++) { - idx_list[idx] = idx; - } - los[len] = 0; - his[len++] = n - 1; - while (0 < len) { - int lo, hi; - len--; - lo = los[len]; - hi = his[len]; - if (5 < (hi - lo)) { - int mid; - cjk_big_qsort(list, size, idx_list, comp, context, lo, hi, &mid); - if (0 < mid) { - los[len] = lo; - his[len++] = mid - 1; - los[len] = mid + 1; - his[len++] = hi; - } - } else { - cjk_big_isort(list, size, idx_list, comp, context, lo, hi); - } - } - for (idx = 0; idx < n; idx++) - memmove(tmp_list + idx * size, list + idx_list[idx] * size, size); - memmove(list, tmp_list, n * size); - free(tmp_list); - free(idx_list); -} -#endif - - -/* stdlib.subproj/qsort.c ============================================== */ - -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#if !defined(min) -#define min(a, b) (a) < (b) ? a : b -#endif - -/* - * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". - */ -#define swapcode(TYPE, parmi, parmj, n) { \ - long i = (n) / sizeof (TYPE); \ - register TYPE *pi = (TYPE *) (parmi); \ - register TYPE *pj = (TYPE *) (parmj); \ - do { \ - register TYPE t = *pi; \ - *pi++ = *pj; \ - *pj++ = t; \ - } while (--i > 0); \ -} - -#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ - es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; - -CF_INLINE void -swapfunc(char *a, char *b, int n, int swaptype) { - if(swaptype <= 1) - swapcode(long, a, b, n) - else - swapcode(char, a, b, n) -} - -#define swap(a, b) \ - if (swaptype == 0) { \ - long t = *(long *)(a); \ - *(long *)(a) = *(long *)(b); \ - *(long *)(b) = t; \ - } else \ - swapfunc(a, b, es, swaptype) - -#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) - -CF_INLINE char * -med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *, void *), void *context) { - return cmp(a, b, context) < 0 ? - (cmp(b, c, context) < 0 ? b : (cmp(a, c, context) < 0 ? c : a )) - :(cmp(b, c, context) > 0 ? b : (cmp(a, c, context) < 0 ? a : c )); -} - -/* Comparator is passed the address of the values. */ -void CFQSortArray(void *aVoidStar, CFIndex n, CFIndex es, CFComparatorFunction cmp, void *context) -{ - char *a = (char *)aVoidStar; - char *pa, *pb, *pc, *pd, *pl, *pm, *pn; - int d, r, swaptype, swap_cnt; - -loop: SWAPINIT(a, es); - swap_cnt = 0; - if (n < 7) { - for (pm = a + es; pm < (char *) a + n * es; pm += es) - for (pl = pm; pl > (char *) a && cmp(pl - es, pl, context) > 0; - pl -= es) - swap(pl, pl - es); - return; - } - pm = a + (n / 2) * es; - if (n > 7) { - pl = a; - pn = a + (n - 1) * es; - if (n > 40) { - d = (n / 8) * es; - pl = med3(pl, pl + d, pl + 2 * d, cmp, context); - pm = med3(pm - d, pm, pm + d, cmp, context); - pn = med3(pn - 2 * d, pn - d, pn, cmp, context); - } - pm = med3(pl, pm, pn, cmp, context); - } - swap(a, pm); - pa = pb = a + es; - - pc = pd = a + (n - 1) * es; - for (;;) { - while (pb <= pc && (r = cmp(pb, a, context)) <= 0) { - if (r == 0) { - swap_cnt = 1; - swap(pa, pb); - pa += es; - } - pb += es; - } - while (pb <= pc && (r = cmp(pc, a, context)) >= 0) { - if (r == 0) { - swap_cnt = 1; - swap(pc, pd); - pd -= es; - } - pc -= es; - } - if (pb > pc) - break; - swap(pb, pc); - swap_cnt = 1; - pb += es; - pc -= es; - } - if (swap_cnt == 0) { /* Switch to insertion sort */ - for (pm = a + es; pm < (char *) a + n * es; pm += es) - for (pl = pm; pl > (char *) a && cmp(pl - es, pl, context) > 0; - pl -= es) - swap(pl, pl - es); - return; - } - - pn = a + n * es; - r = min(pa - (char *)a, pb - pa); - vecswap(a, pb - r, r); - r = min(pd - pc, pn - pd - es); - vecswap(pb, pn - r, r); - if ((r = pb - pa) > es) - CFQSortArray(a, r / es, es, cmp, context); - if ((r = pd - pc) > es) { - /* Iterate rather than recurse to save stack space */ - a = pn - r; - n = r / es; - goto loop; - } -/* CFQSortArray(pn - r, r / es, es, cmp, context);*/ -} - -#undef min -#undef swapcode -#undef SWAPINIT -#undef swap -#undef vecswap - -/* stdlib.subproj/mergesort.c ========================================== */ - -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Peter McIlroy. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - - -/* - * Hybrid exponential search/linear search merge sort with hybrid - * natural/pairwise first pass. Requires about .3% more comparisons - * for random data than LSMS with pairwise first pass alone. - * It works for objects as small as two bytes. - */ - -#define NATURAL -#define THRESHOLD 16 /* Best choice for natural merge cut-off. */ - -/* #define NATURAL to get hybrid natural merge. - * (The default is pairwise merging.) - */ - - -#define ISIZE sizeof(int) -#define PSIZE sizeof(uint8_t *) -#define ICOPY_LIST(src, dst, last) \ - do \ - *(int*)dst = *(int*)src, src += ISIZE, dst += ISIZE; \ - while(src < last) -#define ICOPY_ELT(src, dst, i) \ - do \ - *(int*) dst = *(int*) src, src += ISIZE, dst += ISIZE; \ - while (i -= ISIZE) - -#define CCOPY_LIST(src, dst, last) \ - do \ - *dst++ = *src++; \ - while (src < last) -#define CCOPY_ELT(src, dst, i) \ - do \ - *dst++ = *src++; \ - while (i -= 1) - -/* - * Find the next possible pointer head. (Trickery for forcing an array - * to do double duty as a linked list when objects do not align with word - * boundaries. - */ -/* Assumption: PSIZE is a power of 2. */ -#define EVAL(p) (uint8_t **) \ - ((uint8_t *)0 + \ - (((uint8_t *)p + PSIZE - 1 - (uint8_t *) 0) & ~(PSIZE - 1))) - - -#define swap(a, b) { \ - s = b; \ - i = size; \ - do { \ - tmp = *a; *a++ = *s; *s++ = tmp; \ - } while (--i); \ - a -= size; \ - } -#define reverse(bot, top) { \ - s = top; \ - do { \ - i = size; \ - do { \ - tmp = *bot; *bot++ = *s; *s++ = tmp; \ - } while (--i); \ - s -= size2; \ - } while(bot < s); \ -} - -/* - * This is to avoid out-of-bounds addresses in sorting the - * last 4 elements. - */ -static void -insertionsort(char *a, int n, int size, int (*cmp)(const void *, const void *, void *), void *context) { - char *ai, *s, *t, *u, tmp; - int i; - - for (ai = a+size; --n >= 1; ai += size) - for (t = ai; t > a; t -= size) { - u = t - size; - if (cmp(u, t, context) <= 0) - break; - swap(u, t); - } -} - -/* - * Optional hybrid natural/pairwise first pass. Eats up list1 in runs of - * increasing order, list2 in a corresponding linked list. Checks for runs - * when THRESHOLD/2 pairs compare with same sense. (Only used when NATURAL - * is defined. Otherwise simple pairwise merging is used.) - */ -static void -setup(char *list1, char *list2, int n, int size, int (*cmp)(const void *, const void *, void *), void *context) { - int i, length, size2, tmp, sense; - char *f1, *f2, *s, *l2, *last, *p2; - - size2 = size*2; - if (n <= 5) { - insertionsort(list1, n, size, cmp, context); - *EVAL(list2) = (uint8_t*) list2 + n*size; - return; - } - /* - * Avoid running pointers out of bounds; limit n to evens - * for simplicity. - */ - i = 4 + (n & 1); - insertionsort(list1 + (n - i) * size, i, size, cmp, context); - last = list1 + size * (n - i); - *EVAL(list2 + (last - list1)) = list2 + n * size; - -#ifdef NATURAL - p2 = list2; - f1 = list1; - sense = (cmp(f1, f1 + size, context) > 0); - for (; f1 < last; sense = !sense) { - length = 2; - /* Find pairs with same sense. */ - for (f2 = f1 + size2; f2 < last; f2 += size2) { - if ((cmp(f2, f2+ size, context) > 0) != sense) - break; - length += 2; - } - if (length < THRESHOLD) { /* Pairwise merge */ - do { - p2 = *EVAL(p2) = f1 + size2 - list1 + list2; - if (sense > 0) - swap (f1, f1 + size); - } while ((f1 += size2) < f2); - } else { /* Natural merge */ - l2 = f2; - for (f2 = f1 + size2; f2 < l2; f2 += size2) { - if ((cmp(f2-size, f2, context) > 0) != sense) { - p2 = *EVAL(p2) = f2 - list1 + list2; - if (sense > 0) - reverse(f1, f2-size); - f1 = f2; - } - } - if (sense > 0) - reverse (f1, f2-size); - f1 = f2; - if (f2 < last || cmp(f2 - size, f2, context) > 0) - p2 = *EVAL(p2) = f2 - list1 + list2; - else - p2 = *EVAL(p2) = list2 + n*size; - } - } -#else /* pairwise merge only. */ - for (f1 = list1, p2 = list2; f1 < last; f1 += size2) { - p2 = *EVAL(p2) = p2 + size2; - if (cmp (f1, f1 + size, context) > 0) - swap(f1, f1 + size); - } -#endif /* NATURAL */ -} - -/* - * Arguments are as for qsort. - */ -static int -bsd_mergesort(void *base, int nmemb, int size, CFComparatorFunction cmp, void *context) { - register int i, sense; - int big, iflag; - register uint8_t *f1, *f2, *t, *b, *tp2, *q, *l1, *l2; - uint8_t *list2, *list1, *p2, *p, *last, **p1; - - if (size < (int)PSIZE / 2) { /* Pointers must fit into 2 * size. */ - errno = EINVAL; - return (-1); - } - - /* - * XXX - * Stupid subtraction for the Cray. - */ - iflag = 0; - if (!(size % ISIZE) && !(((char *)base - (char *)0) % ISIZE)) - iflag = 1; - - if ((list2 = malloc(nmemb * size + PSIZE)) == NULL) - return (-1); - - list1 = base; - setup(list1, list2, nmemb, size, cmp, context); - last = list2 + nmemb * size; - i = big = 0; - while (*EVAL(list2) != last) { - l2 = list1; - p1 = EVAL(list1); - for (tp2 = p2 = list2; p2 != last; p1 = EVAL(l2)) { - p2 = *EVAL(p2); - f1 = l2; - f2 = l1 = list1 + (p2 - list2); - if (p2 != last) - p2 = *EVAL(p2); - l2 = list1 + (p2 - list2); - while (f1 < l1 && f2 < l2) { - if ((*cmp)(f1, f2, context) <= 0) { - q = f2; - b = f1, t = l1; - sense = -1; - } else { - q = f1; - b = f2, t = l2; - sense = 0; - } - if (!big) { /* here i = 0 */ -/* LINEAR: */ while ((b += size) < t && cmp(q, b, context) >sense) - if (++i == 6) { - big = 1; - goto EXPONENTIAL; - } - } else { -EXPONENTIAL: for (i = size; ; i <<= 1) - if ((p = (b + i)) >= t) { - if ((p = t - size) > b && - (*cmp)(q, p, context) <= sense) - t = p; - else - b = p; - break; - } else if ((*cmp)(q, p, context) <= sense) { - t = p; - if (i == size) - big = 0; - goto FASTCASE; - } else - b = p; -/* SLOWCASE: */ while (t > b+size) { - i = (((t - b) / size) >> 1) * size; - if ((*cmp)(q, p = b + i, context) <= sense) - t = p; - else - b = p; - } - goto COPY; -FASTCASE: while (i > size) - if ((*cmp)(q, - p = b + (i >>= 1), context) <= sense) - t = p; - else - b = p; -COPY: b = t; - } - i = size; - if (q == f1) { - if (iflag) { - ICOPY_LIST(f2, tp2, b); - ICOPY_ELT(f1, tp2, i); - } else { - CCOPY_LIST(f2, tp2, b); - CCOPY_ELT(f1, tp2, i); - } - } else { - if (iflag) { - ICOPY_LIST(f1, tp2, b); - ICOPY_ELT(f2, tp2, i); - } else { - CCOPY_LIST(f1, tp2, b); - CCOPY_ELT(f2, tp2, i); - } - } - } - if (f2 < l2) { - if (iflag) - ICOPY_LIST(f2, tp2, l2); - else - CCOPY_LIST(f2, tp2, l2); - } else if (f1 < l1) { - if (iflag) - ICOPY_LIST(f1, tp2, l1); - else - CCOPY_LIST(f1, tp2, l1); - } - *p1 = l2; - } - tp2 = list1; /* swap list1, list2 */ - list1 = list2; - list2 = tp2; - last = list2 + nmemb*size; - } - if (base == list2) { - memmove(list2, list1, nmemb*size); - list2 = list1; - } - free(list2); - return (0); -} - -#undef NATURAL -#undef THRESHOLD -#undef ISIZE -#undef PSIZE -#undef ICOPY_LIST -#undef ICOPY_ELT -#undef CCOPY_LIST -#undef CCOPY_ELT -#undef EVAL -#undef swap -#undef reverse - -#if 0 -/* stdlib.subproj/heapsort.c =========================================== */ - -/* - * Copyright (c) 1991, 1993 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Ronnie Kon at Mindcraft Inc., Kevin Lew and Elmer Yglesias. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * Swap two areas of size number of bytes. Although qsort(3) permits random - * blocks of memory to be sorted, sorting pointers is almost certainly the - * common case (and, were it not, could easily be made so). Regardless, it - * isn't worth optimizing; the SWAP's get sped up by the cache, and pointer - * arithmetic gets lost in the time required for comparison function calls. - */ -#define SWAP(a, b, count, size, tmp) { \ - count = size; \ - do { \ - tmp = *a; \ - *a++ = *b; \ - *b++ = tmp; \ - } while (--count); \ -} - -/* Copy one block of size size to another. */ -#define COPY(a, b, count, size, tmp1, tmp2) { \ - count = size; \ - tmp1 = a; \ - tmp2 = b; \ - do { \ - *tmp1++ = *tmp2++; \ - } while (--count); \ -} - -/* - * Build the list into a heap, where a heap is defined such that for - * the records K1 ... KN, Kj/2 >= Kj for 1 <= j/2 <= j <= N. - * - * There two cases. If j == nmemb, select largest of Ki and Kj. If - * j < nmemb, select largest of Ki, Kj and Kj+1. - */ -#define CREATE(initval, nmemb, par_i, child_i, par, child, size, count, tmp) { \ - for (par_i = initval; (child_i = par_i * 2) <= nmemb; \ - par_i = child_i) { \ - child = base + child_i * size; \ - if (child_i < nmemb && compar(child, child + size, context) < 0) { \ - child += size; \ - ++child_i; \ - } \ - par = base + par_i * size; \ - if (compar(child, par, context) <= 0) \ - break; \ - SWAP(par, child, count, size, tmp); \ - } \ -} - -/* - * Select the top of the heap and 'heapify'. Since by far the most expensive - * action is the call to the compar function, a considerable optimization - * in the average case can be achieved due to the fact that k, the displaced - * elememt, is ususally quite small, so it would be preferable to first - * heapify, always maintaining the invariant that the larger child is copied - * over its parent's record. - * - * Then, starting from the *bottom* of the heap, finding k's correct place, - * again maintianing the invariant. As a result of the invariant no element - * is 'lost' when k is assigned its correct place in the heap. - * - * The time savings from this optimization are on the order of 15-20% for the - * average case. See Knuth, Vol. 3, page 158, problem 18. - * - * XXX Don't break the #define SELECT line, below. Reiser cpp gets upset. - */ -#define SELECT(par_i, child_i, nmemb, par, child, size, k, count, tmp1, tmp2) { \ - for (par_i = 1; (child_i = par_i * 2) <= nmemb; par_i = child_i) { \ - child = base + child_i * size; \ - if (child_i < nmemb && compar(child, child + size, context) < 0) { \ - child += size; \ - ++child_i; \ - } \ - par = base + par_i * size; \ - COPY(par, child, count, size, tmp1, tmp2); \ - } \ - for (;;) { \ - child_i = par_i; \ - par_i = child_i / 2; \ - child = base + child_i * size; \ - par = base + par_i * size; \ - if (child_i == 1 || compar(k, par, context) < 0) { \ - COPY(child, k, count, size, tmp1, tmp2); \ - break; \ - } \ - COPY(child, par, count, size, tmp1, tmp2); \ - } \ -} - -/* - * Heapsort -- Knuth, Vol. 3, page 145. Runs in O (N lg N), both average - * and worst. While heapsort is faster than the worst case of quicksort, - * the BSD quicksort does median selection so that the chance of finding - * a data set that will trigger the worst case is nonexistent. Heapsort's - * only advantage over quicksort is that it requires little additional memory. - */ -static int -bsd_heapsort(void *vbase, int nmemb, int size, int (*compar)(const void *, const void *, void *), void *context) { - register int cnt, i, j, l; - register char tmp, *tmp1, *tmp2; - char *base, *k, *p, *t; - - if (nmemb <= 1) - return (0); - - if (!size) { - errno = EINVAL; - return (-1); - } - - if ((k = malloc(size)) == NULL) - return (-1); - - /* - * Items are numbered from 1 to nmemb, so offset from size bytes - * below the starting address. - */ - base = (char *)vbase - size; - - for (l = nmemb / 2 + 1; --l;) - CREATE(l, nmemb, i, j, t, p, size, cnt, tmp); - - /* - * For each element of the heap, save the largest element into its - * final slot, save the displaced element (k), then recreate the - * heap. - */ - while (nmemb > 1) { - COPY(k, base + nmemb * size, cnt, size, tmp1, tmp2); - COPY(base + nmemb * size, base + size, cnt, size, tmp1, tmp2); - --nmemb; - SELECT(i, j, nmemb, t, p, size, k, cnt, tmp1, tmp2); - } - free(k); - return (0); -} - -#undef SWAP -#undef COPY -#undef CREATE -#undef SELECT - -#endif - -/* ===================================================================== */ - -#undef EINVAL - diff --git a/Base.subproj/CFUtilities.c b/Base.subproj/CFUtilities.c deleted file mode 100644 index fed064f..0000000 --- a/Base.subproj/CFUtilities.c +++ /dev/null @@ -1,550 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFUtilities.c - Copyright 1998-2002, Apple, Inc. All rights reserved. - Responsibility: Christopher Kane -*/ - -#include "CFUtilitiesPriv.h" -#include "CFInternal.h" -#include "CFPriv.h" -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__MACH__) - #include - #include - #include - #include - #include - #include - #include - #include -#endif -#if defined(__WIN32__) - #include - #include -#endif -#if defined(__LINUX__) || defined(__FREEBSD__) - #include - #include -#endif - -#define LESS16(A, W) do { if (A < ((uint64_t)1 << (W))) LESS8(A, (W) - 8); LESS8(A, (W) + 8); } while (0) -#define LESS8(A, W) do { if (A < ((uint64_t)1 << (W))) LESS4(A, (W) - 4); LESS4(A, (W) + 4); } while (0) -#define LESS4(A, W) do { if (A < ((uint64_t)1 << (W))) LESS2(A, (W) - 2); LESS2(A, (W) + 2); } while (0) -#define LESS2(A, W) do { if (A < ((uint64_t)1 << (W))) LESS1(A, (W) - 1); LESS1(A, (W) + 1); } while (0) -#define LESS1(A, W) do { if (A < ((uint64_t)1 << (W))) return (W) - 1; return (W); } while (0) - -uint32_t CFLog2(uint64_t x) { - if (x < ((uint64_t)1 << 32)) - LESS16(x, 16); - LESS16(x, 48); - return 0; -} - -#if 0 -// faster version for PPC -int Lg2d(unsigned x) { -// use PPC-specific instruction to count leading zeros - int ret; - if (0 == x) return 0; - __asm__ volatile("cntlzw %0,%1" : "=r" (ret) : "r" (x)); - return 31 - ret; -} -#endif - -#undef LESS1 -#undef LESS2 -#undef LESS4 -#undef LESS8 -#undef LESS16 - -/* Comparator is passed the address of the values. */ -/* Binary searches a sorted-increasing array of some type. - Return value is either 1) the index of the element desired, - if the target value exists in the list, 2) greater than or - equal to count, if the element is greater than all the values - in the list, or 3) the index of the element greater than the - target value. - - For example, a search in the list of integers: - 2 3 5 7 11 13 17 - - For... Will Return... - 2 0 - 5 2 - 23 7 - 1 0 - 9 4 - - For instance, if you just care about found/not found: - index = CFBSearch(list, count, elem); - if (count <= index || list[index] != elem) { - * Not found * - } else { - * Found * - } - - This isn't optimal yet. -*/ -__private_extern__ CFIndex CFBSearch(const void *element, CFIndex elementSize, const void *list, CFIndex count, CFComparatorFunction comparator, void *context) { - SInt32 idx, lg; - const char *ptr = (const char *)list; - if (count < 4) { - switch (count) { - case 3: if (comparator(ptr + elementSize * 2, element, context) < 0) return 3; - case 2: if (comparator(ptr + elementSize * 1, element, context) < 0) return 2; - case 1: if (comparator(ptr + elementSize * 0, element, context) < 0) return 1; - } - return 0; - } - if (comparator(ptr + elementSize * (count - 1), element, context) < 0) return count; - if (comparator(element, ptr + elementSize * 0, context) < 0) return 0; - lg = CFLog2(count); /* This takes about 1/3rd of the time, discounting calls to comparator */ - idx = (comparator(ptr + elementSize * (-1 + (1 << lg)), element, context) < 0) ? count - (1 << lg) : -1; - switch (--lg) { - case 30: if (comparator(ptr + elementSize * (idx + (1 << 30)), element, context) < 0) idx += (1 << 30); - case 29: if (comparator(ptr + elementSize * (idx + (1 << 29)), element, context) < 0) idx += (1 << 29); - case 28: if (comparator(ptr + elementSize * (idx + (1 << 28)), element, context) < 0) idx += (1 << 28); - case 27: if (comparator(ptr + elementSize * (idx + (1 << 27)), element, context) < 0) idx += (1 << 27); - case 26: if (comparator(ptr + elementSize * (idx + (1 << 26)), element, context) < 0) idx += (1 << 26); - case 25: if (comparator(ptr + elementSize * (idx + (1 << 25)), element, context) < 0) idx += (1 << 25); - case 24: if (comparator(ptr + elementSize * (idx + (1 << 24)), element, context) < 0) idx += (1 << 24); - case 23: if (comparator(ptr + elementSize * (idx + (1 << 23)), element, context) < 0) idx += (1 << 23); - case 22: if (comparator(ptr + elementSize * (idx + (1 << 22)), element, context) < 0) idx += (1 << 22); - case 21: if (comparator(ptr + elementSize * (idx + (1 << 21)), element, context) < 0) idx += (1 << 21); - case 20: if (comparator(ptr + elementSize * (idx + (1 << 20)), element, context) < 0) idx += (1 << 20); - case 19: if (comparator(ptr + elementSize * (idx + (1 << 19)), element, context) < 0) idx += (1 << 19); - case 18: if (comparator(ptr + elementSize * (idx + (1 << 18)), element, context) < 0) idx += (1 << 18); - case 17: if (comparator(ptr + elementSize * (idx + (1 << 17)), element, context) < 0) idx += (1 << 17); - case 16: if (comparator(ptr + elementSize * (idx + (1 << 16)), element, context) < 0) idx += (1 << 16); - case 15: if (comparator(ptr + elementSize * (idx + (1 << 15)), element, context) < 0) idx += (1 << 15); - case 14: if (comparator(ptr + elementSize * (idx + (1 << 14)), element, context) < 0) idx += (1 << 14); - case 13: if (comparator(ptr + elementSize * (idx + (1 << 13)), element, context) < 0) idx += (1 << 13); - case 12: if (comparator(ptr + elementSize * (idx + (1 << 12)), element, context) < 0) idx += (1 << 12); - case 11: if (comparator(ptr + elementSize * (idx + (1 << 11)), element, context) < 0) idx += (1 << 11); - case 10: if (comparator(ptr + elementSize * (idx + (1 << 10)), element, context) < 0) idx += (1 << 10); - case 9: if (comparator(ptr + elementSize * (idx + (1 << 9)), element, context) < 0) idx += (1 << 9); - case 8: if (comparator(ptr + elementSize * (idx + (1 << 8)), element, context) < 0) idx += (1 << 8); - case 7: if (comparator(ptr + elementSize * (idx + (1 << 7)), element, context) < 0) idx += (1 << 7); - case 6: if (comparator(ptr + elementSize * (idx + (1 << 6)), element, context) < 0) idx += (1 << 6); - case 5: if (comparator(ptr + elementSize * (idx + (1 << 5)), element, context) < 0) idx += (1 << 5); - case 4: if (comparator(ptr + elementSize * (idx + (1 << 4)), element, context) < 0) idx += (1 << 4); - case 3: if (comparator(ptr + elementSize * (idx + (1 << 3)), element, context) < 0) idx += (1 << 3); - case 2: if (comparator(ptr + elementSize * (idx + (1 << 2)), element, context) < 0) idx += (1 << 2); - case 1: if (comparator(ptr + elementSize * (idx + (1 << 1)), element, context) < 0) idx += (1 << 1); - case 0: if (comparator(ptr + elementSize * (idx + (1 << 0)), element, context) < 0) idx += (1 << 0); - } - return ++idx; -} - - -#define ELF_STEP(B) T1 = (H << 4) + B; T2 = T1 & 0xF0000000; if (T2) T1 ^= (T2 >> 24); T1 &= (~T2); H = T1; - -CFHashCode CFHashBytes(uint8_t *bytes, CFIndex length) { - /* The ELF hash algorithm, used in the ELF object file format */ - UInt32 H = 0, T1, T2; - SInt32 rem = length; - while (3 < rem) { - ELF_STEP(bytes[length - rem]); - ELF_STEP(bytes[length - rem + 1]); - ELF_STEP(bytes[length - rem + 2]); - ELF_STEP(bytes[length - rem + 3]); - rem -= 4; - } - switch (rem) { - case 3: ELF_STEP(bytes[length - 3]); - case 2: ELF_STEP(bytes[length - 2]); - case 1: ELF_STEP(bytes[length - 1]); - case 0: ; - } - return H; -} - -#undef ELF_STEP - -#if defined(__WIN32__) -struct _args { - void *func; - void *arg; - HANDLE handle; -}; -static __stdcall unsigned __CFWinThreadFunc(void *arg) { - struct _args *args = arg; - ((void (*)(void *))args->func)(args->arg); - CloseHandle(args->handle); - CFAllocatorDeallocate(kCFAllocatorSystemDefault, arg); - _endthreadex(0); - return 0; -} -#endif - -__private_extern__ void *__CFStartSimpleThread(void *func, void *arg) { -#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__) - pthread_attr_t attr; - pthread_t tid; - pthread_attr_init(&attr); - pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_attr_setstacksize(&attr, 60 * 1024); // 60K stack for our internal threads is sufficient - pthread_create(&tid, &attr, func, arg); - pthread_attr_destroy(&attr); -//warning CF: we dont actually know that a pthread_t is the same size as void * - return (void *)tid; -#else - unsigned tid; - struct _args *args = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct _args), 0); - if (__CFOASafe) __CFSetLastAllocationEventName(args, "CFUtilities (thread-args)"); - HANDLE handle; - args->func = func; - args->arg = arg; - /* The thread is created suspended, because otherwise there would be a race between the assignment below of the handle field, and it's possible use in the thread func above. */ - args->handle = (HANDLE)_beginthreadex(NULL, 0, (void *)__CFWinThreadFunc, args, CREATE_SUSPENDED, &tid); - handle = args->handle; - ResumeThread(handle); - return handle; -#endif -} - -__private_extern__ CFStringRef _CFCreateLimitedUniqueString() { - /* this unique string is only unique to the current host during the current boot */ - uint64_t tsr = __CFReadTSR(); - UInt32 tsrh = (tsr >> 32), tsrl = (tsr & (int64_t)0xFFFFFFFF); - return CFStringCreateWithFormat(NULL, NULL, CFSTR("CFUniqueString-%lu%lu$"), tsrh, tsrl); -} - - -// Looks for localized version of "nonLocalized" in the SystemVersion bundle -// If not found, and returnNonLocalizedFlag == true, will return the non localized string (retained of course), otherwise NULL -// If bundlePtr != NULL, will use *bundlePtr and will return the bundle in there; otherwise bundle is created and released - -static CFStringRef _CFCopyLocalizedVersionKey(CFBundleRef *bundlePtr, CFStringRef nonLocalized) { - CFStringRef localized = NULL; - CFBundleRef locBundle = bundlePtr ? *bundlePtr : NULL; - if (!locBundle) { - CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR("/System/Library/CoreServices/SystemVersion.bundle"), kCFURLPOSIXPathStyle, false); - if (url) { - locBundle = CFBundleCreate(kCFAllocatorDefault, url); - CFRelease(url); - } - } - if (locBundle) { - localized = CFBundleCopyLocalizedString(locBundle, nonLocalized, nonLocalized, CFSTR("SystemVersion")); - if (bundlePtr) *bundlePtr = locBundle; else CFRelease(locBundle); - } - return localized ? localized : CFRetain(nonLocalized); -} - -static CFDictionaryRef _CFCopyVersionDictionary(CFStringRef path) { - CFPropertyListRef plist = NULL; - CFDataRef data; - CFURLRef url; - - url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, false); - if (url && CFURLCreateDataAndPropertiesFromResource(kCFAllocatorDefault, url, &data, NULL, NULL, NULL)) { - plist = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListMutableContainers, NULL); - CFRelease(data); - } - if (url) CFRelease(url); - - if (plist) { - CFBundleRef locBundle = NULL; - CFStringRef fullVersion, vers, versExtra, build; - CFStringRef versionString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionProductVersionStringKey); - CFStringRef buildString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionBuildStringKey); - CFStringRef fullVersionString = _CFCopyLocalizedVersionKey(&locBundle, CFSTR("FullVersionString")); - if (locBundle) CFRelease(locBundle); - - // Now build the full version string - if (CFEqual(fullVersionString, CFSTR("FullVersionString"))) { - CFRelease(fullVersionString); - fullVersionString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ %%@ (%@ %%@)"), versionString, buildString); - } - vers = CFDictionaryGetValue(plist, _kCFSystemVersionProductVersionKey); - versExtra = CFDictionaryGetValue(plist, _kCFSystemVersionProductVersionExtraKey); - if (vers && versExtra) vers = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@ %@"), vers, versExtra); - build = CFDictionaryGetValue(plist, _kCFSystemVersionBuildVersionKey); - fullVersion = CFStringCreateWithFormat(NULL, NULL, fullVersionString, (vers ? vers : CFSTR("?")), build ? build : CFSTR("?")); - if (vers && versExtra) CFRelease(vers); - - CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionProductVersionStringKey, versionString); - CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionBuildStringKey, buildString); - CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR("FullVersionString"), fullVersion); - CFRelease(versionString); - CFRelease(buildString); - CFRelease(fullVersionString); - CFRelease(fullVersion); - } - return plist; -} - -CFStringRef CFCopySystemVersionString(void) { - CFStringRef versionString; - CFDictionaryRef dict = _CFCopyServerVersionDictionary(); - if (!dict) dict = _CFCopySystemVersionDictionary(); - versionString = CFDictionaryGetValue(dict, CFSTR("FullVersionString")); - if (versionString) CFRetain(versionString); - CFRelease(dict); - return versionString; -} - -// Obsolete: These two functions cache the dictionaries to avoid calling _CFCopyVersionDictionary() more than once per dict desired -// In fact, they do not cache any more, because the file can change after -// apps are running in some situations, and apps need the new info. -// Proper caching and testing to see if the file has changed, without race -// conditions, would require semi-convoluted use of fstat(). - -CFDictionaryRef _CFCopySystemVersionDictionary(void) { - CFPropertyListRef plist = NULL; - plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/SystemVersion.plist")); - return plist; -} - -CFDictionaryRef _CFCopyServerVersionDictionary(void) { - CFPropertyListRef plist = NULL; - plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/ServerVersion.plist")); - return plist; -} - -CONST_STRING_DECL(_kCFSystemVersionProductNameKey, "ProductName") -CONST_STRING_DECL(_kCFSystemVersionProductCopyrightKey, "ProductCopyright") -CONST_STRING_DECL(_kCFSystemVersionProductVersionKey, "ProductVersion") -CONST_STRING_DECL(_kCFSystemVersionProductVersionExtraKey, "ProductVersionExtra") -CONST_STRING_DECL(_kCFSystemVersionProductUserVisibleVersionKey, "ProductUserVisibleVersion") -CONST_STRING_DECL(_kCFSystemVersionBuildVersionKey, "ProductBuildVersion") -CONST_STRING_DECL(_kCFSystemVersionProductVersionStringKey, "Version") -CONST_STRING_DECL(_kCFSystemVersionBuildStringKey, "Build") - -#if defined(__MACH__) - -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; -} - - -/* -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 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[version] = ((vers < versionInfo[version].VERSIONFIELD) ? false : true)); } - -CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) { - // The numbers in the below table should be the numbers for any version of the framework in the release. - // When adding new entries to this table 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, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}, /* CFSystemVersionTiger */ - {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}, /* CFSystemVersionChablis */ - }; - 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 */ - if (results[version] != -2) return results[version]; - - if (_CFIsCFM()) { - results[version] = (version <= CFSystemVersionJaguar) ? true : false; - return results[version]; - } - - 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); - - /* 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; -} -#endif - - -__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); - } - void *dyfunc = NULL; - if (image) { - dyfunc = dlsym(image, name); - } - return dyfunc; -} - -__private_extern__ void *__CFLookupCFNetworkFunction(const char *name) { - static void *image = NULL; - if (NULL == image) { - image = dlopen("/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CFNetwork.framework/Versions/A/CFNetwork", RTLD_LAZY | RTLD_LOCAL); - } - void *dyfunc = NULL; - if (image) { - dyfunc = dlsym(image, name); - } - return dyfunc; -} - - - -static void _CFShowToFile(FILE *file, Boolean flush, const void *obj) { - CFStringRef str; - CFIndex idx, cnt; - CFStringInlineBuffer buffer; - bool lastNL = false; - - if (obj) { - if (CFGetTypeID(obj) == CFStringGetTypeID()) { - // Makes Ali marginally happier - str = __CFCopyFormattingDescription(obj, NULL); - if (!str) str = CFCopyDescription(obj); - } else { - str = CFCopyDescription(obj); - } - } else { - str = CFRetain(CFSTR("(null)")); - } - cnt = CFStringGetLength(str); - - // iTunes used OutputDebugStringW(theString); - - CFStringInitInlineBuffer(str, &buffer, CFRangeMake(0, cnt)); - for (idx = 0; idx < cnt; idx++) { - UniChar ch = __CFStringGetCharacterFromInlineBufferQuick(&buffer, idx); - if (ch < 128) { - fprintf(file, "%c", ch); - lastNL = (ch == '\n'); - } else { - fprintf(file, "\\u%04x", ch); - } - } - if (!lastNL) { - fprintf(file, "\n"); - if (flush) fflush(file); - } - - if (str) CFRelease(str); -} - -void CFShow(const void *obj) { - _CFShowToFile(stderr, true, obj); -} - -static CFGregorianDate gregorianDate(void) { - CFTimeZoneRef tz = CFTimeZoneCopySystem(); // specifically choose system time zone for logs - CFGregorianDate gdate = CFAbsoluteTimeGetGregorianDate(CFAbsoluteTimeGetCurrent(), tz); - CFRelease(tz); - gdate.second = gdate.second + 0.0005; - return gdate; -} - -void CFLog(int p, CFStringRef format, ...) { - CFStringRef result; - va_list argList; - static CFSpinLock_t lock = 0; - - va_start(argList, format); - result = CFStringCreateWithFormatAndArguments(NULL, NULL, format, argList); - va_end(argList); - - __CFSpinLock(&lock); -#if defined(__WIN32__) - fprintf(stderr, "*** %s[%ld] CFLog(%d): ", *_CFGetProgname(), GetCurrentProcessId(), p); -#else - CFGregorianDate gdate = gregorianDate(); - // Date format: YYYY '-' MM '-' DD ' ' hh ':' mm ':' ss.fff - fprintf_l(stderr, NULL, "%04d-%02d-%02d %02d:%02d:%06.3f %s[%d] CFLog (%d): ", (int)gdate.year, gdate.month, gdate.day, gdate.hour, gdate.minute, gdate.second, *_CFGetProgname(), getpid(), p); -#endif - - CFShow(result); - __CFSpinUnlock(&lock); - CFRelease(result); -} - - diff --git a/Base.subproj/CFUtilities.h b/Base.subproj/CFUtilities.h deleted file mode 100644 index 81130d8..0000000 --- a/Base.subproj/CFUtilities.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFUtilities.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. -*/ - -#if !defined(__COREFOUNDATION_CFUTILITIES__) -#define __COREFOUNDATION_CFUTILITIES__ 1 - -#include - -#if defined(__cplusplus) -extern "C" { -#endif - -/* -Only hits in Panther sources on this file: -./DisplayServices/O3Manager/O3Master.m:#import -./HIServices/CoreDrag.subproj/DragManager.c:#include -./HIToolbox/Menus/Source/MenuEvents.cp:#include -./WebBrowser/BugReportController.m:#import - - -lore% grep '\(CFLog2\|CFMergeSortArray\|CFQSortArray\|CFLibraryVersion\|primaryVersion\|secondaryVersion\|tertiaryVersion\|CFGetExecutableLinkedLibraryVersion\|CFGetExecutingLibraryVersion\|CFSystemVersion\|_CFExecutableLinkedOnOrAfter\)' ./DisplayServices/O3Manager/O3Master.m ./HIServices/CoreDrag.subproj/DragManager.c ./HIToolbox/Menus/Source/MenuEvents.cp ./WebBrowser/BugReportController.m - -./DisplayServices/O3Manager/O3Master.m: if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) -./HIServices/CoreDrag.subproj/DragManager.c: if( _CFExecutableLinkedOnOrAfter( CFSystemVersionJaguar ) && (info->remoteAllowableActions == kCoreDragActionNothing) ) -./HIToolbox/Menus/Source/MenuEvents.cp: if ( _CFExecutableLinkedOnOrAfter( CFSystemVersionPanther ) ) - - -... Other than CF, Foundation, and AppKit of course. - -*/ - - - -CF_EXPORT uint32_t CFLog2(uint64_t x); - -CF_EXPORT void CFMergeSortArray(void *list, CFIndex count, CFIndex elementSize, CFComparatorFunction comparator, void *context); -CF_EXPORT void CFQSortArray(void *list, CFIndex count, CFIndex elementSize, CFComparatorFunction comparator, void *context); - -/* _CFExecutableLinkedOnOrAfter(releaseVersionName) will return YES if the current executable seems to be linked on or after the specified release. Example: If you specify CFSystemVersionPuma (10.1), you will get back true for executables linked on Puma or Jaguar(10.2), but false for those linked on Cheetah (10.0) or any of its software updates (10.0.x). You will also get back false for any app whose version info could not be figured out. - This function caches its results, so no need to cache at call sites. - - Note that for non-MACH this function always returns true. -*/ -typedef enum { - CFSystemVersionCheetah = 0, /* 10.0 */ - 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 */ - CFSystemVersionChablis = 5, /* Post-Tiger */ - CFSystemVersionMax /* This should bump up when new entries are added */ -} CFSystemVersion; - -CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version); - - -#if defined(__cplusplus) -} -#endif - -#endif /* ! __COREFOUNDATION_CFUTILITIES__ */ - diff --git a/Base.subproj/CFUtilitiesPriv.h b/Base.subproj/CFUtilitiesPriv.h deleted file mode 100644 index 5553d91..0000000 --- a/Base.subproj/CFUtilitiesPriv.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFUtilitiesPriv.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. -*/ - -#if !defined(__COREFOUNDATION_CFUTILITIES__) -#define __COREFOUNDATION_CFUTILITIES__ 1 - -#include - -#if defined(__cplusplus) -extern "C" { -#endif - -CF_EXPORT uint32_t CFLog2(uint64_t x); - -CF_EXPORT void CFMergeSortArray(void *list, CFIndex count, CFIndex elementSize, CFComparatorFunction comparator, void *context); -CF_EXPORT void CFQSortArray(void *list, CFIndex count, CFIndex elementSize, CFComparatorFunction comparator, void *context); - -/* _CFExecutableLinkedOnOrAfter(releaseVersionName) will return YES if the current executable seems to be linked on or after the specified release. Example: If you specify CFSystemVersionPuma (10.1), you will get back true for executables linked on Puma or Jaguar(10.2), but false for those linked on Cheetah (10.0) or any of its software updates (10.0.x). You will also get back false for any app whose version info could not be figured out. - This function caches its results, so no need to cache at call sites. - - Note that for non-MACH this function always returns true. -*/ -typedef enum { - CFSystemVersionCheetah = 0, /* 10.0 */ - 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 */ - CFSystemVersionChablis = 5, /* Post-Tiger */ - CFSystemVersionMax /* This should bump up when new entries are added */ -} CFSystemVersion; - -CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version); - - - -#if defined(__cplusplus) -} -#endif - -#endif /* ! __COREFOUNDATION_CFUTILITIES__ */ - diff --git a/Base.subproj/auto_stubs.h b/Base.subproj/auto_stubs.h deleted file mode 100644 index 5eed384..0000000 --- a/Base.subproj/auto_stubs.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* auto_stubs.h - Copyright 2005, Apple, Inc. All rights reserved. -*/ - - -#include -#include - -/* Stubs for functions in libauto used by CoreFoundation. */ - -typedef malloc_zone_t auto_zone_t; -typedef enum { AUTO_OBJECT_SCANNED, AUTO_OBJECT_UNSCANNED, AUTO_MEMORY_SCANNED, AUTO_MEMORY_UNSCANNED } auto_memory_type_t; - -CF_INLINE auto_zone_t *auto_zone(void) { return NULL; } -CF_INLINE void* auto_zone_allocate_object(auto_zone_t *zone, size_t size, auto_memory_type_t type, boolean_t rc, boolean_t clear) { return NULL; } -CF_INLINE const void *auto_zone_base_pointer(auto_zone_t *zone, const void *ptr) { return NULL; } -CF_INLINE void auto_zone_retain(auto_zone_t *zone, void *ptr) {} -CF_INLINE unsigned int auto_zone_release(auto_zone_t *zone, void *ptr) { return 0; } -CF_INLINE unsigned int auto_zone_retain_count(auto_zone_t *zone, const void *ptr) { return 0; } -CF_INLINE void auto_zone_set_layout_type(auto_zone_t *zone, void *ptr, auto_memory_type_t type) {} -CF_INLINE void auto_zone_write_barrier_range(auto_zone_t *zone, void *address, size_t size) {} - diff --git a/Base.subproj/uuid.c b/Base.subproj/uuid.c deleted file mode 100644 index 739396f..0000000 --- a/Base.subproj/uuid.c +++ /dev/null @@ -1,1252 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* uuid.c - Copyright 1999-2002, Apple, Inc. All rights reserved. - Responsibility: Doug Davidson -*/ - -#include -#include -#include "CFInternal.h" -#include "CFUtilitiesPriv.h" -#include - -typedef struct -{ - unsigned char eaddr[6]; /* 6 bytes of ethernet hardware address */ -} uuid_address_t; - -#if defined(__WIN32__) - -static OSErr GetEthernetAddr(uuid_address_t *addr) { - return -1; -} - -#else - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if !defined(MAX) -#define MAX(a, b) ((a) < (b) ? (b) : (a)) -#endif - -#define IFR_NEXT(ifr) \ - ((struct ifreq *) ((char *) (ifr) + sizeof(*(ifr)) + \ - MAX(0, (int) (ifr)->ifr_addr.sa_len - (int) sizeof((ifr)->ifr_addr)))) - -static OSErr GetEthernetAddr(uuid_address_t *addr) { - struct ifconf ifc; - struct ifreq ifrbuf[30], *ifr; - register int s, i; - Boolean foundIt = false; - - if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { - return -1; - } - - ifc.ifc_buf = (caddr_t)ifrbuf; - ifc.ifc_len = sizeof (ifrbuf); - if (ioctl(s, SIOCGIFCONF, &ifc) == -1) { - close(s); - return -1; - } - - for (ifr = (struct ifreq *)ifc.ifc_buf, i=0; (char *)ifr < &ifc.ifc_buf[ifc.ifc_len]; ifr = IFR_NEXT(ifr), i++) { - unsigned char *p, c; - - if (*ifr->ifr_name == '\0') { - continue; - } - /* - * Adapt to buggy kernel implementation (> 9 of a type) - */ - - p = &ifr->ifr_name[strlen(ifr->ifr_name)-1]; - if ((c = *p) > '0'+9) { - snprintf(p, 2, "%d", c-'0'); // at least 3 bytes available here, we hope! - } - - if (strcmp(ifr->ifr_name, "en0") == 0) { - if (ifr->ifr_addr.sa_family == AF_LINK) { - struct sockaddr_dl *sa = ((struct sockaddr_dl *)&ifr->ifr_addr); - if (sa->sdl_type == IFT_ETHER || sa->sdl_type == IFT_FDDI || sa->sdl_type == IFT_ISO88023 || sa->sdl_type == IFT_ISO88024 || sa->sdl_type == IFT_ISO88025) { - for (i=0, p=&sa->sdl_data[sa->sdl_nlen] ; i++ < sa->sdl_alen; p++) { - addr->eaddr[i-1] = *p; - } - foundIt = true; - break; - } - } - } - } - close(s); - return (foundIt ? 0 : -1); -} - -#undef IFR_NEXT - -#endif // __WIN32__ - -__private_extern__ CFStringRef __CFCopyRegularEthernetAddrString(void) { - uuid_address_t addr; - static CFStringRef string = NULL; - static Boolean lookedUpAddr = false; - - if (!lookedUpAddr) { - if (GetEthernetAddr(&addr) == 0) { - string = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"), addr.eaddr[0], addr.eaddr[1], addr.eaddr[2], addr.eaddr[3], addr.eaddr[4], addr.eaddr[5]); - } - lookedUpAddr = true; - } - return (string ? CFRetain(string) : NULL); -} - -__private_extern__ CFStringRef __CFCopyEthernetAddrString(void) { - uuid_address_t addr; - static CFStringRef string = NULL; - static Boolean lookedUpAddr = false; - - if (!lookedUpAddr) { - if (GetEthernetAddr(&addr) == 0) { - string = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%02x%02x%02x%02x%02x%02x"), addr.eaddr[0], addr.eaddr[1], addr.eaddr[2], addr.eaddr[3], addr.eaddr[4], addr.eaddr[5]); - } - lookedUpAddr = true; - } - return (string ? CFRetain(string) : NULL); -} - -#if defined(__WIN32__) -/* _CFGenerateUUID function just calls the COM library's UUID generator - * (Aleksey Dukhnyakov) - */ -#include -#include -#include - -LONG _CFGenerateUUID(uint8_t *uuid_bytes) { - RPC_STATUS rStatus; - - /* call GetScode() function to get RPC_STATUS, because - * CoCreateGuid(uuid) function return HRESULT type - */ - rStatus = GetScode(CoCreateGuid((uuid_t *)uuid_bytes)); - - /* We accept only following results RPC_S_OK, RPC_S_UUID_LOCAL_ONLY - */ - if ( rStatus == RPC_S_UUID_NO_ADDRESS) - return rStatus; - - return 0; -}; - -#else - -/* uuid.c - * - * Modifications made by William Woody to make this thing - * work on the Macintosh. - */ - -/* - * - * (c) Copyright 1989 OPEN SOFTWARE FOUNDATION, INC. - * (c) Copyright 1989 HEWLETT-PACKARD COMPANY - * (c) Copyright 1989 DIGITAL EQUIPMENT CORPORATION - * To anyone who acknowledges that this file is provided "AS IS" - * without any express or implied warranty: - * permission to use, copy, modify, and distribute this - * file for any purpose is hereby granted without fee, provided that - * the above copyright notices and this notice appears in all source - * code copies, and that none of the names of Open Software - * Foundation, Inc., Hewlett-Packard Company, or Digital Equipment - * Corporation be used in advertising or publicity pertaining to - * distribution of the software without specific, written prior - * permission. Neither Open Software Foundation, Inc., Hewlett- - * Packard Company, nor Digital Equipment Corporation makes any - * representations about the suitability of this software for any - * purpose. - * - */ -/* - */ -/* -** -** NAME: -** -** uuid.c -** -** FACILITY: -** -** UUID -** -** ABSTRACT: -** -** UUID - routines that manipulate uuid's -** -** -*/ - - -/* uuid - * - * Universal Unique ID. Note this definition will result is a 16-byte - * structure regardless what platform it is on. - */ - -struct uuid_v1_t { - uint32_t time_low; - uint16_t time_mid; - uint16_t time_hi_and_version; - unsigned char clock_seq_hi_and_reserved; - unsigned char clock_seq_low; - unsigned char node[6]; -}; - -typedef struct uuid_v1_t uuid_v1_t; - -enum { - kUUIDInternalError = -21001, - kUUIDInvalidString = -21002 -}; - -typedef struct { - uint32_t lo; - uint32_t hi; -} uuid_time_t; - -static OSErr GenRandomEthernet(uuid_address_t *addr); -static OSErr ReadPrefData(void); - -/* - * Preferences file management - */ - -static uuid_address_t GSavedENetAddr = {{0, 0, 0, 0, 0, 0}}; -static uuid_time_t GLastTime = {0, 0}; /* Clock state info */ -static uint16_t GTimeAdjust = 0; -static uint16_t GClockSeq = 0; - - -/* - * Internal structure of universal unique IDs (UUIDs). - * - * There are three "variants" of UUIDs that this code knows about. The - * variant #0 is what was defined in the 1989 HP/Apollo Network Computing - * Architecture (NCA) specification and implemented in NCS 1.x and DECrpc - * v1. Variant #1 is what was defined for the joint HP/DEC specification - * for the OSF (in DEC's "UID Architecture Functional Specification Version - * X1.0.4") and implemented in NCS 2.0, DECrpc v2, and OSF 1.0 DCE RPC. - * Variant #2 is defined by Microsoft. - * - * This code creates only variant #1 UUIDs. - * - * The three UUID variants can exist on the same wire because they have - * distinct values in the 3 MSB bits of octet 8 (see table below). Do - * NOT confuse the version number with these 3 bits. (Note the distinct - * use of the terms "version" and "variant".) Variant #0 had no version - * field in it. Changes to variant #1 (should any ever need to be made) - * can be accomodated using the current form's 4 bit version field. - * - * The UUID record structure MUST NOT contain padding between fields. - * The total size = 128 bits. - * - * To minimize confusion about bit assignment within octets, the UUID - * record definition is defined only in terms of fields that are integral - * numbers of octets. - * - * Depending on the network data representation, the multi-octet unsigned - * integer fields are subject to byte swapping when communicated between - * dissimilar endian machines. Note that all three UUID variants have - * the same record structure; this allows this byte swapping to occur. - * (The ways in which the contents of the fields are generated can and - * do vary.) - * - * The following information applies to variant #1 UUIDs: - * - * The lowest addressed octet contains the global/local bit and the - * unicast/multicast bit, and is the first octet of the address transmitted - * on an 802.3 LAN. - * - * The adjusted time stamp is split into three fields, and the clockSeq - * is split into two fields. - * - * |<------------------------- 32 bits -------------------------->| - * - * +--------------------------------------------------------------+ - * | low 32 bits of time | 0-3 .time_low - * +-------------------------------+------------------------------- - * | mid 16 bits of time | 4-5 .time_mid - * +-------+-----------------------+ - * | vers. | hi 12 bits of time | 6-7 .time_hi_and_version - * +-------+-------+---------------+ - * |Res| clkSeqHi | 8 .clock_seq_hi_and_reserved - * +---------------+ - * | clkSeqLow | 9 .clock_seq_low - * +---------------+----------...-----+ - * | node ID | 8-16 .node - * +--------------------------...-----+ - * - * -------------------------------------------------------------------------- - * - * The structure layout of all three UUID variants is fixed for all time. - * I.e., the layout consists of a 32 bit int, 2 16 bit ints, and 8 8 - * bit ints. The current form version field does NOT determine/affect - * the layout. This enables us to do certain operations safely on the - * variants of UUIDs without regard to variant; this increases the utility - * of this code even as the version number changes (i.e., this code does - * NOT need to check the version field). - * - * The "Res" field in the octet #8 is the so-called "reserved" bit-field - * and determines whether or not the uuid is a old, current or other - * UUID as follows: - * - * MS-bit 2MS-bit 3MS-bit Variant - * --------------------------------------------- - * 0 x x 0 (NCS 1.5) - * 1 0 x 1 (DCE 1.0 RPC) - * 1 1 0 2 (Microsoft) - * 1 1 1 unspecified - * - * -------------------------------------------------------------------------- - * - * Internal structure of variant #0 UUIDs - * - * The first 6 octets are the number of 4 usec units of time that have - * passed since 1/1/80 0000 GMT. The next 2 octets are reserved for - * future use. The next octet is an address family. The next 7 octets - * are a host ID in the form allowed by the specified address family. - * - * Note that while the family field (octet 8) was originally conceived - * of as being able to hold values in the range [0..255], only [0..13] - * were ever used. Thus, the 2 MSB of this field are always 0 and are - * used to distinguish old and current UUID forms. - * - * +--------------------------------------------------------------+ - * | high 32 bits of time | 0-3 .time_high - * +-------------------------------+------------------------------- - * | low 16 bits of time | 4-5 .time_low - * +-------+-----------------------+ - * | reserved | 6-7 .reserved - * +---------------+---------------+ - * | family | 8 .family - * +---------------+----------...-----+ - * | node ID | 9-16 .node - * +--------------------------...-----+ - * - */ - -/*************************************************************************** - * - * Local definitions - * - **************************************************************************/ - -static const long uuid_c_version = 1; - -/* - * local defines used in uuid bit-diddling - */ -#define HI_WORD(w) ((w) >> 16) -#define RAND_MASK 0x3fff /* same as CLOCK_SEQ_LAST */ - -#define TIME_MID_MASK 0x0000ffff -#define TIME_HIGH_MASK 0x0fff0000 -#define TIME_HIGH_SHIFT_COUNT 16 - -/* - * The following was modified in order to prevent overlap because - * our clock is (theoretically) accurate to 1us (or 1s in CarbonLib) - */ - - -#define MAX_TIME_ADJUST 9 /* Max adjust before tick */ - -#define CLOCK_SEQ_LOW_MASK 0xff -#define CLOCK_SEQ_HIGH_MASK 0x3f00 -#define CLOCK_SEQ_HIGH_SHIFT_COUNT 8 -#define CLOCK_SEQ_FIRST 1 -#define CLOCK_SEQ_LAST 0x3fff /* same as RAND_MASK */ - -/* - * Note: If CLOCK_SEQ_BIT_BANG == true, then we can avoid the modulo - * operation. This should save us a divide instruction and speed - * things up. - */ - -#ifndef CLOCK_SEQ_BIT_BANG -#define CLOCK_SEQ_BIT_BANG 1 -#endif - -#if CLOCK_SEQ_BIT_BANG -#define CLOCK_SEQ_BUMP(seq) ((*seq) = ((*seq) + 1) & CLOCK_SEQ_LAST) -#else -#define CLOCK_SEQ_BUMP(seq) ((*seq) = ((*seq) + 1) % (CLOCK_SEQ_LAST+1)) -#endif - -#define UUID_VERSION_BITS (uuid_c_version << 12) -#define UUID_RESERVED_BITS 0x80 - -#define IS_OLD_UUID(uuid) (((uuid)->clock_seq_hi_and_reserved & 0xc0) != 0x80) - -/**************************************************************************** - * - * local data declarations - * - ****************************************************************************/ - -typedef struct { - uint32_t lo; - uint32_t hi; -} unsigned64_t; - -/* - * declarations used in UTC time calculations - */ - -static uuid_time_t time_now = {0, 0}; /* utc time as of last query */ -//static uuid_time_t time_last; /* utc time last time I looked */ -//static uint16_t time_adjust; /* 'adjustment' to ensure uniqness */ -//static uint16_t clock_seq; /* 'adjustment' for backwards clocks*/ - -/* - * true_random variables - */ - -static uint32_t rand_m = 0; /* multiplier */ -static uint32_t rand_ia = 0; /* adder #1 */ -static uint32_t rand_ib = 0; /* adder #2 */ -static uint32_t rand_irand = 0; /* random value */ - -typedef enum -{ - uuid_e_less_than, uuid_e_equal_to, uuid_e_greater_than -} uuid_compval_t; - - - - -/**************************************************************************** - * - * local function declarations - * - ****************************************************************************/ - -/* - * I N I T - * - * Startup initialization routine for UUID module. - */ - -static OSErr init (void); - -/* - * T R U E _ R A N D O M _ I N I T - */ - -static void true_random_init (void); - -/* - * T R U E _ R A N D O M - */ -static uint16_t true_random (void); - - -/* - * N E W _ C L O C K _ S E Q - * - * Ensure clock_seq is up-to-date - * - * Note: clock_seq is architected to be 14-bits (unsigned) but - * I've put it in here as 16-bits since there isn't a - * 14-bit unsigned integer type (yet) - */ -static void new_clock_seq ( uint16_t * /*clock_seq*/); - - -/* - * T I M E _ C M P - * - * Compares two UUID times (64-bit DEC UID UTC values) - */ -static uuid_compval_t time_cmp ( - uuid_time_t * /*time1*/, - uuid_time_t * /*time2*/ - ); - - -/************************************************************************/ -/* */ -/* New Routines */ -/* */ -/************************************************************************/ - -/* - * saved copy of our IEEE 802 address for quick reference - */ - -static uuid_address_t saved_addr = {{0, 0, 0, 0, 0, 0}}; -static int got_address = false; -static int last_addr_result = false; - -static OSErr GenRandomEthernet(uuid_address_t *addr) { - unsigned int i; - for (i = 0; i < 6; i++) { - addr->eaddr[i] = (unsigned char)(true_random() & 0xff); - } - return 0; -} - -/* -**++ -** -** ROUTINE NAME: uuid_get_address -** -** SCOPE: PUBLIC -** -** DESCRIPTION: -** -** Return our IEEE 802 address. -** -** This function is not really "public", but more like the SPI functions -** -- available but not part of the official API. We've done this so -** that other subsystems (of which there are hopefully few or none) -** that need the IEEE 802 address can use this function rather than -** duplicating the gore it does (or more specifically, the gore that -** "uuid__get_os_address" does). -** -** INPUTS: none -** -** INPUTS/OUTPUTS: none -** -** OUTPUTS: -** -** addr IEEE 802 address -** -** status return status value -** -** IMPLICIT INPUTS: none -** -** IMPLICIT OUTPUTS: none -** -** FUNCTION VALUE: none -** -** SIDE EFFECTS: none -** -**-- -**/ - -static int uuid_get_address(uuid_address_t *addr) -{ - - /* - * just return address we determined previously if we've - * already got one - */ - - if (got_address) { - memmove (addr, &saved_addr, sizeof (uuid_address_t)); - return last_addr_result; - } - - /* - * Otherwise, call the system specific routine. - */ - - last_addr_result = GetEthernetAddr(addr); - - /* - * Was this an error? If so, I need to generate a random - * sequence to use in place of an Ethernet address. - */ - if (last_addr_result) { - last_addr_result = GenRandomEthernet(addr); - } - - got_address = true; - if (last_addr_result == 0) { - /* On no error copy */ - memmove (&saved_addr, addr, sizeof (uuid_address_t)); - } - return last_addr_result; -} - -/***************************************************************************** - * - * Macro definitions - * - ****************************************************************************/ - -/* - * ensure we've been initialized - */ -static int uuid_init_done = false; - -#define EmptyArg -#define UUID_VERIFY_INIT(Arg) \ - if (! uuid_init_done) \ - { \ - init (status); \ - if (*status != uuid_s_ok) \ - { \ - return Arg; \ - } \ - } - -/* - * Check the reserved bits to make sure the UUID is of the known structure. - */ - -#define CHECK_STRUCTURE(uuid) \ -( \ - (((uuid)->clock_seq_hi_and_reserved & 0x80) == 0x00) || /* var #0 */ \ - (((uuid)->clock_seq_hi_and_reserved & 0xc0) == 0x80) || /* var #1 */ \ - (((uuid)->clock_seq_hi_and_reserved & 0xe0) == 0xc0) /* var #2 */ \ -) - -/* - * The following macros invoke CHECK_STRUCTURE(), check that the return - * value is okay and if not, they set the status variable appropriately - * and return either a boolean false, nothing (for void procedures), - * or a value passed to the macro. This has been done so that checking - * can be done more simply and values are returned where appropriate - * to keep compilers happy. - * - * bCHECK_STRUCTURE - returns boolean false - * vCHECK_STRUCTURE - returns nothing (void) - * rCHECK_STRUCTURE - returns 'r' macro parameter - */ - -#define bCHECK_STRUCTURE(uuid, status) \ -{ \ - if (!CHECK_STRUCTURE (uuid)) \ - { \ - *(status) = uuid_s_bad_version; \ - return (false); \ - } \ -} - -#define vCHECK_STRUCTURE(uuid, status) \ -{ \ - if (!CHECK_STRUCTURE (uuid)) \ - { \ - *(status) = uuid_s_bad_version; \ - return; \ - } \ -} - -#define rCHECK_STRUCTURE(uuid, status, result) \ -{ \ - if (!CHECK_STRUCTURE (uuid)) \ - { \ - *(status) = uuid_s_bad_version; \ - return (result); \ - } \ -} - - -/* - * Define constant designation difference in Unix and DTSS base times: - * DTSS UTC base time is October 15, 1582. - * Unix base time is January 1, 1970. - */ -#define uuid_c_os_base_time_diff_lo 0x13814000 -#define uuid_c_os_base_time_diff_hi 0x01B21DD2 - -#ifndef UUID_C_100NS_PER_SEC -#define UUID_C_100NS_PER_SEC 10000000 -#endif - -#ifndef UUID_C_100NS_PER_USEC -#define UUID_C_100NS_PER_USEC 10 -#endif - - - - - -/* - * UADD_UVLW_2_UVLW - macro to add two unsigned 64-bit long integers - * (ie. add two unsigned 'very' long words) - * - * Important note: It is important that this macro accommodate (and it does) - * invocations where one of the addends is also the sum. - * - * This macro was snarfed from the DTSS group and was originally: - * - * UTCadd - macro to add two UTC times - * - * add lo and high order longword separately, using sign bits of the low-order - * longwords to determine carry. sign bits are tested before addition in two - * cases - where sign bits match. when the addend sign bits differ the sign of - * the result is also tested: - * - * sign sign - * addend 1 addend 2 carry? - * - * 1 1 true - * 1 0 true if sign of sum clear - * 0 1 true if sign of sum clear - * 0 0 false - */ -#define UADD_UVLW_2_UVLW(add1, add2, sum) \ - if (!(((add1)->lo&0x80000000UL) ^ ((add2)->lo&0x80000000UL))) \ - { \ - if (((add1)->lo&0x80000000UL)) \ - { \ - (sum)->lo = (add1)->lo + (add2)->lo ; \ - (sum)->hi = (add1)->hi + (add2)->hi+1 ; \ - } \ - else \ - { \ - (sum)->lo = (add1)->lo + (add2)->lo ; \ - (sum)->hi = (add1)->hi + (add2)->hi ; \ - } \ - } \ - else \ - { \ - (sum)->lo = (add1)->lo + (add2)->lo ; \ - (sum)->hi = (add1)->hi + (add2)->hi ; \ - if (!((sum)->lo&0x80000000UL)) \ - (sum)->hi++ ; \ - } - -/* - * UADD_UW_2_UVLW - macro to add a 16-bit unsigned integer to - * a 64-bit unsigned integer - * - * Note: see the UADD_UVLW_2_UVLW() macro - * - */ -#define UADD_UW_2_UVLW(add1, add2, sum) \ -{ \ - (sum)->hi = (add2)->hi; \ - if ((add2)->lo & 0x80000000UL) \ - { \ - (sum)->lo = (*add1) + (add2)->lo; \ - if (!((sum)->lo & 0x80000000UL)) \ - { \ - (sum)->hi++; \ - } \ - } \ - else \ - { \ - (sum)->lo = (*add1) + (add2)->lo; \ - } \ -} - -/* - * U U I D _ _ G E T _ O S _ T I M E - * - * Get OS time - contains platform-specific code. - */ - -static const double utc_conversion_factor = 429.4967296; // 2^32 / 10^7 - -static void uuid__get_os_time (uuid_time_t * uuid_time) -{ - unsigned64_t utc, - os_basetime_diff; - CFAbsoluteTime at = CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970; - double utc_at = at / utc_conversion_factor; - - /* Convert 'at' in double seconds to 100ns units in utc */ - utc.hi = (uint32_t)utc_at; - utc_at -= (double)utc.hi; - utc_at *= utc_conversion_factor; - utc_at *= 10000000.0; - utc.lo = (uint32_t)utc_at; - - /* - * Offset between DTSS formatted times and Unix formatted times. - */ - os_basetime_diff.lo = uuid_c_os_base_time_diff_lo; - os_basetime_diff.hi = uuid_c_os_base_time_diff_hi; - UADD_UVLW_2_UVLW (&utc, &os_basetime_diff, uuid_time); - -} - -/* -**++ -** -** ROUTINE NAME: init -** -** SCOPE: INTERNAL - declared locally -** -** DESCRIPTION: -** -** Startup initialization routine for the UUID module. -** -** INPUTS: none -** -** INPUTS/OUTPUTS: none -** -** OUTPUTS: -** -** status return status value -** -** uuid_s_ok -** uuid_s_coding_error -** -** IMPLICIT INPUTS: none -** -** IMPLICIT OUTPUTS: none -** -** FUNCTION VALUE: void -** -** SIDE EFFECTS: sets uuid_init_done so this won't be done again -** -**-- -**/ - -static OSErr init() -{ - /* - * init the random number generator - */ - - true_random_init(); - - /* - * Read the preferences data from the Macintosh pref file - */ - - ReadPrefData(); - - /* - * Get the time. Note that I renamed 'time_last' to - * GLastTime to indicate that I'm using it elsewhere as - * a shared library global. - */ - - if ((GLastTime.hi == 0) && (GLastTime.lo == 0)) { - uuid__get_os_time (&GLastTime); - GClockSeq = true_random(); - } - uuid_init_done = true; - return 0; -} - -static uint32_t _CFGenerateV1UUID(uint8_t *uuid_bytes) -{ - uuid_v1_t *uuid = (uuid_v1_t *)uuid_bytes; - OSErr err; - uuid_address_t eaddr; - int got_no_time = false; - - if (!uuid_init_done) { - err = init(); - if (err) return err; - } - /* - * get our hardware network address - */ - - if (0 != (err = uuid_get_address(&eaddr))) return err; - - do - { - /* - * get the current time - */ - uuid__get_os_time (&time_now); - - /* - * do stuff like: - * - * o check that our clock hasn't gone backwards and handle it - * accordingly with clock_seq - * o check that we're not generating uuid's faster than we - * can accommodate with our time_adjust fudge factor - */ - switch (time_cmp (&time_now, &GLastTime)) - { - case uuid_e_less_than: - new_clock_seq (&GClockSeq); - GTimeAdjust = 0; - break; - case uuid_e_greater_than: - GTimeAdjust = 0; - break; - case uuid_e_equal_to: - if (GTimeAdjust == MAX_TIME_ADJUST) - { - /* - * spin your wheels while we wait for the clock to tick - */ - got_no_time = true; - } - else - { - GTimeAdjust++; - } - break; - default: - return kUUIDInternalError; - } - } while (got_no_time); - - GLastTime.lo = time_now.lo; - GLastTime.hi = time_now.hi; - - if (GTimeAdjust != 0) - { - UADD_UW_2_UVLW (>imeAdjust, &time_now, &time_now); - } - - /* - * now construct a uuid with the information we've gathered - * plus a few constants - */ - uuid->time_low = time_now.lo; - uuid->time_mid = time_now.hi & TIME_MID_MASK; - - uuid->time_hi_and_version = - (time_now.hi & TIME_HIGH_MASK) >> TIME_HIGH_SHIFT_COUNT; - uuid->time_hi_and_version |= UUID_VERSION_BITS; - - uuid->clock_seq_low = GClockSeq & CLOCK_SEQ_LOW_MASK; - uuid->clock_seq_hi_and_reserved = - (GClockSeq & CLOCK_SEQ_HIGH_MASK) >> CLOCK_SEQ_HIGH_SHIFT_COUNT; - - uuid->clock_seq_hi_and_reserved |= UUID_RESERVED_BITS; - - memmove (uuid->node, &eaddr, sizeof (uuid_address_t)); - - return 0; -} - -#if defined(__MACH__) - -#include - -__private_extern__ uint32_t _CFGenerateUUID(uuid_t *uuid_bytes) { - static Boolean useV1UUIDs = false, checked = false; - uuid_t uuid; - if (!checked) { - const char *value = getenv("CFUUIDVersionNumber"); - if (value) { - if (1 == strtoul(value, NULL, 0)) useV1UUIDs = true; - } else { - if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionTiger)) useV1UUIDs = true; - } - checked = true; - } - if (useV1UUIDs) return _CFGenerateV1UUID(uuid_bytes); - uuid_generate_random(uuid); - memcpy(uuid_bytes, uuid, sizeof(uuid)); - return 0; -} - -#else - -__private_extern__ uint32_t _CFGenerateUUID(uuid_t *uuid_bytes) { - return _CFGenerateV1UUID(uuid_bytes); -} - -#endif // __MACH__ - - -/***************************************************************************** - * - * LOCAL MATH PROCEDURES - math procedures used internally by the UUID module - * - ****************************************************************************/ - -/* -** T I M E _ C M P -** -** Compares two UUID times (64-bit UTC values) -**/ - -static uuid_compval_t time_cmp(uuid_time_t *time1,uuid_time_t *time2) -{ - /* - * first check the hi parts - */ - if (time1->hi < time2->hi) return (uuid_e_less_than); - if (time1->hi > time2->hi) return (uuid_e_greater_than); - - /* - * hi parts are equal, check the lo parts - */ - if (time1->lo < time2->lo) return (uuid_e_less_than); - if (time1->lo > time2->lo) return (uuid_e_greater_than); - - return (uuid_e_equal_to); -} - - - -/**************************************************************************** -** -** U U I D T R U E R A N D O M N U M B E R G E N E R A T O R -** -***************************************************************************** -** -** This random number generator (RNG) was found in the ALGORITHMS Notesfile. -** -** (Note 16.7, July 7, 1989 by Robert (RDVAX::)Gries, Cambridge Research Lab, -** Computational Quality Group) -** -** It is really a "Multiple Prime Random Number Generator" (MPRNG) and is -** completely discussed in reference #1 (see below). -** -** References: -** 1) "The Multiple Prime Random Number Generator" by Alexander Hass -** pp. 368 to 381 in ACM Transactions on Mathematical Software, -** December, 1987 -** 2) "The Art of Computer Programming: Seminumerical Algorithms -** (vol 2)" by Donald E. Knuth, pp. 39 to 113. -** -** A summary of the notesfile entry follows: -** -** Gries discusses the two RNG's available for ULTRIX-C. The default RNG -** uses a Linear Congruential Method (very popular) and the second RNG uses -** a technique known as a linear feedback shift register. -** -** The first (default) RNG suffers from bit-cycles (patterns/repetition), -** ie. it's "not that random." -** -** While the second RNG passes all the emperical tests, there are "states" -** that become "stable", albeit contrived. -** -** Gries then presents the MPRNG and says that it passes all emperical -** tests listed in reference #2. In addition, the number of calls to the -** MPRNG before a sequence of bit position repeats appears to have a normal -** distribution. -** -** Note (mbs): I have coded the Gries's MPRNG with the same constants that -** he used in his paper. I have no way of knowing whether they are "ideal" -** for the range of numbers we are dealing with. -** -****************************************************************************/ - -/* -** T R U E _ R A N D O M _ I N I T -** -** Note: we "seed" the RNG with the bits from the clock and the PID -** -**/ - -static void true_random_init (void) -{ - uuid_time_t t; - uint16_t *seedp, seed=0; - - - /* - * optimal/recommended starting values according to the reference - */ - static uint32_t rand_m_init = 971; - static uint32_t rand_ia_init = 11113; - static uint32_t rand_ib_init = 104322; - static uint32_t rand_irand_init = 4181; - - rand_m = rand_m_init; - rand_ia = rand_ia_init; - rand_ib = rand_ib_init; - rand_irand = rand_irand_init; - - /* - * Generating our 'seed' value - * - * We start with the current time, but, since the resolution of clocks is - * system hardware dependent (eg. Ultrix is 10 msec.) and most likely - * coarser than our resolution (10 usec) we 'mixup' the bits by xor'ing - * all the bits together. This will have the effect of involving all of - * the bits in the determination of the seed value while remaining system - * independent. Then for good measure to ensure a unique seed when there - * are multiple processes creating UUID's on a system, we add in the PID. - */ - uuid__get_os_time(&t); - seedp = (uint16_t *)(&t); - seed ^= *seedp++; - seed ^= *seedp++; - seed ^= *seedp++; - seed ^= *seedp++; - rand_irand += seed; -} - -/* -** T R U E _ R A N D O M -** -** Note: we return a value which is 'tuned' to our purposes. Anyone -** using this routine should modify the return value accordingly. -**/ - -static uint16_t true_random (void) -{ - rand_m += 7; - rand_ia += 1907; - rand_ib += 73939; - - if (rand_m >= 9973) rand_m -= 9871; - if (rand_ia >= 99991) rand_ia -= 89989; - if (rand_ib >= 224729) rand_ib -= 96233; - - rand_irand = (rand_irand * rand_m) + rand_ia + rand_ib; - - return (HI_WORD (rand_irand) ^ (rand_irand & RAND_MASK)); -} - -/***************************************************************************** - * - * LOCAL PROCEDURES - procedures used staticly by the UUID module - * - ****************************************************************************/ - -/* -** N E W _ C L O C K _ S E Q -** -** Ensure *clkseq is up-to-date -** -** Note: clock_seq is architected to be 14-bits (unsigned) but -** I've put it in here as 16-bits since there isn't a -** 14-bit unsigned integer type (yet) -**/ - -static void new_clock_seq -#ifdef _DCE_PROTO_ -( - uint16_t *clkseq -) -#else -(clkseq) -uint16_t *clkseq; -#endif -{ - /* - * A clkseq value of 0 indicates that it hasn't been initialized. - */ - if (*clkseq == 0) - { -#ifdef UUID_NONVOLATILE_CLOCK - *clkseq = uuid__read_clock(); /* read nonvolatile clock */ - if (*clkseq == 0) /* still not init'd ??? */ - { - *clkseq = true_random(); /* yes, set random */ - } -#else - /* - * with a volatile clock, we always init to a random number - */ - *clkseq = true_random(); -#endif - } - - CLOCK_SEQ_BUMP (clkseq); - if (*clkseq == 0) - { - *clkseq = *clkseq + 1; - } - -#ifdef UUID_NONVOLATILE_CLOCK - uuid_write_clock (clkseq); -#endif -} - - - -/* ReadPrefData - * - * Read the preferences data into my global variables - */ - -static OSErr ReadPrefData(void) -{ - /* - * Zero out the saved preferences information - */ - - memset((void *)&GSavedENetAddr, 0, sizeof(GSavedENetAddr)); - memset((void *)&GLastTime, 0, sizeof(GLastTime)); - GTimeAdjust = 0; - GClockSeq = 0; - - - return 0; -} - -#if 0 -// currently unused - -/* WritePrefData - * - * Write the preferences data back out to my global variables. - * This gets called a couple of times. First, this is called by - * my GetRandomEthernet routine if I generated a psudorandom MAC - * address. Second, this is called when the library is being - * terminated through the __terminate() CFM call. - * - * Note this does it's best attempt at writing the data out, - * and relies on ReadPrefData to check for integrety of the actual - * saved file. - */ - -static void WritePrefData(void) -{ -} - -#endif // 0 - -#undef HI_WORD -#undef RAND_MASK -#undef TIME_MID_MASK -#undef TIME_HIGH_MASK -#undef TIME_HIGH_SHIFT_COUNT -#undef MAX_TIME_ADJUST -#undef CLOCK_SEQ_LOW_MASK -#undef CLOCK_SEQ_HIGH_MASK -#undef CLOCK_SEQ_HIGH_SHIFT_COUNT -#undef CLOCK_SEQ_FIRST -#undef CLOCK_SEQ_LAST -#undef CLOCK_SEQ_BIT_BANG -#undef CLOCK_SEQ_BUMP -#undef UUID_VERSION_BITS -#undef UUID_RESERVED_BITS -#undef IS_OLD_UUID -#undef EmptyArg -#undef UUID_VERIFY_INIT -#undef CHECK_STRUCTURE -#undef bCHECK_STRUCTURE -#undef vCHECK_STRUCTURE -#undef rCHECK_STRUCTURE -#undef uuid_c_os_base_time_diff_lo -#undef uuid_c_os_base_time_diff_hi -#undef UUID_C_100NS_PER_SEC -#undef UUID_C_100NS_PER_USEC -#undef UADD_UVLW_2_UVLW -#undef UADD_UW_2_UVLW - -#endif // __WIN32__ diff --git a/BuildCFLite b/BuildCFLite new file mode 100755 index 0000000..9d1d810 --- /dev/null +++ b/BuildCFLite @@ -0,0 +1,91 @@ +#/bin/sh + +echo "Setup ..." + +ALL_CFILES=`ls *.c` +ALL_HFILES=`ls *.h` + +MACHINE_TYPE=`uname -p` +UNICODE_DATA_FILE="UNKNOWN" + +if [ "$MACHINE_TYPE" == "i386" ]; 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 ppc64 -arch i386 -arch x86_64" +CFLAGS="-c -pipe -std=gnu99 -g -Wmost -Wno-trigraphs -mmacosx-version-min=10.5 -fconstant-cfstrings -fexceptions -DCF_BUILDING_CF=1 -DDEPLOYMENT_TARGET_MACOSX=1 -DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_5 -DU_SHOW_DRAFT_API=1 -I$OBJBASE -DVERSION=476.10" +LFLAGS="-dynamiclib -mmacosx-version-min=10.5 -twolevel_namespace -init ___CFInitialize -compatibility_version 150 -current_version 476 -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 + 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/Versions/A/CoreFoundation $DSTBASE/CoreFoundation.framework/Versions/A/CoreFoundation + +echo "Installing done. The framework is in $DSTBASE" + +exit 0 + diff --git a/Preferences.subproj/CFApplicationPreferences.c b/CFApplicationPreferences.c similarity index 81% rename from Preferences.subproj/CFApplicationPreferences.c rename to CFApplicationPreferences.c index 36a026d..4fd73e9 100644 --- a/Preferences.subproj/CFApplicationPreferences.c +++ b/CFApplicationPreferences.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -29,27 +29,21 @@ #include "CFInternal.h" #include #include - +#include +#include +#include +#include +#include +#if __MACH__ +#include +#endif static Boolean _CFApplicationPreferencesSynchronizeNoLock(_CFApplicationPreferences *self); void _CFPreferencesDomainSetMultiple(CFPreferencesDomainRef domain, CFDictionaryRef dict); static void updateDictRep(_CFApplicationPreferences *self); +static void _CFApplicationPreferencesSetSearchList(_CFApplicationPreferences *self, CFArrayRef newSearchList); Boolean _CFApplicationPreferencesContainsDomainNoLock(_CFApplicationPreferences *self, CFPreferencesDomainRef domain); - -static void *__CFInsertionDomain = NULL; -static CFDictionaryRef __CFInsertion = NULL; - -// Bindings internals -extern CFSpinLock_t userDefaultsLock; -extern void *userDefaults; - -// Management externals -extern Boolean _CFPreferencesManagementActive; - - -#define CF_OBJC_KVO_WILLCHANGE(obj, sel) -#define CF_OBJC_KVO_DIDCHANGE(obj, sel) - +static CFTypeRef _CFApplicationPreferencesCreateValueForKey2(_CFApplicationPreferences *self, CFStringRef defaultName); // Right now, nothing is getting destroyed pretty much ever. We probably don't want this to be the case, but it's very tricky - domains live in the cache as well as a given application's preferences, and since they're not CFTypes, there's no reference count. Also, it's not clear we ever want domains destroyed. When they're synchronized, they clear their internal state (to force reading from the disk again), so they're not very big.... REW, 12/17/98 @@ -59,7 +53,7 @@ CFPropertyListRef CFPreferencesCopyAppValue(CFStringRef key, CFStringRef appName CFAssert1(key != NULL, __kCFLogAssertion, "%s(): Cannot access preferences with a NULL key", __PRETTY_FUNCTION__); standardPrefs = _CFStandardApplicationPreferences(appName); - return standardPrefs ? _CFApplicationPreferencesCreateValueForKey(standardPrefs, key) : NULL; + return standardPrefs ? _CFApplicationPreferencesCreateValueForKey2(standardPrefs, key) : NULL; } CF_EXPORT Boolean CFPreferencesAppBooleanValue(CFStringRef key, CFStringRef appName, Boolean *keyExistsAndHasValidFormat) { @@ -79,10 +73,10 @@ CF_EXPORT Boolean CFPreferencesAppBooleanValue(CFStringRef key, CFStringRef appN } typeID = CFGetTypeID(value); if (typeID == CFStringGetTypeID()) { - if (CFStringCompare(value, CFSTR("true"), kCFCompareCaseInsensitive) == kCFCompareEqualTo || CFStringCompare(value, CFSTR("YES"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { + if (CFStringCompare((CFStringRef)value, CFSTR("true"), kCFCompareCaseInsensitive) == kCFCompareEqualTo || CFStringCompare((CFStringRef)value, CFSTR("YES"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { *keyExistsAndHasValidFormat = true; result = true; - } else if (CFStringCompare(value, CFSTR("false"), kCFCompareCaseInsensitive) == kCFCompareEqualTo || CFStringCompare(value, CFSTR("NO"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { + } else if (CFStringCompare((CFStringRef)value, CFSTR("false"), kCFCompareCaseInsensitive) == kCFCompareEqualTo || CFStringCompare((CFStringRef)value, CFSTR("NO"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { *keyExistsAndHasValidFormat = true; result = false; } else { @@ -90,13 +84,13 @@ CF_EXPORT Boolean CFPreferencesAppBooleanValue(CFStringRef key, CFStringRef appN result = false; } } else if (typeID == CFNumberGetTypeID()) { - if (CFNumberIsFloatType(value)) { + if (CFNumberIsFloatType((CFNumberRef)value)) { *keyExistsAndHasValidFormat = false; result = false; } else { int i; *keyExistsAndHasValidFormat = true; - CFNumberGetValue(value, kCFNumberIntType, &i); + CFNumberGetValue((CFNumberRef)value, kCFNumberIntType, &i); result = (i == 0) ? false : true; } } else if (typeID == CFBooleanGetTypeID()) { @@ -129,18 +123,18 @@ __private_extern__ CFIndex CFPreferencesAppIntegerValue(CFStringRef key, CFStrin } typeID = CFGetTypeID(value); if (typeID == CFStringGetTypeID()) { - CFIndex charIndex = 0; + SInt32 charIndex = 0; SInt32 intVal; CFStringInlineBuffer buf; Boolean success; - CFStringInitInlineBuffer(value, &buf, CFRangeMake(0, CFStringGetLength(value))); + CFStringInitInlineBuffer((CFStringRef)value, &buf, CFRangeMake(0, CFStringGetLength((CFStringRef)value))); success = __CFStringScanInteger(&buf, NULL, &charIndex, false, &intVal); - *keyExistsAndHasValidFormat = (success && charIndex == CFStringGetLength(value)); + *keyExistsAndHasValidFormat = (success && charIndex == CFStringGetLength((CFStringRef)value)); result = (*keyExistsAndHasValidFormat) ? intVal : 0; } else if (typeID == CFNumberGetTypeID()) { - *keyExistsAndHasValidFormat = !CFNumberIsFloatType(value); + *keyExistsAndHasValidFormat = !CFNumberIsFloatType((CFNumberRef)value); if (*keyExistsAndHasValidFormat) { - CFNumberGetValue(value, kCFNumberCFIndexType, &result); + CFNumberGetValue((CFNumberRef)value, kCFNumberCFIndexType, &result); } else { result = 0; } @@ -178,14 +172,13 @@ void CFPreferencesSetAppValue(CFStringRef key, CFTypeRef value, CFStringRef appN } -static CFSpinLock_t __CFApplicationPreferencesLock = 0; // Locks access to __CFStandardUserPreferences +static CFSpinLock_t __CFApplicationPreferencesLock = CFSpinLockInit; // Locks access to __CFStandardUserPreferences static CFMutableDictionaryRef __CFStandardUserPreferences = NULL; // Mutable dictionary; keys are app names, values are _CFApplicationPreferences Boolean CFPreferencesAppSynchronize(CFStringRef appName) { _CFApplicationPreferences *standardPrefs; Boolean result; CFAssert1(appName != NULL, __kCFLogAssertion, "%s(): Cannot access application preferences with a NULL application name", __PRETTY_FUNCTION__); - __CFPreferencesCheckFormatType(); // Do not call _CFStandardApplicationPreferences(), as we do not want to create the preferences only to synchronize __CFSpinLock(&__CFApplicationPreferencesLock); @@ -209,7 +202,7 @@ void CFPreferencesFlushCaches(void) { if (count < 32) { prefsArray = prefsBuf; } else { - prefsArray = _CFAllocatorAllocateGC(alloc, count * sizeof(_CFApplicationPreferences *), 0); + prefsArray = (_CFApplicationPreferences **)CFAllocatorAllocate(alloc, count * sizeof(_CFApplicationPreferences *), 0); } CFDictionaryGetKeysAndValues(__CFStandardUserPreferences, NULL, (const void **)prefsArray); @@ -224,7 +217,7 @@ void CFPreferencesFlushCaches(void) { CFRelease(__CFStandardUserPreferences); __CFStandardUserPreferences = NULL; - if(prefsArray != prefsBuf) _CFAllocatorDeallocateGC(alloc, prefsArray); + if(prefsArray != prefsBuf) CFAllocatorDeallocate(alloc, prefsArray); } __CFSpinUnlock(&__CFApplicationPreferencesLock); _CFPreferencesPurgeDomainCache(); @@ -240,7 +233,7 @@ void _CFApplicationPreferencesDomainHasChanged(CFPreferencesDomainRef changedDom if(count < 32) { prefsArray = prefsBuf; } else { - prefsArray = _CFAllocatorAllocateGC(alloc, count * sizeof(_CFApplicationPreferences *), 0); + prefsArray = (_CFApplicationPreferences **)CFAllocatorAllocate(alloc, count * sizeof(_CFApplicationPreferences *), 0); } CFDictionaryGetKeysAndValues(__CFStandardUserPreferences, NULL, (const void **)prefsArray); // For this operation, giving up the lock is the last thing we want to do, so use the modified flavor of _CFApplicationPreferencesContainsDomain @@ -258,9 +251,6 @@ void _CFApplicationPreferencesDomainHasChanged(CFPreferencesDomainRef changedDom // Begin ported code from NSUserDefaults.m -/*************** Constants ***************/ - -// NSString * const NSUserDefaultsDidChangeNotification = @"NSUserDefaultsDidChangeNotification"; static void updateDictRep(_CFApplicationPreferences *self) { if (self->_dictRep) { @@ -270,24 +260,19 @@ static void updateDictRep(_CFApplicationPreferences *self) { } static void __addKeysAndValues(const void *key, const void *value, void *context) { - CFDictionarySetValue(context, key, value); + CFDictionarySetValue((CFMutableDictionaryRef)context, key, value); } -static void computeDictRep(_CFApplicationPreferences *self) { +static CFMutableDictionaryRef computeDictRep(_CFApplicationPreferences *self, Boolean skipC0C0A) { CFAllocatorRef alloc = __CFPreferencesAllocator(); CFMutableArrayRef searchList = self->_search; CFIndex idx; CFIndex cnt = CFArrayGetCount(searchList); CFDictionaryRef subdomainDict; + CFMutableDictionaryRef dictRep; - if (self->_dictRep) { - CFRelease(self->_dictRep); - } - self->_dictRep = CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks); - _CFDictionarySetCapacity(self->_dictRep, 160); // avoid lots of rehashing - - if (!self->_dictRep) return; - if (0 == cnt) return; + dictRep = CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, & kCFTypeDictionaryValueCallBacks); + _CFDictionarySetCapacity(dictRep, 260); // avoid lots of rehashing // For each subdomain triplet in the domain, iterate over dictionaries, adding them if necessary to the dictRep for (idx = cnt; idx--;) { @@ -296,30 +281,16 @@ static void computeDictRep(_CFApplicationPreferences *self) { if (!domain) continue; subdomainDict = _CFPreferencesDomainDeepCopyDictionary(domain); - if(subdomainDict) { - CFDictionaryApplyFunction(subdomainDict, __addKeysAndValues, self->_dictRep); + if (subdomainDict) { + CFDictionaryApplyFunction(subdomainDict, __addKeysAndValues, dictRep); CFRelease(subdomainDict); } - - if (__CFInsertionDomain == domain && __CFInsertion) { - CFDictionaryApplyFunction(__CFInsertion, __addKeysAndValues, self->_dictRep); - } } + return dictRep; } CFTypeRef _CFApplicationPreferencesSearchDownToDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef stopper, CFStringRef key) { - CFTypeRef value = NULL; - __CFSpinLock(&__CFApplicationPreferencesLock); - CFIndex idx, cnt; - cnt = CFArrayGetCount(self->_search); - for (idx = 0; idx < cnt; idx++) { - CFPreferencesDomainRef domain = (CFPreferencesDomainRef)CFArrayGetValueAtIndex(self->_search, idx); - if (domain == stopper) break; - value = _CFPreferencesDomainCreateValueForKey(domain, key); - if (value) break; - } - __CFSpinUnlock(&__CFApplicationPreferencesLock); - return value; + return NULL; } @@ -329,24 +300,20 @@ void _CFApplicationPreferencesUpdate(_CFApplicationPreferences *self) { __CFSpinUnlock(&__CFApplicationPreferencesLock); } +CF_EXPORT CFDictionaryRef _CFApplicationPreferencesCopyRepresentation(_CFApplicationPreferences *self); + __private_extern__ CFDictionaryRef __CFApplicationPreferencesCopyCurrentState(void) { - CFDictionaryRef result; _CFApplicationPreferences *self = _CFStandardApplicationPreferences(kCFPreferencesCurrentApplication); - __CFSpinLock(&__CFApplicationPreferencesLock); - if (!self->_dictRep) { - computeDictRep(self); - } - result = CFDictionaryCreateCopy(kCFAllocatorSystemDefault, self->_dictRep); - __CFSpinUnlock(&__CFApplicationPreferencesLock); + CFDictionaryRef result = _CFApplicationPreferencesCopyRepresentation(self); return result; } // CACHING here - we will only return a value as current as the last time computeDictRep() was called -CFTypeRef _CFApplicationPreferencesCreateValueForKey(_CFApplicationPreferences *self, CFStringRef defaultName) { +static CFTypeRef _CFApplicationPreferencesCreateValueForKey2(_CFApplicationPreferences *self, CFStringRef defaultName) { CFTypeRef result; __CFSpinLock(&__CFApplicationPreferencesLock); if (!self->_dictRep) { - computeDictRep(self); + self->_dictRep = computeDictRep(self, true); } result = (self->_dictRep) ? (CFTypeRef )CFDictionaryGetValue(self->_dictRep, defaultName) : NULL; if (result) { @@ -356,14 +323,10 @@ CFTypeRef _CFApplicationPreferencesCreateValueForKey(_CFApplicationPreferences * return result; } + void _CFApplicationPreferencesSet(_CFApplicationPreferences *self, CFStringRef defaultName, CFTypeRef value) { CFPreferencesDomainRef applicationDomain; - void *defs = NULL; - __CFSpinLock(&userDefaultsLock); - defs = userDefaults; - __CFSpinUnlock(&userDefaultsLock); - - CF_OBJC_KVO_WILLCHANGE(defs, defaultName); + __CFSpinLock(&__CFApplicationPreferencesLock); applicationDomain = _CFPreferencesStandardDomain(self->_appName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); if(applicationDomain) { @@ -374,16 +337,11 @@ void _CFApplicationPreferencesSet(_CFApplicationPreferences *self, CFStringRef d } } __CFSpinUnlock(&__CFApplicationPreferencesLock); - CF_OBJC_KVO_DIDCHANGE(defs, defaultName); } void _CFApplicationPreferencesRemove(_CFApplicationPreferences *self, CFStringRef defaultName) { CFPreferencesDomainRef appDomain; - void *defs = NULL; - __CFSpinLock(&userDefaultsLock); - defs = userDefaults; - __CFSpinUnlock(&userDefaultsLock); - CF_OBJC_KVO_WILLCHANGE(defs, defaultName); + __CFSpinLock(&__CFApplicationPreferencesLock); appDomain = _CFPreferencesStandardDomain(self->_appName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); if(appDomain) { @@ -394,21 +352,16 @@ void _CFApplicationPreferencesRemove(_CFApplicationPreferences *self, CFStringRe } } __CFSpinUnlock(&__CFApplicationPreferencesLock); - CF_OBJC_KVO_DIDCHANGE(defs, defaultName); } static Boolean _CFApplicationPreferencesSynchronizeNoLock(_CFApplicationPreferences *self) { Boolean success = _CFSynchronizeDomainCache(); - if (self->_dictRep) { - CFRelease(self->_dictRep); - self->_dictRep = NULL; - } + updateDictRep(self); return success; } Boolean _CFApplicationPreferencesSynchronize(_CFApplicationPreferences *self) { Boolean result; - __CFPreferencesCheckFormatType(); __CFSpinLock(&__CFApplicationPreferencesLock); result = _CFApplicationPreferencesSynchronizeNoLock(self); __CFSpinUnlock(&__CFApplicationPreferencesLock); @@ -418,10 +371,10 @@ Boolean _CFApplicationPreferencesSynchronize(_CFApplicationPreferences *self) { // appName should not be kCFPreferencesCurrentApplication going in to this call _CFApplicationPreferences *_CFApplicationPreferencesCreateWithUser(CFStringRef userName, CFStringRef appName) { CFAllocatorRef alloc = __CFPreferencesAllocator(); - _CFApplicationPreferences *self = CFAllocatorAllocate(alloc, sizeof(_CFApplicationPreferences), 0); + _CFApplicationPreferences *self = (_CFApplicationPreferences*)CFAllocatorAllocate(alloc, sizeof(_CFApplicationPreferences), 0); if (self) { self->_dictRep = NULL; - self->_appName = CFRetain(appName); + self->_appName = (CFStringRef)CFRetain(appName); self->_search = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks); if (!self->_search) { CFAllocatorDeallocate(alloc, self); @@ -435,24 +388,33 @@ _CFApplicationPreferences *_CFApplicationPreferencesCreateWithUser(CFStringRef u // Do NOT release the domain after adding it to the array; domain_expression should not return a retained object -- REW, 8/26/99 #define ADD_DOMAIN(domain_expression) domain = domain_expression; if (domain) {CFArrayAppendValue(search, domain);} void _CFApplicationPreferencesSetStandardSearchList(_CFApplicationPreferences *appPreferences) { - /* Now we add the standard domains; they are, in order: - this user, this app, this host - this user, this app, any host - this user, any app, this host - this user, any app, any host - any user, this app, this host - any user, this app, any host - any user, any app, this host - any user, any app, any host - - note: for MacOS 8, we only add: - this user, this app, this host - this user, any app, this host - any user, this app, this host - any user, any app, this host + /* Here is how the domains end up in priority order in a search list. Only a subset of these are setup by default. + argument domain + this app, this user, managed + this app, any user, managed + this app, this user, this host + this app, this user, any host (AppDomain) + suiteN, this user, this host + suiteN, this user, any host + ... + suite0, this user, this host + suite0, this user, any host + any app, this user, this host + any app, this user, any host (GlobalDomain) + NSUserDefaults backwards-compat ICU domain + this app, any user, this host + this app, any user, any host + suiteN, any user, this host + suiteN, any user, any host + ... + suite0, any user, this host + suite0, any user, any host + any app, any user, this host + any app, any user, any host + registration domain */ CFPreferencesDomainRef domain; - CFMutableArrayRef search = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFMutableArrayRef search = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); if (!search) { // couldn't allocate memory! return; @@ -460,8 +422,7 @@ void _CFApplicationPreferencesSetStandardSearchList(_CFApplicationPreferences *a ADD_DOMAIN(_CFPreferencesStandardDomain(appPreferences->_appName, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost)); ADD_DOMAIN(_CFPreferencesStandardDomain(appPreferences->_appName, kCFPreferencesCurrentUser, kCFPreferencesAnyHost)); - __CFInsertionDomain = _CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); - ADD_DOMAIN(__CFInsertionDomain); + ADD_DOMAIN(_CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost)); ADD_DOMAIN(_CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost)); ADD_DOMAIN(_CFPreferencesStandardDomain(appPreferences->_appName, kCFPreferencesAnyUser, kCFPreferencesCurrentHost)); ADD_DOMAIN(_CFPreferencesStandardDomain(appPreferences->_appName, kCFPreferencesAnyUser, kCFPreferencesAnyHost)); @@ -479,7 +440,7 @@ __private_extern__ _CFApplicationPreferences *_CFStandardApplicationPreferences( // CFAssert(appName != kCFPreferencesAnyApplication, __kCFLogAssertion, "Cannot use any of the CFPreferences...App... functions with an appName of kCFPreferencesAnyApplication"); __CFSpinLock(&__CFApplicationPreferencesLock); if (!__CFStandardUserPreferences) { - __CFStandardUserPreferences = CFDictionaryCreateMutable(NULL, 0, & kCFTypeDictionaryKeyCallBacks, NULL); + __CFStandardUserPreferences = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, & kCFTypeDictionaryKeyCallBacks, NULL); } if (!__CFStandardUserPreferences) { // Couldn't create @@ -501,7 +462,7 @@ __private_extern__ _CFApplicationPreferences *_CFStandardApplicationPreferences( void _CFApplicationPreferencesSetCacheForApp(_CFApplicationPreferences *appPrefs, CFStringRef appName) { __CFSpinLock(&__CFApplicationPreferencesLock); if (!__CFStandardUserPreferences) { - __CFStandardUserPreferences = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, NULL); + __CFStandardUserPreferences = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); CFDictionarySetValue(__CFStandardUserPreferences, appName, appPrefs); __CFSpinUnlock(&__CFApplicationPreferencesLock); } else { @@ -535,14 +496,15 @@ void _CFDeallocateApplicationPreferences(_CFApplicationPreferences *self) { __CFSpinUnlock(&__CFApplicationPreferencesLock); } -// For Foundation's use -CFDictionaryRef _CFApplicationPreferencesCopyRepresentationWithHint(_CFApplicationPreferences *self, CFDictionaryRef hint) { + +CF_EXPORT +CFDictionaryRef _CFApplicationPreferencesCopyRepresentation(_CFApplicationPreferences *self) { CFDictionaryRef dict; __CFSpinLock(&__CFApplicationPreferencesLock); if (!self->_dictRep) { - computeDictRep(self); + self->_dictRep = computeDictRep(self, true); } - if (self->_dictRep && (self->_dictRep != hint)) { + if (self->_dictRep) { CFRetain(self->_dictRep); } dict = self->_dictRep; @@ -550,24 +512,7 @@ CFDictionaryRef _CFApplicationPreferencesCopyRepresentationWithHint(_CFApplicati return dict; } -// For Foundation's use; does not do what it would seem to from the name -CFDictionaryRef _CFApplicationPreferencesCopyRepresentation3(_CFApplicationPreferences *self, CFDictionaryRef hint, CFDictionaryRef insertion, CFPreferencesDomainRef afterDomain) { - __CFSpinLock(&__CFApplicationPreferencesLock); - if (0 == self && 0 == hint && 0 == afterDomain) { - // This is so so gross. - if (__CFInsertion) CFRelease(__CFInsertion); - __CFInsertion = insertion ? CFRetain(insertion) : NULL; - } - __CFSpinUnlock(&__CFApplicationPreferencesLock); - return 0; -} - -CF_EXPORT -CFDictionaryRef _CFApplicationPreferencesCopyRepresentation(_CFApplicationPreferences *self) { - return _CFApplicationPreferencesCopyRepresentationWithHint(self, NULL); -} - -__private_extern__ void _CFApplicationPreferencesSetSearchList(_CFApplicationPreferences *self, CFArrayRef newSearchList) { +static void _CFApplicationPreferencesSetSearchList(_CFApplicationPreferences *self, CFArrayRef newSearchList) { CFIndex idx, count; __CFSpinLock(&__CFApplicationPreferencesLock); CFArrayRemoveAllValues(self->_search); @@ -618,8 +563,7 @@ void _CFApplicationPreferencesAddSuitePreferences(_CFApplicationPreferences *app domain = _CFPreferencesStandardDomain(appPrefs->_appName, kCFPreferencesAnyUser, kCFPreferencesAnyHost); idx = domain ? CFArrayGetFirstIndexOfValue(appPrefs->_search, range, domain) : kCFNotFound; if (idx == kCFNotFound) { - // Someone blew away the app domain. Can only happen through -[NSUserDefaults setSearchList:]. For the any user case, we look for right below the global domain - // Can this happen anymore? -[NSUserDefaults setSearchList:] is bailing. -- ctp - - 3 Jan 2002 + // Someone blew away the app domain. For the any user case, we look for right below the global domain domain = _CFPreferencesStandardDomain(kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); idx = domain ? CFArrayGetFirstIndexOfValue(appPrefs->_search, range, domain) : kCFNotFound; if (idx == kCFNotFound) { @@ -695,6 +639,11 @@ void _CFApplicationPreferencesAddDomain(_CFApplicationPreferences *self, CFPrefe Boolean _CFApplicationPreferencesContainsDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef domain) { Boolean result; + + if (!domain) { + return false; + } + __CFSpinLock(&__CFApplicationPreferencesLock); result = CFArrayContainsValue(self->_search, CFRangeMake(0, CFArrayGetCount(self->_search)), domain); __CFSpinUnlock(&__CFApplicationPreferencesLock); @@ -721,5 +670,3 @@ void _CFApplicationPreferencesRemoveDomain(_CFApplicationPreferences *self, CFPr updateDictRep(self); __CFSpinUnlock(&__CFApplicationPreferencesLock); } - - diff --git a/Collections.subproj/CFArray.c b/CFArray.c similarity index 77% rename from Collections.subproj/CFArray.c rename to CFArray.c index f741077..075f192 100644 --- a/Collections.subproj/CFArray.c +++ b/CFArray.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -27,10 +27,12 @@ #include #include "CFStorage.h" -#include "CFUtilitiesPriv.h" +#include "CFPriv.h" #include "CFInternal.h" #include +__private_extern__ void _CFStorageSetWeak(CFStorageRef storage); + const CFArrayCallBacks kCFTypeArrayCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual}; static const CFArrayCallBacks __kCFNullArrayCallBacks = {0, NULL, NULL, NULL, NULL}; @@ -38,55 +40,37 @@ struct __CFArrayBucket { const void *_item; }; -struct __CFArrayImmutable { - CFRuntimeBase _base; - CFIndex _count; /* number of objects */ -}; - -struct __CFArrayFixedMutable { - CFRuntimeBase _base; - CFIndex _count; /* number of objects */ - CFIndex _capacity; /* maximum number of objects */ -}; - enum { __CF_MAX_BUCKETS_PER_DEQUE = 262140 }; CF_INLINE CFIndex __CFArrayDequeRoundUpCapacity(CFIndex capacity) { if (capacity < 4) return 4; - return __CFMin((1 << (CFLog2(capacity) + 1)), __CF_MAX_BUCKETS_PER_DEQUE); + return __CFMin((1 << flsl(capacity)), __CF_MAX_BUCKETS_PER_DEQUE); } 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 /* struct __CFArrayBucket buckets follow here */ }; -struct __CFArrayMutable { - CFRuntimeBase _base; - CFIndex _count; /* number of objects */ - void *_store; /* can be NULL when MutableDeque */ -}; - -/* convenience for debugging. */ struct __CFArray { CFRuntimeBase _base; CFIndex _count; /* number of objects */ - union { - CFIndex _capacity; /* maximum number of objects */ - void *_store; /* can be NULL when MutableDeque */ - }; + CFIndex _mutations; + void *_store; /* can be NULL when MutableDeque */ }; /* Flag bits */ enum { /* Bits 0-1 */ __kCFArrayImmutable = 0, - __kCFArrayFixedMutable = 1, - __kCFArrayMutableDeque = 2, - __kCFArrayMutableStore = 3 + __kCFArrayDeque = 2, + __kCFArrayStorage = 3 }; enum { /* Bits 2-3 */ @@ -95,35 +79,35 @@ enum { /* Bits 2-3 */ __kCFArrayHasCustomCallBacks = 3 /* callbacks are at end of header */ }; -/* Bits 4-5 are used by GC */ +/* + Bits 4 & 5 are reserved for GC use. + Bit 4, if set, indicates that the array is weak. + Bit 5 marks whether finalization has occured and, thus, whether to continue to do special retain/release processing of elements. + */ -static bool isStrongMemory(CFTypeRef collection) { - return ! __CFBitfieldGetValue(((const CFRuntimeBase *)collection)->_info, 4, 4); +CF_INLINE bool isStrongMemory(CFTypeRef collection) { + return __CFBitfieldGetValue(((const CFRuntimeBase *)collection)->_cfinfo[CF_INFO_BITS], 4, 4) == 0; } -static bool needsRestore(CFTypeRef collection) { - return __CFBitfieldGetValue(((const CFRuntimeBase *)collection)->_info, 5, 5); +CF_INLINE bool isWeakMemory(CFTypeRef collection) { + return __CFBitfieldGetValue(((const CFRuntimeBase *)collection)->_cfinfo[CF_INFO_BITS], 4, 4) != 0; } +CF_INLINE bool hasBeenFinalized(CFTypeRef collection) { + return __CFBitfieldGetValue(((const CFRuntimeBase *)collection)->_cfinfo[CF_INFO_BITS], 5, 5) != 0; +} + +CF_INLINE void markFinalized(CFTypeRef collection) { + __CFBitfieldSetValue(((CFRuntimeBase *)collection)->_cfinfo[CF_INFO_BITS], 5, 5, 1); +} CF_INLINE CFIndex __CFArrayGetType(CFArrayRef array) { - return __CFBitfieldGetValue(((const CFRuntimeBase *)array)->_info, 1, 0); + return __CFBitfieldGetValue(((const CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS], 1, 0); } CF_INLINE CFIndex __CFArrayGetSizeOfType(CFIndex t) { CFIndex size = 0; - switch (__CFBitfieldGetValue(t, 1, 0)) { - case __kCFArrayImmutable: - size += sizeof(struct __CFArrayImmutable); - break; - case __kCFArrayFixedMutable: - size += sizeof(struct __CFArrayFixedMutable); - break; - case __kCFArrayMutableDeque: - case __kCFArrayMutableStore: - size += sizeof(struct __CFArrayMutable); - break; - } + size += sizeof(struct __CFArray); if (__CFBitfieldGetValue(t, 3, 2) == __kCFArrayHasCustomCallBacks) { size += sizeof(CFArrayCallBacks); } @@ -131,22 +115,21 @@ CF_INLINE CFIndex __CFArrayGetSizeOfType(CFIndex t) { } CF_INLINE CFIndex __CFArrayGetCount(CFArrayRef array) { - return ((struct __CFArrayImmutable *)array)->_count; + return array->_count; } CF_INLINE void __CFArraySetCount(CFArrayRef array, CFIndex v) { - ((struct __CFArrayImmutable *)array)->_count = v; + ((struct __CFArray *)array)->_count = v; } -/* Only applies to immutable, fixed-mutable, and mutable-deque-using arrays; +/* Only applies to immutable and mutable-deque-using arrays; * Returns the bucket holding the left-most real value in the latter case. */ CF_INLINE struct __CFArrayBucket *__CFArrayGetBucketsPtr(CFArrayRef array) { switch (__CFArrayGetType(array)) { case __kCFArrayImmutable: - case __kCFArrayFixedMutable: - return (struct __CFArrayBucket *)((uint8_t *)array + __CFArrayGetSizeOfType(((CFRuntimeBase *)array)->_info)); - case __kCFArrayMutableDeque: { - struct __CFArrayDeque *deque = ((struct __CFArrayMutable *)array)->_store; + return (struct __CFArrayBucket *)((uint8_t *)array + __CFArrayGetSizeOfType(((CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS])); + case __kCFArrayDeque: { + struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store; return (struct __CFArrayBucket *)((uint8_t *)deque + sizeof(struct __CFArrayDeque) + deque->_leftIdx * sizeof(struct __CFArrayBucket)); } } @@ -157,11 +140,10 @@ CF_INLINE struct __CFArrayBucket *__CFArrayGetBucketsPtr(CFArrayRef array) { CF_INLINE struct __CFArrayBucket *__CFArrayGetBucketAtIndex(CFArrayRef array, CFIndex idx) { switch (__CFArrayGetType(array)) { case __kCFArrayImmutable: - case __kCFArrayFixedMutable: - case __kCFArrayMutableDeque: + case __kCFArrayDeque: return __CFArrayGetBucketsPtr(array) + idx; - case __kCFArrayMutableStore: { - CFStorageRef store = ((struct __CFArrayMutable *)array)->_store; + case __kCFArrayStorage: { + CFStorageRef store = (CFStorageRef)array->_store; return (struct __CFArrayBucket *)CFStorageGetValueAtIndex(store, idx, NULL); } } @@ -170,7 +152,7 @@ CF_INLINE struct __CFArrayBucket *__CFArrayGetBucketAtIndex(CFArrayRef array, CF CF_INLINE CFArrayCallBacks *__CFArrayGetCallBacks(CFArrayRef array) { CFArrayCallBacks *result = NULL; - switch (__CFBitfieldGetValue(((const CFRuntimeBase *)array)->_info, 3, 2)) { + switch (__CFBitfieldGetValue(((const CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS], 3, 2)) { case __kCFArrayHasNullCallBacks: return (CFArrayCallBacks *)&__kCFNullArrayCallBacks; case __kCFArrayHasCFTypeCallBacks: @@ -180,14 +162,11 @@ CF_INLINE CFArrayCallBacks *__CFArrayGetCallBacks(CFArrayRef array) { } switch (__CFArrayGetType(array)) { case __kCFArrayImmutable: - result = (CFArrayCallBacks *)((uint8_t *)array + sizeof(struct __CFArrayImmutable)); + result = (CFArrayCallBacks *)((uint8_t *)array + sizeof(struct __CFArray)); break; - case __kCFArrayFixedMutable: - result = (CFArrayCallBacks *)((uint8_t *)array + sizeof(struct __CFArrayFixedMutable)); - break; - case __kCFArrayMutableDeque: - case __kCFArrayMutableStore: - result = (CFArrayCallBacks *)((uint8_t *)array + sizeof(struct __CFArrayMutable)); + case __kCFArrayDeque: + case __kCFArrayStorage: + result = (CFArrayCallBacks *)((uint8_t *)array + sizeof(struct __CFArray)); break; } return result; @@ -226,8 +205,10 @@ static void __CFArrayReleaseValues(CFArrayRef array, CFRange range, bool release CFIndex idx; switch (__CFArrayGetType(array)) { case __kCFArrayImmutable: - case __kCFArrayFixedMutable: - if (NULL != cb->release && 0 < range.length) { + if (NULL != cb->release && 0 < range.length && !hasBeenFinalized(array)) { + // if we've been finalized then we know that + // 1) we're using the standard callback on GC memory + // 2) the slots don't' need to be zeroed struct __CFArrayBucket *buckets = __CFArrayGetBucketsPtr(array); allocator = __CFGetAllocator(array); for (idx = 0; idx < range.length; idx++) { @@ -236,9 +217,9 @@ static void __CFArrayReleaseValues(CFArrayRef array, CFRange range, bool release } } break; - case __kCFArrayMutableDeque: { - struct __CFArrayDeque *deque = ((struct __CFArrayMutable *)array)->_store; - if (0 < range.length && NULL != deque) { + case __kCFArrayDeque: { + struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store; + if (0 < range.length && NULL != deque && !hasBeenFinalized(array)) { struct __CFArrayBucket *buckets = __CFArrayGetBucketsPtr(array); if (NULL != cb->release) { allocator = __CFGetAllocator(array); @@ -255,14 +236,14 @@ 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); - ((struct __CFArrayMutable *)array)->_count = 0; // GC: _count == 0 ==> _store == NULL. - ((struct __CFArrayMutable *)array)->_store = NULL; + __CFArraySetCount(array, 0); // GC: _count == 0 ==> _store == NULL. + ((struct __CFArray *)array)->_store = NULL; } break; } - case __kCFArrayMutableStore: { - CFStorageRef store = ((struct __CFArrayMutable *)array)->_store; - if (NULL != cb->release && 0 < range.length) { + 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; @@ -270,25 +251,27 @@ static void __CFArrayReleaseValues(CFArrayRef array, CFRange range, bool release CFStorageApplyFunction(store, range, __CFArrayStorageRelease, &context); } if (releaseStorageIfPossible && 0 == range.location && __CFArrayGetCount(array) == range.length) { - CFRelease(store); - ((struct __CFArrayMutable *)array)->_count = 0; // GC: _count == 0 ==> _store == NULL. - ((struct __CFArrayMutable *)array)->_store = NULL; - __CFBitfieldSetValue(((CFRuntimeBase *)array)->_info, 1, 0, __kCFArrayMutableDeque); + _CFReleaseGC(store); + __CFArraySetCount(array, 0); // GC: _count == 0 ==> _store == NULL. + ((struct __CFArray *)array)->_store = NULL; + __CFBitfieldSetValue(((CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS], 1, 0, __kCFArrayDeque); } break; } } } -CF_INLINE void __CFArrayValidateRange(CFArrayRef array, CFRange range, const char *func) { #if defined(DEBUG) +CF_INLINE void __CFArrayValidateRange(CFArrayRef array, CFRange range, const char *func) { CFAssert3(0 <= range.location && range.location <= CFArrayGetCount(array), __kCFLogAssertion, "%s(): range.location index (%d) out of bounds (0, %d)", func, range.location, CFArrayGetCount(array)); CFAssert2(0 <= range.length, __kCFLogAssertion, "%s(): range.length (%d) cannot be less than zero", func, range.length); CFAssert3(range.location + range.length <= CFArrayGetCount(array), __kCFLogAssertion, "%s(): ending index (%d) out of bounds (0, %d)", func, range.location + range.length, CFArrayGetCount(array)); -#endif } +#else +#define __CFArrayValidateRange(a,r,f) +#endif -static bool __CFArrayEqual(CFTypeRef cf1, CFTypeRef cf2) { +static Boolean __CFArrayEqual(CFTypeRef cf1, CFTypeRef cf2) { CFArrayRef array1 = (CFArrayRef)cf1; CFArrayRef array2 = (CFArrayRef)cf2; const CFArrayCallBacks *cb1, *cb2; @@ -303,7 +286,10 @@ static bool __CFArrayEqual(CFTypeRef cf1, CFTypeRef cf2) { for (idx = 0; idx < cnt; idx++) { const void *val1 = __CFArrayGetBucketAtIndex(array1, idx)->_item; const void *val2 = __CFArrayGetBucketAtIndex(array2, idx)->_item; - if (val1 != val2 && cb1->equal && !INVOKE_CALLBACK2(cb1->equal, val1, val2)) return false; + if (val1 != val2) { + if (NULL == cb1->equal) return false; + if (!INVOKE_CALLBACK2(cb1->equal, val1, val2)) return false; + } } return true; } @@ -326,13 +312,10 @@ static CFStringRef __CFArrayCopyDescription(CFTypeRef cf) { case __kCFArrayImmutable: CFStringAppendFormat(result, NULL, CFSTR("{type = immutable, count = %u, values = (\n"), cf, allocator, cnt); break; - case __kCFArrayFixedMutable: - CFStringAppendFormat(result, NULL, CFSTR("{type = fixed-mutable, count = %u, capacity = %u, values = (\n"), cf, allocator, cnt, ((struct __CFArrayFixedMutable *)array)->_capacity); - break; - case __kCFArrayMutableDeque: + case __kCFArrayDeque: CFStringAppendFormat(result, NULL, CFSTR("{type = mutable-small, count = %u, values = (\n"), cf, allocator, cnt); break; - case __kCFArrayMutableStore: + case __kCFArrayStorage: CFStringAppendFormat(result, NULL, CFSTR("{type = mutable-large, count = %u, values = (\n"), cf, allocator, cnt); break; } @@ -354,15 +337,26 @@ static CFStringRef __CFArrayCopyDescription(CFTypeRef cf) { return result; } + +static void __CFResourceRelease(CFTypeRef cf, const void *ignored) { + kCFTypeArrayCallBacks.release(kCFAllocatorSystemDefault, cf); +} + static void __CFArrayDeallocate(CFTypeRef cf) { CFArrayRef array = (CFArrayRef)cf; // Under GC, keep contents alive when we know we can, either standard callbacks or NULL // if (__CFBitfieldGetValue(cf->info, 5, 4)) return; // bits only ever set under GC CFAllocatorRef allocator = __CFGetAllocator(array); if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + // XXX_PCB keep array intact during finalization. const CFArrayCallBacks *cb = __CFArrayGetCallBacks(array); if (cb->retain == NULL && cb->release == NULL) - return; // XXX_PCB keep array intact during finalization. + return; + if (cb == &kCFTypeArrayCallBacks || cb->release == kCFTypeArrayCallBacks.release) { + markFinalized(cf); + CFArrayApplyFunction((CFArrayRef)cf, CFRangeMake(0, __CFArrayGetCount(array)), (CFArrayApplierFunction)__CFResourceRelease, 0); + return; + } } __CFArrayReleaseValues(array, CFRangeMake(0, __CFArrayGetCount(array)), true); } @@ -375,7 +369,7 @@ static const CFRuntimeClass __CFArrayClass = { NULL, // init NULL, // copy __CFArrayDeallocate, - (void *)__CFArrayEqual, + __CFArrayEqual, __CFArrayHash, NULL, // __CFArrayCopyDescription @@ -390,23 +384,13 @@ CFTypeID CFArrayGetTypeID(void) { } static CFArrayRef __CFArrayInit(CFAllocatorRef allocator, UInt32 flags, CFIndex capacity, const CFArrayCallBacks *callBacks) { - struct __CFArrayImmutable *memory; + struct __CFArray *memory; UInt32 size; - CFArrayCallBacks nonRetainingCallbacks; __CFBitfieldSetValue(flags, 31, 2, 0); if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { if (!callBacks || (callBacks->retain == NULL && callBacks->release == NULL)) { __CFBitfieldSetValue(flags, 4, 4, 1); // setWeak } - else { - if (callBacks->retain == __CFTypeCollectionRetain && callBacks->release == __CFTypeCollectionRelease) { - nonRetainingCallbacks = *callBacks; - nonRetainingCallbacks.retain = NULL; - nonRetainingCallbacks.release = NULL; - callBacks = &nonRetainingCallbacks; - __CFBitfieldSetValue(flags, 5, 5, 1); // setNeedsRestore - } - } } if (__CFArrayCallBacksMatchNull(callBacks)) { __CFBitfieldSetValue(flags, 3, 2, __kCFArrayHasNullCallBacks); @@ -418,37 +402,30 @@ static CFArrayRef __CFArrayInit(CFAllocatorRef allocator, UInt32 flags, CFIndex size = __CFArrayGetSizeOfType(flags) - sizeof(CFRuntimeBase); switch (__CFBitfieldGetValue(flags, 1, 0)) { case __kCFArrayImmutable: - case __kCFArrayFixedMutable: size += capacity * sizeof(struct __CFArrayBucket); break; - case __kCFArrayMutableDeque: - case __kCFArrayMutableStore: + case __kCFArrayDeque: + case __kCFArrayStorage: break; } - memory = (struct __CFArrayImmutable *)_CFRuntimeCreateInstance(allocator, __kCFArrayTypeID, size, NULL); + memory = (struct __CFArray*)_CFRuntimeCreateInstance(allocator, __kCFArrayTypeID, size, NULL); if (NULL == memory) { return NULL; } - __CFBitfieldSetValue(memory->_base._info, 6, 0, flags); + __CFBitfieldSetValue(memory->_base._cfinfo[CF_INFO_BITS], 6, 0, flags); __CFArraySetCount((CFArrayRef)memory, 0); switch (__CFBitfieldGetValue(flags, 1, 0)) { case __kCFArrayImmutable: - if (!isStrongMemory(memory)) { // if weak, don't scan + if (isWeakMemory(memory)) { // if weak, don't scan auto_zone_set_layout_type(__CFCollectableZone, memory, AUTO_OBJECT_UNSCANNED); } if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFArray (immutable)"); break; - case __kCFArrayFixedMutable: - if (!isStrongMemory(memory)) { // if weak, don't scan - auto_zone_set_layout_type(__CFCollectableZone, memory, AUTO_OBJECT_UNSCANNED); - } - if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFArray (mutable-fixed)"); - ((struct __CFArrayFixedMutable *)memory)->_capacity = capacity; - break; - case __kCFArrayMutableDeque: - case __kCFArrayMutableStore: + case __kCFArrayDeque: + case __kCFArrayStorage: if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFArray (mutable-variable)"); - ((struct __CFArrayMutable *)memory)->_store = NULL; + ((struct __CFArray *)memory)->_mutations = 1; + ((struct __CFArray*)memory)->_store = NULL; break; } if (__kCFArrayHasCustomCallBacks == __CFBitfieldGetValue(flags, 3, 2)) { @@ -474,15 +451,20 @@ 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) ? auto_zone_base_pointer(__CFCollectableZone, buckets) : NULL; - for (idx = 0; idx < numValues; idx++) { - if (NULL != cb->retain) { + bucketsBase = CF_IS_COLLECTABLE_ALLOCATOR(bucketsAllocator) ? (void *)auto_zone_base_pointer(__CFCollectableZone, buckets) : NULL; + if (NULL != cb->retain) { + for (idx = 0; idx < numValues; idx++) { CF_WRITE_BARRIER_BASE_ASSIGN(bucketsAllocator, bucketsBase, buckets->_item, (void *)INVOKE_CALLBACK2(cb->retain, allocator, *values)); - } else { - CF_WRITE_BARRIER_BASE_ASSIGN(bucketsAllocator, bucketsBase, buckets->_item, *values); - } - values++; - buckets++; + values++; + buckets++; + } + } + else { + for (idx = 0; idx < numValues; idx++) { + CF_WRITE_BARRIER_BASE_ASSIGN(bucketsAllocator, bucketsBase, buckets->_item, *values); + values++; + buckets++; + } } __CFArraySetCount(result, numValues); return result; @@ -490,40 +472,41 @@ CFArrayRef CFArrayCreate(CFAllocatorRef allocator, const void **values, CFIndex CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFArrayCallBacks *callBacks) { CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%d) cannot be less than zero", __PRETTY_FUNCTION__, capacity); - return (CFMutableArrayRef)__CFArrayInit(allocator, (0 == capacity) ? __kCFArrayMutableDeque : __kCFArrayFixedMutable, capacity, callBacks); + 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); } // This creates an array which is for CFTypes or NSObjects, with an ownership transfer -- // the array does not take a retain, and the caller does not need to release the inserted objects. // The incoming objects must also be collectable if allocated out of a collectable allocator. -CFArrayRef _CFArrayCreate_ex(CFAllocatorRef allocator, bool mutable, const void **values, CFIndex numValues) { +CFArrayRef _CFArrayCreate_ex(CFAllocatorRef allocator, Boolean isMutable, const void **values, CFIndex numValues) { CFArrayRef result; - result = __CFArrayInit(allocator, mutable ? __kCFArrayMutableDeque : __kCFArrayImmutable, numValues, &kCFTypeArrayCallBacks); - if (!mutable) { + result = __CFArrayInit(allocator, isMutable ? __kCFArrayDeque : __kCFArrayImmutable, numValues, &kCFTypeArrayCallBacks); + if (!isMutable) { struct __CFArrayBucket *buckets = __CFArrayGetBucketsPtr(result); CF_WRITE_BARRIER_MEMMOVE(buckets, values, numValues * sizeof(struct __CFArrayBucket)); } else { if (__CF_MAX_BUCKETS_PER_DEQUE <= numValues) { - CFStorageRef store = CFStorageCreate(allocator, sizeof(const void *)); + CFStorageRef store = (CFStorageRef)CFMakeCollectable(CFStorageCreate(allocator, sizeof(const void *))); if (__CFOASafe) __CFSetLastAllocationEventName(store, "CFArray (store-storage)"); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, result, ((struct __CFArrayMutable *)result)->_store, store); + CF_WRITE_BARRIER_BASE_ASSIGN(allocator, result, result->_store, store); CFStorageInsertValues(store, CFRangeMake(0, numValues)); CFStorageReplaceValues(store, CFRangeMake(0, numValues), values); - __CFBitfieldSetValue(((CFRuntimeBase *)result)->_info, 1, 0, __kCFArrayMutableStore); + __CFBitfieldSetValue(((CFRuntimeBase *)result)->_cfinfo[CF_INFO_BITS], 1, 0, __kCFArrayStorage); } else if (0 <= numValues) { struct __CFArrayDeque *deque; struct __CFArrayBucket *raw_buckets; CFIndex capacity = __CFArrayDequeRoundUpCapacity(numValues); CFIndex size = sizeof(struct __CFArrayDeque) + capacity * sizeof(struct __CFArrayBucket); - deque = _CFAllocatorAllocateGC(allocator, size, isStrongMemory(result) ? AUTO_MEMORY_SCANNED : AUTO_MEMORY_UNSCANNED); + deque = (struct __CFArrayDeque *)_CFAllocatorAllocateGC(allocator, size, isStrongMemory(result) ? __kCFAllocatorGCScannedMemory : 0); if (__CFOASafe) __CFSetLastAllocationEventName(deque, "CFArray (store-deque)"); deque->_leftIdx = (capacity - numValues) / 2; deque->_capacity = capacity; deque->_bias = 0; - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, result, ((struct __CFArrayMutable *)result)->_store, deque); + CF_WRITE_BARRIER_BASE_ASSIGN(allocator, result, result->_store, deque); raw_buckets = (struct __CFArrayBucket *)((uint8_t *)deque + sizeof(struct __CFArrayDeque)); CF_WRITE_BARRIER_MEMMOVE(raw_buckets + deque->_leftIdx + 0, values, numValues * sizeof(struct __CFArrayBucket)); - __CFBitfieldSetValue(((CFRuntimeBase *)result)->_info, 1, 0, __kCFArrayMutableDeque); + __CFBitfieldSetValue(((CFRuntimeBase *)result)->_cfinfo[CF_INFO_BITS], 1, 0, __kCFArrayDeque); } } __CFArraySetCount(result, numValues); @@ -533,7 +516,6 @@ CFArrayRef _CFArrayCreate_ex(CFAllocatorRef allocator, bool mutable, const void CFArrayRef CFArrayCreateCopy(CFAllocatorRef allocator, CFArrayRef array) { CFArrayRef result; const CFArrayCallBacks *cb; - CFArrayCallBacks patchedCB; struct __CFArrayBucket *buckets; CFAllocatorRef bucketsAllocator; void* bucketsBase; @@ -543,20 +525,12 @@ CFArrayRef CFArrayCreateCopy(CFAllocatorRef allocator, CFArrayRef array) { cb = &kCFTypeArrayCallBacks; } else { cb = __CFArrayGetCallBacks(array); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - if (needsRestore(array)) { - patchedCB = *cb; // copy - cb = &patchedCB; // reset to copy - patchedCB.retain = __CFTypeCollectionRetain; - patchedCB.release = __CFTypeCollectionRelease; } - } - } result = __CFArrayInit(allocator, __kCFArrayImmutable, numValues, cb); 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) ? auto_zone_base_pointer(__CFCollectableZone, buckets) : NULL; + bucketsBase = CF_IS_COLLECTABLE_ALLOCATOR(bucketsAllocator) ? (void *)auto_zone_base_pointer(__CFCollectableZone, buckets) : NULL; for (idx = 0; idx < numValues; idx++) { const void *value = CFArrayGetValueAtIndex(array, idx); if (NULL != cb->retain) { @@ -574,23 +548,13 @@ CFMutableArrayRef CFArrayCreateMutableCopy(CFAllocatorRef allocator, CFIndex cap const CFArrayCallBacks *cb; CFIndex idx, numValues = CFArrayGetCount(array); UInt32 flags; - CFArrayCallBacks patchedCB; - CFAssert3(0 == capacity || numValues <= capacity, __kCFLogAssertion, "%s(): for fixed-mutable arrays, capacity (%d) must be greater than or equal to initial number of values (%d)", __PRETTY_FUNCTION__, capacity, numValues); if (CF_IS_OBJC(__kCFArrayTypeID, array)) { cb = &kCFTypeArrayCallBacks; } else { cb = __CFArrayGetCallBacks(array); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - if (needsRestore(array)) { - patchedCB = *cb; // copy - cb = &patchedCB; // reset to copy - patchedCB.retain = __CFTypeCollectionRetain; - patchedCB.release = __CFTypeCollectionRelease; - } - } } - flags = (0 == capacity) ? __kCFArrayMutableDeque : __kCFArrayFixedMutable; + flags = __kCFArrayDeque; result = (CFMutableArrayRef)__CFArrayInit(allocator, flags, capacity, cb); if (0 == capacity) _CFArraySetCapacity(result, numValues); for (idx = 0; idx < numValues; idx++) { @@ -606,15 +570,14 @@ CFIndex CFArrayGetCount(CFArrayRef array) { return __CFArrayGetCount(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, "countOccurrences:", value); -#if defined(DEBUG) __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); -#endif cb = __CFArrayGetCallBacks(array); for (idx = 0; idx < range.length; idx++) { const void *item = __CFArrayGetBucketAtIndex(array, range.location + idx)->_item; @@ -628,10 +591,8 @@ 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); -#if defined(DEBUG) __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); -#endif for (idx = 0; idx < range.length; idx++) { const void *item = __CFArrayGetBucketAtIndex(array, range.location + idx)->_item; if (value == item) { @@ -665,21 +626,18 @@ const void *_CFArrayCheckAndGetValueAtIndex(CFArrayRef array, CFIndex idx) { void CFArrayGetValues(CFArrayRef array, CFRange range, const void **values) { - CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, void, array, "getObjects:inRange:", values, range); -#if defined(DEBUG) + CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, void, array, "getObjects:range:", values, range); __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); CFAssert1(NULL != values, __kCFLogAssertion, "%s(): pointer to values may not be NULL", __PRETTY_FUNCTION__); -#endif if (0 < range.length) { switch (__CFArrayGetType(array)) { case __kCFArrayImmutable: - case __kCFArrayFixedMutable: - case __kCFArrayMutableDeque: + case __kCFArrayDeque: CF_WRITE_BARRIER_MEMMOVE(values, __CFArrayGetBucketsPtr(array) + range.location, range.length * sizeof(struct __CFArrayBucket)); break; - case __kCFArrayMutableStore: { - CFStorageRef store = ((struct __CFArrayMutable *)array)->_store; + case __kCFArrayStorage: { + CFStorageRef store = (CFStorageRef)array->_store; CFStorageGetValues(store, range, values); break; } @@ -687,15 +645,43 @@ void CFArrayGetValues(CFArrayRef array, CFRange range, const void **values) { } } + +unsigned long _CFArrayFastEnumeration(CFArrayRef array, struct __objcFastEnumerationStateEquivalent *state, void *stackbuffer, unsigned long count) { + if (array->_count == 0) return 0; + enum { ATSTART = 0, ATEND = 1 }; + switch (__CFArrayGetType(array)) { + case __kCFArrayImmutable: + if (state->state == ATSTART) { /* first time */ + static const unsigned long const_mu = 1; + state->state = ATEND; + state->mutationsPtr = (unsigned long *)&const_mu; + state->itemsPtr = (unsigned long *)__CFArrayGetBucketsPtr(array); + return array->_count; + } + return 0; + case __kCFArrayDeque: + if (state->state == ATSTART) { /* first time */ + state->state = ATEND; + state->mutationsPtr = (unsigned long *)&array->_mutations; + state->itemsPtr = (unsigned long *)__CFArrayGetBucketsPtr(array); + return array->_count; + } + return 0; + case __kCFArrayStorage: + state->mutationsPtr = (unsigned long *)&array->_mutations; + return _CFStorageFastEnumeration((CFStorageRef)array->_store, state, stackbuffer, count); + } + return 0; +} + + void CFArrayApplyFunction(CFArrayRef array, CFRange range, CFArrayApplierFunction applier, void *context) { CFIndex idx; FAULT_CALLBACK((void **)&(applier)); CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, void, array, "apply:context:", applier, context); -#if defined(DEBUG) __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); CFAssert1(NULL != applier, __kCFLogAssertion, "%s(): pointer to applier function may not be NULL", __PRETTY_FUNCTION__); -#endif for (idx = 0; idx < range.length; idx++) { const void *item = __CFArrayGetBucketAtIndex(array, range.location + idx)->_item; INVOKE_CALLBACK2(applier, item, context); @@ -706,10 +692,8 @@ CFIndex CFArrayGetFirstIndexOfValue(CFArrayRef array, CFRange range, const void const CFArrayCallBacks *cb; CFIndex idx; CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, CFIndex, array, "_cfindexOfObject:inRange:", value, range); -#if defined(DEBUG) __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); -#endif cb = __CFArrayGetCallBacks(array); for (idx = 0; idx < range.length; idx++) { const void *item = __CFArrayGetBucketAtIndex(array, range.location + idx)->_item; @@ -723,10 +707,8 @@ CFIndex CFArrayGetLastIndexOfValue(CFArrayRef array, CFRange range, const void * const CFArrayCallBacks *cb; CFIndex idx; CF_OBJC_FUNCDISPATCH2(__kCFArrayTypeID, CFIndex, array, "_cflastIndexOfObject:inRange:", value, range); -#if defined(DEBUG) __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); -#endif cb = __CFArrayGetCallBacks(array); for (idx = range.length; idx--;) { const void *item = __CFArrayGetBucketAtIndex(array, range.location + idx)->_item; @@ -756,14 +738,15 @@ void CFArraySetValueAtIndex(CFMutableArrayRef array, CFIndex idx, const void *va CFAllocatorRef allocator = __CFGetAllocator(array); CFAllocatorRef bucketsAllocator = isStrongMemory(array) ? allocator : kCFAllocatorNull; struct __CFArrayBucket *bucket = __CFArrayGetBucketAtIndex(array, idx); - if (NULL != cb->retain) { + if (NULL != cb->retain && !hasBeenFinalized(array)) { value = (void *)INVOKE_CALLBACK2(cb->retain, allocator, value); } old_value = bucket->_item; CF_WRITE_BARRIER_ASSIGN(bucketsAllocator, bucket->_item, value); // GC: handles deque/CFStorage cases. - if (NULL != cb->release) { + if (NULL != cb->release && !hasBeenFinalized(array)) { INVOKE_CALLBACK2(cb->release, allocator, old_value); } + array->_mutations++; } } @@ -788,8 +771,11 @@ void CFArrayExchangeValuesAtIndices(CFMutableArrayRef array, CFIndex idx1, CFInd bucket2 = __CFArrayGetBucketAtIndex(array, idx2); tmp = bucket1->_item; bucketsAllocator = isStrongMemory(array) ? __CFGetAllocator(array) : kCFAllocatorNull; + // XXX these aren't needed. CF_WRITE_BARRIER_ASSIGN(bucketsAllocator, bucket1->_item, bucket2->_item); CF_WRITE_BARRIER_ASSIGN(bucketsAllocator, bucket2->_item, tmp); + array->_mutations++; + } void CFArrayRemoveValueAtIndex(CFMutableArrayRef array, CFIndex idx) { @@ -806,25 +792,26 @@ void CFArrayRemoveAllValues(CFMutableArrayRef array) { CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); __CFArrayReleaseValues(array, CFRangeMake(0, __CFArrayGetCount(array)), true); __CFArraySetCount(array, 0); + array->_mutations++; } static void __CFArrayConvertDequeToStore(CFMutableArrayRef array) { - struct __CFArrayDeque *deque = ((struct __CFArrayMutable *)array)->_store; + 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); - store = CFStorageCreate(allocator, sizeof(const void *)); + store = (CFStorageRef)CFMakeCollectable(CFStorageCreate(allocator, sizeof(const void *))); if (__CFOASafe) __CFSetLastAllocationEventName(store, "CFArray (store-storage)"); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, array, ((struct __CFArrayMutable *)array)->_store, store); + CF_WRITE_BARRIER_BASE_ASSIGN(allocator, array, array->_store, store); CFStorageInsertValues(store, CFRangeMake(0, count)); CFStorageReplaceValues(store, CFRangeMake(0, count), raw_buckets + deque->_leftIdx); _CFAllocatorDeallocateGC(__CFGetAllocator(array), deque); - __CFBitfieldSetValue(((CFRuntimeBase *)array)->_info, 1, 0, __kCFArrayMutableStore); + __CFBitfieldSetValue(((CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS], 1, 0, __kCFArrayStorage); } static void __CFArrayConvertStoreToDeque(CFMutableArrayRef array) { - CFStorageRef store = ((struct __CFArrayMutable *)array)->_store; + 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 @@ -832,22 +819,22 @@ static void __CFArrayConvertStoreToDeque(CFMutableArrayRef array) { CFIndex capacity = __CFArrayDequeRoundUpCapacity(count + 6); CFIndex size = sizeof(struct __CFArrayDeque) + capacity * sizeof(struct __CFArrayBucket); CFAllocatorRef allocator = __CFGetAllocator(array); - deque = _CFAllocatorAllocateGC(allocator, size, isStrongMemory(array) ? AUTO_MEMORY_SCANNED : AUTO_MEMORY_UNSCANNED); + deque = (struct __CFArrayDeque *)_CFAllocatorAllocateGC(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0); if (__CFOASafe) __CFSetLastAllocationEventName(deque, "CFArray (store-deque)"); deque->_leftIdx = (capacity - count) / 2; deque->_capacity = capacity; deque->_bias = 0; - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, array, ((struct __CFArrayMutable *)array)->_store, deque); + CF_WRITE_BARRIER_BASE_ASSIGN(allocator, array, array->_store, 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)->_info, 1, 0, __kCFArrayMutableDeque); + _CFReleaseGC(store); // GC: balances CFMakeCollectable() above. + __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 - struct __CFArrayDeque *deque = ((struct __CFArrayMutable *)array)->_store; + struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store; struct __CFArrayBucket *buckets; CFIndex cnt, futureCnt, numNewElems; CFIndex L, A, B, C, R; @@ -865,12 +852,12 @@ static void __CFArrayRepositionDequeRegions(CFMutableArrayRef array, CFRange ran CFIndex wiggle = deque->_capacity >> 17; if (wiggle < 4) wiggle = 4; - if (deque->_capacity < futureCnt || (cnt < futureCnt && L + R < wiggle)) { + if (deque->_capacity < (uint32_t)futureCnt || (cnt < futureCnt && L + R < wiggle)) { // must be inserting or space is tight, reallocate and re-center everything CFIndex capacity = __CFArrayDequeRoundUpCapacity(futureCnt + wiggle); CFIndex size = sizeof(struct __CFArrayDeque) + capacity * sizeof(struct __CFArrayBucket); CFAllocatorRef allocator = __CFGetAllocator(array); - struct __CFArrayDeque *newDeque = _CFAllocatorAllocateGC(allocator, size, isStrongMemory(array) ? AUTO_MEMORY_SCANNED : AUTO_MEMORY_UNSCANNED); + struct __CFArrayDeque *newDeque = (struct __CFArrayDeque *)_CFAllocatorAllocateGC(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0); if (__CFOASafe) __CFSetLastAllocationEventName(newDeque, "CFArray (store-deque)"); struct __CFArrayBucket *newBuckets = (struct __CFArrayBucket *)((uint8_t *)newDeque + sizeof(struct __CFArrayDeque)); CFIndex oldL = L; @@ -879,10 +866,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) CF_WRITE_BARRIER_MEMMOVE(newBuckets + newL, buckets + oldL, A * sizeof(struct __CFArrayBucket)); if (0 < C) CF_WRITE_BARRIER_MEMMOVE(newBuckets + newC0, buckets + oldC0, C * sizeof(struct __CFArrayBucket)); if (deque) _CFAllocatorDeallocateGC(allocator, deque); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, array, ((struct __CFArrayMutable *)array)->_store, newDeque); + CF_WRITE_BARRIER_BASE_ASSIGN(allocator, array, array->_store, newDeque); return; } @@ -934,44 +922,56 @@ static void __CFArrayRepositionDequeRegions(CFMutableArrayRef array, CFRange ran } } +static void __CFArrayHandleOutOfMemory(CFTypeRef obj, CFIndex numBytes) { + CFStringRef msg = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("Attempt to allocate %ld bytes for CFArray failed"), numBytes); + CFBadErrorCallBack cb = _CFGetOutOfMemoryErrorCallBack(); + if (NULL == cb || !cb(obj, CFSTR("NS/CFArray"), msg)) { + CFLog(kCFLogLevelCritical, CFSTR("%@"), msg); + HALT; + } + CFRelease(msg); +} + // This function is for Foundation's benefit; no one else should use it. void _CFArraySetCapacity(CFMutableArrayRef array, CFIndex cap) { if (CF_IS_OBJC(__kCFArrayTypeID, array)) return; -#if defined(DEBUG) __CFGenericValidateType(array, __kCFArrayTypeID); - CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable && __CFArrayGetType(array) != __kCFArrayFixedMutable, __kCFLogAssertion, "%s(): array is immutable or fixed-mutable", __PRETTY_FUNCTION__); + CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); CFAssert3(__CFArrayGetCount(array) <= cap, __kCFLogAssertion, "%s(): desired capacity (%d) is less than count (%d)", __PRETTY_FUNCTION__, cap, __CFArrayGetCount(array)); -#endif // Currently, attempting to set the capacity of an array which is the CFStorage // variant, or set the capacity larger than __CF_MAX_BUCKETS_PER_DEQUE, has no // effect. The primary purpose of this API is to help avoid a bunch of the // resizes at the small capacities 4, 8, 16, etc. - if (__CFArrayGetType(array) == __kCFArrayMutableDeque) { - struct __CFArrayDeque *deque = ((struct __CFArrayMutable *)array)->_store; + if (__CFArrayGetType(array) == __kCFArrayDeque) { + struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store; CFIndex capacity = __CFArrayDequeRoundUpCapacity(cap); CFIndex size = sizeof(struct __CFArrayDeque) + capacity * sizeof(struct __CFArrayBucket); CFAllocatorRef allocator = __CFGetAllocator(array); if (NULL == deque) { - deque = _CFAllocatorAllocateGC(allocator, size, isStrongMemory(array) ? AUTO_MEMORY_SCANNED : AUTO_MEMORY_UNSCANNED); + deque = (struct __CFArrayDeque *)_CFAllocatorAllocateGC(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0); + if (NULL == deque) __CFArrayHandleOutOfMemory(array, size); if (__CFOASafe) __CFSetLastAllocationEventName(deque, "CFArray (store-deque)"); deque->_leftIdx = capacity / 2; } else { - deque = _CFAllocatorReallocateGC(allocator, deque, size, isStrongMemory(array) ? AUTO_MEMORY_SCANNED : AUTO_MEMORY_UNSCANNED); + struct __CFArrayDeque *olddeque = deque; + CFIndex oldcap = deque->_capacity; + deque = (struct __CFArrayDeque *)_CFAllocatorAllocateGC(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0); + if (NULL == deque) __CFArrayHandleOutOfMemory(array, size); + CF_WRITE_BARRIER_MEMMOVE(deque, olddeque, sizeof(struct __CFArrayDeque) + oldcap * sizeof(struct __CFArrayBucket)); + _CFAllocatorDeallocateGC(allocator, olddeque); if (__CFOASafe) __CFSetLastAllocationEventName(deque, "CFArray (store-deque)"); } deque->_capacity = capacity; deque->_bias = 0; - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, array, ((struct __CFArrayMutable *)array)->_store, deque); + CF_WRITE_BARRIER_BASE_ASSIGN(allocator, array, array->_store, deque); } } void CFArrayReplaceValues(CFMutableArrayRef array, CFRange range, const void **newValues, CFIndex newCount) { CF_OBJC_FUNCDISPATCH3(__kCFArrayTypeID, void, array, "replaceObjectsInRange:withObjects:count:", range, (void **)newValues, newCount); -#if defined(DEBUG) __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); -#endif CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); CFAssert2(0 <= newCount, __kCFLogAssertion, "%s(): newCount (%d) cannot be less than zero", __PRETTY_FUNCTION__, newCount); return _CFArrayReplaceValues(array, range, newValues, newCount); @@ -986,13 +986,12 @@ void _CFArrayReplaceValues(CFMutableArrayRef array, CFRange range, const void ** const void **newv, *buffer[256]; cnt = __CFArrayGetCount(array); futureCnt = cnt - range.length + newCount; - CFAssert1((__kCFArrayFixedMutable != __CFArrayGetType(array)) || (futureCnt <= ((struct __CFArrayFixedMutable *)array)->_capacity), __kCFLogAssertion, "%s(): fixed-capacity array is full (or will overflow)", __PRETTY_FUNCTION__); CFAssert1(newCount <= futureCnt, __kCFLogAssertion, "%s(): internal error 1", __PRETTY_FUNCTION__); cb = __CFArrayGetCallBacks(array); allocator = __CFGetAllocator(array); /* Retain new values if needed, possibly allocating a temporary buffer for them */ - if (NULL != cb->retain) { - newv = (newCount <= 256) ? buffer : CFAllocatorAllocate(allocator, newCount * sizeof(void *), 0); // GC OK + if (NULL != cb->retain && !hasBeenFinalized(array)) { + newv = (newCount <= 256) ? (const void **)buffer : (const void **)CFAllocatorAllocate(allocator, 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]); @@ -1000,6 +999,8 @@ void _CFArrayReplaceValues(CFMutableArrayRef array, CFRange range, const void ** } else { newv = newValues; } + array->_mutations++; + /* Now, there are three regions of interest, each of which may be empty: * A: the region from index 0 to one less than the range.location * B: the region of the range @@ -1010,29 +1011,12 @@ void _CFArrayReplaceValues(CFMutableArrayRef array, CFRange range, const void ** * to get shifted if the number of new values is different from * the length of the range being replaced. */ - if (__kCFArrayFixedMutable == __CFArrayGetType(array)) { - struct __CFArrayBucket *buckets = __CFArrayGetBucketsPtr(array); -// CF: we should treat a fixed mutable array like a deque too - if (0 < range.length) { - __CFArrayReleaseValues(array, range, false); - } - if (newCount != range.length && range.location + range.length < cnt) { - /* This neatly moves region C in the proper direction */ - CF_WRITE_BARRIER_MEMMOVE(buckets + range.location + newCount, buckets + range.location + range.length, (cnt - range.location - range.length) * sizeof(struct __CFArrayBucket)); - } - if (0 < newCount) { - CF_WRITE_BARRIER_MEMMOVE(buckets + range.location, newv, newCount * sizeof(void *)); - } - __CFArraySetCount(array, futureCnt); - if (newv != buffer && newv != newValues) CFAllocatorDeallocate(allocator, newv); // GC OK - return; - } if (0 < range.length) { __CFArrayReleaseValues(array, range, false); } // region B elements are now "dead" - if (__kCFArrayMutableStore == __CFArrayGetType(array)) { - CFStorageRef store = ((struct __CFArrayMutable *)array)->_store; + 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)); @@ -1042,31 +1026,31 @@ void _CFArrayReplaceValues(CFMutableArrayRef array, CFRange range, const void ** if (futureCnt <= __CF_MAX_BUCKETS_PER_DEQUE / 2) { __CFArrayConvertStoreToDeque(array); } - } else if (NULL == ((struct __CFArrayMutable *)array)->_store) { + } else if (NULL == array->_store) { if (__CF_MAX_BUCKETS_PER_DEQUE <= futureCnt) { - CFStorageRef store = CFStorageCreate(allocator, sizeof(const void *)); + CFStorageRef store = (CFStorageRef)CFMakeCollectable(CFStorageCreate(allocator, sizeof(const void *))); if (! isStrongMemory(array)) _CFStorageSetWeak(store); if (__CFOASafe) __CFSetLastAllocationEventName(store, "CFArray (store-storage)"); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, array, ((struct __CFArrayMutable *)array)->_store, store); + CF_WRITE_BARRIER_BASE_ASSIGN(allocator, array, array->_store, store); CFStorageInsertValues(store, CFRangeMake(0, newCount)); - __CFBitfieldSetValue(((CFRuntimeBase *)array)->_info, 1, 0, __kCFArrayMutableStore); + __CFBitfieldSetValue(((CFRuntimeBase *)array)->_cfinfo[CF_INFO_BITS], 1, 0, __kCFArrayStorage); } else if (0 <= futureCnt) { struct __CFArrayDeque *deque; CFIndex capacity = __CFArrayDequeRoundUpCapacity(futureCnt); CFIndex size = sizeof(struct __CFArrayDeque) + capacity * sizeof(struct __CFArrayBucket); - deque = _CFAllocatorAllocateGC(allocator, size, isStrongMemory(array) ? AUTO_MEMORY_SCANNED : AUTO_MEMORY_UNSCANNED); + deque = (struct __CFArrayDeque *)_CFAllocatorAllocateGC(allocator, size, isStrongMemory(array) ? __kCFAllocatorGCScannedMemory : 0); if (__CFOASafe) __CFSetLastAllocationEventName(deque, "CFArray (store-deque)"); deque->_leftIdx = (capacity - newCount) / 2; deque->_capacity = capacity; deque->_bias = 0; - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, array, ((struct __CFArrayMutable *)array)->_store, deque); + CF_WRITE_BARRIER_BASE_ASSIGN(allocator, array, array->_store, deque); } } 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 = ((struct __CFArrayMutable *)array)->_store; + 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 @@ -1078,11 +1062,11 @@ void _CFArrayReplaceValues(CFMutableArrayRef array, CFRange range, const void ** } // copy in new region B elements if (0 < newCount) { - if (__kCFArrayMutableStore == __CFArrayGetType(array)) { - CFStorageRef store = ((struct __CFArrayMutable *)array)->_store; + if (__kCFArrayStorage == __CFArrayGetType(array)) { + CFStorageRef store = (CFStorageRef)array->_store; CFStorageReplaceValues(store, CFRangeMake(range.location, newCount), newv); } else { // Deque - struct __CFArrayDeque *deque = ((struct __CFArrayMutable *)array)->_store; + struct __CFArrayDeque *deque = (struct __CFArrayDeque *)array->_store; struct __CFArrayBucket *raw_buckets = (struct __CFArrayBucket *)((uint8_t *)deque + sizeof(struct __CFArrayDeque)); CFAllocatorRef bucketsAllocator = isStrongMemory(array) ? allocator : kCFAllocatorNull; if (newCount == 1) @@ -1109,29 +1093,33 @@ static CFComparisonResult __CFArrayCompareValues(const void *v1, const void *v2, 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); -#if defined(DEBUG) __CFGenericValidateType(array, __kCFArrayTypeID); __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); -#endif 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__); + array->_mutations++; + if (1 < range.length) { struct _acompareContext ctx; struct __CFArrayBucket *bucket; ctx.func = comparator; ctx.context = context; switch (__CFArrayGetType(array)) { - case __kCFArrayFixedMutable: - case __kCFArrayMutableDeque: + case __kCFArrayDeque: bucket = __CFArrayGetBucketsPtr(array) + range.location; - if (CF_USING_COLLECTABLE_MEMORY && isStrongMemory(array)) __CFObjCWriteBarrierRange(bucket, range.length * sizeof(void *)); - CFQSortArray(bucket, range.length, sizeof(void *), (CFComparatorFunction)__CFArrayCompareValues, &ctx); + if (CF_USING_COLLECTABLE_MEMORY && isStrongMemory(array)) { + size_t size = range.length * sizeof(void*); + __CFObjCWriteBarrierRange(bucket, size); + CFQSortArray(bucket, range.length, sizeof(void *), (CFComparatorFunction)__CFArrayCompareValues, &ctx); + } else { + CFQSortArray(bucket, range.length, sizeof(void *), (CFComparatorFunction)__CFArrayCompareValues, &ctx); + } break; - case __kCFArrayMutableStore: { - CFStorageRef store = ((struct __CFArrayMutable *)array)->_store; + case __kCFArrayStorage: { + CFStorageRef store = (CFStorageRef)array->_store; CFAllocatorRef allocator = __CFGetAllocator(array); const void **values, *buffer[256]; - values = (range.length <= 256) ? buffer : CFAllocatorAllocate(allocator, range.length * sizeof(void *), 0); // GC OK + values = (range.length <= 256) ? (const void **)buffer : (const void **)CFAllocatorAllocate(allocator, 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); @@ -1144,18 +1132,14 @@ void CFArraySortValues(CFMutableArrayRef array, CFRange range, CFComparatorFunct } CFIndex CFArrayBSearchValues(CFArrayRef array, CFRange range, const void *value, CFComparatorFunction comparator, void *context) { + __CFGenericValidateType(array, __kCFArrayTypeID); + __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); - CFIndex idx = 0; FAULT_CALLBACK((void **)&(comparator)); - if (!isObjC) { -#if defined(DEBUG) - __CFGenericValidateType(array, __kCFArrayTypeID); - __CFArrayValidateRange(array, range, __PRETTY_FUNCTION__); -#endif - } - CFAssert1(NULL != comparator, __kCFLogAssertion, "%s(): pointer to comparator function may not be NULL", __PRETTY_FUNCTION__); + CFIndex idx = 0; if (range.length <= 0) return range.location; - if (isObjC || __kCFArrayMutableStore == __CFArrayGetType(array)) { + if (isObjC || __kCFArrayStorage == __CFArrayGetType(array)) { const void *item; SInt32 lg; item = CFArrayGetValueAtIndex(array, range.location + range.length - 1); @@ -1166,7 +1150,7 @@ CFIndex CFArrayBSearchValues(CFArrayRef array, CFRange range, const void *value, if ((CFComparisonResult)(INVOKE_CALLBACK3(comparator, value, item, context)) < 0) { return range.location; } - lg = CFLog2(range.length); + 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--) { @@ -1187,12 +1171,10 @@ CFIndex CFArrayBSearchValues(CFArrayRef array, CFRange range, const void *value, void CFArrayAppendArray(CFMutableArrayRef array, CFArrayRef otherArray, CFRange otherRange) { CFIndex idx; -#if defined(DEBUG) __CFGenericValidateType(array, __kCFArrayTypeID); __CFGenericValidateType(otherArray, __kCFArrayTypeID); CFAssert1(__CFArrayGetType(array) != __kCFArrayImmutable, __kCFLogAssertion, "%s(): array is immutable", __PRETTY_FUNCTION__); __CFArrayValidateRange(otherArray, otherRange, __PRETTY_FUNCTION__); -#endif for (idx = otherRange.location; idx < otherRange.location + otherRange.length; idx++) { CFArrayAppendValue(array, CFArrayGetValueAtIndex(otherArray, idx)); } diff --git a/Collections.subproj/CFArray.h b/CFArray.h similarity index 93% rename from Collections.subproj/CFArray.h rename to CFArray.h index 7c507e7..1e68a76 100644 --- a/Collections.subproj/CFArray.h +++ b/CFArray.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFArray.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ /*! @@ -40,14 +40,9 @@ Arrays come in two flavors, immutable, which cannot have values added to them or removed from them after the array is created, and mutable, to which you can add values or from which remove values. - Mutable arrays have two subflavors, fixed-capacity, for which there - is a maximum number set at creation time of values which can be put - into the array, and variable capacity, which can have an unlimited - number of values (or rather, limited only by constraints external - to CFArray, like the amount of available memory). Fixed-capacity - arrays can be somewhat higher performing, if you can put a definite - upper limit on the number of values that might be put into the - array. + Mutable arrays can have an unlimited number of values (or rather, + limited only by constraints external to CFArray, like the amount + of available memory). As with all CoreFoundation collection types, arrays maintain hard references on the values you put in them, but the retaining and @@ -73,9 +68,7 @@ #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN /*! @typedef CFArrayCallBacks @@ -230,13 +223,12 @@ CFArrayRef CFArrayCreateCopy(CFAllocatorRef allocator, CFArrayRef theArray); parameter may be NULL in which case the current default CFAllocator is used. If this reference is not a valid CFAllocator, the behavior is undefined. - @param capacity The maximum number of values that can be contained - by the CFArray. The array starts empty, and can grow to this - number of values (and it can have less). If this parameter - is 0, the array's maximum capacity is unlimited (or rather, - only limited by address space and available memory - constraints). If this parameter is negative, the behavior is - undefined. + @param capacity A hint about the number of values that will be held + by the CFArray. Pass 0 for no hint. The implementation may + ignore this hint, or may use it to optimize various + operations. An array's actual capacity is only limited by + address space and available memory constraints). If this + parameter is negative, the behavior is undefined. @param callBacks A pointer to a CFArrayCallBacks structure initialized with the callbacks for the array to use on each value in the array. A copy of the contents of the @@ -248,7 +240,7 @@ CFArrayRef CFArrayCreateCopy(CFAllocatorRef allocator, CFArrayRef theArray); NULL, in which case the CFArray will do nothing to add a retain to the contained values for the array. The release field may be NULL, in which case the CFArray will do nothing - to remove the arrays retain (if any) on the values when the + to remove the array's retain (if any) on the values when the array is destroyed. If the copyDescription field is NULL, the array will create a simple description for the value. If the equal field is NULL, the array will use pointer equality @@ -275,12 +267,12 @@ CFMutableArrayRef CFArrayCreateMutable(CFAllocatorRef allocator, CFIndex capacit parameter may be NULL in which case the current default CFAllocator is used. If this reference is not a valid CFAllocator, the behavior is undefined. - @param capacity The maximum number of values that can be contained - by the CFArray. The array starts empty, and can grow to this - number of values (and it can have less). If this parameter - is 0, the array's maximum capacity is unlimited (or rather, - only limited by address space and available memory - constraints). This parameter must be greater than or equal + @param capacity A hint about the number of values that will be held + by the CFArray. Pass 0 for no hint. The implementation may + ignore this hint, or may use it to optimize various + operations. An array's actual capacity is only limited by + address space and available memory constraints). + This parameter must be greater than or equal to the count of the array which is to be copied, or the behavior is undefined. If this parameter is negative, the behavior is undefined. @@ -509,8 +501,7 @@ CFIndex CFArrayBSearchValues(CFArrayRef theArray, CFRange range, const void *val Adds the value to the array giving it a new largest index. @param theArray The array to which the value is to be added. If this parameter is not a valid mutable CFArray, the behavior is - undefined. If the array is a fixed-capacity array and it - is full before this operation, the behavior is undefined. + undefined. @param value The value to add to the array. The value is retained by the array using the retain callback provided when the array was created. If the value is not of the sort expected by the @@ -526,8 +517,7 @@ void CFArrayAppendValue(CFMutableArrayRef theArray, const void *value); Adds the value to the array, giving it the given index. @param theArray The array to which the value is to be added. If this parameter is not a valid mutable CFArray, the behavior is - undefined. If the array is a fixed-capacity array and it - is full before this operation, the behavior is undefined. + undefined. @param idx The index to which to add the new value. If the index is outside the index space of the array (0 to N inclusive, where N is the count of the array before the operation), the @@ -548,9 +538,7 @@ void CFArrayInsertValueAtIndex(CFMutableArrayRef theArray, CFIndex idx, const vo Changes the value with the given index in the array. @param theArray The array in which the value is to be changed. If this parameter is not a valid mutable CFArray, the behavior is - undefined. If the array is a fixed-capacity array and it - is full before this operation and the index is the same as - N, the behavior is undefined. + undefined. @param idx The index to which to set the new value. If the index is outside the index space of the array (0 to N inclusive, where N is the count of the array before the operation), the @@ -677,10 +665,7 @@ void CFArraySortValues(CFMutableArrayRef theArray, CFRange range, CFComparatorFu Adds the values from an array to another array. @param theArray The array to which values from the otherArray are to be added. If this parameter is not a valid mutable CFArray, - the behavior is undefined. If the array is a fixed-capacity - array and adding range.length values from the otherArray - exceeds the capacity of the array, the behavior is - undefined. + the behavior is undefined. @param otherArray The array providing the values to be added to the array. If this parameter is not a valid CFArray, the behavior is undefined. @@ -702,9 +687,7 @@ void CFArraySortValues(CFMutableArrayRef theArray, CFRange range, CFComparatorFu CF_EXPORT void CFArrayAppendArray(CFMutableArrayRef theArray, CFArrayRef otherArray, CFRange otherRange); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFARRAY__ */ diff --git a/CFBag.c b/CFBag.c new file mode 100644 index 0000000..d4a63fa --- /dev/null +++ b/CFBag.c @@ -0,0 +1,1467 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFBag.c + Copyright 1998-2006, Apple, Inc. All rights reserved. + Responsibility: Christopher Kane + Machine generated from Notes/HashingCode.template +*/ + + + + +#include +#include "CFInternal.h" +#include + +#define CFDictionary 0 +#define CFSet 0 +#define CFBag 0 +#undef CFBag +#define CFBag 1 + +#if CFDictionary +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}; +static const CFBagKeyCallBacks __kCFNullBagKeyCallBacks = {0, NULL, NULL, NULL, NULL, NULL}; +static const CFBagValueCallBacks __kCFNullBagValueCallBacks = {0, NULL, NULL, NULL, NULL}; + +#define CFHashRef CFDictionaryRef +#define CFMutableHashRef CFMutableDictionaryRef +#define __kCFHashTypeID __kCFDictionaryTypeID +#endif + +#if CFSet +const CFBagCallBacks kCFTypeBagCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; +const CFBagCallBacks kCFCopyStringBagCallBacks = {0, __CFStringCollectionCopy, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; +static const CFBagCallBacks __kCFNullBagCallBacks = {0, NULL, NULL, NULL, NULL, NULL}; + +#define CFBagKeyCallBacks CFBagCallBacks +#define CFBagValueCallBacks CFBagCallBacks +#define kCFTypeBagKeyCallBacks kCFTypeBagCallBacks +#define kCFTypeBagValueCallBacks kCFTypeBagCallBacks +#define __kCFNullBagKeyCallBacks __kCFNullBagCallBacks +#define __kCFNullBagValueCallBacks __kCFNullBagCallBacks + +#define CFHashRef CFSetRef +#define CFMutableHashRef CFMutableSetRef +#define __kCFHashTypeID __kCFSetTypeID +#endif + +#if CFBag +const CFBagCallBacks kCFTypeBagCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; +const CFBagCallBacks kCFCopyStringBagCallBacks = {0, __CFStringCollectionCopy, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; +static const CFBagCallBacks __kCFNullBagCallBacks = {0, NULL, NULL, NULL, NULL, NULL}; + +#define CFBagKeyCallBacks CFBagCallBacks +#define CFBagValueCallBacks CFBagCallBacks +#define kCFTypeBagKeyCallBacks kCFTypeBagCallBacks +#define kCFTypeBagValueCallBacks kCFTypeBagCallBacks +#define __kCFNullBagKeyCallBacks __kCFNullBagCallBacks +#define __kCFNullBagValueCallBacks __kCFNullBagCallBacks + +#define CFHashRef CFBagRef +#define CFMutableHashRef CFMutableBagRef +#define __kCFHashTypeID __kCFBagTypeID +#endif + +#define GETNEWKEY(newKey, oldKey) \ + any_t (*kretain)(CFAllocatorRef, any_t, any_pointer_t) = \ + !hasBeenFinalized(hc) \ + ? (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))__CFBagGetKeyCallBacks(hc)->retain \ + : (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))0; \ + any_t newKey = kretain ? (any_t)INVOKE_CALLBACK3(kretain, allocator, (any_t)key, hc->_context) : (any_t)oldKey + +#define RELEASEKEY(oldKey) \ + void (*krelease)(CFAllocatorRef, any_t, any_pointer_t) = \ + !hasBeenFinalized(hc) \ + ? (void (*)(CFAllocatorRef,any_t,any_pointer_t))__CFBagGetKeyCallBacks(hc)->release \ + : (void (*)(CFAllocatorRef,any_t,any_pointer_t))0; \ + if (krelease) INVOKE_CALLBACK3(krelease, allocator, oldKey, hc->_context) + +#if CFDictionary +#define GETNEWVALUE(newValue) \ + any_t (*vretain)(CFAllocatorRef, any_t, any_pointer_t) = \ + !hasBeenFinalized(hc) \ + ? (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))__CFBagGetValueCallBacks(hc)->retain \ + : (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))0; \ + any_t newValue = vretain ? (any_t)INVOKE_CALLBACK3(vretain, allocator, (any_t)value, hc->_context) : (any_t)value + +#define RELEASEVALUE(oldValue) \ + void (*vrelease)(CFAllocatorRef, any_t, any_pointer_t) = \ + !hasBeenFinalized(hc) \ + ? (void (*)(CFAllocatorRef,any_t,any_pointer_t))__CFBagGetValueCallBacks(hc)->release \ + : (void (*)(CFAllocatorRef,any_t,any_pointer_t))0; \ + if (vrelease) INVOKE_CALLBACK3(vrelease, allocator, oldValue, hc->_context) + +#endif + +static void __CFBagHandleOutOfMemory(CFTypeRef obj, CFIndex numBytes) { + CFStringRef msg = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("Attempt to allocate %ld bytes for NS/CFBag failed"), numBytes); + CFBadErrorCallBack cb = _CFGetOutOfMemoryErrorCallBack(); + if (NULL == cb || !cb(obj, CFSTR("NS/CFBag"), msg)) { + CFLog(kCFLogLevelCritical, CFSTR("%@"), msg); + HALT; + } + CFRelease(msg); +} + + +// Max load is 3/4 number of buckets +CF_INLINE CFIndex __CFHashRoundUpCapacity(CFIndex capacity) { + return 3 * ((CFIndex)1 << (flsl((capacity - 1) / 3))); +} + +// Returns next power of two higher than the capacity +// threshold for the given input capacity. +CF_INLINE CFIndex __CFHashNumBucketsForCapacity(CFIndex capacity) { + return 4 * ((CFIndex)1 << (flsl((capacity - 1) / 3))); +} + +enum { /* Bits 1-0 */ + __kCFHashImmutable = 0, /* unchangable and fixed capacity */ + __kCFHashMutable = 1, /* changeable and variable capacity */ +}; + +enum { /* Bits 5-4 (value), 3-2 (key) */ + __kCFHashHasNullCallBacks = 0, + __kCFHashHasCFTypeCallBacks = 1, + __kCFHashHasCustomCallBacks = 3 /* callbacks are at end of header */ +}; + +// Under GC, we fudge the key/value memory in two ways +// First, if we had null callbacks or null for both retain/release, we use unscanned memory and get +// standard 'dangling' references. +// This means that if people were doing addValue:[xxx new] and never removing, well, that doesn't work +// +// Second, if we notice standard retain/release implementations we use scanned memory, and fudge the +// standard callbacks to generally do nothing if the collection was allocated in GC memory. On special +// CF objects, however, like those used for precious resources like video-card buffers, we do indeed +// do CFRetain on input and CFRelease on output. The tricky case is GC finalization; we need to remember +// that we did the CFReleases so that subsequent collection operations, like removal, don't double CFRelease. +// (In fact we don't really use CFRetain/CFRelease but go directly to the collector) +// + +enum { + __kCFHashFinalized = (1 << 7), + __kCFHashWeakKeys = (1 << 8), + __kCFHashWeakValues = (1 << 9) +}; + +typedef uintptr_t any_t; +typedef const void * const_any_pointer_t; +typedef void * any_pointer_t; + +struct __CFBag { + CFRuntimeBase _base; + CFIndex _count; /* number of values */ + CFIndex _bucketsNum; /* number of buckets */ + CFIndex _bucketsUsed; /* number of used buckets */ + CFIndex _bucketsCap; /* maximum number of used buckets */ + CFIndex _mutations; + CFIndex _deletes; + any_pointer_t _context; /* private */ + CFOptionFlags _xflags; + any_t _marker; + any_t *_keys; /* can be NULL if not allocated yet */ + any_t *_values; /* can be NULL if not allocated yet */ +}; + +/* Bits 1-0 of the _xflags are used for mutability variety */ +/* Bits 3-2 of the _xflags are used for key callback indicator bits */ +/* Bits 5-4 of the _xflags are used for value callback indicator bits */ +/* Bit 6 of the _xflags is special KVO actions bit */ +/* Bits 7,8,9 are GC use */ + +CF_INLINE bool hasBeenFinalized(CFTypeRef collection) { + return __CFBitfieldGetValue(((const struct __CFBag *)collection)->_xflags, 7, 7) != 0; +} + +CF_INLINE void markFinalized(CFTypeRef collection) { + __CFBitfieldSetValue(((struct __CFBag *)collection)->_xflags, 7, 7, 1); +} + + +CF_INLINE CFIndex __CFHashGetType(CFHashRef hc) { + return __CFBitfieldGetValue(hc->_xflags, 1, 0); +} + +CF_INLINE CFIndex __CFBagGetSizeOfType(CFIndex t) { + CFIndex size = sizeof(struct __CFBag); + if (__CFBitfieldGetValue(t, 3, 2) == __kCFHashHasCustomCallBacks) { + size += sizeof(CFBagKeyCallBacks); + } + if (__CFBitfieldGetValue(t, 5, 4) == __kCFHashHasCustomCallBacks) { + size += sizeof(CFBagValueCallBacks); + } + return size; +} + +CF_INLINE const CFBagKeyCallBacks *__CFBagGetKeyCallBacks(CFHashRef hc) { + CFBagKeyCallBacks *result = NULL; + switch (__CFBitfieldGetValue(hc->_xflags, 3, 2)) { + case __kCFHashHasNullCallBacks: + return &__kCFNullBagKeyCallBacks; + case __kCFHashHasCFTypeCallBacks: + return &kCFTypeBagKeyCallBacks; + case __kCFHashHasCustomCallBacks: + break; + } + result = (CFBagKeyCallBacks *)((uint8_t *)hc + sizeof(struct __CFBag)); + return result; +} + +CF_INLINE Boolean __CFBagKeyCallBacksMatchNull(const CFBagKeyCallBacks *c) { + return (NULL == c || + (c->retain == __kCFNullBagKeyCallBacks.retain && + c->release == __kCFNullBagKeyCallBacks.release && + c->copyDescription == __kCFNullBagKeyCallBacks.copyDescription && + c->equal == __kCFNullBagKeyCallBacks.equal && + c->hash == __kCFNullBagKeyCallBacks.hash)); +} + +CF_INLINE Boolean __CFBagKeyCallBacksMatchCFType(const CFBagKeyCallBacks *c) { + return (&kCFTypeBagKeyCallBacks == c || + (c->retain == kCFTypeBagKeyCallBacks.retain && + c->release == kCFTypeBagKeyCallBacks.release && + c->copyDescription == kCFTypeBagKeyCallBacks.copyDescription && + c->equal == kCFTypeBagKeyCallBacks.equal && + c->hash == kCFTypeBagKeyCallBacks.hash)); +} + +CF_INLINE const CFBagValueCallBacks *__CFBagGetValueCallBacks(CFHashRef hc) { + CFBagValueCallBacks *result = NULL; + switch (__CFBitfieldGetValue(hc->_xflags, 5, 4)) { + case __kCFHashHasNullCallBacks: + return &__kCFNullBagValueCallBacks; + case __kCFHashHasCFTypeCallBacks: + return &kCFTypeBagValueCallBacks; + case __kCFHashHasCustomCallBacks: + break; + } + if (__CFBitfieldGetValue(hc->_xflags, 3, 2) == __kCFHashHasCustomCallBacks) { + result = (CFBagValueCallBacks *)((uint8_t *)hc + sizeof(struct __CFBag) + sizeof(CFBagKeyCallBacks)); + } else { + result = (CFBagValueCallBacks *)((uint8_t *)hc + sizeof(struct __CFBag)); + } + return result; +} + +CF_INLINE Boolean __CFBagValueCallBacksMatchNull(const CFBagValueCallBacks *c) { + return (NULL == c || + (c->retain == __kCFNullBagValueCallBacks.retain && + c->release == __kCFNullBagValueCallBacks.release && + c->copyDescription == __kCFNullBagValueCallBacks.copyDescription && + c->equal == __kCFNullBagValueCallBacks.equal)); +} + +CF_INLINE Boolean __CFBagValueCallBacksMatchCFType(const CFBagValueCallBacks *c) { + return (&kCFTypeBagValueCallBacks == c || + (c->retain == kCFTypeBagValueCallBacks.retain && + c->release == kCFTypeBagValueCallBacks.release && + c->copyDescription == kCFTypeBagValueCallBacks.copyDescription && + c->equal == kCFTypeBagValueCallBacks.equal)); +} + +CFIndex _CFBagGetKVOBit(CFHashRef hc) { + return __CFBitfieldGetValue(hc->_xflags, 6, 6); +} + +void _CFBagSetKVOBit(CFHashRef hc, CFIndex bit) { + __CFBitfieldSetValue(((CFMutableHashRef)hc)->_xflags, 6, 6, ((uintptr_t)bit & 0x1)); +} + +CF_INLINE Boolean __CFBagShouldShrink(CFHashRef hc) { + return (__kCFHashMutable == __CFHashGetType(hc)) && + !(CF_USING_COLLECTABLE_MEMORY && auto_zone_is_finalized(__CFCollectableZone, hc)) && /* GC: don't shrink finalizing hcs! */ + (hc->_bucketsNum < 4 * hc->_deletes || (256 <= hc->_bucketsCap && hc-> _bucketsUsed < 3 * hc->_bucketsCap / 16)); +} + +CF_INLINE CFIndex __CFHashGetOccurrenceCount(CFHashRef hc, CFIndex idx) { +#if CFBag + return hc->_values[idx]; +#endif + return 1; +} + +CF_INLINE Boolean __CFHashKeyIsValue(CFHashRef hc, any_t key) { + return (hc->_marker != key && ~hc->_marker != key) ? true : false; +} + +CF_INLINE Boolean __CFHashKeyIsMagic(CFHashRef hc, any_t key) { + return (hc->_marker == key || ~hc->_marker == key) ? true : false; +} + + +#if !defined(CF_OBJC_KVO_WILLCHANGE) +#define CF_OBJC_KVO_WILLCHANGE(obj, key) +#define CF_OBJC_KVO_DIDCHANGE(obj, key) +#endif + +CF_INLINE uintptr_t __CFBagScrambleHash(uintptr_t k) { +#if 0 + return k; +#else +#if __LP64__ + uintptr_t a = 0x4368726973746F70ULL; + uintptr_t b = 0x686572204B616E65ULL; +#else + uintptr_t a = 0x4B616E65UL; + uintptr_t b = 0x4B616E65UL; +#endif + uintptr_t c = 1; + a += k; +#if __LP64__ + a -= b; a -= c; a ^= (c >> 43); + b -= c; b -= a; b ^= (a << 9); + c -= a; c -= b; c ^= (b >> 8); + a -= b; a -= c; a ^= (c >> 38); + b -= c; b -= a; b ^= (a << 23); + c -= a; c -= b; c ^= (b >> 5); + a -= b; a -= c; a ^= (c >> 35); + b -= c; b -= a; b ^= (a << 49); + c -= a; c -= b; c ^= (b >> 11); + a -= b; a -= c; a ^= (c >> 12); + b -= c; b -= a; b ^= (a << 18); + c -= a; c -= b; c ^= (b >> 22); +#else + a -= b; a -= c; a ^= (c >> 13); + b -= c; b -= a; b ^= (a << 8); + c -= a; c -= b; c ^= (b >> 13); + a -= b; a -= c; a ^= (c >> 12); + b -= c; b -= a; b ^= (a << 16); + c -= a; c -= b; c ^= (b >> 5); + a -= b; a -= c; a ^= (c >> 3); + b -= c; b -= a; b ^= (a << 10); + c -= a; c -= b; c ^= (b >> 15); +#endif + return c; +#endif +} + +static CFIndex __CFBagFindBuckets1a(CFHashRef hc, any_t key) { + CFHashCode keyHash = (CFHashCode)key; + keyHash = __CFBagScrambleHash(keyHash); + any_t *keys = hc->_keys; + any_t marker = hc->_marker; + CFIndex probe = keyHash & (hc->_bucketsNum - 1); + CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value + CFIndex start = probe; + for (;;) { + any_t currKey = keys[probe]; + if (marker == currKey) { /* empty */ + return kCFNotFound; + } else if (~marker == currKey) { /* deleted */ + /* do nothing */ + } else if (currKey == key) { + return probe; + } + probe = probe + probeskip; + // This alternative to probe % buckets assumes that + // probeskip is always positive and less than the + // number of buckets. + if (hc->_bucketsNum <= probe) { + probe -= hc->_bucketsNum; + } + if (start == probe) { + return kCFNotFound; + } + } +} + +static CFIndex __CFBagFindBuckets1b(CFHashRef hc, any_t key) { + const CFBagKeyCallBacks *cb = __CFBagGetKeyCallBacks(hc); + CFHashCode keyHash = cb->hash ? (CFHashCode)INVOKE_CALLBACK2(((CFHashCode (*)(any_t, any_pointer_t))cb->hash), key, hc->_context) : (CFHashCode)key; + keyHash = __CFBagScrambleHash(keyHash); + any_t *keys = hc->_keys; + any_t marker = hc->_marker; + CFIndex probe = keyHash & (hc->_bucketsNum - 1); + CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value + CFIndex start = probe; + for (;;) { + any_t currKey = keys[probe]; + if (marker == currKey) { /* empty */ + return kCFNotFound; + } else if (~marker == currKey) { /* deleted */ + /* do nothing */ + } else if (currKey == key || (cb->equal && INVOKE_CALLBACK3((Boolean (*)(any_t, any_t, any_pointer_t))cb->equal, currKey, key, hc->_context))) { + return probe; + } + probe = probe + probeskip; + // This alternative to probe % buckets assumes that + // probeskip is always positive and less than the + // number of buckets. + if (hc->_bucketsNum <= probe) { + probe -= hc->_bucketsNum; + } + if (start == probe) { + return kCFNotFound; + } + } +} + +CF_INLINE CFIndex __CFBagFindBuckets1(CFHashRef hc, any_t key) { + if (__kCFHashHasNullCallBacks == __CFBitfieldGetValue(hc->_xflags, 3, 2)) { + return __CFBagFindBuckets1a(hc, key); + } + return __CFBagFindBuckets1b(hc, key); +} + +static void __CFBagFindBuckets2(CFHashRef hc, any_t key, CFIndex *match, CFIndex *nomatch) { + const CFBagKeyCallBacks *cb = __CFBagGetKeyCallBacks(hc); + CFHashCode keyHash = cb->hash ? (CFHashCode)INVOKE_CALLBACK2(((CFHashCode (*)(any_t, any_pointer_t))cb->hash), key, hc->_context) : (CFHashCode)key; + keyHash = __CFBagScrambleHash(keyHash); + any_t *keys = hc->_keys; + any_t marker = hc->_marker; + CFIndex probe = keyHash & (hc->_bucketsNum - 1); + CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value + CFIndex start = probe; + *match = kCFNotFound; + *nomatch = kCFNotFound; + for (;;) { + any_t currKey = keys[probe]; + if (marker == currKey) { /* empty */ + if (nomatch) *nomatch = probe; + return; + } else if (~marker == currKey) { /* deleted */ + if (nomatch) { + *nomatch = probe; + nomatch = NULL; + } + } else if (currKey == key || (cb->equal && INVOKE_CALLBACK3((Boolean (*)(any_t, any_t, any_pointer_t))cb->equal, currKey, key, hc->_context))) { + *match = probe; + return; + } + probe = probe + probeskip; + // This alternative to probe % buckets assumes that + // probeskip is always positive and less than the + // number of buckets. + if (hc->_bucketsNum <= probe) { + probe -= hc->_bucketsNum; + } + if (start == probe) { + return; + } + } +} + +static void __CFBagFindNewMarker(CFHashRef hc) { + any_t *keys = hc->_keys; + any_t newMarker; + CFIndex idx, nbuckets; + Boolean hit; + + nbuckets = hc->_bucketsNum; + newMarker = hc->_marker; + do { + newMarker--; + hit = false; + for (idx = 0; idx < nbuckets; idx++) { + if (newMarker == keys[idx] || ~newMarker == keys[idx]) { + hit = true; + break; + } + } + } while (hit); + for (idx = 0; idx < nbuckets; idx++) { + if (hc->_marker == keys[idx]) { + keys[idx] = newMarker; + } else if (~hc->_marker == keys[idx]) { + keys[idx] = ~newMarker; + } + } + ((struct __CFBag *)hc)->_marker = newMarker; +} + +static Boolean __CFBagEqual(CFTypeRef cf1, CFTypeRef cf2) { + CFHashRef hc1 = (CFHashRef)cf1; + CFHashRef hc2 = (CFHashRef)cf2; + const CFBagKeyCallBacks *cb1, *cb2; + const CFBagValueCallBacks *vcb1, *vcb2; + any_t *keys; + CFIndex idx, nbuckets; + if (hc1 == hc2) return true; + if (hc1->_count != hc2->_count) return false; + cb1 = __CFBagGetKeyCallBacks(hc1); + cb2 = __CFBagGetKeyCallBacks(hc2); + if (cb1->equal != cb2->equal) return false; + vcb1 = __CFBagGetValueCallBacks(hc1); + vcb2 = __CFBagGetValueCallBacks(hc2); + if (vcb1->equal != vcb2->equal) return false; + if (0 == hc1->_bucketsUsed) return true; /* after function comparison! */ + keys = hc1->_keys; + nbuckets = hc1->_bucketsNum; + for (idx = 0; idx < nbuckets; idx++) { + if (hc1->_marker != keys[idx] && ~hc1->_marker != keys[idx]) { +#if CFDictionary + const_any_pointer_t value; + if (!CFBagGetValueIfPresent(hc2, (any_pointer_t)keys[idx], &value)) return false; + if (hc1->_values[idx] != (any_t)value) { + if (NULL == vcb1->equal) return false; + if (!INVOKE_CALLBACK3((Boolean (*)(any_t, any_t, any_pointer_t))vcb1->equal, hc1->_values[idx], (any_t)value, hc1->_context)) return false; + } +#endif +#if CFSet + const_any_pointer_t value; + if (!CFBagGetValueIfPresent(hc2, (any_pointer_t)keys[idx], &value)) return false; +#endif +#if CFBag + if (hc1->_values[idx] != CFBagGetCountOfValue(hc2, (any_pointer_t)keys[idx])) return false; +#endif + } + } + return true; +} + +static CFHashCode __CFBagHash(CFTypeRef cf) { + CFHashRef hc = (CFHashRef)cf; + return hc->_count; +} + +static CFStringRef __CFBagCopyDescription(CFTypeRef cf) { + CFHashRef hc = (CFHashRef)cf; + CFAllocatorRef allocator; + const CFBagKeyCallBacks *cb; + const CFBagValueCallBacks *vcb; + any_t *keys; + CFIndex idx, nbuckets; + CFMutableStringRef result; + cb = __CFBagGetKeyCallBacks(hc); + vcb = __CFBagGetValueCallBacks(hc); + keys = hc->_keys; + nbuckets = hc->_bucketsNum; + allocator = CFGetAllocator(hc); + result = CFStringCreateMutable(allocator, 0); + const char *type = "?"; + switch (__CFHashGetType(hc)) { + case __kCFHashImmutable: type = "immutable"; break; + case __kCFHashMutable: type = "mutable"; break; + } + CFStringAppendFormat(result, NULL, CFSTR("{type = %s, count = %u, capacity = %u, pairs = (\n"), cf, allocator, type, hc->_count, hc->_bucketsCap); + for (idx = 0; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + CFStringRef kDesc = NULL, vDesc = NULL; + if (NULL != cb->copyDescription) { + kDesc = (CFStringRef)INVOKE_CALLBACK2(((CFStringRef (*)(any_t, any_pointer_t))cb->copyDescription), keys[idx], hc->_context); + } + if (NULL != vcb->copyDescription) { + vDesc = (CFStringRef)INVOKE_CALLBACK2(((CFStringRef (*)(any_t, any_pointer_t))vcb->copyDescription), hc->_values[idx], hc->_context); + } +#if CFDictionary + if (NULL != kDesc && NULL != vDesc) { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@ = %@\n"), idx, kDesc, vDesc); + CFRelease(kDesc); + CFRelease(vDesc); + } else if (NULL != kDesc) { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@ = <%p>\n"), idx, kDesc, hc->_values[idx]); + CFRelease(kDesc); + } else if (NULL != vDesc) { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p> = %@\n"), idx, keys[idx], vDesc); + CFRelease(vDesc); + } else { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p> = <%p>\n"), idx, keys[idx], hc->_values[idx]); + } +#endif +#if CFSet + if (NULL != kDesc) { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@\n"), idx, kDesc); + CFRelease(kDesc); + } else { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p>\n"), idx, keys[idx]); + } +#endif +#if CFBag + if (NULL != kDesc) { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@ (%ld)\n"), idx, kDesc, hc->_values[idx]); + CFRelease(kDesc); + } else { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p> (%ld)\n"), idx, keys[idx], hc->_values[idx]); + } +#endif + } + } + CFStringAppend(result, CFSTR(")}")); + return result; +} + +static void __CFBagDeallocate(CFTypeRef cf) { + CFMutableHashRef hc = (CFMutableHashRef)cf; + CFAllocatorRef allocator = __CFGetAllocator(hc); + const CFBagKeyCallBacks *cb = __CFBagGetKeyCallBacks(hc); + const CFBagValueCallBacks *vcb = __CFBagGetValueCallBacks(hc); + + // mark now in case any callout somehow tries to add an entry back in + markFinalized(cf); + if (vcb->release || cb->release) { + any_t *keys = hc->_keys; + CFIndex idx, nbuckets = hc->_bucketsNum; + for (idx = 0; idx < nbuckets; idx++) { + any_t oldkey = keys[idx]; + if (hc->_marker != oldkey && ~hc->_marker != oldkey) { + if (vcb->release) { + INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, any_t, any_pointer_t))vcb->release), allocator, hc->_values[idx], hc->_context); + } + if (cb->release) { + INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, any_t, any_pointer_t))cb->release), allocator, oldkey, hc->_context); + } + } + } + } + + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + // return early so that contents are preserved after finalization + return; + } + + _CFAllocatorDeallocateGC(allocator, hc->_keys); +#if CFDictionary || CFBag + _CFAllocatorDeallocateGC(allocator, hc->_values); +#endif + hc->_keys = NULL; + hc->_values = NULL; + hc->_count = 0; // GC: also zero count, so the hc will appear empty. + hc->_bucketsUsed = 0; + hc->_bucketsNum = 0; +} + +static CFTypeID __kCFBagTypeID = _kCFRuntimeNotATypeID; + +static const CFRuntimeClass __CFBagClass = { + _kCFRuntimeScannedObject, + "CFBag", + NULL, // init + NULL, // copy + __CFBagDeallocate, + __CFBagEqual, + __CFBagHash, + NULL, // + __CFBagCopyDescription +}; + +__private_extern__ void __CFBagInitialize(void) { + __kCFHashTypeID = _CFRuntimeRegisterClass(&__CFBagClass); +} + +CFTypeID CFBagGetTypeID(void) { + return __kCFHashTypeID; +} + +static CFMutableHashRef __CFBagInit(CFAllocatorRef allocator, CFOptionFlags flags, CFIndex capacity, const CFBagKeyCallBacks *keyCallBacks +#if CFDictionary +, const CFBagValueCallBacks *valueCallBacks +#endif +) { + struct __CFBag *hc; + CFIndex size; + __CFBitfieldSetValue(flags, 31, 2, 0); + CFOptionFlags xflags = 0; + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + // preserve NULL for key or value CB, otherwise fix up. + if (!keyCallBacks || (keyCallBacks->retain == NULL && keyCallBacks->release == NULL)) { + xflags = __kCFHashWeakKeys; + } +#if CFDictionary + if (!valueCallBacks || (valueCallBacks->retain == NULL && valueCallBacks->release == NULL)) { + xflags |= __kCFHashWeakValues; + } +#endif +#if CFBag + xflags |= __kCFHashWeakValues; +#endif + } + if (__CFBagKeyCallBacksMatchNull(keyCallBacks)) { + __CFBitfieldSetValue(flags, 3, 2, __kCFHashHasNullCallBacks); + } else if (__CFBagKeyCallBacksMatchCFType(keyCallBacks)) { + __CFBitfieldSetValue(flags, 3, 2, __kCFHashHasCFTypeCallBacks); + } else { + __CFBitfieldSetValue(flags, 3, 2, __kCFHashHasCustomCallBacks); + } +#if CFDictionary + if (__CFBagValueCallBacksMatchNull(valueCallBacks)) { + __CFBitfieldSetValue(flags, 5, 4, __kCFHashHasNullCallBacks); + } else if (__CFBagValueCallBacksMatchCFType(valueCallBacks)) { + __CFBitfieldSetValue(flags, 5, 4, __kCFHashHasCFTypeCallBacks); + } else { + __CFBitfieldSetValue(flags, 5, 4, __kCFHashHasCustomCallBacks); + } +#endif + size = __CFBagGetSizeOfType(flags) - sizeof(CFRuntimeBase); + hc = (struct __CFBag *)_CFRuntimeCreateInstance(allocator, __kCFHashTypeID, size, NULL); + if (NULL == hc) { + return NULL; + } + hc->_count = 0; + hc->_bucketsUsed = 0; + hc->_marker = (any_t)0xa1b1c1d3; + hc->_context = NULL; + hc->_deletes = 0; + hc->_mutations = 1; + hc->_xflags = xflags | flags; + switch (__CFBitfieldGetValue(flags, 1, 0)) { + case __kCFHashImmutable: + if (__CFOASafe) __CFSetLastAllocationEventName(hc, "CFBag (immutable)"); + break; + case __kCFHashMutable: + if (__CFOASafe) __CFSetLastAllocationEventName(hc, "CFBag (mutable-variable)"); + break; + } + hc->_bucketsCap = __CFHashRoundUpCapacity(1); + hc->_bucketsNum = 0; + hc->_keys = NULL; + hc->_values = NULL; + if (__kCFHashHasCustomCallBacks == __CFBitfieldGetValue(flags, 3, 2)) { + CFBagKeyCallBacks *cb = (CFBagKeyCallBacks *)__CFBagGetKeyCallBacks((CFHashRef)hc); + *cb = *keyCallBacks; + FAULT_CALLBACK((void **)&(cb->retain)); + FAULT_CALLBACK((void **)&(cb->release)); + FAULT_CALLBACK((void **)&(cb->copyDescription)); + FAULT_CALLBACK((void **)&(cb->equal)); + FAULT_CALLBACK((void **)&(cb->hash)); + } +#if CFDictionary + if (__kCFHashHasCustomCallBacks == __CFBitfieldGetValue(flags, 5, 4)) { + CFBagValueCallBacks *vcb = (CFBagValueCallBacks *)__CFBagGetValueCallBacks((CFHashRef)hc); + *vcb = *valueCallBacks; + FAULT_CALLBACK((void **)&(vcb->retain)); + FAULT_CALLBACK((void **)&(vcb->release)); + FAULT_CALLBACK((void **)&(vcb->copyDescription)); + FAULT_CALLBACK((void **)&(vcb->equal)); + } +#endif + return hc; +} + +#if CFDictionary +CFHashRef CFBagCreate(CFAllocatorRef allocator, const_any_pointer_t *keys, const_any_pointer_t *values, CFIndex numValues, const CFBagKeyCallBacks *keyCallBacks, const CFBagValueCallBacks *valueCallBacks) { +#endif +#if CFSet || CFBag +CFHashRef CFBagCreate(CFAllocatorRef allocator, const_any_pointer_t *keys, CFIndex numValues, const CFBagKeyCallBacks *keyCallBacks) { +#endif + CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__, numValues); +#if CFDictionary + CFMutableHashRef hc = __CFBagInit(allocator, __kCFHashImmutable, numValues, keyCallBacks, valueCallBacks); +#endif +#if CFSet || CFBag + CFMutableHashRef hc = __CFBagInit(allocator, __kCFHashImmutable, numValues, keyCallBacks); +#endif + __CFBitfieldSetValue(hc->_xflags, 1, 0, __kCFHashMutable); + for (CFIndex idx = 0; idx < numValues; idx++) { +#if CFDictionary + CFBagAddValue(hc, keys[idx], values[idx]); +#endif +#if CFSet || CFBag + CFBagAddValue(hc, keys[idx]); +#endif + } + __CFBitfieldSetValue(hc->_xflags, 1, 0, __kCFHashImmutable); + return (CFHashRef)hc; +} + +#if CFDictionary +CFMutableHashRef CFBagCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFBagKeyCallBacks *keyCallBacks, const CFBagValueCallBacks *valueCallBacks) { +#endif +#if CFSet || CFBag +CFMutableHashRef CFBagCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFBagKeyCallBacks *keyCallBacks) { +#endif + CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%ld) cannot be less than zero", __PRETTY_FUNCTION__, capacity); +#if CFDictionary + CFMutableHashRef hc = __CFBagInit(allocator, __kCFHashMutable, capacity, keyCallBacks, valueCallBacks); +#endif +#if CFSet || CFBag + CFMutableHashRef hc = __CFBagInit(allocator, __kCFHashMutable, capacity, keyCallBacks); +#endif + return hc; +} + +#if CFDictionary || CFSet +// does not have Add semantics for Bag; it has Set semantics ... is that best? +static void __CFBagGrow(CFMutableHashRef hc, CFIndex numNewValues); + +// This creates a hc which is for CFTypes or NSObjects, with a CFRetain style ownership transfer; +// the hc does not take a retain (since it claims 1), and the caller does not need to release the inserted objects (since we do it). +// The incoming objects must also be collectable if allocated out of a collectable allocator - and are neither released nor retained. +#if CFDictionary +CFHashRef _CFBagCreate_ex(CFAllocatorRef allocator, Boolean isMutable, const_any_pointer_t *keys, const_any_pointer_t *values, CFIndex numValues) { +#endif +#if CFSet || CFBag +CFHashRef _CFBagCreate_ex(CFAllocatorRef allocator, Boolean isMutable, const_any_pointer_t *keys, CFIndex numValues) { +#endif + CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__, numValues); +#if CFDictionary + CFMutableHashRef hc = __CFBagInit(allocator, __kCFHashMutable, numValues, &kCFTypeBagKeyCallBacks, &kCFTypeBagValueCallBacks); +#endif +#if CFSet || CFBag + CFMutableHashRef hc = __CFBagInit(allocator, __kCFHashMutable, numValues, &kCFTypeBagKeyCallBacks); +#endif + __CFBagGrow(hc, numValues); + for (CFIndex idx = 0; idx < numValues; idx++) { + CFIndex match, nomatch; + __CFBagFindBuckets2(hc, (any_t)keys[idx], &match, &nomatch); + if (kCFNotFound == match) { + CFAllocatorRef allocator = __CFGetAllocator(hc); + any_t newKey = (any_t)keys[idx]; + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFBagFindNewMarker(hc); + } + if (hc->_keys[nomatch] == ~hc->_marker) { + hc->_deletes--; + } + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[nomatch], newKey); +#if CFDictionary + any_t newValue = (any_t)values[idx]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[nomatch], newValue); +#endif +#if CFBag + hc->_values[nomatch] = 1; +#endif + hc->_bucketsUsed++; + hc->_count++; + } else { + CFAllocatorRef allocator = __CFGetAllocator(hc); +#if CFSet || CFBag + any_t oldKey = hc->_keys[match]; + any_t newKey = (any_t)keys[idx]; + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], ~hc->_marker); + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFBagFindNewMarker(hc); + } + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], newKey); + RELEASEKEY(oldKey); +#endif +#if CFDictionary + any_t oldValue = hc->_values[match]; + any_t newValue = (any_t)values[idx]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[match], newValue); + RELEASEVALUE(oldValue); +#endif + } + } + if (!isMutable) __CFBitfieldSetValue(hc->_xflags, 1, 0, __kCFHashImmutable); + return (CFHashRef)hc; +} +#endif + +CFHashRef CFBagCreateCopy(CFAllocatorRef allocator, CFHashRef other) { + CFMutableHashRef hc = CFBagCreateMutableCopy(allocator, CFBagGetCount(other), other); + __CFBitfieldSetValue(hc->_xflags, 1, 0, __kCFHashImmutable); + if (__CFOASafe) __CFSetLastAllocationEventName(hc, "CFBag (immutable)"); + return hc; +} + +CFMutableHashRef CFBagCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFHashRef other) { + CFIndex numValues = CFBagGetCount(other); + const_any_pointer_t *list, buffer[256]; + list = (numValues <= 256) ? buffer : (const_any_pointer_t *)CFAllocatorAllocate(allocator, numValues * sizeof(const_any_pointer_t), 0); + if (list != buffer && __CFOASafe) __CFSetLastAllocationEventName(list, "CFBag (temp)"); +#if CFDictionary + const_any_pointer_t *vlist, vbuffer[256]; + vlist = (numValues <= 256) ? vbuffer : (const_any_pointer_t *)CFAllocatorAllocate(allocator, numValues * sizeof(const_any_pointer_t), 0); + if (vlist != vbuffer && __CFOASafe) __CFSetLastAllocationEventName(vlist, "CFBag (temp)"); +#endif +#if CFSet || CFBag + CFBagGetValues(other, list); +#endif +#if CFDictionary + CFBagGetKeysAndValues(other, list, vlist); +#endif + const CFBagKeyCallBacks *kcb; + const CFBagValueCallBacks *vcb; + if (CF_IS_OBJC(__kCFHashTypeID, other)) { + kcb = &kCFTypeBagKeyCallBacks; + vcb = &kCFTypeBagValueCallBacks; + } else { + kcb = __CFBagGetKeyCallBacks(other); + vcb = __CFBagGetValueCallBacks(other); + } +#if CFDictionary + CFMutableHashRef hc = __CFBagInit(allocator, __kCFHashMutable, capacity, kcb, vcb); +#endif +#if CFSet || CFBag + CFMutableHashRef hc = __CFBagInit(allocator, __kCFHashMutable, capacity, kcb); +#endif + if (0 == capacity) _CFBagSetCapacity(hc, numValues); + for (CFIndex idx = 0; idx < numValues; idx++) { +#if CFDictionary + CFBagAddValue(hc, list[idx], vlist[idx]); +#endif +#if CFSet || CFBag + CFBagAddValue(hc, list[idx]); +#endif + } + if (list != buffer) CFAllocatorDeallocate(allocator, list); +#if CFDictionary + if (vlist != vbuffer) CFAllocatorDeallocate(allocator, vlist); +#endif + return hc; +} + +// Used by NSHashTables/NSMapTables and KVO +void _CFBagSetContext(CFHashRef hc, any_pointer_t context) { + __CFGenericValidateType(hc, __kCFHashTypeID); + CF_WRITE_BARRIER_BASE_ASSIGN(__CFGetAllocator(hc), hc, hc->_context, context); +} + +any_pointer_t _CFBagGetContext(CFHashRef hc) { + __CFGenericValidateType(hc, __kCFHashTypeID); + return hc->_context; +} + +CFIndex CFBagGetCount(CFHashRef hc) { + if (CFDictionary || CFSet) CF_OBJC_FUNCDISPATCH0(__kCFHashTypeID, CFIndex, hc, "count"); + __CFGenericValidateType(hc, __kCFHashTypeID); + return hc->_count; +} + +#if CFDictionary +CFIndex CFBagGetCountOfKey(CFHashRef hc, const_any_pointer_t key) { +#endif +#if CFSet || CFBag +CFIndex CFBagGetCountOfValue(CFHashRef hc, const_any_pointer_t key) { +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, CFIndex, hc, "countForKey:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, CFIndex, hc, "countForObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return 0; + CFIndex match = __CFBagFindBuckets1(hc, (any_t)key); + return (kCFNotFound != match ? __CFHashGetOccurrenceCount(hc, match) : 0); +} + +#if CFDictionary +Boolean CFBagContainsKey(CFHashRef hc, const_any_pointer_t key) { +#endif +#if CFSet || CFBag +Boolean CFBagContainsValue(CFHashRef hc, const_any_pointer_t key) { +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, char, hc, "containsKey:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, char, hc, "containsObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return false; + CFIndex match = __CFBagFindBuckets1(hc, (any_t)key); + return (kCFNotFound != match ? true : false); +} + +#if CFDictionary +CFIndex CFBagGetCountOfValue(CFHashRef hc, const_any_pointer_t value) { + CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, CFIndex, hc, "countForObject:", value); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return 0; + any_t *keys = hc->_keys; + Boolean (*equal)(any_t, any_t, any_pointer_t) = (Boolean (*)(any_t, any_t, any_pointer_t))__CFBagGetValueCallBacks(hc)->equal; + CFIndex cnt = 0; + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + if ((hc->_values[idx] == (any_t)value) || (equal && INVOKE_CALLBACK3(equal, hc->_values[idx], (any_t)value, hc->_context))) { + cnt++; + } + } + } + return cnt; +} + +Boolean CFBagContainsValue(CFHashRef hc, const_any_pointer_t value) { + CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, char, hc, "containsObject:", value); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return false; + any_t *keys = hc->_keys; + Boolean (*equal)(any_t, any_t, any_pointer_t) = (Boolean (*)(any_t, any_t, any_pointer_t))__CFBagGetValueCallBacks(hc)->equal; + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + if ((hc->_values[idx] == (any_t)value) || (equal && INVOKE_CALLBACK3(equal, hc->_values[idx], (any_t)value, hc->_context))) { + return true; + } + } + } + return false; +} +#endif + +const_any_pointer_t CFBagGetValue(CFHashRef hc, const_any_pointer_t key) { + if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, const_any_pointer_t, hc, "objectForKey:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, const_any_pointer_t, hc, "member:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return 0; + CFIndex match = __CFBagFindBuckets1(hc, (any_t)key); + return (kCFNotFound != match ? (const_any_pointer_t)(CFDictionary ? hc->_values[match] : hc->_keys[match]) : 0); +} + +Boolean CFBagGetValueIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *value) { + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, Boolean, hc, "_getValue:forKey:", (any_t *)value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, Boolean, hc, "_getValue:forObj:", (any_t *)value, key); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return false; + CFIndex match = __CFBagFindBuckets1(hc, (any_t)key); + return (kCFNotFound != match ? ((value ? __CFObjCStrongAssign((const_any_pointer_t)(CFDictionary ? hc->_values[match] : hc->_keys[match]), value) : 0), true) : false); +} + +#if CFDictionary +Boolean CFBagGetKeyIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *actualkey) { + CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, Boolean, hc, "getActualKey:forKey:", actualkey, key); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return false; + CFIndex match = __CFBagFindBuckets1(hc, (any_t)key); + return (kCFNotFound != match ? ((actualkey ? __CFObjCStrongAssign((const_any_pointer_t)hc->_keys[match], actualkey) : NULL), true) : false); +} +#endif + +#if CFDictionary +void CFBagGetKeysAndValues(CFHashRef hc, const_any_pointer_t *keybuf, const_any_pointer_t *valuebuf) { +#endif +#if CFSet || CFBag +void CFBagGetValues(CFHashRef hc, const_any_pointer_t *keybuf) { + const_any_pointer_t *valuebuf = 0; +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "getObjects:andKeys:", (any_t *)valuebuf, (any_t *)keybuf); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "getObjects:", (any_t *)keybuf); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (CF_USING_COLLECTABLE_MEMORY) { + // GC: speculatively issue a write-barrier on the copied to buffers + __CFObjCWriteBarrierRange(keybuf, hc->_count * sizeof(any_t)); + __CFObjCWriteBarrierRange(valuebuf, hc->_count * sizeof(any_t)); + } + any_t *keys = hc->_keys; + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + for (CFIndex cnt = __CFHashGetOccurrenceCount(hc, idx); cnt--;) { + if (keybuf) *keybuf++ = (const_any_pointer_t)keys[idx]; + if (valuebuf) *valuebuf++ = (const_any_pointer_t)hc->_values[idx]; + } + } + } +} + +#if CFDictionary || CFSet +unsigned long _CFBagFastEnumeration(CFHashRef hc, struct __objcFastEnumerationStateEquivalent *state, void *stackbuffer, unsigned long count) { + /* copy as many as count items over */ + if (0 == state->state) { /* first time */ + state->mutationsPtr = (unsigned long *)&hc->_mutations; + } + state->itemsPtr = (unsigned long *)stackbuffer; + CFIndex cnt = 0; + any_t *keys = hc->_keys; + for (CFIndex idx = (CFIndex)state->state, nbuckets = hc->_bucketsNum; idx < nbuckets && cnt < (CFIndex)count; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + state->itemsPtr[cnt++] = (unsigned long)keys[idx]; + } + state->state++; + } + return cnt; +} +#endif + +void CFBagApplyFunction(CFHashRef hc, CFBagApplierFunction applier, any_pointer_t context) { + FAULT_CALLBACK((void **)&(applier)); + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "_apply:context:", applier, context); + if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "_applyValues:context:", applier, context); + __CFGenericValidateType(hc, __kCFHashTypeID); + any_t *keys = hc->_keys; + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + for (CFIndex cnt = __CFHashGetOccurrenceCount(hc, idx); cnt--;) { +#if CFDictionary + INVOKE_CALLBACK3(applier, (const_any_pointer_t)keys[idx], (const_any_pointer_t)hc->_values[idx], context); +#endif +#if CFSet || CFBag + INVOKE_CALLBACK2(applier, (const_any_pointer_t)keys[idx], context); +#endif + } + } + } +} + +static void __CFBagGrow(CFMutableHashRef hc, CFIndex numNewValues) { + any_t *oldkeys = hc->_keys; + any_t *oldvalues = hc->_values; + CFIndex nbuckets = hc->_bucketsNum; + hc->_bucketsCap = __CFHashRoundUpCapacity(hc->_bucketsUsed + numNewValues); + hc->_bucketsNum = __CFHashNumBucketsForCapacity(hc->_bucketsCap); + hc->_deletes = 0; + CFAllocatorRef allocator = __CFGetAllocator(hc); + CFOptionFlags weakOrStrong = (hc->_xflags & __kCFHashWeakKeys) ? 0 : __kCFAllocatorGCScannedMemory; + any_t *mem = (any_t *)_CFAllocatorAllocateGC(allocator, hc->_bucketsNum * sizeof(any_t), weakOrStrong); + if (NULL == mem) __CFBagHandleOutOfMemory(hc, hc->_bucketsNum * sizeof(any_t)); + if (__CFOASafe) __CFSetLastAllocationEventName(mem, "CFBag (key-store)"); + CF_WRITE_BARRIER_BASE_ASSIGN(allocator, hc, hc->_keys, mem); + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; // GC: avoids write-barrier in weak case. + any_t *keysBase = mem; +#if CFDictionary || CFBag + weakOrStrong = (hc->_xflags & __kCFHashWeakValues) ? 0 : __kCFAllocatorGCScannedMemory; + mem = (any_t *)_CFAllocatorAllocateGC(allocator, hc->_bucketsNum * sizeof(any_t), weakOrStrong); + if (NULL == mem) __CFBagHandleOutOfMemory(hc, hc->_bucketsNum * sizeof(any_t)); + if (__CFOASafe) __CFSetLastAllocationEventName(mem, "CFBag (value-store)"); + CF_WRITE_BARRIER_BASE_ASSIGN(allocator, hc, hc->_values, mem); +#endif +#if CFDictionary + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; // GC: avoids write-barrier in weak case. + any_t *valuesBase = mem; +#endif + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + hc->_keys[idx] = hc->_marker; +#if CFDictionary || CFBag + hc->_values[idx] = 0; +#endif + } + if (NULL == oldkeys) return; + for (CFIndex idx = 0; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, oldkeys[idx])) { + CFIndex match, nomatch; + __CFBagFindBuckets2(hc, oldkeys[idx], &match, &nomatch); + CFAssert3(kCFNotFound == match, __kCFLogAssertion, "%s(): two values (%p, %p) now hash to the same slot; mutable value changed while in table or hash value is not immutable", __PRETTY_FUNCTION__, oldkeys[idx], hc->_keys[match]); + if (kCFNotFound != nomatch) { + CF_WRITE_BARRIER_BASE_ASSIGN(keysAllocator, keysBase, hc->_keys[nomatch], oldkeys[idx]); +#if CFDictionary + CF_WRITE_BARRIER_BASE_ASSIGN(valuesAllocator, valuesBase, hc->_values[nomatch], oldvalues[idx]); +#endif +#if CFBag + hc->_values[nomatch] = oldvalues[idx]; +#endif + } + } + } + _CFAllocatorDeallocateGC(allocator, oldkeys); + _CFAllocatorDeallocateGC(allocator, oldvalues); +} + +// This function is for Foundation's benefit; no one else should use it. +void _CFBagSetCapacity(CFMutableHashRef hc, CFIndex cap) { + if (CF_IS_OBJC(__kCFHashTypeID, hc)) return; + __CFGenericValidateType(hc, __kCFHashTypeID); + CFAssert1(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): collection is immutable", __PRETTY_FUNCTION__); + CFAssert3(hc->_bucketsUsed <= cap, __kCFLogAssertion, "%s(): desired capacity (%ld) is less than bucket count (%ld)", __PRETTY_FUNCTION__, cap, hc->_bucketsUsed); + __CFBagGrow(hc, cap - hc->_bucketsUsed); +} + + +#if CFDictionary +void CFBagAddValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_pointer_t value) { +#endif +#if CFSet || CFBag +void CFBagAddValue(CFMutableHashRef hc, const_any_pointer_t key) { + #define value 0 +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "_addObject:forKey:", value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "addObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + switch (__CFHashGetType(hc)) { + case __kCFHashMutable: + if (hc->_bucketsUsed == hc->_bucketsCap || NULL == hc->_keys) { + __CFBagGrow(hc, 1); + } + break; + default: + CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + break; + } + hc->_mutations++; + CFIndex match, nomatch; + __CFBagFindBuckets2(hc, (any_t)key, &match, &nomatch); + if (kCFNotFound != match) { +#if CFBag + CF_OBJC_KVO_WILLCHANGE(hc, hc->_keys[match]); + hc->_values[match]++; + hc->_count++; + CF_OBJC_KVO_DIDCHANGE(hc, hc->_keys[match]); +#endif + } else { + CFAllocatorRef allocator = __CFGetAllocator(hc); + GETNEWKEY(newKey, key); +#if CFDictionary + GETNEWVALUE(newValue); +#endif + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFBagFindNewMarker(hc); + } + if (hc->_keys[nomatch] == ~hc->_marker) { + hc->_deletes--; + } + CF_OBJC_KVO_WILLCHANGE(hc, key); + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[nomatch], newKey); +#if CFDictionary + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[nomatch], newValue); +#endif +#if CFBag + hc->_values[nomatch] = 1; +#endif + hc->_bucketsUsed++; + hc->_count++; + CF_OBJC_KVO_DIDCHANGE(hc, key); + } +} + +#if CFDictionary +void CFBagReplaceValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_pointer_t value) { +#endif +#if CFSet || CFBag +void CFBagReplaceValue(CFMutableHashRef hc, const_any_pointer_t key) { + #define value 0 +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "_replaceObject:forKey:", value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "_replaceObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + switch (__CFHashGetType(hc)) { + case __kCFHashMutable: + break; + default: + CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + break; + } + hc->_mutations++; + if (0 == hc->_bucketsUsed) return; + CFIndex match = __CFBagFindBuckets1(hc, (any_t)key); + if (kCFNotFound == match) return; + CFAllocatorRef allocator = __CFGetAllocator(hc); +#if CFSet || CFBag + GETNEWKEY(newKey, key); +#endif +#if CFDictionary + GETNEWVALUE(newValue); +#endif + any_t oldKey = hc->_keys[match]; + CF_OBJC_KVO_WILLCHANGE(hc, oldKey); +#if CFSet || CFBag + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], ~hc->_marker); + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFBagFindNewMarker(hc); + } + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], newKey); +#endif +#if CFDictionary + any_t oldValue = hc->_values[match]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[match], newValue); +#endif + CF_OBJC_KVO_DIDCHANGE(hc, oldKey); +#if CFSet || CFBag + RELEASEKEY(oldKey); +#endif +#if CFDictionary + RELEASEVALUE(oldValue); +#endif +} + +#if CFDictionary +void CFBagSetValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_pointer_t value) { +#endif +#if CFSet || CFBag +void CFBagSetValue(CFMutableHashRef hc, const_any_pointer_t key) { + #define value 0 +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "setObject:forKey:", value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "_setObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + switch (__CFHashGetType(hc)) { + case __kCFHashMutable: + if (hc->_bucketsUsed == hc->_bucketsCap || NULL == hc->_keys) { + __CFBagGrow(hc, 1); + } + break; + default: + CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + break; + } + hc->_mutations++; + CFIndex match, nomatch; + __CFBagFindBuckets2(hc, (any_t)key, &match, &nomatch); + if (kCFNotFound == match) { + CFAllocatorRef allocator = __CFGetAllocator(hc); + GETNEWKEY(newKey, key); +#if CFDictionary + GETNEWVALUE(newValue); +#endif + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFBagFindNewMarker(hc); + } + if (hc->_keys[nomatch] == ~hc->_marker) { + hc->_deletes--; + } + CF_OBJC_KVO_WILLCHANGE(hc, key); + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[nomatch], newKey); +#if CFDictionary + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[nomatch], newValue); +#endif +#if CFBag + hc->_values[nomatch] = 1; +#endif + hc->_bucketsUsed++; + hc->_count++; + CF_OBJC_KVO_DIDCHANGE(hc, key); + } else { + CFAllocatorRef allocator = __CFGetAllocator(hc); +#if CFSet || CFBag + GETNEWKEY(newKey, key); +#endif +#if CFDictionary + GETNEWVALUE(newValue); +#endif + any_t oldKey = hc->_keys[match]; + CF_OBJC_KVO_WILLCHANGE(hc, oldKey); +#if CFSet || CFBag + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], ~hc->_marker); + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFBagFindNewMarker(hc); + } + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], newKey); +#endif +#if CFDictionary + any_t oldValue = hc->_values[match]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[match], newValue); +#endif + CF_OBJC_KVO_DIDCHANGE(hc, oldKey); +#if CFSet || CFBag + RELEASEKEY(oldKey); +#endif +#if CFDictionary + RELEASEVALUE(oldValue); +#endif + } +} + +void CFBagRemoveValue(CFMutableHashRef hc, const_any_pointer_t key) { + if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "removeObjectForKey:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "removeObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + switch (__CFHashGetType(hc)) { + case __kCFHashMutable: + break; + default: + CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + break; + } + hc->_mutations++; + if (0 == hc->_bucketsUsed) return; + CFIndex match = __CFBagFindBuckets1(hc, (any_t)key); + if (kCFNotFound == match) return; + if (1 < __CFHashGetOccurrenceCount(hc, match)) { +#if CFBag + CF_OBJC_KVO_WILLCHANGE(hc, hc->_keys[match]); + hc->_values[match]--; + hc->_count--; + CF_OBJC_KVO_DIDCHANGE(hc, hc->_keys[match]); +#endif + } else { + CFAllocatorRef allocator = __CFGetAllocator(hc); + any_t oldKey = hc->_keys[match]; + CF_OBJC_KVO_WILLCHANGE(hc, oldKey); + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], ~hc->_marker); +#if CFDictionary + any_t oldValue = hc->_values[match]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[match], 0); +#endif +#if CFBag + hc->_values[match] = 0; +#endif + hc->_count--; + hc->_bucketsUsed--; + hc->_deletes++; + CF_OBJC_KVO_DIDCHANGE(hc, oldKey); + RELEASEKEY(oldKey); +#if CFDictionary + RELEASEVALUE(oldValue); +#endif + if (__CFBagShouldShrink(hc)) { + __CFBagGrow(hc, 0); + } else { + // When the probeskip == 1 always and only, a DELETED slot followed by an EMPTY slot + // can be converted to an EMPTY slot. By extension, a chain of DELETED slots followed + // by an EMPTY slot can be converted to EMPTY slots, which is what we do here. + if (match < hc->_bucketsNum - 1 && hc->_keys[match + 1] == hc->_marker) { + while (0 <= match && hc->_keys[match] == ~hc->_marker) { + hc->_keys[match] = hc->_marker; + hc->_deletes--; + match--; + } + } + } + } +} + +void CFBagRemoveAllValues(CFMutableHashRef hc) { + if (CFDictionary) CF_OBJC_FUNCDISPATCH0(__kCFHashTypeID, void, hc, "removeAllObjects"); + if (CFSet) CF_OBJC_FUNCDISPATCH0(__kCFHashTypeID, void, hc, "removeAllObjects"); + __CFGenericValidateType(hc, __kCFHashTypeID); + switch (__CFHashGetType(hc)) { + case __kCFHashMutable: + break; + default: + CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + break; + } + hc->_mutations++; + if (0 == hc->_bucketsUsed) return; + CFAllocatorRef allocator = __CFGetAllocator(hc); + any_t *keys = hc->_keys; + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + any_t oldKey = keys[idx]; + CF_OBJC_KVO_WILLCHANGE(hc, oldKey); +#if CFDictionary || CFSet + hc->_count--; +#endif +#if CFBag + hc->_count -= hc->_values[idx]; +#endif + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[idx], ~hc->_marker); +#if CFDictionary + any_t oldValue = hc->_values[idx]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[idx], 0); +#endif +#if CFBag + hc->_values[idx] = 0; +#endif + hc->_bucketsUsed--; + hc->_deletes++; + CF_OBJC_KVO_DIDCHANGE(hc, oldKey); + RELEASEKEY(oldKey); +#if CFDictionary + RELEASEVALUE(oldValue); +#endif + } + } + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + keys[idx] = hc->_marker; + } + hc->_deletes = 0; + hc->_bucketsUsed = 0; + hc->_count = 0; + if (__CFBagShouldShrink(hc) && (256 <= hc->_bucketsCap)) { + __CFBagGrow(hc, 128); + } +} + +#undef CF_OBJC_KVO_WILLCHANGE +#undef CF_OBJC_KVO_DIDCHANGE + diff --git a/Collections.subproj/CFBag.h b/CFBag.h similarity index 94% rename from Collections.subproj/CFBag.h rename to CFBag.h index 97c89d9..ae5c276 100644 --- a/Collections.subproj/CFBag.h +++ b/CFBag.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFBag.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBAG__) @@ -29,9 +29,7 @@ #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN typedef const void * (*CFBagRetainCallBack)(CFAllocatorRef allocator, const void *value); typedef void (*CFBagReleaseCallBack)(CFAllocatorRef allocator, const void *value); @@ -108,9 +106,7 @@ void CFBagRemoveValue(CFMutableBagRef theBag, const void *value); CF_EXPORT void CFBagRemoveAllValues(CFMutableBagRef theBag); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFBAG__ */ diff --git a/Base.subproj/CFBase.c b/CFBase.c similarity index 81% rename from Base.subproj/CFBase.c rename to CFBase.c index c807675..df5f2af 100644 --- a/Base.subproj/CFBase.c +++ b/CFBase.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -27,20 +27,11 @@ #include #include "CFInternal.h" -#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__) - #include -#endif -#if defined(__MACH__) -#endif -#if defined(__WIN32__) - #include -#endif -#if defined(__MACH__) - #include - extern size_t malloc_good_size(size_t size); - #include - #include -#endif +#include +#include +extern size_t malloc_good_size(size_t size); +#include +#include #include #include @@ -50,13 +41,10 @@ // -------- -------- -------- -------- -------- -------- -------- -------- -#if defined(__MACH__) // CFAllocator structure must match struct _malloc_zone_t! // The first two reserved fields in struct _malloc_zone_t are for us with CFRuntimeBase -#endif struct __CFAllocator { CFRuntimeBase _base; -#if defined(__MACH__) 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 */ @@ -69,7 +57,6 @@ struct __CFAllocator { 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; -#endif CFAllocatorRef _allocator; CFAllocatorContext _context; }; @@ -116,7 +103,7 @@ CF_INLINE CFAllocatorPreferredSizeCallBack __CFAllocatorGetPreferredSizeFunction return retval; } -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf); @@ -154,7 +141,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; void *newptr = CFAllocatorAllocate(allocator, size + vm_page_size, 0); - newptr = (void *)round_page((unsigned)newptr); + newptr = (void *)round_page((uintptr_t)newptr); return newptr; } @@ -254,7 +241,7 @@ static void __CFAllocatorSystemDeallocate(void *ptr, void *info) { #endif -#if defined(__WIN32__) || defined(__LINUX__) || defined(__FREEBSD__) +#if defined(__WIN32__) || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD static void *__CFAllocatorSystemAllocate(CFIndex size, CFOptionFlags hint, void *info) { return malloc(size); } @@ -276,9 +263,25 @@ static void *__CFAllocatorNullReallocate(void *ptr, CFIndex newsize, CFOptionFla return NULL; } +#if defined (__cplusplus) +static void * __CFAllocatorCPPMalloc(CFIndex allocSize, CFOptionFlags hint, void *info) +{ + return malloc(allocSize); +} +static void * __CFAllocatorCPPReAlloc(void *ptr, CFIndex newsize, CFOptionFlags hint, void *info) +{ + return realloc(ptr, newsize); +} +static void __CFAllocatorCPPFree(void *ptr, void *info) +{ + free(ptr); +} +#endif // C++ + + static struct __CFAllocator __kCFAllocatorMalloc = { - {NULL, 0, 0x0080}, -#if defined(__MACH__) + INIT_CFRUNTIME_BASE(), +#if DEPLOYMENT_TARGET_MACOSX __CFAllocatorCustomSize, __CFAllocatorCustomMalloc, __CFAllocatorCustomCalloc, @@ -296,12 +299,16 @@ static struct __CFAllocator __kCFAllocatorMalloc = { // Using the malloc functions directly is a total cheat, but works (in C) // because the function signatures match in their common prefix of arguments. // This saves us one hop through an adaptor function. - {0, NULL, NULL, NULL, NULL, (void *)malloc, (void *)realloc, (void *)free, NULL} +#if !defined (__cplusplus) + {0, NULL, NULL, NULL, NULL, (void *)malloc, (void *)realloc, (void *)free, NULL} +#else + {0, NULL, NULL, NULL, NULL, __CFAllocatorCPPMalloc,__CFAllocatorCPPReAlloc, __CFAllocatorCPPFree, NULL} +#endif // __cplusplus }; static struct __CFAllocator __kCFAllocatorMallocZone = { - {NULL, 0, 0x0080}, -#if defined(__MACH__) + INIT_CFRUNTIME_BASE(), +#if DEPLOYMENT_TARGET_MACOSX __CFAllocatorCustomSize, __CFAllocatorCustomMalloc, __CFAllocatorCustomCalloc, @@ -320,8 +327,8 @@ static struct __CFAllocator __kCFAllocatorMallocZone = { }; static struct __CFAllocator __kCFAllocatorSystemDefault = { - {NULL, 0, 0x0080}, -#if defined(__MACH__) + INIT_CFRUNTIME_BASE(), +#if DEPLOYMENT_TARGET_MACOSX __CFAllocatorCustomSize, __CFAllocatorCustomMalloc, __CFAllocatorCustomCalloc, @@ -340,8 +347,8 @@ static struct __CFAllocator __kCFAllocatorSystemDefault = { }; static struct __CFAllocator __kCFAllocatorNull = { - {NULL, 0, 0x0080}, -#if defined(__MACH__) + INIT_CFRUNTIME_BASE(), +#if DEPLOYMENT_TARGET_MACOSX __CFAllocatorNullSize, __CFAllocatorNullMalloc, __CFAllocatorNullCalloc, @@ -364,25 +371,23 @@ const CFAllocatorRef kCFAllocatorSystemDefault = &__kCFAllocatorSystemDefault; const CFAllocatorRef kCFAllocatorMalloc = &__kCFAllocatorMalloc; const CFAllocatorRef kCFAllocatorMallocZone = &__kCFAllocatorMallocZone; const CFAllocatorRef kCFAllocatorNull = &__kCFAllocatorNull; -const CFAllocatorRef kCFAllocatorUseContext = (CFAllocatorRef)0x0227; - -bool kCFUseCollectableAllocator = false; +const CFAllocatorRef kCFAllocatorUseContext = (CFAllocatorRef)0x0257; static CFStringRef __CFAllocatorCopyDescription(CFTypeRef cf) { - CFAllocatorRef self = cf; + CFAllocatorRef self = (CFAllocatorRef)cf; CFAllocatorRef allocator = (kCFAllocatorUseContext == self->_allocator) ? self : self->_allocator; - return CFStringCreateWithFormat(allocator, NULL, CFSTR("{info = 0x%x}"), (UInt32)cf, (UInt32)allocator, self->_context.info); + return CFStringCreateWithFormat(allocator, NULL, CFSTR("{info = %p}"), cf, allocator, self->_context.info); // CF: should use copyDescription function here to describe info field // remember to release value returned from copydescr function when this happens } __private_extern__ CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef cf) { - CFAllocatorRef allocator = cf; + CFAllocatorRef allocator = (CFAllocatorRef)cf; return (kCFAllocatorUseContext == allocator->_allocator) ? allocator : allocator->_allocator; } __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf) { - CFAllocatorRef self = cf; + CFAllocatorRef self = (CFAllocatorRef)cf; CFAllocatorRef allocator = self->_allocator; CFAllocatorReleaseCallBack releaseFunc = __CFAllocatorGetReleaseFunction(&self->_context); if (kCFAllocatorUseContext == allocator) { @@ -400,7 +405,7 @@ __private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf) { if (NULL != releaseFunc) { INVOKE_CALLBACK1(releaseFunc, self->_context.info); } - CFAllocatorDeallocate(allocator, (void *)self); + _CFAllocatorDeallocateGC(allocator, (void *)self); } } @@ -422,24 +427,26 @@ __private_extern__ void __CFAllocatorInitialize(void) { __kCFAllocatorTypeID = _CFRuntimeRegisterClass(&__CFAllocatorClass); _CFRuntimeSetInstanceTypeID(&__kCFAllocatorSystemDefault, __kCFAllocatorTypeID); - __kCFAllocatorSystemDefault._base._isa = __CFISAForTypeID(__kCFAllocatorTypeID); -#if defined(__MACH__) + __kCFAllocatorSystemDefault._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); +#if DEPLOYMENT_TARGET_MACOSX __kCFAllocatorSystemDefault._context.info = (CF_USING_COLLECTABLE_MEMORY ? __CFCollectableZone : malloc_default_zone()); - memset(malloc_default_zone(), 0, 8); + memset(malloc_default_zone(), 0, 2 * sizeof(void *)); #endif __kCFAllocatorSystemDefault._allocator = kCFAllocatorSystemDefault; _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMalloc, __kCFAllocatorTypeID); - __kCFAllocatorMalloc._base._isa = __CFISAForTypeID(__kCFAllocatorTypeID); + __kCFAllocatorMalloc._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); __kCFAllocatorMalloc._allocator = kCFAllocatorSystemDefault; - _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMallocZone, __kCFAllocatorTypeID); - __kCFAllocatorMallocZone._base._isa = __CFISAForTypeID(__kCFAllocatorTypeID); +#if DEPLOYMENT_TARGET_MACOSX + _CFRuntimeSetInstanceTypeID(&__kCFAllocatorMallocZone, __kCFAllocatorTypeID); + __kCFAllocatorMallocZone._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); __kCFAllocatorMallocZone._allocator = kCFAllocatorSystemDefault; __kCFAllocatorMallocZone._context.info = malloc_default_zone(); +#endif //__MACH__ _CFRuntimeSetInstanceTypeID(&__kCFAllocatorNull, __kCFAllocatorTypeID); - __kCFAllocatorNull._base._isa = __CFISAForTypeID(__kCFAllocatorTypeID); + __kCFAllocatorNull._base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); __kCFAllocatorNull._allocator = kCFAllocatorSystemDefault; } @@ -449,7 +456,7 @@ CFTypeID CFAllocatorGetTypeID(void) { } CFAllocatorRef CFAllocatorGetDefault(void) { - CFAllocatorRef allocator = __CFGetThreadSpecificData_inline()->_allocator; + CFAllocatorRef allocator = (CFAllocatorRef)__CFGetThreadSpecificData_inline()->_allocator; if (NULL == allocator) { allocator = kCFAllocatorSystemDefault; } @@ -457,14 +464,14 @@ CFAllocatorRef CFAllocatorGetDefault(void) { } void CFAllocatorSetDefault(CFAllocatorRef allocator) { - CFAllocatorRef current = __CFGetThreadSpecificData_inline()->_allocator; + CFAllocatorRef current = (CFAllocatorRef)__CFGetThreadSpecificData_inline()->_allocator; #if defined(DEBUG) if (NULL != allocator) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } #endif -#if defined(__MACH__) - if (allocator && allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * +#if DEPLOYMENT_TARGET_MACOSX + if (allocator && allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return; // require allocator to this function to be an allocator } #endif @@ -483,8 +490,8 @@ static CFAllocatorRef __CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorC CFAllocatorRetainCallBack retainFunc; CFAllocatorAllocateCallBack allocateFunc; void *retainedInfo; -#if defined(__MACH__) - if (allocator && kCFAllocatorUseContext != allocator && allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * +#if DEPLOYMENT_TARGET_MACOSX + if (allocator && kCFAllocatorUseContext != allocator && allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return NULL; // require allocator to this function to be an allocator } #endif @@ -501,25 +508,29 @@ static CFAllocatorRef __CFAllocatorCreate(CFAllocatorRef allocator, CFAllocatorC if (kCFAllocatorUseContext == allocator) { memory = NULL; if (allocateFunc) { - memory = (void *)INVOKE_CALLBACK3(allocateFunc, sizeof(struct __CFAllocator), 0, retainedInfo); + memory = (struct __CFAllocator *)INVOKE_CALLBACK3(allocateFunc, sizeof(struct __CFAllocator), 0, retainedInfo); } if (NULL == memory) { return NULL; } } else { allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; - memory = CFAllocatorAllocate(allocator, sizeof(struct __CFAllocator), 0); + memory = (struct __CFAllocator *)CFAllocatorAllocate(allocator, sizeof(struct __CFAllocator), __kCFAllocatorGCObjectMemory); if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFAllocator"); if (NULL == memory) { return NULL; } } - memory->_base._isa = 0; + memory->_base._cfisa = 0; +#if __LP64__ memory->_base._rc = 1; - memory->_base._info = 0; +#else + memory->_base._cfinfo[CF_RC_BITS] = 1; +#endif + memory->_base._cfinfo[CF_INFO_BITS] = 0; _CFRuntimeSetInstanceTypeID(memory, __kCFAllocatorTypeID); - memory->_base._isa = __CFISAForTypeID(__kCFAllocatorTypeID); -#if defined(__MACH__) + memory->_base._cfisa = __CFISAForTypeID(__kCFAllocatorTypeID); +#if DEPLOYMENT_TARGET_MACOSX memory->size = __CFAllocatorCustomSize; memory->malloc = __CFAllocatorCustomMalloc; memory->calloc = __CFAllocatorCustomCalloc; @@ -569,21 +580,21 @@ void *CFAllocatorAllocate(CFAllocatorRef allocator, CFIndex size, CFOptionFlags CFAllocatorAllocateCallBack allocateFunc; void *newptr = NULL; allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; -#if defined(__MACH__) && defined(DEBUG) - if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) { +#if (DEPLOYMENT_TARGET_MACOSX) && defined(DEBUG) + if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } #else __CFGenericValidateType(allocator, __kCFAllocatorTypeID); #endif if (0 == size) return NULL; -#if defined(__MACH__) - if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * +#if DEPLOYMENT_TARGET_MACOSX + if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return malloc_zone_malloc((malloc_zone_t *)allocator, size); } #endif if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - newptr = auto_zone_allocate_object((auto_zone_t*)allocator->_context.info, size, (auto_memory_type_t)hint, true, false); + newptr = auto_zone_allocate_object((auto_zone_t*)allocator->_context.info, size, CF_GET_GC_MEMORY_TYPE(hint), true, false); } else { newptr = NULL; allocateFunc = __CFAllocatorGetAllocateFunction(&allocator->_context); @@ -600,16 +611,16 @@ void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize CFAllocatorDeallocateCallBack deallocateFunc; void *newptr; allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; -#if defined(__MACH__) && defined(DEBUG) - if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) { +#if (DEPLOYMENT_TARGET_MACOSX) && defined(DEBUG) + if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } #else __CFGenericValidateType(allocator, __kCFAllocatorTypeID); #endif if (NULL == ptr && 0 < newsize) { -#if defined(__MACH__) - if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * +#if DEPLOYMENT_TARGET_MACOSX + if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return malloc_zone_malloc((malloc_zone_t *)allocator, newsize); } #endif @@ -621,8 +632,8 @@ void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize return newptr; } if (NULL != ptr && 0 == newsize) { -#if defined(__MACH__) - if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * +#if DEPLOYMENT_TARGET_MACOSX + if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * #if defined(DEBUG) size_t size = malloc_size(ptr); if (size) memset(ptr, 0xCC, size); @@ -638,8 +649,8 @@ void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize return NULL; } if (NULL == ptr && 0 == newsize) return NULL; -#if defined(__MACH__) - if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * +#if DEPLOYMENT_TARGET_MACOSX + if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return malloc_zone_realloc((malloc_zone_t *)allocator, ptr, newsize); } #endif @@ -652,15 +663,15 @@ void *CFAllocatorReallocate(CFAllocatorRef allocator, void *ptr, CFIndex newsize void CFAllocatorDeallocate(CFAllocatorRef allocator, void *ptr) { CFAllocatorDeallocateCallBack deallocateFunc; allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; -#if defined(__MACH__) && defined(DEBUG) - if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) { +#if (DEPLOYMENT_TARGET_MACOSX) && defined(DEBUG) + if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } #else __CFGenericValidateType(allocator, __kCFAllocatorTypeID); #endif -#if defined(__MACH__) - if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * +#if DEPLOYMENT_TARGET_MACOSX + if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * #if defined(DEBUG) size_t size = malloc_size(ptr); if (size) memset(ptr, 0xCC, size); @@ -678,15 +689,15 @@ CFIndex CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex siz CFAllocatorPreferredSizeCallBack prefFunc; CFIndex newsize = 0; allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; -#if defined(__MACH__) && defined(DEBUG) - if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) { +#if (DEPLOYMENT_TARGET_MACOSX) && defined(DEBUG) + if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } #else __CFGenericValidateType(allocator, __kCFAllocatorTypeID); #endif -#if defined(__MACH__) - if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * +#if DEPLOYMENT_TARGET_MACOSX + if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return malloc_good_size(size); } #endif @@ -700,16 +711,16 @@ CFIndex CFAllocatorGetPreferredSizeForSize(CFAllocatorRef allocator, CFIndex siz void CFAllocatorGetContext(CFAllocatorRef allocator, CFAllocatorContext *context) { allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; -#if defined(__MACH__) && defined(DEBUG) - if (allocator->_base._isa == __CFISAForTypeID(__kCFAllocatorTypeID)) { +#if (DEPLOYMENT_TARGET_MACOSX) && defined(DEBUG) + if (allocator->_base._cfisa == __CFISAForTypeID(__kCFAllocatorTypeID)) { __CFGenericValidateType(allocator, __kCFAllocatorTypeID); } #else __CFGenericValidateType(allocator, __kCFAllocatorTypeID); #endif CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__); -#if defined(__MACH__) - if (allocator->_base._isa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * +#if DEPLOYMENT_TARGET_MACOSX + if (allocator->_base._cfisa != __CFISAForTypeID(__kCFAllocatorTypeID)) { // malloc_zone_t * return; } #endif @@ -722,7 +733,7 @@ void CFAllocatorGetContext(CFAllocatorRef allocator, CFAllocatorContext *context context->reallocate = __CFAllocatorGetReallocateFunction(&allocator->_context); context->deallocate = __CFAllocatorGetDeallocateFunction(&allocator->_context); context->preferredSize = __CFAllocatorGetPreferredSizeFunction(&allocator->_context); -#if defined(__ppc__) +#if (DEPLOYMENT_TARGET_MACOSX) && defined(__ppc__) context->retain = (void *)((uintptr_t)context->retain & ~0x3); context->release = (void *)((uintptr_t)context->release & ~0x3); context->copyDescription = (void *)((uintptr_t)context->copyDescription & ~0x3); @@ -736,7 +747,7 @@ void CFAllocatorGetContext(CFAllocatorRef allocator, CFAllocatorContext *context void *_CFAllocatorAllocateGC(CFAllocatorRef allocator, CFIndex size, CFOptionFlags hint) { if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) - return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, size, (auto_memory_type_t)hint, false, false); + return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, size, CF_GET_GC_MEMORY_TYPE(hint), false, false); else return CFAllocatorAllocate(allocator, size, hint); } @@ -748,7 +759,7 @@ void *_CFAllocatorReallocateGC(CFAllocatorRef allocator, void *ptr, CFIndex news return NULL; // equivalent to _CFAllocatorDeallocateGC. } if (ptr == NULL) { - return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, newsize, (auto_memory_type_t)hint, false, false); // eq. to _CFAllocator + return auto_zone_allocate_object((auto_zone_t*)kCFAllocatorSystemDefault->_context.info, newsize, CF_GET_GC_MEMORY_TYPE(hint), false, false); // eq. to _CFAllocator } } // otherwise, auto_realloc() now preserves layout type and refCount. @@ -763,29 +774,39 @@ void _CFAllocatorDeallocateGC(CFAllocatorRef allocator, void *ptr) // -------- -------- -------- -------- -------- -------- -------- -------- -#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__) +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD __private_extern__ pthread_key_t __CFTSDKey = (pthread_key_t)NULL; #endif -#if defined(__WIN32__) +#if 0 __private_extern__ DWORD __CFTSDKey = 0xFFFFFFFF; #endif +extern void _CFRunLoop1(void); + // Called for each thread as it exits __private_extern__ void __CFFinalizeThreadData(void *arg) { -#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__) +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD __CFThreadSpecificData *tsd = (__CFThreadSpecificData *)arg; -#elif defined(__WIN32) - __CFThreadSpecificData *tsd = TlsGetValue(__CFTSDKey); +#elif defined(__WIN32__) + __CFThreadSpecificData *tsd = (__CFThreadSpecificData*)TlsGetValue(__CFTSDKey); TlsSetValue(__CFTSDKey, NULL); #endif if (NULL == tsd) return; if (tsd->_allocator) CFRelease(tsd->_allocator); - if (tsd->_runLoop) CFRelease(tsd->_runLoop); +#if DEPLOYMENT_TARGET_MACOSX + _CFRunLoop1(); +#endif +#if 0 || 0 + + if (tsd->_messageHook) UnhookWindowsHookEx(tsd->_messageHook); + +#endif + CFAllocatorDeallocate(kCFAllocatorSystemDefault, tsd); } __private_extern__ __CFThreadSpecificData *__CFGetThreadSpecificData(void) { -#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__) +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD __CFThreadSpecificData *data; data = pthread_getspecific(__CFTSDKey); if (data) { @@ -798,11 +819,11 @@ __private_extern__ __CFThreadSpecificData *__CFGetThreadSpecificData(void) { return data; #elif defined(__WIN32__) __CFThreadSpecificData *data; - data = TlsGetValue(__CFTSDKey); + data = (__CFThreadSpecificData *)TlsGetValue(__CFTSDKey); if (data) { return data; } - data = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFThreadSpecificData), 0); + data = (__CFThreadSpecificData *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFThreadSpecificData), 0); if (__CFOASafe) __CFSetLastAllocationEventName(data, "CFUtilities (thread-data)"); memset(data, 0, sizeof(__CFThreadSpecificData)); TlsSetValue(__CFTSDKey, data); @@ -811,22 +832,32 @@ __private_extern__ __CFThreadSpecificData *__CFGetThreadSpecificData(void) { } __private_extern__ void __CFBaseInitialize(void) { -#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__) +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD pthread_key_create(&__CFTSDKey, __CFFinalizeThreadData); #endif -#if defined(__WIN32__) +#if 0 || 0 __CFTSDKey = TlsAlloc(); #endif - //kCFUseCollectableAllocator = objc_collecting_enabled(); } -#if defined(__WIN32__) +#if 0 || 0 __private_extern__ void __CFBaseCleanup(void) { TlsFree(__CFTSDKey); } #endif +static CFBadErrorCallBack __CFOutOfMemoryCallBack = NULL; + +CFBadErrorCallBack _CFGetOutOfMemoryErrorCallBack(void) { + return __CFOutOfMemoryCallBack; +} + +void _CFSetOutOfMemoryErrorCallBack(CFBadErrorCallBack callBack) { + __CFOutOfMemoryCallBack = callBack; +} + + CFRange __CFRangeMake(CFIndex loc, CFIndex len) { CFRange range; range.location = loc; @@ -834,30 +865,22 @@ CFRange __CFRangeMake(CFIndex loc, CFIndex len) { return range; } -__private_extern__ const void *__CFTypeCollectionRetain(CFAllocatorRef allocator, const void *ptr) { - return (const void *)CFRetain(ptr); -} - -__private_extern__ void __CFTypeCollectionRelease(CFAllocatorRef allocator, const void *ptr) { - CFRelease(ptr); -} - struct __CFNull { CFRuntimeBase _base; }; static struct __CFNull __kCFNull = { - INIT_CFRUNTIME_BASE(NULL, 0, 0x0080) + INIT_CFRUNTIME_BASE() }; const CFNullRef kCFNull = &__kCFNull; static CFStringRef __CFNullCopyDescription(CFTypeRef cf) { - return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR(""), cf, CFGetAllocator(cf)); + return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR(""), cf, CFGetAllocator(cf)); } static CFStringRef __CFNullCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { - return CFRetain(CFSTR("null")); + return (CFStringRef)CFRetain(CFSTR("null")); } static void __CFNullDeallocate(CFTypeRef cf) { @@ -881,13 +904,15 @@ static const CFRuntimeClass __CFNullClass = { __private_extern__ void __CFNullInitialize(void) { __kCFNullTypeID = _CFRuntimeRegisterClass(&__CFNullClass); _CFRuntimeSetInstanceTypeID(&__kCFNull, __kCFNullTypeID); - __kCFNull._base._isa = __CFISAForTypeID(__kCFNullTypeID); + __kCFNull._base._cfisa = __CFISAForTypeID(__kCFNullTypeID); } CFTypeID CFNullGetTypeID(void) { return __kCFNullTypeID; } +void CFCollection_non_gc_storage_error(void) { } + static int hasCFM = 0; @@ -895,19 +920,29 @@ void _CFRuntimeSetCFMPresent(void *addr) { hasCFM = 1; } -#if defined(__MACH__) && defined(__ppc__) +#if (DEPLOYMENT_TARGET_MACOSX) && defined(__ppc__) /* See comments below */ __private_extern__ void __CF_FAULT_CALLBACK(void **ptr) { uintptr_t p = (uintptr_t)*ptr; if ((0 == p) || (p & 0x1)) return; -// warning: revisit this address check in Chablis, and for 64-bit if (0 == hasCFM || (0x90000000 <= p && p < 0xA0000000)) { *ptr = (void *)(p | 0x1); } else { - Dl_info info; - int __known = dladdr(p, &info); - *ptr = (void *)(p | (__known ? 0x1 : 0x3)); + 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)); } } @@ -956,7 +991,7 @@ __asm__ ( __asm__ ( ".text\n" " .align 2\n" -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX ".private_extern ___HALT\n" #else ".globl ___HALT\n" @@ -966,17 +1001,16 @@ __asm__ ( ); #endif -#if defined(__i386__) -#if defined(_MSC_VER) || defined(__MWERKS__) -__private_extern__ void __HALT() -{ +#if defined(__i386__) || defined(__x86_64__) +#if defined(_MSC_VER) +void __HALT() { __asm int 3; } #else __asm__ ( ".text\n" " .align 2, 0x90\n" -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX ".private_extern ___HALT\n" #else ".globl ___HALT\n" @@ -987,3 +1021,4 @@ __asm__ ( #endif #endif + diff --git a/Base.subproj/CFBase.h b/CFBase.h similarity index 72% rename from Base.subproj/CFBase.h rename to CFBase.h index dd6e668..7ff29ee 100644 --- a/Base.subproj/CFBase.h +++ b/CFBase.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFBase.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBASE__) @@ -35,34 +35,50 @@ #define __i386__ 1 #endif -#if defined(__WIN32__) -#include +#if (defined(__i386__) || defined(__x86_64__)) && !defined(__LITTLE_ENDIAN__) + #define __LITTLE_ENDIAN__ 1 +#endif + +#if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) +#error Do not know the endianess of this architecture +#endif + +#if !__BIG_ENDIAN__ && !__LITTLE_ENDIAN__ +#error Both __BIG_ENDIAN__ and __LITTLE_ENDIAN__ cannot be false +#endif + +#if __BIG_ENDIAN__ && __LITTLE_ENDIAN__ +#error Both __BIG_ENDIAN__ and __LITTLE_ENDIAN__ cannot be true #endif -#if defined(__GNUC__) +#if defined(__WIN32__) +#include +#include +#include +#include +#elif defined(__GNUC__) #include #include -#elif defined(__WIN32__) -// mostly for the benefit of MSVC -#include -#include #endif #include #if defined(__MACH__) - #include + #include #endif #if !defined(__MACTYPES__) +#if !defined(_OS_OSTYPES_H) typedef unsigned char Boolean; typedef unsigned char UInt8; typedef signed char SInt8; typedef unsigned short UInt16; typedef signed short SInt16; - typedef unsigned long UInt32; - typedef signed long SInt32; + typedef unsigned int UInt32; + typedef signed int SInt32; typedef uint64_t UInt64; typedef int64_t SInt64; + typedef SInt32 OSStatus; +#endif typedef float Float32; typedef double Float64; typedef unsigned short UniChar; @@ -71,7 +87,8 @@ typedef unsigned char Str255[256]; typedef const unsigned char * ConstStr255Param; typedef SInt16 OSErr; - typedef SInt32 OSStatus; + typedef SInt16 RegionCode; + typedef SInt16 LangCode; #endif #if !defined(__MACTYPES__) || (defined(UNIVERSAL_INTERFACES_VERSION) && UNIVERSAL_INTERFACES_VERSION < 0x0340) typedef UInt32 UTF32Char; @@ -79,22 +96,27 @@ typedef UInt8 UTF8Char; #endif - +#if !defined(CF_EXTERN_C_BEGIN) #if defined(__cplusplus) -extern "C" { +#define CF_EXTERN_C_BEGIN extern "C" { +#define CF_EXTERN_C_END } +#else +#define CF_EXTERN_C_BEGIN +#define CF_EXTERN_C_END +#endif #endif -#ifndef NULL -#ifdef __GNUG__ -#define NULL __null -#else /* ! __GNUG__ */ -#ifndef __cplusplus -#define NULL ((void *)0) -#else /* __cplusplus */ -#define NULL 0 -#endif /* ! __cplusplus */ -#endif /* __GNUG__ */ -#endif /* ! NULL */ +CF_EXTERN_C_BEGIN + +#if !defined(NULL) +#if defined(__GNUG__) + #define NULL __null +#elif defined(__cplusplus) + #define NULL 0 +#else + #define NULL ((void *)0) +#endif +#endif #if !defined(TRUE) #define TRUE 1 @@ -106,14 +128,6 @@ extern "C" { #if defined(__WIN32__) #undef CF_EXPORT -/* - We don't build as a library now, but this would be the starting point. - #if defined(CF_BUILDING_CF_AS_LIB) - // we're building CF as a library - #define CF_EXPORT extern - #elif defined(CF_BUILDING_CF) - // we're building CF as a DLL -*/ #if defined(CF_BUILDING_CF) #define CF_EXPORT __declspec(dllexport) extern #else @@ -131,9 +145,9 @@ extern "C" { #if !defined(CF_INLINE) #if defined(__GNUC__) && (__GNUC__ == 4) && !defined(DEBUG) - #define CF_INLINE static __inline__ __attribute__((always_inline)) + #define CF_INLINE static __inline__ __attribute__((always_inline)) #elif defined(__GNUC__) - #define CF_INLINE static __inline__ + #define CF_INLINE static __inline__ #elif defined(__MWERKS__) || defined(__cplusplus) #define CF_INLINE static inline #elif defined(_MSC_VER) @@ -146,28 +160,53 @@ extern "C" { CF_EXPORT double kCFCoreFoundationVersionNumber; -#define kCFCoreFoundationVersionNumber10_0 196.4 -#define kCFCoreFoundationVersionNumber10_0_3 196.5 -#define kCFCoreFoundationVersionNumber10_1 226.0 -/* Note the next two do not follow the usual numbering policy from the base release */ -#define kCFCoreFoundationVersionNumber10_1_2 227.2 -#define kCFCoreFoundationVersionNumber10_1_4 227.3 -#define kCFCoreFoundationVersionNumber10_2 263.0 -#define kCFCoreFoundationVersionNumber10_3 299.0 -#define kCFCoreFoundationVersionNumber10_3_3 299.3 -#define kCFCoreFoundationVersionNumber10_3_4 299.31 - -#if defined(__ppc64__) -typedef UInt32 CFTypeID; -typedef UInt64 CFOptionFlags; -typedef UInt32 CFHashCode; -typedef SInt64 CFIndex; -#else -typedef UInt32 CFTypeID; -typedef UInt32 CFOptionFlags; -typedef UInt32 CFHashCode; -typedef SInt32 CFIndex; -#endif +#define kCFCoreFoundationVersionNumber10_0 196.40 +#define kCFCoreFoundationVersionNumber10_0_3 196.50 +#define kCFCoreFoundationVersionNumber10_1 226.00 +#define kCFCoreFoundationVersionNumber10_1_1 226.00 +/* Note the next three do not follow the usual numbering policy from the base release */ +#define kCFCoreFoundationVersionNumber10_1_2 227.20 +#define kCFCoreFoundationVersionNumber10_1_3 227.20 +#define kCFCoreFoundationVersionNumber10_1_4 227.30 +#define kCFCoreFoundationVersionNumber10_2 263.00 +#define kCFCoreFoundationVersionNumber10_2_1 263.10 +#define kCFCoreFoundationVersionNumber10_2_2 263.10 +#define kCFCoreFoundationVersionNumber10_2_3 263.30 +#define kCFCoreFoundationVersionNumber10_2_4 263.30 +#define kCFCoreFoundationVersionNumber10_2_5 263.50 +#define kCFCoreFoundationVersionNumber10_2_6 263.50 +#define kCFCoreFoundationVersionNumber10_2_7 263.50 +#define kCFCoreFoundationVersionNumber10_2_8 263.50 +#define kCFCoreFoundationVersionNumber10_3 299.00 +#define kCFCoreFoundationVersionNumber10_3_1 299.00 +#define kCFCoreFoundationVersionNumber10_3_2 299.00 +#define kCFCoreFoundationVersionNumber10_3_3 299.30 +#define kCFCoreFoundationVersionNumber10_3_4 299.31 +#define kCFCoreFoundationVersionNumber10_3_5 299.31 +#define kCFCoreFoundationVersionNumber10_3_6 299.32 +#define kCFCoreFoundationVersionNumber10_3_7 299.33 +#define kCFCoreFoundationVersionNumber10_3_8 299.33 +#define kCFCoreFoundationVersionNumber10_3_9 299.35 +#define kCFCoreFoundationVersionNumber10_4 368.00 +#define kCFCoreFoundationVersionNumber10_4_1 368.10 +#define kCFCoreFoundationVersionNumber10_4_2 368.11 +#define kCFCoreFoundationVersionNumber10_4_3 368.18 +#define kCFCoreFoundationVersionNumber10_4_4_Intel 368.26 +#define kCFCoreFoundationVersionNumber10_4_4_PowerPC 368.25 +#define kCFCoreFoundationVersionNumber10_4_5_Intel 368.26 +#define kCFCoreFoundationVersionNumber10_4_5_PowerPC 368.25 +#define kCFCoreFoundationVersionNumber10_4_6_Intel 368.26 +#define kCFCoreFoundationVersionNumber10_4_6_PowerPC 368.25 +#define kCFCoreFoundationVersionNumber10_4_7 368.27 +#define kCFCoreFoundationVersionNumber10_4_8 368.27 +#define kCFCoreFoundationVersionNumber10_4_9 368.28 +#define kCFCoreFoundationVersionNumber10_4_10 368.28 +#define kCFCoreFoundationVersionNumber10_4_11 368.31 + +typedef unsigned long CFTypeID; +typedef unsigned long CFOptionFlags; +typedef unsigned long CFHashCode; +typedef signed long CFIndex; /* Base "type" of all "CF objects", and polymorphic functions on them */ typedef const void * CFTypeRef; @@ -183,11 +222,12 @@ typedef struct __CFString * CFMutableStringRef; typedef CFTypeRef CFPropertyListRef; /* Values returned from comparison functions */ -typedef enum { +enum { kCFCompareLessThan = -1, kCFCompareEqualTo = 0, kCFCompareGreaterThan = 1 -} CFComparisonResult; +}; +typedef CFIndex CFComparisonResult; /* A standard comparison function */ typedef CFComparisonResult (*CFComparatorFunction)(const void *val1, const void *val2, void *context); @@ -386,9 +426,7 @@ CFStringRef CFCopyDescription(CFTypeRef cf); CF_EXPORT CFAllocatorRef CFGetAllocator(CFTypeRef cf); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFBASE__ */ diff --git a/Collections.subproj/CFBinaryHeap.c b/CFBinaryHeap.c similarity index 78% rename from Collections.subproj/CFBinaryHeap.c rename to CFBinaryHeap.c index 3f7e9eb..6e5f5a6 100644 --- a/Collections.subproj/CFBinaryHeap.c +++ b/CFBinaryHeap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,7 +26,7 @@ */ #include -#include "CFUtilitiesPriv.h" +#include "CFPriv.h" #include "CFInternal.h" const CFBinaryHeapCallBacks kCFStringBinaryHeapCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, (CFComparisonResult (*)(const void *, const void *, void *))CFStringCompare}; @@ -37,7 +37,7 @@ struct __CFBinaryHeapBucket { CF_INLINE CFIndex __CFBinaryHeapRoundUpCapacity(CFIndex capacity) { if (capacity < 4) return 4; - return (1 << (CFLog2(capacity) + 1)); + return (1 << flsl(capacity)); } CF_INLINE CFIndex __CFBinaryHeapNumBucketsForCapacity(CFIndex capacity) { @@ -86,35 +86,32 @@ CF_INLINE void __CFBinaryHeapSetNumBuckets(CFBinaryHeapRef heap, CFIndex v) { } enum { /* bits 1-0 */ - kCFBinaryHeapImmutable = 0x0, /* unchangable and fixed capacity; default */ kCFBinaryHeapMutable = 0x1, /* changeable and variable capacity */ - kCFBinaryHeapFixedMutable = 0x3 /* changeable and fixed capacity */ }; /* Bits 4-5 are used by GC */ -CF_INLINE bool isStrongMemory(CFTypeRef collection) { - return ! __CFBitfieldGetValue(((const CFRuntimeBase *)collection)->_info, 4, 4); +CF_INLINE bool isStrongMemory_Heap(CFTypeRef collection) { + return __CFBitfieldGetValue(((const CFRuntimeBase *)collection)->_cfinfo[CF_INFO_BITS], 4, 4) == 0; } -CF_INLINE bool needsRestore(CFTypeRef collection) { - return __CFBitfieldGetValue(((const CFRuntimeBase *)collection)->_info, 5, 5); +CF_INLINE bool isWeakMemory_Heap(CFTypeRef collection) { + return __CFBitfieldGetValue(((const CFRuntimeBase *)collection)->_cfinfo[CF_INFO_BITS], 4, 4) != 0; } - CF_INLINE UInt32 __CFBinaryHeapMutableVariety(const void *cf) { - return __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 3, 2); + return __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 2); } CF_INLINE void __CFBinaryHeapSetMutableVariety(void *cf, UInt32 v) { - __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_info, 3, 2, v); + __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 2, v); } CF_INLINE UInt32 __CFBinaryHeapMutableVarietyFromFlags(UInt32 flags) { return __CFBitfieldGetValue(flags, 1, 0); } -static bool __CFBinaryHeapEqual(CFTypeRef cf1, CFTypeRef cf2) { +static Boolean __CFBinaryHeapEqual(CFTypeRef cf1, CFTypeRef cf2) { CFBinaryHeapRef heap1 = (CFBinaryHeapRef)cf1; CFBinaryHeapRef heap2 = (CFBinaryHeapRef)cf2; CFComparisonResult (*compare)(const void *, const void *, void *); @@ -126,7 +123,7 @@ static bool __CFBinaryHeapEqual(CFTypeRef cf1, CFTypeRef cf2) { compare = heap1->_callbacks.compare; if (compare != heap2->_callbacks.compare) return false; if (0 == cnt) return true; /* after function comparison */ - list1 = (cnt <= 128) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, 2 * cnt * sizeof(void *), 0); // GC OK + list1 = (cnt <= 128) ? (const void **)buffer : (const void **)CFAllocatorAllocate(kCFAllocatorSystemDefault, 2 * cnt * sizeof(void *), 0); // GC OK if (__CFOASafe && list1 != buffer) __CFSetLastAllocationEventName(list1, "CFBinaryHeap (temp)"); list2 = (cnt <= 128) ? buffer + 128 : list1 + cnt; CFBinaryHeapGetValues(heap1, list1); @@ -136,13 +133,16 @@ static bool __CFBinaryHeapEqual(CFTypeRef cf1, CFTypeRef cf2) { const void *val2 = list2[idx]; // CF: which context info should be passed in? both? // CF: if the context infos are not equal, should the heaps not be equal? - if (val1 != val2 && compare && !compare(val1, val2, heap1->_context.info)) return false; + if (val1 != val2) { + if (NULL == compare) return false; + if (!compare(val1, val2, heap1->_context.info)) return false; + } } if (list1 != buffer) CFAllocatorDeallocate(CFGetAllocator(heap1), list1); // GC OK return true; } -static UInt32 __CFBinaryHeapHash(CFTypeRef cf) { +static CFHashCode __CFBinaryHeapHash(CFTypeRef cf) { CFBinaryHeapRef heap = (CFBinaryHeapRef)cf; return __CFBinaryHeapCount(heap); } @@ -156,7 +156,7 @@ static CFStringRef __CFBinaryHeapCopyDescription(CFTypeRef cf) { cnt = __CFBinaryHeapCount(heap); result = CFStringCreateMutable(CFGetAllocator(heap), 0); CFStringAppendFormat(result, NULL, CFSTR("{count = %u, capacity = %u, objects = (\n"), cf, CFGetAllocator(heap), cnt, __CFBinaryHeapCapacity(heap)); - list = (cnt <= 128) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0); // GC OK + list = (cnt <= 128) ? (const void **)buffer : (const void **)CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0); // GC OK if (__CFOASafe && list != buffer) __CFSetLastAllocationEventName(list, "CFBinaryHeap (temp)"); CFBinaryHeapGetValues(heap, list); for (idx = 0; idx < cnt; idx++) { @@ -169,7 +169,7 @@ static CFStringRef __CFBinaryHeapCopyDescription(CFTypeRef cf) { CFStringAppendFormat(result, NULL, CFSTR("\t%u : %s\n"), idx, desc); CFRelease(desc); } else { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : <0x%x>\n"), idx, (UInt32)item); + CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p>\n"), idx, item); } } CFStringAppend(result, CFSTR(")}")); @@ -200,7 +200,7 @@ static const CFRuntimeClass __CFBinaryHeapClass = { NULL, // init NULL, // copy __CFBinaryHeapDeallocate, - (void *)__CFBinaryHeapEqual, + __CFBinaryHeapEqual, __CFBinaryHeapHash, NULL, // __CFBinaryHeapCopyDescription @@ -215,60 +215,32 @@ CFTypeID CFBinaryHeapGetTypeID(void) { } static CFBinaryHeapRef __CFBinaryHeapInit(CFAllocatorRef allocator, UInt32 flags, CFIndex capacity, const void **values, CFIndex numValues, const CFBinaryHeapCallBacks *callBacks, const CFBinaryHeapCompareContext *compareContext) { -// CF: does not copy the compareContext argument into the object CFBinaryHeapRef memory; CFIndex idx; CFIndex size; CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%d) cannot be less than zero", __PRETTY_FUNCTION__, capacity); - CFAssert3(kCFBinaryHeapFixedMutable != __CFBinaryHeapMutableVarietyFromFlags(flags) || numValues <= capacity, __kCFLogAssertion, "%s(): for fixed-mutable type, capacity (%d) must be greater than or equal to number of initial elements (%d)", __PRETTY_FUNCTION__, capacity, numValues); CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%d) cannot be less than zero", __PRETTY_FUNCTION__, numValues); size = sizeof(struct __CFBinaryHeap) - sizeof(CFRuntimeBase); - if (__CFBinaryHeapMutableVarietyFromFlags(flags) != kCFBinaryHeapMutable) - size += sizeof(struct __CFBinaryHeapBucket) * __CFBinaryHeapNumBucketsForCapacity(capacity); - CFBinaryHeapCallBacks nonRetainingCallbacks; if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { if (!callBacks || (callBacks->retain == NULL && callBacks->release == NULL)) { __CFBitfieldSetValue(flags, 4, 4, 1); // setWeak } - else { - if (callBacks->retain == __CFTypeCollectionRetain && callBacks->release == __CFTypeCollectionRelease) { - nonRetainingCallbacks = *callBacks; - nonRetainingCallbacks.retain = NULL; - nonRetainingCallbacks.release = NULL; - callBacks = &nonRetainingCallbacks; - __CFBitfieldSetValue(flags, 5, 5, 1); // setNeedsRestore - } - } } memory = (CFBinaryHeapRef)_CFRuntimeCreateInstance(allocator, __kCFBinaryHeapTypeID, size, NULL); if (NULL == memory) { return NULL; } - switch (__CFBinaryHeapMutableVarietyFromFlags(flags)) { - case kCFBinaryHeapMutable: __CFBinaryHeapSetCapacity(memory, __CFBinaryHeapRoundUpCapacity(1)); __CFBinaryHeapSetNumBuckets(memory, __CFBinaryHeapNumBucketsForCapacity(__CFBinaryHeapRoundUpCapacity(1))); - void *buckets = _CFAllocatorAllocateGC(allocator, __CFBinaryHeapNumBuckets(memory) * sizeof(struct __CFBinaryHeapBucket), isStrongMemory(memory) ? AUTO_MEMORY_SCANNED : AUTO_MEMORY_UNSCANNED); + void *buckets = _CFAllocatorAllocateGC(allocator, __CFBinaryHeapNumBuckets(memory) * sizeof(struct __CFBinaryHeapBucket), isStrongMemory_Heap(memory) ? __kCFAllocatorGCScannedMemory : 0); CF_WRITE_BARRIER_BASE_ASSIGN(allocator, memory, memory->_buckets, buckets); if (__CFOASafe) __CFSetLastAllocationEventName(memory->_buckets, "CFBinaryHeap (store)"); if (NULL == memory->_buckets) { CFRelease(memory); return NULL; } - break; - case kCFBinaryHeapFixedMutable: - case kCFBinaryHeapImmutable: - if (!isStrongMemory(memory)) { // if weak, don't scan - auto_zone_set_layout_type(__CFCollectableZone, memory, AUTO_OBJECT_UNSCANNED); - } - /* Don't round up capacity */ - __CFBinaryHeapSetCapacity(memory, capacity); - __CFBinaryHeapSetNumBuckets(memory, __CFBinaryHeapNumBucketsForCapacity(capacity)); - memory->_buckets = (struct __CFBinaryHeapBucket *)((int8_t *)memory + sizeof(struct __CFBinaryHeap)); - break; - } __CFBinaryHeapSetNumBucketsUsed(memory, 0); __CFBinaryHeapSetCount(memory, 0); if (NULL != callBacks) { @@ -282,25 +254,22 @@ static CFBinaryHeapRef __CFBinaryHeapInit(CFAllocatorRef allocator, UInt32 flags memory->_callbacks.copyDescription = 0; memory->_callbacks.compare = 0; } - if (__CFBinaryHeapMutableVarietyFromFlags(flags) != kCFBinaryHeapMutable) { - __CFBinaryHeapSetMutableVariety(memory, kCFBinaryHeapFixedMutable); - } else { - __CFBinaryHeapSetMutableVariety(memory, kCFBinaryHeapMutable); - } + __CFBinaryHeapSetMutableVariety(memory, kCFBinaryHeapMutable); for (idx = 0; idx < numValues; idx++) { CFBinaryHeapAddValue(memory, values[idx]); } __CFBinaryHeapSetMutableVariety(memory, __CFBinaryHeapMutableVarietyFromFlags(flags)); + if (compareContext) memcpy(&memory->_context, compareContext, sizeof(CFBinaryHeapCompareContext)); return memory; } CFBinaryHeapRef CFBinaryHeapCreate(CFAllocatorRef allocator, CFIndex capacity, const CFBinaryHeapCallBacks *callBacks, const CFBinaryHeapCompareContext *compareContext) { - return __CFBinaryHeapInit(allocator, (0 == capacity) ? kCFBinaryHeapMutable : kCFBinaryHeapFixedMutable, capacity, NULL, 0, callBacks, compareContext); + return __CFBinaryHeapInit(allocator, kCFBinaryHeapMutable, capacity, NULL, 0, callBacks, compareContext); } CFBinaryHeapRef CFBinaryHeapCreateCopy(CFAllocatorRef allocator, CFIndex capacity, CFBinaryHeapRef heap) { __CFGenericValidateType(heap, __kCFBinaryHeapTypeID); - return __CFBinaryHeapInit(allocator, (0 == capacity) ? kCFBinaryHeapMutable : kCFBinaryHeapFixedMutable, capacity, (const void **)heap->_buckets, __CFBinaryHeapCount(heap), &(heap->_callbacks), &(heap->_context)); + return __CFBinaryHeapInit(allocator, kCFBinaryHeapMutable, capacity, (const void **)heap->_buckets, __CFBinaryHeapCount(heap), &(heap->_callbacks), &(heap->_context)); } CFIndex CFBinaryHeapGetCount(CFBinaryHeapRef heap) { @@ -397,7 +366,7 @@ static void __CFBinaryHeapGrow(CFBinaryHeapRef heap, CFIndex numNewValues) { CFAllocatorRef allocator = CFGetAllocator(heap); __CFBinaryHeapSetCapacity(heap, capacity); __CFBinaryHeapSetNumBuckets(heap, __CFBinaryHeapNumBucketsForCapacity(capacity)); - void *buckets = _CFAllocatorReallocateGC(allocator, heap->_buckets, __CFBinaryHeapNumBuckets(heap) * sizeof(struct __CFBinaryHeapBucket), isStrongMemory(heap) ? AUTO_MEMORY_SCANNED : AUTO_MEMORY_UNSCANNED); + void *buckets = _CFAllocatorReallocateGC(allocator, heap->_buckets, __CFBinaryHeapNumBuckets(heap) * sizeof(struct __CFBinaryHeapBucket), isStrongMemory_Heap(heap) ? __kCFAllocatorGCScannedMemory : 0); CF_WRITE_BARRIER_BASE_ASSIGN(allocator, heap, heap->_buckets, buckets); if (__CFOASafe) __CFSetLastAllocationEventName(heap->_buckets, "CFBinaryHeap (store)"); if (NULL == heap->_buckets) HALT; @@ -408,15 +377,11 @@ void CFBinaryHeapAddValue(CFBinaryHeapRef heap, const void *value) { CFIndex cnt; CFAllocatorRef allocator = CFGetAllocator(heap); __CFGenericValidateType(heap, __kCFBinaryHeapTypeID); - CFAssert1(__CFBinaryHeapMutableVariety(heap) == kCFBinaryHeapMutable || __CFBinaryHeapMutableVariety(heap) == kCFBinaryHeapFixedMutable, __kCFLogAssertion, "%s(): binary heap is immutable", __PRETTY_FUNCTION__); switch (__CFBinaryHeapMutableVariety(heap)) { case kCFBinaryHeapMutable: if (__CFBinaryHeapNumBucketsUsed(heap) == __CFBinaryHeapCapacity(heap)) __CFBinaryHeapGrow(heap, 1); break; - case kCFBinaryHeapFixedMutable: - CFAssert1(__CFBinaryHeapCount(heap) < __CFBinaryHeapCapacity(heap), __kCFLogAssertion, "%s(): fixed-capacity binary heap is full", __PRETTY_FUNCTION__); - break; } cnt = __CFBinaryHeapCount(heap); idx = cnt; @@ -443,7 +408,6 @@ void CFBinaryHeapRemoveMinimumValue(CFBinaryHeapRef heap) { CFIndex cnt; CFAllocatorRef allocator; __CFGenericValidateType(heap, __kCFBinaryHeapTypeID); - CFAssert1(__CFBinaryHeapMutableVariety(heap) == kCFBinaryHeapMutable || __CFBinaryHeapMutableVariety(heap) == kCFBinaryHeapFixedMutable, __kCFLogAssertion, "%s(): binary heap is immutable", __PRETTY_FUNCTION__); cnt = __CFBinaryHeapCount(heap); if (0 == cnt) return; idx = 0; @@ -475,7 +439,6 @@ void CFBinaryHeapRemoveAllValues(CFBinaryHeapRef heap) { CFIndex idx; CFIndex cnt; __CFGenericValidateType(heap, __kCFBinaryHeapTypeID); - CFAssert1(__CFBinaryHeapMutableVariety(heap) == kCFBinaryHeapMutable || __CFBinaryHeapMutableVariety(heap) == kCFBinaryHeapFixedMutable, __kCFLogAssertion, "%s(): binary heap is immutable", __PRETTY_FUNCTION__); cnt = __CFBinaryHeapCount(heap); if (heap->_callbacks.release) for (idx = 0; idx < cnt; idx++) diff --git a/Collections.subproj/CFBinaryHeap.h b/CFBinaryHeap.h similarity index 90% rename from Collections.subproj/CFBinaryHeap.h rename to CFBinaryHeap.h index 9528c4c..b26e457 100644 --- a/Collections.subproj/CFBinaryHeap.h +++ b/CFBinaryHeap.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFBinaryHeap.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ /*! @header CFBinaryHeap @@ -35,9 +35,7 @@ #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN typedef struct { CFIndex version; @@ -110,19 +108,18 @@ CF_EXPORT CFTypeID CFBinaryHeapGetTypeID(void); /*! @function CFBinaryHeapCreate - Creates a new mutable or fixed-mutable binary heap with the given values. + Creates a new mutable binary heap with the given values. @param allocator The CFAllocator which should be used to allocate memory for the binary heap and its storage for values. This parameter may be NULL in which case the current default CFAllocator is used. If this reference is not a valid CFAllocator, the behavior is undefined. - @param capacity The maximum number of values that can be contained - by the CFBinaryHeap. The binary heap starts empty, and can grow to this - number of values (and it can have less). If this parameter - is 0, the binary heap's maximum capacity is unlimited (or rather, - only limited by address space and available memory - constraints). If this parameter is negative, the behavior is - undefined. + @param capacity A hint about the number of values that will be held + by the CFBinaryHeap. Pass 0 for no hint. The implementation may + ignore this hint, or may use it to optimize various + operations. A heap's actual capacity is only limited by + address space and available memory constraints). If this + parameter is negative, the behavior is undefined. @param callBacks A pointer to a CFBinaryHeapCallBacks structure initialized with the callbacks for the binary heap to use on each value in the binary heap. A copy of the contents of the @@ -155,19 +152,21 @@ CF_EXPORT CFBinaryHeapRef CFBinaryHeapCreate(CFAllocatorRef allocator, CFIndex c /*! @function CFBinaryHeapCreateCopy - Creates a new mutable or fixed-mutable binary heap with the values from the given binary heap. + Creates a new mutable binary heap with the values from the given binary heap. @param allocator The CFAllocator which should be used to allocate memory for the binary heap and its storage for values. This parameter may be NULL in which case the current default CFAllocator is used. If this reference is not a valid CFAllocator, the behavior is undefined. - @param capacity The maximum number of values that can be contained - by the CFBinaryHeap. The binary heap starts empty, and can grow to this - number of values (and it can have less). If this parameter - is 0, the binary heap's maximum capacity is unlimited (or rather, - only limited by address space and available memory - constraints). If this parameter is negative, or less than the number of - values in the given binary heap, the behavior is undefined. + @param capacity A hint about the number of values that will be held + by the CFBinaryHeap. Pass 0 for no hint. The implementation may + ignore this hint, or may use it to optimize various + operations. A heap's actual capacity is only limited by + address space and available memory constraints). + This parameter must be greater than or equal + to the count of the heap which is to be copied, or the + behavior is undefined. If this parameter is negative, the + behavior is undefined. @param heap The binary heap which is to be copied. The values from the binary heap are copied as pointers into the new binary heap (that is, the values themselves are copied, not that which the values @@ -176,7 +175,7 @@ CF_EXPORT CFBinaryHeapRef CFBinaryHeapCreate(CFAllocatorRef allocator, CFIndex c be the same as the given binary heap. The new binary heap uses the same callbacks as the binary heap to be copied. If this parameter is not a valid CFBinaryHeap, the behavior is undefined. - @result A reference to the new mutable or fixed-mutable binary heap. + @result A reference to the new mutable binary heap. */ CF_EXPORT CFBinaryHeapRef CFBinaryHeapCreateCopy(CFAllocatorRef allocator, CFIndex capacity, CFBinaryHeapRef heap); @@ -280,8 +279,6 @@ CF_EXPORT void CFBinaryHeapApplyFunction(CFBinaryHeapRef heap, CFBinaryHeapAppl Adds the value to the binary heap. @param heap The binary heap to which the value is to be added. If this parameter is not a valid mutable CFBinaryHeap, the behavior is undefined. - If the binary heap is a fixed-capacity binary heap and it - is full before this operation, the behavior is undefined. @param value The value to add to the binary heap. The value is retained by the binary heap using the retain callback provided when the binary heap was created. If the value is not of the sort expected by the @@ -306,9 +303,7 @@ CF_EXPORT void CFBinaryHeapRemoveMinimumValue(CFBinaryHeapRef heap); */ CF_EXPORT void CFBinaryHeapRemoveAllValues(CFBinaryHeapRef heap); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFBINARYHEAP__ */ diff --git a/CFBinaryPList.c b/CFBinaryPList.c new file mode 100644 index 0000000..8cbbf00 --- /dev/null +++ b/CFBinaryPList.c @@ -0,0 +1,1278 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFBinaryPList.c + Copyright 2000-2002, Apple, Inc. All rights reserved. + Responsibility: Christopher Kane +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "CFInternal.h" + +typedef struct { + int64_t high; + uint64_t low; +} CFSInt128Struct; + +enum { + kCFNumberSInt128Type = 17 +}; + +extern CFNumberType _CFNumberGetType2(CFNumberRef number); + +enum { + CF_NO_ERROR = 0, + CF_OVERFLOW_ERROR = (1 << 0), +}; + +CF_INLINE uint32_t __check_uint32_add_unsigned_unsigned(uint32_t x, uint32_t y, int32_t* err) { + if((UINT_MAX - y) < x) + *err = *err | CF_OVERFLOW_ERROR; + return x + y; +}; + +CF_INLINE uint64_t __check_uint64_add_unsigned_unsigned(uint64_t x, uint64_t y, int32_t* err) { + if((ULLONG_MAX - y) < x) + *err = *err | CF_OVERFLOW_ERROR; + return x + y; +}; + +CF_INLINE uint32_t __check_uint32_mul_unsigned_unsigned(uint32_t x, uint32_t y, int32_t* err) { + uint64_t tmp = (uint64_t) x * (uint64_t) y; + /* If any of the upper 32 bits touched, overflow */ + if(tmp & 0xffffffff00000000ULL) + *err = *err | CF_OVERFLOW_ERROR; + return (uint32_t) tmp; +}; + +CF_INLINE uint64_t __check_uint64_mul_unsigned_unsigned(uint64_t x, uint64_t y, int32_t* err) { + if(x == 0) return 0; + if(ULLONG_MAX/x < y) + *err = *err | CF_OVERFLOW_ERROR; + return x * y; +}; + +#if __LP64__ +#define check_ptr_add(p, a, err) (const uint8_t *)__check_uint64_add_unsigned_unsigned((uintptr_t)p, (uintptr_t)a, err) +#define check_size_t_mul(b, a, err) (size_t)__check_uint64_mul_unsigned_unsigned((size_t)b, (size_t)a, err) +#else +#define check_ptr_add(p, a, err) (const uint8_t *)__check_uint32_add_unsigned_unsigned((uintptr_t)p, (uintptr_t)a, err) +#define check_size_t_mul(b, a, err) (size_t)__check_uint32_mul_unsigned_unsigned((size_t)b, (size_t)a, err) +#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; +}; + +static CFStringRef __CFKeyedArchiverUIDCopyDescription(CFTypeRef cf) { + CFKeyedArchiverUIDRef uid = (CFKeyedArchiverUIDRef)cf; + return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{value = %u}"), cf, CFGetAllocator(cf), uid->_value); +} + +static CFStringRef __CFKeyedArchiverUIDCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { + CFKeyedArchiverUIDRef uid = (CFKeyedArchiverUIDRef)cf; + return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("@%u@"), uid->_value); +} + +static CFTypeID __kCFKeyedArchiverUIDTypeID = _kCFRuntimeNotATypeID; + +static const CFRuntimeClass __CFKeyedArchiverUIDClass = { + 0, + "CFKeyedArchiverUID", + NULL, // init + NULL, // copy + NULL, // finalize + NULL, // equal -- pointer equality only + NULL, // hash -- pointer hashing only + __CFKeyedArchiverUIDCopyFormattingDescription, + __CFKeyedArchiverUIDCopyDescription +}; + +__private_extern__ void __CFKeyedArchiverUIDInitialize(void) { + __kCFKeyedArchiverUIDTypeID = _CFRuntimeRegisterClass(&__CFKeyedArchiverUIDClass); +} + +CFTypeID _CFKeyedArchiverUIDGetTypeID(void) { + return __kCFKeyedArchiverUIDTypeID; +} + +CFKeyedArchiverUIDRef _CFKeyedArchiverUIDCreate(CFAllocatorRef allocator, uint32_t value) { + CFKeyedArchiverUIDRef uid; + uid = (CFKeyedArchiverUIDRef)_CFRuntimeCreateInstance(allocator, __kCFKeyedArchiverUIDTypeID, sizeof(struct __CFKeyedArchiverUID) - sizeof(CFRuntimeBase), NULL); + if (NULL == uid) { + return NULL; + } + ((struct __CFKeyedArchiverUID *)uid)->_value = value; + return uid; +} + + +uint32_t _CFKeyedArchiverUIDGetValue(CFKeyedArchiverUIDRef uid) { + return uid->_value; +} + + +typedef struct { + CFTypeRef stream; + CFTypeRef error; + uint64_t written; + int32_t used; + bool streamIsData; + uint8_t buffer[8192 - 32]; +} __CFBinaryPlistWriteBuffer; + +static void writeBytes(__CFBinaryPlistWriteBuffer *buf, const UInt8 *bytes, CFIndex length) { + if (0 == length) return; + if (buf->error) return; + if (buf->streamIsData) { + CFDataAppendBytes((CFMutableDataRef)buf->stream, bytes, length); + buf->written += length; + } else { + CFAssert(false, __kCFLogAssertion, "Streams are not supported on this platform"); + } +} + +static void bufferWrite(__CFBinaryPlistWriteBuffer *buf, const uint8_t *buffer, CFIndex count) { + if (0 == count) return; + if ((CFIndex)sizeof(buf->buffer) <= count) { + writeBytes(buf, buf->buffer, buf->used); + buf->used = 0; + writeBytes(buf, buffer, count); + return; + } + CFIndex copyLen = __CFMin(count, (CFIndex)sizeof(buf->buffer) - buf->used); + memmove(buf->buffer + buf->used, buffer, copyLen); + buf->used += copyLen; + if (sizeof(buf->buffer) == buf->used) { + writeBytes(buf, buf->buffer, sizeof(buf->buffer)); + memmove(buf->buffer, buffer + copyLen, count - copyLen); + buf->used = count - copyLen; + } +} + +static void bufferFlush(__CFBinaryPlistWriteBuffer *buf) { + writeBytes(buf, buf->buffer, buf->used); + buf->used = 0; +} + +/* +HEADER + magic number ("bplist") + file format version + +OBJECT TABLE + variable-sized objects + + Object Formats (marker byte followed by additional info in some cases) + null 0000 0000 + bool 0000 1000 // false + bool 0000 1001 // true + fill 0000 1111 // fill byte + int 0001 nnnn ... // # of bytes is 2^nnnn, big-endian bytes + real 0010 nnnn ... // # of bytes is 2^nnnn, big-endian bytes + date 0011 0011 ... // 8 byte float follows, big-endian bytes + data 0100 nnnn [int] ... // nnnn is number of bytes unless 1111 then int count follows, followed by bytes + string 0101 nnnn [int] ... // ASCII string, nnnn is # of chars, else 1111 then int count, then bytes + string 0110 nnnn [int] ... // Unicode string, nnnn is # of chars, else 1111 then int count, then big-endian 2-byte uint16_t + 0111 xxxx // unused + uid 1000 nnnn ... // nnnn+1 is # of bytes + 1001 xxxx // unused + array 1010 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows + 1011 xxxx // unused + set 1100 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows + dict 1101 nnnn [int] keyref* objref* // nnnn is count, unless '1111', then int count follows + 1110 xxxx // unused + 1111 xxxx // unused + +OFFSET TABLE + list of ints, byte size of which is given in trailer + -- these are the byte offsets into the file + -- number of these is in the trailer + +TRAILER + byte size of offset ints in offset table + byte size of object refs in arrays and dicts + number of offsets in offset table (also is number of objects) + element # in offset table which is top level object + offset table offset + +*/ + + +static CFTypeID stringtype = -1, datatype = -1, numbertype = -1, datetype = -1; +static CFTypeID booltype = -1, nulltype = -1, dicttype = -1, arraytype = -1, settype = -1; + +static void _appendInt(__CFBinaryPlistWriteBuffer *buf, uint64_t bigint) { + uint8_t marker; + uint8_t *bytes; + CFIndex nbytes; + if (bigint <= (uint64_t)0xff) { + nbytes = 1; + marker = kCFBinaryPlistMarkerInt | 0; + } else if (bigint <= (uint64_t)0xffff) { + nbytes = 2; + marker = kCFBinaryPlistMarkerInt | 1; + } else if (bigint <= (uint64_t)0xffffffff) { + nbytes = 4; + marker = kCFBinaryPlistMarkerInt | 2; + } else { + nbytes = 8; + marker = kCFBinaryPlistMarkerInt | 3; + } + bigint = CFSwapInt64HostToBig(bigint); + bytes = (uint8_t *)&bigint + sizeof(bigint) - nbytes; + bufferWrite(buf, &marker, 1); + bufferWrite(buf, bytes, nbytes); +} + +static void _appendUID(__CFBinaryPlistWriteBuffer *buf, CFKeyedArchiverUIDRef uid) { + uint8_t marker; + uint8_t *bytes; + CFIndex nbytes; + uint64_t bigint = _CFKeyedArchiverUIDGetValue(uid); + if (bigint <= (uint64_t)0xff) { + nbytes = 1; + } else if (bigint <= (uint64_t)0xffff) { + nbytes = 2; + } else if (bigint <= (uint64_t)0xffffffff) { + nbytes = 4; + } else { + nbytes = 8; + } + marker = kCFBinaryPlistMarkerUID | (uint8_t)(nbytes - 1); + bigint = CFSwapInt64HostToBig(bigint); + bytes = (uint8_t *)&bigint + sizeof(bigint) - nbytes; + bufferWrite(buf, &marker, 1); + bufferWrite(buf, bytes, nbytes); +} + +static Boolean __plistNumberEqual(CFTypeRef cf1, CFTypeRef cf2) { + // As long as this equals function is more restrictive than the + // existing one, for any given type, the hash function need not + // also be provided for the uniquing set. + if (CFNumberIsFloatType((CFNumberRef)cf1) != CFNumberIsFloatType((CFNumberRef)cf2)) return false; + return CFEqual(cf1, cf2); +} + +static CFHashCode __plistDataHash(CFTypeRef cf) { + CFDataRef data = (CFDataRef)cf; + return CFHashBytes((UInt8 *)CFDataGetBytePtr(data), __CFMin(CFDataGetLength(data), 1280)); +} + +static void _flattenPlist(CFPropertyListRef plist, CFMutableArrayRef objlist, CFMutableDictionaryRef objtable, CFMutableSetRef uniquingsets[]) { + CFPropertyListRef unique; + uint32_t refnum; + CFTypeID type = __CFGenericTypeID_genericobj_inline(plist); + CFIndex idx; + CFPropertyListRef *list, buffer[256]; + + // Do not unique dictionaries or arrays, because: they + // are slow to compare, and have poor hash codes. + // Uniquing bools is unnecessary. + int which = -1; + if (stringtype == type) { + which = 0; + } else if (numbertype == type) { + which = 1; + } else if (datetype == type) { + which = 2; + } else if (datatype == type) { + which = 3; + } + if (1 && -1 != which) { + CFMutableSetRef uniquingset = uniquingsets[which]; + CFIndex before = CFSetGetCount(uniquingset); + CFSetAddValue(uniquingset, plist); + CFIndex after = CFSetGetCount(uniquingset); + if (after == before) { // already in set + unique = CFSetGetValue(uniquingset, plist); + if (unique != plist) { + refnum = (uint32_t)(uintptr_t)CFDictionaryGetValue(objtable, unique); + CFDictionaryAddValue(objtable, plist, (const void *)(uintptr_t)refnum); + } + return; + } + } + refnum = CFArrayGetCount(objlist); + CFArrayAppendValue(objlist, plist); + 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); + CFDictionaryGetKeysAndValues((CFDictionaryRef)plist, list, list + count); + for (idx = 0; idx < 2 * count; idx++) { + _flattenPlist(list[idx], objlist, objtable, uniquingsets); + } + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + } else if (arraytype == type) { + CFIndex count = CFArrayGetCount((CFArrayRef)plist); + list = (count <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, count * sizeof(CFTypeRef), 0); + CFArrayGetValues((CFArrayRef)plist, CFRangeMake(0, count), list); + for (idx = 0; idx < count; idx++) { + _flattenPlist(list[idx], objlist, objtable, uniquingsets); + } + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + } +} + +// stream must be a CFMutableDataRef +CFIndex __CFBinaryPlistWriteToStream(CFPropertyListRef plist, CFTypeRef stream) { + CFMutableDictionaryRef objtable; + CFMutableArrayRef objlist; + CFBinaryPlistTrailer trailer; + uint64_t *offsets, length_so_far; + uint64_t mask, refnum; + int64_t idx, idx2, cnt; + __CFBinaryPlistWriteBuffer *buf; + + if ((CFTypeID)-1 == stringtype) { + stringtype = CFStringGetTypeID(); + } + if ((CFTypeID)-1 == datatype) { + datatype = CFDataGetTypeID(); + } + if ((CFTypeID)-1 == numbertype) { + numbertype = CFNumberGetTypeID(); + } + if ((CFTypeID)-1 == booltype) { + booltype = CFBooleanGetTypeID(); + } + if ((CFTypeID)-1 == datetype) { + datetype = CFDateGetTypeID(); + } + if ((CFTypeID)-1 == dicttype) { + dicttype = CFDictionaryGetTypeID(); + } + if ((CFTypeID)-1 == arraytype) { + arraytype = CFArrayGetTypeID(); + } + if ((CFTypeID)-1 == settype) { + settype = CFSetGetTypeID(); + } + if ((CFTypeID)-1 == nulltype) { + nulltype = CFNullGetTypeID(); + } + + objtable = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); + _CFDictionarySetCapacity(objtable, 640); + objlist = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, NULL); + _CFArraySetCapacity(objlist, 640); + CFSetCallBacks cb = kCFTypeSetCallBacks; + cb.retain = NULL; + cb.release = NULL; + CFMutableSetRef uniquingsets[4]; + uniquingsets[0] = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &cb); + _CFSetSetCapacity(uniquingsets[0], 1000); + cb.equal = __plistNumberEqual; + uniquingsets[1] = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &cb); + _CFSetSetCapacity(uniquingsets[1], 500); + cb.equal = kCFTypeSetCallBacks.equal; + uniquingsets[2] = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &cb); + _CFSetSetCapacity(uniquingsets[2], 500); + cb.hash = __plistDataHash; + uniquingsets[3] = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &cb); + _CFSetSetCapacity(uniquingsets[3], 500); + + _flattenPlist(plist, objlist, objtable, uniquingsets); + + CFRelease(uniquingsets[0]); + CFRelease(uniquingsets[1]); + CFRelease(uniquingsets[2]); + CFRelease(uniquingsets[3]); + + cnt = CFArrayGetCount(objlist); + offsets = (uint64_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, (CFIndex)(cnt * sizeof(*offsets)), 0); + + buf = (__CFBinaryPlistWriteBuffer *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFBinaryPlistWriteBuffer), 0); + buf->stream = stream; + buf->error = NULL; + buf->streamIsData = (CFGetTypeID(stream) == CFDataGetTypeID()); + buf->written = 0; + buf->used = 0; + bufferWrite(buf, (uint8_t *)"bplist00", 8); // header + + memset(&trailer, 0, sizeof(trailer)); + trailer._numObjects = CFSwapInt64HostToBig(cnt); + trailer._topObject = 0; // true for this implementation + mask = ~(uint64_t)0; + while (cnt & mask) { + trailer._objectRefSize++; + mask = mask << 8; + } + + for (idx = 0; idx < cnt; idx++) { + CFPropertyListRef obj = CFArrayGetValueAtIndex(objlist, (CFIndex)idx); + CFTypeID type = __CFGenericTypeID_genericobj_inline(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); + // presumption, believed to be true, is that ASCII encoding may need + // less bytes, but will not need greater, than the # of unichars + ret = CFStringGetBytes((CFStringRef)obj, CFRangeMake(0, count), kCFStringEncodingASCII, 0, false, bytes, count, &needed); + if (ret == count) { + uint8_t marker = (uint8_t)(kCFBinaryPlistMarkerASCIIString | (needed < 15 ? needed : 0xf)); + bufferWrite(buf, &marker, 1); + if (15 <= needed) { + _appendInt(buf, (uint64_t)needed); + } + bufferWrite(buf, bytes, needed); + } else { + UniChar *chars; + uint8_t marker = (uint8_t)(kCFBinaryPlistMarkerUnicode16String | (count < 15 ? count : 0xf)); + bufferWrite(buf, &marker, 1); + if (15 <= count) { + _appendInt(buf, (uint64_t)count); + } + chars = (UniChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 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); + } + if (bytes != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, bytes); + } else if (numbertype == type) { + uint8_t marker; + uint64_t bigint; + uint8_t *bytes; + CFIndex nbytes; + if (CFNumberIsFloatType((CFNumberRef)obj)) { + CFSwappedFloat64 swapped64; + CFSwappedFloat32 swapped32; + if (CFNumberGetByteSize((CFNumberRef)obj) <= (CFIndex)sizeof(float)) { + float v; + CFNumberGetValue((CFNumberRef)obj, kCFNumberFloat32Type, &v); + swapped32 = CFConvertFloat32HostToSwapped(v); + bytes = (uint8_t *)&swapped32; + nbytes = sizeof(float); + marker = kCFBinaryPlistMarkerReal | 2; + } else { + double v; + CFNumberGetValue((CFNumberRef)obj, kCFNumberFloat64Type, &v); + swapped64 = CFConvertFloat64HostToSwapped(v); + bytes = (uint8_t *)&swapped64; + nbytes = sizeof(double); + marker = kCFBinaryPlistMarkerReal | 3; + } + bufferWrite(buf, &marker, 1); + bufferWrite(buf, bytes, nbytes); + } else { + CFNumberType type = _CFNumberGetType2((CFNumberRef)obj); + if (kCFNumberSInt128Type == type) { + CFSInt128Struct s; + CFNumberGetValue((CFNumberRef)obj, kCFNumberSInt128Type, &s); + struct { + int64_t high; + uint64_t low; + } storage; + storage.high = CFSwapInt64HostToBig(s.high); + storage.low = CFSwapInt64HostToBig(s.low); + uint8_t *bytes = (uint8_t *)&storage; + uint8_t marker = kCFBinaryPlistMarkerInt | 4; + CFIndex nbytes = 16; + bufferWrite(buf, &marker, 1); + bufferWrite(buf, bytes, nbytes); + } else { + CFNumberGetValue((CFNumberRef)obj, kCFNumberSInt64Type, &bigint); + _appendInt(buf, bigint); + } + } + } else if (_CFKeyedArchiverUIDGetTypeID() == type) { + _appendUID(buf, (CFKeyedArchiverUIDRef)obj); + } else if (booltype == type) { + uint8_t marker = CFBooleanGetValue((CFBooleanRef)obj) ? kCFBinaryPlistMarkerTrue : kCFBinaryPlistMarkerFalse; + bufferWrite(buf, &marker, 1); + } else if (datatype == type) { + CFIndex count = CFDataGetLength((CFDataRef)obj); + uint8_t marker = (uint8_t)(kCFBinaryPlistMarkerData | (count < 15 ? count : 0xf)); + bufferWrite(buf, &marker, 1); + if (15 <= count) { + _appendInt(buf, (uint64_t)count); + } + bufferWrite(buf, CFDataGetBytePtr((CFDataRef)obj), count); + } else if (datetype == type) { + CFSwappedFloat64 swapped; + uint8_t marker = kCFBinaryPlistMarkerDate; + bufferWrite(buf, &marker, 1); + swapped = CFConvertFloat64HostToSwapped(CFDateGetAbsoluteTime((CFDateRef)obj)); + bufferWrite(buf, (uint8_t *)&swapped, sizeof(swapped)); + } else if (dicttype == type) { + CFIndex count = CFDictionaryGetCount((CFDictionaryRef)obj); + CFPropertyListRef *list, buffer[512]; + uint8_t marker = (uint8_t)(kCFBinaryPlistMarkerDict | (count < 15 ? count : 0xf)); + bufferWrite(buf, &marker, 1); + if (15 <= count) { + _appendInt(buf, (uint64_t)count); + } + list = (count <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 2 * count * sizeof(CFTypeRef), 0); + CFDictionaryGetKeysAndValues((CFDictionaryRef)obj, list, list + count); + for (idx2 = 0; idx2 < 2 * count; idx2++) { + CFPropertyListRef value = list[idx2]; + uint32_t swapped = 0; + uint8_t *source = (uint8_t *)&swapped; + refnum = (uint32_t)(uintptr_t)CFDictionaryGetValue(objtable, value); + swapped = CFSwapInt32HostToBig((uint32_t)refnum); + bufferWrite(buf, source + sizeof(swapped) - trailer._objectRefSize, trailer._objectRefSize); + } + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + } else if (arraytype == type) { + CFIndex count = CFArrayGetCount((CFArrayRef)obj); + CFPropertyListRef *list, buffer[256]; + uint8_t marker = (uint8_t)(kCFBinaryPlistMarkerArray | (count < 15 ? count : 0xf)); + bufferWrite(buf, &marker, 1); + if (15 <= count) { + _appendInt(buf, (uint64_t)count); + } + list = (count <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, count * sizeof(CFTypeRef), 0); + CFArrayGetValues((CFArrayRef)obj, CFRangeMake(0, count), list); + for (idx2 = 0; idx2 < count; idx2++) { + CFPropertyListRef value = list[idx2]; + uint32_t swapped = 0; + uint8_t *source = (uint8_t *)&swapped; + refnum = (uint32_t)(uintptr_t)CFDictionaryGetValue(objtable, value); + swapped = CFSwapInt32HostToBig((uint32_t)refnum); + bufferWrite(buf, source + sizeof(swapped) - trailer._objectRefSize, trailer._objectRefSize); + } + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + } else { + CFRelease(objtable); + CFRelease(objlist); + if (buf->error) CFRelease(buf->error); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, buf); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, offsets); + return 0; + } + } + CFRelease(objtable); + CFRelease(objlist); + + length_so_far = buf->written + buf->used; + trailer._offsetTableOffset = CFSwapInt64HostToBig(length_so_far); + trailer._offsetIntSize = 0; + mask = ~(uint64_t)0; + while (length_so_far & mask) { + trailer._offsetIntSize++; + mask = mask << 8; + } + + for (idx = 0; idx < cnt; idx++) { + uint64_t swapped = CFSwapInt64HostToBig(offsets[idx]); + uint8_t *source = (uint8_t *)&swapped; + bufferWrite(buf, source + sizeof(*offsets) - trailer._offsetIntSize, trailer._offsetIntSize); + } + length_so_far += cnt * trailer._offsetIntSize; + + bufferWrite(buf, (uint8_t *)&trailer, sizeof(trailer)); + bufferFlush(buf); + length_so_far += sizeof(trailer); + if (buf->error) { + CFRelease(buf->error); + return 0; + } + CFAllocatorDeallocate(kCFAllocatorSystemDefault, buf); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, offsets); + return (CFIndex)length_so_far; +} + + +#define FAIL_FALSE do { return false; } while (0) +#define FAIL_MAXOFFSET do { return UINT64_MAX; } while (0) + +bool __CFBinaryPlistGetTopLevelInfo(const uint8_t *databytes, uint64_t datalen, uint8_t *marker, uint64_t *offset, CFBinaryPlistTrailer *trailer) { + CFBinaryPlistTrailer trail; + + if ((CFTypeID)-1 == stringtype) { + stringtype = CFStringGetTypeID(); + } + if ((CFTypeID)-1 == datatype) { + datatype = CFDataGetTypeID(); + } + if ((CFTypeID)-1 == numbertype) { + numbertype = CFNumberGetTypeID(); + } + if ((CFTypeID)-1 == booltype) { + booltype = CFBooleanGetTypeID(); + } + if ((CFTypeID)-1 == datetype) { + datetype = CFDateGetTypeID(); + } + if ((CFTypeID)-1 == dicttype) { + dicttype = CFDictionaryGetTypeID(); + } + if ((CFTypeID)-1 == arraytype) { + arraytype = CFArrayGetTypeID(); + } + if ((CFTypeID)-1 == settype) { + settype = CFSetGetTypeID(); + } + if ((CFTypeID)-1 == nulltype) { + nulltype = CFNullGetTypeID(); + } + + if (!databytes || datalen < sizeof(trail) + 8 + 1) FAIL_FALSE; + if (0 != memcmp("bplist00", databytes, 8) && 0 != memcmp("bplist01", databytes, 8)) return false; + memmove(&trail, databytes + datalen - sizeof(trail), sizeof(trail)); + if (trail._unused[0] != 0 || trail._unused[1] != 0 || trail._unused[2] != 0 || trail._unused[3] != 0 || trail._unused[4] != 0 || trail._unused[5] != 0) FAIL_FALSE; + trail._numObjects = CFSwapInt64BigToHost(trail._numObjects); + trail._topObject = CFSwapInt64BigToHost(trail._topObject); + trail._offsetTableOffset = CFSwapInt64BigToHost(trail._offsetTableOffset); + if (LONG_MAX < trail._numObjects) FAIL_FALSE; + if (LONG_MAX < trail._offsetTableOffset) FAIL_FALSE; + if (trail._numObjects < 1) FAIL_FALSE; + if (trail._numObjects <= trail._topObject) FAIL_FALSE; + if (trail._offsetTableOffset < 9) FAIL_FALSE; + if (datalen - sizeof(trail) <= trail._offsetTableOffset) FAIL_FALSE; + if (trail._offsetIntSize < 1) FAIL_FALSE; + if (trail._objectRefSize < 1) FAIL_FALSE; + int32_t err = CF_NO_ERROR; + uint64_t offsetIntSize = trail._offsetIntSize; + uint64_t offsetTableSize = __check_uint64_mul_unsigned_unsigned(trail._numObjects, offsetIntSize, &err); + if (CF_NO_ERROR!= err) FAIL_FALSE; + if (offsetTableSize < 1) FAIL_FALSE; + 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; + if (datalen != tmpSum) FAIL_FALSE; + if (trail._objectRefSize < 8 && (1ULL << (8 * trail._objectRefSize)) <= trail._numObjects) FAIL_FALSE; + 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; + const uint8_t *offsetsFirstByte = check_ptr_add(databytes, trail._offsetTableOffset, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + const uint8_t *offsetsLastByte; + offsetsLastByte = check_ptr_add(offsetsFirstByte, offsetTableSize - 1, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + + const uint8_t *bytesptr = databytes + trail._offsetTableOffset; + uint64_t maxOffset = trail._offsetTableOffset - 1; + for (CFIndex idx = 0; idx < trail._numObjects; idx++) { + uint64_t off = 0; + for (CFIndex idx2 = 0; idx2 < trail._offsetIntSize; idx2++) { + off = (off << 8) + bytesptr[idx2]; + } + if (maxOffset < off) FAIL_FALSE; + bytesptr += trail._offsetIntSize; + } + + bytesptr = databytes + trail._offsetTableOffset + trail._topObject * trail._offsetIntSize; + uint64_t off = 0; + for (CFIndex idx = 0; idx < trail._offsetIntSize; idx++) { + off = (off << 8) + bytesptr[idx]; + } + if (off < 8 || trail._offsetTableOffset <= off) FAIL_FALSE; + if (trailer) *trailer = trail; + if (offset) *offset = off; + if (marker) *marker = *(databytes + off); + return true; +} + +CF_INLINE Boolean _plistIsPrimitive(CFPropertyListRef pl) { + CFTypeID type = __CFGenericTypeID_genericobj_inline(pl); + if (dicttype == type || arraytype == type || settype == type) FAIL_FALSE; + return true; +} + +CF_INLINE bool _readInt(const uint8_t *ptr, const uint8_t *end_byte_ptr, uint64_t *bigint, const uint8_t **newptr) { + if (end_byte_ptr < ptr) FAIL_FALSE; + uint8_t marker = *ptr++; + if ((marker & 0xf0) != kCFBinaryPlistMarkerInt) FAIL_FALSE; + uint64_t cnt = 1 << (marker & 0x0f); + int32_t err = CF_NO_ERROR; + const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1; + if (CF_NO_ERROR != err) FAIL_FALSE; + if (end_byte_ptr < extent) FAIL_FALSE; + // integers are not required to be in the most compact possible representation, but only the last 64 bits are significant currently + *bigint = 0; + for (CFIndex idx = 0; idx < cnt; idx++) { + *bigint = (*bigint << 8) + *ptr++; + } + if (newptr) *newptr = ptr; + return true; +} + +// bytesptr points at a ref +CF_INLINE uint64_t _getOffsetOfRefAt(const uint8_t *databytes, const uint8_t *bytesptr, const CFBinaryPlistTrailer *trailer) { + // *trailer contents are trusted, even for overflows -- was checked when the trailer was parsed; + // this pointer arithmetic and the multiplication was also already done once and checked, + // and the offsetTable was already validated. + const uint8_t *objectsFirstByte = databytes + 8; + const uint8_t *offsetsFirstByte = databytes + trailer->_offsetTableOffset; + if (bytesptr < objectsFirstByte || offsetsFirstByte - trailer->_objectRefSize < bytesptr) FAIL_MAXOFFSET; + + uint64_t ref = 0; + for (CFIndex idx = 0; idx < trailer->_objectRefSize; idx++) { + ref = (ref << 8) + bytesptr[idx]; + } + if (trailer->_numObjects <= ref) FAIL_MAXOFFSET; + + bytesptr = databytes + trailer->_offsetTableOffset + ref * trailer->_offsetIntSize; + uint64_t off = 0; + for (CFIndex idx = 0; idx < trailer->_offsetIntSize; idx++) { + off = (off << 8) + bytesptr[idx]; + } + return off; +} + +static 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); + +bool __CFBinaryPlistGetOffsetForValueFromArray2(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFIndex idx, uint64_t *offset, CFMutableDictionaryRef objects) { + uint64_t objectsRangeStart = 8, objectsRangeEnd = trailer->_offsetTableOffset - 1; + if (startOffset < objectsRangeStart || objectsRangeEnd < startOffset) FAIL_FALSE; + const uint8_t *ptr = databytes + startOffset; + uint8_t marker = *ptr; + if ((marker & 0xf0) != kCFBinaryPlistMarkerArray) FAIL_FALSE; + int32_t err = CF_NO_ERROR; + ptr = check_ptr_add(ptr, 1, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + uint64_t cnt = (marker & 0x0f); + if (0xf == cnt) { + uint64_t bigint; + if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE; + if (LONG_MAX < bigint) FAIL_FALSE; + cnt = bigint; + } + if (cnt <= idx) FAIL_FALSE; + size_t byte_cnt = check_size_t_mul(cnt, trailer->_objectRefSize, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + const uint8_t *extent = check_ptr_add(ptr, byte_cnt, &err) - 1; + if (CF_NO_ERROR != err) FAIL_FALSE; + if (databytes + objectsRangeEnd < extent) FAIL_FALSE; + uint64_t off = _getOffsetOfRefAt(databytes, ptr + idx * trailer->_objectRefSize, trailer); + if (offset) *offset = off; + return true; +} + +bool __CFBinaryPlistGetOffsetForValueFromDictionary2(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFTypeRef key, uint64_t *koffset, uint64_t *voffset, CFMutableDictionaryRef objects) { + if (!key || !_plistIsPrimitive(key)) FAIL_FALSE; + uint64_t objectsRangeStart = 8, objectsRangeEnd = trailer->_offsetTableOffset - 1; + if (startOffset < objectsRangeStart || objectsRangeEnd < startOffset) FAIL_FALSE; + const uint8_t *ptr = databytes + startOffset; + uint8_t marker = *ptr; + if ((marker & 0xf0) != kCFBinaryPlistMarkerDict) FAIL_FALSE; + int32_t err = CF_NO_ERROR; + ptr = check_ptr_add(ptr, 1, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + uint64_t cnt = (marker & 0x0f); + if (0xf == cnt) { + uint64_t bigint = 0; + if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE; + if (LONG_MAX < bigint) FAIL_FALSE; + cnt = bigint; + } + cnt = check_size_t_mul(cnt, 2, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + size_t byte_cnt = check_size_t_mul(cnt, trailer->_objectRefSize, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + const uint8_t *extent = check_ptr_add(ptr, byte_cnt, &err) - 1; + if (CF_NO_ERROR != err) FAIL_FALSE; + if (databytes + objectsRangeEnd < extent) FAIL_FALSE; + CFIndex stringKeyLen = -1; + UniChar ubuffer[16]; + if (__CFGenericTypeID_genericobj_inline(key) == stringtype) { + stringKeyLen = CFStringGetLength((CFStringRef)key); + if (stringKeyLen < 0xf) { + CFStringGetCharacters((CFStringRef)key, CFRangeMake(0, stringKeyLen), ubuffer); + } + } + cnt = cnt / 2; + for (CFIndex idx = 0; idx < cnt; idx++) { + uint64_t off = _getOffsetOfRefAt(databytes, ptr, trailer); + uint8_t marker = *(databytes + off); + CFIndex len = marker & 0x0f; + // if it is a short ascii string in the data, and the key is a string + if ((marker & 0xf0) == kCFBinaryPlistMarkerASCIIString && len < 0xf && stringKeyLen != -1) { + if (len != stringKeyLen) goto miss; + 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; + for (CFIndex idx2 = 0; idx2 < stringKeyLen; idx2++) { + if ((UniChar)ptr2[idx2 + 1] != ubuffer[idx2]) goto miss; + } + if (koffset) *koffset = off; + if (voffset) { + off = _getOffsetOfRefAt(databytes, ptr + cnt * trailer->_objectRefSize, trailer); + *voffset = off; + } + return true; + miss:; + } else { + CFPropertyListRef pl = NULL; + if (!__CFBinaryPlistCreateObject2(databytes, datalen, off, trailer, kCFAllocatorSystemDefault, kCFPropertyListImmutable, objects, NULL, 0, &pl) || !_plistIsPrimitive(pl)) { + if (pl) CFRelease(pl); + FAIL_FALSE; + } + if (CFEqual(key, pl)) { + CFRelease(pl); + if (koffset) *koffset = off; + if (voffset) { + off = _getOffsetOfRefAt(databytes, ptr + cnt * trailer->_objectRefSize, trailer); + *voffset = off; + } + return true; + } + CFRelease(pl); + } + ptr += trailer->_objectRefSize; + } + return false; +} + +extern CFArrayRef _CFArrayCreate_ex(CFAllocatorRef allocator, Boolean isMutable, const void **values, CFIndex numValues); +extern CFSetRef _CFSetCreate_ex(CFAllocatorRef allocator, Boolean isMutable, const void **values, CFIndex numValues); +extern CFDictionaryRef _CFDictionaryCreate_ex(CFAllocatorRef allocator, Boolean isMutable, const void **keys, const void **values, CFIndex numValues); + +static 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); + return true; + } + } + + // at any one invocation of this function, set should contain the offsets in the "path" down to this object + if (set && CFSetContainsValue(set, (const void *)(uintptr_t)startOffset)) return false; + + // databytes is trusted to be at least datalen bytes long + // *trailer contents are trusted, even for overflows -- was checked when the trailer was parsed + uint64_t objectsRangeStart = 8, objectsRangeEnd = trailer->_offsetTableOffset - 1; + if (startOffset < objectsRangeStart || objectsRangeEnd < startOffset) FAIL_FALSE; + + uint64_t off; + CFPropertyListRef *list, buffer[256]; + CFAllocatorRef listAllocator; + + uint8_t marker = *(databytes + startOffset); + switch (marker & 0xf0) { + case kCFBinaryPlistMarkerNull: + switch (marker) { + case kCFBinaryPlistMarkerNull: + *plist = kCFNull; + return true; + case kCFBinaryPlistMarkerFalse: + *plist = CFRetain(kCFBooleanFalse); + return true; + case kCFBinaryPlistMarkerTrue: + *plist = CFRetain(kCFBooleanTrue); + return true; + } + FAIL_FALSE; + case kCFBinaryPlistMarkerInt: + { + const uint8_t *ptr = (databytes + startOffset); + int32_t err = CF_NO_ERROR; + ptr = check_ptr_add(ptr, 1, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + uint64_t cnt = 1 << (marker & 0x0f); + const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1; + if (CF_NO_ERROR != err) FAIL_FALSE; + if (databytes + objectsRangeEnd < extent) FAIL_FALSE; + if (16 < cnt) FAIL_FALSE; + // in format version '00', 1, 2, and 4-byte integers have to be interpreted as unsigned, + // whereas 8-byte integers are signed (and 16-byte when available) + // negative 1, 2, 4-byte integers are always emitted as 8 bytes in format '00' + uint64_t bigint = 0; + // integers are not required to be in the most compact possible representation, but only the last 64 bits are significant currently + for (CFIndex idx = 0; idx < cnt; idx++) { + bigint = (bigint << 8) + *ptr++; + } + if (8 < cnt) { + CFSInt128Struct val; + val.high = 0; + val.low = bigint; + *plist = CFNumberCreate(allocator, kCFNumberSInt128Type, &val); + } else { + *plist = CFNumberCreate(allocator, kCFNumberSInt64Type, &bigint); + } + // these are always immutable + if (objects && *plist) { + CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist); + } + return (*plist) ? true : false; + } + case kCFBinaryPlistMarkerReal: + switch (marker & 0x0f) { + case 2: { + const uint8_t *ptr = (databytes + startOffset); + int32_t err = CF_NO_ERROR; + ptr = check_ptr_add(ptr, 1, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + const uint8_t *extent = check_ptr_add(ptr, 4, &err) - 1; + if (CF_NO_ERROR != err) FAIL_FALSE; + if (databytes + objectsRangeEnd < extent) FAIL_FALSE; + CFSwappedFloat32 swapped32; + memmove(&swapped32, ptr, 4); + float f = CFConvertFloat32SwappedToHost(swapped32); + *plist = CFNumberCreate(allocator, kCFNumberFloat32Type, &f); + // these are always immutable + if (objects && *plist) { + CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist); + } + return (*plist) ? true : false; + } + case 3: { + const uint8_t *ptr = (databytes + startOffset); + int32_t err = CF_NO_ERROR; + ptr = check_ptr_add(ptr, 1, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + const uint8_t *extent = check_ptr_add(ptr, 8, &err) - 1; + if (CF_NO_ERROR != err) FAIL_FALSE; + if (databytes + objectsRangeEnd < extent) FAIL_FALSE; + CFSwappedFloat64 swapped64; + memmove(&swapped64, ptr, 8); + double d = CFConvertFloat64SwappedToHost(swapped64); + *plist = CFNumberCreate(allocator, kCFNumberFloat64Type, &d); + // these are always immutable + if (objects && *plist) { + CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist); + } + return (*plist) ? true : false; + } + } + FAIL_FALSE; + case kCFBinaryPlistMarkerDate & 0xf0: + switch (marker) { + case kCFBinaryPlistMarkerDate: { + const uint8_t *ptr = (databytes + startOffset); + int32_t err = CF_NO_ERROR; + ptr = check_ptr_add(ptr, 1, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + const uint8_t *extent = check_ptr_add(ptr, 8, &err) - 1; + if (CF_NO_ERROR != err) FAIL_FALSE; + if (databytes + objectsRangeEnd < extent) FAIL_FALSE; + CFSwappedFloat64 swapped64; + memmove(&swapped64, ptr, 8); + double d = CFConvertFloat64SwappedToHost(swapped64); + *plist = CFDateCreate(allocator, d); + // these are always immutable + if (objects && *plist) { + CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist); + } + return (*plist) ? true : false; + } + } + FAIL_FALSE; + case kCFBinaryPlistMarkerData: { + const uint8_t *ptr = databytes + startOffset; + int32_t err = CF_NO_ERROR; + ptr = check_ptr_add(ptr, 1, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + CFIndex cnt = marker & 0x0f; + if (0xf == cnt) { + uint64_t bigint = 0; + if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE; + if (LONG_MAX < bigint) FAIL_FALSE; + cnt = (CFIndex)bigint; + } + const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1; + if (CF_NO_ERROR != err) FAIL_FALSE; + if (databytes + objectsRangeEnd < extent) FAIL_FALSE; + if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) { + *plist = CFDataCreateMutable(allocator, 0); + if (*plist) CFDataAppendBytes((CFMutableDataRef)*plist, ptr, cnt); + } else { + *plist = CFDataCreate(allocator, ptr, cnt); + } + if (objects && *plist && (mutabilityOption != kCFPropertyListMutableContainersAndLeaves)) { + CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist); + } + return (*plist) ? true : false; + } + case kCFBinaryPlistMarkerASCIIString: { + const uint8_t *ptr = databytes + startOffset; + int32_t err = CF_NO_ERROR; + ptr = check_ptr_add(ptr, 1, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + CFIndex cnt = marker & 0x0f; + if (0xf == cnt) { + uint64_t bigint = 0; + if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE; + if (LONG_MAX < bigint) FAIL_FALSE; + cnt = (CFIndex)bigint; + } + const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1; + if (CF_NO_ERROR != err) FAIL_FALSE; + if (databytes + objectsRangeEnd < extent) FAIL_FALSE; + if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) { + CFStringRef str = CFStringCreateWithBytes(allocator, ptr, cnt, kCFStringEncodingASCII, false); + *plist = str ? CFStringCreateMutableCopy(allocator, 0, str) : NULL; + if (str) CFRelease(str); + } else { + *plist = CFStringCreateWithBytes(allocator, ptr, cnt, kCFStringEncodingASCII, false); + } + if (objects && *plist && (mutabilityOption != kCFPropertyListMutableContainersAndLeaves)) { + CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist); + } + return (*plist) ? true : false; + } + case kCFBinaryPlistMarkerUnicode16String: { + const uint8_t *ptr = databytes + startOffset; + int32_t err = CF_NO_ERROR; + ptr = check_ptr_add(ptr, 1, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + CFIndex cnt = marker & 0x0f; + if (0xf == cnt) { + uint64_t bigint = 0; + if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE; + if (LONG_MAX < bigint) FAIL_FALSE; + cnt = (CFIndex)bigint; + } + const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1; + extent = check_ptr_add(extent, cnt, &err); // 2 bytes per character + if (CF_NO_ERROR != err) FAIL_FALSE; + if (databytes + objectsRangeEnd < extent) FAIL_FALSE; + size_t byte_cnt = check_size_t_mul(cnt, sizeof(UniChar), &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + UniChar *chars = (UniChar *)CFAllocatorAllocate(allocator, 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); + *plist = str ? CFStringCreateMutableCopy(allocator, 0, str) : NULL; + if (str) CFRelease(str); + } else { + *plist = CFStringCreateWithCharactersNoCopy(allocator, chars, cnt, allocator); + } + if (objects && *plist && (mutabilityOption != kCFPropertyListMutableContainersAndLeaves)) { + CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist); + } + return (*plist) ? true : false; + } + case kCFBinaryPlistMarkerUID: { + const uint8_t *ptr = databytes + startOffset; + int32_t err = CF_NO_ERROR; + ptr = check_ptr_add(ptr, 1, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + CFIndex cnt = (marker & 0x0f) + 1; + const uint8_t *extent = check_ptr_add(ptr, cnt, &err) - 1; + if (CF_NO_ERROR != err) FAIL_FALSE; + if (databytes + objectsRangeEnd < extent) FAIL_FALSE; + // uids are not required to be in the most compact possible representation, but only the last 64 bits are significant currently + uint64_t bigint = 0; + for (CFIndex idx = 0; idx < cnt; idx++) { + bigint = (bigint << 8) + *ptr++; + } + if (UINT32_MAX < bigint) FAIL_FALSE; + *plist = _CFKeyedArchiverUIDCreate(allocator, (uint32_t)bigint); + // these are always immutable + if (objects && *plist) { + CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist); + } + return (*plist) ? true : false; + } + case kCFBinaryPlistMarkerArray: + case kCFBinaryPlistMarkerSet: { + const uint8_t *ptr = databytes + startOffset; + int32_t err = CF_NO_ERROR; + ptr = check_ptr_add(ptr, 1, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + CFIndex cnt = marker & 0x0f; + if (0xf == cnt) { + uint64_t bigint = 0; + if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE; + if (LONG_MAX < bigint) FAIL_FALSE; + cnt = (CFIndex)bigint; + } + size_t byte_cnt = check_size_t_mul(cnt, trailer->_objectRefSize, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + const uint8_t *extent = check_ptr_add(ptr, byte_cnt, &err) - 1; + if (CF_NO_ERROR != err) FAIL_FALSE; + if (databytes + objectsRangeEnd < extent) FAIL_FALSE; + byte_cnt = check_size_t_mul(cnt, sizeof(CFPropertyListRef), &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + list = (cnt <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, byte_cnt, __kCFAllocatorGCScannedMemory); + listAllocator = (list == buffer ? kCFAllocatorNull : kCFAllocatorSystemDefault); + if (!list) FAIL_FALSE; + Boolean madeSet = false; + if (!set && 15 < curDepth) { + set = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, NULL); + madeSet = set ? true : false; + } + if (set) CFSetAddValue(set, (const void *)(uintptr_t)startOffset); + for (CFIndex idx = 0; idx < cnt; idx++) { + CFPropertyListRef pl; + off = _getOffsetOfRefAt(databytes, ptr, trailer); + if (!__CFBinaryPlistCreateObject2(databytes, datalen, off, trailer, allocator, mutabilityOption, objects, set, curDepth + 1, &pl)) { + if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + while (idx--) { + CFRelease(list[idx]); + } + } + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + FAIL_FALSE; + } + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + CF_WRITE_BARRIER_BASE_ASSIGN(listAllocator, list, list[idx], CFMakeCollectable(pl)); + } else { + list[idx] = pl; + } + ptr += trailer->_objectRefSize; + } + if (set) CFSetRemoveValue(set, (const void *)(uintptr_t)startOffset); + if (madeSet) { + CFRelease(set); + set = NULL; + } + if ((marker & 0xf0) == kCFBinaryPlistMarkerArray) { + *plist = _CFArrayCreate_ex(allocator, (mutabilityOption != kCFPropertyListImmutable), list, cnt); + } else { + *plist = _CFSetCreate_ex(allocator, (mutabilityOption != kCFPropertyListImmutable), list, cnt); + } + if (objects && *plist && (mutabilityOption == kCFPropertyListImmutable)) { + CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist); + } + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + return (*plist) ? true : false; + } + case kCFBinaryPlistMarkerDict: { + const uint8_t *ptr = databytes + startOffset; + int32_t err = CF_NO_ERROR; + ptr = check_ptr_add(ptr, 1, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + CFIndex cnt = marker & 0x0f; + if (0xf == cnt) { + uint64_t bigint = 0; + if (!_readInt(ptr, databytes + objectsRangeEnd, &bigint, &ptr)) FAIL_FALSE; + if (LONG_MAX < bigint) FAIL_FALSE; + cnt = (CFIndex)bigint; + } + cnt = check_size_t_mul(cnt, 2, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + size_t byte_cnt = check_size_t_mul(cnt, trailer->_objectRefSize, &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + const uint8_t *extent = check_ptr_add(ptr, byte_cnt, &err) - 1; + if (CF_NO_ERROR != err) FAIL_FALSE; + if (databytes + objectsRangeEnd < extent) FAIL_FALSE; + byte_cnt = check_size_t_mul(cnt, sizeof(CFPropertyListRef), &err); + if (CF_NO_ERROR != err) FAIL_FALSE; + list = (cnt <= 256) ? buffer : (CFPropertyListRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, byte_cnt, __kCFAllocatorGCScannedMemory); + listAllocator = (list == buffer ? kCFAllocatorNull : kCFAllocatorSystemDefault); + if (!list) FAIL_FALSE; + Boolean madeSet = false; + if (!set && 15 < curDepth) { + set = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, NULL); + madeSet = set ? true : false; + } + if (set) CFSetAddValue(set, (const void *)(uintptr_t)startOffset); + for (CFIndex idx = 0; idx < cnt; idx++) { + CFPropertyListRef pl = NULL; + off = _getOffsetOfRefAt(databytes, ptr, trailer); + if (!__CFBinaryPlistCreateObject2(databytes, datalen, off, trailer, allocator, mutabilityOption, objects, set, curDepth + 1, &pl) || (idx < cnt / 2 && !_plistIsPrimitive(pl))) { + if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + if (pl) CFRelease(pl); + while (idx--) { + CFRelease(list[idx]); + } + } + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + FAIL_FALSE; + } + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + CF_WRITE_BARRIER_BASE_ASSIGN(listAllocator, list, list[idx], CFMakeCollectable(pl)); + } else { + list[idx] = pl; + } + ptr += trailer->_objectRefSize; + } + if (set) CFSetRemoveValue(set, (const void *)(uintptr_t)startOffset); + if (madeSet) { + CFRelease(set); + set = NULL; + } + *plist = _CFDictionaryCreate_ex(allocator, (mutabilityOption != kCFPropertyListImmutable), list, list + cnt / 2, cnt / 2); + if (objects && *plist && (mutabilityOption == kCFPropertyListImmutable)) { + CFDictionarySetValue(objects, (const void *)(uintptr_t)startOffset, *plist); + } + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); + return (*plist) ? true : false; + } + } + FAIL_FALSE; +} + +bool __CFBinaryPlistCreateObject(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFAllocatorRef allocator, CFOptionFlags mutabilityOption, CFMutableDictionaryRef objects, CFPropertyListRef *plist) { + // for compatibility with Foundation's use, need to leave this here + return __CFBinaryPlistCreateObject2(databytes, datalen, startOffset, trailer, allocator, mutabilityOption, objects, NULL, 0, plist); +} + +__private_extern__ bool __CFTryParseBinaryPlist(CFAllocatorRef allocator, CFDataRef data, CFOptionFlags option, CFPropertyListRef *plist, CFStringRef *errorString) { + uint8_t marker; + CFBinaryPlistTrailer trailer; + uint64_t offset; + const uint8_t *databytes = CFDataGetBytePtr(data); + uint64_t datalen = CFDataGetLength(data); + + if (8 <= datalen && __CFBinaryPlistGetTopLevelInfo(databytes, datalen, &marker, &offset, &trailer)) { + // FALSE: We know for binary plist parsing that the result objects will be retained + // by their containing collections as the parsing proceeds, so we do not need + // to use retaining callbacks for the objects map in this case. WHY: the file might + // 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); + _CFDictionarySetCapacity(objects, 4000); + CFPropertyListRef pl = NULL; + if (__CFBinaryPlistCreateObject2(databytes, datalen, offset, &trailer, allocator, option, objects, NULL, 0, &pl)) { + if (plist) *plist = pl; + } else { + if (plist) *plist = NULL; + if (errorString) *errorString = (CFStringRef)CFRetain(CFSTR("binary data is corrupt")); + } + CFRelease(objects); + return true; + } + return false; +} + diff --git a/Collections.subproj/CFBitVector.c b/CFBitVector.c similarity index 98% rename from Collections.subproj/CFBitVector.c rename to CFBitVector.c index 8b0590c..60c090a 100644 --- a/Collections.subproj/CFBitVector.c +++ b/CFBitVector.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -43,7 +43,7 @@ enum { }; CF_INLINE CFIndex __CFBitVectorRoundUpCapacity(CFIndex capacity) { - return (__CF_BITS_PER_BUCKET < 64) ? (capacity + 63) / 64 : (capacity + __CF_BITS_PER_BUCKET - 1) / __CF_BITS_PER_BUCKET; + return ((capacity + 63) / 64) * 64; } CF_INLINE CFIndex __CFBitVectorNumBucketsForCapacity(CFIndex capacity) { @@ -58,11 +58,11 @@ struct __CFBitVector { }; CF_INLINE UInt32 __CFBitVectorMutableVariety(const void *cf) { - return __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 3, 2); + return __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 2); } CF_INLINE void __CFBitVectorSetMutableVariety(void *cf, UInt32 v) { - __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_info, 3, 2, v); + __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 2, v); } CF_INLINE UInt32 __CFBitVectorMutableVarietyFromFlags(UInt32 flags) { @@ -142,7 +142,7 @@ CF_INLINE void __CFBitVectorValidateRange(CFBitVectorRef bv, CFRange range, cons #define __CFBitVectorValidateRange(bf,r,f) #endif -static bool __CFBitVectorEqual(CFTypeRef cf1, CFTypeRef cf2) { +static Boolean __CFBitVectorEqual(CFTypeRef cf1, CFTypeRef cf2) { CFBitVectorRef bv1 = (CFBitVectorRef)cf1; CFBitVectorRef bv2 = (CFBitVectorRef)cf2; CFIndex idx, cnt; @@ -216,7 +216,7 @@ static const CFRuntimeClass __CFBitVectorClass = { NULL, // init NULL, // copy __CFBitVectorDeallocate, - (void *)__CFBitVectorEqual, + __CFBitVectorEqual, __CFBitVectorHash, NULL, // __CFBitVectorCopyDescription @@ -379,7 +379,7 @@ struct _getBitsContext { }; static __CFBitVectorBucket __CFBitVectorGetBits(__CFBitVectorBucket bucketValue, __CFBitVectorBucket bucketValueMask, void *ctx) { - struct _getBitsContext *context = ctx; + struct _getBitsContext *context = (struct _getBitsContext *)ctx; __CFBitVectorBucket val; CFIndex nBits; val = bucketValue & bucketValueMask; diff --git a/Collections.subproj/CFBitVector.h b/CFBitVector.h similarity index 93% rename from Collections.subproj/CFBitVector.h rename to CFBitVector.h index 36de4f1..6dc5b13 100644 --- a/Collections.subproj/CFBitVector.h +++ b/CFBitVector.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFBitVector.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBITVECTOR__) @@ -29,9 +29,7 @@ #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN typedef UInt32 CFBit; @@ -60,9 +58,7 @@ CF_EXPORT void CFBitVectorSetBitAtIndex(CFMutableBitVectorRef bv, CFIndex idx, CF_EXPORT void CFBitVectorSetBits(CFMutableBitVectorRef bv, CFRange range, CFBit value); CF_EXPORT void CFBitVectorSetAllBits(CFMutableBitVectorRef bv, CFBit value); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFBITVECTOR__ */ diff --git a/StringEncodings.subproj/CFBuiltinConverters.c b/CFBuiltinConverters.c similarity index 84% rename from StringEncodings.subproj/CFBuiltinConverters.c rename to CFBuiltinConverters.c index 3e6459a..92baa98 100644 --- a/StringEncodings.subproj/CFBuiltinConverters.c +++ b/CFBuiltinConverters.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -34,20 +34,27 @@ #define ParagraphSeparator 0x2029 #define ASCIINewLine 0x0a +static int8_t __CFMapsParagraphSeparator = -1; + +CF_INLINE bool __CFIsParagraphSeparator(UTF16Char character) { + if (-1 == __CFMapsParagraphSeparator) __CFMapsParagraphSeparator = (_CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard) ? false : true); + + return ((__CFMapsParagraphSeparator && (ParagraphSeparator == character)) ? true : false); +} /* Precomposition */ -static const UInt32 __CFLatin1CombiningCharBitmap[] = { // 0x300 ~ 0x35FF +static const uint32_t __CFLatin1CombiningCharBitmap[] = { // 0x300 ~ 0x35FF 0xFBB94010, 0x01800000, 0x0000000, }; -Boolean CFStringEncodingIsValidCombiningCharacterForLatin1(UniChar character) { +bool CFStringEncodingIsValidCombiningCharacterForLatin1(UniChar character) { return ((character >= 0x300) && (character < 0x360) && (__CFLatin1CombiningCharBitmap[(character - 0x300) / 32] & (1 << (31 - ((character - 0x300) % 32)))) ? true : false); } -UniChar CFStringEncodingPrecomposeLatinCharacter(const UniChar *character, UInt32 numChars, UInt32 *usedChars) { +UniChar CFStringEncodingPrecomposeLatinCharacter(const UniChar *character, CFIndex numChars, CFIndex *usedChars) { if (numChars > 0) { UTF32Char ch = *(character++), nextCh, composedChar; - UInt32 usedCharLen = 1; + CFIndex usedCharLen = 1; if (CFUniCharIsSurrogateHighCharacter(ch) || CFUniCharIsSurrogateLowCharacter(ch)) { if (usedChars) (*usedChars) = usedCharLen; @@ -77,10 +84,10 @@ UniChar CFStringEncodingPrecomposeLatinCharacter(const UniChar *character, UInt3 } /* ASCII */ -static Boolean __CFToASCII(UInt32 flags, UniChar character, uint8_t *byte) { +static bool __CFToASCII(uint32_t flags, UniChar character, uint8_t *byte) { if (character < 0x80) { *byte = (uint8_t)character; - } else if (character == ParagraphSeparator) { + } else if (__CFIsParagraphSeparator(character)) { *byte = ASCIINewLine; } else { return false; @@ -88,7 +95,7 @@ static Boolean __CFToASCII(UInt32 flags, UniChar character, uint8_t *byte) { return true; } -static Boolean __CFFromASCII(UInt32 flags, uint8_t byte, UniChar *character) { +static bool __CFFromASCII(uint32_t flags, uint8_t byte, UniChar *character) { if (byte < 0x80) { *character = (UniChar)byte; return true; @@ -104,10 +111,10 @@ __private_extern__ const CFStringEncodingConverter __CFConverterASCII = { }; /* ISO Latin 1 (8859-1) */ -static Boolean __CFToISOLatin1(UInt32 flags, UniChar character, uint8_t *byte) { +static bool __CFToISOLatin1(uint32_t flags, UniChar character, uint8_t *byte) { if (character <= 0xFF) { *byte = (uint8_t)character; - } else if (character == ParagraphSeparator) { + } else if (__CFIsParagraphSeparator(character)) { *byte = ASCIINewLine; } else { return false; @@ -116,14 +123,14 @@ static Boolean __CFToISOLatin1(UInt32 flags, UniChar character, uint8_t *byte) { return true; } -static Boolean __CFFromISOLatin1(UInt32 flags, uint8_t byte, UniChar *character) { +static bool __CFFromISOLatin1(uint32_t flags, uint8_t byte, UniChar *character) { *character = (UniChar)byte; return true; } -static UInt32 __CFToISOLatin1Precompose(UInt32 flags, const UniChar *character, UInt32 numChars, uint8_t *bytes, UInt32 maxByteLen, UInt32 *usedByteLen) { +static CFIndex __CFToISOLatin1Precompose(uint32_t flags, const UniChar *character, CFIndex numChars, uint8_t *bytes, CFIndex maxByteLen, CFIndex *usedByteLen) { uint8_t byte; - UInt32 usedCharLen; + CFIndex usedCharLen; if (__CFToISOLatin1(flags, CFStringEncodingPrecomposeLatinCharacter(character, numChars, &usedCharLen), &byte) && byte && (usedCharLen > 1)) { if (maxByteLen) *bytes = byte; @@ -273,7 +280,7 @@ static const CFStringEncodingUnicodeTo8BitCharMap macRoman_from_uni[NUM_MACROMAN { 0xFB02, 0xDF }, /* LATIN SMALL LIGATURE FL */ }; -static Boolean __CFToMacRoman(UInt32 flags, UniChar character, uint8_t *byte) { +static bool __CFToMacRoman(uint32_t flags, UniChar character, uint8_t *byte) { if (character < 0x80) { *byte = (uint8_t)character; return true; @@ -413,14 +420,14 @@ static const UniChar macRoman_to_uni[128] = { 0x02C7, /* CARON */ }; -static Boolean __CFFromMacRoman(UInt32 flags, uint8_t byte, UniChar *character) { +static bool __CFFromMacRoman(uint32_t flags, uint8_t byte, UniChar *character) { *character = (byte < 0x80 ? (UniChar)byte : macRoman_to_uni[byte - 0x80]); return true; } -static UInt32 __CFToMacRomanPrecompose(UInt32 flags, const UniChar *character, UInt32 numChars, uint8_t *bytes, UInt32 maxByteLen, UInt32 *usedByteLen) { +static CFIndex __CFToMacRomanPrecompose(uint32_t flags, const UniChar *character, CFIndex numChars, uint8_t *bytes, CFIndex maxByteLen, CFIndex *usedByteLen) { uint8_t byte; - UInt32 usedCharLen; + CFIndex usedCharLen; if (__CFToMacRoman(flags, CFStringEncodingPrecomposeLatinCharacter(character, numChars, &usedCharLen), &byte) && byte && (usedCharLen > 1)) { if (maxByteLen) *bytes = byte; @@ -468,7 +475,7 @@ static const CFStringEncodingUnicodeTo8BitCharMap cp1252_from_uni[NUM_1252_FROM_ {0x2122, 0x99}, // TRADE MARK SIGN }; -static Boolean __CFToWinLatin1(UInt32 flags, UniChar character, uint8_t *byte) { +static bool __CFToWinLatin1(uint32_t flags, UniChar character, uint8_t *byte) { if ((character < 0x80) || ((character > 0x9F) && (character <= 0x00FF))) { *byte = (uint8_t)character; return true; @@ -511,14 +518,14 @@ static const uint16_t cp1252_to_uni[32] = { 0x0178, // LATIN CAPITAL LETTER Y WITH DIAERESIS }; -static Boolean __CFFromWinLatin1(UInt32 flags, uint8_t byte, UniChar *character) { +static bool __CFFromWinLatin1(uint32_t flags, uint8_t byte, UniChar *character) { *character = (byte < 0x80 || byte > 0x9F ? (UniChar)byte : cp1252_to_uni[byte - 0x80]); return (*character != 0xFFFD); } -static UInt32 __CFToWinLatin1Precompose(UInt32 flags, const UniChar *character, UInt32 numChars, uint8_t *bytes, UInt32 maxByteLen, UInt32 *usedByteLen) { +static CFIndex __CFToWinLatin1Precompose(uint32_t flags, const UniChar *character, CFIndex numChars, uint8_t *bytes, CFIndex maxByteLen, CFIndex *usedByteLen) { uint8_t byte; - UInt32 usedCharLen; + CFIndex usedCharLen; if (__CFToWinLatin1(flags, CFStringEncodingPrecomposeLatinCharacter(character, numChars, &usedCharLen), &byte) && byte && (usedCharLen > 1)) { if (maxByteLen) *bytes = byte; @@ -535,7 +542,7 @@ __private_extern__ const CFStringEncodingConverter __CFConverterWinLatin1 = { }; /* NEXTSTEP Encoding */ -#define NUM_NEXTSTEP_FROM_UNI 128 +#define NUM_NEXTSTEP_FROM_UNI 127 static const CFStringEncodingUnicodeTo8BitCharMap nextstep_from_tab[NUM_NEXTSTEP_FROM_UNI] = { { 0x00a0, 0x80 }, @@ -659,7 +666,6 @@ static const CFStringEncodingUnicodeTo8BitCharMap nextstep_from_tab[NUM_NEXTSTEP { 0x2021, 0xb3 }, { 0x2022, 0xb7 }, { 0x2026, 0xbc }, - { 0x2029, 0x0a }, /* ParagraphSeparator -> ASCIINewLine */ { 0x2030, 0xbd }, { 0x2039, 0xac }, { 0x203a, 0xad }, @@ -669,10 +675,13 @@ static const CFStringEncodingUnicodeTo8BitCharMap nextstep_from_tab[NUM_NEXTSTEP { 0xfffd, 0xff }, }; -static Boolean __CFToNextStepLatin(UInt32 flags, UniChar character, uint8_t *byte) { +static bool __CFToNextStepLatin(uint32_t flags, UniChar character, uint8_t *byte) { if (character < 0x80) { *byte = (uint8_t)character; return true; + } else if (__CFIsParagraphSeparator(character)) { + *byte = ASCIINewLine; + return true; } else { return CFStringEncodingUnicodeTo8BitEncoding(nextstep_from_tab, NUM_NEXTSTEP_FROM_UNI, character, byte); } @@ -810,13 +819,13 @@ static const UniChar NSToPrecompUnicodeTable[128] = { /* 255 .notdef */ 0xFFFD }; -static Boolean __CFFromNextStepLatin(UInt32 flags, uint8_t byte, UniChar *character) { +static bool __CFFromNextStepLatin(uint32_t flags, uint8_t byte, UniChar *character) { return ((*character = (byte < 0x80 ? (UniChar)byte : NSToPrecompUnicodeTable[byte - 0x80])) != 0xFFFD); } -static UInt32 __CFToNextStepLatinPrecompose(UInt32 flags, const UniChar *character, UInt32 numChars, uint8_t *bytes, UInt32 maxByteLen, UInt32 *usedByteLen) { +static CFIndex __CFToNextStepLatinPrecompose(uint32_t flags, const UniChar *character, CFIndex numChars, uint8_t *bytes, CFIndex maxByteLen, CFIndex *usedByteLen) { uint8_t byte; - UInt32 usedCharLen; + CFIndex usedCharLen; if (__CFToNextStepLatin(flags, CFStringEncodingPrecomposeLatinCharacter(character, numChars, &usedCharLen), &byte) && byte && (usedCharLen > 1)) { if (maxByteLen) *bytes = byte; @@ -855,18 +864,18 @@ __private_extern__ const CFStringEncodingConverter __CFConverterNextStepLatin = * remains attached. */ -static const UInt32 kReplacementCharacter = 0x0000FFFDUL; -static const UInt32 kMaximumUCS2 = 0x0000FFFFUL; -static const UInt32 kMaximumUTF16 = 0x0010FFFFUL; -static const UInt32 kMaximumUCS4 = 0x7FFFFFFFUL; +static const uint32_t kReplacementCharacter = 0x0000FFFDUL; +static const uint32_t kMaximumUCS2 = 0x0000FFFFUL; +static const uint32_t kMaximumUTF16 = 0x0010FFFFUL; +static const uint32_t kMaximumUCS4 = 0x7FFFFFFFUL; static const int halfShift = 10; -static const UInt32 halfBase = 0x0010000UL; -static const UInt32 halfMask = 0x3FFUL; -static const UInt32 kSurrogateHighStart = 0xD800UL; -static const UInt32 kSurrogateHighEnd = 0xDBFFUL; -static const UInt32 kSurrogateLowStart = 0xDC00UL; -static const UInt32 kSurrogateLowEnd = 0xDFFFUL; +static const uint32_t halfBase = 0x0010000UL; +static const uint32_t halfMask = 0x3FFUL; +static const uint32_t kSurrogateHighStart = 0xD800UL; +static const uint32_t kSurrogateHighEnd = 0xDBFFUL; +static const uint32_t kSurrogateLowStart = 0xDC00UL; +static const uint32_t kSurrogateLowEnd = 0xDFFFUL; /* * Index into the table below with the first byte of a UTF-8 sequence to @@ -900,7 +909,7 @@ static const uint8_t firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0x * efficiency, in favor of drop-through switch statements. */ -CF_INLINE uint16_t __CFUTF8BytesToWriteForCharacter(UInt32 ch) { +CF_INLINE uint16_t __CFUTF8BytesToWriteForCharacter(uint32_t ch) { if (ch < 0x80) return 1; else if (ch < 0x800) return 2; else if (ch < 0x10000) return 3; @@ -910,10 +919,10 @@ CF_INLINE uint16_t __CFUTF8BytesToWriteForCharacter(UInt32 ch) { else return 0; } -CF_INLINE uint16_t __CFToUTF8Core(UInt32 ch, uint8_t *bytes, UInt32 maxByteLen) { +CF_INLINE uint16_t __CFToUTF8Core(uint32_t ch, uint8_t *bytes, uint32_t maxByteLen) { uint16_t bytesToWrite = __CFUTF8BytesToWriteForCharacter(ch); - const UInt32 byteMask = 0xBF; - const UInt32 byteMark = 0x80; + const uint32_t byteMask = 0xBF; + const uint32_t byteMark = 0x80; if (!bytesToWrite) { bytesToWrite = 2; @@ -933,9 +942,9 @@ CF_INLINE uint16_t __CFToUTF8Core(UInt32 ch, uint8_t *bytes, UInt32 maxByteLen) return bytesToWrite; } -static UInt32 __CFToUTF8(UInt32 flags, const UniChar *characters, UInt32 numChars, uint8_t *bytes, UInt32 maxByteLen, UInt32 *usedByteLen) { +static CFIndex __CFToUTF8(uint32_t flags, const UniChar *characters, CFIndex numChars, uint8_t *bytes, CFIndex maxByteLen, CFIndex *usedByteLen) { uint16_t bytesWritten; - UInt32 ch; + uint32_t ch; const UniChar *beginCharacter = characters; const UniChar *endCharacter = characters + numChars; const uint8_t *beginBytes = bytes; @@ -986,7 +995,7 @@ static UInt32 __CFToUTF8(UInt32 flags, const UniChar *characters, UInt32 numChar * definition of UTF-8 goes up to 4-byte sequences. */ -CF_INLINE bool __CFIsLegalUTF8(const uint8_t *source, int length) { +CF_INLINE bool __CFIsLegalUTF8(const uint8_t *source, CFIndex length) { if (length > 4) return false; const uint8_t *srcptr = source+length; @@ -1000,146 +1009,16 @@ CF_INLINE bool __CFIsLegalUTF8(const uint8_t *source, int length) { return true; } -/* This version of the routine returns the length of the sequence, - or 0 on illegal sequence. This version is correct according to - the Unicode 4.0 spec. */ -#define ISLEGALUTF8_FAST 0 -static CFIndex __CFIsLegalUTF8_2(const uint8_t *source, CFIndex maxBytes) { - if (maxBytes < 1) return 0; - uint8_t first = source[0]; - if (first <= 0x7F) return 1; - if (first < 0xC2) return 0; - if (maxBytes < 2) return 0; - if (first <= 0xDF) { -#if ISLEGALUTF8_FAST - if ((source[1] & 0xC0) == 0x80) return 2; -#else - if (source[1] < 0x80) return 0; - if (source[1] <= 0xBF) return 2; -#endif - return 0; - } - if (maxBytes < 3) return 0; -#if ISLEGALUTF8_FAST - if (first <= 0xEF) { - uint32_t value = (first << 24) | ((*(const uint16_t *)((const uint8_t *)source + 1)) << 8); - uint32_t masked1 = (value & 0xFFF0C000); - - // 0b 11100000 101{0,1}xxxx 10xxxxxx (0xE0) - if (masked1 == 0xE0A08000) return 3; - if (masked1 == 0xE0B08000) return 3; - - // 0b 11101101 100{0,1}xxxx 10xxxxxx (0xED) - if (masked1 == 0xED808000) return 3; - if (masked1 == 0xED908000) return 3; - - // 0b 1110{0001 - 1100} 10xxxxxx 10xxxxxx (0xE1 - 0xEC) - // 0b 1110{1110 - 1111} 10xxxxxx 10xxxxxx (0xEE - 0xEF) - if ((value & 0x00C0C000) == 0x00808000) return 3; - - return 0; - } -#else - if (first == 0xE0) { - if (source[1] < 0xA0 /* NOTE */) return 0; - if (source[1] <= 0xBF) { - if (source[2] < 0x80) return 0; - if (source[2] <= 0xBF) return 3; - } - return 0; - } - if (first <= 0xEC) { - if (source[1] < 0x80) return 0; - if (source[1] <= 0xBF) { - if (source[2] < 0x80) return 0; - if (source[2] <= 0xBF) return 3; - } - return 0; - } - if (first == 0xED) { - if (source[1] < 0x80) return 0; - if (source[1] <= 0x9F /* NOTE */) { - if (source[2] < 0x80) return 0; - if (source[2] <= 0xBF) return 3; - } - return 0; - } - if (first <= 0xEF) { - if (source[1] < 0x80) return 0; - if (source[1] <= 0xBF) { - if (source[2] < 0x80) return 0; - if (source[2] <= 0xBF) return 3; - } - return 0; - } -#endif - if (maxBytes < 4) return 0; -#if ISLEGALUTF8_FAST - if (first <= 0xF4) { - uint32_t value = *(const uint32_t *)source; - uint32_t masked1 = (value & 0xFFF0C0C0); - - // 0b 11110000 10{01,10,11}xxxx 10xxxxxx 10xxxxxx (0xF0) - if (masked1 == 0xF0908080) return 4; - if (masked1 == 0xF0A08080) return 4; - if (masked1 == 0xF0B08080) return 4; - - // 0b 11110100 1000xxxx 10xxxxxx 10xxxxxx (0xF4) - if (masked1 == 0xF4808080) return 4; - - // 0b 111100{01,10,11} 10xxxxxx 10xxxxxx 10xxxxxx (0xF1 - 0xF3) - if ((value & 0x00C0C0C0) == 0x00808080) return 4; - - return 0; - } -#else - if (first == 0xF0) { - if (source[1] < 0x90 /* NOTE */) return 0; - if (source[1] <= 0xBF) { - if (source[2] < 0x80) return 0; - if (source[2] <= 0xBF) { - if (source[3] < 0x80) return 0; - if (source[3] <= 0xBF) return 4; - } - } - return 0; - } - if (first <= 0xF3) { - if (source[1] < 0x80) return 0; - if (source[1] <= 0xBF) { - if (source[2] < 0x80) return 0; - if (source[2] <= 0xBF) { - if (source[3] < 0x80) return 0; - if (source[3] <= 0xBF) return 4; - } - } - return 0; - } - if (first == 0xF4) { - if (source[1] < 0x80) return 0; - if (source[1] <= 0x8F /* NOTE */) { - if (source[2] < 0x80) return 0; - if (source[2] <= 0xBF) { - if (source[3] < 0x80) return 0; - if (source[3] <= 0xBF) return 4; - } - } - return 0; - } -#endif - return 0; -} - -static UInt32 __CFFromUTF8(UInt32 flags, const uint8_t *bytes, UInt32 numBytes, UniChar *characters, UInt32 maxCharLen, UInt32 *usedCharLen) { +static CFIndex __CFFromUTF8(uint32_t flags, const uint8_t *bytes, CFIndex numBytes, UniChar *characters, CFIndex maxCharLen, CFIndex *usedCharLen) { const uint8_t *source = bytes; uint16_t extraBytesToRead; - UInt32 theUsedCharLen = 0; - UInt32 ch; - Boolean isHFSPlus = (flags & kCFStringEncodingUseHFSPlusCanonical ? true : false); - Boolean needsToDecompose = (flags & kCFStringEncodingUseCanonical || isHFSPlus ? true : false); - Boolean strictUTF8 = (flags & kCFStringEncodingLenientUTF8Conversion ? false : true); + CFIndex theUsedCharLen = 0; + uint32_t ch; + bool isHFSPlus = (flags & kCFStringEncodingUseHFSPlusCanonical ? true : false); + bool needsToDecompose = (flags & kCFStringEncodingUseCanonical || isHFSPlus ? true : false); + bool strictUTF8 = (flags & kCFStringEncodingLenientUTF8Conversion ? false : true); UTF32Char decomposed[MAX_DECOMPOSED_LENGTH]; - int32_t decompLength; + CFIndex decompLength; bool isStrict = !isHFSPlus; while (numBytes && (!maxCharLen || (theUsedCharLen < maxCharLen))) { @@ -1184,7 +1063,7 @@ static UInt32 __CFFromUTF8(UInt32 flags, const uint8_t *bytes, UInt32 numBytes, decompLength = CFUniCharDecomposeCharacter(ch, decomposed, MAX_DECOMPOSED_LENGTH); if (maxCharLen) { - if (!CFUniCharFillDestinationBuffer(decomposed, decompLength, (void **)&characters, maxCharLen, (uint32_t *)&theUsedCharLen, kCFUniCharUTF16Format)) break; + if (!CFUniCharFillDestinationBuffer(decomposed, decompLength, (void **)&characters, maxCharLen, &theUsedCharLen, kCFUniCharUTF16Format)) break; } else { theUsedCharLen += decompLength; } @@ -1204,7 +1083,7 @@ static UInt32 __CFFromUTF8(UInt32 flags, const uint8_t *bytes, UInt32 numBytes, decompLength = CFUniCharDecomposeCharacter(ch, decomposed, MAX_DECOMPOSED_LENGTH); if (maxCharLen) { - if (!CFUniCharFillDestinationBuffer(decomposed, decompLength, (void **)&characters, maxCharLen, (uint32_t *)&theUsedCharLen, kCFUniCharUTF16Format)) break; + if (!CFUniCharFillDestinationBuffer(decomposed, decompLength, (void **)&characters, maxCharLen, &theUsedCharLen, kCFUniCharUTF16Format)) break; } else { while (--decompLength >= 0) theUsedCharLen += (decomposed[decompLength] < 0x10000 ? 1 : 2); } @@ -1225,9 +1104,9 @@ static UInt32 __CFFromUTF8(UInt32 flags, const uint8_t *bytes, UInt32 numBytes, return source - bytes; } -static UInt32 __CFToUTF8Len(UInt32 flags, const UniChar *characters, UInt32 numChars) { - UInt32 bytesToWrite = 0; - UInt32 ch; +static CFIndex __CFToUTF8Len(uint32_t flags, const UniChar *characters, CFIndex numChars) { + uint32_t bytesToWrite = 0; + uint32_t ch; while (numChars) { ch = *characters++; @@ -1242,15 +1121,15 @@ static UInt32 __CFToUTF8Len(UInt32 flags, const UniChar *characters, UInt32 numC return bytesToWrite; } -static UInt32 __CFFromUTF8Len(UInt32 flags, const uint8_t *source, UInt32 numBytes) { +static CFIndex __CFFromUTF8Len(uint32_t flags, const uint8_t *source, CFIndex numBytes) { uint16_t extraBytesToRead; - UInt32 theUsedCharLen = 0; - UInt32 ch; - Boolean isHFSPlus = (flags & kCFStringEncodingUseHFSPlusCanonical ? true : false); - Boolean needsToDecompose = (flags & kCFStringEncodingUseCanonical || isHFSPlus ? true : false); - Boolean strictUTF8 = (flags & kCFStringEncodingLenientUTF8Conversion ? false : true); + CFIndex theUsedCharLen = 0; + uint32_t ch; + bool isHFSPlus = (flags & kCFStringEncodingUseHFSPlusCanonical ? true : false); + bool needsToDecompose = (flags & kCFStringEncodingUseCanonical || isHFSPlus ? true : false); + bool strictUTF8 = (flags & kCFStringEncodingLenientUTF8Conversion ? false : true); UTF32Char decomposed[MAX_DECOMPOSED_LENGTH]; - int32_t decompLength; + CFIndex decompLength; bool isStrict = !isHFSPlus; while (numBytes) { diff --git a/PlugIn.subproj/CFBundle.c b/CFBundle.c similarity index 51% rename from PlugIn.subproj/CFBundle.c rename to CFBundle.c index 711467f..f8c702b 100644 --- a/PlugIn.subproj/CFBundle.c +++ b/CFBundle.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFBundle.c - Copyright 1999-2002, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007 Apple Inc. All rights reserved. Responsibility: Doug Davidson */ @@ -30,55 +30,39 @@ #include #include #include +#include #include -#include "CFInternal.h" #include "CFPriv.h" +#include "CFInternal.h" #include #include "CFBundle_BinaryTypes.h" #include +#include +#include #if defined(BINARY_SUPPORT_DYLD) // Import the mach-o headers that define the macho magic numbers #include #include #include -#include #include #include - #include #include #include - #endif /* BINARY_SUPPORT_DYLD */ -#if defined(__MACOS8__) -/* MacOS8 Headers */ -#include -#include -#else -/* Unixy & Windows Headers */ -#include -#include -#endif -#if defined(__LINUX__) -#include -#endif +#if defined(BINARY_SUPPORT_DLFCN) +#include +#endif /* BINARY_SUPPORT_DLFCN */ -#if defined(__WIN32__) -#if !defined(__MINGW32__) && !defined(__CYGWIN__) -// With the MS headers, turning off Standard-C gets you macros for stat vs_stat. -// Strictly speaking, this is supposed to control traditional vs ANSI C features. -#undef __STDC__ -#endif +#if DEPLOYMENT_TARGET_MACOSX #include -#include -#if !defined(__MINGW32__) && !defined(__CYGWIN__) -#define __STDC__ -#endif #endif +#define LOG_BUNDLE_LOAD 0 + // Public CFBundle Info plist keys CONST_STRING_DECL(kCFBundleInfoDictionaryVersionKey, "CFBundleInfoDictionaryVersion") CONST_STRING_DECL(kCFBundleExecutableKey, "CFBundleExecutable") @@ -132,12 +116,18 @@ CONST_STRING_DECL(_kCFBundleOldTypeOSTypesKey, "NSMacOSType") // Internally used keys for loaded Info plists. CONST_STRING_DECL(_kCFBundleInfoPlistURLKey, "CFBundleInfoPlistURL") +CONST_STRING_DECL(_kCFBundleRawInfoPlistURLKey, "CFBundleRawInfoPlistURL") CONST_STRING_DECL(_kCFBundleNumericVersionKey, "CFBundleNumericVersion") CONST_STRING_DECL(_kCFBundleExecutablePathKey, "CFBundleExecutablePath") CONST_STRING_DECL(_kCFBundleResourcesFileMappedKey, "CSResourcesFileMapped") CONST_STRING_DECL(_kCFBundleCFMLoadAsBundleKey, "CFBundleCFMLoadAsBundle") CONST_STRING_DECL(_kCFBundleAllowMixedLocalizationsKey, "CFBundleAllowMixedLocalizations") +// Keys used by NSBundle for loaded Info plists. +CONST_STRING_DECL(_kCFBundleInitialPathKey, "NSBundleInitialPath") +CONST_STRING_DECL(_kCFBundleResolvedPathKey, "NSBundleResolvedPath") +CONST_STRING_DECL(_kCFBundlePrincipalClassKey, "NSPrincipalClass") + static CFTypeID __kCFBundleTypeID = _kCFRuntimeNotATypeID; struct __CFBundle { @@ -163,6 +153,9 @@ struct __CFBundle { const void *_imageCookie; const void *_moduleCookie; + /* dlfcn goop */ + void *_handleCookie; + /* CFM<->DYLD glue */ CFMutableDictionaryRef _glueDict; @@ -173,11 +166,11 @@ struct __CFBundle { #if defined(BINARY_SUPPORT_DLL) HMODULE _hModule; -#endif +#endif /* BINARY_SUPPORT_DLL */ }; -static CFSpinLock_t CFBundleGlobalDataLock = 0; +static CFSpinLock_t CFBundleGlobalDataLock = CFSpinLockInit; static CFMutableDictionaryRef _bundlesByURL = NULL; static CFMutableDictionaryRef _bundlesByIdentifier = NULL; @@ -193,6 +186,8 @@ static Boolean _initedMainBundle = false; static CFBundleRef _mainBundle = NULL; static CFStringRef _defaultLocalization = NULL; +static Boolean _useDlfcn = false; + // 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); @@ -200,73 +195,79 @@ static CFURLRef _CFBundleCopyExecutableURLIgnoringCache(CFBundleRef bundle); static void _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(CFStringRef hint); static void _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(void); static void _CFBundleCheckWorkarounds(CFBundleRef bundle); -#if defined(BINARY_SUPPORT_DYLD) static void _CFBundleEnsureBundleExistsForImagePath(CFStringRef imagePath); static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths); +#if defined(BINARY_SUPPORT_DYLD) static CFDictionaryRef _CFBundleGrokInfoDictFromMainExecutable(void); +static Boolean _CFBundleGrokObjCImageInfoFromMainExecutable(uint32_t *objcVersion, uint32_t *objcFlags); static CFStringRef _CFBundleDYLDCopyLoadedImagePathForPointer(void *p); static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch); #endif /* BINARY_SUPPORT_DYLD */ -#if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__) +#if defined(BINARY_SUPPORT_DLFCN) +static CFStringRef _CFBundleDlfcnCopyLoadedImagePathForPointer(void *p); +static void *_CFBundleDlfcnGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch); +#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 && __ppc__ */ +#endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM */ static void _CFBundleAddToTables(CFBundleRef bundle, Boolean alreadyLocked) { CFStringRef bundleID = CFBundleGetIdentifier(bundle); - if (!alreadyLocked) { - __CFSpinLock(&CFBundleGlobalDataLock); - } + if (!alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock); // Add to the _allBundles list - if (_allBundles == NULL) { + if (!_allBundles) { // Create this from the default allocator CFArrayCallBacks nonRetainingArrayCallbacks = kCFTypeArrayCallBacks; nonRetainingArrayCallbacks.retain = NULL; nonRetainingArrayCallbacks.release = NULL; - _allBundles = CFArrayCreateMutable(NULL, 0, &nonRetainingArrayCallbacks); + _allBundles = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingArrayCallbacks); } CFArrayAppendValue(_allBundles, bundle); // Add to the table that maps urls to bundles - if (_bundlesByURL == NULL) { + if (!_bundlesByURL) { // Create this from the default allocator CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks = kCFTypeDictionaryValueCallBacks; nonRetainingDictionaryValueCallbacks.retain = NULL; nonRetainingDictionaryValueCallbacks.release = NULL; - _bundlesByURL = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &nonRetainingDictionaryValueCallbacks); + _bundlesByURL = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &nonRetainingDictionaryValueCallbacks); } CFDictionarySetValue(_bundlesByURL, bundle->_url, bundle); // Add to the table that maps identifiers to bundles if (bundleID) { + CFMutableArrayRef bundlesWithThisID = NULL; CFBundleRef existingBundle = NULL; - Boolean addIt = true; - if (_bundlesByIdentifier == NULL) { + if (!_bundlesByIdentifier) { // Create this from the default allocator - CFDictionaryValueCallBacks nonRetainingDictionaryValueCallbacks = kCFTypeDictionaryValueCallBacks; - nonRetainingDictionaryValueCallbacks.retain = NULL; - nonRetainingDictionaryValueCallbacks.release = NULL; - _bundlesByIdentifier = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &nonRetainingDictionaryValueCallbacks); - } - existingBundle = (CFBundleRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); - if (existingBundle) { - UInt32 existingVersion, newVersion; - existingVersion = CFBundleGetVersionNumber(existingBundle); - newVersion = CFBundleGetVersionNumber(bundle); - if (newVersion < existingVersion) { - // Less than to means that if you load two bundles with the same identifier and the same version, the last one wins. - addIt = false; + _bundlesByIdentifier = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + } + bundlesWithThisID = (CFMutableArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); + if (bundlesWithThisID) { + CFIndex i, count = CFArrayGetCount(bundlesWithThisID); + UInt32 existingVersion, newVersion = CFBundleGetVersionNumber(bundle); + for (i = 0; i < count; i++) { + existingBundle = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, i); + existingVersion = CFBundleGetVersionNumber(existingBundle); + // If you load two bundles with the same identifier and the same version, the last one wins. + if (newVersion >= existingVersion) break; } + CFArrayInsertValueAtIndex(bundlesWithThisID, i, bundle); + } else { + // Create this from the default allocator + CFArrayCallBacks nonRetainingArrayCallbacks = kCFTypeArrayCallBacks; + nonRetainingArrayCallbacks.retain = NULL; + nonRetainingArrayCallbacks.release = NULL; + bundlesWithThisID = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingArrayCallbacks); + CFArrayAppendValue(bundlesWithThisID, bundle); + CFDictionarySetValue(_bundlesByIdentifier, bundleID, bundlesWithThisID); + CFRelease(bundlesWithThisID); } - if (addIt) { - CFDictionarySetValue(_bundlesByIdentifier, bundleID, bundle); - } - } - if (!alreadyLocked) { - __CFSpinUnlock(&CFBundleGlobalDataLock); } + if (!alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock); } static void _CFBundleRemoveFromTables(CFBundleRef bundle) { @@ -275,38 +276,32 @@ static void _CFBundleRemoveFromTables(CFBundleRef bundle) { __CFSpinLock(&CFBundleGlobalDataLock); // Remove from the various lists - if (_allBundles != NULL) { + if (_allBundles) { CFIndex i = CFArrayGetFirstIndexOfValue(_allBundles, CFRangeMake(0, CFArrayGetCount(_allBundles)), bundle); - if (i>=0) { - CFArrayRemoveValueAtIndex(_allBundles, i); - } + if (i >= 0) CFArrayRemoveValueAtIndex(_allBundles, i); } // Remove from the table that maps urls to bundles - if (_bundlesByURL != NULL) { - CFDictionaryRemoveValue(_bundlesByURL, bundle->_url); - } + if (_bundlesByURL) CFDictionaryRemoveValue(_bundlesByURL, bundle->_url); // Remove from the table that maps identifiers to bundles - if ((bundleID != NULL) && (_bundlesByIdentifier != NULL)) { - if (CFDictionaryGetValue(_bundlesByIdentifier, bundleID) == bundle) { - CFDictionaryRemoveValue(_bundlesByIdentifier, bundleID); + if (bundleID && _bundlesByIdentifier) { + CFMutableArrayRef bundlesWithThisID = (CFMutableArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); + if (bundlesWithThisID) { + CFIndex count = CFArrayGetCount(bundlesWithThisID); + while (count-- > 0) if (bundle == (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, count)) CFArrayRemoveValueAtIndex(bundlesWithThisID, count); + if (0 == CFArrayGetCount(bundlesWithThisID)) CFDictionaryRemoveValue(_bundlesByIdentifier, bundleID); } } + __CFSpinUnlock(&CFBundleGlobalDataLock); } __private_extern__ CFBundleRef _CFBundleFindByURL(CFURLRef url, Boolean alreadyLocked) { CFBundleRef result = NULL; - if (!alreadyLocked) { - __CFSpinLock(&CFBundleGlobalDataLock); - } - if (_bundlesByURL != NULL) { - result = (CFBundleRef)CFDictionaryGetValue(_bundlesByURL, url); - } - if (!alreadyLocked) { - __CFSpinUnlock(&CFBundleGlobalDataLock); - } + if (!alreadyLocked) __CFSpinLock(&CFBundleGlobalDataLock); + if (_bundlesByURL) result = (CFBundleRef)CFDictionaryGetValue(_bundlesByURL, url); + if (!alreadyLocked) __CFSpinUnlock(&CFBundleGlobalDataLock); return result; } @@ -320,44 +315,49 @@ static CFURLRef _CFBundleCopyBundleURLForExecutablePath(CFStringRef str) { buffLen = CFStringGetLength(str); if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize; CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff); - buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); // Remove exe name - - 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); - if ((startOfLastDir > 0) && (startOfLastDir < buffLen)) { - CFStringRef lastDirName = CFStringCreateWithCharacters(NULL, &(buff[startOfLastDir]), buffLen - startOfLastDir); - - if (CFEqual(lastDirName, _CFBundleGetPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetAlternatePlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetOtherPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName())) { - // This is a new bundle. Back off a few more levels - if (buffLen > 0) { - // Remove platform folder - buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); - } - if (buffLen > 0) { - // Remove executables folder (if present) - CFIndex startOfNextDir = _CFStartOfLastPathComponent(buff, buffLen); - if ((startOfNextDir > 0) && (startOfNextDir < buffLen)) { - CFStringRef nextDirName = CFStringCreateWithCharacters(NULL, &(buff[startOfNextDir]), buffLen - startOfNextDir); - if (CFEqual(nextDirName, _CFBundleExecutablesDirectoryName)) { - buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); + + if (!url) { + buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); // Remove exe name + +#if DEPLOYMENT_TARGET_MACOSX + 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); + if ((startOfLastDir > 0) && (startOfLastDir < buffLen)) { + CFStringRef lastDirName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfLastDir]), buffLen - startOfLastDir); + + if (CFEqual(lastDirName, _CFBundleGetPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetAlternatePlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetOtherPlatformExecutablesSubdirectoryName()) || CFEqual(lastDirName, _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName())) { + // This is a new bundle. Back off a few more levels + if (buffLen > 0) { + // Remove platform folder + buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); + } + if (buffLen > 0) { + // Remove executables folder (if present) + CFIndex startOfNextDir = _CFStartOfLastPathComponent(buff, buffLen); + if ((startOfNextDir > 0) && (startOfNextDir < buffLen)) { + CFStringRef nextDirName = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfNextDir]), buffLen - startOfNextDir); + if (CFEqual(nextDirName, _CFBundleExecutablesDirectoryName)) buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); + CFRelease(nextDirName); } - CFRelease(nextDirName); + } + if (buffLen > 0) { + // Remove support files folder + buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); +#endif } } - if (buffLen > 0) { - // Remove support files folder - buffLen = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); - } +#if DEPLOYMENT_TARGET_MACOSX + CFRelease(lastDirName); } - CFRelease(lastDirName); } - } +#endif - if (buffLen > 0) { - outstr = CFStringCreateWithCharactersNoCopy(NULL, buff, buffLen, kCFAllocatorNull); - url = CFURLCreateWithFileSystemPath(NULL, outstr, PLATFORM_PATH_STYLE, true); - CFRelease(outstr); + if (buffLen > 0) { + outstr = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, buff, buffLen, kCFAllocatorNull); + url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, outstr, PLATFORM_PATH_STYLE, true); + CFRelease(outstr); + } } return url; } @@ -375,12 +375,12 @@ static CFURLRef _CFBundleCopyResolvedURLForExecutableURL(CFURLRef url) { CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff); len1 = _CFLengthAfterDeletingLastPathComponent(buff, buffLen); if (len1 > 0 && len1 + 1 < buffLen) { - str1 = CFStringCreateWithCharacters(NULL, buff, len1); - str2 = CFStringCreateWithCharacters(NULL, buff + len1 + 1, buffLen - len1 - 1); + str1 = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, buff, len1); + str2 = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, buff + len1 + 1, buffLen - len1 - 1); if (str1 && str2) { - url1 = CFURLCreateWithFileSystemPath(NULL, str1, PLATFORM_PATH_STYLE, true); + url1 = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str1, PLATFORM_PATH_STYLE, true); if (url1) { - url2 = CFURLCreateWithFileSystemPathRelativeToBase(NULL, str2, PLATFORM_PATH_STYLE, false, url1); + url2 = CFURLCreateWithFileSystemPathRelativeToBase(kCFAllocatorSystemDefault, str2, PLATFORM_PATH_STYLE, false, url1); if (url2) { outURL = CFURLCopyAbsoluteURL(url2); CFRelease(url2); @@ -406,7 +406,7 @@ CFURLRef _CFBundleCopyBundleURLForExecutableURL(CFURLRef url) { CFStringRef str; resolvedURL = _CFBundleCopyResolvedURLForExecutableURL(url); str = CFURLCopyFileSystemPath(resolvedURL, PLATFORM_PATH_STYLE); - if (str != NULL) { + if (str) { outurl = _CFBundleCopyBundleURLForExecutablePath(str); CFRelease(str); } @@ -424,9 +424,7 @@ CFBundleRef _CFBundleCreateIfLooksLikeBundle(CFAllocatorRef allocator, CFURLRef #if defined(BINARY_SUPPORT_CFM) && defined(BINARY_SUPPORT_DYLD) CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); if (executableURL) { - if (bundle->_binaryType == __CFBundleUnknownBinary) { - bundle->_binaryType = _CFBundleGrokBinaryType(executableURL); - } + if (bundle->_binaryType == __CFBundleUnknownBinary) bundle->_binaryType = _CFBundleGrokBinaryType(executableURL); if (bundle->_binaryType == __CFBundleCFMBinary || bundle->_binaryType == __CFBundleUnreadableBinary) { bundle->_version = 4; } else { @@ -457,12 +455,15 @@ CFBundleRef _CFBundleCreateIfLooksLikeBundle(CFAllocatorRef allocator, CFURLRef CFBundleRef _CFBundleGetMainBundleIfLooksLikeBundle(void) { CFBundleRef mainBundle = CFBundleGetMainBundle(); - if (mainBundle && (3 == mainBundle->_version || 4 == mainBundle->_version)) { - mainBundle = NULL; - } + if (mainBundle && (3 == mainBundle->_version || 4 == mainBundle->_version)) mainBundle = NULL; return mainBundle; } +Boolean _CFBundleMainBundleInfoDictionaryComesFromResourceFork(void) { + CFBundleRef mainBundle = CFBundleGetMainBundle(); + return (mainBundle && mainBundle->_resourceData._infoDictionaryFromResourceFork); +} + CFBundleRef _CFBundleCreateWithExecutableURLIfLooksLikeBundle(CFAllocatorRef allocator, CFURLRef url) { CFBundleRef bundle = NULL; CFURLRef bundleURL = _CFBundleCopyBundleURLForExecutableURL(url), resolvedURL = _CFBundleCopyResolvedURLForExecutableURL(url); @@ -471,7 +472,7 @@ CFBundleRef _CFBundleCreateWithExecutableURLIfLooksLikeBundle(CFAllocatorRef all if (bundle) { CFURLRef executableURL = _CFBundleCopyExecutableURLIgnoringCache(bundle); char buff1[CFMaxPathSize], buff2[CFMaxPathSize]; - if (!executableURL || !CFURLGetFileSystemRepresentation(resolvedURL, true, buff1, CFMaxPathSize) || !CFURLGetFileSystemRepresentation(executableURL, true, buff2, CFMaxPathSize) || 0 != strcmp(buff1, buff2)) { + if (!executableURL || !CFURLGetFileSystemRepresentation(resolvedURL, true, (uint8_t *)buff1, CFMaxPathSize) || !CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff2, CFMaxPathSize) || 0 != strcmp(buff1, buff2)) { CFRelease(bundle); bundle = NULL; } @@ -490,57 +491,139 @@ CFURLRef _CFBundleCopyMainBundleExecutableURL(Boolean *looksLikeBundle) { CFURLRef executableURL = NULL; processPath = _CFProcessPath(); if (processPath) { - str = CFStringCreateWithCString(NULL, processPath, CFStringFileSystemEncoding()); + str = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, processPath); if (str) { - executableURL = CFURLCreateWithFileSystemPath(NULL, str, PLATFORM_PATH_STYLE, false); + executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, PLATFORM_PATH_STYLE, false); CFRelease(str); } } if (looksLikeBundle) { CFBundleRef mainBundle = _mainBundle; if (mainBundle && (3 == mainBundle->_version || 4 == mainBundle->_version)) mainBundle = NULL; - *looksLikeBundle = (mainBundle ? YES : NO); + *looksLikeBundle = (mainBundle ? true : false); } return executableURL; } +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); + 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); + _mainBundle->_infoDict = _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 */ + } + if (!_mainBundle->_infoDict) _mainBundle->_infoDict = CFDictionaryCreateMutable(CFGetAllocator(_mainBundle), 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); + } + } +#endif /* BINARY_SUPPORT_CFM */ +} + +CF_EXPORT void _CFBundleFlushBundleCaches(CFBundleRef bundle) { + CFDictionaryRef oldInfoDict = bundle->_infoDict; + CFTypeRef val; + + _CFBundleFlushCachesForURL(bundle->_url); + bundle->_infoDict = NULL; + if (bundle->_localInfoDict) { + CFRelease(bundle->_localInfoDict); + bundle->_localInfoDict = NULL; + } + if (bundle->_searchLanguages) { + CFRelease(bundle->_searchLanguages); + bundle->_searchLanguages = NULL; + } + if (bundle->_resourceData._stringTableCache) { + CFRelease(bundle->_resourceData._stringTableCache); + bundle->_resourceData._stringTableCache = NULL; + } + if (bundle == _mainBundle) { + CFStringRef executablePath = oldInfoDict ? (CFStringRef)CFDictionaryGetValue(oldInfoDict, _kCFBundleExecutablePathKey) : NULL; + __CFSpinLock(&CFBundleGlobalDataLock); + _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(executablePath); + __CFSpinUnlock(&CFBundleGlobalDataLock); + } else { + CFBundleGetInfoDictionary(bundle); + } + if (oldInfoDict) { + if (!bundle->_infoDict) bundle->_infoDict = CFDictionaryCreateMutable(CFGetAllocator(bundle), 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); + } +} + static CFBundleRef _CFBundleGetMainBundleAlreadyLocked(void) { if (!_initedMainBundle) { const char *processPath; CFStringRef str = NULL; CFURLRef executableURL = NULL, bundleURL = NULL; -#if defined(BINARY_SUPPORT_CFM) - Boolean versRegionOverrides = false; -#endif /* BINARY_SUPPORT_CFM */ -#if defined(__MACOS8__) - // do not use Posix-styled _CFProcessPath() - ProcessSerialNumber gProcessID; - ProcessInfoRec processInfo; - FSSpec processAppSpec; - - processInfo.processInfoLength = sizeof(ProcessInfoRec); - processInfo.processAppSpec = &processAppSpec; - - if ((GetCurrentProcess(&gProcessID) == noErr) && (GetProcessInformation(&gProcessID, &processInfo) == noErr)) { - executableURL = _CFCreateURLFromFSSpec(NULL, (void *)(&processAppSpec), false); - } -#endif _initedMainBundle = true; processPath = _CFProcessPath(); if (processPath) { - str = CFStringCreateWithCString(NULL, processPath, CFStringFileSystemEncoding()); - if (!executableURL) executableURL = CFURLCreateWithFileSystemPath(NULL, str, PLATFORM_PATH_STYLE, false); - } - if (executableURL) { - bundleURL = _CFBundleCopyBundleURLForExecutableURL(executableURL); + str = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, processPath); + if (!executableURL) executableURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, PLATFORM_PATH_STYLE, false); } - if (bundleURL != NULL) { + if (executableURL) bundleURL = _CFBundleCopyBundleURLForExecutableURL(executableURL); + if (bundleURL) { // make sure that main bundle has executable path //??? what if we are not the main executable in the bundle? // NB doFinalProcessing must be false here, see below - _mainBundle = _CFBundleCreate(NULL, bundleURL, true, false); - if (_mainBundle != NULL) { - CFBundleGetInfoDictionary(_mainBundle); + _mainBundle = _CFBundleCreate(kCFAllocatorSystemDefault, bundleURL, true, false); + if (_mainBundle) { // make sure that the main bundle is listed as loaded, and mark it as executable _mainBundle->_isLoaded = true; #if defined(BINARY_SUPPORT_DYLD) @@ -550,72 +633,22 @@ static CFBundleRef _CFBundleGetMainBundleAlreadyLocked(void) { } else { _mainBundle->_binaryType = _CFBundleGrokBinaryType(executableURL); #if defined(BINARY_SUPPORT_CFM) - if (_mainBundle->_binaryType != __CFBundleCFMBinary && _mainBundle->_binaryType != __CFBundleUnreadableBinary) { - _mainBundle->_resourceData._executableLacksResourceFork = true; - } + if (_mainBundle->_binaryType != __CFBundleCFMBinary && _mainBundle->_binaryType != __CFBundleUnreadableBinary) _mainBundle->_resourceData._executableLacksResourceFork = true; #endif /* BINARY_SUPPORT_CFM */ } } #endif /* BINARY_SUPPORT_DYLD */ - if (_mainBundle->_infoDict == NULL || 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(NULL, _mainBundle, NULL, NULL); - if (!executableName || !CFStringHasSuffix(str, executableName)) _mainBundle->_version = 4; - if (executableName) CFRelease(executableName); - } -#if defined(BINARY_SUPPORT_DYLD) - if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary) { - if (_mainBundle->_infoDict != NULL) CFRelease(_mainBundle->_infoDict); - _mainBundle->_infoDict = _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(NULL, _mainBundle, NULL, NULL); - Boolean treatAsBundled = false; - if (str) { - CFIndex strLength = CFStringGetLength(str); - if (strLength > 10) treatAsBundled = CFStringFindWithOptions(str, CFSTR(" MX"), CFRangeMake(strLength - 10, 10), 0, NULL); - } - if (!treatAsBundled && (!executableName || !CFStringHasSuffix(str, executableName))) _mainBundle->_version = 4; - if (executableName) CFRelease(executableName); - } - if (_mainBundle->_infoDict != NULL) CFRelease(_mainBundle->_infoDict); - _mainBundle->_infoDict = _CFBundleCopyInfoDictionaryInResourceForkWithAllocator(CFGetAllocator(_mainBundle), executableURL); - if (_mainBundle->_binaryType == __CFBundleUnreadableBinary && _mainBundle->_infoDict != NULL && CFDictionaryGetValue(_mainBundle->_infoDict, kCFBundleDevelopmentRegionKey) != NULL) versRegionOverrides = true; - } -#endif /* BINARY_SUPPORT_CFM */ - } - if (_mainBundle->_infoDict == NULL) { - _mainBundle->_infoDict = CFDictionaryCreateMutable(CFGetAllocator(_mainBundle), 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - } - if (NULL == CFDictionaryGetValue(_mainBundle->_infoDict, _kCFBundleExecutablePathKey)) { - CFDictionarySetValue((CFMutableDictionaryRef)(_mainBundle->_infoDict), _kCFBundleExecutablePathKey, str); - } #if defined(BINARY_SUPPORT_DYLD) // get cookie for already-loaded main bundle if (_mainBundle->_binaryType == __CFBundleDYLDExecutableBinary && !_mainBundle->_imageCookie) { + // ??? need better way to specify main executable image _mainBundle->_imageCookie = (void *)_dyld_get_image_header(0); +#if LOG_BUNDLE_LOAD + printf("main bundle %p getting image %p\n", _mainBundle, _mainBundle->_imageCookie); +#endif /* LOG_BUNDLE_LOAD */ } #endif /* BINARY_SUPPORT_DYLD */ -#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 != NULL) { - CFDictionarySetValue((CFMutableDictionaryRef)(_mainBundle->_infoDict), kCFBundleDevelopmentRegionKey, devLang); - CFRelease(devLang); - } - } -#endif /* BINARY_SUPPORT_CFM */ + _CFBundleInitializeMainBundleInfoDictionaryAlreadyLocked(str); // Perform delayed final processing steps. // This must be done after _isLoaded has been set, for security reasons (3624341). _CFBundleCheckWorkarounds(_mainBundle); @@ -641,63 +674,53 @@ CFBundleRef CFBundleGetMainBundle(void) { return mainBundle; } -#if defined(BINARY_SUPPORT_DYLD) - -static void *_CFBundleReturnAddressFromFrameAddress(void *addr) -{ - void *ret; -#if defined(__ppc__) - __asm__ volatile("lwz %0,0x0008(%1)" : "=r" (ret) : "b" (addr)); -#elif defined(__i386__) - __asm__ volatile("movl 0x4(%1),%0" : "=r" (ret) : "r" (addr)); -#elif defined(hppa) - __asm__ volatile("ldw 0x4(%1),%0" : "=r" (ret) : "r" (addr)); -#elif defined(sparc) - __asm__ volatile("ta 0x3"); - __asm__ volatile("ld [%1 + 60],%0" : "=r" (ret) : "r" (addr)); -#else -#warning Do not know how to define _CFBundleReturnAddressFromFrameAddress on this architecture - ret = NULL; -#endif - return ret; -} - -#endif - CFBundleRef CFBundleGetBundleWithIdentifier(CFStringRef bundleID) { CFBundleRef result = NULL; + CFArrayRef bundlesWithThisID; if (bundleID) { __CFSpinLock(&CFBundleGlobalDataLock); (void)_CFBundleGetMainBundleAlreadyLocked(); - if (_bundlesByIdentifier != NULL) { - result = (CFBundleRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); + if (_bundlesByIdentifier) { + bundlesWithThisID = (CFArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); + if (bundlesWithThisID && CFArrayGetCount(bundlesWithThisID) > 0) result = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, 0); } -#if defined(BINARY_SUPPORT_DYLD) - if (result == NULL) { +#if DEPLOYMENT_TARGET_MACOSX + if (!result) { // Try to create the bundle for the caller and try again - void *p = _CFBundleReturnAddressFromFrameAddress(__builtin_frame_address(1)); - CFStringRef imagePath = _CFBundleDYLDCopyLoadedImagePathForPointer(p); - if (imagePath != NULL) { - _CFBundleEnsureBundleExistsForImagePath(imagePath); - CFRelease(imagePath); - } - if (_bundlesByIdentifier != NULL) { - result = (CFBundleRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); + void *p = __builtin_return_address(0); + if (p) { + CFStringRef imagePath = NULL; +#if defined(BINARY_SUPPORT_DLFCN) + if (!imagePath && _useDlfcn) imagePath = _CFBundleDlfcnCopyLoadedImagePathForPointer(p); +#endif /* BINARY_SUPPORT_DLFCN */ +#if defined(BINARY_SUPPORT_DYLD) + if (!imagePath) imagePath = _CFBundleDYLDCopyLoadedImagePathForPointer(p); +#endif /* BINARY_SUPPORT_DYLD */ + if (imagePath) { + _CFBundleEnsureBundleExistsForImagePath(imagePath); + CFRelease(imagePath); + } + if (_bundlesByIdentifier) { + bundlesWithThisID = (CFArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); + if (bundlesWithThisID && CFArrayGetCount(bundlesWithThisID) > 0) result = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, 0); + } } } #endif - if (result == NULL) { + if (!result) { // Try to guess the bundle from the identifier and try again _CFBundleEnsureBundlesUpToDateWithHintAlreadyLocked(bundleID); - if (_bundlesByIdentifier != NULL) { - result = (CFBundleRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); + if (_bundlesByIdentifier) { + bundlesWithThisID = (CFArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); + if (bundlesWithThisID && CFArrayGetCount(bundlesWithThisID) > 0) result = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, 0); } } - if (result == NULL) { + if (!result) { // Make sure all bundles have been created and try again. _CFBundleEnsureAllBundlesUpToDateAlreadyLocked(); - if (_bundlesByIdentifier != NULL) { - result = (CFBundleRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); + if (_bundlesByIdentifier) { + bundlesWithThisID = (CFArrayRef)CFDictionaryGetValue(_bundlesByIdentifier, bundleID); + if (bundlesWithThisID && CFArrayGetCount(bundlesWithThisID) > 0) result = (CFBundleRef)CFArrayGetValueAtIndex(bundlesWithThisID, 0); } } __CFSpinUnlock(&CFBundleGlobalDataLock); @@ -708,9 +731,7 @@ CFBundleRef CFBundleGetBundleWithIdentifier(CFStringRef bundleID) { static CFStringRef __CFBundleCopyDescription(CFTypeRef cf) { char buff[CFMaxPathSize]; CFStringRef path = NULL, binaryType = NULL, retval = NULL; - if (((CFBundleRef)cf)->_url != NULL && CFURLGetFileSystemRepresentation(((CFBundleRef)cf)->_url, true, buff, CFMaxPathSize)) { - path = CFStringCreateWithCString(NULL, buff, CFStringFileSystemEncoding()); - } + if (((CFBundleRef)cf)->_url && CFURLGetFileSystemRepresentation(((CFBundleRef)cf)->_url, true, (uint8_t *)buff, CFMaxPathSize)) path = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, buff); switch (((CFBundleRef)cf)->_binaryType) { case __CFBundleCFMBinary: binaryType = CFSTR(""); @@ -735,9 +756,9 @@ static CFStringRef __CFBundleCopyDescription(CFTypeRef cf) { break; } if (((CFBundleRef)cf)->_plugInData._isPlugIn) { - retval = CFStringCreateWithFormat(NULL, NULL, CFSTR("CFBundle/CFPlugIn 0x%x <%@> (%@%sloaded)"), cf, path, binaryType, ((CFBundleRef)cf)->_isLoaded ? "" : "not "); + retval = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("CFBundle/CFPlugIn %p <%@> (%@%sloaded)"), cf, path, binaryType, ((CFBundleRef)cf)->_isLoaded ? "" : "not "); } else { - retval = CFStringCreateWithFormat(NULL, NULL, CFSTR("CFBundle 0x%x <%@> (%@%sloaded)"), cf, path, binaryType, ((CFBundleRef)cf)->_isLoaded ? "" : "not "); + retval = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("CFBundle %p <%@> (%@%sloaded)"), cf, path, binaryType, ((CFBundleRef)cf)->_isLoaded ? "" : "not "); } if (path) CFRelease(path); return retval; @@ -745,9 +766,7 @@ static CFStringRef __CFBundleCopyDescription(CFTypeRef cf) { static void _CFBundleDeallocateGlue(const void *key, const void *value, void *context) { CFAllocatorRef allocator = (CFAllocatorRef)context; - if (value != NULL) { - CFAllocatorDeallocate(allocator, (void *)value); - } + if (value) CFAllocatorDeallocate(allocator, (void *)value); } static void __CFBundleDeallocate(CFTypeRef cf) { @@ -766,29 +785,19 @@ static void __CFBundleDeallocate(CFTypeRef cf) { _CFBundleRemoveFromTables(bundle); - if (bundle->_url != NULL) { + if (bundle->_url) { _CFBundleFlushCachesForURL(bundle->_url); CFRelease(bundle->_url); } - if (bundle->_infoDict != NULL) { - CFRelease(bundle->_infoDict); - } - if (bundle->_modDate != NULL) { - CFRelease(bundle->_modDate); - } - if (bundle->_localInfoDict != NULL) { - CFRelease(bundle->_localInfoDict); - } - if (bundle->_searchLanguages != NULL) { - CFRelease(bundle->_searchLanguages); - } - if (bundle->_glueDict != NULL) { + if (bundle->_infoDict) CFRelease(bundle->_infoDict); + if (bundle->_modDate) CFRelease(bundle->_modDate); + if (bundle->_localInfoDict) CFRelease(bundle->_localInfoDict); + if (bundle->_searchLanguages) CFRelease(bundle->_searchLanguages); + if (bundle->_glueDict) { CFDictionaryApplyFunction(bundle->_glueDict, _CFBundleDeallocateGlue, (void *)allocator); CFRelease(bundle->_glueDict); } - if (bundle->_resourceData._stringTableCache != NULL) { - CFRelease(bundle->_resourceData._stringTableCache); - } + if (bundle->_resourceData._stringTableCache) CFRelease(bundle->_resourceData._stringTableCache); } static const CFRuntimeClass __CFBundleClass = { @@ -805,12 +814,36 @@ static const CFRuntimeClass __CFBundleClass = { __private_extern__ void __CFBundleInitialize(void) { __kCFBundleTypeID = _CFRuntimeRegisterClass(&__CFBundleClass); +#if defined(BINARY_SUPPORT_DLFCN) + _useDlfcn = true; +#if defined(BINARY_SUPPORT_DYLD) + if (getenv("CFBundleUseDYLD")) _useDlfcn = false; +#endif /* BINARY_SUPPORT_DYLD */ +#endif /* BINARY_SUPPORT_DLFCN */ +} + +Boolean _CFBundleUseDlfcn(void) { + return _useDlfcn; } CFTypeID CFBundleGetTypeID(void) { return __kCFBundleTypeID; } +CFBundleRef _CFBundleGetExistingBundleWithBundleURL(CFURLRef bundleURL) { + CFBundleRef bundle = NULL; + char buff[CFMaxPathSize]; + CFURLRef newURL = NULL; + + if (!CFURLGetFileSystemRepresentation(bundleURL, true, (uint8_t *)buff, CFMaxPathSize)) return NULL; + + newURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)buff, strlen(buff), true); + if (!newURL) newURL = (CFURLRef)CFRetain(bundleURL); + bundle = _CFBundleFindByURL(newURL, false); + CFRelease(newURL); + return bundle; +} + static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, Boolean alreadyLocked, Boolean doFinalProcessing) { CFBundleRef bundle = NULL; char buff[CFMaxPathSize]; @@ -820,12 +853,10 @@ static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, CFURLRef newURL = NULL; uint8_t localVersion = 0; - if (!CFURLGetFileSystemRepresentation(bundleURL, true, buff, CFMaxPathSize)) return NULL; + if (!CFURLGetFileSystemRepresentation(bundleURL, true, (uint8_t *)buff, CFMaxPathSize)) return NULL; - newURL = CFURLCreateFromFileSystemRepresentation(allocator, buff, strlen(buff), true); - if (NULL == newURL) { - newURL = CFRetain(bundleURL); - } + newURL = CFURLCreateFromFileSystemRepresentation(allocator, (uint8_t *)buff, strlen(buff), true); + if (!newURL) newURL = (CFURLRef)CFRetain(bundleURL); bundle = _CFBundleFindByURL(newURL, alreadyLocked); if (bundle) { CFRetain(bundle); @@ -837,7 +868,7 @@ static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, localVersion = 3; if (_CFGetFileProperties(allocator, newURL, &exists, &mode, NULL, &modDate, NULL, NULL) == 0) { if (!exists || ((mode & S_IFMT) != S_IFDIR)) { - if (NULL != modDate) CFRelease(modDate); + if (modDate) CFRelease(modDate); CFRelease(newURL); return NULL; } @@ -848,7 +879,7 @@ static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, } bundle = (CFBundleRef)_CFRuntimeCreateInstance(allocator, __kCFBundleTypeID, sizeof(struct __CFBundle) - sizeof(CFRuntimeBase), NULL); - if (NULL == bundle) { + if (!bundle) { CFRelease(newURL); return NULL; } @@ -874,18 +905,19 @@ static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, #else /* We'll have to figure it out later */ bundle->_binaryType = __CFBundleUnknownBinary; -#endif +#endif /* BINARY_SUPPORT_DYLD */ bundle->_isLoaded = false; bundle->_sharesStringsFiles = false; - /* ??? For testing purposes? Or for good? */ -#warning Ali or Doug: Decide how to finalize strings sharing if (!getenv("CFBundleDisableStringsSharing") && +#if DEPLOYMENT_TARGET_MACOSX (strncmp(buff, "/System/Library/Frameworks", 26) == 0) && +#endif (strncmp(buff + strlen(buff) - 10, ".framework", 10) == 0)) bundle->_sharesStringsFiles = true; bundle->_connectionCookie = NULL; + bundle->_handleCookie = NULL; bundle->_imageCookie = NULL; bundle->_moduleCookie = NULL; @@ -893,10 +925,10 @@ static CFBundleRef _CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL, #if defined(BINARY_SUPPORT_CFM) bundle->_resourceData._executableLacksResourceFork = false; -#else +#else /* BINARY_SUPPORT_CFM */ bundle->_resourceData._executableLacksResourceFork = true; -#endif - +#endif /* BINARY_SUPPORT_CFM */ + bundle->_resourceData._infoDictionaryFromResourceFork = false; bundle->_resourceData._stringTableCache = NULL; bundle->_plugInData._isPlugIn = false; @@ -926,17 +958,15 @@ CFBundleRef CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL) {return CFArrayRef CFBundleCreateBundlesFromDirectory(CFAllocatorRef alloc, CFURLRef directoryURL, CFStringRef bundleType) { CFMutableArrayRef bundles = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks); CFArrayRef URLs = _CFContentsOfDirectory(alloc, NULL, NULL, directoryURL, bundleType); - if (URLs != NULL) { + if (URLs) { CFIndex i, c = CFArrayGetCount(URLs); CFURLRef curURL; CFBundleRef curBundle; - for (i=0; i_searchLanguages == NULL) { - CFMutableArrayRef langs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (!bundle->_searchLanguages) { + CFMutableArrayRef langs = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); CFStringRef devLang = CFBundleGetDevelopmentRegion(bundle); _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version, bundle->_infoDict, langs, devLang); @@ -973,16 +1003,16 @@ CFArrayRef _CFBundleGetLanguageSearchList(CFBundleRef bundle) { CFArrayRef localizations = CFBundleCopyBundleLocalizations(bundle); if (localizations) { if (CFArrayGetCount(localizations) > 0) { - _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version, bundle->_infoDict, langs, CFArrayGetValueAtIndex(localizations, 0)); + _CFBundleAddPreferredLprojNamesInDirectory(CFGetAllocator(bundle), bundle->_url, bundle->_version, bundle->_infoDict, langs, (CFStringRef)CFArrayGetValueAtIndex(localizations, 0)); } CFRelease(localizations); } } - if (devLang != NULL && !CFArrayContainsValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), devLang)) { + if (devLang && !CFArrayContainsValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), devLang)) { // Make sure that devLang is on the list as a fallback for individual resources that are not present CFArrayAppendValue(langs, devLang); - } else if (devLang == NULL) { + } else if (!devLang) { // Or if there is no devLang, try some variation of English that is present CFArrayRef localizations = CFBundleCopyBundleLocalizations(bundle); if (localizations) { @@ -1000,7 +1030,7 @@ CFArrayRef _CFBundleGetLanguageSearchList(CFBundleRef bundle) { } if (CFArrayGetCount(langs) == 0) { // Total backstop behavior to avoid having an empty array. - if (_defaultLocalization != NULL) { + if (_defaultLocalization) { CFArrayAppendValue(langs, _defaultLocalization); } else { CFArrayAppendValue(langs, CFSTR("en")); @@ -1011,19 +1041,17 @@ CFArrayRef _CFBundleGetLanguageSearchList(CFBundleRef bundle) { return bundle->_searchLanguages; } -CFDictionaryRef CFBundleCopyInfoDictionaryInDirectory(CFURLRef url) {return _CFBundleCopyInfoDictionaryInDirectory(NULL, url, NULL);} +CFDictionaryRef CFBundleCopyInfoDictionaryInDirectory(CFURLRef url) {return _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefault, url, NULL);} CFDictionaryRef CFBundleGetInfoDictionary(CFBundleRef bundle) { - if (bundle->_infoDict == NULL) { - bundle->_infoDict = _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFGetAllocator(bundle), bundle->_url, bundle->_version); - } + if (!bundle->_infoDict) bundle->_infoDict = _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFGetAllocator(bundle), bundle->_url, bundle->_version); return bundle->_infoDict; } CFDictionaryRef _CFBundleGetLocalInfoDictionary(CFBundleRef bundle) {return CFBundleGetLocalInfoDictionary(bundle);} CFDictionaryRef CFBundleGetLocalInfoDictionary(CFBundleRef bundle) { - if (bundle->_localInfoDict == NULL) { + if (!bundle->_localInfoDict) { CFURLRef url = CFBundleCopyResourceURL(bundle, _CFBundleLocalInfoName, _CFBundleStringTableType, NULL); if (url) { CFDataRef data; @@ -1031,10 +1059,8 @@ CFDictionaryRef CFBundleGetLocalInfoDictionary(CFBundleRef bundle) { CFStringRef errStr = NULL; if (CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(bundle), url, &data, NULL, NULL, &errCode)) { - bundle->_localInfoDict = CFPropertyListCreateFromXMLData(CFGetAllocator(bundle), data, kCFPropertyListImmutable, &errStr); - if (errStr) { - CFRelease(errStr); - } + bundle->_localInfoDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(CFGetAllocator(bundle), data, kCFPropertyListImmutable, &errStr); + if (errStr) CFRelease(errStr); if (bundle->_localInfoDict && CFDictionaryGetTypeID() != CFGetTypeID(bundle->_localInfoDict)) { CFRelease(bundle->_localInfoDict); bundle->_localInfoDict = NULL; @@ -1052,16 +1078,12 @@ CFPropertyListRef _CFBundleGetValueForInfoKey(CFBundleRef bundle, CFStringRef ke CFTypeRef CFBundleGetValueForInfoDictionaryKey(CFBundleRef bundle, CFStringRef key) { // Look in InfoPlist.strings first. Then look in Info.plist CFTypeRef result = NULL; - if ((bundle!= NULL) && (key != NULL)) { + if (bundle && key) { CFDictionaryRef dict = CFBundleGetLocalInfoDictionary(bundle); - if (dict != NULL) { - result = CFDictionaryGetValue(dict, key); - } - if (result == NULL) { + if (dict) result = CFDictionaryGetValue(dict, key); + if (!result) { dict = CFBundleGetInfoDictionary(bundle); - if (dict != NULL) { - result = CFDictionaryGetValue(dict, key); - } + if (dict) result = CFDictionaryGetValue(dict, key); } } return result; @@ -1070,9 +1092,7 @@ CFTypeRef CFBundleGetValueForInfoDictionaryKey(CFBundleRef bundle, CFStringRef k CFStringRef CFBundleGetIdentifier(CFBundleRef bundle) { CFStringRef bundleID = NULL; CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); - if (infoDict) { - bundleID = CFDictionaryGetValue(infoDict, kCFBundleIdentifierKey); - } + if (infoDict) bundleID = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleIdentifierKey); return bundleID; } @@ -1277,10 +1297,8 @@ UInt32 CFBundleGetVersionNumber(CFBundleRef bundle) { CFNumberRef versNum; UInt32 vers = 0; - if (unknownVersionValue == NULL) { - unknownVersionValue = CFDictionaryGetValue(infoDict, kCFBundleVersionKey); - } - if (unknownVersionValue != NULL) { + if (!unknownVersionValue) unknownVersionValue = CFDictionaryGetValue(infoDict, kCFBundleVersionKey); + if (unknownVersionValue) { if (CFGetTypeID(unknownVersionValue) == CFStringGetTypeID()) { // Convert a string version number into a numeric one. vers = _CFVersionNumberFromString((CFStringRef)unknownVersionValue); @@ -1301,8 +1319,8 @@ CFStringRef CFBundleGetDevelopmentRegion(CFBundleRef bundle) { CFStringRef devLang = NULL; CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); if (infoDict) { - devLang = CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey); - if (devLang != NULL && (CFGetTypeID(devLang) != CFStringGetTypeID() || CFStringGetLength(devLang) == 0)) { + devLang = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey); + if (devLang && (CFGetTypeID(devLang) != CFStringGetTypeID() || CFStringGetLength(devLang) == 0)) { devLang = NULL; CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, kCFBundleDevelopmentRegionKey); } @@ -1319,9 +1337,7 @@ Boolean _CFBundleGetHasChanged(CFBundleRef bundle) { if (_CFGetFileProperties(CFGetAllocator(bundle), bundle->_url, &exists, &mode, NULL, &modDate, NULL, NULL) == 0) { // If the bundle no longer exists or is not a folder, it must have "changed" - if (!exists || ((mode & S_IFMT) != S_IFDIR)) { - result = true; - } + if (!exists || ((mode & S_IFMT) != S_IFDIR)) result = true; } else { // Something is wrong. The stat failed. result = true; @@ -1355,7 +1371,7 @@ __private_extern__ CFURLRef _CFBundleCopySupportFilesDirectoryURLInDirectory(CFA } else if (2 == version) { result = CFURLCreateWithString(alloc, _CFBundleSupportFilesURLFromBase2, bundleURL); } else { - result = CFRetain(bundleURL); + result = (CFURLRef)CFRetain(bundleURL); } } return result; @@ -1373,7 +1389,7 @@ __private_extern__ CFURLRef _CFBundleCopyResourcesDirectoryURLInDirectory(CFAllo } else if (2 == version) { result = CFURLCreateWithString(alloc, _CFBundleResourcesURLFromBase2, bundleURL); } else { - result = CFRetain(bundleURL); + result = (CFURLRef)CFRetain(bundleURL); } } return result; @@ -1384,16 +1400,13 @@ CFURLRef CFBundleCopyResourcesDirectoryURL(CFBundleRef bundle) {return _CFBundle static CFURLRef _CFBundleCopyExecutableURLRaw(CFAllocatorRef alloc, 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 defined(__MACH__) - const uint8_t *image_suffix = getenv("DYLD_IMAGE_SUFFIX"); -#endif /* __MACH__ */ - - if (urlPath == NULL || exeName == NULL) return NULL; + if (!urlPath || !exeName) return NULL; -#if defined(__MACH__) - if (image_suffix != NULL) { +#if DEPLOYMENT_TARGET_MACOSX + const uint8_t *image_suffix = (uint8_t *)getenv("DYLD_IMAGE_SUFFIX"); + if (image_suffix) { CFStringRef newExeName, imageSuffix; - imageSuffix = CFStringCreateWithCString(NULL, image_suffix, kCFStringEncodingUTF8); + 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); @@ -1402,76 +1415,44 @@ static CFURLRef _CFBundleCopyExecutableURLRaw(CFAllocatorRef alloc, CFURLRef url newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@"), exeName, imageSuffix); } executableURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, newExeName, kCFURLPOSIXPathStyle, false, urlPath); - if (executableURL != NULL && !_urlExists(alloc, executableURL)) { + if (executableURL && !_urlExists(alloc, executableURL)) { CFRelease(executableURL); executableURL = NULL; } CFRelease(newExeName); CFRelease(imageSuffix); } -#endif /* __MACH__ */ - if (executableURL == NULL) { +#endif + if (!executableURL) { executableURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, exeName, kCFURLPOSIXPathStyle, false, urlPath); - if (executableURL != NULL && !_urlExists(alloc, executableURL)) { + if (executableURL && !_urlExists(alloc, executableURL)) { CFRelease(executableURL); executableURL = NULL; } } -#if defined(__WIN32__) - if (executableURL == NULL) { - if (!CFStringHasSuffix(exeName, CFSTR(".dll"))) { - CFStringRef newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@"), exeName, CFSTR(".dll")); - executableURL = CFURLCreateWithString(alloc, newExeName, urlPath); - if (executableURL != NULL && !_urlExists(alloc, executableURL)) { - CFRelease(executableURL); - executableURL = NULL; - } - CFRelease(newExeName); - } - } - if (executableURL == NULL) { - if (!CFStringHasSuffix(exeName, CFSTR(".exe"))) { - CFStringRef newExeName = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%@"), exeName, CFSTR(".exe")); - executableURL = CFURLCreateWithString(alloc, newExeName, urlPath); - if (executableURL != NULL && !_urlExists(alloc, executableURL)) { - CFRelease(executableURL); - executableURL = NULL; - } - CFRelease(newExeName); - } - } -#endif return executableURL; } static CFStringRef _CFBundleCopyExecutableName(CFAllocatorRef alloc, CFBundleRef bundle, CFURLRef url, CFDictionaryRef infoDict) { CFStringRef executableName = NULL; - if (alloc == NULL && bundle != NULL) { - alloc = CFGetAllocator(bundle); - } - if (infoDict == NULL && bundle != NULL) { - infoDict = CFBundleGetInfoDictionary(bundle); - } - if (url == NULL && bundle != NULL) { - url = bundle->_url; - } + if (!alloc && bundle) alloc = CFGetAllocator(bundle); + if (!infoDict && bundle) infoDict = CFBundleGetInfoDictionary(bundle); + if (!url && bundle) url = bundle->_url; - if (infoDict != NULL) { + if (infoDict) { // Figure out the name of the executable. // First try for the new key in the plist. - executableName = CFDictionaryGetValue(infoDict, kCFBundleExecutableKey); - if (executableName == NULL) { - // Second try for the old key in the plist. - executableName = CFDictionaryGetValue(infoDict, _kCFBundleOldExecutableKey); - } - if (executableName != NULL && CFGetTypeID(executableName) == CFStringGetTypeID() && CFStringGetLength(executableName) > 0) { + executableName = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleExecutableKey); + // Second try for the old key in the plist. + if (!executableName) executableName = (CFStringRef)CFDictionaryGetValue(infoDict, _kCFBundleOldExecutableKey); + if (executableName && CFGetTypeID(executableName) == CFStringGetTypeID() && CFStringGetLength(executableName) > 0) { CFRetain(executableName); } else { executableName = NULL; } } - if (executableName == NULL && url != NULL) { + if (!executableName && url) { // Third, take the name of the bundle itself (with path extension stripped) CFURLRef absoluteURL = CFURLCopyAbsoluteURL(url); CFStringRef bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); @@ -1495,9 +1476,9 @@ static CFStringRef _CFBundleCopyExecutableName(CFAllocatorRef alloc, CFBundleRef } __private_extern__ CFURLRef _CFBundleCopyResourceForkURLMayBeLocal(CFBundleRef bundle, Boolean mayBeLocal) { - CFStringRef executableName = _CFBundleCopyExecutableName(NULL, bundle, NULL, NULL); + CFStringRef executableName = _CFBundleCopyExecutableName(kCFAllocatorSystemDefault, bundle, NULL, NULL); CFURLRef resourceForkURL = NULL; - if (executableName != NULL) { + if (executableName) { if (mayBeLocal) { resourceForkURL = CFBundleCopyResourceURL(bundle, executableName, CFSTR("rsrc"), NULL); } else { @@ -1517,9 +1498,9 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRe CFStringRef executablePath = NULL; CFURLRef executableURL = NULL; Boolean foundIt = false; - Boolean lookupMainExe = ((executableName == NULL) ? true : false); + Boolean lookupMainExe = (executableName ? false : true); - if (bundle != NULL) { + if (bundle) { infoDict = CFBundleGetInfoDictionary(bundle); version = bundle->_version; } else { @@ -1527,11 +1508,13 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRe } // If we have a bundle instance and an info dict, see if we have already cached the path - if (lookupMainExe && !ignoreCache && !useOtherPlatform && (bundle != NULL) && (infoDict != NULL)) { - executablePath = CFDictionaryGetValue(infoDict, _kCFBundleExecutablePathKey); - if (executablePath != NULL) { + if (lookupMainExe && !ignoreCache && !useOtherPlatform && bundle && infoDict) { + executablePath = (CFStringRef)CFDictionaryGetValue(infoDict, _kCFBundleExecutablePathKey); + if (executablePath) { +#if DEPLOYMENT_TARGET_MACOSX executableURL = CFURLCreateWithFileSystemPath(alloc, executablePath, kCFURLPOSIXPathStyle, false); - if (executableURL != NULL) foundIt = true; +#endif + if (executableURL) foundIt = true; if (!foundIt) { executablePath = NULL; CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, _kCFBundleExecutablePathKey); @@ -1543,9 +1526,12 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRe if (lookupMainExe) { executableName = _CFBundleCopyExecutableName(alloc, bundle, url, infoDict); } - if (executableName != NULL) { + if (executableName) { +#if DEPLOYMENT_TARGET_MACOSX + Boolean doExecSearch = true; +#endif // Now, look for the executable inside the bundle. - if (0 != version) { + if (doExecSearch && 0 != version) { CFURLRef exeDirURL; CFURLRef exeSubdirURL; @@ -1554,26 +1540,32 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRe } else if (2 == version) { exeDirURL = CFURLCreateWithString(alloc, _CFBundleExecutablesURLFromBase2, url); } else { - exeDirURL = CFRetain(url); +#if DEPLOYMENT_TARGET_MACOSX + exeDirURL = (CFURLRef)CFRetain(url); +#endif } - exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, useOtherPlatform ? _CFBundleGetOtherPlatformExecutablesSubdirectoryName() : _CFBundleGetPlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle, true, exeDirURL); + CFStringRef platformSubDir = useOtherPlatform ? _CFBundleGetOtherPlatformExecutablesSubdirectoryName() : _CFBundleGetPlatformExecutablesSubdirectoryName(); + exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL); executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeSubdirURL, executableName); - if (executableURL == NULL) { + if (!executableURL) { CFRelease(exeSubdirURL); - exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, useOtherPlatform ? _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetAlternatePlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle, true, exeDirURL); + platformSubDir = useOtherPlatform ? _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetAlternatePlatformExecutablesSubdirectoryName(); + exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL); executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeSubdirURL, executableName); } - if (executableURL == NULL) { + if (!executableURL) { CFRelease(exeSubdirURL); - exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, useOtherPlatform ? _CFBundleGetPlatformExecutablesSubdirectoryName() : _CFBundleGetOtherPlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle, true, exeDirURL); + platformSubDir = useOtherPlatform ? _CFBundleGetPlatformExecutablesSubdirectoryName() : _CFBundleGetOtherPlatformExecutablesSubdirectoryName(); + exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL); executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeSubdirURL, executableName); } - if (executableURL == NULL) { + if (!executableURL) { CFRelease(exeSubdirURL); - exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, useOtherPlatform ? _CFBundleGetAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(), kCFURLPOSIXPathStyle, true, exeDirURL); + platformSubDir = useOtherPlatform ? _CFBundleGetAlternatePlatformExecutablesSubdirectoryName() : _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(); + exeSubdirURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, platformSubDir, kCFURLPOSIXPathStyle, true, exeDirURL); executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeSubdirURL, executableName); } - if (executableURL == NULL) { + if (!executableURL) { executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeDirURL, executableName); } @@ -1582,51 +1574,31 @@ static CFURLRef _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFAllocatorRe } // If this was an old bundle, or we did not find the executable in the Excutables subdirectory, look directly in the bundle wrapper. - if (executableURL == NULL) { - executableURL = _CFBundleCopyExecutableURLRaw(alloc, url, executableName); - } + if (!executableURL) executableURL = _CFBundleCopyExecutableURLRaw(alloc, url, executableName); -#if defined(__WIN32__) - // 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 == NULL)) { - CFURLRef exeDirURL; - - exeDirURL = CFURLCreateWithString(alloc, CFSTR("../../Executables"), url); - - executableURL = _CFBundleCopyExecutableURLRaw(alloc, exeDirURL, executableName); - - CFRelease(exeDirURL); - } -#endif - - if (lookupMainExe && !ignoreCache && !useOtherPlatform && (bundle != NULL) && (infoDict != NULL) && (executableURL != NULL)) { + if (lookupMainExe && !ignoreCache && !useOtherPlatform && bundle && infoDict && executableURL) { // We found it. Cache the path. CFURLRef absURL = CFURLCopyAbsoluteURL(executableURL); +#if DEPLOYMENT_TARGET_MACOSX executablePath = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle); +#endif CFRelease(absURL); CFDictionarySetValue((CFMutableDictionaryRef)infoDict, _kCFBundleExecutablePathKey, executablePath); CFRelease(executablePath); } - if (lookupMainExe && !useOtherPlatform && (bundle != NULL) && (executableURL == NULL)) { - bundle->_binaryType = __CFBundleNoBinary; - } - if (lookupMainExe) { - CFRelease(executableName); - } + if (lookupMainExe && !useOtherPlatform && bundle && !executableURL) bundle->_binaryType = __CFBundleNoBinary; + if (lookupMainExe) CFRelease(executableName); } } - if ((bundle == NULL) && (infoDict != NULL)) { - CFRelease(infoDict); - } + if (!bundle && infoDict) CFRelease(infoDict); return executableURL; } -CFURLRef _CFBundleCopyExecutableURLInDirectory(CFURLRef url) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(NULL, NULL, url, NULL, true, false);} +CFURLRef _CFBundleCopyExecutableURLInDirectory(CFURLRef url) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(kCFAllocatorSystemDefault, NULL, url, NULL, true, false);} -CFURLRef _CFBundleCopyOtherExecutableURLInDirectory(CFURLRef url) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(NULL, NULL, url, NULL, true, true);} +CFURLRef _CFBundleCopyOtherExecutableURLInDirectory(CFURLRef url) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(kCFAllocatorSystemDefault, NULL, url, NULL, true, true);} CFURLRef CFBundleCopyExecutableURL(CFBundleRef bundle) {return _CFBundleCopyExecutableURLInDirectoryWithAllocator(CFGetAllocator(bundle), bundle, bundle->_url, NULL, false, false);} @@ -1645,9 +1617,7 @@ CFBundleExecutableType CFBundleGetExecutableType(CFBundleRef bundle) { if (bundle->_binaryType == __CFBundleUnknownBinary) { bundle->_binaryType = _CFBundleGrokBinaryType(executableURL); #if defined(BINARY_SUPPORT_CFM) - if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) { - bundle->_resourceData._executableLacksResourceFork = true; - } + if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true; #endif /* BINARY_SUPPORT_CFM */ } #endif /* BINARY_SUPPORT_DYLD */ @@ -1667,42 +1637,55 @@ CFBundleExecutableType CFBundleGetExecutableType(CFBundleRef bundle) { #define UNKNOWN_FILETYPE 0x0 #define PEF_FILETYPE 0x1000 -#define XLS_FILETYPE 0x10001 -#define DOC_FILETYPE 0x10002 -#define PPT_FILETYPE 0x10003 -#define XLS_NAME "Workbook" -#define XLS_NAME2 "Book" -#define DOC_NAME "WordDocument" -#define PPT_NAME "PowerPoint Document" #define PEF_MAGIC 0x4a6f7921 #define PEF_CIGAM 0x21796f4a -#define PLIST_SEGMENT "__TEXT" +#define TEXT_SEGMENT "__TEXT" #define PLIST_SECTION "__info_plist" +#define OBJC_SEGMENT "__OBJC" +#define IMAGE_INFO_SECTION "__image_info" #define LIB_X11 "/usr/X11R6/lib/libX" +#define XLS_NAME "Book" +#define XLS_NAME2 "Workbook" +#define DOC_NAME "WordDocument" +#define PPT_NAME "PowerPoint Document" + +#define ustrncmp(x, y, z) strncmp((char *)(x), (char *)(y), (z)) +#define ustrncasecmp(x, y, z) strncasecmp_l((char *)(x), (char *)(y), (z), NULL) + static const uint32_t __CFBundleMagicNumbersArray[] = { - 0xcafebabe, 0xbebafeca, 0xfeedface, 0xcefaedfe, 0x4a6f7921, 0x21796f4a, 0x7f454c46, 0xffd8ffe0, - 0x4d4d002a, 0x49492a00, 0x47494638, 0x89504e47, 0x69636e73, 0x00000100, 0x7b5c7274, 0x25504446, - 0x2e7261fd, 0x2e524d46, 0x2e736e64, 0x2e736400, 0x464f524d, 0x52494646, 0x38425053, 0x000001b3, - 0x000001ba, 0x4d546864, 0x504b0304, 0x53495421, 0x53495432, 0x53495435, 0x53495444, 0x53747566, - 0x30373037, 0x3c212d2d, 0x25215053, 0xd0cf11e0, 0x62656769, 0x6b6f6c79, 0x3026b275, 0x0000000c, - 0xfe370023, 0x09020600, 0x09040600, 0x4f676753, 0x664c6143, 0x00010000, 0x74727565, 0x4f54544f, - 0x41433130, 0xc809fe02, 0x0809fe02, 0x2356524d, 0x67696d70, 0x3c435058, 0x28445746, 0x424f4d53 + 0xcafebabe, 0xbebafeca, 0xfeedface, 0xcefaedfe, 0xfeedfacf, 0xcffaedfe, 0x4a6f7921, 0x21796f4a, + 0x7f454c46, 0xffd8ffe0, 0x4d4d002a, 0x49492a00, 0x47494638, 0x89504e47, 0x69636e73, 0x00000100, + 0x7b5c7274, 0x25504446, 0x2e7261fd, 0x2e524d46, 0x2e736e64, 0x2e736400, 0x464f524d, 0x52494646, + 0x38425053, 0x000001b3, 0x000001ba, 0x4d546864, 0x504b0304, 0x53495421, 0x53495432, 0x53495435, + 0x53495444, 0x53747566, 0x30373037, 0x3c212d2d, 0x25215053, 0xd0cf11e0, 0x62656769, 0x3d796265, + 0x6b6f6c79, 0x3026b275, 0x0000000c, 0xfe370023, 0x09020600, 0x09040600, 0x4f676753, 0x664c6143, + 0x00010000, 0x74727565, 0x4f54544f, 0x41433130, 0xc809fe02, 0x0809fe02, 0x2356524d, 0x67696d70, + 0x3c435058, 0x28445746, 0x424f4d53, 0x49544f4c, 0x72746664 }; // string, with groups of 5 characters being 1 element in the array static const char * __CFBundleExtensionsArray = - "mach\0" "mach\0" "mach\0" "mach\0" "pef\0\0" "pef\0\0" "elf\0\0" "jpeg\0" - "tiff\0" "tiff\0" "gif\0\0" "png\0\0" "icns\0" "ico\0\0" "rtf\0\0" "pdf\0\0" - "ra\0\0\0""rm\0\0\0""au\0\0\0""au\0\0\0""iff\0\0" "riff\0" "psd\0\0" "mpeg\0" - "mpeg\0" "mid\0\0" "zip\0\0" "sit\0\0" "sit\0\0" "sit\0\0" "sit\0\0" "sit\0\0" - "cpio\0" "html\0" "ps\0\0\0""ole\0\0" "uu\0\0\0""dmg\0\0" "wmv\0\0" "jp2\0\0" - "doc\0\0" "xls\0\0" "xls\0\0" "ogg\0\0" "flac\0" "ttf\0\0" "ttf\0\0" "otf\0\0" - "dwg\0\0" "dgn\0\0" "dgn\0\0" "wrl\0\0" "xcf\0\0" "cpx\0\0" "dwf\0\0" "bom\0\0"; - -#define NUM_EXTENSIONS 56 -#define EXTENSION_LENGTH 5 -#define MAGIC_BYTES_TO_READ 512 + "mach\0" "mach\0" "mach\0" "mach\0" "mach\0" "mach\0" "pef\0\0" "pef\0\0" + "elf\0\0" "jpeg\0" "tiff\0" "tiff\0" "gif\0\0" "png\0\0" "icns\0" "ico\0\0" + "rtf\0\0" "pdf\0\0" "ra\0\0\0""rm\0\0\0""au\0\0\0""au\0\0\0""iff\0\0" "riff\0" + "psd\0\0" "mpeg\0" "mpeg\0" "mid\0\0" "zip\0\0" "sit\0\0" "sit\0\0" "sit\0\0" + "sit\0\0" "sit\0\0" "cpio\0" "html\0" "ps\0\0\0""ole\0\0" "uu\0\0\0""ync\0\0" + "dmg\0\0" "wmv\0\0" "jp2\0\0" "doc\0\0" "xls\0\0" "xls\0\0" "ogg\0\0" "flac\0" + "ttf\0\0" "ttf\0\0" "otf\0\0" "dwg\0\0" "dgn\0\0" "dgn\0\0" "wrl\0\0" "xcf\0\0" + "cpx\0\0" "dwf\0\0" "bom\0\0" "lit\0\0" "rtfd\0"; + +static const char * __CFBundleOOExtensionsArray = "sxc\0\0" "sxd\0\0" "sxg\0\0" "sxi\0\0" "sxm\0\0" "sxw\0\0"; +static const char * __CFBundleODExtensionsArray = "odc\0\0" "odf\0\0" "odg\0\0" "oth\0\0" "odi\0\0" "odm\0\0" "odp\0\0" "ods\0\0" "odt\0\0"; + +#define EXTENSION_LENGTH 5 +#define NUM_EXTENSIONS 61 +#define MAGIC_BYTES_TO_READ 512 +#define DMG_BYTES_TO_READ 512 +#define ZIP_BYTES_TO_READ 1024 +#define OLE_BYTES_TO_READ 512 +#define X11_BYTES_TO_READ 4096 +#define IMAGE_INFO_BYTES_TO_READ 4096 #if defined(BINARY_SUPPORT_DYLD) @@ -1712,32 +1695,96 @@ CF_INLINE uint32_t _CFBundleSwapInt64Conditional(uint64_t arg, Boolean swap) {re static CFDictionaryRef _CFBundleGrokInfoDictFromData(const char *bytes, uint32_t length) { CFMutableDictionaryRef result = NULL; CFDataRef infoData = NULL; - if (NULL != bytes && 0 < length) { - infoData = CFDataCreateWithBytesNoCopy(NULL, bytes, length, kCFAllocatorNull); + if (bytes && 0 < length) { + infoData = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (uint8_t *)bytes, length, kCFAllocatorNull); if (infoData) { - -__CFSetNastyFile(CFSTR("")); - - result = (CFMutableDictionaryRef)CFPropertyListCreateFromXMLData(NULL, infoData, kCFPropertyListMutableContainers, NULL); + result = (CFMutableDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, infoData, kCFPropertyListMutableContainers, NULL); if (result && CFDictionaryGetTypeID() != CFGetTypeID(result)) { CFRelease(result); result = NULL; } CFRelease(infoData); } - if (!result) { - result = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - } + if (!result) result = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } return result; } static CFDictionaryRef _CFBundleGrokInfoDictFromMainExecutable() { unsigned long length = 0; - char *bytes = getsectdata(PLIST_SEGMENT, PLIST_SECTION, &length); + char *bytes = getsectdata(TEXT_SEGMENT, PLIST_SECTION, &length); return _CFBundleGrokInfoDictFromData(bytes, length); } +static Boolean _CFBundleGrokObjCImageInfoFromMainExecutable(uint32_t *objcVersion, uint32_t *objcFlags) { + Boolean retval = false; + uint32_t localVersion = 0, localFlags = 0; + if (getsegbyname(OBJC_SEGMENT)) { + unsigned long length = 0; + char *bytes = getsectdata(OBJC_SEGMENT, IMAGE_INFO_SECTION, &length); + if (bytes && length >= 8) { + localVersion = *(uint32_t *)bytes; + localFlags = *(uint32_t *)(bytes + 4); + } + retval = true; + } + if (objcVersion) *objcVersion = localVersion; + if (objcFlags) *objcFlags = localFlags; + return retval; +} + +static Boolean _CFBundleGrokX11FromFile(int fd, const void *bytes, CFIndex length, uint32_t offset, Boolean swapped, Boolean sixtyFour) { + static const char libX11name[] = LIB_X11; + char *buffer = NULL; + const char *loc = NULL; + unsigned i; + Boolean result = false; + + if (fd >= 0 && lseek(fd, offset, SEEK_SET) == (off_t)offset) { + buffer = malloc(X11_BYTES_TO_READ); + if (buffer && read(fd, buffer, X11_BYTES_TO_READ) >= X11_BYTES_TO_READ) loc = buffer; + } else if (bytes && length >= offset + X11_BYTES_TO_READ) { + loc = bytes + offset; + } + if (loc) { + if (sixtyFour) { + uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)loc)->ncmds, swapped); + uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)loc)->sizeofcmds, swapped); + const char *startofcmds = loc + sizeof(struct mach_header_64); + const char *endofcmds = startofcmds + sizeofcmds; + struct dylib_command *dlp = (struct dylib_command *)startofcmds; + if (endofcmds > loc + X11_BYTES_TO_READ) endofcmds = loc + X11_BYTES_TO_READ; + for (i = 0; !result && i < ncmds && startofcmds <= (char *)dlp && (char *)dlp < endofcmds; i++) { + if (LC_LOAD_DYLIB == _CFBundleSwapInt32Conditional(dlp->cmd, swapped)) { + uint32_t nameoffset = _CFBundleSwapInt32Conditional(dlp->dylib.name.offset, swapped); + const char *name = (const char *)dlp + nameoffset; + if (startofcmds <= name && name + sizeof(libX11name) <= endofcmds && 0 == strncmp(name, libX11name, sizeof(libX11name) - 1)) result = true; + } + dlp = (struct dylib_command *)((char *)dlp + _CFBundleSwapInt32Conditional(dlp->cmdsize, swapped)); + } + } else { + uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header *)loc)->ncmds, swapped); + uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header *)loc)->sizeofcmds, swapped); + const char *startofcmds = loc + sizeof(struct mach_header); + const char *endofcmds = startofcmds + sizeofcmds; + struct dylib_command *dlp = (struct dylib_command *)startofcmds; + if (endofcmds > loc + X11_BYTES_TO_READ) endofcmds = loc + X11_BYTES_TO_READ; + for (i = 0; !result && i < ncmds && startofcmds <= (char *)dlp && (char *)dlp < endofcmds; i++) { + if (LC_LOAD_DYLIB == _CFBundleSwapInt32Conditional(dlp->cmd, swapped)) { + uint32_t nameoffset = _CFBundleSwapInt32Conditional(dlp->dylib.name.offset, swapped); + const char *name = (const char *)dlp + nameoffset; + if (startofcmds <= name && name + sizeof(libX11name) <= endofcmds && 0 == strncmp(name, libX11name, sizeof(libX11name) - 1)) result = true; + } + dlp = (struct dylib_command *)((char *)dlp + _CFBundleSwapInt32Conditional(dlp->cmdsize, swapped)); + } + } + } + + if (buffer) free(buffer); + + return result; +} + static CFDictionaryRef _CFBundleGrokInfoDictFromFile(int fd, const void *bytes, CFIndex length, uint32_t offset, Boolean swapped, Boolean sixtyFour) { struct stat statBuf; off_t fileLength = 0; @@ -1762,11 +1809,11 @@ static CFDictionaryRef _CFBundleGrokInfoDictFromFile(int fd, const void *bytes, struct segment_command_64 *sgp = (struct segment_command_64 *)startofcmds; if (endofcmds > loc + fileLength) endofcmds = loc + fileLength; for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) { - if (LC_SEGMENT == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) { + if (LC_SEGMENT_64 == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) { struct section_64 *sp = (struct section_64 *)((char *)sgp + sizeof(struct segment_command_64)); uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped); for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) { - if (0 == strncmp(sp->sectname, PLIST_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, PLIST_SEGMENT, sizeof(sp->segname))) { + if (0 == strncmp(sp->sectname, PLIST_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, TEXT_SEGMENT, sizeof(sp->segname))) { uint64_t sectlength64 = _CFBundleSwapInt64Conditional(sp->size, swapped); uint32_t sectlength = (uint32_t)(sectlength64 & 0xffffffff); uint32_t sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped); @@ -1792,7 +1839,7 @@ static CFDictionaryRef _CFBundleGrokInfoDictFromFile(int fd, const void *bytes, struct section *sp = (struct section *)((char *)sgp + sizeof(struct segment_command)); uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped); for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) { - if (0 == strncmp(sp->sectname, PLIST_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, PLIST_SEGMENT, sizeof(sp->segname))) { + if (0 == strncmp(sp->sectname, PLIST_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, TEXT_SEGMENT, sizeof(sp->segname))) { uint32_t sectlength = _CFBundleSwapInt32Conditional(sp->size, swapped); uint32_t sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped); const char *sectbytes = loc + offset + sectoffset; @@ -1810,172 +1857,364 @@ static CFDictionaryRef _CFBundleGrokInfoDictFromFile(int fd, const void *bytes, return result; } -static Boolean _CFBundleGrokX11(int fd, const void *bytes, CFIndex length, uint32_t offset, Boolean swapped, Boolean sixtyFour) { - static const char libX11name[] = LIB_X11; - struct stat statBuf; - off_t fileLength = 0; - char *maploc = NULL; - const char *loc; - unsigned i; - Boolean result = false; - if (fd >= 0 && fstat(fd, &statBuf) == 0 && (maploc = mmap(0, statBuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) != (void *)-1) { - loc = maploc; - fileLength = statBuf.st_size; - } else { - loc = bytes; - fileLength = length; +static void _CFBundleGrokObjcImageInfoFromFile(int fd, const void *bytes, CFIndex length, uint32_t offset, Boolean swapped, Boolean sixtyFour, Boolean *hasObjc, uint32_t *objcVersion, uint32_t *objcFlags) { + uint32_t sectlength = 0, sectoffset = 0, localVersion = 0, localFlags = 0; + char *buffer = NULL; + char sectbuffer[8]; + const char *loc = NULL; + unsigned i, j; + Boolean foundit = false, localHasObjc = false; + + if (fd >= 0 && lseek(fd, offset, SEEK_SET) == (off_t)offset) { + buffer = malloc(IMAGE_INFO_BYTES_TO_READ); + if (buffer && read(fd, buffer, IMAGE_INFO_BYTES_TO_READ) >= IMAGE_INFO_BYTES_TO_READ) loc = buffer; + } else if (bytes && length >= offset + IMAGE_INFO_BYTES_TO_READ) { + loc = bytes + offset; } - if (fileLength > offset + sizeof(struct mach_header_64)) { + if (loc) { if (sixtyFour) { - uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)(loc + offset))->ncmds, swapped); - uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)(loc + offset))->sizeofcmds, swapped); - const char *startofcmds = loc + offset + sizeof(struct mach_header_64); + uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)loc)->ncmds, swapped); + uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header_64 *)loc)->sizeofcmds, swapped); + const char *startofcmds = loc + sizeof(struct mach_header_64); const char *endofcmds = startofcmds + sizeofcmds; - struct dylib_command *dlp = (struct dylib_command *)startofcmds; - if (endofcmds > loc + fileLength) endofcmds = loc + fileLength; - for (i = 0; !result && i < ncmds && startofcmds <= (char *)dlp && (char *)dlp < endofcmds; i++) { - if (LC_LOAD_DYLIB == _CFBundleSwapInt32Conditional(dlp->cmd, swapped)) { - uint32_t nameoffset = _CFBundleSwapInt32Conditional(dlp->dylib.name.offset, swapped); - if (0 == strncmp((char *)dlp + nameoffset, libX11name, sizeof(libX11name) - 1)) result = true; + struct segment_command_64 *sgp = (struct segment_command_64 *)startofcmds; + if (endofcmds > loc + IMAGE_INFO_BYTES_TO_READ) endofcmds = loc + IMAGE_INFO_BYTES_TO_READ; + for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) { + if (LC_SEGMENT_64 == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) { + struct section_64 *sp = (struct section_64 *)((char *)sgp + sizeof(struct segment_command_64)); + uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped); + for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) { + if (0 == strncmp(sp->segname, OBJC_SEGMENT, sizeof(sp->segname))) localHasObjc = true; + if (0 == strncmp(sp->sectname, IMAGE_INFO_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, OBJC_SEGMENT, sizeof(sp->segname))) { + uint64_t sectlength64 = _CFBundleSwapInt64Conditional(sp->size, swapped); + sectlength = (uint32_t)(sectlength64 & 0xffffffff); + sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped); + foundit = true; + } + sp = (struct section_64 *)((char *)sp + sizeof(struct section_64)); + } } - dlp = (struct dylib_command *)((char *)dlp + _CFBundleSwapInt32Conditional(dlp->cmdsize, swapped)); + sgp = (struct segment_command_64 *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped)); } } else { - uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header *)(loc + offset))->ncmds, swapped); - uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header *)(loc + offset))->sizeofcmds, swapped); - const char *startofcmds = loc + offset + sizeof(struct mach_header); + uint32_t ncmds = _CFBundleSwapInt32Conditional(((struct mach_header *)loc)->ncmds, swapped); + uint32_t sizeofcmds = _CFBundleSwapInt32Conditional(((struct mach_header *)loc)->sizeofcmds, swapped); + const char *startofcmds = loc + sizeof(struct mach_header); const char *endofcmds = startofcmds + sizeofcmds; - struct dylib_command *dlp = (struct dylib_command *)startofcmds; - if (endofcmds > loc + fileLength) endofcmds = loc + fileLength; - for (i = 0; !result && i < ncmds && startofcmds <= (char *)dlp && (char *)dlp < endofcmds; i++) { - if (LC_LOAD_DYLIB == _CFBundleSwapInt32Conditional(dlp->cmd, swapped)) { - uint32_t nameoffset = _CFBundleSwapInt32Conditional(dlp->dylib.name.offset, swapped); - if (0 == strncmp((char *)dlp + nameoffset, libX11name, sizeof(libX11name) - 1)) result = true; + struct segment_command *sgp = (struct segment_command *)startofcmds; + if (endofcmds > loc + IMAGE_INFO_BYTES_TO_READ) endofcmds = loc + IMAGE_INFO_BYTES_TO_READ; + for (i = 0; !foundit && i < ncmds && startofcmds <= (char *)sgp && (char *)sgp < endofcmds; i++) { + if (LC_SEGMENT == _CFBundleSwapInt32Conditional(sgp->cmd, swapped)) { + struct section *sp = (struct section *)((char *)sgp + sizeof(struct segment_command)); + uint32_t nsects = _CFBundleSwapInt32Conditional(sgp->nsects, swapped); + for (j = 0; !foundit && j < nsects && startofcmds <= (char *)sp && (char *)sp < endofcmds; j++) { + if (0 == strncmp(sp->segname, OBJC_SEGMENT, sizeof(sp->segname))) localHasObjc = true; + if (0 == strncmp(sp->sectname, IMAGE_INFO_SECTION, sizeof(sp->sectname)) && 0 == strncmp(sp->segname, OBJC_SEGMENT, sizeof(sp->segname))) { + sectlength = _CFBundleSwapInt32Conditional(sp->size, swapped); + sectoffset = _CFBundleSwapInt32Conditional(sp->offset, swapped); + foundit = true; + } + sp = (struct section *)((char *)sp + sizeof(struct section)); + } } - dlp = (struct dylib_command *)((char *)dlp + _CFBundleSwapInt32Conditional(dlp->cmdsize, swapped)); + sgp = (struct segment_command *)((char *)sgp + _CFBundleSwapInt32Conditional(sgp->cmdsize, swapped)); + } + } + if (sectlength >= 8) { + if (fd >= 0 && lseek(fd, offset + sectoffset, SEEK_SET) == (off_t)(offset + sectoffset) && read(fd, sectbuffer, 8) >= 8) { + localVersion = _CFBundleSwapInt32Conditional(*(uint32_t *)sectbuffer, swapped); + localFlags = _CFBundleSwapInt32Conditional(*(uint32_t *)(sectbuffer + 4), swapped); + } else if (bytes && length >= offset + sectoffset + 8) { + localVersion = _CFBundleSwapInt32Conditional(*(uint32_t *)(bytes + offset + sectoffset), swapped); + localFlags = _CFBundleSwapInt32Conditional(*(uint32_t *)(bytes + offset + sectoffset + 4), swapped); } } } - if (maploc) munmap(maploc, statBuf.st_size); - return result; + + if (buffer) free(buffer); + + if (hasObjc) *hasObjc = localHasObjc; + if (objcVersion) *objcVersion = localVersion; + if (objcFlags) *objcFlags = localFlags; } -static UInt32 _CFBundleGrokMachTypeForFatFile(int fd, const void *bytes, CFIndex length, Boolean *isX11, CFDictionaryRef *infodict) { - UInt32 machtype = UNKNOWN_FILETYPE, magic, numFatHeaders = ((struct fat_header *)bytes)->nfat_arch, maxFatHeaders = (length - sizeof(struct fat_header)) / sizeof(struct fat_arch); +static UInt32 _CFBundleGrokMachTypeForFatFile(int fd, const void *bytes, CFIndex length, Boolean *isX11, CFArrayRef *architectures, CFDictionaryRef *infodict, Boolean *hasObjc, uint32_t *objcVersion, uint32_t *objcFlags) { + UInt32 machtype = UNKNOWN_FILETYPE, magic, numFatHeaders = ((struct fat_header *)bytes)->nfat_arch, maxFatHeaders = (length - sizeof(struct fat_header)) / sizeof(struct fat_arch), i; unsigned char buffer[sizeof(struct mach_header_64)]; const unsigned char *moreBytes = NULL; const NXArchInfo *archInfo = NXGetLocalArchInfo(); struct fat_arch *fat = NULL; if (isX11) *isX11 = false; + if (architectures) *architectures = NULL; if (infodict) *infodict = NULL; + if (hasObjc) *hasObjc = false; + if (objcVersion) *objcVersion = 0; + if (objcFlags) *objcFlags = 0; if (numFatHeaders > maxFatHeaders) numFatHeaders = maxFatHeaders; if (numFatHeaders > 0) { fat = NXFindBestFatArch(archInfo->cputype, archInfo->cpusubtype, (struct fat_arch *)(bytes + sizeof(struct fat_header)), numFatHeaders); if (!fat) fat = (struct fat_arch *)(bytes + sizeof(struct fat_header)); + if (architectures) { + CFMutableArrayRef mutableArchitectures = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + for (i = 0; i < numFatHeaders; i++) { + CFNumberRef architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, bytes + sizeof(struct fat_header) + i * sizeof(struct fat_arch)); + if (CFArrayGetFirstIndexOfValue(mutableArchitectures, CFRangeMake(0, CFArrayGetCount(mutableArchitectures)), architecture) < 0) CFArrayAppendValue(mutableArchitectures, architecture); + CFRelease(architecture); + } + *architectures = (CFArrayRef)mutableArchitectures; + } } if (fat) { - if (fd >= 0 && lseek(fd, fat->offset, SEEK_SET) == (off_t)fat->offset && read(fd, buffer, sizeof(buffer)) >= (int)sizeof(buffer)) { + if (fd >= 0 && lseek(fd, fat->offset, SEEK_SET) == (off_t)fat->offset && read(fd, buffer, sizeof(struct mach_header_64)) >= (int)sizeof(struct mach_header_64)) { moreBytes = buffer; - } else if (bytes && (uint32_t)length >= fat->offset + 512) { + } else if (bytes && (uint32_t)length >= fat->offset + sizeof(struct mach_header_64)) { moreBytes = bytes + fat->offset; } if (moreBytes) { magic = *((UInt32 *)moreBytes); if (MH_MAGIC == magic) { machtype = ((struct mach_header *)moreBytes)->filetype; + if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, fat->offset, false, false); if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, fat->offset, false, false); - if (isX11) *isX11 = _CFBundleGrokX11(fd, bytes, length, fat->offset, false, false); + if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, fat->offset, false, false, hasObjc, objcVersion, objcFlags); } else if (MH_CIGAM == magic) { machtype = CFSwapInt32(((struct mach_header *)moreBytes)->filetype); + if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, fat->offset, true, false); if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, fat->offset, true, false); - if (isX11) *isX11 = _CFBundleGrokX11(fd, bytes, length, fat->offset, true, false); + if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, fat->offset, true, false, hasObjc, objcVersion, objcFlags); } else if (MH_MAGIC_64 == magic) { machtype = ((struct mach_header_64 *)moreBytes)->filetype; + if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, fat->offset, false, true); if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, fat->offset, false, true); - if (isX11) *isX11 = _CFBundleGrokX11(fd, bytes, length, fat->offset, false, true); + if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, fat->offset, false, true, hasObjc, objcVersion, objcFlags); } else if (MH_CIGAM_64 == magic) { machtype = CFSwapInt32(((struct mach_header_64 *)moreBytes)->filetype); + if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, fat->offset, true, true); if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, fat->offset, true, true); - if (isX11) *isX11 = _CFBundleGrokX11(fd, bytes, length, fat->offset, true, true); + if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, fat->offset, true, true, hasObjc, objcVersion, objcFlags); } } } return machtype; } -static UInt32 _CFBundleGrokMachType(int fd, const void *bytes, CFIndex length, Boolean *isX11, CFDictionaryRef *infodict) { +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; + CFNumberRef architecture = NULL; CFIndex i; if (isX11) *isX11 = false; + if (architectures) *architectures = NULL; if (infodict) *infodict = NULL; + if (hasObjc) *hasObjc = false; + if (objcVersion) *objcVersion = 0; + if (objcFlags) *objcFlags = 0; if (MH_MAGIC == magic) { machtype = ((struct mach_header *)bytes)->filetype; + if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, 0, false, false); + if (architectures) architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, bytes + 4); if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, 0, false, false); - if (isX11) *isX11 = _CFBundleGrokX11(fd, bytes, length, 0, false, false); + if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, 0, false, false, hasObjc, objcVersion, objcFlags); } else if (MH_CIGAM == magic) { for (i = 0; i < length; i += 4) *(UInt32 *)(bytes + i) = CFSwapInt32(*(UInt32 *)(bytes + i)); machtype = ((struct mach_header *)bytes)->filetype; + if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, 0, true, false); + if (architectures) architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, bytes + 4); if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, 0, true, false); - if (isX11) *isX11 = _CFBundleGrokX11(fd, bytes, length, 0, true, false); + if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, 0, true, false, hasObjc, objcVersion, objcFlags); } else if (MH_MAGIC_64 == magic) { machtype = ((struct mach_header_64 *)bytes)->filetype; + if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, 0, false, true); + if (architectures) architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, bytes + 4); if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, 0, false, true); - if (isX11) *isX11 = _CFBundleGrokX11(fd, bytes, length, 0, false, true); + if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, 0, false, true, hasObjc, objcVersion, objcFlags); } else if (MH_CIGAM_64 == magic) { for (i = 0; i < length; i += 4) *(UInt32 *)(bytes + i) = CFSwapInt32(*(UInt32 *)(bytes + i)); machtype = ((struct mach_header_64 *)bytes)->filetype; + if (isX11 && MH_EXECUTE == machtype) *isX11 = _CFBundleGrokX11FromFile(fd, bytes, length, 0, true, true); + if (architectures) architecture = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt32Type, bytes + 4); if (infodict) *infodict = _CFBundleGrokInfoDictFromFile(fd, bytes, length, 0, true, true); - if (isX11) *isX11 = _CFBundleGrokX11(fd, bytes, length, 0, true, true); + if (hasObjc || objcVersion || objcFlags) _CFBundleGrokObjcImageInfoFromFile(fd, bytes, length, 0, true, true, hasObjc, objcVersion, objcFlags); } else if (FAT_MAGIC == magic) { - machtype = _CFBundleGrokMachTypeForFatFile(fd, bytes, length, isX11, infodict); + machtype = _CFBundleGrokMachTypeForFatFile(fd, bytes, length, isX11, architectures, infodict, hasObjc, objcVersion, objcFlags); } else if (FAT_CIGAM == magic) { for (i = 0; i < length; i += 4) *(UInt32 *)(bytes + i) = CFSwapInt32(*(UInt32 *)(bytes + i)); - machtype = _CFBundleGrokMachTypeForFatFile(fd, bytes, length, isX11, infodict); + machtype = _CFBundleGrokMachTypeForFatFile(fd, bytes, length, isX11, architectures, infodict, hasObjc, objcVersion, objcFlags); } else if (PEF_MAGIC == magic || PEF_CIGAM == magic) { machtype = PEF_FILETYPE; } + if (architectures && architecture) *architectures = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&architecture, 1, &kCFTypeArrayCallBacks); + if (architecture) CFRelease(architecture); return machtype; } #endif /* BINARY_SUPPORT_DYLD */ -static UInt32 _CFBundleGrokFileTypeForOLEFile(int fd, const void *bytes, CFIndex length, off_t offset) { - UInt32 filetype = UNKNOWN_FILETYPE; - static const unsigned char xlsname[] = XLS_NAME, xlsname2[] = XLS_NAME2, docname[] = DOC_NAME, pptname[] = PPT_NAME; +static Boolean _CFBundleGrokFileTypeForZipMimeType(const unsigned char *bytes, CFIndex length, const char **ext) { + unsigned namelength = CFSwapInt16HostToLittle(*((UInt16 *)(bytes + 26))), extralength = CFSwapInt16HostToLittle(*((UInt16 *)(bytes + 28))); + const unsigned char *data = bytes + 30 + namelength + extralength; + int i = -1; + if (bytes < data && data + 56 <= bytes + length && 0 == CFSwapInt16HostToLittle(*((UInt16 *)(bytes + 8))) && (0 == ustrncasecmp(data, "application/vnd.", 16) || 0 == ustrncasecmp(data, "application/x-vnd.", 18))) { + data += ('.' == *(data + 15)) ? 16 : 18; + if (0 == ustrncasecmp(data, "sun.xml.", 8)) { + data += 8; + if (0 == ustrncasecmp(data, "calc", 4)) i = 0; + else if (0 == ustrncasecmp(data, "draw", 4)) i = 1; + else if (0 == ustrncasecmp(data, "writer.global", 13)) i = 2; + else if (0 == ustrncasecmp(data, "impress", 7)) i = 3; + else if (0 == ustrncasecmp(data, "math", 4)) i = 4; + else if (0 == ustrncasecmp(data, "writer", 6)) i = 5; + if (i >= 0 && ext) *ext = __CFBundleOOExtensionsArray + i * EXTENSION_LENGTH; + } else if (0 == ustrncasecmp(data, "oasis.opendocument.", 19)) { + data += 19; + if (0 == ustrncasecmp(data, "chart", 5)) i = 0; + else if (0 == ustrncasecmp(data, "formula", 7)) i = 1; + else if (0 == ustrncasecmp(data, "graphics", 8)) i = 2; + else if (0 == ustrncasecmp(data, "text-web", 8)) i = 3; + else if (0 == ustrncasecmp(data, "image", 5)) i = 4; + else if (0 == ustrncasecmp(data, "text-master", 11)) i = 5; + else if (0 == ustrncasecmp(data, "presentation", 12)) i = 6; + else if (0 == ustrncasecmp(data, "spreadsheet", 11)) i = 7; + else if (0 == ustrncasecmp(data, "text", 4)) i = 8; + if (i >= 0 && ext) *ext = __CFBundleODExtensionsArray + i * EXTENSION_LENGTH; + } + } else if (bytes < data && data + 41 <= bytes + length && 8 == CFSwapInt16HostToLittle(*((UInt16 *)(bytes + 8))) && 0x4b2c28c8 == CFSwapInt32HostToBig(*((UInt32 *)data)) && 0xc94c4e2c == CFSwapInt32HostToBig(*((UInt32 *)(data + 4)))) { + // AbiWord compressed mimetype odt + if (ext) *ext = "odt"; + } + return (i >= 0); +} + +static const char *_CFBundleGrokFileTypeForZipFile(int fd, const unsigned char *bytes, CFIndex length, off_t fileLength) { + const char *ext = "zip"; const unsigned char *moreBytes = NULL; - unsigned char buffer[512]; + unsigned char *buffer = NULL; + CFIndex i; + Boolean foundMimetype = false, hasMetaInf = false, hasContentXML = false, hasManifestMF = false, hasManifestXML = false, hasRels = false, hasContentTypes = false, hasWordDocument = false, hasExcelDocument = false, hasPowerPointDocument = false, hasOPF = false, hasSMIL = false; + + if (bytes) { + for (i = 0; !foundMimetype && i + 30 < length; i++) { + if (0x50 == bytes[i] && 0x4b == bytes[i + 1]) { + unsigned namelength = 0, offset = 0; + if (0x01 == bytes[i + 2] && 0x02 == bytes[i + 3]) { + namelength = (unsigned)CFSwapInt16HostToLittle(*((UInt16 *)(bytes + i + 28))); + offset = 46; + } else if (0x03 == bytes[i + 2] && 0x04 == bytes[i + 3]) { + namelength = (unsigned)CFSwapInt16HostToLittle(*((UInt16 *)(bytes + i + 26))); + offset = 30; + } + if (offset > 0 && (CFIndex)(i + offset + namelength) <= length) { + //printf("%.*s\n", namelength, bytes + i + offset); + if (8 == namelength && 30 == offset && 0 == ustrncasecmp(bytes + i + offset, "mimetype", 8)) foundMimetype = _CFBundleGrokFileTypeForZipMimeType(bytes + i, length - i, &ext); + else if (9 == namelength && 0 == ustrncasecmp(bytes + i + offset, "META-INF/", 9)) hasMetaInf = true; + else if (11 == namelength && 0 == ustrncasecmp(bytes + i + offset, "content.xml", 11)) hasContentXML = true; + else if (11 == namelength && 0 == ustrncasecmp(bytes + i + offset, "_rels/.rels", 11)) hasRels = true; + else if (19 == namelength && 0 == ustrncasecmp(bytes + i + offset, "[Content_Types].xml", 19)) hasContentTypes = true; + else if (20 == namelength && 0 == ustrncasecmp(bytes + i + offset, "META-INF/MANIFEST.MF", 20)) hasManifestMF = true; + else if (21 == namelength && 0 == ustrncasecmp(bytes + i + offset, "META-INF/manifest.xml", 21)) hasManifestXML = true; + 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 (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; + i += offset + namelength - 1; + } + } + } + } + if (!foundMimetype) { + if (fileLength >= ZIP_BYTES_TO_READ) { + if (fd >= 0 && lseek(fd, fileLength - ZIP_BYTES_TO_READ, SEEK_SET) == fileLength - ZIP_BYTES_TO_READ) { + buffer = (unsigned char *)malloc(ZIP_BYTES_TO_READ); + if (buffer && read(fd, buffer, ZIP_BYTES_TO_READ) >= ZIP_BYTES_TO_READ) moreBytes = buffer; + } else if (bytes && length >= ZIP_BYTES_TO_READ) { + moreBytes = bytes + length - ZIP_BYTES_TO_READ; + } + } + if (moreBytes) { + for (i = 0; i + 30 < ZIP_BYTES_TO_READ; i++) { + if (0x50 == moreBytes[i] && 0x4b == moreBytes[i + 1]) { + unsigned namelength = 0, offset = 0; + if (0x01 == moreBytes[i + 2] && 0x02 == moreBytes[i + 3]) { + namelength = CFSwapInt16HostToLittle(*((UInt16 *)(moreBytes + i + 28))); + offset = 46; + } else if (0x03 == moreBytes[i + 2] && 0x04 == moreBytes[i + 3]) { + namelength = CFSwapInt16HostToLittle(*((UInt16 *)(moreBytes + i + 26))); + offset = 30; + } + if (offset > 0 && i + offset + namelength <= ZIP_BYTES_TO_READ) { + //printf("%.*s\n", namelength, moreBytes + i + offset); + if (9 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "META-INF/", 9)) hasMetaInf = true; + else if (11 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "content.xml", 11)) hasContentXML = true; + else if (11 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "_rels/.rels", 11)) hasRels = true; + else if (19 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "[Content_Types].xml", 19)) hasContentTypes = true; + else if (20 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "META-INF/MANIFEST.MF", 20)) hasManifestMF = true; + else if (21 == namelength && 0 == ustrncasecmp(moreBytes + i + offset, "META-INF/manifest.xml", 21)) hasManifestXML = true; + 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 (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; + i += offset + namelength - 1; + } + } + } + } + //printf("hasManifestMF %d hasManifestXML %d hasContentXML %d hasRels %d hasContentTypes %d hasWordDocument %d hasExcelDocument %d hasPowerPointDocument %d hasMetaInf %d hasOPF %d hasSMIL %d\n", hasManifestMF, hasManifestXML, hasContentXML, hasRels, hasContentTypes, hasWordDocument, hasExcelDocument, hasPowerPointDocument, hasMetaInf, hasOPF, hasSMIL); + if (hasManifestMF) ext = "jar"; + else if ((hasRels || hasContentTypes) && hasWordDocument) ext = "docx"; + else if ((hasRels || hasContentTypes) && hasExcelDocument) ext = "xlsx"; + else if ((hasRels || hasContentTypes) && hasPowerPointDocument) ext = "pptx"; + else if (hasManifestXML || hasContentXML) ext = "odt"; + else if (hasMetaInf) ext = "jar"; + else if (hasOPF && hasSMIL) ext = "dtb"; + else if (hasOPF) ext = "oeb"; + + if (buffer) free(buffer); + } + return ext; +} + +static Boolean _CFBundleCheckOLEName(const char *name, const char *bytes, unsigned length) { + Boolean retval = true; + unsigned j; + for (j = 0; retval && j < length; j++) if (bytes[2 * j] != name[j]) retval = false; + return retval; +} + +static const char *_CFBundleGrokFileTypeForOLEFile(int fd, const void *bytes, CFIndex length, off_t offset) { + const char *ext = "ole", *moreBytes = NULL; + char *buffer = NULL; - if (fd >= 0 && lseek(fd, offset, SEEK_SET) == (off_t)offset && read(fd, buffer, sizeof(buffer)) >= (int)sizeof(buffer)) { - moreBytes = buffer; - } else if (bytes && length >= offset + 512) { - moreBytes = bytes + offset; + if (fd >= 0 && lseek(fd, offset, SEEK_SET) == (off_t)offset) { + buffer = (char *)malloc(OLE_BYTES_TO_READ); + if (buffer && read(fd, buffer, OLE_BYTES_TO_READ) >= OLE_BYTES_TO_READ) moreBytes = buffer; + } else if (bytes && length >= offset + OLE_BYTES_TO_READ) { + moreBytes = (char *)bytes + offset; } if (moreBytes) { - CFIndex i, j; Boolean foundit = false; + unsigned i; for (i = 0; !foundit && i < 4; i++) { char namelength = moreBytes[128 * i + 64] / 2; - if (sizeof(xlsname) == namelength) { - for (j = 0, foundit = true; j + 1 < namelength; j++) if (moreBytes[128 * i + 2 * j] != xlsname[j]) foundit = false; - if (foundit) filetype = XLS_FILETYPE; - } else if (sizeof(xlsname2) == namelength) { - for (j = 0, foundit = true; j + 1 < namelength; j++) if (moreBytes[128 * i + 2 * j] != xlsname2[j]) foundit = false; - if (foundit) filetype = XLS_FILETYPE; - } else if (sizeof(docname) == namelength) { - for (j = 0, foundit = true; j + 1 < namelength; j++) if (moreBytes[128 * i + 2 * j] != docname[j]) foundit = false; - if (foundit) filetype = DOC_FILETYPE; - } else if (sizeof(pptname) == namelength) { - for (j = 0, foundit = true; j + 1 < namelength; j++) if (moreBytes[128 * i + 2 * j] != pptname[j]) foundit = false; - if (foundit) filetype = PPT_FILETYPE; - } + foundit = true; + if (sizeof(XLS_NAME) == namelength && _CFBundleCheckOLEName(XLS_NAME, moreBytes + 128 * i, namelength - 1)) ext = "xls"; + else if (sizeof(XLS_NAME2) == namelength && _CFBundleCheckOLEName(XLS_NAME2, moreBytes + 128 * i, namelength - 1)) ext = "xls"; + else if (sizeof(DOC_NAME) == namelength && _CFBundleCheckOLEName(DOC_NAME, moreBytes + 128 * i, namelength - 1)) ext = "doc"; + else if (sizeof(PPT_NAME) == namelength && _CFBundleCheckOLEName(PPT_NAME, moreBytes + 128 * i, namelength - 1)) ext = "ppt"; + else foundit = false; } } - return filetype; + + if (buffer) free(buffer); + + return ext; } -static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef *extension, UInt32 *machtype, CFDictionaryRef *infodict) { +static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef *extension, UInt32 *machtype, CFArrayRef *architectures, CFDictionaryRef *infodict, Boolean *hasObjc, uint32_t *objcVersion, uint32_t *objcFlags) { struct stat statBuf; int fd = -1; char path[CFMaxPathSize]; @@ -1989,17 +2228,16 @@ static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef * Boolean isX11 = false; #endif /* BINARY_SUPPORT_DYLD */ Boolean isFile = false, isPlain = true, isZero = true, isHTML = false; - // extensions returned: o, tool, x11app, pef, core, dylib, bundle, elf, jpeg, jp2, tiff, gif, png, pict, icns, ico, rtf, pdf, ra, rm, au, aiff, aifc, wav, avi, wmv, ogg, flac, psd, mpeg, mid, zip, jar, sit, cpio, html, ps, mov, qtif, ttf, otf, sfont, bmp, hqx, bin, class, tar, txt, gz, Z, uu, bz, bz2, sh, pl, py, rb, dvi, sgi, tga, mp3, xml, plist, xls, doc, ppt, mp4, m4a, m4b, m4p, dmg, cwk, webarchive, dwg, dgn, pfa, pfb, afm, tfm, xcf, cpx, dwf, swf, swc, abw, bom + // extensions returned: o, tool, x11app, pef, core, dylib, bundle, elf, jpeg, jp2, tiff, gif, png, pict, icns, ico, rtf, rtfd, pdf, ra, rm, au, aiff, aifc, wav, avi, wmv, ogg, flac, psd, mpeg, mid, zip, jar, sit, cpio, html, ps, mov, qtif, ttf, otf, sfont, bmp, hqx, bin, class, tar, txt, gz, Z, uu, ync, bz, bz2, sh, pl, py, rb, dvi, sgi, tga, mp3, xml, plist, xls, doc, ppt, mp4, m4a, m4b, m4p, dmg, cwk, webarchive, dwg, dgn, pfa, pfb, afm, tfm, xcf, cpx, dwf, swf, swc, abw, bom, lit, svg, rdf, x3d, oeb, dtb, docx, xlsx, pptx, sxc, sxd, sxg, sxi, sxm, sxw, odc, odf, odg, oth, odi, odm, odp, ods // ??? we do not distinguish between different wm types, returning wmv for any of wmv, wma, or asf - if (url && CFURLGetFileSystemRepresentation(url, true, path, CFMaxPathSize) && stat(path, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFREG && (fd = open(path, O_RDONLY, 0777)) >= 0) { - // cjk: It is not at clear that not caching would be a win here, since - // in most cases the sniffing of the executable is only done lazily, - // the executable is likely to be immediately used again; say, the - // bundle executable loaded. CFBundle does not need the data again, - // but for the system as a whole not caching could be a net win or lose. - // So, this is where the cache disablement would go, but I am not going - // to turn it on at this point. - // fcntl(fd, F_NOCACHE, 1); + // ??? we do not distinguish between ordinary documents and template versions (often there is no difference in file contents) + // ??? the distinctions between docx, xlsx, and pptx may not be entirely reliable + if (architectures) *architectures = NULL; + if (infodict) *infodict = NULL; + if (hasObjc) *hasObjc = false; + if (objcVersion) *objcVersion = 0; + if (objcFlags) *objcFlags = 0; + if (url && CFURLGetFileSystemRepresentation(url, true, (uint8_t *)path, CFMaxPathSize) && stat(path, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFREG && (fd = open(path, O_RDONLY, 0777)) >= 0) { length = read(fd, buffer, MAGIC_BYTES_TO_READ); fileLength = statBuf.st_size; bytes = buffer; @@ -2019,7 +2257,7 @@ static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef * if (ext) { if (0xcafebabe == magic && 8 <= length && 0 != *((UInt16 *)(bytes + 4))) ext = "class"; #if defined(BINARY_SUPPORT_DYLD) - else if ((int)sizeof(struct mach_header_64) <= length) mt = _CFBundleGrokMachType(fd, bytes, length, extension ? &isX11 : NULL, infodict); + else if ((int)sizeof(struct mach_header_64) <= length) mt = _CFBundleGrokMachType(fd, bytes, length, extension ? &isX11 : NULL, architectures, infodict, hasObjc, objcVersion, objcFlags); if (MH_OBJECT == mt) ext = "o"; else if (MH_EXECUTE == mt) ext = isX11 ? "x11app" : "tool"; @@ -2041,8 +2279,11 @@ static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef * else if (0x3026b275 == magic && (8 > length || 0x8e66cf11 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; else if (0x67696d70 == magic && (8 > length || 0x20786366 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; else if (0x424f4d53 == magic && (8 > length || 0x746f7265 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; - else if (0x25215053 == magic && 14 <= length && 0 == strncmp(bytes + 4, "-AdobeFont", 10)) ext = "pfa"; - else if (0x504b0304 == magic && 38 <= length && 0x4d455441 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 30))) && 0x2d494e46 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 34)))) ext = "jar"; + else if (0x49544f4c == magic && (8 > length || 0x49544c53 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; + else if (0x72746664 == magic && (8 > length || 0x00000000 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = NULL; + else if (0x3d796265 == magic && (12 > length || 0x67696e20 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || (0x6c696e65 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8))) && 0x70617274 != CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)))))) ext = NULL; + else if (0x25215053 == magic && 14 <= length && 0 == ustrncmp(bytes + 4, "-AdobeFont", 10)) ext = "pfa"; + else if (0x504b0304 == magic) ext = _CFBundleGrokFileTypeForZipFile(fd, bytes, length, fileLength); else if (0x464f524d == magic) { // IFF ext = NULL; @@ -2061,12 +2302,7 @@ static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef * } } else if (0xd0cf11e0 == magic) { // OLE - if (52 <= length) { - UInt32 ft = _CFBundleGrokFileTypeForOLEFile(fd, bytes, length, 512 * (1 + CFSwapInt32HostToLittle(*((UInt32 *)(bytes + 48))))); - if (XLS_FILETYPE == ft) ext = "xls"; - else if (DOC_FILETYPE == ft) ext = "doc"; - else if (PPT_FILETYPE == ft) ext = "ppt"; - } + if (52 <= length) ext = _CFBundleGrokFileTypeForOLEFile(fd, bytes, length, 512 * (1 + CFSwapInt32HostToLittle(*((UInt32 *)(bytes + 48))))); } else if (0x62656769 == magic) { // uu ext = NULL; @@ -2088,7 +2324,7 @@ static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef * else if (8 <= length && 0x424f424f == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4)))) ext = "cwk"; else if (8 <= length && 0x62706c69 == magic && 0x7374 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 4))) && isdigit(bytes[6]) && isdigit(bytes[7])) { for (i = 8; !ext && i < 128 && i + 16 <= length; i++) { - if (0 == strncmp(bytes + i, "WebMainResource", 15)) ext = "webarchive"; + if (0 == ustrncmp(bytes + i, "WebMainResource", 15)) ext = "webarchive"; } if (!ext) ext = "plist"; } else if (12 <= length && 0x66747970 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4)))) { @@ -2098,7 +2334,7 @@ static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef * else if (0x4d344220 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)))) ext = "m4b"; else if (0x4d345020 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 8)))) ext = "m4p"; } else if (0x424d == shortMagic && 18 <= length && 40 == CFSwapInt32HostToLittle(*((UInt32 *)(bytes + 14)))) ext = "bmp"; - else if (20 <= length && 0 == strncmp(bytes + 6, "%!PS-AdobeFont", 14)) ext = "pfb"; + else if (20 <= length && 0 == ustrncmp(bytes + 6, "%!PS-AdobeFont", 14)) ext = "pfb"; else if (40 <= length && 0x42696e48 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 34))) && 0x6578 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 38)))) ext = "hqx"; else if (128 <= length && 0x6d42494e == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 102)))) ext = "bin"; else if (128 <= length && 0 == bytes[0] && 0 < bytes[1] && bytes[1] < 64 && 0 == bytes[74] && 0 == bytes[82] && 0 == (fileLength % 128)) { @@ -2117,9 +2353,9 @@ static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef * if (endOfLine > 3) { for (i = endOfLine - 1; 0 == lastSlash && i > 1; i--) if ('/' == bytes[i]) lastSlash = i; if (lastSlash > 0) { - if (0 == strncmp(bytes + lastSlash + 1, "perl", 4)) ext = "pl"; - else if (0 == strncmp(bytes + lastSlash + 1, "python", 6)) ext = "py"; - else if (0 == strncmp(bytes + lastSlash + 1, "ruby", 4)) ext = "rb"; + if (0 == ustrncmp(bytes + lastSlash + 1, "perl", 4)) ext = "pl"; + else if (0 == ustrncmp(bytes + lastSlash + 1, "python", 6)) ext = "py"; + else if (0 == ustrncmp(bytes + lastSlash + 1, "ruby", 4)) ext = "rb"; else ext = "sh"; } } @@ -2131,17 +2367,18 @@ static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef * else if (0x425a == shortMagic && 'h' == bytes[2] && isdigit(bytes[3]) && 8 <= length && (0x31415926 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))) || 0x17724538 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + 4))))) ext = "bz2"; else if (0x0011 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 2))) || 0x0012 == CFSwapInt16HostToBig(*((UInt16 *)(bytes + 2)))) ext = "tfm"; else if ('<' == bytes[0] && 14 <= length) { - if (0 == strncasecmp(bytes + 1, "!doctype html", 13) || 0 == strncasecmp(bytes + 1, "head", 4) || 0 == strncasecmp(bytes + 1, "title", 5) || 0 == strncasecmp(bytes + 1, "html", 4)) { + if (0 == ustrncasecmp(bytes + 1, "!doctype html", 13) || 0 == ustrncasecmp(bytes + 1, "head", 4) || 0 == ustrncasecmp(bytes + 1, "title", 5) || 0 == ustrncasecmp(bytes + 1, "html", 4)) { ext = "html"; - } else if (0 == strncasecmp(bytes + 1, "?xml", 4)) { + } else if (0 == ustrncasecmp(bytes + 1, "?xml", 4)) { for (i = 4; !ext && i < 128 && i + 20 <= length; i++) { if ('<' == bytes[i]) { - if (0 == strncasecmp(bytes + i + 1, "abiword", 7)) ext = "abw"; - else if (0 == strncasecmp(bytes + i + 1, "!doctype svg", 12)) ext = "svg"; - else if (0 == strncasecmp(bytes + i + 1, "!doctype x3d", 12)) ext = "x3d"; - else if (0 == strncasecmp(bytes + i + 1, "!doctype html", 13)) ext = "html"; - else if (0 == strncasecmp(bytes + i + 1, "!doctype plist", 14)) ext = "plist"; - else if (0 == strncasecmp(bytes + i + 1, "!doctype posingfont", 19)) ext = "sfont"; + if (0 == ustrncasecmp(bytes + i + 1, "abiword", 7)) ext = "abw"; + else if (0 == ustrncasecmp(bytes + i + 1, "!doctype svg", 12)) ext = "svg"; + else if (0 == ustrncasecmp(bytes + i + 1, "!doctype rdf", 12)) ext = "rdf"; + else if (0 == ustrncasecmp(bytes + i + 1, "!doctype x3d", 12)) ext = "x3d"; + else if (0 == ustrncasecmp(bytes + i + 1, "!doctype html", 13)) ext = "html"; + else if (0 == ustrncasecmp(bytes + i + 1, "!doctype plist", 14)) ext = "plist"; + else if (0 == ustrncasecmp(bytes + i + 1, "!doctype posingfont", 19)) ext = "sfont"; } } if (!ext) ext = "xml"; @@ -2155,12 +2392,12 @@ static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef * char c = bytes[i]; if (0x7f <= c || (0x20 > c && !isspace(c))) isPlain = false; if (0 != c) isZero = false; - if (isPlain && '<' == c && i + 14 <= length && 0 == strncasecmp(bytes + i + 1, "!doctype html", 13)) isHTML = true; + if (isPlain && '<' == c && i + 14 <= length && 0 == ustrncasecmp(bytes + i + 1, "!doctype html", 13)) isHTML = true; } if (isHTML) { ext = "html"; } else if (isPlain) { - if (16 <= length && 0 == strncmp(bytes, "StartFontMetrics", 16)) ext = "afm"; + if (16 <= length && 0 == ustrncmp(bytes, "StartFontMetrics", 16)) ext = "afm"; else ext = "txt"; } else if (isZero && length >= MAGIC_BYTES_TO_READ && fileLength >= 526) { if (isFile) { @@ -2172,48 +2409,59 @@ static Boolean _CFBundleGrokFileType(CFURLRef url, CFDataRef data, CFStringRef * } } } - if (extension && !ext && !isZero && length >= MAGIC_BYTES_TO_READ && fileLength >= 1024) { + if (extension && (!ext || 0 == strcmp(ext, "bz2")) && length >= MAGIC_BYTES_TO_READ && fileLength >= DMG_BYTES_TO_READ) { if (isFile) { - off_t offset = fileLength - 512; - if (lseek(fd, offset, SEEK_SET) == offset && read(fd, buffer, 512) >= 512) { - if (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32 *)buffer)) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32 *)(buffer + 504))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32 *)(buffer + 508))))) ext = "dmg"; + if (lseek(fd, fileLength - DMG_BYTES_TO_READ, SEEK_SET) == fileLength - DMG_BYTES_TO_READ && read(fd, buffer, DMG_BYTES_TO_READ) >= DMG_BYTES_TO_READ) { + if (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32 *)buffer)) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32 *)(buffer + DMG_BYTES_TO_READ - 8))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32 *)(buffer + DMG_BYTES_TO_READ - 4))))) ext = "dmg"; } } else { - if (512 <= length && (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + length - 512))) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + length - 8))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + length - 4)))))) ext = "dmg"; + if (DMG_BYTES_TO_READ <= length && (0x6b6f6c79 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + length - DMG_BYTES_TO_READ))) || (0x63647361 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + length - 8))) && 0x656e6372 == CFSwapInt32HostToBig(*((UInt32 *)(bytes + length - 4)))))) ext = "dmg"; } } } - if (extension) *extension = ext ? CFStringCreateWithCStringNoCopy(NULL, ext, kCFStringEncodingASCII, kCFAllocatorNull) : NULL; + if (extension) *extension = ext ? CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault, ext, kCFStringEncodingUTF8, kCFAllocatorNull) : NULL; if (machtype) *machtype = mt; if (fd >= 0) close(fd); - return (ext != NULL); + return (ext ? true : false); } CFStringRef _CFBundleCopyFileTypeForFileURL(CFURLRef url) { CFStringRef extension = NULL; - (void)_CFBundleGrokFileType(url, NULL, &extension, NULL, NULL); + (void)_CFBundleGrokFileType(url, NULL, &extension, NULL, NULL, NULL, NULL, NULL, NULL); return extension; } CFStringRef _CFBundleCopyFileTypeForFileData(CFDataRef data) { CFStringRef extension = NULL; - (void)_CFBundleGrokFileType(NULL, data, &extension, NULL, NULL); + (void)_CFBundleGrokFileType(NULL, data, &extension, NULL, NULL, NULL, NULL, NULL, NULL); return extension; } __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInExecutable(CFURLRef url) { CFDictionaryRef result = NULL; - (void)_CFBundleGrokFileType(url, NULL, NULL, NULL, &result); + (void)_CFBundleGrokFileType(url, NULL, NULL, NULL, NULL, &result, NULL, NULL, NULL); return result; } +__private_extern__ CFArrayRef _CFBundleCopyArchitecturesForExecutable(CFURLRef url) { + CFArrayRef result = NULL; + (void)_CFBundleGrokFileType(url, NULL, NULL, NULL, &result, NULL, NULL, NULL, NULL); + return result; +} + +static Boolean _CFBundleGetObjCImageInfoForExecutable(CFURLRef url, uint32_t *objcVersion, uint32_t *objcFlags) { + Boolean retval = false; + (void)_CFBundleGrokFileType(url, NULL, NULL, NULL, NULL, NULL, &retval, objcVersion, objcFlags); + return retval; +} + #if defined(BINARY_SUPPORT_DYLD) __private_extern__ __CFPBinaryType _CFBundleGrokBinaryType(CFURLRef executableURL) { // Attempt to grok the type of the binary by looking for DYLD magic numbers. If one of the DYLD magic numbers is found, find out what type of Mach-o file it is. Otherwise, look for the PEF magic numbers to see if it is CFM (if we understand CFM). __CFPBinaryType result = executableURL ? __CFBundleUnreadableBinary : __CFBundleNoBinary; UInt32 machtype = UNKNOWN_FILETYPE; - if (_CFBundleGrokFileType(executableURL, NULL, NULL, &machtype, NULL)) { + if (_CFBundleGrokFileType(executableURL, NULL, NULL, &machtype, NULL, NULL, NULL, NULL, NULL)) { switch (machtype) { case MH_EXECUTE: result = __CFBundleDYLDExecutableBinary; @@ -2246,25 +2494,124 @@ void _CFBundleSetCFMConnectionID(CFBundleRef bundle, void *connectionID) { bundle->_isLoaded = true; } -Boolean CFBundleLoadExecutable(CFBundleRef bundle) { +static CFStringRef _CFBundleCopyLastPathComponent(CFBundleRef bundle) { + CFURLRef bundleURL = CFBundleCopyBundleURL(bundle); + CFStringRef str = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle); + UniChar buff[CFMaxPathSize]; + CFIndex buffLen = CFStringGetLength(str), startOfLastDir = 0; + + CFRelease(bundleURL); + if (buffLen > CFMaxPathSize) buffLen = CFMaxPathSize; + CFStringGetCharacters(str, CFRangeMake(0, buffLen), buff); + CFRelease(str); + if (buffLen > 0) startOfLastDir = _CFStartOfLastPathComponent(buff, buffLen); + return CFStringCreateWithCharacters(kCFAllocatorSystemDefault, &(buff[startOfLastDir]), buffLen - startOfLastDir); +} + +static CFErrorRef _CFBundleCreateErrorDebug(CFAllocatorRef allocator, CFBundleRef bundle, CFIndex code, CFStringRef debugString) { + const void *userInfoKeys[6], *userInfoValues[6]; + CFIndex numKeys = 0; + CFURLRef bundleURL = CFBundleCopyBundleURL(bundle), absoluteURL = CFURLCopyAbsoluteURL(bundleURL), executableURL = CFBundleCopyExecutableURL(bundle); + CFBundleRef bdl = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreFoundation")); + CFStringRef bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE), executablePath = executableURL ? CFURLCopyFileSystemPath(executableURL, PLATFORM_PATH_STYLE) : NULL, descFormat = NULL, desc = NULL, reason = NULL, suggestion = NULL; + CFErrorRef error; + if (bdl) { + CFStringRef name = (CFStringRef)CFBundleGetValueForInfoDictionaryKey(bundle, kCFBundleNameKey); + name = name ? (CFStringRef)CFRetain(name) : _CFBundleCopyLastPathComponent(bundle); + if (CFBundleExecutableNotFoundError == code) { + descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d could not be loaded because its executable could not be located."), "NSFileNoSuchFileError"); + reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-C"), CFSTR("Error"), bdl, CFSTR("The bundle\\U2019s executable could not be located."), "NSFileNoSuchFileError"); + suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr4-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSFileNoSuchFileError"); + } else if (CFBundleExecutableNotLoadableError == code) { + descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d could not be loaded because its executable is not loadable."), "NSExecutableNotLoadableError"); + reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-C"), CFSTR("Error"), bdl, CFSTR("The bundle\\U2019s executable is not loadable."), "NSExecutableNotLoadableError"); + suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3584-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSExecutableNotLoadableError"); + } else if (CFBundleExecutableArchitectureMismatchError == code) { + descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d could not be loaded because it does not contain a version for the current architecture."), "NSExecutableArchitectureMismatchError"); + reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-C"), CFSTR("Error"), bdl, CFSTR("The bundle does not contain a version for the current architecture."), "NSExecutableArchitectureMismatchError"); + suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3585-R"), CFSTR("Error"), bdl, CFSTR("Try installing a universal version of the bundle."), "NSExecutableArchitectureMismatchError"); + } else if (CFBundleExecutableRuntimeMismatchError == code) { + descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d could not be loaded because it is not compatible with the current application."), "NSExecutableRuntimeMismatchError"); + reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-C"), CFSTR("Error"), bdl, CFSTR("The bundle is not compatible with this application."), "NSExecutableRuntimeMismatchError"); + suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3586-R"), CFSTR("Error"), bdl, CFSTR("Try installing a newer version of the bundle."), "NSExecutableRuntimeMismatchError"); + } else if (CFBundleExecutableLoadError == code) { + descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d could not be loaded because it is damaged or missing necessary resources."), "NSExecutableLoadError"); + reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-C"), CFSTR("Error"), bdl, CFSTR("The bundle is damaged or missing necessary resources."), "NSExecutableLoadError"); + suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3587-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSExecutableLoadError"); + } else if (CFBundleExecutableLinkError == code) { + descFormat = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588"), CFSTR("Error"), bdl, CFSTR("The bundle \\U201c%@\\U201d could not be loaded."), "NSExecutableLinkError"); + reason = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-C"), CFSTR("Error"), bdl, CFSTR("The bundle could not be loaded."), "NSExecutableLinkError"); + suggestion = CFCopyLocalizedStringWithDefaultValue(CFSTR("BundleErr3588-R"), CFSTR("Error"), bdl, CFSTR("Try reinstalling the bundle."), "NSExecutableLinkError"); + } + if (descFormat) { + desc = CFStringCreateWithFormat(allocator, NULL, descFormat, name); + CFRelease(descFormat); + } + CFRelease(name); + } + if (bundlePath) { + userInfoKeys[numKeys] = CFSTR("NSBundlePath"); + userInfoValues[numKeys] = bundlePath; + numKeys++; + } + if (executablePath) { + userInfoKeys[numKeys] = CFSTR("NSFilePath"); + userInfoValues[numKeys] = executablePath; + numKeys++; + } + if (desc) { + userInfoKeys[numKeys] = kCFErrorLocalizedDescriptionKey; + userInfoValues[numKeys] = desc; + numKeys++; + } + if (reason) { + userInfoKeys[numKeys] = kCFErrorLocalizedFailureReasonKey; + userInfoValues[numKeys] = reason; + numKeys++; + } + if (suggestion) { + userInfoKeys[numKeys] = kCFErrorLocalizedRecoverySuggestionKey; + userInfoValues[numKeys] = suggestion; + numKeys++; + } + if (debugString) { + userInfoKeys[numKeys] = CFSTR("NSDebugDescription"); + userInfoValues[numKeys] = debugString; + numKeys++; + } + error = CFErrorCreateWithUserInfoKeysAndValues(allocator, kCFErrorDomainCocoa, code, userInfoKeys, userInfoValues, numKeys); + if (bundleURL) CFRelease(bundleURL); + if (absoluteURL) CFRelease(absoluteURL); + if (executableURL) CFRelease(executableURL); + if (bundlePath) CFRelease(bundlePath); + if (executablePath) CFRelease(executablePath); + if (desc) CFRelease(desc); + if (reason) CFRelease(reason); + if (suggestion) CFRelease(suggestion); + return error; +} + +CFErrorRef _CFBundleCreateError(CFAllocatorRef allocator, CFBundleRef bundle, CFIndex code) { + return _CFBundleCreateErrorDebug(allocator, bundle, code, NULL); +} + +Boolean _CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, Boolean forceGlobal, CFErrorRef *error) { Boolean result = false; + CFErrorRef localError = NULL, *subError = (error ? &localError : NULL); CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); - if (!executableURL) { - bundle->_binaryType = __CFBundleNoBinary; - } -#if defined(BINARY_SUPPORT_DYLD) + if (!executableURL) bundle->_binaryType = __CFBundleNoBinary; // make sure we know whether bundle is already loaded or not - if (!bundle->_isLoaded) { - _CFBundleDYLDCheckLoaded(bundle); - } +#if defined(BINARY_SUPPORT_DLFCN) + if (!bundle->_isLoaded && _useDlfcn) _CFBundleDlfcnCheckLoaded(bundle); +#endif /* BINARY_SUPPORT_DLFCN */ +#if defined(BINARY_SUPPORT_DYLD) + if (!bundle->_isLoaded) _CFBundleDYLDCheckLoaded(bundle); // We might need to figure out what it is if (bundle->_binaryType == __CFBundleUnknownBinary) { bundle->_binaryType = _CFBundleGrokBinaryType(executableURL); #if defined(BINARY_SUPPORT_CFM) - if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) { - bundle->_resourceData._executableLacksResourceFork = true; - } + if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true; #endif /* BINARY_SUPPORT_CFM */ } #endif /* BINARY_SUPPORT_DYLD */ @@ -2273,87 +2620,206 @@ Boolean CFBundleLoadExecutable(CFBundleRef bundle) { if (bundle->_isLoaded) { // Remove from the scheduled unload set if we are there. __CFSpinLock(&CFBundleGlobalDataLock); - if (_bundlesToUnload) { - CFSetRemoveValue(_bundlesToUnload, bundle); - } + if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle); __CFSpinUnlock(&CFBundleGlobalDataLock); return true; } // Unload bundles scheduled for unloading - if (!_scheduledBundlesAreUnloading) { - _CFBundleUnloadScheduledBundles(); - } - + if (!_scheduledBundlesAreUnloading) _CFBundleUnloadScheduledBundles(); switch (bundle->_binaryType) { -#if defined(BINARY_SUPPORT_CFM) && defined(__ppc__) +#if defined(BINARY_SUPPORT_CFM) case __CFBundleCFMBinary: case __CFBundleUnreadableBinary: - result = _CFBundleCFMLoad(bundle); + result = _CFBundleCFMLoad(bundle, subError); + break; +#elif defined(BINARY_SUPPORT_DLFCN) + case __CFBundleUnreadableBinary: + result = _CFBundleDlfcnLoadBundle(bundle, forceGlobal, subError); break; -#endif /* BINARY_SUPPORT_CFM && __ppc__ */ +#endif /* BINARY_SUPPORT_CFM */ #if defined(BINARY_SUPPORT_DYLD) case __CFBundleDYLDBundleBinary: - result = _CFBundleDYLDLoadBundle(bundle); +#if defined(BINARY_SUPPORT_DLFCN) + if (_useDlfcn) result = _CFBundleDlfcnLoadBundle(bundle, forceGlobal, subError); else +#endif /* BINARY_SUPPORT_DLFCN */ + result = _CFBundleDYLDLoadBundle(bundle, forceGlobal, subError); break; case __CFBundleDYLDFrameworkBinary: - result = _CFBundleDYLDLoadFramework(bundle); +#if defined(BINARY_SUPPORT_DLFCN) + if (_useDlfcn) result = _CFBundleDlfcnLoadFramework(bundle, subError); else +#endif /* BINARY_SUPPORT_DLFCN */ + result = _CFBundleDYLDLoadFramework(bundle, subError); break; case __CFBundleDYLDExecutableBinary: CFLog(__kCFLogBundle, CFSTR("Attempt to load executable of a type that cannot be dynamically loaded for %@"), bundle); + if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError); break; #endif /* BINARY_SUPPORT_DYLD */ +#if defined(BINARY_SUPPORT_DLFCN) + case __CFBundleUnknownBinary: + case __CFBundleELFBinary: + result = _CFBundleDlfcnLoadBundle(bundle, forceGlobal, subError); + break; +#endif /* BINARY_SUPPORT_DLFCN */ #if defined(BINARY_SUPPORT_DLL) case __CFBundleDLLBinary: - result = _CFBundleDLLLoad(bundle); + result = _CFBundleDLLLoad(bundle, subError); break; #endif /* BINARY_SUPPORT_DLL */ case __CFBundleNoBinary: CFLog(__kCFLogBundle, CFSTR("Cannot find executable for %@"), bundle); + if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError); break; default: CFLog(__kCFLogBundle, CFSTR("Cannot recognize type of executable for %@"), bundle); + if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError); break; } if (result && bundle->_plugInData._isPlugIn) _CFBundlePlugInLoaded(bundle); - + + if (!result && error) *error = localError; return result; } -void CFBundleUnloadExecutable(CFBundleRef bundle) { +Boolean CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, CFErrorRef *error) { + return _CFBundleLoadExecutableAndReturnError(bundle, false, error); +} - if (!_scheduledBundlesAreUnloading) { - // First unload bundles scheduled for unloading (if that's not what we are already doing.) - _CFBundleUnloadScheduledBundles(); +Boolean CFBundleLoadExecutable(CFBundleRef bundle) { + return _CFBundleLoadExecutableAndReturnError(bundle, false, NULL); +} + +Boolean CFBundlePreflightExecutable(CFBundleRef bundle, CFErrorRef *error) { + Boolean result = false; + CFErrorRef localError = NULL, *subError = (error ? &localError : NULL); + CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); + + if (!executableURL) bundle->_binaryType = __CFBundleNoBinary; + // make sure we know whether bundle is already loaded or not +#if defined(BINARY_SUPPORT_DLFCN) + if (!bundle->_isLoaded && _useDlfcn) _CFBundleDlfcnCheckLoaded(bundle); +#endif /* BINARY_SUPPORT_DLFCN */ +#if defined(BINARY_SUPPORT_DYLD) + if (!bundle->_isLoaded) _CFBundleDYLDCheckLoaded(bundle); + // We might need to figure out what it is + if (bundle->_binaryType == __CFBundleUnknownBinary) { + bundle->_binaryType = _CFBundleGrokBinaryType(executableURL); +#if defined(BINARY_SUPPORT_CFM) + if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true; +#endif /* BINARY_SUPPORT_CFM */ } +#endif /* BINARY_SUPPORT_DYLD */ + if (executableURL) CFRelease(executableURL); - if (!bundle->_isLoaded) return; + if (bundle->_isLoaded) return true; - // Remove from the scheduled unload set if we are there. - if (!_scheduledBundlesAreUnloading) { - __CFSpinLock(&CFBundleGlobalDataLock); + switch (bundle->_binaryType) { +#if defined(BINARY_SUPPORT_CFM) + case __CFBundleCFMBinary: + case __CFBundleUnreadableBinary: + result = true; + break; +#elif defined(BINARY_SUPPORT_DLFCN) + case __CFBundleUnreadableBinary: + result = _CFBundleDlfcnPreflight(bundle, subError); + break; +#endif /* BINARY_SUPPORT_CFM */ +#if defined(BINARY_SUPPORT_DYLD) + case __CFBundleDYLDBundleBinary: + result = true; +#if defined(BINARY_SUPPORT_DLFCN) + result = _CFBundleDlfcnPreflight(bundle, subError); +#endif /* BINARY_SUPPORT_DLFCN */ + break; + case __CFBundleDYLDFrameworkBinary: + result = true; +#if defined(BINARY_SUPPORT_DLFCN) + result = _CFBundleDlfcnPreflight(bundle, subError); +#endif /* BINARY_SUPPORT_DLFCN */ + break; + case __CFBundleDYLDExecutableBinary: + if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError); + break; +#endif /* BINARY_SUPPORT_DYLD */ +#if defined(BINARY_SUPPORT_DLFCN) + case __CFBundleUnknownBinary: + case __CFBundleELFBinary: + result = _CFBundleDlfcnPreflight(bundle, subError); + break; +#endif /* BINARY_SUPPORT_DLFCN */ +#if defined(BINARY_SUPPORT_DLL) + case __CFBundleDLLBinary: + result = true; + break; +#endif /* BINARY_SUPPORT_DLL */ + case __CFBundleNoBinary: + if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError); + break; + default: + if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError); + break; } - if (_bundlesToUnload) { - CFSetRemoveValue(_bundlesToUnload, bundle); + if (!result && error) *error = localError; + return result; +} + +CFArrayRef CFBundleCopyExecutableArchitectures(CFBundleRef bundle) { + CFArrayRef result = NULL; + CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); + if (executableURL) { + result = _CFBundleCopyArchitecturesForExecutable(executableURL); + CFRelease(executableURL); } - if (!_scheduledBundlesAreUnloading) { - __CFSpinUnlock(&CFBundleGlobalDataLock); + return result; +} + +static Boolean _CFBundleGetObjCImageInfo(CFBundleRef bundle, uint32_t *objcVersion, uint32_t *objcFlags) { + Boolean retval = false; + uint32_t localVersion = 0, localFlags = 0; + CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); + if (executableURL) { + retval = _CFBundleGetObjCImageInfoForExecutable(executableURL, &localVersion, &localFlags); + CFRelease(executableURL); } + if (objcVersion) *objcVersion = localVersion; + if (objcFlags) *objcFlags = localFlags; + return retval; +} + +void CFBundleUnloadExecutable(CFBundleRef bundle) { + // First unload bundles scheduled for unloading (if that's not what we are already doing.) + if (!_scheduledBundlesAreUnloading) _CFBundleUnloadScheduledBundles(); + + if (!bundle->_isLoaded) return; + + // Remove from the scheduled unload set if we are there. + if (!_scheduledBundlesAreUnloading) __CFSpinLock(&CFBundleGlobalDataLock); + if (_bundlesToUnload) CFSetRemoveValue(_bundlesToUnload, bundle); + if (!_scheduledBundlesAreUnloading) __CFSpinUnlock(&CFBundleGlobalDataLock); // Give the plugIn code a chance to realize this... _CFPlugInWillUnload(bundle); switch (bundle->_binaryType) { -#if defined(BINARY_SUPPORT_CFM) && defined(__ppc__) +#if defined(BINARY_SUPPORT_CFM) case __CFBundleCFMBinary: _CFBundleCFMUnload(bundle); break; -#endif /* BINARY_SUPPORT_CFM && __ppc__ */ +#endif /* BINARY_SUPPORT_CFM */ #if defined(BINARY_SUPPORT_DYLD) case __CFBundleDYLDBundleBinary: +#if defined(BINARY_SUPPORT_DLFCN) + if (bundle->_handleCookie) _CFBundleDlfcnUnload(bundle); else +#endif /* BINARY_SUPPORT_DLFCN */ _CFBundleDYLDUnloadBundle(bundle); break; + case __CFBundleDYLDFrameworkBinary: +#if defined(BINARY_SUPPORT_DLFCN) + if (bundle->_handleCookie && _CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard)) _CFBundleDlfcnUnload(bundle); +#endif /* BINARY_SUPPORT_DLFCN */ + break; #endif /* BINARY_SUPPORT_DYLD */ #if defined(BINARY_SUPPORT_DLL) case __CFBundleDLLBinary: @@ -2361,9 +2827,12 @@ void CFBundleUnloadExecutable(CFBundleRef bundle) { break; #endif /* BINARY_SUPPORT_DLL */ default: +#if defined(BINARY_SUPPORT_DLFCN) + if (bundle->_handleCookie) _CFBundleDlfcnUnload(bundle); +#endif /* BINARY_SUPPORT_DLFCN */ break; } - if (!bundle->_isLoaded && bundle->_glueDict != NULL) { + if (!bundle->_isLoaded && bundle->_glueDict) { CFDictionaryApplyFunction(bundle->_glueDict, _CFBundleDeallocateGlue, (void *)CFGetAllocator(bundle)); CFRelease(bundle->_glueDict); bundle->_glueDict = NULL; @@ -2377,7 +2846,7 @@ __private_extern__ void _CFBundleScheduleForUnloading(CFBundleRef bundle) { CFSetCallBacks nonRetainingCallbacks = kCFTypeSetCallBacks; nonRetainingCallbacks.retain = NULL; nonRetainingCallbacks.release = NULL; - _bundlesToUnload = CFSetCreateMutable(NULL, 0, &nonRetainingCallbacks); + _bundlesToUnload = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &nonRetainingCallbacks); } CFSetAddValue(_bundlesToUnload, bundle); __CFSpinUnlock(&CFBundleGlobalDataLock); @@ -2397,15 +2866,15 @@ __private_extern__ void _CFBundleUnloadScheduledBundles(void) { CFIndex c = CFSetGetCount(_bundlesToUnload); if (c > 0) { CFIndex i; - CFBundleRef *unloadThese = CFAllocatorAllocate(NULL, sizeof(CFBundleRef) * c, 0); + CFBundleRef *unloadThese = (CFBundleRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(CFBundleRef) * c, 0); CFSetGetValues(_bundlesToUnload, (const void **)unloadThese); _scheduledBundlesAreUnloading = true; - for (i=0; i_binaryType) { -#if defined(BINARY_SUPPORT_CFM) && defined(__ppc__) +#if defined(BINARY_SUPPORT_CFM) case __CFBundleCFMBinary: tvp = _CFBundleCFMGetSymbolByName(bundle, funcName, kTVectorCFragSymbol); break; -#endif /* BINARY_SUPPORT_CFM && __ppc__ */ +#endif /* BINARY_SUPPORT_CFM */ #if defined(BINARY_SUPPORT_DYLD) case __CFBundleDYLDBundleBinary: case __CFBundleDYLDFrameworkBinary: case __CFBundleDYLDExecutableBinary: +#if defined(BINARY_SUPPORT_DLFCN) + if (bundle->_handleCookie) return _CFBundleDlfcnGetSymbolByName(bundle, funcName); +#endif /* BINARY_SUPPORT_DLFCN */ return _CFBundleDYLDGetSymbolByName(bundle, funcName); break; #endif /* BINARY_SUPPORT_DYLD */ @@ -2437,21 +2909,22 @@ void *CFBundleGetFunctionPointerForName(CFBundleRef bundle, CFStringRef funcName break; #endif /* BINARY_SUPPORT_DLL */ default: +#if defined(BINARY_SUPPORT_DLFCN) + if (bundle->_handleCookie) return _CFBundleDlfcnGetSymbolByName(bundle, funcName); +#endif /* BINARY_SUPPORT_DLFCN */ break; } -#if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__) - if (tvp != NULL) { - if (bundle->_glueDict == NULL) { - bundle->_glueDict = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, NULL, NULL); - } +#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 == NULL) { + if (!fp) { fp = _CFBundleFunctionPointerForTVector(CFGetAllocator(bundle), tvp); CFDictionarySetValue(bundle->_glueDict, tvp, fp); } return fp; } -#endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */ +#endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM */ return tvp; } @@ -2461,36 +2934,41 @@ 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) switch (bundle->_binaryType) { -#if defined(BINARY_SUPPORT_CFM) && defined(__ppc__) +#if defined(BINARY_SUPPORT_CFM) case __CFBundleCFMBinary: return _CFBundleCFMGetSymbolByName(bundle, funcName, kTVectorCFragSymbol); break; -#endif /* BINARY_SUPPORT_CFM && __ppc__ */ +#endif /* BINARY_SUPPORT_CFM */ #if defined(BINARY_SUPPORT_DYLD) case __CFBundleDYLDBundleBinary: case __CFBundleDYLDFrameworkBinary: case __CFBundleDYLDExecutableBinary: +#if defined(BINARY_SUPPORT_DLFCN) + if (bundle->_handleCookie) fp = _CFBundleDlfcnGetSymbolByNameWithSearch(bundle, funcName, true); else +#endif /* BINARY_SUPPORT_DLFCN */ fp = _CFBundleDYLDGetSymbolByNameWithSearch(bundle, funcName, true); break; #endif /* BINARY_SUPPORT_DYLD */ default: +#if defined(BINARY_SUPPORT_DLFCN) + if (bundle->_handleCookie) fp = _CFBundleDlfcnGetSymbolByNameWithSearch(bundle, funcName, true); +#endif /* BINARY_SUPPORT_DLFCN */ break; } -#if defined(BINARY_SUPPORT_DYLD) && defined(BINARY_SUPPORT_CFM) && defined(__ppc__) - if (fp != NULL) { - if (bundle->_glueDict == NULL) { - bundle->_glueDict = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, NULL, NULL); - } +#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 == NULL) { + if (!tvp) { tvp = _CFBundleTVectorForFunctionPointer(CFGetAllocator(bundle), fp); CFDictionarySetValue(bundle->_glueDict, fp, tvp); } return tvp; } -#endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM && __ppc__ */ +#endif /* BINARY_SUPPORT_DYLD && BINARY_SUPPORT_CFM */ return fp; } @@ -2501,7 +2979,7 @@ void CFBundleGetFunctionPointersForNames(CFBundleRef bundle, CFArrayRef function c = CFArrayGetCount(functionNames); for (i = 0; i < c; i++) { - ftbl[i] = CFBundleGetFunctionPointerForName(bundle, CFArrayGetValueAtIndex(functionNames, i)); + ftbl[i] = CFBundleGetFunctionPointerForName(bundle, (CFStringRef)CFArrayGetValueAtIndex(functionNames, i)); } } @@ -2512,7 +2990,7 @@ void _CFBundleGetCFMFunctionPointersForNames(CFBundleRef bundle, CFArrayRef func c = CFArrayGetCount(functionNames); for (i = 0; i < c; i++) { - ftbl[i] = _CFBundleGetCFMFunctionPointerForName(bundle, CFArrayGetValueAtIndex(functionNames, i)); + ftbl[i] = _CFBundleGetCFMFunctionPointerForName(bundle, (CFStringRef)CFArrayGetValueAtIndex(functionNames, i)); } } @@ -2524,15 +3002,18 @@ void *CFBundleGetDataPointerForName(CFBundleRef bundle, CFStringRef symbolName) } switch (bundle->_binaryType) { -#if defined(BINARY_SUPPORT_CFM) && defined(__ppc__) +#if defined(BINARY_SUPPORT_CFM) case __CFBundleCFMBinary: dp = _CFBundleCFMGetSymbolByName(bundle, symbolName, kDataCFragSymbol); break; -#endif /* BINARY_SUPPORT_CFM && __ppc__ */ +#endif /* BINARY_SUPPORT_CFM */ #if defined(BINARY_SUPPORT_DYLD) case __CFBundleDYLDBundleBinary: case __CFBundleDYLDFrameworkBinary: case __CFBundleDYLDExecutableBinary: +#if defined(BINARY_SUPPORT_DLFCN) + if (bundle->_handleCookie) dp = _CFBundleDlfcnGetSymbolByName(bundle, symbolName); else +#endif /* BINARY_SUPPORT_DLFCN */ dp = _CFBundleDYLDGetSymbolByName(bundle, symbolName); break; #endif /* BINARY_SUPPORT_DYLD */ @@ -2542,6 +3023,9 @@ void *CFBundleGetDataPointerForName(CFBundleRef bundle, CFStringRef symbolName) break; #endif /* BINARY_SUPPORT_DLL */ default: +#if defined(BINARY_SUPPORT_DLFCN) + if (bundle->_handleCookie) dp = _CFBundleDlfcnGetSymbolByName(bundle, symbolName); +#endif /* BINARY_SUPPORT_DLFCN */ break; } return dp; @@ -2554,7 +3038,7 @@ void CFBundleGetDataPointersForNames(CFBundleRef bundle, CFArrayRef symbolNames, c = CFArrayGetCount(symbolNames); for (i = 0; i < c; i++) { - stbl[i] = CFBundleGetDataPointerForName(bundle, CFArrayGetValueAtIndex(symbolNames, i)); + stbl[i] = CFBundleGetDataPointerForName(bundle, (CFStringRef)CFArrayGetValueAtIndex(symbolNames, i)); } } @@ -2579,23 +3063,16 @@ __private_extern__ Boolean _CFBundleCouldBeBundle(CFURLRef url) { Boolean exists; SInt32 mode; - if (_CFGetFileProperties(NULL, url, &exists, &mode, NULL, NULL, NULL, NULL) == 0) { - result = (exists && ((mode & S_IFMT) == S_IFDIR)); -#if !defined(__MACOS8__) - result = (result && ((mode & 0444) != 0)); -#endif + if (_CFGetFileProperties(kCFAllocatorSystemDefault, url, &exists, &mode, NULL, NULL, NULL, NULL) == 0) { + result = (exists && ((mode & S_IFMT) == S_IFDIR) && ((mode & 0444) != 0)); } return result; } +#define LENGTH_OF(A) (sizeof(A) / sizeof(A[0])) + __private_extern__ CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFAllocatorRef alloc, CFStringRef executablePath) { // 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 defined(__WIN32__) - UniChar executablesToFrameworksPathBuff[] = {'.', '.', '\\', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'}; // length 16 - UniChar executablesToPrivateFrameworksPathBuff[] = {'.', '.', '\\', 'P', 'r', 'i', 'v', 'a', 't', 'e', 'F', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k', 's'}; // length 23 - UniChar frameworksExtension[] = {'f', 'r', 'a', 'm', 'e', 'w', 'o', 'r', 'k'}; // length 9 -#endif - UniChar pathBuff[CFMaxPathSize]; UniChar nameBuff[CFMaxPathSize]; CFIndex length, nameStart, nameLength, savedLength; @@ -2616,31 +3093,8 @@ __private_extern__ CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFAllocat length = _CFLengthAfterDeletingLastPathComponent(pathBuff, length); savedLength = length; -#if defined(__WIN32__) - // * (Windows-only) First check the "Executables" directory parallel to the "Frameworks" directory case. - if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToFrameworksPathBuff, 16) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, 9)) { - CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize); - bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true); - if (!_CFBundleCouldBeBundle(bundleURL)) { - CFRelease(bundleURL); - bundleURL = NULL; - } - } - // * (Windows-only) Next check the "Executables" directory parallel to the "PrivateFrameworks" directory case. - if (bundleURL == NULL) { - length = savedLength; - if (_CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, executablesToPrivateFrameworksPathBuff, 23) && _CFAppendPathComponent(pathBuff, &length, CFMaxPathSize, nameBuff, nameLength) && _CFAppendPathExtension(pathBuff, &length, CFMaxPathSize, frameworksExtension, 9)) { - CFStringSetExternalCharactersNoCopy(cheapStr, pathBuff, length, CFMaxPathSize); - bundleURL = CFURLCreateWithFileSystemPath(alloc, cheapStr, PLATFORM_PATH_STYLE, true); - if (!_CFBundleCouldBeBundle(bundleURL)) { - CFRelease(bundleURL); - bundleURL = NULL; - } - } - } -#endif // * Finally check the executable inside the framework case. - if (bundleURL == NULL) { + if (!bundleURL) { // MF:!!! This should ensure the framework name is the same as the library name! CFIndex curStart; @@ -2681,31 +3135,32 @@ __private_extern__ CFURLRef _CFBundleCopyFrameworkURLForExecutablePath(CFAllocat return bundleURL; } -#if defined(BINARY_SUPPORT_DYLD) 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(NULL, imagePath); + CFURLRef curURL = _CFBundleCopyFrameworkURLForExecutablePath(kCFAllocatorSystemDefault, imagePath); Boolean doFinalProcessing = false; - if (curURL != NULL) { + if (curURL) { bundle = _CFBundleFindByURL(curURL, true); - if (bundle == NULL) { - bundle = _CFBundleCreate(NULL, curURL, true, false); + if (!bundle) { + bundle = _CFBundleCreate(kCFAllocatorSystemDefault, curURL, true, false); doFinalProcessing = true; } - if (bundle != NULL && !bundle->_isLoaded) { + if (bundle && !bundle->_isLoaded) { // make sure that these bundles listed as loaded, and mark them frameworks (we probably can't see anything else here, and we cannot unload them) +#if defined(BINARY_SUPPORT_DLFCN) + if (!bundle->_isLoaded && _useDlfcn) _CFBundleDlfcnCheckLoaded(bundle); +#endif /* BINARY_SUPPORT_DLFCN */ #if defined(BINARY_SUPPORT_DYLD) - if (bundle->_binaryType == __CFBundleUnknownBinary) { - bundle->_binaryType = __CFBundleDYLDFrameworkBinary; - } - if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) { - bundle->_resourceData._executableLacksResourceFork = true; - } - if (!bundle->_imageCookie) _CFBundleDYLDCheckLoaded(bundle); + if (bundle->_binaryType == __CFBundleUnknownBinary) bundle->_binaryType = __CFBundleDYLDFrameworkBinary; + if (bundle->_binaryType != __CFBundleCFMBinary && bundle->_binaryType != __CFBundleUnreadableBinary) bundle->_resourceData._executableLacksResourceFork = true; + if (!bundle->_isLoaded) _CFBundleDYLDCheckLoaded(bundle); #endif /* BINARY_SUPPORT_DYLD */ +#if LOG_BUNDLE_LOAD + if (!bundle->_isLoaded) printf("ensure bundle %p set loaded fallback, handle %p image %p conn %p\n", bundle, bundle->_handleCookie, bundle->_imageCookie, bundle->_connectionCookie); +#endif /* LOG_BUNDLE_LOAD */ bundle->_isLoaded = true; } // Perform delayed final processing steps. @@ -2727,45 +3182,46 @@ static void _CFBundleEnsureBundlesExistForImagePaths(CFArrayRef imagePaths) { // 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 (even if it appears in imagePaths). CFIndex i, imagePathCount = CFArrayGetCount(imagePaths); - for (i=0; i_version;} CF_EXPORT CFURLRef _CFBundleCopyInfoPlistURL(CFBundleRef bundle) { CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); - CFStringRef path = CFDictionaryGetValue(infoDict, _kCFBundleInfoPlistURLKey); - return (path ? CFRetain(path) : NULL); + CFURLRef url = (CFURLRef)CFDictionaryGetValue(infoDict, _kCFBundleInfoPlistURLKey); + if (!url) url = (CFURLRef)CFDictionaryGetValue(infoDict, _kCFBundleRawInfoPlistURLKey); + return (url ? (CFURLRef)CFRetain(url) : NULL); } CF_EXPORT CFURLRef _CFBundleCopyPrivateFrameworksURL(CFBundleRef bundle) {return CFBundleCopyPrivateFrameworksURL(bundle);} @@ -2898,27 +3355,32 @@ static const void *__CFBundleDYLDFindImage(char *buff) { __private_extern__ Boolean _CFBundleDYLDCheckLoaded(CFBundleRef bundle) { if (!bundle->_isLoaded) { CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); - - if (executableURL != NULL) { - char buff[CFMaxPathSize]; - - if (CFURLGetFileSystemRepresentation(executableURL, true, buff, CFMaxPathSize)) { - const void *header = __CFBundleDYLDFindImage(buff); - if (header) { - if (bundle->_binaryType == __CFBundleUnknownBinary) { - bundle->_binaryType = __CFBundleDYLDFrameworkBinary; - } - if (!bundle->_imageCookie) bundle->_imageCookie = header; - bundle->_isLoaded = true; + char buff[CFMaxPathSize]; + + if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) { + const void *header = __CFBundleDYLDFindImage(buff); + if (header) { + if (bundle->_binaryType == __CFBundleUnknownBinary) bundle->_binaryType = __CFBundleDYLDFrameworkBinary; + if (!bundle->_imageCookie) { + bundle->_imageCookie = header; +#if LOG_BUNDLE_LOAD + printf("dyld check load bundle %p, find %s getting image %p\n", bundle, buff, bundle->_imageCookie); +#endif /* LOG_BUNDLE_LOAD */ } + bundle->_isLoaded = true; + } else { +#if LOG_BUNDLE_LOAD + printf("dyld check load bundle %p, find %s no image\n", bundle, buff); +#endif /* LOG_BUNDLE_LOAD */ } - CFRelease(executableURL); } + if (executableURL) CFRelease(executableURL); } return bundle->_isLoaded; } -__private_extern__ Boolean _CFBundleDYLDLoadBundle(CFBundleRef bundle) { +__private_extern__ Boolean _CFBundleDYLDLoadBundle(CFBundleRef bundle, Boolean forceGlobal, CFErrorRef *error) { + CFErrorRef localError = NULL, *subError = (error ? &localError : NULL); NSLinkEditErrors c = NSLinkEditUndefinedError; int errorNumber = 0; const char *fileName = NULL; @@ -2926,40 +3388,80 @@ __private_extern__ Boolean _CFBundleDYLDLoadBundle(CFBundleRef bundle) { if (!bundle->_isLoaded) { CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); - - if (executableURL) { - char buff[CFMaxPathSize]; - - if (CFURLGetFileSystemRepresentation(executableURL, true, buff, CFMaxPathSize)) { - NSObjectFileImage image; - NSObjectFileImageReturnCode retCode = NSCreateObjectFileImageFromFile(buff, &image); - if (retCode == NSObjectFileImageSuccess) { - NSModule module = NSLinkModule(image, buff, (NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_RETURN_ON_ERROR)); - if (module) { - bundle->_imageCookie = image; - bundle->_moduleCookie = module; - bundle->_isLoaded = true; + char buff[CFMaxPathSize]; + + if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) { + NSObjectFileImage image; + NSObjectFileImageReturnCode retCode = NSCreateObjectFileImageFromFile(buff, &image); +#if LOG_BUNDLE_LOAD + printf("dyld load bundle %p, create image of %s returns image %p retcode %d\n", bundle, buff, image, retCode); +#endif /* LOG_BUNDLE_LOAD */ + if (retCode == NSObjectFileImageSuccess) { + uint32_t options = forceGlobal ? NSLINKMODULE_OPTION_RETURN_ON_ERROR : (NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_PRIVATE | NSLINKMODULE_OPTION_RETURN_ON_ERROR); + NSModule module = NSLinkModule(image, buff, options); +#if LOG_BUNDLE_LOAD + printf("dyld load bundle %p, link module of %s options 0x%x returns module %p image %p\n", bundle, buff, options, module, image); +#endif /* LOG_BUNDLE_LOAD */ + if (module) { + bundle->_imageCookie = image; + bundle->_moduleCookie = module; + bundle->_isLoaded = true; + } else { + NSLinkEditError(&c, &errorNumber, &fileName, &errorString); + CFLog(__kCFLogBundle, CFSTR("Error loading %s: error code %d, error number %d (%s)"), fileName, c, errorNumber, errorString); + if (error) { +#if defined(BINARY_SUPPORT_DLFCN) + _CFBundleDlfcnPreflight(bundle, subError); +#endif /* BINARY_SUPPORT_DLFCN */ + if (!localError) { + CFStringRef debugString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("error code %d, error number %d (%s)"), c, errorNumber, errorString); + localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString); + CFRelease(debugString); + } + } + (void)NSDestroyObjectFileImage(image); + } + } else { + CFLog(__kCFLogBundle, CFSTR("dyld returns %d when trying to load %@"), retCode, executableURL); + if (error) { + if (retCode == NSObjectFileImageArch) { + localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableArchitectureMismatchError); + } else if (retCode == NSObjectFileImageInappropriateFile) { + Boolean hasRuntimeMismatch = false; + uint32_t mainFlags = 0, bundleFlags = 0; + if (_CFBundleGrokObjCImageInfoFromMainExecutable(NULL, &mainFlags) && (mainFlags & 0x2) != 0) { + if (_CFBundleGetObjCImageInfo(bundle, NULL, &bundleFlags) && (bundleFlags & 0x2) == 0) hasRuntimeMismatch = true; + } + if (hasRuntimeMismatch) { + localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableRuntimeMismatchError); + } else { + localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotLoadableError); + } } else { - NSLinkEditError(&c, &errorNumber, &fileName, &errorString); - CFLog(__kCFLogBundle, CFSTR("Error loading %s: error code %d, error number %d (%s)"), fileName, c, errorNumber, errorString); - if (!NSDestroyObjectFileImage(image)) { - /* MF:!!! Error destroying object file image */ +#if defined(BINARY_SUPPORT_DLFCN) + _CFBundleDlfcnPreflight(bundle, subError); +#endif /* BINARY_SUPPORT_DLFCN */ + if (!localError) { + CFStringRef debugString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("dyld returns %d"), retCode); + localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString); + CFRelease(debugString); } } - } else { - CFLog(__kCFLogBundle, CFSTR("dyld returns %d when trying to load %@"), retCode, executableURL); } } - CFRelease(executableURL); } else { CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle); + if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError); } + if (executableURL) CFRelease(executableURL); } + if (!bundle->_isLoaded && error) *error = localError; return bundle->_isLoaded; } -__private_extern__ Boolean _CFBundleDYLDLoadFramework(CFBundleRef bundle) { +__private_extern__ Boolean _CFBundleDYLDLoadFramework(CFBundleRef bundle, CFErrorRef *error) { // !!! Framework loading should be better. Can't unload frameworks. + CFErrorRef localError = NULL, *subError = (error ? &localError : NULL); NSLinkEditErrors c = NSLinkEditUndefinedError; int errorNumber = 0; const char *fileName = NULL; @@ -2967,37 +3469,50 @@ __private_extern__ Boolean _CFBundleDYLDLoadFramework(CFBundleRef bundle) { if (!bundle->_isLoaded) { CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); - - if (executableURL) { - char buff[CFMaxPathSize]; - - if (CFURLGetFileSystemRepresentation(executableURL, true, buff, CFMaxPathSize)) { - void *image = (void *)NSAddImage(buff, NSADDIMAGE_OPTION_RETURN_ON_ERROR); - if (image) { - bundle->_imageCookie = image; - bundle->_isLoaded = true; - } else { - NSLinkEditError(&c, &errorNumber, &fileName, &errorString); - CFLog(__kCFLogBundle, CFSTR("Error loading %s: error code %d, error number %d (%s)"), fileName, c, errorNumber, errorString); + char buff[CFMaxPathSize]; + + if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) { + void *image = (void *)NSAddImage(buff, NSADDIMAGE_OPTION_RETURN_ON_ERROR); +#if LOG_BUNDLE_LOAD + printf("dyld load framework %p, add image of %s returns image %p\n", bundle, buff, image); +#endif /* LOG_BUNDLE_LOAD */ + if (image) { + bundle->_imageCookie = image; + bundle->_isLoaded = true; + } else { + NSLinkEditError(&c, &errorNumber, &fileName, &errorString); + CFLog(__kCFLogBundle, CFSTR("Error loading %s: error code %d, error number %d (%s)"), fileName, c, errorNumber, errorString); + if (error) { +#if defined(BINARY_SUPPORT_DLFCN) + _CFBundleDlfcnPreflight(bundle, subError); +#endif /* BINARY_SUPPORT_DLFCN */ + if (!localError) { + CFStringRef debugString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("error code %d, error number %d (%s)"), c, errorNumber, errorString); + localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString); + CFRelease(debugString); + } } } - CFRelease(executableURL); } else { CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle); + if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError); } + if (executableURL) CFRelease(executableURL); } + if (!bundle->_isLoaded && error) *error = localError; return bundle->_isLoaded; } __private_extern__ void _CFBundleDYLDUnloadBundle(CFBundleRef bundle) { if (bundle->_isLoaded) { +#if LOG_BUNDLE_LOAD + printf("dyld unload bundle %p, handle %p module %p image %p\n", bundle, bundle->_handleCookie, bundle->_moduleCookie, bundle->_imageCookie); +#endif /* LOG_BUNDLE_LOAD */ if (bundle->_moduleCookie && !NSUnLinkModule((NSModule)(bundle->_moduleCookie), NSUNLINKMODULE_OPTION_NONE)) { CFLog(__kCFLogBundle, CFSTR("Internal error unloading bundle %@"), bundle); } else { - if (bundle->_moduleCookie && bundle->_imageCookie && !NSDestroyObjectFileImage((NSObjectFileImage)(bundle->_imageCookie))) { - /* MF:!!! Error destroying object file image */ - } - bundle->_connectionCookie = NULL; + if (bundle->_moduleCookie && bundle->_imageCookie) (void)NSDestroyObjectFileImage((NSObjectFileImage)(bundle->_imageCookie)); + bundle->_connectionCookie = bundle->_handleCookie = NULL; bundle->_imageCookie = bundle->_moduleCookie = NULL; bundle->_isLoaded = false; } @@ -3011,78 +3526,92 @@ static void *_CFBundleDYLDGetSymbolByNameWithSearch(CFBundleRef bundle, CFString char buff[1026]; NSSymbol symbol = NULL; - // MF:!!! What if the factory was in C++ code (and is therefore mangled differently)? Huh, answer me that! - // MF: The current answer to the mangling question is that you cannot look up C++ functions with this API. Thus things like plugin factories must be extern "C" in plugin code. buff[0] = '_'; - /* MF:??? ASCII appropriate here? */ - if (CFStringGetCString(symbolName, &(buff[1]), 1024, kCFStringEncodingASCII)) { + if (CFStringGetCString(symbolName, &(buff[1]), 1024, kCFStringEncodingUTF8)) { if (bundle->_moduleCookie) { symbol = NSLookupSymbolInModule((NSModule)(bundle->_moduleCookie), buff); } else if (bundle->_imageCookie) { symbol = NSLookupSymbolInImage(bundle->_imageCookie, buff, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND|NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); } - if (NULL == symbol && NULL == bundle->_moduleCookie && (NULL == bundle->_imageCookie || globalSearch)) { + if (!symbol && !bundle->_moduleCookie && (!bundle->_imageCookie || globalSearch)) { char hintBuff[1026]; - CFStringRef executableName = _CFBundleCopyExecutableName(NULL, bundle, NULL, NULL); + CFStringRef executableName = _CFBundleCopyExecutableName(kCFAllocatorSystemDefault, bundle, NULL, NULL); hintBuff[0] = '\0'; if (executableName) { if (!CFStringGetCString(executableName, hintBuff, 1024, kCFStringEncodingUTF8)) hintBuff[0] = '\0'; CFRelease(executableName); } - if (NSIsSymbolNameDefinedWithHint(buff, hintBuff)) { - symbol = NSLookupAndBindSymbolWithHint(buff, hintBuff); - } + // Nowdays, NSIsSymbolNameDefinedWithHint() and NSLookupAndBindSymbolWithHint() + // are identical, except the first just returns a bool, so checking with the + // Is function first just causes a redundant lookup. + // This returns NULL on failure. + symbol = NSLookupAndBindSymbolWithHint(buff, hintBuff); } - if (symbol) { - result = NSAddressOfSymbol(symbol); - } else { + if (symbol) result = NSAddressOfSymbol(symbol); #if defined(DEBUG) - CFLog(__kCFLogBundle, CFSTR("dyld cannot find symbol %s in %@"), buff, bundle); -#endif - } + if (!result) CFLog(__kCFLogBundle, CFSTR("dyld cannot find symbol %s in %@"), buff, bundle); +#endif /* DEBUG */ +#if LOG_BUNDLE_LOAD + printf("bundle %p handle %p module %p image %p dyld returns symbol %p for %s\n", bundle, bundle->_handleCookie, bundle->_moduleCookie, bundle->_imageCookie, result, buff + 1); +#endif /* LOG_BUNDLE_LOAD */ } return result; } static CFStringRef _CFBundleDYLDCopyLoadedImagePathForPointer(void *p) { - uint32_t i, j, n = _dyld_image_count(); - Boolean foundit = false; - const char *name; CFStringRef result = NULL; - for (i = 0; !foundit && i < n; i++) { - // will need modification for 64-bit - const struct mach_header *mh = _dyld_get_image_header(i); - uint32_t addr = (uint32_t)p - _dyld_get_image_vmaddr_slide(i); - if (mh) { - struct load_command *lc = (struct load_command *)((char *)mh + sizeof(struct mach_header)); - for (j = 0; !foundit && j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) { - if (LC_SEGMENT == lc->cmd && addr >= ((struct segment_command *)lc)->vmaddr && addr < ((struct segment_command *)lc)->vmaddr + ((struct segment_command *)lc)->vmsize) { - foundit = true; - name = _dyld_get_image_name(i); - if (name != NULL) { - result = CFStringCreateWithCString(NULL, name, CFStringFileSystemEncoding()); + if (!result) { + uint32_t i, j, n = _dyld_image_count(); + Boolean foundit = false; + const char *name; +#if __LP64__ +#define MACH_HEADER_TYPE struct mach_header_64 +#define MACH_SEGMENT_CMD_TYPE struct segment_command_64 +#define MACH_SEGMENT_FLAVOR LC_SEGMENT_64 +#else +#define MACH_HEADER_TYPE struct mach_header +#define MACH_SEGMENT_CMD_TYPE struct segment_command +#define MACH_SEGMENT_FLAVOR LC_SEGMENT +#endif + for (i = 0; !foundit && i < n; i++) { + const MACH_HEADER_TYPE *mh = (const MACH_HEADER_TYPE *)_dyld_get_image_header(i); + uintptr_t addr = (uintptr_t)p - _dyld_get_image_vmaddr_slide(i); + if (mh) { + struct load_command *lc = (struct load_command *)((char *)mh + sizeof(MACH_HEADER_TYPE)); + for (j = 0; !foundit && j < mh->ncmds; j++, lc = (struct load_command *)((char *)lc + lc->cmdsize)) { + if (MACH_SEGMENT_FLAVOR == lc->cmd && ((MACH_SEGMENT_CMD_TYPE *)lc)->vmaddr <= addr && addr < ((MACH_SEGMENT_CMD_TYPE *)lc)->vmaddr + ((MACH_SEGMENT_CMD_TYPE *)lc)->vmsize) { + foundit = true; + name = _dyld_get_image_name(i); + if (name) result = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, name); } } } } +#undef MACH_HEADER_TYPE +#undef MACH_SEGMENT_CMD_TYPE +#undef MACH_SEGMENT_FLAVOR } +#if LOG_BUNDLE_LOAD + printf("dyld image path for pointer %p is %p\n", p, result); +#endif /* LOG_BUNDLE_LOAD */ return result; } __private_extern__ CFArrayRef _CFBundleDYLDCopyLoadedImagePathsForHint(CFStringRef hint) { uint32_t i, numImages = _dyld_image_count(); - CFMutableArrayRef result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); CFRange range = CFRangeMake(0, CFStringGetLength(hint)); + const char *processPath = _CFProcessPath(); - for (i=0; i_isLoaded) { + CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); + char buff[CFMaxPathSize]; + + if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) { + int mode = RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD | RTLD_FIRST; + void *handle = dlopen(buff, mode); + if (handle) { + if (!bundle->_handleCookie) { + bundle->_handleCookie = handle; +#if LOG_BUNDLE_LOAD + printf("dlfcn check load bundle %p, dlopen of %s mode 0x%x getting handle %p\n", bundle, buff, mode, bundle->_handleCookie); +#endif /* LOG_BUNDLE_LOAD */ + } + bundle->_isLoaded = true; + } else { +#if LOG_BUNDLE_LOAD + printf("dlfcn check load bundle %p, dlopen of %s mode 0x%x no handle\n", bundle, buff, mode); +#endif /* LOG_BUNDLE_LOAD */ + } + } + if (executableURL) CFRelease(executableURL); + } + return bundle->_isLoaded; +} -__private_extern__ Boolean _CFBundleDLLLoad(CFBundleRef bundle) { +static SInt32 _CFBundleCurrentArchitecture(void) { + SInt32 arch = 0; +#if defined(__ppc__) + arch = kCFBundleExecutableArchitecturePPC; +#elif defined(__ppc64__) + arch = kCFBundleExecutableArchitecturePPC64; +#elif defined(__i386__) + arch = kCFBundleExecutableArchitectureI386; +#elif defined(__x86_64__) + arch = kCFBundleExecutableArchitectureX86_64; +#elif defined(BINARY_SUPPORT_DYLD) + const NXArchInfo *archInfo = NXGetLocalArchInfo(); + if (archInfo) arch = archInfo->cputype; +#endif + return arch; +} +extern Boolean _CFBundleDlfcnPreflight(CFBundleRef bundle, CFErrorRef *error) { + Boolean retval = true; + CFErrorRef localError = NULL; if (!bundle->_isLoaded) { CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); + char buff[CFMaxPathSize]; + + retval = false; + if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) { + retval = dlopen_preflight(buff); + if (!retval && error) { + CFArrayRef archs = CFBundleCopyExecutableArchitectures(bundle); + CFStringRef debugString = NULL; + const char *errorString = dlerror(); + if (errorString && strlen(errorString) > 0) debugString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString); + if (archs) { + Boolean hasSuitableArch = false, hasRuntimeMismatch = false; + CFIndex i, count = CFArrayGetCount(archs); + SInt32 arch, curArch = _CFBundleCurrentArchitecture(); + for (i = 0; !hasSuitableArch && i < count; i++) { + if (CFNumberGetValue((CFNumberRef)CFArrayGetValueAtIndex(archs, i), kCFNumberSInt32Type, (void *)&arch) && arch == curArch) hasSuitableArch = true; + } +#if defined(BINARY_SUPPORT_DYLD) + if (hasSuitableArch) { + uint32_t mainFlags = 0, bundleFlags = 0; + if (_CFBundleGrokObjCImageInfoFromMainExecutable(NULL, &mainFlags) && (mainFlags & 0x2) != 0) { + if (_CFBundleGetObjCImageInfo(bundle, NULL, &bundleFlags) && (bundleFlags & 0x2) == 0) hasRuntimeMismatch = true; + } + } +#endif /* BINARY_SUPPORT_DYLD */ + if (hasRuntimeMismatch) { + localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableRuntimeMismatchError, debugString); + } else if (!hasSuitableArch) { + localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableArchitectureMismatchError, debugString); + } else { + localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLoadError, debugString); + } + CFRelease(archs); + } else { + localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLoadError, debugString); + } + if (debugString) CFRelease(debugString); + } + } else { + if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError); + } + if (executableURL) CFRelease(executableURL); + } + if (!retval && error) *error = localError; + return retval; +} - if (executableURL) { - char buff[CFMaxPathSize]; +__private_extern__ Boolean _CFBundleDlfcnLoadBundle(CFBundleRef bundle, Boolean forceGlobal, CFErrorRef *error) { + CFErrorRef localError = NULL, *subError = (error ? &localError : NULL); + if (!bundle->_isLoaded) { + CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); + char buff[CFMaxPathSize]; + if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) { + int mode = forceGlobal ? (RTLD_LAZY | RTLD_GLOBAL | RTLD_FIRST) : (RTLD_NOW | RTLD_LOCAL | RTLD_FIRST); + bundle->_handleCookie = dlopen(buff, mode); +#if LOG_BUNDLE_LOAD + printf("dlfcn load bundle %p, dlopen of %s mode 0x%x returns handle %p\n", bundle, buff, mode, bundle->_handleCookie); +#endif /* LOG_BUNDLE_LOAD */ + if (bundle->_handleCookie) { + bundle->_isLoaded = true; + } else { + CFStringRef debugString = NULL; + const char *errorString = dlerror(); + if (errorString) { + CFLog(__kCFLogBundle, CFSTR("Error loading %s: %s"), buff, errorString); + debugString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString); + } else { + CFLog(__kCFLogBundle, CFSTR("Error loading %s"), buff); + } + if (error && _CFBundleDlfcnPreflight(bundle, subError)) localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString); + if (debugString) CFRelease(debugString); + } + } else { + CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle); + if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError); + } + if (executableURL) CFRelease(executableURL); + } + if (!bundle->_isLoaded && error) *error = localError; + return bundle->_isLoaded; +} - if (CFURLGetFileSystemRepresentation(executableURL, true, buff, CFMaxPathSize)) { - bundle->_hModule = LoadLibrary(buff); - if (bundle->_hModule == NULL) { +__private_extern__ Boolean _CFBundleDlfcnLoadFramework(CFBundleRef bundle, CFErrorRef *error) { + CFErrorRef localError = NULL, *subError = (error ? &localError : NULL); + if (!bundle->_isLoaded) { + CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); + char buff[CFMaxPathSize]; + if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) { + int mode = RTLD_LAZY | RTLD_GLOBAL | RTLD_FIRST; + bundle->_handleCookie = dlopen(buff, mode); +#if LOG_BUNDLE_LOAD + printf("dlfcn load framework %p, dlopen of %s mode 0x%x returns handle %p\n", bundle, buff, mode, bundle->_handleCookie); +#endif /* LOG_BUNDLE_LOAD */ + if (bundle->_handleCookie) { + bundle->_isLoaded = true; + } else { + CFStringRef debugString = NULL; + const char *errorString = dlerror(); + if (errorString) { + CFLog(__kCFLogBundle, CFSTR("Error loading %s: %s"), buff, errorString); + debugString = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, errorString); } else { - bundle->_isLoaded = true; + CFLog(__kCFLogBundle, CFSTR("Error loading %s"), buff); } + if (error && _CFBundleDlfcnPreflight(bundle, subError)) localError = _CFBundleCreateErrorDebug(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError, debugString); + if (debugString) CFRelease(debugString); } - CFRelease(executableURL); } else { CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle); + if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError); } + if (executableURL) CFRelease(executableURL); + } + if (!bundle->_isLoaded && error) *error = localError; + return bundle->_isLoaded; +} + +__private_extern__ void _CFBundleDlfcnUnload(CFBundleRef bundle) { + if (bundle->_isLoaded) { +#if LOG_BUNDLE_LOAD + printf("dlfcn unload bundle %p, handle %p module %p image %p\n", bundle, bundle->_handleCookie, bundle->_moduleCookie, bundle->_imageCookie); +#endif /* LOG_BUNDLE_LOAD */ + if (0 != dlclose(bundle->_handleCookie)) { + CFLog(__kCFLogBundle, CFSTR("Internal error unloading bundle %@"), bundle); + } else { + bundle->_connectionCookie = bundle->_handleCookie = NULL; + bundle->_imageCookie = bundle->_moduleCookie = NULL; + bundle->_isLoaded = false; + } + } +} + +__private_extern__ void *_CFBundleDlfcnGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName) {return _CFBundleDlfcnGetSymbolByNameWithSearch(bundle, symbolName, false);} + +static void *_CFBundleDlfcnGetSymbolByNameWithSearch(CFBundleRef bundle, CFStringRef symbolName, Boolean globalSearch) { + void *result = NULL; + char buff[1026]; + + if (CFStringGetCString(symbolName, buff, 1024, kCFStringEncodingUTF8)) { + result = dlsym(bundle->_handleCookie, buff); + if (!result && globalSearch) result = dlsym(RTLD_DEFAULT, buff); +#if defined(DEBUG) + if (!result) CFLog(__kCFLogBundle, CFSTR("dlsym cannot find symbol %s in %@"), buff, bundle); +#endif /* DEBUG */ +#if LOG_BUNDLE_LOAD + printf("bundle %p handle %p module %p image %p dlsym returns symbol %p for %s\n", bundle, bundle->_handleCookie, bundle->_moduleCookie, bundle->_imageCookie, result, buff); +#endif /* LOG_BUNDLE_LOAD */ } + return result; +} + +static CFStringRef _CFBundleDlfcnCopyLoadedImagePathForPointer(void *p) { + CFStringRef result = NULL; + Dl_info info; + if (0 != dladdr(p, &info) && info.dli_fname) result = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, info.dli_fname); +#if LOG_BUNDLE_LOAD + printf("dlfcn image path for pointer %p is %p\n", p, result); +#endif /* LOG_BUNDLE_LOAD */ + return result; +} +#endif /* BINARY_SUPPORT_DLFCN */ + + +#if defined(BINARY_SUPPORT_DLL) + +__private_extern__ Boolean _CFBundleDLLLoad(CFBundleRef bundle, CFErrorRef *error) { + CFErrorRef localError = NULL; + if (!bundle->_isLoaded) { + CFURLRef executableURL = CFBundleCopyExecutableURL(bundle); + TCHAR buff[CFMaxPathSize]; + + if (executableURL && CFURLGetFileSystemRepresentation(executableURL, true, (uint8_t *)buff, CFMaxPathSize)) { + bundle->_hModule = LoadLibrary(buff); + if (bundle->_hModule) { + bundle->_isLoaded = true; + } else { + if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableLinkError); + } + } else { + CFLog(__kCFLogBundle, CFSTR("Cannot find executable for bundle %@"), bundle); + if (error) localError = _CFBundleCreateError(CFGetAllocator(bundle), bundle, CFBundleExecutableNotFoundError); + } + if (executableURL) CFRelease(executableURL); + } + if (!bundle->_isLoaded && error) *error = localError; return bundle->_isLoaded; } @@ -3162,16 +3927,12 @@ __private_extern__ void _CFBundleDLLUnload(CFBundleRef bundle) { __private_extern__ void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName) { void *result = NULL; char buff[1024]; - - if (CFStringGetCString(symbolName, buff, 1024, kCFStringEncodingWindowsLatin1)) { - result = GetProcAddress(bundle->_hModule, buff); - } + if (CFStringGetCString(symbolName, buff, 1024, kCFStringEncodingWindowsLatin1)) result = GetProcAddress(bundle->_hModule, buff); return result; } #endif /* BINARY_SUPPORT_DLL */ - /* Workarounds to be applied in the presence of certain bundles can go here. This is called on every bundle creation. */ extern void _CFStringSetCompatibility(CFOptionFlags); diff --git a/PlugIn.subproj/CFBundle.h b/CFBundle.h similarity index 71% rename from PlugIn.subproj/CFBundle.h rename to CFBundle.h index 885d04c..b3b3519 100644 --- a/PlugIn.subproj/CFBundle.h +++ b/CFBundle.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFBundle.h - Copyright (c) 1999-2005, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBUNDLE__) @@ -30,12 +30,11 @@ #include #include #include +#include #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN typedef struct __CFBundle *CFBundleRef; typedef struct __CFBundle *CFPlugInRef; @@ -46,24 +45,24 @@ const CFStringRef kCFBundleInfoDictionaryVersionKey; /* The version of the Info.plist format */ CF_EXPORT const CFStringRef kCFBundleExecutableKey; - /* The name of the executable in this bundle (if any) */ + /* The name of the executable in this bundle, if any */ CF_EXPORT const CFStringRef kCFBundleIdentifierKey; /* The bundle identifier (for CFBundleGetBundleWithIdentifier()) */ CF_EXPORT const CFStringRef kCFBundleVersionKey; - /* The version number of the bundle. For Mac OS 9 style version numbers (for example "2.5.3d5"), clients can use CFBundleGetVersionNumber() instead of accessing this key directly since that function will properly convert the version string into its compact integer representation. */ + /* The version number of the bundle. For Mac OS 9 style version numbers (for example "2.5.3d5"), */ + /* clients can use CFBundleGetVersionNumber() instead of accessing this key directly since that */ + /* function will properly convert the version string into its compact integer representation. */ CF_EXPORT const CFStringRef kCFBundleDevelopmentRegionKey; /* The name of the development language of the bundle. */ 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. */ -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED CF_EXPORT -const CFStringRef kCFBundleLocalizationsKey; +const CFStringRef kCFBundleLocalizationsKey AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER; /* Allows an unbundled application that handles localization itself to specify which localizations it has available. */ -#endif /* ===================== Finding Bundles ===================== */ @@ -86,7 +85,7 @@ CFArrayRef CFBundleGetAllBundles(void); /* ===================== Creating Bundles ===================== */ CF_EXPORT -UInt32 CFBundleGetTypeID(void); +CFTypeID CFBundleGetTypeID(void); CF_EXPORT CFBundleRef CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL); @@ -94,8 +93,8 @@ CFBundleRef CFBundleCreate(CFAllocatorRef allocator, CFURLRef bundleURL); CF_EXPORT CFArrayRef CFBundleCreateBundlesFromDirectory(CFAllocatorRef allocator, CFURLRef directoryURL, CFStringRef bundleType); - /* Create instances for all bundles in the given directory matching the given */ - /* type (or all of them if bundleType is NULL) */ + /* Create instances for all bundles in the given directory matching the given type */ + /* (or all of them if bundleType is NULL). Instances are created using CFBundleCreate() and are not released. */ /* ==================== Basic Bundle Info ==================== */ @@ -156,7 +155,7 @@ CFDictionaryRef CFBundleCopyInfoDictionaryInDirectory(CFURLRef bundleURL); CF_EXPORT Boolean CFBundleGetPackageInfoInDirectory(CFURLRef url, UInt32 *packageType, UInt32 *packageCreator); - + /* ==================== Resource Handling API ==================== */ CF_EXPORT @@ -204,64 +203,99 @@ CFArrayRef CFBundleCopyPreferredLocalizationsFromArray(CFArrayRef locArray); /* of them that CFBundle would use in the current application context. */ /* To determine the localizations that would be used for a particular */ /* bundle in the current application context, apply this function to the */ - /* result of CFBundleCopyBundleLocalizations. */ + /* result of CFBundleCopyBundleLocalizations(). */ -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED CF_EXPORT -CFArrayRef CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, CFArrayRef prefArray); +CFArrayRef CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, CFArrayRef prefArray) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER; /* 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. */ /* If prefArray is NULL, the current user's actual preferred localizations will */ - /* be used. This is not the same as CFBundleCopyPreferredLocalizationsFromArray, */ + /* be used. This is not the same as CFBundleCopyPreferredLocalizationsFromArray(), */ /* because that function takes the current application context into account. */ /* To determine the localizations that another application would use, apply */ - /* this function to the result of CFBundleCopyBundleLocalizations. */ -#endif + /* this function to the result of CFBundleCopyBundleLocalizations(). */ CF_EXPORT CFURLRef CFBundleCopyResourceURLForLocalization(CFBundleRef bundle, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName, CFStringRef localizationName); CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfTypeForLocalization(CFBundleRef bundle, CFStringRef resourceType, CFStringRef subDirName, CFStringRef localizationName); + /* The localizationName argument to CFBundleCopyResourceURLForLocalization() or */ + /* CFBundleCopyResourceURLsOfTypeForLocalization() must be identical to one of the */ + /* localizations in the bundle, as returned by CFBundleCopyBundleLocalizations(). */ + /* It is recommended that either CFBundleCopyPreferredLocalizationsFromArray() or */ + /* CFBundleCopyLocalizationsForPreferences() be used to select the localization. */ -#if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED /* =================== Unbundled application info ===================== */ /* 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); - /* For a directory URL, this is equivalent to CFBundleCopyInfoDictionaryInDirectory. */ - /* For a plain file URL representing an unbundled application, this will attempt to read */ - /* an info dictionary either from the (__TEXT, __info_plist) section (for a Mach-o file) */ +CFDictionaryRef CFBundleCopyInfoDictionaryForURL(CFURLRef url) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER; + /* 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); - /* For a directory URL, this is equivalent to calling CFBundleCopyBundleLocalizations */ - /* on the corresponding bundle. For a plain file URL representing an unbundled application, */ +CFArrayRef CFBundleCopyLocalizationsForURL(CFURLRef url) AVAILABLE_MAC_OS_X_VERSION_10_2_AND_LATER; + /* 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 */ /* CFBundleDevelopmentRegion keys in the dictionary returned by CFBundleCopyInfoDictionaryForURL,*/ - /* or a 'vers' resource if those are not present. */ -#endif + /* 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; + /* 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. */ /* ==================== Primitive Code Loading API ==================== */ /* This API abstracts the various different executable formats supported on */ /* various platforms. It can load DYLD, CFM, or DLL shared libraries (on their */ /* appropriate platforms) and gives a uniform API for looking up functions. */ -/* Note that Cocoa-based bundles containing Objective-C or Java code must */ -/* be loaded with NSBundle, not CFBundle. Once they are loaded, however, */ -/* either CFBundle or NSBundle can be used. */ CF_EXPORT CFURLRef CFBundleCopyExecutableURL(CFBundleRef bundle); +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +enum { + kCFBundleExecutableArchitectureI386 = 0x00000007, + kCFBundleExecutableArchitecturePPC = 0x00000012, + kCFBundleExecutableArchitectureX86_64 = 0x01000007, + kCFBundleExecutableArchitecturePPC64 = 0x01000012 +}; +#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 */ + CF_EXPORT -Boolean CFBundleIsExecutableLoaded(CFBundleRef bundle); +CFArrayRef CFBundleCopyExecutableArchitectures(CFBundleRef bundle) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; + /* 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; + /* 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. */ + /* If this function detects problems, it will return false, and return a CFError by reference. */ + /* 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; + /* 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. */ + /* It is the responsibility of the caller to release the CFError. */ CF_EXPORT Boolean CFBundleLoadExecutable(CFBundleRef bundle); +CF_EXPORT +Boolean CFBundleIsExecutableLoaded(CFBundleRef bundle); + CF_EXPORT void CFBundleUnloadExecutable(CFBundleRef bundle); @@ -294,8 +328,14 @@ CFPlugInRef CFBundleGetPlugIn(CFBundleRef bundle); /* ==================== Resource Manager-Related API ==================== */ +#if __LP64__ +typedef int CFBundleRefNum; +#else +typedef SInt16 CFBundleRefNum; +#endif + CF_EXPORT -short CFBundleOpenBundleResourceMap(CFBundleRef bundle); +CFBundleRefNum CFBundleOpenBundleResourceMap(CFBundleRef bundle); /* This function opens the non-localized and the localized resource files */ /* (if any) for the bundle, creates and makes current a single read-only */ /* resource map combining both, and returns a reference number for it. */ @@ -303,16 +343,14 @@ short CFBundleOpenBundleResourceMap(CFBundleRef bundle); /* and returns distinct reference numbers. */ CF_EXPORT -SInt32 CFBundleOpenBundleResourceFiles(CFBundleRef bundle, short *refNum, short *localizedRefNum); - /* Similar to CFBundleOpenBundleResourceMap, except that it creates two */ +SInt32 CFBundleOpenBundleResourceFiles(CFBundleRef bundle, CFBundleRefNum *refNum, CFBundleRefNum *localizedRefNum); + /* Similar to CFBundleOpenBundleResourceMap(), except that it creates two */ /* separate resource maps and returns reference numbers for both. */ CF_EXPORT -void CFBundleCloseBundleResourceMap(CFBundleRef bundle, short refNum); +void CFBundleCloseBundleResourceMap(CFBundleRef bundle, CFBundleRefNum refNum); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFBUNDLE__ */ diff --git a/PlugIn.subproj/CFBundlePriv.h b/CFBundlePriv.h similarity index 92% rename from PlugIn.subproj/CFBundlePriv.h rename to CFBundlePriv.h index 1c8603d..acac0a4 100644 --- a/PlugIn.subproj/CFBundlePriv.h +++ b/CFBundlePriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFBundlePriv.h - Copyright (c) 1999-2005, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBUNDLEPRIV__) @@ -34,9 +34,7 @@ #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN /* Finder stuff */ CF_EXPORT @@ -125,12 +123,18 @@ CFBundleRef _CFBundleCreateIfLooksLikeBundle(CFAllocatorRef allocator, CFURLRef CF_EXPORT CFBundleRef _CFBundleGetMainBundleIfLooksLikeBundle(void); +CF_EXPORT +Boolean _CFBundleMainBundleInfoDictionaryComesFromResourceFork(void); + CF_EXPORT CFBundleRef _CFBundleCreateWithExecutableURLIfLooksLikeBundle(CFAllocatorRef allocator, CFURLRef url); CF_EXPORT CFURLRef _CFBundleCopyMainBundleExecutableURL(Boolean *looksLikeBundle); +CF_EXPORT +CFBundleRef _CFBundleGetExistingBundleWithBundleURL(CFURLRef bundleURL); + /* Functions for examining the structure of a bundle */ CF_EXPORT @@ -204,6 +208,9 @@ void _CFBundleFlushCaches(void); CF_EXPORT 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 void _CFBundleSetStringsFilesShared(CFBundleRef bundle, Boolean flag); @@ -247,14 +254,12 @@ CF_EXPORT CFArrayRef _CFBundleCopyResourceURLsOfTypeForLanguage(CFBundleRef bundle, CFStringRef resourceType, CFStringRef subDirName, CFStringRef language); // deprecated in favor of CFBundleCopyResourceURLsOfTypeForLocalization CF_EXPORT -SInt16 _CFBundleOpenBundleResourceFork(CFBundleRef bundle); // deprecated in favor of CFBundleOpenBundleResourceMap +CFBundleRefNum _CFBundleOpenBundleResourceFork(CFBundleRef bundle); // deprecated in favor of CFBundleOpenBundleResourceMap CF_EXPORT void _CFBundleCloseBundleResourceFork(CFBundleRef bundle); // deprecated in favor of CFBundleCloseBundleResourceMap -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFBUNDLEPRIV__ */ diff --git a/PlugIn.subproj/CFBundle_BinaryTypes.h b/CFBundle_BinaryTypes.h similarity index 83% rename from PlugIn.subproj/CFBundle_BinaryTypes.h rename to CFBundle_BinaryTypes.h index 6585a02..ff70bce 100644 --- a/PlugIn.subproj/CFBundle_BinaryTypes.h +++ b/CFBundle_BinaryTypes.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,28 +21,29 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFBundle_BinaryTypes.h - Copyright (c) 1999-2005, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBUNDLE_BINARYTYPES__) #define __COREFOUNDATION_CFBUNDLE_BINARYTYPES__ 1 -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN -/* We support CFM on OS8 and on PPC OSX */ -/* We support DYLD on OSX only */ -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX || 0 +#if !defined(DISABLE_DYLD_USAGE) #define BINARY_SUPPORT_DYLD 1 #endif - -/* We support DLL on Windows only */ -#if defined(__WIN32__) +#if !defined(DISABLE_DLFCN_USAGE) +#define BINARY_SUPPORT_DLFCN 1 +#endif +#elif 0 || 0 #define BINARY_SUPPORT_DLL 1 +#else +#error Unknown or unspecified DEPLOYMENT_TARGET #endif + typedef enum { __CFBundleUnknownBinary, __CFBundleCFMBinary, @@ -64,9 +65,7 @@ typedef enum { kCFBundleDLLExecutableType } CFBundleExecutableType; -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFBUNDLE_BINARYTYPES__ */ diff --git a/PlugIn.subproj/CFBundle_Internal.h b/CFBundle_Internal.h similarity index 84% rename from PlugIn.subproj/CFBundle_Internal.h rename to CFBundle_Internal.h index 3f6be1f..c6213b9 100644 --- a/PlugIn.subproj/CFBundle_Internal.h +++ b/CFBundle_Internal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFBundle_Internal.h - Copyright (c) 1999-2005, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBUNDLE_INTERNAL__) @@ -30,29 +30,36 @@ #include #include #include +#include #include "CFInternal.h" #include "CFPlugIn_Factory.h" #include "CFBundle_BinaryTypes.h" -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN -#define __kCFLogBundle 21 -#define __kCFLogPlugIn 22 +#define __kCFLogBundle 3 +#define __kCFLogPlugIn 3 -#if defined(__WIN32) +#if DEPLOYMENT_TARGET_MACOSX || 0 +#define PLATFORM_PATH_STYLE kCFURLPOSIXPathStyle +#elif 0 || 0 #define PLATFORM_PATH_STYLE kCFURLWindowsPathStyle -#elif defined (__MACOS8__) -#define PLATFORM_PATH_STYLE kCFURLHFSPathStyle #else -#define PLATFORM_PATH_STYLE kCFURLPOSIXPathStyle +#error Unknown or unspecified DEPLOYMENT_TARGET #endif +#define CFBundleExecutableNotFoundError 4 +#define CFBundleExecutableNotLoadableError 3584 +#define CFBundleExecutableArchitectureMismatchError 3585 +#define CFBundleExecutableRuntimeMismatchError 3586 +#define CFBundleExecutableLoadError 3587 +#define CFBundleExecutableLinkError 3588 + typedef struct __CFResourceData { CFMutableDictionaryRef _stringTableCache; Boolean _executableLacksResourceFork; - char _padding[3]; + Boolean _infoDictionaryFromResourceFork; + char _padding[2]; } _CFResourceData; extern _CFResourceData *__CFBundleGetResourceData(CFBundleRef bundle); @@ -85,6 +92,7 @@ extern CFURLRef _CFBundleCopyResourceForkURLMayBeLocal(CFBundleRef bundle, Boole extern CFDictionaryRef _CFBundleCopyInfoDictionaryInResourceForkWithAllocator(CFAllocatorRef alloc, CFURLRef url); extern CFStringRef _CFBundleCopyBundleDevelopmentRegionFromVersResource(CFBundleRef bundle); extern CFDictionaryRef _CFBundleCopyInfoDictionaryInExecutable(CFURLRef url); +extern CFArrayRef _CFBundleCopyArchitecturesForExecutable(CFURLRef url); extern void _CFBundleAddPreferredLprojNamesInDirectory(CFAllocatorRef alloc, CFURLRef bundleURL, UInt8 version, CFDictionaryRef infoDict, CFMutableArrayRef lprojNames, CFStringRef devLang); @@ -105,33 +113,31 @@ extern void _CFBundleUnloadScheduledBundles(void); // DYLD API extern __CFPBinaryType _CFBundleGrokBinaryType(CFURLRef executableURL); extern Boolean _CFBundleDYLDCheckLoaded(CFBundleRef bundle); -extern Boolean _CFBundleDYLDLoadBundle(CFBundleRef bundle); -extern Boolean _CFBundleDYLDLoadFramework(CFBundleRef bundle); +extern Boolean _CFBundleDYLDLoadBundle(CFBundleRef bundle, Boolean forceGlobal, CFErrorRef *error); +extern Boolean _CFBundleDYLDLoadFramework(CFBundleRef bundle, CFErrorRef *error); extern void _CFBundleDYLDUnloadBundle(CFBundleRef bundle); extern void *_CFBundleDYLDGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName); extern CFArrayRef _CFBundleDYLDCopyLoadedImagePathsIfChanged(void); extern CFArrayRef _CFBundleDYLDCopyLoadedImagePathsForHint(CFStringRef hint); -#endif +#endif /* BINARY_SUPPORT_DYLD */ + +#if defined(BINARY_SUPPORT_DLFCN) +// dlfcn API +extern Boolean _CFBundleDlfcnCheckLoaded(CFBundleRef bundle); +extern Boolean _CFBundleDlfcnPreflight(CFBundleRef bundle, CFErrorRef *error); +extern Boolean _CFBundleDlfcnLoadBundle(CFBundleRef bundle, Boolean forceGlobal, CFErrorRef *error); +extern Boolean _CFBundleDlfcnLoadFramework(CFBundleRef bundle, CFErrorRef *error); +extern void _CFBundleDlfcnUnload(CFBundleRef bundle); +extern void *_CFBundleDlfcnGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName); +#endif /* BINARY_SUPPORT_DLFCN */ -#if defined(BINARY_SUPPORT_CFM) && defined(__ppc__) -// CFM API -#if defined(__MACOS8__) -#include -#else -#endif -extern Boolean _CFBundleCFMLoad(CFBundleRef bundle); -extern void _CFBundleCFMConnect(CFBundleRef bundle); -extern void _CFBundleCFMUnload(CFBundleRef bundle); -extern void *__CFBundleCFMGetSymbol(void *connID, ConstStr255Param name, CFragSymbolClass class); -extern void *_CFBundleCFMGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName, CFragSymbolClass class); -#endif /* BINARY_SUPPORT_CFM && __ppc__ */ #if defined(BINARY_SUPPORT_DLL) -extern Boolean _CFBundleDLLLoad(CFBundleRef bundle); +extern Boolean _CFBundleDLLLoad(CFBundleRef bundle, CFErrorRef *error); extern void _CFBundleDLLUnload(CFBundleRef bundle); extern void *_CFBundleDLLGetSymbolByName(CFBundleRef bundle, CFStringRef symbolName); -#endif BINARY_SUPPORT_DLL +#endif /* BINARY_SUPPORT_DLL */ /* Private PlugIn-related CFBundle API */ @@ -215,6 +221,10 @@ extern void _CFPlugInRemoveFactory(CFPlugInRef plugIn, _CFPFactory *factory); #define _CFBundleLocalizedResourceForkFileName CFSTR("Localized") +#if 0 || 0 +#define _CFBundleWindowsResourceDirectoryExtension CFSTR("resources") +#endif + /* Old platform names (no longer used) */ #define _CFBundleMacOSXPlatformName_OLD CFSTR("macintosh") #define _CFBundleAlternateMacOSXPlatformName_OLD CFSTR("nextstep") @@ -224,9 +234,7 @@ extern void _CFPlugInRemoveFactory(CFPlugInRef plugIn, _CFPFactory *factory); #define _CFBundleMacOSXInfoPlistPlatformName_OLD CFSTR("macos") #define _CFBundleWindowsInfoPlistPlatformName_OLD CFSTR("win32") -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFBUNDLE_INTERNAL__ */ diff --git a/PlugIn.subproj/CFBundle_Resources.c b/CFBundle_Resources.c similarity index 76% rename from PlugIn.subproj/CFBundle_Resources.c rename to CFBundle_Resources.c index cd21ecd..fc9ddae 100644 --- a/PlugIn.subproj/CFBundle_Resources.c +++ b/CFBundle_Resources.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,16 +21,15 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFBundle_Resources.c - Copyright 1999-2002, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007 Apple Inc. All rights reserved. Responsibility: Doug Davidson */ -#if defined(__MACOS8__) || defined(__WIN32__) -#define USE_GETDIRENTRIES 0 -#else -#define USE_GETDIRENTRIES 1 +#if DEPLOYMENT_TARGET_MACOSX +#define READ_DIRECTORIES 1 #endif -#define GETDIRENTRIES_CACHE_CAPACITY 128 + +#define READ_DIRECTORIES_CACHE_CAPACITY 128 #include "CFBundle_Internal.h" #include @@ -40,50 +39,46 @@ #include #include "CFInternal.h" #include "CFPriv.h" - -/* Unixy & Windows Headers */ #include #include -#include #include -#if USE_GETDIRENTRIES -#include +#include + +#if DEPLOYMENT_TARGET_MACOSX +#include +#include #endif +#if READ_DIRECTORIES +#include +#endif /* READ_DIRECTORIES */ + + // All new-style bundles will have these extensions. CF_INLINE CFStringRef _CFGetPlatformName(void) { - // MF:!!! This used to be based on NSInterfaceStyle, not hard-wired by compiler. -#if defined(__WIN32__) - return _CFBundleWindowsPlatformName; -#elif defined(__MACOS8__) - return _CFBundleMacOS8PlatformName; -#elif defined (__MACH__) +#if DEPLOYMENT_TARGET_MACOSX return _CFBundleMacOSXPlatformName; -#elif defined(__svr4__) +#elif DEPLOYMENT_TARGET_SOLARIS return _CFBundleSolarisPlatformName; -#elif defined(__hpux__) +#elif DEPLOYMENT_TARGET_HPUX return _CFBundleHPUXPlatformName; -#elif defined(__LINUX__) +#elif DEPLOYMENT_TARGET_LINUX return _CFBundleLinuxPlatformName; -#elif defined(__FREEBSD__) +#elif DEPLOYMENT_TARGET_FREEBSD return _CFBundleFreeBSDPlatformName; #else - return CFSTR(""); +#error Unknown or unspecified DEPLOYMENT_TARGET #endif } CF_INLINE CFStringRef _CFGetAlternatePlatformName(void) { -#if defined (__MACH__) +#if DEPLOYMENT_TARGET_MACOSX return _CFBundleAlternateMacOSXPlatformName; -#elif defined(__MACOS8__) - return _CFBundleAlternateMacOS8PlatformName; -#else - return CFSTR(""); #endif } -static CFSpinLock_t CFBundleResourceGlobalDataLock = 0; +static CFSpinLock_t CFBundleResourceGlobalDataLock = CFSpinLockInit; static UniChar *_AppSupportUniChars1 = NULL; static CFIndex _AppSupportLen1 = 0; static UniChar *_AppSupportUniChars2 = NULL; @@ -122,7 +117,7 @@ static void _CFBundleInitStaticUniCharBuffers(void) { _GlobalResourcesLen = CFStringGetLength(globalResourcesStr); _InfoExtensionLen = CFStringGetLength(infoExtensionStr); - _AppSupportUniChars1 = CFAllocatorAllocate(alloc, sizeof(UniChar) * (_AppSupportLen1 + _AppSupportLen2 + _ResourcesLen + _PlatformLen + _AlternatePlatformLen + _LprojLen + _GlobalResourcesLen + _InfoExtensionLen), 0); + _AppSupportUniChars1 = (UniChar *)CFAllocatorAllocate(alloc, sizeof(UniChar) * (_AppSupportLen1 + _AppSupportLen2 + _ResourcesLen + _PlatformLen + _AlternatePlatformLen + _LprojLen + _GlobalResourcesLen + _InfoExtensionLen), 0); _AppSupportUniChars2 = _AppSupportUniChars1 + _AppSupportLen1; _ResourcesUniChars = _AppSupportUniChars2 + _AppSupportLen2; _PlatformUniChars = _ResourcesUniChars + _ResourcesLen; @@ -131,41 +126,23 @@ static void _CFBundleInitStaticUniCharBuffers(void) { _GlobalResourcesUniChars = _LprojUniChars + _LprojLen; _InfoExtensionUniChars = _GlobalResourcesUniChars + _GlobalResourcesLen; - if (_AppSupportLen1 > 0) { - CFStringGetCharacters(appSupportStr1, CFRangeMake(0, _AppSupportLen1), _AppSupportUniChars1); - } - if (_AppSupportLen2 > 0) { - CFStringGetCharacters(appSupportStr2, CFRangeMake(0, _AppSupportLen2), _AppSupportUniChars2); - } - if (_ResourcesLen > 0) { - CFStringGetCharacters(resourcesStr, CFRangeMake(0, _ResourcesLen), _ResourcesUniChars); - } - if (_PlatformLen > 0) { - CFStringGetCharacters(platformStr, CFRangeMake(0, _PlatformLen), _PlatformUniChars); - } - if (_AlternatePlatformLen > 0) { - CFStringGetCharacters(alternatePlatformStr, CFRangeMake(0, _AlternatePlatformLen), _AlternatePlatformUniChars); - } - if (_LprojLen > 0) { - CFStringGetCharacters(lprojStr, CFRangeMake(0, _LprojLen), _LprojUniChars); - } - if (_GlobalResourcesLen > 0) { - CFStringGetCharacters(globalResourcesStr, CFRangeMake(0, _GlobalResourcesLen), _GlobalResourcesUniChars); - } - if (_InfoExtensionLen > 0) { - CFStringGetCharacters(infoExtensionStr, CFRangeMake(0, _InfoExtensionLen), _InfoExtensionUniChars); - } + if (_AppSupportLen1 > 0) CFStringGetCharacters(appSupportStr1, CFRangeMake(0, _AppSupportLen1), _AppSupportUniChars1); + if (_AppSupportLen2 > 0) CFStringGetCharacters(appSupportStr2, CFRangeMake(0, _AppSupportLen2), _AppSupportUniChars2); + if (_ResourcesLen > 0) CFStringGetCharacters(resourcesStr, CFRangeMake(0, _ResourcesLen), _ResourcesUniChars); + if (_PlatformLen > 0) CFStringGetCharacters(platformStr, CFRangeMake(0, _PlatformLen), _PlatformUniChars); + if (_AlternatePlatformLen > 0) CFStringGetCharacters(alternatePlatformStr, CFRangeMake(0, _AlternatePlatformLen), _AlternatePlatformUniChars); + 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); } CF_INLINE void _CFEnsureStaticBuffersInited(void) { __CFSpinLock(&CFBundleResourceGlobalDataLock); - if (_AppSupportUniChars1 == NULL) { - _CFBundleInitStaticUniCharBuffers(); - } + if (!_AppSupportUniChars1) _CFBundleInitStaticUniCharBuffers(); __CFSpinUnlock(&CFBundleResourceGlobalDataLock); } -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES static CFMutableDictionaryRef contentsCache = NULL; static CFMutableDictionaryRef directoryContentsCache = NULL; @@ -192,16 +169,18 @@ static CFArrayRef _CFBundleCopyDirectoryContentsAtPath(CFStringRef path, _CFBund __CFSpinUnlock(&CFBundleResourceGlobalDataLock); if (!result) { - Boolean tryToOpen = true, allDots = true; - char cpathBuff[CFMaxPathSize], dirge[8192]; + Boolean tryToOpen = false, allDots = true; + char cpathBuff[CFMaxPathSize]; CFIndex cpathLen = 0, idx, lastSlashIdx = 0; - int fd = -1, numread; - long basep = 0; - CFMutableArrayRef contents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks), directoryContents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks), unknownContents = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + DIR *dirp = NULL; + struct dirent *dent; + CFMutableArrayRef contents = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks), directoryContents = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks), unknownContents = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); CFStringRef dirName, name; struct stat statBuf; - if (_CFStringGetFileSystemRepresentation(path, cpathBuff, CFMaxPathSize)) { + cpathBuff[0] = '\0'; + if (CFStringGetFileSystemRepresentation(path, cpathBuff, CFMaxPathSize)) { + tryToOpen = true; cpathLen = strlen(cpathBuff); // First see whether we already know that the directory doesn't exist @@ -211,9 +190,9 @@ static CFArrayRef _CFBundleCopyDirectoryContentsAtPath(CFStringRef path, _CFBund } if (lastSlashIdx > 0 && lastSlashIdx + 1 < cpathLen && !allDots) { cpathBuff[lastSlashIdx] = '\0'; - dirName = CFStringCreateWithCString(NULL, cpathBuff, CFStringFileSystemEncoding()); + dirName = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, cpathBuff); if (dirName) { - name = CFStringCreateWithCString(NULL, cpathBuff + lastSlashIdx + 1, CFStringFileSystemEncoding()); + name = CFStringCreateWithFileSystemRepresentation(kCFAllocatorSystemDefault, cpathBuff + lastSlashIdx + 1); if (name) { // ??? we might like to use directoryContentsCache rather than contentsCache here, but we cannot unless we resolve DT_LNKs below CFArrayRef dirDirContents = NULL; @@ -234,43 +213,39 @@ static CFArrayRef _CFBundleCopyDirectoryContentsAtPath(CFStringRef path, _CFBund } cpathBuff[lastSlashIdx] = '/'; } - if (tryToOpen) fd = open(cpathBuff, O_RDONLY, 0777); - } - if (fd >= 0 && fstat(fd, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFDIR) { - while ((numread = getdirentries(fd, dirge, sizeof(dirge), &basep)) > 0) { - struct dirent *dent; - for (dent = (struct dirent *)dirge; dent < (struct dirent *)(dirge + numread); dent = (struct dirent *)((char *)dent + dent->d_reclen)) { - CFIndex nameLen = strlen(dent->d_name); - if (0 == dent->d_fileno || (dent->d_name[0] == '.' && (nameLen == 1 || (nameLen == 2 && dent->d_name[1] == '.')))) continue; - name = CFStringCreateWithCString(NULL, dent->d_name, CFStringFileSystemEncoding()); - if (NULL != name) { - // ??? should we follow links for DT_LNK? unless we do, results are approximate, but for performance reasons we do not - // ??? likewise for DT_UNKNOWN - // ??? the utility of distinguishing directories from other contents is somewhat doubtful anyway - CFArrayAppendValue(contents, name); - if (dent->d_type == DT_DIR) { - CFArrayAppendValue(directoryContents, name); - } else if (dent->d_type == DT_UNKNOWN) { - CFArrayAppendValue(unknownContents, name); - } - CFRelease(name); + } + if (tryToOpen && stat(cpathBuff, &statBuf) == 0 && (statBuf.st_mode & S_IFMT) == S_IFDIR && (dirp = opendir(cpathBuff))) { + while ((dent = readdir(dirp))) { + CFIndex nameLen = strlen(dent->d_name); + 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) { + // ??? should we follow links for DT_LNK? unless we do, results are approximate, but for performance reasons we do not + // ??? likewise for DT_UNKNOWN + // ??? the utility of distinguishing directories from other contents is somewhat doubtful anyway + CFArrayAppendValue(contents, name); + if (dent->d_type == DT_DIR) { + CFArrayAppendValue(directoryContents, name); + } else if (dent->d_type == DT_UNKNOWN) { + CFArrayAppendValue(unknownContents, name); } + CFRelease(name); } } + (void)closedir(dirp); } - if (fd >= 0) close(fd); __CFSpinLock(&CFBundleResourceGlobalDataLock); - if (!contentsCache) contentsCache = CFDictionaryCreateMutable(NULL, GETDIRENTRIES_CACHE_CAPACITY, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (GETDIRENTRIES_CACHE_CAPACITY <= CFDictionaryGetCount(contentsCache)) CFDictionaryRemoveAllValues(contentsCache); + if (!contentsCache) contentsCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, READ_DIRECTORIES_CACHE_CAPACITY, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (READ_DIRECTORIES_CACHE_CAPACITY <= CFDictionaryGetCount(contentsCache)) CFDictionaryRemoveAllValues(contentsCache); CFDictionaryAddValue(contentsCache, path, contents); - if (!directoryContentsCache) directoryContentsCache = CFDictionaryCreateMutable(NULL, GETDIRENTRIES_CACHE_CAPACITY, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (GETDIRENTRIES_CACHE_CAPACITY <= CFDictionaryGetCount(directoryContentsCache)) CFDictionaryRemoveAllValues(directoryContentsCache); + if (!directoryContentsCache) directoryContentsCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, READ_DIRECTORIES_CACHE_CAPACITY, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (READ_DIRECTORIES_CACHE_CAPACITY <= CFDictionaryGetCount(directoryContentsCache)) CFDictionaryRemoveAllValues(directoryContentsCache); CFDictionaryAddValue(directoryContentsCache, path, directoryContents); - if (!unknownContentsCache) unknownContentsCache = CFDictionaryCreateMutable(NULL, GETDIRENTRIES_CACHE_CAPACITY, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - if (GETDIRENTRIES_CACHE_CAPACITY <= CFDictionaryGetCount(unknownContentsCache)) CFDictionaryRemoveAllValues(unknownContentsCache); + if (!unknownContentsCache) unknownContentsCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, READ_DIRECTORIES_CACHE_CAPACITY, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (READ_DIRECTORIES_CACHE_CAPACITY <= CFDictionaryGetCount(unknownContentsCache)) CFDictionaryRemoveAllValues(unknownContentsCache); CFDictionaryAddValue(unknownContentsCache, path, unknownContents); if (contentsType == _CFBundleUnknownContents) { @@ -298,14 +273,12 @@ static void _CFBundleFlushContentsCaches(void) { } static void _CFBundleFlushContentsCacheForPath(CFMutableDictionaryRef cache, CFStringRef path) { - CFStringRef keys[GETDIRENTRIES_CACHE_CAPACITY]; + CFStringRef keys[READ_DIRECTORIES_CACHE_CAPACITY]; unsigned i, count = CFDictionaryGetCount(cache); - if (count <= GETDIRENTRIES_CACHE_CAPACITY) { + if (count <= READ_DIRECTORIES_CACHE_CAPACITY) { CFDictionaryGetKeysAndValues(cache, (const void **)keys, NULL); for (i = 0; i < count; i++) { - if (CFStringFindWithOptions(keys[i], path, CFRangeMake(0, CFStringGetLength(keys[i])), kCFCompareAnchored|kCFCompareCaseInsensitive, NULL)) { - CFDictionaryRemoveValue(cache, keys[i]); - } + if (CFStringFindWithOptions(keys[i], path, CFRangeMake(0, CFStringGetLength(keys[i])), kCFCompareAnchored|kCFCompareCaseInsensitive, NULL)) CFDictionaryRemoveValue(cache, keys[i]); } } } @@ -318,36 +291,30 @@ static void _CFBundleFlushContentsCachesForPath(CFStringRef path) { __CFSpinUnlock(&CFBundleResourceGlobalDataLock); } -#endif /* USE_GETDIRENTRIES */ +#endif /* READ_DIRECTORIES */ CF_EXPORT void _CFBundleFlushCachesForURL(CFURLRef url) { -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES CFURLRef absoluteURL = CFURLCopyAbsoluteURL(url); CFStringRef path = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); _CFBundleFlushContentsCachesForPath(path); CFRelease(path); CFRelease(absoluteURL); -#endif /* USE_GETDIRENTRIES */ +#endif /* READ_DIRECTORIES */ } CF_EXPORT void _CFBundleFlushCaches(void) { -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES _CFBundleFlushContentsCaches(); -#endif /* USE_GETDIRENTRIES */ +#endif /* READ_DIRECTORIES */ } __private_extern__ Boolean _CFIsResourceAtURL(CFURLRef url, Boolean *isDir) { Boolean exists; SInt32 mode; - if (_CFGetFileProperties(NULL, url, &exists, &mode, NULL, NULL, NULL, NULL) == 0) { - if (isDir) { - *isDir = ((exists && ((mode & S_IFMT) == S_IFDIR)) ? true : false); - } -#if defined(__MACOS8__) - return (exists); -#else + if (_CFGetFileProperties(kCFAllocatorSystemDefault, url, &exists, &mode, NULL, NULL, NULL, NULL) == 0) { + if (isDir) *isDir = ((exists && ((mode & S_IFMT) == S_IFDIR)) ? true : false); return (exists && (mode & 0444)); -#endif /* __MACOS8__ */ } else { return false; } @@ -356,13 +323,47 @@ __private_extern__ Boolean _CFIsResourceAtURL(CFURLRef url, Boolean *isDir) { __private_extern__ Boolean _CFIsResourceAtPath(CFStringRef path, Boolean *isDir) { Boolean result = false; CFURLRef url = CFURLCreateWithFileSystemPath(CFGetAllocator(path), path, PLATFORM_PATH_STYLE, false); - if (url != NULL) { + if (url) { result = _CFIsResourceAtURL(url, isDir); CFRelease(url); } return result; } +#if READ_DIRECTORIES +static CFArrayRef _CFCopyTypesForSearchBundleDirectory(CFAllocatorRef alloc, UniChar *pathUniChars, CFIndex pathLen, UniChar *nameUniChars, CFIndex nameLen, CFArrayRef resTypes, CFMutableStringRef cheapStr, CFMutableStringRef tmpString, uint8_t version) { + CFMutableArrayRef result = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks); + CFArrayRef contents; + CFRange contentsRange, resultRange = CFRangeMake(0, 0); + CFIndex dirPathLen = pathLen, numResTypes = CFArrayGetCount(resTypes), i, j; + + CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, dirPathLen, dirPathLen); + CFStringReplaceAll(cheapStr, tmpString); + //fprintf(stderr, "looking in ");CFShow(cheapStr); + contents = _CFBundleCopyDirectoryContentsAtPath(cheapStr, _CFBundleAllContents); + contentsRange = CFRangeMake(0, CFArrayGetCount(contents)); + + CFStringSetExternalCharactersNoCopy(tmpString, nameUniChars, nameLen, nameLen); + CFStringReplaceAll(cheapStr, tmpString); + for (i = 0; i < contentsRange.length; i++) { + CFStringRef content = CFArrayGetValueAtIndex(contents, i); + if (CFStringHasPrefix(content, cheapStr)) { + //fprintf(stderr, "found ");CFShow(content); + for (j = 0; j < numResTypes; j++) { + CFStringRef resType = CFArrayGetValueAtIndex(resTypes, j); + if (!CFArrayContainsValue(result, resultRange, resType) && CFStringHasSuffix(content, resType)) { + CFArrayAppendValue(result, resType); + resultRange.length = CFArrayGetCount(result); + } + } + } + } + //fprintf(stderr, "result ");CFShow(result); + CFRelease(contents); + return result; +} +#endif /* READ_DIRECTORIES */ + 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) { // pathUniChars is the full path to the directory we are searching. // nameUniChars is what we are looking for. @@ -374,7 +375,7 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res Boolean appendSucceeded = true, platformGenericFound = false, platformSpecificFound = false, platformGenericIsDir = false, platformSpecificIsDir = false, platformGenericIsUnknown = false, platformSpecificIsUnknown = false; CFStringRef platformGenericStr = NULL; -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES CFIndex dirPathLen = pathLen; CFArrayRef contents, directoryContents, unknownContents; CFRange contentsRange, directoryContentsRange, unknownContentsRange; @@ -388,13 +389,13 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res directoryContentsRange = CFRangeMake(0, CFArrayGetCount(directoryContents)); unknownContents = _CFBundleCopyDirectoryContentsAtPath(cheapStr, _CFBundleUnknownContents); unknownContentsRange = CFRangeMake(0, CFArrayGetCount(unknownContents)); -#endif +#endif /* READ_DIRECTORIES */ if (nameLen > 0) appendSucceeded = _CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, nameUniChars, nameLen); savedPathLen = pathLen; if (appendSucceeded && typeLen > 0) appendSucceeded = _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, typeUniChars, typeLen); if (appendSucceeded) { -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + dirPathLen + 1, pathLen - dirPathLen - 1, pathLen - dirPathLen - 1); CFStringReplaceAll(cheapStr, tmpString); platformGenericFound = CFArrayContainsValue(contents, contentsRange, cheapStr); @@ -407,16 +408,16 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res (void)_CFIsResourceAtPath(cheapStr, &platformGenericIsDir); //if (platformGenericIsDir) fprintf(stderr, "a directory after all\n"); else fprintf(stderr, "not a directory after all\n"); } -#else +#else /* READ_DIRECTORIES */ CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); platformGenericFound = _CFIsResourceAtPath(cheapStr, &platformGenericIsDir); -#endif +#endif /* READ_DIRECTORIES */ } // Check for platform specific. if (platformGenericFound) { - platformGenericStr = CFStringCreateCopy(alloc, cheapStr); + platformGenericStr = (CFStringRef)CFStringCreateCopy(alloc, cheapStr); if (!platformSpecificFound && (_PlatformLen > 0)) { pathLen = savedPathLen; pathUniChars[pathLen++] = (UniChar)'-'; @@ -424,7 +425,7 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res pathLen += _PlatformLen; if (appendSucceeded && typeLen > 0) appendSucceeded = _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, typeUniChars, typeLen); if (appendSucceeded) { -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars + dirPathLen + 1, pathLen - dirPathLen - 1, pathLen - dirPathLen - 1); CFStringReplaceAll(cheapStr, tmpString); platformSpecificFound = CFArrayContainsValue(contents, contentsRange, cheapStr); @@ -437,11 +438,11 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res (void)_CFIsResourceAtPath(cheapStr, &platformSpecificIsDir); //if (platformSpecificIsDir) fprintf(stderr, "a directory after all\n"); else fprintf(stderr, "not a directory after all\n"); } -#else +#else /* READ_DIRECTORIES */ CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); platformSpecificFound = _CFIsResourceAtPath(cheapStr, &platformSpecificIsDir); -#endif +#endif /* READ_DIRECTORIES */ } } } @@ -450,56 +451,54 @@ static void _CFSearchBundleDirectory(CFAllocatorRef alloc, CFMutableArrayRef res CFArrayAppendValue(result, url); CFRelease(url); } else if (platformGenericFound) { - CFURLRef url = CFURLCreateWithFileSystemPath(alloc, ((platformGenericStr != NULL) ? platformGenericStr : cheapStr), PLATFORM_PATH_STYLE, platformGenericIsDir); + CFURLRef url = CFURLCreateWithFileSystemPath(alloc, platformGenericStr ? platformGenericStr : cheapStr, PLATFORM_PATH_STYLE, platformGenericIsDir); CFArrayAppendValue(result, url); CFRelease(url); } - if (platformGenericStr != NULL) { - CFRelease(platformGenericStr); - } -#if USE_GETDIRENTRIES + if (platformGenericStr) CFRelease(platformGenericStr); +#if READ_DIRECTORIES CFRelease(contents); CFRelease(directoryContents); CFRelease(unknownContents); -#endif +#endif /* READ_DIRECTORIES */ } 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) { - if (nameLen > 0) { // If we have a resName, just call the search API. We may have to loop over the resTypes. if (!resTypes) { _CFSearchBundleDirectory(alloc, result, workingUniChars, workingLen, nameUniChars, nameLen, NULL, 0, cheapStr, tmpString, version); } else { + CFArrayRef subResTypes = resTypes; + Boolean releaseSubResTypes = false; CFIndex i, c = CFArrayGetCount(resTypes); - for (i=0; i 2) { + // this is an optimization we employ when searching for large numbers of types, if the directory contents are available + // we scan the directory contents and restrict the list of resTypes to the types that might actually occur with the specified name + subResTypes = _CFCopyTypesForSearchBundleDirectory(alloc, workingUniChars, workingLen, nameUniChars, nameLen, resTypes, cheapStr, tmpString, version); + c = CFArrayGetCount(subResTypes); + releaseSubResTypes = true; + } +#endif /* READ_DIRECTORIES */ + for (i = 0; i < c; i++) { + CFStringRef curType = (CFStringRef)CFArrayGetValueAtIndex(subResTypes, i); CFIndex typeLen = CFStringGetLength(curType); -#if defined(__MACOS8__) || defined(__WIN32__) - UniChar *typeChars = CFAllocatorAllocate(alloc, sizeof(UniChar) * typeLen, 0); - if (typeChars) { -#else - UniChar typeChars[typeLen]; -#endif /* __MACOS8__ */ + STACK_BUFFER_DECL(UniChar, typeChars, typeLen); CFStringGetCharacters(curType, CFRangeMake(0, typeLen), typeChars); _CFSearchBundleDirectory(alloc, result, workingUniChars, workingLen, nameUniChars, nameLen, typeChars, typeLen, cheapStr, tmpString, version); - if (limit <= CFArrayGetCount(result)) { - break; - } -#if defined(__MACOS8__) || defined(__WIN32__) - CFAllocatorDeallocate(alloc, typeChars); - } -#endif /* __MACOS8__ */ + if (limit <= CFArrayGetCount(result)) break; } + if (releaseSubResTypes) CFRelease(subResTypes); } } else { // If we have no resName, do it by hand. We may have to loop over the resTypes. - unsigned char cpathBuff[CFMaxPathSize]; + char cpathBuff[CFMaxPathSize]; CFIndex cpathLen; CFMutableArrayRef children; CFStringSetExternalCharactersNoCopy(tmpString, workingUniChars, workingLen, workingLen); - if (!_CFStringGetFileSystemRepresentation(tmpString, cpathBuff, CFMaxPathSize)) return; + if (!CFStringGetFileSystemRepresentation(tmpString, cpathBuff, CFMaxPathSize)) return; cpathLen = strlen(cpathBuff); if (!resTypes) { @@ -507,28 +506,22 @@ static void _CFFindBundleResourcesInRawDir(CFAllocatorRef alloc, UniChar *workin children = _CFContentsOfDirectory(alloc, cpathBuff, NULL, NULL, NULL); if (children) { CFIndex childIndex, childCount = CFArrayGetCount(children); - for (childIndex = 0; childIndex < childCount; childIndex++) { - CFArrayAppendValue(result, CFArrayGetValueAtIndex(children, childIndex)); - } + for (childIndex = 0; childIndex < childCount; childIndex++) CFArrayAppendValue(result, CFArrayGetValueAtIndex(children, childIndex)); CFRelease(children); } } else { CFIndex i, c = CFArrayGetCount(resTypes); - for (i=0; i 255) curLangLen = 255; CFStringGetCharacters(curLangStr, CFRangeMake(0, curLangLen), curLangUniChars); @@ -599,7 +592,7 @@ 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 != NULL) ? CFGetAllocator(bundle) : CFRetain(__CFGetDefaultAllocator())); + CFAllocatorRef alloc = (bundle ? CFGetAllocator(bundle) : (CFAllocatorRef)CFRetain(__CFGetDefaultAllocator())); CFMutableArrayRef result; UniChar *workingUniChars, *nameUniChars, *subDirUniChars; CFIndex nameLen = (resName ? CFStringGetLength(resName) : 0); @@ -615,25 +608,19 @@ CFArrayRef _CFFindBundleResources(CFBundleRef bundle, CFURLRef bundleURL, CFStri // Build UniChar buffers for some of the string pieces we need. // One malloc will do. - nameUniChars = CFAllocatorAllocate(alloc, sizeof(UniChar) * (nameLen + subDirLen + CFMaxPathSize), 0); + nameUniChars = (UniChar *)CFAllocatorAllocate(alloc, sizeof(UniChar) * (nameLen + subDirLen + CFMaxPathSize), 0); subDirUniChars = nameUniChars + nameLen; workingUniChars = subDirUniChars + subDirLen; - if (nameLen > 0) { - CFStringGetCharacters(resName, CFRangeMake(0, nameLen), nameUniChars); - } - if (subDirLen > 0) { - CFStringGetCharacters(subDirName, CFRangeMake(0, subDirLen), subDirUniChars); - } + 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 != NULL) ? CFRetain(bundleURL) : CFBundleCopyBundleURL(bundle)); + bundleURL = (bundleURL ? (CFURLRef)CFRetain(bundleURL) : CFBundleCopyBundleURL(bundle)); absoluteURL = CFURLCopyAbsoluteURL(bundleURL); bundlePath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); CFRelease(absoluteURL); - if ((workingLen = CFStringGetLength(bundlePath)) > 0) { - CFStringGetCharacters(bundlePath, CFRangeMake(0, workingLen), workingUniChars); - } + if ((workingLen = CFStringGetLength(bundlePath)) > 0) CFStringGetCharacters(bundlePath, CFRangeMake(0, workingLen), workingUniChars); CFRelease(bundlePath); CFRelease(bundleURL); savedWorkingLen = workingLen; @@ -664,9 +651,7 @@ CFArrayRef _CFFindBundleResources(CFBundleRef bundle, CFURLRef bundleURL, CFStri CFRelease(cheapStr); CFRelease(tmpString); CFAllocatorDeallocate(alloc, nameUniChars); - if (bundle == NULL) { - CFRelease(alloc); - } + if (!bundle) CFRelease(alloc); return result; } @@ -681,7 +666,7 @@ CF_EXPORT CFURLRef CFBundleCopyResourceURL(CFBundleRef bundle, CFStringRef resou if (types) CFRelease(types); if (array) { - if (CFArrayGetCount(array) > 0) result = CFRetain(CFArrayGetValueAtIndex(array, 0)); + if (CFArrayGetCount(array) > 0) result = (CFURLRef)CFRetain(CFArrayGetValueAtIndex(array, 0)); CFRelease(array); } return result; @@ -710,7 +695,7 @@ CF_EXPORT CFURLRef CFBundleCopyResourceURLForLocalization(CFBundleRef bundle, CF array = _CFFindBundleResources(bundle, NULL, subDirName, languages, resourceName, types, 1, _CFBundleLayoutVersion(bundle)); if (array) { - if (CFArrayGetCount(array) > 0) result = CFRetain(CFArrayGetValueAtIndex(array, 0)); + if (CFArrayGetCount(array) > 0) result = (CFURLRef)CFRetain(CFArrayGetValueAtIndex(array, 0)); CFRelease(array); } @@ -741,27 +726,22 @@ CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRe CFStringRef result = NULL; CFDictionaryRef stringTable = NULL; - if (key == NULL) return (value ? CFRetain(value) : CFRetain(CFSTR(""))); + if (!key) return (value ? (CFStringRef)CFRetain(value) : (CFStringRef)CFRetain(CFSTR(""))); - if ((tableName == NULL) || CFEqual(tableName, CFSTR(""))) { - tableName = _CFBundleDefaultStringTableName; - } - if (__CFBundleGetResourceData(bundle)->_stringTableCache != NULL) { - // See if we have the table cached. - stringTable = CFDictionaryGetValue(__CFBundleGetResourceData(bundle)->_stringTableCache, tableName); - } - if (stringTable == NULL) { + if (!tableName || CFEqual(tableName, CFSTR(""))) tableName = _CFBundleDefaultStringTableName; + if (__CFBundleGetResourceData(bundle)->_stringTableCache) stringTable = (CFDictionaryRef)CFDictionaryGetValue(__CFBundleGetResourceData(bundle)->_stringTableCache, tableName); + if (!stringTable) { // Go load the table. CFURLRef tableURL = CFBundleCopyResourceURL(bundle, tableName, _CFBundleStringTableType, NULL); if (tableURL) { CFStringRef nameForSharing = NULL; - if (stringTable == NULL) { + if (!stringTable) { CFDataRef tableData = NULL; SInt32 errCode; CFStringRef errStr; if (CFURLCreateDataAndPropertiesFromResource(CFGetAllocator(bundle), tableURL, &tableData, NULL, NULL, &errCode)) { - stringTable = CFPropertyListCreateFromXMLData(CFGetAllocator(bundle), tableData, kCFPropertyListImmutable, &errStr); - if (errStr != NULL) { + stringTable = (CFDictionaryRef)CFPropertyListCreateFromXMLData(CFGetAllocator(bundle), tableData, kCFPropertyListImmutable, &errStr); + if (errStr) { CFRelease(errStr); errStr = NULL; } @@ -775,25 +755,21 @@ CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRe if (nameForSharing) CFRelease(nameForSharing); CFRelease(tableURL); } - if (stringTable == NULL) { - stringTable = CFDictionaryCreate(CFGetAllocator(bundle), NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - } - if (__CFBundleGetResourceData(bundle)->_stringTableCache == NULL) { - __CFBundleGetResourceData(bundle)->_stringTableCache = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - } + if (!stringTable) stringTable = CFDictionaryCreate(CFGetAllocator(bundle), NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (!__CFBundleGetResourceData(bundle)->_stringTableCache) __CFBundleGetResourceData(bundle)->_stringTableCache = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(__CFBundleGetResourceData(bundle)->_stringTableCache, tableName, stringTable); CFRelease(stringTable); } - result = CFDictionaryGetValue(stringTable, key); - if (result == NULL) { + result = (CFStringRef)CFDictionaryGetValue(stringTable, key); + if (!result) { static int capitalize = -1; - if (value == NULL) { - result = CFRetain(key); + if (!value) { + result = (CFStringRef)CFRetain(key); } else if (CFEqual(value, CFSTR(""))) { - result = CFRetain(key); + result = (CFStringRef)CFRetain(key); } else { - result = CFRetain(value); + result = (CFStringRef)CFRetain(value); } if (capitalize != 0) { if (capitalize != 0) { @@ -807,25 +783,24 @@ CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRe } else { CFRetain(result); } + if (CFStringHasSuffix(tableName, CFSTR(".nocache")) && __CFBundleGetResourceData(bundle)->_stringTableCache && _CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard)) CFDictionaryRemoveValue(__CFBundleGetResourceData(bundle)->_stringTableCache, tableName); return result; } CF_EXPORT CFURLRef CFBundleCopyResourceURLInDirectory(CFURLRef bundleURL, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName) { CFURLRef result = NULL; - char buff[CFMaxPathSize]; + unsigned char buff[CFMaxPathSize]; CFURLRef newURL = NULL; if (!CFURLGetFileSystemRepresentation(bundleURL, true, buff, CFMaxPathSize)) return NULL; - newURL = CFURLCreateFromFileSystemRepresentation(NULL, buff, strlen(buff), true); - if (NULL == newURL) { - newURL = CFRetain(bundleURL); - } + newURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, buff, strlen((char *)buff), true); + if (!newURL) newURL = (CFURLRef)CFRetain(bundleURL); if (_CFBundleCouldBeBundle(newURL)) { uint8_t version = 0; - CFArrayRef languages = _CFBundleCopyLanguageSearchListInDirectory(NULL, newURL, &version), types = NULL, array; - if (resourceType) types = CFArrayCreate(NULL, (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); + 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); @@ -833,7 +808,7 @@ CF_EXPORT CFURLRef CFBundleCopyResourceURLInDirectory(CFURLRef bundleURL, CFStri if (languages) CFRelease(languages); if (array) { - if (CFArrayGetCount(array) > 0) result = CFRetain(CFArrayGetValueAtIndex(array, 0)); + if (CFArrayGetCount(array) > 0) result = (CFURLRef)CFRetain(CFArrayGetValueAtIndex(array, 0)); CFRelease(array); } } @@ -843,19 +818,17 @@ CF_EXPORT CFURLRef CFBundleCopyResourceURLInDirectory(CFURLRef bundleURL, CFStri CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfTypeInDirectory(CFURLRef bundleURL, CFStringRef resourceType, CFStringRef subDirName) { CFArrayRef array = NULL; - char buff[CFMaxPathSize]; + unsigned char buff[CFMaxPathSize]; CFURLRef newURL = NULL; if (!CFURLGetFileSystemRepresentation(bundleURL, true, buff, CFMaxPathSize)) return NULL; - newURL = CFURLCreateFromFileSystemRepresentation(NULL, buff, strlen(buff), true); - if (NULL == newURL) { - newURL = CFRetain(bundleURL); - } + newURL = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, buff, strlen((char *)buff), true); + if (!newURL) newURL = (CFURLRef)CFRetain(bundleURL); if (_CFBundleCouldBeBundle(newURL)) { uint8_t version = 0; - CFArrayRef languages = _CFBundleCopyLanguageSearchListInDirectory(NULL, newURL, &version), types = NULL; - if (resourceType) types = CFArrayCreate(NULL, (const void **)&resourceType, 1, &kCFTypeArrayCallBacks); + 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); @@ -871,16 +844,16 @@ CF_EXPORT CFArrayRef CFBundleCopyResourceURLsOfTypeInDirectory(CFURLRef bundleUR const char * __CFBundleLocaleAbbreviationsArray = "en_US\0" "fr_FR\0" "en_GB\0" "de_DE\0" "it_IT\0" "nl_NL\0" "nl_BE\0" "sv_SE\0" "es_ES\0" "da_DK\0" "pt_PT\0" "fr_CA\0" "nb_NO\0" "he_IL\0" "ja_JP\0" "en_AU\0" - "ar\0\0\0\0" "fi_FI\0" "fr_CH\0" "de_CH\0" "el_GR\0" "is_IS\0" "mt_MT\0" "\0\0\0\0\0\0" + "ar\0\0\0\0" "fi_FI\0" "fr_CH\0" "de_CH\0" "el_GR\0" "is_IS\0" "mt_MT\0" "el_CY\0" "tr_TR\0" "hr_HR\0" "nl_NL\0" "nl_BE\0" "en_CA\0" "en_CA\0" "pt_PT\0" "nb_NO\0" "da_DK\0" "hi_IN\0" "ur_PK\0" "tr_TR\0" "it_CH\0" "en\0\0\0\0" "\0\0\0\0\0\0" "ro_RO\0" - "el_GR\0" "lt_LT\0" "pl_PL\0" "hu_HU\0" "et_EE\0" "lv_LV\0" "se\0\0\0\0" "fo_FO\0" + "grc\0\0\0" "lt_LT\0" "pl_PL\0" "hu_HU\0" "et_EE\0" "lv_LV\0" "se\0\0\0\0" "fo_FO\0" "fa_IR\0" "ru_RU\0" "ga_IE\0" "ko_KR\0" "zh_CN\0" "zh_TW\0" "th_TH\0" "\0\0\0\0\0\0" "cs_CZ\0" "sk_SK\0" "\0\0\0\0\0\0" "hu_HU\0" "bn\0\0\0\0" "be_BY\0" "uk_UA\0" "\0\0\0\0\0\0" - "el_GR\0" "sr_YU\0" "sl_SI\0" "mk_MK\0" "hr_HR\0" "\0\0\0\0\0\0" "de_DE\0" "pt_BR\0" + "el_GR\0" "sr_CS\0" "sl_SI\0" "mk_MK\0" "hr_HR\0" "\0\0\0\0\0\0" "de_DE\0" "pt_BR\0" "bg_BG\0" "ca_ES\0" "\0\0\0\0\0\0" "gd\0\0\0\0" "gv\0\0\0\0" "br\0\0\0\0" "iu_CA\0" "cy\0\0\0\0" - "en_CA\0" "ga_IE\0" "en_CA\0" "dz_BT\0" "hy_AM\0" "ka_GE\0" "es\0\0\0\0" "es_ES\0" - "to_TO\0" "pl_PL\0" "ca_ES\0" "fr\0\0\0\0" "de_AT\0" "es\0\0\0\0" "gu_IN\0" "pa\0\0\0\0" + "en_CA\0" "ga_IE\0" "en_CA\0" "dz_BT\0" "hy_AM\0" "ka_GE\0" "es_XL\0" "es_ES\0" + "to_TO\0" "pl_PL\0" "ca_ES\0" "fr\0\0\0\0" "de_AT\0" "es_XL\0" "gu_IN\0" "pa\0\0\0\0" "ur_IN\0" "vi_VN\0" "fr_BE\0" "uz_UZ\0" "en_SG\0" "nn_NO\0" "af_ZA\0" "eo\0\0\0\0" "mr_IN\0" "bo\0\0\0\0" "ne_NP\0" "kl\0\0\0\0" "en_IE\0"; @@ -937,7 +910,7 @@ const char * __CFBundleLanguageAbbreviationsArray = #define NUM_LANGUAGE_ABBREVIATIONS 152 #define LANGUAGE_ABBREVIATION_LENGTH 3 -#ifdef __CONSTANT_CFSTRINGS__ +#if defined(__CONSTANT_CFSTRINGS__) // These are not necessarily common localizations per se, but localizations for which the full language name is still in common use. // These are used to provide a fast path for it (other localizations usually use the abbreviation, which is even faster). @@ -946,10 +919,10 @@ static CFStringRef const __CFBundleCommonLanguageAbbreviationsArray[] = {CFSTR(" #define NUM_COMMON_LANGUAGE_NAMES 7 -#endif // __CONSTANT_CFSTRINGS__ +#endif /* __CONSTANT_CFSTRINGS__ */ static const SInt32 __CFBundleScriptCodesArray[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 1, 4, 0, 6, 0, 0, 0, 0, 2, 4, 9, 21, 3, 29, 29, 29, 29, 29, 0, 0, 4, 7, 25, 0, 0, 0, 0, 29, 29, 0, 5, 7, 7, 7, 7, 7, 7, 7, 7, 4, 24, 23, 7, 7, 7, 7, 27, 7, 4, 4, 4, 4, 26, @@ -978,17 +951,18 @@ static SInt32 _CFBundleGetLanguageCodeForLocalization(CFStringRef localizationNa SInt32 result = -1, i; char buff[256]; CFIndex length = CFStringGetLength(localizationName); - if ((length >= LANGUAGE_ABBREVIATION_LENGTH - 1) && (length <= 255) && CFStringGetCString(localizationName, buff, 255, kCFStringEncodingASCII)) { + if (length >= LANGUAGE_ABBREVIATION_LENGTH - 1 && length <= 255 && CFStringGetCString(localizationName, buff, 255, kCFStringEncodingASCII)) { buff[255] = '\0'; for (i = 0; -1 == result && i < NUM_LANGUAGE_NAMES; i++) { if (0 == strcmp(buff, __CFBundleLanguageNamesArray[i])) result = i; } - if ('n' == buff[0] && 'o' == buff[1]) result = 9; // hack for Norwegian - else if (0 == strcmp(buff, "zh_TW") || 0 == strcmp(buff, "zh-Hant")) result = 19; // hack for mixed-up Chinese language codes - else if (0 == strcmp(buff, "zh_CN") || 0 == strcmp(buff, "zh-Hans")) result = 33; - buff[LANGUAGE_ABBREVIATION_LENGTH - 1] = '\0'; - for (i = 0; -1 == result && i < NUM_LANGUAGE_ABBREVIATIONS * LANGUAGE_ABBREVIATION_LENGTH; i += LANGUAGE_ABBREVIATION_LENGTH) { - if (buff[0] == *(__CFBundleLanguageAbbreviationsArray + i + 0) && buff[1] == *(__CFBundleLanguageAbbreviationsArray + i + 1)) result = i / LANGUAGE_ABBREVIATION_LENGTH; + if (0 == strcmp(buff, "zh_TW") || 0 == strcmp(buff, "zh-Hant")) result = 19; else if (0 == strcmp(buff, "zh_CN") || 0 == strcmp(buff, "zh-Hans")) result = 33; // hack for mixed-up Chinese language codes + if (-1 == result && (length == LANGUAGE_ABBREVIATION_LENGTH - 1 || !isalpha(buff[LANGUAGE_ABBREVIATION_LENGTH - 1]))) { + buff[LANGUAGE_ABBREVIATION_LENGTH - 1] = '\0'; + if ('n' == buff[0] && 'o' == buff[1]) result = 9; // hack for Norwegian + for (i = 0; -1 == result && i < NUM_LANGUAGE_ABBREVIATIONS * LANGUAGE_ABBREVIATION_LENGTH; i += LANGUAGE_ABBREVIATION_LENGTH) { + if (buff[0] == *(__CFBundleLanguageAbbreviationsArray + i + 0) && buff[1] == *(__CFBundleLanguageAbbreviationsArray + i + 1)) result = i / LANGUAGE_ABBREVIATION_LENGTH; + } } } return result; @@ -998,25 +972,21 @@ static CFStringRef _CFBundleCopyLanguageAbbreviationForLanguageCode(SInt32 langu CFStringRef result = NULL; if (0 <= languageCode && languageCode < NUM_LANGUAGE_ABBREVIATIONS) { const char *languageAbbreviation = __CFBundleLanguageAbbreviationsArray + languageCode * LANGUAGE_ABBREVIATION_LENGTH; - if (languageAbbreviation != NULL && *languageAbbreviation != '\0') { - result = CFStringCreateWithCStringNoCopy(NULL, languageAbbreviation, kCFStringEncodingASCII, kCFAllocatorNull); - } + if (languageAbbreviation && *languageAbbreviation != '\0') result = CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault, languageAbbreviation, kCFStringEncodingASCII, kCFAllocatorNull); } return result; } -static inline CFStringRef _CFBundleCopyLanguageNameForLanguageCode(SInt32 languageCode) { +CF_INLINE CFStringRef _CFBundleCopyLanguageNameForLanguageCode(SInt32 languageCode) { CFStringRef result = NULL; if (0 <= languageCode && languageCode < NUM_LANGUAGE_NAMES) { const char *languageName = __CFBundleLanguageNamesArray[languageCode]; - if (languageName != NULL && *languageName != '\0') { - result = CFStringCreateWithCStringNoCopy(NULL, languageName, kCFStringEncodingASCII, kCFAllocatorNull); - } + if (languageName && *languageName != '\0') result = CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault, languageName, kCFStringEncodingASCII, kCFAllocatorNull); } return result; } -static inline CFStringRef _CFBundleCopyLanguageAbbreviationForLocalization(CFStringRef localizationName) { +CF_INLINE CFStringRef _CFBundleCopyLanguageAbbreviationForLocalization(CFStringRef localizationName) { CFStringRef result = NULL; SInt32 languageCode = _CFBundleGetLanguageCodeForLocalization(localizationName); if (languageCode >= 0) { @@ -1024,32 +994,32 @@ static inline CFStringRef _CFBundleCopyLanguageAbbreviationForLocalization(CFStr } else { CFIndex length = CFStringGetLength(localizationName); if (length == LANGUAGE_ABBREVIATION_LENGTH - 1 || (length > LANGUAGE_ABBREVIATION_LENGTH - 1 && CFStringGetCharacterAtIndex(localizationName, LANGUAGE_ABBREVIATION_LENGTH - 1) == '_')) { - result = CFStringCreateWithSubstring(NULL, localizationName, CFRangeMake(0, LANGUAGE_ABBREVIATION_LENGTH - 1)); + result = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, localizationName, CFRangeMake(0, LANGUAGE_ABBREVIATION_LENGTH - 1)); } } return result; } -static inline CFStringRef _CFBundleCopyModifiedLocalization(CFStringRef localizationName) { +CF_INLINE CFStringRef _CFBundleCopyModifiedLocalization(CFStringRef localizationName) { CFMutableStringRef result = NULL; CFIndex length = CFStringGetLength(localizationName); if (length >= 4) { UniChar c = CFStringGetCharacterAtIndex(localizationName, 2); if ('-' == c || '_' == c) { - result = CFStringCreateMutableCopy(NULL, length, localizationName); + result = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, length, localizationName); CFStringReplace(result, CFRangeMake(2, 1), ('-' == c) ? CFSTR("_") : CFSTR("-")); } } return result; } -static inline CFStringRef _CFBundleCopyLanguageNameForLocalization(CFStringRef localizationName) { +CF_INLINE CFStringRef _CFBundleCopyLanguageNameForLocalization(CFStringRef localizationName) { CFStringRef result = NULL; SInt32 languageCode = _CFBundleGetLanguageCodeForLocalization(localizationName); if (languageCode >= 0) { result = _CFBundleCopyLanguageNameForLanguageCode(languageCode); } else { - result = CFStringCreateCopy(NULL, localizationName); + result = (CFStringRef)CFStringCreateCopy(kCFAllocatorSystemDefault, localizationName); } return result; } @@ -1060,7 +1030,7 @@ static SInt32 _CFBundleGetLanguageCodeForRegionCode(SInt32 regionCode) { result = 33; } else if (0 <= regionCode && regionCode < NUM_LOCALE_ABBREVIATIONS) { const char *localeAbbreviation = __CFBundleLocaleAbbreviationsArray + regionCode * LOCALE_ABBREVIATION_LENGTH; - if (localeAbbreviation != NULL && *localeAbbreviation != '\0') { + if (localeAbbreviation && *localeAbbreviation != '\0') { for (i = 0; -1 == result && i < NUM_LANGUAGE_ABBREVIATIONS * LANGUAGE_ABBREVIATION_LENGTH; i += LANGUAGE_ABBREVIATION_LENGTH) { if (localeAbbreviation[0] == *(__CFBundleLanguageAbbreviationsArray + i + 0) && localeAbbreviation[1] == *(__CFBundleLanguageAbbreviationsArray + i + 1)) result = i / LANGUAGE_ABBREVIATION_LENGTH; } @@ -1075,12 +1045,14 @@ static SInt32 _CFBundleGetRegionCodeForLanguageCode(SInt32 languageCode) { result = 53; } else if (0 <= languageCode && languageCode < NUM_LANGUAGE_ABBREVIATIONS) { const char *languageAbbreviation = __CFBundleLanguageAbbreviationsArray + languageCode * LANGUAGE_ABBREVIATION_LENGTH; - if (languageAbbreviation != NULL && *languageAbbreviation != '\0') { + if (languageAbbreviation && *languageAbbreviation != '\0') { for (i = 0; -1 == result && i < NUM_LOCALE_ABBREVIATIONS * LOCALE_ABBREVIATION_LENGTH; i += LOCALE_ABBREVIATION_LENGTH) { if (*(__CFBundleLocaleAbbreviationsArray + i + 0) == languageAbbreviation[0] && *(__CFBundleLocaleAbbreviationsArray + i + 1) == languageAbbreviation[1]) result = i / LOCALE_ABBREVIATION_LENGTH; } } } + if (25 == result) result = 68; + if (28 == result) result = 82; return result; } @@ -1094,6 +1066,9 @@ static SInt32 _CFBundleGetRegionCodeForLocalization(CFStringRef localizationName if (0 == strcmp(buff, __CFBundleLocaleAbbreviationsArray + i)) result = i / LOCALE_ABBREVIATION_LENGTH; } } + if (25 == result) result = 68; + if (28 == result) result = 82; + if (37 == result) result = 0; if (-1 == result) { SInt32 languageCode = _CFBundleGetLanguageCodeForLocalization(localizationName); result = _CFBundleGetRegionCodeForLanguageCode(languageCode); @@ -1105,35 +1080,49 @@ static CFStringRef _CFBundleCopyLocaleAbbreviationForRegionCode(SInt32 regionCod CFStringRef result = NULL; if (0 <= regionCode && regionCode < NUM_LOCALE_ABBREVIATIONS) { const char *localeAbbreviation = __CFBundleLocaleAbbreviationsArray + regionCode * LOCALE_ABBREVIATION_LENGTH; - if (localeAbbreviation != NULL && *localeAbbreviation != '\0') { - result = CFStringCreateWithCStringNoCopy(NULL, localeAbbreviation, kCFStringEncodingASCII, kCFAllocatorNull); + if (localeAbbreviation && *localeAbbreviation != '\0') { + result = CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault, localeAbbreviation, kCFStringEncodingASCII, kCFAllocatorNull); } } return result; } Boolean CFBundleGetLocalizationInfoForLocalization(CFStringRef localizationName, SInt32 *languageCode, SInt32 *regionCode, SInt32 *scriptCode, CFStringEncoding *stringEncoding) { + Boolean retval = false; SInt32 language = -1, region = -1, script = 0; CFStringEncoding encoding = kCFStringEncodingMacRoman; - if (localizationName) { - language = _CFBundleGetLanguageCodeForLocalization(localizationName); - region = _CFBundleGetRegionCodeForLocalization(localizationName); - } else { - _CFBundleGetLanguageAndRegionCodes(&language, ®ion); - } - if ((language < 0 || language > (int)(sizeof(__CFBundleScriptCodesArray)/sizeof(SInt32))) && region != -1) language = _CFBundleGetLanguageCodeForRegionCode(region); - if (region == -1 && language != -1) region = _CFBundleGetRegionCodeForLanguageCode(language); - if (language >= 0 && language < (int)(sizeof(__CFBundleScriptCodesArray)/sizeof(SInt32))) { - script = __CFBundleScriptCodesArray[language]; + if (!localizationName) { + CFBundleRef mainBundle = CFBundleGetMainBundle(); + CFArrayRef languages = NULL; + if (mainBundle) { + languages = _CFBundleGetLanguageSearchList(mainBundle); + if (languages) CFRetain(languages); + } + if (!languages) languages = _CFBundleCopyUserLanguages(false); + if (languages && CFArrayGetCount(languages) > 0) localizationName = (CFStringRef)CFArrayGetValueAtIndex(languages, 0); } - if (language >= 0 && language < (int)(sizeof(__CFBundleStringEncodingsArray)/sizeof(CFStringEncoding))) { - encoding = __CFBundleStringEncodingsArray[language]; + if (!retval) { + if (localizationName) { + language = _CFBundleGetLanguageCodeForLocalization(localizationName); + region = _CFBundleGetRegionCodeForLocalization(localizationName); + } else { + _CFBundleGetLanguageAndRegionCodes(&language, ®ion); + } + if ((language < 0 || language > (int)(sizeof(__CFBundleScriptCodesArray)/sizeof(SInt32))) && region != -1) language = _CFBundleGetLanguageCodeForRegionCode(region); + if (region == -1 && language != -1) region = _CFBundleGetRegionCodeForLanguageCode(language); + if (language >= 0 && language < (int)(sizeof(__CFBundleScriptCodesArray)/sizeof(SInt32))) { + script = __CFBundleScriptCodesArray[language]; + } + if (language >= 0 && language < (int)(sizeof(__CFBundleStringEncodingsArray)/sizeof(CFStringEncoding))) { + encoding = __CFBundleStringEncodingsArray[language]; + } + retval = (language != -1 || region != -1); } if (languageCode) *languageCode = language; if (regionCode) *regionCode = region; if (scriptCode) *scriptCode = script; if (stringEncoding) *stringEncoding = encoding; - return (language != -1 || region != -1); + return retval; } CFStringRef CFBundleCopyLocalizationForLocalizationInfo(SInt32 languageCode, SInt32 regionCode, SInt32 scriptCode, CFStringEncoding stringEncoding) { @@ -1141,6 +1130,9 @@ CFStringRef CFBundleCopyLocalizationForLocalizationInfo(SInt32 languageCode, SIn if (!localizationName) { localizationName = _CFBundleCopyLocaleAbbreviationForRegionCode(regionCode); } + if (!localizationName && 0 <= languageCode && languageCode < SHRT_MAX) { + localizationName = CFLocaleCreateCanonicalLocaleIdentifierFromScriptManagerCodes(kCFAllocatorSystemDefault, (LangCode)languageCode, (RegionCode)-1); + } if (!localizationName) { localizationName = _CFBundleCopyLanguageAbbreviationForLanguageCode(languageCode); } @@ -1175,22 +1167,21 @@ __private_extern__ CFArrayRef _CFBundleCopyUserLanguages(Boolean useBackstops) { if (!didit) { if (__CFAppleLanguages) { CFDataRef data; - CFIndex length = strlen(__CFAppleLanguages); + CFIndex length = strlen((const char *)__CFAppleLanguages); if (length > 0) { - data = CFDataCreateWithBytesNoCopy(NULL, __CFAppleLanguages, length, kCFAllocatorNull); + data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, (const UInt8 *)__CFAppleLanguages, length, kCFAllocatorNull); if (data) { -__CFSetNastyFile(CFSTR("")); - userLanguages = CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable, NULL); + userLanguages = (CFArrayRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL); CFRelease(data); } } } - if (!userLanguages && preferencesArray) userLanguages = CFRetain(preferencesArray); + if (!userLanguages && preferencesArray) userLanguages = (CFArrayRef)CFRetain(preferencesArray); Boolean useEnglishAsBackstop = true; // could perhaps read out of LANG environment variable if (useEnglishAsBackstop && !userLanguages) { - CFStringRef english = CFSTR("English"); - userLanguages = CFArrayCreate(kCFAllocatorDefault, (const void **)&english, 1, &kCFTypeArrayCallBacks); + CFStringRef english = CFSTR("en"); + userLanguages = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&english, 1, &kCFTypeArrayCallBacks); } if (userLanguages && CFGetTypeID(userLanguages) != CFArrayGetTypeID()) { CFRelease(userLanguages); @@ -1200,23 +1191,7 @@ __CFSetNastyFile(CFSTR("")); } __CFSpinUnlock(&CFBundleResourceGlobalDataLock); if (preferencesArray) CFRelease(preferencesArray); -#if defined(__MACOS8__) - if (useBackstops && (NULL == userLanguages || 0 == CFArrayGetCount(userLanguages)) { - // use the system region and language as a backstop on 8 - CFMutableArrayRef mutableUserLanguages = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - CFStringRef localeAbbreviation = _CFBundleCopyLocaleAbbreviationForRegionCode(GetScriptManagerVariable(smRegionCode)), languageAbbreviation = _CFBundleCopyLanguageAbbreviationForLanguageCode(GetScriptVariable(smSystemScript, smScriptLang)); - if (localeAbbreviation) { - CFArrayAppendValue(mutableUserLanguages, localeAbbreviation); - CFRelease(localeAbbreviation); - } - if (languageAbbreviation) { - CFArrayAppendValue(mutableUserLanguages, languageAbbreviation); - CFRelease(languageAbbreviation); - } - result = (CFArrayRef)mutableUserLanguages; - } -#endif /* __MACOS8__ */ - if (!result && userLanguages) result = CFRetain(userLanguages); + if (!result && userLanguages) result = (CFArrayRef)CFRetain(userLanguages); return result; } @@ -1226,24 +1201,23 @@ CF_EXPORT void _CFBundleGetLanguageAndRegionCodes(SInt32 *languageCode, SInt32 * SInt32 language = -1, region = -1; CFBundleRef mainBundle = CFBundleGetMainBundle(); CFArrayRef languages = NULL; - CFStringRef localizationName = NULL; if (mainBundle) { languages = _CFBundleGetLanguageSearchList(mainBundle); if (languages) CFRetain(languages); } if (!languages) languages = _CFBundleCopyUserLanguages(false); - if (languages && (CFArrayGetCount(languages) > 0)) { - localizationName = CFArrayGetValueAtIndex(languages, 0); - language = _CFBundleGetLanguageCodeForLocalization(localizationName); - region = _CFBundleGetRegionCodeForLocalization(localizationName); + if (languages && CFArrayGetCount(languages) > 0) { + CFStringRef localizationName = (CFStringRef)CFArrayGetValueAtIndex(languages, 0); + Boolean retval = false; + LangCode langCode = -1; + RegionCode regCode = -1; + if (!retval) { + language = _CFBundleGetLanguageCodeForLocalization(localizationName); + region = _CFBundleGetRegionCodeForLocalization(localizationName); + } } else { -#if defined(__MACOS8__) - language = GetScriptVariable(smSystemScript, smScriptLang); - region = GetScriptManagerVariable(smRegionCode); -#else language = 0; region = 0; -#endif /* __MACOS8__ */ } if (language == -1 && region != -1) language = _CFBundleGetLanguageCodeForRegionCode(region); if (region == -1 && language != -1) region = _CFBundleGetRegionCodeForLanguageCode(language); @@ -1254,7 +1228,7 @@ CF_EXPORT void _CFBundleGetLanguageAndRegionCodes(SInt32 *languageCode, SInt32 * static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc, UniChar *pathUniChars, CFIndex pathLen, uint8_t version, CFDictionaryRef infoDict, CFStringRef curLangStr, CFMutableArrayRef lprojNames) { - CFIndex curLangLen = CFStringGetLength(curLangStr), savedPathLen, idx; + CFIndex curLangLen = CFStringGetLength(curLangStr), savedPathLen; UniChar curLangUniChars[255]; CFStringRef altLangStr = NULL, modifiedLangStr = NULL, languageAbbreviation = NULL, languageName = NULL, canonicalLanguageIdentifier = NULL; CFMutableDictionaryRef canonicalLanguageIdentifiers = NULL, predefinedCanonicalLanguageIdentifiers = NULL; @@ -1262,12 +1236,12 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc CFArrayRef predefinedLocalizations = NULL; CFRange predefinedLocalizationsRange; CFMutableStringRef cheapStr, tmpString; -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES CFArrayRef contents; CFRange contentsRange; -#else +#else /* READ_DIRECTORIES */ Boolean isDir = false; -#endif +#endif /* READ_DIRECTORIES */ // both of these used for temp string operations, for slightly // different purposes, where each type is appropriate @@ -1275,16 +1249,16 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc _CFStrSetDesiredCapacity(cheapStr, CFMaxPathSize); tmpString = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, NULL, 0, 0, kCFAllocatorNull); -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); contents = _CFBundleCopyDirectoryContentsAtPath(cheapStr, _CFBundleAllContents); contentsRange = CFRangeMake(0, CFArrayGetCount(contents)); -#endif +#endif /* READ_DIRECTORIES */ if (infoDict) { - predefinedLocalizations = CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey); - if (predefinedLocalizations != NULL && CFGetTypeID(predefinedLocalizations) != CFArrayGetTypeID()) { + predefinedLocalizations = (CFArrayRef)CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey); + if (predefinedLocalizations && CFGetTypeID(predefinedLocalizations) != CFArrayGetTypeID()) { predefinedLocalizations = NULL; CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, kCFBundleLocalizationsKey); } @@ -1295,39 +1269,42 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc CFStringGetCharacters(curLangStr, CFRangeMake(0, curLangLen), curLangUniChars); savedPathLen = pathLen; if (_CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, curLangUniChars, curLangLen) && _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, _LprojUniChars, _LprojLen)) { -#if USE_GETDIRENTRIES +#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))) { -#else +#else /* READ_DIRECTORIES */ CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, curLangStr)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) { -#endif +#endif /* READ_DIRECTORIES */ if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), curLangStr)) CFArrayAppendValue(lprojNames, curLangStr); foundOne = true; if (CFStringGetLength(curLangStr) <= 2) { CFRelease(cheapStr); CFRelease(tmpString); -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES CFRelease(contents); -#endif +#endif /* READ_DIRECTORIES */ return foundOne; } } } -#ifdef __CONSTANT_CFSTRINGS__ - for (idx = 0; !altLangStr && idx < NUM_COMMON_LANGUAGE_NAMES; idx++) { - if (CFEqual(curLangStr, __CFBundleCommonLanguageAbbreviationsArray[idx])) altLangStr = __CFBundleCommonLanguageNamesArray[idx]; - else if (CFEqual(curLangStr, __CFBundleCommonLanguageNamesArray[idx])) altLangStr = __CFBundleCommonLanguageAbbreviationsArray[idx]; +#if defined(__CONSTANT_CFSTRINGS__) + if (!altLangStr) { + CFIndex idx; + for (idx = 0; !altLangStr && idx < NUM_COMMON_LANGUAGE_NAMES; idx++) { + if (CFEqual(curLangStr, __CFBundleCommonLanguageAbbreviationsArray[idx])) altLangStr = __CFBundleCommonLanguageNamesArray[idx]; + else if (CFEqual(curLangStr, __CFBundleCommonLanguageNamesArray[idx])) altLangStr = __CFBundleCommonLanguageAbbreviationsArray[idx]; + } } -#endif // __CONSTANT_CFSTRINGS__ +#endif /* __CONSTANT_CFSTRINGS__ */ if (foundOne && altLangStr) { CFRelease(cheapStr); CFRelease(tmpString); -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES CFRelease(contents); -#endif +#endif /* READ_DIRECTORIES */ return foundOne; } if (altLangStr) { @@ -1336,29 +1313,30 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc CFStringGetCharacters(altLangStr, CFRangeMake(0, curLangLen), curLangUniChars); pathLen = savedPathLen; if (_CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, curLangUniChars, curLangLen) && _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, _LprojUniChars, _LprojLen)) { -#if USE_GETDIRENTRIES +#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))) { -#else +#else /* READ_DIRECTORIES */ CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, altLangStr)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) { -#endif +#endif /* READ_DIRECTORIES */ if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), altLangStr)) CFArrayAppendValue(lprojNames, altLangStr); foundOne = true; CFRelease(cheapStr); CFRelease(tmpString); -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES CFRelease(contents); -#endif +#endif /* READ_DIRECTORIES */ return foundOne; } } } -#if USE_GETDIRENTRIES - if (!foundOne) { +#if READ_DIRECTORIES + if (!foundOne && (!predefinedLocalizations || CFArrayGetCount(predefinedLocalizations) == 0)) { Boolean hasLocalizations = false; + CFIndex idx; for (idx = 0; !hasLocalizations && idx < contentsRange.length; idx++) { CFStringRef name = CFArrayGetValueAtIndex(contents, idx); if (CFStringHasSuffix(name, _CFBundleLprojExtensionWithDot)) hasLocalizations = true; @@ -1370,22 +1348,22 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc return foundOne; } } -#endif +#endif /* READ_DIRECTORIES */ if (!altLangStr && (modifiedLangStr = _CFBundleCopyModifiedLocalization(curLangStr))) { curLangLen = CFStringGetLength(modifiedLangStr); if (curLangLen > 255) curLangLen = 255; CFStringGetCharacters(modifiedLangStr, CFRangeMake(0, curLangLen), curLangUniChars); pathLen = savedPathLen; if (_CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, curLangUniChars, curLangLen) && _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, _LprojUniChars, _LprojLen)) { -#if USE_GETDIRENTRIES +#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))) { -#else +#else /* READ_DIRECTORIES */ CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, modifiedLangStr)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) { -#endif +#endif /* READ_DIRECTORIES */ if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), modifiedLangStr)) CFArrayAppendValue(lprojNames, modifiedLangStr); foundOne = true; } @@ -1397,15 +1375,15 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc CFStringGetCharacters(languageAbbreviation, CFRangeMake(0, curLangLen), curLangUniChars); pathLen = savedPathLen; if (_CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, curLangUniChars, curLangLen) && _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, _LprojUniChars, _LprojLen)) { -#if USE_GETDIRENTRIES +#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))) { -#else +#else /* READ_DIRECTORIES */ CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageAbbreviation)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) { -#endif +#endif /* READ_DIRECTORIES */ if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), languageAbbreviation)) CFArrayAppendValue(lprojNames, languageAbbreviation); foundOne = true; } @@ -1417,15 +1395,15 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc CFStringGetCharacters(languageName, CFRangeMake(0, curLangLen), curLangUniChars); pathLen = savedPathLen; if (_CFAppendPathComponent(pathUniChars, &pathLen, CFMaxPathSize, curLangUniChars, curLangLen) && _CFAppendPathExtension(pathUniChars, &pathLen, CFMaxPathSize, _LprojUniChars, _LprojLen)) { -#if USE_GETDIRENTRIES +#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))) { -#else +#else /* READ_DIRECTORIES */ CFStringSetExternalCharactersNoCopy(tmpString, pathUniChars, pathLen, pathLen); CFStringReplaceAll(cheapStr, tmpString); if ((predefinedLocalizations && CFArrayContainsValue(predefinedLocalizations, predefinedLocalizationsRange, languageName)) || (version != 4 && _CFIsResourceAtPath(cheapStr, &isDir) && isDir)) { -#endif +#endif /* READ_DIRECTORIES */ if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), languageName)) CFArrayAppendValue(lprojNames, languageName); foundOne = true; } @@ -1439,9 +1417,9 @@ static Boolean _CFBundleTryOnePreferredLprojNameInDirectory(CFAllocatorRef alloc if (predefinedCanonicalLanguageIdentifiers) CFRelease(predefinedCanonicalLanguageIdentifiers); CFRelease(cheapStr); CFRelease(tmpString); -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES CFRelease(contents); -#endif +#endif /* READ_DIRECTORIES */ return foundOne; } @@ -1506,7 +1484,7 @@ __private_extern__ void _CFBundleAddPreferredLprojNamesInDirectory(CFAllocatorRe // If there is a main bundle, and it isn't this one, try to use the language it prefers. CFArrayRef mainBundleLangs = _CFBundleGetLanguageSearchList(mainBundle); if (mainBundleLangs && (CFArrayGetCount(mainBundleLangs) > 0)) { - curLangStr = CFArrayGetValueAtIndex(mainBundleLangs, 0); + curLangStr = (CFStringRef)CFArrayGetValueAtIndex(mainBundleLangs, 0); foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames); } } @@ -1519,19 +1497,13 @@ __private_extern__ void _CFBundleAddPreferredLprojNamesInDirectory(CFAllocatorRe userLanguages = _CFBundleCopyUserLanguages(true); count = (userLanguages ? CFArrayGetCount(userLanguages) : 0); for (idx = 0; !foundOne && idx < count; idx++) { - curLangStr = CFArrayGetValueAtIndex(userLanguages, idx); + curLangStr = (CFStringRef)CFArrayGetValueAtIndex(userLanguages, idx); foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, curLangStr, lprojNames); } // use development region and U.S. English as backstops - if (!foundOne && devLang != NULL) { - foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, devLang, lprojNames); - } - if (!foundOne) { - foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, CFSTR("en_US"), lprojNames); - } - if (userLanguages != NULL) { - CFRelease(userLanguages); - } + if (!foundOne && devLang) foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, devLang, lprojNames); + if (!foundOne) foundOne = _CFBundleTryOnePreferredLprojNameInDirectory(alloc, pathUniChars, pathLen, version, infoDict, CFSTR("en_US"), lprojNames); + if (userLanguages) CFRelease(userLanguages); } } @@ -1540,7 +1512,6 @@ static Boolean _CFBundleTryOnePreferredLprojNameInArray(CFArrayRef array, CFStri CFRange range = CFRangeMake(0, CFArrayGetCount(array)); CFStringRef altLangStr = NULL, modifiedLangStr = NULL, languageAbbreviation = NULL, languageName = NULL, canonicalLanguageIdentifier = NULL; CFMutableDictionaryRef canonicalLanguageIdentifiers = NULL; - CFIndex idx; if (range.length == 0) return foundOne; if (CFArrayContainsValue(array, range, curLangStr)) { @@ -1549,12 +1520,15 @@ static Boolean _CFBundleTryOnePreferredLprojNameInArray(CFArrayRef array, CFStri if (range.length == 1 || CFStringGetLength(curLangStr) <= 2) return foundOne; } if (range.length == 1 && CFArrayContainsValue(array, range, CFSTR("default"))) return foundOne; -#ifdef __CONSTANT_CFSTRINGS__ - for (idx = 0; !altLangStr && idx < NUM_COMMON_LANGUAGE_NAMES; idx++) { - if (CFEqual(curLangStr, __CFBundleCommonLanguageAbbreviationsArray[idx])) altLangStr = __CFBundleCommonLanguageNamesArray[idx]; - else if (CFEqual(curLangStr, __CFBundleCommonLanguageNamesArray[idx])) altLangStr = __CFBundleCommonLanguageAbbreviationsArray[idx]; +#if defined(__CONSTANT_CFSTRINGS__) + if (!altLangStr) { + CFIndex idx; + for (idx = 0; !altLangStr && idx < NUM_COMMON_LANGUAGE_NAMES; idx++) { + if (CFEqual(curLangStr, __CFBundleCommonLanguageAbbreviationsArray[idx])) altLangStr = __CFBundleCommonLanguageNamesArray[idx]; + else if (CFEqual(curLangStr, __CFBundleCommonLanguageNamesArray[idx])) altLangStr = __CFBundleCommonLanguageAbbreviationsArray[idx]; + } } -#endif // __CONSTANT_CFSTRINGS__ +#endif /* __CONSTANT_CFSTRINGS__ */ if (foundOne && altLangStr) return foundOne; if (altLangStr && CFArrayContainsValue(array, range, altLangStr)) { if (!CFArrayContainsValue(lprojNames, CFRangeMake(0, CFArrayGetCount(lprojNames)), altLangStr)) CFArrayAppendValue(lprojNames, altLangStr); @@ -1589,7 +1563,7 @@ static Boolean _CFBundleTryOnePreferredLprojNameInArray(CFArrayRef array, CFStri } static CFArrayRef _CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, CFArrayRef prefArray, Boolean considerMain) { - CFMutableArrayRef lprojNames = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + CFMutableArrayRef lprojNames = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); Boolean foundOne = false, releasePrefArray = false; CFIndex idx, count; @@ -1599,7 +1573,7 @@ static CFArrayRef _CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, // If there is a main bundle, try to use the language it prefers. CFArrayRef mainBundleLangs = _CFBundleGetLanguageSearchList(mainBundle); if (mainBundleLangs && (CFArrayGetCount(mainBundleLangs) > 0)) { - foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, CFArrayGetValueAtIndex(mainBundleLangs, 0), lprojNames); + foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, (CFStringRef)CFArrayGetValueAtIndex(mainBundleLangs, 0), lprojNames); } } } @@ -1610,7 +1584,7 @@ static CFArrayRef _CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, } count = (prefArray ? CFArrayGetCount(prefArray) : 0); for (idx = 0; !foundOne && idx < count; idx++) { - foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, CFArrayGetValueAtIndex(prefArray, idx), lprojNames); + foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, (CFStringRef)CFArrayGetValueAtIndex(prefArray, idx), lprojNames); } // use U.S. English as backstop if (!foundOne) { @@ -1618,7 +1592,7 @@ static CFArrayRef _CFBundleCopyLocalizationsForPreferences(CFArrayRef locArray, } // use random entry as backstop if (!foundOne && CFArrayGetCount(lprojNames) > 0) { - foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, CFArrayGetValueAtIndex(locArray, 0), lprojNames); + foundOne = _CFBundleTryOnePreferredLprojNameInArray(locArray, (CFStringRef)CFArrayGetValueAtIndex(locArray, 0), lprojNames); } } if (CFArrayGetCount(lprojNames) == 0) { @@ -1640,32 +1614,24 @@ __private_extern__ CFArrayRef _CFBundleCopyLanguageSearchListInDirectory(CFAlloc uint8_t localVersion = 0; CFDictionaryRef infoDict = _CFBundleCopyInfoDictionaryInDirectory(alloc, url, &localVersion); CFStringRef devLang = NULL; - if (infoDict != NULL) { - devLang = CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey); - } - if (devLang != NULL && (CFGetTypeID(devLang) != CFStringGetTypeID() || CFStringGetLength(devLang) == 0)) devLang = NULL; + if (infoDict) devLang = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey); + if (devLang && (CFGetTypeID(devLang) != CFStringGetTypeID() || CFStringGetLength(devLang) == 0)) devLang = NULL; _CFBundleAddPreferredLprojNamesInDirectory(alloc, url, localVersion, infoDict, langs, devLang); - if (devLang != NULL && CFArrayGetFirstIndexOfValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), devLang) < 0) { - CFArrayAppendValue(langs, devLang); - } - if (CFArrayGetCount(langs) == 0) { - // Total backstop behavior to avoid having an empty array. - CFArrayAppendValue(langs, CFSTR("en")); - } - if (infoDict != NULL) { - CFRelease(infoDict); - } - if (version) { - *version = localVersion; - } + if (devLang && CFArrayGetFirstIndexOfValue(langs, CFRangeMake(0, CFArrayGetCount(langs)), devLang) < 0) CFArrayAppendValue(langs, devLang); + + // Total backstop behavior to avoid having an empty array. + if (CFArrayGetCount(langs) == 0) CFArrayAppendValue(langs, CFSTR("en")); + + if (infoDict) CFRelease(infoDict); + if (version) *version = localVersion; return langs; } CF_EXPORT Boolean _CFBundleURLLooksLikeBundle(CFURLRef url) { Boolean result = false; - CFBundleRef bundle = _CFBundleCreateIfLooksLikeBundle(NULL, url); + CFBundleRef bundle = _CFBundleCreateIfLooksLikeBundle(kCFAllocatorSystemDefault, url); if (bundle) { result = true; CFRelease(bundle); @@ -1676,13 +1642,11 @@ CF_EXPORT Boolean _CFBundleURLLooksLikeBundle(CFURLRef url) { // Note that subDirName is expected to be the string for a URL CF_INLINE Boolean _CFBundleURLHasSubDir(CFURLRef url, CFStringRef subDirName) { CFURLRef dirURL; - Boolean isDir, result = false; + Boolean isDir = false, result = false; - dirURL = CFURLCreateWithString(NULL, subDirName, url); - if (dirURL != NULL) { - if (_CFIsResourceAtURL(dirURL, &isDir) && isDir) { - result = true; - } + dirURL = CFURLCreateWithString(kCFAllocatorSystemDefault, subDirName, url); + if (dirURL) { + if (_CFIsResourceAtURL(dirURL, &isDir) && isDir) result = true; CFRelease(dirURL); } return result; @@ -1697,7 +1661,7 @@ __private_extern__ Boolean _CFBundleURLLooksLikeBundleVersion(CFURLRef url, uint // version 3: none of the above (see below) // version 4: not a bundle (for main bundle only) uint8_t localVersion = 3; -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES CFURLRef absoluteURL = CFURLCopyAbsoluteURL(url); CFStringRef directoryPath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); CFArrayRef contents = _CFBundleCopyDirectoryContentsAtPath(directoryPath, _CFBundleAllContents); @@ -1714,8 +1678,9 @@ __private_extern__ Boolean _CFBundleURLLooksLikeBundleVersion(CFURLRef url, uint CFRelease(contents); CFRelease(directoryPath); CFRelease(absoluteURL); -#endif +#endif /* READ_DIRECTORIES */ if (localVersion == 3) { +#if DEPLOYMENT_TARGET_MACOSX if (CFStringHasSuffix(CFURLGetString(url), CFSTR(".framework/"))) { if (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) localVersion = 0; else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase2)) localVersion = 2; @@ -1725,6 +1690,7 @@ __private_extern__ Boolean _CFBundleURLLooksLikeBundleVersion(CFURLRef url, uint else if (_CFBundleURLHasSubDir(url, _CFBundleResourcesURLFromBase0)) localVersion = 0; else if (_CFBundleURLHasSubDir(url, _CFBundleSupportFilesURLFromBase1)) localVersion = 1; } +#endif } if (version) *version = localVersion; return !(localVersion == 3); @@ -1732,17 +1698,16 @@ __private_extern__ Boolean _CFBundleURLLooksLikeBundleVersion(CFURLRef url, uint __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectory(CFAllocatorRef alloc, CFURLRef url, uint8_t *version) { CFDictionaryRef dict = NULL; - char buff[CFMaxPathSize]; + unsigned char buff[CFMaxPathSize]; uint8_t localVersion = 0; if (CFURLGetFileSystemRepresentation(url, true, buff, CFMaxPathSize)) { - CFURLRef newURL = CFURLCreateFromFileSystemRepresentation(alloc, buff, strlen(buff), true); - if (NULL == newURL) newURL = CFRetain(url); + CFURLRef newURL = CFURLCreateFromFileSystemRepresentation(alloc, buff, strlen((char *)buff), true); + if (!newURL) newURL = (CFURLRef)CFRetain(url); - if (!_CFBundleURLLooksLikeBundleVersion(newURL, &localVersion)) { - // version 3 is for flattened pseudo-bundles with no Contents, Support Files, or Resources directories - localVersion = 3; - } + // version 3 is for flattened pseudo-bundles with no Contents, Support Files, or Resources directories + if (!_CFBundleURLLooksLikeBundleVersion(newURL, &localVersion)) localVersion = 3; + dict = _CFBundleCopyInfoDictionaryInDirectoryWithVersion(alloc, newURL, localVersion); CFRelease(newURL); } @@ -1752,56 +1717,73 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectory(CFAllo __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVersion(CFAllocatorRef alloc, CFURLRef url, uint8_t version) { CFDictionaryRef result = NULL; - if (url != NULL) { - CFURLRef infoURL = NULL; + if (url) { + CFURLRef infoURL = NULL, rawInfoURL = NULL; CFDataRef infoData = NULL; UniChar buff[CFMaxPathSize]; CFIndex len; CFMutableStringRef cheapStr; CFStringRef infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension0, infoURLFromBase = _CFBundleInfoURLFromBase0; Boolean tryPlatformSpecific = true, tryGlobal = true; -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES CFURLRef directoryURL = NULL, absoluteURL; CFStringRef directoryPath; CFArrayRef contents = NULL; CFRange contentsRange = CFRangeMake(0, 0); -#endif +#endif /* READ_DIRECTORIES */ _CFEnsureStaticBuffersInited(); if (0 == version) { -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES directoryURL = CFURLCreateWithString(alloc, _CFBundleResourcesURLFromBase0, url); -#endif +#endif /* READ_DIRECTORIES */ infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension0; infoURLFromBase = _CFBundleInfoURLFromBase0; } else if (1 == version) { -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES directoryURL = CFURLCreateWithString(alloc, _CFBundleSupportFilesURLFromBase1, url); -#endif +#endif /* READ_DIRECTORIES */ infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension1; infoURLFromBase = _CFBundleInfoURLFromBase1; } else if (2 == version) { -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES directoryURL = CFURLCreateWithString(alloc, _CFBundleSupportFilesURLFromBase2, url); -#endif +#endif /* READ_DIRECTORIES */ infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension2; infoURLFromBase = _CFBundleInfoURLFromBase2; } else if (3 == version) { +#if DEPLOYMENT_TARGET_MACOSX CFStringRef posixPath = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); // this test is necessary to exclude the case where a bundle is spuriously created from the innards of another bundle if (posixPath) { if (!(CFStringHasSuffix(posixPath, _CFBundleSupportFilesDirectoryName1) || CFStringHasSuffix(posixPath, _CFBundleSupportFilesDirectoryName2) || CFStringHasSuffix(posixPath, _CFBundleResourcesDirectoryName))) { -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES directoryURL = CFRetain(url); -#endif +#endif /* READ_DIRECTORIES */ infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension3; infoURLFromBase = _CFBundleInfoURLFromBase3; } CFRelease(posixPath); } +#elif 0 + CFStringRef windowsPath = CFURLCopyFileSystemPath(url, kCFURLWindowsPathStyle); + // this test is necessary to exclude the case where a bundle is spuriously created from the innards of another bundle + if (windowsPath) { + if (!(CFStringHasSuffix(windowsPath, _CFBundleSupportFilesDirectoryName1) || CFStringHasSuffix(windowsPath, _CFBundleSupportFilesDirectoryName2) || CFStringHasSuffix(windowsPath, _CFBundleResourcesDirectoryName))) { +#if READ_DIRECTORIES + directoryURL = CFRetain(url); +#endif /* READ_DIRECTORIES */ + infoURLFromBaseNoExtension = _CFBundleInfoURLFromBaseNoExtension3; + infoURLFromBase = _CFBundleInfoURLFromBase3; + } + CFRelease(windowsPath); + } +#else +#error Unknown or unspecified DEPLOYMENT_TARGET +#endif } -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES if (directoryURL) { absoluteURL = CFURLCopyAbsoluteURL(directoryURL); directoryPath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); @@ -1811,7 +1793,7 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer CFRelease(absoluteURL); CFRelease(directoryURL); } -#endif +#endif /* READ_DIRECTORIES */ len = CFStringGetLength(infoURLFromBaseNoExtension); CFStringGetCharacters(infoURLFromBaseNoExtension, CFRangeMake(0, len), buff); @@ -1822,7 +1804,7 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer cheapStr = CFStringCreateMutable(alloc, 0); CFStringAppendCharacters(cheapStr, buff, len); infoURL = CFURLCreateWithString(alloc, cheapStr, url); -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES if (contents) { CFIndex resourcesLen, idx; for (resourcesLen = len; resourcesLen > 0; resourcesLen--) if (buff[resourcesLen - 1] == '/') break; @@ -1833,7 +1815,7 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer if (kCFCompareEqualTo == CFStringCompare(cheapStr, CFArrayGetValueAtIndex(contents, idx), kCFCompareCaseInsensitive)) tryPlatformSpecific = true; } } -#endif +#endif /* READ_DIRECTORIES */ if (tryPlatformSpecific) CFURLCreateDataAndPropertiesFromResource(alloc, 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); @@ -1841,7 +1823,7 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer // Check for global Info.plist CFRelease(infoURL); infoURL = CFURLCreateWithString(alloc, infoURLFromBase, url); -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES if (contents) { CFIndex idx; for (tryGlobal = false, idx = 0; !tryGlobal && idx < contentsRange.length; idx++) { @@ -1849,13 +1831,13 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer if (kCFCompareEqualTo == CFStringCompare(_CFBundleInfoFileName, CFArrayGetValueAtIndex(contents, idx), kCFCompareCaseInsensitive)) tryGlobal = true; } } -#endif +#endif /* READ_DIRECTORIES */ if (tryGlobal) CFURLCreateDataAndPropertiesFromResource(alloc, infoURL, &infoData, NULL, NULL, NULL); //fprintf(stderr, "looking for ");CFShow(infoURL);fprintf(stderr, infoData ? "found it\n" : (tryGlobal ? "missed it\n" : "skipped it\n")); } if (infoData) { - result = CFPropertyListCreateFromXMLData(alloc, infoData, kCFPropertyListMutableContainers, NULL); + result = (CFDictionaryRef)CFPropertyListCreateFromXMLData(alloc, infoData, kCFPropertyListMutableContainers, NULL); if (result) { if (CFDictionaryGetTypeID() == CFGetTypeID(result)) { CFDictionarySetValue((CFMutableDictionaryRef)result, _kCFBundleInfoPlistURLKey, infoURL); @@ -1864,16 +1846,18 @@ __private_extern__ CFDictionaryRef _CFBundleCopyInfoDictionaryInDirectoryWithVer result = NULL; } } + if (!result) rawInfoURL = infoURL; CFRelease(infoData); } if (!result) { result = CFDictionaryCreateMutable(alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + if (rawInfoURL) CFDictionarySetValue((CFMutableDictionaryRef)result, _kCFBundleRawInfoPlistURLKey, rawInfoURL); } CFRelease(infoURL); -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES if (contents) CFRelease(contents); -#endif +#endif /* READ_DIRECTORIES */ } return result; } @@ -1887,12 +1871,12 @@ static Boolean _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFAllocatorR tempURL = CFURLCreateWithString(alloc, _CFBundlePkgInfoURLFromBase2, url); CFURLCreateDataAndPropertiesFromResource(alloc, tempURL, &pkgInfoData, NULL, NULL, NULL); CFRelease(tempURL); - if (pkgInfoData == NULL) { + if (!pkgInfoData) { tempURL = CFURLCreateWithString(alloc, _CFBundlePkgInfoURLFromBase1, url); CFURLCreateDataAndPropertiesFromResource(alloc, tempURL, &pkgInfoData, NULL, NULL, NULL); CFRelease(tempURL); } - if (pkgInfoData == NULL) { + if (!pkgInfoData) { // Check for a "pseudo" new bundle tempURL = CFURLCreateWithString(alloc, _CFBundlePseudoPkgInfoURLFromBase, url); CFURLCreateDataAndPropertiesFromResource(alloc, tempURL, &pkgInfoData, NULL, NULL, NULL); @@ -1903,37 +1887,28 @@ static Boolean _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFAllocatorR // If we allow new bundles to not have a PkgInfo (because they already have the same data in the Info.plist), then we have to go read the info plist which makes failure expensive. // drd: So we assume that a new bundle _must_ have a PkgInfo if they have this data at all, otherwise we manufacture it from the extension. - if ((pkgInfoData != NULL) && (CFDataGetLength(pkgInfoData) >= (int)(sizeof(UInt32) * 2))) { + if (pkgInfoData && CFDataGetLength(pkgInfoData) >= (int)(sizeof(UInt32) * 2)) { UInt32 *pkgInfo = (UInt32 *)CFDataGetBytePtr(pkgInfoData); - - if (packageType != NULL) { - *packageType = CFSwapInt32BigToHost(pkgInfo[0]); - } - if (packageCreator != NULL) { - *packageCreator = CFSwapInt32BigToHost(pkgInfo[1]); - } + if (packageType) *packageType = CFSwapInt32BigToHost(pkgInfo[0]); + if (packageCreator) *packageCreator = CFSwapInt32BigToHost(pkgInfo[1]); retVal = hasType = hasCreator = true; } - if (pkgInfoData != NULL) CFRelease(pkgInfoData); + if (pkgInfoData) CFRelease(pkgInfoData); if (!retVal) { if (!infoDict) { infoDict = _CFBundleCopyInfoDictionaryInDirectory(alloc, url, NULL); releaseInfoDict = true; } if (infoDict) { - CFStringRef typeString = CFDictionaryGetValue(infoDict, _kCFBundlePackageTypeKey), creatorString = CFDictionaryGetValue(infoDict, _kCFBundleSignatureKey); + CFStringRef typeString = (CFStringRef)CFDictionaryGetValue(infoDict, _kCFBundlePackageTypeKey), creatorString = (CFStringRef)CFDictionaryGetValue(infoDict, _kCFBundleSignatureKey); UInt32 tmp; CFIndex usedBufLen = 0; if (typeString && CFGetTypeID(typeString) == CFStringGetTypeID() && CFStringGetLength(typeString) == 4 && 4 == CFStringGetBytes(typeString, CFRangeMake(0, 4), kCFStringEncodingMacRoman, 0, false, (UInt8 *)&tmp, 4, &usedBufLen) && 4 == usedBufLen) { - if (packageType != NULL) { - *packageType = CFSwapInt32BigToHost(tmp); - } + if (packageType) *packageType = CFSwapInt32BigToHost(tmp); retVal = hasType = true; } if (creatorString && CFGetTypeID(creatorString) == CFStringGetTypeID() && CFStringGetLength(creatorString) == 4 && 4 == CFStringGetBytes(creatorString, CFRangeMake(0, 4), kCFStringEncodingMacRoman, 0, false, (UInt8 *)&tmp, 4, &usedBufLen) && 4 == usedBufLen) { - if (packageCreator != NULL) { - *packageCreator = CFSwapInt32BigToHost(tmp); - } + if (packageCreator) *packageCreator = CFSwapInt32BigToHost(tmp); retVal = hasCreator = true; } if (releaseInfoDict) CFRelease(infoDict); @@ -1942,10 +1917,8 @@ static Boolean _CFBundleGetPackageInfoInDirectoryWithInfoDictionary(CFAllocatorR if (!hasType || !hasCreator) { // If this looks like a bundle then manufacture the type and creator. if (retVal || _CFBundleURLLooksLikeBundle(url)) { - if (packageCreator != NULL && !hasCreator) { - *packageCreator = 0x3f3f3f3f; // '????' - } - if (packageType != NULL && !hasType) { + if (packageCreator && !hasCreator) *packageCreator = 0x3f3f3f3f; // '????' + if (packageType && !hasType) { CFStringRef urlStr; UniChar buff[CFMaxPathSize]; CFIndex strLen, startOfExtension; @@ -1991,99 +1964,75 @@ 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 (packageType != NULL) { - *packageType = 0x424e444c; // 'BNDL' - } - if (packageCreator != NULL) { - *packageCreator = 0x3f3f3f3f; // '????' - } + if (packageType) *packageType = 0x424e444c; // 'BNDL' + if (packageCreator) *packageCreator = 0x3f3f3f3f; // '????' } if (bundleURL) CFRelease(bundleURL); } -CF_EXPORT Boolean CFBundleGetPackageInfoInDirectory(CFURLRef url, UInt32 *packageType, UInt32 *packageCreator) {return _CFBundleGetPackageInfoInDirectory(NULL, url, packageType, packageCreator);} +CF_EXPORT Boolean CFBundleGetPackageInfoInDirectory(CFURLRef url, UInt32 *packageType, UInt32 *packageCreator) {return _CFBundleGetPackageInfoInDirectory(kCFAllocatorSystemDefault, url, packageType, packageCreator);} __private_extern__ CFStringRef _CFBundleGetPlatformExecutablesSubdirectoryName(void) { -#if defined(__MACOS8__) - return CFSTR("MacOSClassic"); -#elif defined(__WIN32__) - return CFSTR("Windows"); -#elif defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX return CFSTR("MacOS"); -#elif defined(__hpux__) - return CFSTR("HPUX"); -#elif defined(__svr4__) +#elif DEPLOYMENT_TARGET_SOLARIS return CFSTR("Solaris"); -#elif defined(__LINUX__) +#elif DEPLOYMENT_TARGET_HPUX + return CFSTR("HPUX"); +#elif DEPLOYMENT_TARGET_LINUX return CFSTR("Linux"); -#elif defined(__FREEBSD__) +#elif DEPLOYMENT_TARGET_FREEBSD return CFSTR("FreeBSD"); #else -#warning CFBundle: Unknown architecture - return CFSTR("Other"); +#error Unknown or unspecified DEPLOYMENT_TARGET #endif } __private_extern__ CFStringRef _CFBundleGetAlternatePlatformExecutablesSubdirectoryName(void) { -#if defined(__MACOS8__) - return CFSTR("Mac OS 8"); -#elif defined(__WIN32__) - return CFSTR("WinNT"); -#elif defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX return CFSTR("Mac OS X"); -#elif defined(__hpux__) - return CFSTR("HP-UX"); -#elif defined(__svr4__) +#elif DEPLOYMENT_TARGET_SOLARIS return CFSTR("Solaris"); -#elif defined(__LINUX__) +#elif DEPLOYMENT_TARGET_HPUX + return CFSTR("HP-UX"); +#elif DEPLOYMENT_TARGET_LINUX return CFSTR("Linux"); -#elif defined(__FREEBSD__) +#elif DEPLOYMENT_TARGET_FREEBSD return CFSTR("FreeBSD"); #else -#warning CFBundle: Unknown architecture - return CFSTR("Other"); +#error Unknown or unspecified DEPLOYMENT_TARGET #endif } __private_extern__ CFStringRef _CFBundleGetOtherPlatformExecutablesSubdirectoryName(void) { -#if defined(__MACOS8__) - return CFSTR("MacOS"); -#elif defined(__WIN32__) - return CFSTR("Other"); -#elif defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX return CFSTR("MacOSClassic"); -#elif defined(__hpux__) +#elif DEPLOYMENT_TARGET_HPUX return CFSTR("Other"); -#elif defined(__svr4__) +#elif DEPLOYMENT_TARGET_SOLARIS return CFSTR("Other"); -#elif defined(__LINUX__) +#elif DEPLOYMENT_TARGET_LINUX return CFSTR("Other"); -#elif defined(__FREEBSD__) +#elif DEPLOYMENT_TARGET_FREEBSD return CFSTR("Other"); #else -#warning CFBundle: Unknown architecture - return CFSTR("Other"); +#error Unknown or unspecified DEPLOYMENT_TARGET #endif } __private_extern__ CFStringRef _CFBundleGetOtherAlternatePlatformExecutablesSubdirectoryName(void) { -#if defined(__MACOS8__) - return CFSTR("Mac OS X"); -#elif defined(__WIN32__) - return CFSTR("Other"); -#elif defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX return CFSTR("Mac OS 8"); -#elif defined(__hpux__) +#elif DEPLOYMENT_TARGET_HPUX return CFSTR("Other"); -#elif defined(__svr4__) +#elif DEPLOYMENT_TARGET_SOLARIS return CFSTR("Other"); -#elif defined(__LINUX__) +#elif DEPLOYMENT_TARGET_LINUX return CFSTR("Other"); -#elif defined(__FREEBSD__) +#elif DEPLOYMENT_TARGET_FREEBSD return CFSTR("Other"); #else -#warning CFBundle: Unknown architecture - return CFSTR("Other"); +#error Unknown or unspecified DEPLOYMENT_TARGET #endif } @@ -2092,32 +2041,32 @@ __private_extern__ CFArrayRef _CFBundleCopyBundleRegionsArray(CFBundleRef bundle CF_EXPORT CFArrayRef CFBundleCopyBundleLocalizations(CFBundleRef bundle) { CFDictionaryRef infoDict = CFBundleGetInfoDictionary(bundle); CFURLRef resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle); -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES CFURLRef absoluteURL; CFStringRef directoryPath; CFArrayRef contents; CFRange contentsRange; CFIndex idx; -#else +#else /* READ_DIRECTORIES */ CFArrayRef urls = ((_CFBundleLayoutVersion(bundle) != 4) ? _CFContentsOfDirectory(CFGetAllocator(bundle), NULL, NULL, resourcesURL, _CFBundleLprojExtension) : NULL); -#endif +#endif /* READ_DIRECTORIES */ CFArrayRef predefinedLocalizations = NULL; CFMutableArrayRef result = NULL; if (infoDict) { - predefinedLocalizations = CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey); - if (predefinedLocalizations != NULL && CFGetTypeID(predefinedLocalizations) != CFArrayGetTypeID()) { + predefinedLocalizations = (CFArrayRef)CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey); + if (predefinedLocalizations && CFGetTypeID(predefinedLocalizations) != CFArrayGetTypeID()) { predefinedLocalizations = NULL; CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, kCFBundleLocalizationsKey); } - if (predefinedLocalizations != NULL) { + if (predefinedLocalizations) { CFIndex i, c = CFArrayGetCount(predefinedLocalizations); if (c > 0 && !result) result = CFArrayCreateMutable(CFGetAllocator(bundle), 0, &kCFTypeArrayCallBacks); for (i = 0; i < c; i++) CFArrayAppendValue(result, CFArrayGetValueAtIndex(predefinedLocalizations, i)); } } -#if USE_GETDIRENTRIES +#if READ_DIRECTORIES if (resourcesURL) { absoluteURL = CFURLCopyAbsoluteURL(resourcesURL); directoryPath = CFURLCopyFileSystemPath(absoluteURL, PLATFORM_PATH_STYLE); @@ -2126,7 +2075,7 @@ CF_EXPORT CFArrayRef CFBundleCopyBundleLocalizations(CFBundleRef bundle) { for (idx = 0; idx < contentsRange.length; idx++) { CFStringRef name = CFArrayGetValueAtIndex(contents, idx); if (CFStringHasSuffix(name, _CFBundleLprojExtensionWithDot)) { - CFStringRef localization = CFStringCreateWithSubstring(NULL, name, CFRangeMake(0, CFStringGetLength(name) - 6)); + CFStringRef localization = CFStringCreateWithSubstring(kCFAllocatorSystemDefault, name, CFRangeMake(0, CFStringGetLength(name) - 6)); if (!result) result = CFArrayCreateMutable(CFGetAllocator(bundle), 0, &kCFTypeArrayCallBacks); CFArrayAppendValue(result, localization); CFRelease(localization); @@ -2136,7 +2085,7 @@ CF_EXPORT CFArrayRef CFBundleCopyBundleLocalizations(CFBundleRef bundle) { CFRelease(directoryPath); CFRelease(absoluteURL); } -#else +#else /* READ_DIRECTORIES */ if (urls) { CFIndex i, c = CFArrayGetCount(urls); CFURLRef curURL, curAbsoluteURL; @@ -2146,7 +2095,7 @@ CF_EXPORT CFArrayRef CFBundleCopyBundleLocalizations(CFBundleRef bundle) { if (c > 0 && !result) result = CFArrayCreateMutable(CFGetAllocator(bundle), 0, &kCFTypeArrayCallBacks); for (i = 0; i < c; i++) { - curURL = CFArrayGetValueAtIndex(urls, i); + curURL = (CFURLRef)CFArrayGetValueAtIndex(urls, i); curAbsoluteURL = CFURLCopyAbsoluteURL(curURL); curStr = CFURLCopyFileSystemPath(curAbsoluteURL, PLATFORM_PATH_STYLE); CFRelease(curAbsoluteURL); @@ -2163,7 +2112,7 @@ CF_EXPORT CFArrayRef CFBundleCopyBundleLocalizations(CFBundleRef bundle) { } CFRelease(urls); } -#endif +#endif /* READ_DIRECTORIES */ if (!result) { CFStringRef developmentLocalization = CFBundleGetDevelopmentRegion(bundle); @@ -2180,10 +2129,10 @@ CF_EXPORT CFArrayRef CFBundleCopyBundleLocalizations(CFBundleRef bundle) { CF_EXPORT CFDictionaryRef CFBundleCopyInfoDictionaryForURL(CFURLRef url) { CFDictionaryRef result = NULL; - Boolean isDir; + Boolean isDir = false; if (_CFIsResourceAtURL(url, &isDir)) { if (isDir) { - result = _CFBundleCopyInfoDictionaryInDirectory(NULL, url, NULL); + result = _CFBundleCopyInfoDictionaryInDirectory(kCFAllocatorSystemDefault, url, NULL); } else { result = _CFBundleCopyInfoDictionaryInExecutable(url); } @@ -2191,9 +2140,21 @@ CF_EXPORT CFDictionaryRef CFBundleCopyInfoDictionaryForURL(CFURLRef url) { return result; } +CFArrayRef CFBundleCopyExecutableArchitecturesForURL(CFURLRef url) { + CFArrayRef result = NULL; + CFBundleRef bundle = CFBundleCreate(kCFAllocatorSystemDefault, url); + if (bundle) { + result = CFBundleCopyExecutableArchitectures(bundle); + CFRelease(bundle); + } else { + result = _CFBundleCopyArchitecturesForExecutable(url); + } + return result; +} + CFArrayRef CFBundleCopyLocalizationsForURL(CFURLRef url) { CFArrayRef result = NULL; - CFBundleRef bundle = CFBundleCreate(NULL, url); + CFBundleRef bundle = CFBundleCreate(kCFAllocatorSystemDefault, url); CFStringRef devLang = NULL; if (bundle) { result = CFBundleCopyBundleLocalizations(bundle); @@ -2201,15 +2162,11 @@ CFArrayRef CFBundleCopyLocalizationsForURL(CFURLRef url) { } else { CFDictionaryRef infoDict = _CFBundleCopyInfoDictionaryInExecutable(url); if (infoDict) { - CFArrayRef predefinedLocalizations = CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey); - if (predefinedLocalizations != NULL && CFGetTypeID(predefinedLocalizations) == CFArrayGetTypeID()) { - result = CFRetain(predefinedLocalizations); - } + CFArrayRef predefinedLocalizations = (CFArrayRef)CFDictionaryGetValue(infoDict, kCFBundleLocalizationsKey); + if (predefinedLocalizations && CFGetTypeID(predefinedLocalizations) == CFArrayGetTypeID()) result = (CFArrayRef)CFRetain(predefinedLocalizations); if (!result) { - devLang = CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey); - if (devLang != NULL && (CFGetTypeID(devLang) == CFStringGetTypeID() && CFStringGetLength(devLang) > 0)) { - result = CFArrayCreate(NULL, (const void **)&devLang, 1, &kCFTypeArrayCallBacks); - } + devLang = (CFStringRef)CFDictionaryGetValue(infoDict, kCFBundleDevelopmentRegionKey); + if (devLang && (CFGetTypeID(devLang) == CFStringGetTypeID() && CFStringGetLength(devLang) > 0)) result = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)&devLang, 1, &kCFTypeArrayCallBacks); } CFRelease(infoDict); } diff --git a/Base.subproj/CFByteOrder.h b/CFByteOrder.h similarity index 70% rename from Base.subproj/CFByteOrder.h rename to CFByteOrder.h index 0cf01b1..a56cb16 100644 --- a/Base.subproj/CFByteOrder.h +++ b/CFByteOrder.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,60 +21,60 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFByteOrder.h - Copyright (c) 1995-2005, Apple, Inc. All rights reserved. + Copyright (c) 1995-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFBYTEORDER__) #define __COREFOUNDATION_CFBYTEORDER__ 1 -#if defined(__i386__) && !defined(__LITTLE_ENDIAN__) - #define __LITTLE_ENDIAN__ 1 -#endif - -#if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__) -#error Do not know the endianess of this architecture -#endif - #include - -#if defined(__cplusplus) -extern "C" { +#if defined(__MACH__) && !defined(CF_USE_OSBYTEORDER_H) +#include +#define CF_USE_OSBYTEORDER_H 1 #endif -typedef enum __CFByteOrder { +CF_EXTERN_C_BEGIN + +enum __CFByteOrder { CFByteOrderUnknown, CFByteOrderLittleEndian, CFByteOrderBigEndian -} CFByteOrder; +}; +typedef CFIndex CFByteOrder; CF_INLINE CFByteOrder CFByteOrderGetCurrent(void) { - uint32_t x = (CFByteOrderBigEndian << 24) | CFByteOrderLittleEndian; - return (CFByteOrder)*((uint8_t *)&x); +#if CF_USE_OSBYTEORDER_H + int32_t byteOrder = OSHostByteOrder(); + switch (byteOrder) { + case OSLittleEndian: return CFByteOrderLittleEndian; + case OSBigEndian: return CFByteOrderBigEndian; + default: break; + } + return CFByteOrderUnknown; +#else +#if __LITTLE_ENDIAN__ + return CFByteOrderLittleEndian; +#elif __BIG_ENDIAN__ + return CFByteOrderBigEndian; +#else + return CFByteOrderUnknown; +#endif +#endif } CF_INLINE uint16_t CFSwapInt16(uint16_t arg) { -#if defined(__i386__) && defined(__GNUC__) - __asm__("xchgb %b0, %h0" : "+q" (arg)); - return arg; -#elif defined(__ppc__) && defined(__GNUC__) - uint16_t result; - __asm__("lhbrx %0,0,%1" : "=r" (result) : "r" (&arg), "m" (arg)); - return result; +#if CF_USE_OSBYTEORDER_H + return OSSwapInt16(arg); #else uint16_t result; - result = ((arg << 8) & 0xFF00) | ((arg >> 8) & 0xFF); + result = (uint16_t)(((arg << 8) & 0xFF00) | ((arg >> 8) & 0xFF)); return result; #endif } CF_INLINE uint32_t CFSwapInt32(uint32_t arg) { -#if defined(__i386__) && defined(__GNUC__) - __asm__("bswap %0" : "+r" (arg)); - return arg; -#elif defined(__ppc__) && defined(__GNUC__) - uint32_t result; - __asm__("lwbrx %0,0,%1" : "=r" (result) : "r" (&arg), "m" (arg)); - return result; +#if CF_USE_OSBYTEORDER_H + return OSSwapInt32(arg); #else uint32_t result; result = ((arg & 0xFF) << 24) | ((arg & 0xFF00) << 8) | ((arg >> 8) & 0xFF00) | ((arg >> 24) & 0xFF); @@ -83,6 +83,9 @@ CF_INLINE uint32_t CFSwapInt32(uint32_t arg) { } CF_INLINE uint64_t CFSwapInt64(uint64_t arg) { +#if CF_USE_OSBYTEORDER_H + return OSSwapInt64(arg); +#else union CFSwap { uint64_t sv; uint32_t ul[2]; @@ -91,10 +94,13 @@ CF_INLINE uint64_t CFSwapInt64(uint64_t arg) { result.ul[0] = CFSwapInt32(tmp.ul[1]); result.ul[1] = CFSwapInt32(tmp.ul[0]); return result.sv; +#endif } CF_INLINE uint16_t CFSwapInt16BigToHost(uint16_t arg) { -#if defined(__BIG_ENDIAN__) +#if CF_USE_OSBYTEORDER_H + return OSSwapBigToHostInt16(arg); +#elif __BIG_ENDIAN__ return arg; #else return CFSwapInt16(arg); @@ -102,7 +108,9 @@ CF_INLINE uint16_t CFSwapInt16BigToHost(uint16_t arg) { } CF_INLINE uint32_t CFSwapInt32BigToHost(uint32_t arg) { -#if defined(__BIG_ENDIAN__) +#if CF_USE_OSBYTEORDER_H + return OSSwapBigToHostInt32(arg); +#elif __BIG_ENDIAN__ return arg; #else return CFSwapInt32(arg); @@ -110,7 +118,9 @@ CF_INLINE uint32_t CFSwapInt32BigToHost(uint32_t arg) { } CF_INLINE uint64_t CFSwapInt64BigToHost(uint64_t arg) { -#if defined(__BIG_ENDIAN__) +#if CF_USE_OSBYTEORDER_H + return OSSwapBigToHostInt64(arg); +#elif __BIG_ENDIAN__ return arg; #else return CFSwapInt64(arg); @@ -118,7 +128,9 @@ CF_INLINE uint64_t CFSwapInt64BigToHost(uint64_t arg) { } CF_INLINE uint16_t CFSwapInt16HostToBig(uint16_t arg) { -#if defined(__BIG_ENDIAN__) +#if CF_USE_OSBYTEORDER_H + return OSSwapHostToBigInt16(arg); +#elif __BIG_ENDIAN__ return arg; #else return CFSwapInt16(arg); @@ -126,7 +138,9 @@ CF_INLINE uint16_t CFSwapInt16HostToBig(uint16_t arg) { } CF_INLINE uint32_t CFSwapInt32HostToBig(uint32_t arg) { -#if defined(__BIG_ENDIAN__) +#if CF_USE_OSBYTEORDER_H + return OSSwapHostToBigInt32(arg); +#elif __BIG_ENDIAN__ return arg; #else return CFSwapInt32(arg); @@ -134,7 +148,9 @@ CF_INLINE uint32_t CFSwapInt32HostToBig(uint32_t arg) { } CF_INLINE uint64_t CFSwapInt64HostToBig(uint64_t arg) { -#if defined(__BIG_ENDIAN__) +#if CF_USE_OSBYTEORDER_H + return OSSwapHostToBigInt64(arg); +#elif __BIG_ENDIAN__ return arg; #else return CFSwapInt64(arg); @@ -142,7 +158,9 @@ CF_INLINE uint64_t CFSwapInt64HostToBig(uint64_t arg) { } CF_INLINE uint16_t CFSwapInt16LittleToHost(uint16_t arg) { -#if defined(__LITTLE_ENDIAN__) +#if CF_USE_OSBYTEORDER_H + return OSSwapLittleToHostInt16(arg); +#elif __LITTLE_ENDIAN__ return arg; #else return CFSwapInt16(arg); @@ -150,7 +168,9 @@ CF_INLINE uint16_t CFSwapInt16LittleToHost(uint16_t arg) { } CF_INLINE uint32_t CFSwapInt32LittleToHost(uint32_t arg) { -#if defined(__LITTLE_ENDIAN__) +#if CF_USE_OSBYTEORDER_H + return OSSwapLittleToHostInt32(arg); +#elif __LITTLE_ENDIAN__ return arg; #else return CFSwapInt32(arg); @@ -158,7 +178,9 @@ CF_INLINE uint32_t CFSwapInt32LittleToHost(uint32_t arg) { } CF_INLINE uint64_t CFSwapInt64LittleToHost(uint64_t arg) { -#if defined(__LITTLE_ENDIAN__) +#if CF_USE_OSBYTEORDER_H + return OSSwapLittleToHostInt64(arg); +#elif __LITTLE_ENDIAN__ return arg; #else return CFSwapInt64(arg); @@ -166,7 +188,9 @@ CF_INLINE uint64_t CFSwapInt64LittleToHost(uint64_t arg) { } CF_INLINE uint16_t CFSwapInt16HostToLittle(uint16_t arg) { -#if defined(__LITTLE_ENDIAN__) +#if CF_USE_OSBYTEORDER_H + return OSSwapHostToLittleInt16(arg); +#elif __LITTLE_ENDIAN__ return arg; #else return CFSwapInt16(arg); @@ -174,7 +198,9 @@ CF_INLINE uint16_t CFSwapInt16HostToLittle(uint16_t arg) { } CF_INLINE uint32_t CFSwapInt32HostToLittle(uint32_t arg) { -#if defined(__LITTLE_ENDIAN__) +#if CF_USE_OSBYTEORDER_H + return OSSwapHostToLittleInt32(arg); +#elif __LITTLE_ENDIAN__ return arg; #else return CFSwapInt32(arg); @@ -182,7 +208,9 @@ CF_INLINE uint32_t CFSwapInt32HostToLittle(uint32_t arg) { } CF_INLINE uint64_t CFSwapInt64HostToLittle(uint64_t arg) { -#if defined(__LITTLE_ENDIAN__) +#if CF_USE_OSBYTEORDER_H + return OSSwapHostToLittleInt64(arg); +#elif __LITTLE_ENDIAN__ return arg; #else return CFSwapInt64(arg); @@ -198,7 +226,7 @@ CF_INLINE CFSwappedFloat32 CFConvertFloat32HostToSwapped(Float32 arg) { CFSwappedFloat32 sv; } result; result.v = arg; -#if defined(__LITTLE_ENDIAN__) +#if __LITTLE_ENDIAN__ result.sv.v = CFSwapInt32(result.sv.v); #endif return result.sv; @@ -210,7 +238,7 @@ CF_INLINE Float32 CFConvertFloat32SwappedToHost(CFSwappedFloat32 arg) { CFSwappedFloat32 sv; } result; result.sv = arg; -#if defined(__LITTLE_ENDIAN__) +#if __LITTLE_ENDIAN__ result.sv.v = CFSwapInt32(result.sv.v); #endif return result.v; @@ -222,7 +250,7 @@ CF_INLINE CFSwappedFloat64 CFConvertFloat64HostToSwapped(Float64 arg) { CFSwappedFloat64 sv; } result; result.v = arg; -#if defined(__LITTLE_ENDIAN__) +#if __LITTLE_ENDIAN__ result.sv.v = CFSwapInt64(result.sv.v); #endif return result.sv; @@ -234,7 +262,7 @@ CF_INLINE Float64 CFConvertFloat64SwappedToHost(CFSwappedFloat64 arg) { CFSwappedFloat64 sv; } result; result.sv = arg; -#if defined(__LITTLE_ENDIAN__) +#if __LITTLE_ENDIAN__ result.sv.v = CFSwapInt64(result.sv.v); #endif return result.v; @@ -246,7 +274,7 @@ CF_INLINE CFSwappedFloat32 CFConvertFloatHostToSwapped(float arg) { CFSwappedFloat32 sv; } result; result.v = arg; -#if defined(__LITTLE_ENDIAN__) +#if __LITTLE_ENDIAN__ result.sv.v = CFSwapInt32(result.sv.v); #endif return result.sv; @@ -258,7 +286,7 @@ CF_INLINE float CFConvertFloatSwappedToHost(CFSwappedFloat32 arg) { CFSwappedFloat32 sv; } result; result.sv = arg; -#if defined(__LITTLE_ENDIAN__) +#if __LITTLE_ENDIAN__ result.sv.v = CFSwapInt32(result.sv.v); #endif return result.v; @@ -270,7 +298,7 @@ CF_INLINE CFSwappedFloat64 CFConvertDoubleHostToSwapped(double arg) { CFSwappedFloat64 sv; } result; result.v = arg; -#if defined(__LITTLE_ENDIAN__) +#if __LITTLE_ENDIAN__ result.sv.v = CFSwapInt64(result.sv.v); #endif return result.sv; @@ -282,15 +310,13 @@ CF_INLINE double CFConvertDoubleSwappedToHost(CFSwappedFloat64 arg) { CFSwappedFloat64 sv; } result; result.sv = arg; -#if defined(__LITTLE_ENDIAN__) +#if __LITTLE_ENDIAN__ result.sv.v = CFSwapInt64(result.sv.v); #endif return result.v; } -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFBYTEORDER__ */ diff --git a/CFCalendar.c b/CFCalendar.c new file mode 100644 index 0000000..b7ee551 --- /dev/null +++ b/CFCalendar.c @@ -0,0 +1,1051 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFCalendar.c + Copyright 2004-2004, Apple Computer, Inc. All rights reserved. + Responsibility: Christopher Kane +*/ + +#include +#include +#include "CFInternal.h" +#include "CFPriv.h" +#include + +#define BUFFER_SIZE 512 + +struct __CFCalendar { + CFRuntimeBase _base; + CFStringRef _identifier; // canonical identifier, never NULL + CFLocaleRef _locale; + CFStringRef _localeID; + CFTimeZoneRef _tz; + UCalendar *_cal; +}; + +static Boolean __CFCalendarEqual(CFTypeRef cf1, CFTypeRef cf2) { + CFCalendarRef calendar1 = (CFCalendarRef)cf1; + CFCalendarRef calendar2 = (CFCalendarRef)cf2; + return CFEqual(calendar1->_identifier, calendar2->_identifier); +} + +static CFHashCode __CFCalendarHash(CFTypeRef cf) { + CFCalendarRef calendar = (CFCalendarRef)cf; + return CFHash(calendar->_identifier); +} + +static CFStringRef __CFCalendarCopyDescription(CFTypeRef cf) { + CFCalendarRef calendar = (CFCalendarRef)cf; + return CFStringCreateWithFormat(CFGetAllocator(calendar), NULL, CFSTR("{identifier = '%@'}"), cf, CFGetAllocator(calendar), calendar->_identifier); +} + +static void __CFCalendarDeallocate(CFTypeRef cf) { + CFCalendarRef calendar = (CFCalendarRef)cf; + CFRelease(calendar->_identifier); + if (calendar->_locale) CFRelease(calendar->_locale); + if (calendar->_localeID) CFRelease(calendar->_localeID); + CFRelease(calendar->_tz); + if (calendar->_cal) ucal_close(calendar->_cal); +} + +static CFTypeID __kCFCalendarTypeID = _kCFRuntimeNotATypeID; + +static const CFRuntimeClass __CFCalendarClass = { + 0, + "CFCalendar", + NULL, // init + NULL, // copy + __CFCalendarDeallocate, + __CFCalendarEqual, + __CFCalendarHash, + NULL, // + __CFCalendarCopyDescription +}; + +static void __CFCalendarInitialize(void) { + __kCFCalendarTypeID = _CFRuntimeRegisterClass(&__CFCalendarClass); +} + +CFTypeID CFCalendarGetTypeID(void) { + if (_kCFRuntimeNotATypeID == __kCFCalendarTypeID) __CFCalendarInitialize(); + return __kCFCalendarTypeID; +} + +__private_extern__ UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID, CFStringRef localeID, CFTimeZoneRef tz) { + if (calendarID) { + CFDictionaryRef components = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, localeID); + CFMutableDictionaryRef mcomponents = CFDictionaryCreateMutableCopy(kCFAllocatorSystemDefault, 0, components); + CFDictionarySetValue(mcomponents, kCFLocaleCalendarIdentifier, calendarID); + localeID = CFLocaleCreateLocaleIdentifierFromComponents(kCFAllocatorSystemDefault, mcomponents); + CFRelease(mcomponents); + CFRelease(components); + } + + char buffer[BUFFER_SIZE]; + const char *cstr = CFStringGetCStringPtr(localeID, kCFStringEncodingASCII); + if (NULL == cstr) { + if (CFStringGetCString(localeID, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer; + } + if (NULL == cstr) { + if (calendarID) CFRelease(localeID); + return NULL; + } + + UChar ubuffer[BUFFER_SIZE]; + CFStringRef tznam = CFTimeZoneGetName(tz); + CFIndex cnt = CFStringGetLength(tznam); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters(tznam, CFRangeMake(0, cnt), (UniChar *)ubuffer); + + UErrorCode status = U_ZERO_ERROR; + UCalendar *cal = ucal_open(ubuffer, cnt, cstr, UCAL_TRADITIONAL, &status); + if (calendarID) CFRelease(localeID); + return cal; +} + +static void __CFCalendarSetupCal(CFCalendarRef calendar) { + calendar->_cal = __CFCalendarCreateUCalendar(calendar->_identifier, calendar->_localeID, calendar->_tz); +} + +static void __CFCalendarZapCal(CFCalendarRef calendar) { + ucal_close(calendar->_cal); + calendar->_cal = NULL; +} + +CFCalendarRef CFCalendarCopyCurrent(void) { + CFLocaleRef locale = CFLocaleCopyCurrent(); + CFCalendarRef calID = (CFCalendarRef)CFLocaleGetValue(locale, kCFLocaleCalendarIdentifier); + if (calID) { + CFCalendarRef calendar = CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault, (CFStringRef)calID); + CFCalendarSetLocale(calendar, locale); + CFRelease(locale); + return calendar; + } + return NULL; +} + +CFCalendarRef CFCalendarCreateWithIdentifier(CFAllocatorRef allocator, CFStringRef identifier) { + if (allocator == NULL) allocator = __CFGetDefaultAllocator(); + __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); + __CFGenericValidateType(identifier, CFStringGetTypeID()); + // return NULL until Chinese calendar is available + if (identifier != kCFGregorianCalendar && identifier != kCFBuddhistCalendar && identifier != kCFJapaneseCalendar && identifier != kCFIslamicCalendar && identifier != kCFIslamicCivilCalendar && identifier != kCFHebrewCalendar) { +// if (identifier != kCFGregorianCalendar && identifier != kCFBuddhistCalendar && identifier != kCFJapaneseCalendar && identifier != kCFIslamicCalendar && identifier != kCFIslamicCivilCalendar && identifier != kCFHebrewCalendar && identifier != kCFChineseCalendar) { + if (CFEqual(kCFGregorianCalendar, identifier)) identifier = kCFGregorianCalendar; + else if (CFEqual(kCFBuddhistCalendar, identifier)) identifier = kCFBuddhistCalendar; + else if (CFEqual(kCFJapaneseCalendar, identifier)) identifier = kCFJapaneseCalendar; + else if (CFEqual(kCFIslamicCalendar, identifier)) identifier = kCFIslamicCalendar; + else if (CFEqual(kCFIslamicCivilCalendar, identifier)) identifier = kCFIslamicCivilCalendar; + else if (CFEqual(kCFHebrewCalendar, identifier)) identifier = kCFHebrewCalendar; +// else if (CFEqual(kCFChineseCalendar, identifier)) identifier = kCFChineseCalendar; + else return NULL; + } + struct __CFCalendar *calendar = NULL; + uint32_t size = sizeof(struct __CFCalendar) - sizeof(CFRuntimeBase); + calendar = (struct __CFCalendar *)_CFRuntimeCreateInstance(allocator, CFCalendarGetTypeID(), size, NULL); + if (NULL == calendar) { + return NULL; + } + calendar->_identifier = (CFStringRef)CFRetain(identifier); + calendar->_locale = NULL; + calendar->_localeID = CFLocaleGetIdentifier(CFLocaleGetSystem()); + calendar->_tz = CFTimeZoneCopyDefault(); + calendar->_cal = NULL; + return (CFCalendarRef)calendar; +} + +CFStringRef CFCalendarGetIdentifier(CFCalendarRef calendar) { + CF_OBJC_FUNCDISPATCH0(CFCalendarGetTypeID(), CFStringRef, calendar, "calendarIdentifier"); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + return calendar->_identifier; +} + +CFLocaleRef CFCalendarCopyLocale(CFCalendarRef calendar) { + CF_OBJC_FUNCDISPATCH0(CFCalendarGetTypeID(), CFLocaleRef, calendar, "_copyLocale"); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + return (CFLocaleRef)CFLocaleCreate(kCFAllocatorSystemDefault, calendar->_localeID); +} + +void CFCalendarSetLocale(CFCalendarRef calendar, CFLocaleRef locale) { + CF_OBJC_FUNCDISPATCH1(CFCalendarGetTypeID(), void, calendar, "setLocale:", locale); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + __CFGenericValidateType(locale, CFLocaleGetTypeID()); + CFStringRef localeID = CFLocaleGetIdentifier(locale); + if (localeID != calendar->_localeID) { + CFRelease(calendar->_localeID); + CFRetain(localeID); + calendar->_localeID = localeID; + if (calendar->_cal) __CFCalendarZapCal(calendar); + } +} + +CFTimeZoneRef CFCalendarCopyTimeZone(CFCalendarRef calendar) { + CF_OBJC_FUNCDISPATCH0(CFCalendarGetTypeID(), CFTimeZoneRef, calendar, "_copyTimeZone"); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + return (CFTimeZoneRef)CFRetain(calendar->_tz); +} + +void CFCalendarSetTimeZone(CFCalendarRef calendar, CFTimeZoneRef tz) { + CF_OBJC_FUNCDISPATCH1(CFCalendarGetTypeID(), void, calendar, "setTimeZone:", tz); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + if (tz) __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); + if (tz != calendar->_tz) { + CFRelease(calendar->_tz); + calendar->_tz = tz ? (CFTimeZoneRef)CFRetain(tz) : CFTimeZoneCopyDefault(); + if (calendar->_cal) __CFCalendarZapCal(calendar); + } +} + +CFIndex CFCalendarGetFirstWeekday(CFCalendarRef calendar) { + CF_OBJC_FUNCDISPATCH0(CFCalendarGetTypeID(), CFIndex, calendar, "firstWeekday"); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + if (!calendar->_cal) __CFCalendarSetupCal(calendar); + if (calendar->_cal) { + return ucal_getAttribute(calendar->_cal, UCAL_FIRST_DAY_OF_WEEK); + } + return -1; +} + +void CFCalendarSetFirstWeekday(CFCalendarRef calendar, CFIndex wkdy) { + CF_OBJC_FUNCDISPATCH1(CFCalendarGetTypeID(), void, calendar, "setFirstWeekday:", wkdy); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + if (!calendar->_cal) __CFCalendarSetupCal(calendar); + if (calendar->_cal) { + ucal_setAttribute(calendar->_cal, UCAL_FIRST_DAY_OF_WEEK, wkdy); + } +} + +CFIndex CFCalendarGetMinimumDaysInFirstWeek(CFCalendarRef calendar) { + CF_OBJC_FUNCDISPATCH0(CFCalendarGetTypeID(), CFIndex, calendar, "minimumDaysInFirstWeek"); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + if (!calendar->_cal) __CFCalendarSetupCal(calendar); + return calendar->_cal ? ucal_getAttribute(calendar->_cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK) : -1; +} + +void CFCalendarSetMinimumDaysInFirstWeek(CFCalendarRef calendar, CFIndex mwd) { + CF_OBJC_FUNCDISPATCH1(CFCalendarGetTypeID(), void, calendar, "setMinimumDaysInFirstWeek:", mwd); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + if (!calendar->_cal) __CFCalendarSetupCal(calendar); + if (calendar->_cal) ucal_setAttribute(calendar->_cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK, mwd); +} + +CFDateRef CFCalendarCopyGregorianStartDate(CFCalendarRef calendar) { + CF_OBJC_FUNCDISPATCH0(CFCalendarGetTypeID(), CFDateRef, calendar, "_gregorianStartDate"); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + if (!calendar->_cal) __CFCalendarSetupCal(calendar); + UErrorCode status = U_ZERO_ERROR; + UDate udate = calendar->_cal ? ucal_getGregorianChange(calendar->_cal, &status) : 0; + if (calendar->_cal && U_SUCCESS(status)) { + CFAbsoluteTime at = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970; + return CFDateCreate(CFGetAllocator(calendar), at); + } + return NULL; +} + +void CFCalendarSetGregorianStartDate(CFCalendarRef calendar, CFDateRef date) { + CF_OBJC_FUNCDISPATCH1(CFCalendarGetTypeID(), void, calendar, "_setGregorianStartDate:", date); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + if (date) __CFGenericValidateType(date, CFDateGetTypeID()); + if (!calendar->_cal) __CFCalendarSetupCal(calendar); + if (!calendar->_cal) return; + if (!date) { + UErrorCode status = U_ZERO_ERROR; + UCalendar *cal = __CFCalendarCreateUCalendar(calendar->_identifier, calendar->_localeID, calendar->_tz); + UDate udate = cal ? ucal_getGregorianChange(cal, &status) : 0; + if (cal && U_SUCCESS(status)) { + status = U_ZERO_ERROR; + if (calendar->_cal) ucal_setGregorianChange(calendar->_cal, udate, &status); + } + if (cal) ucal_close(cal); + } else { + CFAbsoluteTime at = CFDateGetAbsoluteTime(date); + UDate udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0; + UErrorCode status = U_ZERO_ERROR; + if (calendar->_cal) ucal_setGregorianChange(calendar->_cal, udate, &status); + } +} + + +static UCalendarDateFields __CFCalendarGetICUFieldCode(CFCalendarUnit unit) { + switch (unit) { + case kCFCalendarUnitEra: return UCAL_ERA; + case kCFCalendarUnitYear: return UCAL_YEAR; + case kCFCalendarUnitMonth: return UCAL_MONTH; + case kCFCalendarUnitDay: return UCAL_DAY_OF_MONTH; + case kCFCalendarUnitHour: return UCAL_HOUR_OF_DAY; + case kCFCalendarUnitMinute: return UCAL_MINUTE; + case kCFCalendarUnitSecond: return UCAL_SECOND; + case kCFCalendarUnitWeek: return UCAL_WEEK_OF_YEAR; + case kCFCalendarUnitWeekday: return UCAL_DAY_OF_WEEK; + case kCFCalendarUnitWeekdayOrdinal: return UCAL_DAY_OF_WEEK_IN_MONTH; + } + return (UCalendarDateFields)-1; +} + +static UCalendarDateFields __CFCalendarGetICUFieldCodeFromChar(char ch) { + switch (ch) { + case 'G': return UCAL_ERA; + case 'y': return UCAL_YEAR; + case 'M': return UCAL_MONTH; + case 'd': return UCAL_DAY_OF_MONTH; + case 'h': return UCAL_HOUR; + case 'H': return UCAL_HOUR_OF_DAY; + case 'm': return UCAL_MINUTE; + case 's': return UCAL_SECOND; + case 'S': return UCAL_MILLISECOND; + case 'w': return UCAL_WEEK_OF_YEAR; + case 'W': return UCAL_WEEK_OF_MONTH; + case 'E': return UCAL_DAY_OF_WEEK; + case 'D': return UCAL_DAY_OF_YEAR; + case 'F': return UCAL_DAY_OF_WEEK_IN_MONTH; + case 'a': return UCAL_AM_PM; + case 'g': return UCAL_JULIAN_DAY; + } + return (UCalendarDateFields)-1; +} + +static UCalendarDateFields __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; + } + return (UCalendarDateFields)-1; +} + +CFRange CFCalendarGetMinimumRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit) { + CF_OBJC_FUNCDISPATCH1(CFCalendarGetTypeID(), CFRange, calendar, "_minimumRangeOfUnit:", unit); + CFRange range = {kCFNotFound, kCFNotFound}; + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + if (!calendar->_cal) __CFCalendarSetupCal(calendar); + if (calendar->_cal) { + ucal_clear(calendar->_cal); + UCalendarDateFields field = __CFCalendarGetICUFieldCode(unit); + UErrorCode status = U_ZERO_ERROR; + range.location = ucal_getLimit(calendar->_cal, field, UCAL_GREATEST_MINIMUM, &status); + range.length = ucal_getLimit(calendar->_cal, field, UCAL_LEAST_MAXIMUM, &status) - range.location + 1; + if (UCAL_MONTH == field) range.location++; + if (100000 < range.length) range.length = 100000; + } + return range; +} + +CFRange CFCalendarGetMaximumRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit) { + CF_OBJC_FUNCDISPATCH1(CFCalendarGetTypeID(), CFRange, calendar, "_maximumRangeOfUnit:", unit); + CFRange range = {kCFNotFound, kCFNotFound}; + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + if (!calendar->_cal) __CFCalendarSetupCal(calendar); + if (calendar->_cal) { + ucal_clear(calendar->_cal); + UCalendarDateFields field = __CFCalendarGetICUFieldCode(unit); + UErrorCode status = U_ZERO_ERROR; + range.location = ucal_getLimit(calendar->_cal, field, UCAL_MINIMUM, &status); + range.length = ucal_getLimit(calendar->_cal, field, UCAL_MAXIMUM, &status) - range.location + 1; + if (UCAL_MONTH == field) range.location++; + if (100000 < range.length) range.length = 100000; + } + return range; +} + +static void __CFCalendarSetToFirstInstant(CFCalendarRef calendar, CFCalendarUnit unit, CFAbsoluteTime at) { + // Set UCalendar to first instant of unit prior to 'at' + UErrorCode status = U_ZERO_ERROR; + UDate udate = floor((at + kCFAbsoluteTimeIntervalSince1970) * 1000.0); + 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 kCFCalendarUnitWeek: + { + // 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); + int32_t dow = ucal_get(calendar->_cal, UCAL_DAY_OF_WEEK, &status); + while (dow != goal) { + ucal_add(calendar->_cal, UCAL_DAY_OF_MONTH, -1, &status); + dow = ucal_get(calendar->_cal, UCAL_DAY_OF_WEEK, &status); + } + goto day; + } + case kCFCalendarUnitEra: + { + target_era = ucal_get(calendar->_cal, UCAL_ERA, &status); + ucal_set(calendar->_cal, UCAL_YEAR, ucal_getLimit(calendar->_cal, UCAL_YEAR, UCAL_ACTUAL_MINIMUM, &status)); + } + case kCFCalendarUnitYear: + ucal_set(calendar->_cal, UCAL_MONTH, ucal_getLimit(calendar->_cal, UCAL_MONTH, UCAL_ACTUAL_MINIMUM, &status)); + case kCFCalendarUnitMonth: + ucal_set(calendar->_cal, UCAL_DAY_OF_MONTH, ucal_getLimit(calendar->_cal, UCAL_DAY_OF_MONTH, UCAL_ACTUAL_MINIMUM, &status)); + case kCFCalendarUnitWeekday: + case kCFCalendarUnitDay: + day:; + ucal_set(calendar->_cal, UCAL_HOUR_OF_DAY, ucal_getLimit(calendar->_cal, UCAL_HOUR_OF_DAY, UCAL_ACTUAL_MINIMUM, &status)); + case kCFCalendarUnitHour: + ucal_set(calendar->_cal, UCAL_MINUTE, ucal_getLimit(calendar->_cal, UCAL_MINUTE, UCAL_ACTUAL_MINIMUM, &status)); + case kCFCalendarUnitMinute: + ucal_set(calendar->_cal, UCAL_SECOND, ucal_getLimit(calendar->_cal, UCAL_SECOND, UCAL_ACTUAL_MINIMUM, &status)); + case kCFCalendarUnitSecond: + ucal_set(calendar->_cal, UCAL_MILLISECOND, 0); + } + if (INT_MIN != target_era && ucal_get(calendar->_cal, UCAL_ERA, &status) < target_era) { + // In the Japanese calendar, and possibly others, eras don't necessarily + // start on the first day of a year, so the previous code may have backed + // up into the previous era, and we have to correct forward. + UDate bad_udate = ucal_getMillis(calendar->_cal, &status); + ucal_add(calendar->_cal, UCAL_MONTH, 1, &status); + while (ucal_get(calendar->_cal, UCAL_ERA, &status) < target_era) { + bad_udate = ucal_getMillis(calendar->_cal, &status); + ucal_add(calendar->_cal, UCAL_MONTH, 1, &status); + } + udate = ucal_getMillis(calendar->_cal, &status); + // target date is between bad_udate and udate + for (;;) { + UDate test_udate = (udate + bad_udate) / 2; + ucal_setMillis(calendar->_cal, test_udate, &status); + if (ucal_get(calendar->_cal, UCAL_ERA, &status) < target_era) { + bad_udate = test_udate; + } else { + udate = test_udate; + } + if (fabs(udate - bad_udate) < 1000) break; + } + do { + bad_udate = floor((bad_udate + 1000) / 1000) * 1000; + ucal_setMillis(calendar->_cal, bad_udate, &status); + } while (ucal_get(calendar->_cal, UCAL_ERA, &status) < target_era); + } +} + +static Boolean __validUnits(CFCalendarUnit smaller, CFCalendarUnit bigger) { + switch (bigger) { + case kCFCalendarUnitEra: + if (kCFCalendarUnitEra == smaller) return false; + if (kCFCalendarUnitWeekday == smaller) return false; + 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 kCFCalendarUnitYear: + if (kCFCalendarUnitEra == smaller) return false; + if (kCFCalendarUnitYear == smaller) return false; + if (kCFCalendarUnitWeekday == smaller) return false; + return true; + case kCFCalendarUnitMonth: + if (kCFCalendarUnitEra == smaller) return false; + if (kCFCalendarUnitYear == smaller) return false; + if (kCFCalendarUnitMonth == smaller) return false; + if (kCFCalendarUnitWeekday == smaller) return false; + return true; + case kCFCalendarUnitDay: + if (kCFCalendarUnitHour == smaller) return true; + if (kCFCalendarUnitMinute == smaller) return true; + if (kCFCalendarUnitSecond == smaller) return true; + return false; + case kCFCalendarUnitHour: + if (kCFCalendarUnitMinute == smaller) return true; + if (kCFCalendarUnitSecond == smaller) return true; + return false; + case kCFCalendarUnitMinute: + if (kCFCalendarUnitSecond == smaller) return true; + return false; + case kCFCalendarUnitWeek: + if (kCFCalendarUnitWeekday == smaller) return true; + if (kCFCalendarUnitDay == smaller) return true; + if (kCFCalendarUnitHour == smaller) return true; + if (kCFCalendarUnitMinute == smaller) return true; + if (kCFCalendarUnitSecond == smaller) return true; + return false; + case kCFCalendarUnitSecond: + case kCFCalendarUnitWeekday: + case kCFCalendarUnitWeekdayOrdinal: + return false; + } + return false; +}; + +static CFRange __CFCalendarGetRangeOfUnit1(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) { + CFRange range = {kCFNotFound, kCFNotFound}; + if (!__validUnits(smallerUnit, biggerUnit)) return range; + CF_OBJC_FUNCDISPATCH3(CFCalendarGetTypeID(), CFRange, calendar, "_rangeOfUnit:inUnit:forAT:", smallerUnit, biggerUnit, at); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + if (!calendar->_cal) __CFCalendarSetupCal(calendar); + if (calendar->_cal) { + int32_t dow = -1; + ucal_clear(calendar->_cal); + UCalendarDateFields smallField = __CFCalendarGetICUFieldCode(smallerUnit); + UCalendarDateFields bigField = __CFCalendarGetICUFieldCode(biggerUnit); + if (kCFCalendarUnitWeekdayOrdinal == smallerUnit) { + UErrorCode status = U_ZERO_ERROR; + UDate udate = floor((at + kCFAbsoluteTimeIntervalSince1970) * 1000.0); + ucal_setMillis(calendar->_cal, udate, &status); + dow = ucal_get(calendar->_cal, UCAL_DAY_OF_WEEK, &status); + } + // Set calendar to first instant of big unit + __CFCalendarSetToFirstInstant(calendar, biggerUnit, at); + UErrorCode status = U_ZERO_ERROR; + UDate start = ucal_getMillis(calendar->_cal, &status); + if (kCFCalendarUnitWeek == biggerUnit) { + range.location = ucal_get(calendar->_cal, smallField, &status); + if (kCFCalendarUnitMonth == smallerUnit) range.location++; + } else { + range.location = (kCFCalendarUnitHour == smallerUnit || kCFCalendarUnitMinute == smallerUnit || kCFCalendarUnitSecond == smallerUnit) ? 0 : 1; + } + // Set calendar to first instant of next value of big unit + if (UCAL_ERA == bigField) { + // ICU refuses to do the addition, probably because we are + // at the limit of UCAL_ERA. Use alternate strategy. + CFIndex limit = ucal_getLimit(calendar->_cal, UCAL_YEAR, UCAL_MAXIMUM, &status); + if (100000 < limit) limit = 100000; + ucal_add(calendar->_cal, UCAL_YEAR, limit, &status); + } else { + ucal_add(calendar->_cal, bigField, 1, &status); + } + if (kCFCalendarUnitWeek == smallerUnit && kCFCalendarUnitYear == biggerUnit) { + ucal_add(calendar->_cal, UCAL_SECOND, -1, &status); + range.length = ucal_get(calendar->_cal, UCAL_WEEK_OF_YEAR, &status); + while (1 == range.length) { + ucal_add(calendar->_cal, UCAL_DAY_OF_MONTH, -1, &status); + range.length = ucal_get(calendar->_cal, UCAL_WEEK_OF_YEAR, &status); + } + range.location = 1; + return range; + } else if (kCFCalendarUnitWeek == smallerUnit && kCFCalendarUnitMonth == biggerUnit) { + ucal_add(calendar->_cal, UCAL_SECOND, -1, &status); + range.length = ucal_get(calendar->_cal, UCAL_WEEK_OF_YEAR, &status); + range.location = 1; + return range; + } + UDate goal = ucal_getMillis(calendar->_cal, &status); + // Set calendar back to first instant of big unit + ucal_setMillis(calendar->_cal, start, &status); + if (kCFCalendarUnitWeekdayOrdinal == smallerUnit) { + // roll day forward to first 'dow' + while (ucal_get(calendar->_cal, (kCFCalendarUnitMonth == biggerUnit) ? UCAL_WEEK_OF_MONTH : UCAL_WEEK_OF_YEAR, &status) != 1) { + ucal_add(calendar->_cal, UCAL_DAY_OF_MONTH, 1, &status); + } + while (ucal_get(calendar->_cal, UCAL_DAY_OF_WEEK, &status) != dow) { + ucal_add(calendar->_cal, UCAL_DAY_OF_MONTH, 1, &status); + } + start = ucal_getMillis(calendar->_cal, &status); + goal -= 1000; + range.location = 1; // constant here works around ICU -- see 3948293 + } + UDate curr = start; + range.length = (kCFCalendarUnitWeekdayOrdinal == smallerUnit) ? 1 : 0; + const int multiple_table[] = {0, 0, 16, 19, 24, 26, 24, 28, 14, 14, 14}; + int multiple = (1 << multiple_table[flsl(smallerUnit) - 1]); + Boolean divide = false, alwaysDivide = false; + while (curr < goal) { + ucal_add(calendar->_cal, smallField, multiple, &status); + UDate newcurr = ucal_getMillis(calendar->_cal, &status); + if (curr < newcurr && newcurr <= goal) { + range.length += multiple; + curr = newcurr; + } else { + // Either newcurr is going backwards, or not making + // progress, or has overshot the goal; reset date + // and try smaller multiples. + ucal_setMillis(calendar->_cal, curr, &status); + divide = true; + // once we start overshooting the goal, the add at + // smaller multiples will succeed at most once for + // each multiple, so we reduce it every time through + // the loop. + if (goal < newcurr) alwaysDivide = true; + } + if (divide) { + multiple = multiple / 2; + if (0 == multiple) break; + divide = alwaysDivide; + } + } + } + return range; +} + +static CFRange __CFCalendarGetRangeOfUnit2(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) __attribute__((noinline)); +static CFRange __CFCalendarGetRangeOfUnit2(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) { + CF_OBJC_FUNCDISPATCH3(CFCalendarGetTypeID(), CFRange, calendar, "_rangeOfUnit:inUnit:forAT:", smallerUnit, biggerUnit, at); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + CFRange range = {kCFNotFound, kCFNotFound}; + if (!calendar->_cal) __CFCalendarSetupCal(calendar); + if (calendar->_cal) { + switch (smallerUnit) { + case kCFCalendarUnitSecond: + switch (biggerUnit) { + case kCFCalendarUnitMinute: + case kCFCalendarUnitHour: + case kCFCalendarUnitDay: + case kCFCalendarUnitWeekday: + case kCFCalendarUnitWeek: + case kCFCalendarUnitMonth: + case kCFCalendarUnitYear: + case kCFCalendarUnitEra: + // goto calculate; + range.location = 0; + range.length = 60; + break; + } + break; + case kCFCalendarUnitMinute: + switch (biggerUnit) { + case kCFCalendarUnitHour: + case kCFCalendarUnitDay: + case kCFCalendarUnitWeekday: + case kCFCalendarUnitWeek: + case kCFCalendarUnitMonth: + case kCFCalendarUnitYear: + case kCFCalendarUnitEra: + // goto calculate; + range.location = 0; + range.length = 60; + break; + } + break; + case kCFCalendarUnitHour: + switch (biggerUnit) { + case kCFCalendarUnitDay: + case kCFCalendarUnitWeekday: + case kCFCalendarUnitWeek: + case kCFCalendarUnitMonth: + case kCFCalendarUnitYear: + case kCFCalendarUnitEra: + // goto calculate; + range.location = 0; + range.length = 24; + break; + } + break; + case kCFCalendarUnitDay: + switch (biggerUnit) { + case kCFCalendarUnitWeek: + case kCFCalendarUnitMonth: + case kCFCalendarUnitYear: + case kCFCalendarUnitEra: + goto calculate; + break; + } + break; + case kCFCalendarUnitWeekday: + switch (biggerUnit) { + case kCFCalendarUnitWeek: + case kCFCalendarUnitMonth: + case kCFCalendarUnitYear: + case kCFCalendarUnitEra: + goto calculate; + break; + } + break; + case kCFCalendarUnitWeekdayOrdinal: + switch (biggerUnit) { + case kCFCalendarUnitMonth: + case kCFCalendarUnitYear: + case kCFCalendarUnitEra: + goto calculate; + break; + } + break; + case kCFCalendarUnitWeek: + switch (biggerUnit) { + case kCFCalendarUnitMonth: + case kCFCalendarUnitYear: + case kCFCalendarUnitEra: + goto calculate; + break; + } + break; + case kCFCalendarUnitMonth: + switch (biggerUnit) { + case kCFCalendarUnitYear: + case kCFCalendarUnitEra: + goto calculate; + break; + } + break; + case kCFCalendarUnitYear: + switch (biggerUnit) { + case kCFCalendarUnitEra: + goto calculate; + break; + } + break; + case kCFCalendarUnitEra: + break; + } + } + return range; + + calculate:; + ucal_clear(calendar->_cal); + UCalendarDateFields smallField = __CFCalendarGetICUFieldCode(smallerUnit); + UCalendarDateFields bigField = __CFCalendarGetICUFieldCode(biggerUnit); + UCalendarDateFields yearField = __CFCalendarGetICUFieldCode(kCFCalendarUnitYear); + UCalendarDateFields fieldToAdd = smallField; + if (kCFCalendarUnitWeekday == smallerUnit) { + fieldToAdd = __CFCalendarGetICUFieldCode(kCFCalendarUnitDay); + } + int32_t dow = -1; + if (kCFCalendarUnitWeekdayOrdinal == smallerUnit) { + UErrorCode status = U_ZERO_ERROR; + UDate udate = floor((at + kCFAbsoluteTimeIntervalSince1970) * 1000.0); + ucal_setMillis(calendar->_cal, udate, &status); + dow = ucal_get(calendar->_cal, UCAL_DAY_OF_WEEK, &status); + fieldToAdd = __CFCalendarGetICUFieldCode(kCFCalendarUnitWeek); + } + // Set calendar to first instant of big unit + __CFCalendarSetToFirstInstant(calendar, biggerUnit, at); + if (kCFCalendarUnitWeekdayOrdinal == smallerUnit) { + UErrorCode status = U_ZERO_ERROR; + // roll day forward to first 'dow' + while (ucal_get(calendar->_cal, (kCFCalendarUnitMonth == biggerUnit) ? UCAL_WEEK_OF_MONTH : UCAL_WEEK_OF_YEAR, &status) != 1) { + ucal_add(calendar->_cal, UCAL_DAY_OF_MONTH, 1, &status); + } + while (ucal_get(calendar->_cal, UCAL_DAY_OF_WEEK, &status) != dow) { + ucal_add(calendar->_cal, UCAL_DAY_OF_MONTH, 1, &status); + } + } + int32_t minSmallValue = INT32_MAX; + int32_t maxSmallValue = INT32_MIN; + UErrorCode status = U_ZERO_ERROR; + int32_t bigValue = ucal_get(calendar->_cal, bigField, &status); + for (;;) { + int32_t smallValue = ucal_get(calendar->_cal, smallField, &status); + if (smallValue < minSmallValue) minSmallValue = smallValue; + if (smallValue > maxSmallValue) maxSmallValue = smallValue; + ucal_add(calendar->_cal, fieldToAdd, 1, &status); + if (bigValue != ucal_get(calendar->_cal, bigField, &status)) break; + if (biggerUnit == kCFCalendarUnitEra && ucal_get(calendar->_cal, yearField, &status) > 10000) break; + // we assume an answer for 10000 years can be extrapolated to 100000 years, to save time + } + status = U_ZERO_ERROR; + range.location = minSmallValue; + if (smallerUnit == kCFCalendarUnitMonth) range.location = 1; + range.length = maxSmallValue - minSmallValue + 1; + if (biggerUnit == kCFCalendarUnitEra && ucal_get(calendar->_cal, yearField, &status) > 10000) range.length = 100000; + + return range; +} + +CFRange CFCalendarGetRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) { + if (_CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard)) { + return __CFCalendarGetRangeOfUnit2(calendar, smallerUnit, biggerUnit, at); + } else { + return __CFCalendarGetRangeOfUnit1(calendar, smallerUnit, biggerUnit, at); + } +} + +CFIndex CFCalendarGetOrdinalityOfUnit(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) { + CFIndex result = kCFNotFound; + if (!__validUnits(smallerUnit, biggerUnit)) return result; + CF_OBJC_FUNCDISPATCH3(CFCalendarGetTypeID(), CFIndex, calendar, "_ordinalityOfUnit:inUnit:forAT:", smallerUnit, biggerUnit, at); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + if (!calendar->_cal) __CFCalendarSetupCal(calendar); + if (calendar->_cal) { + UErrorCode status = U_ZERO_ERROR; + ucal_clear(calendar->_cal); + if (kCFCalendarUnitWeek == smallerUnit && kCFCalendarUnitYear == biggerUnit) { + UDate udate = floor((at + kCFAbsoluteTimeIntervalSince1970) * 1000.0); + ucal_setMillis(calendar->_cal, udate, &status); + int32_t val = ucal_get(calendar->_cal, UCAL_WEEK_OF_YEAR, &status); + return val; + } else if (kCFCalendarUnitWeek == smallerUnit && kCFCalendarUnitMonth == biggerUnit) { + UDate udate = floor((at + kCFAbsoluteTimeIntervalSince1970) * 1000.0); + ucal_setMillis(calendar->_cal, udate, &status); + int32_t val = ucal_get(calendar->_cal, UCAL_WEEK_OF_MONTH, &status); + return val; + } + UCalendarDateFields smallField = __CFCalendarGetICUFieldCode(smallerUnit); + // Set calendar to first instant of big unit + __CFCalendarSetToFirstInstant(calendar, biggerUnit, at); + UDate curr = ucal_getMillis(calendar->_cal, &status); + UDate goal = floor((at + kCFAbsoluteTimeIntervalSince1970) * 1000.0); + result = 1; + const int multiple_table[] = {0, 0, 16, 19, 24, 26, 24, 28, 14, 14, 14}; + int multiple = (1 << multiple_table[flsl(smallerUnit) - 1]); + Boolean divide = false, alwaysDivide = false; + while (curr < goal) { + ucal_add(calendar->_cal, smallField, multiple, &status); + UDate newcurr = ucal_getMillis(calendar->_cal, &status); + if (curr < newcurr && newcurr <= goal) { + result += multiple; + curr = newcurr; + } else { + // Either newcurr is going backwards, or not making + // progress, or has overshot the goal; reset date + // and try smaller multiples. + ucal_setMillis(calendar->_cal, curr, &status); + divide = true; + // once we start overshooting the goal, the add at + // smaller multiples will succeed at most once for + // each multiple, so we reduce it every time through + // the loop. + if (goal < newcurr) alwaysDivide = true; + } + if (divide) { + multiple = multiple / 2; + if (0 == multiple) break; + divide = alwaysDivide; + } + } + } + return result; +} + +Boolean _CFCalendarComposeAbsoluteTimeV(CFCalendarRef calendar, /* out */ CFAbsoluteTime *atp, const char *componentDesc, int *vector, int count) { + if (!calendar->_cal) __CFCalendarSetupCal(calendar); + if (calendar->_cal) { + UErrorCode status = U_ZERO_ERROR; + ucal_clear(calendar->_cal); + ucal_set(calendar->_cal, UCAL_YEAR, 1); + ucal_set(calendar->_cal, UCAL_MONTH, 0); + ucal_set(calendar->_cal, UCAL_DAY_OF_MONTH, 1); + ucal_set(calendar->_cal, UCAL_HOUR_OF_DAY, 0); + ucal_set(calendar->_cal, UCAL_MINUTE, 0); + ucal_set(calendar->_cal, UCAL_SECOND, 0); + const char *desc = componentDesc; + Boolean doWOY = false; + char ch = *desc; + while (ch) { + UCalendarDateFields field = __CFCalendarGetICUFieldCodeFromChar(ch); + if (UCAL_WEEK_OF_YEAR == field) { + doWOY = true; + } + desc++; + ch = *desc; + } + desc = componentDesc; + ch = *desc; + while (ch) { + UCalendarDateFields field = __CFCalendarGetICUFieldCodeFromChar(ch); + int value = *vector; + if (UCAL_YEAR == field && doWOY) field = UCAL_YEAR_WOY; + if (UCAL_MONTH == field) value--; + ucal_set(calendar->_cal, field, value); + vector++; + desc++; + ch = *desc; + } + UDate udate = ucal_getMillis(calendar->_cal, &status); + CFAbsoluteTime at = (udate / 1000.0) - kCFAbsoluteTimeIntervalSince1970; + if (atp) *atp = at; + return U_SUCCESS(status) ? true : false; + } + return false; +} + +Boolean _CFCalendarDecomposeAbsoluteTimeV(CFCalendarRef calendar, CFAbsoluteTime at, const char *componentDesc, int **vector, int count) { + if (!calendar->_cal) __CFCalendarSetupCal(calendar); + if (calendar->_cal) { + UErrorCode status = U_ZERO_ERROR; + ucal_clear(calendar->_cal); + UDate udate = floor((at + kCFAbsoluteTimeIntervalSince1970) * 1000.0); + ucal_setMillis(calendar->_cal, udate, &status); + char ch = *componentDesc; + while (ch) { + UCalendarDateFields field = __CFCalendarGetICUFieldCodeFromChar(ch); + int value = ucal_get(calendar->_cal, field, &status); + if (UCAL_MONTH == field) value++; + *(*vector) = value; + vector++; + componentDesc++; + ch = *componentDesc; + } + return U_SUCCESS(status) ? true : false; + } + return false; +} + +Boolean _CFCalendarAddComponentsV(CFCalendarRef calendar, /* inout */ CFAbsoluteTime *atp, CFOptionFlags options, const char *componentDesc, int *vector, int count) { + if (!calendar->_cal) __CFCalendarSetupCal(calendar); + if (calendar->_cal) { + UErrorCode status = U_ZERO_ERROR; + ucal_clear(calendar->_cal); + UDate udate = floor((*atp + kCFAbsoluteTimeIntervalSince1970) * 1000.0); + ucal_setMillis(calendar->_cal, udate, &status); + char ch = *componentDesc; + while (ch) { + UCalendarDateFields field = __CFCalendarGetICUFieldCodeFromChar(ch); + int amount = *vector; + if (options & kCFCalendarComponentsWrap) { + ucal_roll(calendar->_cal, field, amount, &status); + } else { + ucal_add(calendar->_cal, field, amount, &status); + } + vector++; + componentDesc++; + ch = *componentDesc; + } + udate = ucal_getMillis(calendar->_cal, &status); + *atp = (udate / 1000.0) - kCFAbsoluteTimeIntervalSince1970; + return U_SUCCESS(status) ? true : false; + } + return false; +} + +Boolean _CFCalendarGetComponentDifferenceV(CFCalendarRef calendar, CFAbsoluteTime startingAT, CFAbsoluteTime resultAT, CFOptionFlags options, const char *componentDesc, int **vector, int count) { + if (!calendar->_cal) __CFCalendarSetupCal(calendar); + if (calendar->_cal) { + UErrorCode status = U_ZERO_ERROR; + ucal_clear(calendar->_cal); + UDate curr = floor((startingAT + kCFAbsoluteTimeIntervalSince1970) * 1000.0); + UDate goal = floor((resultAT + kCFAbsoluteTimeIntervalSince1970) * 1000.0); + ucal_setMillis(calendar->_cal, curr, &status); + int direction = (startingAT <= resultAT) ? 1 : -1; + char ch = *componentDesc; + while (ch) { + UCalendarDateFields field = __CFCalendarGetICUFieldCodeFromChar(ch); + const int multiple_table[] = {0, 0, 16, 19, 24, 26, 24, 28, 14, 14, 14}; + int multiple = direction * (1 << multiple_table[flsl(__CFCalendarGetCalendarUnitFromChar(ch)) - 1]); + Boolean divide = false, alwaysDivide = false; + int result = 0; + while ((direction > 0 && curr < goal) || (direction < 0 && goal < curr)) { + ucal_add(calendar->_cal, field, multiple, &status); + UDate newcurr = ucal_getMillis(calendar->_cal, &status); + if ((direction > 0 && curr < newcurr && newcurr <= goal) || (direction < 0 && newcurr < curr && goal <= newcurr)) { + result += multiple; + curr = newcurr; + } else { + // Either newcurr is going backwards, or not making + // progress, or has overshot the goal; reset date + // and try smaller multiples. + ucal_setMillis(calendar->_cal, curr, &status); + divide = true; + // once we start overshooting the goal, the add at + // smaller multiples will succeed at most once for + // each multiple, so we reduce it every time through + // the loop. + if ((direction > 0 && goal < newcurr) || (direction < 0 && newcurr < goal)) alwaysDivide = true; + } + if (divide) { + multiple = multiple / 2; + if (0 == multiple) break; + divide = alwaysDivide; + } + } + *(*vector) = result; + vector++; + componentDesc++; + ch = *componentDesc; + } + return U_SUCCESS(status) ? true : false; + } + return false; +} + +Boolean CFCalendarComposeAbsoluteTime(CFCalendarRef calendar, /* out */ CFAbsoluteTime *atp, const char *componentDesc, ...) { + va_list args; + va_start(args, componentDesc); + CF_OBJC_FUNCDISPATCH3(CFCalendarGetTypeID(), Boolean, calendar, "_composeAbsoluteTime:::", atp, componentDesc, args); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + int idx, cnt = strlen((char *)componentDesc); + STACK_BUFFER_DECL(int, vector, cnt); + for (idx = 0; idx < cnt; idx++) { + int arg = va_arg(args, int); + vector[idx] = arg; + } + va_end(args); + return _CFCalendarComposeAbsoluteTimeV(calendar, atp, componentDesc, vector, cnt); +} + +Boolean CFCalendarDecomposeAbsoluteTime(CFCalendarRef calendar, CFAbsoluteTime at, const char *componentDesc, ...) { + va_list args; + va_start(args, componentDesc); + CF_OBJC_FUNCDISPATCH3(CFCalendarGetTypeID(), Boolean, calendar, "_decomposeAbsoluteTime:::", at, componentDesc, args); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + int idx, cnt = strlen((char *)componentDesc); + STACK_BUFFER_DECL(int *, vector, cnt); + for (idx = 0; idx < cnt; idx++) { + int *arg = va_arg(args, int *); + vector[idx] = arg; + } + va_end(args); + return _CFCalendarDecomposeAbsoluteTimeV(calendar, at, componentDesc, vector, cnt); +} + +Boolean CFCalendarAddComponents(CFCalendarRef calendar, /* inout */ CFAbsoluteTime *atp, CFOptionFlags options, const char *componentDesc, ...) { + va_list args; + va_start(args, componentDesc); + CF_OBJC_FUNCDISPATCH4(CFCalendarGetTypeID(), Boolean, calendar, "_addComponents::::", atp, options, componentDesc, args); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + int idx, cnt = strlen((char *)componentDesc); + STACK_BUFFER_DECL(int, vector, cnt); + for (idx = 0; idx < cnt; idx++) { + int arg = va_arg(args, int); + vector[idx] = arg; + } + va_end(args); + return _CFCalendarAddComponentsV(calendar, atp, options, componentDesc, vector, cnt); +} + +Boolean CFCalendarGetComponentDifference(CFCalendarRef calendar, CFAbsoluteTime startingAT, CFAbsoluteTime resultAT, CFOptionFlags options, const char *componentDesc, ...) { + va_list args; + va_start(args, componentDesc); + CF_OBJC_FUNCDISPATCH5(CFCalendarGetTypeID(), Boolean, calendar, "_diffComponents:::::", startingAT, resultAT, options, componentDesc, args); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + int idx, cnt = strlen((char *)componentDesc); + STACK_BUFFER_DECL(int *, vector, cnt); + for (idx = 0; idx < cnt; idx++) { + int *arg = va_arg(args, int *); + vector[idx] = arg; + } + va_end(args); + Boolean ret = _CFCalendarGetComponentDifferenceV(calendar, startingAT, resultAT, options, componentDesc, vector, cnt); + return ret; +} + +Boolean CFCalendarGetTimeRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit, CFAbsoluteTime at, CFAbsoluteTime *startp, CFTimeInterval *tip) { + CF_OBJC_FUNCDISPATCH4(CFCalendarGetTypeID(), Boolean, calendar, "_rangeOfUnit:startTime:interval:forAT:", unit, startp, tip, at); + __CFGenericValidateType(calendar, CFCalendarGetTypeID()); + if (kCFCalendarUnitWeekdayOrdinal == unit) return false; + if (kCFCalendarUnitWeekday == unit) unit = kCFCalendarUnitDay; + if (!calendar->_cal) __CFCalendarSetupCal(calendar); + if (calendar->_cal) { + ucal_clear(calendar->_cal); + __CFCalendarSetToFirstInstant(calendar, unit, at); + UErrorCode status = U_ZERO_ERROR; + UDate start = ucal_getMillis(calendar->_cal, &status); + UCalendarDateFields field = __CFCalendarGetICUFieldCode(unit); + ucal_add(calendar->_cal, field, 1, &status); + UDate end = ucal_getMillis(calendar->_cal, &status); + if (end == start && kCFCalendarUnitEra == unit) { + // ICU refuses to do the addition, probably because we are + // at the limit of UCAL_ERA. Use alternate strategy. + CFIndex limit = ucal_getLimit(calendar->_cal, UCAL_YEAR, UCAL_MAXIMUM, &status); + if (100000 < limit) limit = 100000; + ucal_add(calendar->_cal, UCAL_YEAR, limit, &status); + end = ucal_getMillis(calendar->_cal, &status); + } + if (U_SUCCESS(status)) { + if (startp) *startp = (double)start / 1000.0 - kCFAbsoluteTimeIntervalSince1970; + if (tip) *tip = (double)(end - start) / 1000.0; + return true; + } + } + return false; +} + +#undef BUFFER_SIZE + diff --git a/CFCalendar.h b/CFCalendar.h new file mode 100644 index 0000000..b867306 --- /dev/null +++ b/CFCalendar.h @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFCalendar.h + Copyright (c) 2004-2007, Apple Inc. All rights reserved. +*/ + +#if !defined(__COREFOUNDATION_CFCALENDAR__) +#define __COREFOUNDATION_CFCALENDAR__ 1 + +#include +#include +#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; + +CF_EXPORT +CFCalendarRef CFCalendarCopyCurrent(void) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + +CF_EXPORT +CFCalendarRef CFCalendarCreateWithIdentifier(CFAllocatorRef allocator, CFStringRef identifier) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + // 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; + // Returns the calendar's identifier. + +CF_EXPORT +CFLocaleRef CFCalendarCopyLocale(CFCalendarRef calendar) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + +CF_EXPORT +void CFCalendarSetLocale(CFCalendarRef calendar, CFLocaleRef locale) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + +CF_EXPORT +CFTimeZoneRef CFCalendarCopyTimeZone(CFCalendarRef calendar) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + +CF_EXPORT +void CFCalendarSetTimeZone(CFCalendarRef calendar, CFTimeZoneRef tz) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + +CF_EXPORT +CFIndex CFCalendarGetFirstWeekday(CFCalendarRef calendar) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + +CF_EXPORT +void CFCalendarSetFirstWeekday(CFCalendarRef calendar, CFIndex wkdy) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + +CF_EXPORT +CFIndex CFCalendarGetMinimumDaysInFirstWeek(CFCalendarRef calendar) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + +CF_EXPORT +void CFCalendarSetMinimumDaysInFirstWeek(CFCalendarRef calendar, CFIndex mwd) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + + +enum { + kCFCalendarUnitEra = (1 << 1), + kCFCalendarUnitYear = (1 << 2), + kCFCalendarUnitMonth = (1 << 3), + kCFCalendarUnitDay = (1 << 4), + kCFCalendarUnitHour = (1 << 5), + kCFCalendarUnitMinute = (1 << 6), + kCFCalendarUnitSecond = (1 << 7), + kCFCalendarUnitWeek = (1 << 8), + kCFCalendarUnitWeekday = (1 << 9), + kCFCalendarUnitWeekdayOrdinal = (1 << 10) +}; +typedef CFOptionFlags CFCalendarUnit; + +CF_EXPORT +CFRange CFCalendarGetMinimumRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + +CF_EXPORT +CFRange CFCalendarGetMaximumRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + +CF_EXPORT +CFRange CFCalendarGetRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + +CF_EXPORT +CFIndex CFCalendarGetOrdinalityOfUnit(CFCalendarRef calendar, CFCalendarUnit smallerUnit, CFCalendarUnit biggerUnit, CFAbsoluteTime at) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + +CF_EXPORT +Boolean CFCalendarGetTimeRangeOfUnit(CFCalendarRef calendar, CFCalendarUnit unit, CFAbsoluteTime at, CFAbsoluteTime *startp, CFTimeInterval *tip) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; + +CF_EXPORT +Boolean CFCalendarComposeAbsoluteTime(CFCalendarRef calendar, /* out */ CFAbsoluteTime *at, const char *componentDesc, ...) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + +CF_EXPORT +Boolean CFCalendarDecomposeAbsoluteTime(CFCalendarRef calendar, CFAbsoluteTime at, const char *componentDesc, ...) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + + +enum { + kCFCalendarComponentsWrap = (1 << 0) // option for adding +}; + +CF_EXPORT +Boolean CFCalendarAddComponents(CFCalendarRef calendar, /* inout */ CFAbsoluteTime *at, CFOptionFlags options, const char *componentDesc, ...) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + +CF_EXPORT +Boolean CFCalendarGetComponentDifference(CFCalendarRef calendar, CFAbsoluteTime startingAT, CFAbsoluteTime resultAT, CFOptionFlags options, const char *componentDesc, ...) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + + +CF_EXTERN_C_END + +#endif + +#endif /* ! __COREFOUNDATION_CFCALENDAR__ */ + diff --git a/String.subproj/CFCharacterSet.c b/CFCharacterSet.c similarity index 81% rename from String.subproj/CFCharacterSet.c rename to CFCharacterSet.c index 1cbe9d3..49c0c65 100644 --- a/String.subproj/CFCharacterSet.c +++ b/CFCharacterSet.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -36,9 +36,6 @@ #include #include -#if !defined(__MACOS8__) -#define __MACOS8__ 0 -#endif #define BITSPERBYTE 8 /* (CHAR_BIT * sizeof(unsigned char)) */ #define LOG_BPB 3 @@ -57,7 +54,7 @@ /* The last builtin set ID number */ -#define __kCFLastBuiltinSetID kCFCharacterSetSymbol +#define __kCFLastBuiltinSetID kCFCharacterSetNewline /* How many elements in the "singles" array before we use binary search. */ @@ -132,20 +129,20 @@ enum { /* Inline accessor macros for _base._info */ -CF_INLINE Boolean __CFCSetIsMutable(CFCharacterSetRef cset) {return (cset->_base._info & __kCFCharSetIsMutableMask) == __kCFCharSetIsMutable;} -CF_INLINE Boolean __CFCSetIsBuiltin(CFCharacterSetRef cset) {return (cset->_base._info & __kCFCharSetClassTypeMask) == __kCFCharSetClassBuiltin;} -CF_INLINE Boolean __CFCSetIsRange(CFCharacterSetRef cset) {return (cset->_base._info & __kCFCharSetClassTypeMask) == __kCFCharSetClassRange;} -CF_INLINE Boolean __CFCSetIsString(CFCharacterSetRef cset) {return (cset->_base._info & __kCFCharSetClassTypeMask) == __kCFCharSetClassString;} -CF_INLINE Boolean __CFCSetIsBitmap(CFCharacterSetRef cset) {return (cset->_base._info & __kCFCharSetClassTypeMask) == __kCFCharSetClassBitmap;} -CF_INLINE Boolean __CFCSetIsCompactBitmap(CFCharacterSetRef cset) {return (cset->_base._info & __kCFCharSetClassTypeMask) == __kCFCharSetClassCompactBitmap;} -CF_INLINE Boolean __CFCSetIsInverted(CFCharacterSetRef cset) {return (cset->_base._info & __kCFCharSetIsInvertedMask) == __kCFCharSetIsInverted;} -CF_INLINE Boolean __CFCSetHasHashValue(CFCharacterSetRef cset) {return (cset->_base._info & __kCFCharSetHasHashValueMask) == __kCFCharSetHasHashValue;} -CF_INLINE UInt32 __CFCSetClassType(CFCharacterSetRef cset) {return (cset->_base._info & __kCFCharSetClassTypeMask);} - -CF_INLINE void __CFCSetPutIsMutable(CFMutableCharacterSetRef cset, Boolean isMutable) {(isMutable ? (cset->_base._info |= __kCFCharSetIsMutable) : (cset->_base._info &= ~ __kCFCharSetIsMutable));} -CF_INLINE void __CFCSetPutIsInverted(CFMutableCharacterSetRef cset, Boolean isInverted) {(isInverted ? (cset->_base._info |= __kCFCharSetIsInverted) : (cset->_base._info &= ~__kCFCharSetIsInverted));} -CF_INLINE void __CFCSetPutHasHashValue(CFMutableCharacterSetRef cset, Boolean hasHash) {(hasHash ? (cset->_base._info |= __kCFCharSetHasHashValue) : (cset->_base._info &= ~__kCFCharSetHasHashValue));} -CF_INLINE void __CFCSetPutClassType(CFMutableCharacterSetRef cset, UInt32 classType) {cset->_base._info &= ~__kCFCharSetClassTypeMask; cset->_base._info |= classType;} +CF_INLINE Boolean __CFCSetIsMutable(CFCharacterSetRef cset) {return (cset->_base._cfinfo[CF_INFO_BITS] & __kCFCharSetIsMutableMask) == __kCFCharSetIsMutable;} +CF_INLINE Boolean __CFCSetIsBuiltin(CFCharacterSetRef cset) {return (cset->_base._cfinfo[CF_INFO_BITS] & __kCFCharSetClassTypeMask) == __kCFCharSetClassBuiltin;} +CF_INLINE Boolean __CFCSetIsRange(CFCharacterSetRef cset) {return (cset->_base._cfinfo[CF_INFO_BITS] & __kCFCharSetClassTypeMask) == __kCFCharSetClassRange;} +CF_INLINE Boolean __CFCSetIsString(CFCharacterSetRef cset) {return (cset->_base._cfinfo[CF_INFO_BITS] & __kCFCharSetClassTypeMask) == __kCFCharSetClassString;} +CF_INLINE Boolean __CFCSetIsBitmap(CFCharacterSetRef cset) {return (cset->_base._cfinfo[CF_INFO_BITS] & __kCFCharSetClassTypeMask) == __kCFCharSetClassBitmap;} +CF_INLINE Boolean __CFCSetIsCompactBitmap(CFCharacterSetRef cset) {return (cset->_base._cfinfo[CF_INFO_BITS] & __kCFCharSetClassTypeMask) == __kCFCharSetClassCompactBitmap;} +CF_INLINE Boolean __CFCSetIsInverted(CFCharacterSetRef cset) {return (cset->_base._cfinfo[CF_INFO_BITS] & __kCFCharSetIsInvertedMask) == __kCFCharSetIsInverted;} +CF_INLINE Boolean __CFCSetHasHashValue(CFCharacterSetRef cset) {return (cset->_base._cfinfo[CF_INFO_BITS] & __kCFCharSetHasHashValueMask) == __kCFCharSetHasHashValue;} +CF_INLINE UInt32 __CFCSetClassType(CFCharacterSetRef cset) {return (cset->_base._cfinfo[CF_INFO_BITS] & __kCFCharSetClassTypeMask);} + +CF_INLINE void __CFCSetPutIsMutable(CFMutableCharacterSetRef cset, Boolean isMutable) {(isMutable ? (cset->_base._cfinfo[CF_INFO_BITS] |= __kCFCharSetIsMutable) : (cset->_base._cfinfo[CF_INFO_BITS] &= ~ __kCFCharSetIsMutable));} +CF_INLINE void __CFCSetPutIsInverted(CFMutableCharacterSetRef cset, Boolean isInverted) {(isInverted ? (cset->_base._cfinfo[CF_INFO_BITS] |= __kCFCharSetIsInverted) : (cset->_base._cfinfo[CF_INFO_BITS] &= ~__kCFCharSetIsInverted));} +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;} /* Inline contents accessor macros @@ -234,10 +231,10 @@ static Boolean __CFCSetIsBitmapEqualToRange(const UInt32 *bits, UniChar firstCha UInt32 lastCharMask; length = firstCharIndex % sizeof(UInt32); - firstCharMask = (((((UInt32)0xFF) << (firstChar & (BITSPERBYTE - 1))) & 0xFF) << (((sizeof(UInt32) - 1) - length) * BITSPERBYTE)) | (0xFFFFFFFF >> ((length + 1) * BITSPERBYTE)); + firstCharMask = (((((UInt32)0xFF) << (firstChar & (BITSPERBYTE - 1))) & 0xFF) << (((sizeof(UInt32) - 1) - length) * BITSPERBYTE)) | (((UInt32)0xFFFFFFFF) >> ((length + 1) * BITSPERBYTE)); length = lastCharIndex % sizeof(UInt32); - lastCharMask = ((((UInt32)0xFF) >> ((BITSPERBYTE - 1) - (lastChar & (BITSPERBYTE - 1)))) << (((sizeof(UInt32) - 1) - length) * BITSPERBYTE)) | (0xFFFFFFFF << ((sizeof(UInt32) - length) * BITSPERBYTE)); + lastCharMask = ((((UInt32)0xFF) >> ((BITSPERBYTE - 1) - (lastChar & (BITSPERBYTE - 1)))) << (((sizeof(UInt32) - 1) - length) * BITSPERBYTE)) | (((UInt32)0xFFFFFFFF) << ((sizeof(UInt32) - length) * BITSPERBYTE)); firstCharIndex = firstChar >> LOG_BPLW; lastCharIndex = lastChar >> LOG_BPLW; @@ -256,21 +253,21 @@ static Boolean __CFCSetIsBitmapEqualToRange(const UInt32 *bits, UniChar firstCha } length = firstCharIndex; - value = (isInverted ? 0xFFFFFFFF : 0); + value = (isInverted ? ((UInt32)0xFFFFFFFF) : 0); while (length--) { if (*(bits++) != value) return FALSE; } ++bits; // Skip firstCharIndex length = (lastCharIndex - (firstCharIndex + 1)); - value = (isInverted ? 0 : 0xFFFFFFFF); + value = (isInverted ? 0 : ((UInt32)0xFFFFFFFF)); while (length-- > 0) { if (*(bits++) != value) return FALSE; } if (firstCharIndex != lastCharIndex) ++bits; length = (0xFFFF >> LOG_BPLW) - lastCharIndex; - value = (isInverted ? 0xFFFFFFFF : 0); + value = (isInverted ? ((UInt32)0xFFFFFFFF) : 0); while (length--) { if (*(bits++) != value) return FALSE; } @@ -293,7 +290,7 @@ CF_INLINE Boolean __CFCSetIsBitmapSupersetOfBitmap(const UInt32 *bits1, const UI CF_INLINE Boolean __CFCSetHasNonBMPPlane(CFCharacterSetRef cset) { return ((cset)->_annex && (cset)->_annex->_validEntriesBitmap ? true : false); } CF_INLINE Boolean __CFCSetAnnexIsInverted (CFCharacterSetRef cset) { return ((cset)->_annex && (cset)->_annex->_isAnnexInverted ? true : false); } -CF_INLINE UInt32 __CFCSetAnnexValidEntriesBitmap(CFCharacterSetRef cset) { return ((cset)->_annex && (cset)->_annex->_validEntriesBitmap ? (cset)->_annex->_validEntriesBitmap : 0); } +CF_INLINE UInt32 __CFCSetAnnexValidEntriesBitmap(CFCharacterSetRef cset) { return ((cset)->_annex ? (cset)->_annex->_validEntriesBitmap : 0); } CF_INLINE Boolean __CFCSetIsEmpty(CFCharacterSetRef cset) { if (__CFCSetHasNonBMPPlane(cset) || __CFCSetAnnexIsInverted(cset)) return false; @@ -366,28 +363,33 @@ CF_INLINE void __CFCSetBitmapRemoveCharactersInRange(uint8_t *bitmap, UniChar fi #define __CFCSetAnnexBitmapClearPlane(bitmap,plane) ((bitmap) &= (~(1 << (plane)))) #define __CFCSetAnnexBitmapGetPlane(bitmap,plane) ((bitmap) & (1 << (plane))) -CF_INLINE void __CFCSetAnnexSetIsInverted(CFCharacterSetRef cset, Boolean flag) { - if (cset->_annex) ((CFMutableCharacterSetRef)cset)->_annex->_isAnnexInverted = flag; -} - CF_INLINE void __CFCSetAllocateAnnexForPlane(CFCharacterSetRef cset, int plane) { if (cset->_annex == NULL) { ((CFMutableCharacterSetRef)cset)->_annex = (CFCharSetAnnexStruct *)CFAllocatorAllocate(CFGetAllocator(cset), sizeof(CFCharSetAnnexStruct), 0); cset->_annex->_numOfAllocEntries = plane; cset->_annex->_isAnnexInverted = false; cset->_annex->_validEntriesBitmap = 0; - cset->_annex->_nonBMPPlanes = (CFCharacterSetRef*)CFAllocatorAllocate(CFGetAllocator(cset), sizeof(CFCharacterSetRef) * plane, 0); + cset->_annex->_nonBMPPlanes = ((plane > 0) ? (CFCharacterSetRef*)CFAllocatorAllocate(CFGetAllocator(cset), sizeof(CFCharacterSetRef) * plane, 0) : NULL); } else if (cset->_annex->_numOfAllocEntries < plane) { cset->_annex->_numOfAllocEntries = plane; - cset->_annex->_nonBMPPlanes = (CFCharacterSetRef*)CFAllocatorReallocate(CFGetAllocator(cset), (void *)cset->_annex->_nonBMPPlanes, sizeof(CFCharacterSetRef) * plane, 0); + if (NULL == cset->_annex->_nonBMPPlanes) { + cset->_annex->_nonBMPPlanes = (CFCharacterSetRef*)CFAllocatorAllocate(CFGetAllocator(cset), sizeof(CFCharacterSetRef) * plane, 0); + } else { + cset->_annex->_nonBMPPlanes = (CFCharacterSetRef*)CFAllocatorReallocate(CFGetAllocator(cset), (void *)cset->_annex->_nonBMPPlanes, sizeof(CFCharacterSetRef) * plane, 0); + } } } +CF_INLINE void __CFCSetAnnexSetIsInverted(CFCharacterSetRef cset, Boolean flag) { + if (flag) __CFCSetAllocateAnnexForPlane(cset, 0); + if (cset->_annex) ((CFMutableCharacterSetRef)cset)->_annex->_isAnnexInverted = flag; +} + CF_INLINE void __CFCSetPutCharacterSetToAnnexPlane(CFCharacterSetRef cset, CFCharacterSetRef annexCSet, int plane) { __CFCSetAllocateAnnexForPlane(cset, plane); if (__CFCSetAnnexBitmapGetPlane(cset->_annex->_validEntriesBitmap, plane)) CFRelease(cset->_annex->_nonBMPPlanes[plane - 1]); if (annexCSet) { - cset->_annex->_nonBMPPlanes[plane - 1] = CFRetain(annexCSet); + cset->_annex->_nonBMPPlanes[plane - 1] = (CFCharacterSetRef)CFRetain(annexCSet); __CFCSetAnnexBitmapSetPlane(cset->_annex->_validEntriesBitmap, plane); } else { __CFCSetAnnexBitmapClearPlane(cset->_annex->_validEntriesBitmap, plane); @@ -498,8 +500,8 @@ static void __CFCheckForExpandedSet(CFCharacterSetRef cset) { if (0 > __CFNumberOfPlanesForLogging) { const char *envVar = getenv("CFCharacterSetCheckForExpandedSet"); - long value = (envVar ? strtol(envVar, NULL, 0) : 0); - __CFNumberOfPlanesForLogging = (((value > 0) && (value <= 16)) ? value : 0); + long value = (envVar ? strtol_l(envVar, NULL, 0, NULL) : 0); + __CFNumberOfPlanesForLogging = (int8_t)(((value > 0) && (value <= 16)) ? value : 0); } if (__CFNumberOfPlanesForLogging) { @@ -509,7 +511,7 @@ static void __CFCheckForExpandedSet(CFCharacterSetRef cset) { while (entries) { if ((entries & 1) && (++count >= __CFNumberOfPlanesForLogging)) { if (!warnedOnce) { - CFLog(0, CFSTR("An expanded CFMutableCharacter has been detected. Recommend to compact with CFCharacterSetCreateCopy")); + CFLog(kCFLogLevelWarning, CFSTR("An expanded CFMutableCharacter has been detected. Recommend to compact with CFCharacterSetCreateCopy")); warnedOnce = true; } break; @@ -535,7 +537,7 @@ static void __CFCSetGetBitmap(CFCharacterSetRef cset, uint8_t *bits) { if (!__CFCSetIsEmpty(cset)) { switch (__CFCSetClassType(cset)) { case __kCFCharSetClassBuiltin: { - UInt8 result = CFUniCharGetBitmapForPlane(__CFCSetBuiltinType(cset), 0, bits, isInverted); + UInt8 result = CFUniCharGetBitmapForPlane(__CFCSetBuiltinType(cset), 0, bits, (isInverted != 0)); if (result == kCFUniCharBitmapEmpty && isInverted) { length = __kCFBitmapSize; bitmap = bits; @@ -554,9 +556,9 @@ static void __CFCSetGetBitmap(CFCharacterSetRef cset, uint8_t *bits) { length = __CFCSetRangeLength(cset); if (theChar + length >= NUMCHARACTERS) length = NUMCHARACTERS - theChar; if (isInverted) { - __CFCSetBitmapRemoveCharactersInRange(bits, theChar, (theChar + length) - 1); + __CFCSetBitmapRemoveCharactersInRange(bits, theChar, (UniChar)(theChar + length) - 1); } else { - __CFCSetBitmapAddCharactersInRange(bits, theChar, (theChar + length) - 1); + __CFCSetBitmapAddCharactersInRange(bits, theChar, (UniChar)(theChar + length) - 1); } } } @@ -595,52 +597,33 @@ static Boolean __CFCSetIsEqualAnnex(CFCharacterSetRef cf1, CFCharacterSetRef cf2 } } else { uint8_t bitsBuf[__kCFBitmapSize]; -#if __MACOS8__ - uint8_t *bitsBuf2 = NULL; -#else __MACOS8__ uint8_t bitsBuf2[__kCFBitmapSize]; -#endif __MACOS8__ for (idx = 1;idx <= MAX_ANNEX_PLANE;idx++) { subSet1 = __CFCSetGetAnnexPlaneCharacterSetNoAlloc(cf1, idx); subSet2 = __CFCSetGetAnnexPlaneCharacterSetNoAlloc(cf2, idx); if (subSet1 == NULL && subSet2 == NULL) { -#if __MACOS8__ - if (bitsBuf2) CFAllocatorDeallocate(NULL, bitsBuf2); -#endif __MACOS8__ return false; } else if (subSet1 == NULL) { if (__CFCSetIsBitmap(subSet2)) { if (!__CFCSetIsEqualBitmap((const UInt32 *)__CFCSetBitmapBits(subSet2), (const UInt32 *)-1)) { -#if __MACOS8__ - if (bitsBuf2) CFAllocatorDeallocate(NULL, bitsBuf2); -#endif __MACOS8__ return false; } } else { __CFCSetGetBitmap(subSet2, bitsBuf); if (!__CFCSetIsEqualBitmap((const UInt32 *)bitsBuf, (const UInt32 *)-1)) { -#if __MACOS8__ - if (bitsBuf2) CFAllocatorDeallocate(NULL, bitsBuf2); -#endif __MACOS8__ return false; } } } else if (subSet2 == NULL) { if (__CFCSetIsBitmap(subSet1)) { if (!__CFCSetIsEqualBitmap((const UInt32 *)__CFCSetBitmapBits(subSet1), (const UInt32 *)-1)) { -#if __MACOS8__ - if (bitsBuf2) CFAllocatorDeallocate(NULL, bitsBuf2); -#endif __MACOS8__ return false; } } else { __CFCSetGetBitmap(subSet1, bitsBuf); if (!__CFCSetIsEqualBitmap((const UInt32 *)bitsBuf, (const UInt32 *)-1)) { -#if __MACOS8__ - if (bitsBuf2) CFAllocatorDeallocate(NULL, bitsBuf2); -#endif __MACOS8__ return false; } } @@ -650,21 +633,12 @@ static Boolean __CFCSetIsEqualAnnex(CFCharacterSetRef cf1, CFCharacterSetRef cf2 if (isBitmap1 && isBitmap2) { if (!__CFCSetIsEqualBitmapInverted((const UInt32 *)__CFCSetBitmapBits(subSet1), (const UInt32 *)__CFCSetBitmapBits(subSet2))) { -#if __MACOS8__ - if (bitsBuf2) CFAllocatorDeallocate(NULL, bitsBuf2); -#endif __MACOS8__ return false; } } else if (!isBitmap1 && !isBitmap2) { __CFCSetGetBitmap(subSet1, bitsBuf); -#if __MACOS8__ - if (bitsBuf2 == NULL) bitsBuf2 = (UInt32 *)CFAllocatorAllocate(NULL, __kCFBitmapSize, 0); -#endif __MACOS8__ __CFCSetGetBitmap(subSet2, bitsBuf2); if (!__CFCSetIsEqualBitmapInverted((const UInt32 *)bitsBuf, (const UInt32 *)bitsBuf2)) { -#if __MACOS8__ - CFAllocatorDeallocate(NULL, bitsBuf2); -#endif __MACOS8__ return false; } } else { @@ -675,9 +649,6 @@ static Boolean __CFCSetIsEqualAnnex(CFCharacterSetRef cf1, CFCharacterSetRef cf2 } __CFCSetGetBitmap(subSet2, bitsBuf); if (!__CFCSetIsEqualBitmapInverted((const UInt32 *)__CFCSetBitmapBits(subSet1), (const UInt32 *)bitsBuf)) { -#if __MACOS8__ - if (bitsBuf2) CFAllocatorDeallocate(NULL, bitsBuf2); -#endif __MACOS8__ return false; } } @@ -705,7 +676,7 @@ static uint8_t *__CFCreateCompactBitmap(CFAllocatorRef allocator, const uint8_t src += __kCFCompactBitmapPageSize; } - dst = (uint8_t *)CFAllocatorAllocate(allocator, __kCFCompactBitmapNumPages + (__kCFCompactBitmapPageSize * numPages), AUTO_MEMORY_UNSCANNED); + dst = (uint8_t *)CFAllocatorAllocate(allocator, __kCFCompactBitmapNumPages + (__kCFCompactBitmapPageSize * numPages), 0); if (numPages > 0) { uint8_t *dstBody = dst + __kCFCompactBitmapNumPages; @@ -799,7 +770,7 @@ static void __CFCSetRemoveNonBMPPlanesInRange(CFMutableCharacterSetRef cset, CFR static void __CFCSetMakeBitmap(CFMutableCharacterSetRef cset) { if (!__CFCSetIsBitmap(cset) || !__CFCSetBitmapBits(cset)) { CFAllocatorRef allocator = CFGetAllocator(cset); - uint8_t *bitmap = CFAllocatorAllocate(allocator, __kCFBitmapSize, AUTO_MEMORY_UNSCANNED); + uint8_t *bitmap = (uint8_t *)CFAllocatorAllocate(allocator, __kCFBitmapSize, 0); __CFCSetGetBitmap(cset, bitmap); if (__CFCSetIsBuiltin(cset)) { @@ -814,7 +785,7 @@ static void __CFCSetMakeBitmap(CFMutableCharacterSetRef cset) { __CFCSetAllocateAnnexForPlane(cset, numPlanes - 1); for (idx = 1;idx < numPlanes;idx++) { if (NULL == annexBitmap) { - annexBitmap = CFAllocatorAllocate(allocator, __kCFBitmapSize, AUTO_MEMORY_UNSCANNED); + annexBitmap = (uint8_t *)CFAllocatorAllocate(allocator, __kCFBitmapSize, 0); } result = CFUniCharGetBitmapForPlane(__CFCSetBuiltinType(cset), idx, annexBitmap, false); if (result == kCFUniCharBitmapEmpty) continue; @@ -856,7 +827,7 @@ CF_INLINE CFMutableCharacterSetRef __CFCSetGenericCreate(CFAllocatorRef allocato cset = (CFMutableCharacterSetRef)_CFRuntimeCreateInstance(allocator, CFCharacterSetGetTypeID(), size, NULL); if (NULL == cset) return NULL; - cset->_base._info |= flags; + cset->_base._cfinfo[CF_INFO_BITS] |= flags; cset->_hashValue = 0; cset->_annex = NULL; @@ -898,6 +869,7 @@ CONST_STRING_DECL(__kCFCSetNamePunctuation, "") CONST_STRING_DECL(__kCFCSetNameCapitalizedLetter, "") CONST_STRING_DECL(__kCFCSetNameSymbol, "") +CONST_STRING_DECL(__kCFCSetNameNewline, "") CONST_STRING_DECL(__kCFCSetNameStringTypeFormat, "_hashValue != ((CFCharacterSetRef)cf2)->_hashValue) return false; - if (__CFCSetIsEmpty(cf1) && __CFCSetIsEmpty(cf2) && !isInvertStateIdentical) return false; + if (__CFCSetHasHashValue((CFCharacterSetRef)cf1) && __CFCSetHasHashValue((CFCharacterSetRef)cf2) && ((CFCharacterSetRef)cf1)->_hashValue != ((CFCharacterSetRef)cf2)->_hashValue) return false; + if (__CFCSetIsEmpty((CFCharacterSetRef)cf1) && __CFCSetIsEmpty((CFCharacterSetRef)cf2) && !isInvertStateIdentical) return false; - if (__CFCSetClassType(cf1) == __CFCSetClassType(cf2)) { // Types are identical, we can do it fast - switch (__CFCSetClassType(cf1)) { + if (__CFCSetClassType((CFCharacterSetRef)cf1) == __CFCSetClassType((CFCharacterSetRef)cf2)) { // Types are identical, we can do it fast + switch (__CFCSetClassType((CFCharacterSetRef)cf1)) { case __kCFCharSetClassBuiltin: - return (__CFCSetBuiltinType(cf1) == __CFCSetBuiltinType(cf2) && isInvertStateIdentical ? true : false); + return (__CFCSetBuiltinType((CFCharacterSetRef)cf1) == __CFCSetBuiltinType((CFCharacterSetRef)cf2) && isInvertStateIdentical ? true : false); case __kCFCharSetClassRange: - return (__CFCSetRangeFirstChar(cf1) == __CFCSetRangeFirstChar(cf2) && __CFCSetRangeLength(cf1) && __CFCSetRangeLength(cf2) && isInvertStateIdentical ? true : false); + return (__CFCSetRangeFirstChar((CFCharacterSetRef)cf1) == __CFCSetRangeFirstChar((CFCharacterSetRef)cf2) && __CFCSetRangeLength((CFCharacterSetRef)cf1) && __CFCSetRangeLength((CFCharacterSetRef)cf2) && isInvertStateIdentical ? true : false); case __kCFCharSetClassString: - if (__CFCSetStringLength(cf1) == __CFCSetStringLength(cf2) && isInvertStateIdentical) { - const UniChar *buf1 = __CFCSetStringBuffer(cf1); - const UniChar *buf2 = __CFCSetStringBuffer(cf2); - CFIndex length = __CFCSetStringLength(cf1); + if (__CFCSetStringLength((CFCharacterSetRef)cf1) == __CFCSetStringLength((CFCharacterSetRef)cf2) && isInvertStateIdentical) { + const UniChar *buf1 = __CFCSetStringBuffer((CFCharacterSetRef)cf1); + const UniChar *buf2 = __CFCSetStringBuffer((CFCharacterSetRef)cf2); + CFIndex length = __CFCSetStringLength((CFCharacterSetRef)cf1); while (length--) if (*buf1++ != *buf2++) return false; } else { @@ -945,16 +917,16 @@ static Boolean __CFCharacterSetEqual(CFTypeRef cf1, CFTypeRef cf2) { break; case __kCFCharSetClassBitmap: - if (!__CFCSetIsEqualBitmap((const UInt32 *)__CFCSetBitmapBits(cf1), (const UInt32 *)__CFCSetBitmapBits(cf2))) return false; + if (!__CFCSetIsEqualBitmap((const UInt32 *)__CFCSetBitmapBits((CFCharacterSetRef)cf1), (const UInt32 *)__CFCSetBitmapBits((CFCharacterSetRef)cf2))) return false; break; } - return __CFCSetIsEqualAnnex(cf1, cf2); + return __CFCSetIsEqualAnnex((CFCharacterSetRef)cf1, (CFCharacterSetRef)cf2); } // Check for easy empty cases - if (__CFCSetIsEmpty(cf1) || __CFCSetIsEmpty(cf2)) { - CFCharacterSetRef emptySet = (__CFCSetIsEmpty(cf1) ? cf1 : cf2); - CFCharacterSetRef nonEmptySet = (emptySet == cf1 ? cf2 : cf1); + if (__CFCSetIsEmpty((CFCharacterSetRef)cf1) || __CFCSetIsEmpty((CFCharacterSetRef)cf2)) { + CFCharacterSetRef emptySet = (__CFCSetIsEmpty((CFCharacterSetRef)cf1) ? (CFCharacterSetRef)cf1 : (CFCharacterSetRef)cf2); + CFCharacterSetRef nonEmptySet = (emptySet == cf1 ? (CFCharacterSetRef)cf2 : (CFCharacterSetRef)cf1); if (__CFCSetIsBuiltin(nonEmptySet)) { return false; @@ -997,9 +969,9 @@ static Boolean __CFCharacterSetEqual(CFTypeRef cf1, CFTypeRef cf2) { } } - if (__CFCSetIsBuiltin(cf1) || __CFCSetIsBuiltin(cf2)) { - CFCharacterSetRef builtinSet = (__CFCSetIsBuiltin(cf1) ? cf1 : cf2); - CFCharacterSetRef nonBuiltinSet = (builtinSet == cf1 ? cf2 : cf1); + if (__CFCSetIsBuiltin((CFCharacterSetRef)cf1) || __CFCSetIsBuiltin((CFCharacterSetRef)cf2)) { + CFCharacterSetRef builtinSet = (__CFCSetIsBuiltin((CFCharacterSetRef)cf1) ? (CFCharacterSetRef)cf1 : (CFCharacterSetRef)cf2); + CFCharacterSetRef nonBuiltinSet = (builtinSet == cf1 ? (CFCharacterSetRef)cf2 : (CFCharacterSetRef)cf1); if (__CFCSetIsRange(nonBuiltinSet)) { @@ -1010,7 +982,7 @@ static Boolean __CFCharacterSetEqual(CFTypeRef cf1, CFTypeRef cf2) { uint8_t result; for (idx = 0;idx < MAX_ANNEX_PLANE;idx++) { - result = CFUniCharGetBitmapForPlane(__CFCSetBuiltinType(builtinSet), idx, bitsBuf, isInvertStateIdentical); + result = CFUniCharGetBitmapForPlane(__CFCSetBuiltinType(builtinSet), idx, bitsBuf, (isInvertStateIdentical != 0)); if (idx < firstPlane || idx > lastPlane) { if (result == kCFUniCharBitmapAll) { @@ -1044,27 +1016,17 @@ static Boolean __CFCharacterSetEqual(CFTypeRef cf1, CFTypeRef cf2) { } return true; } else { -#if __MACOS8__ - uint8_t *bitsBuf2 = NULL; -#else __MACOS8__ uint8_t bitsBuf2[__kCFBitmapSize]; -#endif __MACOS8__ uint8_t result; - result = CFUniCharGetBitmapForPlane(__CFCSetBuiltinType(builtinSet), 0, bitsBuf, __CFCSetIsInverted(builtinSet)); + result = CFUniCharGetBitmapForPlane(__CFCSetBuiltinType(builtinSet), 0, bitsBuf, (__CFCSetIsInverted(builtinSet) != 0)); if (result == kCFUniCharBitmapFilled) { if (__CFCSetIsBitmap(nonBuiltinSet)) { if (!__CFCSetIsEqualBitmap((const UInt32 *)bitsBuf, (const UInt32 *)__CFCSetBitmapBits(nonBuiltinSet))) return false; } else { -#if __MACOS8__ - bitsBuf2 = CFAllocatorAllocate(CFGetAllocator(nonBuiltinSet), __kCFBitmapSize, 0); -#endif __MACOS8__ __CFCSetGetBitmap(nonBuiltinSet, bitsBuf2); if (!__CFCSetIsEqualBitmap((const UInt32 *)bitsBuf, (const UInt32 *)bitsBuf2)) { -#if __MACOS8__ - CFAllocatorDeallocate(CFGetAllocator(nonBuiltinSet), bitsBuf2); -#endif __MACOS8__ return false; } } @@ -1085,66 +1047,42 @@ static Boolean __CFCharacterSetEqual(CFTypeRef cf1, CFTypeRef cf2) { if (result == kCFUniCharBitmapFilled) { if (NULL == subSet1) { -#if __MACOS8__ - if (bitsBuf2) CFAllocatorDeallocate(CFGetAllocator(nonBuiltinSet), bitsBuf2); -#endif __MACOS8__ return false; } else if (__CFCSetIsBitmap(subSet1)) { if (!__CFCSetIsEqualBitmap((const UInt32*)bitsBuf, (const UInt32*)__CFCSetBitmapBits(subSet1))) { -#if __MACOS8__ - if (bitsBuf2) CFAllocatorDeallocate(CFGetAllocator(nonBuiltinSet), bitsBuf2); -#endif __MACOS8__ return false; } } else { -#if __MACOS8__ - if (NULL == bitsBuf2) bitsBuf2 = CFAllocatorAllocate(CFGetAllocator(nonBuiltinSet), __kCFBitmapSize, 0); -#endif __MACOS8__ __CFCSetGetBitmap(subSet1, bitsBuf2); if (!__CFCSetIsEqualBitmap((const UInt32*)bitsBuf, (const UInt32*)bitsBuf2)) { -#if __MACOS8__ - CFAllocatorDeallocate(CFGetAllocator(nonBuiltinSet), bitsBuf2); -#endif __MACOS8__ return false; } } } else { if (NULL == subSet1) { if (result == kCFUniCharBitmapAll) { -#if __MACOS8__ - if (bitsBuf2) CFAllocatorDeallocate(CFGetAllocator(nonBuiltinSet), bitsBuf2); -#endif __MACOS8__ return false; } } else if (__CFCSetIsBitmap(subSet1)) { if (!__CFCSetIsEqualBitmap((result == kCFUniCharBitmapAll ? (const UInt32*)-1: NULL), (const UInt32*)__CFCSetBitmapBits(subSet1))) { -#if __MACOS8__ - if (bitsBuf2) CFAllocatorDeallocate(CFGetAllocator(nonBuiltinSet), bitsBuf2); -#endif __MACOS8__ return false; } } else { __CFCSetGetBitmap(subSet1, bitsBuf); if (!__CFCSetIsEqualBitmap((result == kCFUniCharBitmapAll ? (const UInt32*)-1: NULL), (const UInt32*)bitsBuf)) { -#if __MACOS8__ - if (bitsBuf2) CFAllocatorDeallocate(CFGetAllocator(nonBuiltinSet), bitsBuf2); -#endif __MACOS8__ return false; } } } } -#if __MACOS8__ - if (bitsBuf2) CFAllocatorDeallocate(CFGetAllocator(nonBuiltinSet), bitsBuf2); -#endif __MACOS8__ return true; } } - if (__CFCSetIsRange(cf1) || __CFCSetIsRange(cf2)) { - CFCharacterSetRef rangeSet = (__CFCSetIsRange(cf1) ? cf1 : cf2); - CFCharacterSetRef nonRangeSet = (rangeSet == cf1 ? cf2 : cf1); + if (__CFCSetIsRange((CFCharacterSetRef)cf1) || __CFCSetIsRange((CFCharacterSetRef)cf2)) { + CFCharacterSetRef rangeSet = (__CFCSetIsRange((CFCharacterSetRef)cf1) ? (CFCharacterSetRef)cf1 : (CFCharacterSetRef)cf2); + CFCharacterSetRef nonRangeSet = (rangeSet == cf1 ? (CFCharacterSetRef)cf2 : (CFCharacterSetRef)cf1); UTF32Char firstChar = __CFCSetRangeFirstChar(rangeSet); UTF32Char lastChar = (firstChar + __CFCSetRangeLength(rangeSet) - 1); uint8_t firstPlane = (firstChar >> 16) & 0xFF; @@ -1204,53 +1142,43 @@ static Boolean __CFCharacterSetEqual(CFTypeRef cf1, CFTypeRef cf2) { return true; } - isBitmap1 = __CFCSetIsBitmap(cf1); - isBitmap2 = __CFCSetIsBitmap(cf2); + isBitmap1 = __CFCSetIsBitmap((CFCharacterSetRef)cf1); + isBitmap2 = __CFCSetIsBitmap((CFCharacterSetRef)cf2); if (isBitmap1 && isBitmap2) { - if (!__CFCSetIsEqualBitmap((const UInt32*)__CFCSetBitmapBits(cf1), (const UInt32*)__CFCSetBitmapBits(cf2))) return false; + if (!__CFCSetIsEqualBitmap((const UInt32 *)__CFCSetBitmapBits((CFCharacterSetRef)cf1), (const UInt32 *)__CFCSetBitmapBits((CFCharacterSetRef)cf2))) return false; } else if (!isBitmap1 && !isBitmap2) { -#if __MACOS8__ - uint8_t *bitsBuf2 = (uint8_t *)CFAllocatorAllocate(NULL, __kCFBitmapSize, 0); -#else __MACOS8__ uint8_t bitsBuf2[__kCFBitmapSize]; -#endif __MACOS8__ - __CFCSetGetBitmap(cf1, bitsBuf); - __CFCSetGetBitmap(cf2, bitsBuf2); + __CFCSetGetBitmap((CFCharacterSetRef)cf1, bitsBuf); + __CFCSetGetBitmap((CFCharacterSetRef)cf2, bitsBuf2); if (!__CFCSetIsEqualBitmap((const UInt32*)bitsBuf, (const UInt32*)bitsBuf2)) { -#if __MACOS8__ - CFAllocatorDeallocate(NULL, bitsBuf2); -#endif __MACOS8__ return false; } -#if __MACOS8__ - CFAllocatorDeallocate(NULL, bitsBuf2); -#endif __MACOS8__ } else { if (isBitmap2) { - CFCharacterSetRef tmp = cf2; + CFCharacterSetRef tmp = (CFCharacterSetRef)cf2; cf2 = cf1; cf1 = tmp; } - __CFCSetGetBitmap(cf2, bitsBuf); + __CFCSetGetBitmap((CFCharacterSetRef)cf2, bitsBuf); - if (!__CFCSetIsEqualBitmap((const UInt32*)__CFCSetBitmapBits(cf1), (const UInt32*)bitsBuf)) return false; + if (!__CFCSetIsEqualBitmap((const UInt32 *)__CFCSetBitmapBits((CFCharacterSetRef)cf1), (const UInt32 *)bitsBuf)) return false; } - return __CFCSetIsEqualAnnex(cf1, cf2); + return __CFCSetIsEqualAnnex((CFCharacterSetRef)cf1, (CFCharacterSetRef)cf2); } static CFHashCode __CFCharacterSetHash(CFTypeRef cf) { - if (!__CFCSetHasHashValue(cf)) { - if (__CFCSetIsEmpty(cf)) { - ((CFMutableCharacterSetRef)cf)->_hashValue = (__CFCSetIsInverted(cf) ? 0xFFFFFFFF : 0); - } else if (__CFCSetIsBitmap(cf)) { - ((CFMutableCharacterSetRef)cf)->_hashValue = CFHashBytes(__CFCSetBitmapBits(cf), __kCFBitmapSize); + if (!__CFCSetHasHashValue((CFCharacterSetRef)cf)) { + if (__CFCSetIsEmpty((CFCharacterSetRef)cf)) { + ((CFMutableCharacterSetRef)cf)->_hashValue = (__CFCSetIsInverted((CFCharacterSetRef)cf) ? ((UInt32)0xFFFFFFFF) : 0); + } else if (__CFCSetIsBitmap( (CFCharacterSetRef) cf )) { + ((CFMutableCharacterSetRef)cf)->_hashValue = CFHashBytes(__CFCSetBitmapBits((CFCharacterSetRef)cf), __kCFBitmapSize); } else { uint8_t bitsBuf[__kCFBitmapSize]; - __CFCSetGetBitmap(cf, bitsBuf); + __CFCSetGetBitmap((CFCharacterSetRef)cf, bitsBuf); ((CFMutableCharacterSetRef)cf)->_hashValue = CFHashBytes(bitsBuf, __kCFBitmapSize); } __CFCSetPutHasHashValue((CFMutableCharacterSetRef)cf, true); @@ -1263,46 +1191,47 @@ static CFStringRef __CFCharacterSetCopyDescription(CFTypeRef cf) { CFIndex idx; CFIndex length; - if (__CFCSetIsEmpty(cf)) { - return (__CFCSetIsInverted(cf) ? CFRetain(CFSTR("")) : CFRetain(CFSTR(""))); + if (__CFCSetIsEmpty((CFCharacterSetRef)cf)) { + return (CFStringRef)(__CFCSetIsInverted((CFCharacterSetRef)cf) ? CFRetain(CFSTR("")) : CFRetain(CFSTR(""))); } - switch (__CFCSetClassType(cf)) { + switch (__CFCSetClassType((CFCharacterSetRef)cf)) { case __kCFCharSetClassBuiltin: - switch (__CFCSetBuiltinType(cf)) { - case kCFCharacterSetControl: return CFRetain(__kCFCSetNameControl); - case kCFCharacterSetWhitespace : return CFRetain(__kCFCSetNameWhitespace); - case kCFCharacterSetWhitespaceAndNewline: return CFRetain(__kCFCSetNameWhitespaceAndNewline); - case kCFCharacterSetDecimalDigit: return CFRetain(__kCFCSetNameDecimalDigit); - case kCFCharacterSetLetter: return CFRetain(__kCFCSetNameLetter); - case kCFCharacterSetLowercaseLetter: return CFRetain(__kCFCSetNameLowercaseLetter); - case kCFCharacterSetUppercaseLetter: return CFRetain(__kCFCSetNameUppercaseLetter); - case kCFCharacterSetNonBase: return CFRetain(__kCFCSetNameNonBase); - case kCFCharacterSetDecomposable: return CFRetain(__kCFCSetNameDecomposable); - case kCFCharacterSetAlphaNumeric: return CFRetain(__kCFCSetNameAlphaNumeric); - case kCFCharacterSetPunctuation: return CFRetain(__kCFCSetNamePunctuation); - case kCFCharacterSetIllegal: return CFRetain(__kCFCSetNameIllegal); - case kCFCharacterSetCapitalizedLetter: return CFRetain(__kCFCSetNameCapitalizedLetter); - case kCFCharacterSetSymbol: return CFRetain(__kCFCSetNameSymbol); + switch (__CFCSetBuiltinType((CFCharacterSetRef)cf)) { + case kCFCharacterSetControl: return (CFStringRef)CFRetain(__kCFCSetNameControl); + case kCFCharacterSetWhitespace : return (CFStringRef)CFRetain(__kCFCSetNameWhitespace); + case kCFCharacterSetWhitespaceAndNewline: return (CFStringRef)CFRetain(__kCFCSetNameWhitespaceAndNewline); + case kCFCharacterSetDecimalDigit: return (CFStringRef)CFRetain(__kCFCSetNameDecimalDigit); + case kCFCharacterSetLetter: return (CFStringRef)CFRetain(__kCFCSetNameLetter); + case kCFCharacterSetLowercaseLetter: return (CFStringRef)CFRetain(__kCFCSetNameLowercaseLetter); + case kCFCharacterSetUppercaseLetter: return (CFStringRef)CFRetain(__kCFCSetNameUppercaseLetter); + case kCFCharacterSetNonBase: return (CFStringRef)CFRetain(__kCFCSetNameNonBase); + case kCFCharacterSetDecomposable: return (CFStringRef)CFRetain(__kCFCSetNameDecomposable); + case kCFCharacterSetAlphaNumeric: return (CFStringRef)CFRetain(__kCFCSetNameAlphaNumeric); + case kCFCharacterSetPunctuation: return (CFStringRef)CFRetain(__kCFCSetNamePunctuation); + case kCFCharacterSetIllegal: return (CFStringRef)CFRetain(__kCFCSetNameIllegal); + case kCFCharacterSetCapitalizedLetter: return (CFStringRef)CFRetain(__kCFCSetNameCapitalizedLetter); + case kCFCharacterSetSymbol: return (CFStringRef)CFRetain(__kCFCSetNameSymbol); + case kCFCharacterSetNewline: return (CFStringRef)CFRetain(__kCFCSetNameNewline); } break; case __kCFCharSetClassRange: - return CFStringCreateWithFormat(CFGetAllocator(cf), NULL, CFSTR(""), __CFCSetRangeFirstChar(cf), __CFCSetRangeLength(cf)); + return CFStringCreateWithFormat(CFGetAllocator((CFCharacterSetRef)cf), NULL, CFSTR(""), __CFCSetRangeFirstChar((CFCharacterSetRef)cf), __CFCSetRangeLength((CFCharacterSetRef)cf)); case __kCFCharSetClassString: - length = __CFCSetStringLength(cf); + length = __CFCSetStringLength((CFCharacterSetRef)cf); string = CFStringCreateMutable(CFGetAllocator(cf), CFStringGetLength(__kCFCSetNameStringTypeFormat) + 7 * length + 2); // length of__kCFCSetNameStringTypeFormat + "U+XXXX "(7) * length + ")>"(2) CFStringAppend(string, __kCFCSetNameStringTypeFormat); for (idx = 0;idx < length;idx++) { - CFStringAppendFormat(string, NULL, CFSTR("%sU+%04X"), (idx > 0 ? " " : ""), (UInt32)((__CFCSetStringBuffer(cf))[idx])); + CFStringAppendFormat(string, NULL, CFSTR("%sU+%04X"), (idx > 0 ? " " : ""), (UInt32)((__CFCSetStringBuffer((CFCharacterSetRef)cf))[idx])); } CFStringAppend(string, CFSTR(")>")); return string; case __kCFCharSetClassBitmap: case __kCFCharSetClassCompactBitmap: - return CFRetain(CFSTR("")); // ??? Should generate description for 8k bitmap ? + return (CFStringRef)CFRetain(CFSTR("")); // ??? Should generate description for 8k bitmap ? } CFAssert1(0, __kCFLogAssertion, "%s: Internal inconsistency error: unknown character set type", __PRETTY_FUNCTION__); // We should never come here return NULL; @@ -1311,18 +1240,18 @@ static CFStringRef __CFCharacterSetCopyDescription(CFTypeRef cf) { static void __CFCharacterSetDeallocate(CFTypeRef cf) { CFAllocatorRef allocator = CFGetAllocator(cf); - if (__CFCSetIsBuiltin(cf) && !__CFCSetIsMutable(cf) && !__CFCSetIsInverted(cf)) { - CFCharacterSetRef sharedSet = CFCharacterSetGetPredefined(__CFCSetBuiltinType(cf)); + if (__CFCSetIsBuiltin((CFCharacterSetRef)cf) && !__CFCSetIsMutable((CFCharacterSetRef)cf) && !__CFCSetIsInverted((CFCharacterSetRef)cf)) { + CFCharacterSetRef sharedSet = CFCharacterSetGetPredefined(__CFCSetBuiltinType((CFCharacterSetRef)cf)); if (sharedSet == cf) { // We're trying to dealloc the builtin set - CFAssert1(0, __kCFLogAssertion, "%s: Trying to deallocate predefined set", __PRETTY_FUNCTION__); + CFAssert1(0, __kCFLogAssertion, "%s: Trying to deallocate predefined set. The process is likely to crash.", __PRETTY_FUNCTION__); return; // We never deallocate builtin set } } - if (__CFCSetIsString(cf) && __CFCSetStringBuffer(cf)) CFAllocatorDeallocate(allocator, __CFCSetStringBuffer(cf)); - else if (__CFCSetIsBitmap(cf) && __CFCSetBitmapBits(cf)) CFAllocatorDeallocate(allocator, __CFCSetBitmapBits(cf)); - else if (__CFCSetIsCompactBitmap(cf) && __CFCSetCompactBitmapBits(cf)) CFAllocatorDeallocate(allocator, __CFCSetCompactBitmapBits(cf)); - __CFCSetDeallocateAnnexPlane(cf); + if (__CFCSetIsString((CFCharacterSetRef)cf) && __CFCSetStringBuffer((CFCharacterSetRef)cf)) CFAllocatorDeallocate(allocator, __CFCSetStringBuffer((CFCharacterSetRef)cf)); + else if (__CFCSetIsBitmap((CFCharacterSetRef)cf) && __CFCSetBitmapBits((CFCharacterSetRef)cf)) CFAllocatorDeallocate(allocator, __CFCSetBitmapBits((CFCharacterSetRef)cf)); + else if (__CFCSetIsCompactBitmap((CFCharacterSetRef)cf) && __CFCSetCompactBitmapBits((CFCharacterSetRef)cf)) CFAllocatorDeallocate(allocator, __CFCSetCompactBitmapBits((CFCharacterSetRef)cf)); + __CFCSetDeallocateAnnexPlane((CFCharacterSetRef)cf); } static CFTypeID __kCFCharacterSetTypeID = _kCFRuntimeNotATypeID; @@ -1351,14 +1280,6 @@ __private_extern__ void __CFCharacterSetInitialize(void) { /* Public functions */ -#if defined(__MACOS8__) -CFTypeID CFCharacterSetTypeID(void) { -#ifdef DEBUG - CFLog(__kCFLogAssertion, CFSTR("CFCharacterSetTypeID should be CFCharacterSetGetTypeID")); -#endif /* DEBUG */ - return __kCFCharacterSetTypeID; -} -#endif /* __MACOS8__ */ CFTypeID CFCharacterSetGetTypeID(void) { return __kCFCharacterSetTypeID; @@ -1368,23 +1289,27 @@ CFTypeID CFCharacterSetGetTypeID(void) { /* Functions to create basic immutable characterset. */ CFCharacterSetRef CFCharacterSetGetPredefined(CFCharacterSetPredefinedSet theSetIdentifier) { - CFMutableCharacterSetRef cset; + CFCharacterSetRef cset; __CFCSetValidateBuiltinType(theSetIdentifier, __PRETTY_FUNCTION__); - if (__CFBuiltinSets && __CFBuiltinSets[theSetIdentifier - 1]) return __CFBuiltinSets[theSetIdentifier - 1]; + __CFSpinLock(&__CFCharacterSetLock); + cset = ((NULL != __CFBuiltinSets) ? __CFBuiltinSets[theSetIdentifier - 1] : NULL); + __CFSpinUnlock(&__CFCharacterSetLock); + + if (NULL != cset) return cset; if (!(cset = __CFCSetGenericCreate(kCFAllocatorSystemDefault, __kCFCharSetClassBuiltin))) return NULL; - __CFCSetPutBuiltinType(cset, theSetIdentifier); + __CFCSetPutBuiltinType((CFMutableCharacterSetRef)cset, theSetIdentifier); + __CFSpinLock(&__CFCharacterSetLock); if (!__CFBuiltinSets) { - __CFSpinLock(&__CFCharacterSetLock); - __CFBuiltinSets = (CFCharacterSetRef *)CFAllocatorAllocate(CFRetain(__CFGetDefaultAllocator()), sizeof(CFCharacterSetRef) * __kCFLastBuiltinSetID, 0); + __CFBuiltinSets = (CFCharacterSetRef *)CFAllocatorAllocate((CFAllocatorRef)CFRetain(__CFGetDefaultAllocator()), sizeof(CFCharacterSetRef) * __kCFLastBuiltinSetID, 0); memset(__CFBuiltinSets, 0, sizeof(CFCharacterSetRef) * __kCFLastBuiltinSetID); - __CFSpinUnlock(&__CFCharacterSetLock); } __CFBuiltinSets[theSetIdentifier - 1] = cset; + __CFSpinUnlock(&__CFCharacterSetLock); return cset; } @@ -1419,7 +1344,7 @@ CFCharacterSetRef CFCharacterSetCreateWithCharactersInString(CFAllocatorRef allo CFMutableCharacterSetRef cset; if (!(cset = __CFCSetGenericCreate(allocator, __kCFCharSetClassString))) return NULL; - __CFCSetPutStringBuffer(cset, CFAllocatorAllocate(CFGetAllocator(cset), __kCFStringCharSetMax * sizeof(UniChar), AUTO_MEMORY_UNSCANNED)); + __CFCSetPutStringBuffer(cset, (UniChar *)CFAllocatorAllocate(CFGetAllocator(cset), __kCFStringCharSetMax * sizeof(UniChar), 0)); __CFCSetPutStringLength(cset, length); CFStringGetCharacters(theString, CFRangeMake(0, length), __CFCSetStringBuffer(cset)); qsort(__CFCSetStringBuffer(cset), length, sizeof(UniChar), chcompar); @@ -1434,15 +1359,6 @@ CFCharacterSetRef CFCharacterSetCreateWithCharactersInString(CFAllocatorRef allo } } -#if defined(__MACOS8__) -CFCharacterSetRef CFCharacterSetCreateWithBitmapReresentation(CFAllocatorRef allocator, CFDataRef theData) { -#ifdef DEBUG - CFLog(__kCFLogAssertion, CFSTR("CFCharacterSetCreateWithBitmapReresentation should be CFCharacterSetCreateWithBitmapRepresentation")); -#endif /* DEBUG */ - return CFCharacterSetCreateWithBitmapRepresentation(allocator, theData); -} -#endif /* __MACOS8__ */ - CFCharacterSetRef CFCharacterSetCreateWithBitmapRepresentation(CFAllocatorRef allocator, CFDataRef theData) { CFMutableCharacterSetRef cset; CFIndex length; @@ -1454,7 +1370,7 @@ CFCharacterSetRef CFCharacterSetCreateWithBitmapRepresentation(CFAllocatorRef al uint8_t *cBitmap; if (length < __kCFBitmapSize) { - bitmap = (uint8_t *)CFAllocatorAllocate(allocator, __kCFBitmapSize, AUTO_MEMORY_UNSCANNED); + bitmap = (uint8_t *)CFAllocatorAllocate(allocator, __kCFBitmapSize, 0); memmove(bitmap, CFDataGetBytePtr(theData), length); memset(bitmap + length, 0, __kCFBitmapSize - length); @@ -1471,7 +1387,7 @@ CFCharacterSetRef CFCharacterSetCreateWithBitmapRepresentation(CFAllocatorRef al cBitmap = __CFCreateCompactBitmap(allocator, CFDataGetBytePtr(theData)); if (cBitmap == NULL) { - bitmap = (uint8_t *)CFAllocatorAllocate(allocator, __kCFBitmapSize, AUTO_MEMORY_UNSCANNED); + bitmap = (uint8_t *)CFAllocatorAllocate(allocator, __kCFBitmapSize, 0); memmove(bitmap, CFDataGetBytePtr(theData), __kCFBitmapSize); __CFCSetPutBitmapBits(cset, bitmap); @@ -1482,7 +1398,7 @@ CFCharacterSetRef CFCharacterSetCreateWithBitmapRepresentation(CFAllocatorRef al if (length > __kCFBitmapSize) { CFMutableCharacterSetRef annexSet; - const char *bytes = CFDataGetBytePtr(theData) + __kCFBitmapSize; + const uint8_t *bytes = CFDataGetBytePtr(theData) + __kCFBitmapSize; length -= __kCFBitmapSize; @@ -1491,7 +1407,7 @@ CFCharacterSetRef CFCharacterSetCreateWithBitmapRepresentation(CFAllocatorRef al --length; // Decrement the plane no byte if (length < __kCFBitmapSize) { - bitmap = (uint8_t *)CFAllocatorAllocate(allocator, __kCFBitmapSize, AUTO_MEMORY_UNSCANNED); + bitmap = (uint8_t *)CFAllocatorAllocate(allocator, __kCFBitmapSize, 0); memmove(bitmap, bytes, length); memset(bitmap + length, 0, __kCFBitmapSize - length); @@ -1508,7 +1424,7 @@ CFCharacterSetRef CFCharacterSetCreateWithBitmapRepresentation(CFAllocatorRef al cBitmap = __CFCreateCompactBitmap(allocator, bytes); if (cBitmap == NULL) { - bitmap = (uint8_t *)CFAllocatorAllocate(allocator, __kCFBitmapSize, AUTO_MEMORY_UNSCANNED); + bitmap = (uint8_t *)CFAllocatorAllocate(allocator, __kCFBitmapSize, 0); memmove(bitmap, bytes, __kCFBitmapSize); __CFCSetPutBitmapBits(annexSet, bitmap); @@ -1583,7 +1499,8 @@ CFMutableCharacterSetRef __CFCharacterSetCreateCopy(CFAllocatorRef alloc, CFChar break; case __kCFCharSetClassString: - __CFCSetPutStringBuffer(cset, CFAllocatorAllocate(alloc, __kCFStringCharSetMax * sizeof(UniChar), AUTO_MEMORY_UNSCANNED)); + __CFCSetPutStringBuffer(cset, (UniChar *)CFAllocatorAllocate(alloc, __kCFStringCharSetMax * sizeof(UniChar), 0)); + __CFCSetPutStringLength(cset, __CFCSetStringLength(theSet)); memmove(__CFCSetStringBuffer(cset), __CFCSetStringBuffer(theSet), __CFCSetStringLength(theSet) * sizeof(UniChar)); break; @@ -1593,7 +1510,7 @@ CFMutableCharacterSetRef __CFCharacterSetCreateCopy(CFAllocatorRef alloc, CFChar uint8_t * bitmap = (isMutable ? NULL : __CFCreateCompactBitmap(alloc, __CFCSetBitmapBits(theSet))); if (bitmap == NULL) { - bitmap = (uint8_t *)CFAllocatorAllocate(alloc, sizeof(uint8_t) * __kCFBitmapSize, AUTO_MEMORY_UNSCANNED); + bitmap = (uint8_t *)CFAllocatorAllocate(alloc, sizeof(uint8_t) * __kCFBitmapSize, 0); memmove(bitmap, __CFCSetBitmapBits(theSet), __kCFBitmapSize); __CFCSetPutBitmapBits(cset, bitmap); } else { @@ -1610,7 +1527,7 @@ CFMutableCharacterSetRef __CFCharacterSetCreateCopy(CFAllocatorRef alloc, CFChar if (compactBitmap) { uint32_t size = __CFCSetGetCompactBitmapSize(compactBitmap); - uint8_t *newBitmap = (uint8_t *)CFAllocatorAllocate(alloc, size, AUTO_MEMORY_UNSCANNED); + uint8_t *newBitmap = (uint8_t *)CFAllocatorAllocate(alloc, size, 0); memmove(newBitmap, compactBitmap, size); __CFCSetPutCompactBitmapBits(cset, newBitmap); @@ -1651,7 +1568,44 @@ CFMutableCharacterSetRef CFCharacterSetCreateMutableCopy(CFAllocatorRef alloc, C /*** Basic accessors ***/ Boolean CFCharacterSetIsCharacterMember(CFCharacterSetRef theSet, UniChar theChar) { - return CFCharacterSetIsLongCharacterMember(theSet, theChar); + CFIndex length; + Boolean isInverted; + Boolean result = false; + + CF_OBJC_FUNCDISPATCH1(__kCFCharacterSetTypeID, Boolean, theSet, "longCharacterIsMember:", theChar); + + __CFGenericValidateType(theSet, __kCFCharacterSetTypeID); + + isInverted = __CFCSetIsInverted(theSet); + + switch (__CFCSetClassType(theSet)) { + case __kCFCharSetClassBuiltin: + result = (CFUniCharIsMemberOf(theChar, __CFCSetBuiltinType(theSet)) ? !isInverted : isInverted); + break; + + case __kCFCharSetClassRange: + length = __CFCSetRangeLength(theSet); + result = (length && __CFCSetRangeFirstChar(theSet) <= theChar && theChar < __CFCSetRangeFirstChar(theSet) + length ? !isInverted : isInverted); + break; + + case __kCFCharSetClassString: + result = ((length = __CFCSetStringLength(theSet)) ? (__CFCSetBsearchUniChar(__CFCSetStringBuffer(theSet), length, theChar) ? !isInverted : isInverted) : isInverted); + break; + + case __kCFCharSetClassBitmap: + result = (__CFCSetCompactBitmapBits(theSet) ? (__CFCSetIsMemberBitmap(__CFCSetBitmapBits(theSet), theChar) ? true : false) : isInverted); + break; + + case __kCFCharSetClassCompactBitmap: + result = (__CFCSetCompactBitmapBits(theSet) ? (__CFCSetIsMemberInCompactBitmap(__CFCSetCompactBitmapBits(theSet), theChar) ? true : false) : isInverted); + break; + + default: + CFAssert1(0, __kCFLogAssertion, "%s: Internal inconsistency error: unknown character set type", __PRETTY_FUNCTION__); // We should never come here + break; + } + + return result; } Boolean CFCharacterSetIsLongCharacterMember(CFCharacterSetRef theSet, UTF32Char theChar) { @@ -1726,7 +1680,7 @@ Boolean CFCharacterSetIsSurrogatePairMember(CFCharacterSetRef theSet, UniChar su } -static CFCharacterSetRef __CFCharacterSetGetExpandedSetForNSCharacterSet(const void *characterSet) { +static inline CFCharacterSetRef __CFCharacterSetGetExpandedSetForNSCharacterSet(const void *characterSet) { CF_OBJC_FUNCDISPATCH0(__kCFCharacterSetTypeID, CFCharacterSetRef , characterSet, "_expandedCFCharacterSet"); return NULL; } @@ -1819,7 +1773,7 @@ Boolean CFCharacterSetIsSupersetOfSet(CFCharacterSetRef theSet, CFCharacterSetRe } } - copy = CFCharacterSetCreateMutableCopy(NULL, theSet); + copy = CFCharacterSetCreateMutableCopy(kCFAllocatorSystemDefault, theSet); CFCharacterSetIntersect(copy, theOtherSet); result = __CFCharacterSetEqual(copy, theOtherSet); CFRelease(copy); @@ -1843,7 +1797,7 @@ Boolean CFCharacterSetHasMemberInPlane(CFCharacterSetRef theSet, CFIndex thePlan } else { return (CFUniCharGetBitmapPtrForPlane(type, thePlane) ? TRUE : FALSE); } - } else if (type < kCFCharacterSetDecimalDigit) { + } else if ((type < kCFCharacterSetDecimalDigit) || (type == kCFCharacterSetNewline)) { return (thePlane && !isInverted ? FALSE : TRUE); } else if (__CFCSetBuiltinType(theSet) == kCFCharacterSetIllegal) { return (isInverted ? (thePlane < 3 || thePlane > 13 ? TRUE : FALSE) : TRUE); // This is according to Unicode 3.1 @@ -1919,7 +1873,7 @@ CFDataRef CFCharacterSetCreateBitmapRepresentation(CFAllocatorRef alloc, CFChara __CFGenericValidateType(theSet, __kCFCharacterSetTypeID); - isAnnexInverted = __CFCSetAnnexIsInverted(theSet); + isAnnexInverted = (__CFCSetAnnexIsInverted(theSet) != 0); if (__CFCSetHasNonBMPPlane(theSet)) { for (idx = 1;idx <= MAX_ANNEX_PLANE;idx++) { @@ -1934,7 +1888,7 @@ CFDataRef CFCharacterSetCreateBitmapRepresentation(CFAllocatorRef alloc, CFChara UInt32 lastChar = __CFCSetRangeFirstChar(theSet) + __CFCSetRangeLength(theSet) - 1; int firstPlane = (firstChar >> 16); int lastPlane = (lastChar >> 16); - bool isInverted = __CFCSetIsInverted(theSet); + bool isInverted = (__CFCSetIsInverted(theSet) != 0); if (lastPlane > 0) { if (firstPlane == 0) { @@ -1964,7 +1918,7 @@ CFDataRef CFCharacterSetCreateBitmapRepresentation(CFAllocatorRef alloc, CFChara __CFCSetGetBitmap(theSet, CFDataGetMutableBytePtr(data)); if (numNonBMPPlanes > 0) { - char *bytes = CFDataGetMutableBytePtr(data) + __kCFBitmapSize; + uint8_t *bytes = CFDataGetMutableBytePtr(data) + __kCFBitmapSize; if (__CFCSetHasNonBMPPlane(theSet)) { CFCharacterSetRef subset; @@ -1989,10 +1943,11 @@ CFDataRef CFCharacterSetCreateBitmapRepresentation(CFAllocatorRef alloc, CFChara } } else if (__CFCSetIsBuiltin(theSet)) { UInt8 result; + CFIndex delta; Boolean isInverted = __CFCSetIsInverted(theSet); for (idx = 0;idx < numNonBMPPlanes;idx++) { - if ((result = CFUniCharGetBitmapForPlane(__CFCSetBuiltinType(theSet), idx + 1, bytes + 1, isInverted)) == kCFUniCharBitmapEmpty) continue; + if ((result = CFUniCharGetBitmapForPlane(__CFCSetBuiltinType(theSet), idx + 1, bytes + 1, (isInverted != 0))) == kCFUniCharBitmapEmpty) continue; *(bytes++) = idx + 1; if (result == kCFUniCharBitmapAll) { CFIndex bitmapLength = __kCFBitmapSize; @@ -2001,7 +1956,8 @@ CFDataRef CFCharacterSetCreateBitmapRepresentation(CFAllocatorRef alloc, CFChara bytes += __kCFBitmapSize; } } - if (bytes - (const char *)CFDataGetBytePtr(data) < length) CFDataSetLength(data, bytes - (const char *)CFDataGetBytePtr(data)); + delta = bytes - (const uint8_t *)CFDataGetBytePtr(data); + if (delta < length) CFDataSetLength(data, delta); } else if (__CFCSetIsRange(theSet)) { UInt32 firstChar = __CFCSetRangeFirstChar(theSet); UInt32 lastChar = __CFCSetRangeFirstChar(theSet) + __CFCSetRangeLength(theSet) - 1; @@ -2104,10 +2060,10 @@ void CFCharacterSetAddCharactersInRange(CFMutableCharacterSetRef theSet, CFRange } else if (__CFCSetIsString(theSet) && __CFCSetStringLength(theSet) + theRange.length < __kCFStringCharSetMax) { UniChar *buffer; if (!__CFCSetStringBuffer(theSet)) - __CFCSetPutStringBuffer(theSet, CFAllocatorAllocate(CFGetAllocator(theSet), __kCFStringCharSetMax * sizeof(UniChar), AUTO_MEMORY_UNSCANNED)); + __CFCSetPutStringBuffer(theSet, (UniChar *)CFAllocatorAllocate(CFGetAllocator(theSet), __kCFStringCharSetMax * sizeof(UniChar), 0)); buffer = __CFCSetStringBuffer(theSet) + __CFCSetStringLength(theSet); __CFCSetPutStringLength(theSet, __CFCSetStringLength(theSet) + theRange.length); - while (theRange.length--) *buffer++ = theRange.location++; + while (theRange.length--) *buffer++ = (UniChar)theRange.location++; qsort(__CFCSetStringBuffer(theSet), __CFCSetStringLength(theSet), sizeof(UniChar), chcompar); __CFCSetPutHasHashValue(theSet, false); return; @@ -2119,7 +2075,7 @@ void CFCharacterSetAddCharactersInRange(CFMutableCharacterSetRef theSet, CFRange __CFCSetAddNonBMPPlanesInRange(theSet, theRange); if (theRange.location < 0x10000) { // theRange is in BMP if (theRange.location + theRange.length >= NUMCHARACTERS) theRange.length = NUMCHARACTERS - theRange.location; - __CFCSetBitmapAddCharactersInRange(__CFCSetBitmapBits(theSet), theRange.location, theRange.location + theRange.length - 1); + __CFCSetBitmapAddCharactersInRange(__CFCSetBitmapBits(theSet), (UniChar)theRange.location, (UniChar)(theRange.location + theRange.length - 1)); } __CFCSetPutHasHashValue(theSet, false); @@ -2162,10 +2118,10 @@ void CFCharacterSetRemoveCharactersInRange(CFMutableCharacterSetRef theSet, CFRa } else if (__CFCSetIsString(theSet) && __CFCSetStringLength(theSet) + theRange.length < __kCFStringCharSetMax) { UniChar *buffer; if (!__CFCSetStringBuffer(theSet)) - __CFCSetPutStringBuffer(theSet, CFAllocatorAllocate(CFGetAllocator(theSet), __kCFStringCharSetMax * sizeof(UniChar), AUTO_MEMORY_UNSCANNED)); + __CFCSetPutStringBuffer(theSet, (UniChar *)CFAllocatorAllocate(CFGetAllocator(theSet), __kCFStringCharSetMax * sizeof(UniChar), 0)); buffer = __CFCSetStringBuffer(theSet) + __CFCSetStringLength(theSet); __CFCSetPutStringLength(theSet, __CFCSetStringLength(theSet) + theRange.length); - while (theRange.length--) *buffer++ = theRange.location++; + while (theRange.length--) *buffer++ = (UniChar)theRange.location++; qsort(__CFCSetStringBuffer(theSet), __CFCSetStringLength(theSet), sizeof(UniChar), chcompar); __CFCSetPutHasHashValue(theSet, false); return; @@ -2181,7 +2137,7 @@ void CFCharacterSetRemoveCharactersInRange(CFMutableCharacterSetRef theSet, CFRa CFAllocatorDeallocate(CFGetAllocator(theSet), __CFCSetBitmapBits(theSet)); __CFCSetPutBitmapBits(theSet, NULL); } else { - __CFCSetBitmapRemoveCharactersInRange(__CFCSetBitmapBits(theSet), theRange.location, theRange.location + theRange.length - 1); + __CFCSetBitmapRemoveCharactersInRange(__CFCSetBitmapBits(theSet), (UniChar)theRange.location, (UniChar)(theRange.location + theRange.length - 1)); } } @@ -2203,10 +2159,13 @@ void CFCharacterSetAddCharactersInString(CFMutableCharacterSetRef theSet, CFStr CFIndex newLength = length + (__CFCSetIsEmpty(theSet) ? 0 : (__CFCSetIsString(theSet) ? __CFCSetStringLength(theSet) : __kCFStringCharSetMax)); if (newLength < __kCFStringCharSetMax) { - if (__CFCSetIsEmpty(theSet)) __CFCSetPutStringLength(theSet, 0); // Make sure to reset this - + if (__CFCSetIsEmpty(theSet)) { + __CFCSetPutClassType(theSet, __kCFCharSetClassString); + __CFCSetPutStringLength(theSet, 0); // Make sure to reset this + } + if (!__CFCSetStringBuffer(theSet)) - __CFCSetPutStringBuffer(theSet, CFAllocatorAllocate(CFGetAllocator(theSet), __kCFStringCharSetMax * sizeof(UniChar), AUTO_MEMORY_UNSCANNED)); + __CFCSetPutStringBuffer(theSet, (UniChar *)CFAllocatorAllocate(CFGetAllocator(theSet), __kCFStringCharSetMax * sizeof(UniChar), 0)); buffer = __CFCSetStringBuffer(theSet) + __CFCSetStringLength(theSet); __CFCSetPutClassType(theSet, __kCFCharSetClassString); @@ -2247,10 +2206,13 @@ void CFCharacterSetRemoveCharactersInString(CFMutableCharacterSetRef theSet, CFS CFIndex newLength = length + (__CFCSetIsEmpty(theSet) ? 0 : (__CFCSetIsString(theSet) ? __CFCSetStringLength(theSet) : __kCFStringCharSetMax)); if (newLength < __kCFStringCharSetMax) { - if (__CFCSetIsEmpty(theSet)) __CFCSetPutStringLength(theSet, 0); // Make sure to reset this + if (__CFCSetIsEmpty(theSet)) { + __CFCSetPutClassType(theSet, __kCFCharSetClassString); + __CFCSetPutStringLength(theSet, 0); // Make sure to reset this + } if (!__CFCSetStringBuffer(theSet)) - __CFCSetPutStringBuffer(theSet, CFAllocatorAllocate(CFGetAllocator(theSet), __kCFStringCharSetMax * sizeof(UniChar), AUTO_MEMORY_UNSCANNED)); + __CFCSetPutStringBuffer(theSet, (UniChar *)CFAllocatorAllocate(CFGetAllocator(theSet), __kCFStringCharSetMax * sizeof(UniChar), 0)); buffer = __CFCSetStringBuffer(theSet) + __CFCSetStringLength(theSet); __CFCSetPutClassType(theSet, __kCFCharSetClassString); @@ -2303,87 +2265,85 @@ void CFCharacterSetUnion(CFMutableCharacterSetRef theSet, CFCharacterSetRef theO __CFCSetPutIsInverted(theSet, true); __CFCSetPutHasHashValue(theSet, false); __CFCSetDeallocateAnnexPlane(theSet); - } else { - return; // Nothing to do here } - } - - if (__CFCSetIsBuiltin(theOtherSet) && __CFCSetIsEmpty(theSet)) { // theSet can be builtin set + } else if (__CFCSetIsBuiltin(theOtherSet) && __CFCSetIsEmpty(theSet)) { // theSet can be builtin set __CFCSetPutClassType(theSet, __kCFCharSetClassBuiltin); __CFCSetPutBuiltinType(theSet, __CFCSetBuiltinType(theOtherSet)); __CFCSetPutHasHashValue(theSet, false); - } else if (__CFCSetIsRange(theOtherSet)) { - if (__CFCSetIsInverted(theOtherSet)) { - UTF32Char firstChar = __CFCSetRangeFirstChar(theOtherSet); - CFIndex length = __CFCSetRangeLength(theOtherSet); - - if (firstChar > 0) CFCharacterSetAddCharactersInRange(theSet, CFRangeMake(0, firstChar)); - firstChar += length; - length = 0x110000 - firstChar; - CFCharacterSetAddCharactersInRange(theSet, CFRangeMake(firstChar, length)); - } else { - CFCharacterSetAddCharactersInRange(theSet, CFRangeMake(__CFCSetRangeFirstChar(theOtherSet), __CFCSetRangeLength(theOtherSet))); - } - } else if (__CFCSetIsString(theOtherSet)) { - CFStringRef string = CFStringCreateWithCharactersNoCopy(CFGetAllocator(theSet), __CFCSetStringBuffer(theOtherSet), __CFCSetStringLength(theOtherSet), kCFAllocatorNull); - CFCharacterSetAddCharactersInString(theSet, string); - CFRelease(string); } else { - __CFCSetMakeBitmap(theSet); - if (__CFCSetIsBitmap(theOtherSet)) { - UInt32 *bitmap1 = (UInt32*)__CFCSetBitmapBits(theSet); - UInt32 *bitmap2 = (UInt32*)__CFCSetBitmapBits(theOtherSet); - CFIndex length = __kCFBitmapSize / sizeof(UInt32); - while (length--) *bitmap1++ |= *bitmap2++; + if (__CFCSetIsRange(theOtherSet)) { + if (__CFCSetIsInverted(theOtherSet)) { + UTF32Char firstChar = __CFCSetRangeFirstChar(theOtherSet); + CFIndex length = __CFCSetRangeLength(theOtherSet); + + if (firstChar > 0) CFCharacterSetAddCharactersInRange(theSet, CFRangeMake(0, firstChar)); + firstChar += length; + length = 0x110000 - firstChar; + CFCharacterSetAddCharactersInRange(theSet, CFRangeMake(firstChar, length)); + } else { + CFCharacterSetAddCharactersInRange(theSet, CFRangeMake(__CFCSetRangeFirstChar(theOtherSet), __CFCSetRangeLength(theOtherSet))); + } + } else if (__CFCSetIsString(theOtherSet)) { + CFStringRef string = CFStringCreateWithCharactersNoCopy(CFGetAllocator(theSet), __CFCSetStringBuffer(theOtherSet), __CFCSetStringLength(theOtherSet), kCFAllocatorNull); + CFCharacterSetAddCharactersInString(theSet, string); + CFRelease(string); } else { - UInt32 *bitmap1 = (UInt32*)__CFCSetBitmapBits(theSet); - UInt32 *bitmap2; - CFIndex length = __kCFBitmapSize / sizeof(UInt32); - uint8_t bitmapBuffer[__kCFBitmapSize]; - __CFCSetGetBitmap(theOtherSet, bitmapBuffer); - bitmap2 = (UInt32*)bitmapBuffer; - while (length--) *bitmap1++ |= *bitmap2++; + __CFCSetMakeBitmap(theSet); + if (__CFCSetIsBitmap(theOtherSet)) { + UInt32 *bitmap1 = (UInt32*)__CFCSetBitmapBits(theSet); + UInt32 *bitmap2 = (UInt32*)__CFCSetBitmapBits(theOtherSet); + CFIndex length = __kCFBitmapSize / sizeof(UInt32); + while (length--) *bitmap1++ |= *bitmap2++; + } else { + UInt32 *bitmap1 = (UInt32*)__CFCSetBitmapBits(theSet); + UInt32 *bitmap2; + CFIndex length = __kCFBitmapSize / sizeof(UInt32); + uint8_t bitmapBuffer[__kCFBitmapSize]; + __CFCSetGetBitmap(theOtherSet, bitmapBuffer); + bitmap2 = (UInt32*)bitmapBuffer; + while (length--) *bitmap1++ |= *bitmap2++; + } + __CFCSetPutHasHashValue(theSet, false); } - __CFCSetPutHasHashValue(theSet, false); - } - if (__CFCSetHasNonBMPPlane(theOtherSet)) { - CFMutableCharacterSetRef otherSetPlane; - int idx; + if (__CFCSetHasNonBMPPlane(theOtherSet)) { + CFMutableCharacterSetRef otherSetPlane; + int idx; - for (idx = 1;idx <= MAX_ANNEX_PLANE;idx++) { - if ((otherSetPlane = (CFMutableCharacterSetRef)__CFCSetGetAnnexPlaneCharacterSetNoAlloc(theOtherSet, idx))) { - CFCharacterSetUnion((CFMutableCharacterSetRef)__CFCSetGetAnnexPlaneCharacterSet(theSet, idx), otherSetPlane); + for (idx = 1;idx <= MAX_ANNEX_PLANE;idx++) { + if ((otherSetPlane = (CFMutableCharacterSetRef)__CFCSetGetAnnexPlaneCharacterSetNoAlloc(theOtherSet, idx))) { + CFCharacterSetUnion((CFMutableCharacterSetRef)__CFCSetGetAnnexPlaneCharacterSet(theSet, idx), otherSetPlane); + } } - } - } else if (__CFCSetIsBuiltin(theOtherSet)) { - CFMutableCharacterSetRef annexPlane; - uint8_t bitmapBuffer[__kCFBitmapSize]; - uint8_t result; - int planeIndex; - Boolean isOtherAnnexPlaneInverted = __CFCSetAnnexIsInverted(theOtherSet); - UInt32 *bitmap1; - UInt32 *bitmap2; - CFIndex length; + } else if (__CFCSetIsBuiltin(theOtherSet)) { + CFMutableCharacterSetRef annexPlane; + uint8_t bitmapBuffer[__kCFBitmapSize]; + uint8_t result; + int planeIndex; + Boolean isOtherAnnexPlaneInverted = __CFCSetAnnexIsInverted(theOtherSet); + UInt32 *bitmap1; + UInt32 *bitmap2; + CFIndex length; - for (planeIndex = 1;planeIndex <= MAX_ANNEX_PLANE;planeIndex++) { - result = CFUniCharGetBitmapForPlane(__CFCSetBuiltinType(theOtherSet), planeIndex, bitmapBuffer, isOtherAnnexPlaneInverted); - if (result != kCFUniCharBitmapEmpty) { - annexPlane = (CFMutableCharacterSetRef)__CFCSetGetAnnexPlaneCharacterSet(theSet, planeIndex); - if (result == kCFUniCharBitmapAll) { - CFCharacterSetAddCharactersInRange(annexPlane, CFRangeMake(0x0000, 0x10000)); - } else { - __CFCSetMakeBitmap(annexPlane); - bitmap1 = (UInt32 *)__CFCSetBitmapBits(annexPlane); - length = __kCFBitmapSize / sizeof(UInt32); - bitmap2 = (UInt32*)bitmapBuffer; - while (length--) *bitmap1++ |= *bitmap2++; + for (planeIndex = 1;planeIndex <= MAX_ANNEX_PLANE;planeIndex++) { + result = CFUniCharGetBitmapForPlane(__CFCSetBuiltinType(theOtherSet), planeIndex, bitmapBuffer, (isOtherAnnexPlaneInverted != 0)); + if (result != kCFUniCharBitmapEmpty) { + annexPlane = (CFMutableCharacterSetRef)__CFCSetGetAnnexPlaneCharacterSet(theSet, planeIndex); + if (result == kCFUniCharBitmapAll) { + CFCharacterSetAddCharactersInRange(annexPlane, CFRangeMake(0x0000, 0x10000)); + } else { + __CFCSetMakeBitmap(annexPlane); + bitmap1 = (UInt32 *)__CFCSetBitmapBits(annexPlane); + length = __kCFBitmapSize / sizeof(UInt32); + bitmap2 = (UInt32*)bitmapBuffer; + while (length--) *bitmap1++ |= *bitmap2++; + } } } } } if (__CFCheckForExapendedSet) __CFCheckForExpandedSet(theSet); } else { // It's NSCharacterSet - CFDataRef bitmapRep = CFCharacterSetCreateBitmapRepresentation(NULL, theOtherSet); + CFDataRef bitmapRep = CFCharacterSetCreateBitmapRepresentation(kCFAllocatorSystemDefault, theOtherSet); const UInt32 *bitmap2 = (bitmapRep && CFDataGetLength(bitmapRep) ? (const UInt32 *)CFDataGetBytePtr(bitmapRep) : NULL); if (bitmap2) { UInt32 *bitmap1; @@ -2456,12 +2416,12 @@ void CFCharacterSetIntersect(CFMutableCharacterSetRef theSet, CFCharacterSetRef case __kCFCharSetClassString: __CFCSetPutStringLength(theSet, __CFCSetStringLength(theOtherSet)); if (!__CFCSetStringBuffer(theSet)) - __CFCSetPutStringBuffer(theSet, CFAllocatorAllocate(CFGetAllocator(theSet), __kCFStringCharSetMax * sizeof(UniChar), AUTO_MEMORY_UNSCANNED)); + __CFCSetPutStringBuffer(theSet, (UniChar *)CFAllocatorAllocate(CFGetAllocator(theSet), __kCFStringCharSetMax * sizeof(UniChar), 0)); memmove(__CFCSetStringBuffer(theSet), __CFCSetStringBuffer(theOtherSet), __CFCSetStringLength(theSet) * sizeof(UniChar)); break; case __kCFCharSetClassBitmap: - __CFCSetPutBitmapBits(theSet, CFAllocatorAllocate(CFGetAllocator(theSet), sizeof(uint8_t) * __kCFBitmapSize, AUTO_MEMORY_UNSCANNED)); + __CFCSetPutBitmapBits(theSet, (uint8_t *)CFAllocatorAllocate(CFGetAllocator(theSet), sizeof(uint8_t) * __kCFBitmapSize, 0)); memmove(__CFCSetBitmapBits(theSet), __CFCSetBitmapBits(theOtherSet), __kCFBitmapSize); break; @@ -2469,7 +2429,7 @@ void CFCharacterSetIntersect(CFMutableCharacterSetRef theSet, CFCharacterSetRef const uint8_t *cBitmap = __CFCSetCompactBitmapBits(theOtherSet); uint8_t *newBitmap; uint32_t size = __CFCSetGetCompactBitmapSize(cBitmap); - newBitmap = (uint8_t *)CFAllocatorAllocate(CFGetAllocator(theSet), sizeof(uint8_t) * size, AUTO_MEMORY_UNSCANNED); + newBitmap = (uint8_t *)CFAllocatorAllocate(CFGetAllocator(theSet), sizeof(uint8_t) * size, 0); __CFCSetPutBitmapBits(theSet, newBitmap); memmove(newBitmap, cBitmap, size); } @@ -2522,7 +2482,7 @@ void CFCharacterSetIntersect(CFMutableCharacterSetRef theSet, CFCharacterSetRef for (planeIndex = 1;planeIndex <= MAX_ANNEX_PLANE;planeIndex++) { annexPlane = (CFMutableCharacterSetRef)__CFCSetGetAnnexPlaneCharacterSetNoAlloc(theSet, planeIndex); if (annexPlane) { - result = CFUniCharGetBitmapForPlane(__CFCSetBuiltinType(theOtherSet), planeIndex, bitmapBuffer, isOtherAnnexPlaneInverted); + result = CFUniCharGetBitmapForPlane(__CFCSetBuiltinType(theOtherSet), planeIndex, bitmapBuffer, (isOtherAnnexPlaneInverted != 0)); if (result == kCFUniCharBitmapEmpty) { __CFCSetPutCharacterSetToAnnexPlane(theSet, NULL, planeIndex); } else if (result == kCFUniCharBitmapFilled) { @@ -2566,7 +2526,7 @@ void CFCharacterSetIntersect(CFMutableCharacterSetRef theSet, CFCharacterSetRef } if (__CFCheckForExapendedSet) __CFCheckForExpandedSet(theSet); } else { // It's NSCharacterSet - CFDataRef bitmapRep = CFCharacterSetCreateBitmapRepresentation(NULL, theOtherSet); + CFDataRef bitmapRep = CFCharacterSetCreateBitmapRepresentation(kCFAllocatorSystemDefault, theOtherSet); const UInt32 *bitmap2 = (bitmapRep && CFDataGetLength(bitmapRep) ? (const UInt32 *)CFDataGetBytePtr(bitmapRep) : NULL); if (bitmap2) { UInt32 *bitmap1; @@ -2594,9 +2554,9 @@ void CFCharacterSetInvert(CFMutableCharacterSetRef theSet) { UInt32 *bitmap = (UInt32*) __CFCSetBitmapBits(theSet); if (NULL == bitmap) { - bitmap = (UInt32 *)CFAllocatorAllocate(CFGetAllocator(theSet), __kCFBitmapSize, AUTO_MEMORY_UNSCANNED); + bitmap = (UInt32 *)CFAllocatorAllocate(CFGetAllocator(theSet), __kCFBitmapSize, 0); __CFCSetPutBitmapBits(theSet, (uint8_t *)bitmap); - for (idx = 0;idx < count;idx++) bitmap[idx] = 0xFFFFFFFF; + for (idx = 0;idx < count;idx++) bitmap[idx] = ((UInt32)0xFFFFFFFF); } else { for (idx = 0;idx < count;idx++) bitmap[idx] = ~(bitmap[idx]); } @@ -2659,11 +2619,11 @@ void CFCharacterSetFast(CFMutableCharacterSetRef theSet) { */ CFCharacterSetKeyedCodingType _CFCharacterSetGetKeyedCodingType(CFCharacterSetRef cset) { switch (__CFCSetClassType(cset)) { - case __kCFCharSetClassBuiltin: return ((__CFCSetBuiltinType(cset) < kCFCharacterSetSymbol) ? kCFCharacterSetKeyedCodingTypeBuiltin : kCFCharacterSetKeyedCodingTypeBitmap); + case __kCFCharSetClassBuiltin: return ((__CFCSetBuiltinType(cset) < kCFCharacterSetSymbol) ? kCFCharacterSetKeyedCodingTypeBuiltin : kCFCharacterSetKeyedCodingTypeBuiltinAndBitmap); case __kCFCharSetClassRange: return kCFCharacterSetKeyedCodingTypeRange; case __kCFCharSetClassString: // We have to check if we have non-BMP here - if (!__CFCSetHasNonBMPPlane(cset)) return kCFCharacterSetKeyedCodingTypeString; // BMP only. we can archive the string + if (!__CFCSetHasNonBMPPlane(cset) && !__CFCSetAnnexIsInverted(cset)) return kCFCharacterSetKeyedCodingTypeString; // BMP only. we can archive the string /* fallthrough */ default: @@ -2673,9 +2633,95 @@ CFCharacterSetKeyedCodingType _CFCharacterSetGetKeyedCodingType(CFCharacterSetRe CFCharacterSetPredefinedSet _CFCharacterSetGetKeyedCodingBuiltinType(CFCharacterSetRef cset) { return __CFCSetBuiltinType(cset); } CFRange _CFCharacterSetGetKeyedCodingRange(CFCharacterSetRef cset) { return CFRangeMake(__CFCSetRangeFirstChar(cset), __CFCSetRangeLength(cset)); } -CFStringRef _CFCharacterSetCreateKeyedCodingString(CFCharacterSetRef cset) { return CFStringCreateWithCharacters(NULL, __CFCSetStringBuffer(cset), __CFCSetStringLength(cset)); } +CFStringRef _CFCharacterSetCreateKeyedCodingString(CFCharacterSetRef cset) { return CFStringCreateWithCharacters(kCFAllocatorSystemDefault, __CFCSetStringBuffer(cset), __CFCSetStringLength(cset)); } -bool _CFCharacterSetIsInverted(CFCharacterSetRef cset) { return __CFCSetIsInverted(cset); } +bool _CFCharacterSetIsInverted(CFCharacterSetRef cset) { return (__CFCSetIsInverted(cset) != 0); } void _CFCharacterSetSetIsInverted(CFCharacterSetRef cset, bool flag) { __CFCSetPutIsInverted((CFMutableCharacterSetRef)cset, flag); } +/* Inline buffer support +*/ +void CFCharacterSetInitInlineBuffer(CFCharacterSetRef cset, CFCharacterSetInlineBuffer *buffer) { + memset(buffer, 0, sizeof(CFCharacterSetInlineBuffer)); + buffer->cset = cset; + buffer->rangeLimit = 0x10000; + + if (CF_IS_OBJC(__kCFCharacterSetTypeID, cset)) { + CFCharacterSetRef expandedSet = __CFCharacterSetGetExpandedSetForNSCharacterSet(cset); + + if (NULL == expandedSet) { + buffer->flags = kCFCharacterSetNoBitmapAvailable; + buffer->rangeLimit = 0x110000; + return; + } else { + cset = expandedSet; + } + } + + switch (__CFCSetClassType(cset)) { + case __kCFCharSetClassBuiltin: + buffer->bitmap = CFUniCharGetBitmapPtrForPlane(__CFCSetBuiltinType(cset), 0); + buffer->rangeLimit = 0x110000; + if (NULL == buffer->bitmap) { + buffer->flags = kCFCharacterSetNoBitmapAvailable; + } else { + if (__CFCSetIsInverted(cset)) buffer->flags = kCFCharacterSetIsInverted; + } + break; + + case __kCFCharSetClassRange: + buffer->rangeStart = __CFCSetRangeFirstChar(cset); + buffer->rangeLimit = __CFCSetRangeFirstChar(cset) + __CFCSetRangeLength(cset); + if (__CFCSetIsInverted(cset)) buffer->flags = kCFCharacterSetIsInverted; + return; + + case __kCFCharSetClassString: + buffer->flags = kCFCharacterSetNoBitmapAvailable; + if (__CFCSetStringLength(cset) > 0) { + buffer->rangeStart = *__CFCSetStringBuffer(cset); + buffer->rangeLimit = *(__CFCSetStringBuffer(cset) + __CFCSetStringLength(cset) - 1) + 1; + + if (__CFCSetIsInverted(cset)) { + if (0 == buffer->rangeStart) { + buffer->rangeStart = buffer->rangeLimit; + buffer->rangeLimit = 0x10000; + } else if (0x10000 == buffer->rangeLimit) { + buffer->rangeLimit = buffer->rangeStart; + buffer->rangeStart = 0; + } else { + buffer->rangeStart = 0; + buffer->rangeLimit = 0x10000; + } + } + } + break; + + case __kCFCharSetClassBitmap: + case __kCFCharSetClassCompactBitmap: + buffer->bitmap = __CFCSetCompactBitmapBits(cset); + if (NULL == buffer->bitmap) { + buffer->flags = kCFCharacterSetIsCompactBitmap; + if (__CFCSetIsInverted(cset)) buffer->flags |= kCFCharacterSetIsInverted; + } else { + if (__kCFCharSetClassCompactBitmap == __CFCSetClassType(cset)) buffer->flags = kCFCharacterSetIsCompactBitmap; + } + break; + + default: + CFAssert1(0, __kCFLogAssertion, "%s: Internal inconsistency error: unknown character set type", __PRETTY_FUNCTION__); // We should never come here + return; + } + + if (__CFCSetAnnexIsInverted(cset)) { + buffer->rangeLimit = 0x110000; + } else if (__CFCSetHasNonBMPPlane(cset)) { + CFIndex index; + + for (index = MAX_ANNEX_PLANE;index > 0;index--) { + if (NULL != __CFCSetGetAnnexPlaneCharacterSetNoAlloc(cset, index)) { + buffer->rangeLimit = (index + 1) << 16; + break; + } + } + } +} diff --git a/String.subproj/CFCharacterSet.h b/CFCharacterSet.h similarity index 95% rename from String.subproj/CFCharacterSet.h rename to CFCharacterSet.h index a2aab31..5b38c50 100644 --- a/String.subproj/CFCharacterSet.h +++ b/CFCharacterSet.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFCharacterSet.h - Copyright (c) 1999-2005, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007, Apple Inc. All rights reserved. */ /*! @@ -56,9 +56,7 @@ #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN /*! @typedef CFCharacterSetRef @@ -76,7 +74,8 @@ typedef struct __CFCharacterSet * CFMutableCharacterSetRef; @typedef CFCharacterSetPredefinedSet Type of the predefined CFCharacterSet selector values. */ -typedef enum { + +enum { kCFCharacterSetControl = 1, /* Control character set (Unicode General Category Cc and Cf) */ kCFCharacterSetWhitespace, /* Whitespace character set (Unicode General Category Zs and U0009 CHARACTER TABULATION) */ kCFCharacterSetWhitespaceAndNewline, /* Whitespace and Newline character set (Unicode General Category Z*, U000A ~ U000D, and U0085) */ @@ -88,14 +87,18 @@ typedef 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*) */ - kCFCharacterSetIllegal /* Illegal character set */ #if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED - , kCFCharacterSetCapitalizedLetter /* Titlecase character set (Unicode General Category Lt) */ + kCFCharacterSetCapitalizedLetter = 13, /* Titlecase character set (Unicode General Category Lt) */ #endif #if MAC_OS_X_VERSION_10_3 <= MAC_OS_X_VERSION_MAX_ALLOWED - , kCFCharacterSetSymbol /* Symbol character set (Unicode General Category S*) */ + 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 -} CFCharacterSetPredefinedSet; + kCFCharacterSetIllegal = 12/* Illegal character set */ +}; +typedef CFIndex CFCharacterSetPredefinedSet; /*! @function CFCharacterSetGetTypeID @@ -165,13 +168,13 @@ CFCharacterSetRef CFCharacterSetCreateWithCharactersInString(CFAllocatorRef allo bitmap representation of the Unicode character points the character set is filled with. The bitmap representation could contain all the Unicode character - range starting from BMP to Plane 16. The first 8K bytes - of the data represents the BMP range. The BMP range 8K - bytes can be followed by zero to sixteen 8K byte + range starting from BMP to Plane 16. The first 8192 bytes + of the data represent the BMP range. The BMP range 8192 + bytes can be followed by zero to sixteen 8192 byte bitmaps, each one with the plane index byte prepended. For example, the bitmap representing the BMP and Plane 2 - has the size of 16385 bytes (8K bytes for BMP, 1 byte - index + 8K bytes bitmap for Plane 2). The plane index + has the size of 16385 bytes (8192 bytes for BMP, 1 byte + index + 8192 bytes bitmap for Plane 2). The plane index byte, in this case, contains the integer value two. If this parameter is not a valid CFData or it contains a Plane index byte outside of the valid Plane range @@ -248,7 +251,7 @@ CFMutableCharacterSetRef CFCharacterSetCreateMutable(CFAllocatorRef alloc); */ CF_EXPORT CFCharacterSetRef CFCharacterSetCreateCopy(CFAllocatorRef alloc, CFCharacterSetRef theSet) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; -#endif /* MAC_OS_X_VERSION_10_3 <= MAC_OS_X_VERSION_MAX_ALLOWED */ +#endif /*! @function CFCharacterSetCreateMutableCopy @@ -406,9 +409,7 @@ void CFCharacterSetIntersect(CFMutableCharacterSetRef theSet, CFCharacterSetRef CF_EXPORT void CFCharacterSetInvert(CFMutableCharacterSetRef theSet); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END -#endif /* !__COREFOUNDATION_CFCHARACTERSET__ */ +#endif /* ! __COREFOUNDATION_CFCHARACTERSET__ */ diff --git a/CharacterSets/CFCharacterSetBitmaps.bitmap b/CFCharacterSetBitmaps.bitmap similarity index 75% rename from CharacterSets/CFCharacterSetBitmaps.bitmap rename to CFCharacterSetBitmaps.bitmap index e57ddcd21c5521c5f655a4cdf6b6d37f19796954..b0874f9ea3e1d477ba24a7c60b08eea9d01c7154 100644 GIT binary patch delta 5268 zcmd5=3vg7`8NTP7d$XHOb~hoL_hauSn*$eIJH)y=rkJ0?SIbQY(kWj zcBY-4nS0K;=XL+{pa1{P_up3%g>NOwqL(%{N|^TXOp-KWKQSgraaq)fq}ZjFB}ri_ zkv^v=spOI*97khr(NE(Z@y@h-Nm3<=g|Wo-Sl=|eOcjVyR(*CEF2wROBFTM4c0;OI zl!{s+7Em-SaRDV(Dn6*B%0-!_Rq|5bGi>~X%rX8#+VRo0*UBDz&%?)M?4v;}m+Hx< zu*fnN1?q4}p798o#hVAhfvd|fOA&ml8rY*QR*jT4&B$&mh**{-wP|^!c^KYb>3=krW$8=c}{$B#~O9t#-+C{t^|h zSWlPMW)uNG2QydDw%_RfZ1(p#pwK*+K)bbCdcWg_=SKzf!x-}Hz z?@=k5PI_YDz_V9==7wk1(_FZ0kQ5l&;%;MGSb?Q)l50uKI2x`LpO7tF%GkO5zKpD8 z1F@@bQeZdEG!Nj;0PkD zhpMQvke;Y?t{FOoC+gjd8{J38S4R<-4Q%bLbD??tJjXcpKn2|1Nv7$^I(v-vC~e;! zLoMqgB*67M8wb82oBR7HQHe)Sqz?i0U1rX!XQ>kG|2WGy(094}OXG+ATqK@O8IfHT zbDAXy{dEZ6qwn?i_cx%Q@FYf9*w9a(=6Qerjc?jzf4^(srd=+EmdNeYVSML_@3UF) z1(36fJf|n07D5(T(ayr8G&X~mWw@%*7FmbFEGvazT>cRp3CphD-RN_B)Q82if!4$| zWh7*5c_&D6P%R#1Y)qE%TB?EF`9O!BsLRvd8ns5ac}W!=9Ua?FLfarK@&0-SzKDci zBaNDRA-&7CpMlrj^-$)GtMKf5bPftoW4Gs{sfhHrOO?dT?Srfd`>V>tcc0%a8)a~5 zIk}(vRS-KCDCslkp)Nq(R>PtI36`K9&{4-y$gT`qQRoSfCL)}m8r}?$4I~$?uO_d< zC2jOxfEse6+p&1s3%)&8P2{(O%$n-n7^$f zBOYZTV(Ks|?b|N6VvwS}TmwTvSvK$2$b-cBy&RJ0D_Co<{O zaqFzLbIg#f4<_NIJ#GSC`i@u=@iMmOh;^F5NQ72F(MzPnWgUFAH73O^hXhx2(h70} zZt0`}W6k_r*!U9Z_)qY3)bfwxX&&?*BsWX|RU1~n0;9Dd0=96F3GHlI1F6~bc?n$5uk<;NTolYqo%nV$4;LgUSuz-Hj{2yJnsT@so* zsUJ@w3vTVC%Ta-QJ86*kIlq}>uY~yp@EaWE$A>|~3cBBiHLQzg3|EfmiHeM&D9EE) zJLcN&lc>!%;5S{gpdPL9%xSz={kS21DtyJU&0#e<%o{Af(G>Ba8k?bcCA|_!WL~`= z^^!hANjip0h?{oz;;5}c?6yXucpYq8&ZgtcHsau?Y|Eydk1OGlV*2^~nST%$ZiJqb zv;}^*iZ1uwo&3w_+Q?6jUG6T9b2x&9Vt8YJaL`vR4Gfeu*=m!GgrOZM}V`RNH7 zpgSF~W;I1z3*MfNt}k`lAv* z=D-*{EOLpPAMobCp?3pYM@FH&hu(?6(N&sJ^K|&IjQO(pIy}|riDJ7Cb&gPWi@Cj= zEp~ua%iK`4itI9y^lk52>mMSBa&WdP4WlXfdyla!fFQe!_~B@f`IM1CHq4Ez)MT~n z4#L%0$Fm%GtPW*~nx1-gcPSc{xlv>J<;bDGdZ5{KO3nkwd1jgiy4XMqo{O?XyUN~# zWi`a@nnQ|7sWjAymXI2bqwb<-@r{cMb zxRB_FnZ(b-I*u;D{CIB#%y^uU32+R1G*n7eJ*#l)UNPxDTxDOz5~u$wLd|LL1rcf| z)swPY%N5KJjY5)~dSWHqe1d%_PV)k|^#Zl}qWs{MGXmHBBD}og`TqWyB3^j9-<7wi z|7}5jmH^#k*t|Z0M5LIy62ESylcjvYKE2 z9|>VZIHH{sj^K}n3kgTQEJfqpBD5CFNIP^pm$u>mR9ZtZ|J)}Z4Z!9AbsK-6#|aOm z8wj!B@XPXN7|gtINPd;J%!R=k8e-PzQ`r4#DeXpH;DaYqvfs8U-1s}C#TZoZq>3DE z+fEd^t633_7*2=9h)p@>A5-$DAsY%!gu;cK6$!?0H|2ilfTXH~QH-X5vIMbZJZAFZ z&kddkkD2s<(nN>T)EsGz13n5U_h97IS*>i$z(R`QvoxKM=cnE3Nc zje%CJRMszS3`@D9OJtfyjg7zY+NRrh1N@+xOowNxl})yWF-rBxv5+3A#HlrS1-Ri<4gPu&e}yIotmo6{*95Gz@1T)-piKM-5js6z%=&KDKLG*#w)Fr2 delta 3520 zcmcgv4Qv$072cWI-Lua>XU8@e?D+QRQ3z?kE>Y`X?7K6Lp(G@r)~NzgIYSOYqY9&{ z>JL%x3?!jZgS}bBPbm?05JAx;X|Y^b3MJmdU_?{FqLwBt5v;+1s6WA}K{B%O_Ra43 zY)GT3k=iGFes=!ey!qbu-o2li*`F$jKUi5Mpd8?ZAcTqgAEkoO#oV?fIyF%ww~oq! zfaAo-a%!r0o$oZ7S(L5vo;byu;o zfoP;_3v1j+Qc8HOwG%}(-_{P0do+VSrdg~&8zfff(7;9=L#?k@(QlI;eIx2-eYh;qGHdXnr}!@Ih%@*OK2c&*|s2t-?!~i8zs(* zULP-~%GQZaoHs%Y*Px7JJ5G6NV;k2WohD%0a zG$j|OgKFOoEfFGV7bD&r;gil=wtf5LaOXqXaAYy*)hg>}6Q(^;zl{*>&-KbzplwjB(%w1oH9E_1j&T5F*6b0XGA!-n2YGeF5MQ3D zg-2JRIxmk-s8cRFqX;rle&sw_pr-DF2MF;I8EOfskV;5Xlb}Zl+0Iywq4ZS64svM9 za%Ne+YKk1At&U>)Y9fu!fVvv;V}06X+D-Awha8=Ahy{^|ysXs4m#aU=mm?!Kf!8B) z70kFyzXZJr;(?DMh zQLpu0y*esiOuLX-)95}2j+m1EK^IxZR5Pk4_K{s>aLb}42j`1>6!_~B*{7Qpsa7Wa zsoDBp`xERUwBqyJ#*=>*U31cNV2sekp5DGwwFw~sAxizE57tupgW~=-=1v-2$B3LB9*7``KF6EQMnaOF3|$6?tQCP%2f; za=7^%-K?6;`pM^Mz7KVM)!VUyWaS3omfi) zg$S_9hM_5h4aP}Y3_}qydtn?^xs#s99eS1>dLH$28uIuB-%x1h1U+j5;gaHBz7FM@ z`*KcuDjR$9IgwAos^d6aJSUAR-0_o3w~?u@_g$)u3Vn#bzq|cm?1vq=1z-oRK(9<4 zr$LhaU$ZwV>q2i0Xnk}&{Jw#Fmc)Z_>;x?ebS8Xb!^nl4b2<6qWsudKEAdD2jX-BV z4IqQhFF@LKC-B*V?SWK~K2+>jEImKO_rP7CE5@efIUoI4j^li8_Kg`fe+FLNz$&4? zpH^c=(Q%5FkX{&wh+pYxU%rUx&;E|qc{7tUF$BJSo<6RcT|9^+Bpz9C`Wz8DFR&~p zkjQai#IkM8AC18GELw(p!;2P;!8*xBf3X`>rec2)<5;SIkAK1PwQFHt=GXxL?uEC) z;xxC#qYOsBTsV7@&X{zJYMn&b&y)#h7Q_B#7EsMFc-FC~YTgI!>)0Er*_QT%dpV64 zyZHUEf#_g7#r(zTxQBM#%FNWS>cw1tu2!|Q2Ij|Dp{EUvh}MV37;F4og9k7VbHb)g z7Q(Fo$l5utKj(Ew8jz$Pft?Aq1vW`^=>$m( zP8wEOZ2~VnC2r6@ZCs|BbDaznHpaxO6L0YDWFqm|jNk=7KQK6JZeg%~USQSU z=$fX3$>ak(vq`?0#B5ynz?;22C}ihBU_iVVLIFvJh5<2nSN4;O;k%G$JDb3YVtRb5 zF|3;Nc(x(K=8q5jL6f$ds&JhmA71$wqf||;~7>loW3GGs+#L%o`xb{ z8T3(3177&!pj4PnRvZ%M+1C}K|KTeBdO;sXSp(22am|Br(|FqWpX*rI4u1O DlzQhW diff --git a/String.subproj/CFCharacterSetPriv.h b/CFCharacterSetPriv.h similarity index 88% rename from String.subproj/CFCharacterSetPriv.h rename to CFCharacterSetPriv.h index d343c69..bb36bae 100644 --- a/String.subproj/CFCharacterSetPriv.h +++ b/CFCharacterSetPriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,17 +21,15 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFCharacterSetPriv.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ -#if !defined(__COREFOUNDATION_CFCHARACTERSET_PRIV__) -#define __COREFOUNDATION_CFCHARACTERSET_PRIV__ 1 +#if !defined(__COREFOUNDATION_CFCHARACTERSETPRIV__) +#define __COREFOUNDATION_CFCHARACTERSETPRIV__ 1 #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN #if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED /*! @@ -73,12 +71,14 @@ CF_EXPORT Boolean CFCharacterSetIsSurrogatePairMember(CFCharacterSetRef theSet, /* Keyed-coding support */ -typedef enum { +enum { kCFCharacterSetKeyedCodingTypeBitmap = 1, kCFCharacterSetKeyedCodingTypeBuiltin = 2, kCFCharacterSetKeyedCodingTypeRange = 3, - kCFCharacterSetKeyedCodingTypeString = 4 -} CFCharacterSetKeyedCodingType; + kCFCharacterSetKeyedCodingTypeString = 4, + kCFCharacterSetKeyedCodingTypeBuiltinAndBitmap = 5 +}; +typedef CFIndex CFCharacterSetKeyedCodingType; CF_EXPORT CFCharacterSetKeyedCodingType _CFCharacterSetGetKeyedCodingType(CFCharacterSetRef cset); CF_EXPORT CFCharacterSetPredefinedSet _CFCharacterSetGetKeyedCodingBuiltinType(CFCharacterSetRef cset); @@ -87,8 +87,7 @@ CF_EXPORT CFStringRef _CFCharacterSetCreateKeyedCodingString(CFCharacterSetRef c CF_EXPORT bool _CFCharacterSetIsInverted(CFCharacterSetRef cset); CF_EXPORT void _CFCharacterSetSetIsInverted(CFCharacterSetRef cset, bool flag); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END + +#endif /* ! __COREFOUNDATION_CFCHARACTERSETPRIV__ */ -#endif /* !__COREFOUNDATION_CFCHARACTERSET_PRIV__ */ diff --git a/Stream.subproj/CFConcreteStreams.c b/CFConcreteStreams.c similarity index 83% rename from Stream.subproj/CFConcreteStreams.c rename to CFConcreteStreams.c index cbd4ad5..e71ca10 100644 --- a/Stream.subproj/CFConcreteStreams.c +++ b/CFConcreteStreams.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -25,22 +25,26 @@ Responsibility: Becky Willrich */ -#include +#define _DARWIN_UNLIMITED_SELECT 1 + +#include "CFStreamInternal.h" +#include "CFInternal.h" +#include "CFPriv.h" +#include +#include #include -#include #include #include #include -#include -#include "CFStream.h" -#include "CFStreamPriv.h" -#include "CFInternal.h" -#include "CFUtilitiesPriv.h" +#if DEPLOYMENT_TARGET_MACOSX +#include +#include +#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 !defined(__WIN32__) +#if DEPLOYMENT_TARGET_MACOSX #define REAL_FILE_SCHEDULING (1) #endif @@ -48,22 +52,23 @@ #define SCHEDULE_AFTER_READ (1) #define APPEND (3) #define AT_EOF (4) +#define USE_RUNLOOP_ARRAY (5) + /* File callbacks */ typedef struct { - CFURLRef url; - int fd; + CFURLRef url; + int fd; #ifdef REAL_FILE_SCHEDULING union { - CFSocketRef sock; // socket created once we open and have an fd - CFMutableArrayRef rlArray; // scheduling information prior to open + CFSocketRef sock; // socket created once we open and have an fd + CFMutableArrayRef rlArray; // scheduling information prior to open } rlInfo; // If fd > 0, sock exists. Otherwise, rlArray. #else - uint16_t scheduled; // ref count of how many times we've been scheduled + uint16_t scheduled; // ref count of how many times we've been scheduled #endif - CFOptionFlags flags; - - off_t offset; + CFOptionFlags flags; + off_t offset; } _CFFileStreamContext; @@ -95,11 +100,6 @@ static void constructCFSocket(_CFFileStreamContext *fileStream, Boolean forRead, static Boolean constructFD(_CFFileStreamContext *fileStream, CFStreamError *error, Boolean forRead, struct _CFStream *stream) { UInt8 path[1024]; int flags = forRead ? O_RDONLY : (O_CREAT | O_TRUNC | O_WRONLY); -#if defined(__WIN32__) - flags |= (_O_BINARY|_O_NOINHERIT); -#endif - -__CFSetNastyFile(fileStream->url); if (CFURLGetFileSystemRepresentation(fileStream->url, TRUE, path, 1024) == FALSE) { error->error = ENOENT; @@ -112,7 +112,7 @@ __CFSetNastyFile(fileStream->url); } do { - fileStream->fd = open(path, flags, 0666); + fileStream->fd = open((const char *)path, flags, 0666); if (fileStream->fd < 0) break; @@ -129,6 +129,7 @@ __CFSetNastyFile(fileStream->url); return TRUE; } while (1); + __CFBitSet(fileStream->flags, USE_RUNLOOP_ARRAY); error->error = errno; error->domain = kCFStreamErrorDomainPOSIX; @@ -137,27 +138,28 @@ __CFSetNastyFile(fileStream->url); static Boolean fileOpen(struct _CFStream *stream, CFStreamError *errorCode, Boolean *openComplete, void *info) { _CFFileStreamContext *ctxt = (_CFFileStreamContext *)info; - if (ctxt->fd >= 0) { - // Open already occurred - errorCode->error = 0; - *openComplete = TRUE; - return TRUE; - } Boolean forRead = (CFGetTypeID(stream) == CFReadStreamGetTypeID()); - if (constructFD(ctxt, errorCode, forRead, stream)) { - *openComplete = TRUE; + *openComplete = TRUE; + if (ctxt->url) { + if (constructFD(ctxt, errorCode, forRead, stream)) { #ifndef REAL_FILE_SCHEDULING - if (ctxt->scheduled > 0) { - if (forRead) - CFReadStreamSignalEvent((CFReadStreamRef)stream, kCFStreamEventHasBytesAvailable, NULL); - else - CFWriteStreamSignalEvent((CFWriteStreamRef)stream, kCFStreamEventCanAcceptBytes, NULL); + if (ctxt->scheduled > 0) { + if (forRead) + CFReadStreamSignalEvent((CFReadStreamRef)stream, kCFStreamEventHasBytesAvailable, NULL); + else + CFWriteStreamSignalEvent((CFWriteStreamRef)stream, kCFStreamEventCanAcceptBytes, NULL); + } +#endif + return TRUE; + } else { + return FALSE; } +#ifdef REAL_FILE_SCHEDULING + } else if (ctxt->rlInfo.rlArray != NULL) { + constructCFSocket(ctxt, forRead, stream); #endif - return TRUE; - } else { - return FALSE; } + return TRUE; } __private_extern__ CFIndex fdRead(int fd, UInt8 *buffer, CFIndex bufferLength, CFStreamError *errorCode, Boolean *atEOF) { @@ -333,7 +335,7 @@ static void fileSchedule(struct _CFStream *stream, CFRunLoopRef runLoop, CFStrin return; } #ifdef REAL_FILE_SCHEDULING - if (fileStream->fd < 0) { + if (status == kCFStreamStatusNotOpen) { if (!fileStream->rlInfo.rlArray) { fileStream->rlInfo.rlArray = CFArrayCreateMutable(CFGetAllocator(stream), 0, &kCFTypeArrayCallBacks); } @@ -362,7 +364,9 @@ static void fileSchedule(struct _CFStream *stream, CFRunLoopRef runLoop, CFStrin static void fileUnschedule(struct _CFStream *stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info) { _CFFileStreamContext *fileStream = (_CFFileStreamContext *)info; #ifdef REAL_FILE_SCHEDULING - if (fileStream->fd < 0) { + Boolean isReadStream = (CFGetTypeID(stream) == CFReadStreamGetTypeID()); + CFStreamStatus status = isReadStream ? CFReadStreamGetStatus((CFReadStreamRef)stream) : CFWriteStreamGetStatus((CFWriteStreamRef)stream); + if (status == kCFStreamStatusNotOpen) { // Not opened yet if (fileStream->rlInfo.rlArray) { CFMutableArrayRef runloops = fileStream->rlInfo.rlArray; @@ -376,9 +380,22 @@ static void fileUnschedule(struct _CFStream *stream, CFRunLoopRef runLoop, CFStr } } } else if (fileStream->rlInfo.sock) { - CFRunLoopSourceRef sockSource = CFSocketCreateRunLoopSource(CFGetAllocator(stream), fileStream->rlInfo.sock, 0); - CFRunLoopRemoveSource(runLoop, sockSource, runLoopMode); - CFRelease(sockSource); + 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 + CFMutableArrayRef runloops = fileStream->rlInfo.rlArray; + CFIndex i, c; + for (i = 0, c = CFArrayGetCount(runloops); i+1 < c; i += 2) { + if (CFEqual(CFArrayGetValueAtIndex(runloops, i), runLoop) && CFEqual(CFArrayGetValueAtIndex(runloops, i+1), runLoopMode)) { + CFArrayRemoveValueAtIndex(runloops, i); + CFArrayRemoveValueAtIndex(runloops, i); + break; + } + } + } else { + CFRunLoopSourceRef sockSource = CFSocketCreateRunLoopSource(CFGetAllocator(stream), fileStream->rlInfo.sock, 0); + CFRunLoopRemoveSource(runLoop, sockSource, runLoopMode); + CFRelease(sockSource); + } } #else if (fileStream->scheduled > 0) @@ -442,9 +459,12 @@ static Boolean fileSetProperty(struct _CFStream *stream, CFStringRef prop, CFTyp static void *fileCreate(struct _CFStream *stream, void *info) { _CFFileStreamContext *ctxt = (_CFFileStreamContext *)info; - _CFFileStreamContext *newCtxt = CFAllocatorAllocate(CFGetAllocator(stream), sizeof(_CFFileStreamContext), 0); + _CFFileStreamContext *newCtxt = (_CFFileStreamContext *)CFAllocatorAllocate(CFGetAllocator(stream), sizeof(_CFFileStreamContext), 0); if (!newCtxt) return NULL; - newCtxt->url = CFRetain(ctxt->url); + newCtxt->url = ctxt->url; + if (newCtxt->url) { + CFRetain(newCtxt->url); + } newCtxt->fd = ctxt->fd; #ifdef REAL_FILE_SCHEDULING newCtxt->rlInfo.sock = NULL; @@ -471,13 +491,20 @@ static void fileFinalize(struct _CFStream *stream, void *info) { CFRelease(ctxt->rlInfo.rlArray); #endif } - CFRelease(ctxt->url); + if (ctxt->url) { + CFRelease(ctxt->url); + } CFAllocatorDeallocate(CFGetAllocator(stream), ctxt); } static CFStringRef fileCopyDescription(struct _CFStream *stream, void *info) { // This needs work - return CFCopyDescription(((_CFFileStreamContext *)info)->url); + _CFFileStreamContext *ctxt = (_CFFileStreamContext *)info; + if (ctxt->url) { + return CFCopyDescription(ctxt->url); + } else { + return CFStringCreateWithFormat(CFGetAllocator(stream), NULL, CFSTR("fd = %d"), ctxt->fd); + } } /* CFData stream callbacks */ @@ -663,7 +690,7 @@ static CFPropertyListRef dataCopyProperty(struct _CFStream *stream, CFStringRef size += buf->length; } if (size == 0) return NULL; - bytes = CFAllocatorAllocate(alloc, size, 0); + bytes = (UInt8 *)CFAllocatorAllocate(alloc, size, 0); currByte = bytes; for (buf = dataStream->firstBuf; buf != NULL; buf = buf->next) { memmove(currByte, buf->bytes, buf->length); @@ -676,7 +703,7 @@ static void *readDataCreate(struct _CFStream *stream, void *info) { _CFReadDataStreamContext *ctxt = (_CFReadDataStreamContext *)info; _CFReadDataStreamContext *newCtxt = (_CFReadDataStreamContext *)CFAllocatorAllocate(CFGetAllocator(stream), sizeof(_CFReadDataStreamContext), 0); if (!newCtxt) return NULL; - newCtxt->data = CFRetain(ctxt->data); + newCtxt->data = (CFDataRef)CFRetain(ctxt->data); newCtxt->loc = CFDataGetBytePtr(newCtxt->data); newCtxt->scheduled = FALSE; return (void *)newCtxt; @@ -698,7 +725,7 @@ static void *writeDataCreate(struct _CFStream *stream, void *info) { if (ctxt->bufferAllocator != kCFAllocatorNull) { if (ctxt->bufferAllocator == NULL) ctxt->bufferAllocator = CFAllocatorGetDefault(); CFRetain(ctxt->bufferAllocator); - newCtxt = CFAllocatorAllocate(CFGetAllocator(stream), sizeof(_CFWriteDataStreamContext) + sizeof(_CFStreamByteBuffer) + BUF_SIZE, 0); + newCtxt = (_CFWriteDataStreamContext *)CFAllocatorAllocate(CFGetAllocator(stream), sizeof(_CFWriteDataStreamContext) + sizeof(_CFStreamByteBuffer) + BUF_SIZE, 0); newCtxt->firstBuf = (_CFStreamByteBuffer *)(newCtxt + 1); newCtxt->firstBuf->bytes = (UInt8 *)(newCtxt->firstBuf + 1); newCtxt->firstBuf->capacity = BUF_SIZE; @@ -736,10 +763,10 @@ static void writeDataFinalize(struct _CFStream *stream, void *info) { } static CFStringRef writeDataCopyDescription(struct _CFStream *stream, void *info) { - return CFStringCreateWithFormat(NULL, NULL, CFSTR(""), (int)info); + return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR(""), info); } -static const struct _CFStreamCallBacks fileCallBacks = {1, fileCreate, fileFinalize, fileCopyDescription, fileOpen, NULL, fileRead, NULL, fileCanRead, fileWrite, fileCanWrite, fileClose, fileCopyProperty, fileSetProperty, NULL, fileSchedule, fileUnschedule}; +static const struct _CFStreamCallBacksV1 fileCallBacks = {1, fileCreate, fileFinalize, fileCopyDescription, fileOpen, NULL, fileRead, NULL, fileCanRead, fileWrite, fileCanWrite, fileClose, fileCopyProperty, fileSetProperty, NULL, fileSchedule, fileUnschedule}; static struct _CFStream *_CFStreamCreateWithFile(CFAllocatorRef alloc, CFURLRef fileURL, Boolean forReading) { _CFFileStreamContext fileContext; @@ -751,7 +778,7 @@ static struct _CFStream *_CFStreamCreateWithFile(CFAllocatorRef alloc, CFURLRef CFRelease(scheme); fileContext.url = fileURL; fileContext.fd = -1; - return _CFStreamCreateWithConstantCallbacks(alloc, &fileContext, &fileCallBacks, forReading); + return _CFStreamCreateWithConstantCallbacks(alloc, &fileContext, (struct _CFStreamCallBacks *)(&fileCallBacks), forReading); } CF_EXPORT CFReadStreamRef CFReadStreamCreateWithFile(CFAllocatorRef alloc, CFURLRef fileURL) { @@ -762,18 +789,45 @@ CF_EXPORT CFWriteStreamRef CFWriteStreamCreateWithFile(CFAllocatorRef alloc, CFU return (CFWriteStreamRef)_CFStreamCreateWithFile(alloc, fileURL, FALSE); } -static const struct _CFStreamCallBacks readDataCallBacks = {1, readDataCreate, readDataFinalize, readDataCopyDescription, readDataOpen, NULL, dataRead, dataGetBuffer, dataCanRead, NULL, NULL, NULL, NULL, NULL, NULL, readDataSchedule, NULL}; -static const struct _CFStreamCallBacks writeDataCallBacks = {1, writeDataCreate, writeDataFinalize, writeDataCopyDescription, writeDataOpen, NULL, NULL, NULL, NULL, dataWrite, dataCanWrite, NULL, dataCopyProperty, NULL, NULL, writeDataSchedule, NULL}; +CFReadStreamRef _CFReadStreamCreateFromFileDescriptor(CFAllocatorRef alloc, int fd) { + _CFFileStreamContext fileContext; + fileContext.url = NULL; + fileContext.fd = fd; + return (CFReadStreamRef)_CFStreamCreateWithConstantCallbacks(alloc, &fileContext, (struct _CFStreamCallBacks *)(&fileCallBacks), TRUE); +} + +CFWriteStreamRef _CFWriteStreamCreateFromFileDescriptor(CFAllocatorRef alloc, int fd) { + _CFFileStreamContext fileContext; + fileContext.url = NULL; + fileContext.fd = fd; + return (CFWriteStreamRef)_CFStreamCreateWithConstantCallbacks(alloc, &fileContext, (struct _CFStreamCallBacks *)(&fileCallBacks), FALSE); +} + + + +static const struct _CFStreamCallBacksV1 readDataCallBacks = {1, readDataCreate, readDataFinalize, readDataCopyDescription, readDataOpen, NULL, dataRead, dataGetBuffer, dataCanRead, NULL, NULL, NULL, NULL, NULL, NULL, readDataSchedule, NULL}; +static const struct _CFStreamCallBacksV1 writeDataCallBacks = {1, writeDataCreate, writeDataFinalize, writeDataCopyDescription, writeDataOpen, NULL, NULL, NULL, NULL, dataWrite, dataCanWrite, NULL, dataCopyProperty, NULL, NULL, writeDataSchedule, NULL}; CF_EXPORT CFReadStreamRef CFReadStreamCreateWithBytesNoCopy(CFAllocatorRef alloc, const UInt8 *bytes, CFIndex length, CFAllocatorRef bytesDeallocator) { _CFReadDataStreamContext ctxt; CFReadStreamRef result; ctxt.data = CFDataCreateWithBytesNoCopy(alloc, bytes, length, bytesDeallocator); - result = (CFReadStreamRef)_CFStreamCreateWithConstantCallbacks(alloc, &ctxt, &readDataCallBacks, TRUE); + result = (CFReadStreamRef)_CFStreamCreateWithConstantCallbacks(alloc, &ctxt, (struct _CFStreamCallBacks *)(&readDataCallBacks), TRUE); CFRelease(ctxt.data); return result; } +/* This needs to be exported to make it callable from Foundation. */ +CF_EXPORT CFReadStreamRef CFReadStreamCreateWithData(CFAllocatorRef alloc, CFDataRef data) { + _CFReadDataStreamContext ctxt; + CFReadStreamRef result = NULL; + + ctxt.data = CFRetain(data); + result = (CFReadStreamRef)_CFStreamCreateWithConstantCallbacks(alloc, &ctxt, (struct _CFStreamCallBacks *)(&readDataCallBacks), TRUE); + CFRelease(data); + return result; +} + CFWriteStreamRef CFWriteStreamCreateWithBuffer(CFAllocatorRef alloc, UInt8 *buffer, CFIndex bufferCapacity) { _CFStreamByteBuffer buf; _CFWriteDataStreamContext ctxt; @@ -784,7 +838,7 @@ CFWriteStreamRef CFWriteStreamCreateWithBuffer(CFAllocatorRef alloc, UInt8 *buff ctxt.firstBuf = &buf; ctxt.currentBuf = ctxt.firstBuf; ctxt.bufferAllocator = kCFAllocatorNull; - return (CFWriteStreamRef)_CFStreamCreateWithConstantCallbacks(alloc, &ctxt, &writeDataCallBacks, FALSE); + return (CFWriteStreamRef)_CFStreamCreateWithConstantCallbacks(alloc, &ctxt, (struct _CFStreamCallBacks *)(&writeDataCallBacks), FALSE); } CF_EXPORT CFWriteStreamRef CFWriteStreamCreateWithAllocatedBuffers(CFAllocatorRef alloc, CFAllocatorRef bufferAllocator) { @@ -792,7 +846,8 @@ CF_EXPORT CFWriteStreamRef CFWriteStreamCreateWithAllocatedBuffers(CFAllocatorRe ctxt.firstBuf = NULL; ctxt.currentBuf = NULL; ctxt.bufferAllocator = bufferAllocator; - return (CFWriteStreamRef)_CFStreamCreateWithConstantCallbacks(alloc, &ctxt, &writeDataCallBacks, FALSE); + return (CFWriteStreamRef)_CFStreamCreateWithConstantCallbacks(alloc, &ctxt, (struct _CFStreamCallBacks *)(&writeDataCallBacks), FALSE); } #undef BUF_SIZE + diff --git a/Collections.subproj/CFData.c b/CFData.c similarity index 93% rename from Collections.subproj/CFData.c rename to CFData.c index 449043c..b8fc681 100644 --- a/Collections.subproj/CFData.c +++ b/CFData.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,7 +26,7 @@ */ #include -#include "CFUtilitiesPriv.h" +#include "CFPriv.h" #include "CFInternal.h" #include @@ -41,11 +41,11 @@ struct __CFData { /* Bits 3-2 are used for mutability variation */ CF_INLINE UInt32 __CFMutableVariety(const void *cf) { - return __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 3, 2); + return __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 2); } CF_INLINE void __CFSetMutableVariety(void *cf, UInt32 v) { - __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_info, 3, 2, v); + __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 2, v); } CF_INLINE UInt32 __CFMutableVarietyFromFlags(UInt32 flags) { @@ -90,13 +90,23 @@ CF_INLINE void __CFDataSetNumBytes(CFMutableDataRef data, CFIndex v) { CF_INLINE CFIndex __CFDataRoundUpCapacity(CFIndex capacity) { if (capacity < 16) return 16; // CF: quite probably, this doubling should slow as the data gets larger and larger; should not use strict doubling - return (1 << (CFLog2(capacity) + 1)); + return (1 << flsl(capacity)); } CF_INLINE CFIndex __CFDataNumBytesForCapacity(CFIndex capacity) { return capacity; } +static void __CFDataHandleOutOfMemory(CFTypeRef obj, CFIndex numBytes) { + CFStringRef msg = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("Attempt to allocate %ld bytes for NS/CFData failed"), numBytes); + CFBadErrorCallBack cb = _CFGetOutOfMemoryErrorCallBack(); + if (NULL == cb || !cb(obj, CFSTR("NS/CFData"), msg)) { + CFLog(kCFLogLevelCritical, CFSTR("%@"), msg); + HALT; + } + CFRelease(msg); +} + #if defined(DEBUG) CF_INLINE void __CFDataValidateRange(CFDataRef data, CFRange range, const char *func) { CFAssert2(0 <= range.location && range.location <= __CFDataLength(data), __kCFLogAssertion, "%s(): range.location index (%d) out of bounds", func, range.location); @@ -107,7 +117,7 @@ CF_INLINE void __CFDataValidateRange(CFDataRef data, CFRange range, const char * #define __CFDataValidateRange(a,r,f) #endif -static bool __CFDataEqual(CFTypeRef cf1, CFTypeRef cf2) { +static Boolean __CFDataEqual(CFTypeRef cf1, CFTypeRef cf2) { CFDataRef data1 = (CFDataRef)cf1; CFDataRef data2 = (CFDataRef)cf2; CFIndex length; @@ -118,7 +128,7 @@ static bool __CFDataEqual(CFTypeRef cf1, CFTypeRef cf2) { static CFHashCode __CFDataHash(CFTypeRef cf) { CFDataRef data = (CFDataRef)cf; - return CFHashBytes(data->_bytes, __CFMin(__CFDataLength(data), 16)); + return CFHashBytes(data->_bytes, __CFMin(__CFDataLength(data), 80)); } static CFStringRef __CFDataCopyDescription(CFTypeRef cf) { @@ -156,7 +166,7 @@ enum { static void __CFDataDeallocate(CFTypeRef cf) { CFMutableDataRef data = (CFMutableDataRef)cf; - CFAllocatorRef allocator = CFGetAllocator(data); + CFAllocatorRef allocator = __CFGetAllocator(data); switch (__CFMutableVariety(data)) { case kCFMutable: _CFAllocatorDeallocateGC(allocator, data->_bytes); @@ -187,7 +197,7 @@ static const CFRuntimeClass __CFDataClass = { NULL, // init NULL, // copy __CFDataDeallocate, - (void *)__CFDataEqual, + __CFDataEqual, __CFDataHash, NULL, // __CFDataCopyDescription @@ -230,7 +240,7 @@ static CFMutableDataRef __CFDataInit(CFAllocatorRef allocator, CFOptionFlags fla // GC: if allocated in the collectable zone, mark the object as needing to be scanned. if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) auto_zone_set_layout_type(__CFCollectableZone, memory, AUTO_MEMORY_SCANNED); // assume that allocators give 16-byte aligned memory back -- it is their responsibility - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, memory, memory->_bytes, _CFAllocatorAllocateGC(allocator, __CFDataNumBytes(memory) * sizeof(uint8_t), AUTO_MEMORY_UNSCANNED)); + CF_WRITE_BARRIER_BASE_ASSIGN(allocator, memory, memory->_bytes, _CFAllocatorAllocateGC(allocator, __CFDataNumBytes(memory) * sizeof(uint8_t), 0)); if (__CFOASafe) __CFSetLastAllocationEventName(memory->_bytes, "CFData (store)"); if (NULL == memory->_bytes) { CFRelease(memory); @@ -255,7 +265,7 @@ static CFMutableDataRef __CFDataInit(CFAllocatorRef allocator, CFOptionFlags fla __CFDataSetNumBytes(memory, __CFDataNumBytesForCapacity(capacity)); if (bytesDeallocator != NULL) { CF_WRITE_BARRIER_BASE_ASSIGN(allocator, memory, memory->_bytes, (uint8_t *)bytes); - memory->_bytesDeallocator = CFRetain(bytesDeallocator); + memory->_bytesDeallocator = (CFAllocatorRef)CFRetain(bytesDeallocator); __CFDataSetNumBytesUsed(memory, length); __CFDataSetLength(memory, length); } else { @@ -277,9 +287,6 @@ CFDataRef CFDataCreate(CFAllocatorRef allocator, const uint8_t *bytes, CFIndex l CFDataRef CFDataCreateWithBytesNoCopy(CFAllocatorRef allocator, const uint8_t *bytes, CFIndex length, CFAllocatorRef bytesDeallocator) { CFAssert1((0 == length || bytes != NULL), __kCFLogAssertion, "%s(): bytes pointer cannot be NULL if length is non-zero", __PRETTY_FUNCTION__); if (NULL == bytesDeallocator) bytesDeallocator = __CFGetDefaultAllocator(); - if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { - bytesDeallocator = NULL; - } return __CFDataInit(allocator, kCFImmutable, length, bytes, length, bytesDeallocator); } @@ -325,9 +332,10 @@ static void __CFDataGrow(CFMutableDataRef data, CFIndex numNewValues) { CFAllocatorRef allocator = CFGetAllocator(data); __CFDataSetCapacity(data, capacity); __CFDataSetNumBytes(data, __CFDataNumBytesForCapacity(capacity)); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, data, data->_bytes, _CFAllocatorReallocateGC(allocator, data->_bytes, __CFDataNumBytes(data) * sizeof(uint8_t), AUTO_MEMORY_UNSCANNED)); + void *bytes = _CFAllocatorReallocateGC(allocator, data->_bytes, __CFDataNumBytes(data) * sizeof(uint8_t), 0); + if (NULL == bytes) __CFDataHandleOutOfMemory(data, __CFDataNumBytes(data) * sizeof(uint8_t)); + CF_WRITE_BARRIER_BASE_ASSIGN(allocator, data, data->_bytes, bytes); if (__CFOASafe) __CFSetLastAllocationEventName(data->_bytes, "CFData (store)"); - if (NULL == data->_bytes) HALT; } void CFDataSetLength(CFMutableDataRef data, CFIndex length) { diff --git a/Collections.subproj/CFData.h b/CFData.h similarity index 92% rename from Collections.subproj/CFData.h rename to CFData.h index beaa349..b53d8bd 100644 --- a/Collections.subproj/CFData.h +++ b/CFData.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFData.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFDATA__) @@ -29,9 +29,7 @@ #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN typedef const struct __CFData * CFDataRef; typedef struct __CFData * CFMutableDataRef; @@ -82,9 +80,7 @@ void CFDataReplaceBytes(CFMutableDataRef theData, CFRange range, const UInt8 *ne CF_EXPORT void CFDataDeleteBytes(CFMutableDataRef theData, CFRange range); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFDATA__ */ diff --git a/NumberDate.subproj/CFDate.c b/CFDate.c similarity index 83% rename from NumberDate.subproj/CFDate.c rename to CFDate.c index 3f774f0..d47cf92 100644 --- a/NumberDate.subproj/CFDate.c +++ b/CFDate.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -33,11 +33,8 @@ #include #include "CFInternal.h" #include -#if defined(__MACH__) || defined(__LINUX__) - #include -#endif -#if defined(__WIN32__) - #include +#if DEPLOYMENT_TARGET_MACOSX +#include #endif const CFTimeInterval kCFAbsoluteTimeIntervalSince1970 = 978307200.0L; @@ -46,52 +43,45 @@ const CFTimeInterval kCFAbsoluteTimeIntervalSince1904 = 3061152000.0L; /* cjk: The Julian Date for the reference date is 2451910.5, I think, in case that's ever useful. */ -struct __CFDate { - CFRuntimeBase _base; - CFAbsoluteTime _time; /* immutable */ -}; - -#if defined(__WIN32__) -// We should export this as SPI or API to clients - 3514284 -CFAbsoluteTime _CFAbsoluteTimeFromFileTime(const FILETIME *ft) { - CFAbsoluteTime ret = (CFTimeInterval)ft->dwHighDateTime * 429.49672960; - ret += (CFTimeInterval)ft->dwLowDateTime / 10000000.0; - ret -= (11644473600.0 + kCFAbsoluteTimeIntervalSince1970); - /* seconds between 1601 and 1970, 1970 and 2001 */ - return ret; -} -#endif - -#if defined(__MACH__) || defined(__WIN32__) -static double __CFTSRRate = 0.0; +__private_extern__ double __CFTSRRate = 0.0; static double __CF1_TSRRate = 0.0; __private_extern__ int64_t __CFTimeIntervalToTSR(CFTimeInterval ti) { + if ((ti * __CFTSRRate) > INT64_MAX / 2) return (INT64_MAX / 2); return (int64_t)(ti * __CFTSRRate); } __private_extern__ CFTimeInterval __CFTSRToTimeInterval(int64_t tsr) { return (CFTimeInterval)((double)tsr * __CF1_TSRRate); } -#endif CFAbsoluteTime CFAbsoluteTimeGetCurrent(void) { CFAbsoluteTime ret; -#if defined(__MACH__) || defined(__svr4__) || defined(__hpux__) || defined(__LINUX__) +#if DEPLOYMENT_TARGET_MACOSX struct timeval tv; gettimeofday(&tv, NULL); ret = (CFTimeInterval)tv.tv_sec - kCFAbsoluteTimeIntervalSince1970; ret += (1.0E-6 * (CFTimeInterval)tv.tv_usec); -#elif defined(__WIN32__) - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - ret = _CFAbsoluteTimeFromFileTime(&ft); -#else -#error CFAbsoluteTimeGetCurrent unimplemented for this platform #endif return ret; } +__private_extern__ void __CFDateInitialize(void) { +#if DEPLOYMENT_TARGET_MACOSX + struct mach_timebase_info info; + mach_timebase_info(&info); + __CFTSRRate = (1.0E9 / (double)info.numer) * (double)info.denom; + __CF1_TSRRate = 1.0 / __CFTSRRate; +#endif + CFDateGetTypeID(); // cause side-effects +} + +#if 1 +struct __CFDate { + CFRuntimeBase _base; + CFAbsoluteTime _time; /* immutable */ +}; + static Boolean __CFDateEqual(CFTypeRef cf1, CFTypeRef cf2) { CFDateRef date1 = (CFDateRef)cf1; CFDateRef date2 = (CFDateRef)cf2; @@ -114,42 +104,25 @@ static CFTypeID __kCFDateTypeID = _kCFRuntimeNotATypeID; static const CFRuntimeClass __CFDateClass = { 0, "CFDate", - NULL, // init - NULL, // copy - NULL, // dealloc + NULL, // init + NULL, // copy + NULL, // dealloc __CFDateEqual, __CFDateHash, - NULL, // + NULL, // __CFDateCopyDescription }; -__private_extern__ void __CFDateInitialize(void) { -#if defined(__MACH__) - struct mach_timebase_info info; - mach_timebase_info(&info); - __CFTSRRate = (1.0E9 / (double)info.numer) * (double)info.denom; - __CF1_TSRRate = 1.0 / __CFTSRRate; -#endif -#if defined(__WIN32__) - LARGE_INTEGER freq; - if (!QueryPerformanceFrequency(&freq)) { - HALT; - } - __CFTSRRate = freq.QuadPart; - __CF1_TSRRate = 1.0 / __CFTSRRate; -#endif - __kCFDateTypeID = _CFRuntimeRegisterClass(&__CFDateClass); -} - CFTypeID CFDateGetTypeID(void) { + if (_kCFRuntimeNotATypeID == __kCFDateTypeID) __kCFDateTypeID = _CFRuntimeRegisterClass(&__CFDateClass); return __kCFDateTypeID; } CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at) { - CFDateRef memory; + CFDateRef memory; uint32_t size; size = sizeof(struct __CFDate) - sizeof(CFRuntimeBase); - memory = _CFRuntimeCreateInstance(allocator, __kCFDateTypeID, size, NULL); + memory = (CFDateRef)_CFRuntimeCreateInstance(allocator, CFDateGetTypeID(), size, NULL); if (NULL == memory) { return NULL; } @@ -158,26 +131,27 @@ CFDateRef CFDateCreate(CFAllocatorRef allocator, CFAbsoluteTime at) { } CFTimeInterval CFDateGetAbsoluteTime(CFDateRef date) { - CF_OBJC_FUNCDISPATCH0(__kCFDateTypeID, CFTimeInterval, date, "timeIntervalSinceReferenceDate"); + CF_OBJC_FUNCDISPATCH0(CFDateGetTypeID(), CFTimeInterval, date, "timeIntervalSinceReferenceDate"); __CFGenericValidateType(date, CFDateGetTypeID()); return date->_time; } CFTimeInterval CFDateGetTimeIntervalSinceDate(CFDateRef date, CFDateRef otherDate) { - CF_OBJC_FUNCDISPATCH1(__kCFDateTypeID, CFTimeInterval, date, "timeIntervalSinceDate:", otherDate); + CF_OBJC_FUNCDISPATCH1(CFDateGetTypeID(), CFTimeInterval, date, "timeIntervalSinceDate:", otherDate); __CFGenericValidateType(date, CFDateGetTypeID()); __CFGenericValidateType(otherDate, CFDateGetTypeID()); return date->_time - otherDate->_time; -} - +} + CFComparisonResult CFDateCompare(CFDateRef date, CFDateRef otherDate, void *context) { - CF_OBJC_FUNCDISPATCH1(__kCFDateTypeID, CFComparisonResult, date, "compare:", otherDate); + CF_OBJC_FUNCDISPATCH1(CFDateGetTypeID(), CFComparisonResult, date, "compare:", otherDate); __CFGenericValidateType(date, CFDateGetTypeID()); __CFGenericValidateType(otherDate, CFDateGetTypeID()); if (date->_time < otherDate->_time) return kCFCompareLessThan; if (date->_time > otherDate->_time) return kCFCompareGreaterThan; return kCFCompareEqualTo; } +#endif CF_INLINE int32_t __CFDoubleModToInt(double d, int32_t modulus) { int32_t result = (int32_t)(float)floor(d - floor(d / modulus) * modulus); @@ -195,31 +169,31 @@ static const uint8_t daysInMonth[16] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 3 static const uint16_t daysBeforeMonth[16] = {0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365, 0, 0}; static const uint16_t daysAfterMonth[16] = {365, 334, 306, 275, 245, 214, 184, 153, 122, 92, 61, 31, 0, 0, 0, 0}; -static inline bool isleap(int32_t year) { - int32_t y = (year + 1) % 400; /* correct to nearest multiple-of-400 year, then find the remainder */ +CF_INLINE bool isleap(int64_t year) { + int64_t y = (year + 1) % 400; /* correct to nearest multiple-of-400 year, then find the remainder */ if (y < 0) y = -y; return (0 == (y & 3) && 100 != y && 200 != y && 300 != y); } /* year arg is absolute year; Gregorian 2001 == year 0; 2001/1/1 = absolute date 0 */ -static inline uint8_t __CFDaysInMonth(int8_t month, int32_t year, bool leap) { +CF_INLINE uint8_t __CFDaysInMonth(int8_t month, int64_t year, bool leap) { return daysInMonth[month] + (2 == month && leap); } /* year arg is absolute year; Gregorian 2001 == year 0; 2001/1/1 = absolute date 0 */ -static inline uint16_t __CFDaysBeforeMonth(int8_t month, int32_t year, bool leap) { +CF_INLINE uint16_t __CFDaysBeforeMonth(int8_t month, int64_t year, bool leap) { return daysBeforeMonth[month] + (2 < month && leap); } /* year arg is absolute year; Gregorian 2001 == year 0; 2001/1/1 = absolute date 0 */ -static inline uint16_t __CFDaysAfterMonth(int8_t month, int32_t year, bool leap) { +CF_INLINE uint16_t __CFDaysAfterMonth(int8_t month, int64_t year, bool leap) { return daysAfterMonth[month] + (month < 2 && leap); } /* year arg is absolute year; Gregorian 2001 == year 0; 2001/1/1 = absolute date 0 */ -static void __CFYMDFromAbsolute(int32_t absolute, int32_t *year, int8_t *month, int8_t *day) { - int32_t b = absolute / 146097; // take care of as many multiples of 400 years as possible - int32_t y = b * 400; +static void __CFYMDFromAbsolute(int64_t absolute, int64_t *year, int8_t *month, int8_t *day) { + int64_t b = absolute / 146097; // take care of as many multiples of 400 years as possible + int64_t y = b * 400; uint16_t ydays; absolute -= b * 146097; while (absolute < 0) { @@ -245,10 +219,10 @@ static void __CFYMDFromAbsolute(int32_t absolute, int32_t *year, int8_t *month, } /* year arg is absolute year; Gregorian 2001 == year 0; 2001/1/1 = absolute date 0 */ -static double __CFAbsoluteFromYMD(int32_t year, int8_t month, int8_t day) { +static double __CFAbsoluteFromYMD(int64_t year, int8_t month, int8_t day) { double absolute = 0.0; - int32_t idx; - int32_t b = year / 400; // take care of as many multiples of 400 years as possible + int64_t idx; + int64_t b = year / 400; // take care of as many multiples of 400 years as possible absolute += b * 146097.0; year -= b * 400; if (year < 0) { @@ -270,7 +244,7 @@ Boolean CFGregorianDateIsValid(CFGregorianDate gdate, CFOptionFlags unitFlags) { if ((unitFlags & kCFGregorianUnitsHours) && (gdate.hour < 0 || 23 < gdate.hour)) return false; if ((unitFlags & kCFGregorianUnitsMinutes) && (gdate.minute < 0 || 59 < gdate.minute)) return false; if ((unitFlags & kCFGregorianUnitsSeconds) && (gdate.second < 0.0 || 60.0 <= gdate.second)) return false; - if ((unitFlags & kCFGregorianUnitsDays) && (__CFDaysInMonth(gdate.month, gdate.year - 2001, isleap(gdate.year - 2001)) < gdate.day)) return false; + if ((unitFlags & kCFGregorianUnitsDays) && (unitFlags & kCFGregorianUnitsMonths) && (unitFlags & kCFGregorianUnitsYears) && (__CFDaysInMonth(gdate.month, gdate.year - 2001, isleap(gdate.year - 2001)) < gdate.day)) return false; return true; } @@ -292,21 +266,23 @@ CFAbsoluteTime CFGregorianDateGetAbsoluteTime(CFGregorianDate gdate, CFTimeZoneR CFGregorianDate CFAbsoluteTimeGetGregorianDate(CFAbsoluteTime at, CFTimeZoneRef tz) { CFGregorianDate gdate; - int32_t absolute, year; + int64_t absolute, year; int8_t month, day; CFAbsoluteTime fixedat; if (NULL != tz) { __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); } fixedat = at + (NULL != tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0); - absolute = (int32_t)(float)floor(fixedat / 86400.0); + absolute = (int64_t)floor(fixedat / 86400.0); __CFYMDFromAbsolute(absolute, &year, &month, &day); + if (INT32_MAX - 2001 < year) year = INT32_MAX - 2001; gdate.year = year + 2001; gdate.month = month; gdate.day = day; gdate.hour = __CFDoubleModToInt(floor(fixedat / 3600.0), 24); gdate.minute = __CFDoubleModToInt(floor(fixedat / 60.0), 60); gdate.second = __CFDoubleMod(fixedat, 60); + if (0.0 == gdate.second) gdate.second = 0.0; // stomp out possible -0.0 return gdate; } @@ -411,7 +387,7 @@ CFGregorianUnits CFAbsoluteTimeGetDifferenceAsGregorianUnits(CFAbsoluteTime at1, /* Successive approximation: years, then months, then days, then hours, then minutes. */ for (idx = 0; idx < 5; idx++) { if (unitFlags & (1 << idx)) { - ((int32_t *)&units)[idx] = -3 * incr + (at1 - atnew) / seconds[idx]; + ((int32_t *)&units)[idx] = -3 * incr + (int32_t)((at1 - atnew) / seconds[idx]); do { atold = atnew; ((int32_t *)&units)[idx] += incr; @@ -424,46 +400,47 @@ CFGregorianUnits CFAbsoluteTimeGetDifferenceAsGregorianUnits(CFAbsoluteTime at1, if (unitFlags & kCFGregorianUnitsSeconds) { units.seconds = at1 - atnew; } + if (0.0 == units.seconds) units.seconds = 0.0; // stomp out possible -0.0 return units; } SInt32 CFAbsoluteTimeGetDayOfWeek(CFAbsoluteTime at, CFTimeZoneRef tz) { - int32_t absolute; + int64_t absolute; CFAbsoluteTime fixedat; if (NULL != tz) { __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); } fixedat = at + (NULL != tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0); - absolute = (int32_t)(float)floor(fixedat / 86400.0); + absolute = (int64_t)floor(fixedat / 86400.0); return (absolute < 0) ? ((absolute + 1) % 7 + 7) : (absolute % 7 + 1); /* Monday = 1, etc. */ } SInt32 CFAbsoluteTimeGetDayOfYear(CFAbsoluteTime at, CFTimeZoneRef tz) { CFAbsoluteTime fixedat; - int32_t absolute, year; + int64_t absolute, year; int8_t month, day; if (NULL != tz) { __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); } fixedat = at + (NULL != tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0); - absolute = (int32_t)(float)floor(fixedat / 86400.0); + absolute = (int64_t)floor(fixedat / 86400.0); __CFYMDFromAbsolute(absolute, &year, &month, &day); return __CFDaysBeforeMonth(month, year, isleap(year)) + day; } /* "the first week of a year is the one which includes the first Thursday" (ISO 8601) */ SInt32 CFAbsoluteTimeGetWeekOfYear(CFAbsoluteTime at, CFTimeZoneRef tz) { - int32_t absolute, year; + int64_t absolute, year; int8_t month, day; CFAbsoluteTime fixedat; if (NULL != tz) { __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); } fixedat = at + (NULL != tz ? CFTimeZoneGetSecondsFromGMT(tz, at) : 0.0); - absolute = (int32_t)(float)floor(fixedat / 86400.0); + absolute = (int64_t)floor(fixedat / 86400.0); __CFYMDFromAbsolute(absolute, &year, &month, &day); double absolute0101 = __CFAbsoluteFromYMD(year, 1, 1); - int32_t dow0101 = __CFDoubleModToInt(absolute0101, 7) + 1; + int64_t dow0101 = __CFDoubleModToInt(absolute0101, 7) + 1; /* First three and last three days of a year can end up in a week of a different year */ if (1 == month && day < 4) { if ((day < 4 && 5 == dow0101) || (day < 3 && 6 == dow0101) || (day < 2 && 7 == dow0101)) { @@ -472,12 +449,12 @@ SInt32 CFAbsoluteTimeGetWeekOfYear(CFAbsoluteTime at, CFTimeZoneRef tz) { } if (12 == month && 28 < day) { double absolute20101 = __CFAbsoluteFromYMD(year + 1, 1, 1); - int32_t dow20101 = __CFDoubleModToInt(absolute20101, 7) + 1; + int64_t dow20101 = __CFDoubleModToInt(absolute20101, 7) + 1; if ((28 < day && 4 == dow20101) || (29 < day && 3 == dow20101) || (30 < day && 2 == dow20101)) { return 1; } } - /* Days into year, plus a week-shifting correction, divided by 7. First week is #1. */ + /* Days into year, plus a week-shifting correction, divided by 7. First week is 1. */ return (__CFDaysBeforeMonth(month, year, isleap(year)) + day + (dow0101 - 11) % 7 + 2) / 7 + 1; } diff --git a/NumberDate.subproj/CFDate.h b/CFDate.h similarity index 90% rename from NumberDate.subproj/CFDate.h rename to CFDate.h index 35d379a..4808f4b 100644 --- a/NumberDate.subproj/CFDate.h +++ b/CFDate.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFDate.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFDATE__) @@ -29,9 +29,7 @@ #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN typedef double CFTimeInterval; typedef CFTimeInterval CFAbsoluteTime; @@ -83,19 +81,16 @@ typedef struct { double seconds; } CFGregorianUnits; -typedef enum { +enum { kCFGregorianUnitsYears = (1 << 0), kCFGregorianUnitsMonths = (1 << 1), kCFGregorianUnitsDays = (1 << 2), kCFGregorianUnitsHours = (1 << 3), kCFGregorianUnitsMinutes = (1 << 4), kCFGregorianUnitsSeconds = (1 << 5), -#if 0 - kCFGregorianUnitsTimeZone = (1 << 8), - kCFGregorianUnitsDayOfWeek = (1 << 9), -#endif kCFGregorianAllUnits = 0x00FFFFFF -} CFGregorianUnitFlags; +}; +typedef CFOptionFlags CFGregorianUnitFlags; CF_EXPORT Boolean CFGregorianDateIsValid(CFGregorianDate gdate, CFOptionFlags unitFlags); @@ -121,9 +116,7 @@ SInt32 CFAbsoluteTimeGetDayOfYear(CFAbsoluteTime at, CFTimeZoneRef tz); CF_EXPORT SInt32 CFAbsoluteTimeGetWeekOfYear(CFAbsoluteTime at, CFTimeZoneRef tz); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFDATE__ */ diff --git a/CFDateFormatter.c b/CFDateFormatter.c new file mode 100644 index 0000000..e6fe19c --- /dev/null +++ b/CFDateFormatter.c @@ -0,0 +1,713 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFDateFormatter.c + Copyright 2002-2003, Apple, Inc. All rights reserved. + Responsibility: Christopher Kane +*/ + +#include +#include +#include +#include +#include +#include "CFInternal.h" +#include +#include +#include + +extern UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID, CFStringRef localeID, CFTimeZoneRef tz); +static void __CFDateFormatterCustomize(CFDateFormatterRef formatter); + +extern const CFStringRef kCFDateFormatterCalendarIdentifier; + +#define BUFFER_SIZE 768 + +struct __CFDateFormatter { + CFRuntimeBase _base; + UDateFormat *_df; + CFLocaleRef _locale; + CFDateFormatterStyle _timeStyle; + CFDateFormatterStyle _dateStyle; + CFStringRef _format; + CFStringRef _defformat; + CFStringRef _calendarName; + CFTimeZoneRef _tz; + CFDateRef _defaultDate; +}; + +static CFStringRef __CFDateFormatterCopyDescription(CFTypeRef cf) { + CFDateFormatterRef formatter = (CFDateFormatterRef)cf; + return CFStringCreateWithFormat(CFGetAllocator(formatter), NULL, CFSTR(""), cf, CFGetAllocator(formatter)); +} + +static void __CFDateFormatterDeallocate(CFTypeRef cf) { + CFDateFormatterRef formatter = (CFDateFormatterRef)cf; + if (formatter->_df) udat_close(formatter->_df); + if (formatter->_locale) CFRelease(formatter->_locale); + if (formatter->_format) CFRelease(formatter->_format); + if (formatter->_defformat) CFRelease(formatter->_defformat); + if (formatter->_calendarName) CFRelease(formatter->_calendarName); + if (formatter->_tz) CFRelease(formatter->_tz); + if (formatter->_defaultDate) CFRelease(formatter->_defaultDate); +} + +static CFTypeID __kCFDateFormatterTypeID = _kCFRuntimeNotATypeID; + +static const CFRuntimeClass __CFDateFormatterClass = { + 0, + "CFDateFormatter", + NULL, // init + NULL, // copy + __CFDateFormatterDeallocate, + NULL, + NULL, + NULL, // + __CFDateFormatterCopyDescription +}; + +static void __CFDateFormatterInitialize(void) { + __kCFDateFormatterTypeID = _CFRuntimeRegisterClass(&__CFDateFormatterClass); +} + +CFTypeID CFDateFormatterGetTypeID(void) { + if (_kCFRuntimeNotATypeID == __kCFDateFormatterTypeID) __CFDateFormatterInitialize(); + return __kCFDateFormatterTypeID; +} + +CFDateFormatterRef CFDateFormatterCreate(CFAllocatorRef allocator, CFLocaleRef locale, CFDateFormatterStyle dateStyle, CFDateFormatterStyle timeStyle) { + struct __CFDateFormatter *memory; + uint32_t size = sizeof(struct __CFDateFormatter) - sizeof(CFRuntimeBase); + if (allocator == NULL) allocator = __CFGetDefaultAllocator(); + __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); + if (locale) __CFGenericValidateType(locale, CFLocaleGetTypeID()); + memory = (struct __CFDateFormatter *)_CFRuntimeCreateInstance(allocator, CFDateFormatterGetTypeID(), size, NULL); + if (NULL == memory) { + return NULL; + } + memory->_df = NULL; + memory->_locale = NULL; + memory->_format = NULL; + memory->_defformat = NULL; + memory->_calendarName = NULL; + memory->_tz = NULL; + memory->_defaultDate = NULL; + if (NULL == locale) locale = CFLocaleGetSystem(); + memory->_dateStyle = dateStyle; + memory->_timeStyle = timeStyle; + int32_t udstyle, utstyle; + switch (dateStyle) { + case kCFDateFormatterNoStyle: udstyle = UDAT_NONE; break; + case kCFDateFormatterShortStyle: udstyle = UDAT_SHORT; break; + case kCFDateFormatterMediumStyle: udstyle = UDAT_MEDIUM; break; + case kCFDateFormatterLongStyle: udstyle = UDAT_LONG; break; + case kCFDateFormatterFullStyle: udstyle = UDAT_FULL; break; + default: + CFAssert2(0, __kCFLogAssertion, "%s(): unknown date style %d", __PRETTY_FUNCTION__, dateStyle); + udstyle = UDAT_MEDIUM; + memory->_dateStyle = kCFDateFormatterMediumStyle; + break; + } + switch (timeStyle) { + case kCFDateFormatterNoStyle: utstyle = UDAT_NONE; break; + case kCFDateFormatterShortStyle: utstyle = UDAT_SHORT; break; + case kCFDateFormatterMediumStyle: utstyle = UDAT_MEDIUM; break; + case kCFDateFormatterLongStyle: utstyle = UDAT_LONG; break; + case kCFDateFormatterFullStyle: utstyle = UDAT_FULL; break; + default: + CFAssert2(0, __kCFLogAssertion, "%s(): unknown time style %d", __PRETTY_FUNCTION__, timeStyle); + utstyle = UDAT_MEDIUM; + memory->_timeStyle = kCFDateFormatterMediumStyle; + break; + } + CFStringRef localeName = locale ? CFLocaleGetIdentifier(locale) : CFSTR(""); + char buffer[BUFFER_SIZE]; + const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII); + if (NULL == cstr) { + if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer; + } + if (NULL == cstr) { + CFRelease(memory); + return NULL; + } + UChar ubuffer[BUFFER_SIZE]; + memory->_tz = CFTimeZoneCopyDefault(); + CFStringRef tznam = CFTimeZoneGetName(memory->_tz); + CFIndex cnt = CFStringGetLength(tznam); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters(tznam, CFRangeMake(0, cnt), (UniChar *)ubuffer); + UErrorCode status = U_ZERO_ERROR; + memory->_df = udat_open((UDateFormatStyle)utstyle, (UDateFormatStyle)udstyle, cstr, ubuffer, cnt, NULL, 0, &status); + CFAssert2(memory->_df, __kCFLogAssertion, "%s(): error (%d) creating date formatter", __PRETTY_FUNCTION__, status); + if (NULL == memory->_df) { + CFRelease(memory->_tz); + CFRelease(memory); + return NULL; + } + udat_setLenient(memory->_df, 0); + if (kCFDateFormatterNoStyle == dateStyle && kCFDateFormatterNoStyle == timeStyle) { + udat_applyPattern(memory->_df, false, NULL, 0); + } + CFTypeRef calident = CFLocaleGetValue(locale, kCFLocaleCalendarIdentifier); + if (calident && CFEqual(calident, kCFGregorianCalendar)) { + status = U_ZERO_ERROR; + udat_set2DigitYearStart(memory->_df, -631152000000.0, &status); // 1950-01-01 00:00:00 GMT + } + memory->_locale = locale ? CFLocaleCreateCopy(allocator, locale) : CFLocaleGetSystem(); + __CFDateFormatterCustomize(memory); + status = U_ZERO_ERROR; + int32_t ret = udat_toPattern(memory->_df, false, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && ret <= BUFFER_SIZE) { + memory->_format = CFStringCreateWithCharacters(allocator, (const UniChar *)ubuffer, ret); + } + memory->_defformat = memory->_format ? (CFStringRef)CFRetain(memory->_format) : NULL; + return (CFDateFormatterRef)memory; +} + +extern CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale); + +static void __substituteFormatStringFromPrefsDF(CFDateFormatterRef formatter, bool doTime) { + CFIndex formatStyle = doTime ? formatter->_timeStyle : formatter->_dateStyle; + CFStringRef prefName = doTime ? CFSTR("AppleICUTimeFormatStrings") : CFSTR("AppleICUDateFormatStrings"); + if (kCFDateFormatterNoStyle != formatStyle) { + CFStringRef pref = NULL; + CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale); + CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, prefName) : NULL; + if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) { + CFStringRef key; + switch (formatStyle) { + case kCFDateFormatterShortStyle: key = CFSTR("1"); break; + case kCFDateFormatterMediumStyle: key = CFSTR("2"); break; + case kCFDateFormatterLongStyle: key = CFSTR("3"); break; + case kCFDateFormatterFullStyle: key = CFSTR("4"); break; + default: key = CFSTR("0"); break; + } + pref = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)metapref, key); + } + if (NULL != pref && CFGetTypeID(pref) == CFStringGetTypeID()) { + int32_t icustyle = UDAT_NONE; + switch (formatStyle) { + case kCFDateFormatterShortStyle: icustyle = UDAT_SHORT; break; + case kCFDateFormatterMediumStyle: icustyle = UDAT_MEDIUM; break; + case kCFDateFormatterLongStyle: icustyle = UDAT_LONG; break; + case kCFDateFormatterFullStyle: icustyle = UDAT_FULL; break; + } + CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale); + char buffer[BUFFER_SIZE]; + const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII); + if (NULL == cstr) { + if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer; + } + UErrorCode status = U_ZERO_ERROR; + UDateFormat *df = udat_open((UDateFormatStyle)(doTime ? icustyle : UDAT_NONE), (UDateFormatStyle)(doTime ? UDAT_NONE : icustyle), cstr, NULL, 0, NULL, 0, &status); + if (NULL != df) { + UChar ubuffer[BUFFER_SIZE]; + status = U_ZERO_ERROR; + int32_t date_len = udat_toPattern(df, false, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && date_len <= BUFFER_SIZE) { + CFStringRef dateString = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)ubuffer, date_len); + status = U_ZERO_ERROR; + int32_t formatter_len = udat_toPattern(formatter->_df, false, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && formatter_len <= BUFFER_SIZE) { + CFMutableStringRef formatString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); + CFStringAppendCharacters(formatString, (UniChar *)ubuffer, formatter_len); + // find dateString inside formatString, substitute the pref in that range + CFRange result; + if (CFStringFindWithOptions(formatString, dateString, CFRangeMake(0, formatter_len), 0, &result)) { + CFStringReplace(formatString, result, pref); + int32_t new_len = CFStringGetLength(formatString); + STACK_BUFFER_DECL(UChar, new_buffer, new_len); + const UChar *new_ustr = (UChar *)CFStringGetCharactersPtr(formatString); + if (NULL == new_ustr) { + CFStringGetCharacters(formatString, CFRangeMake(0, new_len), (UniChar *)new_buffer); + new_ustr = new_buffer; + } + status = U_ZERO_ERROR; +// udat_applyPattern(formatter->_df, false, new_ustr, new_len, &status); + udat_applyPattern(formatter->_df, false, new_ustr, new_len); + } + CFRelease(formatString); + } + CFRelease(dateString); + } + udat_close(df); + } + } + } +} + +static void __CFDateFormatterApplySymbolPrefs(const void *key, const void *value, void *context) { + if (CFGetTypeID(key) == CFStringGetTypeID() && CFGetTypeID(value) == CFArrayGetTypeID()) { + CFDateFormatterRef formatter = (CFDateFormatterRef)context; + UDateFormatSymbolType sym = (UDateFormatSymbolType)CFStringGetIntValue((CFStringRef)key); + CFArrayRef array = (CFArrayRef)value; + CFIndex idx, cnt = CFArrayGetCount(array); + for (idx = 0; idx < cnt; idx++) { + CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(array, idx); + if (CFGetTypeID(item) != CFStringGetTypeID()) continue; + CFIndex item_cnt = CFStringGetLength(item); + STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt)); + UChar *item_ustr = (UChar *)CFStringGetCharactersPtr(item); + if (NULL == item_ustr) { + item_cnt = __CFMin(BUFFER_SIZE, item_cnt); + CFStringGetCharacters(item, CFRangeMake(0, item_cnt), (UniChar *)item_buffer); + item_ustr = item_buffer; + } + UErrorCode status = U_ZERO_ERROR; + udat_setSymbols(formatter->_df, sym, idx, item_ustr, item_cnt, &status); + } + } +} + +static void __CFDateFormatterCustomize(CFDateFormatterRef formatter) { + __substituteFormatStringFromPrefsDF(formatter, false); + __substituteFormatStringFromPrefsDF(formatter, true); + CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale); + CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUDateTimeSymbols")) : NULL; + if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) { + CFDictionaryApplyFunction((CFDictionaryRef)metapref, __CFDateFormatterApplySymbolPrefs, formatter); + } +} + +CFLocaleRef CFDateFormatterGetLocale(CFDateFormatterRef formatter) { + __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); + return formatter->_locale; +} + +CFDateFormatterStyle CFDateFormatterGetDateStyle(CFDateFormatterRef formatter) { + __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); + return formatter->_dateStyle; +} + +CFDateFormatterStyle CFDateFormatterGetTimeStyle(CFDateFormatterRef formatter) { + __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); + return formatter->_timeStyle; +} + +CFStringRef CFDateFormatterGetFormat(CFDateFormatterRef formatter) { + __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); + return formatter->_format; +} + +void CFDateFormatterSetFormat(CFDateFormatterRef formatter, CFStringRef formatString) { + __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); + __CFGenericValidateType(formatString, CFStringGetTypeID()); + CFIndex cnt = CFStringGetLength(formatString); + CFAssert1(cnt <= 1024, __kCFLogAssertion, "%s(): format string too long", __PRETTY_FUNCTION__); + if (formatter->_format != formatString && cnt <= 1024) { + STACK_BUFFER_DECL(UChar, ubuffer, cnt); + const UChar *ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)formatString); + if (NULL == ustr) { + CFStringGetCharacters(formatString, CFRangeMake(0, cnt), (UniChar *)ubuffer); + ustr = ubuffer; + } + UErrorCode status = U_ZERO_ERROR; +// udat_applyPattern(formatter->_df, false, ustr, cnt, &status); + udat_applyPattern(formatter->_df, false, ustr, cnt); + if (U_SUCCESS(status)) { + if (formatter->_format) CFRelease(formatter->_format); + formatter->_format = (CFStringRef)CFStringCreateCopy(CFGetAllocator(formatter), formatString); + } + } +} + +CFStringRef CFDateFormatterCreateStringWithDate(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFDateRef date) { + if (allocator == NULL) allocator = __CFGetDefaultAllocator(); + __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); + __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); + __CFGenericValidateType(date, CFDateGetTypeID()); + return CFDateFormatterCreateStringWithAbsoluteTime(allocator, formatter, CFDateGetAbsoluteTime(date)); +} + +CFStringRef CFDateFormatterCreateStringWithAbsoluteTime(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFAbsoluteTime at) { + if (allocator == NULL) allocator = __CFGetDefaultAllocator(); + __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); + __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); + UChar *ustr = NULL, ubuffer[BUFFER_SIZE]; + UErrorCode status = U_ZERO_ERROR; + CFIndex used, cnt = BUFFER_SIZE; + UDate ud = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0 + 0.5; + used = udat_format(formatter->_df, ud, ubuffer, cnt, NULL, &status); + if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) { + cnt = used + 1; + ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0); + status = U_ZERO_ERROR; + used = udat_format(formatter->_df, ud, ustr, cnt, NULL, &status); + } + CFStringRef string = NULL; + if (U_SUCCESS(status)) { + string = CFStringCreateWithCharacters(allocator, (const UniChar *)(ustr ? ustr : ubuffer), used); + } + if (ustr) CFAllocatorDeallocate(kCFAllocatorSystemDefault, ustr); + return string; +} + +CFDateRef CFDateFormatterCreateDateFromString(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFStringRef string, CFRange *rangep) { + if (allocator == NULL) allocator = __CFGetDefaultAllocator(); + __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); + __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); + __CFGenericValidateType(string, CFStringGetTypeID()); + CFAbsoluteTime at; + if (CFDateFormatterGetAbsoluteTimeFromString(formatter, string, rangep, &at)) { + return CFDateCreate(allocator, at); + } + return NULL; +} + +Boolean CFDateFormatterGetAbsoluteTimeFromString(CFDateFormatterRef formatter, CFStringRef string, CFRange *rangep, CFAbsoluteTime *atp) { + __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); + __CFGenericValidateType(string, CFStringGetTypeID()); + CFRange range = {0, 0}; + if (rangep) { + range = *rangep; + } else { + range.length = CFStringGetLength(string); + } + if (1024 < range.length) range.length = 1024; + const UChar *ustr = (UChar *)CFStringGetCharactersPtr(string); + STACK_BUFFER_DECL(UChar, ubuffer, (NULL == ustr) ? range.length : 1); + if (NULL == ustr) { + CFStringGetCharacters(string, range, (UniChar *)ubuffer); + ustr = ubuffer; + } else { + ustr += range.location; + } + UDate udate; + int32_t dpos = 0; + UErrorCode status = U_ZERO_ERROR; + if (formatter->_defaultDate) { + CFAbsoluteTime at = CFDateGetAbsoluteTime(formatter->_defaultDate); + udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0; + UDateFormat *df2 = udat_clone(formatter->_df, &status); + UCalendar *cal2 = (UCalendar *)udat_getCalendar(df2); + ucal_setMillis(cal2, udate, &status); + udat_parseCalendar(formatter->_df, cal2, ustr, range.length, &dpos, &status); + udate = ucal_getMillis(cal2, &status); + udat_close(df2); + } else { + udate = udat_parse(formatter->_df, ustr, range.length, &dpos, &status); + } + if (rangep) rangep->length = dpos; + if (U_FAILURE(status)) { + return false; + } + if (atp) { + *atp = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970; + } + return true; +} + +#define SET_SYMBOLS_ARRAY(ICU_CODE, INDEX_BASE) \ + __CFGenericValidateType(value, CFArrayGetTypeID()); \ + CFArrayRef array = (CFArrayRef)value; \ + CFIndex idx, cnt = CFArrayGetCount(array); \ + for (idx = 0; idx < cnt; idx++) { \ + CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(array, idx); \ + __CFGenericValidateType(item, CFStringGetTypeID()); \ + CFIndex item_cnt = CFStringGetLength(item); \ + STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt)); \ + UChar *item_ustr = (UChar *)CFStringGetCharactersPtr(item); \ + if (NULL == item_ustr) { \ + item_cnt = __CFMin(BUFFER_SIZE, item_cnt); \ + CFStringGetCharacters(item, CFRangeMake(0, item_cnt), (UniChar *)item_buffer); \ + item_ustr = item_buffer; \ + } \ + status = U_ZERO_ERROR; \ + udat_setSymbols(formatter->_df, ICU_CODE, idx + INDEX_BASE, item_ustr, item_cnt, &status); \ + } + +void CFDateFormatterSetProperty(CFDateFormatterRef formatter, CFStringRef key, CFTypeRef value) { + __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); + __CFGenericValidateType(key, CFStringGetTypeID()); + UErrorCode status = U_ZERO_ERROR; + UChar ubuffer[BUFFER_SIZE]; + + if (kCFDateFormatterIsLenient == key) { + __CFGenericValidateType(value, CFBooleanGetTypeID()); + udat_setLenient(formatter->_df, (kCFBooleanTrue == value)); + } else if (kCFDateFormatterCalendar == key) { + __CFGenericValidateType(value, CFCalendarGetTypeID()); + CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale); + CFDictionaryRef components = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, localeName); + CFMutableDictionaryRef mcomponents = CFDictionaryCreateMutableCopy(kCFAllocatorSystemDefault, 0, components); + CFDictionarySetValue(mcomponents, kCFLocaleCalendarIdentifier, CFCalendarGetIdentifier((CFCalendarRef)value)); + localeName = CFLocaleCreateLocaleIdentifierFromComponents(kCFAllocatorSystemDefault, mcomponents); + CFRelease(mcomponents); + CFRelease(components); + CFLocaleRef newLocale = CFLocaleCreate(CFGetAllocator(formatter->_locale), localeName); + CFRelease(localeName); + CFRelease(formatter->_locale); + formatter->_locale = newLocale; + UCalendar *cal = __CFCalendarCreateUCalendar(NULL, CFLocaleGetIdentifier(formatter->_locale), formatter->_tz); + if (cal) udat_setCalendar(formatter->_df, cal); + if (cal) ucal_close(cal); + } else if (kCFDateFormatterCalendarIdentifier == key || kCFDateFormatterCalendarName == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale); + CFDictionaryRef components = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, localeName); + CFMutableDictionaryRef mcomponents = CFDictionaryCreateMutableCopy(kCFAllocatorSystemDefault, 0, components); + CFDictionarySetValue(mcomponents, kCFLocaleCalendarIdentifier, value); + localeName = CFLocaleCreateLocaleIdentifierFromComponents(kCFAllocatorSystemDefault, mcomponents); + CFRelease(mcomponents); + CFRelease(components); + CFLocaleRef newLocale = CFLocaleCreate(CFGetAllocator(formatter->_locale), localeName); + CFRelease(localeName); + CFRelease(formatter->_locale); + formatter->_locale = newLocale; + UCalendar *cal = __CFCalendarCreateUCalendar(NULL, CFLocaleGetIdentifier(formatter->_locale), formatter->_tz); + if (cal) udat_setCalendar(formatter->_df, cal); + if (cal) ucal_close(cal); + } else if (kCFDateFormatterTimeZone == key) { + __CFGenericValidateType(value, CFTimeZoneGetTypeID()); + CFTimeZoneRef old = formatter->_tz; + formatter->_tz = value ? (CFTimeZoneRef)CFRetain(value) : CFTimeZoneCopyDefault(); + if (old) CFRelease(old); + CFStringRef tznam = CFTimeZoneGetName(formatter->_tz); + UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df); + CFIndex ucnt = CFStringGetLength(tznam); + if (BUFFER_SIZE < ucnt) ucnt = BUFFER_SIZE; + CFStringGetCharacters(tznam, CFRangeMake(0, ucnt), (UniChar *)ubuffer); + ucal_setTimeZone(cal, ubuffer, ucnt, &status); + } else if (kCFDateFormatterDefaultFormat == key) { + // read-only attribute + } else if (kCFDateFormatterTwoDigitStartDate == key) { + __CFGenericValidateType(value, CFDateGetTypeID()); + CFAbsoluteTime at = CFDateGetAbsoluteTime((CFDateRef)value); + UDate udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0; + udat_set2DigitYearStart(formatter->_df, udate, &status); + } else if (kCFDateFormatterDefaultDate == key) { + __CFGenericValidateType(value, CFDateGetTypeID()); + CFDateRef old = formatter->_defaultDate; + formatter->_defaultDate = value ? (CFDateRef)CFRetain(value) : NULL; + if (old) CFRelease(old); + } else if (kCFDateFormatterEraSymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_ERAS, 0) + } else if (kCFDateFormatterMonthSymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_MONTHS, 0) + } else if (kCFDateFormatterShortMonthSymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_SHORT_MONTHS, 0) + } else if (kCFDateFormatterWeekdaySymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_WEEKDAYS, 1) + } else if (kCFDateFormatterShortWeekdaySymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_SHORT_WEEKDAYS, 1) + } else if (kCFDateFormatterAMSymbol == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + CFIndex item_cnt = CFStringGetLength((CFStringRef)value); + STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt)); + UChar *item_ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)value); + if (NULL == item_ustr) { + item_cnt = __CFMin(BUFFER_SIZE, item_cnt); + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, item_cnt), (UniChar *)item_buffer); + item_ustr = item_buffer; + } + udat_setSymbols(formatter->_df, UDAT_AM_PMS, 0, item_ustr, item_cnt, &status); + } else if (kCFDateFormatterPMSymbol == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + CFIndex item_cnt = CFStringGetLength((CFStringRef)value); + STACK_BUFFER_DECL(UChar, item_buffer, __CFMin(BUFFER_SIZE, item_cnt)); + UChar *item_ustr = (UChar *)CFStringGetCharactersPtr((CFStringRef)value); + if (NULL == item_ustr) { + item_cnt = __CFMin(BUFFER_SIZE, item_cnt); + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, item_cnt), (UniChar *)item_buffer); + item_ustr = item_buffer; + } + udat_setSymbols(formatter->_df, UDAT_AM_PMS, 1, item_ustr, item_cnt, &status); + } else if (kCFDateFormatterGregorianStartDate == key) { + __CFGenericValidateType(value, CFDateGetTypeID()); + CFAbsoluteTime at = CFDateGetAbsoluteTime((CFDateRef)value); + UDate udate = (at + kCFAbsoluteTimeIntervalSince1970) * 1000.0; + UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df); + ucal_setGregorianChange(cal, udate, &status); + } else if (kCFDateFormatterLongEraSymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_ERA_NAMES, 0) + } else if (kCFDateFormatterVeryShortMonthSymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_NARROW_MONTHS, 0) + } else if (kCFDateFormatterStandaloneMonthSymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_STANDALONE_MONTHS, 0) + } else if (kCFDateFormatterShortStandaloneMonthSymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_MONTHS, 0) + } else if (kCFDateFormatterVeryShortStandaloneMonthSymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_MONTHS, 0) + } else if (kCFDateFormatterVeryShortWeekdaySymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_NARROW_WEEKDAYS, 1) + } else if (kCFDateFormatterStandaloneWeekdaySymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_STANDALONE_WEEKDAYS, 1) + } else if (kCFDateFormatterShortStandaloneWeekdaySymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_WEEKDAYS, 1) + } else if (kCFDateFormatterVeryShortStandaloneWeekdaySymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_WEEKDAYS, 1) + } else if (kCFDateFormatterQuarterSymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_QUARTERS, 1) + } else if (kCFDateFormatterShortQuarterSymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_SHORT_QUARTERS, 1) + } else if (kCFDateFormatterStandaloneQuarterSymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_STANDALONE_QUARTERS, 1) + } else if (kCFDateFormatterShortStandaloneQuarterSymbols == key) { + SET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_QUARTERS, 1) + } else { + CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key); + } +} + +#define GET_SYMBOLS_ARRAY(ICU_CODE, INDEX_BASE) \ + CFIndex idx, cnt = udat_countSymbols(formatter->_df, ICU_CODE) - INDEX_BASE; \ + STACK_BUFFER_DECL(CFStringRef, strings, cnt); \ + for (idx = 0; idx < cnt; idx++) { \ + CFStringRef str = NULL; \ + status = U_ZERO_ERROR; \ + CFIndex ucnt = udat_getSymbols(formatter->_df, ICU_CODE, idx + INDEX_BASE, ubuffer, BUFFER_SIZE, &status); \ + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { \ + str = CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, ucnt); \ + } \ + strings[idx] = !str ? (CFStringRef)CFRetain(CFSTR("")) : str; \ + } \ + CFArrayRef array = CFArrayCreate(CFGetAllocator(formatter), (const void **)strings, cnt, &kCFTypeArrayCallBacks); \ + while (cnt--) { \ + CFRelease(strings[cnt]); \ + } \ + return array; + +CFTypeRef CFDateFormatterCopyProperty(CFDateFormatterRef formatter, CFStringRef key) { + __CFGenericValidateType(formatter, CFDateFormatterGetTypeID()); + __CFGenericValidateType(key, CFStringGetTypeID()); + UErrorCode status = U_ZERO_ERROR; + UChar ubuffer[BUFFER_SIZE]; + + if (kCFDateFormatterIsLenient == key) { + return CFRetain(udat_isLenient(formatter->_df) ? kCFBooleanTrue : kCFBooleanFalse); + } else if (kCFDateFormatterCalendar == key) { + CFCalendarRef calendar = (CFCalendarRef)CFLocaleGetValue(formatter->_locale, kCFLocaleCalendar); + return calendar ? CFRetain(calendar) : NULL; + } else if (kCFDateFormatterCalendarIdentifier == key || kCFDateFormatterCalendarName == key) { + CFStringRef ident = (CFStringRef)CFLocaleGetValue(formatter->_locale, kCFLocaleCalendarIdentifier); + return ident ? CFRetain(ident) : NULL; + } else if (kCFDateFormatterTimeZone == key) { + return CFRetain(formatter->_tz); + } else if (kCFDateFormatterDefaultFormat == key) { + return formatter->_defformat ? CFRetain(formatter->_defformat) : NULL; + } else if (kCFDateFormatterTwoDigitStartDate == key) { + UDate udate = udat_get2DigitYearStart(formatter->_df, &status); + if (U_SUCCESS(status)) { + CFAbsoluteTime at = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970; + return CFDateCreate(CFGetAllocator(formatter), at); + } + } else if (kCFDateFormatterDefaultDate == key) { + return formatter->_defaultDate ? CFRetain(formatter->_defaultDate) : NULL; + } else if (kCFDateFormatterEraSymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_ERAS, 0) + } else if (kCFDateFormatterMonthSymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_MONTHS, 0) + } else if (kCFDateFormatterShortMonthSymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_SHORT_MONTHS, 0) + } else if (kCFDateFormatterWeekdaySymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_WEEKDAYS, 1) + } else if (kCFDateFormatterShortWeekdaySymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_SHORT_WEEKDAYS, 1) + } else if (kCFDateFormatterAMSymbol == key) { + CFIndex cnt = udat_countSymbols(formatter->_df, UDAT_AM_PMS); + if (2 <= cnt) { + CFIndex ucnt = udat_getSymbols(formatter->_df, UDAT_AM_PMS, 0, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (UniChar *)ubuffer, ucnt); + } + } + } else if (kCFDateFormatterPMSymbol == key) { + CFIndex cnt = udat_countSymbols(formatter->_df, UDAT_AM_PMS); + if (2 <= cnt) { + CFIndex ucnt = udat_getSymbols(formatter->_df, UDAT_AM_PMS, 1, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (UniChar *)ubuffer, ucnt); + } + } + } else if (kCFDateFormatterGregorianStartDate == key) { + UCalendar *cal = (UCalendar *)udat_getCalendar(formatter->_df); + UDate udate = ucal_getGregorianChange(cal, &status); + if (U_SUCCESS(status)) { + CFAbsoluteTime at = (double)udate / 1000.0 - kCFAbsoluteTimeIntervalSince1970; + return CFDateCreate(CFGetAllocator(formatter), at); + } + } else if (kCFDateFormatterLongEraSymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_ERA_NAMES, 0) + } else if (kCFDateFormatterVeryShortMonthSymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_NARROW_MONTHS, 0) + } else if (kCFDateFormatterStandaloneMonthSymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_STANDALONE_MONTHS, 0) + } else if (kCFDateFormatterShortStandaloneMonthSymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_MONTHS, 0) + } else if (kCFDateFormatterVeryShortStandaloneMonthSymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_MONTHS, 0) + } else if (kCFDateFormatterVeryShortWeekdaySymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_NARROW_WEEKDAYS, 1) + } else if (kCFDateFormatterStandaloneWeekdaySymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_STANDALONE_WEEKDAYS, 1) + } else if (kCFDateFormatterShortStandaloneWeekdaySymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_WEEKDAYS, 1) + } else if (kCFDateFormatterVeryShortStandaloneWeekdaySymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_STANDALONE_NARROW_WEEKDAYS, 1) + } else if (kCFDateFormatterQuarterSymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_QUARTERS, 1) + } else if (kCFDateFormatterShortQuarterSymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_SHORT_QUARTERS, 1) + } else if (kCFDateFormatterStandaloneQuarterSymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_STANDALONE_QUARTERS, 1) + } else if (kCFDateFormatterShortStandaloneQuarterSymbols == key) { + GET_SYMBOLS_ARRAY(UDAT_STANDALONE_SHORT_QUARTERS, 1) + } else { + CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key); + } + return NULL; +} + +CONST_STRING_DECL(kCFDateFormatterIsLenient, "kCFDateFormatterIsLenient") +CONST_STRING_DECL(kCFDateFormatterTimeZone, "kCFDateFormatterTimeZone") +CONST_STRING_DECL(kCFDateFormatterCalendarName, "kCFDateFormatterCalendarName") +CONST_STRING_DECL(kCFDateFormatterCalendarIdentifier, "kCFDateFormatterCalendarIdentifier") +CONST_STRING_DECL(kCFDateFormatterCalendar, "kCFDateFormatterCalendar") +CONST_STRING_DECL(kCFDateFormatterDefaultFormat, "kCFDateFormatterDefaultFormat") + +CONST_STRING_DECL(kCFDateFormatterTwoDigitStartDate, "kCFDateFormatterTwoDigitStartDate") +CONST_STRING_DECL(kCFDateFormatterDefaultDate, "kCFDateFormatterDefaultDate") +CONST_STRING_DECL(kCFDateFormatterEraSymbols, "kCFDateFormatterEraSymbols") +CONST_STRING_DECL(kCFDateFormatterMonthSymbols, "kCFDateFormatterMonthSymbols") +CONST_STRING_DECL(kCFDateFormatterShortMonthSymbols, "kCFDateFormatterShortMonthSymbols") +CONST_STRING_DECL(kCFDateFormatterWeekdaySymbols, "kCFDateFormatterWeekdaySymbols") +CONST_STRING_DECL(kCFDateFormatterShortWeekdaySymbols, "kCFDateFormatterShortWeekdaySymbols") +CONST_STRING_DECL(kCFDateFormatterAMSymbol, "kCFDateFormatterAMSymbol") +CONST_STRING_DECL(kCFDateFormatterPMSymbol, "kCFDateFormatterPMSymbol") + +CONST_STRING_DECL(kCFDateFormatterLongEraSymbols, "kCFDateFormatterLongEraSymbols") +CONST_STRING_DECL(kCFDateFormatterVeryShortMonthSymbols, "kCFDateFormatterVeryShortMonthSymbols") +CONST_STRING_DECL(kCFDateFormatterStandaloneMonthSymbols, "kCFDateFormatterStandaloneMonthSymbols") +CONST_STRING_DECL(kCFDateFormatterShortStandaloneMonthSymbols, "kCFDateFormatterShortStandaloneMonthSymbols") +CONST_STRING_DECL(kCFDateFormatterVeryShortStandaloneMonthSymbols, "kCFDateFormatterVeryShortStandaloneMonthSymbols") +CONST_STRING_DECL(kCFDateFormatterVeryShortWeekdaySymbols, "kCFDateFormatterVeryShortWeekdaySymbols") +CONST_STRING_DECL(kCFDateFormatterStandaloneWeekdaySymbols, "kCFDateFormatterStandaloneWeekdaySymbols") +CONST_STRING_DECL(kCFDateFormatterShortStandaloneWeekdaySymbols, "kCFDateFormatterShortStandaloneWeekdaySymbols") +CONST_STRING_DECL(kCFDateFormatterVeryShortStandaloneWeekdaySymbols, "kCFDateFormatterVeryShortStandaloneWeekdaySymbols") +CONST_STRING_DECL(kCFDateFormatterQuarterSymbols, "kCFDateFormatterQuarterSymbols") +CONST_STRING_DECL(kCFDateFormatterShortQuarterSymbols, "kCFDateFormatterShortQuarterSymbols") +CONST_STRING_DECL(kCFDateFormatterStandaloneQuarterSymbols, "kCFDateFormatterStandaloneQuarterSymbols") +CONST_STRING_DECL(kCFDateFormatterShortStandaloneQuarterSymbols, "kCFDateFormatterShortStandaloneQuarterSymbols") +CONST_STRING_DECL(kCFDateFormatterGregorianStartDate, "kCFDateFormatterGregorianStartDate") + +#undef BUFFER_SIZE + diff --git a/CFDateFormatter.h b/CFDateFormatter.h new file mode 100644 index 0000000..16a007e --- /dev/null +++ b/CFDateFormatter.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFDateFormatter.h + Copyright (c) 2003-2007, Apple Inc. All rights reserved. +*/ + +#if !defined(__COREFOUNDATION_CFDATEFORMATTER__) +#define __COREFOUNDATION_CFDATEFORMATTER__ 1 + +#include +#include +#include + +#if MAC_OS_X_VERSION_10_3 <= MAC_OS_X_VERSION_MAX_ALLOWED + +CF_EXTERN_C_BEGIN + +typedef struct __CFDateFormatter *CFDateFormatterRef; + +// CFDateFormatters are not thread-safe. Do not use one from multiple threads! + +CF_EXPORT +CFTypeID CFDateFormatterGetTypeID(void) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + +enum { // date and time format styles + kCFDateFormatterNoStyle = 0, + kCFDateFormatterShortStyle = 1, + kCFDateFormatterMediumStyle = 2, + kCFDateFormatterLongStyle = 3, + kCFDateFormatterFullStyle = 4 +}; +typedef CFIndex CFDateFormatterStyle; + +// The exact formatted result for these date and time styles depends on the +// locale, but generally: +// Short is completely numeric, such as "12/13/52" or "3:30pm" +// Medium is longer, such as "Jan 12, 1952" +// Long is longer, such as "January 12, 1952" or "3:30:32pm" +// Full is pretty complete; e.g. "Tuesday, April 12, 1952 AD" or "3:30:42pm PST" +// The specifications though are left fuzzy, in part simply because a user's +// preference choices may affect the output, and also the results may change +// from one OS release to another. To produce an exactly formatted date you +// should not rely on styles and localization, but set the format string and +// 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; + // 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; + +CF_EXPORT +CFDateFormatterStyle CFDateFormatterGetDateStyle(CFDateFormatterRef formatter) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + +CF_EXPORT +CFDateFormatterStyle CFDateFormatterGetTimeStyle(CFDateFormatterRef formatter) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + // 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; + +CF_EXPORT +void CFDateFormatterSetFormat(CFDateFormatterRef formatter, CFStringRef formatString) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + // 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 + // default format string defined by the style arguments with + // which it was created. + + +CF_EXPORT +CFStringRef CFDateFormatterCreateStringWithDate(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFDateRef date) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + +CF_EXPORT +CFStringRef CFDateFormatterCreateStringWithAbsoluteTime(CFAllocatorRef allocator, CFDateFormatterRef formatter, CFAbsoluteTime at) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + // 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; + +CF_EXPORT +Boolean CFDateFormatterGetAbsoluteTimeFromString(CFDateFormatterRef formatter, CFStringRef string, CFRange *rangep, CFAbsoluteTime *atp) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + // 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 + // output indicates the extent that was used; this parameter can + // be NULL, in which case the whole string may be used. The + // return value indicates whether some date was computed and + // (if atp is not NULL) stored at the location specified by atp. + + +CF_EXPORT +void CFDateFormatterSetProperty(CFDateFormatterRef formatter, CFStringRef key, CFTypeRef value) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + +CF_EXPORT +CFTypeRef CFDateFormatterCopyProperty(CFDateFormatterRef formatter, CFStringRef key) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + // 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 + +// See CFLocale.h for these calendar constants: +// const CFStringRef kCFGregorianCalendar; +// const CFStringRef kCFBuddhistCalendar; +// const CFStringRef kCFJapaneseCalendar; +// const CFStringRef kCFIslamicCalendar; +// const CFStringRef kCFIslamicCivilCalendar; +// const CFStringRef kCFHebrewCalendar; +// const CFStringRef kCFChineseCalendar; + +CF_EXTERN_C_END + +#endif + +#endif /* ! __COREFOUNDATION_CFDATEFORMATTER__ */ + diff --git a/CFDictionary.c b/CFDictionary.c new file mode 100644 index 0000000..716dc77 --- /dev/null +++ b/CFDictionary.c @@ -0,0 +1,1467 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFDictionary.c + Copyright 1998-2006, Apple, Inc. All rights reserved. + Responsibility: Christopher Kane + Machine generated from Notes/HashingCode.template +*/ + + + + +#include +#include "CFInternal.h" +#include + +#define CFDictionary 0 +#define CFSet 0 +#define CFBag 0 +#undef CFDictionary +#define CFDictionary 1 + +#if CFDictionary +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}; +static const CFDictionaryKeyCallBacks __kCFNullDictionaryKeyCallBacks = {0, NULL, NULL, NULL, NULL, NULL}; +static const CFDictionaryValueCallBacks __kCFNullDictionaryValueCallBacks = {0, NULL, NULL, NULL, NULL}; + +#define CFHashRef CFDictionaryRef +#define CFMutableHashRef CFMutableDictionaryRef +#define __kCFHashTypeID __kCFDictionaryTypeID +#endif + +#if CFSet +const CFDictionaryCallBacks kCFTypeDictionaryCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; +const CFDictionaryCallBacks kCFCopyStringDictionaryCallBacks = {0, __CFStringCollectionCopy, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; +static const CFDictionaryCallBacks __kCFNullDictionaryCallBacks = {0, NULL, NULL, NULL, NULL, NULL}; + +#define CFDictionaryKeyCallBacks CFDictionaryCallBacks +#define CFDictionaryValueCallBacks CFDictionaryCallBacks +#define kCFTypeDictionaryKeyCallBacks kCFTypeDictionaryCallBacks +#define kCFTypeDictionaryValueCallBacks kCFTypeDictionaryCallBacks +#define __kCFNullDictionaryKeyCallBacks __kCFNullDictionaryCallBacks +#define __kCFNullDictionaryValueCallBacks __kCFNullDictionaryCallBacks + +#define CFHashRef CFSetRef +#define CFMutableHashRef CFMutableSetRef +#define __kCFHashTypeID __kCFSetTypeID +#endif + +#if CFBag +const CFDictionaryCallBacks kCFTypeDictionaryCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; +const CFDictionaryCallBacks kCFCopyStringDictionaryCallBacks = {0, __CFStringCollectionCopy, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; +static const CFDictionaryCallBacks __kCFNullDictionaryCallBacks = {0, NULL, NULL, NULL, NULL, NULL}; + +#define CFDictionaryKeyCallBacks CFDictionaryCallBacks +#define CFDictionaryValueCallBacks CFDictionaryCallBacks +#define kCFTypeDictionaryKeyCallBacks kCFTypeDictionaryCallBacks +#define kCFTypeDictionaryValueCallBacks kCFTypeDictionaryCallBacks +#define __kCFNullDictionaryKeyCallBacks __kCFNullDictionaryCallBacks +#define __kCFNullDictionaryValueCallBacks __kCFNullDictionaryCallBacks + +#define CFHashRef CFBagRef +#define CFMutableHashRef CFMutableBagRef +#define __kCFHashTypeID __kCFBagTypeID +#endif + +#define GETNEWKEY(newKey, oldKey) \ + any_t (*kretain)(CFAllocatorRef, any_t, any_pointer_t) = \ + !hasBeenFinalized(hc) \ + ? (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))__CFDictionaryGetKeyCallBacks(hc)->retain \ + : (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))0; \ + any_t newKey = kretain ? (any_t)INVOKE_CALLBACK3(kretain, allocator, (any_t)key, hc->_context) : (any_t)oldKey + +#define RELEASEKEY(oldKey) \ + void (*krelease)(CFAllocatorRef, any_t, any_pointer_t) = \ + !hasBeenFinalized(hc) \ + ? (void (*)(CFAllocatorRef,any_t,any_pointer_t))__CFDictionaryGetKeyCallBacks(hc)->release \ + : (void (*)(CFAllocatorRef,any_t,any_pointer_t))0; \ + if (krelease) INVOKE_CALLBACK3(krelease, allocator, oldKey, hc->_context) + +#if CFDictionary +#define GETNEWVALUE(newValue) \ + any_t (*vretain)(CFAllocatorRef, any_t, any_pointer_t) = \ + !hasBeenFinalized(hc) \ + ? (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))__CFDictionaryGetValueCallBacks(hc)->retain \ + : (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))0; \ + any_t newValue = vretain ? (any_t)INVOKE_CALLBACK3(vretain, allocator, (any_t)value, hc->_context) : (any_t)value + +#define RELEASEVALUE(oldValue) \ + void (*vrelease)(CFAllocatorRef, any_t, any_pointer_t) = \ + !hasBeenFinalized(hc) \ + ? (void (*)(CFAllocatorRef,any_t,any_pointer_t))__CFDictionaryGetValueCallBacks(hc)->release \ + : (void (*)(CFAllocatorRef,any_t,any_pointer_t))0; \ + if (vrelease) INVOKE_CALLBACK3(vrelease, allocator, oldValue, hc->_context) + +#endif + +static void __CFDictionaryHandleOutOfMemory(CFTypeRef obj, CFIndex numBytes) { + CFStringRef msg = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("Attempt to allocate %ld bytes for NS/CFDictionary failed"), numBytes); + CFBadErrorCallBack cb = _CFGetOutOfMemoryErrorCallBack(); + if (NULL == cb || !cb(obj, CFSTR("NS/CFDictionary"), msg)) { + CFLog(kCFLogLevelCritical, CFSTR("%@"), msg); + HALT; + } + CFRelease(msg); +} + + +// Max load is 3/4 number of buckets +CF_INLINE CFIndex __CFHashRoundUpCapacity(CFIndex capacity) { + return 3 * ((CFIndex)1 << (flsl((capacity - 1) / 3))); +} + +// Returns next power of two higher than the capacity +// threshold for the given input capacity. +CF_INLINE CFIndex __CFHashNumBucketsForCapacity(CFIndex capacity) { + return 4 * ((CFIndex)1 << (flsl((capacity - 1) / 3))); +} + +enum { /* Bits 1-0 */ + __kCFHashImmutable = 0, /* unchangable and fixed capacity */ + __kCFHashMutable = 1, /* changeable and variable capacity */ +}; + +enum { /* Bits 5-4 (value), 3-2 (key) */ + __kCFHashHasNullCallBacks = 0, + __kCFHashHasCFTypeCallBacks = 1, + __kCFHashHasCustomCallBacks = 3 /* callbacks are at end of header */ +}; + +// Under GC, we fudge the key/value memory in two ways +// First, if we had null callbacks or null for both retain/release, we use unscanned memory and get +// standard 'dangling' references. +// This means that if people were doing addValue:[xxx new] and never removing, well, that doesn't work +// +// Second, if we notice standard retain/release implementations we use scanned memory, and fudge the +// standard callbacks to generally do nothing if the collection was allocated in GC memory. On special +// CF objects, however, like those used for precious resources like video-card buffers, we do indeed +// do CFRetain on input and CFRelease on output. The tricky case is GC finalization; we need to remember +// that we did the CFReleases so that subsequent collection operations, like removal, don't double CFRelease. +// (In fact we don't really use CFRetain/CFRelease but go directly to the collector) +// + +enum { + __kCFHashFinalized = (1 << 7), + __kCFHashWeakKeys = (1 << 8), + __kCFHashWeakValues = (1 << 9) +}; + +typedef uintptr_t any_t; +typedef const void * const_any_pointer_t; +typedef void * any_pointer_t; + +struct __CFDictionary { + CFRuntimeBase _base; + CFIndex _count; /* number of values */ + CFIndex _bucketsNum; /* number of buckets */ + CFIndex _bucketsUsed; /* number of used buckets */ + CFIndex _bucketsCap; /* maximum number of used buckets */ + CFIndex _mutations; + CFIndex _deletes; + any_pointer_t _context; /* private */ + CFOptionFlags _xflags; + any_t _marker; + any_t *_keys; /* can be NULL if not allocated yet */ + any_t *_values; /* can be NULL if not allocated yet */ +}; + +/* Bits 1-0 of the _xflags are used for mutability variety */ +/* Bits 3-2 of the _xflags are used for key callback indicator bits */ +/* Bits 5-4 of the _xflags are used for value callback indicator bits */ +/* Bit 6 of the _xflags is special KVO actions bit */ +/* Bits 7,8,9 are GC use */ + +CF_INLINE bool hasBeenFinalized(CFTypeRef collection) { + return __CFBitfieldGetValue(((const struct __CFDictionary *)collection)->_xflags, 7, 7) != 0; +} + +CF_INLINE void markFinalized(CFTypeRef collection) { + __CFBitfieldSetValue(((struct __CFDictionary *)collection)->_xflags, 7, 7, 1); +} + + +CF_INLINE CFIndex __CFHashGetType(CFHashRef hc) { + return __CFBitfieldGetValue(hc->_xflags, 1, 0); +} + +CF_INLINE CFIndex __CFDictionaryGetSizeOfType(CFIndex t) { + CFIndex size = sizeof(struct __CFDictionary); + if (__CFBitfieldGetValue(t, 3, 2) == __kCFHashHasCustomCallBacks) { + size += sizeof(CFDictionaryKeyCallBacks); + } + if (__CFBitfieldGetValue(t, 5, 4) == __kCFHashHasCustomCallBacks) { + size += sizeof(CFDictionaryValueCallBacks); + } + return size; +} + +CF_INLINE const CFDictionaryKeyCallBacks *__CFDictionaryGetKeyCallBacks(CFHashRef hc) { + CFDictionaryKeyCallBacks *result = NULL; + switch (__CFBitfieldGetValue(hc->_xflags, 3, 2)) { + case __kCFHashHasNullCallBacks: + return &__kCFNullDictionaryKeyCallBacks; + case __kCFHashHasCFTypeCallBacks: + return &kCFTypeDictionaryKeyCallBacks; + case __kCFHashHasCustomCallBacks: + break; + } + result = (CFDictionaryKeyCallBacks *)((uint8_t *)hc + sizeof(struct __CFDictionary)); + return result; +} + +CF_INLINE Boolean __CFDictionaryKeyCallBacksMatchNull(const CFDictionaryKeyCallBacks *c) { + return (NULL == c || + (c->retain == __kCFNullDictionaryKeyCallBacks.retain && + c->release == __kCFNullDictionaryKeyCallBacks.release && + c->copyDescription == __kCFNullDictionaryKeyCallBacks.copyDescription && + c->equal == __kCFNullDictionaryKeyCallBacks.equal && + c->hash == __kCFNullDictionaryKeyCallBacks.hash)); +} + +CF_INLINE Boolean __CFDictionaryKeyCallBacksMatchCFType(const CFDictionaryKeyCallBacks *c) { + return (&kCFTypeDictionaryKeyCallBacks == c || + (c->retain == kCFTypeDictionaryKeyCallBacks.retain && + c->release == kCFTypeDictionaryKeyCallBacks.release && + c->copyDescription == kCFTypeDictionaryKeyCallBacks.copyDescription && + c->equal == kCFTypeDictionaryKeyCallBacks.equal && + c->hash == kCFTypeDictionaryKeyCallBacks.hash)); +} + +CF_INLINE const CFDictionaryValueCallBacks *__CFDictionaryGetValueCallBacks(CFHashRef hc) { + CFDictionaryValueCallBacks *result = NULL; + switch (__CFBitfieldGetValue(hc->_xflags, 5, 4)) { + case __kCFHashHasNullCallBacks: + return &__kCFNullDictionaryValueCallBacks; + case __kCFHashHasCFTypeCallBacks: + return &kCFTypeDictionaryValueCallBacks; + case __kCFHashHasCustomCallBacks: + break; + } + if (__CFBitfieldGetValue(hc->_xflags, 3, 2) == __kCFHashHasCustomCallBacks) { + result = (CFDictionaryValueCallBacks *)((uint8_t *)hc + sizeof(struct __CFDictionary) + sizeof(CFDictionaryKeyCallBacks)); + } else { + result = (CFDictionaryValueCallBacks *)((uint8_t *)hc + sizeof(struct __CFDictionary)); + } + return result; +} + +CF_INLINE Boolean __CFDictionaryValueCallBacksMatchNull(const CFDictionaryValueCallBacks *c) { + return (NULL == c || + (c->retain == __kCFNullDictionaryValueCallBacks.retain && + c->release == __kCFNullDictionaryValueCallBacks.release && + c->copyDescription == __kCFNullDictionaryValueCallBacks.copyDescription && + c->equal == __kCFNullDictionaryValueCallBacks.equal)); +} + +CF_INLINE Boolean __CFDictionaryValueCallBacksMatchCFType(const CFDictionaryValueCallBacks *c) { + return (&kCFTypeDictionaryValueCallBacks == c || + (c->retain == kCFTypeDictionaryValueCallBacks.retain && + c->release == kCFTypeDictionaryValueCallBacks.release && + c->copyDescription == kCFTypeDictionaryValueCallBacks.copyDescription && + c->equal == kCFTypeDictionaryValueCallBacks.equal)); +} + +CFIndex _CFDictionaryGetKVOBit(CFHashRef hc) { + return __CFBitfieldGetValue(hc->_xflags, 6, 6); +} + +void _CFDictionarySetKVOBit(CFHashRef hc, CFIndex bit) { + __CFBitfieldSetValue(((CFMutableHashRef)hc)->_xflags, 6, 6, ((uintptr_t)bit & 0x1)); +} + +CF_INLINE Boolean __CFDictionaryShouldShrink(CFHashRef hc) { + return (__kCFHashMutable == __CFHashGetType(hc)) && + !(CF_USING_COLLECTABLE_MEMORY && auto_zone_is_finalized(__CFCollectableZone, hc)) && /* GC: don't shrink finalizing hcs! */ + (hc->_bucketsNum < 4 * hc->_deletes || (256 <= hc->_bucketsCap && hc-> _bucketsUsed < 3 * hc->_bucketsCap / 16)); +} + +CF_INLINE CFIndex __CFHashGetOccurrenceCount(CFHashRef hc, CFIndex idx) { +#if CFBag + return hc->_values[idx]; +#endif + return 1; +} + +CF_INLINE Boolean __CFHashKeyIsValue(CFHashRef hc, any_t key) { + return (hc->_marker != key && ~hc->_marker != key) ? true : false; +} + +CF_INLINE Boolean __CFHashKeyIsMagic(CFHashRef hc, any_t key) { + return (hc->_marker == key || ~hc->_marker == key) ? true : false; +} + + +#if !defined(CF_OBJC_KVO_WILLCHANGE) +#define CF_OBJC_KVO_WILLCHANGE(obj, key) +#define CF_OBJC_KVO_DIDCHANGE(obj, key) +#endif + +CF_INLINE uintptr_t __CFDictionaryScrambleHash(uintptr_t k) { +#if 0 + return k; +#else +#if __LP64__ + uintptr_t a = 0x4368726973746F70ULL; + uintptr_t b = 0x686572204B616E65ULL; +#else + uintptr_t a = 0x4B616E65UL; + uintptr_t b = 0x4B616E65UL; +#endif + uintptr_t c = 1; + a += k; +#if __LP64__ + a -= b; a -= c; a ^= (c >> 43); + b -= c; b -= a; b ^= (a << 9); + c -= a; c -= b; c ^= (b >> 8); + a -= b; a -= c; a ^= (c >> 38); + b -= c; b -= a; b ^= (a << 23); + c -= a; c -= b; c ^= (b >> 5); + a -= b; a -= c; a ^= (c >> 35); + b -= c; b -= a; b ^= (a << 49); + c -= a; c -= b; c ^= (b >> 11); + a -= b; a -= c; a ^= (c >> 12); + b -= c; b -= a; b ^= (a << 18); + c -= a; c -= b; c ^= (b >> 22); +#else + a -= b; a -= c; a ^= (c >> 13); + b -= c; b -= a; b ^= (a << 8); + c -= a; c -= b; c ^= (b >> 13); + a -= b; a -= c; a ^= (c >> 12); + b -= c; b -= a; b ^= (a << 16); + c -= a; c -= b; c ^= (b >> 5); + a -= b; a -= c; a ^= (c >> 3); + b -= c; b -= a; b ^= (a << 10); + c -= a; c -= b; c ^= (b >> 15); +#endif + return c; +#endif +} + +static CFIndex __CFDictionaryFindBuckets1a(CFHashRef hc, any_t key) { + CFHashCode keyHash = (CFHashCode)key; + keyHash = __CFDictionaryScrambleHash(keyHash); + any_t *keys = hc->_keys; + any_t marker = hc->_marker; + CFIndex probe = keyHash & (hc->_bucketsNum - 1); + CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value + CFIndex start = probe; + for (;;) { + any_t currKey = keys[probe]; + if (marker == currKey) { /* empty */ + return kCFNotFound; + } else if (~marker == currKey) { /* deleted */ + /* do nothing */ + } else if (currKey == key) { + return probe; + } + probe = probe + probeskip; + // This alternative to probe % buckets assumes that + // probeskip is always positive and less than the + // number of buckets. + if (hc->_bucketsNum <= probe) { + probe -= hc->_bucketsNum; + } + if (start == probe) { + return kCFNotFound; + } + } +} + +static CFIndex __CFDictionaryFindBuckets1b(CFHashRef hc, any_t key) { + const CFDictionaryKeyCallBacks *cb = __CFDictionaryGetKeyCallBacks(hc); + CFHashCode keyHash = cb->hash ? (CFHashCode)INVOKE_CALLBACK2(((CFHashCode (*)(any_t, any_pointer_t))cb->hash), key, hc->_context) : (CFHashCode)key; + keyHash = __CFDictionaryScrambleHash(keyHash); + any_t *keys = hc->_keys; + any_t marker = hc->_marker; + CFIndex probe = keyHash & (hc->_bucketsNum - 1); + CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value + CFIndex start = probe; + for (;;) { + any_t currKey = keys[probe]; + if (marker == currKey) { /* empty */ + return kCFNotFound; + } else if (~marker == currKey) { /* deleted */ + /* do nothing */ + } else if (currKey == key || (cb->equal && INVOKE_CALLBACK3((Boolean (*)(any_t, any_t, any_pointer_t))cb->equal, currKey, key, hc->_context))) { + return probe; + } + probe = probe + probeskip; + // This alternative to probe % buckets assumes that + // probeskip is always positive and less than the + // number of buckets. + if (hc->_bucketsNum <= probe) { + probe -= hc->_bucketsNum; + } + if (start == probe) { + return kCFNotFound; + } + } +} + +CF_INLINE CFIndex __CFDictionaryFindBuckets1(CFHashRef hc, any_t key) { + if (__kCFHashHasNullCallBacks == __CFBitfieldGetValue(hc->_xflags, 3, 2)) { + return __CFDictionaryFindBuckets1a(hc, key); + } + return __CFDictionaryFindBuckets1b(hc, key); +} + +static void __CFDictionaryFindBuckets2(CFHashRef hc, any_t key, CFIndex *match, CFIndex *nomatch) { + const CFDictionaryKeyCallBacks *cb = __CFDictionaryGetKeyCallBacks(hc); + CFHashCode keyHash = cb->hash ? (CFHashCode)INVOKE_CALLBACK2(((CFHashCode (*)(any_t, any_pointer_t))cb->hash), key, hc->_context) : (CFHashCode)key; + keyHash = __CFDictionaryScrambleHash(keyHash); + any_t *keys = hc->_keys; + any_t marker = hc->_marker; + CFIndex probe = keyHash & (hc->_bucketsNum - 1); + CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value + CFIndex start = probe; + *match = kCFNotFound; + *nomatch = kCFNotFound; + for (;;) { + any_t currKey = keys[probe]; + if (marker == currKey) { /* empty */ + if (nomatch) *nomatch = probe; + return; + } else if (~marker == currKey) { /* deleted */ + if (nomatch) { + *nomatch = probe; + nomatch = NULL; + } + } else if (currKey == key || (cb->equal && INVOKE_CALLBACK3((Boolean (*)(any_t, any_t, any_pointer_t))cb->equal, currKey, key, hc->_context))) { + *match = probe; + return; + } + probe = probe + probeskip; + // This alternative to probe % buckets assumes that + // probeskip is always positive and less than the + // number of buckets. + if (hc->_bucketsNum <= probe) { + probe -= hc->_bucketsNum; + } + if (start == probe) { + return; + } + } +} + +static void __CFDictionaryFindNewMarker(CFHashRef hc) { + any_t *keys = hc->_keys; + any_t newMarker; + CFIndex idx, nbuckets; + Boolean hit; + + nbuckets = hc->_bucketsNum; + newMarker = hc->_marker; + do { + newMarker--; + hit = false; + for (idx = 0; idx < nbuckets; idx++) { + if (newMarker == keys[idx] || ~newMarker == keys[idx]) { + hit = true; + break; + } + } + } while (hit); + for (idx = 0; idx < nbuckets; idx++) { + if (hc->_marker == keys[idx]) { + keys[idx] = newMarker; + } else if (~hc->_marker == keys[idx]) { + keys[idx] = ~newMarker; + } + } + ((struct __CFDictionary *)hc)->_marker = newMarker; +} + +static Boolean __CFDictionaryEqual(CFTypeRef cf1, CFTypeRef cf2) { + CFHashRef hc1 = (CFHashRef)cf1; + CFHashRef hc2 = (CFHashRef)cf2; + const CFDictionaryKeyCallBacks *cb1, *cb2; + const CFDictionaryValueCallBacks *vcb1, *vcb2; + any_t *keys; + CFIndex idx, nbuckets; + if (hc1 == hc2) return true; + if (hc1->_count != hc2->_count) return false; + cb1 = __CFDictionaryGetKeyCallBacks(hc1); + cb2 = __CFDictionaryGetKeyCallBacks(hc2); + if (cb1->equal != cb2->equal) return false; + vcb1 = __CFDictionaryGetValueCallBacks(hc1); + vcb2 = __CFDictionaryGetValueCallBacks(hc2); + if (vcb1->equal != vcb2->equal) return false; + if (0 == hc1->_bucketsUsed) return true; /* after function comparison! */ + keys = hc1->_keys; + nbuckets = hc1->_bucketsNum; + for (idx = 0; idx < nbuckets; idx++) { + if (hc1->_marker != keys[idx] && ~hc1->_marker != keys[idx]) { +#if CFDictionary + const_any_pointer_t value; + if (!CFDictionaryGetValueIfPresent(hc2, (any_pointer_t)keys[idx], &value)) return false; + if (hc1->_values[idx] != (any_t)value) { + if (NULL == vcb1->equal) return false; + if (!INVOKE_CALLBACK3((Boolean (*)(any_t, any_t, any_pointer_t))vcb1->equal, hc1->_values[idx], (any_t)value, hc1->_context)) return false; + } +#endif +#if CFSet + const_any_pointer_t value; + if (!CFDictionaryGetValueIfPresent(hc2, (any_pointer_t)keys[idx], &value)) return false; +#endif +#if CFBag + if (hc1->_values[idx] != CFDictionaryGetCountOfValue(hc2, (any_pointer_t)keys[idx])) return false; +#endif + } + } + return true; +} + +static CFHashCode __CFDictionaryHash(CFTypeRef cf) { + CFHashRef hc = (CFHashRef)cf; + return hc->_count; +} + +static CFStringRef __CFDictionaryCopyDescription(CFTypeRef cf) { + CFHashRef hc = (CFHashRef)cf; + CFAllocatorRef allocator; + const CFDictionaryKeyCallBacks *cb; + const CFDictionaryValueCallBacks *vcb; + any_t *keys; + CFIndex idx, nbuckets; + CFMutableStringRef result; + cb = __CFDictionaryGetKeyCallBacks(hc); + vcb = __CFDictionaryGetValueCallBacks(hc); + keys = hc->_keys; + nbuckets = hc->_bucketsNum; + allocator = CFGetAllocator(hc); + result = CFStringCreateMutable(allocator, 0); + const char *type = "?"; + switch (__CFHashGetType(hc)) { + case __kCFHashImmutable: type = "immutable"; break; + case __kCFHashMutable: type = "mutable"; break; + } + CFStringAppendFormat(result, NULL, CFSTR("{type = %s, count = %u, capacity = %u, pairs = (\n"), cf, allocator, type, hc->_count, hc->_bucketsCap); + for (idx = 0; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + CFStringRef kDesc = NULL, vDesc = NULL; + if (NULL != cb->copyDescription) { + kDesc = (CFStringRef)INVOKE_CALLBACK2(((CFStringRef (*)(any_t, any_pointer_t))cb->copyDescription), keys[idx], hc->_context); + } + if (NULL != vcb->copyDescription) { + vDesc = (CFStringRef)INVOKE_CALLBACK2(((CFStringRef (*)(any_t, any_pointer_t))vcb->copyDescription), hc->_values[idx], hc->_context); + } +#if CFDictionary + if (NULL != kDesc && NULL != vDesc) { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@ = %@\n"), idx, kDesc, vDesc); + CFRelease(kDesc); + CFRelease(vDesc); + } else if (NULL != kDesc) { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@ = <%p>\n"), idx, kDesc, hc->_values[idx]); + CFRelease(kDesc); + } else if (NULL != vDesc) { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p> = %@\n"), idx, keys[idx], vDesc); + CFRelease(vDesc); + } else { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p> = <%p>\n"), idx, keys[idx], hc->_values[idx]); + } +#endif +#if CFSet + if (NULL != kDesc) { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@\n"), idx, kDesc); + CFRelease(kDesc); + } else { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p>\n"), idx, keys[idx]); + } +#endif +#if CFBag + if (NULL != kDesc) { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@ (%ld)\n"), idx, kDesc, hc->_values[idx]); + CFRelease(kDesc); + } else { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p> (%ld)\n"), idx, keys[idx], hc->_values[idx]); + } +#endif + } + } + CFStringAppend(result, CFSTR(")}")); + return result; +} + +static void __CFDictionaryDeallocate(CFTypeRef cf) { + CFMutableHashRef hc = (CFMutableHashRef)cf; + CFAllocatorRef allocator = __CFGetAllocator(hc); + const CFDictionaryKeyCallBacks *cb = __CFDictionaryGetKeyCallBacks(hc); + const CFDictionaryValueCallBacks *vcb = __CFDictionaryGetValueCallBacks(hc); + + // mark now in case any callout somehow tries to add an entry back in + markFinalized(cf); + if (vcb->release || cb->release) { + any_t *keys = hc->_keys; + CFIndex idx, nbuckets = hc->_bucketsNum; + for (idx = 0; idx < nbuckets; idx++) { + any_t oldkey = keys[idx]; + if (hc->_marker != oldkey && ~hc->_marker != oldkey) { + if (vcb->release) { + INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, any_t, any_pointer_t))vcb->release), allocator, hc->_values[idx], hc->_context); + } + if (cb->release) { + INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, any_t, any_pointer_t))cb->release), allocator, oldkey, hc->_context); + } + } + } + } + + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + // return early so that contents are preserved after finalization + return; + } + + _CFAllocatorDeallocateGC(allocator, hc->_keys); +#if CFDictionary || CFBag + _CFAllocatorDeallocateGC(allocator, hc->_values); +#endif + hc->_keys = NULL; + hc->_values = NULL; + hc->_count = 0; // GC: also zero count, so the hc will appear empty. + hc->_bucketsUsed = 0; + hc->_bucketsNum = 0; +} + +static CFTypeID __kCFDictionaryTypeID = _kCFRuntimeNotATypeID; + +static const CFRuntimeClass __CFDictionaryClass = { + _kCFRuntimeScannedObject, + "CFDictionary", + NULL, // init + NULL, // copy + __CFDictionaryDeallocate, + __CFDictionaryEqual, + __CFDictionaryHash, + NULL, // + __CFDictionaryCopyDescription +}; + +__private_extern__ void __CFDictionaryInitialize(void) { + __kCFHashTypeID = _CFRuntimeRegisterClass(&__CFDictionaryClass); +} + +CFTypeID CFDictionaryGetTypeID(void) { + return __kCFHashTypeID; +} + +static CFMutableHashRef __CFDictionaryInit(CFAllocatorRef allocator, CFOptionFlags flags, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks +#if CFDictionary +, const CFDictionaryValueCallBacks *valueCallBacks +#endif +) { + struct __CFDictionary *hc; + CFIndex size; + __CFBitfieldSetValue(flags, 31, 2, 0); + CFOptionFlags xflags = 0; + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + // preserve NULL for key or value CB, otherwise fix up. + if (!keyCallBacks || (keyCallBacks->retain == NULL && keyCallBacks->release == NULL)) { + xflags = __kCFHashWeakKeys; + } +#if CFDictionary + if (!valueCallBacks || (valueCallBacks->retain == NULL && valueCallBacks->release == NULL)) { + xflags |= __kCFHashWeakValues; + } +#endif +#if CFBag + xflags |= __kCFHashWeakValues; +#endif + } + if (__CFDictionaryKeyCallBacksMatchNull(keyCallBacks)) { + __CFBitfieldSetValue(flags, 3, 2, __kCFHashHasNullCallBacks); + } else if (__CFDictionaryKeyCallBacksMatchCFType(keyCallBacks)) { + __CFBitfieldSetValue(flags, 3, 2, __kCFHashHasCFTypeCallBacks); + } else { + __CFBitfieldSetValue(flags, 3, 2, __kCFHashHasCustomCallBacks); + } +#if CFDictionary + if (__CFDictionaryValueCallBacksMatchNull(valueCallBacks)) { + __CFBitfieldSetValue(flags, 5, 4, __kCFHashHasNullCallBacks); + } else if (__CFDictionaryValueCallBacksMatchCFType(valueCallBacks)) { + __CFBitfieldSetValue(flags, 5, 4, __kCFHashHasCFTypeCallBacks); + } else { + __CFBitfieldSetValue(flags, 5, 4, __kCFHashHasCustomCallBacks); + } +#endif + size = __CFDictionaryGetSizeOfType(flags) - sizeof(CFRuntimeBase); + hc = (struct __CFDictionary *)_CFRuntimeCreateInstance(allocator, __kCFHashTypeID, size, NULL); + if (NULL == hc) { + return NULL; + } + hc->_count = 0; + hc->_bucketsUsed = 0; + hc->_marker = (any_t)0xa1b1c1d3; + hc->_context = NULL; + hc->_deletes = 0; + hc->_mutations = 1; + hc->_xflags = xflags | flags; + switch (__CFBitfieldGetValue(flags, 1, 0)) { + case __kCFHashImmutable: + if (__CFOASafe) __CFSetLastAllocationEventName(hc, "CFDictionary (immutable)"); + break; + case __kCFHashMutable: + if (__CFOASafe) __CFSetLastAllocationEventName(hc, "CFDictionary (mutable-variable)"); + break; + } + hc->_bucketsCap = __CFHashRoundUpCapacity(1); + hc->_bucketsNum = 0; + hc->_keys = NULL; + hc->_values = NULL; + if (__kCFHashHasCustomCallBacks == __CFBitfieldGetValue(flags, 3, 2)) { + CFDictionaryKeyCallBacks *cb = (CFDictionaryKeyCallBacks *)__CFDictionaryGetKeyCallBacks((CFHashRef)hc); + *cb = *keyCallBacks; + FAULT_CALLBACK((void **)&(cb->retain)); + FAULT_CALLBACK((void **)&(cb->release)); + FAULT_CALLBACK((void **)&(cb->copyDescription)); + FAULT_CALLBACK((void **)&(cb->equal)); + FAULT_CALLBACK((void **)&(cb->hash)); + } +#if CFDictionary + if (__kCFHashHasCustomCallBacks == __CFBitfieldGetValue(flags, 5, 4)) { + CFDictionaryValueCallBacks *vcb = (CFDictionaryValueCallBacks *)__CFDictionaryGetValueCallBacks((CFHashRef)hc); + *vcb = *valueCallBacks; + FAULT_CALLBACK((void **)&(vcb->retain)); + FAULT_CALLBACK((void **)&(vcb->release)); + FAULT_CALLBACK((void **)&(vcb->copyDescription)); + FAULT_CALLBACK((void **)&(vcb->equal)); + } +#endif + return hc; +} + +#if CFDictionary +CFHashRef CFDictionaryCreate(CFAllocatorRef allocator, const_any_pointer_t *keys, const_any_pointer_t *values, CFIndex numValues, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks) { +#endif +#if CFSet || CFBag +CFHashRef CFDictionaryCreate(CFAllocatorRef allocator, const_any_pointer_t *keys, CFIndex numValues, const CFDictionaryKeyCallBacks *keyCallBacks) { +#endif + CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__, numValues); +#if CFDictionary + CFMutableHashRef hc = __CFDictionaryInit(allocator, __kCFHashImmutable, numValues, keyCallBacks, valueCallBacks); +#endif +#if CFSet || CFBag + CFMutableHashRef hc = __CFDictionaryInit(allocator, __kCFHashImmutable, numValues, keyCallBacks); +#endif + __CFBitfieldSetValue(hc->_xflags, 1, 0, __kCFHashMutable); + for (CFIndex idx = 0; idx < numValues; idx++) { +#if CFDictionary + CFDictionaryAddValue(hc, keys[idx], values[idx]); +#endif +#if CFSet || CFBag + CFDictionaryAddValue(hc, keys[idx]); +#endif + } + __CFBitfieldSetValue(hc->_xflags, 1, 0, __kCFHashImmutable); + return (CFHashRef)hc; +} + +#if CFDictionary +CFMutableHashRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks) { +#endif +#if CFSet || CFBag +CFMutableHashRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks) { +#endif + CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%ld) cannot be less than zero", __PRETTY_FUNCTION__, capacity); +#if CFDictionary + CFMutableHashRef hc = __CFDictionaryInit(allocator, __kCFHashMutable, capacity, keyCallBacks, valueCallBacks); +#endif +#if CFSet || CFBag + CFMutableHashRef hc = __CFDictionaryInit(allocator, __kCFHashMutable, capacity, keyCallBacks); +#endif + return hc; +} + +#if CFDictionary || CFSet +// does not have Add semantics for Bag; it has Set semantics ... is that best? +static void __CFDictionaryGrow(CFMutableHashRef hc, CFIndex numNewValues); + +// This creates a hc which is for CFTypes or NSObjects, with a CFRetain style ownership transfer; +// the hc does not take a retain (since it claims 1), and the caller does not need to release the inserted objects (since we do it). +// The incoming objects must also be collectable if allocated out of a collectable allocator - and are neither released nor retained. +#if CFDictionary +CFHashRef _CFDictionaryCreate_ex(CFAllocatorRef allocator, Boolean isMutable, const_any_pointer_t *keys, const_any_pointer_t *values, CFIndex numValues) { +#endif +#if CFSet || CFBag +CFHashRef _CFDictionaryCreate_ex(CFAllocatorRef allocator, Boolean isMutable, const_any_pointer_t *keys, CFIndex numValues) { +#endif + CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__, numValues); +#if CFDictionary + CFMutableHashRef hc = __CFDictionaryInit(allocator, __kCFHashMutable, numValues, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); +#endif +#if CFSet || CFBag + CFMutableHashRef hc = __CFDictionaryInit(allocator, __kCFHashMutable, numValues, &kCFTypeDictionaryKeyCallBacks); +#endif + __CFDictionaryGrow(hc, numValues); + for (CFIndex idx = 0; idx < numValues; idx++) { + CFIndex match, nomatch; + __CFDictionaryFindBuckets2(hc, (any_t)keys[idx], &match, &nomatch); + if (kCFNotFound == match) { + CFAllocatorRef allocator = __CFGetAllocator(hc); + any_t newKey = (any_t)keys[idx]; + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFDictionaryFindNewMarker(hc); + } + if (hc->_keys[nomatch] == ~hc->_marker) { + hc->_deletes--; + } + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[nomatch], newKey); +#if CFDictionary + any_t newValue = (any_t)values[idx]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[nomatch], newValue); +#endif +#if CFBag + hc->_values[nomatch] = 1; +#endif + hc->_bucketsUsed++; + hc->_count++; + } else { + CFAllocatorRef allocator = __CFGetAllocator(hc); +#if CFSet || CFBag + any_t oldKey = hc->_keys[match]; + any_t newKey = (any_t)keys[idx]; + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], ~hc->_marker); + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFDictionaryFindNewMarker(hc); + } + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], newKey); + RELEASEKEY(oldKey); +#endif +#if CFDictionary + any_t oldValue = hc->_values[match]; + any_t newValue = (any_t)values[idx]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[match], newValue); + RELEASEVALUE(oldValue); +#endif + } + } + if (!isMutable) __CFBitfieldSetValue(hc->_xflags, 1, 0, __kCFHashImmutable); + return (CFHashRef)hc; +} +#endif + +CFHashRef CFDictionaryCreateCopy(CFAllocatorRef allocator, CFHashRef other) { + CFMutableHashRef hc = CFDictionaryCreateMutableCopy(allocator, CFDictionaryGetCount(other), other); + __CFBitfieldSetValue(hc->_xflags, 1, 0, __kCFHashImmutable); + if (__CFOASafe) __CFSetLastAllocationEventName(hc, "CFDictionary (immutable)"); + return hc; +} + +CFMutableHashRef CFDictionaryCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFHashRef other) { + CFIndex numValues = CFDictionaryGetCount(other); + const_any_pointer_t *list, buffer[256]; + list = (numValues <= 256) ? buffer : (const_any_pointer_t *)CFAllocatorAllocate(allocator, numValues * sizeof(const_any_pointer_t), 0); + if (list != buffer && __CFOASafe) __CFSetLastAllocationEventName(list, "CFDictionary (temp)"); +#if CFDictionary + const_any_pointer_t *vlist, vbuffer[256]; + vlist = (numValues <= 256) ? vbuffer : (const_any_pointer_t *)CFAllocatorAllocate(allocator, numValues * sizeof(const_any_pointer_t), 0); + if (vlist != vbuffer && __CFOASafe) __CFSetLastAllocationEventName(vlist, "CFDictionary (temp)"); +#endif +#if CFSet || CFBag + CFDictionaryGetValues(other, list); +#endif +#if CFDictionary + CFDictionaryGetKeysAndValues(other, list, vlist); +#endif + const CFDictionaryKeyCallBacks *kcb; + const CFDictionaryValueCallBacks *vcb; + if (CF_IS_OBJC(__kCFHashTypeID, other)) { + kcb = &kCFTypeDictionaryKeyCallBacks; + vcb = &kCFTypeDictionaryValueCallBacks; + } else { + kcb = __CFDictionaryGetKeyCallBacks(other); + vcb = __CFDictionaryGetValueCallBacks(other); + } +#if CFDictionary + CFMutableHashRef hc = __CFDictionaryInit(allocator, __kCFHashMutable, capacity, kcb, vcb); +#endif +#if CFSet || CFBag + CFMutableHashRef hc = __CFDictionaryInit(allocator, __kCFHashMutable, capacity, kcb); +#endif + if (0 == capacity) _CFDictionarySetCapacity(hc, numValues); + for (CFIndex idx = 0; idx < numValues; idx++) { +#if CFDictionary + CFDictionaryAddValue(hc, list[idx], vlist[idx]); +#endif +#if CFSet || CFBag + CFDictionaryAddValue(hc, list[idx]); +#endif + } + if (list != buffer) CFAllocatorDeallocate(allocator, list); +#if CFDictionary + if (vlist != vbuffer) CFAllocatorDeallocate(allocator, vlist); +#endif + return hc; +} + +// Used by NSHashTables/NSMapTables and KVO +void _CFDictionarySetContext(CFHashRef hc, any_pointer_t context) { + __CFGenericValidateType(hc, __kCFHashTypeID); + CF_WRITE_BARRIER_BASE_ASSIGN(__CFGetAllocator(hc), hc, hc->_context, context); +} + +any_pointer_t _CFDictionaryGetContext(CFHashRef hc) { + __CFGenericValidateType(hc, __kCFHashTypeID); + return hc->_context; +} + +CFIndex CFDictionaryGetCount(CFHashRef hc) { + if (CFDictionary || CFSet) CF_OBJC_FUNCDISPATCH0(__kCFHashTypeID, CFIndex, hc, "count"); + __CFGenericValidateType(hc, __kCFHashTypeID); + return hc->_count; +} + +#if CFDictionary +CFIndex CFDictionaryGetCountOfKey(CFHashRef hc, const_any_pointer_t key) { +#endif +#if CFSet || CFBag +CFIndex CFDictionaryGetCountOfValue(CFHashRef hc, const_any_pointer_t key) { +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, CFIndex, hc, "countForKey:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, CFIndex, hc, "countForObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return 0; + CFIndex match = __CFDictionaryFindBuckets1(hc, (any_t)key); + return (kCFNotFound != match ? __CFHashGetOccurrenceCount(hc, match) : 0); +} + +#if CFDictionary +Boolean CFDictionaryContainsKey(CFHashRef hc, const_any_pointer_t key) { +#endif +#if CFSet || CFBag +Boolean CFDictionaryContainsValue(CFHashRef hc, const_any_pointer_t key) { +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, char, hc, "containsKey:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, char, hc, "containsObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return false; + CFIndex match = __CFDictionaryFindBuckets1(hc, (any_t)key); + return (kCFNotFound != match ? true : false); +} + +#if CFDictionary +CFIndex CFDictionaryGetCountOfValue(CFHashRef hc, const_any_pointer_t value) { + CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, CFIndex, hc, "countForObject:", value); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return 0; + any_t *keys = hc->_keys; + Boolean (*equal)(any_t, any_t, any_pointer_t) = (Boolean (*)(any_t, any_t, any_pointer_t))__CFDictionaryGetValueCallBacks(hc)->equal; + CFIndex cnt = 0; + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + if ((hc->_values[idx] == (any_t)value) || (equal && INVOKE_CALLBACK3(equal, hc->_values[idx], (any_t)value, hc->_context))) { + cnt++; + } + } + } + return cnt; +} + +Boolean CFDictionaryContainsValue(CFHashRef hc, const_any_pointer_t value) { + CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, char, hc, "containsObject:", value); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return false; + any_t *keys = hc->_keys; + Boolean (*equal)(any_t, any_t, any_pointer_t) = (Boolean (*)(any_t, any_t, any_pointer_t))__CFDictionaryGetValueCallBacks(hc)->equal; + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + if ((hc->_values[idx] == (any_t)value) || (equal && INVOKE_CALLBACK3(equal, hc->_values[idx], (any_t)value, hc->_context))) { + return true; + } + } + } + return false; +} +#endif + +const_any_pointer_t CFDictionaryGetValue(CFHashRef hc, const_any_pointer_t key) { + if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, const_any_pointer_t, hc, "objectForKey:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, const_any_pointer_t, hc, "member:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return 0; + CFIndex match = __CFDictionaryFindBuckets1(hc, (any_t)key); + return (kCFNotFound != match ? (const_any_pointer_t)(CFDictionary ? hc->_values[match] : hc->_keys[match]) : 0); +} + +Boolean CFDictionaryGetValueIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *value) { + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, Boolean, hc, "_getValue:forKey:", (any_t *)value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, Boolean, hc, "_getValue:forObj:", (any_t *)value, key); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return false; + CFIndex match = __CFDictionaryFindBuckets1(hc, (any_t)key); + return (kCFNotFound != match ? ((value ? __CFObjCStrongAssign((const_any_pointer_t)(CFDictionary ? hc->_values[match] : hc->_keys[match]), value) : 0), true) : false); +} + +#if CFDictionary +Boolean CFDictionaryGetKeyIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *actualkey) { + CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, Boolean, hc, "getActualKey:forKey:", actualkey, key); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return false; + CFIndex match = __CFDictionaryFindBuckets1(hc, (any_t)key); + return (kCFNotFound != match ? ((actualkey ? __CFObjCStrongAssign((const_any_pointer_t)hc->_keys[match], actualkey) : NULL), true) : false); +} +#endif + +#if CFDictionary +void CFDictionaryGetKeysAndValues(CFHashRef hc, const_any_pointer_t *keybuf, const_any_pointer_t *valuebuf) { +#endif +#if CFSet || CFBag +void CFDictionaryGetValues(CFHashRef hc, const_any_pointer_t *keybuf) { + const_any_pointer_t *valuebuf = 0; +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "getObjects:andKeys:", (any_t *)valuebuf, (any_t *)keybuf); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "getObjects:", (any_t *)keybuf); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (CF_USING_COLLECTABLE_MEMORY) { + // GC: speculatively issue a write-barrier on the copied to buffers + __CFObjCWriteBarrierRange(keybuf, hc->_count * sizeof(any_t)); + __CFObjCWriteBarrierRange(valuebuf, hc->_count * sizeof(any_t)); + } + any_t *keys = hc->_keys; + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + for (CFIndex cnt = __CFHashGetOccurrenceCount(hc, idx); cnt--;) { + if (keybuf) *keybuf++ = (const_any_pointer_t)keys[idx]; + if (valuebuf) *valuebuf++ = (const_any_pointer_t)hc->_values[idx]; + } + } + } +} + +#if CFDictionary || CFSet +unsigned long _CFDictionaryFastEnumeration(CFHashRef hc, struct __objcFastEnumerationStateEquivalent *state, void *stackbuffer, unsigned long count) { + /* copy as many as count items over */ + if (0 == state->state) { /* first time */ + state->mutationsPtr = (unsigned long *)&hc->_mutations; + } + state->itemsPtr = (unsigned long *)stackbuffer; + CFIndex cnt = 0; + any_t *keys = hc->_keys; + for (CFIndex idx = (CFIndex)state->state, nbuckets = hc->_bucketsNum; idx < nbuckets && cnt < (CFIndex)count; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + state->itemsPtr[cnt++] = (unsigned long)keys[idx]; + } + state->state++; + } + return cnt; +} +#endif + +void CFDictionaryApplyFunction(CFHashRef hc, CFDictionaryApplierFunction applier, any_pointer_t context) { + FAULT_CALLBACK((void **)&(applier)); + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "_apply:context:", applier, context); + if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "_applyValues:context:", applier, context); + __CFGenericValidateType(hc, __kCFHashTypeID); + any_t *keys = hc->_keys; + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + for (CFIndex cnt = __CFHashGetOccurrenceCount(hc, idx); cnt--;) { +#if CFDictionary + INVOKE_CALLBACK3(applier, (const_any_pointer_t)keys[idx], (const_any_pointer_t)hc->_values[idx], context); +#endif +#if CFSet || CFBag + INVOKE_CALLBACK2(applier, (const_any_pointer_t)keys[idx], context); +#endif + } + } + } +} + +static void __CFDictionaryGrow(CFMutableHashRef hc, CFIndex numNewValues) { + any_t *oldkeys = hc->_keys; + any_t *oldvalues = hc->_values; + CFIndex nbuckets = hc->_bucketsNum; + hc->_bucketsCap = __CFHashRoundUpCapacity(hc->_bucketsUsed + numNewValues); + hc->_bucketsNum = __CFHashNumBucketsForCapacity(hc->_bucketsCap); + hc->_deletes = 0; + CFAllocatorRef allocator = __CFGetAllocator(hc); + CFOptionFlags weakOrStrong = (hc->_xflags & __kCFHashWeakKeys) ? 0 : __kCFAllocatorGCScannedMemory; + any_t *mem = (any_t *)_CFAllocatorAllocateGC(allocator, hc->_bucketsNum * sizeof(any_t), weakOrStrong); + if (NULL == mem) __CFDictionaryHandleOutOfMemory(hc, hc->_bucketsNum * sizeof(any_t)); + if (__CFOASafe) __CFSetLastAllocationEventName(mem, "CFDictionary (key-store)"); + CF_WRITE_BARRIER_BASE_ASSIGN(allocator, hc, hc->_keys, mem); + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; // GC: avoids write-barrier in weak case. + any_t *keysBase = mem; +#if CFDictionary || CFBag + weakOrStrong = (hc->_xflags & __kCFHashWeakValues) ? 0 : __kCFAllocatorGCScannedMemory; + mem = (any_t *)_CFAllocatorAllocateGC(allocator, hc->_bucketsNum * sizeof(any_t), weakOrStrong); + if (NULL == mem) __CFDictionaryHandleOutOfMemory(hc, hc->_bucketsNum * sizeof(any_t)); + if (__CFOASafe) __CFSetLastAllocationEventName(mem, "CFDictionary (value-store)"); + CF_WRITE_BARRIER_BASE_ASSIGN(allocator, hc, hc->_values, mem); +#endif +#if CFDictionary + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; // GC: avoids write-barrier in weak case. + any_t *valuesBase = mem; +#endif + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + hc->_keys[idx] = hc->_marker; +#if CFDictionary || CFBag + hc->_values[idx] = 0; +#endif + } + if (NULL == oldkeys) return; + for (CFIndex idx = 0; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, oldkeys[idx])) { + CFIndex match, nomatch; + __CFDictionaryFindBuckets2(hc, oldkeys[idx], &match, &nomatch); + CFAssert3(kCFNotFound == match, __kCFLogAssertion, "%s(): two values (%p, %p) now hash to the same slot; mutable value changed while in table or hash value is not immutable", __PRETTY_FUNCTION__, oldkeys[idx], hc->_keys[match]); + if (kCFNotFound != nomatch) { + CF_WRITE_BARRIER_BASE_ASSIGN(keysAllocator, keysBase, hc->_keys[nomatch], oldkeys[idx]); +#if CFDictionary + CF_WRITE_BARRIER_BASE_ASSIGN(valuesAllocator, valuesBase, hc->_values[nomatch], oldvalues[idx]); +#endif +#if CFBag + hc->_values[nomatch] = oldvalues[idx]; +#endif + } + } + } + _CFAllocatorDeallocateGC(allocator, oldkeys); + _CFAllocatorDeallocateGC(allocator, oldvalues); +} + +// This function is for Foundation's benefit; no one else should use it. +void _CFDictionarySetCapacity(CFMutableHashRef hc, CFIndex cap) { + if (CF_IS_OBJC(__kCFHashTypeID, hc)) return; + __CFGenericValidateType(hc, __kCFHashTypeID); + CFAssert1(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): collection is immutable", __PRETTY_FUNCTION__); + CFAssert3(hc->_bucketsUsed <= cap, __kCFLogAssertion, "%s(): desired capacity (%ld) is less than bucket count (%ld)", __PRETTY_FUNCTION__, cap, hc->_bucketsUsed); + __CFDictionaryGrow(hc, cap - hc->_bucketsUsed); +} + + +#if CFDictionary +void CFDictionaryAddValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_pointer_t value) { +#endif +#if CFSet || CFBag +void CFDictionaryAddValue(CFMutableHashRef hc, const_any_pointer_t key) { + #define value 0 +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "_addObject:forKey:", value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "addObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + switch (__CFHashGetType(hc)) { + case __kCFHashMutable: + if (hc->_bucketsUsed == hc->_bucketsCap || NULL == hc->_keys) { + __CFDictionaryGrow(hc, 1); + } + break; + default: + CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + break; + } + hc->_mutations++; + CFIndex match, nomatch; + __CFDictionaryFindBuckets2(hc, (any_t)key, &match, &nomatch); + if (kCFNotFound != match) { +#if CFBag + CF_OBJC_KVO_WILLCHANGE(hc, hc->_keys[match]); + hc->_values[match]++; + hc->_count++; + CF_OBJC_KVO_DIDCHANGE(hc, hc->_keys[match]); +#endif + } else { + CFAllocatorRef allocator = __CFGetAllocator(hc); + GETNEWKEY(newKey, key); +#if CFDictionary + GETNEWVALUE(newValue); +#endif + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFDictionaryFindNewMarker(hc); + } + if (hc->_keys[nomatch] == ~hc->_marker) { + hc->_deletes--; + } + CF_OBJC_KVO_WILLCHANGE(hc, key); + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[nomatch], newKey); +#if CFDictionary + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[nomatch], newValue); +#endif +#if CFBag + hc->_values[nomatch] = 1; +#endif + hc->_bucketsUsed++; + hc->_count++; + CF_OBJC_KVO_DIDCHANGE(hc, key); + } +} + +#if CFDictionary +void CFDictionaryReplaceValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_pointer_t value) { +#endif +#if CFSet || CFBag +void CFDictionaryReplaceValue(CFMutableHashRef hc, const_any_pointer_t key) { + #define value 0 +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "_replaceObject:forKey:", value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "_replaceObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + switch (__CFHashGetType(hc)) { + case __kCFHashMutable: + break; + default: + CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + break; + } + hc->_mutations++; + if (0 == hc->_bucketsUsed) return; + CFIndex match = __CFDictionaryFindBuckets1(hc, (any_t)key); + if (kCFNotFound == match) return; + CFAllocatorRef allocator = __CFGetAllocator(hc); +#if CFSet || CFBag + GETNEWKEY(newKey, key); +#endif +#if CFDictionary + GETNEWVALUE(newValue); +#endif + any_t oldKey = hc->_keys[match]; + CF_OBJC_KVO_WILLCHANGE(hc, oldKey); +#if CFSet || CFBag + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], ~hc->_marker); + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFDictionaryFindNewMarker(hc); + } + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], newKey); +#endif +#if CFDictionary + any_t oldValue = hc->_values[match]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[match], newValue); +#endif + CF_OBJC_KVO_DIDCHANGE(hc, oldKey); +#if CFSet || CFBag + RELEASEKEY(oldKey); +#endif +#if CFDictionary + RELEASEVALUE(oldValue); +#endif +} + +#if CFDictionary +void CFDictionarySetValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_pointer_t value) { +#endif +#if CFSet || CFBag +void CFDictionarySetValue(CFMutableHashRef hc, const_any_pointer_t key) { + #define value 0 +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "setObject:forKey:", value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "_setObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + switch (__CFHashGetType(hc)) { + case __kCFHashMutable: + if (hc->_bucketsUsed == hc->_bucketsCap || NULL == hc->_keys) { + __CFDictionaryGrow(hc, 1); + } + break; + default: + CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + break; + } + hc->_mutations++; + CFIndex match, nomatch; + __CFDictionaryFindBuckets2(hc, (any_t)key, &match, &nomatch); + if (kCFNotFound == match) { + CFAllocatorRef allocator = __CFGetAllocator(hc); + GETNEWKEY(newKey, key); +#if CFDictionary + GETNEWVALUE(newValue); +#endif + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFDictionaryFindNewMarker(hc); + } + if (hc->_keys[nomatch] == ~hc->_marker) { + hc->_deletes--; + } + CF_OBJC_KVO_WILLCHANGE(hc, key); + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[nomatch], newKey); +#if CFDictionary + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[nomatch], newValue); +#endif +#if CFBag + hc->_values[nomatch] = 1; +#endif + hc->_bucketsUsed++; + hc->_count++; + CF_OBJC_KVO_DIDCHANGE(hc, key); + } else { + CFAllocatorRef allocator = __CFGetAllocator(hc); +#if CFSet || CFBag + GETNEWKEY(newKey, key); +#endif +#if CFDictionary + GETNEWVALUE(newValue); +#endif + any_t oldKey = hc->_keys[match]; + CF_OBJC_KVO_WILLCHANGE(hc, oldKey); +#if CFSet || CFBag + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], ~hc->_marker); + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFDictionaryFindNewMarker(hc); + } + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], newKey); +#endif +#if CFDictionary + any_t oldValue = hc->_values[match]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[match], newValue); +#endif + CF_OBJC_KVO_DIDCHANGE(hc, oldKey); +#if CFSet || CFBag + RELEASEKEY(oldKey); +#endif +#if CFDictionary + RELEASEVALUE(oldValue); +#endif + } +} + +void CFDictionaryRemoveValue(CFMutableHashRef hc, const_any_pointer_t key) { + if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "removeObjectForKey:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "removeObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + switch (__CFHashGetType(hc)) { + case __kCFHashMutable: + break; + default: + CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + break; + } + hc->_mutations++; + if (0 == hc->_bucketsUsed) return; + CFIndex match = __CFDictionaryFindBuckets1(hc, (any_t)key); + if (kCFNotFound == match) return; + if (1 < __CFHashGetOccurrenceCount(hc, match)) { +#if CFBag + CF_OBJC_KVO_WILLCHANGE(hc, hc->_keys[match]); + hc->_values[match]--; + hc->_count--; + CF_OBJC_KVO_DIDCHANGE(hc, hc->_keys[match]); +#endif + } else { + CFAllocatorRef allocator = __CFGetAllocator(hc); + any_t oldKey = hc->_keys[match]; + CF_OBJC_KVO_WILLCHANGE(hc, oldKey); + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], ~hc->_marker); +#if CFDictionary + any_t oldValue = hc->_values[match]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[match], 0); +#endif +#if CFBag + hc->_values[match] = 0; +#endif + hc->_count--; + hc->_bucketsUsed--; + hc->_deletes++; + CF_OBJC_KVO_DIDCHANGE(hc, oldKey); + RELEASEKEY(oldKey); +#if CFDictionary + RELEASEVALUE(oldValue); +#endif + if (__CFDictionaryShouldShrink(hc)) { + __CFDictionaryGrow(hc, 0); + } else { + // When the probeskip == 1 always and only, a DELETED slot followed by an EMPTY slot + // can be converted to an EMPTY slot. By extension, a chain of DELETED slots followed + // by an EMPTY slot can be converted to EMPTY slots, which is what we do here. + if (match < hc->_bucketsNum - 1 && hc->_keys[match + 1] == hc->_marker) { + while (0 <= match && hc->_keys[match] == ~hc->_marker) { + hc->_keys[match] = hc->_marker; + hc->_deletes--; + match--; + } + } + } + } +} + +void CFDictionaryRemoveAllValues(CFMutableHashRef hc) { + if (CFDictionary) CF_OBJC_FUNCDISPATCH0(__kCFHashTypeID, void, hc, "removeAllObjects"); + if (CFSet) CF_OBJC_FUNCDISPATCH0(__kCFHashTypeID, void, hc, "removeAllObjects"); + __CFGenericValidateType(hc, __kCFHashTypeID); + switch (__CFHashGetType(hc)) { + case __kCFHashMutable: + break; + default: + CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + break; + } + hc->_mutations++; + if (0 == hc->_bucketsUsed) return; + CFAllocatorRef allocator = __CFGetAllocator(hc); + any_t *keys = hc->_keys; + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + any_t oldKey = keys[idx]; + CF_OBJC_KVO_WILLCHANGE(hc, oldKey); +#if CFDictionary || CFSet + hc->_count--; +#endif +#if CFBag + hc->_count -= hc->_values[idx]; +#endif + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[idx], ~hc->_marker); +#if CFDictionary + any_t oldValue = hc->_values[idx]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[idx], 0); +#endif +#if CFBag + hc->_values[idx] = 0; +#endif + hc->_bucketsUsed--; + hc->_deletes++; + CF_OBJC_KVO_DIDCHANGE(hc, oldKey); + RELEASEKEY(oldKey); +#if CFDictionary + RELEASEVALUE(oldValue); +#endif + } + } + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + keys[idx] = hc->_marker; + } + hc->_deletes = 0; + hc->_bucketsUsed = 0; + hc->_count = 0; + if (__CFDictionaryShouldShrink(hc) && (256 <= hc->_bucketsCap)) { + __CFDictionaryGrow(hc, 128); + } +} + +#undef CF_OBJC_KVO_WILLCHANGE +#undef CF_OBJC_KVO_DIDCHANGE + diff --git a/Collections.subproj/CFDictionary.h b/CFDictionary.h similarity index 94% rename from Collections.subproj/CFDictionary.h rename to CFDictionary.h index 86a0a75..2ca8ecf 100644 --- a/Collections.subproj/CFDictionary.h +++ b/CFDictionary.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFDictionary.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ /*! @@ -45,14 +45,9 @@ Dictionaries come in two flavors, immutable, which cannot have values added to them or removed from them after the dictionary is created, and mutable, to which you can add values or from which - remove values. Mutable dictionaries have two subflavors, - fixed-capacity, for which there is a maximum number set at creation - time of values which can be put into the dictionary, and variable - capacity, which can have an unlimited number of values (or rather, - limited only by constraints external to CFDictionary, like the - amount of available memory). Fixed-capacity dictionaries can be - somewhat higher performing, if you can put a definate upper limit - on the number of values that might be put into the dictionary. + remove values. Mutable dictionaries can have an unlimited number + of values (or rather, limited only by constraints external to + CFDictionary, like the amount of available memory). As with all CoreFoundation collection types, dictionaries maintain hard references on the values you put in them, but the retaining and @@ -88,9 +83,7 @@ #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN /*! @typedef CFDictionaryKeyCallBacks @@ -338,13 +331,12 @@ CFDictionaryRef CFDictionaryCreateCopy(CFAllocatorRef allocator, CFDictionaryRef parameter may be NULL in which case the current default CFAllocator is used. If this reference is not a valid CFAllocator, the behavior is undefined. - @param capacity The maximum number of values that can be contained by - the CFDictionary. The dictionary starts empty, and can grow - to this number of values (and it can have less). If this - parameter is 0, the dictionary's maximum capacity is unlimited - (or rather, only limited by address space and available memory - constraints). If this parameter is negative, the behavior is - undefined. + @param capacity A hint about the number of values that will be held + by the CFDictionary. Pass 0 for no hint. The implementation may + ignore this hint, or may use it to optimize various + operations. A dictionary's actual capacity is only limited by + address space and available memory constraints). If this + parameter is negative, the behavior is undefined. @param keyCallBacks A pointer to a CFDictionaryKeyCallBacks structure initialized with the callbacks for the dictionary to use on each key in the dictionary. A copy of the contents of the @@ -412,15 +404,15 @@ CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFInd parameter may be NULL in which case the current default CFAllocator is used. If this reference is not a valid CFAllocator, the behavior is undefined. - @param capacity The maximum number of values that can be contained - by the CFDictionary. The dictionary starts empty, and can grow - to this number of values (and it can have less). If this - parameter is 0, the dictionary's maximum capacity is unlimited - (or rather, only limited by address space and available memory - constraints). This parameter must be greater than or equal - to the count of the dictionary which is to be copied, or the - behavior is undefined. If this parameter is negative, the - behavior is undefined. + @param capacity A hint about the number of values that will be held + by the CFDictionary. Pass 0 for no hint. The implementation may + ignore this hint, or may use it to optimize various + operations. A dictionary's actual capacity is only limited by + address space and available memory constraints). + This parameter must be greater than or equal + to the count of the dictionary which is to be copied, or the + behavior is undefined. If this parameter is negative, the + behavior is undefined. @param theDict The dictionary which is to be copied. The keys and values from the dictionary are copied as pointers into the new dictionary (that is, the values themselves are copied, not @@ -610,8 +602,7 @@ void CFDictionaryApplyFunction(CFDictionaryRef theDict, CFDictionaryApplierFunct Adds the key-value pair to the dictionary if no such key already exists. @param theDict The dictionary to which the value is to be added. If this parameter is not a valid mutable CFDictionary, the behavior is - undefined. If the dictionary is a fixed-capacity dictionary and - it is full before this operation, the behavior is undefined. + undefined. @param key The key of the value to add to the dictionary. The key is retained by the dictionary using the retain callback provided when the dictionary was created. If the key is not of the sort @@ -631,9 +622,7 @@ void CFDictionaryAddValue(CFMutableDictionaryRef theDict, const void *key, const Sets the value of the key in the dictionary. @param theDict The dictionary to which the value is to be set. If this parameter is not a valid mutable CFDictionary, the behavior is - undefined. If the dictionary is a fixed-capacity dictionary and - it is full before this operation, and the key does not exist in - the dictionary, the behavior is undefined. + undefined. @param key The key of the value to set into the dictionary. If a key which matches this key is already present in the dictionary, only the value is changed ("add if absent, replace if present"). If @@ -694,9 +683,7 @@ void CFDictionaryRemoveValue(CFMutableDictionaryRef theDict, const void *key); CF_EXPORT void CFDictionaryRemoveAllValues(CFMutableDictionaryRef theDict); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFDICTIONARY__ */ diff --git a/CFError.c b/CFError.c new file mode 100644 index 0000000..cae7644 --- /dev/null +++ b/CFError.c @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFError.c + Copyright 2006, Apple, Inc. All rights reserved. + Responsibility: Ali Ozer +*/ + +#include +#include +#include "CFInternal.h" +#include "CFPriv.h" +#if DEPLOYMENT_TARGET_MACOSX +#include +#include +#endif + +/* Pre-defined userInfo keys +*/ +CONST_STRING_DECL(kCFErrorLocalizedDescriptionKey, "NSLocalizedDescription"); +CONST_STRING_DECL(kCFErrorLocalizedFailureReasonKey, "NSLocalizedFailureReason"); +CONST_STRING_DECL(kCFErrorLocalizedRecoverySuggestionKey, "NSLocalizedRecoverySuggestion"); +CONST_STRING_DECL(kCFErrorDescriptionKey, "NSDescription"); +CONST_STRING_DECL(kCFErrorDebugDescriptionKey, "NSDebugDescription"); +CONST_STRING_DECL(kCFErrorUnderlyingErrorKey, "NSUnderlyingError"); + +/* Pre-defined error domains +*/ +CONST_STRING_DECL(kCFErrorDomainPOSIX, "NSPOSIXErrorDomain"); +CONST_STRING_DECL(kCFErrorDomainOSStatus, "NSOSStatusErrorDomain"); +CONST_STRING_DECL(kCFErrorDomainMach, "NSMachErrorDomain"); +CONST_STRING_DECL(kCFErrorDomainCocoa, "NSCocoaErrorDomain"); + +/* We put the localized names of domain names here so genstrings can pick them out. Any additional domains that are added should be listed here if we'd like them localized. + +CFCopyLocalizedStringWithDefaultValue(CFSTR("NSMachErrorDomain"), CFSTR("Error"), NULL, CFSTR("Mach"), "Name of the 'Mach' error domain when showing to user. This probably will not get localized, unless there is a generally recognized phrase for 'Mach' in the language.") +CFCopyLocalizedStringWithDefaultValue(CFSTR("NSCoreFoundationErrorDomain"), CFSTR("Error"), NULL, CFSTR("Core Foundation"), "Name of the 'Core Foundation' error domain when showing to user. Very likely this will not get localized differently in other languages.") +CFCopyLocalizedStringWithDefaultValue(CFSTR("NSPOSIXErrorDomain"), CFSTR("Error"), NULL, CFSTR("POSIX"), "Name of the 'POSIX' error domain when showing to user. This probably will not get localized, unless there is a generally recognized phrase for 'POSIX' in the language.") +CFCopyLocalizedStringWithDefaultValue(CFSTR("NSOSStatusErrorDomain"), CFSTR("Error"), NULL, CFSTR("OSStatus"), "Name of the 'OSStatus' error domain when showing to user. Very likely this will not get localized.") +CFCopyLocalizedStringWithDefaultValue(CFSTR("NSCocoaErrorDomain"), CFSTR("Error"), NULL, CFSTR("Cocoa"), "Name of the 'Cocoa' error domain when showing to user. Very likely this will not get localized.") +*/ + + + +/* Forward declarations +*/ +static CFDictionaryRef _CFErrorGetUserInfo(CFErrorRef err); +static CFStringRef _CFErrorCopyUserInfoKey(CFErrorRef err, CFStringRef key); +static CFDictionaryRef _CFErrorCreateEmptyDictionary(CFAllocatorRef allocator); + +/* Assertions and other macros/inlines +*/ +#define __CFAssertIsError(cf) __CFGenericValidateType(cf, __kCFErrorTypeID) + +/* This lock is used in the few places in CFError where we create and access shared static objects. Should only be around tiny snippets of code; no recursion +*/ +static CFSpinLock_t _CFErrorSpinlock = CFSpinLockInit; + + + + +/**** CFError CF runtime stuff ****/ + +struct __CFError { // Potentially interesting to keep layout same as NSError (but currently not a requirement) + CFRuntimeBase _base; + CFIndex code; + CFStringRef domain; // !!! Could compress well-known domains down to few bits, but probably not worth its weight in code since CFErrors are rare + CFDictionaryRef userInfo; // !!! Could avoid allocating this slot if userInfo is NULL, but probably not worth its weight in code since CFErrors are rare +}; + +/* CFError equal checks for equality of domain, code, and userInfo. +*/ +static Boolean __CFErrorEqual(CFTypeRef cf1, CFTypeRef cf2) { + CFErrorRef err1 = (CFErrorRef)cf1; + CFErrorRef err2 = (CFErrorRef)cf2; + + // First do quick checks of code and domain (in that order for performance) + if (CFErrorGetCode(err1) != CFErrorGetCode(err2)) return false; + if (!CFEqual(CFErrorGetDomain(err1), CFErrorGetDomain(err2))) return false; + + // If those are equal, then check the dictionaries + CFDictionaryRef dict1 = CFErrorCopyUserInfo(err1); + CFDictionaryRef dict2 = CFErrorCopyUserInfo(err2); + + Boolean result = false; + + if (dict1 == dict2) { + result = true; + } else if (dict1 && dict2 && CFEqual(dict1, dict2)) { + result = true; + } + + if (dict1) CFRelease(dict1); + if (dict2) CFRelease(dict2); + + return result; +} + +/* CFError hash code is hash(domain) + code +*/ +static CFHashCode __CFErrorHash(CFTypeRef cf) { + CFErrorRef err = (CFErrorRef)cf; + /* !!! We do not need an assertion here, as this is called by the CFBase runtime only */ + return CFHash(err->domain) + err->code; +} + +/* This is the full debug description. Shows the description (possibly localized), plus the domain, code, and userInfo explicitly. If there is a debug description, shows that as well. +*/ +static CFStringRef __CFErrorCopyDescription(CFTypeRef cf) { + return _CFErrorCreateDebugDescription((CFErrorRef)cf); +} + +/* This is the description you get for %@; we tone it down a bit from what you get in __CFErrorCopyDescription(). +*/ +static CFStringRef __CFErrorCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { + CFErrorRef err = (CFErrorRef)cf; + return CFErrorCopyDescription(err); // No need to release, since we are returning from a Copy function +} + +static void __CFErrorDeallocate(CFTypeRef cf) { + CFErrorRef err = (CFErrorRef)cf; + CFRelease(err->domain); + CFRelease(err->userInfo); +} + + +static CFTypeID __kCFErrorTypeID = _kCFRuntimeNotATypeID; + +static const CFRuntimeClass __CFErrorClass = { + 0, + "CFError", + NULL, // init + NULL, // copy + __CFErrorDeallocate, + __CFErrorEqual, + __CFErrorHash, + __CFErrorCopyFormattingDescription, + __CFErrorCopyDescription +}; + +__private_extern__ void __CFErrorInitialize(void) { + __kCFErrorTypeID = _CFRuntimeRegisterClass(&__CFErrorClass); +} + +CFTypeID CFErrorGetTypeID(void) { + return __kCFErrorTypeID; +} + + + + +/**** CFError support functions ****/ + +/* Returns a shared empty dictionary (unless the allocator is not kCFAllocatorSystemDefault, in which case returns a newly allocated one). +*/ +static CFDictionaryRef _CFErrorCreateEmptyDictionary(CFAllocatorRef allocator) { + if (allocator == NULL) allocator = __CFGetDefaultAllocator(); + if (allocator == kCFAllocatorSystemDefault) { + static CFDictionaryRef emptyErrorDictionary = NULL; + if (emptyErrorDictionary == NULL) { + CFDictionaryRef tmp = CFDictionaryCreate(allocator, NULL, NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + __CFSpinLock(&_CFErrorSpinlock); + if (emptyErrorDictionary == NULL) { + emptyErrorDictionary = tmp; + __CFSpinUnlock(&_CFErrorSpinlock); + } else { + __CFSpinUnlock(&_CFErrorSpinlock); + CFRelease(tmp); + } + } + return (CFDictionaryRef)CFRetain(emptyErrorDictionary); + } else { + return CFDictionaryCreate(allocator, NULL, NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + } +} + +/* A non-retained accessor for the userInfo. Might return NULL in some cases, if the subclass of NSError returned nil for some reason. It works with a CF or NSError. +*/ +static CFDictionaryRef _CFErrorGetUserInfo(CFErrorRef err) { + CF_OBJC_FUNCDISPATCH0(__kCFErrorTypeID, CFDictionaryRef, err, "userInfo"); + __CFAssertIsError(err); + return err->userInfo; +} + +/* This function retrieves the value of the specified key from the userInfo, or from the callback. It works with a CF or NSError. +*/ +static CFStringRef _CFErrorCopyUserInfoKey(CFErrorRef err, CFStringRef key) { + CFStringRef result = NULL; + // First consult the userInfo dictionary + CFDictionaryRef userInfo = _CFErrorGetUserInfo(err); + if (userInfo) result = (CFStringRef)CFDictionaryGetValue(userInfo, key); + // If that doesn't work, consult the callback + if (result) { + CFRetain(result); + } else { + CFErrorUserInfoKeyCallBack callBack = CFErrorGetCallBackForDomain(CFErrorGetDomain(err)); + if (callBack) result = (CFStringRef)callBack(err, key); + } + return result; +} + +/* The real guts of the description creation functionality. See the header file for the steps this function goes through to compute the description. This function can take a CF or NSError. It's called by NSError for the localizedDescription computation. +*/ +CFStringRef _CFErrorCreateLocalizedDescription(CFErrorRef err) { + // First look for kCFErrorLocalizedDescriptionKey; if non-NULL, return that as-is. + CFStringRef localizedDesc = _CFErrorCopyUserInfoKey(err, kCFErrorLocalizedDescriptionKey); + if (localizedDesc) return localizedDesc; + + // Cache the CF bundle since we will be using it for localized strings. !!! Might be good to check for NULL, although that indicates some serious problem. + CFBundleRef cfBundle = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreFoundation")); + + // Then look for kCFErrorLocalizedFailureReasonKey; if there, create a full sentence from that. + CFStringRef reason = _CFErrorCopyUserInfoKey(err, kCFErrorLocalizedFailureReasonKey); + if (reason) { + CFStringRef operationFailedStr = CFCopyLocalizedStringFromTableInBundle(CFSTR("Operation could not be completed. %@"), CFSTR("Error"), cfBundle, "A generic error string indicating there was a problem. The %@ will be replaced by a second sentence which indicates why the operation failed."); + CFStringRef result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, operationFailedStr, reason); + CFRelease(operationFailedStr); + CFRelease(reason); + return result; + } + + // Otherwise, generate a semi-user presentable string from the domain, code, and if available, the presumably non-localized kCFErrorDescriptionKey. + CFStringRef result; + CFStringRef desc = _CFErrorCopyUserInfoKey(err, kCFErrorDescriptionKey); + CFStringRef localizedDomain = CFCopyLocalizedStringFromTableInBundle(CFErrorGetDomain(err), CFSTR("Error"), cfBundle, "These are localized in the comment above"); + if (desc) { // We have kCFErrorDescriptionKey, so include that with the error domain and code + CFStringRef operationFailedStr = CFCopyLocalizedStringFromTableInBundle(CFSTR("Operation could not be completed. (%@ error %ld - %@)"), CFSTR("Error"), cfBundle, "A generic error string indicating there was a problem, followed by a parenthetical sentence which indicates error domain, code, and a description when there is no other way to present an error to the user. The first %@ indicates the error domain, %ld indicates the error code, and the second %@ indicates the description; so this might become '(Mach error 42 - Server error.)' for instance."); + result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, operationFailedStr, localizedDomain, (long)CFErrorGetCode(err), desc); + CFRelease(operationFailedStr); + CFRelease(desc); + } else { // We don't have kCFErrorDescriptionKey, so just use error domain and code + CFStringRef operationFailedStr = CFCopyLocalizedStringFromTableInBundle(CFSTR("Operation could not be completed. (%@ error %ld.)"), CFSTR("Error"), cfBundle, "A generic error string indicating there was a problem, followed by a parenthetical sentence which indicates error domain and code when there is no other way to present an error to the user. The %@ indicates the error domain while %ld indicates the error code; so this might become '(Mach error 42.)' for instance."); + result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, operationFailedStr, localizedDomain, (long)CFErrorGetCode(err)); + CFRelease(operationFailedStr); + } + CFRelease(localizedDomain); + return result; +} + +/* 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. +*/ +CFStringRef _CFErrorCreateLocalizedFailureReason(CFErrorRef err) { + // We simply return the value of kCFErrorLocalizedFailureReasonKey; no other searching takes place + return _CFErrorCopyUserInfoKey(err, kCFErrorLocalizedFailureReasonKey); +} + +/* The real guts of the recovery suggestion functionality. This function can take a CF or NSError. It's called by NSError for the localizedRecoverySuggestion computation. +*/ +CFStringRef _CFErrorCreateLocalizedRecoverySuggestion(CFErrorRef err) { + // We simply return the value of kCFErrorLocalizedRecoverySuggestionKey; no other searching takes place + return _CFErrorCopyUserInfoKey(err, kCFErrorLocalizedRecoverySuggestionKey); +} + +/* The "debug" description, used by CFCopyDescription and -[NSObject description]. +*/ +CFStringRef _CFErrorCreateDebugDescription(CFErrorRef err) { + CFStringRef desc = CFErrorCopyDescription(err); + CFStringRef debugDesc = _CFErrorCopyUserInfoKey(err, kCFErrorDebugDescriptionKey); + CFDictionaryRef userInfo = _CFErrorGetUserInfo(err); + 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); + CFStringAppendFormat(result, NULL, CFSTR(" \"%@\""), desc); + if (debugDesc && CFStringGetLength(debugDesc) > 0) CFStringAppendFormat(result, NULL, CFSTR(" (%@)"), debugDesc); + if (debugDesc) CFRelease(debugDesc); + if (desc) CFRelease(desc); + return result; +} + + + + +/**** CFError API/SPI ****/ + +/* Note that there are two entry points for creating CFErrors. This one does it with a presupplied userInfo dictionary. +*/ +CFErrorRef CFErrorCreate(CFAllocatorRef allocator, CFStringRef domain, CFIndex code, CFDictionaryRef userInfo) { + __CFGenericValidateType(domain, CFStringGetTypeID()); + if (userInfo) __CFGenericValidateType(userInfo, CFDictionaryGetTypeID()); + + CFErrorRef err = (CFErrorRef)_CFRuntimeCreateInstance(allocator, __kCFErrorTypeID, sizeof(struct __CFError) - sizeof(CFRuntimeBase), NULL); + if (NULL == err) return NULL; + + err->domain = CFStringCreateCopy(allocator, domain); + err->code = code; + err->userInfo = userInfo ? CFDictionaryCreateCopy(allocator, userInfo) : _CFErrorCreateEmptyDictionary(allocator); + + return err; +} + +/* Note that there are two entry points for creating CFErrors. This one does it with individual keys and values which are used to create the userInfo dictionary. +*/ +CFErrorRef CFErrorCreateWithUserInfoKeysAndValues(CFAllocatorRef allocator, CFStringRef domain, CFIndex code, const void *const *userInfoKeys, const void *const *userInfoValues, CFIndex numUserInfoValues) { + __CFGenericValidateType(domain, CFStringGetTypeID()); + + CFErrorRef err = (CFErrorRef)_CFRuntimeCreateInstance(allocator, __kCFErrorTypeID, sizeof(struct __CFError) - sizeof(CFRuntimeBase), NULL); + if (NULL == err) return NULL; + + err->domain = CFStringCreateCopy(allocator, domain); + err->code = code; + err->userInfo = CFDictionaryCreate(allocator, (const void **)userInfoKeys, (const void **)userInfoValues, numUserInfoValues, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + return err; +} + +CFStringRef CFErrorGetDomain(CFErrorRef err) { + CF_OBJC_FUNCDISPATCH0(__kCFErrorTypeID, CFStringRef, err, "domain"); + __CFAssertIsError(err); + return err->domain; +} + +CFIndex CFErrorGetCode(CFErrorRef err) { + CF_OBJC_FUNCDISPATCH0(__kCFErrorTypeID, CFIndex, err, "code"); + __CFAssertIsError(err); + return err->code; +} + +/* This accessor never returns NULL. For usage inside this file, consider __CFErrorGetUserInfo(). +*/ +CFDictionaryRef CFErrorCopyUserInfo(CFErrorRef err) { + CFDictionaryRef userInfo = _CFErrorGetUserInfo(err); + return userInfo ? (CFDictionaryRef)CFRetain(userInfo) : _CFErrorCreateEmptyDictionary(CFGetAllocator(err)); +} + +CFStringRef CFErrorCopyDescription(CFErrorRef err) { + if (CF_IS_OBJC(__kCFErrorTypeID, err)) { // Since we have to return a retained result, we need to treat the toll-free bridging specially + CFStringRef desc; + CF_OBJC_CALL0(CFStringRef, desc, err, "localizedDescription"); + return desc ? (CFStringRef)CFRetain(desc) : NULL; // !!! It really should never return nil. + } + __CFAssertIsError(err); + return _CFErrorCreateLocalizedDescription(err); +} + +CFStringRef CFErrorCopyFailureReason(CFErrorRef err) { + if (CF_IS_OBJC(__kCFErrorTypeID, err)) { // Since we have to return a retained result, we need to treat the toll-free bridging specially + CFStringRef str; + CF_OBJC_CALL0(CFStringRef, str, err, "localizedFailureReason"); + return str ? (CFStringRef)CFRetain(str) : NULL; // It's possible for localizedFailureReason to return nil + } + __CFAssertIsError(err); + return _CFErrorCreateLocalizedFailureReason(err); +} + +CFStringRef CFErrorCopyRecoverySuggestion(CFErrorRef err) { + if (CF_IS_OBJC(__kCFErrorTypeID, err)) { // Since we have to return a retained result, we need to treat the toll-free bridging specially + CFStringRef str; + CF_OBJC_CALL0(CFStringRef, str, err, "localizedRecoverySuggestion"); + return str ? (CFStringRef)CFRetain(str) : NULL; // It's possible for localizedRecoverySuggestion to return nil + } + __CFAssertIsError(err); + return _CFErrorCreateLocalizedRecoverySuggestion(err); +} + + +/**** CFError CallBack management ****/ + +/* Domain-to-callback mapping dictionary +*/ +static CFMutableDictionaryRef _CFErrorCallBackTable = NULL; + + +/* Built-in callback for POSIX domain. Note that we will pick up localizations from ErrnoErrors.strings in /System/Library/CoreServices/CoreTypes.bundle, if the file happens to be there. +*/ +static CFTypeRef _CFErrorPOSIXCallBack(CFErrorRef err, CFStringRef key) { + if (!CFEqual(key, kCFErrorDescriptionKey) && !CFEqual(key, kCFErrorLocalizedFailureReasonKey)) return NULL; + + const char *errCStr = strerror(CFErrorGetCode(err)); + CFStringRef errStr = (errCStr && strlen(errCStr)) ? CFStringCreateWithCString(kCFAllocatorSystemDefault, errCStr, kCFStringEncodingUTF8) : NULL; + + if (!errStr) return NULL; + if (CFEqual(key, kCFErrorDescriptionKey)) return errStr; // If all we wanted was the non-localized description, we're done + + // 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); + if (paths) { + if (CFArrayGetCount(paths) > 0) { + CFStringRef path = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@/CoreServices/CoreTypes.bundle"), CFArrayGetValueAtIndex(paths, 0)); + CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, path, kCFURLPOSIXPathStyle, false /* not a directory */); + if (url) { + CFBundleRef bundle = CFBundleCreate(kCFAllocatorSystemDefault, url); + if (bundle) { + // We only want to return a result if there was a localization + CFStringRef localizedErrStr = CFBundleCopyLocalizedString(bundle, errStr, errStr, CFSTR("ErrnoErrors")); + if (localizedErrStr == errStr) { + CFRelease(localizedErrStr); + CFRelease(errStr); + errStr = NULL; + } else { + CFRelease(errStr); + errStr = localizedErrStr; + } + CFRelease(bundle); + } + CFRelease(url); + } + CFRelease(path); + } + CFRelease(paths); + } + + return errStr; +} + +#if DEPLOYMENT_TARGET_MACOSX +/* Built-in callback for Mach domain. +*/ +static CFTypeRef _CFErrorMachCallBack(CFErrorRef err, CFStringRef key) { + if (CFEqual(key, kCFErrorDescriptionKey)) { + const char *errStr = mach_error_string(CFErrorGetCode(err)); + if (errStr && strlen(errStr)) return CFStringCreateWithCString(kCFAllocatorSystemDefault, errStr, kCFStringEncodingUTF8); + } + return NULL; +} +#endif + + +/* This initialize function is meant to be called lazily, the first time a callback is registered or requested. It creates the table and registers the built-in callbacks. Clearly doing this non-lazily in _CFErrorInitialize() would be simpler, but this is a fine example of something that should not have to happen at launch time. +*/ +static void _CFErrorInitializeCallBackTable(void) { + // Create the table outside the lock + CFMutableDictionaryRef table = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, NULL); + __CFSpinLock(&_CFErrorSpinlock); + if (!_CFErrorCallBackTable) { + _CFErrorCallBackTable = table; + __CFSpinUnlock(&_CFErrorSpinlock); + } else { + __CFSpinUnlock(&_CFErrorSpinlock); + CFRelease(table); + // Note, even though the table looks like it was initialized, we go on to register the items on this thread as well, since otherwise we might consult the table before the items are actually registered. + } + CFErrorSetCallBackForDomain(kCFErrorDomainPOSIX, _CFErrorPOSIXCallBack); +#if DEPLOYMENT_TARGET_MACOSX + CFErrorSetCallBackForDomain(kCFErrorDomainMach, _CFErrorMachCallBack); +#endif +} + +void CFErrorSetCallBackForDomain(CFStringRef domainName, CFErrorUserInfoKeyCallBack callBack) { + if (!_CFErrorCallBackTable) _CFErrorInitializeCallBackTable(); + __CFSpinLock(&_CFErrorSpinlock); + if (callBack) { + CFDictionarySetValue(_CFErrorCallBackTable, domainName, callBack); + } else { + CFDictionaryRemoveValue(_CFErrorCallBackTable, domainName); + } + __CFSpinUnlock(&_CFErrorSpinlock); +} + +CFErrorUserInfoKeyCallBack CFErrorGetCallBackForDomain(CFStringRef domainName) { + if (!_CFErrorCallBackTable) _CFErrorInitializeCallBackTable(); + __CFSpinLock(&_CFErrorSpinlock); + CFErrorUserInfoKeyCallBack callBack = (CFErrorUserInfoKeyCallBack)CFDictionaryGetValue(_CFErrorCallBackTable, domainName); + __CFSpinUnlock(&_CFErrorSpinlock); + return callBack; +} + + + diff --git a/CFError.h b/CFError.h new file mode 100644 index 0000000..4382294 --- /dev/null +++ b/CFError.h @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFError.h + Copyright (c) 2006-2007, Apple Inc. All rights reserved. +*/ + +/*! + @header CFError + @discussion + CFErrors are used to encompass information about errors. At minimum, errors are identified by their domain (a string) and an error code within that domain. In addition a "userInfo" dictionary supplied at creation time enables providing additional info that might be useful for the interpretation and reporting of the error. This dictionary can even contain an "underlying" error, which is wrapped as an error bubbles up through various layers. + + CFErrors have the ability to provide human-readable descriptions for the errors; in fact, they are designed to provide localizable, end-user presentable errors that can appear in the UI. CFError has a number of predefined userInfo keys to enable developers to supply the info. + + Usage recommendation for CFErrors is to return them as by-ref parameters in functions. This enables the caller to pass NULL in when they don't actually want information about the error. The presence of an error should be reported by other means, for instance a NULL or false return value from the function call proper: + + CFError *error; + if (!ReadFromFile(fd, &error)) { + ... process error ... + CFRelease(error); // If an error occurs, the returned CFError must be released. + } + + It is the responsibility of anyone returning CFErrors this way to: + - Not touch the error argument if no error occurs + - Create and assign the error for return only if the error argument is non-NULL + + In addition, it's recommended that CFErrors be used in error situations only (not status), and where there are multiple possible errors to distinguish between. For instance there is no plan to add CFErrors to existing APIs in CF which currently don't return errors; in many cases, there is one possible reason for failure, and a false or NULL return is enough to indicate it. + + CFError is toll-free bridged to NSError in Foundation. NSError in Foundation has some additional guidelines which makes it easy to automatically report errors to users and even try to recover from them. See http://developer.apple.com/documentation/Cocoa/Conceptual/ErrorHandlingCocoa/ErrorHandling/chapter_1_section_1.html for more info on NSError programming guidelines. +*/ + +#if !defined(__COREFOUNDATION_CFERROR__) +#define __COREFOUNDATION_CFERROR__ 1 + +#include +#include +#include + +CF_EXTERN_C_BEGIN + +/*! + @typedef CFErrorRef + This is the type of a reference to CFErrors. CFErrorRef is toll-free bridged with NSError. +*/ +typedef struct __CFError * CFErrorRef; + +/*! + @function CFErrorGetTypeID + Returns the type identifier of all CFError instances. +*/ +CF_EXPORT +CFTypeID CFErrorGetTypeID(void) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; + + +// 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; + +// 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. + +// 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. + +// 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. + + +/*! + @function CFErrorCreate + @abstract Creates a new CFError. + @param allocator The CFAllocator which should be used to allocate memory for the error. This parameter may be NULL in which case the + current default CFAllocator is used. If this reference is not a valid CFAllocator, the behavior is undefined. + @param domain A CFString identifying the error domain. If this reference is NULL or is otherwise not a valid CFString, the behavior is undefined. + @param code A CFIndex identifying the error code. The code is interpreted within the context of the error domain. + @param userInfo A CFDictionary created with kCFCopyStringDictionaryKeyCallBacks and kCFTypeDictionaryValueCallBacks. It will be copied with CFDictionaryCreateCopy(). + If no userInfo dictionary is desired, NULL may be passed in as a convenience, in which case an empty userInfo dictionary will be assigned. + @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; + +/*! + @function CFErrorCreateWithUserInfoKeysAndValues + @abstract Creates a new CFError without having to create an intermediate userInfo dictionary. + @param allocator The CFAllocator which should be used to allocate memory for the error. This parameter may be NULL in which case the + current default CFAllocator is used. If this reference is not a valid CFAllocator, the behavior is undefined. + @param domain A CFString identifying the error domain. If this reference is NULL or is otherwise not a valid CFString, the behavior is undefined. + @param code A CFIndex identifying the error code. The code is interpreted within the context of the error domain. + @param userInfoKeys An array of numUserInfoValues CFStrings used as keys in creating the userInfo dictionary. NULL is valid only if numUserInfoValues is 0. + @param userInfoValues An array of numUserInfoValues CF types used as values in creating the userInfo dictionary. NULL is valid only if numUserInfoValues is 0. + @param numUserInfoValues CFIndex representing the number of keys and values in the userInfoKeys and userInfoValues arrays. + @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; + +/*! + @function CFErrorGetDomain + @abstract Returns the error domain the CFError was created with. + @param err The CFError whose error domain is to be returned. If this reference is not a valid CFError, the behavior is undefined. + @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; + +/*! + @function CFErrorGetCode + @abstract Returns the error code the CFError was created with. + @param err The CFError whose error code is to be returned. If this reference is not a valid CFError, the behavior is undefined. + @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; + +/*! + @function CFErrorCopyUserInfo + @abstract Returns CFError userInfo dictionary. + @discussion Returns a dictionary containing the same keys and values as in the userInfo dictionary the CFError was created with. Returns an empty dictionary if NULL was supplied to CFErrorCreate(). + @param err The CFError whose error user info is to be returned. If this reference is not a valid CFError, the behavior is undefined. + @result The user info of the CFError. +*/ +CF_EXPORT +CFDictionaryRef CFErrorCopyUserInfo(CFErrorRef err) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; + +/*! + @function CFErrorCopyDescription + @abstract Returns a human-presentable description for the error. CFError creators should strive to make sure the return value is human-presentable and localized by providing a value for kCFErrorLocalizedDescriptionKey at the time of CFError creation. + @discussion This is a complete sentence or two which says what failed and why it failed. Rules for computing the return value: + - Look for kCFErrorLocalizedDescriptionKey in the user info and if not NULL, returns that as-is. + - Otherwise, if there is a kCFErrorLocalizedFailureReasonKey in the user info, generate an error from that. Something like: "Operation code not be completed. " + kCFErrorLocalizedFailureReasonKey + - Otherwise, generate a semi-user presentable string from kCFErrorDescriptionKey, the domain, and code. Something like: "Operation could not be completed. Error domain/code occurred. " or "Operation could not be completed. " + kCFErrorDescriptionKey + " (Error domain/code)" + Toll-free bridged NSError instances might provide additional behaviors for manufacturing a description string. Do not count on the exact contents or format of the returned string, it might change. + @param err The CFError whose description is to be returned. If this reference is not a valid CFError, the behavior is undefined. + @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; + +/*! + @function CFErrorCopyFailureReason + @abstract Returns a human-presentable failure reason for the error. May return NULL. CFError creators should strive to make sure the return value is human-presentable and localized by providing a value for kCFErrorLocalizedFailureReasonKey at the time of CFError creation. + @discussion This is a complete sentence which describes why the operation failed. In many cases this will be just the "because" part of the description (but as a complete sentence, which makes localization easier). By default this looks for kCFErrorLocalizedFailureReasonKey in the user info. Toll-free bridged NSError instances might provide additional behaviors for manufacturing this value. If no user-presentable string is available, returns NULL. + Example Description: "Could not save file 'Letter' in folder 'Documents' because the volume 'MyDisk' doesn't have enough space." + Corresponding FailureReason: "The volume 'MyDisk' doesn't have enough space." + @param err The CFError whose failure reason is to be returned. If this reference is not a valid CFError, the behavior is undefined. + @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; + +/*! + @function CFErrorCopyRecoverySuggestion + @abstract Returns a human presentable recovery suggestion for the error. May return NULL. CFError creators should strive to make sure the return value is human-presentable and localized by providing a value for kCFErrorLocalizedRecoverySuggestionKey at the time of CFError creation. + @discussion This is the string that can be displayed as the "informative" (aka "secondary") message on an alert panel. By default this looks for kCFErrorLocalizedRecoverySuggestionKey in the user info. Toll-free bridged NSError instances might provide additional behaviors for manufacturing this value. If no user-presentable string is available, returns NULL. + Example Description: "Could not save file 'Letter' in folder 'Documents' because the volume 'MyDisk' doesn't have enough space." + Corresponding RecoverySuggestion: "Remove some files from the volume and try again." + @param err The CFError whose recovery suggestion is to be returned. If this reference is not a valid CFError, the behavior is undefined. + @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; + + + +CF_EXTERN_C_END + +#endif /* ! __COREFOUNDATION_CFERROR__ */ + diff --git a/CFError_Private.h b/CFError_Private.h new file mode 100644 index 0000000..2cfd3ea --- /dev/null +++ b/CFError_Private.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFError_Private.h + Copyright (c) 2006-2007, Apple Inc. All rights reserved. + + This is Apple-internal SPI for CFError. +*/ + +#if !defined(__COREFOUNDATION_CFERRORPRIVATE__) +#define __COREFOUNDATION_CFERRORPRIVATE__ 1 + +#include + +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; + +/* 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 kCFErrorDebugDescription AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; + + +CF_EXTERN_C_END + +#endif /* ! __COREFOUNDATION_CFERRORPRIVATE__ */ + diff --git a/Base.subproj/CFFileUtilities.c b/CFFileUtilities.c similarity index 68% rename from Base.subproj/CFFileUtilities.c rename to CFFileUtilities.c index 9a17577..cdeca52 100644 --- a/Base.subproj/CFFileUtilities.c +++ b/CFFileUtilities.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -27,67 +27,54 @@ #include "CFInternal.h" #include "CFPriv.h" -#if defined(__WIN32__) - #include - #include - #include - #include - #define timeval xxx_timeval - #define BOOLEAN xxx_BOOLEAN - #include - #undef BOOLEAN - #undef timeval - #define fstat _fstat - #define open _open - #define close _close - #define write _write - #define read _read - #define stat _stat -#else - #include - #include - #include - #include - #include - #include - #include - #include - #include -#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include -#if defined(__WIN32__) - #define CF_OPENFLGS (_O_BINARY|_O_NOINHERIT) -#else - #define CF_OPENFLGS (0) -#endif +#define CF_OPENFLGS (0) __private_extern__ CFStringRef _CFCopyExtensionForAbstractType(CFStringRef abstractType) { - return (abstractType ? CFRetain(abstractType) : NULL); + return (abstractType ? (CFStringRef)CFRetain(abstractType) : NULL); } __private_extern__ Boolean _CFCreateDirectory(const char *path) { -#if defined(__WIN32__) +#if 0 || 0 return CreateDirectoryA(path, (LPSECURITY_ATTRIBUTES)NULL); #else - return ((mkdir(path, 0777) == 0) ? true : false); + int no_hang_fd = open("/dev/autofs_nowait", 0); + int ret = ((mkdir(path, 0777) == 0) ? true : false); + close(no_hang_fd); + return ret; #endif } __private_extern__ Boolean _CFRemoveDirectory(const char *path) { -#if defined(__WIN32__) +#if 0 || 0 return RemoveDirectoryA(path); #else - return ((rmdir(path) == 0) ? true : false); + int no_hang_fd = open("/dev/autofs_nowait", 0); + int ret = ((rmdir(path) == 0) ? true : false); + close(no_hang_fd); + return ret; #endif } __private_extern__ Boolean _CFDeleteFile(const char *path) { -#if defined(__WIN32__) +#if 0 || 0 return DeleteFileA(path); #else - return unlink(path) == 0; + int no_hang_fd = open("/dev/autofs_nowait", 0); + int ret = unlink(path) == 0; + close(no_hang_fd); + return ret; #endif } @@ -96,29 +83,33 @@ __private_extern__ Boolean _CFReadBytesFromFile(CFAllocatorRef alloc, CFURLRef u struct stat statBuf; int fd = -1; char path[CFMaxPathSize]; - if (!CFURLGetFileSystemRepresentation(url, true, path, CFMaxPathSize)) { + if (!CFURLGetFileSystemRepresentation(url, true, (uint8_t *)path, CFMaxPathSize)) { return false; } *bytes = NULL; -#if defined(__WIN32__) +#if 0 || 0 fd = open(path, O_RDONLY|CF_OPENFLGS, 0666|_S_IREAD); #else + int no_hang_fd = open("/dev/autofs_nowait", 0); fd = open(path, O_RDONLY|CF_OPENFLGS, 0666); #endif if (fd < 0) { + close(no_hang_fd); return false; } if (fstat(fd, &statBuf) < 0) { int saveerr = thread_errno(); close(fd); + close(no_hang_fd); thread_set_errno(saveerr); return false; } if ((statBuf.st_mode & S_IFMT) != S_IFREG) { close(fd); + close(no_hang_fd); thread_set_errno(EACCES); return false; } @@ -139,40 +130,33 @@ __private_extern__ Boolean _CFReadBytesFromFile(CFAllocatorRef alloc, CFURLRef u if (read(fd, *bytes, desiredLength) < 0) { CFAllocatorDeallocate(alloc, *bytes); close(fd); + close(no_hang_fd); return false; } *length = desiredLength; } close(fd); + close(no_hang_fd); return true; } __private_extern__ Boolean _CFWriteBytesToFile(CFURLRef url, const void *bytes, CFIndex length) { struct stat statBuf; int fd = -1; - int mode, mask; + int mode; char path[CFMaxPathSize]; - if (!CFURLGetFileSystemRepresentation(url, true, path, CFMaxPathSize)) { + if (!CFURLGetFileSystemRepresentation(url, true, (uint8_t *)path, CFMaxPathSize)) { return false; } -#if defined(__WIN32__) - mask = 0; -#else - mask = umask(0); - umask(mask); -#endif - mode = 0666 & ~mask; +#if 0 || 0 + mode = 0666; if (0 == stat(path, &statBuf)) { mode = statBuf.st_mode; } else if (thread_errno() != ENOENT) { return false; } -#if defined(__WIN32__) fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|CF_OPENFLGS, 0666|_S_IWRITE); -#else - fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|CF_OPENFLGS, 0666); -#endif if (fd < 0) { return false; } @@ -182,18 +166,40 @@ __private_extern__ Boolean _CFWriteBytesToFile(CFURLRef url, const void *bytes, thread_set_errno(saveerr); return false; } -#if defined(__WIN32__) FlushFileBuffers((HANDLE)_get_osfhandle(fd)); + close(fd); #else + int no_hang_fd = open("/dev/autofs_nowait", 0); + mode = 0666; + if (0 == stat(path, &statBuf)) { + mode = statBuf.st_mode; + } else if (thread_errno() != ENOENT) { + close(no_hang_fd); + return false; + } + fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|CF_OPENFLGS, 0666); + if (fd < 0) { + close(no_hang_fd); + return false; + } + if (length && write(fd, bytes, length) != length) { + int saveerr = thread_errno(); + close(fd); + close(no_hang_fd); + thread_set_errno(saveerr); + return false; + } fsync(fd); -#endif close(fd); + close(no_hang_fd); +#endif return true; } /* On Mac OS 8/9, one of dirSpec and dirURL must be non-NULL. On all other platforms, one of path and dirURL must be non-NULL If both are present, they are assumed to be in-synch; that is, they both refer to the same directory. */ +/* Lately, dirSpec appears to be (rightfully) unused. */ __private_extern__ CFMutableArrayRef _CFContentsOfDirectory(CFAllocatorRef alloc, char *dirPath, void *dirSpec, CFURLRef dirURL, CFStringRef matchingAbstractType) { CFMutableArrayRef files = NULL; Boolean releaseBase = false; @@ -204,7 +210,7 @@ __private_extern__ CFMutableArrayRef _CFContentsOfDirectory(CFAllocatorRef alloc uint8_t extBuff[CFMaxPathSize]; if (extLen > 0) { - CFStringGetBytes(extension, CFRangeMake(0, extLen), CFStringFileSystemEncoding(), 0, false, extBuff, CFMaxPathSize, &extLen); + CFStringGetBytes(extension, CFRangeMake(0, extLen), CFStringFileSystemEncoding(), 0, false, extBuff, CFMaxPathLength, &extLen); extBuff[extLen] = '\0'; } @@ -215,82 +221,30 @@ __private_extern__ CFMutableArrayRef _CFContentsOfDirectory(CFAllocatorRef alloc if (extension) CFRelease(extension); return NULL; } else { - dirPath = pathBuf; + dirPath = (char *)pathBuf; pathLength = strlen(dirPath); } } -#if defined(__WIN32__) - WIN32_FIND_DATA file; - HANDLE handle; - - if (pathLength + 2 >= CFMaxPathLength) { - if (extension) { - CFRelease(extension); - } - return NULL; - } - - dirPath[pathLength] = '\\'; - dirPath[pathLength + 1] = '*'; - dirPath[pathLength + 2] = '\0'; - handle = FindFirstFileA(dirPath, &file); - if (INVALID_HANDLE_VALUE == handle) { - dirPath[pathLength] = '\0'; - if (extension) { - CFRelease(extension); - } - return NULL; - } - - files = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks); - - do { - CFURLRef fileURL; - CFIndex namelen = strlen(file.cFileName); - if (file.cFileName[0] == '.' && (namelen == 1 || (namelen == 2 && file.cFileName[1] == '.'))) { - continue; - } - if (extLen > 0) { - // Check to see if it matches the extension we're looking for. - if (_stricmp(&(file.cFileName[namelen - extLen]), extBuff) != 0) { - continue; - } - } - if (dirURL == NULL) { - dirURL = CFURLCreateFromFileSystemRepresentation(alloc, dirPath, pathLength, true); - releaseBase = true; - } - // MF:!!! What about the trailing slash? - fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc, file.cFileName, namelen, false, dirURL); - CFArrayAppendValue(files, fileURL); - CFRelease(fileURL); - } while (FindNextFileA(handle, &file)); - FindClose(handle); - dirPath[pathLength] = '\0'; - -#elif defined(__svr4__) || defined(__hpux__) || defined(__LINUX__) || defined(__FREEBSD__) - /* Solaris and HPUX Implementation */ - /* The Solaris and HPUX code has not been updated for: - base has been renamed dirURL - dirPath may be NULL (in which case dirURL is not) - if dirPath is NULL, pathLength is 0 - */ - DIR *dirp; +#if (DEPLOYMENT_TARGET_MACOSX) || defined(__svr4__) || defined(__hpux__) || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD + struct dirent buffer; struct dirent *dp; int err; - - dirp = opendir(dirPath); + + int no_hang_fd = open("/dev/autofs_nowait", 0); + + DIR *dirp = opendir(dirPath); if (!dirp) { if (extension) { CFRelease(extension); } + close(no_hang_fd); return NULL; // raiseErrno("opendir", path); } files = CFArrayCreateMutable(alloc, 0, & kCFTypeArrayCallBacks); - while((dp = readdir(dirp)) != NULL) { + while((0 == readdir_r(dirp, &buffer, &dp)) && dp) { CFURLRef fileURL; unsigned namelen = strlen(dp->d_name); @@ -298,23 +252,41 @@ __private_extern__ CFMutableArrayRef _CFContentsOfDirectory(CFAllocatorRef alloc if (dp->d_name[0] == '.' && (namelen == 1 || (namelen == 2 && dp->d_name[1] == '.'))) { 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]), extBuff, extLen) != 0) { + if (strncmp(&(dp->d_name[namelen - extLen]), (char *)extBuff, extLen) != 0) { continue; } } if (dirURL == NULL) { - dirURL = CFURLCreateFromFileSystemRepresentation(alloc, dirPath, pathLength, true); + dirURL = CFURLCreateFromFileSystemRepresentation(alloc, (uint8_t *)dirPath, pathLength, true); releaseBase = true; } - // MF:!!! What about the trailing slash? - fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc, dp->d_name, namelen, false, dirURL); + if (dp->d_type == DT_DIR || dp->d_type == DT_UNKNOWN) { + Boolean isDir = (dp->d_type == DT_DIR); + if (!isDir) { + // Ugh; must stat. + char subdirPath[CFMaxPathLength]; + struct stat statBuf; + strlcpy(subdirPath, dirPath, sizeof(subdirPath)); + strlcat(subdirPath, "/", sizeof(subdirPath)); + strlcat(subdirPath, dp->d_name, sizeof(subdirPath)); + if (stat(subdirPath, &statBuf) == 0) { + isDir = ((statBuf.st_mode & S_IFMT) == S_IFDIR); + } + } + fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc, (uint8_t *)dp->d_name, dp->d_namlen, isDir, dirURL); + } else { + fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase (alloc, (uint8_t *)dp->d_name, dp->d_namlen, false, dirURL); + } CFArrayAppendValue(files, fileURL); CFRelease(fileURL); } err = closedir(dirp); + close(no_hang_fd); if (err != 0) { CFRelease(files); if (releaseBase) { @@ -324,78 +296,8 @@ __private_extern__ CFMutableArrayRef _CFContentsOfDirectory(CFAllocatorRef alloc CFRelease(extension); } return NULL; - // raiseErrno("closedir", path); } -#elif defined(__MACH__) - int fd, numread; - long basep; - char dirge[8192]; - - fd = open(dirPath, O_RDONLY, 0777); - if (fd < 0) { - if (extension) { - CFRelease(extension); - } - return NULL; - } - files = CFArrayCreateMutable(alloc, 0, &kCFTypeArrayCallBacks); - - while ((numread = getdirentries(fd, dirge, sizeof(dirge), &basep)) > 0) { - struct dirent *dent; - for (dent = (struct dirent *)dirge; dent < (struct dirent *)(dirge + numread); dent = (struct dirent *)((char *)dent + dent->d_reclen)) { - CFURLRef fileURL; - CFIndex nameLen; - - nameLen = dent->d_namlen; - // skip . & ..; they cause descenders to go berserk - if (0 == dent->d_fileno || (dent->d_name[0] == '.' && (nameLen == 1 || (nameLen == 2 && dent->d_name[1] == '.')))) { - continue; - } - if (extLen > 0) { - // Check to see if it matches the extension we're looking for. - if (strncmp(&(dent->d_name[nameLen - extLen]), extBuff, extLen) != 0) { - continue; - } - } - if (dirURL == NULL) { - dirURL = CFURLCreateFromFileSystemRepresentation(alloc, dirPath, pathLength, true); - releaseBase = true; - } - - if (dent->d_type == DT_DIR || dent->d_type == DT_UNKNOWN) { - Boolean isDir = (dent->d_type == DT_DIR); - if (!isDir) { - // Ugh; must stat. - char subdirPath[CFMaxPathLength]; - struct stat statBuf; - strncpy(subdirPath, dirPath, pathLength); - subdirPath[pathLength] = '/'; - strncpy(subdirPath + pathLength + 1, dent->d_name, nameLen); - subdirPath[pathLength + nameLen + 1] = '\0'; - if (stat(subdirPath, &statBuf) == 0) { - isDir = ((statBuf.st_mode & S_IFMT) == S_IFDIR); - } - } - fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase(alloc, dent->d_name, nameLen, isDir, dirURL); - } else { - fileURL = CFURLCreateFromFileSystemRepresentationRelativeToBase (alloc, dent->d_name, nameLen, false, dirURL); - } - CFArrayAppendValue(files, fileURL); - CFRelease(fileURL); - } - } - close(fd); - if (-1 == numread) { - CFRelease(files); - if (releaseBase) { - CFRelease(dirURL); - } - if (extension) { - CFRelease(extension); - } - return NULL; - } #else #error _CFContentsOfDirectory() unknown architechture, not implemented @@ -415,19 +317,19 @@ __private_extern__ SInt32 _CFGetFileProperties(CFAllocatorRef alloc, CFURLRef pa Boolean fileExists; Boolean isDirectory = false; - struct stat statBuf; - char path[CFMaxPathLength]; + struct stat64 statBuf; + char path[CFMaxPathSize]; if ((exists == NULL) && (posixMode == NULL) && (size == NULL) && (modTime == NULL) && (ownerID == NULL) && (dirContents == NULL)) { // Nothing to do. return 0; } - if (!CFURLGetFileSystemRepresentation(pathURL, true, path, CFMaxPathLength)) { + if (!CFURLGetFileSystemRepresentation(pathURL, true, (uint8_t *)path, CFMaxPathLength)) { return -1; } - if (stat(path, &statBuf) != 0) { + if (stat64(path, &statBuf) != 0) { // stat failed, but why? if (thread_errno() == ENOENT) { fileExists = false; @@ -466,10 +368,8 @@ __private_extern__ SInt32 _CFGetFileProperties(CFAllocatorRef alloc, CFURLRef pa if (modTime != NULL) { if (fileExists) { - CFTimeInterval theTime; - - theTime = kCFAbsoluteTimeIntervalSince1970 + statBuf.st_mtime; - + CFAbsoluteTime theTime = (CFAbsoluteTime)statBuf.st_mtimespec.tv_sec - kCFAbsoluteTimeIntervalSince1970; + theTime += (CFAbsoluteTime)statBuf.st_mtimespec.tv_nsec / 1000000000.0; *modTime = CFDateCreate(alloc, theTime); } else { *modTime = NULL; @@ -505,7 +405,7 @@ __private_extern__ SInt32 _CFGetFileProperties(CFAllocatorRef alloc, CFURLRef pa // MF:!!! Should pull in the rest of the UniChar based path utils from Foundation. -#if defined(__MACH__) || defined(__svr4__) || defined(__hpux__) || defined(__LINUX__) || defined(__FREEBSD__) +#if (DEPLOYMENT_TARGET_MACOSX) || defined(__svr4__) || defined(__hpux__) || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD #define UNIX_PATH_SEMANTICS #elif defined(__WIN32__) #define WINDOWS_PATH_SEMANTICS diff --git a/Base.subproj/CFInternal.h b/CFInternal.h similarity index 63% rename from Base.subproj/CFInternal.h rename to CFInternal.h index 471aa92..cc4bd80 100644 --- a/Base.subproj/CFInternal.h +++ b/CFInternal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFInternal.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ /* @@ -41,41 +41,38 @@ #include #include #include +#include +#include "CFLogUtilities.h" #include "CFRuntime.h" -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX #include -#include #include #endif -#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__) +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD #include #include #endif #include -#include #include "auto_stubs.h" +#if !defined (__WIN32__) +#include +#endif //__WIN32__ +#ifndef __WIN32__ #include +#endif //__WIN32__ - -#if defined(__MACH__) -#if defined(__ppc__) -// This hack is in here because B&I kernel does not set up comm page with Tiger additions yet. -#define AtomicCompareAndSwap(mem, old, new) ({bool result; if (((void **)OSMemoryBarrier)[1] == 0x0) {result = ((*(mem) == (old)) ? (*(mem) = (new), 1) : 0);} else {result = OSAtomicCompareAndSwap32(old, new, (int32_t *)mem); OSMemoryBarrier();} result;}) -#define AtomicAdd32(mem, val) ({if (((void **)OSMemoryBarrier)[1] == 0x0) {*(mem) += (val);} else {OSAtomicAdd32(val, mem); OSMemoryBarrier();} 0;}) -#else -#define AtomicCompareAndSwap(mem, old, new) ({bool result; result = OSAtomicCompareAndSwap32(old, new, (int32_t *)mem); OSMemoryBarrier(); result;}) -#define AtomicAdd32(mem, val) ({OSAtomicAdd32(val, mem); OSMemoryBarrier(); 0;}) -#endif +#if defined(__BIG_ENDIAN__) +#define __CF_BIG_ENDIAN__ 1 +#define __CF_LITTLE_ENDIAN__ 0 #endif -#include "ForFoundationOnly.h" - -#if !defined(__MACH__) -#define __private_extern__ +#if defined(__LITTLE_ENDIAN__) +#define __CF_LITTLE_ENDIAN__ 1 +#define __CF_BIG_ENDIAN__ 0 #endif -CF_EXPORT char **_CFArgv(void); -CF_EXPORT int _CFArgc(void); + +#include "ForFoundationOnly.h" CF_EXPORT const char *_CFProcessName(void); CF_EXPORT CFStringRef _CFProcessNameString(void); @@ -85,18 +82,19 @@ CF_EXPORT Boolean _CFIsCFM(void); CF_EXPORT Boolean _CFGetCurrentDirectory(char *path, int maxlen); CF_EXPORT CFStringRef _CFGetUserName(void); -CF_EXPORT CFStringRef _CFStringCreateHostName(void); -CF_EXPORT void __CFSetNastyFile(CFTypeRef cf); +CF_EXPORT CFArrayRef _CFGetWindowsBinaryDirectories(void); + +CF_EXPORT CFStringRef _CFStringCreateHostName(void); CF_EXPORT void _CFMachPortInstallNotifyPort(CFRunLoopRef rl, CFStringRef mode); #if defined(__ppc__) || defined(__ppc64__) #define HALT asm __volatile__("trap") -#elif defined(__i386__) +#elif defined(__i386__) || defined(__x86_64__) #if defined(__GNUC__) #define HALT asm __volatile__("int3") - #elif defined(_MSC_VER) || defined(__MWERKS__) + #elif defined(_MSC_VER) #define HALT __asm int 3; #else #error Compiler not supported @@ -127,15 +125,17 @@ CF_EXPORT void _CFMachPortInstallNotifyPort(CFRunLoopRef rl, CFStringRef mode); #define CFAssert4(condition, priority, description, a1, a2, a3, a4) \ __CFAssert((condition), (priority), description, (a1), (a2), (a3), (a4), 0) -#define __kCFLogAssertion 15 +#define __kCFLogAssertion 3 #if defined(DEBUG) extern void __CFGenericValidateType_(CFTypeRef cf, CFTypeID type, const char *func); #define __CFGenericValidateType(cf, type) __CFGenericValidateType_(cf, type, __PRETTY_FUNCTION__) #else -#define __CFGenericValidateType(cf, type) +#define __CFGenericValidateType(cf, type) ((void)0) #endif +#define CF_INFO_BITS (!!(__CF_BIG_ENDIAN__) * 3) +#define CF_RC_BITS (!!(__CF_LITTLE_ENDIAN__) * 3) /* Bit manipulation macros */ /* Bits are numbered from 31 on left to 0 on right */ @@ -153,39 +153,32 @@ extern void __CFGenericValidateType_(CFTypeRef cf, CFTypeID type, const char *fu typedef struct ___CFThreadSpecificData { void *_unused1; void *_allocator; - void *_runLoop; - int _runLoop_pid; // If you add things to this struct, add cleanup to __CFFinalizeThreadData() } __CFThreadSpecificData; extern __CFThreadSpecificData *__CFGetThreadSpecificData(void); __private_extern__ void __CFFinalizeThreadData(void *arg); -#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__) +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD extern pthread_key_t __CFTSDKey; #endif -#if defined(__WIN32__) -extern DWORD __CFTSDKey; -#endif //extern void *pthread_getspecific(pthread_key_t key); CF_INLINE __CFThreadSpecificData *__CFGetThreadSpecificData_inline(void) { -#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__) +#if DEPLOYMENT_TARGET_MACOSX|| DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD __CFThreadSpecificData *data = pthread_getspecific(__CFTSDKey); return data ? data : __CFGetThreadSpecificData(); #elif defined(__WIN32__) - __CFThreadSpecificData *data = TlsGetValue(__CFTSDKey); + __CFThreadSpecificData *data = (__CFThreadSpecificData *)TlsGetValue(__CFTSDKey); return data ? data : __CFGetThreadSpecificData(); #endif } -CF_EXPORT void CFLog(int p, CFStringRef str, ...); - #define __kCFAllocatorTypeID_CONST 2 CF_INLINE CFAllocatorRef __CFGetDefaultAllocator(void) { - CFAllocatorRef allocator = __CFGetThreadSpecificData_inline()->_allocator; + CFAllocatorRef allocator = (CFAllocatorRef)__CFGetThreadSpecificData_inline()->_allocator; if (NULL == allocator) { allocator = kCFAllocatorSystemDefault; } @@ -199,7 +192,7 @@ extern CFTypeID __CFGenericTypeID(const void *cf); // 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)->_info, 7, 7), 1)) { + if (__builtin_expect(__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 7, 7), 1)) { return kCFAllocatorSystemDefault; } return *(CFAllocatorRef *)((char *)cf - sizeof(CFAllocatorRef)); @@ -238,6 +231,13 @@ CF_INLINE CFAllocatorRef __CFGetAllocator(CFTypeRef cf) { // !!! Use with CF typ #define __kCFAllocatorTempMemory 0x2 #define __kCFAllocatorNoPointers 0x10 #define __kCFAllocatorDoNotRecordEvent 0x100 +#define __kCFAllocatorGCScannedMemory 0x200 /* GC: memory should be scanned. */ +#define __kCFAllocatorGCObjectMemory 0x400 /* GC: memory needs to be finalized. */ + +CF_INLINE auto_memory_type_t CF_GET_GC_MEMORY_TYPE(CFOptionFlags flags) { + auto_memory_type_t type = (flags & __kCFAllocatorGCScannedMemory ? 0 : AUTO_UNSCANNED) | (flags & __kCFAllocatorGCObjectMemory ? AUTO_OBJECT : 0); + return type; +} CF_EXPORT CFAllocatorRef _CFTemporaryMemoryAllocator(void); @@ -248,13 +248,15 @@ extern CFStringRef __CFCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef f /* result is long long or int, depending on doLonglong */ -extern Boolean __CFStringScanInteger(CFStringInlineBuffer *buf, CFDictionaryRef locale, SInt32 *indexPtr, Boolean doLonglong, void *result); -extern Boolean __CFStringScanDouble(CFStringInlineBuffer *buf, CFDictionaryRef locale, SInt32 *indexPtr, double *resultPtr); +extern Boolean __CFStringScanInteger(CFStringInlineBuffer *buf, CFTypeRef locale, SInt32 *indexPtr, Boolean doLonglong, void *result); +extern Boolean __CFStringScanDouble(CFStringInlineBuffer *buf, CFTypeRef locale, SInt32 *indexPtr, double *resultPtr); extern Boolean __CFStringScanHex(CFStringInlineBuffer *buf, SInt32 *indexPtr, unsigned *result); +#define STACK_BUFFER_DECL(T, N, C) T N[C]; + #ifdef __CONSTANT_CFSTRINGS__ -#define CONST_STRING_DECL(S, V) const CFStringRef S = __builtin___CFStringMakeConstantString(V); +#define CONST_STRING_DECL(S, V) const CFStringRef S = (const CFStringRef)__builtin___CFStringMakeConstantString(V); #else struct CF_CONST_STRING { @@ -266,30 +268,45 @@ struct CF_CONST_STRING { extern 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 defined(__ppc__) || defined(__ppc64__) +#if 0 +#define ___WindowsConstantStringClassReference &__CFConstantStringClassReference +#else +#define ___WindowsConstantStringClassReference NULL +#endif + +#if __CF_BIG_ENDIAN__ #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 ## __ = {{&__CFConstantStringClassReference, {0x0000, 0x07c8}}, V, sizeof(V) - 1}; \ const CFStringRef S = (CFStringRef) & __ ## S ## __; -#elif defined(__i386__) +#elif !defined (__WIN32__) #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 ## __ = {{&__CFConstantStringClassReference, {0x07c8, 0x0000}}, V, sizeof(V) - 1}; \ const CFStringRef S = (CFStringRef) & __ ## S ## __; +#elif 0 +#define CONST_STRING_DECL(S, V) \ +static struct CF_CONST_STRING __ ## S ## __ = {{___WindowsConstantStringClassReference, {0xc8, 0x07, 0x00, 0x00}},(uint8_t *) V, sizeof(V) - 1}; \ +const CFStringRef S = (CFStringRef) & __ ## S ## __; + +#define CONST_STRING_DECL_EXPORT(S, V) \ +struct CF_CONST_STRING __ ## S ## __ = {{___WindowsConstantStringClassReference, {0xc8, 0x07, 0x00, 0x00}}, (uint8_t *)V, sizeof(V) - 1}; \ +CF_EXPORT const CFStringRef S = (CFStringRef) & __ ## S ## __; + #else -#error undefined architecture -#endif -#endif +#define CONST_STRING_DECL(S, V) \ +static struct CF_CONST_STRING __ ## S ## __ = {{NULL, {0xc8, 0x07, 0x00, 0x00}},(uint8_t *) V, sizeof(V) - 1}; \ +const CFStringRef S = (CFStringRef) & __ ## S ## __; -#if defined(__MACH__) -#define __kCFCharacterSetDir "/System/Library/CoreServices" -#elif defined(__LINUX__) || defined(__FREEBSD__) -#define __kCFCharacterSetDir "/usr/local/share/CoreFoundation" -#elif defined(__WIN32__) -#define __kCFCharacterSetDir "\\Windows\\CoreFoundation" -#endif +#define CONST_STRING_DECL_EXPORT(S, V) \ +struct CF_CONST_STRING __ ## S ## __ = {{NULL, {0xc8, 0x07, 0x00, 0x00}}, (uint8_t *)V, sizeof(V) - 1}; \ +CF_EXPORT const CFStringRef S = (CFStringRef) & __ ## S ## __; + +#endif // __WIN32__ +#endif // __BIG_ENDIAN__ +#undef ___WindowsConstantStringClassReference /* Buffer size for file pathname */ -#if defined(__WIN32__) +#if 0 || 0 #define CFMaxPathSize ((CFIndex)262) #define CFMaxPathLength ((CFIndex)260) #else @@ -297,19 +314,11 @@ const CFStringRef S = (CFStringRef) & __ ## S ## __; #define CFMaxPathLength ((CFIndex)1024) #endif -#if defined(__MACH__) -extern bool __CFOASafe; -extern void __CFSetLastAllocationEventName(void *ptr, const char *classname); -#else #define __CFOASafe 0 -#define __CFSetLastAllocationEventName(a, b) -#endif - +#define __CFSetLastAllocationEventName(a, b) ((void) 0) CF_EXPORT CFStringRef _CFCreateLimitedUniqueString(void); -extern CFStringRef __CFCopyEthernetAddrString(void); - /* Comparators are passed the address of the values; this is somewhat different than CFComparatorFunction is used in public API usually. */ CF_EXPORT CFIndex CFBSearch(const void *element, CFIndex elementSize, const void *list, CFIndex count, CFComparatorFunction comparator, void *context); @@ -317,24 +326,19 @@ CF_EXPORT CFHashCode CFHashBytes(UInt8 *bytes, CFIndex length); CF_EXPORT CFStringEncoding CFStringFileSystemEncoding(void); -CF_EXPORT CFStringRef __CFStringCreateImmutableFunnel3(CFAllocatorRef alloc, const void *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean possiblyExternalFormat, Boolean tryToReduceUnicode, Boolean hasLengthByte, Boolean hasNullByte, Boolean noCopy, CFAllocatorRef contentsDeallocator, UInt32 converterFlags); +__private_extern__ CFStringRef __CFStringCreateImmutableFunnel3(CFAllocatorRef alloc, const void *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean possiblyExternalFormat, Boolean tryToReduceUnicode, Boolean hasLengthByte, Boolean hasNullByte, Boolean noCopy, CFAllocatorRef contentsDeallocator, UInt32 converterFlags); +extern const void *__CFStringCollectionCopy(CFAllocatorRef allocator, const void *ptr); extern const void *__CFTypeCollectionRetain(CFAllocatorRef allocator, const void *ptr); extern void __CFTypeCollectionRelease(CFAllocatorRef allocator, const void *ptr); -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX typedef OSSpinLock CFSpinLock_t; #define CFSpinLockInit OS_SPINLOCK_INIT - -#if defined(__i386__) -extern void _spin_lock(CFSpinLock_t *lockp); -extern void _spin_unlock(CFSpinLock_t *lockp); -#define OSSpinLockLock(p) _spin_lock(p) -#define OSSpinLockUnlock(p) _spin_unlock(p) -#endif +#define CF_SPINLOCK_INIT_FOR_STRUCTS(X) (X = CFSpinLockInit) CF_INLINE void __CFSpinLock(CFSpinLock_t *lockp) { OSSpinLockLock(lockp); @@ -346,16 +350,22 @@ CF_INLINE void __CFSpinUnlock(CFSpinLock_t *lockp) { #elif defined(__WIN32__) -typedef LONG CFSpinLock_t; +typedef CRITICAL_SECTION CFSpinLock_t; + +#define CFSpinLockInit {0} +// For some reason, the {0} initializer does not work when the spinlock is a member of a structure; hence this macro +#define CF_SPINLOCK_INIT_FOR_STRUCTS(X) InitializeCriticalSection(&X) +extern CFSpinLock_t *theLock; CF_INLINE void __CFSpinLock(CFSpinLock_t *slock) { - while (InterlockedExchange(slock, 1) != 0) { - Sleep(1); // 1ms + if (NULL == slock->DebugInfo) { + InitializeCriticalSection(slock); } + EnterCriticalSection(slock); } CF_INLINE void __CFSpinUnlock(CFSpinLock_t *lock) { - *lock = 0; + LeaveCriticalSection(lock); } #else @@ -366,9 +376,17 @@ CF_INLINE void __CFSpinUnlock(CFSpinLock_t *lock) { #endif +#if !defined(CHECK_FOR_FORK) +#define CHECK_FOR_FORK() do { } while (0) +#endif + +#if !defined(HAS_FORKED) +#define HAS_FORKED() 0 +#endif + #if defined(__svr4__) || defined(__hpux__) || defined(__WIN32__) #include -#elif defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__) +#elif DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD #include #endif @@ -394,7 +412,7 @@ CF_EXPORT Boolean _CFReadBytesFromFile(CFAllocatorRef alloc, CFURLRef url, void /* maxLength of zero means the whole file. Otherwise it sets a limit on the number of bytes read. */ CF_EXPORT Boolean _CFWriteBytesToFile(CFURLRef url, const void *bytes, CFIndex length); -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX CF_EXPORT Boolean _CFWriteBytesToFileWithAtomicity(CFURLRef url, const void *bytes, unsigned int length, SInt32 mode, Boolean atomic); #endif @@ -423,8 +441,6 @@ CF_EXPORT CFIndex _CFLengthAfterDeletingLastPathComponent(UniChar *unichars, CFI CF_EXPORT CFIndex _CFStartOfPathExtension(UniChar *unichars, CFIndex length); CF_EXPORT CFIndex _CFLengthAfterDeletingPathExtension(UniChar *unichars, CFIndex length); -#if !defined(__MACH__) - #define CF_IS_OBJC(typeID, obj) (false) #define CF_OBJC_VOIDCALL0(obj, sel) @@ -435,123 +451,38 @@ CF_EXPORT CFIndex _CFLengthAfterDeletingPathExtension(UniChar *unichars, CFIndex #define CF_OBJC_CALL1(rettype, retvar, obj, sel, a1) #define CF_OBJC_CALL2(rettype, retvar, obj, sel, a1, a2) +#if defined (__WIN32__) +#define CF_OBJC_FUNCDISPATCH0(typeID, rettype, obj, sel) ((void)0) +#define CF_OBJC_FUNCDISPATCH1(typeID, rettype, obj, sel, a1) ((void)0) +#define CF_OBJC_FUNCDISPATCH2(typeID, rettype, obj, sel, a1, a2) ((void)0) +#define CF_OBJC_FUNCDISPATCH3(typeID, rettype, obj, sel, a1, a2, a3) ((void)0) +#define CF_OBJC_FUNCDISPATCH4(typeID, rettype, obj, sel, a1, a2, a3, a4) ((void)0) +#define CF_OBJC_FUNCDISPATCH5(typeID, rettype, obj, sel, a1, a2, a3, a4, a5) ((void)0) +#else #define CF_OBJC_FUNCDISPATCH0(typeID, rettype, obj, sel) #define CF_OBJC_FUNCDISPATCH1(typeID, rettype, obj, sel, a1) #define CF_OBJC_FUNCDISPATCH2(typeID, rettype, obj, sel, a1, a2) #define CF_OBJC_FUNCDISPATCH3(typeID, rettype, obj, sel, a1, a2, a3) #define CF_OBJC_FUNCDISPATCH4(typeID, rettype, obj, sel, a1, a2, a3, a4) #define CF_OBJC_FUNCDISPATCH5(typeID, rettype, obj, sel, a1, a2, a3, a4, a5) +#endif //__WIN32__ -#endif - -#if defined(__LINUX__) || defined(__FREEBSD__) || defined(__WIN32__) -#define __CFISAForTypeID(x) (NULL) -#endif - -#define __CFMaxRuntimeTypes 256 - -#if defined(__MACH__) - -#include - -extern struct objc_class *__CFRuntimeObjCClassTable[]; -CF_INLINE void *__CFISAForTypeID(CFTypeID typeID) { - return (void *)(__CFRuntimeObjCClassTable[typeID]); -} - -#if defined(__ppc__) -#define __CFSendObjCMsg 0xfffeff00 -#else -extern void * (*__CFSendObjCMsg)(const void *, SEL, ...); -#endif +#define __CFISAForTypeID(x) (0) -#if 0 -// Although it might seem to make better performance to check for NULL -// first, doing the other check first is better. -CF_INLINE int CF_IS_OBJC(CFTypeID typeID, const void *obj) { - return (((CFRuntimeBase *)obj)->_isa != __CFISAForTypeID(typeID) && ((CFRuntimeBase *)obj)->_isa > (void *)0xFFF); -} -#else -#define CF_IS_OBJC(typeID, obj) (false) -#endif - -// 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 *)__CFSendObjCMsg; \ - 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 *)__CFSendObjCMsg; \ - 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 *)__CFSendObjCMsg; \ - 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) = (void *)__CFSendObjCMsg; \ - 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, ...) = (void *)__CFSendObjCMsg; \ - 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, ...) = (void *)__CFSendObjCMsg; \ - 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) = (void *)__CFSendObjCMsg; \ - 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, ...) = (void *)__CFSendObjCMsg; \ - 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, ...) = (void *)__CFSendObjCMsg; \ - 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, ...) = (void *)__CFSendObjCMsg; \ - 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, ...) = (void *)__CFSendObjCMsg; \ - 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, ...) = (void *)__CFSendObjCMsg; \ - static SEL s = NULL; if (!s) s = sel_registerName(sel); \ - return func((const void *)obj, s, (a1), (a2), (a3), (a4), (a5));} - -#endif +#define __CFMaxRuntimeTypes 65535 /* See comments in CFBase.c */ -#if defined(__ppc__) && defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX && defined(__ppc__) extern void __CF_FAULT_CALLBACK(void **ptr); extern void *__CF_INVOKE_CALLBACK(void *, ...); - #define FAULT_CALLBACK(V) __CF_FAULT_CALLBACK(V) -#define INVOKE_CALLBACK1(P, A) (((uintptr_t)(P) & 0x2) ? __CF_INVOKE_CALLBACK(P, A) : (P)(A)) -#define INVOKE_CALLBACK2(P, A, B) (((uintptr_t)(P) & 0x2) ? __CF_INVOKE_CALLBACK(P, A, B) : (P)(A, B)) -#define INVOKE_CALLBACK3(P, A, B, C) (((uintptr_t)(P) & 0x2) ? __CF_INVOKE_CALLBACK(P, A, B, C) : (P)(A, B, C)) -#define INVOKE_CALLBACK4(P, A, B, C, D) (((uintptr_t)(P) & 0x2) ? __CF_INVOKE_CALLBACK(P, A, B, C, D) : (P)(A, B, C, D)) -#define INVOKE_CALLBACK5(P, A, B, C, D, E) (((uintptr_t)(P) & 0x2) ? __CF_INVOKE_CALLBACK(P, A, B, C, D, E) : (P)(A, B, C, D, E)) +#define INVOKE_CALLBACK1(P, A) (__CF_INVOKE_CALLBACK(P, A)) +#define INVOKE_CALLBACK2(P, A, B) (__CF_INVOKE_CALLBACK(P, A, B)) +#define INVOKE_CALLBACK3(P, A, B, C) (__CF_INVOKE_CALLBACK(P, A, B, C)) +#define INVOKE_CALLBACK4(P, A, B, C, D) (__CF_INVOKE_CALLBACK(P, A, B, C, D)) +#define INVOKE_CALLBACK5(P, A, B, C, D, E) (__CF_INVOKE_CALLBACK(P, A, B, C, D, E)) +#define UNFAULT_CALLBACK(V) do { V = (void *)((uintptr_t)V & ~0x3); } while (0) #else #define FAULT_CALLBACK(V) #define INVOKE_CALLBACK1(P, A) (P)(A) @@ -559,14 +490,10 @@ extern void *__CF_INVOKE_CALLBACK(void *, ...); #define INVOKE_CALLBACK3(P, A, B, C) (P)(A, B, C) #define INVOKE_CALLBACK4(P, A, B, C, D) (P)(A, B, C, D) #define INVOKE_CALLBACK5(P, A, B, C, D, E) (P)(A, B, C, D, E) +#define UNFAULT_CALLBACK(V) do { } while (0) #endif -#if defined(__MACH__) - /* For the support of functionality which needs CarbonCore or other frameworks */ -extern void *__CFLookupCarbonCoreFunction(const char *name); -extern void *__CFLookupCFNetworkFunction(const char *name); - // These macros define an upcall or weak "symbol-lookup" wrapper function. // The parameters are: // R : the return type of the function @@ -584,44 +511,76 @@ extern void *__CFLookupCFNetworkFunction(const char *name); // DEFINE_WEAK_CARBONCORE_FUNC(void, DisposeHandle, (Handle h), (h)) // -#define DEFINE_WEAK_CARBONCORE_FUNC(R, N, P, A, ...) \ -static R __CFCarbonCore_ ## N P { \ - static R (*dyfunc) P = (void *)(~(uintptr_t)0); \ - if ((void *)(~(uintptr_t)0) == dyfunc) { \ - dyfunc = __CFLookupCarbonCoreFunction(#N); } \ - return dyfunc ? dyfunc A : (R)(0 , ## __VA_ARGS__); \ -} +#if DEPLOYMENT_TARGET_MACOSX -#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); } \ - return dyfunc ? dyfunc A : (R)(0 , ## __VA_ARGS__); \ +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__ ; \ } #else -#define DEFINE_WEAK_CARBONCORE_FUNC(R, N, P, A, ...) #define DEFINE_WEAK_CFNETWORK_FUNC(R, N, P, A, ...) #endif +#if !defined(DEFINE_WEAK_CARBONCORE_FUNC) +#define DEFINE_WEAK_CARBONCORE_FUNC(R, N, P, A, ...) +#endif + + __private_extern__ CFArrayRef _CFBundleCopyUserLanguages(Boolean useBackstops); /* GC related internal SPIs. */ extern malloc_zone_t *__CFCollectableZone; -__private_extern__ void _CFStorageSetWeak(struct __CFStorage *storage); - -#if defined(__WIN32__) -__private_extern__ const char *_CFDLLPath(void); -__private_extern__ void __CFStringCleanup(void); -__private_extern__ void __CFSocketCleanup(void); -__private_extern__ void __CFUniCharCleanup(void); -__private_extern__ void __CFStreamCleanup(void); -// We should export this as SPI or API to clients - 3514284 -CF_EXPORT CFAbsoluteTime _CFAbsoluteTimeFromFileTime(const FILETIME *ft); -#endif + +/* !!! Avoid #importing objc.h; e.g. converting this to a .m file */ +struct __objcFastEnumerationStateEquivalent { + unsigned long state; + unsigned long *itemsPtr; + unsigned long *mutationsPtr; + unsigned long extra[5]; +}; + +unsigned long _CFStorageFastEnumeration(CFStorageRef storage, struct __objcFastEnumerationStateEquivalent *state, void *stackbuffer, unsigned long count); + + +// Allocate an id[count], new slots are nil +extern void *__CFAllocateObjectArray(unsigned long count); +extern void *__CFReallocateObjectArray(id *array, unsigned long count); +extern void __CFFreeObjectArray(id *array); + +// check against LONG_MAX to catch negative numbers +#define new_id_array(N, C) \ + size_t N ## _count__ = (C); \ + if (N ## _count__ > LONG_MAX) { \ + id rr = [objc_lookUpClass("NSString") stringWithFormat:@"*** attempt to create a temporary id buffer which is too large or with a negative count (%lu) -- possibly data is corrupt", N ## _count__]; \ + @throw [NSException exceptionWithName:NSGenericException reason:rr userInfo:nil]; \ + } \ + NSInteger N ## _is_stack__ = (N ## _count__ <= 256); \ + id N ## _buffer__[N ## _is_stack__ ? N ## _count__ : 0]; \ + if (N ## _is_stack__) memset(N ## _buffer__, 0, sizeof(N ## _buffer__)); \ + id * N = N ## _is_stack__ ? N ## _buffer__ : __CFAllocateObjectArray(N ## _count__); \ + if (! N) { \ + id rr = [objc_lookUpClass("NSString") stringWithFormat:@"*** attempt to create a temporary id buffer of length (%lu) failed", N ## _count__]; \ + @throw [NSException exceptionWithName:NSMallocException reason:rr userInfo:nil]; \ + } \ + do {} while (0) + +#define free_id_array(N) \ + if (! N ## _is_stack__) __CFFreeObjectArray(N) + +extern void *__CFFullMethodName(Class cls, id obj, SEL sel); +extern void *__CFExceptionProem(id obj, SEL sel); +extern void __CFRequireConcreteImplementation(Class absClass, id obj, SEL sel); + #endif /* ! __COREFOUNDATION_CFINTERNAL__ */ + diff --git a/CFLocale.c b/CFLocale.c new file mode 100644 index 0000000..cab8fd1 --- /dev/null +++ b/CFLocale.c @@ -0,0 +1,983 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFLocale.c + Copyright 2002-2003, Apple Computer, Inc. All rights reserved. + Responsibility: Christopher Kane +*/ + +// Note the header file is in the OpenSource set (stripped to almost nothing), but not the .c file + +#include +#include +#include +#include +#include +#include +#include +#include "CFInternal.h" +#include // ICU locales +#include // ICU locale data +#include // ICU currency functions +#include // ICU Unicode sets +#include // ICU low-level utilities +#include // ICU message formatting +#if DEPLOYMENT_TARGET_MACOSX +#include +#include +#include +#include +#endif + +CONST_STRING_DECL(kCFLocaleCurrentLocaleDidChangeNotification, "kCFLocaleCurrentLocaleDidChangeNotification") + +static const char *kCalendarKeyword = "calendar"; +static const char *kCollationKeyword = "collation"; +#define kMaxICUNameSize 1024 + +typedef struct __CFLocale *CFMutableLocaleRef; + +__private_extern__ CONST_STRING_DECL(__kCFLocaleCollatorID, "locale:collator id") + +enum { + __kCFLocaleKeyTableCount = 16 +}; + +struct key_table { + CFStringRef key; + bool (*get)(CFLocaleRef, bool user, CFTypeRef *, CFStringRef context); // returns an immutable copy & reference + bool (*set)(CFMutableLocaleRef, CFTypeRef, CFStringRef context); + bool (*name)(const char *, const char *, CFStringRef *); + CFStringRef context; +}; + + +// Must forward decl. these functions: +static bool __CFLocaleCopyLocaleID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); +static bool __CFLocaleSetNOP(CFMutableLocaleRef locale, CFTypeRef cf, CFStringRef context); +static bool __CFLocaleFullName(const char *locale, const char *value, CFStringRef *out); +static bool __CFLocaleCopyCodes(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); +static bool __CFLocaleCountryName(const char *locale, const char *value, CFStringRef *out); +static bool __CFLocaleScriptName(const char *locale, const char *value, CFStringRef *out); +static bool __CFLocaleLanguageName(const char *locale, const char *value, CFStringRef *out); +static bool __CFLocaleCurrencyShortName(const char *locale, const char *value, CFStringRef *out); +static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); +static bool __CFLocaleVariantName(const char *locale, const char *value, CFStringRef *out); +static bool __CFLocaleNoName(const char *locale, const char *value, CFStringRef *out); +static bool __CFLocaleCopyCalendarID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); +static bool __CFLocaleCalendarName(const char *locale, const char *value, CFStringRef *out); +static bool __CFLocaleCollationName(const char *locale, const char *value, CFStringRef *out); +static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); +static bool __CFLocaleCopyCalendar(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); +static bool __CFLocaleCopyCollationID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); +static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); +static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); +static bool __CFLocaleCopyNumberFormat2(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); +static bool __CFLocaleCurrencyFullName(const char *locale, const char *value, CFStringRef *out); +static bool __CFLocaleCopyCollatorID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context); + +// Note string members start with an extra &, and are fixed up at init time +static struct key_table __CFLocaleKeyTable[__kCFLocaleKeyTableCount] = { + {(CFStringRef)&kCFLocaleIdentifier, __CFLocaleCopyLocaleID, __CFLocaleSetNOP, __CFLocaleFullName, NULL}, + {(CFStringRef)&kCFLocaleLanguageCode, __CFLocaleCopyCodes, __CFLocaleSetNOP, __CFLocaleLanguageName, (CFStringRef)&kCFLocaleLanguageCode}, + {(CFStringRef)&kCFLocaleCountryCode, __CFLocaleCopyCodes, __CFLocaleSetNOP, __CFLocaleCountryName, (CFStringRef)&kCFLocaleCountryCode}, + {(CFStringRef)&kCFLocaleScriptCode, __CFLocaleCopyCodes, __CFLocaleSetNOP, __CFLocaleScriptName, (CFStringRef)&kCFLocaleScriptCode}, + {(CFStringRef)&kCFLocaleVariantCode, __CFLocaleCopyCodes, __CFLocaleSetNOP, __CFLocaleVariantName, (CFStringRef)&kCFLocaleVariantCode}, + {(CFStringRef)&kCFLocaleExemplarCharacterSet, __CFLocaleCopyExemplarCharSet, __CFLocaleSetNOP, __CFLocaleNoName, NULL}, + {(CFStringRef)&kCFLocaleCalendarIdentifier, __CFLocaleCopyCalendarID, __CFLocaleSetNOP, __CFLocaleCalendarName, NULL}, + {(CFStringRef)&kCFLocaleCalendar, __CFLocaleCopyCalendar, __CFLocaleSetNOP, __CFLocaleNoName, NULL}, + {(CFStringRef)&kCFLocaleCollationIdentifier, __CFLocaleCopyCollationID, __CFLocaleSetNOP, __CFLocaleCollationName, NULL}, + {(CFStringRef)&kCFLocaleUsesMetricSystem, __CFLocaleCopyUsesMetric, __CFLocaleSetNOP, __CFLocaleNoName, NULL}, + {(CFStringRef)&kCFLocaleMeasurementSystem, __CFLocaleCopyMeasurementSystem, __CFLocaleSetNOP, __CFLocaleNoName, NULL}, + {(CFStringRef)&kCFLocaleDecimalSeparator, __CFLocaleCopyNumberFormat, __CFLocaleSetNOP, __CFLocaleNoName, (CFStringRef)&kCFNumberFormatterDecimalSeparator}, + {(CFStringRef)&kCFLocaleGroupingSeparator, __CFLocaleCopyNumberFormat, __CFLocaleSetNOP, __CFLocaleNoName, (CFStringRef)&kCFNumberFormatterGroupingSeparator}, + {(CFStringRef)&kCFLocaleCurrencySymbol, __CFLocaleCopyNumberFormat2, __CFLocaleSetNOP, __CFLocaleCurrencyShortName, (CFStringRef)&kCFNumberFormatterCurrencySymbol}, + {(CFStringRef)&kCFLocaleCurrencyCode, __CFLocaleCopyNumberFormat2, __CFLocaleSetNOP, __CFLocaleCurrencyFullName, (CFStringRef)&kCFNumberFormatterCurrencyCode}, + {(CFStringRef)&__kCFLocaleCollatorID, __CFLocaleCopyCollatorID, __CFLocaleSetNOP, __CFLocaleNoName, NULL}, +}; + + +static CFLocaleRef __CFLocaleSystem = NULL; +static CFMutableDictionaryRef __CFLocaleCache = NULL; +static CFSpinLock_t __CFLocaleGlobalLock = CFSpinLockInit; + +struct __CFLocale { + CFRuntimeBase _base; + CFStringRef _identifier; // canonical identifier, never NULL + CFMutableDictionaryRef _cache; + CFMutableDictionaryRef _overrides; + CFDictionaryRef _prefs; + CFSpinLock_t _lock; +}; + +/* Flag bits */ +enum { /* Bits 0-1 */ + __kCFLocaleOrdinary = 0, + __kCFLocaleSystem = 1, + __kCFLocaleUser = 2, + __kCFLocaleCustom = 3 +}; + +CF_INLINE CFIndex __CFLocaleGetType(CFLocaleRef locale) { + return __CFBitfieldGetValue(((const CFRuntimeBase *)locale)->_cfinfo[CF_INFO_BITS], 1, 0); +} + +CF_INLINE void __CFLocaleSetType(CFLocaleRef locale, CFIndex type) { + __CFBitfieldSetValue(((CFRuntimeBase *)locale)->_cfinfo[CF_INFO_BITS], 1, 0, (uint8_t)type); +} + +CF_INLINE void __CFLocaleLockGlobal(void) { + __CFSpinLock(&__CFLocaleGlobalLock); +} + +CF_INLINE void __CFLocaleUnlockGlobal(void) { + __CFSpinUnlock(&__CFLocaleGlobalLock); +} + +CF_INLINE void __CFLocaleLock(CFLocaleRef locale) { + __CFSpinLock(&locale->_lock); +} + +CF_INLINE void __CFLocaleUnlock(CFLocaleRef locale) { + __CFSpinUnlock(&locale->_lock); +} + + +static Boolean __CFLocaleEqual(CFTypeRef cf1, CFTypeRef cf2) { + CFLocaleRef locale1 = (CFLocaleRef)cf1; + CFLocaleRef locale2 = (CFLocaleRef)cf2; + // a user locale and a locale created with an ident are not the same even if their contents are + if (__CFLocaleGetType(locale1) != __CFLocaleGetType(locale2)) return false; + if (!CFEqual(locale1->_identifier, locale2->_identifier)) return false; + if (NULL == locale1->_overrides && NULL != locale2->_overrides) return false; + 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 true; +} + +static CFHashCode __CFLocaleHash(CFTypeRef cf) { + CFLocaleRef locale = (CFLocaleRef)cf; + return CFHash(locale->_identifier); +} + +static CFStringRef __CFLocaleCopyDescription(CFTypeRef cf) { + CFLocaleRef locale = (CFLocaleRef)cf; + const char *type = NULL; + switch (__CFLocaleGetType(locale)) { + case __kCFLocaleOrdinary: type = "ordinary"; break; + case __kCFLocaleSystem: type = "system"; break; + case __kCFLocaleUser: type = "user"; break; + case __kCFLocaleCustom: type = "custom"; break; + } + return CFStringCreateWithFormat(CFGetAllocator(locale), NULL, CFSTR("{type = %s, identifier = '%@'}"), cf, CFGetAllocator(locale), type, locale->_identifier); +} + +static void __CFLocaleDeallocate(CFTypeRef cf) { + CFLocaleRef locale = (CFLocaleRef)cf; + CFRelease(locale->_identifier); + if (NULL != locale->_cache) CFRelease(locale->_cache); + if (NULL != locale->_overrides) CFRelease(locale->_overrides); + if (NULL != locale->_prefs) CFRelease(locale->_prefs); +} + +static CFTypeID __kCFLocaleTypeID = _kCFRuntimeNotATypeID; + +static const CFRuntimeClass __CFLocaleClass = { + 0, + "CFLocale", + NULL, // init + NULL, // copy + __CFLocaleDeallocate, + __CFLocaleEqual, + __CFLocaleHash, + NULL, // + __CFLocaleCopyDescription +}; + +static void __CFLocaleInitialize(void) { + CFIndex idx; + __kCFLocaleTypeID = _CFRuntimeRegisterClass(&__CFLocaleClass); + for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { + // table fixup to workaround compiler/language limitations + __CFLocaleKeyTable[idx].key = *((CFStringRef *)__CFLocaleKeyTable[idx].key); + if (NULL != __CFLocaleKeyTable[idx].context) { + __CFLocaleKeyTable[idx].context = *((CFStringRef *)__CFLocaleKeyTable[idx].context); + } + } +} + +CFTypeID CFLocaleGetTypeID(void) { + if (_kCFRuntimeNotATypeID == __kCFLocaleTypeID) __CFLocaleInitialize(); + return __kCFLocaleTypeID; +} + +CFLocaleRef CFLocaleGetSystem(void) { + CFLocaleRef locale; + __CFLocaleLockGlobal(); + if (NULL == __CFLocaleSystem) { + __CFLocaleUnlockGlobal(); + locale = CFLocaleCreate(kCFAllocatorSystemDefault, CFSTR("")); + if (!locale) return NULL; + __CFLocaleSetType(locale, __kCFLocaleSystem); + __CFLocaleLockGlobal(); + if (NULL == __CFLocaleSystem) { + __CFLocaleSystem = locale; + } else { + if (locale) CFRelease(locale); + } + } + locale = __CFLocaleSystem ? (CFLocaleRef)CFRetain(__CFLocaleSystem) : NULL; + __CFLocaleUnlockGlobal(); + return locale; +} + +static CFLocaleRef __CFLocaleCurrent = NULL; + +#if DEPLOYMENT_TARGET_MACOSX +#define FALLBACK_LOCALE_NAME CFSTR("") +#endif + +CFLocaleRef CFLocaleCopyCurrent(void) { + + __CFLocaleLockGlobal(); + if (__CFLocaleCurrent) { + CFRetain(__CFLocaleCurrent); + __CFLocaleUnlockGlobal(); + return __CFLocaleCurrent; + } + __CFLocaleUnlockGlobal(); + + CFDictionaryRef prefs = NULL; + CFStringRef identifier = NULL; + + struct __CFLocale *locale; + uint32_t size = sizeof(struct __CFLocale) - sizeof(CFRuntimeBase); + locale = (struct __CFLocale *)_CFRuntimeCreateInstance(kCFAllocatorSystemDefault, CFLocaleGetTypeID(), size, NULL); + if (NULL == locale) { + return NULL; + } + __CFLocaleSetType(locale, __kCFLocaleUser); + if (NULL == identifier) identifier = CFRetain(FALLBACK_LOCALE_NAME); + locale->_identifier = identifier; + locale->_cache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); + locale->_overrides = NULL; + locale->_prefs = prefs; + locale->_lock = CFSpinLockInit; + + __CFLocaleLockGlobal(); + if (NULL == __CFLocaleCurrent) { + __CFLocaleCurrent = locale; + } else { + CFRelease(locale); + } + locale = (struct __CFLocale *)CFRetain(__CFLocaleCurrent); + __CFLocaleUnlockGlobal(); + return locale; +} + +__private_extern__ CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale) { + return locale->_prefs; +} + +CFLocaleRef CFLocaleCreate(CFAllocatorRef allocator, CFStringRef identifier) { + if (allocator == NULL) allocator = __CFGetDefaultAllocator(); + __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); + __CFGenericValidateType(identifier, CFStringGetTypeID()); + CFStringRef localeIdentifier = NULL; + if (identifier) { + localeIdentifier = CFLocaleCreateCanonicalLocaleIdentifierFromString(allocator, identifier); + } + if (NULL == localeIdentifier) return NULL; + CFStringRef old = localeIdentifier; + localeIdentifier = (CFStringRef)CFStringCreateCopy(allocator, localeIdentifier); + CFRelease(old); + __CFLocaleLockGlobal(); + // Look for cases where we can return a cached instance. + // We only use cached objects if the allocator is the system + // default allocator. + if (!allocator) allocator = __CFGetDefaultAllocator(); + Boolean canCache = (kCFAllocatorSystemDefault == allocator); + if (canCache && __CFLocaleCache) { + CFLocaleRef locale = (CFLocaleRef)CFDictionaryGetValue(__CFLocaleCache, localeIdentifier); + if (locale) { + CFRetain(locale); + __CFLocaleUnlockGlobal(); + CFRelease(localeIdentifier); + return locale; + } + } + struct __CFLocale *locale = NULL; + uint32_t size = sizeof(struct __CFLocale) - sizeof(CFRuntimeBase); + locale = (struct __CFLocale *)_CFRuntimeCreateInstance(allocator, CFLocaleGetTypeID(), size, NULL); + if (NULL == locale) { + return NULL; + } + __CFLocaleSetType(locale, __kCFLocaleOrdinary); + locale->_identifier = localeIdentifier; + locale->_cache = CFDictionaryCreateMutable(allocator, 0, NULL, &kCFTypeDictionaryValueCallBacks); + locale->_overrides = NULL; + locale->_prefs = NULL; + locale->_lock = CFSpinLockInit; + if (canCache) { + if (NULL == __CFLocaleCache) { + __CFLocaleCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + } + CFDictionarySetValue(__CFLocaleCache, localeIdentifier, locale); + } + __CFLocaleUnlockGlobal(); + return (CFLocaleRef)locale; +} + +CFLocaleRef CFLocaleCreateCopy(CFAllocatorRef allocator, CFLocaleRef locale) { + return (CFLocaleRef)CFRetain(locale); +} + +CFStringRef CFLocaleGetIdentifier(CFLocaleRef locale) { + CF_OBJC_FUNCDISPATCH0(CFLocaleGetTypeID(), CFStringRef, locale, "localeIdentifier"); + return locale->_identifier; +} + +CFTypeRef CFLocaleGetValue(CFLocaleRef locale, CFStringRef key) { + CF_OBJC_FUNCDISPATCH1(CFLocaleGetTypeID(), CFTypeRef, locale, "objectForKey:", key); + CFIndex idx, slot = -1; + for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { + if (__CFLocaleKeyTable[idx].key == key) { + slot = idx; + break; + } + } + if (-1 == slot && NULL != key) { + for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { + if (CFEqual(__CFLocaleKeyTable[idx].key, key)) { + slot = idx; + break; + } + } + } + if (-1 == slot) { + return NULL; + } + CFTypeRef value; + if (NULL != locale->_overrides && CFDictionaryGetValueIfPresent(locale->_overrides, __CFLocaleKeyTable[slot].key, &value)) { + return value; + } + __CFLocaleLock(locale); + if (CFDictionaryGetValueIfPresent(locale->_cache, __CFLocaleKeyTable[slot].key, &value)) { + __CFLocaleUnlock(locale); + return value; + } + if (__kCFLocaleUser == __CFLocaleGetType(locale) && __CFLocaleKeyTable[slot].get(locale, true, &value, __CFLocaleKeyTable[slot].context)) { + if (value) CFDictionarySetValue(locale->_cache, __CFLocaleKeyTable[idx].key, value); + if (value) CFRelease(value); + __CFLocaleUnlock(locale); + return value; + } + if (__CFLocaleKeyTable[slot].get(locale, false, &value, __CFLocaleKeyTable[slot].context)) { + if (value) CFDictionarySetValue(locale->_cache, __CFLocaleKeyTable[idx].key, value); + if (value) CFRelease(value); + __CFLocaleUnlock(locale); + return value; + } + __CFLocaleUnlock(locale); + return NULL; +} + +CFStringRef CFLocaleCopyDisplayNameForPropertyValue(CFLocaleRef displayLocale, CFStringRef key, CFStringRef value) { + CF_OBJC_FUNCDISPATCH2(CFLocaleGetTypeID(), CFStringRef, displayLocale, "_copyDisplayNameForKey:value:", key, value); + CFIndex idx, slot = -1; + for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { + if (__CFLocaleKeyTable[idx].key == key) { + slot = idx; + break; + } + } + if (-1 == slot && NULL != key) { + for (idx = 0; idx < __kCFLocaleKeyTableCount; idx++) { + if (CFEqual(__CFLocaleKeyTable[idx].key, key)) { + slot = idx; + break; + } + } + } + if (-1 == slot || !value) { + return NULL; + } + // Get the locale ID as a C string + char localeID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; + char cValue[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; + if (CFStringGetCString(displayLocale->_identifier, localeID, sizeof(localeID)/sizeof(localeID[0]), kCFStringEncodingASCII) && CFStringGetCString(value, cValue, sizeof(cValue)/sizeof(char), kCFStringEncodingASCII)) { + CFStringRef result; + if ((NULL == displayLocale->_prefs) && __CFLocaleKeyTable[slot].name(localeID, cValue, &result)) { + return result; + } + + // We could not find a result using the requested language. Fall back through all preferred languages. + CFArrayRef langPref; + if (displayLocale->_prefs) { + langPref = (CFArrayRef)CFDictionaryGetValue(displayLocale->_prefs, CFSTR("AppleLanguages")); + if (langPref) CFRetain(langPref); + } else { + langPref = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication); + } + if (langPref != NULL) { + CFIndex count = CFArrayGetCount(langPref); + CFIndex i; + bool success = false; + for (i = 0; i < count && !success; ++i) { + CFStringRef language = (CFStringRef)CFArrayGetValueAtIndex(langPref, i); + CFStringRef cleanLanguage = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, language); + if (CFStringGetCString(cleanLanguage, localeID, sizeof(localeID)/sizeof(localeID[0]), kCFStringEncodingASCII)) { + success = __CFLocaleKeyTable[slot].name(localeID, cValue, &result); + } + CFRelease(cleanLanguage); + } + CFRelease(langPref); + if (success) + return result; + } + } + return NULL; +} + +CFArrayRef CFLocaleCopyAvailableLocaleIdentifiers(void) { + int32_t locale, localeCount = uloc_countAvailable(); + CFMutableSetRef working = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeSetCallBacks); + 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 + CFRelease(string1); + CFRelease(string2); + } + CFIndex cnt = CFSetGetCount(working); + STACK_BUFFER_DECL(const void *, buffer, cnt); + CFSetGetValues(working, buffer); + CFArrayRef result = CFArrayCreate(kCFAllocatorSystemDefault, buffer, cnt, &kCFTypeArrayCallBacks); + CFRelease(working); + return result; +} + +static CFArrayRef __CFLocaleCopyCStringsAsArray(const char* const* p) { + CFMutableArrayRef working = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + for (; *p; ++p) { + CFStringRef string = CFStringCreateWithCString(kCFAllocatorSystemDefault, *p, kCFStringEncodingASCII); + CFArrayAppendValue(working, string); + CFRelease(string); + } + CFArrayRef result = CFArrayCreateCopy(kCFAllocatorSystemDefault, working); + CFRelease(working); + return result; +} + +static CFArrayRef __CFLocaleCopyUEnumerationAsArray(UEnumeration *enumer, UErrorCode *icuErr) { + const UChar *next = NULL; + int32_t len = 0; + CFMutableArrayRef working = NULL; + if (U_SUCCESS(*icuErr)) { + working = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + } + while ((next = uenum_unext(enumer, &len, icuErr)) && U_SUCCESS(*icuErr)) { + CFStringRef string = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)next, (CFIndex) len); + CFArrayAppendValue(working, string); + CFRelease(string); + } + if (*icuErr == U_INDEX_OUTOFBOUNDS_ERROR) { + *icuErr = U_ZERO_ERROR; // Temp: Work around bug (ICU 5220) in ucurr enumerator + } + CFArrayRef result = NULL; + if (U_SUCCESS(*icuErr)) { + result = CFArrayCreateCopy(kCFAllocatorSystemDefault, working); + } + if (working != NULL) { + CFRelease(working); + } + return result; +} + +CFArrayRef CFLocaleCopyISOLanguageCodes(void) { + const char* const* p = uloc_getISOLanguages(); + return __CFLocaleCopyCStringsAsArray(p); +} + +CFArrayRef CFLocaleCopyISOCountryCodes(void) { + const char* const* p = uloc_getISOCountries(); + return __CFLocaleCopyCStringsAsArray(p); +} + +CFArrayRef CFLocaleCopyISOCurrencyCodes(void) { + UErrorCode icuStatus = U_ZERO_ERROR; + UEnumeration *enumer = ucurr_openISOCurrencies(UCURR_ALL, &icuStatus); + CFArrayRef result = __CFLocaleCopyUEnumerationAsArray(enumer, &icuStatus); + uenum_close(enumer); + return result; +} + +CFArrayRef CFLocaleCopyCommonISOCurrencyCodes(void) { + UErrorCode icuStatus = U_ZERO_ERROR; + UEnumeration *enumer = ucurr_openISOCurrencies(UCURR_COMMON|UCURR_NON_DEPRECATED, &icuStatus); + CFArrayRef result = __CFLocaleCopyUEnumerationAsArray(enumer, &icuStatus); + uenum_close(enumer); + return result; +} + +CFArrayRef CFLocaleCopyPreferredLanguages(void) { + CFMutableArrayRef newArray = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + CFArrayRef languagesArray = (CFArrayRef)CFPreferencesCopyAppValue(CFSTR("AppleLanguages"), kCFPreferencesCurrentApplication); + if (languagesArray && (CFArrayGetTypeID() == CFGetTypeID(languagesArray))) { + for (CFIndex idx = 0, cnt = CFArrayGetCount(languagesArray); idx < cnt; idx++) { + CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(languagesArray, idx); + if (str && (CFStringGetTypeID() == CFGetTypeID(str))) { + CFStringRef ident = CFLocaleCreateCanonicalLanguageIdentifierFromString(kCFAllocatorSystemDefault, str); + CFArrayAppendValue(newArray, ident); + CFRelease(ident); + } + } + } + if (languagesArray) CFRelease(languagesArray); + return newArray; +} + +// -------- -------- -------- -------- -------- -------- + +// These functions return true or false depending on the success or failure of the function. +// In the Copy case, this is failure to fill the *cf out parameter, and that out parameter is +// returned by reference WITH a retain on it. +static bool __CFLocaleSetNOP(CFMutableLocaleRef locale, CFTypeRef cf, CFStringRef context) { + return false; +} + +static bool __CFLocaleCopyLocaleID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { + *cf = CFRetain(locale->_identifier); + return true; +} + + +static bool __CFLocaleCopyCodes(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { + CFDictionaryRef codes = NULL; + // this access of _cache is protected by the lock in CFLocaleGetValue() + if (!CFDictionaryGetValueIfPresent(locale->_cache, CFSTR("__kCFLocaleCodes"), (const void **)&codes)) { + codes = CFLocaleCreateComponentsFromLocaleIdentifier(kCFAllocatorSystemDefault, locale->_identifier); + if (codes) CFDictionarySetValue(locale->_cache, CFSTR("__kCFLocaleCodes"), codes); + if (codes) CFRelease(codes); + } + if (codes) { + CFStringRef value = (CFStringRef)CFDictionaryGetValue(codes, context); // context is one of kCFLocale*Code constants + if (value) CFRetain(value); + *cf = value; + return true; + } + return false; +} + +CFCharacterSetRef _CFCreateCharacterSetFromUSet(USet *set) { + UErrorCode icuErr = U_ZERO_ERROR; + CFMutableCharacterSetRef working = CFCharacterSetCreateMutable(NULL); + UChar buffer[2048]; // Suitable for most small sets + int32_t stringLen; + + if (working == NULL) + return NULL; + + int32_t itemCount = uset_getItemCount(set); + int32_t i; + for (i = 0; i < itemCount; ++i) + { + UChar32 start, end; + UChar * string; + + string = buffer; + stringLen = uset_getItem(set, i, &start, &end, buffer, sizeof(buffer)/sizeof(UChar), &icuErr); + if (icuErr == U_BUFFER_OVERFLOW_ERROR) + { + string = (UChar *) malloc(sizeof(UChar)*(stringLen+1)); + if (!string) + { + CFRelease(working); + return NULL; + } + icuErr = U_ZERO_ERROR; + (void) uset_getItem(set, i, &start, &end, string, stringLen+1, &icuErr); + } + if (U_FAILURE(icuErr)) + { + if (string != buffer) + free(string); + CFRelease(working); + return NULL; + } + if (stringLen <= 0) + CFCharacterSetAddCharactersInRange(working, CFRangeMake(start, end-start+1)); + else + { + CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, (UniChar *)string, stringLen, kCFAllocatorNull); + CFCharacterSetAddCharactersInString(working, cfString); + CFRelease(cfString); + } + if (string != buffer) + free(string); + } + + CFCharacterSetRef result = CFCharacterSetCreateCopy(kCFAllocatorSystemDefault, working); + CFRelease(working); + return result; +} + + +static bool __CFLocaleCopyExemplarCharSet(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { + 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; + ULocaleData* uld = ulocdata_open(localeID, &icuStatus); + USet *set = ulocdata_getExemplarSet(uld, NULL, USET_ADD_CASE_MAPPINGS, ULOCDATA_ES_STANDARD, &icuStatus); + ulocdata_close(uld); + if (U_FAILURE(icuStatus)) + return false; + if (icuStatus == U_USING_DEFAULT_WARNING) // If default locale used, force to empty set + uset_clear(set); + *cf = (CFTypeRef) _CFCreateCharacterSetFromUSet(set); + uset_close(set); + return (*cf != NULL); + } + return false; +} + +static bool __CFLocaleCopyICUKeyword(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)) + { + char value[ULOC_KEYWORD_AND_VALUES_CAPACITY]; + UErrorCode icuStatus = U_ZERO_ERROR; + if (uloc_getKeywordValue(localeID, keyword, value, sizeof(value)/sizeof(char), &icuStatus) > 0 && U_SUCCESS(icuStatus)) + { + *cf = (CFTypeRef) CFStringCreateWithCString(kCFAllocatorSystemDefault, value, kCFStringEncodingASCII); + return true; + } + } + *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) { + if (CFEqual(*cf, kCFGregorianCalendar)) { + CFRelease(*cf); + *cf = CFRetain(kCFGregorianCalendar); + } else if (CFEqual(*cf, kCFBuddhistCalendar)) { + CFRelease(*cf); + *cf = CFRetain(kCFBuddhistCalendar); + } else if (CFEqual(*cf, kCFJapaneseCalendar)) { + CFRelease(*cf); + *cf = CFRetain(kCFJapaneseCalendar); + } else if (CFEqual(*cf, kCFIslamicCalendar)) { + CFRelease(*cf); + *cf = CFRetain(kCFIslamicCalendar); + } else if (CFEqual(*cf, kCFIslamicCivilCalendar)) { + CFRelease(*cf); + *cf = CFRetain(kCFIslamicCivilCalendar); + } else if (CFEqual(*cf, kCFHebrewCalendar)) { + CFRelease(*cf); + *cf = CFRetain(kCFHebrewCalendar); + } else if (CFEqual(*cf, kCFChineseCalendar)) { + CFRelease(*cf); + *cf = CFRetain(kCFChineseCalendar); + } + } else { + *cf = CFRetain(kCFGregorianCalendar); + } + return true; +} + +static bool __CFLocaleCopyCalendar(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { + if (__CFLocaleCopyCalendarID(locale, user, cf, context)) { + CFCalendarRef calendar = CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault, (CFStringRef)*cf); + CFCalendarSetLocale(calendar, locale); + CFRelease(*cf); + *cf = calendar; + return true; + } + return false; +} + +static bool __CFLocaleCopyCollationID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { + return __CFLocaleCopyICUKeyword(locale, user, cf, context, kCollationKeyword); +} + +static bool __CFLocaleCopyCollatorID(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { + CFStringRef canonLocaleCFStr = NULL; + if (!canonLocaleCFStr) { + canonLocaleCFStr = CFLocaleGetIdentifier(locale); + CFRetain(canonLocaleCFStr); + } + *cf = canonLocaleCFStr; + return canonLocaleCFStr ? true : false; +} + +static bool __CFLocaleCopyUsesMetric(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { + bool us = false; // Default is Metric + bool done = false; + + if (!done) { + 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; + UMeasurementSystem ms = UMS_SI; + ms = ulocdata_getMeasurementSystem(localeID, &icuStatus); + if (U_SUCCESS(icuStatus)) { + us = (ms == UMS_US); + done = true; + } + } + } + if (!done) + us = false; + *cf = us ? CFRetain(kCFBooleanFalse) : CFRetain(kCFBooleanTrue); + return true; +} + +static bool __CFLocaleCopyMeasurementSystem(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { + if (__CFLocaleCopyUsesMetric(locale, user, cf, context)) { + bool us = (*cf == kCFBooleanFalse); + CFRelease(*cf); + *cf = us ? CFRetain(CFSTR("U.S.")) : CFRetain(CFSTR("Metric")); + return true; + } + return false; +} + +static bool __CFLocaleCopyNumberFormat(CFLocaleRef locale, bool user, CFTypeRef *cf, CFStringRef context) { + CFStringRef str = NULL; +#if DEPLOYMENT_TARGET_MACOSX + CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale, kCFNumberFormatterDecimalStyle); + str = nf ? CFNumberFormatterCopyProperty(nf, context) : NULL; + if (nf) CFRelease(nf); +#endif + if (str) { + *cf = str; + return true; + } + return false; +} + +// ICU does not reliably set up currency info for other than Currency-type formatters, +// 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 + CFNumberFormatterRef nf = CFNumberFormatterCreate(kCFAllocatorSystemDefault, locale, kCFNumberFormatterCurrencyStyle); + str = nf ? CFNumberFormatterCopyProperty(nf, context) : NULL; + if (nf) CFRelease(nf); +#endif + if (str) { + *cf = str; + return true; + } + return false; +} + +typedef int32_t (*__CFICUFunction)(const char *, const char *, UChar *, int32_t, UErrorCode *); + +static bool __CFLocaleICUName(const char *locale, const char *valLocale, CFStringRef *out, __CFICUFunction icu) { + UErrorCode icuStatus = U_ZERO_ERROR; + int32_t size; + UChar name[kMaxICUNameSize]; + + size = (*icu)(valLocale, locale, name, kMaxICUNameSize, &icuStatus); + if (U_SUCCESS(icuStatus) && size > 0 && icuStatus != U_USING_DEFAULT_WARNING) { + *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); + return (*out != NULL); + } + return false; +} + +static bool __CFLocaleICUKeywordValueName(const char *locale, const char *value, const char *keyword, CFStringRef *out) { + UErrorCode icuStatus = U_ZERO_ERROR; + int32_t size = 0; + UChar name[kMaxICUNameSize]; + // Need to make a fake locale ID + char lid[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; + if (strlen(value) < ULOC_KEYWORD_AND_VALUES_CAPACITY) { + snprintf(lid, sizeof(lid), "en_US@%s=%s", keyword, value); + size = uloc_getDisplayKeywordValue(lid, keyword, locale, name, kMaxICUNameSize, &icuStatus); + if (U_SUCCESS(icuStatus) && size > 0 && icuStatus != U_USING_DEFAULT_WARNING) { + *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); + return (*out != NULL); + } + } + return false; +} + +static bool __CFLocaleICUCurrencyName(const char *locale, const char *value, UCurrNameStyle style, CFStringRef *out) { + int valLen = strlen(value); + if (valLen != 3) // not a valid ISO code + return false; + UChar curr[4]; + UBool isChoice = FALSE; + int32_t size = 0; + UErrorCode icuStatus = U_ZERO_ERROR; + u_charsToUChars(value, curr, valLen); + curr[valLen] = '\0'; + const UChar *name; + name = ucurr_getName(curr, locale, style, &isChoice, &size, &icuStatus); + if (U_FAILURE(icuStatus) || icuStatus == U_USING_DEFAULT_WARNING) + return false; + UChar result[kMaxICUNameSize]; + if (isChoice) + { + UChar pattern[kMaxICUNameSize]; + CFStringRef patternRef = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{0,choice,%S}"), name); + CFIndex pattlen = CFStringGetLength(patternRef); + CFStringGetCharacters(patternRef, CFRangeMake(0, pattlen), (UniChar *)pattern); + CFRelease(patternRef); + pattern[pattlen] = '\0'; // null terminate the pattern + // Format the message assuming a large amount of the currency + size = u_formatMessage("en_US", pattern, pattlen, result, kMaxICUNameSize, &icuStatus, 10.0); + if (U_FAILURE(icuStatus)) + return false; + name = result; + + } + *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); + return (*out != NULL); +} + +static bool __CFLocaleFullName(const char *locale, const char *value, CFStringRef *out) { + UErrorCode icuStatus = U_ZERO_ERROR; + int32_t size; + UChar name[kMaxICUNameSize]; + + // First, try to get the full locale. + size = uloc_getDisplayName(value, locale, name, kMaxICUNameSize, &icuStatus); + if (U_FAILURE(icuStatus) || size <= 0) + return false; + + // Did we wind up using a default somewhere? + if (icuStatus == U_USING_DEFAULT_WARNING) { + // For some locale IDs, there may be no language which has a translation for every + // piece. Rather than return nothing, see if we can at least handle + // the language part of the locale. + UErrorCode localStatus = U_ZERO_ERROR; + int32_t localSize; + UChar localName[kMaxICUNameSize]; + localSize = uloc_getDisplayLanguage(value, locale, localName, kMaxICUNameSize, &localStatus); + if (U_FAILURE(localStatus) || size <= 0 || localStatus == U_USING_DEFAULT_WARNING) + return false; + } + + // This locale is OK, so use the result. + *out = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (UniChar *)name, size); + return (*out != NULL); +} + +static bool __CFLocaleLanguageName(const char *locale, const char *value, CFStringRef *out) { + int len = strlen(value); + if (len >= 2 && len <= 3) + return __CFLocaleICUName(locale, value, out, uloc_getDisplayLanguage); + return false; +} + +static bool __CFLocaleCountryName(const char *locale, const char *value, CFStringRef *out) { + // Need to make a fake locale ID + char lid[ULOC_FULLNAME_CAPACITY]; + if (strlen(value) == 2) { + snprintf(lid, sizeof(lid), "en_%s", value); + return __CFLocaleICUName(locale, lid, out, uloc_getDisplayCountry); + } + return false; +} + +static bool __CFLocaleScriptName(const char *locale, const char *value, CFStringRef *out) { + // Need to make a fake locale ID + char lid[ULOC_FULLNAME_CAPACITY]; + if (strlen(value) == 4) { + snprintf(lid, sizeof(lid), "en_%s_US", value); + return __CFLocaleICUName(locale, lid, out, uloc_getDisplayScript); + } + return false; +} + +static bool __CFLocaleVariantName(const char *locale, const char *value, CFStringRef *out) { + // Need to make a fake locale ID + char lid[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; + if (strlen(value) < ULOC_FULLNAME_CAPACITY) { + snprintf(lid, sizeof(lid), "en_US_%s", value); + return __CFLocaleICUName(locale, lid, out, uloc_getDisplayVariant); + } + return false; +} + +static bool __CFLocaleCalendarName(const char *locale, const char *value, CFStringRef *out) { + return __CFLocaleICUKeywordValueName(locale, value, kCalendarKeyword, out); +} + +static bool __CFLocaleCollationName(const char *locale, const char *value, CFStringRef *out) { + return __CFLocaleICUKeywordValueName(locale, value, kCollationKeyword, out); +} + +static bool __CFLocaleCurrencyShortName(const char *locale, const char *value, CFStringRef *out) { + return __CFLocaleICUCurrencyName(locale, value, UCURR_SYMBOL_NAME, out); +} + +static bool __CFLocaleCurrencyFullName(const char *locale, const char *value, CFStringRef *out) { + return __CFLocaleICUCurrencyName(locale, value, UCURR_LONG_NAME, out); +} + +static bool __CFLocaleNoName(const char *locale, const char *value, CFStringRef *out) { + return false; +} + +// Remember to keep the names such that they would make sense for the user locale, +// in addition to the others; for example, it is "Currency", not "DefaultCurrency". +// (And besides, "Default" is almost always implied.) Words like "Default" and +// "Preferred" and so on should be left out of the names. +CONST_STRING_DECL(kCFLocaleIdentifier, "locale:id") +CONST_STRING_DECL(kCFLocaleLanguageCode, "locale:language code") +CONST_STRING_DECL(kCFLocaleCountryCode, "locale:country code") +CONST_STRING_DECL(kCFLocaleScriptCode, "locale:script code") +CONST_STRING_DECL(kCFLocaleVariantCode, "locale:variant code") +CONST_STRING_DECL(kCFLocaleExemplarCharacterSet, "locale:exemplar characters") +CONST_STRING_DECL(kCFLocaleCalendarIdentifier, "calendar") +CONST_STRING_DECL(kCFLocaleCalendar, "locale:calendarref") +CONST_STRING_DECL(kCFLocaleCollationIdentifier, "collation") +CONST_STRING_DECL(kCFLocaleUsesMetricSystem, "locale:uses metric") +CONST_STRING_DECL(kCFLocaleMeasurementSystem, "locale:measurement system") +CONST_STRING_DECL(kCFLocaleDecimalSeparator, "locale:decimal separator") +CONST_STRING_DECL(kCFLocaleGroupingSeparator, "locale:grouping separator") +CONST_STRING_DECL(kCFLocaleCurrencySymbol, "locale:currency symbol") +CONST_STRING_DECL(kCFLocaleCurrencyCode, "currency") + +CONST_STRING_DECL(kCFGregorianCalendar, "gregorian") +CONST_STRING_DECL(kCFBuddhistCalendar, "buddhist") +CONST_STRING_DECL(kCFJapaneseCalendar, "japanese") +CONST_STRING_DECL(kCFIslamicCalendar, "islamic") +CONST_STRING_DECL(kCFIslamicCivilCalendar, "islamic-civil") +CONST_STRING_DECL(kCFHebrewCalendar, "hebrew") +CONST_STRING_DECL(kCFChineseCalendar, "chinese") + +#undef kMaxICUNameSize + diff --git a/CFLocale.h b/CFLocale.h new file mode 100644 index 0000000..ec73158 --- /dev/null +++ b/CFLocale.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFLocale.h + Copyright (c) 2002-2007, Apple Inc. All rights reserved. +*/ + +#if !defined(__COREFOUNDATION_CFLOCALE__) +#define __COREFOUNDATION_CFLOCALE__ 1 + +#include +#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; + +CF_EXPORT +CFLocaleRef CFLocaleGetSystem(void) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + // Returns the "root", canonical locale. Contains fixed "backstop" settings. + +CF_EXPORT +CFLocaleRef CFLocaleCopyCurrent(void) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + // 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 + // you get from this locale do not change under you as CFPreferences + // are changed (for safety and correctness). Generally you would not + // grab this and hold onto it forever, but use it to do the operations + // you need to do at the moment, then throw it away. (The non-changing + // ensures that all the results of your operations are consistent.) + +CF_EXPORT +CFArrayRef CFLocaleCopyAvailableLocaleIdentifiers(void) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + // 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; + // 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; + // 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; + // 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; + // 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; + // 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; + // 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; + // 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; + // Map a Mac OS LangCode and RegionCode to the canonical locale identifier. + +CF_EXPORT +CFDictionaryRef CFLocaleCreateComponentsFromLocaleIdentifier(CFAllocatorRef allocator, CFStringRef localeID) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + // 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 + // will correspond to constants where available. + // Example: "en_US@calendar=japanese" yields a dictionary with three + // entries: kCFLocaleLanguageCode=en, kCFLocaleCountryCode=US, and + // kCFLocaleCalendarIdentifier=kCFJapaneseCalendar. + +CF_EXPORT +CFStringRef CFLocaleCreateLocaleIdentifierFromComponents(CFAllocatorRef allocator, CFDictionaryRef dictionary) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; + // Reverses the actions of CFLocaleCreateDictionaryFromLocaleIdentifier, + // creating a single string from the data in the dictionary. The + // dictionary {kCFLocaleLanguageCode=en, kCFLocaleCountryCode=US, + // kCFLocaleCalendarIdentifier=kCFJapaneseCalendar} becomes + // "en_US@calendar=japanese". + +CF_EXPORT +CFLocaleRef CFLocaleCreate(CFAllocatorRef allocator, CFStringRef localeIdentifier) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + // 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; + // 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; + // 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; + // 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; + // 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; + + +// 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 + +// 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_EXTERN_C_END + +#endif + +#endif /* ! __COREFOUNDATION_CFLOCALE__ */ + diff --git a/CFLocaleIdentifier.c b/CFLocaleIdentifier.c new file mode 100644 index 0000000..2b5cc35 --- /dev/null +++ b/CFLocaleIdentifier.c @@ -0,0 +1,1897 @@ +/* + * Copyright (c) 2008 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@ + */ +/* + CFLocaleIdentifier.c + Copyright (c) 2002-2007, Apple Inc. All rights reserved. + Responsibility: Christopher Kane + + CFLocaleIdentifier.c defines + - enum value kLocaleIdentifierCStringMax + - structs KeyStringToResultString, SpecialCaseUpdates + and provides the following data for the functions + CFLocaleCreateCanonicalLocaleIdentifierFromScriptManagerCodes, + CFLocaleCreateCanonicalLocaleIdentifierFromString + CFLocaleCreateCanonicalLanguageIdentifierFromString + + 1. static const char * regionCodeToLocaleString[]; enum kNumRegionCodeToLocaleString; + map RegionCode 0..kNumRegionCodeToLocaleString-1 to canonical locale string + + 2. static const char * langCodeToLocaleString[]; enum kNumLangCodeToLocaleString; + map LangCode 0..kNumLangCodeToLocaleString-1 to canonical locale string + + 3. static const KeyStringToResultString oldAppleLocaleToCanonical[]; enum kNumOldAppleLocaleToCanonical; + map old Apple string oldAppleLocaleToCanonical[n].key + to canonical locale string oldAppleLocaleToCanonical[n].result + for n = 0..kNumOldAppleLocaleToCanonical-1 + + 4. static const KeyStringToResultString localeStringPrefixToCanonical[]; enum kNumLocaleStringPrefixToCanonical; + map non-canonical language prefix (3-letter, obsolete) localeStringPrefixToCanonical[].key + to updated replacement localeStringPrefixToCanonical[].result + for n = 0..kNumLocaleStringPrefixToCanonical-1 + + 5. static const SpecialCaseUpdates specialCases[]; + various special cases for updating region codes, or for updating language codes based on region codes + + 6. static const KeyStringToResultString localeStringRegionToDefaults[]; enum kNumLocaleStringRegionToDefaults; + map locale string region tag localeStringRegionToDefaults[n].key + to default substrings to delete localeStringRegionToDefaults[n].result + for n = 0..kNumLocaleStringRegionToDefaults-1 + + 7. static const KeyStringToResultString localeStringPrefixToDefaults[]; enum kNumLocaleStringPrefixToDefaults; + map locale string initial part localeStringPrefixToDefaults[n].key + to default substrings to delete localeStringPrefixToDefaults[n].result + for n = 0..kNumLocaleStringPrefixToDefaults-1 + + 8. static const KeyStringToResultString appleLocaleToLanguageString[]; enum kNumAppleLocaleToLanguageString; + map Apple locale string appleLocaleToLanguageString[].key + to equivalent language string appleLocaleToLanguageString[].result + for n = 0..kNumAppleLocaleToLanguageString-1 + +*/ + +#include +#include +#include +#include +#include + + +// Max byte length of locale identifier (ASCII) as C string, including terminating null byte +enum { + kLocaleIdentifierCStringMax = ULOC_FULLNAME_CAPACITY + ULOC_KEYWORD_AND_VALUES_CAPACITY // currently 56 + 100 +}; + +// KeyStringToResultString struct used in data tables for CFLocaleCreateCanonicalLocaleIdentifierFromString +struct KeyStringToResultString { + const char * key; + const char * result; +}; +typedef struct KeyStringToResultString KeyStringToResultString; + +// SpecialCaseUpdates struct used in data tables for CFLocaleCreateCanonicalLocaleIdentifierFromString +struct SpecialCaseUpdates { + const char * lang; + const char * reg1; + const char * update1; + const char * reg2; + const char * update2; +}; +typedef struct SpecialCaseUpdates SpecialCaseUpdates; + + +static const char * const regionCodeToLocaleString[] = { +// map RegionCode (array index) to canonical locale string +// +// canon. string region code; language code; [comment] [ # __CFBundleLocaleAbbreviationsArray +// -------- ------------ ------------------ ------------ -------- string, if different ] + "en_US", // 0 verUS; 0 langEnglish; + "fr_FR", // 1 verFrance; 1 langFrench; + "en_GB", // 2 verBritain; 0 langEnglish; + "de_DE", // 3 verGermany; 2 langGerman; + "it_IT", // 4 verItaly; 3 langItalian; + "nl_NL", // 5 verNetherlands; 4 langDutch; + "nl_BE", // 6 verFlemish; 34 langFlemish (redundant, =Dutch); + "sv_SE", // 7 verSweden; 5 langSwedish; + "es_ES", // 8 verSpain; 6 langSpanish; + "da_DK", // 9 verDenmark; 7 langDanish; + "pt_PT", // 10 verPortugal; 8 langPortuguese; + "fr_CA", // 11 verFrCanada; 1 langFrench; + "nb_NO", // 12 verNorway; 9 langNorwegian (Bokmal); # "no_NO" + "he_IL", // 13 verIsrael; 10 langHebrew; + "ja_JP", // 14 verJapan; 11 langJapanese; + "en_AU", // 15 verAustralia; 0 langEnglish; + "ar", // 16 verArabic; 12 langArabic; + "fi_FI", // 17 verFinland; 13 langFinnish; + "fr_CH", // 18 verFrSwiss; 1 langFrench; + "de_CH", // 19 verGrSwiss; 2 langGerman; + "el_GR", // 20 verGreece; 14 langGreek (modern)-Grek-mono; + "is_IS", // 21 verIceland; 15 langIcelandic; + "mt_MT", // 22 verMalta; 16 langMaltese; + "el_CY", // 23 verCyprus; 14 langGreek?; el or tr? guess el # "" + "tr_TR", // 24 verTurkey; 17 langTurkish; + "hr_HR", // 25 verYugoCroatian; 18 langCroatian; * one-way mapping -> verCroatia + "nl_NL", // 26 KCHR, Netherlands; 4 langDutch; * one-way mapping + "nl_BE", // 27 KCHR, verFlemish; 34 langFlemish; * one-way mapping + "_CA", // 28 KCHR, Canada-en/fr?; -1 none; * one-way mapping # "en_CA" + "_CA", // 29 KCHR, Canada-en/fr?; -1 none; * one-way mapping # "en_CA" + "pt_PT", // 30 KCHR, Portugal; 8 langPortuguese; * one-way mapping + "nb_NO", // 31 KCHR, Norway; 9 langNorwegian (Bokmal); * one-way mapping # "no_NO" + "da_DK", // 32 KCHR, Denmark; 7 langDanish; * one-way mapping + "hi_IN", // 33 verIndiaHindi; 21 langHindi; + "ur_PK", // 34 verPakistanUrdu; 20 langUrdu; + "tr_TR", // 35 verTurkishModified; 17 langTurkish; * one-way mapping + "it_CH", // 36 verItalianSwiss; 3 langItalian; + "en_001", // 37 verInternational; 0 langEnglish; ASCII only # "en" + NULL, // 38 *unassigned; -1 none; * one-way mapping # "" + "ro_RO", // 39 verRomania; 37 langRomanian; + "grc", // 40 verGreekAncient; 148 langGreekAncient -Grek-poly; # "el_GR" + "lt_LT", // 41 verLithuania; 24 langLithuanian; + "pl_PL", // 42 verPoland; 25 langPolish; + "hu_HU", // 43 verHungary; 26 langHungarian; + "et_EE", // 44 verEstonia; 27 langEstonian; + "lv_LV", // 45 verLatvia; 28 langLatvian; + "se", // 46 verSami; 29 langSami; + "fo_FO", // 47 verFaroeIsl; 30 langFaroese; + "fa_IR", // 48 verIran; 31 langFarsi/Persian; + "ru_RU", // 49 verRussia; 32 langRussian; + "ga_IE", // 50 verIreland; 35 langIrishGaelic (no dots); + "ko_KR", // 51 verKorea; 23 langKorean; + "zh_CN", // 52 verChina; 33 langSimpChinese; + "zh_TW", // 53 verTaiwan; 19 langTradChinese; + "th_TH", // 54 verThailand; 22 langThai; + "und", // 55 verScriptGeneric; -1 none; # "" // <1.9> + "cs_CZ", // 56 verCzech; 38 langCzech; + "sk_SK", // 57 verSlovak; 39 langSlovak; + "und", // 58 verEastAsiaGeneric; -1 none; * one-way mapping # "" // <1.9> + "hu_HU", // 59 verMagyar; 26 langHungarian; * one-way mapping -> verHungary + "bn", // 60 verBengali; 67 langBengali; _IN or _BD? guess generic + "be_BY", // 61 verBelarus; 46 langBelorussian; + "uk_UA", // 62 verUkraine; 45 langUkrainian; + NULL, // 63 *unused; -1 none; * one-way mapping # "" + "el_GR", // 64 verGreeceAlt; 14 langGreek (modern)-Grek-mono; * one-way mapping + "sr_CS", // 65 verSerbian; 42 langSerbian -Cyrl; // <1.18> + "sl_SI", // 66 verSlovenian; 40 langSlovenian; + "mk_MK", // 67 verMacedonian; 43 langMacedonian; + "hr_HR", // 68 verCroatia; 18 langCroatian; + NULL, // 69 *unused; -1 none; * one-way mapping # "" + "de-1996", // 70 verGermanReformed; 2 langGerman; 1996 orthogr. # "de_DE" + "pt_BR", // 71 verBrazil; 8 langPortuguese; + "bg_BG", // 72 verBulgaria; 44 langBulgarian; + "ca_ES", // 73 verCatalonia; 130 langCatalan; + "mul", // 74 verMultilingual; -1 none; # "" + "gd", // 75 verScottishGaelic; 144 langScottishGaelic; + "gv", // 76 verManxGaelic; 145 langManxGaelic; + "br", // 77 verBreton; 142 langBreton; + "iu_CA", // 78 verNunavut; 143 langInuktitut -Cans; + "cy", // 79 verWelsh; 128 langWelsh; + "_CA", // 80 KCHR, Canada-en/fr?; -1 none; * one-way mapping # "en_CA" + "ga-Latg_IE", // 81 verIrishGaelicScrip; 146 langIrishGaelicScript -dots; # "ga_IE" // + "en_CA", // 82 verEngCanada; 0 langEnglish; + "dz_BT", // 83 verBhutan; 137 langDzongkha; + "hy_AM", // 84 verArmenian; 51 langArmenian; + "ka_GE", // 85 verGeorgian; 52 langGeorgian; + "es_419", // 86 verSpLatinAmerica; 6 langSpanish; # "es" + "es_ES", // 87 KCHR, Spain; 6 langSpanish; * one-way mapping + "to_TO", // 88 verTonga; 147 langTongan; + "pl_PL", // 89 KCHR, Poland; 25 langPolish; * one-way mapping + "ca_ES", // 90 KCHR, Catalonia; 130 langCatalan; * one-way mapping + "fr_001", // 91 verFrenchUniversal; 1 langFrench; + "de_AT", // 92 verAustria; 2 langGerman; + "es_419", // 93 > verSpLatinAmerica; 6 langSpanish; * one-way mapping # "es" + "gu_IN", // 94 verGujarati; 69 langGujarati; + "pa", // 95 verPunjabi; 70 langPunjabi; _IN or _PK? guess generic + "ur_IN", // 96 verIndiaUrdu; 20 langUrdu; + "vi_VN", // 97 verVietnam; 80 langVietnamese; + "fr_BE", // 98 verFrBelgium; 1 langFrench; + "uz_UZ", // 99 verUzbek; 47 langUzbek; + "en_SG", // 100 verSingapore; 0 langEnglish?; en, zh, or ms? guess en # "" + "nn_NO", // 101 verNynorsk; 151 langNynorsk; # "" + "af_ZA", // 102 verAfrikaans; 141 langAfrikaans; + "eo", // 103 verEsperanto; 94 langEsperanto; + "mr_IN", // 104 verMarathi; 66 langMarathi; + "bo", // 105 verTibetan; 63 langTibetan; + "ne_NP", // 106 verNepal; 64 langNepali; + "kl", // 107 verGreenland; 149 langGreenlandic; + "en_IE", // 108 verIrelandEnglish; 0 langEnglish; # (no entry) +}; +enum { + kNumRegionCodeToLocaleString = sizeof(regionCodeToLocaleString)/sizeof(char *) +}; + +static const char * const langCodeToLocaleString[] = { +// map LangCode (array index) to canonical locale string +// +// canon. string language code; [ comment] [ # __CFBundleLanguageAbbreviationsArray +// -------- -------------- ---------- -------- string, if different ] + "en", // 0 langEnglish; + "fr", // 1 langFrench; + "de", // 2 langGerman; + "it", // 3 langItalian; + "nl", // 4 langDutch; + "sv", // 5 langSwedish; + "es", // 6 langSpanish; + "da", // 7 langDanish; + "pt", // 8 langPortuguese; + "nb", // 9 langNorwegian (Bokmal); # "no" + "he", // 10 langHebrew -Hebr; + "ja", // 11 langJapanese -Jpan; + "ar", // 12 langArabic -Arab; + "fi", // 13 langFinnish; + "el", // 14 langGreek (modern)-Grek-mono; + "is", // 15 langIcelandic; + "mt", // 16 langMaltese -Latn; + "tr", // 17 langTurkish -Latn; + "hr", // 18 langCroatian; + "zh-Hant", // 19 langTradChinese; # "zh" + "ur", // 20 langUrdu -Arab; + "hi", // 21 langHindi -Deva; + "th", // 22 langThai -Thai; + "ko", // 23 langKorean -Hang; + "lt", // 24 langLithuanian; + "pl", // 25 langPolish; + "hu", // 26 langHungarian; + "et", // 27 langEstonian; + "lv", // 28 langLatvian; + "se", // 29 langSami; + "fo", // 30 langFaroese; + "fa", // 31 langFarsi/Persian -Arab; + "ru", // 32 langRussian -Cyrl; + "zh-Hans", // 33 langSimpChinese; # "zh" + "nl-BE", // 34 langFlemish (redundant, =Dutch); # "nl" + "ga", // 35 langIrishGaelic (no dots); + "sq", // 36 langAlbanian; no region codes + "ro", // 37 langRomanian; + "cs", // 38 langCzech; + "sk", // 39 langSlovak; + "sl", // 40 langSlovenian; + "yi", // 41 langYiddish -Hebr; no region codes + "sr", // 42 langSerbian -Cyrl; + "mk", // 43 langMacedonian -Cyrl; + "bg", // 44 langBulgarian -Cyrl; + "uk", // 45 langUkrainian -Cyrl; + "be", // 46 langBelorussian -Cyrl; + "uz-Cyrl", // 47 langUzbek -Cyrl; also -Latn, -Arab + "kk", // 48 langKazakh -Cyrl; no region codes; also -Latn, -Arab + "az-Cyrl", // 49 langAzerbaijani -Cyrl; no region codes # "az" + "az-Arab", // 50 langAzerbaijanAr -Arab; no region codes # "az" + "hy", // 51 langArmenian -Armn; + "ka", // 52 langGeorgian -Geor; + "mo", // 53 langMoldavian -Cyrl; no region codes + "ky", // 54 langKirghiz -Cyrl; no region codes; also -Latn, -Arab + "tg-Cyrl", // 55 langTajiki -Cyrl; no region codes; also -Latn, -Arab + "tk-Cyrl", // 56 langTurkmen -Cyrl; no region codes; also -Latn, -Arab + "mn-Mong", // 57 langMongolian -Mong; no region codes # "mn" + "mn-Cyrl", // 58 langMongolianCyr -Cyrl; no region codes # "mn" + "ps", // 59 langPashto -Arab; no region codes + "ku", // 60 langKurdish -Arab; no region codes + "ks", // 61 langKashmiri -Arab; no region codes + "sd", // 62 langSindhi -Arab; no region codes + "bo", // 63 langTibetan -Tibt; + "ne", // 64 langNepali -Deva; + "sa", // 65 langSanskrit -Deva; no region codes + "mr", // 66 langMarathi -Deva; + "bn", // 67 langBengali -Beng; + "as", // 68 langAssamese -Beng; no region codes + "gu", // 69 langGujarati -Gujr; + "pa", // 70 langPunjabi -Guru; + "or", // 71 langOriya -Orya; no region codes + "ml", // 72 langMalayalam -Mlym; no region codes + "kn", // 73 langKannada -Knda; no region codes + "ta", // 74 langTamil -Taml; no region codes + "te", // 75 langTelugu -Telu; no region codes + "si", // 76 langSinhalese -Sinh; no region codes + "my", // 77 langBurmese -Mymr; no region codes + "km", // 78 langKhmer -Khmr; no region codes + "lo", // 79 langLao -Laoo; no region codes + "vi", // 80 langVietnamese -Latn; + "id", // 81 langIndonesian -Latn; no region codes + "tl", // 82 langTagalog -Latn; no region codes + "ms", // 83 langMalayRoman -Latn; no region codes # "ms" + "ms-Arab", // 84 langMalayArabic -Arab; no region codes # "ms" + "am", // 85 langAmharic -Ethi; no region codes + "ti", // 86 langTigrinya -Ethi; no region codes + "om", // 87 langOromo -Ethi; no region codes + "so", // 88 langSomali -Latn; no region codes + "sw", // 89 langSwahili -Latn; no region codes + "rw", // 90 langKinyarwanda -Latn; no region codes + "rn", // 91 langRundi -Latn; no region codes + "ny", // 92 langNyanja/Chewa -Latn; no region codes # "" + "mg", // 93 langMalagasy -Latn; no region codes + "eo", // 94 langEsperanto -Latn; + NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, // 95 to 105 (gap) + NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, // 106 to 116 (gap) + NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL, // 107 to 117 (gap) + "cy", // 128 langWelsh -Latn; + "eu", // 129 langBasque -Latn; no region codes + "ca", // 130 langCatalan -Latn; + "la", // 131 langLatin -Latn; no region codes + "qu", // 132 langQuechua -Latn; no region codes + "gn", // 133 langGuarani -Latn; no region codes + "ay", // 134 langAymara -Latn; no region codes + "tt-Cyrl", // 135 langTatar -Cyrl; no region codes + "ug", // 136 langUighur -Arab; no region codes + "dz", // 137 langDzongkha -Tibt; + "jv", // 138 langJavaneseRom -Latn; no region codes + "su", // 139 langSundaneseRom -Latn; no region codes + "gl", // 140 langGalician -Latn; no region codes + "af", // 141 langAfrikaans -Latn; + "br", // 142 langBreton -Latn; + "iu", // 143 langInuktitut -Cans; + "gd", // 144 langScottishGaelic; + "gv", // 145 langManxGaelic -Latn; + "ga-Latg", // 146 langIrishGaelicScript -Latn-dots; # "ga" // + "to", // 147 langTongan -Latn; + "grc", // 148 langGreekAncient -Grek-poly; # "el" + "kl", // 149 langGreenlandic -Latn; + "az-Latn", // 150 langAzerbaijanRoman -Latn; no region codes # "az" + "nn", // 151 langNynorsk -Latn; # (no entry) +}; +enum { + kNumLangCodeToLocaleString = sizeof(langCodeToLocaleString)/sizeof(char *) +}; + +static const KeyStringToResultString oldAppleLocaleToCanonical[] = { +// Map obsolete/old-style Apple strings to canonical +// Must be sorted according to how strcmp compares the strings in the first column +// +// non-canonical canonical [ comment ] # source/reason for non-canonical string +// string string +// ------------- --------- + { "Afrikaans", "af" }, // # __CFBundleLanguageNamesArray + { "Albanian", "sq" }, // # __CFBundleLanguageNamesArray + { "Amharic", "am" }, // # __CFBundleLanguageNamesArray + { "Arabic", "ar" }, // # __CFBundleLanguageNamesArray + { "Armenian", "hy" }, // # __CFBundleLanguageNamesArray + { "Assamese", "as" }, // # __CFBundleLanguageNamesArray + { "Aymara", "ay" }, // # __CFBundleLanguageNamesArray + { "Azerbaijani", "az" }, // -Arab,-Cyrl,-Latn? # __CFBundleLanguageNamesArray (had 3 entries "Azerbaijani" for "az-Arab", "az-Cyrl", "az-Latn") + { "Basque", "eu" }, // # __CFBundleLanguageNamesArray + { "Belarusian", "be" }, // # handle other names + { "Belorussian", "be" }, // # handle other names + { "Bengali", "bn" }, // # __CFBundleLanguageNamesArray + { "Brazilian Portugese", "pt-BR" }, // # from Installer.app Info.plist IFLanguages key, misspelled + { "Brazilian Portuguese", "pt-BR" }, // # correct spelling for above + { "Breton", "br" }, // # __CFBundleLanguageNamesArray + { "Bulgarian", "bg" }, // # __CFBundleLanguageNamesArray + { "Burmese", "my" }, // # __CFBundleLanguageNamesArray + { "Byelorussian", "be" }, // # __CFBundleLanguageNamesArray + { "Catalan", "ca" }, // # __CFBundleLanguageNamesArray + { "Chewa", "ny" }, // # handle other names + { "Chichewa", "ny" }, // # handle other names + { "Chinese", "zh" }, // -Hans,-Hant? # __CFBundleLanguageNamesArray (had 2 entries "Chinese" for "zh-Hant", "zh-Hans") + { "Chinese, Simplified", "zh-Hans" }, // # from Installer.app Info.plist IFLanguages key + { "Chinese, Traditional", "zh-Hant" }, // # correct spelling for below + { "Chinese, Tradtional", "zh-Hant" }, // # from Installer.app Info.plist IFLanguages key, misspelled + { "Croatian", "hr" }, // # __CFBundleLanguageNamesArray + { "Czech", "cs" }, // # __CFBundleLanguageNamesArray + { "Danish", "da" }, // # __CFBundleLanguageNamesArray + { "Dutch", "nl" }, // # __CFBundleLanguageNamesArray (had 2 entries "Dutch" for "nl", "nl-BE") + { "Dzongkha", "dz" }, // # __CFBundleLanguageNamesArray + { "English", "en" }, // # __CFBundleLanguageNamesArray + { "Esperanto", "eo" }, // # __CFBundleLanguageNamesArray + { "Estonian", "et" }, // # __CFBundleLanguageNamesArray + { "Faroese", "fo" }, // # __CFBundleLanguageNamesArray + { "Farsi", "fa" }, // # __CFBundleLanguageNamesArray + { "Finnish", "fi" }, // # __CFBundleLanguageNamesArray + { "Flemish", "nl-BE" }, // # handle other names + { "French", "fr" }, // # __CFBundleLanguageNamesArray + { "Galician", "gl" }, // # __CFBundleLanguageNamesArray + { "Gallegan", "gl" }, // # handle other names + { "Georgian", "ka" }, // # __CFBundleLanguageNamesArray + { "German", "de" }, // # __CFBundleLanguageNamesArray + { "Greek", "el" }, // # __CFBundleLanguageNamesArray (had 2 entries "Greek" for "el", "grc") + { "Greenlandic", "kl" }, // # __CFBundleLanguageNamesArray + { "Guarani", "gn" }, // # __CFBundleLanguageNamesArray + { "Gujarati", "gu" }, // # __CFBundleLanguageNamesArray + { "Hawaiian", "haw" }, // # handle new languages + { "Hebrew", "he" }, // # __CFBundleLanguageNamesArray + { "Hindi", "hi" }, // # __CFBundleLanguageNamesArray + { "Hungarian", "hu" }, // # __CFBundleLanguageNamesArray + { "Icelandic", "is" }, // # __CFBundleLanguageNamesArray + { "Indonesian", "id" }, // # __CFBundleLanguageNamesArray + { "Inuktitut", "iu" }, // # __CFBundleLanguageNamesArray + { "Irish", "ga" }, // # __CFBundleLanguageNamesArray (had 2 entries "Irish" for "ga", "ga-dots") + { "Italian", "it" }, // # __CFBundleLanguageNamesArray + { "Japanese", "ja" }, // # __CFBundleLanguageNamesArray + { "Javanese", "jv" }, // # __CFBundleLanguageNamesArray + { "Kalaallisut", "kl" }, // # handle other names + { "Kannada", "kn" }, // # __CFBundleLanguageNamesArray + { "Kashmiri", "ks" }, // # __CFBundleLanguageNamesArray + { "Kazakh", "kk" }, // # __CFBundleLanguageNamesArray + { "Khmer", "km" }, // # __CFBundleLanguageNamesArray + { "Kinyarwanda", "rw" }, // # __CFBundleLanguageNamesArray + { "Kirghiz", "ky" }, // # __CFBundleLanguageNamesArray + { "Korean", "ko" }, // # __CFBundleLanguageNamesArray + { "Kurdish", "ku" }, // # __CFBundleLanguageNamesArray + { "Lao", "lo" }, // # __CFBundleLanguageNamesArray + { "Latin", "la" }, // # __CFBundleLanguageNamesArray + { "Latvian", "lv" }, // # __CFBundleLanguageNamesArray + { "Lithuanian", "lt" }, // # __CFBundleLanguageNamesArray + { "Macedonian", "mk" }, // # __CFBundleLanguageNamesArray + { "Malagasy", "mg" }, // # __CFBundleLanguageNamesArray + { "Malay", "ms" }, // -Latn,-Arab? # __CFBundleLanguageNamesArray (had 2 entries "Malay" for "ms-Latn", "ms-Arab") + { "Malayalam", "ml" }, // # __CFBundleLanguageNamesArray + { "Maltese", "mt" }, // # __CFBundleLanguageNamesArray + { "Manx", "gv" }, // # __CFBundleLanguageNamesArray + { "Marathi", "mr" }, // # __CFBundleLanguageNamesArray + { "Moldavian", "mo" }, // # __CFBundleLanguageNamesArray + { "Mongolian", "mn" }, // -Mong,-Cyrl? # __CFBundleLanguageNamesArray (had 2 entries "Mongolian" for "mn-Mong", "mn-Cyrl") + { "Nepali", "ne" }, // # __CFBundleLanguageNamesArray + { "Norwegian", "nb" }, // # __CFBundleLanguageNamesArray (had "Norwegian" mapping to "no") + { "Nyanja", "ny" }, // # __CFBundleLanguageNamesArray + { "Nynorsk", "nn" }, // # handle other names (no entry in __CFBundleLanguageNamesArray) + { "Oriya", "or" }, // # __CFBundleLanguageNamesArray + { "Oromo", "om" }, // # __CFBundleLanguageNamesArray + { "Panjabi", "pa" }, // # handle other names + { "Pashto", "ps" }, // # __CFBundleLanguageNamesArray + { "Persian", "fa" }, // # handle other names + { "Polish", "pl" }, // # __CFBundleLanguageNamesArray + { "Portuguese", "pt" }, // # __CFBundleLanguageNamesArray + { "Portuguese, Brazilian", "pt-BR" }, // # handle other names + { "Punjabi", "pa" }, // # __CFBundleLanguageNamesArray + { "Pushto", "ps" }, // # handle other names + { "Quechua", "qu" }, // # __CFBundleLanguageNamesArray + { "Romanian", "ro" }, // # __CFBundleLanguageNamesArray + { "Ruanda", "rw" }, // # handle other names + { "Rundi", "rn" }, // # __CFBundleLanguageNamesArray + { "Russian", "ru" }, // # __CFBundleLanguageNamesArray + { "Sami", "se" }, // # __CFBundleLanguageNamesArray + { "Sanskrit", "sa" }, // # __CFBundleLanguageNamesArray + { "Scottish", "gd" }, // # __CFBundleLanguageNamesArray + { "Serbian", "sr" }, // # __CFBundleLanguageNamesArray + { "Simplified Chinese", "zh-Hans" }, // # handle other names + { "Sindhi", "sd" }, // # __CFBundleLanguageNamesArray + { "Sinhalese", "si" }, // # __CFBundleLanguageNamesArray + { "Slovak", "sk" }, // # __CFBundleLanguageNamesArray + { "Slovenian", "sl" }, // # __CFBundleLanguageNamesArray + { "Somali", "so" }, // # __CFBundleLanguageNamesArray + { "Spanish", "es" }, // # __CFBundleLanguageNamesArray + { "Sundanese", "su" }, // # __CFBundleLanguageNamesArray + { "Swahili", "sw" }, // # __CFBundleLanguageNamesArray + { "Swedish", "sv" }, // # __CFBundleLanguageNamesArray + { "Tagalog", "tl" }, // # __CFBundleLanguageNamesArray + { "Tajik", "tg" }, // # handle other names + { "Tajiki", "tg" }, // # __CFBundleLanguageNamesArray + { "Tamil", "ta" }, // # __CFBundleLanguageNamesArray + { "Tatar", "tt" }, // # __CFBundleLanguageNamesArray + { "Telugu", "te" }, // # __CFBundleLanguageNamesArray + { "Thai", "th" }, // # __CFBundleLanguageNamesArray + { "Tibetan", "bo" }, // # __CFBundleLanguageNamesArray + { "Tigrinya", "ti" }, // # __CFBundleLanguageNamesArray + { "Tongan", "to" }, // # __CFBundleLanguageNamesArray + { "Traditional Chinese", "zh-Hant" }, // # handle other names + { "Turkish", "tr" }, // # __CFBundleLanguageNamesArray + { "Turkmen", "tk" }, // # __CFBundleLanguageNamesArray + { "Uighur", "ug" }, // # __CFBundleLanguageNamesArray + { "Ukrainian", "uk" }, // # __CFBundleLanguageNamesArray + { "Urdu", "ur" }, // # __CFBundleLanguageNamesArray + { "Uzbek", "uz" }, // # __CFBundleLanguageNamesArray + { "Vietnamese", "vi" }, // # __CFBundleLanguageNamesArray + { "Welsh", "cy" }, // # __CFBundleLanguageNamesArray + { "Yiddish", "yi" }, // # __CFBundleLanguageNamesArray + { "ar_??", "ar" }, // # from old MapScriptInfoAndISOCodes + { "az.Ar", "az-Arab" }, // # from old LocaleRefGetPartString + { "az.Cy", "az-Cyrl" }, // # from old LocaleRefGetPartString + { "az.La", "az-Latn" }, // # from old LocaleRefGetPartString + { "be_??", "be_BY" }, // # from old MapScriptInfoAndISOCodes + { "bn_??", "bn" }, // # from old LocaleRefGetPartString + { "bo_??", "bo" }, // # from old MapScriptInfoAndISOCodes + { "br_??", "br" }, // # from old MapScriptInfoAndISOCodes + { "cy_??", "cy" }, // # from old MapScriptInfoAndISOCodes + { "de-96", "de-1996" }, // # from old MapScriptInfoAndISOCodes // <1.9> + { "de_96", "de-1996" }, // # from old MapScriptInfoAndISOCodes // <1.9> + { "de_??", "de-1996" }, // # from old MapScriptInfoAndISOCodes + { "el.El-P", "grc" }, // # from old LocaleRefGetPartString + { "en-ascii", "en_001" }, // # from earlier version of tables in this file! + { "en_??", "en_001" }, // # from old MapScriptInfoAndISOCodes + { "eo_??", "eo" }, // # from old MapScriptInfoAndISOCodes + { "es_??", "es_419" }, // # from old MapScriptInfoAndISOCodes + { "es_XL", "es_419" }, // # from earlier version of tables in this file! + { "fr_??", "fr_001" }, // # from old MapScriptInfoAndISOCodes + { "ga-dots", "ga-Latg" }, // # from earlier version of tables in this file! // <1.8> + { "ga-dots_IE", "ga-Latg_IE" }, // # from earlier version of tables in this file! // <1.8> + { "ga.Lg", "ga-Latg" }, // # from old LocaleRefGetPartString // <1.8> + { "ga.Lg_IE", "ga-Latg_IE" }, // # from old LocaleRefGetPartString // <1.8> + { "gd_??", "gd" }, // # from old MapScriptInfoAndISOCodes + { "gv_??", "gv" }, // # from old MapScriptInfoAndISOCodes + { "jv.La", "jv" }, // # logical extension // <1.9> + { "jw.La", "jv" }, // # from old LocaleRefGetPartString + { "kk.Cy", "kk" }, // # from old LocaleRefGetPartString + { "kl.La", "kl" }, // # from old LocaleRefGetPartString + { "kl.La_GL", "kl_GL" }, // # from old LocaleRefGetPartString // <1.9> + { "lp_??", "se" }, // # from old MapScriptInfoAndISOCodes + { "mk_??", "mk_MK" }, // # from old MapScriptInfoAndISOCodes + { "mn.Cy", "mn-Cyrl" }, // # from old LocaleRefGetPartString + { "mn.Mn", "mn-Mong" }, // # from old LocaleRefGetPartString + { "ms.Ar", "ms-Arab" }, // # from old LocaleRefGetPartString + { "ms.La", "ms" }, // # from old LocaleRefGetPartString + { "nl-be", "nl-BE" }, // # from old LocaleRefGetPartString + { "nl-be_BE", "nl_BE" }, // # from old LocaleRefGetPartString +// { "no-bok_NO", "nb_NO" }, // # from old LocaleRefGetPartString - handled by localeStringPrefixToCanonical +// { "no-nyn_NO", "nn_NO" }, // # from old LocaleRefGetPartString - handled by localeStringPrefixToCanonical +// { "nya", "ny" }, // # from old LocaleRefGetPartString - handled by localeStringPrefixToCanonical + { "pa_??", "pa" }, // # from old LocaleRefGetPartString + { "sa.Dv", "sa" }, // # from old LocaleRefGetPartString + { "sl_??", "sl_SI" }, // # from old MapScriptInfoAndISOCodes + { "sr_??", "sr_CS" }, // # from old MapScriptInfoAndISOCodes // <1.18> + { "su.La", "su" }, // # from old LocaleRefGetPartString + { "yi.He", "yi" }, // # from old LocaleRefGetPartString + { "zh-simp", "zh-Hans" }, // # from earlier version of tables in this file! + { "zh-trad", "zh-Hant" }, // # from earlier version of tables in this file! + { "zh.Ha-S", "zh-Hans" }, // # from old LocaleRefGetPartString + { "zh.Ha-S_CN", "zh_CN" }, // # from old LocaleRefGetPartString + { "zh.Ha-T", "zh-Hant" }, // # from old LocaleRefGetPartString + { "zh.Ha-T_TW", "zh_TW" }, // # from old LocaleRefGetPartString +}; +enum { + kNumOldAppleLocaleToCanonical = sizeof(oldAppleLocaleToCanonical)/sizeof(KeyStringToResultString) +}; + +static const KeyStringToResultString localeStringPrefixToCanonical[] = { +// Map 3-letter & obsolete ISO 639 codes, plus obsolete RFC 3066 codes, to 2-letter ISO 639 code. +// (special cases for 'sh' handled separately) +// First column must be all lowercase; must be sorted according to how strcmp compares the strings in the first column. +// +// non-canonical canonical [ comment ] # source/reason for non-canonical string +// prefix prefix +// ------------- --------- + + { "afr", "af" }, // Afrikaans + { "alb", "sq" }, // Albanian + { "amh", "am" }, // Amharic + { "ara", "ar" }, // Arabic + { "arm", "hy" }, // Armenian + { "asm", "as" }, // Assamese + { "aym", "ay" }, // Aymara + { "aze", "az" }, // Azerbaijani + { "baq", "eu" }, // Basque + { "bel", "be" }, // Belarusian + { "ben", "bn" }, // Bengali + { "bih", "bh" }, // Bihari + { "bod", "bo" }, // Tibetan + { "bos", "bs" }, // Bosnian + { "bre", "br" }, // Breton + { "bul", "bg" }, // Bulgarian + { "bur", "my" }, // Burmese + { "cat", "ca" }, // Catalan + { "ces", "cs" }, // Czech + { "che", "ce" }, // Chechen + { "chi", "zh" }, // Chinese + { "cor", "kw" }, // Cornish + { "cos", "co" }, // Corsican + { "cym", "cy" }, // Welsh + { "cze", "cs" }, // Czech + { "dan", "da" }, // Danish + { "deu", "de" }, // German + { "dut", "nl" }, // Dutch + { "dzo", "dz" }, // Dzongkha + { "ell", "el" }, // Greek, Modern (1453-) + { "eng", "en" }, // English + { "epo", "eo" }, // Esperanto + { "est", "et" }, // Estonian + { "eus", "eu" }, // Basque + { "fao", "fo" }, // Faroese + { "fas", "fa" }, // Persian + { "fin", "fi" }, // Finnish + { "fra", "fr" }, // French + { "fre", "fr" }, // French + { "geo", "ka" }, // Georgian + { "ger", "de" }, // German + { "gla", "gd" }, // Gaelic,Scottish + { "gle", "ga" }, // Irish + { "glg", "gl" }, // Gallegan + { "glv", "gv" }, // Manx + { "gre", "el" }, // Greek, Modern (1453-) + { "grn", "gn" }, // Guarani + { "guj", "gu" }, // Gujarati + { "heb", "he" }, // Hebrew + { "hin", "hi" }, // Hindi + { "hrv", "hr" }, // Croatian + { "hun", "hu" }, // Hungarian + { "hye", "hy" }, // Armenian + { "i-hak", "zh-hakka" }, // Hakka # deprecated RFC 3066 + { "i-lux", "lb" }, // Luxembourgish # deprecated RFC 3066 + { "i-navajo", "nv" }, // Navajo # deprecated RFC 3066 + { "ice", "is" }, // Icelandic + { "iku", "iu" }, // Inuktitut + { "ile", "ie" }, // Interlingue + { "in", "id" }, // Indonesian # deprecated 639 code in -> id (1989) + { "ina", "ia" }, // Interlingua + { "ind", "id" }, // Indonesian + { "isl", "is" }, // Icelandic + { "ita", "it" }, // Italian + { "iw", "he" }, // Hebrew # deprecated 639 code iw -> he (1989) + { "jav", "jv" }, // Javanese + { "jaw", "jv" }, // Javanese # deprecated 639 code jaw -> jv (2001) + { "ji", "yi" }, // Yiddish # deprecated 639 code ji -> yi (1989) + { "jpn", "ja" }, // Japanese + { "kal", "kl" }, // Kalaallisut + { "kan", "kn" }, // Kannada + { "kas", "ks" }, // Kashmiri + { "kat", "ka" }, // Georgian + { "kaz", "kk" }, // Kazakh + { "khm", "km" }, // Khmer + { "kin", "rw" }, // Kinyarwanda + { "kir", "ky" }, // Kirghiz + { "kor", "ko" }, // Korean + { "kur", "ku" }, // Kurdish + { "lao", "lo" }, // Lao + { "lat", "la" }, // Latin + { "lav", "lv" }, // Latvian + { "lit", "lt" }, // Lithuanian + { "ltz", "lb" }, // Letzeburgesch + { "mac", "mk" }, // Macedonian + { "mal", "ml" }, // Malayalam + { "mar", "mr" }, // Marathi + { "may", "ms" }, // Malay + { "mkd", "mk" }, // Macedonian + { "mlg", "mg" }, // Malagasy + { "mlt", "mt" }, // Maltese + { "mol", "mo" }, // Moldavian + { "mon", "mn" }, // Mongolian + { "msa", "ms" }, // Malay + { "mya", "my" }, // Burmese + { "nep", "ne" }, // Nepali + { "nld", "nl" }, // Dutch + { "nno", "nn" }, // Norwegian Nynorsk + { "no", "nb" }, // Norwegian generic # ambiguous 639 code no -> nb + { "no-bok", "nb" }, // Norwegian Bokmal # deprecated RFC 3066 tag - used in old LocaleRefGetPartString + { "no-nyn", "nn" }, // Norwegian Nynorsk # deprecated RFC 3066 tag - used in old LocaleRefGetPartString + { "nob", "nb" }, // Norwegian Bokmal + { "nor", "nb" }, // Norwegian generic # ambiguous 639 code nor -> nb + { "nya", "ny" }, // Nyanja/Chewa/Chichewa # 3-letter code used in old LocaleRefGetPartString + { "oci", "oc" }, // Occitan/Provencal + { "ori", "or" }, // Oriya + { "orm", "om" }, // Oromo,Galla + { "pan", "pa" }, // Panjabi + { "per", "fa" }, // Persian + { "pol", "pl" }, // Polish + { "por", "pt" }, // Portuguese + { "pus", "ps" }, // Pushto + { "que", "qu" }, // Quechua + { "roh", "rm" }, // Raeto-Romance + { "ron", "ro" }, // Romanian + { "rum", "ro" }, // Romanian + { "run", "rn" }, // Rundi + { "rus", "ru" }, // Russian + { "san", "sa" }, // Sanskrit + { "scc", "sr" }, // Serbian + { "scr", "hr" }, // Croatian + { "sin", "si" }, // Sinhalese + { "slk", "sk" }, // Slovak + { "slo", "sk" }, // Slovak + { "slv", "sl" }, // Slovenian + { "sme", "se" }, // Sami,Northern + { "snd", "sd" }, // Sindhi + { "som", "so" }, // Somali + { "spa", "es" }, // Spanish + { "sqi", "sq" }, // Albanian + { "srp", "sr" }, // Serbian + { "sun", "su" }, // Sundanese + { "swa", "sw" }, // Swahili + { "swe", "sv" }, // Swedish + { "tam", "ta" }, // Tamil + { "tat", "tt" }, // Tatar + { "tel", "te" }, // Telugu + { "tgk", "tg" }, // Tajik + { "tgl", "tl" }, // Tagalog + { "tha", "th" }, // Thai + { "tib", "bo" }, // Tibetan + { "tir", "ti" }, // Tigrinya + { "ton", "to" }, // Tongan + { "tuk", "tk" }, // Turkmen + { "tur", "tr" }, // Turkish + { "uig", "ug" }, // Uighur + { "ukr", "uk" }, // Ukrainian + { "urd", "ur" }, // Urdu + { "uzb", "uz" }, // Uzbek + { "vie", "vi" }, // Vietnamese + { "wel", "cy" }, // Welsh + { "yid", "yi" }, // Yiddish + { "zho", "zh" }, // Chinese +}; +enum { + kNumLocaleStringPrefixToCanonical = sizeof(localeStringPrefixToCanonical)/sizeof(KeyStringToResultString) +}; + + +static const SpecialCaseUpdates specialCases[] = { +// Data for special cases +// a) The 3166 code CS was used for Czechoslovakia until 1993, when that country split and the code was +// replaced by CZ and SK. Then in 2003-07, the code YU (formerly designating all of Yugoslavia, then after +// the 1990s breakup just designating what is now Serbia and Montenegro) was changed to CS! However, ICU +// and RFC 3066bis will continue to use YU for this. So now CS is ambiguous. We guess as follows: If we +// see CS but a language of cs or sk, we change CS to CZ or SK. Otherwise, we change CS to YU. +// b) The 639 code sh for Serbo-Croatian was also replaced in the 1990s by separate codes hr and sr, and +// deprecated in 2000. We guess which one to map it to as follows: If there is a region tag of HR we use +// hr; if there is a region tag of (now) YU we use sr; else we do not change it (not enough info). +// c) There are other codes that have been updated without these issues (eg. TP to TL), plus among the +// "exceptionally reserved" codes some are just alternates for standard codes (eg. UK for GB). + { NULL, "-UK", "GB", NULL, NULL }, // always change UK to GB (UK is "exceptionally reserved" to mean GB) + { NULL, "-TP", "TL", NULL, NULL }, // always change TP to TL (East Timor, code changed 2002-05) + { "cs", "-CS", "CZ", NULL, NULL }, // if language is cs, change CS (pre-1993 Czechoslovakia) to CZ (Czech Republic) + { "sk", "-CS", "SK", NULL, NULL }, // if language is sk, change CS (pre-1993 Czechoslovakia) to SK (Slovakia) + { NULL, "-YU", "CS", NULL, NULL }, // then always change YU to CS (map old Yugoslavia code to new 2003-07 ISO code + // for Serbia & Montenegro per RFC3066bis & ICU) // <1.18> + // Note: do this after fixing CS for cs/sk as above. + { "sh", "-HR", "hr", "-CS", "sr" }, // if language is old 'sh' (SerboCroatian), change it to 'hr' (Croatian) if we find + // HR (Croatia) or to 'sr' (Serbian) if we find CS (Serbia & Montenegro, Yugoslavia). // <1.18> + // Note: Do this after changing YU to CS as above. + { NULL, NULL, NULL, NULL, NULL } // terminator +}; + + +static const KeyStringToResultString localeStringRegionToDefaults[] = { +// For some region-code suffixes, there are default substrings to strip off for canonical string. +// Must be sorted according to how strcmp compares the strings in the first column +// +// region default writing +// suffix system tags, strip comment +// -------- ------------- --------- + { "_CN", "-Hans" }, // mainland China, default is simplified + { "_HK", "-Hant" }, // Hong Kong, default is traditional + { "_MO", "-Hant" }, // Macao, default is traditional + { "_SG", "-Hans" }, // Singapore, default is simplified + { "_TW", "-Hant" }, // Taiwan, default is traditional +}; +enum { + kNumLocaleStringRegionToDefaults = sizeof(localeStringRegionToDefaults)/sizeof(KeyStringToResultString) +}; + +static const KeyStringToResultString localeStringPrefixToDefaults[] = { +// For some initial portions of language tag, there are default substrings to strip off for canonical string. +// Must be sorted according to how strcmp compares the strings in the first column +// +// language default writing +// tag prefix system tags, strip comment +// -------- ------------- --------- + { "ab-", "-Cyrl" }, // Abkhazian + { "af-", "-Latn" }, // Afrikaans + { "am-", "-Ethi" }, // Amharic + { "ar-", "-Arab" }, // Arabic + { "as-", "-Beng" }, // Assamese + { "ay-", "-Latn" }, // Aymara + { "be-", "-Cyrl" }, // Belarusian + { "bg-", "-Cyrl" }, // Bulgarian + { "bn-", "-Beng" }, // Bengali + { "bo-", "-Tibt" }, // Tibetan (? not Suppress-Script) + { "br-", "-Latn" }, // Breton (? not Suppress-Script) + { "bs-", "-Latn" }, // Bosnian + { "ca-", "-Latn" }, // Catalan + { "cs-", "-Latn" }, // Czech + { "cy-", "-Latn" }, // Welsh + { "da-", "-Latn" }, // Danish + { "de-", "-Latn -1901" }, // German, traditional orthography + { "dv-", "-Thaa" }, // Divehi/Maldivian + { "dz-", "-Tibt" }, // Dzongkha + { "el-", "-Grek" }, // Greek (modern, monotonic) + { "en-", "-Latn" }, // English + { "eo-", "-Latn" }, // Esperanto + { "es-", "-Latn" }, // Spanish + { "et-", "-Latn" }, // Estonian + { "eu-", "-Latn" }, // Basque + { "fa-", "-Arab" }, // Farsi + { "fi-", "-Latn" }, // Finnish + { "fo-", "-Latn" }, // Faroese + { "fr-", "-Latn" }, // French + { "ga-", "-Latn" }, // Irish + { "gd-", "-Latn" }, // Scottish Gaelic (? not Suppress-Script) + { "gl-", "-Latn" }, // Galician + { "gn-", "-Latn" }, // Guarani + { "gu-", "-Gujr" }, // Gujarati + { "gv-", "-Latn" }, // Manx + { "haw-", "-Latn" }, // Hawaiian (? not Suppress-Script) + { "he-", "-Hebr" }, // Hebrew + { "hi-", "-Deva" }, // Hindi + { "hr-", "-Latn" }, // Croatian + { "hu-", "-Latn" }, // Hungarian + { "hy-", "-Armn" }, // Armenian + { "id-", "-Latn" }, // Indonesian + { "is-", "-Latn" }, // Icelandic + { "it-", "-Latn" }, // Italian + { "ja-", "-Jpan" }, // Japanese + { "ka-", "-Geor" }, // Georgian + { "kk-", "-Cyrl" }, // Kazakh + { "kl-", "-Latn" }, // Kalaallisut/Greenlandic + { "km-", "-Khmr" }, // Central Khmer + { "kn-", "-Knda" }, // Kannada + { "ko-", "-Hang" }, // Korean (? not Suppress-Script) + { "kok-", "-Deva" }, // Konkani + { "la-", "-Latn" }, // Latin + { "lb-", "-Latn" }, // Luxembourgish + { "lo-", "-Laoo" }, // Lao + { "lt-", "-Latn" }, // Lithuanian + { "lv-", "-Latn" }, // Latvian + { "mg-", "-Latn" }, // Malagasy + { "mk-", "-Cyrl" }, // Macedonian + { "ml-", "-Mlym" }, // Malayalam + { "mo-", "-Latn" }, // Moldavian + { "mr-", "-Deva" }, // Marathi + { "ms-", "-Latn" }, // Malay + { "mt-", "-Latn" }, // Maltese + { "my-", "-Mymr" }, // Burmese/Myanmar + { "nb-", "-Latn" }, // Norwegian Bokmal + { "ne-", "-Deva" }, // Nepali + { "nl-", "-Latn" }, // Dutch + { "nn-", "-Latn" }, // Norwegian Nynorsk + { "ny-", "-Latn" }, // Chichewa/Nyanja + { "om-", "-Latn" }, // Oromo + { "or-", "-Orya" }, // Oriya + { "pa-", "-Guru" }, // Punjabi + { "pl-", "-Latn" }, // Polish + { "ps-", "-Arab" }, // Pushto + { "pt-", "-Latn" }, // Portuguese + { "qu-", "-Latn" }, // Quechua + { "rn-", "-Latn" }, // Rundi + { "ro-", "-Latn" }, // Romanian + { "ru-", "-Cyrl" }, // Russian + { "rw-", "-Latn" }, // Kinyarwanda + { "sa-", "-Deva" }, // Sanskrit (? not Suppress-Script) + { "se-", "-Latn" }, // Sami (? not Suppress-Script) + { "si-", "-Sinh" }, // Sinhala + { "sk-", "-Latn" }, // Slovak + { "sl-", "-Latn" }, // Slovenian + { "so-", "-Latn" }, // Somali + { "sq-", "-Latn" }, // Albanian + { "sv-", "-Latn" }, // Swedish + { "sw-", "-Latn" }, // Swahili + { "ta-", "-Taml" }, // Tamil + { "te-", "-Telu" }, // Telugu + { "th-", "-Thai" }, // Thai + { "ti-", "-Ethi" }, // Tigrinya + { "tl-", "-Latn" }, // Tagalog + { "tn-", "-Latn" }, // Tswana + { "to-", "-Latn" }, // Tonga of Tonga Islands + { "tr-", "-Latn" }, // Turkish + { "uk-", "-Cyrl" }, // Ukrainian + { "ur-", "-Arab" }, // Urdu + { "vi-", "-Latn" }, // Vietnamese + { "wo-", "-Latn" }, // Wolof + { "xh-", "-Latn" }, // Xhosa + { "yi-", "-Hebr" }, // Yiddish + { "zh-", "-Hani" }, // Chinese (? not Suppress-Script) + { "zu-", "-Latn" }, // Zulu +}; +enum { + kNumLocaleStringPrefixToDefaults = sizeof(localeStringPrefixToDefaults)/sizeof(KeyStringToResultString) +}; + +static const KeyStringToResultString appleLocaleToLanguageString[] = { +// Map locale strings that Apple uses as language IDs to real language strings. +// Must be sorted according to how strcmp compares the strings in the first column. +// Note: Now we remove all transforms of the form ll_RR -> ll-RR, they are now +// handled in the code. <1.19> +// +// locale lang [ comment ] +// string string +// ------- ------- + { "en_US_POSIX", "en-US-POSIX" }, // POSIX locale, need as language string // <1.17> [3840752] + { "zh_CN", "zh-Hans" }, // mainland China => simplified + { "zh_HK", "zh-Hant" }, // Hong Kong => traditional, not currently used + { "zh_MO", "zh-Hant" }, // Macao => traditional, not currently used + { "zh_SG", "zh-Hans" }, // Singapore => simplified, not currently used + { "zh_TW", "zh-Hant" }, // Taiwan => traditional +}; +enum { + kNumAppleLocaleToLanguageString = sizeof(appleLocaleToLanguageString)/sizeof(KeyStringToResultString) +}; + +static const KeyStringToResultString appleLocaleToLanguageStringForCFBundle[] = { +// Map locale strings that Apple uses as language IDs to real language strings. +// Must be sorted according to how strcmp compares the strings in the first column. +// +// locale lang [ comment ] +// string string +// ------- ------- + { "de_AT", "de-AT" }, // Austrian German + { "de_CH", "de-CH" }, // Swiss German +// { "de_DE", "de-DE" }, // German for Germany (default), not currently used + { "en_AU", "en-AU" }, // Australian English + { "en_CA", "en-CA" }, // Canadian English + { "en_GB", "en-GB" }, // British English +// { "en_IE", "en-IE" }, // Irish English, not currently used + { "en_US", "en-US" }, // U.S. English + { "en_US_POSIX", "en-US-POSIX" }, // POSIX locale, need as language string // <1.17> [3840752] +// { "fr_BE", "fr-BE" }, // Belgian French, not currently used + { "fr_CA", "fr-CA" }, // Canadian French + { "fr_CH", "fr-CH" }, // Swiss French +// { "fr_FR", "fr-FR" }, // French for France (default), not currently used + { "nl_BE", "nl-BE" }, // Flemish = Vlaams, Dutch for Belgium +// { "nl_NL", "nl-NL" }, // Dutch for Netherlands (default), not currently used + { "pt_BR", "pt-BR" }, // Brazilian Portuguese + { "pt_PT", "pt-PT" }, // Portuguese for Portugal + { "zh_CN", "zh-Hans" }, // mainland China => simplified + { "zh_HK", "zh-Hant" }, // Hong Kong => traditional, not currently used + { "zh_MO", "zh-Hant" }, // Macao => traditional, not currently used + { "zh_SG", "zh-Hans" }, // Singapore => simplified, not currently used + { "zh_TW", "zh-Hant" }, // Taiwan => traditional +}; +enum { + kNumAppleLocaleToLanguageStringForCFBundle = sizeof(appleLocaleToLanguageStringForCFBundle)/sizeof(KeyStringToResultString) +}; + + +struct LocaleToLegacyCodes { + const char * locale; // reduced to language plus one other component (script, region, variant), separators normalized to'_' + RegionCode regCode; + LangCode langCode; + CFStringEncoding encoding; +}; +typedef struct LocaleToLegacyCodes LocaleToLegacyCodes; + +static const LocaleToLegacyCodes localeToLegacyCodes[] = { + // locale RegionCode LangCode CFStringEncoding + { "af"/*ZA*/, 102/*verAfrikaans*/, 141/*langAfrikaans*/, 0/*Roman*/ }, // Latn + { "am", -1, 85/*langAmharic*/, 28/*Ethiopic*/ }, // Ethi + { "ar", 16/*verArabic*/, 12/*langArabic*/, 4/*Arabic*/ }, // Arab; + { "as", -1, 68/*langAssamese*/, 13/*Bengali*/ }, // Beng; + { "ay", -1, 134/*langAymara*/, 0/*Roman*/ }, // Latn; + { "az", -1, 49/*langAzerbaijani*/, 7/*Cyrillic*/ }, // assume "az" defaults to -Cyrl + { "az_Arab", -1, 50/*langAzerbaijanAr*/, 4/*Arabic*/ }, // Arab; + { "az_Cyrl", -1, 49/*langAzerbaijani*/, 7/*Cyrillic*/ }, // Cyrl; + { "az_Latn", -1, 150/*langAzerbaijanRoman*/, 0/*Roman*/ }, // Latn; + { "be"/*BY*/, 61/*verBelarus*/, 46/*langBelorussian*/, 7/*Cyrillic*/ }, // Cyrl; + { "bg"/*BG*/, 72/*verBulgaria*/, 44/*langBulgarian*/, 7/*Cyrillic*/ }, // Cyrl; + { "bn", 60/*verBengali*/, 67/*langBengali*/, 13/*Bengali*/ }, // Beng; + { "bo", 105/*verTibetan*/, 63/*langTibetan*/, 26/*Tibetan*/ }, // Tibt; + { "br", 77/*verBreton*/, 142/*langBreton*/, 39/*Celtic*/ }, // Latn; + { "ca"/*ES*/, 73/*verCatalonia*/, 130/*langCatalan*/, 0/*Roman*/ }, // Latn; + { "cs"/*CZ*/, 56/*verCzech*/, 38/*langCzech*/, 29/*CentralEurRoman*/ }, // Latn; + { "cy", 79/*verWelsh*/, 128/*langWelsh*/, 39/*Celtic*/ }, // Latn; + { "da"/*DK*/, 9/*verDenmark*/, 7/*langDanish*/, 0/*Roman*/ }, // Latn; + { "de", 3/*verGermany*/, 2/*langGerman*/, 0/*Roman*/ }, // assume "de" defaults to verGermany + { "de_1996", 70/*verGermanReformed*/, 2/*langGerman*/, 0/*Roman*/ }, + { "de_AT", 92/*verAustria*/, 2/*langGerman*/, 0/*Roman*/ }, + { "de_CH", 19/*verGrSwiss*/, 2/*langGerman*/, 0/*Roman*/ }, + { "de_DE", 3/*verGermany*/, 2/*langGerman*/, 0/*Roman*/ }, + { "dz"/*BT*/, 83/*verBhutan*/, 137/*langDzongkha*/, 26/*Tibetan*/ }, // Tibt; + { "el", 20/*verGreece*/, 14/*langGreek*/, 6/*Greek*/ }, // assume "el" defaults to verGreece + { "el_CY", 23/*verCyprus*/, 14/*langGreek*/, 6/*Greek*/ }, + { "el_GR", 20/*verGreece*/, 14/*langGreek*/, 6/*Greek*/ }, // modern monotonic + { "en", 0/*verUS*/, 0/*langEnglish*/, 0/*Roman*/ }, // "en" defaults to verUS (per Chris Hansten) + { "en_001", 37/*verInternational*/, 0/*langEnglish*/, 0/*Roman*/ }, + { "en_AU", 15/*verAustralia*/, 0/*langEnglish*/, 0/*Roman*/ }, + { "en_CA", 82/*verEngCanada*/, 0/*langEnglish*/, 0/*Roman*/ }, + { "en_GB", 2/*verBritain*/, 0/*langEnglish*/, 0/*Roman*/ }, + { "en_IE", 108/*verIrelandEnglish*/, 0/*langEnglish*/, 0/*Roman*/ }, + { "en_SG", 100/*verSingapore*/, 0/*langEnglish*/, 0/*Roman*/ }, + { "en_US", 0/*verUS*/, 0/*langEnglish*/, 0/*Roman*/ }, + { "eo", 103/*verEsperanto*/, 94/*langEsperanto*/, 0/*Roman*/ }, // Latn; + { "es", 8/*verSpain*/, 6/*langSpanish*/, 0/*Roman*/ }, // "es" defaults to verSpain (per Chris Hansten) + { "es_419", 86/*verSpLatinAmerica*/, 6/*langSpanish*/, 0/*Roman*/ }, // new BCP 47 tag + { "es_ES", 8/*verSpain*/, 6/*langSpanish*/, 0/*Roman*/ }, + { "es_MX", 86/*verSpLatinAmerica*/, 6/*langSpanish*/, 0/*Roman*/ }, + { "es_US", 86/*verSpLatinAmerica*/, 6/*langSpanish*/, 0/*Roman*/ }, + { "et"/*EE*/, 44/*verEstonia*/, 27/*langEstonian*/, 29/*CentralEurRoman*/ }, + { "eu", -1, 129/*langBasque*/, 0/*Roman*/ }, // Latn; + { "fa"/*IR*/, 48/*verIran*/, 31/*langFarsi/Persian*/, 0x8C/*Farsi*/ }, // Arab; + { "fi"/*FI*/, 17/*verFinland*/, 13/*langFinnish*/, 0/*Roman*/ }, + { "fo"/*FO*/, 47/*verFaroeIsl*/, 30/*langFaroese*/, 37/*Icelandic*/ }, + { "fr", 1/*verFrance*/, 1/*langFrench*/, 0/*Roman*/ }, // "fr" defaults to verFrance (per Chris Hansten) + { "fr_001", 91/*verFrenchUniversal*/, 1/*langFrench*/, 0/*Roman*/ }, + { "fr_BE", 98/*verFrBelgium*/, 1/*langFrench*/, 0/*Roman*/ }, + { "fr_CA", 11/*verFrCanada*/, 1/*langFrench*/, 0/*Roman*/ }, + { "fr_CH", 18/*verFrSwiss*/, 1/*langFrench*/, 0/*Roman*/ }, + { "fr_FR", 1/*verFrance*/, 1/*langFrench*/, 0/*Roman*/ }, + { "ga"/*IE*/, 50/*verIreland*/, 35/*langIrishGaelic*/, 0/*Roman*/ }, // no dots (h after) + { "ga_Latg"/*IE*/, 81/*verIrishGaelicScrip*/, 146/*langIrishGaelicScript*/, 40/*Gaelic*/ }, // using dots + { "gd", 75/*verScottishGaelic*/, 144/*langScottishGaelic*/, 39/*Celtic*/ }, + { "gl", -1, 140/*langGalician*/, 0/*Roman*/ }, // Latn; + { "gn", -1, 133/*langGuarani*/, 0/*Roman*/ }, // Latn; + { "grc", 40/*verGreekAncient*/, 148/*langGreekAncient*/, 6/*Greek*/ }, // polytonic (MacGreek doesn't actually support it) + { "gu"/*IN*/, 94/*verGujarati*/, 69/*langGujarati*/, 11/*Gujarati*/ }, // Gujr; + { "gv", 76/*verManxGaelic*/, 145/*langManxGaelic*/, 39/*Celtic*/ }, // Latn; + { "he"/*IL*/, 13/*verIsrael*/, 10/*langHebrew*/, 5/*Hebrew*/ }, // Hebr; + { "hi"/*IN*/, 33/*verIndiaHindi*/, 21/*langHindi*/, 9/*Devanagari*/ }, // Deva; + { "hr"/*HR*/, 68/*verCroatia*/, 18/*langCroatian*/, 36/*Croatian*/ }, + { "hu"/*HU*/, 43/*verHungary*/, 26/*langHungarian*/, 29/*CentralEurRoman*/ }, + { "hy"/*AM*/, 84/*verArmenian*/, 51/*langArmenian*/, 24/*Armenian*/ }, // Armn; + { "id", -1, 81/*langIndonesian*/, 0/*Roman*/ }, // Latn; + { "is"/*IS*/, 21/*verIceland*/, 15/*langIcelandic*/, 37/*Icelandic*/ }, + { "it", 4/*verItaly*/, 3/*langItalian*/, 0/*Roman*/ }, // "it" defaults to verItaly + { "it_CH", 36/*verItalianSwiss*/, 3/*langItalian*/, 0/*Roman*/ }, + { "it_IT", 4/*verItaly*/, 3/*langItalian*/, 0/*Roman*/ }, + { "iu"/*CA*/, 78/*verNunavut*/, 143/*langInuktitut*/, 0xEC/*Inuit*/ }, // Cans; + { "ja"/*JP*/, 14/*verJapan*/, 11/*langJapanese*/, 1/*Japanese*/ }, // Jpan; + { "jv", -1, 138/*langJavaneseRom*/, 0/*Roman*/ }, // Latn; + { "ka"/*GE*/, 85/*verGeorgian*/, 52/*langGeorgian*/, 23/*Georgian*/ }, // Geor; + { "kk", -1, 48/*langKazakh*/, 7/*Cyrillic*/ }, // "kk" defaults to -Cyrl; also have -Latn, -Arab + { "kl", 107/*verGreenland*/, 149/*langGreenlandic*/, 0/*Roman*/ }, // Latn; + { "km", -1, 78/*langKhmer*/, 20/*Khmer*/ }, // Khmr; + { "kn", -1, 73/*langKannada*/, 16/*Kannada*/ }, // Knda; + { "ko"/*KR*/, 51/*verKorea*/, 23/*langKorean*/, 3/*Korean*/ }, // Hang; + { "ks", -1, 61/*langKashmiri*/, 4/*Arabic*/ }, // Arab; + { "ku", -1, 60/*langKurdish*/, 4/*Arabic*/ }, // Arab; + { "ky", -1, 54/*langKirghiz*/, 7/*Cyrillic*/ }, // Cyrl; also -Latn, -Arab + { "la", -1, 131/*langLatin*/, 0/*Roman*/ }, // Latn; + { "lo", -1, 79/*langLao*/, 22/*Laotian*/ }, // Laoo; + { "lt"/*LT*/, 41/*verLithuania*/, 24/*langLithuanian*/, 29/*CentralEurRoman*/ }, + { "lv"/*LV*/, 45/*verLatvia*/, 28/*langLatvian*/, 29/*CentralEurRoman*/ }, + { "mg", -1, 93/*langMalagasy*/, 0/*Roman*/ }, // Latn; + { "mk"/*MK*/, 67/*verMacedonian*/, 43/*langMacedonian*/, 7/*Cyrillic*/ }, // Cyrl; + { "ml", -1, 72/*langMalayalam*/, 17/*Malayalam*/ }, // Mlym; + { "mn", -1, 57/*langMongolian*/, 27/*Mongolian*/ }, // "mn" defaults to -Mong + { "mn_Cyrl", -1, 58/*langMongolianCyr*/, 7/*Cyrillic*/ }, // Cyrl; + { "mn_Mong", -1, 57/*langMongolian*/, 27/*Mongolian*/ }, // Mong; + { "mo", -1, 53/*langMoldavian*/, 7/*Cyrillic*/ }, // Cyrl; + { "mr"/*IN*/, 104/*verMarathi*/, 66/*langMarathi*/, 9/*Devanagari*/ }, // Deva; + { "ms", -1, 83/*langMalayRoman*/, 0/*Roman*/ }, // "ms" defaults to -Latn; + { "ms_Arab", -1, 84/*langMalayArabic*/, 4/*Arabic*/ }, // Arab; + { "mt"/*MT*/, 22/*verMalta*/, 16/*langMaltese*/, 0/*Roman*/ }, // Latn; + { "mul", 74/*verMultilingual*/, -1, 0 }, + { "my", -1, 77/*langBurmese*/, 19/*Burmese*/ }, // Mymr; + { "nb"/*NO*/, 12/*verNorway*/, 9/*langNorwegian*/, 0/*Roman*/ }, + { "ne"/*NP*/, 106/*verNepal*/, 64/*langNepali*/, 9/*Devanagari*/ }, // Deva; + { "nl", 5/*verNetherlands*/, 4/*langDutch*/, 0/*Roman*/ }, // "nl" defaults to verNetherlands + { "nl_BE", 6/*verFlemish*/, 34/*langFlemish*/, 0/*Roman*/ }, + { "nl_NL", 5/*verNetherlands*/, 4/*langDutch*/, 0/*Roman*/ }, + { "nn"/*NO*/, 101/*verNynorsk*/, 151/*langNynorsk*/, 0/*Roman*/ }, + { "ny", -1, 92/*langNyanja/Chewa*/, 0/*Roman*/ }, // Latn; + { "om", -1, 87/*langOromo*/, 28/*Ethiopic*/ }, // Ethi; + { "or", -1, 71/*langOriya*/, 12/*Oriya*/ }, // Orya; + { "pa", 95/*verPunjabi*/, 70/*langPunjabi*/, 10/*Gurmukhi*/ }, // Guru; + { "pl"/*PL*/, 42/*verPoland*/, 25/*langPolish*/, 29/*CentralEurRoman*/ }, + { "ps", -1, 59/*langPashto*/, 0x8C/*Farsi*/ }, // Arab; + { "pt", 71/*verBrazil*/, 8/*langPortuguese*/, 0/*Roman*/ }, // "pt" defaults to verBrazil (per Chris Hansten) + { "pt_BR", 71/*verBrazil*/, 8/*langPortuguese*/, 0/*Roman*/ }, + { "pt_PT", 10/*verPortugal*/, 8/*langPortuguese*/, 0/*Roman*/ }, + { "qu", -1, 132/*langQuechua*/, 0/*Roman*/ }, // Latn; + { "rn", -1, 91/*langRundi*/, 0/*Roman*/ }, // Latn; + { "ro"/*RO*/, 39/*verRomania*/, 37/*langRomanian*/, 38/*Romanian*/ }, + { "ru"/*RU*/, 49/*verRussia*/, 32/*langRussian*/, 7/*Cyrillic*/ }, // Cyrl; + { "rw", -1, 90/*langKinyarwanda*/, 0/*Roman*/ }, // Latn; + { "sa", -1, 65/*langSanskrit*/, 9/*Devanagari*/ }, // Deva; + { "sd", -1, 62/*langSindhi*/, 0x8C/*Farsi*/ }, // Arab; + { "se", 46/*verSami*/, 29/*langSami*/, 0/*Roman*/ }, + { "si", -1, 76/*langSinhalese*/, 18/*Sinhalese*/ }, // Sinh; + { "sk"/*SK*/, 57/*verSlovak*/, 39/*langSlovak*/, 29/*CentralEurRoman*/ }, + { "sl"/*SI*/, 66/*verSlovenian*/, 40/*langSlovenian*/, 36/*Croatian*/ }, + { "so", -1, 88/*langSomali*/, 0/*Roman*/ }, // Latn; + { "sq", -1, 36/*langAlbanian*/, 0/*Roman*/ }, + { "sr"/*CS,RS*/, 65/*verSerbian*/, 42/*langSerbian*/, 7/*Cyrillic*/ }, // Cyrl; + { "su", -1, 139/*langSundaneseRom*/, 0/*Roman*/ }, // Latn; + { "sv"/*SE*/, 7/*verSweden*/, 5/*langSwedish*/, 0/*Roman*/ }, + { "sw", -1, 89/*langSwahili*/, 0/*Roman*/ }, // Latn; + { "ta", -1, 74/*langTamil*/, 14/*Tamil*/ }, // Taml; + { "te", -1, 75/*langTelugu*/, 15/*Telugu*/ }, // Telu + { "tg", -1, 55/*langTajiki*/, 7/*Cyrillic*/ }, // "tg" defaults to "Cyrl" + { "tg_Cyrl", -1, 55/*langTajiki*/, 7/*Cyrillic*/ }, // Cyrl; also -Latn, -Arab + { "th"/*TH*/, 54/*verThailand*/, 22/*langThai*/, 21/*Thai*/ }, // Thai; + { "ti", -1, 86/*langTigrinya*/, 28/*Ethiopic*/ }, // Ethi; + { "tk", -1, 56/*langTurkmen*/, 7/*Cyrillic*/ }, // "tk" defaults to Cyrl + { "tk_Cyrl", -1, 56/*langTurkmen*/, 7/*Cyrillic*/ }, // Cyrl; also -Latn, -Arab + { "tl", -1, 82/*langTagalog*/, 0/*Roman*/ }, // Latn; + { "to"/*TO*/, 88/*verTonga*/, 147/*langTongan*/, 0/*Roman*/ }, // Latn; + { "tr"/*TR*/, 24/*verTurkey*/, 17/*langTurkish*/, 35/*Turkish*/ }, // Latn; + { "tt", -1, 135/*langTatar*/, 7/*Cyrillic*/ }, // Cyrl; + { "tt_Cyrl", -1, 135/*langTatar*/, 7/*Cyrillic*/ }, // Cyrl; + { "ug", -1, 136/*langUighur*/, 4/*Arabic*/ }, // Arab; + { "uk"/*UA*/, 62/*verUkraine*/, 45/*langUkrainian*/, 7/*Cyrillic*/ }, // Cyrl; + { "und", 55/*verScriptGeneric*/, -1, 0 }, + { "ur", 34/*verPakistanUrdu*/, 20/*langUrdu*/, 0x8C/*Farsi*/ }, // "ur" defaults to verPakistanUrdu + { "ur_IN", 96/*verIndiaUrdu*/, 20/*langUrdu*/, 0x8C/*Farsi*/ }, // Arab + { "ur_PK", 34/*verPakistanUrdu*/, 20/*langUrdu*/, 0x8C/*Farsi*/ }, // Arab + { "uz"/*UZ*/, 99/*verUzbek*/, 47/*langUzbek*/, 7/*Cyrillic*/ }, // Cyrl; also -Latn, -Arab + { "uz_Cyrl", 99/*verUzbek*/, 47/*langUzbek*/, 7/*Cyrillic*/ }, + { "vi"/*VN*/, 97/*verVietnam*/, 80/*langVietnamese*/, 30/*Vietnamese*/ }, // Latn + { "yi", -1, 41/*langYiddish*/, 5/*Hebrew*/ }, // Hebr; + { "zh", 52/*verChina*/, 33/*langSimpChinese*/, 25/*ChineseSimp*/ }, // "zh" defaults to verChina, langSimpChinese + { "zh_CN", 52/*verChina*/, 33/*langSimpChinese*/, 25/*ChineseSimp*/ }, + { "zh_HK", 53/*verTaiwan*/, 19/*langTradChinese*/, 2/*ChineseTrad*/ }, + { "zh_Hans", 52/*verChina*/, 33/*langSimpChinese*/, 25/*ChineseSimp*/ }, + { "zh_Hant", 53/*verTaiwan*/, 19/*langTradChinese*/, 2/*ChineseTrad*/ }, + { "zh_MO", 53/*verTaiwan*/, 19/*langTradChinese*/, 2/*ChineseTrad*/ }, + { "zh_SG", 52/*verChina*/, 33/*langSimpChinese*/, 25/*ChineseSimp*/ }, + { "zh_TW", 53/*verTaiwan*/, 19/*langTradChinese*/, 2/*ChineseTrad*/ }, +}; +enum { + kNumLocaleToLegacyCodes = sizeof(localeToLegacyCodes)/sizeof(localeToLegacyCodes[0]) +}; + +/* + For reference here is a list of ICU locales with variants and how some + of them are canonicalized with the ICU function uloc_canonicalize: + + ICU 3.0 has: + en_US_POSIX x no change + hy_AM_REVISED x no change + ja_JP_TRADITIONAL -> ja_JP@calendar=japanese + th_TH_TRADITIONAL -> th_TH@calendar=buddhist + + ICU 2.8 also had the following (now obsolete): + ca_ES_PREEURO + de__PHONEBOOK -> de@collation=phonebook + de_AT_PREEURO + de_DE_PREEURO + de_LU_PREEURO + el_GR_PREEURO + en_BE_PREEURO + en_GB_EURO -> en_GB@currency=EUR + en_IE_PREEURO -> en_IE@currency=IEP + es__TRADITIONAL -> es@collation=traditional + es_ES_PREEURO + eu_ES_PREEURO + fi_FI_PREEURO + fr_BE_PREEURO + fr_FR_PREEURO -> fr_FR@currency=FRF + fr_LU_PREEURO + ga_IE_PREEURO + gl_ES_PREEURO + hi__DIRECT -> hi@collation=direct + it_IT_PREEURO + nl_BE_PREEURO + nl_NL_PREEURO + pt_PT_PREEURO + zh__PINYIN -> zh@collation=pinyin + zh_TW_STROKE -> zh_TW@collation=stroke + +*/ + +// _CompareTestEntryToTableEntryKey +// (Local function for CFLocaleCreateCanonicalLocaleIdentifierFromString) +// comparison function for bsearch +static int _CompareTestEntryToTableEntryKey(const void *testEntryPtr, const void *tableEntryKeyPtr) { + return strcmp( ((const KeyStringToResultString *)testEntryPtr)->key, ((const KeyStringToResultString *)tableEntryKeyPtr)->key ); +} + +// _CompareTestEntryPrefixToTableEntryKey +// (Local function for CFLocaleCreateCanonicalLocaleIdentifierFromString) +// Comparison function for bsearch. Assumes prefix IS terminated with '-' or '_'. +// Do the following instead of strlen & strncmp so we don't walk tableEntry key twice. +static int _CompareTestEntryPrefixToTableEntryKey(const void *testEntryPtr, const void *tableEntryKeyPtr) { + const char * testPtr = ((const KeyStringToResultString *)testEntryPtr)->key; + const char * tablePtr = ((const KeyStringToResultString *)tableEntryKeyPtr)->key; + + while ( *testPtr == *tablePtr && *tablePtr != 0 ) { + testPtr++; tablePtr++; + } + if ( *tablePtr != 0 ) { + // strings are different, and the string in the table has not run out; + // i.e. the table entry is not a prefix of the text string. + return ( *testPtr < *tablePtr )? -1: 1; + } + return 0; +} + +// _CompareLowerTestEntryPrefixToTableEntryKey +// (Local function for CFLocaleCreateCanonicalLocaleIdentifierFromString) +// Comparison function for bsearch. Assumes prefix NOT terminated with '-' or '_'. +// Lowercases the test string before comparison (the table should already have lowercased entries). +static int _CompareLowerTestEntryPrefixToTableEntryKey(const void *testEntryPtr, const void *tableEntryKeyPtr) { + const char * testPtr = ((const KeyStringToResultString *)testEntryPtr)->key; + const char * tablePtr = ((const KeyStringToResultString *)tableEntryKeyPtr)->key; + char lowerTestChar; + + while ( (lowerTestChar = tolower(*testPtr)) == *tablePtr && *tablePtr != 0 && lowerTestChar != '_' ) { // <1.9> + testPtr++; tablePtr++; + } + if ( *tablePtr != 0 ) { + // strings are different, and the string in the table has not run out; + // i.e. the table entry is not a prefix of the text string. + if (lowerTestChar == '_') // <1.9> + return -1; // <1.9> + return ( lowerTestChar < *tablePtr )? -1: 1; + } + // The string in the table has run out. If the test string char is not alnum, + // then the string matches, else the test string sorts after. + return ( !isalnum(lowerTestChar) )? 0: 1; +} + +// _DeleteCharsAtPointer +// (Local function for CFLocaleCreateCanonicalLocaleIdentifierFromString) +// remove _length_ characters from the beginning of the string indicated by _stringPtr_ +// (we know that the string has at least _length_ characters in it) +static void _DeleteCharsAtPointer(char *stringPtr, int length) { + do { + *stringPtr = stringPtr[length]; + } while (*stringPtr++ != 0); +} + +// _CopyReplacementAtPointer +// (Local function for CFLocaleCreateCanonicalLocaleIdentifierFromString) +// Copy replacement string (*excluding* terminating NULL byte) to the place indicated by stringPtr +static void _CopyReplacementAtPointer(char *stringPtr, const char *replacementPtr) { + while (*replacementPtr != 0) { + *stringPtr++ = *replacementPtr++; + } +} + +// _CheckForTag +// (Local function for CFLocaleCreateCanonicalLocaleIdentifierFromString) +static Boolean _CheckForTag(const char *localeStringPtr, const char *tagPtr, int tagLen) { + return ( strncmp(localeStringPtr, tagPtr, tagLen) == 0 && !isalnum(localeStringPtr[tagLen]) ); +} + +// _ReplacePrefix +// Move this code from _UpdateFullLocaleString into separate function // <1.10> +static void _ReplacePrefix(char locString[], int locStringMaxLen, int oldPrefixLen, const char *newPrefix) { + int newPrefixLen = strlen(newPrefix); + int lengthDelta = newPrefixLen - oldPrefixLen; + + if (lengthDelta < 0) { + // replacement is shorter, delete chars by shifting tail of string + _DeleteCharsAtPointer(locString + newPrefixLen, -lengthDelta); + } else if (lengthDelta > 0) { + // replacement is longer... + int stringLen = strlen(locString); + + if (stringLen + lengthDelta < locStringMaxLen) { + // make room by shifting tail of string + char * tailShiftPtr = locString + stringLen; + char * tailStartPtr = locString + oldPrefixLen; // pointer to tail of string to shift + + while (tailShiftPtr >= tailStartPtr) { + tailShiftPtr[lengthDelta] = *tailShiftPtr; + tailShiftPtr--; + } + } else { + // no room, can't do substitution + newPrefix = NULL; + } + } + + if (newPrefix) { + // do the substitution + _CopyReplacementAtPointer(locString, newPrefix); + } +} + +// _UpdateFullLocaleString +// Given a locale string that uses standard codes (not a special old-style Apple string), +// update all the language codes and region codes to latest versions, map 3-letter +// language codes to 2-letter codes if possible, and normalize casing. If requested, return +// pointers to a language-region variant subtag (if present) and a region tag (if present). +// (add locStringMaxLen parameter) // <1.10> +static void _UpdateFullLocaleString(char inLocaleString[], int locStringMaxLen, + char **langRegSubtagRef, char **regionTagRef, + char varKeyValueString[]) // <1.17> +{ + KeyStringToResultString testEntry; + KeyStringToResultString * foundEntry; + const SpecialCaseUpdates * specialCasePtr; + char * inLocalePtr; + char * subtagPtr; + char * langRegSubtag = NULL; + char * regionTag = NULL; + char * variantTag = NULL; + Boolean subtagHasDigits, pastPrimarySubtag, hadRegion; + + // 1. First replace any non-canonical prefix (case insensitive) with canonical + // (change 3-letter ISO 639 code to 2-letter, update obsolete ISO 639 codes & RFC 3066 tags, etc.) + + testEntry.key = inLocaleString; + foundEntry = (KeyStringToResultString *)bsearch( &testEntry, localeStringPrefixToCanonical, kNumLocaleStringPrefixToCanonical, + sizeof(KeyStringToResultString), _CompareLowerTestEntryPrefixToTableEntryKey ); + if (foundEntry) { + // replace key (at beginning of string) with result + _ReplacePrefix(inLocaleString, locStringMaxLen, strlen(foundEntry->key), foundEntry->result); // <1.10> + } + + // 2. Walk through input string, normalizing case & marking use of ISO 3166 codes + + inLocalePtr = inLocaleString; + subtagPtr = inLocaleString; + subtagHasDigits = false; + pastPrimarySubtag = false; + hadRegion = false; + + while ( true ) { + if ( isalpha(*inLocalePtr) ) { + // if not past a region tag, then lowercase, else uppercase + *inLocalePtr = (!hadRegion)? tolower(*inLocalePtr): toupper(*inLocalePtr); + } else if ( isdigit(*inLocalePtr) ) { + subtagHasDigits = true; + } else { + + if (!pastPrimarySubtag) { + // may have a NULL primary subtag + if (subtagHasDigits) { + break; + } + pastPrimarySubtag = true; + } else if (!hadRegion) { + // We are after any primary language subtag, but not past any region tag. + // This subtag is preceded by '-' or '_'. + int subtagLength = inLocalePtr - subtagPtr; // includes leading '-' or '_' + + if (subtagLength == 3 && !subtagHasDigits) { + // potential ISO 3166 code for region or language variant; if so, needs uppercasing + if (*subtagPtr == '_') { + regionTag = subtagPtr; + hadRegion = true; + subtagPtr[1] = toupper(subtagPtr[1]); + subtagPtr[2] = toupper(subtagPtr[2]); + } else if (langRegSubtag == NULL) { + langRegSubtag = subtagPtr; + subtagPtr[1] = toupper(subtagPtr[1]); + subtagPtr[2] = toupper(subtagPtr[2]); + } + } else if (subtagLength == 4 && subtagHasDigits) { + // potential UN M.49 region code + if (*subtagPtr == '_') { + regionTag = subtagPtr; + hadRegion = true; + } else if (langRegSubtag == NULL) { + langRegSubtag = subtagPtr; + } + } else if (subtagLength == 5 && !subtagHasDigits) { + // ISO 15924 script code, uppercase just the first letter + subtagPtr[1] = toupper(subtagPtr[1]); + } else if (subtagLength == 1 && *subtagPtr == '_') { // <1.17> + hadRegion = true; + } + + if (!hadRegion) { + // convert improper '_' to '-' + *subtagPtr = '-'; + } + } else { + variantTag = subtagPtr; // <1.17> + } + + if (*inLocalePtr == '-' || *inLocalePtr == '_') { + subtagPtr = inLocalePtr; + subtagHasDigits = false; + } else { + break; + } + } + + inLocalePtr++; + } + + // 3 If there is a variant tag, see if ICU canonicalizes it to keywords. // <1.17> [3577669] + // If so, copy the keywords to varKeyValueString and delete the variant tag + // from the original string (but don't otherwise use the ICU canonicalization). + varKeyValueString[0] = 0; + if (variantTag) { + UErrorCode icuStatus; + int icuCanonStringLen; + char * varKeyValueStringPtr = varKeyValueString; + + icuStatus = U_ZERO_ERROR; + icuCanonStringLen = uloc_canonicalize( inLocaleString, varKeyValueString, locStringMaxLen, &icuStatus ); + if ( U_SUCCESS(icuStatus) ) { + char * icuCanonStringPtr = varKeyValueString; + + if (icuCanonStringLen >= locStringMaxLen) + icuCanonStringLen = locStringMaxLen - 1; + varKeyValueString[icuCanonStringLen] = 0; + while (*icuCanonStringPtr != 0 && *icuCanonStringPtr != ULOC_KEYWORD_SEPARATOR) + ++icuCanonStringPtr; + if (*icuCanonStringPtr != 0) { + // the canonicalized string has keywords + // delete the variant tag in the original string (and other trailing '_' or '-') + *variantTag-- = 0; + while (*variantTag == '_') + *variantTag-- = 0; + // delete all of the canonicalized string except the keywords + while (*icuCanonStringPtr != 0) + *varKeyValueStringPtr++ = *icuCanonStringPtr++; + } + *varKeyValueStringPtr = 0; + } + } + + // 4. Handle special cases of updating region codes, or updating language codes based on + // region code. + for (specialCasePtr = specialCases; specialCasePtr->reg1 != NULL; specialCasePtr++) { + if ( specialCasePtr->lang == NULL || _CheckForTag(inLocaleString, specialCasePtr->lang, 2) ) { + // OK, we matched any language specified. Now what needs updating? + char * foundTag; + + if ( isupper(specialCasePtr->update1[0]) ) { + // updating a region code + if ( ( foundTag = strstr(inLocaleString, specialCasePtr->reg1) ) && !isalnum(foundTag[3]) ) { + _CopyReplacementAtPointer(foundTag+1, specialCasePtr->update1); + } + if ( regionTag && _CheckForTag(regionTag+1, specialCasePtr->reg1 + 1, 2) ) { + _CopyReplacementAtPointer(regionTag+1, specialCasePtr->update1); + } + + } else { + // updating the language, there will be two choices based on region + if ( ( regionTag && _CheckForTag(regionTag+1, specialCasePtr->reg1 + 1, 2) ) || + ( ( foundTag = strstr(inLocaleString, specialCasePtr->reg1) ) && !isalnum(foundTag[3]) ) ) { + _CopyReplacementAtPointer(inLocaleString, specialCasePtr->update1); + } else if ( ( regionTag && _CheckForTag(regionTag+1, specialCasePtr->reg2 + 1, 2) ) || + ( ( foundTag = strstr(inLocaleString, specialCasePtr->reg2) ) && !isalnum(foundTag[3]) ) ) { + _CopyReplacementAtPointer(inLocaleString, specialCasePtr->update2); + } + } + } + } + + // 5. return pointers if requested. + if (langRegSubtagRef != NULL) { + *langRegSubtagRef = langRegSubtag; + } + if (regionTagRef != NULL) { + *regionTagRef = regionTag; + } +} + + +// _RemoveSubstringsIfPresent +// (Local function for CFLocaleCreateCanonicalLocaleIdentifierFromString) +// substringList is a list of space-separated substrings to strip if found in localeString +static void _RemoveSubstringsIfPresent(char *localeString, const char *substringList) { + while (*substringList != 0) { + char currentSubstring[kLocaleIdentifierCStringMax]; + int substringLength = 0; + char * foundSubstring; + + // copy current substring & get its length + while ( isgraph(*substringList) ) { + currentSubstring[substringLength++] = *substringList++; + } + // move to next substring + while ( isspace(*substringList) ) { + substringList++; + } + + // search for current substring in locale string + if (substringLength == 0) + continue; + currentSubstring[substringLength] = 0; + foundSubstring = strstr(localeString, currentSubstring); + + // if substring is found, delete it + if (foundSubstring) { + _DeleteCharsAtPointer(foundSubstring, substringLength); + } + } +} + + +// _GetKeyValueString // <1.10> +// Removes any key-value string from inLocaleString, puts canonized version in keyValueString + +static void _GetKeyValueString(char inLocaleString[], char keyValueString[]) { + char * inLocalePtr = inLocaleString; + + while (*inLocalePtr != 0 && *inLocalePtr != ULOC_KEYWORD_SEPARATOR) { + inLocalePtr++; + } + if (*inLocalePtr != 0) { // we found a key-value section + char * keyValuePtr = keyValueString; + + *keyValuePtr = *inLocalePtr; + *inLocalePtr = 0; + do { + if ( *(++inLocalePtr) != ' ' ) { + *(++keyValuePtr) = *inLocalePtr; // remove "tolower() for *inLocalePtr" // <1.11> + } + } while (*inLocalePtr != 0); + } else { + keyValueString[0] = 0; + } +} + +static void _AppendKeyValueString(char inLocaleString[], int locStringMaxLen, char keyValueString[]) { + if (keyValueString[0] != 0) { + UErrorCode uerr = U_ZERO_ERROR; + UEnumeration * uenum = uloc_openKeywords(keyValueString, &uerr); + if ( uenum != NULL ) { + const char * keyword; + int32_t length; + char value[ULOC_KEYWORDS_CAPACITY]; // use as max for keyword value + while ( U_SUCCESS(uerr) ) { + keyword = uenum_next(uenum, &length, &uerr); + if ( keyword == NULL ) { + break; + } + length = uloc_getKeywordValue( keyValueString, keyword, value, sizeof(value), &uerr ); + length = uloc_setKeywordValue( keyword, value, inLocaleString, locStringMaxLen, &uerr ); + } + uenum_close(uenum); + } + } +} + +__private_extern__ CFStringRef _CFLocaleCreateCanonicalLanguageIdentifierForCFBundle(CFAllocatorRef allocator, CFStringRef localeIdentifier) { + char inLocaleString[kLocaleIdentifierCStringMax]; + CFStringRef outStringRef = NULL; + + if ( localeIdentifier && CFStringGetCString(localeIdentifier, inLocaleString, sizeof(inLocaleString), kCFStringEncodingASCII) ) { + KeyStringToResultString testEntry; + KeyStringToResultString * foundEntry; + char keyValueString[sizeof(inLocaleString)]; // <1.10> + char varKeyValueString[sizeof(inLocaleString)]; // <1.17> + + _GetKeyValueString(inLocaleString, keyValueString); // <1.10> + testEntry.result = NULL; + + // A. First check if input string matches an old-style string that has a replacement + // (do this before case normalization) + testEntry.key = inLocaleString; + foundEntry = (KeyStringToResultString *)bsearch( &testEntry, oldAppleLocaleToCanonical, kNumOldAppleLocaleToCanonical, + sizeof(KeyStringToResultString), _CompareTestEntryToTableEntryKey ); + if (foundEntry) { + // It does match, so replace old string with new + strlcpy(inLocaleString, foundEntry->result, sizeof(inLocaleString)); + varKeyValueString[0] = 0; + } else { + // B. No match with an old-style string, use input string but update codes, normalize case, etc. + _UpdateFullLocaleString(inLocaleString, sizeof(inLocaleString), NULL, NULL, varKeyValueString); // <1.10><1.17> + } + + // C. Now we have an up-to-date locale string, but we need to strip defaults and turn it into a language string + + // 1. Strip defaults in input string based on initial part of locale string + // (mainly to strip default script tag for a language) + testEntry.key = inLocaleString; + foundEntry = (KeyStringToResultString *)bsearch( &testEntry, localeStringPrefixToDefaults, kNumLocaleStringPrefixToDefaults, + sizeof(KeyStringToResultString), _CompareTestEntryPrefixToTableEntryKey ); + if (foundEntry) { + // The input string begins with a character sequence for which + // there are default substrings which should be stripped if present + _RemoveSubstringsIfPresent(inLocaleString, foundEntry->result); + } + + // 2. If the string matches a locale string used by Apple as a language string, turn it into a language string + testEntry.key = inLocaleString; + foundEntry = (KeyStringToResultString *)bsearch( &testEntry, appleLocaleToLanguageStringForCFBundle, kNumAppleLocaleToLanguageStringForCFBundle, + sizeof(KeyStringToResultString), _CompareTestEntryToTableEntryKey ); + if (foundEntry) { + // it does match + strlcpy(inLocaleString, foundEntry->result, sizeof(inLocaleString)); + } else { + // just delete the region tag and anything after + char * inLocalePtr = inLocaleString; + while (*inLocalePtr != 0 && *inLocalePtr != '_') { + inLocalePtr++; + } + *inLocalePtr = 0; + } + + // D. Re-append any key-value strings, now canonical // <1.10><1.17> + _AppendKeyValueString( inLocaleString, sizeof(inLocaleString), varKeyValueString ); + _AppendKeyValueString( inLocaleString, sizeof(inLocaleString), keyValueString ); + + // All done, return what we came up with. + outStringRef = CFStringCreateWithCString(allocator, inLocaleString, kCFStringEncodingASCII); + } + + return outStringRef; +} + +CFStringRef CFLocaleCreateCanonicalLanguageIdentifierFromString(CFAllocatorRef allocator, CFStringRef localeIdentifier) { + char inLocaleString[kLocaleIdentifierCStringMax]; + CFStringRef outStringRef = NULL; + + if ( localeIdentifier && CFStringGetCString(localeIdentifier, inLocaleString, sizeof(inLocaleString), kCFStringEncodingASCII) ) { + KeyStringToResultString testEntry; + KeyStringToResultString * foundEntry; + char keyValueString[sizeof(inLocaleString)]; // <1.10> + char varKeyValueString[sizeof(inLocaleString)]; // <1.17> + + _GetKeyValueString(inLocaleString, keyValueString); // <1.10> + testEntry.result = NULL; + + // A. First check if input string matches an old-style string that has a replacement + // (do this before case normalization) + testEntry.key = inLocaleString; + foundEntry = (KeyStringToResultString *)bsearch( &testEntry, oldAppleLocaleToCanonical, kNumOldAppleLocaleToCanonical, + sizeof(KeyStringToResultString), _CompareTestEntryToTableEntryKey ); + if (foundEntry) { + // It does match, so replace old string with new + strlcpy(inLocaleString, foundEntry->result, sizeof(inLocaleString)); + varKeyValueString[0] = 0; + } else { + char * langRegSubtag = NULL; + char * regionTag = NULL; + + // B. No match with an old-style string, use input string but update codes, normalize case, etc. + _UpdateFullLocaleString(inLocaleString, sizeof(inLocaleString), &langRegSubtag, ®ionTag, varKeyValueString); // <1.10><1.17><1.19> + + // if the language part already includes a regional variant, then delete any region tag. <1.19> + if (langRegSubtag && regionTag) + *regionTag = 0; + } + + // C. Now we have an up-to-date locale string, but we need to strip defaults and turn it into a language string + + // 1. Strip defaults in input string based on initial part of locale string + // (mainly to strip default script tag for a language) + testEntry.key = inLocaleString; + foundEntry = (KeyStringToResultString *)bsearch( &testEntry, localeStringPrefixToDefaults, kNumLocaleStringPrefixToDefaults, + sizeof(KeyStringToResultString), _CompareTestEntryPrefixToTableEntryKey ); + if (foundEntry) { + // The input string begins with a character sequence for which + // there are default substrings which should be stripped if present + _RemoveSubstringsIfPresent(inLocaleString, foundEntry->result); + } + + // 2. If the string matches a locale string used by Apple as a language string, turn it into a language string + testEntry.key = inLocaleString; + foundEntry = (KeyStringToResultString *)bsearch( &testEntry, appleLocaleToLanguageString, kNumAppleLocaleToLanguageString, + sizeof(KeyStringToResultString), _CompareTestEntryToTableEntryKey ); + if (foundEntry) { + // it does match + strlcpy(inLocaleString, foundEntry->result, sizeof(inLocaleString)); + } else { + // skip to any region tag or java-type variant + char * inLocalePtr = inLocaleString; + while (*inLocalePtr != 0 && *inLocalePtr != '_') { + inLocalePtr++; + } + // if there is still a region tag, turn it into a language variant <1.19> + if (*inLocalePtr == '_') { + // handle 3-digit regions in addition to 2-letter ones + char * regionTag = inLocalePtr++; + long expectedLength = 0; + if ( isalpha(*inLocalePtr) ) { + while ( isalpha(*(++inLocalePtr)) ) + ; + expectedLength = 3; + } else if ( isdigit(*inLocalePtr) ) { + while ( isdigit(*(++inLocalePtr)) ) + ; + expectedLength = 4; + } + *regionTag = (inLocalePtr - regionTag == expectedLength)? '-': 0; + } + // anything else at/after '_' just gets deleted + *inLocalePtr = 0; + } + + // D. Re-append any key-value strings, now canonical // <1.10><1.17> + _AppendKeyValueString( inLocaleString, sizeof(inLocaleString), varKeyValueString ); + _AppendKeyValueString( inLocaleString, sizeof(inLocaleString), keyValueString ); + + // All done, return what we came up with. + outStringRef = CFStringCreateWithCString(allocator, inLocaleString, kCFStringEncodingASCII); + } + + return outStringRef; +} + + +CFStringRef CFLocaleCreateCanonicalLocaleIdentifierFromString(CFAllocatorRef allocator, CFStringRef localeIdentifier) { + char inLocaleString[kLocaleIdentifierCStringMax]; + CFStringRef outStringRef = NULL; + + if ( localeIdentifier && CFStringGetCString(localeIdentifier, inLocaleString, sizeof(inLocaleString), kCFStringEncodingASCII) ) { + KeyStringToResultString testEntry; + KeyStringToResultString * foundEntry; + char keyValueString[sizeof(inLocaleString)]; // <1.10> + char varKeyValueString[sizeof(inLocaleString)]; // <1.17> + + _GetKeyValueString(inLocaleString, keyValueString); // <1.10> + testEntry.result = NULL; + + // A. First check if input string matches an old-style Apple string that has a replacement + // (do this before case normalization) + testEntry.key = inLocaleString; + foundEntry = (KeyStringToResultString *)bsearch( &testEntry, oldAppleLocaleToCanonical, kNumOldAppleLocaleToCanonical, + sizeof(KeyStringToResultString), _CompareTestEntryToTableEntryKey ); + if (foundEntry) { + // It does match, so replace old string with new // <1.10> + strlcpy(inLocaleString, foundEntry->result, sizeof(inLocaleString)); + varKeyValueString[0] = 0; + } else { + char * langRegSubtag = NULL; + char * regionTag = NULL; + + // B. No match with an old-style string, use input string but update codes, normalize case, etc. + _UpdateFullLocaleString(inLocaleString, sizeof(inLocaleString), &langRegSubtag, ®ionTag, varKeyValueString); // <1.10><1.17> + + + // C. Now strip defaults that are implied by other fields. + + // 1. If an ISO 3166 region tag matches an ISO 3166 regional language variant subtag, strip the latter. + if ( langRegSubtag && regionTag && strncmp(langRegSubtag+1, regionTag+1, 2) == 0 ) { + _DeleteCharsAtPointer(langRegSubtag, 3); + } + + // 2. Strip defaults in input string based on final region tag in locale string + // (mainly for Chinese, to strip -Hans for _CN/_SG, -Hant for _TW/_HK/_MO) + if ( regionTag ) { + testEntry.key = regionTag; + foundEntry = (KeyStringToResultString *)bsearch( &testEntry, localeStringRegionToDefaults, kNumLocaleStringRegionToDefaults, + sizeof(KeyStringToResultString), _CompareTestEntryToTableEntryKey ); + if (foundEntry) { + _RemoveSubstringsIfPresent(inLocaleString, foundEntry->result); + } + } + + // 3. Strip defaults in input string based on initial part of locale string + // (mainly to strip default script tag for a language) + testEntry.key = inLocaleString; + foundEntry = (KeyStringToResultString *)bsearch( &testEntry, localeStringPrefixToDefaults, kNumLocaleStringPrefixToDefaults, + sizeof(KeyStringToResultString), _CompareTestEntryPrefixToTableEntryKey ); + if (foundEntry) { + // The input string begins with a character sequence for which + // there are default substrings which should be stripped if present + _RemoveSubstringsIfPresent(inLocaleString, foundEntry->result); + } + } + + // D. Re-append any key-value strings, now canonical // <1.10><1.17> + _AppendKeyValueString( inLocaleString, sizeof(inLocaleString), varKeyValueString ); + _AppendKeyValueString( inLocaleString, sizeof(inLocaleString), keyValueString ); + + // Now create the CFString (even if empty!) + outStringRef = CFStringCreateWithCString(allocator, inLocaleString, kCFStringEncodingASCII); + } + + return outStringRef; +} + +// CFLocaleCreateCanonicalLocaleIdentifierFromScriptManagerCodes, based on +// the first part of the SPI CFBundleCopyLocalizationForLocalizationInfo in CFBundle_Resources.c +CFStringRef CFLocaleCreateCanonicalLocaleIdentifierFromScriptManagerCodes(CFAllocatorRef allocator, LangCode lcode, RegionCode rcode) { + CFStringRef result = NULL; + if (0 <= rcode && rcode < kNumRegionCodeToLocaleString) { + const char *localeString = regionCodeToLocaleString[rcode]; + if (localeString != NULL && *localeString != '\0') { + result = CFStringCreateWithCStringNoCopy(allocator, localeString, kCFStringEncodingASCII, kCFAllocatorNull); + } + } + if (result) return result; + if (0 <= lcode && lcode < kNumLangCodeToLocaleString) { + const char *localeString = langCodeToLocaleString[lcode]; + if (localeString != NULL && *localeString != '\0') { + result = CFStringCreateWithCStringNoCopy(allocator, localeString, kCFStringEncodingASCII, kCFAllocatorNull); + } + } + return result; +} + + +CFDictionaryRef CFLocaleCreateComponentsFromLocaleIdentifier(CFAllocatorRef allocator, CFStringRef localeID) { + char cLocaleID[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; + char buffer[ULOC_FULLNAME_CAPACITY+ULOC_KEYWORD_AND_VALUES_CAPACITY]; + CFMutableDictionaryRef working = CFDictionaryCreateMutable(allocator, 10, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + UErrorCode icuStatus = U_ZERO_ERROR; + int32_t length = 0; + + // Extract the C string locale ID, for ICU + CFIndex outBytes = 0; + CFStringGetBytes(localeID, CFRangeMake(0, CFStringGetLength(localeID)), kCFStringEncodingASCII, (UInt8) '?', true, (unsigned char *)cLocaleID, sizeof(cLocaleID)/sizeof(char) - 1, &outBytes); + cLocaleID[outBytes] = '\0'; + + // Get the components + length = uloc_getLanguage(cLocaleID, buffer, sizeof(buffer)/sizeof(char), &icuStatus); + if (U_SUCCESS(icuStatus) && length > 0) + { + CFStringRef string = CFStringCreateWithBytes(allocator, (UInt8 *)buffer, length, kCFStringEncodingASCII, true); + CFDictionaryAddValue(working, kCFLocaleLanguageCode, string); + CFRelease(string); + } + icuStatus = U_ZERO_ERROR; + + length = uloc_getScript(cLocaleID, buffer, sizeof(buffer)/sizeof(char), &icuStatus); + if (U_SUCCESS(icuStatus) && length > 0) + { + CFStringRef string = CFStringCreateWithBytes(allocator, (UInt8 *)buffer, length, kCFStringEncodingASCII, true); + CFDictionaryAddValue(working, kCFLocaleScriptCode, string); + CFRelease(string); + } + icuStatus = U_ZERO_ERROR; + + length = uloc_getCountry(cLocaleID, buffer, sizeof(buffer)/sizeof(char), &icuStatus); + if (U_SUCCESS(icuStatus) && length > 0) + { + CFStringRef string = CFStringCreateWithBytes(allocator, (UInt8 *)buffer, length, kCFStringEncodingASCII, true); + CFDictionaryAddValue(working, kCFLocaleCountryCode, string); + CFRelease(string); + } + icuStatus = U_ZERO_ERROR; + + length = uloc_getVariant(cLocaleID, buffer, sizeof(buffer)/sizeof(char), &icuStatus); + if (U_SUCCESS(icuStatus) && length > 0) + { + CFStringRef string = CFStringCreateWithBytes(allocator, (UInt8 *)buffer, length, kCFStringEncodingASCII, true); + CFDictionaryAddValue(working, kCFLocaleVariantCode, string); + CFRelease(string); + } + icuStatus = U_ZERO_ERROR; + + // Now get the keywords; open an enumerator on them + UEnumeration *iter = uloc_openKeywords(cLocaleID, &icuStatus); + const char *locKey = NULL; + int32_t locKeyLen = 0; + while ((locKey = uenum_next(iter, &locKeyLen, &icuStatus)) && U_SUCCESS(icuStatus)) + { + char locValue[ULOC_KEYWORD_AND_VALUES_CAPACITY]; + + // Get the value for this keyword + if (uloc_getKeywordValue(cLocaleID, locKey, locValue, sizeof(locValue)/sizeof(char), &icuStatus) > 0 + && U_SUCCESS(icuStatus)) + { + CFStringRef key = CFStringCreateWithBytes(allocator, (UInt8 *)locKey, strlen(locKey), kCFStringEncodingASCII, true); + CFStringRef value = CFStringCreateWithBytes(allocator, (UInt8 *)locValue, strlen(locValue), kCFStringEncodingASCII, true); + if (key && value) + CFDictionaryAddValue(working, key, value); + if (key) + CFRelease(key); + if (value) + CFRelease(value); + } + } + uenum_close(iter); + + // Convert to an immutable dictionary and return + CFDictionaryRef result = CFDictionaryCreateCopy(allocator, working); + CFRelease(working); + return result; +} + +typedef struct __AppendContext +{ + char separator; + CFMutableStringRef working; +} __AppendContext; + +static void __AppendKeywords(const void *k, const void *v, void *c) +{ + __AppendContext *context = (__AppendContext *) c; + CFStringRef key = (CFStringRef) k; + CFStringRef value = (CFStringRef) v; + if (CFEqual(key, kCFLocaleLanguageCode) || CFEqual(key, kCFLocaleScriptCode) || CFEqual(key, kCFLocaleCountryCode) || CFEqual(key, kCFLocaleVariantCode)) + return; + CFStringAppendFormat(context->working, NULL, CFSTR("%c%@%c%@"), context->separator, key, ULOC_KEYWORD_ASSIGN, value); + context->separator = ULOC_KEYWORD_ITEM_SEPARATOR; +} + +CFStringRef CFLocaleCreateLocaleIdentifierFromComponents(CFAllocatorRef allocator, CFDictionaryRef dictionary) { + CFMutableStringRef working = CFStringCreateMutable(allocator, 0); + CFStringRef value = NULL; + bool country = false; + __AppendContext context = {ULOC_KEYWORD_SEPARATOR, working}; + + if ((value = (CFStringRef) CFDictionaryGetValue(dictionary, kCFLocaleLanguageCode))) + { + CFStringAppend(working, value); + } + + if ((value = (CFStringRef) CFDictionaryGetValue(dictionary, kCFLocaleScriptCode))) + { + CFStringAppendFormat(working, NULL, CFSTR("_%@"), value); + } + + if ((value = (CFStringRef) CFDictionaryGetValue(dictionary, kCFLocaleCountryCode))) + { + CFStringAppendFormat(working, NULL, CFSTR("_%@"), value); + country = true; + } + + if ((value = (CFStringRef) CFDictionaryGetValue(dictionary, kCFLocaleVariantCode))) + { + if (!country) + CFStringAppend(working, CFSTR("_")); + CFStringAppendFormat(working, NULL, CFSTR("_%@"), value); + } + + // Now iterate through any remaining entries and append as keywords + CFDictionaryApplyFunction(dictionary, __AppendKeywords, &context); + + // Convert to immutable string and return + CFStringRef result = (CFStringRef)CFStringCreateCopy(allocator, working); + CFRelease(working); + return result; +} + diff --git a/CFLogUtilities.h b/CFLogUtilities.h new file mode 100644 index 0000000..07004b9 --- /dev/null +++ b/CFLogUtilities.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFLogUtilities.h + Copyright (c) 2004-2007, Apple Inc. All rights reserved. +*/ + +/* + APPLE SPI: NOT TO BE USED OUTSIDE APPLE! +*/ + +#if !defined(__COREFOUNDATION_CFLOGUTILITIES__) +#define __COREFOUNDATION_CFLOGUTILITIES__ 1 + +#include +#include + +CF_EXTERN_C_BEGIN + + +enum { // Legal level values for CFLog() + kCFLogLevelEmergency = 0, + kCFLogLevelAlert = 1, + kCFLogLevelCritical = 2, + kCFLogLevelError = 3, + kCFLogLevelWarning = 4, + kCFLogLevelNotice = 5, + kCFLogLevelInfo = 6, + kCFLogLevelDebug = 7, +}; + +CF_EXPORT void CFLog(int32_t level, CFStringRef format, ...); +/* Passing in a level value which is outside the range of 0-7 will cause the the call to do nothing. + CFLog() logs the message using the asl.h API, and uses the level parameter as the log level. + Note that the asl subsystem ignores some log levels by default. + CFLog() is not fast, and is not going to be guaranteed to be fast. + Even "no-op" CFLogs are not necessarily fast. + If you care about performance, you shouldn't be logging. +*/ + +CF_EXTERN_C_END + +#endif /* ! __COREFOUNDATION_CFLOGUTILITIES__ */ + diff --git a/RunLoop.subproj/CFMachPort.c b/CFMachPort.c similarity index 72% rename from RunLoop.subproj/CFMachPort.c rename to CFMachPort.c index 50d1c35..dfde9dd 100644 --- a/RunLoop.subproj/CFMachPort.c +++ b/CFMachPort.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -107,27 +107,6 @@ don't have to worry about that. These may be some things to think about in the future, but is usually overkill. - Finally, one tricky bit mostly specific to CFMachPort - deserves mention: use of __CFMachPortCurrentPID. Mach - ports are not inherited by a child process created with - fork(), unlike most other things. Thus, on fork(), in - the child, all cached CFMachPorts should be invalidated. - However, because the ports were never in the new task's - port space, the Mach part of the kernel doesn't send - dead-name notifications (which is used to autoinvalidate - CFMachPorts) to the new task, which is reasonable. There - is also no other notification that a fork() has occurred, - though, so how is CFMachPort to deal with this? An - atfork() function, similar to atexit(), would be nice, - but is not available. So CFMachPort does the best it - can, which is to compare the current process's PID with - the last PID recorded and if different, invalidate all - CFMachPorts, whenever various CFMachPort functions are - called. To avoid going insane, I've assumed that clients - aren't going to fork() as a result of callouts from this - code, which in a couple places might actually cause trouble. - It also isn't completely thread-safe. - In general, with higher level functionalities in the system, it isn't even possible for a process to fork() and the child not exec(), but continue running, since the higher levels @@ -138,8 +117,6 @@ */ -#if defined(__MACH__) - #include #include #include @@ -147,13 +124,14 @@ #include #include #include +#include #include "CFInternal.h" +#include -static CFSpinLock_t __CFAllMachPortsLock = 0; +static CFSpinLock_t __CFAllMachPortsLock = CFSpinLockInit; static CFMutableDictionaryRef __CFAllMachPorts = NULL; static mach_port_t __CFNotifyRawMachPort = MACH_PORT_NULL; static CFMachPortRef __CFNotifyMachPort = NULL; -static int __CFMachPortCurrentPID = 0; struct __CFMachPort { CFRuntimeBase _base; @@ -172,39 +150,39 @@ struct __CFMachPort { /* Bit 3 in the base reserved bits is used for is-deallocing state */ CF_INLINE Boolean __CFMachPortIsValid(CFMachPortRef mp) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)mp)->_info, 0, 0); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)mp)->_cfinfo[CF_INFO_BITS], 0, 0); } CF_INLINE void __CFMachPortSetValid(CFMachPortRef mp) { - __CFBitfieldSetValue(((CFRuntimeBase *)mp)->_info, 0, 0, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)mp)->_cfinfo[CF_INFO_BITS], 0, 0, 1); } CF_INLINE void __CFMachPortUnsetValid(CFMachPortRef mp) { - __CFBitfieldSetValue(((CFRuntimeBase *)mp)->_info, 0, 0, 0); + __CFBitfieldSetValue(((CFRuntimeBase *)mp)->_cfinfo[CF_INFO_BITS], 0, 0, 0); } CF_INLINE Boolean __CFMachPortHasReceive(CFMachPortRef mp) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)mp)->_info, 1, 1); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)mp)->_cfinfo[CF_INFO_BITS], 1, 1); } CF_INLINE void __CFMachPortSetHasReceive(CFMachPortRef mp) { - __CFBitfieldSetValue(((CFRuntimeBase *)mp)->_info, 1, 1, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)mp)->_cfinfo[CF_INFO_BITS], 1, 1, 1); } CF_INLINE Boolean __CFMachPortHasSend(CFMachPortRef mp) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)mp)->_info, 2, 2); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)mp)->_cfinfo[CF_INFO_BITS], 2, 2); } CF_INLINE void __CFMachPortSetHasSend(CFMachPortRef mp) { - __CFBitfieldSetValue(((CFRuntimeBase *)mp)->_info, 2, 2, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)mp)->_cfinfo[CF_INFO_BITS], 2, 2, 1); } CF_INLINE Boolean __CFMachPortIsDeallocing(CFMachPortRef mp) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)mp)->_info, 3, 3); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)mp)->_cfinfo[CF_INFO_BITS], 3, 3); } CF_INLINE void __CFMachPortSetIsDeallocing(CFMachPortRef mp) { - __CFBitfieldSetValue(((CFRuntimeBase *)mp)->_info, 3, 3, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)mp)->_cfinfo[CF_INFO_BITS], 3, 3, 1); } CF_INLINE void __CFMachPortLock(CFMachPortRef mp) { @@ -215,109 +193,69 @@ CF_INLINE void __CFMachPortUnlock(CFMachPortRef mp) { __CFSpinUnlock(&(mp->_lock)); } -// The only CFMachPort this releases is the notify port, which -// no one else should have gotten their grubby hands on. Set the -// new PID first, to avoid reentrant invocations of this function. -static void __CFMachPortDidFork(void) { - CFMachPortRef oldNotify; - __CFMachPortCurrentPID = getpid(); - __CFSpinLock(&__CFAllMachPortsLock); - oldNotify = __CFNotifyMachPort; - __CFNotifyMachPort = NULL; - __CFNotifyRawMachPort = MACH_PORT_NULL; - if (NULL != __CFAllMachPorts) { - CFIndex idx, cnt; - CFMachPortRef *mps, buffer[128]; - cnt = CFDictionaryGetCount(__CFAllMachPorts); - mps = (cnt <= 128) ? buffer : CFAllocatorAllocate(kCFAllocatorDefault, cnt * sizeof(CFMachPortRef), 0); - CFDictionaryGetKeysAndValues(__CFAllMachPorts, NULL, (const void **)mps); - CFRelease(__CFAllMachPorts); - __CFAllMachPorts = NULL; - __CFSpinUnlock(&__CFAllMachPortsLock); - for (idx = 0; idx < cnt; idx++) { - // invalidation must be outside the lock - CFMachPortInvalidate(mps[idx]); - } - if (mps != buffer) CFAllocatorDeallocate(kCFAllocatorDefault, mps); - } else { - __CFSpinUnlock(&__CFAllMachPortsLock); - } - if (NULL != oldNotify) { - // The global is NULL'd before this, just in case. - // __CFNotifyMachPort was in the cache and was - // invalidated above, but that's harmless. - CFRelease(oldNotify); - } -} - -CF_INLINE void __CFMachPortCheckForFork(void) { - if (getpid() != __CFMachPortCurrentPID) { - __CFMachPortDidFork(); - } -} - void _CFMachPortInstallNotifyPort(CFRunLoopRef rl, CFStringRef mode) { CFRunLoopSourceRef source; if (NULL == __CFNotifyMachPort) return; - source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, __CFNotifyMachPort, -1000); + source = CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault, __CFNotifyMachPort, -1000); CFRunLoopAddSource(rl, source, mode); CFRelease(source); } static void __CFNotifyDeadMachPort(CFMachPortRef port, void *msg, CFIndex size, void *info) { mach_msg_header_t *header = (mach_msg_header_t *)msg; + mach_port_t dead_port = MACH_PORT_NULL; if (header && header->msgh_id == MACH_NOTIFY_DEAD_NAME) { - mach_port_t dead_port = ((mach_dead_name_notification_t *)msg)->not_port; - if (((mach_dead_name_notification_t *)msg)->NDR.int_rep != NDR_record.int_rep) { - dead_port = CFSwapInt32(dead_port); - } - CFMachPortRef existing; - /* If the CFMachPort has already been invalidated, it won't be found here. */ - __CFSpinLock(&__CFAllMachPortsLock); - if (NULL != __CFAllMachPorts && CFDictionaryGetValueIfPresent(__CFAllMachPorts, (void *)dead_port, (const void **)&existing)) { - CFDictionaryRemoveValue(__CFAllMachPorts, (void *)dead_port); - CFRetain(existing); - __CFSpinUnlock(&__CFAllMachPortsLock); - CFMachPortInvalidate(existing); - CFRelease(existing); - } else { - __CFSpinUnlock(&__CFAllMachPortsLock); - } - /* Delete port reference we got for this notification */ - mach_port_deallocate(mach_task_self(), dead_port); + dead_port = ((mach_dead_name_notification_t *)msg)->not_port; + if (((mach_dead_name_notification_t *)msg)->NDR.int_rep != NDR_record.int_rep) { + dead_port = CFSwapInt32(dead_port); + } } else if (header && header->msgh_id == MACH_NOTIFY_PORT_DELETED) { - mach_port_t dead_port = ((mach_port_deleted_notification_t *)msg)->not_port; - if (((mach_dead_name_notification_t *)msg)->NDR.int_rep != NDR_record.int_rep) { - dead_port = CFSwapInt32(dead_port); - } - CFMachPortRef existing; - /* If the CFMachPort has already been invalidated, it won't be found here. */ - __CFSpinLock(&__CFAllMachPortsLock); - if (NULL != __CFAllMachPorts && CFDictionaryGetValueIfPresent(__CFAllMachPorts, (void *)dead_port, (const void **)&existing)) { - CFDictionaryRemoveValue(__CFAllMachPorts, (void *)dead_port); - CFRetain(existing); - __CFSpinUnlock(&__CFAllMachPortsLock); - CFMachPortInvalidate(existing); - CFRelease(existing); - } else { - __CFSpinUnlock(&__CFAllMachPortsLock); - } - /* Delete port reference we got for this notification */ - // Don't do this, since this always fails, and could cause trouble - // mach_port_deallocate(mach_task_self(), dead_port); + dead_port = ((mach_port_deleted_notification_t *)msg)->not_port; + if (((mach_port_deleted_notification_t *)msg)->NDR.int_rep != NDR_record.int_rep) { + dead_port = CFSwapInt32(dead_port); + } + } else { + return; + } + + CFMachPortRef existing; + /* If the CFMachPort has already been invalidated, it won't be found here. */ + __CFSpinLock(&__CFAllMachPortsLock); + if (NULL != __CFAllMachPorts && CFDictionaryGetValueIfPresent(__CFAllMachPorts, (void *)(uintptr_t)dead_port, (const void **)&existing)) { + CFDictionaryRemoveValue(__CFAllMachPorts, (void *)(uintptr_t)dead_port); + CFRetain(existing); + __CFSpinUnlock(&__CFAllMachPortsLock); + __CFMachPortLock(existing); + mach_port_t old_port = existing->_oldnotify; + existing->_oldnotify = MACH_PORT_NULL; + __CFMachPortUnlock(existing); + if (MACH_PORT_NULL != old_port) { + header->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0) | MACH_MSGH_BITS_COMPLEX; + header->msgh_local_port = MACH_PORT_NULL; + header->msgh_remote_port = old_port; + mach_msg(header, MACH_SEND_MSG, header->msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + } + CFMachPortInvalidate(existing); + CFRelease(existing); + } else { + __CFSpinUnlock(&__CFAllMachPortsLock); + } + + if (header && header->msgh_id == MACH_NOTIFY_DEAD_NAME) { + /* Delete port reference we got for this notification */ + mach_port_deallocate(mach_task_self(), dead_port); } } static Boolean __CFMachPortEqual(CFTypeRef cf1, CFTypeRef cf2) { CFMachPortRef mp1 = (CFMachPortRef)cf1; CFMachPortRef mp2 = (CFMachPortRef)cf2; -// __CFMachPortCheckForFork(); do not do this here return (mp1->_port == mp2->_port); } static CFHashCode __CFMachPortHash(CFTypeRef cf) { + CHECK_FOR_FORK(); CFMachPortRef mp = (CFMachPortRef)cf; -// __CFMachPortCheckForFork(); do not do this here -- can cause strange reentrancies 3843642 return (CFHashCode)mp->_port; } @@ -333,7 +271,10 @@ static CFStringRef __CFMachPortCopyDescription(CFTypeRef cf) { if (NULL == contextDesc) { contextDesc = CFStringCreateWithFormat(CFGetAllocator(mp), NULL, CFSTR(""), mp->_context.info); } - result = CFStringCreateWithFormat(CFGetAllocator(mp), NULL, CFSTR("{locked = %s, valid = %s, port = %p, source = %p, callout = %p, context = %@}"), cf, CFGetAllocator(mp), locked, (__CFMachPortIsValid(mp) ? "Yes" : "No"), mp->_port, mp->_source, mp->_callout, (NULL != contextDesc ? contextDesc : CFSTR(""))); + void *addr = mp->_callout; + Dl_info info; + const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; + result = CFStringCreateWithFormat(CFGetAllocator(mp), NULL, CFSTR("{locked = %s, valid = %s, port = %p, source = %p, callout = %s (%p), context = %@}"), cf, CFGetAllocator(mp), locked, (__CFMachPortIsValid(mp) ? "Yes" : "No"), mp->_port, mp->_source, name, addr, (NULL != contextDesc ? contextDesc : CFSTR(""))); if (NULL != contextDesc) { CFRelease(contextDesc); } @@ -341,6 +282,7 @@ static CFStringRef __CFMachPortCopyDescription(CFTypeRef cf) { } static void __CFMachPortDeallocate(CFTypeRef cf) { + CHECK_FOR_FORK(); CFMachPortRef mp = (CFMachPortRef)cf; __CFMachPortSetIsDeallocing(mp); CFMachPortInvalidate(mp); @@ -353,7 +295,6 @@ static void __CFMachPortDeallocate(CFTypeRef cf) { if (__CFMachPortHasReceive(mp)) { mach_port_mod_refs(mach_task_self(), mp->_port, MACH_PORT_RIGHT_RECEIVE, -1); } - __CFMachPortCheckForFork(); } static CFTypeID __kCFMachPortTypeID = _kCFRuntimeNotATypeID; @@ -372,11 +313,9 @@ static const CFRuntimeClass __CFMachPortClass = { __private_extern__ void __CFMachPortInitialize(void) { __kCFMachPortTypeID = _CFRuntimeRegisterClass(&__CFMachPortClass); - __CFMachPortCurrentPID = getpid(); } CFTypeID CFMachPortGetTypeID(void) { - __CFMachPortCheckForFork(); return __kCFMachPortTypeID; } @@ -384,7 +323,6 @@ CFMachPortRef CFMachPortCreate(CFAllocatorRef allocator, CFMachPortCallBack call CFMachPortRef result; mach_port_t port; kern_return_t ret; - __CFMachPortCheckForFork(); if (shouldFreeInfo) *shouldFreeInfo = true; ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); if (KERN_SUCCESS != ret) { @@ -408,16 +346,17 @@ CFMachPortRef CFMachPortCreate(CFAllocatorRef allocator, CFMachPortCallBack call * references on the port if the kernel ever allows that in the future, * but will not cleanup any references you got when you got the port. */ CFMachPortRef CFMachPortCreateWithPort(CFAllocatorRef allocator, mach_port_t port, CFMachPortCallBack callout, CFMachPortContext *context, Boolean *shouldFreeInfo) { + CHECK_FOR_FORK(); CFMachPortRef memory; SInt32 size; Boolean didCreateNotifyPort = false; CFRunLoopSourceRef source; - __CFMachPortCheckForFork(); if (shouldFreeInfo) *shouldFreeInfo = true; __CFSpinLock(&__CFAllMachPortsLock); - if (NULL != __CFAllMachPorts && CFDictionaryGetValueIfPresent(__CFAllMachPorts, (void *)port, (const void **)&memory)) { + if (NULL != __CFAllMachPorts && CFDictionaryGetValueIfPresent(__CFAllMachPorts, (void *)(uintptr_t)port, (const void **)&memory)) { + CFRetain(memory); __CFSpinUnlock(&__CFAllMachPortsLock); - return (CFMachPortRef)CFRetain(memory); + return (CFMachPortRef)(memory); } size = sizeof(struct __CFMachPort) - sizeof(CFRuntimeBase); memory = (CFMachPortRef)_CFRuntimeCreateInstance(allocator, __kCFMachPortTypeID, size, NULL); @@ -426,7 +365,7 @@ CFMachPortRef CFMachPortCreateWithPort(CFAllocatorRef allocator, mach_port_t por return NULL; } __CFMachPortUnsetValid(memory); - memory->_lock = 0; + memory->_lock = CFSpinLockInit; memory->_port = port; memory->_source = NULL; memory->_icallout = NULL; @@ -464,14 +403,14 @@ CFMachPortRef CFMachPortCreateWithPort(CFAllocatorRef allocator, mach_port_t por memory->_context.info = context->retain ? (void *)context->retain(context->info) : context->info; } if (NULL == __CFAllMachPorts) { - __CFAllMachPorts = CFDictionaryCreateMutable(kCFAllocatorMallocZone, 0, NULL, NULL); // XXX_PCB make it GC weak. + __CFAllMachPorts = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); _CFDictionarySetCapacity(__CFAllMachPorts, 20); } - CFDictionaryAddValue(__CFAllMachPorts, (void *)port, memory); + CFDictionaryAddValue(__CFAllMachPorts, (void *)(uintptr_t)port, memory); __CFSpinUnlock(&__CFAllMachPortsLock); if (didCreateNotifyPort) { // __CFNotifyMachPort ends up in cache - CFMachPortRef mp = CFMachPortCreateWithPort(kCFAllocatorDefault, __CFNotifyRawMachPort, __CFNotifyDeadMachPort, NULL, NULL); + CFMachPortRef mp = CFMachPortCreateWithPort(kCFAllocatorSystemDefault, __CFNotifyRawMachPort, __CFNotifyDeadMachPort, NULL, NULL); __CFMachPortSetHasReceive(mp); __CFNotifyMachPort = mp; } @@ -482,7 +421,7 @@ CFMachPortRef CFMachPortCreateWithPort(CFAllocatorRef allocator, mach_port_t por // the call which creates the __CFNotifyMachPort itself, but that's // OK since it will happen in the invocation of this function // from which that call was triggered. - source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, __CFNotifyMachPort, -1000); + source = CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault, __CFNotifyMachPort, -1000); CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes); CFRelease(source); } @@ -491,29 +430,28 @@ CFMachPortRef CFMachPortCreateWithPort(CFAllocatorRef allocator, mach_port_t por } mach_port_t CFMachPortGetPort(CFMachPortRef mp) { + CHECK_FOR_FORK(); CF_OBJC_FUNCDISPATCH0(__kCFMachPortTypeID, mach_port_t, mp, "machPort"); __CFGenericValidateType(mp, __kCFMachPortTypeID); - __CFMachPortCheckForFork(); return mp->_port; } void CFMachPortGetContext(CFMachPortRef mp, CFMachPortContext *context) { __CFGenericValidateType(mp, __kCFMachPortTypeID); CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__); - __CFMachPortCheckForFork(); CF_WRITE_BARRIER_MEMMOVE(context, &mp->_context, sizeof(CFMachPortContext)); } void CFMachPortInvalidate(CFMachPortRef mp) { + CHECK_FOR_FORK(); CF_OBJC_FUNCDISPATCH0(__kCFMachPortTypeID, void, mp, "invalidate"); __CFGenericValidateType(mp, __kCFMachPortTypeID); - __CFMachPortCheckForFork(); if (!__CFMachPortIsDeallocing(mp)) { CFRetain(mp); } __CFSpinLock(&__CFAllMachPortsLock); if (NULL != __CFAllMachPorts) { - CFDictionaryRemoveValue(__CFAllMachPorts, (void *)(mp->_port)); + CFDictionaryRemoveValue(__CFAllMachPorts, (void *)(uintptr_t)(mp->_port)); } __CFSpinUnlock(&__CFAllMachPortsLock); __CFMachPortLock(mp); @@ -541,14 +479,6 @@ void CFMachPortInvalidate(CFMachPortRef mp) { CFRunLoopSourceInvalidate(source); CFRelease(source); } - // here we get rid of the previous notify port - // [cjk - somehow it is the right thing to do to - // hold this until this point, then deallocate it, - // though I don't understand what that triggers - // with respect to the send-once right, and I - // doubt people are doing the right thing about - // handling the "death" (CFMachPort included) of - // the send-once right.] if (MACH_PORT_NULL != old_port) { mach_port_deallocate(mach_task_self(), old_port); } @@ -563,19 +493,16 @@ void CFMachPortInvalidate(CFMachPortRef mp) { Boolean CFMachPortIsValid(CFMachPortRef mp) { CF_OBJC_FUNCDISPATCH0(__kCFMachPortTypeID, Boolean, mp, "isValid"); __CFGenericValidateType(mp, __kCFMachPortTypeID); - __CFMachPortCheckForFork(); return __CFMachPortIsValid(mp); } CFMachPortInvalidationCallBack CFMachPortGetInvalidationCallBack(CFMachPortRef mp) { __CFGenericValidateType(mp, __kCFMachPortTypeID); - __CFMachPortCheckForFork(); return mp->_icallout; } void CFMachPortSetInvalidationCallBack(CFMachPortRef mp, CFMachPortInvalidationCallBack callout) { __CFGenericValidateType(mp, __kCFMachPortTypeID); - __CFMachPortCheckForFork(); if (!__CFMachPortIsValid(mp) && NULL != callout) { callout(mp, mp->_context.info); } else { @@ -585,6 +512,7 @@ void CFMachPortSetInvalidationCallBack(CFMachPortRef mp, CFMachPortInvalidationC /* Returns the number of messages queued for a receive port. */ CFIndex CFMachPortGetQueuedMessageCount(CFMachPortRef mp) { + CHECK_FOR_FORK(); mach_port_status_t status; mach_msg_type_number_t num = MACH_PORT_RECEIVE_STATUS_COUNT; kern_return_t ret; @@ -592,23 +520,16 @@ CFIndex CFMachPortGetQueuedMessageCount(CFMachPortRef mp) { return (KERN_SUCCESS != ret) ? 0 : status.mps_msgcount; } -void CFMachPortInvalidateAll(void) { -// This function has been removed from the public API; -// it was a very bad idea to call it. -} - - static mach_port_t __CFMachPortGetPort(void *info) { CFMachPortRef mp = info; - __CFMachPortCheckForFork(); return mp->_port; } static void *__CFMachPortPerform(void *msg, CFIndex size, CFAllocatorRef allocator, void *info) { + CHECK_FOR_FORK(); CFMachPortRef mp = info; void *context_info; void (*context_release)(const void *); - __CFMachPortCheckForFork(); __CFMachPortLock(mp); if (!__CFMachPortIsValid(mp)) { __CFMachPortUnlock(mp); @@ -623,6 +544,7 @@ static void *__CFMachPortPerform(void *msg, CFIndex size, CFAllocatorRef allocat } __CFMachPortUnlock(mp); mp->_callout(mp, msg, size, mp->_context.info); + CHECK_FOR_FORK(); if (context_release) { context_release(context_info); } @@ -630,28 +552,14 @@ static void *__CFMachPortPerform(void *msg, CFIndex size, CFAllocatorRef allocat } CFRunLoopSourceRef CFMachPortCreateRunLoopSource(CFAllocatorRef allocator, CFMachPortRef mp, CFIndex order) { + CHECK_FOR_FORK(); CFRunLoopSourceRef result = NULL; __CFGenericValidateType(mp, __kCFMachPortTypeID); - __CFMachPortCheckForFork(); __CFMachPortLock(mp); if (!__CFMachPortIsValid(mp)) { __CFMachPortUnlock(mp); return NULL; } -#if 0 -#warning CF: adding ref to receive right is disabled for now -- doesnt work in 1F - if (!__CFMachPortHasReceive(mp)) { - kern_return_t ret; - -// this fails in 1F with KERN_INVALID_VALUE -- only 0 and -1 are valid for delta - ret = mach_port_mod_refs(mach_task_self(), mp->_port, MACH_PORT_RIGHT_RECEIVE, +1); - if (KERN_SUCCESS != ret) { - __CFMachPortUnlock(mp); - return NULL; - } - __CFMachPortSetHasReceive(mp); - } -#endif if (NULL == mp->_source) { CFRunLoopSourceContext1 context; context.version = 1; @@ -672,5 +580,4 @@ CFRunLoopSourceRef CFMachPortCreateRunLoopSource(CFAllocatorRef allocator, CFMac return result; } -#endif /* __MACH__ */ diff --git a/RunLoop.subproj/CFMachPort.h b/CFMachPort.h similarity index 91% rename from RunLoop.subproj/CFMachPort.h rename to CFMachPort.h index 35c1c27..067a609 100644 --- a/RunLoop.subproj/CFMachPort.h +++ b/CFMachPort.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,20 +21,16 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFMachPort.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFMACHPORT__) #define __COREFOUNDATION_CFMACHPORT__ 1 -#if defined(__MACH__) - #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN typedef struct __CFMachPort * CFMachPortRef; @@ -63,11 +59,7 @@ CF_EXPORT void CFMachPortSetInvalidationCallBack(CFMachPortRef port, CFMachPort CF_EXPORT CFRunLoopSourceRef CFMachPortCreateRunLoopSource(CFAllocatorRef allocator, CFMachPortRef port, CFIndex order); -#if defined(__cplusplus) -} -#endif - -#endif /* __MACH__ */ +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFMACHPORT__ */ diff --git a/RunLoop.subproj/CFMessagePort.c b/CFMessagePort.c similarity index 68% rename from RunLoop.subproj/CFMessagePort.c rename to CFMessagePort.c index 932f3a8..0e9b79b 100644 --- a/RunLoop.subproj/CFMessagePort.c +++ b/CFMessagePort.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -25,8 +25,6 @@ Responsibility: Christopher Kane */ -#if !defined(__WIN32__) - #include #include #include @@ -37,9 +35,10 @@ #include #include #include -#include +#include #include #include +#include #define __kCFMessagePortMaxNameLengthMax 255 @@ -55,7 +54,7 @@ #define __kCFMessagePortMaxNameLength __kCFMessagePortMaxNameLengthMax #endif -static CFSpinLock_t __CFAllMessagePortsLock = 0; +static CFSpinLock_t __CFAllMessagePortsLock = CFSpinLockInit; static CFMutableDictionaryRef __CFAllLocalMessagePorts = NULL; static CFMutableDictionaryRef __CFAllRemoteMessagePorts = NULL; @@ -66,6 +65,7 @@ struct __CFMessagePort { CFMachPortRef _port; /* immutable; invalidated */ CFMutableDictionaryRef _replies; int32_t _convCounter; + int32_t _perPID; /* zero if not per-pid, else pid */ CFMachPortRef _replyPort; /* only used by remote port; immutable once created; invalidated */ CFRunLoopSourceRef _source; /* only used by local port; immutable once created; invalidated */ CFMessagePortInvalidationCallBack _icallout; @@ -74,39 +74,52 @@ struct __CFMessagePort { }; /* Bit 0 in the base reserved bits is used for invalid state */ +/* Bit 1 of the base reserved bits is used for has-extra-port-refs state */ /* Bit 2 of the base reserved bits is used for is-remote state */ /* Bit 3 in the base reserved bits is used for is-deallocing state */ CF_INLINE Boolean __CFMessagePortIsValid(CFMessagePortRef ms) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)ms)->_info, 0, 0); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 0, 0); } CF_INLINE void __CFMessagePortSetValid(CFMessagePortRef ms) { - __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_info, 0, 0, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 0, 0, 1); } CF_INLINE void __CFMessagePortUnsetValid(CFMessagePortRef ms) { - __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_info, 0, 0, 0); + __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 0, 0, 0); +} + +CF_INLINE Boolean __CFMessagePortExtraMachRef(CFMessagePortRef ms) { + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 1, 1); +} + +CF_INLINE void __CFMessagePortSetExtraMachRef(CFMessagePortRef ms) { + __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 1, 1, 1); +} + +CF_INLINE void __CFMessagePortUnsetExtraMachRef(CFMessagePortRef ms) { + __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 1, 1, 0); } CF_INLINE Boolean __CFMessagePortIsRemote(CFMessagePortRef ms) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)ms)->_info, 2, 2); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 2, 2); } CF_INLINE void __CFMessagePortSetRemote(CFMessagePortRef ms) { - __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_info, 2, 2, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 2, 2, 1); } CF_INLINE void __CFMessagePortUnsetRemote(CFMessagePortRef ms) { - __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_info, 2, 2, 0); + __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 2, 2, 0); } CF_INLINE Boolean __CFMessagePortIsDeallocing(CFMessagePortRef ms) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)ms)->_info, 3, 3); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 3, 3); } CF_INLINE void __CFMessagePortSetIsDeallocing(CFMessagePortRef ms) { - __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_info, 3, 3, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)ms)->_cfinfo[CF_INFO_BITS], 3, 3, 1); } CF_INLINE void __CFMessagePortLock(CFMessagePortRef ms) { @@ -177,26 +190,6 @@ static struct __CFMessagePortMachMessage *__CFMessagePortCreateMessage(CFAllocat return msg; } -static Boolean __CFMessagePortNativeSetNameLocal(CFMachPortRef port, uint8_t *portname) { - mach_port_t bp; - kern_return_t ret; - task_get_bootstrap_port(mach_task_self(), &bp); - ret = bootstrap_register(bp, portname, CFMachPortGetPort(port)); -if (ret != KERN_SUCCESS) CFLog(0, CFSTR("CFMessagePort: bootstrap_register(): failed %d (0x%x), port = 0x%x, name = '%s'\nSee /usr/include/servers/bootstrap_defs.h for the error codes."), ret, ret, CFMachPortGetPort(port), portname); - return (ret == KERN_SUCCESS) ? true : false; -} - -static Boolean __CFMessagePortEqual(CFTypeRef cf1, CFTypeRef cf2) { - CFMessagePortRef ms1 = (CFMessagePortRef)cf1; - CFMessagePortRef ms2 = (CFMessagePortRef)cf2; - return CFEqual(ms1->_port, ms2->_port); -} - -static CFHashCode __CFMessagePortHash(CFTypeRef cf) { - CFMessagePortRef ms = (CFMessagePortRef)cf; - return CFHash(ms->_port); -} - static CFStringRef __CFMessagePortCopyDescription(CFTypeRef cf) { CFMessagePortRef ms = (CFMessagePortRef)cf; CFStringRef result; @@ -208,11 +201,14 @@ static CFStringRef __CFMessagePortCopyDescription(CFTypeRef cf) { contextDesc = ms->_context.copyDescription(ms->_context.info); } if (NULL == contextDesc) { - contextDesc = CFStringCreateWithFormat(CFGetAllocator(ms), NULL, CFSTR(""), ms->_context.info); + contextDesc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR(""), ms->_context.info); } - result = CFStringCreateWithFormat(CFGetAllocator(ms), NULL, CFSTR("{locked = %s, valid = %s, remote = %s, name = %@}"), cf, CFGetAllocator(ms), locked, (__CFMessagePortIsValid(ms) ? "Yes" : "No"), (__CFMessagePortIsRemote(ms) ? "Yes" : "No"), ms->_name); + result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{locked = %s, valid = %s, remote = %s, name = %@}"), cf, CFGetAllocator(ms), locked, (__CFMessagePortIsValid(ms) ? "Yes" : "No"), (__CFMessagePortIsRemote(ms) ? "Yes" : "No"), ms->_name); } else { - result = CFStringCreateWithFormat(CFGetAllocator(ms), NULL, CFSTR("{locked = %s, valid = %s, remote = %s, name = %@, source = %p, callout = %p, context = %@}"), cf, CFGetAllocator(ms), locked, (__CFMessagePortIsValid(ms) ? "Yes" : "No"), (__CFMessagePortIsRemote(ms) ? "Yes" : "No"), ms->_name, ms->_source, ms->_callout, (NULL != contextDesc ? contextDesc : CFSTR(""))); + void *addr = ms->_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, 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(""))); } if (NULL != contextDesc) { CFRelease(contextDesc); @@ -233,9 +229,40 @@ static void __CFMessagePortDeallocate(CFTypeRef cf) { CFRelease(ms->_name); } if (NULL != ms->_port) { + if (__CFMessagePortExtraMachRef(ms)) { + mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(ms->_port), MACH_PORT_RIGHT_SEND, -1); + mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(ms->_port), MACH_PORT_RIGHT_RECEIVE, -1); + } CFMachPortInvalidate(ms->_port); CFRelease(ms->_port); } + + // A remote message port for a local message port in the same process will get the + // same mach port, and the remote port will keep the mach port from being torn down, + // thus keeping the remote port from getting any sort of death notification and + // auto-invalidating; so we manually implement the 'auto-invalidation' here by + // tickling each remote port to check its state after any message port is destroyed, + // but most importantly after local message ports are destroyed. + __CFSpinLock(&__CFAllMessagePortsLock); + CFMessagePortRef *remotePorts = NULL; + CFIndex cnt = 0; + if (NULL != __CFAllRemoteMessagePorts) { + cnt = CFDictionaryGetCount(__CFAllRemoteMessagePorts); + remotePorts = CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(CFMessagePortRef), __kCFAllocatorGCScannedMemory); + CFDictionaryGetKeysAndValues(__CFAllRemoteMessagePorts, NULL, (const void **)remotePorts); + for (CFIndex idx = 0; idx < cnt; idx++) { + CFRetain(remotePorts[idx]); + } + } + __CFSpinUnlock(&__CFAllMessagePortsLock); + if (remotePorts) { + for (CFIndex idx = 0; idx < cnt; idx++) { + // as a side-effect, this will auto-invalidate the CFMessagePort if the CFMachPort is invalid + CFMessagePortIsValid(remotePorts[idx]); + CFRelease(remotePorts[idx]); + } + CFAllocatorDeallocate(kCFAllocatorSystemDefault, remotePorts); + } } static CFTypeID __kCFMessagePortTypeID = _kCFRuntimeNotATypeID; @@ -246,8 +273,8 @@ static const CFRuntimeClass __CFMessagePortClass = { NULL, // init NULL, // copy __CFMessagePortDeallocate, - __CFMessagePortEqual, - __CFMessagePortHash, + NULL, + NULL, NULL, // __CFMessagePortCopyDescription }; @@ -292,45 +319,44 @@ static void __CFMessagePortInvalidationCallBack(CFMachPortRef port, void *info) CFMessagePortInvalidate(info); } -CFMessagePortRef CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) { +static CFMessagePortRef __CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo, Boolean perPID) { CFMessagePortRef memory; - CFMachPortRef native; - CFMachPortContext ctx; uint8_t *utfname = NULL; - CFIndex size; if (shouldFreeInfo) *shouldFreeInfo = true; if (NULL != name) { name = __CFMessagePortSanitizeStringName(allocator, name, &utfname, NULL); } __CFSpinLock(&__CFAllMessagePortsLock); - if (NULL != name) { + if (!perPID && NULL != name) { CFMessagePortRef existing; if (NULL != __CFAllLocalMessagePorts && CFDictionaryGetValueIfPresent(__CFAllLocalMessagePorts, name, (const void **)&existing)) { + CFRetain(existing); __CFSpinUnlock(&__CFAllMessagePortsLock); CFRelease(name); CFAllocatorDeallocate(allocator, utfname); - return (CFMessagePortRef)CFRetain(existing); + return (CFMessagePortRef)(existing); } } - size = sizeof(struct __CFMessagePort) - sizeof(CFRuntimeBase); + __CFSpinUnlock(&__CFAllMessagePortsLock); + CFIndex size = sizeof(struct __CFMessagePort) - sizeof(CFRuntimeBase); memory = (CFMessagePortRef)_CFRuntimeCreateInstance(allocator, __kCFMessagePortTypeID, size, NULL); if (NULL == memory) { - __CFSpinUnlock(&__CFAllMessagePortsLock); if (NULL != name) { CFRelease(name); } CFAllocatorDeallocate(allocator, utfname); -CFLog(99, CFSTR("CFMessagePortCreateLocal(): failed to allocate object")); return NULL; } __CFMessagePortUnsetValid(memory); + __CFMessagePortUnsetExtraMachRef(memory); __CFMessagePortUnsetRemote(memory); - memory->_lock = 0; + memory->_lock = CFSpinLockInit; memory->_name = name; memory->_port = NULL; memory->_replies = NULL; memory->_convCounter = 0; + memory->_perPID = perPID ? getpid() : 0; // actual value not terribly useful for local ports memory->_replyPort = NULL; memory->_source = NULL; memory->_icallout = NULL; @@ -339,34 +365,64 @@ CFLog(99, CFSTR("CFMessagePortCreateLocal(): failed to allocate object")); memory->_context.retain = NULL; memory->_context.release = NULL; memory->_context.copyDescription = NULL; - ctx.version = 0; - ctx.info = memory; - ctx.retain = NULL; - ctx.release = NULL; - ctx.copyDescription = NULL; - native = CFMachPortCreate(allocator, __CFMessagePortDummyCallback, &ctx, NULL); -if (!native) CFLog(99, CFSTR("CFMessagePortCreateLocal(): failed to allocate CFMachPortRef")); - if (NULL != native && NULL != name && !__CFMessagePortNativeSetNameLocal(native, utfname)) { -CFLog(99, CFSTR("CFMessagePortCreateLocal(): failed to name Mach port (%@)"), name); - CFMachPortInvalidate(native); - CFRelease(native); - native = NULL; + + if (NULL != name) { + CFMachPortRef native = NULL; + kern_return_t ret; + mach_port_t bs, mp; + task_get_bootstrap_port(mach_task_self(), &bs); + if (!perPID) { + ret = bootstrap_check_in(bs, (char *)utfname, &mp); /* If we're started by launchd or the old mach_init */ + if (ret == KERN_SUCCESS) { + ret = mach_port_insert_right(mach_task_self(), mp, mp, MACH_MSG_TYPE_MAKE_SEND); + if (KERN_SUCCESS == ret) { + CFMachPortContext ctx = {0, memory, NULL, NULL, NULL}; + native = CFMachPortCreateWithPort(allocator, mp, __CFMessagePortDummyCallback, &ctx, NULL); + __CFMessagePortSetExtraMachRef(memory); + } else { + CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePort: mach_port_insert_member() after bootstrap_check_in(): failed %d (0x%x) '%s', port = 0x%x, name = '%s'"), ret, ret, bootstrap_strerror(ret), mp, utfname); + mach_port_destroy(mach_task_self(), mp); + CFAllocatorDeallocate(allocator, utfname); + // name is released by deallocation + CFRelease(memory); + return NULL; + } + } + } + if (!native) { + CFMachPortContext ctx = {0, memory, NULL, NULL, NULL}; + native = CFMachPortCreate(allocator, __CFMessagePortDummyCallback, &ctx, NULL); + mp = CFMachPortGetPort(native); + ret = bootstrap_register2(bs, (char *)utfname, mp, perPID ? BOOTSTRAP_PER_PID_SERVICE : 0); + if (ret != KERN_SUCCESS) { + CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePort: bootstrap_register(): failed %d (0x%x) '%s', port = 0x%x, name = '%s'\nSee /usr/include/servers/bootstrap_defs.h for the error codes."), ret, ret, bootstrap_strerror(ret), mp, utfname); + CFMachPortInvalidate(native); + CFRelease(native); + CFAllocatorDeallocate(allocator, utfname); + // name is released by deallocation + CFRelease(memory); + return NULL; + } + } + CFMachPortSetInvalidationCallBack(native, __CFMessagePortInvalidationCallBack); + memory->_port = native; } + CFAllocatorDeallocate(allocator, utfname); - if (NULL == native) { - __CFSpinUnlock(&__CFAllMessagePortsLock); - // name is released by deallocation - CFRelease(memory); - return NULL; - } - memory->_port = native; - CFMachPortSetInvalidationCallBack(native, __CFMessagePortInvalidationCallBack); __CFMessagePortSetValid(memory); if (NULL != context) { memmove(&memory->_context, context, sizeof(CFMessagePortContext)); memory->_context.info = context->retain ? (void *)context->retain(context->info) : context->info; } - if (NULL != name) { + __CFSpinLock(&__CFAllMessagePortsLock); + if (!perPID && NULL != name) { + CFMessagePortRef existing; + if (NULL != __CFAllLocalMessagePorts && CFDictionaryGetValueIfPresent(__CFAllLocalMessagePorts, name, (const void **)&existing)) { + CFRetain(existing); + __CFSpinUnlock(&__CFAllMessagePortsLock); + CFRelease(memory); + return (CFMessagePortRef)(existing); + } if (NULL == __CFAllLocalMessagePorts) { __CFAllLocalMessagePorts = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); } @@ -377,7 +433,15 @@ CFLog(99, CFSTR("CFMessagePortCreateLocal(): failed to name Mach port (%@)"), na return memory; } -CFMessagePortRef CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef name) { +CFMessagePortRef CFMessagePortCreateLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) { + return __CFMessagePortCreateLocal(allocator, name, callout, context, shouldFreeInfo, false); +} + +CFMessagePortRef CFMessagePortCreatePerProcessLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo) { + return __CFMessagePortCreateLocal(allocator, name, callout, context, shouldFreeInfo, true); +} + +static CFMessagePortRef __CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef name, Boolean perPID, CFIndex pid) { CFMessagePortRef memory; CFMachPortRef native; CFMachPortContext ctx; @@ -391,19 +455,20 @@ CFMessagePortRef CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef return NULL; } __CFSpinLock(&__CFAllMessagePortsLock); - if (NULL != name) { + if (!perPID && NULL != name) { CFMessagePortRef existing; if (NULL != __CFAllRemoteMessagePorts && CFDictionaryGetValueIfPresent(__CFAllRemoteMessagePorts, name, (const void **)&existing)) { + CFRetain(existing); __CFSpinUnlock(&__CFAllMessagePortsLock); CFRelease(name); CFAllocatorDeallocate(allocator, utfname); - return (CFMessagePortRef)CFRetain(existing); + return (CFMessagePortRef)(existing); } } + __CFSpinUnlock(&__CFAllMessagePortsLock); size = sizeof(struct __CFMessagePort) - sizeof(CFMessagePortContext) - sizeof(CFRuntimeBase); memory = (CFMessagePortRef)_CFRuntimeCreateInstance(allocator, __kCFMessagePortTypeID, size, NULL); if (NULL == memory) { - __CFSpinUnlock(&__CFAllMessagePortsLock); if (NULL != name) { CFRelease(name); } @@ -411,12 +476,14 @@ CFMessagePortRef CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef return NULL; } __CFMessagePortUnsetValid(memory); + __CFMessagePortUnsetExtraMachRef(memory); __CFMessagePortSetRemote(memory); - memory->_lock = 0; + memory->_lock = CFSpinLockInit; memory->_name = name; memory->_port = NULL; - memory->_replies = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, NULL, NULL); + memory->_replies = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); memory->_convCounter = 0; + memory->_perPID = perPID ? pid : 0; memory->_replyPort = NULL; memory->_source = NULL; memory->_icallout = NULL; @@ -427,11 +494,10 @@ CFMessagePortRef CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef ctx.release = NULL; ctx.copyDescription = NULL; task_get_bootstrap_port(mach_task_self(), &bp); - ret = bootstrap_look_up(bp, utfname, &port); + ret = bootstrap_look_up2(bp, (char *)utfname, &port, perPID ? (pid_t)pid : 0, perPID ? BOOTSTRAP_PER_PID_SERVICE : 0); native = (KERN_SUCCESS == ret) ? CFMachPortCreateWithPort(allocator, port, __CFMessagePortDummyCallback, &ctx, NULL) : NULL; CFAllocatorDeallocate(allocator, utfname); if (NULL == native) { - __CFSpinUnlock(&__CFAllMessagePortsLock); // name is released by deallocation CFRelease(memory); return NULL; @@ -439,7 +505,15 @@ CFMessagePortRef CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef memory->_port = native; CFMachPortSetInvalidationCallBack(native, __CFMessagePortInvalidationCallBack); __CFMessagePortSetValid(memory); - if (NULL != name) { + __CFSpinLock(&__CFAllMessagePortsLock); + if (!perPID && NULL != name) { + CFMessagePortRef existing; + if (NULL != __CFAllRemoteMessagePorts && CFDictionaryGetValueIfPresent(__CFAllRemoteMessagePorts, name, (const void **)&existing)) { + CFRetain(existing); + __CFSpinUnlock(&__CFAllMessagePortsLock); + CFRelease(memory); + return (CFMessagePortRef)(existing); + } if (NULL == __CFAllRemoteMessagePorts) { __CFAllRemoteMessagePorts = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); } @@ -449,6 +523,14 @@ CFMessagePortRef CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef return (CFMessagePortRef)memory; } +CFMessagePortRef CFMessagePortCreateRemote(CFAllocatorRef allocator, CFStringRef name) { + return __CFMessagePortCreateRemote(allocator, name, false, 0); +} + +CFMessagePortRef CFMessagePortCreatePerProcessRemote(CFAllocatorRef allocator, CFStringRef name, CFIndex pid) { + return __CFMessagePortCreateRemote(allocator, name, true, pid); +} + Boolean CFMessagePortIsRemote(CFMessagePortRef ms) { __CFGenericValidateType(ms, __kCFMessagePortTypeID); return __CFMessagePortIsRemote(ms); @@ -464,9 +546,7 @@ Boolean CFMessagePortSetName(CFMessagePortRef ms, CFStringRef name) { uint8_t *utfname = NULL; __CFGenericValidateType(ms, __kCFMessagePortTypeID); -// if (__CFMessagePortIsRemote(ms)) return false; -//#warning CF: make this an assertion -// and assert than newName is non-NULL + if (ms->_perPID || __CFMessagePortIsRemote(ms)) return false; name = __CFMessagePortSanitizeStringName(allocator, name, &utfname, NULL); if (NULL == name) { return false; @@ -481,13 +561,60 @@ Boolean CFMessagePortSetName(CFMessagePortRef ms, CFStringRef name) { return false; } } + __CFSpinUnlock(&__CFAllMessagePortsLock); + if (NULL != name && (NULL == ms->_name || !CFEqual(ms->_name, name))) { - if (!__CFMessagePortNativeSetNameLocal(ms->_port, utfname)) { - __CFSpinUnlock(&__CFAllMessagePortsLock); - CFRelease(name); - CFAllocatorDeallocate(allocator, utfname); - return false; + CFMachPortRef oldPort = ms->_port; + CFMachPortRef native = NULL; + kern_return_t ret; + mach_port_t bs, mp; + task_get_bootstrap_port(mach_task_self(), &bs); + ret = bootstrap_check_in(bs, (char *)utfname, &mp); /* If we're started by launchd or the old mach_init */ + if (ret == KERN_SUCCESS) { + ret = mach_port_insert_right(mach_task_self(), mp, mp, MACH_MSG_TYPE_MAKE_SEND); + if (KERN_SUCCESS == ret) { + CFMachPortContext ctx = {0, ms, NULL, NULL, NULL}; + native = CFMachPortCreateWithPort(allocator, mp, __CFMessagePortDummyCallback, &ctx, NULL); + __CFMessagePortSetExtraMachRef(ms); + } else { + mach_port_destroy(mach_task_self(), mp); + CFAllocatorDeallocate(allocator, utfname); + CFRelease(name); + return false; + } + } + if (!native) { + CFMachPortContext ctx = {0, ms, NULL, NULL, NULL}; + native = CFMachPortCreate(allocator, __CFMessagePortDummyCallback, &ctx, NULL); + mp = CFMachPortGetPort(native); + ret = bootstrap_register2(bs, (char *)utfname, mp, 0); + if (ret != KERN_SUCCESS) { + CFLog(kCFLogLevelWarning, CFSTR("*** CFMessagePort: bootstrap_register(): failed %d (0x%x) '%s', port = 0x%x, name = '%s'\nSee /usr/include/servers/bootstrap_defs.h for the error codes."), ret, ret, bootstrap_strerror(ret), mp, utfname); + CFMachPortInvalidate(native); + CFRelease(native); + CFAllocatorDeallocate(allocator, utfname); + CFRelease(name); + return false; + } + } + CFMachPortSetInvalidationCallBack(native, __CFMessagePortInvalidationCallBack); + ms->_port = native; + if (NULL != oldPort && oldPort != native) { + if (__CFMessagePortExtraMachRef(ms)) { + mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(oldPort), MACH_PORT_RIGHT_SEND, -1); + mach_port_mod_refs(mach_task_self(), CFMachPortGetPort(oldPort), MACH_PORT_RIGHT_RECEIVE, -1); + } + CFMachPortInvalidate(oldPort); + CFRelease(oldPort); } + __CFSpinLock(&__CFAllMessagePortsLock); + // This relocking without checking to see if something else has grabbed + // that name in the cache is rather suspect, but what would that even + // mean has happened? We'd expect the bootstrap_* calls above to have + // failed for this one and not gotten this far, or failed for all of the + // other simultaneous attempts to get the name (and having succeeded for + // this one, gotten here). So we're not going to try very hard here + // with the thread-safety. if (NULL == __CFAllLocalMessagePorts) { __CFAllLocalMessagePorts = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL); } @@ -497,8 +624,9 @@ Boolean CFMessagePortSetName(CFMessagePortRef ms, CFStringRef name) { } ms->_name = name; CFDictionaryAddValue(__CFAllLocalMessagePorts, name, ms); + __CFSpinUnlock(&__CFAllMessagePortsLock); } - __CFSpinUnlock(&__CFAllMessagePortsLock); + CFAllocatorDeallocate(allocator, utfname); return true; } @@ -534,7 +662,7 @@ void CFMessagePortInvalidate(CFMessagePortRef ms) { __CFMessagePortUnlock(ms); __CFSpinLock(&__CFAllMessagePortsLock); - if (NULL != (__CFMessagePortIsRemote(ms) ? __CFAllRemoteMessagePorts : __CFAllLocalMessagePorts)) { + if (0 == ms->_perPID && NULL != (__CFMessagePortIsRemote(ms) ? __CFAllRemoteMessagePorts : __CFAllLocalMessagePorts)) { CFDictionaryRemoveValue(__CFMessagePortIsRemote(ms) ? __CFAllRemoteMessagePorts : __CFAllLocalMessagePorts, name); } __CFSpinUnlock(&__CFAllMessagePortsLock); @@ -613,7 +741,7 @@ static void __CFMessagePortReplyCallBack(CFMachPortRef port, void *msg, CFIndex return; } // assert: (int32_t)msgp->head.msgh_id < 0 - if (CFDictionaryContainsKey(ms->_replies, (void *)msgp->head.msgh_id)) { + if (CFDictionaryContainsKey(ms->_replies, (void *)(uintptr_t)msgp->head.msgh_id)) { CFDataRef reply = NULL; replymsg = (struct __CFMessagePortMachMessage *)msg; if (0 == replymsg->body.msgh_descriptor_count) { @@ -621,14 +749,14 @@ static void __CFMessagePortReplyCallBack(CFMachPortRef port, void *msg, CFIndex if (0 <= byteslen) { reply = CFDataCreate(kCFAllocatorSystemDefault, replymsg->contents.msg0.bytes, byteslen); } else { - reply = (void *)0xffffffff; // means NULL data + reply = (void *)~0; // means NULL data } } else { //#warning CF: should create a no-copy data here that has a custom VM-freeing allocator, and not vm_dealloc here reply = CFDataCreate(kCFAllocatorSystemDefault, replymsg->contents.msg1.desc.out_of_line.address, replymsg->contents.msg1.desc.out_of_line.size); vm_deallocate(mach_task_self(), (vm_address_t)replymsg->contents.msg1.desc.out_of_line.address, replymsg->contents.msg1.desc.out_of_line.size); } - CFDictionarySetValue(ms->_replies, (void *)msgp->head.msgh_id, (void *)reply); + CFDictionarySetValue(ms->_replies, (void *)(uintptr_t)msgp->head.msgh_id, (void *)reply); } else { /* discard message */ if (1 == msgp->body.msgh_descriptor_count) { vm_deallocate(mach_task_self(), (vm_address_t)msgp->contents.msg1.desc.out_of_line.address, msgp->contents.msg1.desc.out_of_line.size); @@ -663,10 +791,10 @@ SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CFDataRef } remote->_convCounter++; desiredReply = -remote->_convCounter; - CFDictionarySetValue(remote->_replies, (void *)desiredReply, NULL); - sendmsg = __CFMessagePortCreateMessage(CFGetAllocator(remote), false, CFMachPortGetPort(remote->_port), (replyMode != NULL ? CFMachPortGetPort(remote->_replyPort) : MACH_PORT_NULL), -desiredReply, msgid, (data ? CFDataGetBytePtr(data) : NULL), (data ? CFDataGetLength(data) : 0)); + sendmsg = __CFMessagePortCreateMessage(kCFAllocatorSystemDefault, false, CFMachPortGetPort(remote->_port), (replyMode != NULL ? CFMachPortGetPort(remote->_replyPort) : MACH_PORT_NULL), -desiredReply, msgid, (data ? CFDataGetBytePtr(data) : NULL), (data ? CFDataGetLength(data) : 0)); __CFMessagePortUnlock(remote); if (replyMode != NULL) { + CFDictionarySetValue(remote->_replies, (void *)(uintptr_t)desiredReply, NULL); source = CFMachPortCreateRunLoopSource(CFGetAllocator(remote), remote->_replyPort, -100); didRegister = !CFRunLoopContainsSource(currentRL, source, replyMode); if (didRegister) { @@ -681,15 +809,17 @@ SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CFDataRef sendTimeOut = floor(sendTimeout); } ret = mach_msg((mach_msg_header_t *)sendmsg, MACH_SEND_MSG|sendOpts, sendmsg->head.msgh_size, 0, MACH_PORT_NULL, sendTimeOut, MACH_PORT_NULL); - CFAllocatorDeallocate(CFGetAllocator(remote), sendmsg); if (KERN_SUCCESS != ret) { + // need to deallocate the send-once right that might have been created + if (replyMode != NULL) mach_port_deallocate(mach_task_self(), ((mach_msg_header_t *)sendmsg)->msgh_local_port); if (didRegister) { CFRunLoopRemoveSource(currentRL, source, replyMode); - CFRelease(source); } - if (MACH_SEND_TIMED_OUT == ret) return kCFMessagePortSendTimeout; - return kCFMessagePortTransportError; + if (source) CFRelease(source); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, sendmsg); + return (MACH_SEND_TIMED_OUT == ret) ? kCFMessagePortSendTimeout : kCFMessagePortTransportError; } + CFAllocatorDeallocate(kCFAllocatorSystemDefault, sendmsg); if (replyMode == NULL) { return kCFMessagePortSuccess; } @@ -699,7 +829,7 @@ SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CFDataRef for (;;) { CFRunLoopRunInMode(replyMode, __CFTSRToTimeInterval(termTSR - mach_absolute_time()), true); // warning: what, if anything, should be done if remote is now invalid? - reply = CFDictionaryGetValue(remote->_replies, (void *)desiredReply); + reply = CFDictionaryGetValue(remote->_replies, (void *)(uintptr_t)desiredReply); if (NULL != reply || termTSR < (int64_t)mach_absolute_time()) { break; } @@ -711,26 +841,27 @@ SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CFDataRef // Should we uninstall the notify port? A complex question... if (didRegister) { CFRunLoopRemoveSource(currentRL, source, replyMode); - CFRelease(source); } + if (source) CFRelease(source); if (NULL == reply) { - CFDictionaryRemoveValue(remote->_replies, (void *)desiredReply); + CFDictionaryRemoveValue(remote->_replies, (void *)(uintptr_t)desiredReply); CFRelease(remote); return CFMessagePortIsValid(remote) ? kCFMessagePortReceiveTimeout : -5; } if (NULL != returnDatap) { - *returnDatap = ((void *)0xffffffff == reply) ? NULL : reply; - } else if ((void *)0xffffffff != reply) { + *returnDatap = ((void *)~0 == reply) ? NULL : reply; + } else if ((void *)~0 != reply) { CFRelease(reply); } - CFDictionaryRemoveValue(remote->_replies, (void *)desiredReply); + CFDictionaryRemoveValue(remote->_replies, (void *)(uintptr_t)desiredReply); CFRelease(remote); return kCFMessagePortSuccess; } static mach_port_t __CFMessagePortGetPort(void *info) { CFMessagePortRef ms = info; - return CFMachPortGetPort(ms->_port); + if (!ms->_port) CFLog(kCFLogLevelWarning, CFSTR("*** Warning: A local CFMessagePort (%p) is being put in a run loop, 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; } static void *__CFMessagePortPerform(void *msg, CFIndex size, CFAllocatorRef allocator, void *info) { @@ -822,8 +953,8 @@ CFRunLoopSourceRef CFMessagePortCreateRunLoopSource(CFAllocatorRef allocator, CF context.retain = (const void *(*)(const void *))CFRetain; context.release = (void (*)(const void *))CFRelease; context.copyDescription = (CFStringRef (*)(const void *))__CFMessagePortCopyDescription; - context.equal = (Boolean (*)(const void *, const void *))__CFMessagePortEqual; - context.hash = (CFHashCode (*)(const void *))__CFMessagePortHash; + context.equal = NULL; + context.hash = NULL; context.getPort = __CFMessagePortGetPort; context.perform = __CFMessagePortPerform; ms->_source = CFRunLoopSourceCreate(allocator, order, (CFRunLoopSourceContext *)&context); @@ -835,5 +966,4 @@ CFRunLoopSourceRef CFMessagePortCreateRunLoopSource(CFAllocatorRef allocator, CF return result; } -#endif /* !__WIN32__ */ diff --git a/RunLoop.subproj/CFMessagePort.h b/CFMessagePort.h similarity index 94% rename from RunLoop.subproj/CFMessagePort.h rename to CFMessagePort.h index 2be5fa6..367b401 100644 --- a/RunLoop.subproj/CFMessagePort.h +++ b/CFMessagePort.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFMessagePort.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFMESSAGEPORT__) @@ -31,9 +31,7 @@ #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN typedef struct __CFMessagePort * CFMessagePortRef; @@ -76,9 +74,7 @@ CF_EXPORT SInt32 CFMessagePortSendRequest(CFMessagePortRef remote, SInt32 msgid, CF_EXPORT CFRunLoopSourceRef CFMessagePortCreateRunLoopSource(CFAllocatorRef allocator, CFMessagePortRef local, CFIndex order); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFMESSAGEPORT__ */ diff --git a/CFNumber.c b/CFNumber.c new file mode 100644 index 0000000..b185dc4 --- /dev/null +++ b/CFNumber.c @@ -0,0 +1,1115 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFNumber.c + Copyright 1999-2002, Apple, Inc. All rights reserved. + Responsibility: Ali Ozer +*/ + +#include +#include "CFInternal.h" +#include "CFPriv.h" +#include +#include + +#define __CFAssertIsBoolean(cf) __CFGenericValidateType(cf, __kCFBooleanTypeID) + +struct __CFBoolean { + CFRuntimeBase _base; +}; + +static struct __CFBoolean __kCFBooleanTrue = { + INIT_CFRUNTIME_BASE() +}; +const CFBooleanRef kCFBooleanTrue = &__kCFBooleanTrue; + +static struct __CFBoolean __kCFBooleanFalse = { + INIT_CFRUNTIME_BASE() +}; +const CFBooleanRef kCFBooleanFalse = &__kCFBooleanFalse; + +static CFStringRef __CFBooleanCopyDescription(CFTypeRef cf) { + CFBooleanRef boolean = (CFBooleanRef)cf; + return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{value = %s}"), cf, CFGetAllocator(cf), (boolean == kCFBooleanTrue) ? "true" : "false"); +} + +static CFStringRef __CFBooleanCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { + CFBooleanRef boolean = (CFBooleanRef)cf; + return (CFStringRef)CFRetain((boolean == kCFBooleanTrue) ? CFSTR("true") : CFSTR("false")); +} + +static void __CFBooleanDeallocate(CFTypeRef cf) { + CFAssert(false, __kCFLogAssertion, "Deallocated CFBoolean!"); +} + +static CFTypeID __kCFBooleanTypeID = _kCFRuntimeNotATypeID; + +static const CFRuntimeClass __CFBooleanClass = { + 0, + "CFBoolean", + NULL, // init + NULL, // copy + __CFBooleanDeallocate, + NULL, + NULL, + __CFBooleanCopyFormattingDescription, + __CFBooleanCopyDescription +}; + +__private_extern__ void __CFBooleanInitialize(void) { + __kCFBooleanTypeID = _CFRuntimeRegisterClass(&__CFBooleanClass); + _CFRuntimeSetInstanceTypeID(&__kCFBooleanTrue, __kCFBooleanTypeID); + __kCFBooleanTrue._base._cfisa = __CFISAForTypeID(__kCFBooleanTypeID); + _CFRuntimeSetInstanceTypeID(&__kCFBooleanFalse, __kCFBooleanTypeID); + __kCFBooleanFalse._base._cfisa = __CFISAForTypeID(__kCFBooleanTypeID); +} + +CFTypeID CFBooleanGetTypeID(void) { + return __kCFBooleanTypeID; +} + +Boolean CFBooleanGetValue(CFBooleanRef boolean) { + CF_OBJC_FUNCDISPATCH0(__kCFBooleanTypeID, Boolean, boolean, "boolValue"); + return (boolean == kCFBooleanTrue) ? true : false; +} + + +/*** CFNumber ***/ + +#define __CFAssertIsNumber(cf) __CFGenericValidateType(cf, __kCFNumberTypeID) +#define __CFAssertIsValidNumberType(type) CFAssert2((0 < type && type <= kCFNumberMaxType) || (type == kCFNumberSInt128Type), __kCFLogAssertion, "%s(): bad CFNumber type %d", __PRETTY_FUNCTION__, type); + +/* The IEEE bit patterns... Also have: +0x7f800000 float +Inf +0x7fc00000 float NaN +0xff800000 float -Inf +*/ +#define BITSFORDOUBLENAN ((uint64_t)0x7ff8000000000000ULL) +#define BITSFORDOUBLEPOSINF ((uint64_t)0x7ff0000000000000ULL) +#define BITSFORDOUBLENEGINF ((uint64_t)0xfff0000000000000ULL) + +#if DEPLOYMENT_TARGET_MACOSX +#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 +#endif + +typedef struct { // NOTE WELL: these two fields may switch position someday, do not use '= {high, low}' -style initialization + int64_t high; + uint64_t low; +} CFSInt128Struct; + +enum { + kCFNumberSInt128Type = 17 +}; + +static uint8_t isNeg128(const CFSInt128Struct *in) { + return in->high < 0; +} + +static CFComparisonResult cmp128(const CFSInt128Struct *in1, const CFSInt128Struct *in2) { + if (in1->high < in2->high) return kCFCompareLessThan; + if (in1->high > in2->high) return kCFCompareGreaterThan; + if (in1->low < in2->low) return kCFCompareLessThan; + if (in1->low > in2->low) return kCFCompareGreaterThan; + return kCFCompareEqualTo; +} + +// allows out to be the same as in1 or in2 +static void add128(CFSInt128Struct *out, CFSInt128Struct *in1, CFSInt128Struct *in2) { + CFSInt128Struct tmp; + tmp.low = in1->low + in2->low; + tmp.high = in1->high + in2->high; + if (UINT64_MAX - in1->low < in2->low) { + tmp.high++; + } + *out = tmp; +} + +// allows out to be the same as in +static void neg128(CFSInt128Struct *out, CFSInt128Struct *in) { + uint64_t tmplow = ~in->low; + out->low = tmplow + 1; + out->high = ~in->high; + if (UINT64_MAX == tmplow) { + out->high++; + } +} + +static const CFSInt128Struct powersOf10[] = { + { 0x4B3B4CA85A86C47ALL, 0x098A224000000000ULL }, + { 0x0785EE10D5DA46D9LL, 0x00F436A000000000ULL }, + { 0x00C097CE7BC90715LL, 0xB34B9F1000000000ULL }, + { 0x0013426172C74D82LL, 0x2B878FE800000000ULL }, + { 0x0001ED09BEAD87C0LL, 0x378D8E6400000000ULL }, + { 0x0000314DC6448D93LL, 0x38C15B0A00000000ULL }, + { 0x000004EE2D6D415BLL, 0x85ACEF8100000000ULL }, + { 0x0000007E37BE2022LL, 0xC0914B2680000000ULL }, + { 0x0000000C9F2C9CD0LL, 0x4674EDEA40000000ULL }, + { 0x00000001431E0FAELL, 0x6D7217CAA0000000ULL }, + { 0x00000000204FCE5ELL, 0x3E25026110000000ULL }, + { 0x00000000033B2E3CLL, 0x9FD0803CE8000000ULL }, + { 0x000000000052B7D2LL, 0xDCC80CD2E4000000ULL }, + { 0x0000000000084595LL, 0x161401484A000000ULL }, + { 0x000000000000D3C2LL, 0x1BCECCEDA1000000ULL }, + { 0x000000000000152DLL, 0x02C7E14AF6800000ULL }, + { 0x000000000000021ELL, 0x19E0C9BAB2400000ULL }, + { 0x0000000000000036LL, 0x35C9ADC5DEA00000ULL }, + { 0x0000000000000005LL, 0x6BC75E2D63100000ULL }, + { 0x0000000000000000LL, 0x8AC7230489E80000ULL }, + { 0x0000000000000000LL, 0x0DE0B6B3A7640000ULL }, + { 0x0000000000000000LL, 0x016345785D8A0000ULL }, + { 0x0000000000000000LL, 0x002386F26FC10000ULL }, + { 0x0000000000000000LL, 0x00038D7EA4C68000ULL }, + { 0x0000000000000000LL, 0x00005AF3107A4000ULL }, + { 0x0000000000000000LL, 0x000009184E72A000ULL }, + { 0x0000000000000000LL, 0x000000E8D4A51000ULL }, + { 0x0000000000000000LL, 0x000000174876E800ULL }, + { 0x0000000000000000LL, 0x00000002540BE400ULL }, + { 0x0000000000000000LL, 0x000000003B9ACA00ULL }, + { 0x0000000000000000LL, 0x0000000005F5E100ULL }, + { 0x0000000000000000LL, 0x0000000000989680ULL }, + { 0x0000000000000000LL, 0x00000000000F4240ULL }, + { 0x0000000000000000LL, 0x00000000000186A0ULL }, + { 0x0000000000000000LL, 0x0000000000002710ULL }, + { 0x0000000000000000LL, 0x00000000000003E8ULL }, + { 0x0000000000000000LL, 0x0000000000000064ULL }, + { 0x0000000000000000LL, 0x000000000000000AULL }, + { 0x0000000000000000LL, 0x0000000000000001ULL }, +}; + +static const CFSInt128Struct neg_powersOf10[] = { + { 0xB4C4B357A5793B85LL, 0xF675DDC000000000ULL }, + { 0xF87A11EF2A25B926LL, 0xFF0BC96000000000ULL }, + { 0xFF3F68318436F8EALL, 0x4CB460F000000000ULL }, + { 0xFFECBD9E8D38B27DLL, 0xD478701800000000ULL }, + { 0xFFFE12F64152783FLL, 0xC872719C00000000ULL }, + { 0xFFFFCEB239BB726CLL, 0xC73EA4F600000000ULL }, + { 0xFFFFFB11D292BEA4LL, 0x7A53107F00000000ULL }, + { 0xFFFFFF81C841DFDDLL, 0x3F6EB4D980000000ULL }, + { 0xFFFFFFF360D3632FLL, 0xB98B1215C0000000ULL }, + { 0xFFFFFFFEBCE1F051LL, 0x928DE83560000000ULL }, + { 0xFFFFFFFFDFB031A1LL, 0xC1DAFD9EF0000000ULL }, + { 0xFFFFFFFFFCC4D1C3LL, 0x602F7FC318000000ULL }, + { 0xFFFFFFFFFFAD482DLL, 0x2337F32D1C000000ULL }, + { 0xFFFFFFFFFFF7BA6ALL, 0xE9EBFEB7B6000000ULL }, + { 0xFFFFFFFFFFFF2C3DLL, 0xE43133125F000000ULL }, + { 0xFFFFFFFFFFFFEAD2LL, 0xFD381EB509800000ULL }, + { 0xFFFFFFFFFFFFFDE1LL, 0xE61F36454DC00000ULL }, + { 0xFFFFFFFFFFFFFFC9LL, 0xCA36523A21600000ULL }, + { 0xFFFFFFFFFFFFFFFALL, 0x9438A1D29CF00000ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0x7538DCFB76180000ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xF21F494C589C0000ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFE9CBA87A2760000ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFDC790D903F0000ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFFC72815B398000ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFA50CEF85C000ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFF6E7B18D6000ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFF172B5AF000ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFE8B7891800ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFDABF41C00ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFC4653600ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFA0A1F00ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFF676980ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFF0BDC0ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFE7960ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFD8F0ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFC18ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFF9CULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFF6ULL }, + { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFFFULL }, +}; + +static void emit128(char *buffer, const CFSInt128Struct *in, Boolean forcePlus) { + CFSInt128Struct tmp = *in; + if (isNeg128(&tmp)) { + neg128(&tmp, &tmp); + *buffer++ = '-'; + } else if (forcePlus) { + *buffer++ = '+'; + } + Boolean doneOne = false; + int idx; + for (idx = 0; idx < sizeof(powersOf10) / sizeof(powersOf10[0]); idx++) { + int count = 0; + while (cmp128(&powersOf10[idx], &tmp) <= 0) { + add128(&tmp, &tmp, (CFSInt128Struct *)&neg_powersOf10[idx]); + count++; + } + if (0 != count || doneOne) { + *buffer++ = '0' + count; + doneOne = true; + } + } + if (!doneOne) { + *buffer++ = '0'; + } + *buffer = '\0'; +} + +static void cvtSInt128ToFloat64(Float64 *out, const CFSInt128Struct *in) { + // switching to a positive number results in better accuracy + // for negative numbers close to zero, because the multiply + // of -1 by 2^64 (scaling the Float64 high) is avoided + Boolean wasNeg = false; + CFSInt128Struct tmp = *in; + if (isNeg128(&tmp)) { + neg128(&tmp, &tmp); + wasNeg = true; + } + Float64 d = (Float64)tmp.high * FLOAT_POSITIVE_2_TO_THE_64 + (Float64)tmp.low; + if (wasNeg) d = -d; + *out = d; +} + +static void cvtFloat64ToSInt128(CFSInt128Struct *out, const Float64 *in) { + CFSInt128Struct i; + Float64 d = *in; + if (d < FLOAT_NEGATIVE_2_TO_THE_127) { + i.high = 0x8000000000000000LL; + i.low = 0x0000000000000000ULL; + *out = i; + return; + } + if (FLOAT_POSITIVE_2_TO_THE_127<= d) { + i.high = 0x7fffffffffffffffLL; + i.low = 0xffffffffffffffffULL; + *out = i; + return; + } + Float64 t = floor(d / FLOAT_POSITIVE_2_TO_THE_64); + i.high = (int64_t)t; + i.low = (uint64_t)(d - t * FLOAT_POSITIVE_2_TO_THE_64); + *out = i; +} + +struct __CFNumber { + CFRuntimeBase _base; + uint64_t _pad; // need this space here for the constant objects + /* 0 or 8 more bytes allocated here */ +}; + +/* Seven bits in base: + Bits 6..5: unused + Bits 4..0: CFNumber type +*/ + +static struct __CFNumber __kCFNumberNaN = { + INIT_CFRUNTIME_BASE(), 0ULL +}; +const CFNumberRef kCFNumberNaN = &__kCFNumberNaN; + +static struct __CFNumber __kCFNumberNegativeInfinity = { + INIT_CFRUNTIME_BASE(), 0ULL +}; +const CFNumberRef kCFNumberNegativeInfinity = &__kCFNumberNegativeInfinity; + +static struct __CFNumber __kCFNumberPositiveInfinity = { + INIT_CFRUNTIME_BASE(), 0ULL +}; +const CFNumberRef kCFNumberPositiveInfinity = &__kCFNumberPositiveInfinity; + +static const struct { + uint16_t canonicalType:5; // canonical fixed-width type + uint16_t floatBit:1; // is float + uint16_t storageBit:1; // storage size (0: (float ? 4 : 8), 1: (float ? 8 : 16) bits) + uint16_t lgByteSize:3; // base-2 log byte size of public type + uint16_t unused:6; +} __CFNumberTypeTable[] = { + /* 0 */ {0, 0, 0, 0}, + + /* kCFNumberSInt8Type */ {kCFNumberSInt8Type, 0, 0, 0, 0}, + /* kCFNumberSInt16Type */ {kCFNumberSInt16Type, 0, 0, 1, 0}, + /* kCFNumberSInt32Type */ {kCFNumberSInt32Type, 0, 0, 2, 0}, + /* kCFNumberSInt64Type */ {kCFNumberSInt64Type, 0, 0, 3, 0}, + /* kCFNumberFloat32Type */ {kCFNumberFloat32Type, 1, 0, 2, 0}, + /* kCFNumberFloat64Type */ {kCFNumberFloat64Type, 1, 1, 3, 0}, + + /* kCFNumberCharType */ {kCFNumberSInt8Type, 0, 0, 0, 0}, + /* kCFNumberShortType */ {kCFNumberSInt16Type, 0, 0, 1, 0}, + /* kCFNumberIntType */ {kCFNumberSInt32Type, 0, 0, 2, 0}, +#if __LP64__ + /* kCFNumberLongType */ {kCFNumberSInt64Type, 0, 0, 3, 0}, +#else + /* kCFNumberLongType */ {kCFNumberSInt32Type, 0, 0, 2, 0}, +#endif + /* kCFNumberLongLongType */ {kCFNumberSInt64Type, 0, 0, 3, 0}, + /* kCFNumberFloatType */ {kCFNumberFloat32Type, 1, 0, 2, 0}, + /* kCFNumberDoubleType */ {kCFNumberFloat64Type, 1, 1, 3, 0}, + +#if __LP64__ + /* kCFNumberCFIndexType */ {kCFNumberSInt64Type, 0, 0, 3, 0}, + /* kCFNumberNSIntegerType */ {kCFNumberSInt64Type, 0, 0, 3, 0}, + /* kCFNumberCGFloatType */ {kCFNumberFloat64Type, 1, 1, 3, 0}, +#else + /* kCFNumberCFIndexType */ {kCFNumberSInt32Type, 0, 0, 2, 0}, + /* kCFNumberNSIntegerType */ {kCFNumberSInt32Type, 0, 0, 2, 0}, + /* kCFNumberCGFloatType */ {kCFNumberFloat32Type, 1, 0, 2, 0}, +#endif + + /* kCFNumberSInt128Type */ {kCFNumberSInt128Type, 0, 1, 4, 0}, +}; + +CF_INLINE CFNumberType __CFNumberGetType(CFNumberRef num) { + return __CFBitfieldGetValue(num->_base._cfinfo[CF_INFO_BITS], 4, 0); +} + +#define CVT(SRC_TYPE, DST_TYPE, DST_MIN, DST_MAX) do { \ + SRC_TYPE sv; memmove(&sv, data, sizeof(SRC_TYPE)); \ + DST_TYPE dv = (sv < DST_MIN) ? (DST_TYPE)DST_MIN : (DST_TYPE)(((DST_MAX < sv) ? DST_MAX : sv)); \ + memmove(valuePtr, &dv, sizeof(DST_TYPE)); \ + SRC_TYPE vv = (SRC_TYPE)dv; return (vv == sv); \ + } while (0) + +#define CVT128ToInt(SRC_TYPE, DST_TYPE, DST_MIN, DST_MAX) do { \ + SRC_TYPE sv; memmove(&sv, data, sizeof(SRC_TYPE)); \ + DST_TYPE dv; Boolean noLoss = false; \ + if (0 < sv.high || (0 == sv.high && (int64_t)DST_MAX < sv.low)) { \ + dv = DST_MAX; \ + } else if (sv.high < -1 || (-1 == sv.high && sv.low < (int64_t)DST_MIN)) { \ + dv = DST_MIN; \ + } else { \ + dv = (DST_TYPE)sv.low; \ + noLoss = true; \ + } \ + memmove(valuePtr, &dv, sizeof(DST_TYPE)); \ + return noLoss; \ + } while (0) + +// returns false if the output value is not the same as the number's value, which +// can occur due to accuracy loss and the value not being within the target range +static Boolean __CFNumberGetValue(CFNumberRef number, CFNumberType type, void *valuePtr) { + type = __CFNumberTypeTable[type].canonicalType; + CFNumberType ntype = __CFNumberGetType(number); + const void *data = &(number->_pad); + switch (type) { + case kCFNumberSInt8Type: + if (__CFNumberTypeTable[ntype].floatBit) { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT(Float32, int8_t, INT8_MIN, INT8_MAX); + } else { + CVT(Float64, int8_t, INT8_MIN, INT8_MAX); + } + } else { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT(int64_t, int8_t, INT8_MIN, INT8_MAX); + } else { + CVT128ToInt(CFSInt128Struct, int8_t, INT8_MIN, INT8_MAX); + } + } + return true; + case kCFNumberSInt16Type: + if (__CFNumberTypeTable[ntype].floatBit) { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT(Float32, int16_t, INT16_MIN, INT16_MAX); + } else { + CVT(Float64, int16_t, INT16_MIN, INT16_MAX); + } + } else { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT(int64_t, int16_t, INT16_MIN, INT16_MAX); + } else { + CVT128ToInt(CFSInt128Struct, int16_t, INT16_MIN, INT16_MAX); + } + } + return true; + case kCFNumberSInt32Type: + if (__CFNumberTypeTable[ntype].floatBit) { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT(Float32, int32_t, INT32_MIN, INT32_MAX); + } else { + CVT(Float64, int32_t, INT32_MIN, INT32_MAX); + } + } else { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT(int64_t, int32_t, INT32_MIN, INT32_MAX); + } else { + CVT128ToInt(CFSInt128Struct, int32_t, INT32_MIN, INT32_MAX); + } + } + return true; + case kCFNumberSInt64Type: + if (__CFNumberTypeTable[ntype].floatBit) { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT(Float32, int64_t, INT64_MIN, INT64_MAX); + } else { + CVT(Float64, int64_t, INT64_MIN, INT64_MAX); + } + } else { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + memmove(valuePtr, data, 8); + } else { + CVT128ToInt(CFSInt128Struct, int64_t, INT64_MIN, INT64_MAX); + } + } + return true; + case kCFNumberSInt128Type: + if (__CFNumberTypeTable[ntype].floatBit) { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + Float32 f; + memmove(&f, data, 4); + Float64 d = f; + CFSInt128Struct i; + cvtFloat64ToSInt128(&i, &d); + memmove(valuePtr, &i, 16); + Float64 d2; + cvtSInt128ToFloat64(&d2, &i); + Float32 f2 = (Float32)d2; + return (f2 == f); + } else { + Float64 d; + memmove(&d, data, 8); + CFSInt128Struct i; + cvtFloat64ToSInt128(&i, &d); + memmove(valuePtr, &i, 16); + Float64 d2; + cvtSInt128ToFloat64(&d2, &i); + return (d2 == d); + } + } else { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + int64_t j; + memmove(&j, data, 8); + CFSInt128Struct i; + i.low = j; + i.high = (j < 0) ? -1LL : 0LL; + memmove(valuePtr, &i, 16); + } else { + memmove(valuePtr, data, 16); + } + } + return true; + case kCFNumberFloat32Type: + if (__CFNumberTypeTable[ntype].floatBit) { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + memmove(valuePtr, data, 4); + } else { + double d; + memmove(&d, data, 8); + if (isnan(d)) { + uint32_t l = 0x7fc00000; + memmove(valuePtr, &l, 4); + return true; + } else if (isinf(d)) { + uint32_t l = 0x7f800000; + if (d < 0.0) l += 0x80000000UL; + memmove(valuePtr, &l, 4); + return true; + } + CVT(Float64, Float32, -FLT_MAX, FLT_MAX); + } + } else { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT(int64_t, Float32, -FLT_MAX, FLT_MAX); + } else { + CFSInt128Struct i; + memmove(&i, data, 16); + Float64 d; + cvtSInt128ToFloat64(&d, &i); + Float32 f = (Float32)d; + memmove(valuePtr, &f, 4); + d = f; + CFSInt128Struct i2; + cvtFloat64ToSInt128(&i2, &d); + return cmp128(&i2, &i) == kCFCompareEqualTo; + } + } + return true; + case kCFNumberFloat64Type: + if (__CFNumberTypeTable[ntype].floatBit) { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + float f; + memmove(&f, data, 4); + if (isnan(f)) { + uint64_t l = BITSFORDOUBLENAN; + memmove(valuePtr, &l, 8); + return true; + } else if (isinf(f)) { + uint64_t l = BITSFORDOUBLEPOSINF; + if (f < 0.0) l += 0x8000000000000000ULL; + memmove(valuePtr, &l, 8); + return true; + } + CVT(Float32, Float64, -DBL_MAX, DBL_MAX); + } else { + memmove(valuePtr, data, 8); + } + } else { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT(int64_t, Float64, -DBL_MAX, DBL_MAX); + } else { + CFSInt128Struct i; + memmove(&i, data, 16); + Float64 d; + cvtSInt128ToFloat64(&d, &i); + memmove(valuePtr, &d, 8); + CFSInt128Struct i2; + cvtFloat64ToSInt128(&i2, &d); + return cmp128(&i2, &i) == kCFCompareEqualTo; + } + } + return true; + } + return false; +} + +#define CVT_COMPAT(SRC_TYPE, DST_TYPE, FT) do { \ + SRC_TYPE sv; memmove(&sv, data, sizeof(SRC_TYPE)); \ + DST_TYPE dv = (DST_TYPE)(sv); \ + memmove(valuePtr, &dv, sizeof(DST_TYPE)); \ + SRC_TYPE vv = (SRC_TYPE)dv; return (FT) || (vv == sv); \ + } while (0) + +#define CVT128ToInt_COMPAT(SRC_TYPE, DST_TYPE) do { \ + SRC_TYPE sv; memmove(&sv, data, sizeof(SRC_TYPE)); \ + DST_TYPE dv; dv = (DST_TYPE)sv.low; \ + memmove(valuePtr, &dv, sizeof(DST_TYPE)); \ + uint64_t vv = (uint64_t)dv; return (vv == sv.low); \ + } while (0) + +// this has the old cast-style behavior +static Boolean __CFNumberGetValueCompat(CFNumberRef number, CFNumberType type, void *valuePtr) { + type = __CFNumberTypeTable[type].canonicalType; + CFNumberType ntype = __CFNumberGetType(number); + const void *data = &(number->_pad); + switch (type) { + case kCFNumberSInt8Type: + if (__CFNumberTypeTable[ntype].floatBit) { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT_COMPAT(Float32, int8_t, 0); + } else { + CVT_COMPAT(Float64, int8_t, 0); + } + } else { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT_COMPAT(int64_t, int8_t, 1); + } else { + CVT128ToInt_COMPAT(CFSInt128Struct, int8_t); + } + } + return true; + case kCFNumberSInt16Type: + if (__CFNumberTypeTable[ntype].floatBit) { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT_COMPAT(Float32, int16_t, 0); + } else { + CVT_COMPAT(Float64, int16_t, 0); + } + } else { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT_COMPAT(int64_t, int16_t, 1); + } else { + CVT128ToInt_COMPAT(CFSInt128Struct, int16_t); + } + } + return true; + case kCFNumberSInt32Type: + if (__CFNumberTypeTable[ntype].floatBit) { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT_COMPAT(Float32, int32_t, 0); + } else { + CVT_COMPAT(Float64, int32_t, 0); + } + } else { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT_COMPAT(int64_t, int32_t, 0); + } else { + CVT128ToInt_COMPAT(CFSInt128Struct, int32_t); + } + } + return true; + case kCFNumberSInt64Type: + if (__CFNumberTypeTable[ntype].floatBit) { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT_COMPAT(Float32, int64_t, 0); + } else { + CVT_COMPAT(Float64, int64_t, 0); + } + } else { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT_COMPAT(int64_t, int64_t, 0); + } else { + CVT128ToInt_COMPAT(CFSInt128Struct, int64_t); + } + } + return true; + case kCFNumberSInt128Type: + if (__CFNumberTypeTable[ntype].floatBit) { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + Float32 f; + memmove(&f, data, 4); + Float64 d = f; + CFSInt128Struct i; + cvtFloat64ToSInt128(&i, &d); + memmove(valuePtr, &i, 16); + Float64 d2; + cvtSInt128ToFloat64(&d2, &i); + Float32 f2 = (Float32)d2; + return (f2 == f); + } else { + Float64 d; + memmove(&d, data, 8); + CFSInt128Struct i; + cvtFloat64ToSInt128(&i, &d); + memmove(valuePtr, &i, 16); + Float64 d2; + cvtSInt128ToFloat64(&d2, &i); + return (d2 == d); + } + } else { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + int64_t j; + memmove(&j, data, 8); + CFSInt128Struct i; + i.low = j; + i.high = (j < 0) ? -1LL : 0LL; + memmove(valuePtr, &i, 16); + } else { + memmove(valuePtr, data, 16); + } + } + return true; + case kCFNumberFloat32Type: + if (__CFNumberTypeTable[ntype].floatBit) { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + memmove(valuePtr, data, 4); + } else { + CVT_COMPAT(Float64, Float32, 0); + } + } else { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT_COMPAT(int64_t, Float32, 0); + } else { + CFSInt128Struct i; + memmove(&i, data, 16); + Float64 d; + cvtSInt128ToFloat64(&d, &i); + Float32 f = (Float32)d; + memmove(valuePtr, &f, 4); + d = f; + CFSInt128Struct i2; + cvtFloat64ToSInt128(&i2, &d); + return cmp128(&i2, &i) == kCFCompareEqualTo; + } + } + return true; + case kCFNumberFloat64Type: + if (__CFNumberTypeTable[ntype].floatBit) { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT_COMPAT(Float32, Float64, 0); + } else { + memmove(valuePtr, data, 8); + } + } else { + if (0 == __CFNumberTypeTable[ntype].storageBit) { + CVT_COMPAT(int64_t, Float64, 0); + } else { + CFSInt128Struct i; + memmove(&i, data, 16); + Float64 d; + cvtSInt128ToFloat64(&d, &i); + memmove(valuePtr, &d, 8); + CFSInt128Struct i2; + cvtFloat64ToSInt128(&i2, &d); + return cmp128(&i2, &i) == kCFCompareEqualTo; + } + } + return true; + } + return false; +} + +static CFStringRef __CFNumberCopyDescription(CFTypeRef cf) { + CFNumberRef number = (CFNumberRef)cf; + CFNumberType type = __CFNumberGetType(number); + CFMutableStringRef mstr = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); + CFStringAppendFormat(mstr, NULL, CFSTR("{value = "), cf, CFGetAllocator(cf)); + if (__CFNumberTypeTable[type].floatBit) { + Float64 d; + __CFNumberGetValue(number, kCFNumberFloat64Type, &d); + if (isnan(d)) { + CFStringAppend(mstr, CFSTR("nan")); + } else if (isinf(d)) { + CFStringAppend(mstr, (0.0 < d) ? CFSTR("+infinity") : CFSTR("-infinity")); + } else if (0.0 == d) { + CFStringAppend(mstr, (copysign(1.0, d) < 0.0) ? CFSTR("-0.0") : CFSTR("+0.0")); + } else { + CFStringAppendFormat(mstr, NULL, CFSTR("%+.*f"), (__CFNumberTypeTable[type].storageBit ? 20 : 10), d); + } + const char *typeName = "unknown float"; + switch (type) { + case kCFNumberFloat32Type: typeName = "kCFNumberFloat32Type"; break; + case kCFNumberFloat64Type: typeName = "kCFNumberFloat64Type"; break; + } + CFStringAppendFormat(mstr, NULL, CFSTR(", type = %s}"), typeName); + } else { + CFSInt128Struct i; + __CFNumberGetValue(number, kCFNumberSInt128Type, &i); + char buffer[128]; + emit128(buffer, &i, true); + const char *typeName = "unknown integer"; + switch (type) { + case kCFNumberSInt8Type: typeName = "kCFNumberSInt8Type"; break; + case kCFNumberSInt16Type: typeName = "kCFNumberSInt16Type"; break; + case kCFNumberSInt32Type: typeName = "kCFNumberSInt32Type"; break; + case kCFNumberSInt64Type: typeName = "kCFNumberSInt64Type"; break; + case kCFNumberSInt128Type: typeName = "kCFNumberSInt128Type"; break; + } + CFStringAppendFormat(mstr, NULL, CFSTR("%s, type = %s}"), buffer, typeName); + } + return mstr; +} + +// This function separated out from __CFNumberCopyFormattingDescription() so the plist creation can use it as well. + +static CFStringRef __CFNumberCopyFormattingDescriptionAsFloat64_new(CFTypeRef cf) { + Float64 d; + CFNumberGetValue((CFNumberRef)cf, kCFNumberFloat64Type, &d); + if (isnan(d)) { + return (CFStringRef)CFRetain(CFSTR("nan")); + } + if (isinf(d)) { + return (CFStringRef)CFRetain((0.0 < d) ? CFSTR("+infinity") : CFSTR("-infinity")); + } + if (0.0 == d) { + 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); +} + +__private_extern__ CFStringRef __CFNumberCopyFormattingDescriptionAsFloat64(CFTypeRef cf) { + CFStringRef result = __CFNumberCopyFormattingDescriptionAsFloat64_new(cf); + return result; +} + +static CFStringRef __CFNumberCopyFormattingDescription_new(CFTypeRef cf, CFDictionaryRef formatOptions) { + CFNumberRef number = (CFNumberRef)cf; + CFNumberType type = __CFNumberGetType(number); + if (__CFNumberTypeTable[type].floatBit) { + return __CFNumberCopyFormattingDescriptionAsFloat64(number); + } + CFSInt128Struct i; + __CFNumberGetValue(number, kCFNumberSInt128Type, &i); + char buffer[128]; + emit128(buffer, &i, false); + return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%s"), buffer); +} + +static CFStringRef __CFNumberCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { + CFStringRef result = __CFNumberCopyFormattingDescription_new(cf, formatOptions); + return result; +} + + +static Boolean __CFNumberEqual(CFTypeRef cf1, CFTypeRef cf2) { + Boolean b = CFNumberCompare((CFNumberRef)cf1, (CFNumberRef)cf2, 0) == kCFCompareEqualTo; + return b; +} + +static CFHashCode __CFNumberHash(CFTypeRef cf) { + CFHashCode h; + CFNumberRef number = (CFNumberRef)cf; + switch (__CFNumberGetType(number)) { + case kCFNumberSInt8Type: + case kCFNumberSInt16Type: + case kCFNumberSInt32Type: { + SInt32 i; + __CFNumberGetValue(number, kCFNumberSInt32Type, &i); + h = _CFHashInt(i); + break; + } + default: { + Float64 d; + __CFNumberGetValue(number, kCFNumberFloat64Type, &d); + h = _CFHashDouble((double)d); + break; + } + } + return h; +} + +static CFTypeID __kCFNumberTypeID = _kCFRuntimeNotATypeID; + +static const CFRuntimeClass __CFNumberClass = { + 0, + "CFNumber", + NULL, // init + NULL, // copy + NULL, + __CFNumberEqual, + __CFNumberHash, + __CFNumberCopyFormattingDescription, + __CFNumberCopyDescription +}; + +__private_extern__ void __CFNumberInitialize(void) { + __kCFNumberTypeID = _CFRuntimeRegisterClass(&__CFNumberClass); + + _CFRuntimeSetInstanceTypeID(&__kCFNumberNaN, __kCFNumberTypeID); + __kCFNumberNaN._base._cfisa = __CFISAForTypeID(__kCFNumberTypeID); + __CFBitfieldSetValue(__kCFNumberNaN._base._cfinfo[CF_INFO_BITS], 4, 0, kCFNumberFloat64Type); + __kCFNumberNaN._pad = BITSFORDOUBLENAN; + + _CFRuntimeSetInstanceTypeID(& __kCFNumberNegativeInfinity, __kCFNumberTypeID); + __kCFNumberNegativeInfinity._base._cfisa = __CFISAForTypeID(__kCFNumberTypeID); + __CFBitfieldSetValue(__kCFNumberNegativeInfinity._base._cfinfo[CF_INFO_BITS], 4, 0, kCFNumberFloat64Type); + __kCFNumberNegativeInfinity._pad = BITSFORDOUBLENEGINF; + + _CFRuntimeSetInstanceTypeID(& __kCFNumberPositiveInfinity, __kCFNumberTypeID); + __kCFNumberPositiveInfinity._base._cfisa = __CFISAForTypeID(__kCFNumberTypeID); + __CFBitfieldSetValue(__kCFNumberPositiveInfinity._base._cfinfo[CF_INFO_BITS], 4, 0, kCFNumberFloat64Type); + __kCFNumberPositiveInfinity._pad = BITSFORDOUBLEPOSINF; +} + +CFTypeID CFNumberGetTypeID(void) { + return __kCFNumberTypeID; +} + +#define MinCachedInt (-1) +#define MaxCachedInt (12) +#define NotToBeCached (MinCachedInt - 1) +static CFNumberRef __CFNumberCache[MaxCachedInt - MinCachedInt + 1] = {NULL}; // Storing CFNumberRefs for range MinCachedInt..MaxCachedInt + +CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType type, const void *valuePtr) { + __CFAssertIsValidNumberType(type); +//printf("+ [%p] CFNumberCreate(%p, %d, %p)\n", pthread_self(), allocator, type, valuePtr); + + // 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) { + CFNumberRef cached = NULL; + if (0 == __CFNumberTypeTable[type].storageBit) { + Float32 f = *(Float32 *)valuePtr; + if (isnan(f)) cached = kCFNumberNaN; + if (isinf(f)) cached = (f < 0.0) ? kCFNumberNegativeInfinity : kCFNumberPositiveInfinity; + } else { + Float64 d = *(Float64 *)valuePtr; + if (isnan(d)) cached = kCFNumberNaN; + if (isinf(d)) cached = (d < 0.0) ? kCFNumberNegativeInfinity : kCFNumberPositiveInfinity; + } + if (cached) return (CFNumberRef)CFRetain(cached); + } else if (kCFAllocatorSystemDefault == allocator) { + 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;} + case kCFNumberSInt32Type: {int32_t val = *(int32_t *)valuePtr; if (MinCachedInt <= val && val <= MaxCachedInt) valToBeCached = (int64_t)val; break;} + case kCFNumberSInt64Type: {int64_t val = *(int64_t *)valuePtr; if (MinCachedInt <= val && val <= MaxCachedInt) valToBeCached = (int64_t)val; break;} + } + if (NotToBeCached != valToBeCached) { + CFNumberRef cached = __CFNumberCache[valToBeCached - MinCachedInt]; // Atomic to access the value in the cache + if (NULL != cached) return (CFNumberRef)CFRetain(cached); + } + } + + CFIndex size = 8 + ((!__CFNumberTypeTable[type].floatBit && __CFNumberTypeTable[type].storageBit) ? 8 : 0); + CFNumberRef result = (CFNumberRef)_CFRuntimeCreateInstance(allocator, __kCFNumberTypeID, size, NULL); + if (NULL == result) { + return NULL; + } + __CFBitfieldSetValue(((struct __CFNumber *)result)->_base._cfinfo[CF_INFO_BITS], 4, 0, (uint8_t)__CFNumberTypeTable[type].canonicalType); + + + // for a value to be cached, we already have the value handy + if (NotToBeCached != valToBeCached) { + memmove((void *)&result->_pad, &valToBeCached, 8); + // Put this in the cache unless the cache is already filled (by another thread). If we do put it in the cache, retain it an extra time for the cache. + // Note that we don't bother freeing this result and returning the cached value if the cache was filled, since cached CFNumbers are not guaranteed unique. + // Barrier assures that the number that is placed in the cache is properly formed. + CFNumberType origType = __CFNumberGetType(result); + // Force all cached numbers to have the same type, so that the type does not + // depend on the order and original type in/with which the numbers are created. + // Forcing the type AFTER it was cached would cause a race condition with other + // threads pulling the number object out of the cache and using it. + __CFBitfieldSetValue(((struct __CFNumber *)result)->_base._cfinfo[CF_INFO_BITS], 4, 0, (uint8_t)kCFNumberSInt32Type); + if (OSAtomicCompareAndSwapPtrBarrier(NULL, (void *)result, (void *volatile *)&__CFNumberCache[valToBeCached - MinCachedInt])) { + CFRetain(result); + } else { + // Did not cache the number object, put original type back. + __CFBitfieldSetValue(((struct __CFNumber *)result)->_base._cfinfo[CF_INFO_BITS], 4, 0, (uint8_t)origType); + } + return result; + } + + uint64_t value; + switch (__CFNumberTypeTable[type].canonicalType) { + case kCFNumberSInt8Type: value = (uint64_t)(int64_t)*(int8_t *)valuePtr; goto smallVal; + case kCFNumberSInt16Type: value = (uint64_t)(int64_t)*(int16_t *)valuePtr; goto smallVal; + case kCFNumberSInt32Type: value = (uint64_t)(int64_t)*(int32_t *)valuePtr; goto smallVal; + smallVal: memmove((void *)&result->_pad, &value, 8); break; + case kCFNumberSInt64Type: memmove((void *)&result->_pad, valuePtr, 8); break; + case kCFNumberSInt128Type: memmove((void *)&result->_pad, valuePtr, 16); break; + case kCFNumberFloat32Type: memmove((void *)&result->_pad, valuePtr, 4); break; + case kCFNumberFloat64Type: memmove((void *)&result->_pad, valuePtr, 8); break; + } +//printf(" => %p\n", result); + return result; +} + +CFNumberType CFNumberGetType(CFNumberRef number) { +//printf("+ [%p] CFNumberGetType(%p)\n", pthread_self(), number); + CF_OBJC_FUNCDISPATCH0(__kCFNumberTypeID, CFNumberType, number, "_cfNumberType"); + __CFAssertIsNumber(number); + CFNumberType type = __CFNumberGetType(number); + if (kCFNumberSInt128Type == type) type = kCFNumberSInt64Type; // must hide this type, since it is not public +//printf(" => %d\n", type); + return type; +} + +CFNumberType _CFNumberGetType2(CFNumberRef number) { + __CFAssertIsNumber(number); + return __CFNumberGetType(number); +} + +CFIndex CFNumberGetByteSize(CFNumberRef number) { +//printf("+ [%p] CFNumberGetByteSize(%p)\n", pthread_self(), number); + __CFAssertIsNumber(number); + CFIndex r = 1 << __CFNumberTypeTable[CFNumberGetType(number)].lgByteSize; +//printf(" => %d\n", r); + return r; +} + +Boolean CFNumberIsFloatType(CFNumberRef number) { +//printf("+ [%p] CFNumberIsFloatType(%p)\n", pthread_self(), number); + __CFAssertIsNumber(number); + Boolean r = __CFNumberTypeTable[CFNumberGetType(number)].floatBit; +//printf(" => %d\n", r); + return r; +} + +Boolean CFNumberGetValue(CFNumberRef number, CFNumberType type, void *valuePtr) { +//printf("+ [%p] CFNumberGetValue(%p, %d, %p)\n", pthread_self(), number, type, valuePtr); + CF_OBJC_FUNCDISPATCH2(__kCFNumberTypeID, Boolean, number, "_getValue:forType:", valuePtr, __CFNumberTypeTable[type].canonicalType); + __CFAssertIsNumber(number); + __CFAssertIsValidNumberType(type); + uint8_t localMemory[128]; + Boolean r = __CFNumberGetValueCompat(number, type, valuePtr ? valuePtr : localMemory); +//printf(" => %d\n", r); + return r; +} + +static CFComparisonResult CFNumberCompare_new(CFNumberRef number1, CFNumberRef number2, void *context) { + CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID, CFComparisonResult, number1, "compare:", number2); + CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID, CFComparisonResult, number2, "_reverseCompare:", number1); + __CFAssertIsNumber(number1); + __CFAssertIsNumber(number2); + + CFNumberType type1 = __CFNumberGetType(number1); + CFNumberType type2 = __CFNumberGetType(number2); + // Both numbers are integers + if (!__CFNumberTypeTable[type1].floatBit && !__CFNumberTypeTable[type2].floatBit) { + CFSInt128Struct i1, i2; + __CFNumberGetValue(number1, kCFNumberSInt128Type, &i1); + __CFNumberGetValue(number2, kCFNumberSInt128Type, &i2); + return cmp128(&i1, &i2); + } + // Both numbers are floats + if (__CFNumberTypeTable[type1].floatBit && __CFNumberTypeTable[type2].floatBit) { + Float64 d1, d2; + __CFNumberGetValue(number1, kCFNumberFloat64Type, &d1); + __CFNumberGetValue(number2, kCFNumberFloat64Type, &d2); + double s1 = copysign(1.0, d1); + double s2 = copysign(1.0, d2); + if (isnan(d1) && isnan(d2)) return kCFCompareEqualTo; + if (isnan(d1)) return (s2 < 0.0) ? kCFCompareGreaterThan : kCFCompareLessThan; + if (isnan(d2)) return (s1 < 0.0) ? kCFCompareLessThan : kCFCompareGreaterThan; + // at this point, we know we don't have any NaNs + if (s1 < s2) return kCFCompareLessThan; + if (s2 < s1) return kCFCompareGreaterThan; + // at this point, we know the signs are the same; do not combine these tests + if (d1 < d2) return kCFCompareLessThan; + if (d2 < d1) return kCFCompareGreaterThan; + return kCFCompareEqualTo; + } + // One float, one integer; swap if necessary so number1 is the float + Boolean swapResult = false; + if (__CFNumberTypeTable[type2].floatBit) { + CFNumberRef tmp = number1; + number1 = number2; + number2 = tmp; + swapResult = true; + } + // At large integer values, the precision of double is quite low + // e.g. all values roughly 2^127 +- 2^73 are represented by 1 double, 2^127. + // If we just used double compare, that would make the 2^73 largest 128-bit + // integers look equal, so we have to use integer comparison when possible. + Float64 d1, d2; + __CFNumberGetValue(number1, kCFNumberFloat64Type, &d1); + // if the double value is really big, cannot be equal to integer + // nan d1 will not compare true here + if (d1 < FLOAT_NEGATIVE_2_TO_THE_127) { + return !swapResult ? kCFCompareLessThan : kCFCompareGreaterThan; + } + if (FLOAT_POSITIVE_2_TO_THE_127 <= d1) { + return !swapResult ? kCFCompareGreaterThan : kCFCompareLessThan; + } + CFSInt128Struct i1, i2; + __CFNumberGetValue(number1, kCFNumberSInt128Type, &i1); + __CFNumberGetValue(number2, kCFNumberSInt128Type, &i2); + CFComparisonResult res = cmp128(&i1, &i2); + if (kCFCompareEqualTo != res) { + return !swapResult ? res : -res; + } + // now things are equal, but perhaps due to rounding or nan + if (isnan(d1)) { + if (isNeg128(&i2)) { + return !swapResult ? kCFCompareGreaterThan : kCFCompareLessThan; + } + // nan compares less than positive 0 too + return !swapResult ? kCFCompareLessThan : kCFCompareGreaterThan; + } + // at this point, we know we don't have NaN + double s1 = copysign(1.0, d1); + double s2 = isNeg128(&i2) ? -1.0 : 1.0; + if (s1 < s2) return !swapResult ? kCFCompareLessThan : kCFCompareGreaterThan; + if (s2 < s1) return !swapResult ? kCFCompareGreaterThan : kCFCompareLessThan; + // at this point, we know the signs are the same; do not combine these tests + __CFNumberGetValue(number2, kCFNumberFloat64Type, &d2); + if (d1 < d2) return !swapResult ? kCFCompareLessThan : kCFCompareGreaterThan; + if (d2 < d1) return !swapResult ? kCFCompareGreaterThan : kCFCompareLessThan; + return kCFCompareEqualTo; +} + +CFComparisonResult CFNumberCompare(CFNumberRef number1, CFNumberRef number2, void *context) { +//printf("+ [%p] CFNumberCompare(%p, %p, %p)\n", pthread_self(), number1, number2, context); + CFComparisonResult r = CFNumberCompare_new(number1, number2, context); +//printf(" => %d\n", r); + return r; +} + +#undef __CFAssertIsBoolean +#undef __CFAssertIsNumber +#undef __CFAssertIsValidNumberType +#undef BITSFORDOUBLENAN +#undef BITSFORDOUBLEPOSINF +#undef BITSFORDOUBLENEGINF +#undef MinCachedInt +#undef MaxCachedInt +#undef NotToBeCached + diff --git a/NumberDate.subproj/CFNumber.h b/CFNumber.h similarity index 92% rename from NumberDate.subproj/CFNumber.h rename to CFNumber.h index e6c7437..55e9001 100644 --- a/NumberDate.subproj/CFNumber.h +++ b/CFNumber.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFNumber.h - Copyright (c) 1999-2005, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFNUMBER__) @@ -29,9 +29,7 @@ #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN typedef const struct __CFBoolean * CFBooleanRef; @@ -46,8 +44,8 @@ CFTypeID CFBooleanGetTypeID(void); CF_EXPORT Boolean CFBooleanGetValue(CFBooleanRef boolean); -typedef enum { - /* Types from MacTypes.h */ +enum { + /* Fixed-width types */ kCFNumberSInt8Type = 1, kCFNumberSInt16Type = 2, kCFNumberSInt32Type = 3, @@ -64,8 +62,15 @@ typedef enum { kCFNumberDoubleType = 13, /* Other */ kCFNumberCFIndexType = 14, +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + kCFNumberNSIntegerType = 15, + kCFNumberCGFloatType = 16, + kCFNumberMaxType = 16 +#else kCFNumberMaxType = 14 -} CFNumberType; +#endif +}; +typedef CFIndex CFNumberType; typedef const struct __CFNumber * CFNumberRef; @@ -138,9 +143,7 @@ Boolean CFNumberGetValue(CFNumberRef number, CFNumberType theType, void *valuePt CF_EXPORT CFComparisonResult CFNumberCompare(CFNumberRef number, CFNumberRef otherNumber, void *context); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFNUMBER__ */ diff --git a/CFNumberFormatter.c b/CFNumberFormatter.c new file mode 100644 index 0000000..12e2a63 --- /dev/null +++ b/CFNumberFormatter.c @@ -0,0 +1,981 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFNumberFormatter.c + Copyright 2002-2003, Apple, Inc. All rights reserved. + Responsibility: Christopher Kane +*/ + +#include +#include "CFInternal.h" +#include +#include +#include +#include + +static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter); + +#define BUFFER_SIZE 768 + +struct __CFNumberFormatter { + CFRuntimeBase _base; + UNumberFormat *_nf; + CFLocaleRef _locale; + CFNumberFormatterStyle _style; + CFStringRef _format; // NULL for RBNFs + CFStringRef _defformat; + CFNumberRef _multiplier; + CFStringRef _zeroSym; +}; + +static CFStringRef __CFNumberFormatterCopyDescription(CFTypeRef cf) { + CFNumberFormatterRef formatter = (CFNumberFormatterRef)cf; + return CFStringCreateWithFormat(CFGetAllocator(formatter), NULL, CFSTR(""), cf, CFGetAllocator(formatter)); +} + +static void __CFNumberFormatterDeallocate(CFTypeRef cf) { + CFNumberFormatterRef formatter = (CFNumberFormatterRef)cf; + if (formatter->_nf) unum_close(formatter->_nf); + if (formatter->_locale) CFRelease(formatter->_locale); + if (formatter->_format) CFRelease(formatter->_format); + if (formatter->_defformat) CFRelease(formatter->_defformat); + if (formatter->_multiplier) CFRelease(formatter->_multiplier); + if (formatter->_zeroSym) CFRelease(formatter->_zeroSym); +} + +static CFTypeID __kCFNumberFormatterTypeID = _kCFRuntimeNotATypeID; + +static const CFRuntimeClass __CFNumberFormatterClass = { + 0, + "CFNumberFormatter", + NULL, // init + NULL, // copy + __CFNumberFormatterDeallocate, + NULL, + NULL, + NULL, // + __CFNumberFormatterCopyDescription +}; + +static void __CFNumberFormatterInitialize(void) { + __kCFNumberFormatterTypeID = _CFRuntimeRegisterClass(&__CFNumberFormatterClass); +} + +CFTypeID CFNumberFormatterGetTypeID(void) { + if (_kCFRuntimeNotATypeID == __kCFNumberFormatterTypeID) __CFNumberFormatterInitialize(); + return __kCFNumberFormatterTypeID; +} + +CFNumberFormatterRef CFNumberFormatterCreate(CFAllocatorRef allocator, CFLocaleRef locale, CFNumberFormatterStyle style) { + struct __CFNumberFormatter *memory; + uint32_t size = sizeof(struct __CFNumberFormatter) - sizeof(CFRuntimeBase); + if (allocator == NULL) allocator = __CFGetDefaultAllocator(); + __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); + __CFGenericValidateType(locale, CFLocaleGetTypeID()); + memory = (struct __CFNumberFormatter *)_CFRuntimeCreateInstance(allocator, CFNumberFormatterGetTypeID(), size, NULL); + if (NULL == memory) { + return NULL; + } + memory->_nf = NULL; + memory->_locale = NULL; + memory->_format = NULL; + memory->_defformat = NULL; + memory->_multiplier = NULL; + memory->_zeroSym = NULL; + if (NULL == locale) locale = CFLocaleGetSystem(); + memory->_style = style; + uint32_t ustyle; + switch (style) { + case kCFNumberFormatterNoStyle: ustyle = UNUM_IGNORE; break; + case kCFNumberFormatterDecimalStyle: ustyle = UNUM_DECIMAL; break; + case kCFNumberFormatterCurrencyStyle: ustyle = UNUM_CURRENCY; break; + case kCFNumberFormatterPercentStyle: ustyle = UNUM_PERCENT; break; + case kCFNumberFormatterScientificStyle: ustyle = UNUM_SCIENTIFIC; break; + case kCFNumberFormatterSpellOutStyle: ustyle = UNUM_SPELLOUT; break; + default: + CFAssert2(0, __kCFLogAssertion, "%s(): unknown style %d", __PRETTY_FUNCTION__, style); + ustyle = UNUM_DECIMAL; + memory->_style = kCFNumberFormatterDecimalStyle; + break; + } + CFStringRef localeName = locale ? CFLocaleGetIdentifier(locale) : CFSTR(""); + char buffer[BUFFER_SIZE]; + const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII); + if (NULL == cstr) { + if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer; + } + if (NULL == cstr) { + CFRelease(memory); + return NULL; + } + UErrorCode status = U_ZERO_ERROR; + memory->_nf = unum_open((UNumberFormatStyle)ustyle, NULL, 0, cstr, NULL, &status); + CFAssert2(memory->_nf, __kCFLogAssertion, "%s(): error (%d) creating number formatter", __PRETTY_FUNCTION__, status); + if (NULL == memory->_nf) { + CFRelease(memory); + return NULL; + } + UChar ubuff[4]; + if (kCFNumberFormatterNoStyle == style) { + status = U_ZERO_ERROR; + ubuff[0] = '#'; ubuff[1] = ';'; ubuff[2] = '#'; + unum_applyPattern(memory->_nf, false, ubuff, 3, NULL, &status); + unum_setAttribute(memory->_nf, UNUM_MAX_INTEGER_DIGITS, 42); + unum_setAttribute(memory->_nf, UNUM_MAX_FRACTION_DIGITS, 0); + } + memory->_locale = locale ? CFLocaleCreateCopy(allocator, locale) : CFLocaleGetSystem(); + __CFNumberFormatterCustomize(memory); + if (kCFNumberFormatterSpellOutStyle != memory->_style) { + UChar ubuffer[BUFFER_SIZE]; + status = U_ZERO_ERROR; + int32_t ret = unum_toPattern(memory->_nf, false, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && ret <= BUFFER_SIZE) { + memory->_format = CFStringCreateWithCharacters(allocator, (const UniChar *)ubuffer, ret); + } + } + memory->_defformat = memory->_format ? (CFStringRef)CFRetain(memory->_format) : NULL; + if (kCFNumberFormatterSpellOutStyle != memory->_style) { + int32_t n = unum_getAttribute(memory->_nf, UNUM_MULTIPLIER); + if (1 != n) { + memory->_multiplier = CFNumberCreate(allocator, kCFNumberSInt32Type, &n); + unum_setAttribute(memory->_nf, UNUM_MULTIPLIER, 1); + } + } + return (CFNumberFormatterRef)memory; +} + +extern CFDictionaryRef __CFLocaleGetPrefs(CFLocaleRef locale); + +static void __substituteFormatStringFromPrefsNF(CFNumberFormatterRef formatter) { + CFIndex formatStyle = formatter->_style; + if (kCFNumberFormatterSpellOutStyle == formatStyle) return; + CFStringRef prefName = CFSTR("AppleICUNumberFormatStrings"); + if (kCFNumberFormatterNoStyle != formatStyle) { + CFStringRef pref = NULL; + CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale); + CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, prefName) : NULL; + if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) { + CFStringRef key; + switch (formatStyle) { + case kCFNumberFormatterDecimalStyle: key = CFSTR("1"); break; + case kCFNumberFormatterCurrencyStyle: key = CFSTR("2"); break; + case kCFNumberFormatterPercentStyle: key = CFSTR("3"); break; + case kCFNumberFormatterScientificStyle: key = CFSTR("4"); break; + case kCFNumberFormatterSpellOutStyle: key = CFSTR("5"); break; + default: key = CFSTR("0"); break; + } + pref = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)metapref, key); + } + if (NULL != pref && CFGetTypeID(pref) == CFStringGetTypeID()) { + int32_t icustyle = UNUM_IGNORE; + switch (formatStyle) { + case kCFNumberFormatterDecimalStyle: icustyle = UNUM_DECIMAL; break; + case kCFNumberFormatterCurrencyStyle: icustyle = UNUM_CURRENCY; break; + case kCFNumberFormatterPercentStyle: icustyle = UNUM_PERCENT; break; + case kCFNumberFormatterScientificStyle: icustyle = UNUM_SCIENTIFIC; break; + case kCFNumberFormatterSpellOutStyle: icustyle = UNUM_SPELLOUT; break; + } + CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale); + char buffer[BUFFER_SIZE]; + const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII); + if (NULL == cstr) { + if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer; + } + UErrorCode status = U_ZERO_ERROR; + UNumberFormat *nf = unum_open((UNumberFormatStyle)icustyle, NULL, 0, cstr, NULL, &status); + if (NULL != nf) { + UChar ubuffer[BUFFER_SIZE]; + status = U_ZERO_ERROR; + int32_t number_len = unum_toPattern(nf, false, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && number_len <= BUFFER_SIZE) { + CFStringRef numberString = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, (const UniChar *)ubuffer, number_len); + status = U_ZERO_ERROR; + int32_t formatter_len = unum_toPattern(formatter->_nf, false, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && formatter_len <= BUFFER_SIZE) { + CFMutableStringRef formatString = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); + CFStringAppendCharacters(formatString, (const UniChar *)ubuffer, formatter_len); + // find numberString inside formatString, substitute the pref in that range + CFRange result; + if (CFStringFindWithOptions(formatString, numberString, CFRangeMake(0, formatter_len), 0, &result)) { + CFStringReplace(formatString, result, pref); + int32_t new_len = CFStringGetLength(formatString); + STACK_BUFFER_DECL(UChar, new_buffer, new_len); + const UChar *new_ustr = (const UChar *)CFStringGetCharactersPtr(formatString); + if (NULL == new_ustr) { + CFStringGetCharacters(formatString, CFRangeMake(0, new_len), (UniChar *)new_buffer); + new_ustr = new_buffer; + } + status = U_ZERO_ERROR; + unum_applyPattern(formatter->_nf, false, new_ustr, new_len, NULL, &status); + } + CFRelease(formatString); + } + CFRelease(numberString); + } + unum_close(nf); + } + } + } +} + +static void __CFNumberFormatterApplySymbolPrefs(const void *key, const void *value, void *context) { + if (CFGetTypeID(key) == CFStringGetTypeID() && CFGetTypeID(value) == CFStringGetTypeID()) { + CFNumberFormatterRef formatter = (CFNumberFormatterRef)context; + UNumberFormatSymbol sym = (UNumberFormatSymbol)CFStringGetIntValue((CFStringRef)key); + CFStringRef item = (CFStringRef)value; + CFIndex item_cnt = CFStringGetLength(item); + STACK_BUFFER_DECL(UChar, item_buffer, item_cnt); + UChar *item_ustr = (UChar *)CFStringGetCharactersPtr(item); + if (NULL == item_ustr) { + CFStringGetCharacters(item, CFRangeMake(0, __CFMin(BUFFER_SIZE, item_cnt)), (UniChar *)item_buffer); + item_ustr = item_buffer; + } + UErrorCode status = U_ZERO_ERROR; + unum_setSymbol(formatter->_nf, sym, item_ustr, item_cnt, &status); + } +} + +static void __CFNumberFormatterCustomize(CFNumberFormatterRef formatter) { + __substituteFormatStringFromPrefsNF(formatter); + CFDictionaryRef prefs = __CFLocaleGetPrefs(formatter->_locale); + CFPropertyListRef metapref = prefs ? CFDictionaryGetValue(prefs, CFSTR("AppleICUNumberSymbols")) : NULL; + if (NULL != metapref && CFGetTypeID(metapref) == CFDictionaryGetTypeID()) { + CFDictionaryApplyFunction((CFDictionaryRef)metapref, __CFNumberFormatterApplySymbolPrefs, formatter); + } +} + +CFLocaleRef CFNumberFormatterGetLocale(CFNumberFormatterRef formatter) { + __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID()); + return formatter->_locale; +} + +CFNumberFormatterStyle CFNumberFormatterGetStyle(CFNumberFormatterRef formatter) { + __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID()); + return formatter->_style; +} + +CFStringRef CFNumberFormatterGetFormat(CFNumberFormatterRef formatter) { + __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID()); + if (kCFNumberFormatterSpellOutStyle == formatter->_style) return NULL; + UChar ubuffer[BUFFER_SIZE]; + CFStringRef newString = NULL; + UErrorCode status = U_ZERO_ERROR; + int32_t ret = unum_toPattern(formatter->_nf, false, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && ret <= BUFFER_SIZE) { + newString = CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, ret); + } + if (newString && !formatter->_format) { + formatter->_format = newString; + } else if (newString && !CFEqual(newString, formatter->_format)) { + CFRelease(formatter->_format); + formatter->_format = newString; + } else if (newString) { + CFRelease(newString); + } + return formatter->_format; +} + +void CFNumberFormatterSetFormat(CFNumberFormatterRef formatter, CFStringRef formatString) { + __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID()); + __CFGenericValidateType(formatString, CFStringGetTypeID()); + if (kCFNumberFormatterSpellOutStyle == 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) { + STACK_BUFFER_DECL(UChar, ubuffer, cnt); + const UChar *ustr = (const UChar *)CFStringGetCharactersPtr(formatString); + if (NULL == ustr) { + CFStringGetCharacters(formatString, CFRangeMake(0, cnt), (UniChar *)ubuffer); + ustr = ubuffer; + } + UErrorCode status = U_ZERO_ERROR; + unum_applyPattern(formatter->_nf, false, ustr, cnt, NULL, &status); + if (U_SUCCESS(status)) { + if (formatter->_format) CFRelease(formatter->_format); + UChar ubuffer2[BUFFER_SIZE]; + status = U_ZERO_ERROR; + int32_t ret = unum_toPattern(formatter->_nf, false, ubuffer2, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && ret <= BUFFER_SIZE) { + formatter->_format = CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer2, ret); + } + } + } +} + +CFStringRef CFNumberFormatterCreateStringWithNumber(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberRef number) { + if (allocator == NULL) allocator = __CFGetDefaultAllocator(); + __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); + __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID()); + __CFGenericValidateType(number, CFNumberGetTypeID()); + CFNumberType type = CFNumberGetType(number); + char buffer[64]; + CFNumberGetValue(number, type, buffer); + return CFNumberFormatterCreateStringWithValue(allocator, formatter, type, buffer); +} + +#define FORMAT(T, FUNC) \ + T value = *(T *)valuePtr; \ + if (0 == value && formatter->_zeroSym) { return (CFStringRef)CFRetain(formatter->_zeroSym); } \ + if (1.0 != multiplier) value = (T)(value * multiplier); \ + status = U_ZERO_ERROR; \ + used = FUNC(formatter->_nf, value, ubuffer, cnt, NULL, &status); \ + if (status == U_BUFFER_OVERFLOW_ERROR || cnt < used) { \ + cnt = used + 1; \ + ustr = (UChar *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UChar) * cnt, 0); \ + status = U_ZERO_ERROR; \ + used = FUNC(formatter->_nf, value, ustr, cnt, NULL, &status); \ + } + +CFStringRef CFNumberFormatterCreateStringWithValue(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberType numberType, const void *valuePtr) { + if (allocator == NULL) allocator = __CFGetDefaultAllocator(); + __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); + __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID()); + double multiplier = 1.0; + if (formatter->_multiplier) { + if (!CFNumberGetValue(formatter->_multiplier, kCFNumberFloat64Type, &multiplier)) { + multiplier = 1.0; + } + } + UChar *ustr = NULL, ubuffer[BUFFER_SIZE]; + UErrorCode status = U_ZERO_ERROR; + CFIndex used, cnt = BUFFER_SIZE; + if (numberType == kCFNumberFloat64Type || numberType == kCFNumberDoubleType) { + FORMAT(double, unum_formatDouble) + } else if (numberType == kCFNumberFloat32Type || numberType == kCFNumberFloatType) { + FORMAT(float, unum_formatDouble) + } else if (numberType == kCFNumberSInt64Type || numberType == kCFNumberLongLongType) { + FORMAT(int64_t, unum_formatInt64) + } else if (numberType == kCFNumberLongType || numberType == kCFNumberCFIndexType) { +#if __LP64__ + FORMAT(int64_t, unum_formatInt64) +#else + FORMAT(int32_t, unum_formatInt64) +#endif + } else if (numberType == kCFNumberSInt32Type || numberType == kCFNumberIntType) { + FORMAT(int32_t, unum_formatInt64) + } else if (numberType == kCFNumberSInt16Type || numberType == kCFNumberShortType) { + FORMAT(int16_t, unum_formatInt64) + } else if (numberType == kCFNumberSInt8Type || numberType == kCFNumberCharType) { + FORMAT(int8_t, unum_formatInt64) + } else { + CFAssert2(0, __kCFLogAssertion, "%s(): unknown CFNumberType (%d)", __PRETTY_FUNCTION__, numberType); + return NULL; + } + CFStringRef string = NULL; + if (U_SUCCESS(status)) { + string = CFStringCreateWithCharacters(allocator, ustr ? (const UniChar *)ustr : (const UniChar *)ubuffer, used); + } + if (ustr) CFAllocatorDeallocate(kCFAllocatorSystemDefault, ustr); + return string; +} + +#undef FORMAT + +CFNumberRef CFNumberFormatterCreateNumberFromString(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFStringRef string, CFRange *rangep, CFOptionFlags options) { + if (allocator == NULL) allocator = __CFGetDefaultAllocator(); + __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); + __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID()); + __CFGenericValidateType(string, CFStringGetTypeID()); + CFNumberType type = (options & kCFNumberFormatterParseIntegersOnly) ? kCFNumberSInt64Type : kCFNumberFloat64Type; + char buffer[16]; + if (CFNumberFormatterGetValueFromString(formatter, string, rangep, type, buffer)) { + return CFNumberCreate(allocator, type, buffer); + } + return NULL; +} + +Boolean CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter, CFStringRef string, CFRange *rangep, CFNumberType numberType, void *valuePtr) { + __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID()); + __CFGenericValidateType(string, CFStringGetTypeID()); + Boolean isZero = false; + CFRange range = {0, 0}; + if (rangep) { + range = *rangep; + } else { + range.length = CFStringGetLength(string); + } + if (formatter->_zeroSym && kCFCompareEqualTo == CFStringCompareWithOptions(string, formatter->_zeroSym, range, 0)) { + isZero = true; + } + if (1024 < range.length) range.length = 1024; + const UChar *ustr = (const UChar *)CFStringGetCharactersPtr(string); + STACK_BUFFER_DECL(UChar, ubuffer, (NULL == ustr) ? range.length : 1); + if (NULL == ustr) { + CFStringGetCharacters(string, range, (UniChar *)ubuffer); + ustr = ubuffer; + } else { + ustr += range.location; + } + Boolean integerOnly = 1; + switch (numberType) { + case kCFNumberSInt8Type: case kCFNumberCharType: + case kCFNumberSInt16Type: case kCFNumberShortType: + case kCFNumberSInt32Type: case kCFNumberIntType: + case kCFNumberLongType: case kCFNumberCFIndexType: + case kCFNumberSInt64Type: case kCFNumberLongLongType: + unum_setAttribute(formatter->_nf, UNUM_PARSE_INT_ONLY, 1); + break; + default: + unum_setAttribute(formatter->_nf, UNUM_PARSE_INT_ONLY, 0); + integerOnly = 0; + break; + } + int32_t dpos = 0; + UErrorCode status = U_ZERO_ERROR; + int64_t dreti = 0; + double dretd = 0.0; + if (isZero) { + dpos = rangep ? rangep->length : 0; + } else { + if (integerOnly) { + dreti = unum_parseInt64(formatter->_nf, ustr, range.length, &dpos, &status); + } else { + dretd = unum_parseDouble(formatter->_nf, ustr, range.length, &dpos, &status); + } + } + if (rangep) rangep->length = dpos; + if (U_FAILURE(status)) { + return false; + } + if (formatter->_multiplier) { + double multiplier = 1.0; + if (!CFNumberGetValue(formatter->_multiplier, kCFNumberFloat64Type, &multiplier)) { + multiplier = 1.0; + } + dreti = (int64_t)((double)dreti / multiplier); // integer truncation + dretd = dretd / multiplier; + } + switch (numberType) { + case kCFNumberSInt8Type: case kCFNumberCharType: + if (INT8_MIN <= dreti && dreti <= INT8_MAX) { + *(int8_t *)valuePtr = (int8_t)dreti; + return true; + } + break; + case kCFNumberSInt16Type: case kCFNumberShortType: + if (INT16_MIN <= dreti && dreti <= INT16_MAX) { + *(int16_t *)valuePtr = (int16_t)dreti; + return true; + } + break; + case kCFNumberSInt32Type: case kCFNumberIntType: +#if !__LP64__ + case kCFNumberLongType: case kCFNumberCFIndexType: +#endif + if (INT32_MIN <= dreti && dreti <= INT32_MAX) { + *(int32_t *)valuePtr = (int32_t)dreti; + return true; + } + break; + case kCFNumberSInt64Type: case kCFNumberLongLongType: +#if __LP64__ + case kCFNumberLongType: case kCFNumberCFIndexType: +#endif + if (INT64_MIN <= dreti && dreti <= INT64_MAX) { + *(int64_t *)valuePtr = (int64_t)dreti; + return true; + } + break; + case kCFNumberFloat32Type: case kCFNumberFloatType: + if (-FLT_MAX <= dretd && dretd <= FLT_MAX) { + *(float *)valuePtr = (float)dretd; + return true; + } + break; + case kCFNumberFloat64Type: case kCFNumberDoubleType: + if (-DBL_MAX <= dretd && dretd <= DBL_MAX) { + *(double *)valuePtr = (double)dretd; + return true; + } + break; + } + return false; +} + +void CFNumberFormatterSetProperty(CFNumberFormatterRef formatter, CFStringRef key, CFTypeRef value) { + int32_t n; + double d; + UErrorCode status = U_ZERO_ERROR; + UChar ubuffer[BUFFER_SIZE]; + CFIndex cnt; + __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID()); + __CFGenericValidateType(key, CFStringGetTypeID()); + if (kCFNumberFormatterCurrencyCode == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setTextAttribute(formatter->_nf, UNUM_CURRENCY_CODE, ubuffer, cnt, &status); + } else if (kCFNumberFormatterDecimalSeparator == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setSymbol(formatter->_nf, UNUM_DECIMAL_SEPARATOR_SYMBOL, ubuffer, cnt, &status); + } else if (kCFNumberFormatterCurrencyDecimalSeparator == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setSymbol(formatter->_nf, UNUM_MONETARY_SEPARATOR_SYMBOL, ubuffer, cnt, &status); + } else if (kCFNumberFormatterAlwaysShowDecimalSeparator == key) { + __CFGenericValidateType(value, CFBooleanGetTypeID()); + unum_setAttribute(formatter->_nf, UNUM_DECIMAL_ALWAYS_SHOWN, (kCFBooleanTrue == value)); + } else if (kCFNumberFormatterGroupingSeparator == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setSymbol(formatter->_nf, UNUM_GROUPING_SEPARATOR_SYMBOL, (const UChar *)ubuffer, cnt, &status); + } else if (kCFNumberFormatterUseGroupingSeparator == key) { + __CFGenericValidateType(value, CFBooleanGetTypeID()); + unum_setAttribute(formatter->_nf, UNUM_GROUPING_USED, (kCFBooleanTrue == value)); + } else if (kCFNumberFormatterPercentSymbol == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setSymbol(formatter->_nf, UNUM_PERCENT_SYMBOL, ubuffer, cnt, &status); + } else if (kCFNumberFormatterZeroSymbol == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + CFStringRef old = formatter->_zeroSym; + formatter->_zeroSym = value ? (CFStringRef)CFRetain(value) : NULL; + if (old) CFRelease(old); + } else if (kCFNumberFormatterNaNSymbol == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setSymbol(formatter->_nf, UNUM_NAN_SYMBOL, ubuffer, cnt, &status); + } else if (kCFNumberFormatterInfinitySymbol == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setSymbol(formatter->_nf, UNUM_INFINITY_SYMBOL, ubuffer, cnt, &status); + } else if (kCFNumberFormatterMinusSign == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setSymbol(formatter->_nf, UNUM_MINUS_SIGN_SYMBOL, ubuffer, cnt, &status); + } else if (kCFNumberFormatterPlusSign == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setSymbol(formatter->_nf, UNUM_PLUS_SIGN_SYMBOL, ubuffer, cnt, &status); + } else if (kCFNumberFormatterCurrencySymbol == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setSymbol(formatter->_nf, UNUM_CURRENCY_SYMBOL, (const UChar *)ubuffer, cnt, &status); + } else if (kCFNumberFormatterExponentSymbol == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setSymbol(formatter->_nf, UNUM_EXPONENTIAL_SYMBOL, ubuffer, cnt, &status); + } else if (kCFNumberFormatterMinIntegerDigits == key) { + __CFGenericValidateType(value, CFNumberGetTypeID()); + CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n); + unum_setAttribute(formatter->_nf, UNUM_MIN_INTEGER_DIGITS, n); + } else if (kCFNumberFormatterMaxIntegerDigits == key) { + __CFGenericValidateType(value, CFNumberGetTypeID()); + CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n); + unum_setAttribute(formatter->_nf, UNUM_MAX_INTEGER_DIGITS, n); + } else if (kCFNumberFormatterMinFractionDigits == key) { + __CFGenericValidateType(value, CFNumberGetTypeID()); + CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n); + unum_setAttribute(formatter->_nf, UNUM_MIN_FRACTION_DIGITS, n); + } else if (kCFNumberFormatterMaxFractionDigits == key) { + __CFGenericValidateType(value, CFNumberGetTypeID()); + CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n); + unum_setAttribute(formatter->_nf, UNUM_MAX_FRACTION_DIGITS, n); + } else if (kCFNumberFormatterGroupingSize == key) { + __CFGenericValidateType(value, CFNumberGetTypeID()); + CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n); + unum_setAttribute(formatter->_nf, UNUM_GROUPING_SIZE, n); + } else if (kCFNumberFormatterSecondaryGroupingSize == key) { + __CFGenericValidateType(value, CFNumberGetTypeID()); + CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n); + unum_setAttribute(formatter->_nf, UNUM_SECONDARY_GROUPING_SIZE, n); + } else if (kCFNumberFormatterRoundingMode == key) { + __CFGenericValidateType(value, CFNumberGetTypeID()); + CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n); + unum_setAttribute(formatter->_nf, UNUM_ROUNDING_MODE, n); + } else if (kCFNumberFormatterRoundingIncrement == key) { + __CFGenericValidateType(value, CFNumberGetTypeID()); + CFNumberGetValue((CFNumberRef)value, kCFNumberDoubleType, &d); + unum_setDoubleAttribute(formatter->_nf, UNUM_ROUNDING_INCREMENT, d); + } else if (kCFNumberFormatterFormatWidth == key) { + __CFGenericValidateType(value, CFNumberGetTypeID()); + CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n); + unum_setAttribute(formatter->_nf, UNUM_FORMAT_WIDTH, n); + } else if (kCFNumberFormatterPaddingPosition == key) { + __CFGenericValidateType(value, CFNumberGetTypeID()); + CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n); + unum_setAttribute(formatter->_nf, UNUM_PADDING_POSITION, n); + } else if (kCFNumberFormatterPaddingCharacter == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setTextAttribute(formatter->_nf, UNUM_PADDING_CHARACTER, ubuffer, cnt, &status); + } else if (kCFNumberFormatterDefaultFormat == key) { + // read-only attribute + } else if (kCFNumberFormatterMultiplier == key) { + __CFGenericValidateType(value, CFNumberGetTypeID()); + CFNumberRef old = formatter->_multiplier; + formatter->_multiplier = value ? (CFNumberRef)CFRetain(value) : NULL; + if (old) CFRelease(old); + } else if (kCFNumberFormatterPositivePrefix == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setTextAttribute(formatter->_nf, UNUM_POSITIVE_PREFIX, ubuffer, cnt, &status); + } else if (kCFNumberFormatterPositiveSuffix == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setTextAttribute(formatter->_nf, UNUM_POSITIVE_SUFFIX, (const UChar *)ubuffer, cnt, &status); + } else if (kCFNumberFormatterNegativePrefix == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setTextAttribute(formatter->_nf, UNUM_NEGATIVE_PREFIX, ubuffer, cnt, &status); + } else if (kCFNumberFormatterNegativeSuffix == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setTextAttribute(formatter->_nf, UNUM_NEGATIVE_SUFFIX, (const UChar *)ubuffer, cnt, &status); + } else if (kCFNumberFormatterPerMillSymbol == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setSymbol(formatter->_nf, UNUM_PERMILL_SYMBOL, ubuffer, cnt, &status); + } else if (kCFNumberFormatterInternationalCurrencySymbol == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setSymbol(formatter->_nf, UNUM_INTL_CURRENCY_SYMBOL, ubuffer, cnt, &status); + } else if (kCFNumberFormatterCurrencyGroupingSeparator == key) { + __CFGenericValidateType(value, CFStringGetTypeID()); + cnt = CFStringGetLength((CFStringRef)value); + if (BUFFER_SIZE < cnt) cnt = BUFFER_SIZE; + CFStringGetCharacters((CFStringRef)value, CFRangeMake(0, cnt), (UniChar *)ubuffer); + unum_setSymbol(formatter->_nf, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, ubuffer, cnt, &status); + } else if (kCFNumberFormatterIsLenient == key) { + __CFGenericValidateType(value, CFBooleanGetTypeID()); + unum_setAttribute(formatter->_nf, UNUM_LENIENT_PARSE, (kCFBooleanTrue == value)); + } else if (kCFNumberFormatterUseSignificantDigits == key) { + __CFGenericValidateType(value, CFBooleanGetTypeID()); + unum_setAttribute(formatter->_nf, UNUM_SIGNIFICANT_DIGITS_USED, (kCFBooleanTrue == value)); + } else if (kCFNumberFormatterMinSignificantDigits == key) { + __CFGenericValidateType(value, CFNumberGetTypeID()); + CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n); + unum_setAttribute(formatter->_nf, UNUM_MIN_SIGNIFICANT_DIGITS, n); + } else if (kCFNumberFormatterMaxSignificantDigits == key) { + __CFGenericValidateType(value, CFNumberGetTypeID()); + CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &n); + unum_setAttribute(formatter->_nf, UNUM_MAX_SIGNIFICANT_DIGITS, n); + } else { + CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key); + } +} + +CFTypeRef CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter, CFStringRef key) { + int32_t n; + double d; + UErrorCode status = U_ZERO_ERROR; + UChar ubuffer[BUFFER_SIZE]; + CFIndex cnt; + __CFGenericValidateType(formatter, CFNumberFormatterGetTypeID()); + __CFGenericValidateType(key, CFStringGetTypeID()); + if (kCFNumberFormatterCurrencyCode == key) { + cnt = unum_getTextAttribute(formatter->_nf, UNUM_CURRENCY_CODE, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt == 0) { + CFStringRef localeName = CFLocaleGetIdentifier(formatter->_locale); + char buffer[BUFFER_SIZE]; + const char *cstr = CFStringGetCStringPtr(localeName, kCFStringEncodingASCII); + if (NULL == cstr) { + if (CFStringGetCString(localeName, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer; + } + if (NULL == cstr) { + return NULL; + } + UErrorCode status = U_ZERO_ERROR; + UNumberFormat *nf = unum_open(UNUM_CURRENCY, NULL, 0, cstr, NULL, &status); + if (NULL != nf) { + cnt = unum_getTextAttribute(nf, UNUM_CURRENCY_CODE, ubuffer, BUFFER_SIZE, &status); + unum_close(nf); + } + } + if (U_SUCCESS(status) && 0 < cnt && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterDecimalSeparator == key) { + cnt = unum_getSymbol(formatter->_nf, UNUM_DECIMAL_SEPARATOR_SYMBOL, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterCurrencyDecimalSeparator == key) { + cnt = unum_getSymbol(formatter->_nf, UNUM_MONETARY_SEPARATOR_SYMBOL, (UChar *)ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterAlwaysShowDecimalSeparator == key) { + n = unum_getAttribute(formatter->_nf, UNUM_DECIMAL_ALWAYS_SHOWN); + if (1) { + return CFRetain(n ? kCFBooleanTrue : kCFBooleanFalse); + } + } else if (kCFNumberFormatterGroupingSeparator == key) { + cnt = unum_getSymbol(formatter->_nf, UNUM_GROUPING_SEPARATOR_SYMBOL, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterUseGroupingSeparator == key) { + n = unum_getAttribute(formatter->_nf, UNUM_GROUPING_USED); + if (1) { + return CFRetain(n ? kCFBooleanTrue : kCFBooleanFalse); + } + } else if (kCFNumberFormatterPercentSymbol == key) { + cnt = unum_getSymbol(formatter->_nf, UNUM_PERCENT_SYMBOL, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterZeroSymbol == key) { + return formatter->_zeroSym ? CFRetain(formatter->_zeroSym) : NULL; + } else if (kCFNumberFormatterNaNSymbol == key) { + cnt = unum_getSymbol(formatter->_nf, UNUM_NAN_SYMBOL, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterInfinitySymbol == key) { + cnt = unum_getSymbol(formatter->_nf, UNUM_INFINITY_SYMBOL, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterMinusSign == key) { + cnt = unum_getSymbol(formatter->_nf, UNUM_MINUS_SIGN_SYMBOL, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterPlusSign == key) { + cnt = unum_getSymbol(formatter->_nf, UNUM_PLUS_SIGN_SYMBOL, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterCurrencySymbol == key) { + cnt = unum_getSymbol(formatter->_nf, UNUM_CURRENCY_SYMBOL, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterExponentSymbol == key) { + cnt = unum_getSymbol(formatter->_nf, UNUM_EXPONENTIAL_SYMBOL, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterMinIntegerDigits == key) { + n = unum_getAttribute(formatter->_nf, UNUM_MIN_INTEGER_DIGITS); + if (1) { + return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n); + } + } else if (kCFNumberFormatterMaxIntegerDigits == key) { + n = unum_getAttribute(formatter->_nf, UNUM_MAX_INTEGER_DIGITS); + if (1) { + return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n); + } + } else if (kCFNumberFormatterMinFractionDigits == key) { + n = unum_getAttribute(formatter->_nf, UNUM_MIN_FRACTION_DIGITS); + if (1) { + return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n); + } + } else if (kCFNumberFormatterMaxFractionDigits == key) { + n = unum_getAttribute(formatter->_nf, UNUM_MAX_FRACTION_DIGITS); + if (1) { + return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n); + } + } else if (kCFNumberFormatterGroupingSize == key) { + n = unum_getAttribute(formatter->_nf, UNUM_GROUPING_SIZE); + if (1) { + return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n); + } + } else if (kCFNumberFormatterSecondaryGroupingSize == key) { + n = unum_getAttribute(formatter->_nf, UNUM_SECONDARY_GROUPING_SIZE); + if (1) { + return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n); + } + } else if (kCFNumberFormatterRoundingMode == key) { + n = unum_getAttribute(formatter->_nf, UNUM_ROUNDING_MODE); + if (1) { + return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n); + } + } else if (kCFNumberFormatterRoundingIncrement == key) { + d = unum_getDoubleAttribute(formatter->_nf, UNUM_ROUNDING_INCREMENT); + if (1) { + return CFNumberCreate(CFGetAllocator(formatter), kCFNumberDoubleType, &d); + } + } else if (kCFNumberFormatterFormatWidth == key) { + n = unum_getAttribute(formatter->_nf, UNUM_FORMAT_WIDTH); + if (1) { + return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n); + } + } else if (kCFNumberFormatterPaddingPosition == key) { + n = unum_getAttribute(formatter->_nf, UNUM_PADDING_POSITION); + if (1) { + return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n); + } + } else if (kCFNumberFormatterPaddingCharacter == key) { + cnt = unum_getTextAttribute(formatter->_nf, UNUM_PADDING_CHARACTER, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterDefaultFormat == key) { + return formatter->_defformat ? CFRetain(formatter->_defformat) : NULL; + } else if (kCFNumberFormatterMultiplier == key) { + return formatter->_multiplier ? CFRetain(formatter->_multiplier) : NULL; + } else if (kCFNumberFormatterPositivePrefix == key) { + cnt = unum_getTextAttribute(formatter->_nf, UNUM_POSITIVE_PREFIX, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterPositiveSuffix == key) { + cnt = unum_getTextAttribute(formatter->_nf, UNUM_POSITIVE_SUFFIX, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterNegativePrefix == key) { + cnt = unum_getTextAttribute(formatter->_nf, UNUM_NEGATIVE_PREFIX, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterNegativeSuffix == key) { + cnt = unum_getTextAttribute(formatter->_nf, UNUM_NEGATIVE_SUFFIX, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterPerMillSymbol == key) { + cnt = unum_getSymbol(formatter->_nf, UNUM_PERMILL_SYMBOL, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterInternationalCurrencySymbol == key) { + cnt = unum_getSymbol(formatter->_nf, UNUM_INTL_CURRENCY_SYMBOL, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterCurrencyGroupingSeparator == key) { + cnt = unum_getSymbol(formatter->_nf, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, ubuffer, BUFFER_SIZE, &status); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(formatter), (const UniChar *)ubuffer, cnt); + } + } else if (kCFNumberFormatterIsLenient == key) { + n = unum_getAttribute(formatter->_nf, UNUM_LENIENT_PARSE); + if (1) { + return CFRetain(n ? kCFBooleanTrue : kCFBooleanFalse); + } + } else if (kCFNumberFormatterUseSignificantDigits == key) { + n = unum_getAttribute(formatter->_nf, UNUM_SIGNIFICANT_DIGITS_USED); + if (1) { + return CFRetain(n ? kCFBooleanTrue : kCFBooleanFalse); + } + } else if (kCFNumberFormatterMinSignificantDigits == key) { + n = unum_getAttribute(formatter->_nf, UNUM_MIN_SIGNIFICANT_DIGITS); + if (1) { + return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n); + } + } else if (kCFNumberFormatterMaxSignificantDigits == key) { + n = unum_getAttribute(formatter->_nf, UNUM_MAX_SIGNIFICANT_DIGITS); + if (1) { + return CFNumberCreate(CFGetAllocator(formatter), kCFNumberSInt32Type, &n); + } + } else { + CFAssert3(0, __kCFLogAssertion, "%s(): unknown key %p (%@)", __PRETTY_FUNCTION__, key, key); + } + return NULL; +} + +CONST_STRING_DECL(kCFNumberFormatterCurrencyCode, "kCFNumberFormatterCurrencyCode") +CONST_STRING_DECL(kCFNumberFormatterDecimalSeparator, "kCFNumberFormatterDecimalSeparator") +CONST_STRING_DECL(kCFNumberFormatterCurrencyDecimalSeparator, "kCFNumberFormatterCurrencyDecimalSeparator") +CONST_STRING_DECL(kCFNumberFormatterAlwaysShowDecimalSeparator, "kCFNumberFormatterAlwaysShowDecimalSeparator") +CONST_STRING_DECL(kCFNumberFormatterGroupingSeparator, "kCFNumberFormatterGroupingSeparator") +CONST_STRING_DECL(kCFNumberFormatterUseGroupingSeparator, "kCFNumberFormatterUseGroupingSeparator") +CONST_STRING_DECL(kCFNumberFormatterPercentSymbol, "kCFNumberFormatterPercentSymbol") +CONST_STRING_DECL(kCFNumberFormatterZeroSymbol, "kCFNumberFormatterZeroSymbol") +CONST_STRING_DECL(kCFNumberFormatterNaNSymbol, "kCFNumberFormatterNaNSymbol") +CONST_STRING_DECL(kCFNumberFormatterInfinitySymbol, "kCFNumberFormatterInfinitySymbol") +CONST_STRING_DECL(kCFNumberFormatterMinusSign, "kCFNumberFormatterMinusSignSymbol") +CONST_STRING_DECL(kCFNumberFormatterPlusSign, "kCFNumberFormatterPlusSignSymbol") +CONST_STRING_DECL(kCFNumberFormatterCurrencySymbol, "kCFNumberFormatterCurrencySymbol") +CONST_STRING_DECL(kCFNumberFormatterExponentSymbol, "kCFNumberFormatterExponentSymbol") +CONST_STRING_DECL(kCFNumberFormatterMinIntegerDigits, "kCFNumberFormatterMinIntegerDigits") +CONST_STRING_DECL(kCFNumberFormatterMaxIntegerDigits, "kCFNumberFormatterMaxIntegerDigits") +CONST_STRING_DECL(kCFNumberFormatterMinFractionDigits, "kCFNumberFormatterMinFractionDigits") +CONST_STRING_DECL(kCFNumberFormatterMaxFractionDigits, "kCFNumberFormatterMaxFractionDigits") +CONST_STRING_DECL(kCFNumberFormatterGroupingSize, "kCFNumberFormatterGroupingSize") +CONST_STRING_DECL(kCFNumberFormatterSecondaryGroupingSize, "kCFNumberFormatterSecondaryGroupingSize") +CONST_STRING_DECL(kCFNumberFormatterRoundingMode, "kCFNumberFormatterRoundingMode") +CONST_STRING_DECL(kCFNumberFormatterRoundingIncrement, "kCFNumberFormatterRoundingIncrement") +CONST_STRING_DECL(kCFNumberFormatterFormatWidth, "kCFNumberFormatterFormatWidth") +CONST_STRING_DECL(kCFNumberFormatterPaddingPosition, "kCFNumberFormatterPaddingPosition") +CONST_STRING_DECL(kCFNumberFormatterPaddingCharacter, "kCFNumberFormatterPaddingCharacter") +CONST_STRING_DECL(kCFNumberFormatterDefaultFormat, "kCFNumberFormatterDefaultFormat") + +CONST_STRING_DECL(kCFNumberFormatterMultiplier, "kCFNumberFormatterMultiplier") +CONST_STRING_DECL(kCFNumberFormatterPositivePrefix, "kCFNumberFormatterPositivePrefix") +CONST_STRING_DECL(kCFNumberFormatterPositiveSuffix, "kCFNumberFormatterPositiveSuffix") +CONST_STRING_DECL(kCFNumberFormatterNegativePrefix, "kCFNumberFormatterNegativePrefix") +CONST_STRING_DECL(kCFNumberFormatterNegativeSuffix, "kCFNumberFormatterNegativeSuffix") +CONST_STRING_DECL(kCFNumberFormatterPerMillSymbol, "kCFNumberFormatterPerMillSymbol") +CONST_STRING_DECL(kCFNumberFormatterInternationalCurrencySymbol, "kCFNumberFormatterInternationalCurrencySymbol") + +CONST_STRING_DECL(kCFNumberFormatterCurrencyGroupingSeparator, "kCFNumberFormatterCurrencyGroupingSeparator") +CONST_STRING_DECL(kCFNumberFormatterIsLenient, "kCFNumberFormatterIsLenient") +CONST_STRING_DECL(kCFNumberFormatterUseSignificantDigits, "kCFNumberFormatterUseSignificantDigits") +CONST_STRING_DECL(kCFNumberFormatterMinSignificantDigits, "kCFNumberFormatterMinSignificantDigits") +CONST_STRING_DECL(kCFNumberFormatterMaxSignificantDigits, "kCFNumberFormatterMaxSignificantDigits") + +Boolean CFNumberFormatterGetDecimalInfoForCurrencyCode(CFStringRef currencyCode, int32_t *defaultFractionDigits, double *roundingIncrement) { + UChar ubuffer[4]; + __CFGenericValidateType(currencyCode, CFStringGetTypeID()); + CFAssert1(3 == CFStringGetLength(currencyCode), __kCFLogAssertion, "%s(): currencyCode is not 3 characters", __PRETTY_FUNCTION__); + CFStringGetCharacters(currencyCode, CFRangeMake(0, 3), (UniChar *)ubuffer); + ubuffer[3] = 0; + UErrorCode icuStatus = U_ZERO_ERROR; + if (defaultFractionDigits) *defaultFractionDigits = ucurr_getDefaultFractionDigits(ubuffer, &icuStatus); + if (roundingIncrement) *roundingIncrement = ucurr_getRoundingIncrement(ubuffer, &icuStatus); + if (U_FAILURE(icuStatus)) + return false; + return (!defaultFractionDigits || 0 <= *defaultFractionDigits) && (!roundingIncrement || 0.0 <= *roundingIncrement); +} + +#undef BUFFER_SIZE + diff --git a/CFNumberFormatter.h b/CFNumberFormatter.h new file mode 100644 index 0000000..faaf9d8 --- /dev/null +++ b/CFNumberFormatter.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFNumberFormatter.h + Copyright (c) 2003-2007, Apple Inc. All rights reserved. +*/ + +#if !defined(__COREFOUNDATION_CFNUMBERFORMATTER__) +#define __COREFOUNDATION_CFNUMBERFORMATTER__ 1 + +#include +#include +#include + +#if MAC_OS_X_VERSION_10_3 <= MAC_OS_X_VERSION_MAX_ALLOWED + +CF_EXTERN_C_BEGIN + +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; + +enum { // number format styles + kCFNumberFormatterNoStyle = 0, + kCFNumberFormatterDecimalStyle = 1, + kCFNumberFormatterCurrencyStyle = 2, + kCFNumberFormatterPercentStyle = 3, + kCFNumberFormatterScientificStyle = 4, + kCFNumberFormatterSpellOutStyle = 5 +}; +typedef CFIndex CFNumberFormatterStyle; + + +CF_EXPORT +CFNumberFormatterRef CFNumberFormatterCreate(CFAllocatorRef allocator, CFLocaleRef locale, CFNumberFormatterStyle style) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + // 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; + +CF_EXPORT +CFNumberFormatterStyle CFNumberFormatterGetStyle(CFNumberFormatterRef formatter) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + // 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; + +CF_EXPORT +void CFNumberFormatterSetFormat(CFNumberFormatterRef formatter, CFStringRef formatString) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + // Set the format description string of the number formatter. This + // overrides the style settings. The format of the format string + // is as defined by the ICU library, and is similar to that found + // in Microsoft Excel and NSNumberFormatter (and Java I believe). + // The number formatter starts with a default format string defined + // by the style argument with which it was created. + + +CF_EXPORT +CFStringRef CFNumberFormatterCreateStringWithNumber(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberRef number) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + +CF_EXPORT +CFStringRef CFNumberFormatterCreateStringWithValue(CFAllocatorRef allocator, CFNumberFormatterRef formatter, CFNumberType numberType, const void *valuePtr) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + // Create a string representation of the given number or value + // using the current state of the number formatter. + + +enum { + kCFNumberFormatterParseIntegersOnly = 1 /* only parse integers */ +}; +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; + +CF_EXPORT +Boolean CFNumberFormatterGetValueFromString(CFNumberFormatterRef formatter, CFStringRef string, CFRange *rangep, CFNumberType numberType, void *valuePtr) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + // 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 + // output indicates the extent that was used; this parameter can + // be NULL, in which case the whole string may be used. The + // return value indicates whether some number was computed and + // (if valuePtr is not NULL) stored at the location specified by + // valuePtr. The numberType indicates the type of value pointed + // to by valuePtr. + + +CF_EXPORT +void CFNumberFormatterSetProperty(CFNumberFormatterRef formatter, CFStringRef key, CFTypeRef value) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + +CF_EXPORT +CFTypeRef CFNumberFormatterCopyProperty(CFNumberFormatterRef formatter, CFStringRef key) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + // 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 + +enum { + kCFNumberFormatterRoundCeiling = 0, + kCFNumberFormatterRoundFloor = 1, + kCFNumberFormatterRoundDown = 2, + kCFNumberFormatterRoundUp = 3, + kCFNumberFormatterRoundHalfEven = 4, + kCFNumberFormatterRoundHalfDown = 5, + kCFNumberFormatterRoundHalfUp = 6 +}; +typedef CFIndex CFNumberFormatterRoundingMode; + +enum { + kCFNumberFormatterPadBeforePrefix = 0, + kCFNumberFormatterPadAfterPrefix = 1, + kCFNumberFormatterPadBeforeSuffix = 2, + kCFNumberFormatterPadAfterSuffix = 3 +}; +typedef CFIndex CFNumberFormatterPadPosition; + + +CF_EXPORT +Boolean CFNumberFormatterGetDecimalInfoForCurrencyCode(CFStringRef currencyCode, int32_t *defaultFractionDigits, double *roundingIncrement) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; + // 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 + // or the information is not available. + // Not localized because these are properties of the currency. + +CF_EXTERN_C_END + +#endif + +#endif /* ! __COREFOUNDATION_CFNUMBERFORMATTER__ */ + diff --git a/Base.subproj/CFPlatform.c b/CFPlatform.c similarity index 59% rename from Base.subproj/CFPlatform.c rename to CFPlatform.c index 7564e45..d0dbed0 100644 --- a/Base.subproj/CFPlatform.c +++ b/CFPlatform.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -27,42 +27,33 @@ #include "CFInternal.h" #include "CFPriv.h" -#if defined(__WIN32__) - #include - #include -#else - #include - #include - #include - #include -#endif -#if defined(__MACH__) - #include -#endif - -extern char *getenv(const char *name); - -#if defined(__MACH__) +#include +#include +#include +#include +#include +#include +#include + +#if DEPLOYMENT_TARGET_MACOSX #define kCFPlatformInterfaceStringEncoding kCFStringEncodingUTF8 #else #define kCFPlatformInterfaceStringEncoding CFStringGetSystemEncoding() #endif -#if defined(__MACH__) -char **_CFArgv(void) { - return *_NSGetArgv(); -} +static CFStringRef _CFUserName(void); -int _CFArgc(void) { - return *_NSGetArgc(); -} +#if DEPLOYMENT_TARGET_MACOSX +// CoreGraphics and LaunchServices are only projects (1 Dec 2006) that use these +char **_CFArgv(void) { return *_NSGetArgv(); } +int _CFArgc(void) { return *_NSGetArgc(); } #endif __private_extern__ Boolean _CFGetCurrentDirectory(char *path, int maxlen) { -#if defined(__WIN32__) +#if 0 || 0 DWORD len = GetCurrentDirectoryA(maxlen, path); - return (0 != len && len + 1 <= maxlen); + return ((0 != len) && (maxlen > 0) && (len + 1 <= (DWORD)maxlen)); #else return getcwd(path, maxlen) != NULL; #endif @@ -75,7 +66,7 @@ __private_extern__ Boolean _CFIsCFM(void) { return __CFIsCFM; } -#if defined(__WIN32__) +#if 0 || 0 #define PATH_SEP '\\' #else #define PATH_SEP '/' @@ -84,26 +75,27 @@ __private_extern__ Boolean _CFIsCFM(void) { #if !defined(__WIN32__) #define PATH_LIST_SEP ':' -static char *_CFSearchForNameInPath(CFAllocatorRef alloc, const char *name, char *path) { +static char *_CFSearchForNameInPath(const char *name, char *path) { struct stat statbuf; - char *nname = CFAllocatorAllocate(alloc, strlen(name) + strlen(path) + 2, 0); - if (__CFOASafe) __CFSetLastAllocationEventName(nname, "CFUtilities (temp)"); + char nname[strlen(name) + strlen(path) + 2]; + int no_hang_fd = open("/dev/autofs_nowait", 0); for (;;) { char *p = (char *)strchr(path, PATH_LIST_SEP); if (NULL != p) { *p = '\0'; } nname[0] = '\0'; - strcat(nname, path); - strcat(nname, "/"); - strcat(nname, name); + strlcat(nname, path, sizeof(nname)); + strlcat(nname, "/", sizeof(nname)); + strlcat(nname, name, sizeof(nname)); // Could also do access(us, X_OK) == 0 in next condition, // for executable-only searching if (0 == stat(nname, &statbuf) && (statbuf.st_mode & S_IFMT) == S_IFREG) { if (p != NULL) { *p = PATH_LIST_SEP; } - return nname; + close(no_hang_fd); + return strdup(nname); } if (NULL == p) { break; @@ -111,47 +103,12 @@ static char *_CFSearchForNameInPath(CFAllocatorRef alloc, const char *name, char *p = PATH_LIST_SEP; path = p + 1; } - CFAllocatorDeallocate(alloc, nname); + close(no_hang_fd); return NULL; } #endif - -#if defined(__WIN32__) -// Returns the path to the CF DLL, which we can then use to find resources like char sets - -__private_extern__ const char *_CFDLLPath(void) { - static TCHAR cachedPath[MAX_PATH+1] = ""; - - if ('\0' == cachedPath[0]) { -#if defined(DEBUG) - char *DLLFileName = "CoreFoundation_debug"; -#elif defined(PROFILE) - char *DLLFileName = "CoreFoundation_profile"; -#else - char *DLLFileName = "CoreFoundation"; -#endif - HMODULE ourModule = GetModuleHandle(DLLFileName); - CFAssert(ourModule, __kCFLogAssertion, "GetModuleHandle failed"); - - DWORD wResult = GetModuleFileName(ourModule, cachedPath, MAX_PATH+1); - CFAssert1(wResult > 0, __kCFLogAssertion, "GetModuleFileName failed: %d", GetLastError()); - CFAssert1(wResult < MAX_PATH+1, __kCFLogAssertion, "GetModuleFileName result truncated: %s", cachedPath); - - // strip off last component, the DLL name - CFIndex idx; - for (idx = wResult - 1; idx; idx--) { - if ('\\' == cachedPath[idx]) { - cachedPath[idx] = '\0'; - break; - } - } - } - return cachedPath; -} -#endif - static const char *__CFProcessPath = NULL; static const char *__CFprogname = NULL; @@ -168,49 +125,26 @@ const char **_CFGetProcessPath(void) { } const char *_CFProcessPath(void) { - CFAllocatorRef alloc = NULL; - char *thePath = NULL; - if (__CFProcessPath) return __CFProcessPath; - if (!__CFProcessPath) { - thePath = getenv("CFProcessPath"); - - alloc = CFRetain(__CFGetDefaultAllocator()); - + + char *thePath = NULL; +#if DEPLOYMENT_TARGET_MACOSX + if (!issetugid()) { + thePath = getenv("CFProcessPath"); if (thePath) { int len = strlen(thePath); - __CFProcessPath = CFAllocatorAllocate(alloc, len+1, 0); - if (__CFOASafe) __CFSetLastAllocationEventName((void *)__CFProcessPath, "CFUtilities (process-path)"); + __CFProcessPath = (const char *)CFAllocatorAllocate(kCFAllocatorSystemDefault, len+1, 0); + if (__CFOASafe) __CFSetLastAllocationEventName((void *)__CFProcessPath, "CFUtilities (process-path)"); memmove((char *)__CFProcessPath, thePath, len + 1); } } - -#if defined(__MACH__) +#endif +#if DEPLOYMENT_TARGET_MACOSX int execIndex = 0; - { - struct stat exec, lcfm; - uint32_t size = CFMaxPathSize; - char buffer[CFMaxPathSize]; - if (0 == _NSGetExecutablePath(buffer, &size) && - strcasestr(buffer, "LaunchCFMApp") != NULL && - 0 == stat("/System/Library/Frameworks/Carbon.framework/Versions/Current/Support/LaunchCFMApp", &lcfm) && - 0 == stat(buffer, &exec) && - (lcfm.st_dev == exec.st_dev) && - (lcfm.st_ino == exec.st_ino)) { - // Executable is LaunchCFMApp, take special action - execIndex = 1; - __CFIsCFM = true; - } - } #endif -#if defined(__WIN32__) - if (!__CFProcessPath) { - char buf[CFMaxPathSize] = {0}; - DWORD rlen = GetModuleFileName(NULL, buf, 1028); - thePath = rlen ? buf : NULL; -#else if (!__CFProcessPath && NULL != (*_NSGetArgv())[execIndex]) { + int no_hang_fd = open("/dev/autofs_nowait", 0); char buf[CFMaxPathSize] = {0}; struct stat statbuf; const char *arg0 = (*_NSGetArgv())[execIndex]; @@ -220,20 +154,20 @@ const char *_CFProcessPath(void) { } else { char *theList = getenv("PATH"); if (NULL != theList && NULL == strrchr(arg0, '/')) { - thePath = _CFSearchForNameInPath(alloc, arg0, theList); + thePath = _CFSearchForNameInPath(arg0, theList); if (thePath) { // User could have "." or "../bin" or other relative path in $PATH if (('/' != thePath[0]) && _CFGetCurrentDirectory(buf, CFMaxPathSize)) { - strlcat(buf, "/", CFMaxPathSize); - strlcat(buf, thePath, CFMaxPathSize); + strlcat(buf, "/", sizeof(buf)); + strlcat(buf, thePath, sizeof(buf)); if (0 == stat(buf, &statbuf)) { - CFAllocatorDeallocate(alloc, (void *)thePath); + free(thePath); thePath = buf; } } if (thePath != buf) { - strlcpy(buf, thePath, CFMaxPathSize); - CFAllocatorDeallocate(alloc, (void *)thePath); + strlcpy(buf, thePath, sizeof(buf)); + free((void *)thePath); thePath = buf; } } @@ -244,7 +178,7 @@ const char *_CFProcessPath(void) { // try prepending the current directory to argv[0]. if (!thePath && _CFGetCurrentDirectory(buf, CFMaxPathSize)) { if (buf[strlen(buf)-1] != '/') { - strlcat(buf, "/", CFMaxPathSize); + strlcat(buf, "/", sizeof(buf)); } strlcat(buf, arg0, CFMaxPathSize); if (0 == stat(buf, &statbuf)) { @@ -266,10 +200,10 @@ const char *_CFProcessPath(void) { if (!thePath) { thePath = (*_NSGetArgv())[execIndex]; } -#endif + if (thePath) { - int len = strlen(thePath); - __CFProcessPath = CFAllocatorAllocate(alloc, len + 1, 0); + int len = strlen(thePath); + __CFProcessPath = (const char *)CFAllocatorAllocate(kCFAllocatorSystemDefault, len + 1, 0); if (__CFOASafe) __CFSetLastAllocationEventName((void *)__CFProcessPath, "CFUtilities (process-path)"); memmove((char *)__CFProcessPath, thePath, len + 1); } @@ -286,6 +220,8 @@ const char *_CFProcessPath(void) { else __CFprogname = __CFProcessPath; } + + close(no_hang_fd); } if (!__CFProcessPath) { __CFProcessPath = ""; @@ -317,15 +253,23 @@ __private_extern__ CFStringRef _CFProcessNameString(void) { static CFStringRef __CFUserName = NULL; -#if defined(__MACH__) || defined(__svr4__) || defined(__hpux__) || defined(__LINUX__) || defined(__FREEBSD__) +#if (DEPLOYMENT_TARGET_MACOSX) || defined(__svr4__) || defined(__hpux__) || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD static CFURLRef __CFHomeDirectory = NULL; static uint32_t __CFEUID = -1; static uint32_t __CFUID = -1; static CFURLRef _CFCopyHomeDirURLForUser(struct passwd *upwd) { CFURLRef home = NULL; - if (upwd && upwd->pw_dir) { - home = CFURLCreateFromFileSystemRepresentation(NULL, upwd->pw_dir, strlen(upwd->pw_dir), true); + if (!issetugid()) { + const char *path = getenv("CFFIXED_USER_HOME"); + if (path) { + home = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)path, strlen(path), true); + } + } + if (!home) { + if (upwd && upwd->pw_dir) { + home = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)upwd->pw_dir, strlen(upwd->pw_dir), true); + } } return home; } @@ -345,7 +289,7 @@ static void _CFUpdateUserInfo(void) { if (!__CFHomeDirectory) { const char *cpath = getenv("HOME"); if (cpath) { - __CFHomeDirectory = CFURLCreateFromFileSystemRepresentation(NULL, cpath, strlen(cpath), true); + __CFHomeDirectory = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)cpath, strlen(cpath), true); } } @@ -354,17 +298,17 @@ static void _CFUpdateUserInfo(void) { // expect NeXTSTEP encodings. A great test of our localized system would // be to have a user "O-umlat z e r". XXX if (upwd && upwd->pw_name) { - __CFUserName = CFStringCreateWithCString(NULL, upwd->pw_name, kCFPlatformInterfaceStringEncoding); + __CFUserName = CFStringCreateWithCString(kCFAllocatorSystemDefault, upwd->pw_name, kCFPlatformInterfaceStringEncoding); } else { const char *cuser = getenv("USER"); if (cuser) - __CFUserName = CFStringCreateWithCString(NULL, cuser, kCFPlatformInterfaceStringEncoding); + __CFUserName = CFStringCreateWithCString(kCFAllocatorSystemDefault, cuser, kCFPlatformInterfaceStringEncoding); } } #endif static CFURLRef _CFCreateHomeDirectoryURLForUser(CFStringRef uName) { -#if defined(__MACH__) || defined(__svr4__) || defined(__hpux__) || defined(__LINUX__) || defined(__FREEBSD__) +#if (DEPLOYMENT_TARGET_MACOSX) || defined(__svr4__) || defined(__hpux__) || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD if (!uName) { if (geteuid() != __CFEUID || getuid() != __CFUID || !__CFHomeDirectory) _CFUpdateUserInfo(); @@ -378,80 +322,81 @@ static CFURLRef _CFCreateHomeDirectoryURLForUser(CFStringRef uName) { if (size < 127) { user = buf; } else { - user = CFAllocatorAllocate(kCFAllocatorDefault, size+1, 0); + user = CFAllocatorAllocate(kCFAllocatorSystemDefault, size+1, 0); if (__CFOASafe) __CFSetLastAllocationEventName(user, "CFUtilities (temp)"); } - if (CFStringGetBytes(uName, CFRangeMake(0, len), kCFPlatformInterfaceStringEncoding, 0, true, user, size, &usedSize) == len) { + if (CFStringGetBytes(uName, CFRangeMake(0, len), kCFPlatformInterfaceStringEncoding, 0, true, (uint8_t *)user, size, &usedSize) == len) { user[usedSize] = '\0'; upwd = getpwnam(user); } if (buf != user) { - CFAllocatorDeallocate(kCFAllocatorDefault, user); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, user); } return _CFCopyHomeDirURLForUser(upwd); } #elif defined(__WIN32__) -#warning CF: Windows home directory goop disabled - return NULL; -#if 0 - CFString *user = !uName ? CFUserName() : uName; + CFStringRef user = !uName ? _CFUserName() : uName; + CFURLRef home = NULL; - if (!uName || CFEqual(user, CFUserName())) { + if (!uName || CFEqual(user, _CFUserName())) { const char *cpath = getenv("HOMEPATH"); const char *cdrive = getenv("HOMEDRIVE"); if (cdrive && cpath) { char fullPath[CFMaxPathSize]; CFStringRef str; - strcpy(fullPath, cdrive); - strncat(fullPath, cpath, CFMaxPathSize-strlen(cdrive)-1); - str = CFStringCreateWithCString(NULL, fullPath, kCFPlatformInterfaceStringEncoding); - home = CFURLCreateWithFileSystemPath(NULL, str, kCFURLWindowsPathStyle, true); + strlcpy(fullPath, cdrive, sizeof(fullPath)); + strlcat(fullPath, cpath, sizeof(fullPath)); + str = CFStringCreateWithCString(kCFAllocatorSystemDefault, fullPath, kCFPlatformInterfaceStringEncoding); + home = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, kCFURLWindowsPathStyle, true); CFRelease(str); } } - if (!home) { - struct _USER_INFO_2 *userInfo; - HINSTANCE hinstDll = GetModuleHandleA("NETAPI32"); - if (!hinstDll) - hinstDll = LoadLibraryEx("NETAPI32", NULL, 0); - if (hinstDll) { - FARPROC lpfn = GetProcAddress(hinstDll, "NetUserGetInfo"); - if (lpfn) { - unsigned namelen = CFStringGetLength(user); - UniChar *username; - username = CFAllocatorAllocate(kCFAllocatorDefault, sizeof(UniChar) * (namelen + 1), 0); - if (__CFOASafe) __CFSetLastAllocationEventName(username, "CFUtilities (temp)"); - CFStringGetCharacters(user, CFRangeMake(0, namelen), username); - if (!(*lpfn)(NULL, (LPWSTR)username, 2, (LPBYTE *)&userInfo)) { - UInt32 len = 0; - CFMutableStringRef str; - while (userInfo->usri2_home_dir[len] != 0) len ++; - str = CFStringCreateMutable(NULL, len+1); - CFStringAppendCharacters(str, userInfo->usri2_home_dir, len); - home = CFURLCreateWithFileSystemPath(NULL, str, kCFURLWindowsPathStyle, true); - CFRelease(str); + if (home == NULL) { + UniChar pathChars[MAX_PATH]; + if (S_OK == SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, (LPWSTR) pathChars)) { + UniChar* p = pathChars; + CFIndex len = 0; + CFStringRef str; + while (*p++ != 0) + ++len; + str = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, pathChars, len); + home = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, kCFURLWindowsPathStyle, true); + CFRelease(str); + } else { + // We have to get "some" directory location, so fall-back to the + // processes current directory. + UniChar currDir[MAX_PATH]; + DWORD dwChars = GetCurrentDirectory(MAX_PATH + 1, (LPWSTR)currDir); + if (dwChars > 0) { + UniChar* p = currDir; + CFIndex len = 0; + CFStringRef str; + while (*p++ != 0) + ++len; + str = CFStringCreateWithCharacters(kCFAllocatorSystemDefault, currDir, len); + home = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, str, kCFURLWindowsPathStyle, true); + } } - CFAllocatorDeallocate(kCFAllocatorDefault, username); - } - } else { - } } // 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 (CFStringGetLength(CFURLGetPath(home)) == 0) { - CFRelease(home); - home=NULL; + if (home) { + CFStringRef str = CFURLCopyFileSystemPath(home, kCFURLWindowsPathStyle); + if (str && CFStringGetLength(str) == 0) { + CFRelease(home); + home=NULL; + } + if (str) CFRelease(str); } -#endif - + return home; #else #error Dont know how to compute users home directories on this platform #endif } static CFStringRef _CFUserName(void) { -#if defined(__MACH__) || defined(__svr4__) || defined(__hpux__) || defined(__LINUX__) || defined(__FREEBSD__) +#if (DEPLOYMENT_TARGET_MACOSX) || defined(__svr4__) || defined(__hpux__) || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD if (geteuid() != __CFEUID || getuid() != __CFUID) _CFUpdateUserInfo(); #elif defined(__WIN32__) @@ -460,23 +405,23 @@ static CFStringRef _CFUserName(void) { DWORD size = 1040; username[0] = 0; if (GetUserNameA(username, &size)) { - __CFUserName = CFStringCreateWithCString(NULL, username, kCFPlatformInterfaceStringEncoding); + __CFUserName = CFStringCreateWithCString(kCFAllocatorSystemDefault, username, kCFPlatformInterfaceStringEncoding); } else { const char *cname = getenv("USERNAME"); if (cname) - __CFUserName = CFStringCreateWithCString(NULL, cname, kCFPlatformInterfaceStringEncoding); + __CFUserName = CFStringCreateWithCString(kCFAllocatorSystemDefault, cname, kCFPlatformInterfaceStringEncoding); } } #else #error Dont know how to compute user name on this platform #endif if (!__CFUserName) - __CFUserName = CFRetain(CFSTR("")); + __CFUserName = (CFStringRef)CFRetain(CFSTR("")); return __CFUserName; } __private_extern__ CFStringRef _CFGetUserName(void) { - return CFStringCreateCopy(NULL, _CFUserName()); + return CFStringCreateCopy(kCFAllocatorSystemDefault, _CFUserName()); } #define CFMaxHostNameLength 256 @@ -487,7 +432,7 @@ __private_extern__ CFStringRef _CFStringCreateHostName(void) { // return @"" instead of nil a la CFUserName() and Ali Ozer if (0 != gethostname(myName, CFMaxHostNameSize)) myName[0] = '\0'; - return CFStringCreateWithCString(NULL, myName, kCFPlatformInterfaceStringEncoding); + return CFStringCreateWithCString(kCFAllocatorSystemDefault, myName, kCFPlatformInterfaceStringEncoding); } /* These are sanitized versions of the above functions. We might want to eliminate the above ones someday. diff --git a/PlugIn.subproj/CFPlugIn.c b/CFPlugIn.c similarity index 94% rename from PlugIn.subproj/CFPlugIn.c rename to CFPlugIn.c index 46ecba7..da89132 100644 --- a/PlugIn.subproj/CFPlugIn.c +++ b/CFPlugIn.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFPlugIn.c - Copyright 1999-2002, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007 Apple Inc. All rights reserved. Responsibility: Doug Davidson */ @@ -49,7 +49,7 @@ CF_EXPORT CFArrayRef CFPlugInFindFactoriesForPlugInType(CFUUIDRef typeID) { SInt32 i, c = CFArrayGetCount(array); // Use default allocator - result = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); for (i=0; i #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN /* ================ Standard Info.plist keys for plugIns ================ */ @@ -65,7 +63,7 @@ typedef void *(*CFPlugInFactoryFunction)(CFAllocatorRef allocator, CFUUIDRef typ /* ================= Creating PlugIns ================= */ CF_EXPORT -UInt32 CFPlugInGetTypeID(void); +CFTypeID CFPlugInGetTypeID(void); CF_EXPORT CFPlugInRef CFPlugInCreate(CFAllocatorRef allocator, CFURLRef plugInURL); @@ -146,17 +144,15 @@ CFStringRef CFPlugInInstanceGetFactoryName(CFPlugInInstanceRef instance); CF_EXPORT void *CFPlugInInstanceGetInstanceData(CFPlugInInstanceRef instance); CF_EXPORT -UInt32 CFPlugInInstanceGetTypeID(void); +CFTypeID CFPlugInInstanceGetTypeID(void); CF_EXPORT CFPlugInInstanceRef CFPlugInInstanceCreateWithInstanceDataSize(CFAllocatorRef allocator, CFIndex instanceDataSize, CFPlugInInstanceDeallocateInstanceDataFunction deallocateInstanceFunction, CFStringRef factoryName, CFPlugInInstanceGetInterfaceFunction getInterfaceFunction); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #if !COREFOUNDATION_CFPLUGINCOM_SEPARATE #include -#endif +#endif /* !COREFOUNDATION_CFPLUGINCOM_SEPARATE */ #endif /* ! __COREFOUNDATION_CFPLUGIN__ */ diff --git a/PlugIn.subproj/CFPlugInCOM.h b/CFPlugInCOM.h similarity index 91% rename from PlugIn.subproj/CFPlugInCOM.h rename to CFPlugInCOM.h index 21c932b..dcc1af4 100644 --- a/PlugIn.subproj/CFPlugInCOM.h +++ b/CFPlugInCOM.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFPlugInCOM.h - Copyright (c) 1999-2005, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFPLUGINCOM__) @@ -29,9 +29,7 @@ #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN /* ================= IUnknown definition (C struct) ================= */ @@ -81,7 +79,7 @@ typedef CFUUIDBytes REFIID; #define __RPC_FAR /* The IUnknown interface */ -#define IUnknownUUID CFUUIDGetConstantUUIDWithBytes(NULL, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46) +#define IUnknownUUID CFUUIDGetConstantUUIDWithBytes(kCFAllocatorSystemDefault, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46) #define IUNKNOWN_C_GUTS \ void *_reserved; \ @@ -93,10 +91,7 @@ typedef struct IUnknownVTbl { IUNKNOWN_C_GUTS; } IUnknownVTbl; -/* End of extern "C" stuff */ -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END /* C++ specific stuff */ @@ -108,7 +103,7 @@ typedef struct IUnknownVTbl { class IUnknown #if defined(__MWERKS__) && !defined(__MACH__) : __comobject -#endif +#endif /* __MWERKS__ && !__MACH__ */ { public: virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) = 0; @@ -116,7 +111,7 @@ class IUnknown virtual ULONG STDMETHODCALLTYPE Release(void) = 0; }; -#endif +#endif /* __cplusplus */ #endif /* ! __COREFOUNDATION_CFPLUGINCOM__ */ diff --git a/PlugIn.subproj/CFPlugIn_Factory.c b/CFPlugIn_Factory.c similarity index 87% rename from PlugIn.subproj/CFPlugIn_Factory.c rename to CFPlugIn_Factory.c index 436d458..876cce7 100644 --- a/PlugIn.subproj/CFPlugIn_Factory.c +++ b/CFPlugIn_Factory.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,14 +21,14 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFPlugIn_Factory.c - Copyright 1999-2002, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007 Apple Inc. All rights reserved. Responsibility: Doug Davidson */ #include "CFBundle_Internal.h" #include "CFInternal.h" -static CFSpinLock_t CFPlugInGlobalDataLock = 0; +static CFSpinLock_t CFPlugInGlobalDataLock = CFSpinLockInit; static CFMutableDictionaryRef _factoriesByFactoryID = NULL; /* Value is _CFPFactory */ static CFMutableDictionaryRef _factoriesByTypeID = NULL; /* Value is array of _CFPFactory */ @@ -37,7 +37,7 @@ static void _CFPFactoryAddToTable(_CFPFactory *factory) { if (_factoriesByFactoryID == NULL) { CFDictionaryValueCallBacks _factoryDictValueCallbacks = {0, NULL, NULL, NULL, NULL}; // Use default allocator - _factoriesByFactoryID = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &_factoryDictValueCallbacks); + _factoriesByFactoryID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &_factoryDictValueCallbacks); } CFDictionarySetValue(_factoriesByFactoryID, factory->_uuid, factory); __CFSpinUnlock(&CFPlugInGlobalDataLock); @@ -78,7 +78,7 @@ static void _CFPFactoryDeallocate(_CFPFactory *factory) { /* Remove all types for this factory. */ c = CFArrayGetCount(factory->_types); while (c--) { - _CFPFactoryRemoveType(factory, CFArrayGetValueAtIndex(factory->_types, c)); + _CFPFactoryRemoveType(factory, (CFUUIDRef)CFArrayGetValueAtIndex(factory->_types, c)); } CFRelease(factory->_types); @@ -98,8 +98,8 @@ static _CFPFactory *_CFPFactoryCommonCreate(CFAllocatorRef allocator, CFUUIDRef _CFPFactory *factory; UInt32 size; size = sizeof(_CFPFactory); - allocator = ((NULL == allocator) ? CFRetain(__CFGetDefaultAllocator()) : CFRetain(allocator)); - factory = CFAllocatorAllocate(allocator, size, 0); + allocator = ((NULL == allocator) ? (CFAllocatorRef)CFRetain(__CFGetDefaultAllocator()) : (CFAllocatorRef)CFRetain(allocator)); + factory = (_CFPFactory *)CFAllocatorAllocate(allocator, size, 0); if (NULL == factory) { CFRelease(allocator); return NULL; @@ -107,7 +107,7 @@ static _CFPFactory *_CFPFactoryCommonCreate(CFAllocatorRef allocator, CFUUIDRef factory->_allocator = allocator; - factory->_uuid = CFRetain(factoryID); + factory->_uuid = (CFUUIDRef)CFRetain(factoryID); factory->_enabled = true; factory->_instanceCount = 0; @@ -136,7 +136,7 @@ __private_extern__ _CFPFactory *_CFPFactoryCreateByName(CFAllocatorRef allocator if (plugIn) { _CFPlugInAddFactory(plugIn, factory); } - factory->_funcName = (funcName ? CFStringCreateCopy(allocator, funcName) : NULL); + factory->_funcName = (funcName ? (CFStringRef)CFStringCreateCopy(allocator, funcName) : NULL); return factory; } @@ -153,26 +153,22 @@ __private_extern__ void *_CFPFactoryCreateInstance(CFAllocatorRef allocator, _CF void *result = NULL; if (factory->_enabled) { if (factory->_func == NULL) { - factory->_func = CFBundleGetFunctionPointerForName(factory->_plugIn, factory->_funcName); + factory->_func = (CFPlugInFactoryFunction)CFBundleGetFunctionPointerForName(factory->_plugIn, factory->_funcName); if (factory->_func == NULL) { CFLog(__kCFLogPlugIn, CFSTR("Cannot find function pointer %@ for factory %@ in %@"), factory->_funcName, factory->_uuid, factory->_plugIn); } -#if defined(__MACH__) && defined(__ppc__) +#if BINARY_SUPPORT_CFM else { // 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 +#endif /* BINARY_SUPPORT_CFM */ } if (factory->_func) { -#if 1 // UPPGOOP FAULT_CALLBACK((void **)&(factory->_func)); result = (void *)INVOKE_CALLBACK2(factory->_func, allocator, typeID); -#else - result = factory->_func(allocator, typeID); -#endif } } else { CFLog(__kCFLogPlugIn, CFSTR("Factory %@ is disabled"), factory->_uuid); @@ -207,13 +203,13 @@ __private_extern__ void _CFPFactoryAddType(_CFPFactory *factory, CFUUIDRef typeI __CFSpinLock(&CFPlugInGlobalDataLock); if (_factoriesByTypeID == NULL) { // Create this from default allocator - _factoriesByTypeID = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + _factoriesByTypeID = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); } array = (CFMutableArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID); if (array == NULL) { CFArrayCallBacks _factoryArrayCallbacks = {0, NULL, NULL, NULL, NULL}; // Create this from default allocator - array = CFArrayCreateMutable(NULL, 0, &_factoryArrayCallbacks); + array = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &_factoryArrayCallbacks); CFDictionarySetValue(_factoriesByTypeID, typeID, array); CFRelease(array); } @@ -259,7 +255,7 @@ __private_extern__ CFArrayRef _CFPFactoryFindForType(CFUUIDRef typeID) { __CFSpinLock(&CFPlugInGlobalDataLock); if (_factoriesByTypeID != NULL) { - result = CFDictionaryGetValue(_factoriesByTypeID, typeID); + result = (CFArrayRef)CFDictionaryGetValue(_factoriesByTypeID, typeID); } __CFSpinUnlock(&CFPlugInGlobalDataLock); diff --git a/PlugIn.subproj/CFPlugIn_Factory.h b/CFPlugIn_Factory.h similarity index 93% rename from PlugIn.subproj/CFPlugIn_Factory.h rename to CFPlugIn_Factory.h index 51fe51f..4a17ca6 100644 --- a/PlugIn.subproj/CFPlugIn_Factory.h +++ b/CFPlugIn_Factory.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFPlugIn_Factory.h - Copyright (c) 1999-2005, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFPLUGIN_FACTORY__) @@ -29,9 +29,7 @@ #include "CFBundle_Internal.h" -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN typedef struct __CFPFactory { CFAllocatorRef _allocator; @@ -73,9 +71,7 @@ extern CFArrayRef _CFPFactoryFindForType(CFUUIDRef typeID); extern void _CFPFactoryAddInstance(_CFPFactory *factory); extern void _CFPFactoryRemoveInstance(_CFPFactory *factory); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFPLUGIN_FACTORY__ */ diff --git a/PlugIn.subproj/CFPlugIn_Instance.c b/CFPlugIn_Instance.c similarity index 94% rename from PlugIn.subproj/CFPlugIn_Instance.c rename to CFPlugIn_Instance.c index 3705c6b..077a2d1 100644 --- a/PlugIn.subproj/CFPlugIn_Instance.c +++ b/CFPlugIn_Instance.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFPlugIn_Instance.c - Copyright 1999-2002, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007 Apple Inc. All rights reserved. Responsibility: Doug Davidson */ @@ -37,8 +37,15 @@ struct __CFPlugInInstance { CFPlugInInstanceGetInterfaceFunction getInterfaceFunction; CFPlugInInstanceDeallocateInstanceDataFunction deallocateInstanceDataFunction; - + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4200) +#endif //_MSC_VER uint8_t _instanceData[0]; +#ifdef _MSC_VER +#pragma warning(pop) +#endif //_MSC_VER }; static CFStringRef __CFPlugInInstanceCopyDescription(CFTypeRef cf) { diff --git a/PlugIn.subproj/CFPlugIn_PlugIn.c b/CFPlugIn_PlugIn.c similarity index 90% rename from PlugIn.subproj/CFPlugIn_PlugIn.c rename to CFPlugIn_PlugIn.c index 2f139ca..ce68bdd 100644 --- a/PlugIn.subproj/CFPlugIn_PlugIn.c +++ b/CFPlugIn_PlugIn.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFPlugIn_PlugIn.c - Copyright 1999-2002, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007 Apple Inc. All rights reserved. Responsibility: Doug Davidson */ @@ -33,8 +33,8 @@ static void _registerFactory(const void *key, const void *val, void *context) { CFStringRef factoryIDStr = (CFStringRef)key; CFStringRef factoryFuncStr = (CFStringRef)val; CFBundleRef bundle = (CFBundleRef)context; - CFUUIDRef factoryID = (CFGetTypeID(factoryIDStr) == CFStringGetTypeID()) ? CFUUIDCreateFromString(NULL, factoryIDStr) : NULL; - if (NULL == factoryID) factoryID = CFRetain(factoryIDStr); + CFUUIDRef factoryID = (CFGetTypeID(factoryIDStr) == CFStringGetTypeID()) ? CFUUIDCreateFromString(kCFAllocatorSystemDefault, factoryIDStr) : NULL; + if (NULL == factoryID) factoryID = (CFUUIDRef)CFRetain(factoryIDStr); if (CFGetTypeID(factoryFuncStr) != CFStringGetTypeID() || CFStringGetLength(factoryFuncStr) <= 0) factoryFuncStr = NULL; CFPlugInRegisterFactoryFunctionByName(factoryID, bundle, factoryFuncStr); if (NULL != factoryID) CFRelease(factoryID); @@ -46,19 +46,19 @@ static void _registerType(const void *key, const void *val, void *context) { CFBundleRef bundle = (CFBundleRef)context; SInt32 i, c = (CFGetTypeID(factoryIDStrArray) == CFArrayGetTypeID()) ? CFArrayGetCount(factoryIDStrArray) : 0; CFStringRef curFactoryIDStr; - CFUUIDRef typeID = (CFGetTypeID(typeIDStr) == CFStringGetTypeID()) ? CFUUIDCreateFromString(NULL, typeIDStr) : NULL; + CFUUIDRef typeID = (CFGetTypeID(typeIDStr) == CFStringGetTypeID()) ? CFUUIDCreateFromString(kCFAllocatorSystemDefault, typeIDStr) : NULL; CFUUIDRef curFactoryID; - if (NULL == typeID) typeID = CFRetain(typeIDStr); + if (NULL == typeID) typeID = (CFUUIDRef)CFRetain(typeIDStr); if (0 == c && (CFGetTypeID(factoryIDStrArray) != CFArrayGetTypeID())) { curFactoryIDStr = (CFStringRef)val; curFactoryID = (CFGetTypeID(curFactoryIDStr) == CFStringGetTypeID()) ? CFUUIDCreateFromString(CFGetAllocator(bundle), curFactoryIDStr) : NULL; - if (NULL == curFactoryID) curFactoryID = CFRetain(curFactoryIDStr); + if (NULL == curFactoryID) curFactoryID = (CFUUIDRef)CFRetain(curFactoryIDStr); CFPlugInRegisterPlugInType(curFactoryID, typeID); if (NULL != curFactoryID) CFRelease(curFactoryID); } else for (i=0; i_isPlugIn || __CFBundleGetPlugInData(bundle)->_isDoingDynamicRegistration || !infoDict || !CFBundleIsExecutableLoaded(bundle)) return; - tempStr = CFDictionaryGetValue(infoDict, CFSTR("CFPlugInNeedsDynamicRegistration")); + tempStr = (CFStringRef)CFDictionaryGetValue(infoDict, CFSTR("CFPlugInNeedsDynamicRegistration")); if (tempStr != NULL && CFGetTypeID(tempStr) == CFStringGetTypeID() && CFStringCompare(tempStr, CFSTR("YES"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { CFDictionaryRemoveValue((CFMutableDictionaryRef)infoDict, CFSTR("CFPlugInNeedsDynamicRegistration")); - tempStr = CFDictionaryGetValue(infoDict, kCFPlugInDynamicRegisterFunctionKey); + tempStr = (CFStringRef)CFDictionaryGetValue(infoDict, kCFPlugInDynamicRegisterFunctionKey); if (tempStr == NULL || CFGetTypeID(tempStr) != CFStringGetTypeID() || CFStringGetLength(tempStr) <= 0) { tempStr = CFSTR("CFPlugInDynamicRegister"); } @@ -177,7 +177,7 @@ __private_extern__ void _CFBundleDeallocatePlugIn(CFBundleRef bundle) { } } -UInt32 CFPlugInGetTypeID(void) { +CFTypeID CFPlugInGetTypeID(void) { return CFBundleGetTypeID(); } diff --git a/Preferences.subproj/CFPreferences.c b/CFPreferences.c similarity index 72% rename from Preferences.subproj/CFPreferences.c rename to CFPreferences.c index abfcd21..6e9083d 100644 --- a/Preferences.subproj/CFPreferences.c +++ b/CFPreferences.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -27,22 +27,26 @@ #include #include +#ifndef __WIN32__ #include +#endif #include #include #include #include -#include +#include "CFPriv.h" #include "CFInternal.h" #include +#if DEPLOYMENT_TARGET_MACOSX +#include +#endif //__MACH__ -#if defined(__WIN32__) -#include -#endif #if DEBUG_PREFERENCES_MEMORY #include "../Tests/CFCountingAllocator.c" #endif +static CFURLRef _CFPreferencesURLForStandardDomainWithSafetyLevel(CFStringRef domainName, CFStringRef userName, CFStringRef hostName, unsigned long safeLevel); + struct __CFPreferencesDomain { CFRuntimeBase _base; /* WARNING - not copying the callbacks; we know they are always static structs */ @@ -86,12 +90,58 @@ CF_EXPORT void CFPreferencesDumpMem(void) { } #endif -static CFURLRef _CFPreferencesURLForStandardDomainWithSafetyLevel(CFStringRef domainName, CFStringRef userName, CFStringRef hostName, unsigned long safeLevel); +#if DEPLOYMENT_TARGET_MACOSX +#pragma mark - +#pragma mark Determining host UUID +#endif + + +__private_extern__ CFStringRef _CFPreferencesGetByHostIdentifierString(void) { + return CFSTR(""); +} + + static unsigned long __CFSafeLaunchLevel = 0; +#if 0 +#include + +CF_INLINE CFIndex strlen_UniChar(const UniChar* p) { + CFIndex result = 0; + while ((*p++) != 0) + ++result; + return result; +} + +#endif + static CFURLRef _preferencesDirectoryForUserHostSafetyLevel(CFStringRef userName, CFStringRef hostName, unsigned long safeLevel) { CFAllocatorRef alloc = __CFPreferencesAllocator(); +#if 0 + + CFURLRef url = NULL; + + UniChar szPath[MAX_PATH]; + if (S_OK == SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, (LPWSTR) szPath)) { + CFStringRef directoryPath = CFStringCreateWithCharacters(alloc, szPath, strlen_UniChar(szPath)); + if (directoryPath) { + CFStringRef completePath = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@\\Apple\\"), directoryPath); + if (completePath) { + url = CFURLCreateWithFileSystemPath(alloc, completePath, kCFURLWindowsPathStyle, true); + CFRelease(completePath); + } + CFRelease(directoryPath); + } + } + + // Can't find a better place? Home directory then? + if (url == NULL) + url = CFCopyHomeDirectoryURLForUser((userName == kCFPreferencesCurrentUser) ? NULL : userName); + + return url; + +#else CFURLRef home = NULL; CFURLRef url; int levels = 0; @@ -123,42 +173,20 @@ static CFURLRef _preferencesDirectoryForUserHostSafetyLevel(CFStringRef userName } } return url; +#endif } static CFURLRef _preferencesDirectoryForUserHost(CFStringRef userName, CFStringRef hostName) { return _preferencesDirectoryForUserHostSafetyLevel(userName, hostName, __CFSafeLaunchLevel); } -// Bindings internals -__private_extern__ CFSpinLock_t userDefaultsLock = 0; -__private_extern__ void *userDefaults = NULL; - -void _CFPreferencesSetStandardUserDefaults(void *sudPtr) { - __CFSpinLock(&userDefaultsLock); - userDefaults = sudPtr; - __CFSpinUnlock(&userDefaultsLock); -} - - -#define CF_OBJC_KVO_WILLCHANGE(obj, sel) -#define CF_OBJC_KVO_DIDCHANGE(obj, sel) - - -static Boolean __CFPreferencesWritesXML = false; +static Boolean __CFPreferencesWritesXML = true; Boolean __CFPreferencesShouldWriteXML(void) { return __CFPreferencesWritesXML; } -void __CFPreferencesCheckFormatType(void) { - static int checked = 0; - if (!checked) { - checked = 1; - __CFPreferencesWritesXML = CFPreferencesGetAppBooleanValue(CFSTR("CFPreferencesWritesXML"), kCFPreferencesCurrentApplication, NULL); - } -} - -static CFSpinLock_t domainCacheLock = 0; +static CFSpinLock_t domainCacheLock = CFSpinLockInit; static CFMutableDictionaryRef domainCache = NULL; // mutable // Public API @@ -176,17 +204,17 @@ CFTypeRef CFPreferencesCopyValue(CFStringRef key, CFStringRef appName, CFStri } } -CFDictionaryRef CFPreferencesCopyMultiple(CFArrayRef keysToFetch, CFStringRef appName, CFStringRef userName, CFStringRef hostName) { +CFDictionaryRef CFPreferencesCopyMultiple(CFArrayRef keysToFetch, CFStringRef appName, CFStringRef user, CFStringRef host) { CFPreferencesDomainRef domain; CFMutableDictionaryRef result; CFIndex idx, count; - CFAssert1(appName != NULL && userName != NULL && hostName != NULL, __kCFLogAssertion, "%s(): Cannot access preferences for a NULL application name, user, or host", __PRETTY_FUNCTION__); + CFAssert1(appName != NULL && user != NULL && host != NULL, __kCFLogAssertion, "%s(): Cannot access preferences for a NULL application name, user, or host", __PRETTY_FUNCTION__); __CFGenericValidateType(appName, CFStringGetTypeID()); - __CFGenericValidateType(userName, CFStringGetTypeID()); - __CFGenericValidateType(hostName, CFStringGetTypeID()); + __CFGenericValidateType(user, CFStringGetTypeID()); + __CFGenericValidateType(host, CFStringGetTypeID()); - domain = _CFPreferencesStandardDomain(appName, userName, hostName); + domain = _CFPreferencesStandardDomain(appName, user, host); if (!domain) return NULL; if (!keysToFetch) { return _CFPreferencesDomainDeepCopyDictionary(domain); @@ -196,7 +224,7 @@ CFDictionaryRef CFPreferencesCopyMultiple(CFArrayRef keysToFetch, CFStringRef ap result = CFDictionaryCreateMutable(CFGetAllocator(domain), count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (!result) return NULL; for (idx = 0; idx < count; idx ++) { - CFStringRef key = CFArrayGetValueAtIndex(keysToFetch, idx); + CFStringRef key = (CFStringRef)CFArrayGetValueAtIndex(keysToFetch, idx); CFPropertyListRef value; __CFGenericValidateType(key, CFStringGetTypeID()); value = _CFPreferencesDomainCreateValueForKey(domain, key); @@ -216,58 +244,45 @@ void CFPreferencesSetValue(CFStringRef key, CFTypeRef value, CFStringRef appN domain = _CFPreferencesStandardDomain(appName, user, host); if (domain) { - void *defs = NULL; - __CFSpinLock(&userDefaultsLock); - defs = userDefaults; - __CFSpinUnlock(&userDefaultsLock); - CF_OBJC_KVO_WILLCHANGE(defs, key); _CFPreferencesDomainSet(domain, key, value); _CFApplicationPreferencesDomainHasChanged(domain); - CF_OBJC_KVO_DIDCHANGE(defs, key); } } -void CFPreferencesSetMultiple(CFDictionaryRef keysToSet, CFArrayRef keysToRemove, CFStringRef appName, CFStringRef userName, CFStringRef hostName) { +void CFPreferencesSetMultiple(CFDictionaryRef keysToSet, CFArrayRef keysToRemove, CFStringRef appName, CFStringRef user, CFStringRef host) { CFPreferencesDomainRef domain; CFIndex idx, count; - CFAssert1(appName != NULL && userName != NULL && hostName != NULL, __kCFLogAssertion, "%s(): Cannot access preferences for a NULL application name, user, or host", __PRETTY_FUNCTION__); + CFAssert1(appName != NULL && user != NULL && host != NULL, __kCFLogAssertion, "%s(): Cannot access preferences for a NULL application name, user, or host", __PRETTY_FUNCTION__); if (keysToSet) __CFGenericValidateType(keysToSet, CFDictionaryGetTypeID()); if (keysToRemove) __CFGenericValidateType(keysToRemove, CFArrayGetTypeID()); __CFGenericValidateType(appName, CFStringGetTypeID()); - __CFGenericValidateType(userName, CFStringGetTypeID()); - __CFGenericValidateType(hostName, CFStringGetTypeID()); + __CFGenericValidateType(user, CFStringGetTypeID()); + __CFGenericValidateType(host, CFStringGetTypeID()); CFTypeRef *keys = NULL; CFTypeRef *values; CFIndex numOfKeysToSet = 0; - domain = _CFPreferencesStandardDomain(appName, userName, hostName); + domain = _CFPreferencesStandardDomain(appName, user, host); if (!domain) return; CFAllocatorRef alloc = CFGetAllocator(domain); - void *defs = NULL; - - __CFSpinLock(&userDefaultsLock); - defs = userDefaults; - __CFSpinUnlock(&userDefaultsLock); if (keysToSet && (count = CFDictionaryGetCount(keysToSet))) { numOfKeysToSet = count; - keys = CFAllocatorAllocate(alloc, 2*count*sizeof(CFTypeRef), 0); + keys = (CFTypeRef *)CFAllocatorAllocate(alloc, 2*count*sizeof(CFTypeRef), 0); if (keys) { values = &(keys[count]); CFDictionaryGetKeysAndValues(keysToSet, keys, values); for (idx = 0; idx < count; idx ++) { - CF_OBJC_KVO_WILLCHANGE(defs, keys[idx]); - _CFPreferencesDomainSet(domain, keys[idx], values[idx]); + _CFPreferencesDomainSet(domain, (CFStringRef)keys[idx], values[idx]); } } } if (keysToRemove && (count = CFArrayGetCount(keysToRemove))) { for (idx = 0; idx < count; idx ++) { - CFStringRef removedKey = CFArrayGetValueAtIndex(keysToRemove, idx); - CF_OBJC_KVO_WILLCHANGE(defs, removedKey); + CFStringRef removedKey = (CFStringRef)CFArrayGetValueAtIndex(keysToRemove, idx); _CFPreferencesDomainSet(domain, removedKey, NULL); } } @@ -275,20 +290,6 @@ void CFPreferencesSetMultiple(CFDictionaryRef keysToSet, CFArrayRef keysToRemove _CFApplicationPreferencesDomainHasChanged(domain); - // here, we have to do things in reverse order. - if(keysToRemove) { - count = CFArrayGetCount(keysToRemove); - for(idx = count - 1; idx >= 0; idx--) { - CF_OBJC_KVO_DIDCHANGE(defs, CFArrayGetValueAtIndex(keysToRemove, idx)); - } - } - - if(numOfKeysToSet > 0) { - for(idx = numOfKeysToSet - 1; idx >= 0; idx--) { - CF_OBJC_KVO_DIDCHANGE(defs, keys[idx]); - } - } - if(keys) CFAllocatorDeallocate(alloc, keys); } @@ -296,41 +297,41 @@ Boolean CFPreferencesSynchronize(CFStringRef appName, CFStringRef user, CFStri CFPreferencesDomainRef domain; CFAssert1(appName != NULL && user != NULL && host != NULL, __kCFLogAssertion, "%s(): Cannot access preferences for a NULL application name, user, or host", __PRETTY_FUNCTION__); - __CFPreferencesCheckFormatType(); - domain = _CFPreferencesStandardDomain(appName, user, host); if(domain) _CFApplicationPreferencesDomainHasChanged(domain); return domain ? _CFPreferencesDomainSynchronize(domain) : false; } -CFArrayRef CFPreferencesCopyApplicationList(CFStringRef userName, CFStringRef hostName) { +CFArrayRef CFPreferencesCopyApplicationList(CFStringRef user, CFStringRef host) { CFArrayRef array; - CFAssert1(userName != NULL && hostName != NULL, __kCFLogAssertion, "%s(): Cannot access preferences for a NULL user or host", __PRETTY_FUNCTION__); - array = _CFPreferencesCreateDomainList(userName, hostName); + CFAssert1(user != NULL && host != NULL, __kCFLogAssertion, "%s(): Cannot access preferences for a NULL user or host", __PRETTY_FUNCTION__); + array = _CFPreferencesCreateDomainList(user, host); return array; } -CFArrayRef CFPreferencesCopyKeyList(CFStringRef appName, CFStringRef userName, CFStringRef hostName) { +CFArrayRef CFPreferencesCopyKeyList(CFStringRef appName, CFStringRef user, CFStringRef host) { CFPreferencesDomainRef domain; - CFAssert1(appName != NULL && userName != NULL && hostName != NULL, __kCFLogAssertion, "%s(): Cannot access preferences for a NULL application name, user, or host", __PRETTY_FUNCTION__); + CFAssert1(appName != NULL && user != NULL && host != NULL, __kCFLogAssertion, "%s(): Cannot access preferences for a NULL application name, user, or host", __PRETTY_FUNCTION__); - domain = _CFPreferencesStandardDomain(appName, userName, hostName); + domain = _CFPreferencesStandardDomain(appName, user, host); if (!domain) { return NULL; } else { - void **buf = NULL; - CFAllocatorRef alloc = __CFPreferencesAllocator(); CFArrayRef result; - CFIndex numPairs = 0; - _CFPreferencesDomainGetKeysAndValues(alloc, domain, &buf, &numPairs); - if (numPairs == 0) { + + CFAllocatorRef alloc = __CFPreferencesAllocator(); + CFDictionaryRef d = _CFPreferencesDomainDeepCopyDictionary(domain); + CFIndex count = d ? CFDictionaryGetCount(d) : 0; + CFTypeRef *keys = (CFTypeRef *)CFAllocatorAllocate(alloc, count * sizeof(CFTypeRef), 0); + if (d) CFDictionaryGetKeysAndValues(d, keys, NULL); + if (count == 0) { result = NULL; } else { - // It would be nice to avoid this allocation.... - result = CFArrayCreate(alloc, (const void **)buf, numPairs, &kCFTypeArrayCallBacks); - CFAllocatorDeallocate(alloc, buf); + result = CFArrayCreate(alloc, keys, count, &kCFTypeArrayCallBacks); } + CFAllocatorDeallocate(alloc, keys); + if (d) CFRelease(d); return result; } } @@ -341,11 +342,11 @@ CFArrayRef CFPreferencesCopyKeyList(CFStringRef appName, CFStringRef userName /****************************/ static CFStringRef __CFPreferencesDomainCopyDescription(CFTypeRef cf) { - return CFStringCreateWithFormat(__CFPreferencesAllocator(), NULL, CFSTR("\n"), (UInt32)cf); + return CFStringCreateWithFormat(__CFPreferencesAllocator(), NULL, CFSTR("\n"), cf); } static void __CFPreferencesDomainDeallocate(CFTypeRef cf) { - const struct __CFPreferencesDomain *domain = cf; + const struct __CFPreferencesDomain *domain = (struct __CFPreferencesDomain *)cf; CFAllocatorRef alloc = __CFPreferencesAllocator(); domain->_callBacks->freeDomain(alloc, domain->_context, domain->_domain); if (domain->_context) CFRelease(domain->_context); @@ -371,24 +372,25 @@ __private_extern__ void __CFPreferencesDomainInitialize(void) { } /* We spend a lot of time constructing these prefixes; we should cache. REW, 7/19/99 */ -__private_extern__ CFStringRef _CFPreferencesCachePrefixForUserHost(CFStringRef userName, CFStringRef hostName) { - Boolean freeHost = false; - CFStringRef result; +static CFStringRef _CFPreferencesCachePrefixForUserHost(CFStringRef userName, CFStringRef hostName) { + if (userName == kCFPreferencesAnyUser && hostName == kCFPreferencesAnyHost) { + return (CFStringRef)CFRetain(CFSTR("*/*/")); + } + CFMutableStringRef result = CFStringCreateMutable(__CFPreferencesAllocator(), 0); if (userName == kCFPreferencesCurrentUser) { userName = CFGetUserName(); + CFStringAppend(result, userName); + CFStringAppend(result, CFSTR("/")); } else if (userName == kCFPreferencesAnyUser) { - userName = CFSTR("*"); + CFStringAppend(result, CFSTR("*/")); } - if (hostName == kCFPreferencesCurrentHost) { - hostName = __CFCopyEthernetAddrString(); - if (!hostName) hostName = _CFStringCreateHostName(); - freeHost = true; + CFStringRef hostID = _CFPreferencesGetByHostIdentifierString(); + CFStringAppend(result, hostID); + CFStringAppend(result, CFSTR("/")); } else if (hostName == kCFPreferencesAnyHost) { - hostName = CFSTR("*"); + CFStringAppend(result, CFSTR("*/")); } - result = CFStringCreateWithFormat(__CFPreferencesAllocator(), NULL, CFSTR("%@/%@/"), userName, hostName); - if (freeHost && hostName != NULL) CFRelease(hostName); return result; } @@ -404,26 +406,10 @@ static CFStringRef _CFPreferencesStandardDomainCacheKey(CFStringRef domainName return result; } -#if defined(__MACOS8__) -// Define a custom hash function so that we don't inadvertantly make the -// result of CFHash() on a string persistent, and locked-in for all time. -static UInt16 hashString(CFStringRef str) { - UInt32 h = 0; - CFIndex idx, cnt; - cnt = CFStringGetLength(str); - h = cnt; - for (idx = 0; idx < cnt; idx++) { - h <<= 2; - h += CFStringGetCharacterAtIndex(str, idx); - } - return (h >> 16) ^ (h & 0xFFFF); -} -#endif - static CFURLRef _CFPreferencesURLForStandardDomainWithSafetyLevel(CFStringRef domainName, CFStringRef userName, CFStringRef hostName, unsigned long safeLevel) { CFURLRef theURL = NULL; CFAllocatorRef prefAlloc = __CFPreferencesAllocator(); -#if defined(__MACH__) +#if (DEPLOYMENT_TARGET_MACOSX) || defined(__WIN32__) CFURLRef prefDir = _preferencesDirectoryForUserHostSafetyLevel(userName, hostName, safeLevel); CFStringRef appName; CFStringRef fileName; @@ -445,12 +431,10 @@ static CFURLRef _CFPreferencesURLForStandardDomainWithSafetyLevel(CFStringRef do if (hostName == kCFPreferencesAnyHost) { fileName = CFStringCreateWithFormat(prefAlloc, NULL, CFSTR("%@.plist"), appName); } else if (hostName == kCFPreferencesCurrentHost) { - CFStringRef host = __CFCopyEthernetAddrString(); - if (!host) host = _CFStringCreateHostName(); - fileName = CFStringCreateWithFormat(prefAlloc, NULL, CFSTR("%@.%@.plist"), appName, host); - CFRelease(host); + CFStringRef hostID = _CFPreferencesGetByHostIdentifierString(); + fileName = CFStringCreateWithFormat(prefAlloc, NULL, CFSTR("%@.%@.plist"), appName, hostID); } else { - fileName = CFStringCreateWithFormat(prefAlloc, NULL, CFSTR("%@.%@.plist"), appName, hostName); + fileName = CFStringCreateWithFormat(prefAlloc, NULL, CFSTR("%@.%@.plist"), appName, hostName); // sketchy - this allows someone to set an arbitrary hostname. } } else { fileName = CFStringCreateWithFormat(prefAlloc, NULL, CFSTR("%@.plist"), appName); @@ -464,7 +448,7 @@ static CFURLRef _CFPreferencesURLForStandardDomainWithSafetyLevel(CFStringRef do CFRelease(fileName); } #else -#error Do not know where to store NSUserDefaults on this platform +//#error Do not know where to store NSUserDefaults on this platform #endif return theURL; } @@ -487,9 +471,10 @@ CFPreferencesDomainRef _CFPreferencesStandardDomain(CFStringRef domainName, CFS __CFSpinUnlock(&domainCacheLock); if (!domain) { // Domain's not in the cache; load from permanent storage - CFURLRef theURL = _CFPreferencesURLForStandardDomain(domainName, userName, hostName); + CFURLRef theURL = _CFPreferencesURLForStandardDomain(domainName, userName, hostName); if (theURL) { - domain = _CFPreferencesDomainCreate(theURL, &__kCFXMLPropertyListDomainCallBacks); + domain = _CFPreferencesDomainCreate(theURL, &__kCFXMLPropertyListDomainCallBacks); + if (userName == kCFPreferencesAnyUser) { _CFPreferencesDomainSetIsWorldReadable(domain, true); } @@ -544,39 +529,6 @@ __private_extern__ void _CFPreferencesPurgeDomainCache(void) { } __private_extern__ CFArrayRef _CFPreferencesCreateDomainList(CFStringRef userName, CFStringRef hostName) { -#if 0 && defined(__WIN32__) - DWORD idx, numSubkeys, maxSubKey, cnt; - CFMutableArrayRef retVal; - LONG result; - id *list, buffer[512]; - result = RegQueryInfoKeyA(_masterKey, NULL, NULL, NULL, &numSubkeys, &maxSubKey, NULL, NULL, NULL, NULL, NULL, NULL); - if (result != ERROR_SUCCESS) { - NSLog(@"%@: cannot query master key info; %d", _NSMethodExceptionProem(self, _cmd), result); - return [NSArray array]; - } - maxSubKey++; - list = (numSubkeys <= 512) ? buffer : NSZoneMalloc(NULL, numSubkeys * sizeof(void *)); - if (_useCStringDomains < 0) - _useCStringDomains = (NSWindows95OperatingSystem == [[NSProcessInfo processInfo] operatingSystem]); - if (_useCStringDomains) { - for (idx = 0, cnt = 0; idx < numSubkeys; idx++) { - char name[maxSubKey + 1]; - DWORD nameSize = maxSubKey; - if (RegEnumKeyExA(_masterKey, idx, name, &nameSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) - list[cnt++] = [NSString stringWithCString:name length:nameSize]; - } - } else { - for (idx = 0, cnt = 0; idx < numSubkeys; idx++) { - unichar name[maxSubKey + 1]; - DWORD nameSize = maxSubKey; - if (RegEnumKeyExW(_masterKey, idx, name, &nameSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) - list[cnt++] = [NSString stringWithCharacters:name length:nameSize]; - } - } - retVal = [NSArray arrayWithObjects:list count:cnt]; - if (list != buffer) NSZoneFree(NULL, list); - return retVal; -#elif defined(__MACH__) || defined(__svr4__) || defined(__hpux__) CFAllocatorRef prefAlloc = __CFPreferencesAllocator(); CFArrayRef domains; CFMutableArrayRef marray; @@ -586,23 +538,21 @@ __private_extern__ CFArrayRef _CFPreferencesCreateDomainList(CFStringRef userN CFStringRef suffix; UInt32 suffixLen; CFURLRef prefDir = _preferencesDirectoryForUserHost(userName, hostName); - + if (!prefDir) { return NULL; } if (hostName == kCFPreferencesAnyHost) { suffix = CFStringCreateWithCString(prefAlloc, ".plist", kCFStringEncodingASCII); } else if (hostName == kCFPreferencesCurrentHost) { - CFStringRef host = __CFCopyEthernetAddrString(); - if (!host) host = _CFStringCreateHostName(); - suffix = CFStringCreateWithFormat(prefAlloc, NULL, CFSTR(".%@.plist"), host); - CFRelease(host); + CFStringRef hostID = _CFPreferencesGetByHostIdentifierString(); + suffix = CFStringCreateWithFormat(prefAlloc, NULL, CFSTR(".%@.plist"), hostID); } else { - suffix = CFStringCreateWithFormat(prefAlloc, NULL, CFSTR(".%@.plist"), hostName); + suffix = CFStringCreateWithFormat(prefAlloc, NULL, CFSTR(".%@.plist"), hostName); // sketchy - this allows someone to create a domain list for an arbitrary hostname. } suffixLen = CFStringGetLength(suffix); - - domains = CFURLCreatePropertyFromResource(prefAlloc, prefDir, kCFURLFileDirectoryContents, NULL); + + domains = (CFArrayRef)CFURLCreatePropertyFromResource(prefAlloc, prefDir, kCFURLFileDirectoryContents, NULL); CFRelease(prefDir); if (domains){ marray = CFArrayCreateMutableCopy(prefAlloc, 0, domains); @@ -611,7 +561,7 @@ __private_extern__ CFArrayRef _CFPreferencesCreateDomainList(CFStringRef userN marray = CFArrayCreateMutable(prefAlloc, 0, & kCFTypeArrayCallBacks); } for (idx = CFArrayGetCount(marray)-1; idx >= 0; idx --) { - CFURLRef url = CFArrayGetValueAtIndex(marray, idx); + CFURLRef url = (CFURLRef)CFArrayGetValueAtIndex(marray, idx); CFStringRef string = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle); if (!CFStringHasSuffix(string, suffix)) { CFArrayRemoveValueAtIndex(marray, idx); @@ -627,7 +577,7 @@ __private_extern__ CFArrayRef _CFPreferencesCreateDomainList(CFStringRef userN CFRelease(string); } CFRelease(suffix); - + // Now add any domains added in the cache; delete any that have been deleted in the cache __CFSpinLock(&domainCacheLock); if (!domainCache) { @@ -635,7 +585,7 @@ __private_extern__ CFArrayRef _CFPreferencesCreateDomainList(CFStringRef userN return marray; } cnt = CFDictionaryGetCount(domainCache); - cachedDomainKeys = CFAllocatorAllocate(prefAlloc, 2 * cnt * sizeof(CFStringRef), 0); + cachedDomainKeys = (CFStringRef *)CFAllocatorAllocate(prefAlloc, 2 * cnt * sizeof(CFStringRef), 0); cachedDomains = (CFPreferencesDomainRef *)(cachedDomainKeys + cnt); CFDictionaryGetKeysAndValues(domainCache, (const void **)cachedDomainKeys, (const void **)cachedDomains); __CFSpinUnlock(&domainCacheLock); @@ -647,17 +597,19 @@ __private_extern__ CFArrayRef _CFPreferencesCreateDomainList(CFStringRef userN CFPreferencesDomainRef domain = cachedDomains[idx]; CFStringRef domainName; CFIndex keyCount = 0; - + if (!CFStringHasPrefix(domainKey, suffix)) continue; domainName = CFStringCreateWithSubstring(prefAlloc, domainKey, CFRangeMake(suffixLen, CFStringGetLength(domainKey) - suffixLen)); if (CFEqual(domainName, CFSTR("*"))) { CFRelease(domainName); - domainName = CFRetain(kCFPreferencesAnyApplication); + domainName = (CFStringRef)CFRetain(kCFPreferencesAnyApplication); } else if (CFEqual(domainName, kCFPreferencesCurrentApplication)) { CFRelease(domainName); - domainName = CFRetain(_CFProcessNameString()); + domainName = (CFStringRef)CFRetain(_CFProcessNameString()); } - _CFPreferencesDomainGetKeysAndValues(kCFAllocatorNull, domain, NULL, &keyCount); + CFDictionaryRef d = _CFPreferencesDomainDeepCopyDictionary(domain); + keyCount = d ? CFDictionaryGetCount(d) : 0; + if (keyCount) CFRelease(d); if (keyCount == 0) { // Domain was deleted SInt32 firstIndexOfValue = CFArrayGetFirstIndexOfValue(marray, CFRangeMake(0, CFArrayGetCount(marray)), domainName); @@ -672,8 +624,6 @@ __private_extern__ CFArrayRef _CFPreferencesCreateDomainList(CFStringRef userN CFRelease(suffix); CFAllocatorDeallocate(prefAlloc, cachedDomainKeys); return marray; -#else -#endif } // @@ -706,62 +656,40 @@ __private_extern__ Boolean _CFPreferencesDomainSynchronize(CFPreferencesDomainRe return domain->_callBacks->synchronize(domain->_context, domain->_domain); } -__private_extern__ void _CFPreferencesDomainGetKeysAndValues(CFAllocatorRef alloc, CFPreferencesDomainRef domain, void **buf[], CFIndex *numKeyValuePairs) { - domain->_callBacks->getKeysAndValues(alloc, domain->_context, domain->_domain, buf, numKeyValuePairs); -} - __private_extern__ void _CFPreferencesDomainSetIsWorldReadable(CFPreferencesDomainRef domain, Boolean isWorldReadable) { if (domain->_callBacks->setIsWorldReadable) { domain->_callBacks->setIsWorldReadable(domain->_context, domain->_domain, isWorldReadable); } } +__private_extern__ void *_CFPreferencesDomainCopyDictFunc(CFPreferencesDomainRef domain) { + return domain->_callBacks->copyDomainDictionary; +} + void _CFPreferencesDomainSetDictionary(CFPreferencesDomainRef domain, CFDictionaryRef dict) { - CFTypeRef buf[32], *keys = buf; - CFIndex idx, count = 16; CFAllocatorRef alloc = __CFPreferencesAllocator(); - - _CFPreferencesDomainGetKeysAndValues(kCFAllocatorNull, domain, (void ***)(&keys), &count); - if (count > 16) { - // Have to allocate - keys = NULL; - count = 0; - _CFPreferencesDomainGetKeysAndValues(alloc, domain, (void ***)(&keys), &count); - } + CFDictionaryRef d = _CFPreferencesDomainDeepCopyDictionary(domain); + CFIndex idx, count = d ? CFDictionaryGetCount(d) : 0; + + CFTypeRef *keys = (CFTypeRef *)CFAllocatorAllocate(alloc, count * sizeof(CFTypeRef), 0); + if (d) CFDictionaryGetKeysAndValues(d, keys, NULL); for (idx = 0; idx < count; idx ++) { _CFPreferencesDomainSet(domain, (CFStringRef)keys[idx], NULL); } - if (keys != buf) { - CFAllocatorDeallocate(alloc, keys); - } + CFAllocatorDeallocate(alloc, keys); + if (d) CFRelease(d); if (dict && (count = CFDictionaryGetCount(dict)) != 0) { - CFStringRef *newKeys = (count < 32) ? buf : CFAllocatorAllocate(alloc, count * sizeof(CFStringRef), 0); + CFStringRef *newKeys = (CFStringRef *)CFAllocatorAllocate(alloc, count * sizeof(CFStringRef), 0); CFDictionaryGetKeysAndValues(dict, (const void **)newKeys, NULL); for (idx = 0; idx < count; idx ++) { CFStringRef key = newKeys[idx]; _CFPreferencesDomainSet(domain, key, (CFTypeRef)CFDictionaryGetValue(dict, key)); } - if (((CFTypeRef)newKeys) != buf) { CFAllocatorDeallocate(alloc, newKeys); - } } } -CFDictionaryRef _CFPreferencesDomainCopyDictionary(CFPreferencesDomainRef domain) { - CFTypeRef *keys = NULL; - CFIndex count = 0; - CFAllocatorRef alloc = __CFPreferencesAllocator(); - CFDictionaryRef dict = NULL; - _CFPreferencesDomainGetKeysAndValues(alloc, domain, (void ***)&keys, &count); - if (count && keys) { - CFTypeRef *values = keys + count; - dict = CFDictionaryCreate(alloc, keys, values, count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFAllocatorDeallocate(alloc, keys); - } - return dict; -} - CFDictionaryRef _CFPreferencesDomainDeepCopyDictionary(CFPreferencesDomainRef domain) { CFDictionaryRef result = domain->_callBacks->copyDomainDictionary(domain->_context, domain->_domain); if(result && CFDictionaryGetCount(result) == 0) { @@ -773,11 +701,11 @@ CFDictionaryRef _CFPreferencesDomainDeepCopyDictionary(CFPreferencesDomainRef do Boolean _CFPreferencesDomainExists(CFStringRef domainName, CFStringRef userName, CFStringRef hostName) { CFPreferencesDomainRef domain; - CFIndex count = 0; domain = _CFPreferencesStandardDomain(domainName, userName, hostName); if (domain) { - _CFPreferencesDomainGetKeysAndValues(kCFAllocatorNull, domain, NULL, &count); - return (count > 0); + CFDictionaryRef d = _CFPreferencesDomainDeepCopyDictionary(domain); + if (d) CFRelease(d); + return d != NULL; } else { return false; } @@ -820,9 +748,9 @@ static void getVolatileKeysAndValues(CFAllocatorRef alloc, CFTypeRef context, vo CFDictionaryGetKeysAndValues(dict, (const void **)*buf, (const void **)values); } else if (alloc != kCFAllocatorNull) { if (*buf) { - *buf = CFAllocatorReallocate(alloc, *buf, count * 2 * sizeof(void *), 0); + *buf = (void **)CFAllocatorReallocate(alloc, *buf, count * 2 * sizeof(void *), 0); } else { - *buf = CFAllocatorAllocate(alloc, count*2*sizeof(void *), 0); + *buf = (void **)CFAllocatorAllocate(alloc, count*2*sizeof(void *), 0); } if (*buf) { values = *buf + count; @@ -841,5 +769,3 @@ static CFDictionaryRef copyVolatileDomainDictionary(CFTypeRef context, void *vol } const _CFPreferencesDomainCallBacks __kCFVolatileDomainCallBacks = {createVolatileDomain, freeVolatileDomain, fetchVolatileValue, writeVolatileValue, synchronizeVolatileDomain, getVolatileKeysAndValues, copyVolatileDomainDictionary, NULL}; - - diff --git a/Preferences.subproj/CFPreferences.h b/CFPreferences.h similarity index 96% rename from Preferences.subproj/CFPreferences.h rename to CFPreferences.h index c3b1915..7383f11 100644 --- a/Preferences.subproj/CFPreferences.h +++ b/CFPreferences.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFPreferences.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFPREFERENCES__) @@ -31,9 +31,7 @@ #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN CF_EXPORT const CFStringRef kCFPreferencesAnyApplication; @@ -139,9 +137,7 @@ CF_EXPORT CFArrayRef CFPreferencesCopyKeyList(CFStringRef applicationID, CFStringRef userName, CFStringRef hostName); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFPREFERENCES__ */ diff --git a/Base.subproj/CFPriv.h b/CFPriv.h similarity index 66% rename from Base.subproj/CFPriv.h rename to CFPriv.h index 1df483f..ae662c9 100644 --- a/Base.subproj/CFPriv.h +++ b/CFPriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFPriv.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ /* @@ -39,16 +39,25 @@ #include +#if defined(__MACH__) +#include +#endif + #if defined(__MACH__) || defined(__WIN32__) #include -#include #include #endif -#if defined(__cplusplus) -extern "C" { +#if defined(__MACH__) +#include #endif +#if 0 +#include +#endif + +CF_EXTERN_C_BEGIN + CF_EXPORT intptr_t _CFDoOperation(intptr_t code, intptr_t subcode1, intptr_t subcode2); CF_EXPORT void _CFRuntimeSetCFMPresent(void *a); @@ -69,17 +78,19 @@ CF_EXPORT void _CFRunLoopAddModeToMode(CFRunLoopRef rl, CFStringRef modeName, CF CF_EXPORT void _CFRunLoopRemoveModeFromMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef fromModeName); CF_EXPORT void _CFRunLoopStopMode(CFRunLoopRef rl, CFStringRef modeName); +#if defined(__MACH__) CF_EXPORT CFIndex CFMachPortGetQueuedMessageCount(CFMachPortRef mp); +#endif CF_EXPORT CFPropertyListRef _CFURLCopyPropertyListRepresentation(CFURLRef url); CF_EXPORT CFURLRef _CFURLCreateFromPropertyListRepresentation(CFAllocatorRef alloc, CFPropertyListRef pListRepresentation); -#endif /* __MACH__ */ +#endif +CF_EXPORT CFPropertyListRef _CFURLCopyPropertyListRepresentation(CFURLRef url); +CF_EXPORT CFURLRef _CFURLCreateFromPropertyListRepresentation(CFAllocatorRef alloc, CFPropertyListRef pListRepresentation); CF_EXPORT void CFPreferencesFlushCaches(void); -CF_EXPORT CFTimeInterval _CFTimeZoneGetDSTOffset(CFTimeZoneRef tz, CFAbsoluteTime at); -CF_EXPORT CFAbsoluteTime _CFTimeZoneGetNextDSTSwitch(CFTimeZoneRef tz, CFAbsoluteTime at); - +#if !__LP64__ #if !defined(__WIN32__) struct FSSpec; CF_EXPORT @@ -88,13 +99,15 @@ Boolean _CFGetFSSpecFromURL(CFAllocatorRef alloc, CFURLRef url, struct FSSpec *s CF_EXPORT CFURLRef _CFCreateURLFromFSSpec(CFAllocatorRef alloc, const struct FSSpec *voidspec, Boolean isDirectory); #endif +#endif #if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED -typedef enum { +enum { kCFURLComponentDecompositionNonHierarchical, kCFURLComponentDecompositionRFC1808, /* use this for RFC 1738 decompositions as well */ kCFURLComponentDecompositionRFC2396 -} CFURLComponentDecomposition; +}; +typedef CFIndex CFURLComponentDecomposition; typedef struct { CFStringRef scheme; @@ -152,6 +165,12 @@ CFStringRef CFGetUserName(void); CF_EXPORT CFURLRef CFCopyHomeDirectoryURLForUser(CFStringRef uName); /* Pass NULL for the current user's home directory */ + +/* Extra user notification key for iPhone */ +CF_EXPORT +const CFStringRef kCFUserNotificationKeyboardTypesKey AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; + + /* CFCopySearchPathForDirectoriesInDomains returns the various standard system directories where apps, resources, etc get @@ -166,7 +185,7 @@ CFURLRef CFCopyHomeDirectoryURLForUser(CFStringRef uName); /* Pass NULL for the directories! ??? On MacOS 8 this function currently returns an empty array. */ -typedef enum { +enum { kCFApplicationDirectory = 1, /* supported applications (Applications) */ kCFDemoApplicationDirectory, /* unsupported applications, demonstration versions (Demos) */ kCFDeveloperApplicationDirectory, /* developer applications (Developer/Applications) */ @@ -178,15 +197,17 @@ typedef enum { kCFDocumentDirectory, /* documents (Library/Documents) */ kCFAllApplicationsDirectory = 100, /* all directories where applications can occur (ie Applications, Demos, Administration, Developer/Applications) */ kCFAllLibrariesDirectory = 101 /* all directories where resources can occur (Library, Developer) */ -} CFSearchPathDirectory; +}; +typedef CFIndex CFSearchPathDirectory; -typedef enum { +enum { kCFUserDomainMask = 1, /* user's home directory --- place to install user's personal items (~) */ kCFLocalDomainMask = 2, /* local to the current machine --- place to install items available to everyone on this machine (/Local) */ kCFNetworkDomainMask = 4, /* publically available location in the local area network --- place to install items available on the network (/Network) */ kCFSystemDomainMask = 8, /* provided by Apple, unmodifiable (/System) */ kCFAllDomainsMask = 0x0ffff /* all domains: all of the above and more, future items */ -} CFSearchPathDomainMask; +}; +typedef CFOptionFlags CFSearchPathDomainMask; CF_EXPORT CFArrayRef CFCopySearchPathForDirectoriesInDomains(CFSearchPathDirectory directory, CFSearchPathDomainMask domainMask, Boolean expandTilde); @@ -214,18 +235,46 @@ CF_EXPORT const CFStringRef _kCFSystemVersionBuildVersionKey; CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionStringKey; // Localized string for the string "Version" CF_EXPORT const CFStringRef _kCFSystemVersionBuildStringKey; // Localized string for the string "Build" -typedef enum { - kCFStringGramphemeCluster = 1, /* Unicode Grapheme Cluster (not different from kCFStringComposedCharacterCluster right now) */ + +CF_EXPORT void CFMergeSortArray(void *list, CFIndex count, CFIndex elementSize, CFComparatorFunction comparator, void *context); +CF_EXPORT void CFQSortArray(void *list, CFIndex count, CFIndex elementSize, CFComparatorFunction comparator, void *context); + +/* _CFExecutableLinkedOnOrAfter(releaseVersionName) will return YES if the current executable seems to be linked on or after the specified release. Example: If you specify CFSystemVersionPuma (10.1), you will get back true for executables linked on Puma or Jaguar(10.2), but false for those linked on Cheetah (10.0) or any of its software updates (10.0.x). You will also get back false for any app whose version info could not be figured out. + This function caches its results, so no need to cache at call sites. + + Note that for non-MACH this function always returns true. +*/ +enum { + CFSystemVersionCheetah = 0, /* 10.0 */ + 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, /* Post-Tiger */ + CFSystemVersionChablis = 5, /* Deprecated name for Leopard */ + CFSystemVersionMax /* This should bump up when new entries are added */ +}; +typedef CFIndex CFSystemVersion; + +CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version); + + +enum { + kCFStringGraphemeCluster = 1, /* Unicode Grapheme Cluster */ kCFStringComposedCharacterCluster = 2, /* Compose all non-base (including spacing marks) */ kCFStringCursorMovementCluster = 3, /* Cluster suitable for cursor movements */ kCFStringBackwardDeletionCluster = 4 /* Cluster suitable for backward deletion */ -} CFStringCharacterClusterType; +}; +typedef CFIndex CFStringCharacterClusterType; CF_EXPORT CFRange CFStringGetRangeOfCharacterClusterAtIndex(CFStringRef string, CFIndex charIndex, CFStringCharacterClusterType type); +// Compatibility kCFCompare flags. Use the new public kCFCompareDiacriticInsensitive enum { - kCFCompareDiacriticsInsensitive = (1 << 28), - kCFCompareWidthInsensitive = (1 << 29), + kCFCompareDiacriticsInsensitive = 128, /* kCFCompareDiacriticInsensitive */ + kCFCompareDiacriticsInsensitiveCompatibilityMask = ((1 << 28)|kCFCompareDiacriticsInsensitive), }; /* CFStringEncoding SPI */ @@ -257,14 +306,14 @@ CF_INLINE void CFStringGetCharactersFromInlineBuffer(CFStringInlineBuffer *buf, memmove(outBuf, buf->directBuffer + buf->rangeToBuffer.location + desiredRange.location, desiredRange.length * sizeof(UniChar)); } else { if ((desiredRange.location >= buf->bufferedRangeStart) && (desiredRange.location < buf->bufferedRangeEnd)) { - int bufLen = desiredRange.length; + CFIndex bufLen = desiredRange.length; if (bufLen > (buf->bufferedRangeEnd - desiredRange.location)) bufLen = (buf->bufferedRangeEnd - desiredRange.location); memmove(outBuf, buf->buffer + (desiredRange.location - buf->bufferedRangeStart), bufLen * sizeof(UniChar)); outBuf += bufLen; desiredRange.location += bufLen; desiredRange.length -= bufLen; } else { - int desiredRangeMax = (desiredRange.location + desiredRange.length); + CFIndex desiredRangeMax = (desiredRange.location + desiredRange.length); if ((desiredRangeMax > buf->bufferedRangeStart) && (desiredRangeMax < buf->bufferedRangeEnd)) { desiredRange.length = (buf->bufferedRangeStart - desiredRange.location); @@ -285,9 +334,92 @@ CF_INLINE void CFStringGetCharactersFromInlineBuffer(CFStringInlineBuffer *buf, #endif /* CF_INLINE */ -#if defined(__cplusplus) +/* + CFCharacterSetInlineBuffer related declarations + */ +/*! +@typedef CFCharacterSetInlineBuffer + @field cset The character set this inline buffer is initialized with. + The object is not retained by the structure. + @field flags The field is a bit mask that carries various settings. + @field rangeStart The beginning of the character range that contains all members. + It is guaranteed that there is no member below this value. + @field rangeLimit The end of the character range that contains all members. + It is guaranteed that there is no member above and equal to this value. + @field bitmap The bitmap data representing the membership of the Basic Multilingual Plane characters. + If NULL, all BMP characters inside the range are members of the character set. + */ +typedef struct { + CFCharacterSetRef cset; + uint32_t flags; + uint32_t rangeStart; + uint32_t rangeLimit; + const uint8_t *bitmap; +} CFCharacterSetInlineBuffer; + +// Bits for flags field +enum { + kCFCharacterSetIsCompactBitmap = (1 << 0), + kCFCharacterSetNoBitmapAvailable = (1 << 1), + kCFCharacterSetIsInverted = (1 << 2) +}; + +/*! +@function CFCharacterSetInitInlineBuffer + Initializes buffer with cset. + @param cset The character set used to initialized the buffer. + If this parameter is not a valid CFCharacterSet, the behavior is undefined. + @param buffer The reference to the inline buffer to be initialized. + */ +CF_EXPORT +void CFCharacterSetInitInlineBuffer(CFCharacterSetRef cset, CFCharacterSetInlineBuffer *buffer); + +/*! +@function CFCharacterSetInlineBufferIsLongCharacterMember + Reports whether or not the UTF-32 character is in the character set. + @param buffer The reference to the inline buffer to be searched. + @param character The UTF-32 character for which to test against the + character set. + @result true, if the value is in the character set, otherwise false. + */ +#if defined(CF_INLINE) +CF_INLINE bool CFCharacterSetInlineBufferIsLongCharacterMember(CFCharacterSetInlineBuffer *buffer, UTF32Char character) { + bool isInverted = ((0 == (buffer->flags & kCFCharacterSetIsInverted)) ? false : true); + + if ((character >= buffer->rangeStart) && (character < buffer->rangeLimit)) { + if ((character > 0xFFFF) || (0 != (buffer->flags & kCFCharacterSetNoBitmapAvailable))) return (CFCharacterSetIsLongCharacterMember(buffer->cset, character) != 0); + if (NULL == buffer->bitmap) { + if (0 == (buffer->flags & kCFCharacterSetIsCompactBitmap)) isInverted = !isInverted; + } else if (0 == (buffer->flags & kCFCharacterSetIsCompactBitmap)) { + if (buffer->bitmap[character >> 3] & (1 << (character & 7))) isInverted = !isInverted; + } else { + uint8_t value = buffer->bitmap[character >> 8]; + + if (value == 0xFF) { + isInverted = !isInverted; + } else if (value > 0) { + const uint8_t *segment = buffer->bitmap + (256 + (32 * (value - 1))); + character &= 0xFF; + if (segment[character >> 3] & (1 << (character % 8))) isInverted = !isInverted; + } + } + } + return isInverted; } +#else /* CF_INLINE */ +#define CFCharacterSetInlineBufferIsLongCharacterMember(buffer, character) (CFCharacterSetIsLongCharacterMember(buffer->cset, character)) +#endif /* CF_INLINE */ + + +#if defined(__MACH__) +#include + +CFMessagePortRef CFMessagePortCreatePerProcessLocal(CFAllocatorRef allocator, CFStringRef name, CFMessagePortCallBack callout, CFMessagePortContext *context, Boolean *shouldFreeInfo); +CFMessagePortRef CFMessagePortCreatePerProcessRemote(CFAllocatorRef allocator, CFStringRef name, CFIndex pid); #endif + +CF_EXTERN_C_END + #endif /* ! __COREFOUNDATION_CFPRIV__ */ diff --git a/Parsing.subproj/CFPropertyList.c b/CFPropertyList.c similarity index 85% rename from Parsing.subproj/CFPropertyList.c rename to CFPropertyList.c index 087bd32..e3a5392 100644 --- a/Parsing.subproj/CFPropertyList.c +++ b/CFPropertyList.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -29,19 +29,21 @@ #include #include #include -#include "CFUtilitiesPriv.h" +#include "CFPriv.h" #include "CFStringEncodingConverter.h" #include "CFInternal.h" #include -#if defined(__MACH__) -#include -#endif // __MACH__ +#include #include #include #include #include #include #include +#if DEPLOYMENT_TARGET_MACOSX +#include +#include +#endif __private_extern__ bool allowMissingSemi = false; @@ -83,10 +85,43 @@ intptr_t _CFDoOperation(intptr_t code, intptr_t subcode1, intptr_t subcode2) { #define CDSECT_TAG_LENGTH 9 // 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(): 0x%x not of a property list type", __PRETTY_FUNCTION__, (UInt32)cf); +#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 CFTypeID stringtype = -1, datatype = -1, numbertype = -1, datetype = -1; +static CFTypeID booltype = -1, nulltype = -1, dicttype = -1, arraytype = -1, settype = -1; + +static void initStatics() { + if ((CFTypeID)-1 == stringtype) { + stringtype = CFStringGetTypeID(); + } + if ((CFTypeID)-1 == datatype) { + datatype = CFDataGetTypeID(); + } + if ((CFTypeID)-1 == numbertype) { + numbertype = CFNumberGetTypeID(); + } + if ((CFTypeID)-1 == booltype) { + booltype = CFBooleanGetTypeID(); + } + if ((CFTypeID)-1 == datetype) { + datetype = CFDateGetTypeID(); + } + if ((CFTypeID)-1 == dicttype) { + dicttype = CFDictionaryGetTypeID(); + } + if ((CFTypeID)-1 == arraytype) { + arraytype = CFArrayGetTypeID(); + } + if ((CFTypeID)-1 == settype) { + settype = CFSetGetTypeID(); + } + if ((CFTypeID)-1 == nulltype) { + nulltype = CFNullGetTypeID(); + } +} + struct context { bool answer; CFMutableSetRef set; @@ -97,7 +132,7 @@ static void __CFPropertyListIsArrayPlistAux(const void *value, void *context) { struct context *ctx = (struct context *)context; if (!ctx->answer) return; #if defined(DEBUG) - if (!value) CFLog(0, CFSTR("CFPropertyListIsValid(): property list arrays cannot contain NULL")); + if (!value) CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListIsValid(): property list arrays cannot contain NULL")); #endif ctx->answer = value && __CFPropertyListIsValidAux(value, true, ctx->set, ctx->format); } @@ -106,57 +141,59 @@ static void __CFPropertyListIsDictPlistAux(const void *key, const void *value, v struct context *ctx = (struct context *)context; if (!ctx->answer) return; #if defined(DEBUG) - if (!key) CFLog(0, CFSTR("CFPropertyListIsValid(): property list dictionaries cannot contain NULL keys")); - if (!value) CFLog(0, CFSTR("CFPropertyListIsValid(): property list dictionaries cannot contain NULL values")); - if (CFStringGetTypeID() != CFGetTypeID(key)) { + 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)) { CFStringRef desc = CFCopyTypeIDDescription(CFGetTypeID(key)); - CFLog(0, CFSTR("CFPropertyListIsValid(): property list dictionaries may only have keys which are CFStrings, not '%@'"), desc); + CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListIsValid(): property list dictionaries may only have keys which are CFStrings, not '%@'"), desc); CFRelease(desc); } #endif - ctx->answer = key && value && (CFStringGetTypeID() == CFGetTypeID(key)) && __CFPropertyListIsValidAux(value, true, ctx->set, ctx->format); + ctx->answer = key && value && (stringtype == CFGetTypeID(key)) && __CFPropertyListIsValidAux(value, true, ctx->set, ctx->format); } static bool __CFPropertyListIsValidAux(CFPropertyListRef plist, bool recursive, CFMutableSetRef set, CFPropertyListFormat format) { CFTypeID type; #if defined(DEBUG) - if (!plist) CFLog(0, CFSTR("CFPropertyListIsValid(): property lists cannot contain NULL")); + if (!plist) CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListIsValid(): property lists cannot contain NULL")); #endif if (!plist) return false; type = CFGetTypeID(plist); - if (CFStringGetTypeID() == type) return true; - if (CFDataGetTypeID() == type) return true; + if (stringtype == type) return true; + if (datatype == type) return true; if (kCFPropertyListOpenStepFormat != format) { - if (CFBooleanGetTypeID() == type) return true; - if (CFNumberGetTypeID() == type) return true; - if (CFDateGetTypeID() == type) return true; + if (booltype == type) return true; + if (numbertype == type) return true; + if (datetype == type) return true; +#if DEPLOYMENT_TARGET_MACOSX if (_CFKeyedArchiverUIDGetTypeID() == type) return true; +#endif } - if (!recursive && CFArrayGetTypeID() == type) return true; - if (!recursive && CFDictionaryGetTypeID() == type) return true; + 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(0, CFSTR("CFPropertyListIsValid(): property lists cannot contain recursive container references")); + if (CFSetContainsValue(set, plist)) CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListIsValid(): property lists cannot contain recursive container references")); #endif if (CFSetContainsValue(set, plist)) return false; - if (CFArrayGetTypeID() == type) { + if (arraytype == type) { struct context ctx = {true, set, format}; CFSetAddValue(set, plist); - CFArrayApplyFunction(plist, CFRangeMake(0, CFArrayGetCount(plist)), __CFPropertyListIsArrayPlistAux, &ctx); + CFArrayApplyFunction((CFArrayRef)plist, CFRangeMake(0, CFArrayGetCount((CFArrayRef)plist)), __CFPropertyListIsArrayPlistAux, &ctx); CFSetRemoveValue(set, plist); return ctx.answer; } - if (CFDictionaryGetTypeID() == type) { + if (dicttype == type) { struct context ctx = {true, set, format}; CFSetAddValue(set, plist); - CFDictionaryApplyFunction(plist, __CFPropertyListIsDictPlistAux, &ctx); + CFDictionaryApplyFunction((CFDictionaryRef)plist, __CFPropertyListIsDictPlistAux, &ctx); CFSetRemoveValue(set, plist); return ctx.answer; } #if defined(DEBUG) { CFStringRef desc = CFCopyTypeIDDescription(type); - CFLog(0, CFSTR("CFPropertyListIsValid(): property lists cannot contain objects of type '%@'"), desc); + CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListIsValid(): property lists cannot contain objects of type '%@'"), desc); CFRelease(desc); } #endif @@ -164,11 +201,10 @@ static bool __CFPropertyListIsValidAux(CFPropertyListRef plist, bool recursive, } Boolean CFPropertyListIsValid(CFPropertyListRef plist, CFPropertyListFormat format) { - CFMutableSetRef set; - bool result; + initStatics(); CFAssert1(plist != NULL, __kCFLogAssertion, "%s(): NULL is not a property list", __PRETTY_FUNCTION__); - set = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, NULL); - result = __CFPropertyListIsValidAux(plist, true, set, format); + CFMutableSetRef set = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, NULL); + bool result = __CFPropertyListIsValidAux(plist, true, set, format); CFRelease(set); return result; } @@ -233,8 +269,8 @@ static void _plistAppendCharacters(CFMutableDataRef mData, const UniChar *chars, if (curLoc < length) { // Now deal with non-ASCII chars CFDataRef data = NULL; CFStringRef str = NULL; - if ((str = CFStringCreateWithCharactersNoCopy(NULL, chars + curLoc, length - curLoc, kCFAllocatorNull))) { - if ((data = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0))) { + if ((str = CFStringCreateWithCharactersNoCopy(kCFAllocatorSystemDefault, chars + curLoc, length - curLoc, kCFAllocatorNull))) { + if ((data = CFStringCreateExternalRepresentation(kCFAllocatorSystemDefault, str, kCFStringEncodingUTF8, 0))) { CFDataAppendBytes (mData, CFDataGetBytePtr(data), CFDataGetLength(data)); CFRelease(data); } @@ -254,7 +290,7 @@ static void _plistAppendString(CFMutableDataRef mData, CFStringRef str) { _plistAppendCharacters(mData, chars, CFStringGetLength(str)); } else if ((cStr = CFStringGetCStringPtr(str, kCFStringEncodingASCII)) || (cStr = CFStringGetCStringPtr(str, kCFStringEncodingUTF8))) { _plistAppendUTF8CString(mData, cStr); - } else if ((data = CFStringCreateExternalRepresentation(NULL, str, kCFStringEncodingUTF8, 0))) { + } else if ((data = CFStringCreateExternalRepresentation(kCFAllocatorSystemDefault, str, kCFStringEncodingUTF8, 0))) { CFDataAppendBytes (mData, CFDataGetBytePtr(data), CFDataGetLength(data)); CFRelease(data); } else { @@ -270,7 +306,7 @@ static void _plistAppendFormat(CFMutableDataRef mData, CFStringRef format, ...) va_list argList; va_start(argList, format); - fStr = CFStringCreateWithFormatAndArguments(NULL, NULL, format, argList); + fStr = CFStringCreateWithFormatAndArguments(kCFAllocatorSystemDefault, NULL, format, argList); va_end(argList); CFAssert1(fStr, __kCFLogAssertion, "%s(): Error writing plist", __PRETTY_FUNCTION__); @@ -411,14 +447,15 @@ extern CFStringRef __CFNumberCopyFormattingDescriptionAsFloat64(CFTypeRef cf); static void _CFAppendXML0(CFTypeRef object, UInt32 indentation, CFMutableDataRef xmlString) { UInt32 typeID = CFGetTypeID(object); _appendIndents(indentation, xmlString); - if (typeID == CFStringGetTypeID()) { + if (typeID == stringtype) { _plistAppendUTF8CString(xmlString, "<"); _plistAppendCharacters(xmlString, CFXMLPlistTags[STRING_IX], STRING_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">"); - _appendEscapedString(object, xmlString); + _appendEscapedString((CFStringRef)object, xmlString); _plistAppendUTF8CString(xmlString, "\n"); +#if DEPLOYMENT_TARGET_MACOSX } else if (typeID == _CFKeyedArchiverUIDGetTypeID()) { _plistAppendUTF8CString(xmlString, "<"); _plistAppendCharacters(xmlString, CFXMLPlistTags[DICT_IX], DICT_TAG_LENGTH); @@ -436,7 +473,7 @@ static void _CFAppendXML0(CFTypeRef object, UInt32 indentation, CFMutableDataRef _plistAppendCharacters(xmlString, CFXMLPlistTags[INTEGER_IX], INTEGER_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">"); - uint64_t v = _CFKeyedArchiverUIDGetValue(object); + uint64_t v = _CFKeyedArchiverUIDGetValue((CFKeyedArchiverUIDRef)object); CFNumberRef num = CFNumberCreate(kCFAllocatorSystemDefault, kCFNumberSInt64Type, &v); _plistAppendFormat(xmlString, CFSTR("%@"), num); CFRelease(num); @@ -448,8 +485,12 @@ static void _CFAppendXML0(CFTypeRef object, UInt32 indentation, CFMutableDataRef _plistAppendUTF8CString(xmlString, "\n"); - } else if (typeID == CFArrayGetTypeID()) { - UInt32 i, count = CFArrayGetCount(object); +#elif 0 +#else +#error Unknown or unspecified DEPLOYMENT_TARGET +#endif + } else if (typeID == arraytype) { + UInt32 i, count = CFArrayGetCount((CFArrayRef)object); if (count == 0) { _plistAppendUTF8CString(xmlString, "<"); _plistAppendCharacters(xmlString, CFXMLPlistTags[ARRAY_IX], ARRAY_TAG_LENGTH); @@ -460,15 +501,14 @@ static void _CFAppendXML0(CFTypeRef object, UInt32 indentation, CFMutableDataRef _plistAppendCharacters(xmlString, CFXMLPlistTags[ARRAY_IX], ARRAY_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">\n"); for (i = 0; i < count; i ++) { - _CFAppendXML0(CFArrayGetValueAtIndex(object, i), indentation+1, xmlString); + _CFAppendXML0(CFArrayGetValueAtIndex((CFArrayRef)object, i), indentation+1, xmlString); } _appendIndents(indentation, xmlString); _plistAppendUTF8CString(xmlString, "\n"); - } else if (typeID == CFDictionaryGetTypeID()) { - UInt32 i, count = CFDictionaryGetCount(object); - CFAllocatorRef allocator = CFGetAllocator(xmlString); + } else if (typeID == dicttype) { + UInt32 i, count = CFDictionaryGetCount((CFDictionaryRef)object); CFMutableArrayRef keyArray; CFTypeRef *keys; if (count == 0) { @@ -480,9 +520,9 @@ static void _CFAppendXML0(CFTypeRef object, UInt32 indentation, CFMutableDataRef _plistAppendUTF8CString(xmlString, "<"); _plistAppendCharacters(xmlString, CFXMLPlistTags[DICT_IX], DICT_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">\n"); - keys = (CFTypeRef *)CFAllocatorAllocate(allocator, count * sizeof(CFTypeRef), 0); - CFDictionaryGetKeysAndValues(object, keys, NULL); - keyArray = CFArrayCreateMutable(allocator, count, &kCFTypeArrayCallBacks); + keys = (CFTypeRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, count * sizeof(CFTypeRef), 0); + CFDictionaryGetKeysAndValues((CFDictionaryRef)object, keys, NULL); + keyArray = CFArrayCreateMutable(kCFAllocatorSystemDefault, count, &kCFTypeArrayCallBacks); CFArrayReplaceValues(keyArray, CFRangeMake(0, 0), keys, count); CFArraySortValues(keyArray, CFRangeMake(0, count), (CFComparatorFunction)CFStringCompare, NULL); CFArrayGetValues(keyArray, CFRangeMake(0, count), keys); @@ -493,67 +533,60 @@ static void _CFAppendXML0(CFTypeRef object, UInt32 indentation, CFMutableDataRef _plistAppendUTF8CString(xmlString, "<"); _plistAppendCharacters(xmlString, CFXMLPlistTags[KEY_IX], KEY_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">"); - _appendEscapedString(key, xmlString); + _appendEscapedString((CFStringRef)key, xmlString); _plistAppendUTF8CString(xmlString, "\n"); - _CFAppendXML0(CFDictionaryGetValue(object, key), indentation+1, xmlString); + _CFAppendXML0(CFDictionaryGetValue((CFDictionaryRef)object, key), indentation+1, xmlString); } - CFAllocatorDeallocate(allocator, keys); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, keys); _appendIndents(indentation, xmlString); _plistAppendUTF8CString(xmlString, "\n"); - } else if (typeID == CFDataGetTypeID()) { + } else if (typeID == datatype) { _plistAppendUTF8CString(xmlString, "<"); _plistAppendCharacters(xmlString, CFXMLPlistTags[DATA_IX], DATA_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">\n"); - _XMLPlistAppendDataUsingBase64(xmlString, object, indentation); + _XMLPlistAppendDataUsingBase64(xmlString, (CFDataRef)object, indentation); _appendIndents(indentation, xmlString); _plistAppendUTF8CString(xmlString, "\n"); - } else if (typeID == CFDateGetTypeID()) { + } else if (typeID == datetype) { // YYYY '-' MM '-' DD 'T' hh ':' mm ':' ss 'Z' - CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(CFDateGetAbsoluteTime(object), NULL); - + int32_t y = 0, M = 0, d = 0, H = 0, m = 0, s = 0; +#if 1 + CFGregorianDate date = CFAbsoluteTimeGetGregorianDate(CFDateGetAbsoluteTime((CFDateRef)object), NULL); + y = date.year; + M = date.month; + d = date.day; + H = date.hour; + m = date.minute; + s = (int32_t)date.second; +#else + CFCalendarRef calendar = CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault, kCFGregorianCalendar); + CFTimeZoneRef tz = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, CFSTR("GMT"), true); + CFCalendarSetTimeZone(calendar, tz); + CFCalendarDecomposeAbsoluteTime(calendar, CFDateGetAbsoluteTime((CFDateRef)object), (const uint8_t *)"yMdHms", &y, &M, &d, &H, &m, &s); + CFRelease(calendar); + CFRelease(tz); +#endif _plistAppendUTF8CString(xmlString, "<"); _plistAppendCharacters(xmlString, CFXMLPlistTags[DATE_IX], DATE_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">"); - - _plistAppendFormat(xmlString, CFSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), date.year, date.month, date.day, date.hour, date.minute, (int)date.second); - + _plistAppendFormat(xmlString, CFSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), y, M, d, H, m, s); _plistAppendUTF8CString(xmlString, "\n"); - } else if (typeID == CFNumberGetTypeID()) { - if (CFNumberIsFloatType(object)) { + } else if (typeID == numbertype) { + if (CFNumberIsFloatType((CFNumberRef)object)) { _plistAppendUTF8CString(xmlString, "<"); _plistAppendCharacters(xmlString, CFXMLPlistTags[REAL_IX], REAL_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">"); - - if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { CFStringRef s = __CFNumberCopyFormattingDescriptionAsFloat64(object); _plistAppendString(xmlString, s); CFRelease(s); - } else if (CFNumberGetType(object) == kCFNumberFloat64Type || CFNumberGetType(object) == kCFNumberDoubleType) { - double doubleVal; - static CFStringRef doubleFormatString = NULL; - CFNumberGetValue(object, kCFNumberDoubleType, &doubleVal); - if (!doubleFormatString) { - doubleFormatString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%%.%de"), DBL_DIG); - } - _plistAppendFormat(xmlString, doubleFormatString, doubleVal); - } else { - float floatVal; - static CFStringRef floatFormatString = NULL; - CFNumberGetValue(object, kCFNumberFloatType, &floatVal); - if (!floatFormatString) { - floatFormatString = CFStringCreateWithFormat(NULL, NULL, CFSTR("%%.%de"), FLT_DIG); - } - _plistAppendFormat(xmlString, floatFormatString, floatVal); - } - _plistAppendUTF8CString(xmlString, "\n"); @@ -568,8 +601,8 @@ static void _CFAppendXML0(CFTypeRef object, UInt32 indentation, CFMutableDataRef _plistAppendCharacters(xmlString, CFXMLPlistTags[INTEGER_IX], INTEGER_TAG_LENGTH); _plistAppendUTF8CString(xmlString, ">\n"); } - } else if (typeID == CFBooleanGetTypeID()) { - if (CFBooleanGetValue(object)) { + } else if (typeID == booltype) { + if (CFBooleanGetValue((CFBooleanRef)object)) { _plistAppendUTF8CString(xmlString, "<"); _plistAppendCharacters(xmlString, CFXMLPlistTags[TRUE_IX], TRUE_TAG_LENGTH); _plistAppendUTF8CString(xmlString, "/>\n"); @@ -584,7 +617,7 @@ static void _CFAppendXML0(CFTypeRef object, UInt32 indentation, CFMutableDataRef static void _CFGenerateXMLPropertyListToData(CFMutableDataRef xml, CFTypeRef propertyList) { _plistAppendUTF8CString(xml, "\n\n<"); + _plistAppendUTF8CString(xml, " PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<"); _plistAppendCharacters(xml, CFXMLPlistTags[PLIST_IX], PLIST_TAG_LENGTH); _plistAppendUTF8CString(xml, " version=\"1.0\">\n"); @@ -596,18 +629,18 @@ static void _CFGenerateXMLPropertyListToData(CFMutableDataRef xml, CFTypeRef pro } CFDataRef CFPropertyListCreateXMLData(CFAllocatorRef allocator, CFPropertyListRef propertyList) { + initStatics(); CFMutableDataRef xml; CFAssert1(propertyList != NULL, __kCFLogAssertion, "%s(): Cannot be called with a NULL property list", __PRETTY_FUNCTION__); __CFAssertIsPList(propertyList); - if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { if (!CFPropertyListIsValid(propertyList, kCFPropertyListXMLFormat_v1_0)) return NULL; - } xml = CFDataCreateMutable(allocator, 0); _CFGenerateXMLPropertyListToData(xml, propertyList); return xml; } CFDataRef _CFPropertyListCreateXMLDataWithExtras(CFAllocatorRef allocator, CFPropertyListRef propertyList) { + initStatics(); CFMutableDataRef xml; CFAssert1(propertyList != NULL, __kCFLogAssertion, "%s(): Cannot be called with a NULL property list", __PRETTY_FUNCTION__); xml = CFDataCreateMutable(allocator, 0); @@ -832,16 +865,15 @@ static const signed char __CFPLDataDecodeTable[128] = { /* 'x' */ 49, 50, 51, -1, -1, -1, -1, -1 }; -static CFDataRef __CFPLDataDecode(_CFXMLPlistParseInfo *pInfo, Boolean mutable) { +static CFDataRef __CFPLDataDecode(_CFXMLPlistParseInfo *pInfo, Boolean isMutable) { int tmpbufpos = 0; - int tmpbuflen = 64; + int tmpbuflen = 256; uint8_t *tmpbuf; int numeq = 0; int acc = 0; int cntr = 0; - // GrP GC: collector shouldn't scan this raw data - tmpbuf = CFAllocatorAllocate(pInfo->allocator, tmpbuflen, AUTO_MEMORY_UNSCANNED); + tmpbuf = (uint8_t *)CFAllocatorAllocate(pInfo->allocator, tmpbuflen, 0); for (; pInfo->curr < pInfo->end; pInfo->curr++) { UniChar c = *(pInfo->curr); if (c == '<') { @@ -859,8 +891,17 @@ static CFDataRef __CFPLDataDecode(_CFXMLPlistParseInfo *pInfo, Boolean mutable) acc += __CFPLDataDecodeTable[c]; if (0 == (cntr & 0x3)) { if (tmpbuflen <= tmpbufpos + 2) { - tmpbuflen <<= 2; - tmpbuf = CFAllocatorReallocate(pInfo->allocator, tmpbuf, tmpbuflen, AUTO_MEMORY_UNSCANNED); + if (tmpbuflen < 256 * 1024) { + tmpbuflen *= 4; + } else if (tmpbuflen < 16 * 1024 * 1024) { + tmpbuflen *= 2; + } else { + // once in this stage, this will be really slow + // and really potentially fragment memory + tmpbuflen += 256 * 1024; + } + tmpbuf = (uint8_t *)CFAllocatorReallocate(pInfo->allocator, tmpbuf, tmpbuflen, 0); + if (!tmpbuf) HALT; } tmpbuf[tmpbufpos++] = (acc >> 16) & 0xff; if (numeq < 2) @@ -869,13 +910,13 @@ static CFDataRef __CFPLDataDecode(_CFXMLPlistParseInfo *pInfo, Boolean mutable) tmpbuf[tmpbufpos++] = acc & 0xff; } } - if (mutable) { + if (isMutable) { CFMutableDataRef result = CFDataCreateMutable(pInfo->allocator, 0); CFDataAppendBytes(result, tmpbuf, tmpbufpos); CFAllocatorDeallocate(pInfo->allocator, tmpbuf); return result; } else { - return CFDataCreateWithBytesNoCopy(pInfo->allocator, (char const *) tmpbuf, tmpbufpos, pInfo->allocator); + return CFDataCreateWithBytesNoCopy(pInfo->allocator, tmpbuf, tmpbufpos, pInfo->allocator); } } @@ -1067,14 +1108,13 @@ static void parseEntityReference_pl(_CFXMLPlistParseInfo *pInfo, CFMutableString CFStringAppendCharacters(string, &ch, 1); } -extern const void *__CFSetAddValueAndReturn(CFMutableSetRef set, const void *value); - static CFStringRef _uniqueStringForString(_CFXMLPlistParseInfo *pInfo, CFStringRef stringToUnique) { if (!pInfo->stringSet) { pInfo->stringSet = CFSetCreateMutable(pInfo->allocator, 0, &kCFCopyStringSetCallBacks); _CFSetSetCapacity(pInfo->stringSet, 160); // set capacity high to avoid lots of rehashes, though waste some memory } - return __CFSetAddValueAndReturn(pInfo->stringSet, stringToUnique); + CFSetAddValue(pInfo->stringSet, stringToUnique); + return (CFStringRef)CFSetGetValue(pInfo->stringSet, stringToUnique); } extern void _CFStrSetDesiredCapacity(CFMutableStringRef str, CFIndex len); @@ -1098,15 +1138,16 @@ static CFStringRef _uniqueStringForCharacters(_CFXMLPlistParseInfo *pInfo, const isASCII = true; for (idx = 0; isASCII && idx < length; idx++) isASCII = isASCII && (base[idx] < 0x80); if (isASCII) { - ascii = (length < (CFIndex)sizeof(buffer)) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, length + 1, 0); + ascii = (length < (CFIndex)sizeof(buffer)) ? buffer : (uint8_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, length + 1, 0); for (idx = 0; idx < length; idx++) ascii[idx] = (uint8_t)base[idx]; ascii[length] = '\0'; - CFStringAppendCString(pInfo->tmpString, ascii, kCFStringEncodingASCII); + CFStringAppendCString(pInfo->tmpString, (char *)ascii, kCFStringEncodingASCII); if (ascii != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, ascii); } else { CFStringAppendCharacters(pInfo->tmpString, base, length); } - return __CFSetAddValueAndReturn(pInfo->stringSet, pInfo->tmpString); + CFSetAddValue(pInfo->stringSet, pInfo->tmpString); + return (CFStringRef)CFSetGetValue(pInfo->stringSet, pInfo->tmpString); } @@ -1140,7 +1181,7 @@ static CFStringRef getString(_CFXMLPlistParseInfo *pInfo) { if (!string) { if (pInfo->mutabilityOption != kCFPropertyListMutableContainersAndLeaves) { CFStringRef uniqueString = _uniqueStringForCharacters(pInfo, mark, pInfo->curr-mark); - CFRetain(uniqueString); + if (uniqueString) CFRetain(uniqueString); return uniqueString; } else { string = CFStringCreateMutable(pInfo->allocator, 0); @@ -1151,7 +1192,7 @@ static CFStringRef getString(_CFXMLPlistParseInfo *pInfo) { _catFromMarkToBuf(mark, pInfo->curr, &string, pInfo->allocator); if (pInfo->mutabilityOption != kCFPropertyListMutableContainersAndLeaves) { CFStringRef uniqueString = _uniqueStringForString(pInfo, string); - CFRetain(uniqueString); + if (uniqueString) CFRetain(uniqueString); CFRelease(string); return uniqueString; } @@ -1295,17 +1336,19 @@ static CFTypeRef parseDictTag(_CFXMLPlistParseInfo *pInfo) { } } else { CFIndex cnt = CFDictionaryGetCount(dict); +#if DEPLOYMENT_TARGET_MACOSX if (1 == cnt) { CFTypeRef val = CFDictionaryGetValue(dict, CFSTR("CF$UID")); - if (val && CFGetTypeID(val) == CFNumberGetTypeID()) { + if (val && CFGetTypeID(val) == numbertype) { CFTypeRef uid; uint32_t v; - CFNumberGetValue(val, kCFNumberSInt32Type, &v); + CFNumberGetValue((CFNumberRef)val, kCFNumberSInt32Type, &v); uid = (CFTypeRef)_CFKeyedArchiverUIDCreate(pInfo->allocator, v); CFRelease(dict); return uid; } } +#endif if (-1 == allowImmutableCollections) checkImmutableCollections(); if (1 == allowImmutableCollections) { if (pInfo->mutabilityOption == kCFPropertyListImmutable) { @@ -1335,7 +1378,7 @@ static CFTypeRef parseDataTag(_CFXMLPlistParseInfo *pInfo) { return NULL; } -CF_INLINE Boolean read2DigitNumber(_CFXMLPlistParseInfo *pInfo, int8_t *result) { +CF_INLINE Boolean read2DigitNumber(_CFXMLPlistParseInfo *pInfo, int32_t *result) { UniChar ch1, ch2; if (pInfo->curr + 2 >= pInfo->end) return false; ch1 = *pInfo->curr; @@ -1348,13 +1391,12 @@ CF_INLINE Boolean read2DigitNumber(_CFXMLPlistParseInfo *pInfo, int8_t *result) // YYYY '-' MM '-' DD 'T' hh ':' mm ':' ss 'Z' static CFTypeRef parseDateTag(_CFXMLPlistParseInfo *pInfo) { - CFGregorianDate date; - int8_t num; + int32_t year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0; + int32_t num = 0; Boolean badForm = false; - date.year = 0; while (pInfo->curr < pInfo->end && isdigit(*pInfo->curr)) { - date.year = 10*date.year + (*pInfo->curr) - '0'; + year = 10*year + (*pInfo->curr) - '0'; pInfo->curr ++; } if (pInfo->curr >= pInfo->end || *pInfo->curr != '-') { @@ -1363,32 +1405,32 @@ static CFTypeRef parseDateTag(_CFXMLPlistParseInfo *pInfo) { pInfo->curr ++; } - if (!badForm && read2DigitNumber(pInfo, &date.month) && pInfo->curr < pInfo->end && *pInfo->curr == '-') { + if (!badForm && read2DigitNumber(pInfo, &month) && pInfo->curr < pInfo->end && *pInfo->curr == '-') { pInfo->curr ++; } else { badForm = true; } - if (!badForm && read2DigitNumber(pInfo, &date.day) && pInfo->curr < pInfo->end && *pInfo->curr == 'T') { + if (!badForm && read2DigitNumber(pInfo, &day) && pInfo->curr < pInfo->end && *pInfo->curr == 'T') { pInfo->curr ++; } else { badForm = true; } - if (!badForm && read2DigitNumber(pInfo, &date.hour) && pInfo->curr < pInfo->end && *pInfo->curr == ':') { + if (!badForm && read2DigitNumber(pInfo, &hour) && pInfo->curr < pInfo->end && *pInfo->curr == ':') { pInfo->curr ++; } else { badForm = true; } - if (!badForm && read2DigitNumber(pInfo, &date.minute) && pInfo->curr < pInfo->end && *pInfo->curr == ':') { + if (!badForm && read2DigitNumber(pInfo, &minute) && pInfo->curr < pInfo->end && *pInfo->curr == ':') { pInfo->curr ++; } else { badForm = true; } if (!badForm && read2DigitNumber(pInfo, &num) && pInfo->curr < pInfo->end && *pInfo->curr == 'Z') { - date.second = num; + second = num; pInfo->curr ++; } else { badForm = true; @@ -1399,7 +1441,20 @@ static CFTypeRef parseDateTag(_CFXMLPlistParseInfo *pInfo) { return NULL; } if (!checkForCloseTag(pInfo, CFXMLPlistTags[DATE_IX], DATE_TAG_LENGTH)) return NULL; - return CFDateCreate(pInfo->allocator, CFGregorianDateGetAbsoluteTime(date, NULL)); + + CFAbsoluteTime at = 0.0; +#if 1 + CFGregorianDate date = {year, month, day, hour, minute, second}; + at = CFGregorianDateGetAbsoluteTime(date, NULL); +#else + CFCalendarRef calendar = CFCalendarCreateWithIdentifier(kCFAllocatorSystemDefault, kCFGregorianCalendar); + CFTimeZoneRef tz = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, CFSTR("GMT"), true); + CFCalendarSetTimeZone(calendar, tz); + CFCalendarComposeAbsoluteTime(calendar, &at, (const uint8_t *)"yMdHms", year, month, day, hour, minute, second); + CFRelease(calendar); + CFRelease(tz); +#endif + return CFDateCreate(pInfo->allocator, at); } static CFTypeRef parseRealTag(_CFXMLPlistParseInfo *pInfo) { @@ -1414,7 +1469,6 @@ static CFTypeRef parseRealTag(_CFXMLPlistParseInfo *pInfo) { return NULL; } - if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { if (kCFCompareEqualTo == CFStringCompare(str, CFSTR("nan"), kCFCompareCaseInsensitive)) { CFRelease(str); return (checkForCloseTag(pInfo, CFXMLPlistTags[REAL_IX], REAL_TAG_LENGTH)) ? CFRetain(kCFNumberNaN) : NULL; @@ -1443,7 +1497,6 @@ static CFTypeRef parseRealTag(_CFXMLPlistParseInfo *pInfo) { CFRelease(str); return (checkForCloseTag(pInfo, CFXMLPlistTags[REAL_IX], REAL_TAG_LENGTH)) ? CFRetain(kCFNumberPositiveInfinity) : NULL; } - } len = CFStringGetLength(str); CFStringInitInlineBuffer(str, &buf, CFRangeMake(0, len)); @@ -1466,9 +1519,17 @@ static CFTypeRef parseRealTag(_CFXMLPlistParseInfo *pInfo) { } \ ch = *(pInfo->curr) +typedef struct { + int64_t high; + uint64_t low; +} CFSInt128Struct; + +enum { + kCFNumberSInt128Type = 17 +}; + static CFTypeRef parseIntegerTag(_CFXMLPlistParseInfo *pInfo) { bool isHex = false, isNeg = false, hadLeadingZero = false; - int64_t value = (int64_t)0; UniChar ch = 0; // decimal_constant S*(-|+)?S*[0-9]+ (S == space) @@ -1513,40 +1574,40 @@ static CFTypeRef parseIntegerTag(_CFXMLPlistParseInfo *pInfo) { pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Incomplete on line %d"), lineNumber(pInfo)); return NULL; } + uint64_t value = 0; + uint32_t multiplier = (isHex ? 16 : 10); while ('<' != ch) { - int64_t old_value = value; + uint32_t new_digit = 0; switch (ch) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - value = (isHex ? 16 : 10) * value + (ch - '0'); + new_digit = (ch - '0'); break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - if (!isHex) { - pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Hex digit in non-hex on line %d"), lineNumber(pInfo)); - return NULL; - } - value = 16 * value + (ch - 'a' + 10); + new_digit = (ch - 'a' + 10); break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - if (!isHex) { - pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Hex digit in non-hex on line %d"), lineNumber(pInfo)); - return NULL; - } - value = 16 * value + (ch - 'A' + 10); + new_digit = (ch - 'A' + 10); break; default: // other character pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Unknown character '%c' (0x%x) in on line %d"), ch, ch, lineNumber(pInfo)); return NULL; } - if (isNeg && LLONG_MIN == value) { - // overflow by one when isNeg gives the proper value, if we're done with the number - if (pInfo->curr + 1 < pInfo->end && '<' == *(pInfo->curr + 1)) { - pInfo->curr++; - isNeg = false; - break; - } + if (!isHex && new_digit > 9) { + pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Hex digit in non-hex on line %d"), lineNumber(pInfo)); + return NULL; } - if (value < old_value) { - pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Encountered too large to represent on line %d"), lineNumber(pInfo)); + if (UINT64_MAX / multiplier < value) { + pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Integer overflow in on line %d"), lineNumber(pInfo)); + return NULL; + } + value = multiplier * value; + if (UINT64_MAX - new_digit < value) { + pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Integer overflow in on line %d"), lineNumber(pInfo)); + return NULL; + } + value = value + new_digit; + if (isNeg && (uint64_t)INT64_MAX + 1 < value) { + pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Integer underflow in on line %d"), lineNumber(pInfo)); return NULL; } pInfo->curr++; @@ -1556,8 +1617,15 @@ static CFTypeRef parseIntegerTag(_CFXMLPlistParseInfo *pInfo) { // checkForCloseTag() sets error string return NULL; } - if (isNeg) value = -value; - return CFNumberCreate(pInfo->allocator, kCFNumberSInt64Type, &value); + if (isNeg || value <= INT64_MAX) { + int64_t v = value; + if (isNeg) v = -v; // no-op if INT64_MIN + return CFNumberCreate(pInfo->allocator, kCFNumberSInt64Type, &v); + } + CFSInt128Struct val; + val.high = 0; + val.low = value; + return CFNumberCreate(pInfo->allocator, kCFNumberSInt128Type, &val); } #undef GET_CH @@ -1698,18 +1766,14 @@ static CFTypeRef parseXMLElement(_CFXMLPlistParseInfo *pInfo, Boolean *isKey) { } case TRUE_IX: if (!isEmpty) { - pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Encountered non-empty tag on line %d"), lineNumber(pInfo)); - return NULL; - } else { - return CFRetain(kCFBooleanTrue); - } + if (!checkForCloseTag(pInfo, CFXMLPlistTags[TRUE_IX], TRUE_TAG_LENGTH)) return NULL; + } + return CFRetain(kCFBooleanTrue); case FALSE_IX: if (!isEmpty) { - pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Encountered non-empty tag on line %d"), lineNumber(pInfo)); - return NULL; - } else { - return CFRetain(kCFBooleanFalse); - } + if (!checkForCloseTag(pInfo, CFXMLPlistTags[FALSE_IX], FALSE_TAG_LENGTH)) return NULL; + } + return CFRetain(kCFBooleanFalse); case REAL_IX: if (isEmpty) { pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Encountered empty on line %d"), lineNumber(pInfo)); @@ -1817,7 +1881,7 @@ static CFStringEncoding encodingForXMLData(CFDataRef data, CFStringRef *error) { len = idx - base; if (len == 5 && (*base == 'u' || *base == 'U') && (base[1] == 't' || base[1] == 'T') && (base[2] == 'f' || base[2] == 'F') && (base[3] == '-') && (base[4] == '8')) return kCFStringEncodingUTF8; - encodingName = CFStringCreateWithBytes(NULL, base, len, kCFStringEncodingISOLatin1, false); + encodingName = CFStringCreateWithBytes(kCFAllocatorSystemDefault, base, len, kCFStringEncodingISOLatin1, false); enc = CFStringConvertIANACharSetNameToEncoding(encodingName); if (enc != kCFStringEncodingInvalidId) { CFRelease(encodingName); @@ -1825,27 +1889,53 @@ static CFStringEncoding encodingForXMLData(CFDataRef data, CFStringRef *error) { } if (error) { - *error = CFStringCreateWithFormat(NULL, NULL, CFSTR("Encountered unknown encoding (%@)"), encodingName); + *error = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("Encountered unknown encoding (%@)"), encodingName); CFRelease(encodingName); } return 0; } } -CFTypeRef __CFNastyFile__ = NULL; -static CFSpinLock_t __CFNastyFileLock__ = 0; - -void __CFSetNastyFile(CFTypeRef cf) { - __CFSpinLock(&__CFNastyFileLock__); - if (__CFNastyFile__) CFRelease(__CFNastyFile__); - __CFNastyFile__ = cf ? CFRetain(cf) : cf; - __CFSpinUnlock(&__CFNastyFileLock__); -} - extern bool __CFTryParseBinaryPlist(CFAllocatorRef allocator, CFDataRef data, CFOptionFlags option, CFPropertyListRef *plist, CFStringRef *errorString); int32_t _CFPropertyListAllowNonUTF8 = 0; +#define SAVE_PLISTS 0 + +#if SAVE_PLISTS +static Boolean __savePlistData(CFDataRef data, CFOptionFlags opt) { + uint8_t pn[2048]; + uint8_t fn[2048]; + uint32_t pnlen = sizeof(pn); + uint8_t *pnp = NULL; + if (0 == _NSGetExecutablePath((char *)pn, &pnlen)) { + pnp = strrchr((char *)pn, '/'); + } + if (!pnp) { + pnp = pn; + } else { + pnp++; + } + if (0 == strcmp((char *)pnp, "parse_plists")) return true; + CFUUIDRef r = CFUUIDCreate(kCFAllocatorSystemDefault); + CFStringRef s = CFUUIDCreateString(kCFAllocatorSystemDefault, r); + CFStringRef p = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("/tmp/plists/%s#%@#0x%x"), pnp, s, opt); + _CFStringGetFileSystemRepresentation(p, fn, sizeof(fn)); + CFRelease(r); + CFRelease(s); + CFRelease(p); + int fd = open((const char *)fn, O_WRONLY|O_CREAT|O_TRUNC, 0666); + if (fd < 0) return false; + int len = CFDataGetLength(data); + int w = write(fd, CFDataGetBytePtr(data), len); + fsync(fd); + close(fd); + if (w != len) return false; + return true; +} +#endif + CFTypeRef _CFPropertyListCreateFromXMLData(CFAllocatorRef allocator, CFDataRef xmlData, CFOptionFlags option, CFStringRef *errorString, Boolean allowNewTypes, CFPropertyListFormat *format) { + initStatics(); CFStringEncoding encoding; CFStringRef xmlString; UInt32 length; @@ -1860,6 +1950,10 @@ CFTypeRef _CFPropertyListCreateFromXMLData(CFAllocatorRef allocator, CFDataRef x return NULL; } +#if SAVE_PLISTS + __savePlistData(xmlData, option); +#endif + if (__CFTryParseBinaryPlist(allocator, xmlData, option, &plist, errorString)) { if (format) *format = kCFPropertyListBinaryFormat_v1_0; return plist; @@ -1878,17 +1972,9 @@ CFTypeRef _CFPropertyListCreateFromXMLData(CFAllocatorRef allocator, CFDataRef x } xmlString = CFStringCreateWithBytes(allocator, CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData), encoding, true); - if (NULL == xmlString && (!_CFExecutableLinkedOnOrAfter(CFSystemVersionChablis) || _CFPropertyListAllowNonUTF8)) { // conversion failed, probably because not in proper encoding - CFTypeRef f = (__CFNastyFile__) ? (__CFNastyFile__) : CFSTR("(UNKNOWN)"); - if (encoding == kCFStringEncodingUTF8) { - CFLog(0, CFSTR("\n\tCFPropertyListCreateFromXMLData(): plist parse failed; the data is not proper UTF-8. The file name for this data could be:\n\t%@\n\tThe parser will retry as in 10.2, but the problem should be corrected in the plist."), f); -#if defined(DEBUG) - } else { - CFLog(0, CFSTR("\n\tCFPropertyListCreateFromXMLData(): conversion of data failed.\n\tThe file is not in the encoding specified in XML header if XML.\n\tThe file name for this data could be:\n\t\t%@\n."), f); -#endif - } + if (NULL == xmlString && (!_CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard) || _CFPropertyListAllowNonUTF8)) { // conversion failed, probably because not in proper encoding // Call __CFStringCreateImmutableFunnel3() the same way CFStringCreateWithBytes() does, except with the addt'l flag - if (encoding == kCFStringEncodingUTF8) xmlString = __CFStringCreateImmutableFunnel3(allocator, CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData), kCFStringEncodingUTF8, true, true, false, false, false, (void *)-1 /* ALLOCATORSFREEFUNC */, kCFStringEncodingLenientUTF8Conversion); + if (encoding == kCFStringEncodingUTF8) xmlString = __CFStringCreateImmutableFunnel3(allocator, CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData), kCFStringEncodingUTF8, true, true, false, false, false, (CFAllocatorRef)-1 /* ALLOCATORSFREEFUNC */, kCFStringEncodingLenientUTF8Conversion); } length = xmlString ? CFStringGetLength(xmlString) : 0; @@ -1927,7 +2013,7 @@ CFTypeRef _CFPropertyListCreateFromXMLData(CFAllocatorRef allocator, CFDataRef x result = parseOldStylePropertyListOrStringsFile(pInfo); if (result && format) *format = kCFPropertyListOpenStepFormat; if (!result) { - if (errorString) *errorString = CFStringCreateWithFormat(NULL, NULL, CFSTR("XML parser error:\n\t%@\nOld-style plist parser error:\n\t%@\n"), err, pInfo->errorString); + if (errorString) *errorString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("XML parser error:\n\t%@\nOld-style plist parser error:\n\t%@\n"), err, pInfo->errorString); } if (err) CFRelease(err); if (pInfo->errorString) CFRelease(pInfo->errorString); @@ -1943,18 +2029,20 @@ CFTypeRef _CFPropertyListCreateFromXMLData(CFAllocatorRef allocator, CFDataRef x return result; } else { if (errorString) - *errorString = CFRetain(CFSTR("Conversion of data failed. The file is not UTF-8, or in the encoding specified in XML header if XML.")); + *errorString = (CFStringRef)CFRetain(CFSTR("Conversion of data failed. The file is not UTF-8, or in the encoding specified in XML header if XML.")); return NULL; } } CFTypeRef CFPropertyListCreateFromXMLData(CFAllocatorRef allocator, CFDataRef xmlData, CFOptionFlags option, CFStringRef *errorString) { + initStatics(); CFAssert1(xmlData != NULL, __kCFLogAssertion, "%s(): NULL data not allowed", __PRETTY_FUNCTION__); CFAssert2(option == kCFPropertyListImmutable || option == kCFPropertyListMutableContainers || option == kCFPropertyListMutableContainersAndLeaves, __kCFLogAssertion, "%s(): Unrecognized option %d", __PRETTY_FUNCTION__, option); return _CFPropertyListCreateFromXMLData(allocator, xmlData, option, errorString, true, NULL); } CFIndex CFPropertyListWriteToStream(CFPropertyListRef propertyList, CFWriteStreamRef stream, CFPropertyListFormat format, CFStringRef *errorString) { + initStatics(); CFAssert1(stream != NULL, __kCFLogAssertion, "%s(): NULL stream not allowed", __PRETTY_FUNCTION__); CFAssert2(format == kCFPropertyListOpenStepFormat || format == kCFPropertyListXMLFormat_v1_0 || format == kCFPropertyListBinaryFormat_v1_0, __kCFLogAssertion, "%s(): Unrecognized option %d", __PRETTY_FUNCTION__, format); CFAssert1(propertyList != NULL, __kCFLogAssertion, "%s(): Cannot be called with a NULL property list", __PRETTY_FUNCTION__); @@ -1964,27 +2052,46 @@ CFIndex CFPropertyListWriteToStream(CFPropertyListRef propertyList, CFWriteStrea if (errorString) *errorString = NULL; if (!CFPropertyListIsValid(propertyList, format)) { - if (errorString) *errorString = CFRetain(CFSTR("Property list invalid for format")); + if (errorString) *errorString = (CFStringRef)CFRetain(CFSTR("Property list invalid for format")); return 0; } if (format == kCFPropertyListOpenStepFormat) { - if (errorString) *errorString = CFRetain(CFSTR("Property list format kCFPropertyListOpenStepFormat not supported for writing")); + if (errorString) *errorString = (CFStringRef)CFRetain(CFSTR("Property list format kCFPropertyListOpenStepFormat not supported for writing")); return 0; } if (format == kCFPropertyListXMLFormat_v1_0) { - CFDataRef data = CFPropertyListCreateXMLData(kCFAllocatorSystemDefault, propertyList); - CFIndex len = data ? CFDataGetLength(data) : 0; - CFIndex ret = CFWriteStreamWrite(stream, CFDataGetBytePtr(data), len); + CFDataRef data = CFPropertyListCreateXMLData(kCFAllocatorSystemDefault, propertyList); + if (!data) { + if (errorString) *errorString = (CFStringRef)CFRetain(CFSTR("Property list in XML format could not be created for unknown reasons.")); + return 0; + } + CFIndex len = CFDataGetLength(data); + const uint8_t *ptr = CFDataGetBytePtr(data); + while (0 < len) { + CFIndex ret = CFWriteStreamWrite(stream, ptr, len); + if (ret == 0) { + if (errorString) *errorString = (CFStringRef)CFRetain(CFSTR("Property list writing could not be completed because stream is full.")); + return 0; + } + if (ret < 0) { + CFErrorRef err = CFWriteStreamCopyError(stream); + CFStringRef str = err ? CFErrorCopyDescription(err) : NULL; + if (errorString) *errorString = str ? str : (CFStringRef)CFRetain(CFSTR("Property list writing could not be completed because the stream had an unknown error.")); + if (err) CFRelease(err); + return 0; + } + ptr += ret; + len -= ret; + } + len = CFDataGetLength(data); CFRelease(data); - if (len != ret) { - } return len; } if (format == kCFPropertyListBinaryFormat_v1_0) { CFIndex len = __CFBinaryPlistWriteToStream(propertyList, stream); return len; } - if (errorString) *errorString = CFRetain(CFSTR("Unknown format option")); + if (errorString) *errorString = (CFStringRef)CFRetain(CFSTR("Unknown format option")); return 0; } @@ -1993,23 +2100,38 @@ static void __CFConvertReadStreamToBytes(CFReadStreamRef stream, CFIndex max, ui uint8_t *buf = NULL, sbuf[8192]; for (;;) { retlen = CFReadStreamRead(stream, sbuf, __CFMin(8192, max)); - max -= retlen; - if (retlen <= 0 || max <= 0) { + if (retlen <= 0) { *buffer = buf; *length = buflen; return; } if (bufsize < buflen + retlen) { - bufsize = 2 * bufsize; - if (bufsize < buflen + retlen) bufsize = buflen + retlen; - buf = CFAllocatorReallocate(kCFAllocatorSystemDefault, buf, bufsize, 0); - } + if (bufsize < 256 * 1024) { + bufsize *= 4; + } else if (bufsize < 16 * 1024 * 1024) { + bufsize *= 2; + } else { + // once in this stage, this will be really slow + // and really potentially fragment memory + bufsize += 256 * 1024; + } + if (bufsize < buflen + retlen) bufsize = buflen + retlen; + buf = (uint8_t *)CFAllocatorReallocate(kCFAllocatorSystemDefault, buf, bufsize, 0); + if (!buf) HALT; + } memmove(buf + buflen, sbuf, retlen); buflen += retlen; + max -= retlen; + if (max <= 0) { + *buffer = buf; + *length = buflen; + return; + } } } CFPropertyListRef CFPropertyListCreateFromStream(CFAllocatorRef allocator, CFReadStreamRef stream, CFIndex length, CFOptionFlags mutabilityOption, CFPropertyListFormat *format, CFStringRef *errorString) { + initStatics(); CFPropertyListRef pl; CFDataRef data; CFIndex buflen = 0; @@ -2024,7 +2146,7 @@ CFPropertyListRef CFPropertyListCreateFromStream(CFAllocatorRef allocator, CFRea __CFConvertReadStreamToBytes(stream, length, &buffer, &buflen); if (!buffer || buflen < 6) { if (buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, buffer); - if (errorString) *errorString = CFRetain(CFSTR("stream had too few bytes")); + if (errorString) *errorString = (CFStringRef)CFRetain(CFSTR("stream had too few bytes")); return NULL; } data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, buffer, buflen, kCFAllocatorSystemDefault); @@ -2097,7 +2219,7 @@ static UniChar getSlashedChar(_CFXMLPlistParseInfo *pInfo) { case '7': { uint8_t num = ch - '0'; UniChar result; - UInt32 usedCharLen; + CFIndex usedCharLen; /* three digits maximum to avoid reading \000 followed by 5 as \5 ! */ if ((ch = *(pInfo->curr)) >= '0' && ch <= '7') { // we use in this test the fact that the buffer is zero-terminated pInfo->curr ++; @@ -2153,10 +2275,8 @@ static CFStringRef parseQuotedPlistString(_CFXMLPlistParseInfo *pInfo, UniChar q } if (pInfo->end <= pInfo->curr) { if (str) CFRelease(str); - if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { pInfo->curr = startMark; pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Unterminated quoted string starting on line %d"), lineNumber(pInfo)); - } return NULL; } if (!str) { @@ -2172,8 +2292,8 @@ static CFStringRef parseQuotedPlistString(_CFXMLPlistParseInfo *pInfo, UniChar q } if (pInfo->mutabilityOption != kCFPropertyListMutableContainersAndLeaves) { CFStringRef uniqueString = _uniqueStringForString(pInfo, str); - CFRelease(str); CFRetain(uniqueString); + CFRelease(str); str = (CFMutableStringRef)uniqueString; } } @@ -2204,9 +2324,7 @@ static CFStringRef parseUnquotedPlistString(_CFXMLPlistParseInfo *pInfo) { return str; } } - if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Unexpected EOF")); - } return NULL; } @@ -2214,7 +2332,7 @@ static CFStringRef parsePlistString(_CFXMLPlistParseInfo *pInfo, bool requireObj UniChar ch; advanceToNonSpace(pInfo); if (pInfo->curr >= pInfo->end) { - if (requireObject && _CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { + if (requireObject) { pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Unexpected EOF while parsing string")); } return NULL; @@ -2226,7 +2344,7 @@ static CFStringRef parsePlistString(_CFXMLPlistParseInfo *pInfo, bool requireObj } else if (isValidUnquotedStringCharacter(ch)) { return parseUnquotedPlistString(pInfo); } else { - if (requireObject && _CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { + if (requireObject) { pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Invalid string character at line %d"), lineNumber(pInfo)); } return NULL; @@ -2250,9 +2368,7 @@ static CFTypeRef parsePlistArray(_CFXMLPlistParseInfo *pInfo) { advanceToNonSpace(pInfo); if (*pInfo->curr != ')') { CFRelease(array); - if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Expected terminating ')' for array at line %d"), lineNumber(pInfo)); - } return NULL; } if (pInfo->errorString) { @@ -2283,9 +2399,7 @@ static CFDictionaryRef parsePlistDictContent(_CFXMLPlistParseInfo *pInfo) { break; } } else { - if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Unexpected ';' or '=' after key at line %d"), lineNumber(pInfo)); - } failedParse = true; break; } @@ -2299,14 +2413,7 @@ static CFDictionaryRef parsePlistDictContent(_CFXMLPlistParseInfo *pInfo) { pInfo->curr ++; key = parsePlistString(pInfo, false); } else if (!allowMissingSemi && _CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { - static int yanmode = -1; - if (-1 == yanmode) yanmode = (getenv("YanMode") != NULL); - if (1 != yanmode) { - CFLog(0, CFSTR("CFPropertyListCreateFromXMLData(): Old-style plist parser: missing semicolon in dictionary.")); - if (__CFNastyFile__) { - CFLog(0, CFSTR("CFPropertyListCreateFromXMLData(): The file name for this data might be (or it might not): %@"), __CFNastyFile__); - } - } + CFLog(kCFLogLevelWarning, CFSTR("CFPropertyListCreateFromXMLData(): Old-style plist parser: missing semicolon in dictionary.")); failedParse = true; pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Missing ';' on line %d"), lineNumber(pInfo)); } else { @@ -2333,9 +2440,7 @@ static CFTypeRef parsePlistDict(_CFXMLPlistParseInfo *pInfo) { advanceToNonSpace(pInfo); if (*pInfo->curr != '}') { CFRelease(dict); - if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Expected terminating '}' for dictionary at line %d"), lineNumber(pInfo)); - } return NULL; } pInfo->curr ++; @@ -2358,12 +2463,12 @@ static int getDataBytes(_CFXMLPlistParseInfo *pInfo, unsigned char *bytes, int b int first, second; UniChar ch1 = *pInfo->curr; if (ch1 == '>') return numBytesRead; // Meaning we're done - first = fromHexDigit(ch1); + first = fromHexDigit((unsigned char)ch1); if (first != 0xff) { // If the first char is a hex, then try to read a second hex pInfo->curr++; if (pInfo->curr >= pInfo->end) return -2; // Error: uneven number of hex digits UniChar ch2 = *pInfo->curr; - second = fromHexDigit(ch2); + second = fromHexDigit((unsigned char)ch2); if (second == 0xff) return -2; // Error: uneven number of hex digits bytes[numBytesRead++] = (first << 4) + second; pInfo->curr++; @@ -2376,22 +2481,20 @@ static int getDataBytes(_CFXMLPlistParseInfo *pInfo, unsigned char *bytes, int b return numBytesRead; // This does likely mean we didn't encounter a '>', but we'll let the caller deal with that } +#define numBytes 400 static CFTypeRef parsePlistData(_CFXMLPlistParseInfo *pInfo) { CFMutableDataRef result = CFDataCreateMutable(pInfo->allocator, 0); // Read hex bytes and append them to result while (1) { - #define numBytes 400 unsigned char bytes[numBytes]; int numBytesRead = getDataBytes(pInfo, bytes, numBytes); if (numBytesRead < 0) { CFRelease(result); - if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { switch (numBytesRead) { case -2: pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Malformed data byte group at line %d; uneven length"), lineNumber(pInfo)); break; default: pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Malformed data byte group at line %d; invalid hex"), lineNumber(pInfo)); break; } - } return NULL; } if (numBytesRead == 0) break; @@ -2408,19 +2511,18 @@ static CFTypeRef parsePlistData(_CFXMLPlistParseInfo *pInfo) { return result; } else { CFRelease(result); - if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Expected terminating '>' for data at line %d"), lineNumber(pInfo)); - } return NULL; } } +#undef numBytes // Returned object is retained; caller must free. static CFTypeRef parsePlistObject(_CFXMLPlistParseInfo *pInfo, bool requireObject) { UniChar ch; advanceToNonSpace(pInfo); if (pInfo->curr + 1 >= pInfo->end) { - if (requireObject && _CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { + if (requireObject) { pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Unexpected EOF while parsing plist")); } return NULL; @@ -2440,7 +2542,7 @@ static CFTypeRef parsePlistObject(_CFXMLPlistParseInfo *pInfo, bool requireObjec return parseUnquotedPlistString(pInfo); } else { pInfo->curr --; // Must back off the charcter we just read - if (requireObject && _CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { + if (requireObject) { pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Unexpected character '0x%x' at line %d"), ch, lineNumber(pInfo)); } return NULL; @@ -2457,11 +2559,9 @@ static CFTypeRef parseOldStylePropertyListOrStringsFile(_CFXMLPlistParseInfo *pI advanceToNonSpace(pInfo); if (pInfo->curr >= pInfo->end) return result; if (!result) return NULL; - if (CFGetTypeID(result) != CFStringGetTypeID()) { + if (CFGetTypeID(result) != stringtype) { CFRelease(result); - if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { - pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Junk after plist at line %d"), lineNumber(pInfo)); - } + pInfo->errorString = CFStringCreateWithFormat(pInfo->allocator, NULL, CFSTR("Junk after plist at line %d"), lineNumber(pInfo)); return NULL; } CFRelease(result); @@ -2478,7 +2578,7 @@ static CFArrayRef _arrayDeepImmutableCopy(CFAllocatorRef allocator, CFArrayRef a CFTypeRef *values; if (c == 0) { result = CFArrayCreate(allocator, NULL, 0, &kCFTypeArrayCallBacks); - } else if ((values = CFAllocatorAllocate(allocator, c*sizeof(CFTypeRef), 0)) != NULL) { + } else if ((values = (CFTypeRef *)CFAllocatorAllocate(allocator, c*sizeof(CFTypeRef), 0)) != NULL) { CFArrayGetValues(array, CFRangeMake(0, c), values); for (i = 0; i < c; i ++) { values[i] = CFPropertyListCreateDeepCopy(allocator, values[i], mutabilityOption); @@ -2515,35 +2615,34 @@ 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 (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { if (!CFPropertyListIsValid(propertyList, kCFPropertyListBinaryFormat_v1_0)) return NULL; - } if (allocator == NULL) { - allocator = CFRetain(__CFGetDefaultAllocator()); + allocator = (CFAllocatorRef)CFRetain(__CFGetDefaultAllocator()); } else { CFRetain(allocator); } typeID = CFGetTypeID(propertyList); - if (typeID == CFDictionaryGetTypeID()) { + if (typeID == dicttype) { CFDictionaryRef dict = (CFDictionaryRef)propertyList; - Boolean mutable = (mutabilityOption != kCFPropertyListImmutable); + Boolean isMutable = (mutabilityOption != kCFPropertyListImmutable); CFIndex count = CFDictionaryGetCount(dict); CFTypeRef *keys, *values; if (count == 0) { - result = mutable ? CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks): CFDictionaryCreate(allocator, NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - } else if ((keys = CFAllocatorAllocate(allocator, 2 * count * sizeof(CFTypeRef), 0)) != NULL) { + 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) { CFIndex i; values = keys+count; CFDictionaryGetKeysAndValues(dict, keys, values); for (i = 0; i < count; i ++) { - keys[i] = CFStringCreateCopy(allocator, keys[i]); + keys[i] = CFStringCreateCopy(allocator, (CFStringRef)keys[i]); if (keys[i] == NULL) { break; } @@ -2554,9 +2653,9 @@ CFPropertyListRef CFPropertyListCreateDeepCopy(CFAllocatorRef allocator, CFPrope } } if (i == count) { - result = mutable ? CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) : CFDictionaryCreate(allocator, keys, values, count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + result = isMutable ? CFDictionaryCreateMutable(allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks) : CFDictionaryCreate(allocator, keys, values, count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); for (i = 0; i < count; i ++) { - if (mutable) { + if (isMutable) { CFDictionarySetValue((CFMutableDictionaryRef)result, keys[i], values[i]); } CFRelease(keys[i]); @@ -2574,41 +2673,42 @@ CFPropertyListRef CFPropertyListCreateDeepCopy(CFAllocatorRef allocator, CFPrope } else { result = NULL; } - } else if (typeID == CFArrayGetTypeID()) { + } else if (typeID == arraytype) { if (mutabilityOption == kCFPropertyListImmutable) { result = _arrayDeepImmutableCopy(allocator, (CFArrayRef)propertyList, mutabilityOption); } else { result = _arrayDeepMutableCopy(allocator, (CFArrayRef)propertyList, mutabilityOption); } - } else if (typeID == CFDataGetTypeID()) { + } else if (typeID == datatype) { if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) { result = CFDataCreateMutableCopy(allocator, 0, (CFDataRef)propertyList); } else { result = CFDataCreateCopy(allocator, (CFDataRef)propertyList); } - } else if (typeID == CFNumberGetTypeID()) { - // Warning - this will break if byteSize is ever greater than 16 - uint8_t bytes[16]; + } else if (typeID == numbertype) { + // Warning - this will break if byteSize is ever greater than 32 + uint8_t bytes[32]; CFNumberType numType = CFNumberGetType((CFNumberRef)propertyList); CFNumberGetValue((CFNumberRef)propertyList, numType, (void *)bytes); result = CFNumberCreate(allocator, numType, (void *)bytes); - } else if (typeID == CFBooleanGetTypeID()) { + } else if (typeID == booltype) { // Booleans are immutable & shared instances CFRetain(propertyList); result = propertyList; - } else if (typeID == CFDateGetTypeID()) { + } else if (typeID == datetype) { // Dates are immutable result = CFDateCreate(allocator, CFDateGetAbsoluteTime((CFDateRef)propertyList)); - } else if (typeID == CFStringGetTypeID()) { + } else if (typeID == stringtype) { if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) { result = CFStringCreateMutableCopy(allocator, 0, (CFStringRef)propertyList); } else { result = CFStringCreateCopy(allocator, (CFStringRef)propertyList); } } else { - CFAssert2(false, __kCFLogAssertion, "%s(): 0x%x is not a property list type", __PRETTY_FUNCTION__, propertyList); + CFAssert2(false, __kCFLogAssertion, "%s(): %p is not a property list type", __PRETTY_FUNCTION__, propertyList); result = NULL; } CFRelease(allocator); return result; } + diff --git a/Parsing.subproj/CFPropertyList.h b/CFPropertyList.h similarity index 94% rename from Parsing.subproj/CFPropertyList.h rename to CFPropertyList.h index 8e53f23..9058434 100644 --- a/Parsing.subproj/CFPropertyList.h +++ b/CFPropertyList.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFPropertyList.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFPROPERTYLIST__) @@ -32,15 +32,14 @@ #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN -typedef enum { +enum { kCFPropertyListImmutable = 0, kCFPropertyListMutableContainers, kCFPropertyListMutableContainersAndLeaves -} CFPropertyListMutabilityOptions; +}; +typedef CFOptionFlags CFPropertyListMutabilityOptions; /* Creates a property list object from its XML description; xmlData should @@ -77,11 +76,12 @@ CFPropertyListRef CFPropertyListCreateDeepCopy(CFAllocatorRef allocator, CFPrope #if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED -typedef enum { +enum { kCFPropertyListOpenStepFormat = 1, kCFPropertyListXMLFormat_v1_0 = 100, kCFPropertyListBinaryFormat_v1_0 = 200 -} CFPropertyListFormat; +}; +typedef CFIndex CFPropertyListFormat; CF_EXPORT Boolean CFPropertyListIsValid(CFPropertyListRef plist, CFPropertyListFormat format); @@ -119,9 +119,7 @@ CFPropertyListRef CFPropertyListCreateFromStream(CFAllocatorRef allocator, CFRea #endif -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFPROPERTYLIST__ */ diff --git a/RunLoop.subproj/CFRunLoop.c b/CFRunLoop.c similarity index 82% rename from RunLoop.subproj/CFRunLoop.c rename to CFRunLoop.c index e960db1..5eed260 100644 --- a/RunLoop.subproj/CFRunLoop.c +++ b/CFRunLoop.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -25,18 +25,21 @@ Responsibility: Christopher Kane */ +#if (DEPLOYMENT_TARGET_MACOSX) || defined(__WIN32__) + #include #include #include -#include "CFRunLoopPriv.h" #include "CFInternal.h" #include #include #include -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX #include #include #include +#include +#include #else #if !defined(__MINGW32__) && !defined(__CYGWIN__) // With the MS headers, turning off Standard-C gets you macros for stat vs _stat. @@ -44,18 +47,55 @@ #undef __STDC__ #endif #include +#include #include #if !defined(__MINGW32__) && !defined(__CYGWIN__) #define __STDC__ #endif #endif +static int _LogCFRunLoop = 0; + +#if 0 || 0 +static pthread_t kNilPthreadT = { nil, nil }; +#define pthreadPointer(a) a.p +#define lockCount(a) a.LockCount +#else +static pthread_t kNilPthreadT = (pthread_t)0; +#define pthreadPointer(a) a +#define lockCount(a) a +#endif + + +#if DEPLOYMENT_TARGET_MACOSX +#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 extern bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict, const void *key, const void **actualkey); // In order to reuse most of the code across Mach and Windows v1 RunLoopSources, we define a // simple abstraction layer spanning Mach ports and Windows HANDLES -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX typedef mach_port_t __CFPort; #define CFPORT_NULL MACH_PORT_NULL @@ -137,7 +177,7 @@ static __CFPortSet __CFPortSetAllocate(void) { result->used = 0; result->size = 4; result->handles = CFAllocatorAllocate(kCFAllocatorSystemDefault, result->size * sizeof(HANDLE), 0); - result->lock = 0; + CF_SPINLOCK_INIT_FOR_STRUCTS(result->lock); return result; } @@ -165,7 +205,7 @@ static Boolean __CFPortSetInsert(__CFPort port, __CFPortSet portSet) { portSet->handles = CFAllocatorReallocate(kCFAllocatorSystemDefault, portSet->handles, portSet->size * sizeof(HANDLE), 0); } if (portSet->used >= MAXIMUM_WAIT_OBJECTS) - CFLog(0, CFSTR("*** More than MAXIMUM_WAIT_OBJECTS (%d) ports add to a port set. The last ones will be ignored."), 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; @@ -190,7 +230,7 @@ static Boolean __CFPortSetRemove(__CFPort port, __CFPortSet portSet) { #endif -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX extern mach_port_name_t mk_timer_create(void); extern kern_return_t mk_timer_destroy(mach_port_name_t name); extern kern_return_t mk_timer_arm(mach_port_name_t name, AbsoluteTime expire_time); @@ -241,12 +281,9 @@ struct __CFRunLoopMode { CFMutableSetRef _timers; CFMutableArrayRef _submodes; // names of the submodes __CFPortSet _portSet; -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX int _kq; #endif -#if defined(__WIN32__) - DWORD _msgQMask; -#endif }; static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl, CFRunLoopModeRef rlm); @@ -274,13 +311,8 @@ static CFStringRef __CFRunLoopModeCopyDescription(CFTypeRef cf) { CFRunLoopModeRef rlm = (CFRunLoopModeRef)cf; CFMutableStringRef result; result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); - CFStringAppendFormat(result, NULL, CFSTR("{name = %@, locked = %s, "), rlm, CFGetAllocator(rlm), rlm->_name, rlm->_lock ? "true" : "false"); -#if defined(__MACH__) + CFStringAppendFormat(result, NULL, CFSTR("{name = %@, locked = %s, "), rlm, CFGetAllocator(rlm), rlm->_name, lockCount(rlm->_lock) ? "true" : "false"); CFStringAppendFormat(result, NULL, CFSTR("port set = %p,"), rlm->_portSet); -#endif -#if defined(__WIN32__) - 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); return result; } @@ -293,7 +325,7 @@ static void __CFRunLoopModeDeallocate(CFTypeRef cf) { if (NULL != rlm->_submodes) CFRelease(rlm->_submodes); CFRelease(rlm->_name); __CFPortSetFree(rlm->_portSet); -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX if (-1 != rlm->_kq) close(rlm->_kq); #endif } @@ -302,11 +334,12 @@ struct __CFRunLoop { CFRuntimeBase _base; CFSpinLock_t _lock; /* locked for accessing mode list */ __CFPort _wakeUpPort; // used for CFRunLoopWakeUp - volatile CFIndex *_stopped; + volatile uint32_t *_stopped; CFMutableSetRef _commonModes; CFMutableSetRef _commonModeItems; CFRunLoopModeRef _currentMode; CFMutableSetRef _modes; + void *_counterpart; }; /* Bit 0 of the base reserved bits is used for stopped state */ @@ -326,23 +359,23 @@ CF_INLINE void __CFRunLoopUnsetStopped(CFRunLoopRef rl) { } CF_INLINE Boolean __CFRunLoopIsSleeping(CFRunLoopRef rl) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_info, 1, 1); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1); } CF_INLINE void __CFRunLoopSetSleeping(CFRunLoopRef rl) { - __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_info, 1, 1, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 1); } CF_INLINE void __CFRunLoopUnsetSleeping(CFRunLoopRef rl) { - __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_info, 1, 1, 0); + __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 1, 1, 0); } CF_INLINE Boolean __CFRunLoopIsDeallocating(CFRunLoopRef rl) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_info, 2, 2); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 2, 2); } CF_INLINE void __CFRunLoopSetDeallocating(CFRunLoopRef rl) { - __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_info, 2, 2, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)rl)->_cfinfo[CF_INFO_BITS], 2, 2, 1); } CF_INLINE void __CFRunLoopLock(CFRunLoopRef rl) { @@ -357,17 +390,18 @@ static CFStringRef __CFRunLoopCopyDescription(CFTypeRef cf) { CFRunLoopRef rl = (CFRunLoopRef)cf; CFMutableStringRef result; result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); - CFStringAppendFormat(result, NULL, CFSTR("{locked = %s, wait port = 0x%x, stopped = %s,\ncurrent mode = %@,\n"), cf, CFGetAllocator(cf), rl->_lock ? "true" : "false", rl->_wakeUpPort, (rl->_stopped && *(rl->_stopped)) ? "true" : "false", rl->_currentMode ? rl->_currentMode->_name : CFSTR("(none)")); + CFStringAppendFormat(result, NULL, CFSTR("{locked = %s, wait 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("common modes = %@,\ncommon mode items = %@,\nmodes = %@}\n"), rl->_commonModes, rl->_commonModeItems, rl->_modes); return result; } /* call with rl locked */ static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeName, Boolean create) { + CHECK_FOR_FORK(); CFRunLoopModeRef rlm; struct __CFRunLoopMode srlm; - srlm._base._isa = __CFISAForTypeID(__kCFRunLoopModeTypeID); - srlm._base._info = 0; + srlm._base._cfisa = __CFISAForTypeID(__kCFRunLoopModeTypeID); + srlm._base._cfinfo[CF_INFO_BITS] = 0; _CFRuntimeSetInstanceTypeID(&srlm, __kCFRunLoopModeTypeID); srlm._name = modeName; rlm = (CFRunLoopModeRef)CFSetGetValue(rl->_modes, &srlm); @@ -382,7 +416,7 @@ static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeNam if (NULL == rlm) { return NULL; } - rlm->_lock = 0; + CF_SPINLOCK_INIT_FOR_STRUCTS(rlm->_lock); rlm->_name = CFStringCreateCopy(CFGetAllocator(rlm), modeName); rlm->_stopped = false; rlm->_sources = NULL; @@ -392,11 +426,8 @@ static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeNam rlm->_portSet = __CFPortSetAllocate(); if (CFPORT_NULL == rlm->_portSet) HALT; if (!__CFPortSetInsert(rl->_wakeUpPort, rlm->_portSet)) HALT; -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX rlm->_kq = -1; -#endif -#if defined(__WIN32__) - rlm->_msgQMask = 0; #endif CFSetAddValue(rl->_modes, rlm); CFRelease(rlm); @@ -407,10 +438,8 @@ static CFRunLoopModeRef __CFRunLoopFindMode(CFRunLoopRef rl, CFStringRef modeNam // expects rl and rlm locked static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm) { + CHECK_FOR_FORK(); if (NULL == rlm) return true; -#if defined(__WIN32__) - if (0 != rlm->_msgQMask) return false; -#endif if (NULL != rlm->_sources && 0 < CFSetGetCount(rlm->_sources)) return false; if (NULL != rlm->_timers && 0 < CFSetGetCount(rlm->_timers)) return false; if (NULL != rlm->_submodes) { @@ -428,42 +457,18 @@ static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm) { return true; } -#if defined(__WIN32__) -DWORD __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef modeName) { - CFRunLoopModeRef rlm; - DWORD result = 0; - __CFRunLoopLock(rl); - rlm = __CFRunLoopFindMode(rl, modeName, false); - if (rlm) { - result = rlm->_msgQMask; - __CFRunLoopModeUnlock(rlm); - } - __CFRunLoopUnlock(rl); - return result; -} - -void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, DWORD mask, CFStringRef modeName) { - CFRunLoopModeRef rlm; - __CFRunLoopLock(rl); - rlm = __CFRunLoopFindMode(rl, modeName, true); - rlm->_msgQMask = mask; - __CFRunLoopModeUnlock(rlm); - __CFRunLoopUnlock(rl); -} -#endif - /* Bit 3 in the base reserved bits is used for invalid state in run loop objects */ CF_INLINE Boolean __CFIsValid(const void *cf) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 3, 3); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3); } CF_INLINE void __CFSetValid(void *cf) { - __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_info, 3, 3, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3, 1); } CF_INLINE void __CFUnsetValid(void *cf) { - __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_info, 3, 3, 0); + __CFBitfieldSetValue(((CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 3, 3, 0); } struct __CFRunLoopSource { @@ -475,11 +480,10 @@ struct __CFRunLoopSource { union { CFRunLoopSourceContext version0; /* immutable, except invalidation */ CFRunLoopSourceContext1 version1; /* immutable, except invalidation */ - CFRunLoopSourceContext2 version2; /* immutable, except invalidation */ } _context; }; -/* Bit 1 of the base reserved bits is used for signaled state */ +/* Bit 1 of the base reserved bits is used for signalled state */ CF_INLINE Boolean __CFRunLoopSourceIsSignaled(CFRunLoopSourceRef rls) { return (Boolean)__CFBitfieldGetValue(rls->_bits, 1, 1); @@ -505,9 +509,7 @@ CF_INLINE void __CFRunLoopSourceUnlock(CFRunLoopSourceRef rls) { static void __CFRunLoopSourceSchedule(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFRunLoopModeRef rlm) { /* DOES CALLOUT */ __CFRunLoopSourceLock(rls); if (NULL == rls->_runLoops) { - // GrP GC: source -> runloop is a WEAK REFERENCE - // Use non-scanned memory and non-retaining callbacks. - rls->_runLoops = CFBagCreateMutable(CF_USING_COLLECTABLE_MEMORY ? kCFAllocatorMallocZone : CFGetAllocator(rls), 0, NULL); + rls->_runLoops = CFBagCreateMutable(CFGetAllocator(rls), 0, NULL); } CFBagAddValue(rls->_runLoops, rl); __CFRunLoopSourceUnlock(rls); // have to unlock before the callout -- cannot help clients with safety @@ -520,18 +522,6 @@ static void __CFRunLoopSourceSchedule(CFRunLoopSourceRef rls, CFRunLoopRef rl, C if (CFPORT_NULL != port) { __CFPortSetInsert(port, rlm->_portSet); } - } else if (2 == rls->_context.version0.version) { -#if defined(__MACH__) - if (-1 == rlm->_kq) { - rlm->_kq = kqueue_from_portset_np(rlm->_portSet); - } - rls->_context.version2.event.flags |= EV_ADD; - int ret = kevent(rlm->_kq, &(rls->_context.version2.event), 1, NULL, 0, NULL); - rls->_context.version2.event.flags &= ~EV_ADD; - if (ret < 0) { - CFLog(0, CFSTR("CFRunLoop: tragic kevent failure #1")); - } -#endif } } @@ -546,18 +536,6 @@ static void __CFRunLoopSourceCancel(CFRunLoopSourceRef rls, CFRunLoopRef rl, CFR if (CFPORT_NULL != port) { __CFPortSetRemove(port, rlm->_portSet); } - } else if (2 == rls->_context.version0.version) { -#if defined(__MACH__) - if (-1 == rlm->_kq) { - rlm->_kq = kqueue_from_portset_np(rlm->_portSet); - } - rls->_context.version2.event.flags |= EV_DELETE; - int ret = kevent(rlm->_kq, &(rls->_context.version2.event), 1, NULL, 0, NULL); - rls->_context.version2.event.flags &= ~EV_DELETE; - if (ret < 0) { - CFLog(0, CFSTR("CFRunLoop: tragic kevent failure #2")); - } -#endif } __CFRunLoopSourceLock(rls); if (NULL != rls->_runLoops) { @@ -581,27 +559,27 @@ struct __CFRunLoopObserver { /* Bit 1 of the base reserved bits is used for repeats state */ CF_INLINE Boolean __CFRunLoopObserverIsFiring(CFRunLoopObserverRef rlo) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_info, 0, 0); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0); } CF_INLINE void __CFRunLoopObserverSetFiring(CFRunLoopObserverRef rlo) { - __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_info, 0, 0, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 1); } CF_INLINE void __CFRunLoopObserverUnsetFiring(CFRunLoopObserverRef rlo) { - __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_info, 0, 0, 0); + __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 0, 0, 0); } CF_INLINE Boolean __CFRunLoopObserverRepeats(CFRunLoopObserverRef rlo) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_info, 1, 1); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1); } CF_INLINE void __CFRunLoopObserverSetRepeats(CFRunLoopObserverRef rlo) { - __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_info, 1, 1, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1, 1); } CF_INLINE void __CFRunLoopObserverUnsetRepeats(CFRunLoopObserverRef rlo) { - __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_info, 1, 1, 0); + __CFBitfieldSetValue(((CFRuntimeBase *)rlo)->_cfinfo[CF_INFO_BITS], 1, 1, 0); } CF_INLINE void __CFRunLoopObserverLock(CFRunLoopObserverRef rlo) { @@ -635,7 +613,7 @@ struct __CFRunLoopTimer { CFSpinLock_t _lock; CFRunLoopRef _runLoop; CFIndex _rlCount; -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX mach_port_name_t _port; #endif CFIndex _order; /* immutable */ @@ -649,27 +627,27 @@ 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)->_info, 0, 0); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0); } CF_INLINE void __CFRunLoopTimerSetFiring(CFRunLoopTimerRef rlt) { - __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_info, 0, 0, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0, 1); } CF_INLINE void __CFRunLoopTimerUnsetFiring(CFRunLoopTimerRef rlt) { - __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_info, 0, 0, 0); + __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 0, 0, 0); } CF_INLINE Boolean __CFRunLoopTimerDidFire(CFRunLoopTimerRef rlt) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_info, 1, 1); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1); } CF_INLINE void __CFRunLoopTimerSetDidFire(CFRunLoopTimerRef rlt) { - __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_info, 1, 1, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1, 1); } CF_INLINE void __CFRunLoopTimerUnsetDidFire(CFRunLoopTimerRef rlt) { - __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_info, 1, 1, 0); + __CFBitfieldSetValue(((CFRuntimeBase *)rlt)->_cfinfo[CF_INFO_BITS], 1, 1, 0); } CF_INLINE void __CFRunLoopTimerLock(CFRunLoopTimerRef rlt) { @@ -680,7 +658,7 @@ CF_INLINE void __CFRunLoopTimerUnlock(CFRunLoopTimerRef rlt) { __CFSpinUnlock(&(rlt->_lock)); } -static CFSpinLock_t __CFRLTFireTSRLock = 0; +static CFSpinLock_t __CFRLTFireTSRLock = CFSpinLockInit; CF_INLINE void __CFRunLoopTimerFireTSRLock(void) { __CFSpinLock(&__CFRLTFireTSRLock); @@ -690,9 +668,9 @@ CF_INLINE void __CFRunLoopTimerFireTSRUnlock(void) { __CFSpinUnlock(&__CFRLTFireTSRLock); } -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX static CFMutableDictionaryRef __CFRLTPortMap = NULL; -static CFSpinLock_t __CFRLTPortMapLock = 0; +static CFSpinLock_t __CFRLTPortMapLock = CFSpinLockInit; CF_INLINE void __CFRunLoopTimerPortMapLock(void) { __CFSpinLock(&__CFRLTPortMapLock); @@ -704,7 +682,7 @@ CF_INLINE void __CFRunLoopTimerPortMapUnlock(void) { #endif static void __CFRunLoopTimerSchedule(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRunLoopModeRef rlm) { -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX __CFRunLoopTimerLock(rlt); if (0 == rlt->_rlCount) { rlt->_runLoop = rl; @@ -715,7 +693,7 @@ static void __CFRunLoopTimerSchedule(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFR if (NULL == __CFRLTPortMap) { __CFRLTPortMap = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); } - CFDictionarySetValue(__CFRLTPortMap, (void *)rlt->_port, rlt); + CFDictionarySetValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port, rlt); __CFRunLoopTimerPortMapUnlock(); } rlt->_rlCount++; @@ -726,14 +704,14 @@ static void __CFRunLoopTimerSchedule(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFR } static void __CFRunLoopTimerCancel(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRunLoopModeRef rlm) { -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX __CFRunLoopTimerLock(rlt); __CFPortSetRemove(rlt->_port, rlm->_portSet); rlt->_rlCount--; if (0 == rlt->_rlCount) { __CFRunLoopTimerPortMapLock(); if (NULL != __CFRLTPortMap) { - CFDictionaryRemoveValue(__CFRLTPortMap, (void *)rlt->_port); + CFDictionaryRemoveValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port); } __CFRunLoopTimerPortMapUnlock(); rlt->_runLoop = NULL; @@ -745,57 +723,11 @@ static void __CFRunLoopTimerCancel(CFRunLoopTimerRef rlt, CFRunLoopRef rl, CFRun // Caller must hold the Timer lock for safety static void __CFRunLoopTimerRescheduleWithAllModes(CFRunLoopTimerRef rlt, CFRunLoopRef rl) { -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX mk_timer_arm(rlt->_port, __CFUInt64ToAbsoluteTime(rlt->_fireTSR)); #endif } -#if defined(__WIN32__) - -struct _collectTimersContext { - CFMutableArrayRef results; - int64_t cutoffTSR; -}; - -static void __CFRunLoopCollectTimers(const void *value, void *ctx) { - CFRunLoopTimerRef rlt = (CFRunLoopTimerRef)value; - struct _collectTimersContext *context = ctx; - if (rlt->_fireTSR <= context->cutoffTSR) { - if (NULL == context->results) - context->results = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); - CFArrayAppendValue(context->results, rlt); - } -} - -// 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); - } - } - } -} - -// RunLoop and RunLoopMode must be locked -static CFArrayRef __CFRunLoopTimersToFire(CFRunLoopRef rl, CFRunLoopModeRef rlm) { - struct _collectTimersContext ctxt = {NULL, __CFReadTSR()}; - __CFRunLoopTimersToFireRecursive(rl, rlm, &ctxt); - return ctxt.results; -} -#endif - /* CFRunLoop */ CONST_STRING_DECL(kCFRunLoopDefaultMode, "kCFRunLoopDefaultMode") @@ -822,6 +754,7 @@ static void __CFRunLoopFindSource(const void *value, void *ctx) { // call with rl and rlm locked static CFRunLoopSourceRef __CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl, CFRunLoopModeRef rlm, __CFPort port) { /* DOES CALLOUT */ + CHECK_FOR_FORK(); struct _findsource context = {port, NULL}; if (NULL != rlm->_sources) { CFSetApplyFunction(rlm->_sources, (__CFRunLoopFindSource), &context); @@ -846,13 +779,14 @@ static CFRunLoopSourceRef __CFRunLoopModeFindSourceForMachPort(CFRunLoopRef rl, return context.result; } -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX // 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 *)port); + result = (CFRunLoopTimerRef)CFDictionaryGetValue(__CFRLTPortMap, (void *)(uintptr_t)port); } __CFRunLoopTimerPortMapUnlock(); return result; @@ -992,7 +926,7 @@ static CFRunLoopRef __CFRunLoopCreate(void) { return NULL; } loop->_stopped = NULL; - loop->_lock = 0; + CF_SPINLOCK_INIT_FOR_STRUCTS(loop->_lock); loop->_wakeUpPort = __CFPortAllocate(); if (CFPORT_NULL == loop->_wakeUpPort) HALT; loop->_commonModes = CFSetCreateMutable(CFGetAllocator(loop), 0, &kCFTypeSetCallBacks); @@ -1001,80 +935,114 @@ static CFRunLoopRef __CFRunLoopCreate(void) { loop->_currentMode = NULL; loop->_modes = CFSetCreateMutable(CFGetAllocator(loop), 0, &kCFTypeSetCallBacks); _CFSetSetCapacity(loop->_modes, 10); + loop->_counterpart = NULL; rlm = __CFRunLoopFindMode(loop, kCFRunLoopDefaultMode, true); if (NULL != rlm) __CFRunLoopModeUnlock(rlm); return loop; } -#if defined(__MACH__) -// We don't properly call _CFRunLoopSetMain on Win32, so better to cut these routines -// out until they are properly implemented. +static CFMutableDictionaryRef runLoops = NULL; +static char setMainLoop = 0; +static CFSpinLock_t loopsLock = CFSpinLockInit; -static CFRunLoopRef mainLoop = NULL; -static int mainLoopPid = 0; -static CFSpinLock_t mainLoopLock = 0; +// If this is called on a non-main thread, and the main thread pthread_t is passed in, +// and this has not yet beed called on the main thread (since the last fork(), this will +// produce a different run loop that will probably be tossed away eventually, than the +// main thread run loop. There's nothing much we can do about that, without a call to +// fetch the main thread's pthread_t from the pthreads subsystem. -CFRunLoopRef CFRunLoopGetMain(void) { - __CFSpinLock(&mainLoopLock); - if (mainLoopPid != getpid()) { - // intentionally leak mainLoop so we don't kill any ports in the child - mainLoop = NULL; +// t==0 is a synonym for "main thread" that always works +__private_extern__ CFRunLoopRef _CFRunLoop0(pthread_t t) { + CFRunLoopRef loop = NULL; + __CFSpinLock(&loopsLock); + if (!runLoops) { + __CFSpinUnlock(&loopsLock); + CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); + CFRunLoopRef mainLoop = __CFRunLoopCreate(); + CFDictionarySetValue(dict, 0, mainLoop); + if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&runLoops)) { + CFRelease(dict); + CFRelease(mainLoop); + } + __CFSpinLock(&loopsLock); + } + if (pthread_main_np() && pthread_equal(t, pthread_self())) { + t = kNilPthreadT; + } + loop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(t)); + if (!loop) { + __CFSpinUnlock(&loopsLock); + CFRunLoopRef newLoop = __CFRunLoopCreate(); + __CFGetThreadSpecificData(); // just cause the thread finalizer to be called as a side effect + __CFSpinLock(&loopsLock); + loop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(t)); + if (loop) { + CFRelease(newLoop); + } else { + CFDictionarySetValue(runLoops, pthreadPointer(t), newLoop); + loop = newLoop; + } } - if (!mainLoop) { - mainLoop = __CFRunLoopCreate(); - mainLoopPid = getpid(); + if (!setMainLoop && pthread_main_np()) { + if (pthread_equal(t, kNilPthreadT)) { + CFDictionarySetValue(runLoops, pthreadPointer(pthread_self()), loop); + } else { + CFRunLoopRef mainLoop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(kNilPthreadT)); + CFDictionarySetValue(runLoops, pthreadPointer(pthread_self()), mainLoop); + } + setMainLoop = 1; } - __CFSpinUnlock(&mainLoopLock); - return mainLoop; + __CFSpinUnlock(&loopsLock); + return loop; } -static void _CFRunLoopSetMain(CFRunLoopRef rl) { - if (rl != mainLoop) { - if (rl) CFRetain(rl); -// intentionally leak the old main run loop -// if (mainLoop) CFRelease(mainLoop); - mainLoop = rl; +__private_extern__ void _CFRunLoop1(void) { + __CFSpinLock(&loopsLock); + if (runLoops) { + pthread_t t = pthread_self(); + CFRunLoopRef currentLoop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(t)); + CFRunLoopRef mainLoop = (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(kNilPthreadT)); + if (currentLoop && mainLoop != currentLoop) { + CFDictionaryRemoveValue(runLoops, pthreadPointer(t)); + CFRelease(currentLoop); + } } + __CFSpinUnlock(&loopsLock); +} + +CFRunLoopRef CFRunLoopGetMain(void) { + CHECK_FOR_FORK(); + return _CFRunLoop0(kNilPthreadT); } -#endif CFRunLoopRef CFRunLoopGetCurrent(void) { -#if defined(__MACH__) - if (pthread_main_np()) { - return CFRunLoopGetMain(); - } -#endif - CFRunLoopRef currentLoop = __CFGetThreadSpecificData_inline()->_runLoop; - int currentLoopPid = __CFGetThreadSpecificData_inline()->_runLoop_pid; - if (currentLoopPid != getpid()) { - // intentionally leak currentLoop so we don't kill any ports in the child - currentLoop = NULL; - } - if (!currentLoop) { - currentLoop = __CFRunLoopCreate(); - __CFGetThreadSpecificData_inline()->_runLoop = currentLoop; - __CFGetThreadSpecificData_inline()->_runLoop_pid = getpid(); - } - return currentLoop; + CHECK_FOR_FORK(); + return _CFRunLoop0(pthread_self()); } void _CFRunLoopSetCurrent(CFRunLoopRef rl) { -#if defined(__MACH__) - if (pthread_main_np()) { - return _CFRunLoopSetMain(rl); - } -#endif - CFRunLoopRef currentLoop = __CFGetThreadSpecificData_inline()->_runLoop; + __CFSpinLock(&loopsLock); + CFRunLoopRef currentLoop = runLoops ? (CFRunLoopRef)CFDictionaryGetValue(runLoops, pthreadPointer(pthread_self())) : NULL; if (rl != currentLoop) { - if (rl) CFRetain(rl); -// intentionally leak old run loop -// if (currentLoop) CFRelease(currentLoop); - __CFGetThreadSpecificData_inline()->_runLoop = rl; - __CFGetThreadSpecificData_inline()->_runLoop_pid = getpid(); + // intentionally leak currentLoop so we don't kill any ports in the child + // if (currentLoop) CFRelease(currentLoop); + if (rl) { + if (!runLoops) { + runLoops = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); + CFRunLoopRef mainLoop = __CFRunLoopCreate(); + CFDictionarySetValue(runLoops, pthreadPointer(kNilPthreadT), mainLoop); + } + CFRetain(rl); + CFDictionarySetValue(runLoops, pthreadPointer(pthread_self()), rl); + } else { + CFDictionaryRemoveValue(runLoops, pthreadPointer(pthread_self())); + } } + __CFSpinUnlock(&loopsLock); } CFStringRef CFRunLoopCopyCurrentMode(CFRunLoopRef rl) { + CHECK_FOR_FORK(); CFStringRef result = NULL; __CFRunLoopLock(rl); if (NULL != rl->_currentMode) { @@ -1091,9 +1059,10 @@ static void __CFRunLoopGetModeName(const void *value, void *context) { } CFArrayRef CFRunLoopCopyAllModes(CFRunLoopRef rl) { + CHECK_FOR_FORK(); CFMutableArrayRef array; __CFRunLoopLock(rl); - array = CFArrayCreateMutable(kCFAllocatorDefault, CFSetGetCount(rl->_modes), &kCFTypeArrayCallBacks); + array = CFArrayCreateMutable(kCFAllocatorSystemDefault, CFSetGetCount(rl->_modes), &kCFTypeArrayCallBacks); CFSetApplyFunction(rl->_modes, (__CFRunLoopGetModeName), array); __CFRunLoopUnlock(rl); return array; @@ -1138,7 +1107,23 @@ static void __CFRunLoopRemoveItemFromCommonModes(const void *value, void *ctx) { } } +Boolean _CFRunLoop01(CFRunLoopRef rl, CFStringRef modeName) { + __CFRunLoopLock(rl); + Boolean present = CFSetContainsValue(rl->_commonModes, modeName); + __CFRunLoopUnlock(rl); + return present; +} + +void *_CFRunLoop02(CFRunLoopRef rl) { + return rl->_counterpart; +} + +void _CFRunLoop03(CFRunLoopRef rl, void *ns) { + rl->_counterpart = ns; +} + void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef modeName) { + CHECK_FOR_FORK(); if (__CFRunLoopIsDeallocating(rl)) return; __CFRunLoopLock(rl); if (!CFSetContainsValue(rl->_commonModes, modeName)) { @@ -1156,66 +1141,70 @@ void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef modeName) { } } -static CFComparisonResult __CFRunLoopObserverComparator(const void *val1, const void *val2, void *context) { - CFRunLoopObserverRef o1 = (CFRunLoopObserverRef)val1; - CFRunLoopObserverRef o2 = (CFRunLoopObserverRef)val2; +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; + } + if (!o2) { + return kCFCompareGreaterThan; + } if (o1->_order < o2->_order) return kCFCompareLessThan; if (o2->_order < o1->_order) return kCFCompareGreaterThan; return kCFCompareEqualTo; } -struct _collectobs { - CFRunLoopActivity activity; - CFMutableArrayRef array; -}; - -static void __CFRunLoopCollectObservers(const void *value, void *context) { - CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)value; - struct _collectobs *info = (struct _collectobs *)context; - if (0 != (rlo->_activities & info->activity) && __CFIsValid(rlo) && !__CFRunLoopObserverIsFiring(rlo)) { - CFArrayAppendValue(info->array, rlo); - } -} /* 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; - CFMutableArrayRef array; CFArrayRef submodes; - struct _collectobs info; /* Fire the observers */ submodes = (NULL != rlm->_submodes && 0 < CFArrayGetCount(rlm->_submodes)) ? CFArrayCreateCopy(kCFAllocatorSystemDefault, rlm->_submodes) : NULL; if (NULL != rlm->_observers) { - array = CFArrayCreateMutable(kCFAllocatorSystemDefault, CFSetGetCount(rlm->_observers), &kCFTypeArrayCallBacks); - info.array = array; - info.activity = activity; - CFSetApplyFunction(rlm->_observers, (__CFRunLoopCollectObservers), &info); - cnt = CFArrayGetCount(array); + cnt = CFSetGetCount(rlm->_observers); if (0 < cnt) { - __CFRunLoopModeUnlock(rlm); - CFArraySortValues(array, CFRangeMake(0, cnt), (__CFRunLoopObserverComparator), NULL); + CFRunLoopObserverRef buffer[(cnt <= 1024) ? cnt : 1]; + CFRunLoopObserverRef *collectedObservers = (cnt <= 1024) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(CFRunLoopObserverRef), 0); + CFSetGetValues(rlm->_observers, (const void **)collectedObservers); for (idx = 0; idx < cnt; idx++) { - CFRunLoopObserverRef rlo = (CFRunLoopObserverRef)CFArrayGetValueAtIndex(array, idx); - __CFRunLoopObserverLock(rlo); - if (__CFIsValid(rlo)) { - __CFRunLoopObserverUnlock(rlo); - __CFRunLoopObserverSetFiring(rlo); - rlo->_callout(rlo, activity, rlo->_context.info); /* CALLOUT */ - __CFRunLoopObserverUnsetFiring(rlo); - if (!__CFRunLoopObserverRepeats(rlo)) { - CFRunLoopObserverInvalidate(rlo); - } + CFRunLoopObserverRef rlo = collectedObservers[idx]; + if (0 != (rlo->_activities & activity) && __CFIsValid(rlo) && !__CFRunLoopObserverIsFiring(rlo)) { + CFRetain(rlo); } else { - __CFRunLoopObserverUnlock(rlo); + /* 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); } - CFRelease(array); } if (NULL != submodes) { __CFRunLoopModeUnlock(rlm); @@ -1263,6 +1252,7 @@ static void __CFRunLoopCollectSources0(const void *value, void *context) { /* rl is unlocked, rlm is locked on entrance and exit */ static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Boolean stopAfterHandle) { /* DOES CALLOUT */ + CHECK_FOR_FORK(); CFTypeRef sources = NULL; Boolean sourceHandled = false; CFIndex idx, cnt; @@ -1297,6 +1287,7 @@ static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Bool __CFRunLoopSourceUnlock(rls); if (NULL != rls->_context.version0.perform) { rls->_context.version0.perform(rls->_context.version0.info); /* CALLOUT */ + CHECK_FOR_FORK(); } sourceHandled = true; } else { @@ -1313,6 +1304,7 @@ static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Bool __CFRunLoopSourceUnlock(rls); if (NULL != rls->_context.version0.perform) { rls->_context.version0.perform(rls->_context.version0.info); /* CALLOUT */ + CHECK_FOR_FORK(); } sourceHandled = true; } else { @@ -1331,10 +1323,11 @@ static Boolean __CFRunLoopDoSources0(CFRunLoopRef rl, CFRunLoopModeRef rlm, Bool // msg, size and reply are unused on Windows static Boolean __CFRunLoopDoSource1(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopSourceRef rls -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX , mach_msg_header_t *msg, CFIndex size, mach_msg_header_t **reply #endif ) { /* DOES CALLOUT */ + CHECK_FOR_FORK(); Boolean sourceHandled = false; /* Fire a version 1 source */ @@ -1345,14 +1338,20 @@ static Boolean __CFRunLoopDoSource1(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRun __CFRunLoopSourceUnsetSignaled(rls); __CFRunLoopSourceUnlock(rls); if (NULL != rls->_context.version1.perform) { -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX *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(); #endif - } + } else { + if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 perform is NULL"), CFRunLoopGetCurrent(), *_CFGetProgname()); } + } sourceHandled = true; } else { + if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s) __CFRunLoopDoSource1 rls %p is invalid"), CFRunLoopGetCurrent(), *_CFGetProgname(), rls); } __CFRunLoopSourceUnlock(rls); } CFRelease(rls); @@ -1376,6 +1375,7 @@ static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLo oldFireTSR = rlt->_fireTSR; __CFRunLoopTimerFireTSRUnlock(); rlt->_callout(rlt, rlt->_context.info); /* CALLOUT */ + CHECK_FOR_FORK(); __CFRunLoopTimerUnsetFiring(rlt); timerHandled = true; } else { @@ -1428,6 +1428,7 @@ static Boolean __CFRunLoopDoTimer(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLo } CF_EXPORT Boolean _CFRunLoopFinished(CFRunLoopRef rl, CFStringRef modeName) { + CHECK_FOR_FORK(); CFRunLoopModeRef rlm; Boolean result = false; __CFRunLoopLock(rl); @@ -1457,22 +1458,11 @@ static void __CFRunLoopModeAddPortsToPortSet(CFRunLoopRef rl, CFRunLoopModeRef r if (CFPORT_NULL != port) { __CFPortSetInsert(port, portSet); } - } else if (2 == rls->_context.version0.version) { -#if defined(__MACH__) - int kq = kqueue_from_portset_np(portSet); - rls->_context.version2.event.flags |= EV_ADD; - int ret = kevent(kq, &(rls->_context.version2.event), 1, NULL, 0, NULL); - rls->_context.version2.event.flags &= ~EV_ADD; - close(kq); - if (ret < 0) { - CFLog(0, CFSTR("CFRunLoop: tragic kevent failure #3")); - } -#endif } } if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); } -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX if (NULL != rlm->_timers) { cnt = CFSetGetCount(rlm->_timers); list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(void *), 0); @@ -1498,19 +1488,19 @@ static void __CFRunLoopModeAddPortsToPortSet(CFRunLoopRef rl, CFRunLoopModeRef r } } -static __CFPortSet _LastMainWaitSet = NULL; +static __CFPortSet _LastMainWaitSet = 0; // return NO if we're the main runloop and there are no messages waiting on the port set int _CFRunLoopInputsReady(void) { + CHECK_FOR_FORK(); // XXX_PCB: the following 2 lines aren't safe to call during GC, because another // thread may have entered CFRunLoopGetMain(), which grabs a spink lock, and then // is suspended by the GC. We can check for the main thread more directly // by calling pthread_main_np(). // CFRunLoopRef current = CFRunLoopGetMain() // if (current != CFRunLoopGetMain()) return true; -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX if (!pthread_main_np()) return true; -#endif // XXX_PCB: can't be any messages waiting if the wait set is NULL. if (_LastMainWaitSet == MACH_PORT_NULL) return false; @@ -1526,12 +1516,74 @@ int _CFRunLoopInputsReady(void) { 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); return (MACH_RCV_TOO_LARGE == ret); +#endif + return true; +} + +#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; + } + } + } } +#endif /* rl is unlocked, rlm locked on entrance and exit */ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInterval seconds, Boolean stopAfterHandle, Boolean waitIfEmpty) { /* DOES CALLOUT */ int64_t termTSR; -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX mach_port_name_t timeoutPort = MACH_PORT_NULL; Boolean timeoutPortAdded = false; #endif @@ -1546,13 +1598,11 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter } if (seconds <= 0.0) { termTSR = 0; - } else if (__CFTSRToTimeInterval(LLONG_MAX) < seconds) { - termTSR = LLONG_MAX; - } else if ((uint64_t)LLONG_MAX <= __CFReadTSR() + (uint64_t)__CFTimeIntervalToTSR(seconds)) { + } else if (3.1556952e+9 < seconds) { termTSR = LLONG_MAX; } else { termTSR = (int64_t)__CFReadTSR() + __CFTimeIntervalToTSR(seconds); -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX timeoutPort = mk_timer_create(); mk_timer_arm(timeoutPort, __CFUInt64ToAbsoluteTime(termTSR)); #endif @@ -1560,16 +1610,16 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter if (seconds <= 0.0) { poll = true; } - if (rl == mainLoop) _LastMainWaitSet = CFPORT_NULL; + if (rl == _CFRunLoop0(kNilPthreadT)) _LastMainWaitSet = CFPORT_NULL; for (;;) { __CFPortSet waitSet = CFPORT_NULL; waitSet = CFPORT_NULL; Boolean destroyWaitSet = false; CFRunLoopSourceRef rls; -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX mach_msg_header_t *msg; kern_return_t ret; - uint8_t buffer[1024 + 80]; // large enough for 1k of inline payload + uint8_t buffer[1024 + 80] = {0}; // large enough for 1k of inline payload; must be zeroed for GC #else CFArrayRef timersToCall = NULL; #endif @@ -1598,7 +1648,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter __CFRunLoopModeLock(rlm); __CFRunLoopModeAddPortsToPortSet(rl, rlm, waitSet); __CFRunLoopUnlock(rl); -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX if (CFPORT_NULL != timeoutPort) { __CFPortSetInsert(timeoutPort, waitSet); } @@ -1606,17 +1656,17 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter destroyWaitSet = true; } else { waitSet = rlm->_portSet; -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX if (!timeoutPortAdded && CFPORT_NULL != timeoutPort) { __CFPortSetInsert(timeoutPort, waitSet); timeoutPortAdded = true; } #endif } - if (rl == mainLoop) _LastMainWaitSet = waitSet; + if (rl == _CFRunLoop0(kNilPthreadT)) _LastMainWaitSet = waitSet; __CFRunLoopModeUnlock(rlm); -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX msg = (mach_msg_header_t *)buffer; msg->msgh_size = sizeof(buffer); @@ -1641,7 +1691,6 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter HALT; } #elif defined(__WIN32__) - __CFRunLoopModeUnlock(rlm); DWORD waitResult = WAIT_TIMEOUT; HANDLE handleBuf[MAXIMUM_WAIT_OBJECTS]; HANDLE *handles; @@ -1663,6 +1712,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter if (poll) timeout = 0; else { + __CFRunLoopModeLock(rlm); int64_t nextStop = __CFRunLoopGetNextTimerFireTSR(rl, rlm); if (nextStop <= 0) nextStop = termTSR; @@ -1680,13 +1730,16 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter timeout = timeoutCF; } } - waitResult = MsgWaitForMultipleObjects(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, false, timeout, rlm->_msgQMask); + if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s)- about to wait for %d objects, wakeupport is %p"), CFRunLoopGetCurrent(), *_CFGetProgname(), handleCount, rl->_wakeUpPort); } + if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("All RLM sources = %@"), rlm->_sources); } + waitResult = MsgWaitForMultipleObjects(__CFMin(handleCount, MAXIMUM_WAIT_OBJECTS), handles, false, timeout, rlm->_msgQMask); + if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s)- waitResult was %d"), CFRunLoopGetCurrent(), *_CFGetProgname(), waitResult); } } ResetEvent(rl->_wakeUpPort); #endif if (destroyWaitSet) { __CFPortSetFree(waitSet); - if (rl == mainLoop) _LastMainWaitSet = NULL; + if (rl == _CFRunLoop0(kNilPthreadT)) _LastMainWaitSet = 0; } __CFRunLoopLock(rl); __CFRunLoopModeLock(rlm); @@ -1701,7 +1754,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter __CFRunLoopModeLock(rlm); __CFPort livePort = CFPORT_NULL; -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX if (NULL != msg) { livePort = msg->msgh_local_port; } @@ -1710,8 +1763,9 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter 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 + // a handle was signalled livePort = handles[waitResult-WAIT_OBJECT_0]; + if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("%p (%s)- Resetting event %p"), CFRunLoopGetCurrent(), *_CFGetProgname(), livePort); } } else if (waitResult == WAIT_OBJECT_0+handleCount) { // windows message received - the CFWindowsMessageQueue will pick this up when // the v0 RunLoopSources get their chance @@ -1728,45 +1782,23 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter if (CFPORT_NULL == livePort) { __CFRunLoopUnlock(rl); -#if defined(__MACH__) - if (NULL != msg) { - // This must be a kevent, msgh_local_port is MACH_PORT_NULL in that case - struct kevent *kev = (void *)msg + sizeof(mach_msg_header_t) + ((msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) ? (sizeof(mach_msg_body_t) + sizeof(mach_msg_descriptor_t) * ((mach_msg_base_t *)msg)->body.msgh_descriptor_count) : 0); - rls = kev->udata; - kev->udata = NULL; - - /* Fire a version 2 source */ - CFRetain(rls); - __CFRunLoopModeUnlock(rlm); - __CFRunLoopSourceLock(rls); - if (__CFIsValid(rls)) { - __CFRunLoopSourceUnsetSignaled(rls); - __CFRunLoopSourceUnlock(rls); - if (NULL != rls->_context.version2.perform) { - rls->_context.version2.perform(kev, rls->_context.version2.info); /* CALLOUT */ - } - sourceHandledThisLoop = true; - } else { - __CFRunLoopSourceUnlock(rls); - } - CFRelease(rls); - __CFRunLoopModeLock(rlm); - } -#endif } else if (livePort == rl->_wakeUpPort) { // wakeup + if (_LogCFRunLoop) { CFLog(kCFLogLevelDebug, CFSTR("wakeupPort was signalled")); } __CFRunLoopUnlock(rl); } -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX else if (livePort == timeoutPort) { returnValue = kCFRunLoopRunTimedOut; __CFRunLoopUnlock(rl); } 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? @@ -1784,21 +1816,13 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter #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; } } #endif -#if defined(__WIN32__) - if (NULL != timersToCall) { - int i; - for (i = CFArrayGetCount(timersToCall)-1; i >= 0; i--) - __CFRunLoopDoTimer(rl, rlm, (CFRunLoopTimerRef)CFArrayGetValueAtIndex(timersToCall, i)); - CFRelease(timersToCall); - } -#endif - __CFRunLoopModeUnlock(rlm); // locks must be taken in order __CFRunLoopLock(rl); __CFRunLoopModeLock(rlm); @@ -1819,7 +1843,7 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter } __CFRunLoopUnlock(rl); if (0 != returnValue) { -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX if (MACH_PORT_NULL != timeoutPort) { if (!destroyWaitSet) __CFPortSetRemove(timeoutPort, waitSet); mk_timer_destroy(timeoutPort); @@ -1832,34 +1856,31 @@ static int32_t __CFRunLoopRun(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFTimeInter } SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */ - CFRunLoopModeRef currentMode, previousMode; - CFIndex *previousStopped; - int32_t result; - + CHECK_FOR_FORK(); if (__CFRunLoopIsDeallocating(rl)) return kCFRunLoopRunFinished; __CFRunLoopLock(rl); - currentMode = __CFRunLoopFindMode(rl, modeName, false); + CFRunLoopModeRef currentMode = __CFRunLoopFindMode(rl, modeName, false); if (NULL == currentMode || __CFRunLoopModeIsEmpty(rl, currentMode)) { if (currentMode) __CFRunLoopModeUnlock(currentMode); __CFRunLoopUnlock(rl); return kCFRunLoopRunFinished; } - // We can drop the volatile-ness for the previousStopped ptr - previousStopped = (CFIndex *)rl->_stopped; - rl->_stopped = CFAllocatorAllocate(kCFAllocatorSystemDefault, 16, 0); + uint32_t *previousStopped = (uint32_t *)rl->_stopped; + rl->_stopped = CFAllocatorAllocate(kCFAllocatorSystemDefault, 4 * sizeof(uint32_t), 0); rl->_stopped[0] = 0x4346524C; rl->_stopped[1] = 0x4346524C; // 'CFRL' rl->_stopped[2] = 0x00000000; // here the value is stored rl->_stopped[3] = 0x4346524C; - previousMode = rl->_currentMode; + CFRunLoopModeRef previousMode = rl->_currentMode; rl->_currentMode = currentMode; __CFRunLoopUnlock(rl); + int32_t result; __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry); result = __CFRunLoopRun(rl, currentMode, seconds, returnAfterSourceHandled, false); __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit); __CFRunLoopModeUnlock(currentMode); __CFRunLoopLock(rl); - CFAllocatorDeallocate(kCFAllocatorSystemDefault, (CFIndex *)rl->_stopped); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, (uint32_t *)rl->_stopped); rl->_stopped = previousStopped; rl->_currentMode = previousMode; __CFRunLoopUnlock(rl); @@ -1870,10 +1891,12 @@ void CFRunLoopRun(void) { /* DOES CALLOUT */ int32_t result; do { result = CFRunLoopRunSpecific(CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 1.0e10, false); + CHECK_FOR_FORK(); } while (kCFRunLoopRunStopped != result && kCFRunLoopRunFinished != result); } SInt32 CFRunLoopRunInMode(CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled) { /* DOES CALLOUT */ + CHECK_FOR_FORK(); return CFRunLoopRunSpecific(CFRunLoopGetCurrent(), modeName, seconds, returnAfterSourceHandled); } @@ -1913,11 +1936,12 @@ static int64_t __CFRunLoopGetNextTimerFireTSR(CFRunLoopRef rl, CFRunLoopModeRef } } __CFRunLoopModeUnlock(rlm); -} + } return fireTime; } CFAbsoluteTime CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFStringRef modeName) { + CHECK_FOR_FORK(); CFRunLoopModeRef rlm; int64_t fireTSR; __CFRunLoopLock(rl); @@ -1930,11 +1954,13 @@ CFAbsoluteTime CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFStringRef modeNa } Boolean CFRunLoopIsWaiting(CFRunLoopRef rl) { + CHECK_FOR_FORK(); return __CFRunLoopIsSleeping(rl); } void CFRunLoopWakeUp(CFRunLoopRef rl) { -#if defined(__MACH__) + CHECK_FOR_FORK(); +#if DEPLOYMENT_TARGET_MACOSX kern_return_t ret; /* We unconditionally try to send the message, since we don't want * to lose a wakeup, but the send may fail if there is already a @@ -1949,6 +1975,7 @@ void CFRunLoopWakeUp(CFRunLoopRef rl) { } void CFRunLoopStop(CFRunLoopRef rl) { + CHECK_FOR_FORK(); __CFRunLoopLock(rl); __CFRunLoopSetStopped(rl); __CFRunLoopUnlock(rl); @@ -1956,6 +1983,7 @@ void CFRunLoopStop(CFRunLoopRef rl) { } CF_EXPORT void _CFRunLoopStopMode(CFRunLoopRef rl, CFStringRef modeName) { + CHECK_FOR_FORK(); CFRunLoopModeRef rlm; __CFRunLoopLock(rl); rlm = __CFRunLoopFindMode(rl, modeName, true); @@ -1968,6 +1996,7 @@ CF_EXPORT void _CFRunLoopStopMode(CFRunLoopRef rl, CFStringRef modeName) { } CF_EXPORT Boolean _CFRunLoopModeContainsMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef candidateContainedName) { + CHECK_FOR_FORK(); CFRunLoopModeRef rlm; if (modeName == kCFRunLoopCommonModes || candidateContainedName == kCFRunLoopCommonModes) { return false; @@ -2005,6 +2034,7 @@ CF_EXPORT Boolean _CFRunLoopModeContainsMode(CFRunLoopRef rl, CFStringRef modeNa } 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 @@ -2028,6 +2058,7 @@ CF_EXPORT void _CFRunLoopAddModeToMode(CFRunLoopRef rl, CFStringRef modeName, CF } CF_EXPORT void _CFRunLoopRemoveModeFromMode(CFRunLoopRef rl, CFStringRef modeName, CFStringRef fromModeName) { + 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. @@ -2049,6 +2080,7 @@ CF_EXPORT void _CFRunLoopRemoveModeFromMode(CFRunLoopRef rl, CFStringRef modeNam } Boolean CFRunLoopContainsSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { + CHECK_FOR_FORK(); CFRunLoopModeRef rlm; Boolean hasValue = false; __CFRunLoopLock(rl); @@ -2071,6 +2103,7 @@ Boolean CFRunLoopContainsSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStrin } void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { /* DOES CALLOUT */ + CHECK_FOR_FORK(); CFRunLoopModeRef rlm; if (__CFRunLoopIsDeallocating(rl)) return; if (!__CFIsValid(rls)) return; @@ -2107,6 +2140,7 @@ void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef mod } void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef modeName) { /* DOES CALLOUT */ + CHECK_FOR_FORK(); CFRunLoopModeRef rlm; __CFRunLoopLock(rl); if (modeName == kCFRunLoopCommonModes) { @@ -2139,6 +2173,7 @@ void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef rls, CFStringRef } Boolean CFRunLoopContainsObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) { + CHECK_FOR_FORK(); CFRunLoopModeRef rlm; Boolean hasValue = false; __CFRunLoopLock(rl); @@ -2161,6 +2196,7 @@ Boolean CFRunLoopContainsObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFS } void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) { + CHECK_FOR_FORK(); CFRunLoopModeRef rlm; if (__CFRunLoopIsDeallocating(rl)) return; if (!__CFIsValid(rlo) || (NULL != rlo->_runLoop && rlo->_runLoop != rl)) return; @@ -2195,6 +2231,7 @@ void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef } void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFStringRef modeName) { + CHECK_FOR_FORK(); CFRunLoopModeRef rlm; __CFRunLoopLock(rl); if (modeName == kCFRunLoopCommonModes) { @@ -2227,6 +2264,7 @@ void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef rlo, CFString } Boolean CFRunLoopContainsTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) { + CHECK_FOR_FORK(); CFRunLoopModeRef rlm; Boolean hasValue = false; __CFRunLoopLock(rl); @@ -2249,6 +2287,7 @@ Boolean CFRunLoopContainsTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringR } void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) { + CHECK_FOR_FORK(); CFRunLoopModeRef rlm; if (__CFRunLoopIsDeallocating(rl)) return; if (!__CFIsValid(rlt) || (NULL != rlt->_runLoop && rlt->_runLoop != rl)) return; @@ -2283,6 +2322,7 @@ void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeN } void CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef rlt, CFStringRef modeName) { + CHECK_FOR_FORK(); CFRunLoopModeRef rlm; __CFRunLoopLock(rl); if (modeName == kCFRunLoopCommonModes) { @@ -2327,8 +2367,6 @@ static Boolean __CFRunLoopSourceEqual(CFTypeRef cf1, CFTypeRef cf2) { /* DOES CA if (rls1->_context.version0.equal != rls2->_context.version0.equal) return false; if (0 == rls1->_context.version0.version && rls1->_context.version0.perform != rls2->_context.version0.perform) return false; if (1 == rls1->_context.version0.version && rls1->_context.version1.perform != rls2->_context.version1.perform) return false; - if (2 == rls1->_context.version0.version && rls1->_context.version2.perform != rls2->_context.version2.perform) return false; - if (2 == rls1->_context.version0.version && !(rls1->_context.version2.event.ident == rls2->_context.version2.event.ident && rls1->_context.version2.event.filter == rls2->_context.version2.event.filter)) return false; if (rls1->_context.version0.equal) return rls1->_context.version0.equal(rls1->_context.version0.info, rls2->_context.version0.info); return (rls1->_context.version0.info == rls2->_context.version0.info); @@ -2349,9 +2387,16 @@ static CFStringRef __CFRunLoopSourceCopyDescription(CFTypeRef cf) { /* DOES CALL contextDesc = rls->_context.version0.copyDescription(rls->_context.version0.info); } if (NULL == contextDesc) { - contextDesc = CFStringCreateWithFormat(CFGetAllocator(rls), NULL, CFSTR(""), rls->_context.version0.info); + void *addr = rls->_context.version0.version == 0 ? (void *)rls->_context.version0.perform : (rls->_context.version0.version == 1 ? (void *)rls->_context.version1.perform : NULL); +#if DEPLOYMENT_TARGET_MACOSX + Dl_info info; + const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; + contextDesc = CFStringCreateWithFormat(CFGetAllocator(rls), NULL, CFSTR("{version = %ld, info = %p, callout = %s (%p)}"), rls->_context.version0.version, rls->_context.version0.info, name, addr); +#else +#error Unknown or unspecified DEPLOYMENT_TARGET +#endif } -result = CFStringCreateWithFormat(CFGetAllocator(rls), NULL, CFSTR("{locked = %s, signaled = %s, valid = %s, order = %d, context = %@}"), cf, CFGetAllocator(rls), rls->_lock ? "Yes" : "No", __CFRunLoopSourceIsSignaled(rls) ? "Yes" : "No", __CFIsValid(rls) ? "Yes" : "No", rls->_order, contextDesc); +result = CFStringCreateWithFormat(CFGetAllocator(rls), 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); CFRelease(contextDesc); return result; } @@ -2385,6 +2430,7 @@ CFTypeID CFRunLoopSourceGetTypeID(void) { } CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order, CFRunLoopSourceContext *context) { + CHECK_FOR_FORK(); CFRunLoopSourceRef memory; uint32_t size; if (NULL == context) HALT; @@ -2395,7 +2441,7 @@ CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order } __CFSetValid(memory); __CFRunLoopSourceUnsetSignaled(memory); - memory->_lock = 0; + CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock); memory->_bits = 0; memory->_order = order; memory->_runLoops = NULL; @@ -2407,15 +2453,13 @@ CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order case 1: size = sizeof(CFRunLoopSourceContext1); break; +#if DEPLOYMENT_TARGET_MACOSX case 2: size = sizeof(CFRunLoopSourceContext2); break; +#endif } CF_WRITE_BARRIER_MEMMOVE(&memory->_context, context, size); - if (2 == memory->_context.version0.version) { - memory->_context.version2.event.udata = memory; - memory->_context.version2.event.flags &= ~(EV_SYSFLAGS | 0xFF0F); // clear all but a few flags - } if (context->retain) { memory->_context.version0.info = (void *)context->retain(context->info); } @@ -2423,6 +2467,7 @@ CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order } CFIndex CFRunLoopSourceGetOrder(CFRunLoopSourceRef rls) { + CHECK_FOR_FORK(); __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID); return rls->_order; } @@ -2445,11 +2490,13 @@ static void __CFRunLoopSourceRemoveFromRunLoop(const void *value, void *context) } void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls) { + CHECK_FOR_FORK(); __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID); CFRetain(rls); __CFRunLoopSourceLock(rls); if (__CFIsValid(rls)) { __CFUnsetValid(rls); + __CFRunLoopSourceUnsetSignaled(rls); if (NULL != rls->_runLoops) { CFTypeRef params[2] = {rls, NULL}; CFBagRef bag = CFBagCreateCopy(kCFAllocatorSystemDefault, rls->_runLoops); @@ -2469,13 +2516,15 @@ void CFRunLoopSourceInvalidate(CFRunLoopSourceRef rls) { } Boolean CFRunLoopSourceIsValid(CFRunLoopSourceRef rls) { + CHECK_FOR_FORK(); __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID); return __CFIsValid(rls); } void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls, CFRunLoopSourceContext *context) { + CHECK_FOR_FORK(); __CFGenericValidateType(rls, __kCFRunLoopSourceTypeID); - CFAssert1(0 == context->version || 1 == context->version || 2 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__); + CFAssert1(0 == context->version || 1 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0 or 1", __PRETTY_FUNCTION__); CFIndex size = 0; switch (context->version) { case 0: @@ -2484,14 +2533,17 @@ void CFRunLoopSourceGetContext(CFRunLoopSourceRef rls, CFRunLoopSourceContext *c case 1: size = sizeof(CFRunLoopSourceContext1); break; +#if DEPLOYMENT_TARGET_MACOSX case 2: size = sizeof(CFRunLoopSourceContext2); break; +#endif } memmove(context, &rls->_context, size); } void CFRunLoopSourceSignal(CFRunLoopSourceRef rls) { + CHECK_FOR_FORK(); __CFRunLoopSourceLock(rls); if (__CFIsValid(rls)) { __CFRunLoopSourceSetSignaled(rls); @@ -2499,6 +2551,13 @@ void CFRunLoopSourceSignal(CFRunLoopSourceRef rls) { __CFRunLoopSourceUnlock(rls); } +Boolean CFRunLoopSourceIsSignalled(CFRunLoopSourceRef rls) { + CHECK_FOR_FORK(); + __CFRunLoopSourceLock(rls); + Boolean ret = __CFRunLoopSourceIsSignaled(rls) ? true : false; + __CFRunLoopSourceUnlock(rls); + return ret; +} /* CFRunLoopObserver */ @@ -2512,7 +2571,14 @@ static CFStringRef __CFRunLoopObserverCopyDescription(CFTypeRef cf) { /* DOES CA if (!contextDesc) { contextDesc = CFStringCreateWithFormat(CFGetAllocator(rlo), NULL, CFSTR(""), rlo->_context.info); } - result = CFStringCreateWithFormat(CFGetAllocator(rlo), NULL, CFSTR("{locked = %s, valid = %s, activities = 0x%x, repeats = %s, order = %d, callout = %p, context = %@}"), cf, CFGetAllocator(rlo), rlo->_lock ? "Yes" : "No", __CFIsValid(rlo) ? "Yes" : "No", rlo->_activities, __CFRunLoopObserverRepeats(rlo) ? "Yes" : "No", rlo->_order, rlo->_callout, contextDesc); +#if DEPLOYMENT_TARGET_MACOSX + 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(CFGetAllocator(rlo), 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); +#else +#error Unknown or unspecified DEPLOYMENT_TARGET +#endif CFRelease(contextDesc); return result; } @@ -2543,6 +2609,7 @@ CFTypeID CFRunLoopObserverGetTypeID(void) { } CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context) { + CHECK_FOR_FORK(); CFRunLoopObserverRef memory; UInt32 size; size = sizeof(struct __CFRunLoopObserver) - sizeof(CFRuntimeBase); @@ -2557,7 +2624,7 @@ CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionF } else { __CFRunLoopObserverUnsetRepeats(memory); } - memory->_lock = 0; + CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock); memory->_runLoop = NULL; memory->_rlCount = 0; memory->_activities = activities; @@ -2582,21 +2649,25 @@ CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionF } CFOptionFlags CFRunLoopObserverGetActivities(CFRunLoopObserverRef rlo) { + CHECK_FOR_FORK(); __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); return rlo->_activities; } CFIndex CFRunLoopObserverGetOrder(CFRunLoopObserverRef rlo) { + CHECK_FOR_FORK(); __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); return rlo->_order; } Boolean CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef rlo) { + CHECK_FOR_FORK(); __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); return __CFRunLoopObserverRepeats(rlo); } void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo) { /* DOES CALLOUT */ + CHECK_FOR_FORK(); __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); CFRetain(rlo); __CFRunLoopObserverLock(rlo); @@ -2625,10 +2696,12 @@ void CFRunLoopObserverInvalidate(CFRunLoopObserverRef rlo) { /* DOES CALLOUT */ } Boolean CFRunLoopObserverIsValid(CFRunLoopObserverRef rlo) { + CHECK_FOR_FORK(); return __CFIsValid(rlo); } void CFRunLoopObserverGetContext(CFRunLoopObserverRef rlo, CFRunLoopObserverContext *context) { + CHECK_FOR_FORK(); __CFGenericValidateType(rlo, __kCFRunLoopObserverTypeID); CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__); *context = rlo->_context; @@ -2652,7 +2725,14 @@ static CFStringRef __CFRunLoopTimerCopyDescription(CFTypeRef cf) { /* DOES CALLO } int64_t now2 = (int64_t)mach_absolute_time(); CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); - result = CFStringCreateWithFormat(CFGetAllocator(rlt), NULL, CFSTR("{locked = %s, valid = %s, interval = %0.09g, next fire date = %0.09g, order = %d, callout = %p, context = %@}"), cf, CFGetAllocator(rlt), rlt->_lock ? "Yes" : "No", __CFIsValid(rlt) ? "Yes" : "No", __CFTSRToTimeInterval(rlt->_intervalTSR), now1 + __CFTSRToTimeInterval(fireTime - now2), rlt->_order, rlt->_callout, contextDesc); +#if DEPLOYMENT_TARGET_MACOSX + 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(CFGetAllocator(rlt), 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", __CFTSRToTimeInterval(rlt->_intervalTSR), now1 + __CFTSRToTimeInterval(fireTime - now2), rlt->_order, name, addr, contextDesc); +#else +#error Unknown or unspecified DEPLOYMENT_TARGET +#endif CFRelease(contextDesc); return result; } @@ -2683,6 +2763,7 @@ CFTypeID CFRunLoopTimerGetTypeID(void) { } CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context) { + CHECK_FOR_FORK(); CFRunLoopTimerRef memory; UInt32 size; size = sizeof(struct __CFRunLoopTimer) - sizeof(CFRuntimeBase); @@ -2693,15 +2774,16 @@ CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime __CFSetValid(memory); __CFRunLoopTimerUnsetFiring(memory); __CFRunLoopTimerUnsetDidFire(memory); - memory->_lock = 0; + CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock); memory->_runLoop = NULL; memory->_rlCount = 0; -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX memory->_port = MACH_PORT_NULL; #endif memory->_order = order; int64_t now2 = (int64_t)mach_absolute_time(); CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); + if (3.1556952e+9 < fireDate) fireDate = 3.1556952e+9; if (fireDate < now1) { memory->_fireTSR = now2; } else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < fireDate) { @@ -2709,6 +2791,7 @@ CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime } else { memory->_fireTSR = now2 + __CFTimeIntervalToTSR(fireDate - now1); } + if (3.1556952e+9 < interval) interval = 3.1556952e+9; if (interval <= 0.0) { memory->_intervalTSR = 0; } else if (__CFTSRToTimeInterval(LLONG_MAX) < interval) { @@ -2736,6 +2819,7 @@ CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime } CFAbsoluteTime CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt) { + CHECK_FOR_FORK(); int64_t fireTime, result = 0; CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFAbsoluteTime, rlt, "_cffireTime"); __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); @@ -2753,9 +2837,11 @@ CFAbsoluteTime CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef rlt) { } void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt, CFAbsoluteTime fireDate) { + CHECK_FOR_FORK(); __CFRunLoopTimerFireTSRLock(); int64_t now2 = (int64_t)mach_absolute_time(); CFAbsoluteTime now1 = CFAbsoluteTimeGetCurrent(); + if (3.1556952e+9 < fireDate) fireDate = 3.1556952e+9; if (fireDate < now1) { rlt->_fireTSR = now2; } else if (now1 + __CFTSRToTimeInterval(LLONG_MAX) < fireDate) { @@ -2770,23 +2856,27 @@ void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef rlt, CFAbsoluteTime fireDat } CFTimeInterval CFRunLoopTimerGetInterval(CFRunLoopTimerRef rlt) { + CHECK_FOR_FORK(); CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, CFTimeInterval, rlt, "timeInterval"); __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); return __CFTSRToTimeInterval(rlt->_intervalTSR); } Boolean CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef rlt) { + CHECK_FOR_FORK(); __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); return (0 != rlt->_intervalTSR); } 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(); CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, void, rlt, "invalidate"); __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); CFRetain(rlt); @@ -2795,10 +2885,10 @@ void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt) { /* DOES CALLOUT */ CFRunLoopRef rl = rlt->_runLoop; void *info = rlt->_context.info; __CFUnsetValid(rlt); -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX __CFRunLoopTimerPortMapLock(); if (NULL != __CFRLTPortMap) { - CFDictionaryRemoveValue(__CFRLTPortMap, (void *)rlt->_port); + CFDictionaryRemoveValue(__CFRLTPortMap, (void *)(uintptr_t)rlt->_port); } __CFRunLoopTimerPortMapUnlock(); mk_timer_destroy(rlt->_port); @@ -2827,141 +2917,18 @@ void CFRunLoopTimerInvalidate(CFRunLoopTimerRef rlt) { /* DOES CALLOUT */ } Boolean CFRunLoopTimerIsValid(CFRunLoopTimerRef rlt) { + CHECK_FOR_FORK(); CF_OBJC_FUNCDISPATCH0(__kCFRunLoopTimerTypeID, Boolean, rlt, "isValid"); __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); return __CFIsValid(rlt); } void CFRunLoopTimerGetContext(CFRunLoopTimerRef rlt, CFRunLoopTimerContext *context) { + CHECK_FOR_FORK(); __CFGenericValidateType(rlt, __kCFRunLoopTimerTypeID); CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__); *context = rlt->_context; } -struct rlpair { - CFRunLoopRef rl; // not retained - CFStringRef mode; // not retained -}; - -static Boolean __CFRLPKeyEqual(const void *value1, const void *value2) { - const struct rlpair *s1 = value1; - const struct rlpair *s2 = value2; - return (s1->rl == s2->rl) && CFEqual(s1->mode, s2->mode); -} - -static CFHashCode __CFRLPKeyHash(const void *value) { - const struct rlpair *s = value; - return (CFHashCode)s->rl + CFHash(s->mode); -} - -static CFSpinLock_t __CFRunLoopPerformLock = 0; -static CFMutableDictionaryRef __CFRunLoopPerformSources = NULL; - -struct performentry { - CFRunLoopPerformCallBack callout; - void *info; -}; - -struct performinfo { - CFSpinLock_t lock; - CFRunLoopSourceRef source; - CFRunLoopRef rl; - CFStringRef mode; - CFIndex count; - CFIndex size; - struct performentry *entries; -}; - -static void __CFRunLoopPerformCancel(void *info, CFRunLoopRef rl, CFStringRef mode) { - // we don't ever remove the source, so we know the run loop is dying - struct rlpair key, *pair; - struct performinfo *pinfo = info; - __CFSpinLock(&__CFRunLoopPerformLock); - key.rl = rl; - key.mode = mode; - if (CFDictionaryGetKeyIfPresent(__CFRunLoopPerformSources, &key, (const void **)&pair)) { - CFDictionaryRemoveValue(__CFRunLoopPerformSources, pair); - CFAllocatorDeallocate(kCFAllocatorSystemDefault, pair); - } - CFRunLoopSourceInvalidate(pinfo->source); - CFAllocatorDeallocate(kCFAllocatorSystemDefault, pinfo->entries); - CFAllocatorDeallocate(kCFAllocatorSystemDefault, pinfo); - // We can free pinfo here, even though the source isn't freed and still has - // a weak pointer to it, because the hash and equal callbacks of the source - // don't indirect into the info for their operations. - __CFSpinUnlock(&__CFRunLoopPerformLock); -} - -static void __CFRunLoopPerformPerform(void *info) { - struct performinfo *pinfo = info; - struct performentry *entries; - CFIndex idx, cnt; - __CFSpinLock(&(pinfo->lock)); - entries = pinfo->entries; - cnt = pinfo->count; - pinfo->entries = NULL; - pinfo->count = 0; - pinfo->size = 0; - __CFSpinUnlock(&(pinfo->lock)); - for (idx = 0; idx < cnt; idx++) { - entries[idx].callout(entries[idx].info); - } - // done with this list - CFAllocatorDeallocate(kCFAllocatorSystemDefault, entries); - // don't need to check to see if there's still something in the queue, - // and resignal here, since anything added during the callouts, - // from this or another thread, would have caused resignalling -} - -// retaining and freeing the info pointer and stuff inside is completely -// the caller's (and probably the callout's) responsibility -void _CFRunLoopPerformEnqueue(CFRunLoopRef rl, CFStringRef mode, CFRunLoopPerformCallBack callout, void *info) { - CFRunLoopSourceContext context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; - CFRunLoopSourceRef source; - struct rlpair key; - struct performinfo *pinfo; - __CFSpinLock(&__CFRunLoopPerformLock); - if (!__CFRunLoopPerformSources) { - CFDictionaryKeyCallBacks kcb = {0, NULL, NULL, NULL, __CFRLPKeyEqual, __CFRLPKeyHash}; - __CFRunLoopPerformSources = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kcb, &kCFTypeDictionaryValueCallBacks); - } - key.rl = rl; - key.mode = mode; - if (!CFDictionaryGetValueIfPresent(__CFRunLoopPerformSources, &key, (const void **)&source)) { - struct rlpair *pair; - context.info = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct performinfo), 0); - pinfo = context.info; - pinfo->lock = 0; - pinfo->rl = rl; - pinfo->mode = mode; - pinfo->count = 0; - pinfo->size = 0; - pinfo->entries = NULL; - context.cancel = __CFRunLoopPerformCancel; - context.perform = __CFRunLoopPerformPerform; - source = CFRunLoopSourceCreate(kCFAllocatorSystemDefault, 0, &context); - pair = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(*pair), 0); - *pair = key; - CFDictionarySetValue(__CFRunLoopPerformSources, pair, source); - pinfo->source = source; - CFRunLoopAddSource(rl, source, mode); - } else { - CFRetain(source); - CFRunLoopSourceGetContext(source, &context); - pinfo = context.info; - } - __CFSpinLock(&(pinfo->lock)); - __CFSpinUnlock(&__CFRunLoopPerformLock); - if (pinfo->count == pinfo->size) { - pinfo->size = (0 == pinfo->size ? 3 : 2 * pinfo->size); - pinfo->entries = CFAllocatorReallocate(kCFAllocatorSystemDefault, pinfo->entries, pinfo->size * sizeof(struct performentry), 0); - } - pinfo->entries[pinfo->count].callout = callout; - pinfo->entries[pinfo->count].info = info; - pinfo->count++; - __CFSpinUnlock(&(pinfo->lock)); - CFRunLoopSourceSignal(source); - CFRunLoopWakeUp(rl); - CFRelease(source); -} +#endif diff --git a/CFRunLoop.h b/CFRunLoop.h new file mode 100644 index 0000000..1a96c69 --- /dev/null +++ b/CFRunLoop.h @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFRunLoop.h + Copyright (c) 1998-2007, Apple Inc. All rights reserved. +*/ + +#if !defined(__COREFOUNDATION_CFRUNLOOP__) +#define __COREFOUNDATION_CFRUNLOOP__ 1 + +#include +#include +#include +#include +#if defined(__MACH__) + #include +#endif + +CF_EXTERN_C_BEGIN + +typedef struct __CFRunLoop * CFRunLoopRef; + +typedef struct __CFRunLoopSource * CFRunLoopSourceRef; + +typedef struct __CFRunLoopObserver * CFRunLoopObserverRef; + +typedef struct __CFRunLoopTimer * CFRunLoopTimerRef; + +/* Reasons for CFRunLoopRunInMode() to Return */ +enum { + kCFRunLoopRunFinished = 1, + kCFRunLoopRunStopped = 2, + kCFRunLoopRunTimedOut = 3, + kCFRunLoopRunHandledSource = 4 +}; + +/* Run Loop Observer Activities */ +enum { + kCFRunLoopEntry = (1 << 0), + kCFRunLoopBeforeTimers = (1 << 1), + kCFRunLoopBeforeSources = (1 << 2), + kCFRunLoopBeforeWaiting = (1 << 5), + kCFRunLoopAfterWaiting = (1 << 6), + kCFRunLoopExit = (1 << 7), + kCFRunLoopAllActivities = 0x0FFFFFFFU +}; +typedef CFOptionFlags CFRunLoopActivity; + +CF_EXPORT const CFStringRef kCFRunLoopDefaultMode; +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 CFStringRef CFRunLoopCopyCurrentMode(CFRunLoopRef rl); + +CF_EXPORT CFArrayRef CFRunLoopCopyAllModes(CFRunLoopRef rl); + +CF_EXPORT void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef mode); + +CF_EXPORT CFAbsoluteTime CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFStringRef mode); + +CF_EXPORT void CFRunLoopRun(void); +CF_EXPORT SInt32 CFRunLoopRunInMode(CFStringRef mode, CFTimeInterval seconds, Boolean returnAfterSourceHandled); +CF_EXPORT Boolean CFRunLoopIsWaiting(CFRunLoopRef rl); +CF_EXPORT void CFRunLoopWakeUp(CFRunLoopRef rl); +CF_EXPORT void CFRunLoopStop(CFRunLoopRef rl); + +CF_EXPORT Boolean CFRunLoopContainsSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef mode); +CF_EXPORT void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef mode); +CF_EXPORT void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef mode); + +CF_EXPORT Boolean CFRunLoopContainsObserver(CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef mode); +CF_EXPORT void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef mode); +CF_EXPORT void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef mode); + +CF_EXPORT Boolean CFRunLoopContainsTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode); +CF_EXPORT void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode); +CF_EXPORT void CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode); + +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 (*schedule)(void *info, CFRunLoopRef rl, CFStringRef mode); + void (*cancel)(void *info, CFRunLoopRef rl, CFStringRef mode); + void (*perform)(void *info); +} CFRunLoopSourceContext; + +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); +#if defined(__MACH__) + mach_port_t (*getPort)(void *info); + void * (*perform)(void *msg, CFIndex size, CFAllocatorRef allocator, void *info); +#else + HANDLE (*getPort)(void *info); + void (*perform)(void *info); +#endif +} CFRunLoopSourceContext1; + +CF_EXPORT CFTypeID CFRunLoopSourceGetTypeID(void); + +CF_EXPORT CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order, CFRunLoopSourceContext *context); + +CF_EXPORT CFIndex CFRunLoopSourceGetOrder(CFRunLoopSourceRef source); +CF_EXPORT void CFRunLoopSourceInvalidate(CFRunLoopSourceRef source); +CF_EXPORT Boolean CFRunLoopSourceIsValid(CFRunLoopSourceRef source); +CF_EXPORT void CFRunLoopSourceGetContext(CFRunLoopSourceRef source, CFRunLoopSourceContext *context); +CF_EXPORT void CFRunLoopSourceSignal(CFRunLoopSourceRef source); + +typedef struct { + CFIndex version; + void * info; + const void *(*retain)(const void *info); + void (*release)(const void *info); + CFStringRef (*copyDescription)(const void *info); +} CFRunLoopObserverContext; + +typedef void (*CFRunLoopObserverCallBack)(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info); + +CF_EXPORT CFTypeID CFRunLoopObserverGetTypeID(void); + +CF_EXPORT CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context); + +CF_EXPORT CFOptionFlags CFRunLoopObserverGetActivities(CFRunLoopObserverRef observer); +CF_EXPORT Boolean CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef observer); +CF_EXPORT CFIndex CFRunLoopObserverGetOrder(CFRunLoopObserverRef observer); +CF_EXPORT void CFRunLoopObserverInvalidate(CFRunLoopObserverRef observer); +CF_EXPORT Boolean CFRunLoopObserverIsValid(CFRunLoopObserverRef observer); +CF_EXPORT void CFRunLoopObserverGetContext(CFRunLoopObserverRef observer, CFRunLoopObserverContext *context); + +typedef struct { + CFIndex version; + void * info; + const void *(*retain)(const void *info); + void (*release)(const void *info); + CFStringRef (*copyDescription)(const void *info); +} CFRunLoopTimerContext; + +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); +CF_EXPORT CFAbsoluteTime CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef timer); +CF_EXPORT void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef timer, CFAbsoluteTime fireDate); +CF_EXPORT CFTimeInterval CFRunLoopTimerGetInterval(CFRunLoopTimerRef timer); +CF_EXPORT Boolean CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef timer); +CF_EXPORT CFIndex CFRunLoopTimerGetOrder(CFRunLoopTimerRef timer); +CF_EXPORT void CFRunLoopTimerInvalidate(CFRunLoopTimerRef timer); +CF_EXPORT Boolean CFRunLoopTimerIsValid(CFRunLoopTimerRef timer); +CF_EXPORT void CFRunLoopTimerGetContext(CFRunLoopTimerRef timer, CFRunLoopTimerContext *context); + +CF_EXTERN_C_END + +#endif /* ! __COREFOUNDATION_CFRUNLOOP__ */ + diff --git a/CFRunLoopPriv.h b/CFRunLoopPriv.h new file mode 100644 index 0000000..9d516ee --- /dev/null +++ b/CFRunLoopPriv.h @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFRunLoopPriv.h + Copyright (c) 2006-2007, Apple Inc. All rights reserved. +*/ + +#if (DEPLOYMENT_TARGET_MACOSX || 0) + +/* -------- -------- -------- -------- -------- -------- -------- -------- */ + +#import "CFObject.h" +#include +#include +#include +#include +#include +#include +#include +#include + +@class CFRunLoopSourceSet; +typedef CFRunLoopSourceContext CFRunLoopSourceContext0; +typedef CFMachPortContext CFRunLoopMachPortContext; +typedef CFSocketContext CFRunLoopSocketContext; + +/* -------- -------- -------- -------- -------- -------- -------- -------- */ + +@interface CFRunLoopSource : CFObject { + uint8_t _cfruntime_[8]; // large enough for 32-bit or 64-bit + int _kq; + mach_port_t _portset; + mach_port_t _port; + CFIndex _order; + uint8_t _invalid; + uint8_t _firing; + uint8_t _ownsPort; + uint8_t _async; +} + +- (int)kqueue; +- (mach_port_t)machPortSet; +- (mach_port_t)machPort; + +- (void)setOrder:(CFIndex)o; +- (CFIndex)order; + +- (void)setAsyncStrategy:(uint8_t)s; +- (uint8_t)asyncStrategy; + +- (void)perform:(mach_msg_header_t *)msg; + +- (void)invalidate; +- (Boolean)isValid; + +- (void)noteAddedToSourceSet:(CFRunLoopSourceSet *)ss; +- (void)noteRemovedFromSourceSet:(CFRunLoopSourceSet *)ss; + +- (CFStringRef)copyPartialDebugDescription; // subclasses override +- (CFStringRef)copyDebugDescription; + +@end + +@interface CFRunLoopVersion0SourceCFRef : CFRunLoopSource { + CFRunLoopSourceContext0 _context; +} + +- (Boolean)setContext:(CFRunLoopSourceContext0)c; +- (CFRunLoopSourceContext0)context; + +- (void)markReady; +- (void)handle; + +- (void)scheduleInRunLoop:(CFRunLoopRef)rl mode:(CFStringRef)n; +- (void)cancelFromRunLoop:(CFRunLoopRef)rl mode:(CFStringRef)n; + +@end + +@interface CFRunLoopVersion1SourceCFRef : CFRunLoopSource { + CFRunLoopSourceContext1 _context; +} + +- (Boolean)setContext:(CFRunLoopSourceContext1)c; +- (CFRunLoopSourceContext1)context; + +- (void)markReady; +- (void)handle:(mach_msg_header_t *)msg; + +@end + +/* -------- -------- -------- -------- -------- -------- -------- -------- */ + +@interface CFRunLoopTimerSource : CFRunLoopSource { + CFAbsoluteTime _fireAT; + CFTimeInterval _interval; +} + +- (void)setFireTime:(CFAbsoluteTime)at; +- (CFAbsoluteTime)fireTime; + +- (void)setInterval:(CFTimeInterval)i; +- (CFTimeInterval)interval; + +- (void)handle; + +@end + +@interface CFRunLoopTimerSourceCFRef : CFRunLoopTimerSource { + void *_function; + CFRunLoopTimerContext _context; +} + +- (void)setFunction:(void *)f; +- (void *)function; + +- (Boolean)setContext:(CFRunLoopTimerContext)c; +- (CFRunLoopTimerContext)context; + +@end + +/* -------- -------- -------- -------- -------- -------- -------- -------- */ + +@interface CFRunLoopMachPortSource : CFRunLoopSource { + mach_port_t _notifyPort; + mach_port_t _oldNotifyPort; +} + ++ (id)newWithPort:(mach_port_t)p; + +- (void)handle:(mach_msg_header_t *)msg; + +@end + +@interface CFRunLoopMachPortSourceCFRef : CFRunLoopMachPortSource { + void *_function; + CFRunLoopMachPortContext _context; + void *_invalidation; +} + +- (void)setFunction:(void *)f; +- (void *)function; + +- (Boolean)setContext:(CFRunLoopMachPortContext)c; +- (CFRunLoopMachPortContext)context; + +- (void)setInvalidationFunction:(void *)f; +- (void *)invalidationFunction; + +@end + +/* -------- -------- -------- -------- -------- -------- -------- -------- */ + +@interface CFRunLoopKEventSource : CFRunLoopSource { + struct kevent _filter; +} + +- (Boolean)setFilter:(struct kevent)kev; +- (struct kevent)filter; + +- (void)handle:(struct kevent *)kev; + +@end + +/* -------- -------- -------- -------- -------- -------- -------- -------- */ + +@interface CFRunLoopSignalSource : CFRunLoopSource { + int _signal; +} + +- (Boolean)setSignal:(int)sig; +- (int)signal; + +- (long)poll; + +- (void)handle:(long)n; + +@end + +/* -------- -------- -------- -------- -------- -------- -------- -------- */ + +@interface CFRunLoopProcessDeathSource : CFRunLoopSource { + int _pid; +} + +- (Boolean)setProcessID:(int)pid; +- (int)processID; + +- (void)handle; + +@end + +/* -------- -------- -------- -------- -------- -------- -------- -------- */ + +@interface CFRunLoopSocketSource : CFRunLoopSource { + int _socket; + uint8_t _ownsSocket; + uint8_t _enabledR; + uint8_t _enabledW; +} + ++ (id)newWithSocket:(int)s; + +- (int)socket; +- (CFDataRef)copyLocalAddress; +- (CFDataRef)copyRemoteAddress; + +- (void)setReadEventsEnabled:(Boolean)b; +- (Boolean)readEventsEnabled; + +- (void)setWriteEventsEnabled:(Boolean)b; +- (Boolean)writeEventsEnabled; + +- (void)handleReadability:(CFIndex)amt endOfFile:(Boolean)b; +- (void)performRead:(struct kevent *)kev; + +- (void)handleWritability:(CFIndex)amt endOfFile:(Boolean)b; +- (void)performWrite:(struct kevent *)kev; + +@end + +@interface CFRunLoopSocketSourceCFRef : CFRunLoopSocketSource { + void *_function; + CFRunLoopSocketContext _context; + uint8_t _callbacks; + uint8_t _flags; + uint8_t _disabled; +} + +- (void)setFunction:(void *)f; +- (void *)function; + +- (Boolean)setContext:(CFRunLoopSocketContext)c; +- (CFRunLoopSocketContext)context; + +- (void)setCallBackTypes:(uint8_t)f; +- (uint8_t)callBackTypes; + +- (void)setFlags:(uint8_t)f; +- (uint8_t)flags; + +- (void)setDisabledFlags:(uint8_t)f; +- (uint8_t)disabledFlags; + +- (Boolean)handleAcceptError:(int)err; +- (Boolean)handleReadError:(int)err; + +@end + +/* -------- -------- -------- -------- -------- -------- -------- -------- */ + +@interface CFRunLoopObserver : CFRunLoopSource { +} + +- (void)observeEntry:(CFRunLoopSourceSet *)ss; +- (void)observeBeforeWaiting:(CFRunLoopSourceSet *)ss; +- (void)observeAfterWaiting:(CFRunLoopSourceSet *)ss; +- (void)observeExit:(CFRunLoopSourceSet *)ss; + +@end + +@interface CFRunLoopObserverCFRef : CFRunLoopObserver { + void *_function; + CFRunLoopObserverContext _context; + CFOptionFlags _activities; + uint8_t _oneshot; +} + +- (void)setFunction:(void *)f; +- (void *)function; + +- (Boolean)setContext:(CFRunLoopObserverContext)c; +- (CFRunLoopObserverContext)context; + +- (void)setActivities:(CFOptionFlags)a; +- (CFOptionFlags)activities; + +- (void)setOneshot:(Boolean)b; +- (Boolean)oneshot; + +@end + +/* -------- -------- -------- -------- -------- -------- -------- -------- */ + +@interface CFRunLoopSourceSet : CFRunLoopObserver { + CFMutableBagRef _sources; + CFStringRef _name; + pthread_t _thread; + CFMutableArrayRef _observers[4]; + CFRunLoopTimerSource *_timeoutTimer; + CFRunLoopMachPortSource *_wakeupPort; + uint8_t _stopped; + uint8_t _waiting; +} + ++ (void)removeSourceFromAllSets:(CFRunLoopSource *)src; + +- (void)setName:(CFStringRef)n; +- (CFStringRef)name; + +- (void)setAffineThread:(pthread_t)t; +- (pthread_t)affineThread; + +- (Boolean)containsObserver:(CFRunLoopObserver *)o; +- (void)addObserver:(CFRunLoopObserver *)o activities:(CFRunLoopActivity)a; +- (void)removeObserver:(CFRunLoopObserver *)o activities:(CFRunLoopActivity)a; + +- (Boolean)containsSource:(CFRunLoopSource *)src; +- (void)addSource:(CFRunLoopSource *)src; +- (void)removeSource:(CFRunLoopSource *)src; + +- (void)forEachSource:(Boolean (*)(CFRunLoopSource *, void *))f context:(void *)c; + +- (void)stop; +- (void)wakeup; +- (Boolean)isWaiting; +- (Boolean)isEmpty; +- (Boolean)hasInputAvailable; + +- (int32_t)serviceUntil:(CFAbsoluteTime)at handleOne:(Boolean)handleOne; + +@end + +/* -------- -------- -------- -------- -------- -------- -------- -------- */ + +@interface CFRunLoopCFRef : CFObject { + uint8_t _cfruntime_[8]; // large enough for 32-bit or 64-bit + pthread_t _thread; + void *_counterpart; + CFMutableArrayRef _sourceSets; + CFRunLoopSourceSet *_currentSet; + uint8_t _invalid; +} + +- (void)setAffineThread:(pthread_t)t; +- (pthread_t)affineThread; + +- (void)setCounterpart:(void *)c; +- (void *)counterpart; + +- (void)invalidate; +- (Boolean)isValid; + +- (CFArrayRef)copySourceSets; + +- (void)setCurrentSourceSet:(CFRunLoopSourceSet *)ss; +- (CFRunLoopSourceSet *)currentSourceSet; + +- (CFRunLoopSourceSet *)lookupSourceSetWithName:(CFStringRef)n; +- (CFRunLoopSourceSet *)lookupOrCreateSourceSetWithName:(CFStringRef)n; + +- (CFStringRef)copyDebugDescription; + +@end + +/* -------- -------- -------- -------- -------- -------- -------- -------- */ + +#endif + diff --git a/CFRuntime.c b/CFRuntime.c new file mode 100644 index 0000000..be667e1 --- /dev/null +++ b/CFRuntime.c @@ -0,0 +1,1068 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFRuntime.c + Copyright 1999-2002, Apple, Inc. All rights reserved. + Responsibility: Christopher Kane +*/ + +#define ENABLE_ZOMBIES 1 + +#include "CFRuntime.h" +#include "CFInternal.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "auto_stubs.h" + +#define __CFRecordAllocationEvent(a, b, c, d, e) ((void)0) + +enum { +// retain/release recording constants -- must match values +// used by OA for now; probably will change in the future +__kCFRetainEvent = 28, +__kCFReleaseEvent = 29 +}; + +#include + +extern void __HALT(void); + +static CFTypeID __kCFNotATypeTypeID = _kCFRuntimeNotATypeID; + +#if !defined (__cplusplus) +static const CFRuntimeClass __CFNotATypeClass = { + 0, + "Not A Type", + (void *)__HALT, + (void *)__HALT, + (void *)__HALT, + (void *)__HALT, + (void *)__HALT, + (void *)__HALT, + (void *)__HALT +}; + +static CFTypeID __kCFTypeTypeID = _kCFRuntimeNotATypeID; + +static const CFRuntimeClass __CFTypeClass = { + 0, + "CFType", + (void *)__HALT, + (void *)__HALT, + (void *)__HALT, + (void *)__HALT, + (void *)__HALT, + (void *)__HALT, + (void *)__HALT +}; +#else +void SIG1(CFTypeRef){__HALT();};; +CFTypeRef SIG2(CFAllocatorRef,CFTypeRef){__HALT();return NULL;}; +Boolean SIG3(CFTypeRef,CFTypeRef){__HALT();return FALSE;}; +CFHashCode SIG4(CFTypeRef){__HALT(); return 0;}; +CFStringRef SIG5(CFTypeRef,CFDictionaryRef){__HALT();return NULL;}; +CFStringRef SIG6(CFTypeRef){__HALT();return NULL;}; + +static const CFRuntimeClass __CFNotATypeClass = { + 0, + "Not A Type", + SIG1, + SIG2, + SIG1, + SIG3, + SIG4, + SIG5, + SIG6 +}; + +static CFTypeID __kCFTypeTypeID = _kCFRuntimeNotATypeID; + +static const CFRuntimeClass __CFTypeClass = { + 0, + "CFType", + SIG1, + SIG2, + SIG1, + SIG3, + SIG4, + SIG5, + SIG6 +}; +#endif //__cplusplus + +static CFRuntimeClass ** __CFRuntimeClassTable = NULL; +int32_t __CFRuntimeClassTableSize = 0; +static int32_t __CFRuntimeClassTableCount = 0; + +__private_extern__ void * (*__CFSendObjCMsg)(const void *, SEL, ...) = NULL; + +__private_extern__ malloc_zone_t *__CFCollectableZone = NULL; + +bool (*__CFObjCIsCollectable)(void *) = NULL; + +static const void* objc_AssignIvar_none(const void *value, const void *base, const void **slot) { return (*slot = value); } +const void* (*__CFObjCAssignIvar)(const void *value, const void *base, const void **slot) = objc_AssignIvar_none; + +static const void* objc_StrongAssign_none(const void *value, const void **slot) { return (*slot = value); } +const void* (*__CFObjCStrongAssign)(const void *value, const void **slot) = objc_StrongAssign_none; + +void* (*__CFObjCMemmoveCollectable)(void *dst, const void *, size_t) = memmove; + +// GC: to be moved to objc if necessary. +static void objc_WriteBarrierRange_none(void *ptr, size_t size) {} +static void objc_WriteBarrierRange_auto(void *ptr, size_t size) { auto_zone_write_barrier_range(__CFCollectableZone, ptr, size); } +void (*__CFObjCWriteBarrierRange)(void *, size_t) = objc_WriteBarrierRange_none; + +// Compiler uses this symbol name; must match compiler built-in decl +#if __LP64__ +int __CFConstantStringClassReference[24] = {0}; +#else +int __CFConstantStringClassReference[12] = {0}; +#endif + +// #warning the whole business of reallocating the ClassTables is not thread-safe, because access to those values is not protected + +CFTypeID _CFRuntimeRegisterClass(const CFRuntimeClass * const cls) { +// version field must be 0 +// className must be pure ASCII string, non-null + if (__CFMaxRuntimeTypes <= __CFRuntimeClassTableCount) { + CFLog(kCFLogLevelWarning, CFSTR("*** CoreFoundation class table full; registration failing for class '%s'. Program will crash soon."), cls->className); + 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; + __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. + } + __CFRuntimeClassTable[__CFRuntimeClassTableCount++] = (CFRuntimeClass *)cls; + return __CFRuntimeClassTableCount - 1; +} + +void _CFRuntimeBridgeClasses(CFTypeID cf_typeID, const char *objc_classname) { + return; +} + +const CFRuntimeClass * _CFRuntimeGetClassWithTypeID(CFTypeID typeID) { + return __CFRuntimeClassTable[typeID]; +} + +void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID) { + __CFRuntimeClassTable[typeID] = NULL; +} + + +#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; +static uint8_t __CFZombieEnabled = 0; +static uint8_t __CFDeallocateZombies = 0; +static void *_original_objc_dealloc = 0; + +#endif /* DEBUG */ + +// XXX_PCB: use the class version field as a bitmask, to allow classes to opt-in for GC scanning. + +#define CF_GET_COLLECTABLE_MEMORY_TYPE(x) (0) + +CFTypeRef _CFRuntimeCreateInstance(CFAllocatorRef allocator, CFTypeID typeID, CFIndex extraBytes, unsigned char *category) { + CFRuntimeBase *memory; + Boolean usesSystemDefaultAllocator; + CFIndex size; + + CFAssert1(typeID != _kCFRuntimeNotATypeID, __kCFLogAssertion, "%s(): Uninitialized type id", __PRETTY_FUNCTION__); + + if (NULL == __CFRuntimeClassTable[typeID]) { + return NULL; + } + allocator = (NULL == allocator) ? __CFGetDefaultAllocator() : allocator; + usesSystemDefaultAllocator = (allocator == kCFAllocatorSystemDefault); + 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 + memory = (CFRuntimeBase *)CFAllocatorAllocate(allocator, size, CF_GET_COLLECTABLE_MEMORY_TYPE(__CFRuntimeClassTable[typeID])); + if (NULL == memory) { + return NULL; + } + memset(memory, 0, malloc_size(memory)); + if (__CFOASafe && category) { + __CFSetLastAllocationEventName(memory, (char *)category); + } else if (__CFOASafe) { + __CFSetLastAllocationEventName(memory, (char *)__CFRuntimeClassTable[typeID]->className); + } + 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); + memory = (CFRuntimeBase *)((char *)memory + sizeof(CFAllocatorRef)); + } + memory->_cfisa = __CFISAForTypeID(typeID); +#if __LP64__ + *(uint32_t *)(memory->_cfinfo) = (uint32_t)((0 << 24) + ((typeID & 0xFFFF) << 8) + (usesSystemDefaultAllocator ? 0x80 : 0x00)); + memory->_rc = 1; +#else + *(uint32_t *)(memory->_cfinfo) = (uint32_t)((1 << 24) + ((typeID & 0xFFFF) << 8) + (usesSystemDefaultAllocator ? 0x80 : 0x00)); +#endif + if (NULL != __CFRuntimeClassTable[typeID]->init) { + (__CFRuntimeClassTable[typeID]->init)(memory); + } + return memory; +} + +void _CFRuntimeInitStaticInstance(void *ptr, CFTypeID typeID) { + CFRuntimeBase *memory = (CFRuntimeBase *)ptr; + CFAssert1(typeID != _kCFRuntimeNotATypeID, __kCFLogAssertion, "%s(): Uninitialized type id", __PRETTY_FUNCTION__); + if (NULL == __CFRuntimeClassTable[typeID]) { + return; + } + memory->_cfisa = __CFISAForTypeID(typeID); + *(uint32_t *)(memory->_cfinfo) = (uint32_t)((0 << 24) + ((typeID & 0xFFFF) << 8) + 0x80); +#if __LP64__ + memory->_rc = 0; +#endif + if (NULL != __CFRuntimeClassTable[typeID]->init) { + (__CFRuntimeClassTable[typeID]->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 (objc_getClass((id)cls) == nil) return false; + const char *cname = class_getName(cls); + if (cname && 0 == strncmp(cname, "_NSZombie_", 10)) return true; + return false; +} + +CFTypeID __CFGenericTypeID(const void *cf) { + return (*(uint32_t *)(((CFRuntimeBase *)cf)->_cfinfo) >> 8) & 0xFFFF; +} + +CF_INLINE CFTypeID __CFGenericTypeID_inline(const void *cf) { + return (*(uint32_t *)(((CFRuntimeBase *)cf)->_cfinfo) >> 8) & 0xFFFF; +} + +CFTypeID CFTypeGetTypeID(void) { + return __kCFTypeTypeID; +} + +__private_extern__ void __CFGenericValidateType_(CFTypeRef cf, CFTypeID type, const char *func) { + if (cf && CF_IS_OBJC(type, cf)) return; + 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", func, cf); \ + CFAssert3(__CFGenericTypeID_inline(cf) == type, __kCFLogAssertion, "%s(): pointer %p is not a %s", func, cf, __CFRuntimeClassTable[type]->className); \ +} + +#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); + +#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) + +CFTypeID CFGetTypeID(CFTypeRef cf) { +#if defined(DEBUG) + if (NULL == cf) HALT; +#endif + CFTYPE_OBJC_FUNCDISPATCH0(CFTypeID, cf, "_cfTypeID"); + __CFGenericAssertIsCF(cf); + return __CFGenericTypeID_inline(cf); +} + +CFStringRef CFCopyTypeIDDescription(CFTypeID type) { + CFAssert2((NULL != __CFRuntimeClassTable[type]) && __kCFNotATypeTypeID != type && __kCFTypeTypeID != type, __kCFLogAssertion, "%s(): type %d is not a CF type ID", __PRETTY_FUNCTION__, type); + return CFStringCreateWithCString(kCFAllocatorSystemDefault, __CFRuntimeClassTable[type]->className, kCFStringEncodingASCII); +} + +#define DISGUISE(object) ((void *)(((uintptr_t)object) + 1)) +#define UNDISGUISE(disguised) ((id)(((uintptr_t)disguised) - 1)) + +// 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); +CF_EXPORT CFHashCode _CFHash(CFTypeRef cf); + +CFTypeRef CFRetain(CFTypeRef cf) { + if (CF_IS_COLLECTABLE(cf)) { + // always honor CFRetain's with a GC-visible retain. + auto_zone_retain(__CFCollectableZone, (void*)cf); + return cf; + } + CFTYPE_OBJC_FUNCDISPATCH0(CFTypeRef, cf, "retain"); + if (cf) __CFGenericAssertIsCF(cf); + return _CFRetain(cf); +} + +__private_extern__ void __CFAllocatorDeallocate(CFTypeRef cf); + +void CFRelease(CFTypeRef cf) { +#if !defined(__WIN32__) + if (CF_IS_COLLECTABLE(cf)) { + // release the GC-visible reference. + if (auto_zone_release(__CFCollectableZone, (void*)cf) == 0 && !CFTYPE_IS_OBJC(cf)) { + CFRuntimeClass *cfClass = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]; + if (cfClass->version & _kCFRuntimeResourcefulObject) { + if (cfClass->reclaim) cfClass->reclaim(cf); + } + } + return; + } +#endif + CFTYPE_OBJC_FUNCDISPATCH0(void, cf, "release"); + if (cf) __CFGenericAssertIsCF(cf); + _CFRelease(cf); +} + + +__private_extern__ const void *__CFStringCollectionCopy(CFAllocatorRef allocator, const void *ptr) { + CFStringRef theString = (CFStringRef)ptr; + CFStringRef result = CFStringCreateCopy(allocator, theString); + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + result = (CFStringRef)CFMakeCollectable(result); + } + return (const void *)result; +} + +extern void CFCollection_non_gc_storage_error(void); + +__private_extern__ const void *__CFTypeCollectionRetain(CFAllocatorRef allocator, const void *ptr) { + CFTypeRef cf = (CFTypeRef)ptr; + // 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(__CFCollectableZone, 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 an extra heap membership test. + auto_zone_retain(__CFCollectableZone, (void*)cf); + } + else + ; // don't retain normal CF objects + return cf; + } else { + // support constant CFTypeRef objects. +#if __LP64__ + uint32_t lowBits = ((CFRuntimeBase *)cf)->_rc; +#else + uint32_t lowBits = ((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS]; +#endif + if (lowBits == 0) return cf; + // complain about non-GC objects in GC containers. + CFLog(kCFLogLevelWarning, CFSTR("storing a non-GC object %p in a GC collection, break on CFCollection_non_gc_storage_error to debug."), cf); + CFCollection_non_gc_storage_error(); + // XXX should halt, except Patrick is using this somewhere. + // HALT; + } + } + return CFRetain(cf); +} + + +__private_extern__ void __CFTypeCollectionRelease(CFAllocatorRef allocator, const void *ptr) { + CFTypeRef cf = (CFTypeRef)ptr; + // 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(__CFCollectableZone, cf)) { +#if !defined(__WIN32__) + // 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 an extra heap membership test. + CFRuntimeClass *cfClass = __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]; + if (cfClass->version & _kCFRuntimeResourcefulObject && auto_zone_release(__CFCollectableZone, (void*)cf) == 0) { + // ResourceFull objects trigger 'reclaim' on transition to zero + if (cfClass->reclaim) cfClass->reclaim(cf); + } + else // avoid releasing normal CF objects. Like other collections, for example + ; + return; +#endif + } else { + // support constant CFTypeRef objects. +#if __LP64__ + uint32_t lowBits = ((CFRuntimeBase *)cf)->_rc; +#else + uint32_t lowBits = ((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS]; +#endif + if (lowBits == 0) return; + } + } + CFRelease(cf); +} + +#if !__LP64__ +static CFSpinLock_t __CFRuntimeExternRefCountTableLock = CFSpinLockInit; +static CFMutableBagRef __CFRuntimeExternRefCountTable = NULL; +#endif + +static uint64_t __CFGetFullRetainCount(CFTypeRef cf) { +#if __LP64__ + uint32_t lowBits = ((CFRuntimeBase *)cf)->_rc; + if (0 == lowBits) { + return (uint64_t)0x0fffffffffffffffULL; + } + return lowBits; +#else + uint32_t lowBits = ((CFRuntimeBase *)cf)->_cfinfo[CF_RC_BITS]; + if (0 == lowBits) { + return (uint64_t)0x0fffffffffffffffULL; + } + uint64_t highBits = 0; + if ((lowBits & 0x80) != 0) { + __CFSpinLock(&__CFRuntimeExternRefCountTableLock); + highBits = (uint64_t)CFBagGetCountOfValue(__CFRuntimeExternRefCountTable, DISGUISE(cf)); + __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock); + } + uint64_t compositeRC = (lowBits & 0x7f) + (highBits << 6); + return compositeRC; +#endif +} + +CFTypeRef _CFRetainGC(CFTypeRef cf) { +#if defined(DEBUG) + if (CF_USING_COLLECTABLE_MEMORY && !CF_IS_COLLECTABLE(cf)) { + fprintf(stderr, "non-auto object %p passed to _CFRetainGC.\n", cf); + HALT; + } +#endif + return CF_USING_COLLECTABLE_MEMORY ? cf : CFRetain(cf); +} + +void _CFReleaseGC(CFTypeRef cf) { +#if defined(DEBUG) + if (CF_USING_COLLECTABLE_MEMORY && !CF_IS_COLLECTABLE(cf)) { + fprintf(stderr, "non-auto object %p passed to _CFReleaseGC.\n", cf); + HALT; + } +#endif + if (!CF_USING_COLLECTABLE_MEMORY) CFRelease(cf); +} + +CFIndex CFGetRetainCount(CFTypeRef cf) { + if (NULL == cf) return 0; + if (CF_IS_COLLECTABLE(cf)) { + return auto_zone_retain_count(__CFCollectableZone, cf); + } + CFTYPE_OBJC_FUNCDISPATCH0(CFIndex, cf, "retainCount"); + __CFGenericAssertIsCF(cf); + uint64_t rc = __CFGetFullRetainCount(cf); + return (rc < (uint64_t)LONG_MAX) ? (CFIndex)rc : (CFIndex)LONG_MAX; +} + +CFTypeRef CFMakeCollectable(CFTypeRef cf) { + if (NULL == cf) return NULL; + if (CF_IS_COLLECTABLE(cf)) { +#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 (auto_zone_retain_count(__CFCollectableZone, cf) == 0) { + CFLog(kCFLogLevelWarning, CFSTR("object %p with 0 retain-count passed to CFMakeCollectable."), cf); + return cf; + } + auto_zone_release(__CFCollectableZone, (void *)cf); + } + return cf; +} + +Boolean CFEqual(CFTypeRef cf1, CFTypeRef cf2) { +#if defined(DEBUG) + if (NULL == cf1) HALT; + if (NULL == cf2) HALT; +#endif + if (cf1 == cf2) return true; + 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; + if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal) { + return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal(cf1, cf2); + } + return false; +} + +CFHashCode CFHash(CFTypeRef cf) { + CFTYPE_OBJC_FUNCDISPATCH0(CFHashCode, cf, "hash"); + __CFGenericAssertIsCF(cf); + return _CFHash(cf); +} + +// definition: produces a normally non-NULL debugging description of the object +CFStringRef CFCopyDescription(CFTypeRef cf) { +#if defined(DEBUG) + if (NULL == cf) HALT; +#endif + __CFGenericAssertIsCF(cf); + if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyDebugDesc) { + CFStringRef result; + 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)); +} + +// Definition: if type produces a formatting description, return that string, otherwise NULL +__private_extern__ CFStringRef __CFCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { +#if defined(DEBUG) + if (NULL == cf) HALT; +#endif + __CFGenericAssertIsCF(cf); + if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyFormattingDesc) { + return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->copyFormattingDesc(cf, formatOptions); + } + return NULL; +} + +extern CFAllocatorRef __CFAllocatorGetAllocator(CFTypeRef); + +CFAllocatorRef CFGetAllocator(CFTypeRef cf) { + if (NULL == cf) return kCFAllocatorSystemDefault; + 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); +extern void __CFArrayInitialize(void); +extern void __CFBagInitialize(void); +extern void __CFBooleanInitialize(void); +extern void __CFCharacterSetInitialize(void); +extern void __CFDataInitialize(void); +extern void __CFDateInitialize(void); +extern void __CFDictionaryInitialize(void); +extern void __CFNumberInitialize(void); +extern void __CFSetInitialize(void); +extern void __CFStorageInitialize(void); +extern void __CFErrorInitialize(void); +extern void __CFTimeZoneInitialize(void); +extern void __CFTreeInitialize(void); +extern void __CFURLInitialize(void); +#if DEPLOYMENT_TARGET_MACOSX +extern void __CFMachPortInitialize(void); +#endif +#if DEPLOYMENT_TARGET_MACOSX +extern void __CFMessagePortInitialize(void); +#endif +#if DEPLOYMENT_TARGET_MACOSX || defined(__WIN32__) +extern void __CFRunLoopInitialize(void); +extern void __CFRunLoopObserverInitialize(void); +extern void __CFRunLoopSourceInitialize(void); +extern void __CFRunLoopTimerInitialize(void); +extern void __CFSocketInitialize(void); +#endif +extern void __CFBundleInitialize(void); +extern void __CFPlugInInitialize(void); +extern void __CFPlugInInstanceInitialize(void); +extern void __CFUUIDInitialize(void); +extern void __CFBinaryHeapInitialize(void); +extern void __CFBitVectorInitialize(void); +extern void __CFStreamInitialize(void); + +static void __exceptionInit(void) {} +static void __collatorInit(void) {} +static void __forwarding_prep_0___(void) {} +static void __forwarding_prep_1___(void) {} +static void __NSFastEnumerationMutationHandler(id obj) {} +const void *__CFArgStuff = NULL; +__private_extern__ void *__CFAppleLanguages = NULL; + +bool kCFUseCollectableAllocator = false; + + +#if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD +static void __CFInitialize(void) __attribute__ ((constructor)); +static +#endif +void __CFInitialize(void) { + static int __done = 0; + + if (!__done) { + __done = 1; + +#if defined(DEBUG) || defined(ENABLE_ZOMBIES) + const char *value = getenv("NSZombieEnabled"); + if (value && (*value == 'Y' || *value == 'y')) __CFZombieEnabled = 0xff; + value = getenv("NSDeallocateZombies"); + if (value && (*value == 'Y' || *value == 'y')) __CFDeallocateZombies = 0xff; + + value = getenv("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 *)); + __CFBaseInitialize(); + + /* Here so that two runtime classes get indices 0, 1. */ + __kCFNotATypeTypeID = _CFRuntimeRegisterClass(&__CFNotATypeClass); + __kCFTypeTypeID = _CFRuntimeRegisterClass(&__CFTypeClass); + + /* Here so that __kCFAllocatorTypeID gets index 2. */ + __CFAllocatorInitialize(); + +#if DEPLOYMENT_TARGET_MACOSX + { + CFIndex idx, cnt; + char **args = *_NSGetArgv(); + cnt = *_NSGetArgc(); + for (idx = 1; idx < cnt - 1; idx++) { + if (NULL == args[idx]) continue; + if (0 == strcmp(args[idx], "-AppleLanguages") && args[idx + 1]) { + CFIndex length = strlen(args[idx + 1]); + __CFAppleLanguages = malloc(length + 1); + memmove(__CFAppleLanguages, args[idx + 1], length + 1); + break; + } + } + } +#endif + + + /* CFBag needs to be up before CFString. */ + __CFBagInitialize(); + +#if !__LP64__ + // Creating this lazily in CFRetain causes recursive call to CFRetain + __CFRuntimeExternRefCountTable = CFBagCreateMutable(kCFAllocatorSystemDefault, 0, NULL); +#endif + + /*** _CFRuntimeCreateInstance() can finally be called generally after this line. ***/ + + __CFRuntimeClassTableCount = 7; + __CFStringInitialize(); // CFString's TypeID must be 0x7, now and forever + __CFRuntimeClassTableCount = 16; + __CFDictionaryInitialize(); + __CFArrayInitialize(); + __CFDataInitialize(); + __CFSetInitialize(); + __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 + + + __CFDateInitialize(); // just initializes the time goo +// _CFRuntimeBridgeClasses(CFDateGetTypeID(), objc_lookUpClass("NSCFDate") ? "NSCFDate" : "__NSCFDate"); + __CFTimeZoneInitialize(); +// _CFRuntimeBridgeClasses(CFTimeZoneGetTypeID(), "NSCFTimeZone"); + __CFBinaryHeapInitialize(); + __CFBitVectorInitialize(); + __CFCharacterSetInitialize(); + __CFStorageInitialize(); + __CFErrorInitialize(); + __CFTreeInitialize(); + __CFURLInitialize(); + __CFBundleInitialize(); +#if DEPLOYMENT_TARGET_MACOSX + __CFPlugInInitialize(); + __CFPlugInInstanceInitialize(); +#endif //__MACH__ + __CFUUIDInitialize(); +#if DEPLOYMENT_TARGET_MACOSX + __CFMessagePortInitialize(); +#endif +#if DEPLOYMENT_TARGET_MACOSX + __CFMachPortInitialize(); +#endif + __CFStreamInitialize(); + __CFPreferencesDomainInitialize(); +#if DEPLOYMENT_TARGET_MACOSX || defined(__WIN32__) + __CFRunLoopInitialize(); + __CFRunLoopObserverInitialize(); + __CFRunLoopSourceInitialize(); + __CFRunLoopTimerInitialize(); + __CFSocketInitialize(); +#endif + + +#if DEPLOYMENT_TARGET_MACOSX + { + CFIndex idx, cnt; + char **args; + args = *_NSGetArgv(); + cnt = *_NSGetArgc(); + CFIndex count; + CFStringRef *list, buffer[256]; + list = (cnt <= 256) ? buffer : malloc(cnt * sizeof(CFStringRef)); + for (idx = 0, count = 0; idx < cnt; idx++) { + if (NULL == args[idx]) continue; + list[count] = CFStringCreateWithCString(kCFAllocatorSystemDefault, args[idx], kCFStringEncodingUTF8); + if (NULL == list[count]) { + list[count] = CFStringCreateWithCString(kCFAllocatorSystemDefault, args[idx], kCFStringEncodingISOLatin1); + // We CANNOT use the string SystemEncoding here; + // Do not argue: it is not initialized yet, but these + // arguments MUST be initialized before it is. + // We should just ignore the argument if the UTF-8 + // conversion fails, but out of charity we try once + // more with ISO Latin1, a standard unix encoding. + } + if (NULL != list[count]) count++; + } + __CFArgStuff = CFArrayCreate(kCFAllocatorSystemDefault, (const void **)list, count, &kCFTypeArrayCallBacks); + } +#endif + _CFProcessPath(); // cache this early + + if (__CFRuntimeClassTableCount < 256) __CFRuntimeClassTableCount = 256; + +#if defined(DEBUG) && !defined(__WIN32__) + CFLog(kCFLogLevelWarning, CFSTR("Assertions enabled")); +#endif + } +} + +//#if defined(__WIN32__) + +#ifdef _BUILD_NET_FOUNDATION_ +#ifdef __cplusplus +extern "C"{ +#endif //C++ +extern void _CFFTPCleanup(void); +extern void _CFHTTPMessageCleanup(void); +extern void _CFHTTPStreamCleanup(void); +#ifdef __cplusplus +} +#endif //C++ + +#endif //_BUILD_NET_FOUNDATION_ + +#if 0 + +/* We have to call __CFInitialize when library is attached to the process. + * (Sergey Zubarev) + */ +#if defined(_BUILD_NET_FOUNDATION_) +extern "C" { +BOOL WINAPI CoreFoundationDllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID pReserved ); +} + +BOOL WINAPI CoreFoundationDllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID pReserved ) { +#else +BOOL WINAPI DllMain( HINSTANCE hInstance, DWORD dwReason, LPVOID pReserved ) { +#endif + static CFBundleRef cfBundle = NULL; + if (dwReason == DLL_PROCESS_ATTACH) { + __CFInitialize(); + cfBundle = RegisterCoreFoundationBundle(); + } else if (dwReason == DLL_PROCESS_DETACH) { + if (cfBundle) CFRelease(cfBundle); +#if !0 + __CFStringCleanup(); + __CFSocketCleanup(); +#endif + __CFUniCharCleanup(); + __CFStreamCleanup(); + __CFBaseCleanup(); + } else if (dwReason == DLL_THREAD_DETACH) { + __CFFinalizeThreadData(NULL); + } + return TRUE; +} + +#endif + +// Functions that avoid ObC dispatch and CF type validation, for use by NSNotifyingCFArray, etc. +// Hopefully all of this will just go away. 3321464. M.P. To Do - 7/9/03 + +Boolean _CFEqual(CFTypeRef cf1, CFTypeRef cf2) { + if (cf1 == cf2) return true; + if (NULL == cf1) return false; + if (NULL == cf2) return false; + __CFGenericAssertIsCF(cf1); + __CFGenericAssertIsCF(cf2); + if (__CFGenericTypeID_inline(cf1) != __CFGenericTypeID_inline(cf2)) return false; + if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal) { + return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf1)]->equal(cf1, cf2); + } + return false; +} + +CFIndex _CFGetRetainCount(CFTypeRef cf) { + if (NULL == cf) return 0; + if (CF_IS_COLLECTABLE(cf)) { + return auto_zone_retain_count(__CFCollectableZone, cf); + } + uint64_t rc = __CFGetFullRetainCount(cf); + return (rc < (uint64_t)LONG_MAX) ? (CFIndex)rc : (CFIndex)LONG_MAX; +} + +CFHashCode _CFHash(CFTypeRef cf) { + if (NULL == cf) return 0; + if (NULL != __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->hash) { + return __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->hash(cf); + } + return (CFHashCode)cf; +} + +#if 0 || 0 +static inline bool myOSAtomicCompareAndSwap32Barrier(int32_t oldValue, int32_t newValue, volatile int32_t *theValue) { + int32_t actualOldValue = InterlockedCompareExchange((volatile LONG *)theValue, newValue, oldValue); + return actualOldValue == oldValue ? true : false; +} +#else +static bool (*myOSAtomicCompareAndSwap32Barrier)(int32_t __oldValue, int32_t __newValue, volatile int32_t *__theValue) = OSAtomicCompareAndSwap32Barrier; +#endif + +CF_EXPORT CFTypeRef _CFRetain(CFTypeRef cf) { + if (NULL == cf) return NULL; +#if __LP64__ + uint32_t lowBits; + do { + lowBits = ((CFRuntimeBase *)cf)->_rc; + if (0 == lowBits) return cf; // Constant CFTypeRef + } while (!myOSAtomicCompareAndSwap32Barrier(lowBits, lowBits + 1, (int32_t *)&((CFRuntimeBase *)cf)->_rc)); +#else +#define RC_START 24 +#define RC_END 31 + volatile UInt32 *infoLocation = (UInt32 *)&(((CFRuntimeBase *)cf)->_cfinfo); + CFIndex rcLowBits = __CFBitfieldGetValue(*infoLocation, RC_END, RC_START); + if (__builtin_expect(0 == rcLowBits, 0)) 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. + prospectiveNewInfo += (1 << RC_START); + rcLowBits = __CFBitfieldGetValue(prospectiveNewInfo, RC_END, RC_START); + if (__builtin_expect((rcLowBits & 0x7f) == 0, 0)) { + /* Roll over another bit to the external ref count + Real ref count = low 7 bits of info[CF_RC_BITS] + external ref count << 6 + Bit 8 of low bits indicates that external ref count is in use. + External ref count is shifted by 6 rather than 7 so that we can set the low + bits to to 1100 0000 rather than 1000 0000. + 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; + __CFBitfieldSetValue(prospectiveNewInfo, RC_END, RC_START, ((1 << 7) | (1 << 6))); + __CFSpinLock(&__CFRuntimeExternRefCountTableLock); + success = myOSAtomicCompareAndSwap32Barrier(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); + if (__builtin_expect(success, 1)) { + CFBagAddValue(__CFRuntimeExternRefCountTable, DISGUISE(cf)); + } + __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock); + } else { + success = myOSAtomicCompareAndSwap32Barrier(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); + } + } while (__builtin_expect(!success, 0)); +#endif + if (__builtin_expect(__CFOASafe, 0)) { + __CFRecordAllocationEvent(__kCFRetainEvent, (void *)cf, 0, _CFGetRetainCount(cf), NULL); + } + return cf; +} + +CF_EXPORT void _CFRelease(CFTypeRef cf) { + Boolean isAllocator = false; +#if __LP64__ + uint32_t lowBits; + do { + lowBits = ((CFRuntimeBase *)cf)->_rc; + if (0 == lowBits) return; // Constant CFTypeRef + if (1 == lowBits) { + // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION + CFTypeID typeID = __CFGenericTypeID_inline(cf); + isAllocator = (__kCFAllocatorTypeID_CONST == typeID); + CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; + if (cfClass->version & _kCFRuntimeResourcefulObject && cfClass->reclaim != NULL) { + cfClass->reclaim(cf); + } + void (*func)(CFTypeRef) = __CFRuntimeClassTable[typeID]->finalize; + 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 || myOSAtomicCompareAndSwap32Barrier(1, 0, (int32_t *)&((CFRuntimeBase *)cf)->_rc)) { + goto really_free; + } + } + } while (!myOSAtomicCompareAndSwap32Barrier(lowBits, lowBits - 1, (int32_t *)&((CFRuntimeBase *)cf)->_rc)); +#else + volatile UInt32 *infoLocation = (UInt32 *)&(((CFRuntimeBase *)cf)->_cfinfo); + CFIndex rcLowBits = __CFBitfieldGetValue(*infoLocation, RC_END, RC_START); + if (__builtin_expect(0 == rcLowBits, 0)) return; // Constant CFTypeRef + bool success = 0; + do { + UInt32 initialCheckInfo = *infoLocation; + rcLowBits = __CFBitfieldGetValue(initialCheckInfo, RC_END, RC_START); + if (__builtin_expect(1 == rcLowBits, 0)) { + // we think cf should be deallocated + if (__builtin_expect(__kCFAllocatorTypeID_CONST == __CFGenericTypeID_inline(cf), 0)) { + if (__builtin_expect(__CFOASafe, 0)) __CFRecordAllocationEvent(__kCFReleaseEvent, (void *)cf, 0, 0, NULL); + __CFAllocatorDeallocate((void *)cf); + success = 1; + } else { + // CANNOT WRITE ANY NEW VALUE INTO [CF_RC_BITS] UNTIL AFTER FINALIZATION + CFTypeID typeID = __CFGenericTypeID_inline(cf); + CFRuntimeClass *cfClass = __CFRuntimeClassTable[typeID]; + if (cfClass->version & _kCFRuntimeResourcefulObject && cfClass->reclaim != NULL) { + cfClass->reclaim(cf); + } + if (NULL != __CFRuntimeClassTable[typeID]->finalize) { + __CFRuntimeClassTable[__CFGenericTypeID_inline(cf)]->finalize(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 + // 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. + rcLowBits = __CFBitfieldGetValue(*infoLocation, RC_END, RC_START); + success = (1 == rcLowBits); + if (__builtin_expect(success, 1)) { + goto really_free; + } + } + } 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. + if (__builtin_expect((1 << 7) == rcLowBits, 0)) { + // Time to remove a bit from the external ref count + __CFSpinLock(&__CFRuntimeExternRefCountTableLock); + CFIndex rcHighBitsCnt = CFBagGetCountOfValue(__CFRuntimeExternRefCountTable, DISGUISE(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 = myOSAtomicCompareAndSwap32Barrier(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); + if (__builtin_expect(success, 1)) { + CFBagRemoveValue(__CFRuntimeExternRefCountTable, DISGUISE(cf)); + } + __CFSpinUnlock(&__CFRuntimeExternRefCountTableLock); + } else { + prospectiveNewInfo -= (1 << RC_START); + success = myOSAtomicCompareAndSwap32Barrier(*(int32_t *)&initialCheckInfo, *(int32_t *)&prospectiveNewInfo, (int32_t *)infoLocation); + } + } + } while (__builtin_expect(!success, 0)); + +#endif + if (__builtin_expect(__CFOASafe, 0)) { + __CFRecordAllocationEvent(__kCFReleaseEvent, (void *)cf, 0, _CFGetRetainCount(cf), NULL); + } + return; + + really_free:; + if (__builtin_expect(__CFOASafe, 0)) { + // do not use _CFGetRetainCount() because cf has been freed if it was an allocator + __CFRecordAllocationEvent(__kCFReleaseEvent, (void *)cf, 0, 0, NULL); + } + // cannot zombify allocators, which get deallocated by __CFAllocatorDeallocate (finalize) + if (!isAllocator) { + CFAllocatorRef allocator; + Boolean usesSystemDefaultAllocator; + + if (__CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_cfinfo[CF_INFO_BITS], 7, 7)) { + allocator = kCFAllocatorSystemDefault; + } else { + allocator = CFGetAllocator(cf); + } + usesSystemDefaultAllocator = (allocator == kCFAllocatorSystemDefault); + + if (__CFZombieLevel & (1 << 0)) { + 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 (!(__CFZombieLevel & (1 << 4))) { + CFAllocatorDeallocate(allocator, (uint8_t *)cf - (usesSystemDefaultAllocator ? 0 : sizeof(CFAllocatorRef))); + } + + if (kCFAllocatorSystemDefault != allocator) { + CFRelease(allocator); + } + } +} + +#undef __kCFAllocatorTypeID_CONST +#undef __CFGenericAssertIsCF + diff --git a/Base.subproj/CFRuntime.h b/CFRuntime.h similarity index 90% rename from Base.subproj/CFRuntime.h rename to CFRuntime.h index c763910..6c81c5c 100644 --- a/Base.subproj/CFRuntime.h +++ b/CFRuntime.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFRuntime.h - Copyright (c) 1999-2005, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFRUNTIME__) @@ -29,18 +29,17 @@ #include #include +#include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN // GC: until we link against ObjC must use indirect functions. Overridden in CFSetupFoundationBridging extern bool kCFUseCollectableAllocator; extern bool (*__CFObjCIsCollectable)(void *); extern const void* (*__CFObjCAssignIvar)(const void *value, const void *base, const void **slot); extern const void* (*__CFObjCStrongAssign)(const void *value, const void **slot); -extern void* (*__CFObjCMemmoveCollectable)(void *dest, const void *src, unsigned); -extern void (*__CFObjCWriteBarrierRange)(void *, unsigned); +extern void* (*__CFObjCMemmoveCollectable)(void *dest, const void *src, size_t); +extern void (*__CFObjCWriteBarrierRange)(void *, size_t); // GC: primitives. // is GC on? @@ -84,8 +83,10 @@ CF_EXPORT void *_CFAllocatorReallocateGC(CFAllocatorRef allocator, void *ptr, CF CF_EXPORT void _CFAllocatorDeallocateGC(CFAllocatorRef allocator, void *ptr); enum { - _kCFRuntimeNotATypeID = 0, - _kCFRuntimeScannedObject = (1 << 0) + _kCFRuntimeNotATypeID = 0, + _kCFRuntimeScannedObject = (1 << 0), + /* _kCFRuntimeUncollectableObject = (1 << 1), No longer used; obsolete. */ + _kCFRuntimeResourcefulObject = (1 << 2) }; typedef struct __CFRuntimeClass { // Version 0 struct @@ -102,8 +103,14 @@ typedef struct __CFRuntimeClass { // Version 0 struct 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 +#define CF_RECLAIM_AVAILABLE 1 + void (*reclaim)(CFTypeRef cf); +#endif } CFRuntimeClass; +#define RADAR_5115468_FIXED 1 + /* Note that CF runtime class registration and unregistration is not currently * thread-safe, which should not currently be a problem, as long as unregistration * is done only when valid to do so. @@ -204,27 +211,20 @@ CF_EXPORT void _CFRuntimeUnregisterClassWithTypeID(CFTypeID typeID); * release to release. */ typedef struct __CFRuntimeBase { - void *_isa; -#if defined(__ppc__) || defined(__ppc64__) - uint16_t _rc; - uint16_t _info; -#elif defined(__i386__) - uint16_t _info; - uint16_t _rc; -#else -#error unknown architecture + uintptr_t _cfisa; + uint8_t _cfinfo[4]; +#if __LP64__ + uint32_t _rc; #endif } CFRuntimeBase; -#if defined(__ppc__) || defined(__ppc64__) -#define INIT_CFRUNTIME_BASE(isa, info, rc) { isa, info, rc } -#elif defined(__i386__) -#define INIT_CFRUNTIME_BASE(isa, info, rc) { isa, rc, info } +#if __BIG_ENDIAN__ +#define INIT_CFRUNTIME_BASE(...) {0, {0, 0, 0, 0x80}} #else -#error unknown architecture +#define INIT_CFRUNTIME_BASE(...) {0, {0x80, 0, 0, 0}} #endif -CF_EXPORT CFTypeRef _CFRuntimeCreateInstance(CFAllocatorRef allocator, CFTypeID typeID, uint32_t extraBytes, unsigned char *category); +CF_EXPORT CFTypeRef _CFRuntimeCreateInstance(CFAllocatorRef allocator, CFTypeID typeID, CFIndex extraBytes, unsigned char *category); /* Creates a new CF instance of the class specified by the * given CFTypeID, using the given allocator, and returns it. * If the allocator returns NULL, this function returns NULL. @@ -250,6 +250,19 @@ CF_EXPORT void _CFRuntimeSetInstanceTypeID(CFTypeRef cf, CFTypeID typeID); * as faulting. */ +CF_EXPORT void _CFRuntimeInitStaticInstance(void *memory, CFTypeID typeID); + /* This function initializes a memory block to be a constant + * (unreleaseable) CF object of the given typeID. + * If the specified CFTypeID is unknown to the CF runtime, + * this function does nothing. The memory block should + * be a chunk of in-binary writeable static memory, and at + * 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. + */ +#define CF_HAS_INIT_STATIC_INSTANCE 1 + #if 0 // ========================= EXAMPLE ========================= @@ -361,8 +374,6 @@ uint32_t EXRangeGetLength(EXRangeRef rangeref) { #endif -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFRUNTIME__ */ diff --git a/CFSet.c b/CFSet.c new file mode 100644 index 0000000..4c0e1f0 --- /dev/null +++ b/CFSet.c @@ -0,0 +1,1467 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFSet.c + Copyright 1998-2006, Apple, Inc. All rights reserved. + Responsibility: Christopher Kane + Machine generated from Notes/HashingCode.template +*/ + + + + +#include +#include "CFInternal.h" +#include + +#define CFDictionary 0 +#define CFSet 0 +#define CFBag 0 +#undef CFSet +#define CFSet 1 + +#if CFDictionary +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}; +static const CFSetKeyCallBacks __kCFNullSetKeyCallBacks = {0, NULL, NULL, NULL, NULL, NULL}; +static const CFSetValueCallBacks __kCFNullSetValueCallBacks = {0, NULL, NULL, NULL, NULL}; + +#define CFHashRef CFDictionaryRef +#define CFMutableHashRef CFMutableDictionaryRef +#define __kCFHashTypeID __kCFDictionaryTypeID +#endif + +#if CFSet +const CFSetCallBacks kCFTypeSetCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; +const CFSetCallBacks kCFCopyStringSetCallBacks = {0, __CFStringCollectionCopy, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; +static const CFSetCallBacks __kCFNullSetCallBacks = {0, NULL, NULL, NULL, NULL, NULL}; + +#define CFSetKeyCallBacks CFSetCallBacks +#define CFSetValueCallBacks CFSetCallBacks +#define kCFTypeSetKeyCallBacks kCFTypeSetCallBacks +#define kCFTypeSetValueCallBacks kCFTypeSetCallBacks +#define __kCFNullSetKeyCallBacks __kCFNullSetCallBacks +#define __kCFNullSetValueCallBacks __kCFNullSetCallBacks + +#define CFHashRef CFSetRef +#define CFMutableHashRef CFMutableSetRef +#define __kCFHashTypeID __kCFSetTypeID +#endif + +#if CFBag +const CFSetCallBacks kCFTypeSetCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; +const CFSetCallBacks kCFCopyStringSetCallBacks = {0, __CFStringCollectionCopy, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; +static const CFSetCallBacks __kCFNullSetCallBacks = {0, NULL, NULL, NULL, NULL, NULL}; + +#define CFSetKeyCallBacks CFSetCallBacks +#define CFSetValueCallBacks CFSetCallBacks +#define kCFTypeSetKeyCallBacks kCFTypeSetCallBacks +#define kCFTypeSetValueCallBacks kCFTypeSetCallBacks +#define __kCFNullSetKeyCallBacks __kCFNullSetCallBacks +#define __kCFNullSetValueCallBacks __kCFNullSetCallBacks + +#define CFHashRef CFBagRef +#define CFMutableHashRef CFMutableBagRef +#define __kCFHashTypeID __kCFBagTypeID +#endif + +#define GETNEWKEY(newKey, oldKey) \ + any_t (*kretain)(CFAllocatorRef, any_t, any_pointer_t) = \ + !hasBeenFinalized(hc) \ + ? (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))__CFSetGetKeyCallBacks(hc)->retain \ + : (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))0; \ + any_t newKey = kretain ? (any_t)INVOKE_CALLBACK3(kretain, allocator, (any_t)key, hc->_context) : (any_t)oldKey + +#define RELEASEKEY(oldKey) \ + void (*krelease)(CFAllocatorRef, any_t, any_pointer_t) = \ + !hasBeenFinalized(hc) \ + ? (void (*)(CFAllocatorRef,any_t,any_pointer_t))__CFSetGetKeyCallBacks(hc)->release \ + : (void (*)(CFAllocatorRef,any_t,any_pointer_t))0; \ + if (krelease) INVOKE_CALLBACK3(krelease, allocator, oldKey, hc->_context) + +#if CFDictionary +#define GETNEWVALUE(newValue) \ + any_t (*vretain)(CFAllocatorRef, any_t, any_pointer_t) = \ + !hasBeenFinalized(hc) \ + ? (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))__CFSetGetValueCallBacks(hc)->retain \ + : (any_t (*)(CFAllocatorRef,any_t,any_pointer_t))0; \ + any_t newValue = vretain ? (any_t)INVOKE_CALLBACK3(vretain, allocator, (any_t)value, hc->_context) : (any_t)value + +#define RELEASEVALUE(oldValue) \ + void (*vrelease)(CFAllocatorRef, any_t, any_pointer_t) = \ + !hasBeenFinalized(hc) \ + ? (void (*)(CFAllocatorRef,any_t,any_pointer_t))__CFSetGetValueCallBacks(hc)->release \ + : (void (*)(CFAllocatorRef,any_t,any_pointer_t))0; \ + if (vrelease) INVOKE_CALLBACK3(vrelease, allocator, oldValue, hc->_context) + +#endif + +static void __CFSetHandleOutOfMemory(CFTypeRef obj, CFIndex numBytes) { + CFStringRef msg = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("Attempt to allocate %ld bytes for NS/CFSet failed"), numBytes); + CFBadErrorCallBack cb = _CFGetOutOfMemoryErrorCallBack(); + if (NULL == cb || !cb(obj, CFSTR("NS/CFSet"), msg)) { + CFLog(kCFLogLevelCritical, CFSTR("%@"), msg); + HALT; + } + CFRelease(msg); +} + + +// Max load is 3/4 number of buckets +CF_INLINE CFIndex __CFHashRoundUpCapacity(CFIndex capacity) { + return 3 * ((CFIndex)1 << (flsl((capacity - 1) / 3))); +} + +// Returns next power of two higher than the capacity +// threshold for the given input capacity. +CF_INLINE CFIndex __CFHashNumBucketsForCapacity(CFIndex capacity) { + return 4 * ((CFIndex)1 << (flsl((capacity - 1) / 3))); +} + +enum { /* Bits 1-0 */ + __kCFHashImmutable = 0, /* unchangable and fixed capacity */ + __kCFHashMutable = 1, /* changeable and variable capacity */ +}; + +enum { /* Bits 5-4 (value), 3-2 (key) */ + __kCFHashHasNullCallBacks = 0, + __kCFHashHasCFTypeCallBacks = 1, + __kCFHashHasCustomCallBacks = 3 /* callbacks are at end of header */ +}; + +// Under GC, we fudge the key/value memory in two ways +// First, if we had null callbacks or null for both retain/release, we use unscanned memory and get +// standard 'dangling' references. +// This means that if people were doing addValue:[xxx new] and never removing, well, that doesn't work +// +// Second, if we notice standard retain/release implementations we use scanned memory, and fudge the +// standard callbacks to generally do nothing if the collection was allocated in GC memory. On special +// CF objects, however, like those used for precious resources like video-card buffers, we do indeed +// do CFRetain on input and CFRelease on output. The tricky case is GC finalization; we need to remember +// that we did the CFReleases so that subsequent collection operations, like removal, don't double CFRelease. +// (In fact we don't really use CFRetain/CFRelease but go directly to the collector) +// + +enum { + __kCFHashFinalized = (1 << 7), + __kCFHashWeakKeys = (1 << 8), + __kCFHashWeakValues = (1 << 9) +}; + +typedef uintptr_t any_t; +typedef const void * const_any_pointer_t; +typedef void * any_pointer_t; + +struct __CFSet { + CFRuntimeBase _base; + CFIndex _count; /* number of values */ + CFIndex _bucketsNum; /* number of buckets */ + CFIndex _bucketsUsed; /* number of used buckets */ + CFIndex _bucketsCap; /* maximum number of used buckets */ + CFIndex _mutations; + CFIndex _deletes; + any_pointer_t _context; /* private */ + CFOptionFlags _xflags; + any_t _marker; + any_t *_keys; /* can be NULL if not allocated yet */ + any_t *_values; /* can be NULL if not allocated yet */ +}; + +/* Bits 1-0 of the _xflags are used for mutability variety */ +/* Bits 3-2 of the _xflags are used for key callback indicator bits */ +/* Bits 5-4 of the _xflags are used for value callback indicator bits */ +/* Bit 6 of the _xflags is special KVO actions bit */ +/* Bits 7,8,9 are GC use */ + +CF_INLINE bool hasBeenFinalized(CFTypeRef collection) { + return __CFBitfieldGetValue(((const struct __CFSet *)collection)->_xflags, 7, 7) != 0; +} + +CF_INLINE void markFinalized(CFTypeRef collection) { + __CFBitfieldSetValue(((struct __CFSet *)collection)->_xflags, 7, 7, 1); +} + + +CF_INLINE CFIndex __CFHashGetType(CFHashRef hc) { + return __CFBitfieldGetValue(hc->_xflags, 1, 0); +} + +CF_INLINE CFIndex __CFSetGetSizeOfType(CFIndex t) { + CFIndex size = sizeof(struct __CFSet); + if (__CFBitfieldGetValue(t, 3, 2) == __kCFHashHasCustomCallBacks) { + size += sizeof(CFSetKeyCallBacks); + } + if (__CFBitfieldGetValue(t, 5, 4) == __kCFHashHasCustomCallBacks) { + size += sizeof(CFSetValueCallBacks); + } + return size; +} + +CF_INLINE const CFSetKeyCallBacks *__CFSetGetKeyCallBacks(CFHashRef hc) { + CFSetKeyCallBacks *result = NULL; + switch (__CFBitfieldGetValue(hc->_xflags, 3, 2)) { + case __kCFHashHasNullCallBacks: + return &__kCFNullSetKeyCallBacks; + case __kCFHashHasCFTypeCallBacks: + return &kCFTypeSetKeyCallBacks; + case __kCFHashHasCustomCallBacks: + break; + } + result = (CFSetKeyCallBacks *)((uint8_t *)hc + sizeof(struct __CFSet)); + return result; +} + +CF_INLINE Boolean __CFSetKeyCallBacksMatchNull(const CFSetKeyCallBacks *c) { + return (NULL == c || + (c->retain == __kCFNullSetKeyCallBacks.retain && + c->release == __kCFNullSetKeyCallBacks.release && + c->copyDescription == __kCFNullSetKeyCallBacks.copyDescription && + c->equal == __kCFNullSetKeyCallBacks.equal && + c->hash == __kCFNullSetKeyCallBacks.hash)); +} + +CF_INLINE Boolean __CFSetKeyCallBacksMatchCFType(const CFSetKeyCallBacks *c) { + return (&kCFTypeSetKeyCallBacks == c || + (c->retain == kCFTypeSetKeyCallBacks.retain && + c->release == kCFTypeSetKeyCallBacks.release && + c->copyDescription == kCFTypeSetKeyCallBacks.copyDescription && + c->equal == kCFTypeSetKeyCallBacks.equal && + c->hash == kCFTypeSetKeyCallBacks.hash)); +} + +CF_INLINE const CFSetValueCallBacks *__CFSetGetValueCallBacks(CFHashRef hc) { + CFSetValueCallBacks *result = NULL; + switch (__CFBitfieldGetValue(hc->_xflags, 5, 4)) { + case __kCFHashHasNullCallBacks: + return &__kCFNullSetValueCallBacks; + case __kCFHashHasCFTypeCallBacks: + return &kCFTypeSetValueCallBacks; + case __kCFHashHasCustomCallBacks: + break; + } + if (__CFBitfieldGetValue(hc->_xflags, 3, 2) == __kCFHashHasCustomCallBacks) { + result = (CFSetValueCallBacks *)((uint8_t *)hc + sizeof(struct __CFSet) + sizeof(CFSetKeyCallBacks)); + } else { + result = (CFSetValueCallBacks *)((uint8_t *)hc + sizeof(struct __CFSet)); + } + return result; +} + +CF_INLINE Boolean __CFSetValueCallBacksMatchNull(const CFSetValueCallBacks *c) { + return (NULL == c || + (c->retain == __kCFNullSetValueCallBacks.retain && + c->release == __kCFNullSetValueCallBacks.release && + c->copyDescription == __kCFNullSetValueCallBacks.copyDescription && + c->equal == __kCFNullSetValueCallBacks.equal)); +} + +CF_INLINE Boolean __CFSetValueCallBacksMatchCFType(const CFSetValueCallBacks *c) { + return (&kCFTypeSetValueCallBacks == c || + (c->retain == kCFTypeSetValueCallBacks.retain && + c->release == kCFTypeSetValueCallBacks.release && + c->copyDescription == kCFTypeSetValueCallBacks.copyDescription && + c->equal == kCFTypeSetValueCallBacks.equal)); +} + +CFIndex _CFSetGetKVOBit(CFHashRef hc) { + return __CFBitfieldGetValue(hc->_xflags, 6, 6); +} + +void _CFSetSetKVOBit(CFHashRef hc, CFIndex bit) { + __CFBitfieldSetValue(((CFMutableHashRef)hc)->_xflags, 6, 6, ((uintptr_t)bit & 0x1)); +} + +CF_INLINE Boolean __CFSetShouldShrink(CFHashRef hc) { + return (__kCFHashMutable == __CFHashGetType(hc)) && + !(CF_USING_COLLECTABLE_MEMORY && auto_zone_is_finalized(__CFCollectableZone, hc)) && /* GC: don't shrink finalizing hcs! */ + (hc->_bucketsNum < 4 * hc->_deletes || (256 <= hc->_bucketsCap && hc-> _bucketsUsed < 3 * hc->_bucketsCap / 16)); +} + +CF_INLINE CFIndex __CFHashGetOccurrenceCount(CFHashRef hc, CFIndex idx) { +#if CFBag + return hc->_values[idx]; +#endif + return 1; +} + +CF_INLINE Boolean __CFHashKeyIsValue(CFHashRef hc, any_t key) { + return (hc->_marker != key && ~hc->_marker != key) ? true : false; +} + +CF_INLINE Boolean __CFHashKeyIsMagic(CFHashRef hc, any_t key) { + return (hc->_marker == key || ~hc->_marker == key) ? true : false; +} + + +#if !defined(CF_OBJC_KVO_WILLCHANGE) +#define CF_OBJC_KVO_WILLCHANGE(obj, key) +#define CF_OBJC_KVO_DIDCHANGE(obj, key) +#endif + +CF_INLINE uintptr_t __CFSetScrambleHash(uintptr_t k) { +#if 0 + return k; +#else +#if __LP64__ + uintptr_t a = 0x4368726973746F70ULL; + uintptr_t b = 0x686572204B616E65ULL; +#else + uintptr_t a = 0x4B616E65UL; + uintptr_t b = 0x4B616E65UL; +#endif + uintptr_t c = 1; + a += k; +#if __LP64__ + a -= b; a -= c; a ^= (c >> 43); + b -= c; b -= a; b ^= (a << 9); + c -= a; c -= b; c ^= (b >> 8); + a -= b; a -= c; a ^= (c >> 38); + b -= c; b -= a; b ^= (a << 23); + c -= a; c -= b; c ^= (b >> 5); + a -= b; a -= c; a ^= (c >> 35); + b -= c; b -= a; b ^= (a << 49); + c -= a; c -= b; c ^= (b >> 11); + a -= b; a -= c; a ^= (c >> 12); + b -= c; b -= a; b ^= (a << 18); + c -= a; c -= b; c ^= (b >> 22); +#else + a -= b; a -= c; a ^= (c >> 13); + b -= c; b -= a; b ^= (a << 8); + c -= a; c -= b; c ^= (b >> 13); + a -= b; a -= c; a ^= (c >> 12); + b -= c; b -= a; b ^= (a << 16); + c -= a; c -= b; c ^= (b >> 5); + a -= b; a -= c; a ^= (c >> 3); + b -= c; b -= a; b ^= (a << 10); + c -= a; c -= b; c ^= (b >> 15); +#endif + return c; +#endif +} + +static CFIndex __CFSetFindBuckets1a(CFHashRef hc, any_t key) { + CFHashCode keyHash = (CFHashCode)key; + keyHash = __CFSetScrambleHash(keyHash); + any_t *keys = hc->_keys; + any_t marker = hc->_marker; + CFIndex probe = keyHash & (hc->_bucketsNum - 1); + CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value + CFIndex start = probe; + for (;;) { + any_t currKey = keys[probe]; + if (marker == currKey) { /* empty */ + return kCFNotFound; + } else if (~marker == currKey) { /* deleted */ + /* do nothing */ + } else if (currKey == key) { + return probe; + } + probe = probe + probeskip; + // This alternative to probe % buckets assumes that + // probeskip is always positive and less than the + // number of buckets. + if (hc->_bucketsNum <= probe) { + probe -= hc->_bucketsNum; + } + if (start == probe) { + return kCFNotFound; + } + } +} + +static CFIndex __CFSetFindBuckets1b(CFHashRef hc, any_t key) { + const CFSetKeyCallBacks *cb = __CFSetGetKeyCallBacks(hc); + CFHashCode keyHash = cb->hash ? (CFHashCode)INVOKE_CALLBACK2(((CFHashCode (*)(any_t, any_pointer_t))cb->hash), key, hc->_context) : (CFHashCode)key; + keyHash = __CFSetScrambleHash(keyHash); + any_t *keys = hc->_keys; + any_t marker = hc->_marker; + CFIndex probe = keyHash & (hc->_bucketsNum - 1); + CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value + CFIndex start = probe; + for (;;) { + any_t currKey = keys[probe]; + if (marker == currKey) { /* empty */ + return kCFNotFound; + } else if (~marker == currKey) { /* deleted */ + /* do nothing */ + } else if (currKey == key || (cb->equal && INVOKE_CALLBACK3((Boolean (*)(any_t, any_t, any_pointer_t))cb->equal, currKey, key, hc->_context))) { + return probe; + } + probe = probe + probeskip; + // This alternative to probe % buckets assumes that + // probeskip is always positive and less than the + // number of buckets. + if (hc->_bucketsNum <= probe) { + probe -= hc->_bucketsNum; + } + if (start == probe) { + return kCFNotFound; + } + } +} + +CF_INLINE CFIndex __CFSetFindBuckets1(CFHashRef hc, any_t key) { + if (__kCFHashHasNullCallBacks == __CFBitfieldGetValue(hc->_xflags, 3, 2)) { + return __CFSetFindBuckets1a(hc, key); + } + return __CFSetFindBuckets1b(hc, key); +} + +static void __CFSetFindBuckets2(CFHashRef hc, any_t key, CFIndex *match, CFIndex *nomatch) { + const CFSetKeyCallBacks *cb = __CFSetGetKeyCallBacks(hc); + CFHashCode keyHash = cb->hash ? (CFHashCode)INVOKE_CALLBACK2(((CFHashCode (*)(any_t, any_pointer_t))cb->hash), key, hc->_context) : (CFHashCode)key; + keyHash = __CFSetScrambleHash(keyHash); + any_t *keys = hc->_keys; + any_t marker = hc->_marker; + CFIndex probe = keyHash & (hc->_bucketsNum - 1); + CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value + CFIndex start = probe; + *match = kCFNotFound; + *nomatch = kCFNotFound; + for (;;) { + any_t currKey = keys[probe]; + if (marker == currKey) { /* empty */ + if (nomatch) *nomatch = probe; + return; + } else if (~marker == currKey) { /* deleted */ + if (nomatch) { + *nomatch = probe; + nomatch = NULL; + } + } else if (currKey == key || (cb->equal && INVOKE_CALLBACK3((Boolean (*)(any_t, any_t, any_pointer_t))cb->equal, currKey, key, hc->_context))) { + *match = probe; + return; + } + probe = probe + probeskip; + // This alternative to probe % buckets assumes that + // probeskip is always positive and less than the + // number of buckets. + if (hc->_bucketsNum <= probe) { + probe -= hc->_bucketsNum; + } + if (start == probe) { + return; + } + } +} + +static void __CFSetFindNewMarker(CFHashRef hc) { + any_t *keys = hc->_keys; + any_t newMarker; + CFIndex idx, nbuckets; + Boolean hit; + + nbuckets = hc->_bucketsNum; + newMarker = hc->_marker; + do { + newMarker--; + hit = false; + for (idx = 0; idx < nbuckets; idx++) { + if (newMarker == keys[idx] || ~newMarker == keys[idx]) { + hit = true; + break; + } + } + } while (hit); + for (idx = 0; idx < nbuckets; idx++) { + if (hc->_marker == keys[idx]) { + keys[idx] = newMarker; + } else if (~hc->_marker == keys[idx]) { + keys[idx] = ~newMarker; + } + } + ((struct __CFSet *)hc)->_marker = newMarker; +} + +static Boolean __CFSetEqual(CFTypeRef cf1, CFTypeRef cf2) { + CFHashRef hc1 = (CFHashRef)cf1; + CFHashRef hc2 = (CFHashRef)cf2; + const CFSetKeyCallBacks *cb1, *cb2; + const CFSetValueCallBacks *vcb1, *vcb2; + any_t *keys; + CFIndex idx, nbuckets; + if (hc1 == hc2) return true; + if (hc1->_count != hc2->_count) return false; + cb1 = __CFSetGetKeyCallBacks(hc1); + cb2 = __CFSetGetKeyCallBacks(hc2); + if (cb1->equal != cb2->equal) return false; + vcb1 = __CFSetGetValueCallBacks(hc1); + vcb2 = __CFSetGetValueCallBacks(hc2); + if (vcb1->equal != vcb2->equal) return false; + if (0 == hc1->_bucketsUsed) return true; /* after function comparison! */ + keys = hc1->_keys; + nbuckets = hc1->_bucketsNum; + for (idx = 0; idx < nbuckets; idx++) { + if (hc1->_marker != keys[idx] && ~hc1->_marker != keys[idx]) { +#if CFDictionary + const_any_pointer_t value; + if (!CFSetGetValueIfPresent(hc2, (any_pointer_t)keys[idx], &value)) return false; + if (hc1->_values[idx] != (any_t)value) { + if (NULL == vcb1->equal) return false; + if (!INVOKE_CALLBACK3((Boolean (*)(any_t, any_t, any_pointer_t))vcb1->equal, hc1->_values[idx], (any_t)value, hc1->_context)) return false; + } +#endif +#if CFSet + const_any_pointer_t value; + if (!CFSetGetValueIfPresent(hc2, (any_pointer_t)keys[idx], &value)) return false; +#endif +#if CFBag + if (hc1->_values[idx] != CFSetGetCountOfValue(hc2, (any_pointer_t)keys[idx])) return false; +#endif + } + } + return true; +} + +static CFHashCode __CFSetHash(CFTypeRef cf) { + CFHashRef hc = (CFHashRef)cf; + return hc->_count; +} + +static CFStringRef __CFSetCopyDescription(CFTypeRef cf) { + CFHashRef hc = (CFHashRef)cf; + CFAllocatorRef allocator; + const CFSetKeyCallBacks *cb; + const CFSetValueCallBacks *vcb; + any_t *keys; + CFIndex idx, nbuckets; + CFMutableStringRef result; + cb = __CFSetGetKeyCallBacks(hc); + vcb = __CFSetGetValueCallBacks(hc); + keys = hc->_keys; + nbuckets = hc->_bucketsNum; + allocator = CFGetAllocator(hc); + result = CFStringCreateMutable(allocator, 0); + const char *type = "?"; + switch (__CFHashGetType(hc)) { + case __kCFHashImmutable: type = "immutable"; break; + case __kCFHashMutable: type = "mutable"; break; + } + CFStringAppendFormat(result, NULL, CFSTR("{type = %s, count = %u, capacity = %u, pairs = (\n"), cf, allocator, type, hc->_count, hc->_bucketsCap); + for (idx = 0; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + CFStringRef kDesc = NULL, vDesc = NULL; + if (NULL != cb->copyDescription) { + kDesc = (CFStringRef)INVOKE_CALLBACK2(((CFStringRef (*)(any_t, any_pointer_t))cb->copyDescription), keys[idx], hc->_context); + } + if (NULL != vcb->copyDescription) { + vDesc = (CFStringRef)INVOKE_CALLBACK2(((CFStringRef (*)(any_t, any_pointer_t))vcb->copyDescription), hc->_values[idx], hc->_context); + } +#if CFDictionary + if (NULL != kDesc && NULL != vDesc) { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@ = %@\n"), idx, kDesc, vDesc); + CFRelease(kDesc); + CFRelease(vDesc); + } else if (NULL != kDesc) { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@ = <%p>\n"), idx, kDesc, hc->_values[idx]); + CFRelease(kDesc); + } else if (NULL != vDesc) { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p> = %@\n"), idx, keys[idx], vDesc); + CFRelease(vDesc); + } else { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p> = <%p>\n"), idx, keys[idx], hc->_values[idx]); + } +#endif +#if CFSet + if (NULL != kDesc) { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@\n"), idx, kDesc); + CFRelease(kDesc); + } else { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p>\n"), idx, keys[idx]); + } +#endif +#if CFBag + if (NULL != kDesc) { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@ (%ld)\n"), idx, kDesc, hc->_values[idx]); + CFRelease(kDesc); + } else { + CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p> (%ld)\n"), idx, keys[idx], hc->_values[idx]); + } +#endif + } + } + CFStringAppend(result, CFSTR(")}")); + return result; +} + +static void __CFSetDeallocate(CFTypeRef cf) { + CFMutableHashRef hc = (CFMutableHashRef)cf; + CFAllocatorRef allocator = __CFGetAllocator(hc); + const CFSetKeyCallBacks *cb = __CFSetGetKeyCallBacks(hc); + const CFSetValueCallBacks *vcb = __CFSetGetValueCallBacks(hc); + + // mark now in case any callout somehow tries to add an entry back in + markFinalized(cf); + if (vcb->release || cb->release) { + any_t *keys = hc->_keys; + CFIndex idx, nbuckets = hc->_bucketsNum; + for (idx = 0; idx < nbuckets; idx++) { + any_t oldkey = keys[idx]; + if (hc->_marker != oldkey && ~hc->_marker != oldkey) { + if (vcb->release) { + INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, any_t, any_pointer_t))vcb->release), allocator, hc->_values[idx], hc->_context); + } + if (cb->release) { + INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, any_t, any_pointer_t))cb->release), allocator, oldkey, hc->_context); + } + } + } + } + + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + // return early so that contents are preserved after finalization + return; + } + + _CFAllocatorDeallocateGC(allocator, hc->_keys); +#if CFDictionary || CFBag + _CFAllocatorDeallocateGC(allocator, hc->_values); +#endif + hc->_keys = NULL; + hc->_values = NULL; + hc->_count = 0; // GC: also zero count, so the hc will appear empty. + hc->_bucketsUsed = 0; + hc->_bucketsNum = 0; +} + +static CFTypeID __kCFSetTypeID = _kCFRuntimeNotATypeID; + +static const CFRuntimeClass __CFSetClass = { + _kCFRuntimeScannedObject, + "CFSet", + NULL, // init + NULL, // copy + __CFSetDeallocate, + __CFSetEqual, + __CFSetHash, + NULL, // + __CFSetCopyDescription +}; + +__private_extern__ void __CFSetInitialize(void) { + __kCFHashTypeID = _CFRuntimeRegisterClass(&__CFSetClass); +} + +CFTypeID CFSetGetTypeID(void) { + return __kCFHashTypeID; +} + +static CFMutableHashRef __CFSetInit(CFAllocatorRef allocator, CFOptionFlags flags, CFIndex capacity, const CFSetKeyCallBacks *keyCallBacks +#if CFDictionary +, const CFSetValueCallBacks *valueCallBacks +#endif +) { + struct __CFSet *hc; + CFIndex size; + __CFBitfieldSetValue(flags, 31, 2, 0); + CFOptionFlags xflags = 0; + if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { + // preserve NULL for key or value CB, otherwise fix up. + if (!keyCallBacks || (keyCallBacks->retain == NULL && keyCallBacks->release == NULL)) { + xflags = __kCFHashWeakKeys; + } +#if CFDictionary + if (!valueCallBacks || (valueCallBacks->retain == NULL && valueCallBacks->release == NULL)) { + xflags |= __kCFHashWeakValues; + } +#endif +#if CFBag + xflags |= __kCFHashWeakValues; +#endif + } + if (__CFSetKeyCallBacksMatchNull(keyCallBacks)) { + __CFBitfieldSetValue(flags, 3, 2, __kCFHashHasNullCallBacks); + } else if (__CFSetKeyCallBacksMatchCFType(keyCallBacks)) { + __CFBitfieldSetValue(flags, 3, 2, __kCFHashHasCFTypeCallBacks); + } else { + __CFBitfieldSetValue(flags, 3, 2, __kCFHashHasCustomCallBacks); + } +#if CFDictionary + if (__CFSetValueCallBacksMatchNull(valueCallBacks)) { + __CFBitfieldSetValue(flags, 5, 4, __kCFHashHasNullCallBacks); + } else if (__CFSetValueCallBacksMatchCFType(valueCallBacks)) { + __CFBitfieldSetValue(flags, 5, 4, __kCFHashHasCFTypeCallBacks); + } else { + __CFBitfieldSetValue(flags, 5, 4, __kCFHashHasCustomCallBacks); + } +#endif + size = __CFSetGetSizeOfType(flags) - sizeof(CFRuntimeBase); + hc = (struct __CFSet *)_CFRuntimeCreateInstance(allocator, __kCFHashTypeID, size, NULL); + if (NULL == hc) { + return NULL; + } + hc->_count = 0; + hc->_bucketsUsed = 0; + hc->_marker = (any_t)0xa1b1c1d3; + hc->_context = NULL; + hc->_deletes = 0; + hc->_mutations = 1; + hc->_xflags = xflags | flags; + switch (__CFBitfieldGetValue(flags, 1, 0)) { + case __kCFHashImmutable: + if (__CFOASafe) __CFSetLastAllocationEventName(hc, "CFSet (immutable)"); + break; + case __kCFHashMutable: + if (__CFOASafe) __CFSetLastAllocationEventName(hc, "CFSet (mutable-variable)"); + break; + } + hc->_bucketsCap = __CFHashRoundUpCapacity(1); + hc->_bucketsNum = 0; + hc->_keys = NULL; + hc->_values = NULL; + if (__kCFHashHasCustomCallBacks == __CFBitfieldGetValue(flags, 3, 2)) { + CFSetKeyCallBacks *cb = (CFSetKeyCallBacks *)__CFSetGetKeyCallBacks((CFHashRef)hc); + *cb = *keyCallBacks; + FAULT_CALLBACK((void **)&(cb->retain)); + FAULT_CALLBACK((void **)&(cb->release)); + FAULT_CALLBACK((void **)&(cb->copyDescription)); + FAULT_CALLBACK((void **)&(cb->equal)); + FAULT_CALLBACK((void **)&(cb->hash)); + } +#if CFDictionary + if (__kCFHashHasCustomCallBacks == __CFBitfieldGetValue(flags, 5, 4)) { + CFSetValueCallBacks *vcb = (CFSetValueCallBacks *)__CFSetGetValueCallBacks((CFHashRef)hc); + *vcb = *valueCallBacks; + FAULT_CALLBACK((void **)&(vcb->retain)); + FAULT_CALLBACK((void **)&(vcb->release)); + FAULT_CALLBACK((void **)&(vcb->copyDescription)); + FAULT_CALLBACK((void **)&(vcb->equal)); + } +#endif + return hc; +} + +#if CFDictionary +CFHashRef CFSetCreate(CFAllocatorRef allocator, const_any_pointer_t *keys, const_any_pointer_t *values, CFIndex numValues, const CFSetKeyCallBacks *keyCallBacks, const CFSetValueCallBacks *valueCallBacks) { +#endif +#if CFSet || CFBag +CFHashRef CFSetCreate(CFAllocatorRef allocator, const_any_pointer_t *keys, CFIndex numValues, const CFSetKeyCallBacks *keyCallBacks) { +#endif + CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__, numValues); +#if CFDictionary + CFMutableHashRef hc = __CFSetInit(allocator, __kCFHashImmutable, numValues, keyCallBacks, valueCallBacks); +#endif +#if CFSet || CFBag + CFMutableHashRef hc = __CFSetInit(allocator, __kCFHashImmutable, numValues, keyCallBacks); +#endif + __CFBitfieldSetValue(hc->_xflags, 1, 0, __kCFHashMutable); + for (CFIndex idx = 0; idx < numValues; idx++) { +#if CFDictionary + CFSetAddValue(hc, keys[idx], values[idx]); +#endif +#if CFSet || CFBag + CFSetAddValue(hc, keys[idx]); +#endif + } + __CFBitfieldSetValue(hc->_xflags, 1, 0, __kCFHashImmutable); + return (CFHashRef)hc; +} + +#if CFDictionary +CFMutableHashRef CFSetCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFSetKeyCallBacks *keyCallBacks, const CFSetValueCallBacks *valueCallBacks) { +#endif +#if CFSet || CFBag +CFMutableHashRef CFSetCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFSetKeyCallBacks *keyCallBacks) { +#endif + CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%ld) cannot be less than zero", __PRETTY_FUNCTION__, capacity); +#if CFDictionary + CFMutableHashRef hc = __CFSetInit(allocator, __kCFHashMutable, capacity, keyCallBacks, valueCallBacks); +#endif +#if CFSet || CFBag + CFMutableHashRef hc = __CFSetInit(allocator, __kCFHashMutable, capacity, keyCallBacks); +#endif + return hc; +} + +#if CFDictionary || CFSet +// does not have Add semantics for Bag; it has Set semantics ... is that best? +static void __CFSetGrow(CFMutableHashRef hc, CFIndex numNewValues); + +// This creates a hc which is for CFTypes or NSObjects, with a CFRetain style ownership transfer; +// the hc does not take a retain (since it claims 1), and the caller does not need to release the inserted objects (since we do it). +// The incoming objects must also be collectable if allocated out of a collectable allocator - and are neither released nor retained. +#if CFDictionary +CFHashRef _CFSetCreate_ex(CFAllocatorRef allocator, Boolean isMutable, const_any_pointer_t *keys, const_any_pointer_t *values, CFIndex numValues) { +#endif +#if CFSet || CFBag +CFHashRef _CFSetCreate_ex(CFAllocatorRef allocator, Boolean isMutable, const_any_pointer_t *keys, CFIndex numValues) { +#endif + CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%ld) cannot be less than zero", __PRETTY_FUNCTION__, numValues); +#if CFDictionary + CFMutableHashRef hc = __CFSetInit(allocator, __kCFHashMutable, numValues, &kCFTypeSetKeyCallBacks, &kCFTypeSetValueCallBacks); +#endif +#if CFSet || CFBag + CFMutableHashRef hc = __CFSetInit(allocator, __kCFHashMutable, numValues, &kCFTypeSetKeyCallBacks); +#endif + __CFSetGrow(hc, numValues); + for (CFIndex idx = 0; idx < numValues; idx++) { + CFIndex match, nomatch; + __CFSetFindBuckets2(hc, (any_t)keys[idx], &match, &nomatch); + if (kCFNotFound == match) { + CFAllocatorRef allocator = __CFGetAllocator(hc); + any_t newKey = (any_t)keys[idx]; + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFSetFindNewMarker(hc); + } + if (hc->_keys[nomatch] == ~hc->_marker) { + hc->_deletes--; + } + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[nomatch], newKey); +#if CFDictionary + any_t newValue = (any_t)values[idx]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[nomatch], newValue); +#endif +#if CFBag + hc->_values[nomatch] = 1; +#endif + hc->_bucketsUsed++; + hc->_count++; + } else { + CFAllocatorRef allocator = __CFGetAllocator(hc); +#if CFSet || CFBag + any_t oldKey = hc->_keys[match]; + any_t newKey = (any_t)keys[idx]; + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], ~hc->_marker); + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFSetFindNewMarker(hc); + } + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], newKey); + RELEASEKEY(oldKey); +#endif +#if CFDictionary + any_t oldValue = hc->_values[match]; + any_t newValue = (any_t)values[idx]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[match], newValue); + RELEASEVALUE(oldValue); +#endif + } + } + if (!isMutable) __CFBitfieldSetValue(hc->_xflags, 1, 0, __kCFHashImmutable); + return (CFHashRef)hc; +} +#endif + +CFHashRef CFSetCreateCopy(CFAllocatorRef allocator, CFHashRef other) { + CFMutableHashRef hc = CFSetCreateMutableCopy(allocator, CFSetGetCount(other), other); + __CFBitfieldSetValue(hc->_xflags, 1, 0, __kCFHashImmutable); + if (__CFOASafe) __CFSetLastAllocationEventName(hc, "CFSet (immutable)"); + return hc; +} + +CFMutableHashRef CFSetCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFHashRef other) { + CFIndex numValues = CFSetGetCount(other); + const_any_pointer_t *list, buffer[256]; + list = (numValues <= 256) ? buffer : (const_any_pointer_t *)CFAllocatorAllocate(allocator, numValues * sizeof(const_any_pointer_t), 0); + if (list != buffer && __CFOASafe) __CFSetLastAllocationEventName(list, "CFSet (temp)"); +#if CFDictionary + const_any_pointer_t *vlist, vbuffer[256]; + vlist = (numValues <= 256) ? vbuffer : (const_any_pointer_t *)CFAllocatorAllocate(allocator, numValues * sizeof(const_any_pointer_t), 0); + if (vlist != vbuffer && __CFOASafe) __CFSetLastAllocationEventName(vlist, "CFSet (temp)"); +#endif +#if CFSet || CFBag + CFSetGetValues(other, list); +#endif +#if CFDictionary + CFSetGetKeysAndValues(other, list, vlist); +#endif + const CFSetKeyCallBacks *kcb; + const CFSetValueCallBacks *vcb; + if (CF_IS_OBJC(__kCFHashTypeID, other)) { + kcb = &kCFTypeSetKeyCallBacks; + vcb = &kCFTypeSetValueCallBacks; + } else { + kcb = __CFSetGetKeyCallBacks(other); + vcb = __CFSetGetValueCallBacks(other); + } +#if CFDictionary + CFMutableHashRef hc = __CFSetInit(allocator, __kCFHashMutable, capacity, kcb, vcb); +#endif +#if CFSet || CFBag + CFMutableHashRef hc = __CFSetInit(allocator, __kCFHashMutable, capacity, kcb); +#endif + if (0 == capacity) _CFSetSetCapacity(hc, numValues); + for (CFIndex idx = 0; idx < numValues; idx++) { +#if CFDictionary + CFSetAddValue(hc, list[idx], vlist[idx]); +#endif +#if CFSet || CFBag + CFSetAddValue(hc, list[idx]); +#endif + } + if (list != buffer) CFAllocatorDeallocate(allocator, list); +#if CFDictionary + if (vlist != vbuffer) CFAllocatorDeallocate(allocator, vlist); +#endif + return hc; +} + +// Used by NSHashTables/NSMapTables and KVO +void _CFSetSetContext(CFHashRef hc, any_pointer_t context) { + __CFGenericValidateType(hc, __kCFHashTypeID); + CF_WRITE_BARRIER_BASE_ASSIGN(__CFGetAllocator(hc), hc, hc->_context, context); +} + +any_pointer_t _CFSetGetContext(CFHashRef hc) { + __CFGenericValidateType(hc, __kCFHashTypeID); + return hc->_context; +} + +CFIndex CFSetGetCount(CFHashRef hc) { + if (CFDictionary || CFSet) CF_OBJC_FUNCDISPATCH0(__kCFHashTypeID, CFIndex, hc, "count"); + __CFGenericValidateType(hc, __kCFHashTypeID); + return hc->_count; +} + +#if CFDictionary +CFIndex CFSetGetCountOfKey(CFHashRef hc, const_any_pointer_t key) { +#endif +#if CFSet || CFBag +CFIndex CFSetGetCountOfValue(CFHashRef hc, const_any_pointer_t key) { +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, CFIndex, hc, "countForKey:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, CFIndex, hc, "countForObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return 0; + CFIndex match = __CFSetFindBuckets1(hc, (any_t)key); + return (kCFNotFound != match ? __CFHashGetOccurrenceCount(hc, match) : 0); +} + +#if CFDictionary +Boolean CFSetContainsKey(CFHashRef hc, const_any_pointer_t key) { +#endif +#if CFSet || CFBag +Boolean CFSetContainsValue(CFHashRef hc, const_any_pointer_t key) { +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, char, hc, "containsKey:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, char, hc, "containsObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return false; + CFIndex match = __CFSetFindBuckets1(hc, (any_t)key); + return (kCFNotFound != match ? true : false); +} + +#if CFDictionary +CFIndex CFSetGetCountOfValue(CFHashRef hc, const_any_pointer_t value) { + CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, CFIndex, hc, "countForObject:", value); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return 0; + any_t *keys = hc->_keys; + Boolean (*equal)(any_t, any_t, any_pointer_t) = (Boolean (*)(any_t, any_t, any_pointer_t))__CFSetGetValueCallBacks(hc)->equal; + CFIndex cnt = 0; + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + if ((hc->_values[idx] == (any_t)value) || (equal && INVOKE_CALLBACK3(equal, hc->_values[idx], (any_t)value, hc->_context))) { + cnt++; + } + } + } + return cnt; +} + +Boolean CFSetContainsValue(CFHashRef hc, const_any_pointer_t value) { + CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, char, hc, "containsObject:", value); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return false; + any_t *keys = hc->_keys; + Boolean (*equal)(any_t, any_t, any_pointer_t) = (Boolean (*)(any_t, any_t, any_pointer_t))__CFSetGetValueCallBacks(hc)->equal; + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + if ((hc->_values[idx] == (any_t)value) || (equal && INVOKE_CALLBACK3(equal, hc->_values[idx], (any_t)value, hc->_context))) { + return true; + } + } + } + return false; +} +#endif + +const_any_pointer_t CFSetGetValue(CFHashRef hc, const_any_pointer_t key) { + if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, const_any_pointer_t, hc, "objectForKey:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, const_any_pointer_t, hc, "member:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return 0; + CFIndex match = __CFSetFindBuckets1(hc, (any_t)key); + return (kCFNotFound != match ? (const_any_pointer_t)(CFDictionary ? hc->_values[match] : hc->_keys[match]) : 0); +} + +Boolean CFSetGetValueIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *value) { + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, Boolean, hc, "_getValue:forKey:", (any_t *)value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, Boolean, hc, "_getValue:forObj:", (any_t *)value, key); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return false; + CFIndex match = __CFSetFindBuckets1(hc, (any_t)key); + return (kCFNotFound != match ? ((value ? __CFObjCStrongAssign((const_any_pointer_t)(CFDictionary ? hc->_values[match] : hc->_keys[match]), value) : 0), true) : false); +} + +#if CFDictionary +Boolean CFSetGetKeyIfPresent(CFHashRef hc, const_any_pointer_t key, const_any_pointer_t *actualkey) { + CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, Boolean, hc, "getActualKey:forKey:", actualkey, key); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (0 == hc->_bucketsUsed) return false; + CFIndex match = __CFSetFindBuckets1(hc, (any_t)key); + return (kCFNotFound != match ? ((actualkey ? __CFObjCStrongAssign((const_any_pointer_t)hc->_keys[match], actualkey) : NULL), true) : false); +} +#endif + +#if CFDictionary +void CFSetGetKeysAndValues(CFHashRef hc, const_any_pointer_t *keybuf, const_any_pointer_t *valuebuf) { +#endif +#if CFSet || CFBag +void CFSetGetValues(CFHashRef hc, const_any_pointer_t *keybuf) { + const_any_pointer_t *valuebuf = 0; +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "getObjects:andKeys:", (any_t *)valuebuf, (any_t *)keybuf); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "getObjects:", (any_t *)keybuf); + __CFGenericValidateType(hc, __kCFHashTypeID); + if (CF_USING_COLLECTABLE_MEMORY) { + // GC: speculatively issue a write-barrier on the copied to buffers + __CFObjCWriteBarrierRange(keybuf, hc->_count * sizeof(any_t)); + __CFObjCWriteBarrierRange(valuebuf, hc->_count * sizeof(any_t)); + } + any_t *keys = hc->_keys; + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + for (CFIndex cnt = __CFHashGetOccurrenceCount(hc, idx); cnt--;) { + if (keybuf) *keybuf++ = (const_any_pointer_t)keys[idx]; + if (valuebuf) *valuebuf++ = (const_any_pointer_t)hc->_values[idx]; + } + } + } +} + +#if CFDictionary || CFSet +unsigned long _CFSetFastEnumeration(CFHashRef hc, struct __objcFastEnumerationStateEquivalent *state, void *stackbuffer, unsigned long count) { + /* copy as many as count items over */ + if (0 == state->state) { /* first time */ + state->mutationsPtr = (unsigned long *)&hc->_mutations; + } + state->itemsPtr = (unsigned long *)stackbuffer; + CFIndex cnt = 0; + any_t *keys = hc->_keys; + for (CFIndex idx = (CFIndex)state->state, nbuckets = hc->_bucketsNum; idx < nbuckets && cnt < (CFIndex)count; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + state->itemsPtr[cnt++] = (unsigned long)keys[idx]; + } + state->state++; + } + return cnt; +} +#endif + +void CFSetApplyFunction(CFHashRef hc, CFSetApplierFunction applier, any_pointer_t context) { + FAULT_CALLBACK((void **)&(applier)); + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "_apply:context:", applier, context); + if (CFSet) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "_applyValues:context:", applier, context); + __CFGenericValidateType(hc, __kCFHashTypeID); + any_t *keys = hc->_keys; + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + for (CFIndex cnt = __CFHashGetOccurrenceCount(hc, idx); cnt--;) { +#if CFDictionary + INVOKE_CALLBACK3(applier, (const_any_pointer_t)keys[idx], (const_any_pointer_t)hc->_values[idx], context); +#endif +#if CFSet || CFBag + INVOKE_CALLBACK2(applier, (const_any_pointer_t)keys[idx], context); +#endif + } + } + } +} + +static void __CFSetGrow(CFMutableHashRef hc, CFIndex numNewValues) { + any_t *oldkeys = hc->_keys; + any_t *oldvalues = hc->_values; + CFIndex nbuckets = hc->_bucketsNum; + hc->_bucketsCap = __CFHashRoundUpCapacity(hc->_bucketsUsed + numNewValues); + hc->_bucketsNum = __CFHashNumBucketsForCapacity(hc->_bucketsCap); + hc->_deletes = 0; + CFAllocatorRef allocator = __CFGetAllocator(hc); + CFOptionFlags weakOrStrong = (hc->_xflags & __kCFHashWeakKeys) ? 0 : __kCFAllocatorGCScannedMemory; + any_t *mem = (any_t *)_CFAllocatorAllocateGC(allocator, hc->_bucketsNum * sizeof(any_t), weakOrStrong); + if (NULL == mem) __CFSetHandleOutOfMemory(hc, hc->_bucketsNum * sizeof(any_t)); + if (__CFOASafe) __CFSetLastAllocationEventName(mem, "CFSet (key-store)"); + CF_WRITE_BARRIER_BASE_ASSIGN(allocator, hc, hc->_keys, mem); + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; // GC: avoids write-barrier in weak case. + any_t *keysBase = mem; +#if CFDictionary || CFBag + weakOrStrong = (hc->_xflags & __kCFHashWeakValues) ? 0 : __kCFAllocatorGCScannedMemory; + mem = (any_t *)_CFAllocatorAllocateGC(allocator, hc->_bucketsNum * sizeof(any_t), weakOrStrong); + if (NULL == mem) __CFSetHandleOutOfMemory(hc, hc->_bucketsNum * sizeof(any_t)); + if (__CFOASafe) __CFSetLastAllocationEventName(mem, "CFSet (value-store)"); + CF_WRITE_BARRIER_BASE_ASSIGN(allocator, hc, hc->_values, mem); +#endif +#if CFDictionary + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; // GC: avoids write-barrier in weak case. + any_t *valuesBase = mem; +#endif + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + hc->_keys[idx] = hc->_marker; +#if CFDictionary || CFBag + hc->_values[idx] = 0; +#endif + } + if (NULL == oldkeys) return; + for (CFIndex idx = 0; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, oldkeys[idx])) { + CFIndex match, nomatch; + __CFSetFindBuckets2(hc, oldkeys[idx], &match, &nomatch); + CFAssert3(kCFNotFound == match, __kCFLogAssertion, "%s(): two values (%p, %p) now hash to the same slot; mutable value changed while in table or hash value is not immutable", __PRETTY_FUNCTION__, oldkeys[idx], hc->_keys[match]); + if (kCFNotFound != nomatch) { + CF_WRITE_BARRIER_BASE_ASSIGN(keysAllocator, keysBase, hc->_keys[nomatch], oldkeys[idx]); +#if CFDictionary + CF_WRITE_BARRIER_BASE_ASSIGN(valuesAllocator, valuesBase, hc->_values[nomatch], oldvalues[idx]); +#endif +#if CFBag + hc->_values[nomatch] = oldvalues[idx]; +#endif + } + } + } + _CFAllocatorDeallocateGC(allocator, oldkeys); + _CFAllocatorDeallocateGC(allocator, oldvalues); +} + +// This function is for Foundation's benefit; no one else should use it. +void _CFSetSetCapacity(CFMutableHashRef hc, CFIndex cap) { + if (CF_IS_OBJC(__kCFHashTypeID, hc)) return; + __CFGenericValidateType(hc, __kCFHashTypeID); + CFAssert1(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): collection is immutable", __PRETTY_FUNCTION__); + CFAssert3(hc->_bucketsUsed <= cap, __kCFLogAssertion, "%s(): desired capacity (%ld) is less than bucket count (%ld)", __PRETTY_FUNCTION__, cap, hc->_bucketsUsed); + __CFSetGrow(hc, cap - hc->_bucketsUsed); +} + + +#if CFDictionary +void CFSetAddValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_pointer_t value) { +#endif +#if CFSet || CFBag +void CFSetAddValue(CFMutableHashRef hc, const_any_pointer_t key) { + #define value 0 +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "_addObject:forKey:", value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "addObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + switch (__CFHashGetType(hc)) { + case __kCFHashMutable: + if (hc->_bucketsUsed == hc->_bucketsCap || NULL == hc->_keys) { + __CFSetGrow(hc, 1); + } + break; + default: + CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + break; + } + hc->_mutations++; + CFIndex match, nomatch; + __CFSetFindBuckets2(hc, (any_t)key, &match, &nomatch); + if (kCFNotFound != match) { +#if CFBag + CF_OBJC_KVO_WILLCHANGE(hc, hc->_keys[match]); + hc->_values[match]++; + hc->_count++; + CF_OBJC_KVO_DIDCHANGE(hc, hc->_keys[match]); +#endif + } else { + CFAllocatorRef allocator = __CFGetAllocator(hc); + GETNEWKEY(newKey, key); +#if CFDictionary + GETNEWVALUE(newValue); +#endif + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFSetFindNewMarker(hc); + } + if (hc->_keys[nomatch] == ~hc->_marker) { + hc->_deletes--; + } + CF_OBJC_KVO_WILLCHANGE(hc, key); + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[nomatch], newKey); +#if CFDictionary + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[nomatch], newValue); +#endif +#if CFBag + hc->_values[nomatch] = 1; +#endif + hc->_bucketsUsed++; + hc->_count++; + CF_OBJC_KVO_DIDCHANGE(hc, key); + } +} + +#if CFDictionary +void CFSetReplaceValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_pointer_t value) { +#endif +#if CFSet || CFBag +void CFSetReplaceValue(CFMutableHashRef hc, const_any_pointer_t key) { + #define value 0 +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "_replaceObject:forKey:", value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "_replaceObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + switch (__CFHashGetType(hc)) { + case __kCFHashMutable: + break; + default: + CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + break; + } + hc->_mutations++; + if (0 == hc->_bucketsUsed) return; + CFIndex match = __CFSetFindBuckets1(hc, (any_t)key); + if (kCFNotFound == match) return; + CFAllocatorRef allocator = __CFGetAllocator(hc); +#if CFSet || CFBag + GETNEWKEY(newKey, key); +#endif +#if CFDictionary + GETNEWVALUE(newValue); +#endif + any_t oldKey = hc->_keys[match]; + CF_OBJC_KVO_WILLCHANGE(hc, oldKey); +#if CFSet || CFBag + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], ~hc->_marker); + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFSetFindNewMarker(hc); + } + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], newKey); +#endif +#if CFDictionary + any_t oldValue = hc->_values[match]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[match], newValue); +#endif + CF_OBJC_KVO_DIDCHANGE(hc, oldKey); +#if CFSet || CFBag + RELEASEKEY(oldKey); +#endif +#if CFDictionary + RELEASEVALUE(oldValue); +#endif +} + +#if CFDictionary +void CFSetSetValue(CFMutableHashRef hc, const_any_pointer_t key, const_any_pointer_t value) { +#endif +#if CFSet || CFBag +void CFSetSetValue(CFMutableHashRef hc, const_any_pointer_t key) { + #define value 0 +#endif + if (CFDictionary) CF_OBJC_FUNCDISPATCH2(__kCFHashTypeID, void, hc, "setObject:forKey:", value, key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "_setObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + switch (__CFHashGetType(hc)) { + case __kCFHashMutable: + if (hc->_bucketsUsed == hc->_bucketsCap || NULL == hc->_keys) { + __CFSetGrow(hc, 1); + } + break; + default: + CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + break; + } + hc->_mutations++; + CFIndex match, nomatch; + __CFSetFindBuckets2(hc, (any_t)key, &match, &nomatch); + if (kCFNotFound == match) { + CFAllocatorRef allocator = __CFGetAllocator(hc); + GETNEWKEY(newKey, key); +#if CFDictionary + GETNEWVALUE(newValue); +#endif + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFSetFindNewMarker(hc); + } + if (hc->_keys[nomatch] == ~hc->_marker) { + hc->_deletes--; + } + CF_OBJC_KVO_WILLCHANGE(hc, key); + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[nomatch], newKey); +#if CFDictionary + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[nomatch], newValue); +#endif +#if CFBag + hc->_values[nomatch] = 1; +#endif + hc->_bucketsUsed++; + hc->_count++; + CF_OBJC_KVO_DIDCHANGE(hc, key); + } else { + CFAllocatorRef allocator = __CFGetAllocator(hc); +#if CFSet || CFBag + GETNEWKEY(newKey, key); +#endif +#if CFDictionary + GETNEWVALUE(newValue); +#endif + any_t oldKey = hc->_keys[match]; + CF_OBJC_KVO_WILLCHANGE(hc, oldKey); +#if CFSet || CFBag + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], ~hc->_marker); + if (__CFHashKeyIsMagic(hc, newKey)) { + __CFSetFindNewMarker(hc); + } + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], newKey); +#endif +#if CFDictionary + any_t oldValue = hc->_values[match]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[match], newValue); +#endif + CF_OBJC_KVO_DIDCHANGE(hc, oldKey); +#if CFSet || CFBag + RELEASEKEY(oldKey); +#endif +#if CFDictionary + RELEASEVALUE(oldValue); +#endif + } +} + +void CFSetRemoveValue(CFMutableHashRef hc, const_any_pointer_t key) { + if (CFDictionary) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "removeObjectForKey:", key); + if (CFSet) CF_OBJC_FUNCDISPATCH1(__kCFHashTypeID, void, hc, "removeObject:", key); + __CFGenericValidateType(hc, __kCFHashTypeID); + switch (__CFHashGetType(hc)) { + case __kCFHashMutable: + break; + default: + CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + break; + } + hc->_mutations++; + if (0 == hc->_bucketsUsed) return; + CFIndex match = __CFSetFindBuckets1(hc, (any_t)key); + if (kCFNotFound == match) return; + if (1 < __CFHashGetOccurrenceCount(hc, match)) { +#if CFBag + CF_OBJC_KVO_WILLCHANGE(hc, hc->_keys[match]); + hc->_values[match]--; + hc->_count--; + CF_OBJC_KVO_DIDCHANGE(hc, hc->_keys[match]); +#endif + } else { + CFAllocatorRef allocator = __CFGetAllocator(hc); + any_t oldKey = hc->_keys[match]; + CF_OBJC_KVO_WILLCHANGE(hc, oldKey); + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[match], ~hc->_marker); +#if CFDictionary + any_t oldValue = hc->_values[match]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[match], 0); +#endif +#if CFBag + hc->_values[match] = 0; +#endif + hc->_count--; + hc->_bucketsUsed--; + hc->_deletes++; + CF_OBJC_KVO_DIDCHANGE(hc, oldKey); + RELEASEKEY(oldKey); +#if CFDictionary + RELEASEVALUE(oldValue); +#endif + if (__CFSetShouldShrink(hc)) { + __CFSetGrow(hc, 0); + } else { + // When the probeskip == 1 always and only, a DELETED slot followed by an EMPTY slot + // can be converted to an EMPTY slot. By extension, a chain of DELETED slots followed + // by an EMPTY slot can be converted to EMPTY slots, which is what we do here. + if (match < hc->_bucketsNum - 1 && hc->_keys[match + 1] == hc->_marker) { + while (0 <= match && hc->_keys[match] == ~hc->_marker) { + hc->_keys[match] = hc->_marker; + hc->_deletes--; + match--; + } + } + } + } +} + +void CFSetRemoveAllValues(CFMutableHashRef hc) { + if (CFDictionary) CF_OBJC_FUNCDISPATCH0(__kCFHashTypeID, void, hc, "removeAllObjects"); + if (CFSet) CF_OBJC_FUNCDISPATCH0(__kCFHashTypeID, void, hc, "removeAllObjects"); + __CFGenericValidateType(hc, __kCFHashTypeID); + switch (__CFHashGetType(hc)) { + case __kCFHashMutable: + break; + default: + CFAssert2(__CFHashGetType(hc) != __kCFHashImmutable, __kCFLogAssertion, "%s(): immutable collection %p passed to mutating operation", __PRETTY_FUNCTION__, hc); + break; + } + hc->_mutations++; + if (0 == hc->_bucketsUsed) return; + CFAllocatorRef allocator = __CFGetAllocator(hc); + any_t *keys = hc->_keys; + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + if (__CFHashKeyIsValue(hc, keys[idx])) { + any_t oldKey = keys[idx]; + CF_OBJC_KVO_WILLCHANGE(hc, oldKey); +#if CFDictionary || CFSet + hc->_count--; +#endif +#if CFBag + hc->_count -= hc->_values[idx]; +#endif + CFAllocatorRef keysAllocator = (hc->_xflags & __kCFHashWeakKeys) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(keysAllocator, hc->_keys[idx], ~hc->_marker); +#if CFDictionary + any_t oldValue = hc->_values[idx]; + CFAllocatorRef valuesAllocator = (hc->_xflags & __kCFHashWeakValues) ? kCFAllocatorNull : allocator; + CF_WRITE_BARRIER_ASSIGN(valuesAllocator, hc->_values[idx], 0); +#endif +#if CFBag + hc->_values[idx] = 0; +#endif + hc->_bucketsUsed--; + hc->_deletes++; + CF_OBJC_KVO_DIDCHANGE(hc, oldKey); + RELEASEKEY(oldKey); +#if CFDictionary + RELEASEVALUE(oldValue); +#endif + } + } + for (CFIndex idx = 0, nbuckets = hc->_bucketsNum; idx < nbuckets; idx++) { + keys[idx] = hc->_marker; + } + hc->_deletes = 0; + hc->_bucketsUsed = 0; + hc->_count = 0; + if (__CFSetShouldShrink(hc) && (256 <= hc->_bucketsCap)) { + __CFSetGrow(hc, 128); + } +} + +#undef CF_OBJC_KVO_WILLCHANGE +#undef CF_OBJC_KVO_DIDCHANGE + diff --git a/Collections.subproj/CFSet.h b/CFSet.h similarity index 94% rename from Collections.subproj/CFSet.h rename to CFSet.h index cfeb293..7da0aea 100644 --- a/Collections.subproj/CFSet.h +++ b/CFSet.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFSet.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ /*! @header CFSet @@ -33,9 +33,7 @@ #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN /*! @typedef CFSetRetainCallBack @@ -238,13 +236,12 @@ CFSetRef CFSetCreateCopy(CFAllocatorRef allocator, CFSetRef theSet); parameter may be NULL in which case the current default CFAllocator is used. If this reference is not a valid CFAllocator, the behavior is undefined. - @param capacity The maximum number of values that can be contained - by the CFSet. The set starts empty, and can grow to this - number of values (and it can have less). If this parameter - is 0, the set's maximum capacity is unlimited (or rather, - only limited by address space and available memory - constraints). If this parameter is negative, the behavior is - undefined. + @param capacity A hint about the number of values that will be held + by the CFSet. Pass 0 for no hint. The implementation may + ignore this hint, or may use it to optimize various + operations. A set's actual capacity is only limited by + address space and available memory constraints). If this + parameter is negative, the behavior is undefined. @param callBacks A C pointer to a CFSetCallBacks structure initialized with the callbacks for the set to use on each value in the set. A copy of the contents of the @@ -285,14 +282,15 @@ CFMutableSetRef CFSetCreateMutable(CFAllocatorRef allocator, CFIndex capacity, c parameter may be NULL in which case the current default CFAllocator is used. If this reference is not a valid CFAllocator, the behavior is undefined. - @param capacity The maximum number of values that can be contained - by the CFSet. The set starts with the same values as the - set to be copied, and can grow to this number of values. - If this parameter is 0, the set's maximum capacity is - unlimited (or rather, only limited by address space and - available memory constraints). This parameter must be - greater than or equal to the count of the set which is to - be copied, or the behavior is undefined. + @param capacity A hint about the number of values that will be held + by the CFSet. Pass 0 for no hint. The implementation may + ignore this hint, or may use it to optimize various + operations. A set's actual capacity is only limited by + address space and available memory constraints). + This parameter must be greater than or equal + to the count of the set which is to be copied, or the + behavior is undefined. If this parameter is negative, the + behavior is undefined. @param theSet The set which is to be copied. The values from the set are copied as pointers into the new set (that is, the values themselves are copied, not that which the values @@ -428,8 +426,7 @@ void CFSetApplyFunction(CFSetRef theSet, CFSetApplierFunction applier, void *con Adds the value to the set if it is not already present. @param theSet The set to which the value is to be added. If this parameter is not a valid mutable CFSet, the behavior is - undefined. If the set is a fixed-capacity set and it - is full before this operation, the behavior is undefined. + undefined. @param value The value to add to the set. The value is retained by the set using the retain callback provided when the set was created. If the value is not of the sort expected by the @@ -503,9 +500,7 @@ void CFSetRemoveValue(CFMutableSetRef theSet, const void *value); CF_EXPORT void CFSetRemoveAllValues(CFMutableSetRef theSet); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFSET__ */ diff --git a/RunLoop.subproj/CFSocket.c b/CFSocket.c similarity index 67% rename from RunLoop.subproj/CFSocket.c rename to CFSocket.c index 8635d88..51a1ca7 100644 --- a/RunLoop.subproj/CFSocket.c +++ b/CFSocket.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,10 +21,12 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFSocket.c - Copyright 1999-2002, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007 Apple Inc. All rights reserved. Responsibility: Doug Davidson */ +#define _DARWIN_UNLIMITED_SELECT 1 + #include #include #include @@ -36,64 +38,20 @@ #include #include #include "CFInternal.h" -#if defined(__WIN32__) -#include -#include -// Careful with remapping these - different WinSock routines return different errors than -// on BSD, so if these are used many places they won't work. -#define EINPROGRESS WSAEINPROGRESS -#ifdef EBADF -#undef EBADF -#endif -#define EBADF WSAENOTSOCK -#elif defined(__MACH__) #include -#else -#include -#include -#include -#include -#include -#endif +#include +#include "auto_stubs.h" // 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. -// -// On Win32 we (primarily) use a v1 RunLoopSource. Code protected by USE_V1_RUN_LOOP_SOURCE currently -// assumes __WIN32__ is defined. The Win32 v1 RunLoopSource uses a Windows event object to be notified -// of socket events like FD_READ, FD_CONNECT, etc, at which point it can immediately make client -// callbacks instead of doing any inter-thread signaling. -// -// Because of the peculiar way that FD_WRITE is signalled (see WSAEventSelect doc in MSDN), we -// could not implement the current CFSocket client write callback semantics on top of the FD_WRITE -// events received by the v1 source. However, because the performance gains on the read side -// were so great with the v1 source, we use a hybrid approach to implement the write side. Read -// callbacks are triggered straightforwardly by FD_READ events. Write callbacks are triggered in -// two ways. Most commonly, as we return to the core run loop we poll a socket's writability -// using select(). If it can accept bytes, we signal our v1 RunLoopSource such that it will be -// immediately fired, and we can make the write callback. Alternatively, if the socket is full, -// we then use the old v0-style approach of notifying the SocketManager thread to listen for -// notification that the socket can accept bytes using select(). Of course these two modes also -// must respect the various write callback settings and autoenabling flags setup by the client. -// The net effect is that we rarely must interact with the SocketMgr thread, which leads to a -// performance win. -// -// Because of this hybrid, we end up needing both a v1 RunLoopSource (to watch the Windows FD_* -// events) and a v0 RunLoopSource (to be signaled from the socket manager). Since our API exports -// a single RunLoopSource that clients may schedule, we hand out the v0 RunLoopSource, and as it -// is scheduled and canceled we install the v1 RunLoopSource in the same modes. -#if defined(__WIN32__) -#define USE_V1_RUN_LOOP_SOURCE -#endif //#define LOG_CFSOCKET -#if !defined(__WIN32__) #define INVALID_SOCKET (CFSocketNativeHandle)(-1) -#endif /* __WIN32__ */ -#define MAX_SOCKADDR_LEN 256 -#define MAX_DATA_SIZE 32768 +enum { + kCFSocketLeaveErrors = 64 // candidate for publicization in future +}; static uint16_t __CFSocketDefaultNameRegistryPortNumber = 2454; @@ -106,37 +64,72 @@ CONST_STRING_DECL(kCFSocketRegisterCommand, "Register") CONST_STRING_DECL(kCFSocketRetrieveCommand, "Retrieve") CONST_STRING_DECL(__kCFSocketRegistryRequestRunLoopMode, "CFSocketRegistryRequest") +#define closesocket(a) close((a)) +#define ioctlsocket(a,b,c) ioctl((a),(b),(c)) + +CF_INLINE int __CFSocketLastError(void) { + return thread_errno(); +} + +CF_INLINE CFIndex __CFSocketFdGetSize(CFDataRef fdSet) { + return NBBY * CFDataGetLength(fdSet); +} + +CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fdSet) { + /* returns true if a change occurred, false otherwise */ + Boolean retval = false; + if (INVALID_SOCKET != sock && 0 <= sock) { + CFIndex numFds = NBBY * CFDataGetLength(fdSet); + fd_mask *fds_bits; + if (sock >= numFds) { + CFIndex oldSize = numFds / NFDBITS, newSize = (sock + NFDBITS) / NFDBITS, changeInBytes = (newSize - oldSize) * sizeof(fd_mask); + CFDataIncreaseLength(fdSet, changeInBytes); + fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet); + memset(fds_bits + oldSize, 0, changeInBytes); + } else { + fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet); + } + if (!FD_ISSET(sock, (fd_set *)fds_bits)) { + retval = true; + FD_SET(sock, (fd_set *)fds_bits); + } + } + return retval; +} + + +#define NEW_SOCKET 0 +#if NEW_SOCKET + +__private_extern__ void __CFSocketInitialize(void) {} + +#else + +#define MAX_SOCKADDR_LEN 256 +#define MAX_DATA_SIZE 65535 +#define MAX_CONNECTION_ORIENTED_DATA_SIZE 32768 + /* locks are to be acquired in the following order: (1) __CFAllSocketsLock (2) an individual CFSocket's lock (3) __CFActiveSocketsLock */ -static CFSpinLock_t __CFAllSocketsLock = 0; /* controls __CFAllSockets */ +static CFSpinLock_t __CFAllSocketsLock = CFSpinLockInit; /* controls __CFAllSockets */ static CFMutableDictionaryRef __CFAllSockets = NULL; -static CFSpinLock_t __CFActiveSocketsLock = 0; /* controls __CFRead/WriteSockets, __CFRead/WriteSocketsFds, __CFSocketManagerThread, and __CFSocketManagerIteration */ +static CFSpinLock_t __CFActiveSocketsLock = CFSpinLockInit; /* controls __CFRead/WriteSockets, __CFRead/WriteSocketsFds, __CFSocketManagerThread, and __CFSocketManagerIteration */ static volatile UInt32 __CFSocketManagerIteration = 0; static CFMutableArrayRef __CFWriteSockets = NULL; static CFMutableArrayRef __CFReadSockets = NULL; static CFMutableDataRef __CFWriteSocketsFds = NULL; static CFMutableDataRef __CFReadSocketsFds = NULL; -#if defined(__WIN32__) -// We need to select on exceptFDs on Win32 to hear of connect failures -static CFMutableDataRef __CFExceptSocketsFds = NULL; -#endif static CFDataRef zeroLengthData = NULL; +static Boolean __CFReadSocketsTimeoutInvalid = true; /* rebuild the timeout value before calling select */ static CFSocketNativeHandle __CFWakeupSocketPair[2] = {INVALID_SOCKET, INVALID_SOCKET}; static void *__CFSocketManagerThread = NULL; -#if !defined(__WIN32__) -#define CFSOCKET_USE_SOCKETPAIR -#define closesocket(a) close((a)) -#define ioctlsocket(a,b,c) ioctl((a),(b),(c)) -#endif - static CFTypeID __kCFSocketTypeID = _kCFRuntimeNotATypeID; static void __CFSocketDoCallback(CFSocketRef s, CFDataRef data, CFDataRef address, CFSocketNativeHandle sock); -static void __CFSocketInvalidate(CFSocketRef s, Boolean wakeup); struct __CFSocket { CFRuntimeBase _base; @@ -160,15 +153,18 @@ struct __CFSocket { CFMutableArrayRef _runLoops; CFSocketCallBack _callout; /* immutable */ CFSocketContext _context; /* immutable */ -#if !defined(USE_V1_RUN_LOOP_SOURCE) - CFIndex _maxQueueLen; // queues to pass data from SocketMgr thread - CFMutableArrayRef _dataQueue; + CFMutableArrayRef _dataQueue; // queues to pass data from SocketMgr thread CFMutableArrayRef _addressQueue; -#else - CFRunLoopSourceRef _source1; // v1 RLS, triggered by _event happenings - HANDLE _event; // used to hear about socket events - long _oldEventMask; // last event mask value set with WSAEventSelect -#endif + + struct timeval _readBufferTimeout; + CFMutableDataRef _readBuffer; + CFIndex _bytesToBuffer; /* is length of _readBuffer */ + CFIndex _bytesToBufferPos; /* where the next _CFSocketRead starts from */ + CFIndex _bytesToBufferReadPos; /* Where the buffer will next be read into (always after _bytesToBufferPos, but less than _bytesToBuffer) */ + Boolean _atEOF; + int _bufferedReadError; + + CFMutableDataRef _leftoverBytes; }; /* Bit 6 in the base reserved bits is used for write-signalled state (mutable) */ @@ -178,51 +174,51 @@ struct __CFSocket { /* Of this, bits 0-1 are used for the read callback type. */ CF_INLINE Boolean __CFSocketIsWriteSignalled(CFSocketRef s) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_info, 6, 6); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 6, 6); } CF_INLINE void __CFSocketSetWriteSignalled(CFSocketRef s) { - __CFBitfieldSetValue(((CFRuntimeBase *)s)->_info, 6, 6, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 6, 6, 1); } CF_INLINE void __CFSocketUnsetWriteSignalled(CFSocketRef s) { - __CFBitfieldSetValue(((CFRuntimeBase *)s)->_info, 6, 6, 0); + __CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 6, 6, 0); } CF_INLINE Boolean __CFSocketIsReadSignalled(CFSocketRef s) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_info, 5, 5); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 5, 5); } CF_INLINE void __CFSocketSetReadSignalled(CFSocketRef s) { - __CFBitfieldSetValue(((CFRuntimeBase *)s)->_info, 5, 5, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 5, 5, 1); } CF_INLINE void __CFSocketUnsetReadSignalled(CFSocketRef s) { - __CFBitfieldSetValue(((CFRuntimeBase *)s)->_info, 5, 5, 0); + __CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 5, 5, 0); } CF_INLINE Boolean __CFSocketIsValid(CFSocketRef s) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_info, 4, 4); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 4, 4); } CF_INLINE void __CFSocketSetValid(CFSocketRef s) { - __CFBitfieldSetValue(((CFRuntimeBase *)s)->_info, 4, 4, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 4, 4, 1); } CF_INLINE void __CFSocketUnsetValid(CFSocketRef s) { - __CFBitfieldSetValue(((CFRuntimeBase *)s)->_info, 4, 4, 0); + __CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 4, 4, 0); } CF_INLINE uint8_t __CFSocketCallBackTypes(CFSocketRef s) { - return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_info, 3, 0); + return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 3, 0); } CF_INLINE uint8_t __CFSocketReadCallBackType(CFSocketRef s) { - return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_info, 1, 0); + return (uint8_t)__CFBitfieldGetValue(((const CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 1, 0); } CF_INLINE void __CFSocketSetCallBackTypes(CFSocketRef s, uint8_t types) { - __CFBitfieldSetValue(((CFRuntimeBase *)s)->_info, 3, 0, types & 0xF); + __CFBitfieldSetValue(((CFRuntimeBase *)s)->_cfinfo[CF_INFO_BITS], 3, 0, types & 0xF); } CF_INLINE void __CFSocketLock(CFSocketRef s) { @@ -233,14 +229,6 @@ CF_INLINE void __CFSocketUnlock(CFSocketRef s) { __CFSpinUnlock(&(s->_lock)); } -CF_INLINE void __CFSocketWriteLock(CFSocketRef s) { - __CFSpinLock(&(s->_writeLock)); -} - -CF_INLINE void __CFSocketWriteUnlock(CFSocketRef s) { - __CFSpinUnlock(&(s->_writeLock)); -} - CF_INLINE Boolean __CFSocketIsConnectionOriented(CFSocketRef s) { return (SOCK_STREAM == s->_socketType || SOCK_SEQPACKET == s->_socketType); } @@ -253,7 +241,7 @@ CF_INLINE void __CFSocketEstablishAddress(CFSocketRef s) { /* socket should already be locked */ uint8_t name[MAX_SOCKADDR_LEN]; int namelen = sizeof(name); - if (__CFSocketIsValid(s) && NULL == s->_address && INVALID_SOCKET != s->_socket && 0 == getsockname(s->_socket, (struct sockaddr *)name, &namelen) && NULL != name && 0 < namelen) { + if (__CFSocketIsValid(s) && NULL == s->_address && INVALID_SOCKET != s->_socket && 0 == getsockname(s->_socket, (struct sockaddr *)name, (socklen_t *)&namelen) && NULL != name && 0 < namelen) { s->_address = CFDataCreate(CFGetAllocator(s), name, namelen); } } @@ -262,84 +250,20 @@ CF_INLINE void __CFSocketEstablishPeerAddress(CFSocketRef s) { /* socket should already be locked */ uint8_t name[MAX_SOCKADDR_LEN]; int namelen = sizeof(name); - if (__CFSocketIsValid(s) && NULL == s->_peerAddress && INVALID_SOCKET != s->_socket && 0 == getpeername(s->_socket, (struct sockaddr *)name, &namelen) && NULL != name && 0 < namelen) { + if (__CFSocketIsValid(s) && NULL == s->_peerAddress && INVALID_SOCKET != s->_socket && 0 == getpeername(s->_socket, (struct sockaddr *)name, (socklen_t *)&namelen) && NULL != name && 0 < namelen) { s->_peerAddress = CFDataCreate(CFGetAllocator(s), name, namelen); } } -CF_INLINE CFIndex __CFSocketFdGetSize(CFDataRef fdSet) { -#if defined(__WIN32__) - fd_set* set = (fd_set*)CFDataGetBytePtr(fdSet); - return set ? set->fd_count : 0; -#else - return NBBY * CFDataGetLength(fdSet); -#endif -} - -CF_INLINE int __CFSocketLastError(void) { -#if defined(__WIN32__) - return WSAGetLastError(); -#else - return thread_errno(); -#endif -} - static Boolean __CFNativeSocketIsValid(CFSocketNativeHandle sock) { -#if defined(__WIN32__) - SInt32 errorCode = 0; - int errorSize = sizeof(errorCode); - return !(0 != getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&errorCode, &errorSize) && WSAGetLastError() == WSAENOTSOCK); -#else SInt32 flags = fcntl(sock, F_GETFL, 0); return !(0 > flags && EBADF == thread_errno()); -#endif -} - -CF_INLINE Boolean __CFSocketFdSet(CFSocketNativeHandle sock, CFMutableDataRef fdSet) { - /* returns true if a change occurred, false otherwise */ - Boolean retval = false; - if (INVALID_SOCKET != sock && 0 <= sock) { -#if defined(__WIN32__) - fd_set* set = (fd_set*)CFDataGetMutableBytePtr(fdSet); - if ((set->fd_count * sizeof(SOCKET) + sizeof(u_int)) >= CFDataGetLength(fdSet)) { - CFDataIncreaseLength(fdSet, sizeof(SOCKET)); - set = (fd_set*)CFDataGetMutableBytePtr(fdSet); - } - if (!FD_ISSET(sock, set)) { - retval = true; - FD_SET(sock, set); - } -#else - CFIndex numFds = NBBY * CFDataGetLength(fdSet); - fd_mask *fds_bits; - if (sock >= numFds) { - CFIndex oldSize = numFds / NFDBITS, newSize = (sock + NFDBITS) / NFDBITS, changeInBytes = (newSize - oldSize) * sizeof(fd_mask); - CFDataIncreaseLength(fdSet, changeInBytes); - fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet); - memset(fds_bits + oldSize, 0, changeInBytes); - } else { - fds_bits = (fd_mask *)CFDataGetMutableBytePtr(fdSet); - } - if (!FD_ISSET(sock, (fd_set *)fds_bits)) { - retval = true; - FD_SET(sock, (fd_set *)fds_bits); - } -#endif - } - return retval; } CF_INLINE Boolean __CFSocketFdClr(CFSocketNativeHandle sock, CFMutableDataRef fdSet) { /* returns true if a change occurred, false otherwise */ Boolean retval = false; if (INVALID_SOCKET != sock && 0 <= sock) { -#if defined(__WIN32__) - fd_set* set = (fd_set*)CFDataGetMutableBytePtr(fdSet); - if (FD_ISSET(sock, set)) { - retval = true; - FD_CLR(sock, set); - } -#else CFIndex numFds = NBBY * CFDataGetLength(fdSet); fd_mask *fds_bits; if (sock < numFds) { @@ -349,78 +273,15 @@ CF_INLINE Boolean __CFSocketFdClr(CFSocketNativeHandle sock, CFMutableDataRef fd FD_CLR(sock, (fd_set *)fds_bits); } } -#endif } return retval; } static SInt32 __CFSocketCreateWakeupSocketPair(void) { -#if defined(CFSOCKET_USE_SOCKETPAIR) return socketpair(PF_LOCAL, SOCK_DGRAM, 0, __CFWakeupSocketPair); -#else - //??? should really use native Win32 facilities - 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; - } - return error; -#endif -} - -#if defined(USE_V1_RUN_LOOP_SOURCE) -// Version 1 RunLoopSources set a mask in a Windows System Event to control what socket activity we -// hear about. Because you can only set the mask as a whole, we must remember the previous value so -// set can make relative changes to it. The way we enable/disable precludes calculating the whole -// mask from scratch from the current state we keep. - -static Boolean __CFSocketSetWholeEventMask(CFSocketRef s, long newMask) { - if (s->_oldEventMask != newMask) { - int err; -#if defined(LOG_CFSOCKET) - fprintf(stdout, "calling WSAEventSelect for socket/event %d/%d with event flags 0x%lx\n", s->_socket, (int)s->_event, newMask); -#endif - err = WSAEventSelect(s->_socket, s->_event, newMask); - CFAssert2(0 == err, __kCFLogAssertion, "%s(): WSAEventSelect failed: %d", __PRETTY_FUNCTION__, WSAGetLastError()); - s->_oldEventMask = newMask; - return TRUE; - } else - return FALSE; -} - -CF_INLINE Boolean __CFSocketSetFDForRead(CFSocketRef s) { - long bitToSet; - // we assume that some read bits are set - all callers have checked this - CFAssert1(0 != __CFSocketReadCallBackType(s), __kCFLogAssertion, "%s(): __CFSocketReadCallBackType is zero", __PRETTY_FUNCTION__); - bitToSet = (__CFSocketReadCallBackType(s) == kCFSocketAcceptCallBack) ? FD_ACCEPT : FD_READ; - return __CFSocketSetWholeEventMask(s, s->_oldEventMask | bitToSet); } -CF_INLINE Boolean __CFSocketClearFDForRead(CFSocketRef s) { - long bitToClear; - // we assume that some read bits are set - all callers have checked this - CFAssert1(0 != __CFSocketReadCallBackType(s), __kCFLogAssertion, "%s(): __CFSocketReadCallBackType is zero", __PRETTY_FUNCTION__); - bitToClear = (__CFSocketReadCallBackType(s) == kCFSocketAcceptCallBack) ? FD_ACCEPT : FD_READ; - return __CFSocketSetWholeEventMask(s, s->_oldEventMask & ~bitToClear); -} -#else // !USE_V1_RUN_LOOP_SOURCE // Version 0 RunLoopSources set a mask in an FD set to control what socket activity we hear about. CF_INLINE Boolean __CFSocketSetFDForRead(CFSocketRef s) { return __CFSocketFdSet(s->_socket, __CFReadSocketsFds); @@ -429,7 +290,6 @@ CF_INLINE Boolean __CFSocketSetFDForRead(CFSocketRef s) { CF_INLINE Boolean __CFSocketClearFDForRead(CFSocketRef s) { return __CFSocketFdClr(s->_socket, __CFReadSocketsFds); } -#endif CF_INLINE Boolean __CFSocketSetFDForWrite(CFSocketRef s) { return __CFSocketFdSet(s->_socket, __CFWriteSocketsFds); @@ -439,87 +299,6 @@ CF_INLINE Boolean __CFSocketClearFDForWrite(CFSocketRef s) { return __CFSocketFdClr(s->_socket, __CFWriteSocketsFds); } -#if defined(USE_V1_RUN_LOOP_SOURCE) -static Boolean __CFSocketCanAcceptBytes(CFSocketRef s) { - struct timeval timeout = {0, 0}; - fd_set set; - int result; - FD_ZERO(&set); - FD_SET(s->_socket, &set); - result = select(s->_socket + 1, NULL, &set, NULL, &timeout); -#if defined(LOG_CFSOCKET) - fprintf(stdout, "polling writability of %d yields %d\n", s->_socket, result); -#endif - return result == 1; -} - -static Boolean __CFSocketHasBytesToRead(CFSocketRef s) { - unsigned long avail; - int err = ioctlsocket(s->_socket, FIONREAD, &avail); - CFAssert3(0 == err, __kCFLogAssertion, "%s(): unexpected error from ioctlsocket(%d, FIONREAD,...): %d", __PRETTY_FUNCTION__, s->_socket, WSAGetLastError()); -#if defined(LOG_CFSOCKET) - fprintf(stdout, "polling readability of %d yields %ld\n", s->_socket, avail); -#endif - return (0 == err) && avail > 0; -} -#endif - -#if defined(__WIN32__) -static Boolean WinSockUsed = FALSE; - -static void __CFSocketInitializeWinSock_Guts(void) { - if (!WinSockUsed) { - WinSockUsed = TRUE; - WORD versionRequested = MAKEWORD(2, 0); - WSADATA wsaData; - int errorStatus = WSAStartup(versionRequested, &wsaData); - if (errorStatus != 0 || LOBYTE(wsaData.wVersion) != LOBYTE(versionRequested) || HIBYTE(wsaData.wVersion) != HIBYTE(versionRequested)) { - WSACleanup(); - CFLog(0, CFSTR("*** Could not initialize WinSock subsystem!!!")); - } - } -} - -CF_EXPORT void __CFSocketInitializeWinSock(void) { - __CFSpinLock(&__CFActiveSocketsLock); - __CFSocketInitializeWinSock_Guts(); - __CFSpinUnlock(&__CFActiveSocketsLock); -} - -__private_extern__ void __CFSocketCleanup(void) { - __CFSpinLock(&__CFActiveSocketsLock); - if (NULL != __CFReadSockets) { - CFRelease(__CFWriteSockets); - __CFWriteSockets = NULL; - CFRelease(__CFReadSockets); - __CFReadSockets = NULL; - CFRelease(__CFWriteSocketsFds); - __CFWriteSocketsFds = NULL; - CFRelease(__CFReadSocketsFds); - __CFReadSocketsFds = NULL; - CFRelease(__CFExceptSocketsFds); - __CFExceptSocketsFds = NULL; - CFRelease(zeroLengthData); - zeroLengthData = NULL; - } - if (NULL != __CFAllSockets) { - CFRelease(__CFAllSockets); - __CFAllSockets = NULL; - } - 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) { - WSACleanup(); - } - __CFSpinUnlock(&__CFActiveSocketsLock); -} -#endif // CFNetwork needs to call this, especially for Win32 to get WSAStartup static void __CFSocketInitializeSockets(void) { @@ -528,16 +307,8 @@ static void __CFSocketInitializeSockets(void) { __CFWriteSocketsFds = CFDataCreateMutable(kCFAllocatorSystemDefault, 0); __CFReadSocketsFds = CFDataCreateMutable(kCFAllocatorSystemDefault, 0); zeroLengthData = CFDataCreateMutable(kCFAllocatorSystemDefault, 0); -#if defined(__WIN32__) - __CFSocketInitializeWinSock_Guts(); - // make sure we have space for the count field and the first socket - CFDataIncreaseLength(__CFWriteSocketsFds, sizeof(u_int) + sizeof(SOCKET)); - CFDataIncreaseLength(__CFReadSocketsFds, sizeof(u_int) + sizeof(SOCKET)); - __CFExceptSocketsFds = CFDataCreateMutable(kCFAllocatorSystemDefault, 0); - CFDataIncreaseLength(__CFExceptSocketsFds, sizeof(u_int) + sizeof(SOCKET)); -#endif if (0 > __CFSocketCreateWakeupSocketPair()) { - CFLog(0, CFSTR("*** Could not create wakeup socket pair for CFSocket!!!")); + CFLog(kCFLogLevelWarning, CFSTR("*** Could not create wakeup socket pair for CFSocket!!!")); } else { UInt32 yes = 1; /* wakeup sockets must be non-blocking */ @@ -600,10 +371,10 @@ static void __CFSocketHandleWrite(CFSocketRef s, Boolean callBackNow) { CFOptionFlags writeCallBacksAvailable; if (!CFSocketIsValid(s)) return; - if (0 != getsockopt(s->_socket, SOL_SOCKET, SO_ERROR, (void *)&errorCode, &errorSize)) errorCode = 0; // cast for WinSock bad API + 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 defined(LOG_CFSOCKET) if (errorCode) fprintf(stdout, "error %ld on socket %d\n", errorCode, s->_socket); -#endif +#endif /* LOG_CFSOCKET */ __CFSocketLock(s); writeCallBacksAvailable = __CFSocketCallBackTypes(s) & (kCFSocketWriteCallBack | kCFSocketConnectCallBack); if ((s->_f.client & kCFSocketConnectCallBack) != 0) writeCallBacksAvailable &= ~kCFSocketConnectCallBack; @@ -615,7 +386,7 @@ static void __CFSocketHandleWrite(CFSocketRef s, Boolean callBackNow) { __CFSocketSetWriteSignalled(s); #if defined(LOG_CFSOCKET) fprintf(stdout, "write signaling source for socket %d\n", s->_socket); -#endif +#endif /* LOG_CFSOCKET */ if (callBackNow) { __CFSocketDoCallback(s, NULL, NULL, 0); } else { @@ -630,18 +401,26 @@ static void __CFSocketHandleWrite(CFSocketRef s, Boolean callBackNow) { } } -static void __CFSocketHandleRead(CFSocketRef s) { +static void __CFSocketHandleRead(CFSocketRef s, Boolean causedByTimeout) +{ CFDataRef data = NULL, address = NULL; CFSocketNativeHandle sock = INVALID_SOCKET; if (!CFSocketIsValid(s)) return; if (__CFSocketReadCallBackType(s) == kCFSocketDataCallBack) { - uint8_t buffer[MAX_DATA_SIZE]; + uint8_t bufferArray[MAX_CONNECTION_ORIENTED_DATA_SIZE], *buffer; uint8_t name[MAX_SOCKADDR_LEN]; int namelen = sizeof(name); - SInt32 recvlen = recvfrom(s->_socket, buffer, sizeof(buffer), 0, (struct sockaddr *)name, &namelen); + 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); + } else { + buffer = malloc(MAX_DATA_SIZE); + if (buffer) recvlen = recvfrom(s->_socket, 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); -#endif +#endif /* LOG_CFSOCKET */ if (0 >= recvlen) { //??? should return error if <0 /* zero-length data is the signal for perform to invalidate */ @@ -649,6 +428,7 @@ static void __CFSocketHandleRead(CFSocketRef s) { } else { data = CFDataCreate(CFGetAllocator(s), buffer, recvlen); } + if (buffer && buffer != bufferArray) free(buffer); __CFSocketLock(s); if (!__CFSocketIsValid(s)) { CFRelease(data); @@ -666,7 +446,6 @@ static void __CFSocketHandleRead(CFSocketRef s) { if (NULL == address) { address = CFRetain(zeroLengthData); } -#if !defined(USE_V1_RUN_LOOP_SOURCE) if (NULL == s->_dataQueue) { s->_dataQueue = CFArrayCreateMutable(CFGetAllocator(s), 0, &kCFTypeArrayCallBacks); } @@ -677,13 +456,9 @@ static void __CFSocketHandleRead(CFSocketRef s) { CFRelease(data); CFArrayAppendValue(s->_addressQueue, address); CFRelease(address); -#endif // !USE_V1_RUN_LOOP_SOURCE if (0 < recvlen && (s->_f.client & kCFSocketDataCallBack) != 0 && (s->_f.disabled & kCFSocketDataCallBack) == 0 && __CFSocketIsScheduled(s) -#if !defined(USE_V1_RUN_LOOP_SOURCE) - && (0 == s->_maxQueueLen || CFArrayGetCount(s->_dataQueue) < s->_maxQueueLen) -#endif // !USE_V1_RUN_LOOP_SOURCE ) { __CFSpinLock(&__CFActiveSocketsLock); /* restore socket to fds */ @@ -693,7 +468,7 @@ static void __CFSocketHandleRead(CFSocketRef s) { } else if (__CFSocketReadCallBackType(s) == kCFSocketAcceptCallBack) { uint8_t name[MAX_SOCKADDR_LEN]; int namelen = sizeof(name); - sock = accept(s->_socket, (struct sockaddr *)name, &namelen); + sock = accept(s->_socket, (struct sockaddr *)name, (socklen_t *)&namelen); if (INVALID_SOCKET == sock) { //??? should return error return; @@ -711,22 +486,17 @@ static void __CFSocketHandleRead(CFSocketRef s) { return; } __CFSocketSetReadSignalled(s); -#if !defined(USE_V1_RUN_LOOP_SOURCE) if (NULL == s->_dataQueue) { s->_dataQueue = CFArrayCreateMutable(CFGetAllocator(s), 0, NULL); } if (NULL == s->_addressQueue) { s->_addressQueue = CFArrayCreateMutable(CFGetAllocator(s), 0, &kCFTypeArrayCallBacks); } - CFArrayAppendValue(s->_dataQueue, (void *)sock); + CFArrayAppendValue(s->_dataQueue, (void *)(uintptr_t)sock); CFArrayAppendValue(s->_addressQueue, address); CFRelease(address); -#endif // !USE_V1_RUN_LOOP_SOURCE if ((s->_f.client & kCFSocketAcceptCallBack) != 0 && (s->_f.disabled & kCFSocketAcceptCallBack) == 0 && __CFSocketIsScheduled(s) -#if !defined(USE_V1_RUN_LOOP_SOURCE) - && (0 == s->_maxQueueLen || CFArrayGetCount(s->_dataQueue) < s->_maxQueueLen) -#endif // !USE_V1_RUN_LOOP_SOURCE ) { __CFSpinLock(&__CFActiveSocketsLock); /* restore socket to fds */ @@ -739,18 +509,80 @@ static void __CFSocketHandleRead(CFSocketRef s) { __CFSocketUnlock(s); return; } - __CFSocketSetReadSignalled(s); + + if (causedByTimeout) { +#if defined(LOG_CFSOCKET) + fprintf(stdout, "TIMEOUT RECEIVED - WILL SIGNAL IMMEDIATELY TO FLUSH (%d buffered)\n", s->_bytesToBufferPos); +#endif /* LOG_CFSOCKET */ + /* we've got a timeout, but no bytes read. Ignore the timeout. */ + if (s->_bytesToBufferPos == 0) { +#if defined(LOG_CFSOCKET) + fprintf(stdout, "TIMEOUT - but no bytes, restoring to active set\n"); + fflush(stdout); +#endif + + __CFSpinLock(&__CFActiveSocketsLock); + /* restore socket to fds */ + __CFSocketSetFDForRead(s); + __CFSpinUnlock(&__CFActiveSocketsLock); + __CFSocketUnlock(s); + return; + } + } else if (s->_bytesToBuffer != 0 && ! s->_atEOF) { + UInt8* base; + CFIndex ctRead; + CFIndex ctRemaining = s->_bytesToBuffer - s->_bytesToBufferPos; + + /* if our buffer has room, we go ahead and buffer */ + if (ctRemaining > 0) { + base = CFDataGetMutableBytePtr(s->_readBuffer); + + do { + ctRead = read(CFSocketGetNative(s), &base[s->_bytesToBufferPos], ctRemaining); + } while (ctRead == -1 && errno == EAGAIN); + + switch (ctRead) { + case -1: + s->_bufferedReadError = errno; + s->_atEOF = true; +#if defined(LOG_CFSOCKET) + fprintf(stderr, "BUFFERED READ GOT ERROR %d\n", errno); +#endif /* LOG_CFSOCKET */ + break; + + case 0: + #if defined(LOG_CFSOCKET) + fprintf(stdout, "DONE READING (EOF) - GOING TO SIGNAL\n"); + #endif /* LOG_CFSOCKET */ + s->_atEOF = true; + break; + + default: + 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); + #endif /* LOG_CFSOCKET */ + __CFSpinLock(&__CFActiveSocketsLock); + /* restore socket to fds */ + __CFSocketSetFDForRead(s); + __CFSpinUnlock(&__CFActiveSocketsLock); + __CFSocketUnlock(s); + return; + } else { + #if defined(LOG_CFSOCKET) + fprintf(stdout, "DONE READING (read %d bytes) - GOING TO SIGNAL\n", ctRead); + #endif /* LOG_CFSOCKET */ + } + } + } + } + + __CFSocketSetReadSignalled(s); } #if defined(LOG_CFSOCKET) fprintf(stdout, "read signaling source for socket %d\n", s->_socket); -#endif -#if defined(USE_V1_RUN_LOOP_SOURCE) - // since in the v0 case data and sock come from the same queue, only one could be set - CFAssert1(NULL == data || 0 == sock, __kCFLogAssertion, "%s(): both data and sock are set", __PRETTY_FUNCTION__); - __CFSocketDoCallback(s, data, address, sock); // does __CFSocketUnlock(s) - if (NULL != data) CFRelease(data); - if (NULL != address) CFRelease(address); -#else +#endif /* LOG_CFSOCKET */ CFRunLoopSourceSignal(s->_source0); CFRunLoopRef rl = __CFSocketCopyRunLoopToWakeUp(s); __CFSocketUnlock(s); @@ -758,7 +590,225 @@ static void __CFSocketHandleRead(CFSocketRef s) { CFRunLoopWakeUp(rl); CFRelease(rl); } -#endif // !USE_V1_RUN_LOOP_SOURCE +} + +static struct timeval* intervalToTimeval(CFTimeInterval timeout, struct timeval* tv) +{ + if (timeout == 0.0) + timerclear(tv); + else { + tv->tv_sec = (0 >= timeout || INT_MAX <= timeout) ? INT_MAX : (int)(float)floor(timeout); + tv->tv_usec = (int)((timeout - floor(timeout)) * 1.0E6); + } + return tv; +} + +/* note that this returns a pointer to the min value, which won't have changed during + the dictionary apply, since we've got the active sockets lock held */ +static void _calcMinTimeout_locked(const void* val, void* ctxt) +{ + CFSocketRef s = (CFSocketRef) val; + struct timeval** minTime = (struct timeval**) ctxt; + if (timerisset(&s->_readBufferTimeout) && (*minTime == NULL || timercmp(&s->_readBufferTimeout, *minTime, <))) + *minTime = &s->_readBufferTimeout; +} + +void __CFSocketSetReadBufferTimeout(CFSocketRef s, CFTimeInterval timeout) +{ + struct timeval timeoutVal; + + intervalToTimeval(timeout, &timeoutVal); + + /* lock ordering is socket lock, activesocketslock */ + /* activesocketslock protects our timeout calculation */ + __CFSocketLock(s); + __CFSpinLock(&__CFActiveSocketsLock); + if (timercmp(&s->_readBufferTimeout, &timeoutVal, !=)) { + s->_readBufferTimeout = timeoutVal; + __CFReadSocketsTimeoutInvalid = true; + } + __CFSpinUnlock(&__CFActiveSocketsLock); + __CFSocketUnlock(s); +} + +void __CFSocketSetReadBufferLength(CFSocketRef s, CFIndex length) +{ + __CFSocketLock(s); + if (s->_bytesToBuffer != length) { + if (s->_bytesToBufferPos != 0 && s->_bytesToBufferReadPos != 0) { + /* As originally envisaged, you were supposed to be sure to drain the buffer before + * issuing another request on the socket. In practice, there seem to be times when we want to re-use + * the stream (or perhaps, are on our way to closing it out) and this policy doesn't work so well. + * So, if someone changes the buffer size while we have bytes already buffered, we put them + * aside and use them to satisfy any subsequent reads. + */ +#if defined(DEBUG) + fprintf(stderr, "%s(%d): WARNING: shouldn't set read buffer length while data is still in the read buffer\n\n", __FUNCTION__, __LINE__); +#endif + if (s->_leftoverBytes == NULL) + s->_leftoverBytes = CFDataCreateMutable(CFGetAllocator(s), 0); + + /* append the current buffered bytes over. We'll keep draining _leftoverBytes while we have them... */ + CFDataAppendBytes(s->_leftoverBytes, CFDataGetBytePtr(s->_readBuffer) + s->_bytesToBufferPos, s->_bytesToBufferReadPos - s->_bytesToBufferPos); + CFRelease(s->_readBuffer); + s->_readBuffer = NULL; + + s->_bytesToBuffer = 0; + s->_bytesToBufferPos = 0; + s->_bytesToBufferReadPos = 0; + } + if (length == 0) { + s->_bytesToBuffer = 0; + s->_bytesToBufferPos = 0; + s->_bytesToBufferReadPos = 0; + if (s->_readBuffer) { + CFRelease(s->_readBuffer); + s->_readBuffer = NULL; + } + } else { + /* if the buffer shrank, we can re-use the old one */ + if (length > s->_bytesToBuffer) { + if (s->_readBuffer) { + CFRelease(s->_readBuffer); + s->_readBuffer = NULL; + } + } + + s->_bytesToBuffer = length; + s->_bytesToBufferPos = 0; + s->_bytesToBufferReadPos = 0; + if (s->_readBuffer == NULL) { + s->_readBuffer = CFDataCreateMutable(kCFAllocatorDefault, length); + CFDataSetLength(s->_readBuffer, length); + } + } + } + __CFSocketUnlock(s); + if (length == 0) + __CFSocketSetReadBufferTimeout(s, 0.0); +} + +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); +#endif /* LOG_CFSOCKET */ + + CFIndex result = -1; + + __CFSocketLock(s); + + *error = 0; + + /* Any leftover buffered bytes? */ + if (s->_leftoverBytes) { + CFIndex ctBuffer = CFDataGetLength(s->_leftoverBytes); +#if defined(DEBUG) + fprintf(stderr, "%s(%d): WARNING: Draining %d leftover bytes first\n\n", __FUNCTION__, __LINE__, ctBuffer); +#endif + if (ctBuffer > length) + ctBuffer = length; + memcpy(buffer, CFDataGetBytePtr(s->_leftoverBytes), ctBuffer); + if (ctBuffer < CFDataGetLength(s->_leftoverBytes)) + CFDataReplaceBytes(s->_leftoverBytes, CFRangeMake(0, ctBuffer), NULL, 0); + else { + CFRelease(s->_leftoverBytes); + s->_leftoverBytes = NULL; + } + result = ctBuffer; + goto unlock; + } + + /* return whatever we've buffered */ + if (s->_bytesToBuffer != 0) { + CFIndex ctBuffer = s->_bytesToBufferPos - s->_bytesToBufferReadPos; + if (ctBuffer > 0) { + /* drain our buffer first */ + if (ctBuffer > length) + ctBuffer = length; + memcpy(buffer, CFDataGetBytePtr(s->_readBuffer) + s->_bytesToBufferReadPos, ctBuffer); + s->_bytesToBufferReadPos += ctBuffer; + if (s->_bytesToBufferReadPos == s->_bytesToBufferPos) { +#if defined(LOG_CFSOCKET) + fprintf(stdout, "DRAINED BUFFER - SHOULD START BUFFERING AGAIN!\n"); +#endif /* LOG_CFSOCKET */ + s->_bytesToBufferPos = 0; + s->_bytesToBufferReadPos = 0; + } + +#if defined(LOG_CFSOCKET) + fprintf(stdout, "SLURPED %d BYTES FROM BUFFER %d LEFT TO READ!\n", ctBuffer, length); +#endif /* LOG_CFSOCKET */ + + result = ctBuffer; + goto unlock; + } + } + /* nothing buffered, or no buffer selected */ + + /* Did we get an error on a previous read (or buffered read)? */ + if (s->_bufferedReadError != 0) { +#if defined(LOG_CFSOCKET) + fprintf(stdout, "RETURNING ERROR %d\n", s->_bufferedReadError); +#endif /* LOG_CFSOCKET */ + *error = s->_bufferedReadError; + result = -1; + goto unlock; + } + + /* nothing buffered, if we've hit eof, don't bother reading any more */ + if (s->_atEOF) { +#if defined(LOG_CFSOCKET) + fprintf(stdout, "RETURNING EOF\n"); +#endif /* LOG_CFSOCKET */ + result = 0; + goto unlock; + } + + /* normal read */ + result = read(CFSocketGetNative(s), buffer, length); +#if defined(LOG_CFSOCKET) + fprintf(stdout, "READ %d bytes", result); +#endif /* LOG_CFSOCKET */ + + if (result == 0) { + /* note that we hit EOF */ + s->_atEOF = true; + } else if (result < 0) { + *error = errno; + + /* if it wasn't EAGAIN, record it (although we shouldn't get called again) */ + if (*error != EAGAIN) { + s->_bufferedReadError = *error; + } + } + +unlock: + __CFSocketUnlock(s); + + return result; +} + +Boolean __CFSocketGetBytesAvailable(CFSocketRef s, CFIndex* ctBytesAvailable) +{ + CFIndex ctBuffer = s->_bytesToBufferPos - s->_bytesToBufferReadPos; + if (ctBuffer != 0) { + *ctBytesAvailable = ctBuffer; + return true; + } else { + int result; +#if ! defined(__WIN32__) + 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; + return true; + } } #if defined(LOG_CFSOCKET) @@ -774,30 +824,30 @@ static void __CFSocketWriteSocketList(CFArrayRef sockets, CFDataRef fdSet, Boole } } } -#endif +#endif /* LOG_CFSOCKET */ #ifdef __GNUC__ __attribute__ ((noreturn)) // mostly interesting for shutting up a warning -#endif +#endif /* __GNUC__ */ static void __CFSocketManager(void * arg) { + if (objc_collecting_enabled()) auto_zone_register_thread(auto_zone()); SInt32 nrfds, maxnrfds, fdentries = 1; SInt32 rfds, wfds; -#if defined(__WIN32__) - fd_set *exceptfds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(SOCKET) + sizeof(u_int), 0); - fd_set *writefds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(SOCKET) + sizeof(u_int), 0); - fd_set *readfds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(SOCKET) + sizeof(u_int), 0); -#else fd_set *exceptfds = NULL; fd_set *writefds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(fd_mask), 0); fd_set *readfds = (fd_set *)CFAllocatorAllocate(kCFAllocatorSystemDefault, fdentries * sizeof(fd_mask), 0); -#endif fd_set *tempfds; SInt32 idx, cnt; uint8_t buffer[256]; CFMutableArrayRef selectedWriteSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); CFMutableArrayRef selectedReadSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + CFIndex selectedWriteSocketsIndex = 0, selectedReadSocketsIndex = 0; + struct timeval tv; + struct timeval* pTimeout = NULL; + struct timeval timeBeforeSelect; + for (;;) { __CFSpinLock(&__CFActiveSocketsLock); __CFSocketManagerIteration++; @@ -807,30 +857,12 @@ static void __CFSocketManager(void * arg) if (0 < CFArrayGetCount(__CFWriteSockets)) { fprintf(stdout, " and write sockets "); __CFSocketWriteSocketList(__CFWriteSockets, __CFWriteSocketsFds, FALSE); -#if defined(__WIN32__) - fprintf(stdout, " and except sockets "); - __CFSocketWriteSocketList(__CFWriteSockets, __CFExceptSocketsFds, TRUE); -#endif } fprintf(stdout, "\n"); -#endif +#endif /* LOG_CFSOCKET */ rfds = __CFSocketFdGetSize(__CFReadSocketsFds); wfds = __CFSocketFdGetSize(__CFWriteSocketsFds); maxnrfds = __CFMax(rfds, wfds); -#if defined(__WIN32__) - if (maxnrfds > fdentries) { - fdentries = maxnrfds; - exceptfds = (fd_set *)CFAllocatorReallocate(kCFAllocatorSystemDefault, exceptfds, fdentries * sizeof(SOCKET) + sizeof(u_int), 0); - writefds = (fd_set *)CFAllocatorReallocate(kCFAllocatorSystemDefault, writefds, fdentries * sizeof(SOCKET) + sizeof(u_int), 0); - readfds = (fd_set *)CFAllocatorReallocate(kCFAllocatorSystemDefault, readfds, fdentries * sizeof(SOCKET) + sizeof(u_int), 0); - } - memset(exceptfds, 0, fdentries * sizeof(SOCKET) + sizeof(u_int)); - memset(writefds, 0, fdentries * sizeof(SOCKET) + sizeof(u_int)); - memset(readfds, 0, fdentries * sizeof(SOCKET) + sizeof(u_int)); - CFDataGetBytes(__CFExceptSocketsFds, CFRangeMake(0, __CFSocketFdGetSize(__CFExceptSocketsFds) * sizeof(SOCKET) + sizeof(u_int)), (UInt8 *)exceptfds); - CFDataGetBytes(__CFWriteSocketsFds, CFRangeMake(0, wfds * sizeof(SOCKET) + sizeof(u_int)), (UInt8 *)writefds); - CFDataGetBytes(__CFReadSocketsFds, CFRangeMake(0, rfds * sizeof(SOCKET) + sizeof(u_int)), (UInt8 *)readfds); -#else if (maxnrfds > fdentries * (int)NFDBITS) { fdentries = (maxnrfds + NFDBITS - 1) / NFDBITS; writefds = (fd_set *)CFAllocatorReallocate(kCFAllocatorSystemDefault, writefds, fdentries * sizeof(fd_mask), 0); @@ -840,19 +872,94 @@ static void __CFSocketManager(void * arg) memset(readfds, 0, fdentries * sizeof(fd_mask)); CFDataGetBytes(__CFWriteSocketsFds, CFRangeMake(0, CFDataGetLength(__CFWriteSocketsFds)), (UInt8 *)writefds); CFDataGetBytes(__CFReadSocketsFds, CFRangeMake(0, CFDataGetLength(__CFReadSocketsFds)), (UInt8 *)readfds); -#endif - __CFSpinUnlock(&__CFActiveSocketsLock); - - nrfds = select(maxnrfds, readfds, writefds, exceptfds, NULL); + + if (__CFReadSocketsTimeoutInvalid) { + struct timeval* minTimeout = NULL; + __CFReadSocketsTimeoutInvalid = false; #if defined(LOG_CFSOCKET) - fprintf(stdout, "socket manager woke from select, ret=%ld\n", nrfds); -#endif - if (0 == nrfds) continue; - if (0 > nrfds) { + fprintf(stdout, "Figuring out which sockets have timeouts...\n"); +#endif /* LOG_CFSOCKET */ + CFArrayApplyFunction(__CFReadSockets, CFRangeMake(0, CFArrayGetCount(__CFReadSockets)), _calcMinTimeout_locked, (void*) &minTimeout); + + if (minTimeout == NULL) { +#if defined(LOG_CFSOCKET) + fprintf(stdout, "No one wants a timeout!\n"); +#endif /* LOG_CFSOCKET */ + pTimeout = NULL; + } else { +#if defined(LOG_CFSOCKET) + fprintf(stdout, "timeout will be %d, %d!\n", minTimeout->tv_sec, minTimeout->tv_usec); +#endif /* LOG_CFSOCKET */ + tv = *minTimeout; + pTimeout = &tv; + } + } + + if (pTimeout) { +#if defined(LOG_CFSOCKET) + fprintf(stdout, "select will have a %d, %d timeout\n", pTimeout->tv_sec, pTimeout->tv_usec); +#endif /* LOG_CFSOCKET */ + gettimeofday(&timeBeforeSelect, NULL); + } + + __CFSpinUnlock(&__CFActiveSocketsLock); + + nrfds = select(maxnrfds, readfds, writefds, exceptfds, pTimeout); + +#if defined(LOG_CFSOCKET) + fprintf(stdout, "socket manager woke from select, ret=%ld\n", nrfds); +#endif /* LOG_CFSOCKET */ + + /* + * select returned a timeout + */ + if (0 == nrfds) { + struct timeval timeAfterSelect; + struct timeval deltaTime; + gettimeofday(&timeAfterSelect, NULL); + /* timeBeforeSelect becomes the delta */ + 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); +#endif /* LOG_CFSOCKET */ + + __CFSpinLock(&__CFActiveSocketsLock); + + tempfds = NULL; + cnt = CFArrayGetCount(__CFReadSockets); + for (idx = 0; idx < cnt; idx++) { + CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFReadSockets, idx); + if (timerisset(&s->_readBufferTimeout)) { + CFSocketNativeHandle sock = s->_socket; + // We might have an new element in __CFReadSockets that we weren't listening to, + // in which case we must be sure not to test a bit in the fdset that is + // outside our mask size. + Boolean sockInBounds = (0 <= sock && sock < maxnrfds); + /* if this sockets timeout is less than or equal elapsed time, then signal it */ + if (INVALID_SOCKET != sock && sockInBounds && timercmp(&s->_readBufferTimeout, &deltaTime, <=)) { +#if defined(LOG_CFSOCKET) + fprintf(stdout, "Expiring socket %d (delta %d, %d)\n", sock, s->_readBufferTimeout.tv_sec, s->_readBufferTimeout.tv_usec); +#endif /* LOG_CFSOCKET */ + CFArraySetValueAtIndex(selectedReadSockets, selectedReadSocketsIndex, s); + selectedReadSocketsIndex++; + /* socket is removed from fds here, will be restored in read handling or in perform function */ + if (!tempfds) tempfds = (fd_set *)CFDataGetMutableBytePtr(__CFReadSocketsFds); + FD_CLR(sock, tempfds); + } + } + } + + __CFSpinUnlock(&__CFActiveSocketsLock); + + /* and below, we dispatch through the normal read dispatch mechanism */ + } + + if (0 > nrfds) { SInt32 selectError = __CFSocketLastError(); #if defined(LOG_CFSOCKET) fprintf(stdout, "socket manager received error %ld from select\n", selectError); -#endif +#endif /* LOG_CFSOCKET */ if (EBADF == selectError) { CFMutableArrayRef invalidSockets = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); __CFSpinLock(&__CFActiveSocketsLock); @@ -862,7 +969,7 @@ static void __CFSocketManager(void * arg) if (!__CFNativeSocketIsValid(s->_socket)) { #if defined(LOG_CFSOCKET) fprintf(stdout, "socket manager found write socket %d invalid\n", s->_socket); -#endif +#endif /* LOG_CFSOCKET */ CFArrayAppendValue(invalidSockets, s); } } @@ -872,7 +979,7 @@ static void __CFSocketManager(void * arg) if (!__CFNativeSocketIsValid(s->_socket)) { #if defined(LOG_CFSOCKET) fprintf(stdout, "socket manager found read socket %d invalid\n", s->_socket); -#endif +#endif /* LOG_CFSOCKET */ CFArrayAppendValue(invalidSockets, s); } } @@ -880,7 +987,7 @@ static void __CFSocketManager(void * arg) cnt = CFArrayGetCount(invalidSockets); for (idx = 0; idx < cnt; idx++) { - __CFSocketInvalidate(((CFSocketRef)CFArrayGetValueAtIndex(invalidSockets, idx)), false); + CFSocketInvalidate(((CFSocketRef)CFArrayGetValueAtIndex(invalidSockets, idx))); } CFRelease(invalidSockets); } @@ -890,7 +997,7 @@ static void __CFSocketManager(void * arg) recv(__CFWakeupSocketPair[1], buffer, sizeof(buffer), 0); #if defined(LOG_CFSOCKET) fprintf(stdout, "socket manager received %c on wakeup socket\n", buffer[0]); -#endif +#endif /* LOG_CFSOCKET */ } __CFSpinLock(&__CFActiveSocketsLock); tempfds = NULL; @@ -898,36 +1005,18 @@ static void __CFSocketManager(void * arg) for (idx = 0; idx < cnt; idx++) { CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFWriteSockets, idx); CFSocketNativeHandle sock = s->_socket; -#if !defined(__WIN32__) // We might have an new element in __CFWriteSockets that we weren't listening to, // in which case we must be sure not to test a bit in the fdset that is // outside our mask size. Boolean sockInBounds = (0 <= sock && sock < maxnrfds); -#else - // fdset's are arrays, so we don't have that issue above - Boolean sockInBounds = true; -#endif if (INVALID_SOCKET != sock && sockInBounds) { if (FD_ISSET(sock, writefds)) { - CFArrayAppendValue(selectedWriteSockets, s); + CFArraySetValueAtIndex(selectedWriteSockets, selectedWriteSocketsIndex, s); + selectedWriteSocketsIndex++; /* socket is removed from fds here, restored by CFSocketReschedule */ if (!tempfds) tempfds = (fd_set *)CFDataGetMutableBytePtr(__CFWriteSocketsFds); FD_CLR(sock, tempfds); -#if defined(__WIN32__) - fd_set *exfds = (fd_set *)CFDataGetMutableBytePtr(__CFExceptSocketsFds); - FD_CLR(sock, exfds); -#endif - } -#if defined(__WIN32__) - else if (FD_ISSET(sock, exceptfds)) { - // On Win32 connect errors come in on exceptFDs. We treat these as if - // they had come on writeFDs, since the rest of our Unix-based code - // expects that. - CFArrayAppendValue(selectedWriteSockets, s); - fd_set *exfds = (fd_set *)CFDataGetMutableBytePtr(__CFExceptSocketsFds); - FD_CLR(sock, exfds); } -#endif } } tempfds = NULL; @@ -935,17 +1024,13 @@ static void __CFSocketManager(void * arg) for (idx = 0; idx < cnt; idx++) { CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(__CFReadSockets, idx); CFSocketNativeHandle sock = s->_socket; -#if !defined(__WIN32__) // We might have an new element in __CFReadSockets that we weren't listening to, // in which case we must be sure not to test a bit in the fdset that is // outside our mask size. Boolean sockInBounds = (0 <= sock && sock < maxnrfds); -#else - // fdset's are arrays, so we don't have that issue above - Boolean sockInBounds = true; -#endif if (INVALID_SOCKET != sock && sockInBounds && FD_ISSET(sock, readfds)) { - CFArrayAppendValue(selectedReadSockets, s); + CFArraySetValueAtIndex(selectedReadSockets, selectedReadSocketsIndex, s); + selectedReadSocketsIndex++; /* socket is removed from fds here, will be restored in read handling or in perform function */ if (!tempfds) tempfds = (fd_set *)CFDataGetMutableBytePtr(__CFReadSocketsFds); FD_CLR(sock, tempfds); @@ -953,228 +1038,102 @@ static void __CFSocketManager(void * arg) } __CFSpinUnlock(&__CFActiveSocketsLock); - cnt = CFArrayGetCount(selectedWriteSockets); - for (idx = 0; idx < cnt; idx++) { + for (idx = 0; idx < selectedWriteSocketsIndex; idx++) { CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(selectedWriteSockets, idx); + if (kCFNull == (CFNullRef)s) continue; #if defined(LOG_CFSOCKET) fprintf(stdout, "socket manager signaling socket %d for write\n", s->_socket); -#endif +#endif /* LOG_CFSOCKET */ __CFSocketHandleWrite(s, FALSE); + CFArraySetValueAtIndex(selectedWriteSockets, idx, kCFNull); } - if (0 < cnt) CFArrayRemoveAllValues(selectedWriteSockets); - cnt = CFArrayGetCount(selectedReadSockets); - for (idx = 0; idx < cnt; idx++) { + selectedWriteSocketsIndex = 0; + + for (idx = 0; idx < selectedReadSocketsIndex; idx++) { CFSocketRef s = (CFSocketRef)CFArrayGetValueAtIndex(selectedReadSockets, idx); + if (kCFNull == (CFNullRef)s) continue; #if defined(LOG_CFSOCKET) fprintf(stdout, "socket manager signaling socket %d for read\n", s->_socket); -#endif - __CFSocketHandleRead(s); +#endif /* LOG_CFSOCKET */ + __CFSocketHandleRead(s, nrfds == 0); + CFArraySetValueAtIndex(selectedReadSockets, idx, kCFNull); } - if (0 < cnt) CFArrayRemoveAllValues(selectedReadSockets); + selectedReadSocketsIndex = 0; } + if (objc_collecting_enabled()) auto_zone_unregister_thread(auto_zone()); } static CFStringRef __CFSocketCopyDescription(CFTypeRef cf) { CFSocketRef s = (CFSocketRef)cf; CFMutableStringRef result; - CFStringRef contextDesc = NULL; - void *contextInfo = NULL; - CFStringRef (*contextCopyDescription)(const void *info) = NULL; - result = CFStringCreateMutable(CFGetAllocator(s), 0); - __CFSocketLock(s); - CFStringAppendFormat(result, NULL, CFSTR("{valid = %s, type = %d, socket = %d, socket set count = %ld\n callback types = 0x%x, callout = %x, source = %p,\n run loops = %@,\n context = "), cf, CFGetAllocator(s), (__CFSocketIsValid(s) ? "Yes" : "No"), s->_socketType, s->_socket, s->_socketSetCount, __CFSocketCallBackTypes(s), s->_callout, s->_source0, s->_runLoops); - contextInfo = s->_context.info; - contextCopyDescription = s->_context.copyDescription; - __CFSocketUnlock(s); - if (NULL != contextInfo && NULL != contextCopyDescription) { - contextDesc = (CFStringRef)contextCopyDescription(contextInfo); - } - if (NULL == contextDesc) { - contextDesc = CFStringCreateWithFormat(CFGetAllocator(s), NULL, CFSTR(""), contextInfo); - } - CFStringAppend(result, contextDesc); - CFRelease(contextDesc); - return result; -} - -static void __CFSocketDeallocate(CFTypeRef cf) { - /* Since CFSockets are cached, we can only get here sometime after being invalidated */ - CFSocketRef s = (CFSocketRef)cf; - if (NULL != s->_address) { - CFRelease(s->_address); - s->_address = NULL; - } -} - -static const CFRuntimeClass __CFSocketClass = { - 0, - "CFSocket", - NULL, // init - NULL, // copy - __CFSocketDeallocate, - NULL, // equal - NULL, // hash - NULL, // - __CFSocketCopyDescription -}; - -__private_extern__ void __CFSocketInitialize(void) { - __kCFSocketTypeID = _CFRuntimeRegisterClass(&__CFSocketClass); -} - -CFTypeID CFSocketGetTypeID(void) { - return __kCFSocketTypeID; -} - -CFSocketError CFSocketSetAddress(CFSocketRef s, CFDataRef address) { - const uint8_t *name; - SInt32 namelen, result = 0; - __CFGenericValidateType(s, __kCFSocketTypeID); - if (NULL == address) return -1; - name = CFDataGetBytePtr(address); - namelen = CFDataGetLength(address); - __CFSocketLock(s); - if (__CFSocketIsValid(s) && INVALID_SOCKET != s->_socket && NULL != name && 0 < namelen) { - result = bind(s->_socket, (struct sockaddr *)name, namelen); - if (0 == result) { - __CFSocketEstablishAddress(s); - listen(s->_socket, 256); - } - } - if (NULL == s->_address && NULL != name && 0 < namelen && 0 == result) { - s->_address = CFDataCreateCopy(CFGetAllocator(s), address); - } - __CFSocketUnlock(s); - //??? should return errno - return result; -} - -__private_extern__ void CFSocketSetAcceptBacklog(CFSocketRef s, CFIndex limit) { - __CFGenericValidateType(s, __kCFSocketTypeID); - __CFSocketLock(s); - if (__CFSocketIsValid(s) && INVALID_SOCKET != s->_socket) { - listen(s->_socket, limit); - } - __CFSocketUnlock(s); -} - -__private_extern__ void CFSocketSetMaximumQueueLength(CFSocketRef s, CFIndex length) { - __CFGenericValidateType(s, __kCFSocketTypeID); -#if !defined(USE_V1_RUN_LOOP_SOURCE) - __CFSocketLock(s); - if (__CFSocketIsValid(s)) { - s->_maxQueueLen = length; - } - __CFSocketUnlock(s); -#endif -} - -CFSocketError CFSocketConnectToAddress(CFSocketRef s, CFDataRef address, CFTimeInterval timeout) { - //??? need error handling, retries - const uint8_t *name; - SInt32 namelen, result = -1, connect_err = 0, select_err = 0; - UInt32 yes = 1, no = 0; - Boolean wasBlocking = true; - - __CFGenericValidateType(s, __kCFSocketTypeID); - name = CFDataGetBytePtr(address); - namelen = CFDataGetLength(address); - __CFSocketLock(s); - if (__CFSocketIsValid(s) && INVALID_SOCKET != s->_socket && NULL != name && 0 < namelen) { -#if !defined(__WIN32__) - SInt32 flags = fcntl(s->_socket, F_GETFL, 0); - if (flags >= 0) wasBlocking = ((flags & O_NONBLOCK) == 0); - if (wasBlocking && (timeout > 0.0 || timeout < 0.0)) ioctlsocket(s->_socket, FIONBIO, &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. - if (timeout > 0.0 || timeout < 0.0) ioctlsocket(s->_socket, FIONBIO, &yes); - wasBlocking = false; -#endif - result = connect(s->_socket, (struct sockaddr *)name, namelen); - if (result != 0) { - connect_err = __CFSocketLastError(); -#if defined(__WIN32__) - if (connect_err == WSAEWOULDBLOCK) connect_err = EINPROGRESS; -#endif - } -#if defined(LOG_CFSOCKET) -#if !defined(__WIN32__) - fprintf(stdout, "connection attempt returns %ld error %ld on socket %d (flags 0x%lx blocking %d)\n", result, connect_err, s->_socket, flags, wasBlocking); -#else - fprintf(stdout, "connection attempt returns %ld error %ld on socket %d\n", result, connect_err, s->_socket); -#endif -#endif - if (EINPROGRESS == connect_err && timeout >= 0.0) { - /* select on socket */ - SInt32 nrfds; - int error_size = sizeof(select_err); - struct timeval tv; - CFMutableDataRef fds = CFDataCreateMutable(kCFAllocatorSystemDefault, 0); -#if defined(__WIN32__) - CFDataIncreaseLength(fds , sizeof(u_int) + sizeof(SOCKET)); -#endif - __CFSocketFdSet(s->_socket, fds); - tv.tv_sec = (0 >= timeout || INT_MAX <= timeout) ? INT_MAX : (int)(float)floor(timeout); - tv.tv_usec = (int)((timeout - floor(timeout)) * 1.0E6); - nrfds = select(__CFSocketFdGetSize(fds), NULL, (fd_set *)CFDataGetMutableBytePtr(fds), NULL, &tv); - if (nrfds < 0) { - select_err = __CFSocketLastError(); - result = -1; - } else if (nrfds == 0) { - result = -2; - } else { - if (0 != getsockopt(s->_socket, SOL_SOCKET, SO_ERROR, (void *)&select_err, &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", s->_socket, result, nrfds, select_err); -#endif - } - if (wasBlocking && (timeout > 0.0 || timeout < 0.0)) ioctlsocket(s->_socket, FIONBIO, &no); - if (0 == result) { - __CFSocketEstablishPeerAddress(s); - if (NULL == s->_peerAddress && NULL != name && 0 < namelen && __CFSocketIsConnectionOriented(s)) { - s->_peerAddress = CFDataCreateCopy(CFGetAllocator(s), address); - } - } - if (EINPROGRESS == connect_err && timeout < 0.0) { - result = 0; -#if defined(LOG_CFSOCKET) - fprintf(stdout, "connection attempt continues in background on socket %d\n", s->_socket); -#endif - } - } + CFStringRef contextDesc = NULL; + void *contextInfo = NULL; + CFStringRef (*contextCopyDescription)(const void *info) = NULL; + result = CFStringCreateMutable(CFGetAllocator(s), 0); + __CFSocketLock(s); + void *addr = s->_callout; + Dl_info info; + const char *name = (dladdr(addr, &info) && info.dli_saddr == addr && info.dli_sname) ? info.dli_sname : "???"; + 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; __CFSocketUnlock(s); - //??? should return errno + if (NULL != contextInfo && NULL != contextCopyDescription) { + contextDesc = (CFStringRef)contextCopyDescription(contextInfo); + } + if (NULL == contextDesc) { + contextDesc = CFStringCreateWithFormat(CFGetAllocator(s), NULL, CFSTR(""), contextInfo); + } + CFStringAppend(result, contextDesc); + CFStringAppend(result, CFSTR("}")); + CFRelease(contextDesc); return result; } -CFSocketRef CFSocketCreate(CFAllocatorRef allocator, SInt32 protocolFamily, SInt32 socketType, SInt32 protocol, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) { - CFSocketNativeHandle sock = INVALID_SOCKET; - CFSocketRef s = NULL; - if (0 >= protocolFamily) protocolFamily = PF_INET; - if (PF_INET == protocolFamily) { - if (0 >= socketType) socketType = SOCK_STREAM; - if (0 >= protocol && SOCK_STREAM == socketType) protocol = IPPROTO_TCP; - if (0 >= protocol && SOCK_DGRAM == socketType) protocol = IPPROTO_UDP; +static void __CFSocketDeallocate(CFTypeRef cf) { + /* Since CFSockets are cached, we can only get here sometime after being invalidated */ + CFSocketRef s = (CFSocketRef)cf; + if (NULL != s->_address) { + CFRelease(s->_address); + s->_address = NULL; } -#if !defined(__WIN32__) - if (PF_LOCAL == protocolFamily && 0 >= socketType) socketType = SOCK_STREAM; -#else - /* WinSock needs to be initialized at this point for Windows, before socket() */ - __CFSocketInitializeWinSock(); -#endif - sock = socket(protocolFamily, socketType, protocol); - if (INVALID_SOCKET != sock) { - s = CFSocketCreateWithNative(allocator, sock, callBackTypes, callout, context); + if (NULL != s->_readBuffer) { + CFRelease(s->_readBuffer); + s->_readBuffer = NULL; } - return s; + if (NULL != s->_leftoverBytes) { + CFRelease(s->_leftoverBytes); + s->_leftoverBytes = NULL; + } + timerclear(&s->_readBufferTimeout); + s->_bytesToBuffer = 0; + s->_bytesToBufferPos = 0; + s->_bytesToBufferReadPos = 0; + s->_atEOF = true; + s->_bufferedReadError = 0; } -CFSocketRef CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHandle sock, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) { +static const CFRuntimeClass __CFSocketClass = { + 0, + "CFSocket", + NULL, // init + NULL, // copy + __CFSocketDeallocate, + NULL, // equal + NULL, // hash + NULL, // + __CFSocketCopyDescription +}; + +__private_extern__ void __CFSocketInitialize(void) { + __kCFSocketTypeID = _CFRuntimeRegisterClass(&__CFSocketClass); +} + +CFTypeID CFSocketGetTypeID(void) { + return __kCFSocketTypeID; +} +static CFSocketRef _CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHandle sock, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context, Boolean useExistingInstance) { + CHECK_FOR_FORK(); CFSocketRef memory; int typeSize = sizeof(memory->_socketType); __CFSpinLock(&__CFActiveSocketsLock); @@ -1184,10 +1143,19 @@ CFSocketRef CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHan if (NULL == __CFAllSockets) { __CFAllSockets = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks); } - if (INVALID_SOCKET != sock && CFDictionaryGetValueIfPresent(__CFAllSockets, (void *)sock, (const void **)&memory)) { - __CFSpinUnlock(&__CFAllSocketsLock); - CFRetain(memory); - return memory; + if (INVALID_SOCKET != sock && CFDictionaryGetValueIfPresent(__CFAllSockets, (void *)(uintptr_t)sock, (const void **)&memory)) { + if (useExistingInstance) { + __CFSpinUnlock(&__CFAllSocketsLock); + CFRetain(memory); + return memory; + } else { +#if defined(LOG_CFSOCKET) + fprintf(stdout, "useExistingInstance is FALSE, removing existing instance %d from __CFAllSockets\n", (int)memory); +#endif /* LOG_CFSOCKET */ + __CFSpinUnlock(&__CFAllSocketsLock); + CFSocketInvalidate(memory); + __CFSpinLock(&__CFAllSocketsLock); + } } memory = (CFSocketRef)_CFRuntimeCreateInstance(allocator, __kCFSocketTypeID, sizeof(struct __CFSocket) - sizeof(CFRuntimeBase), NULL); if (NULL == memory) { @@ -1203,10 +1171,10 @@ CFSocketRef CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHan memory->_f.connected = FALSE; memory->_f.writableHint = FALSE; memory->_f.closeSignaled = FALSE; - memory->_lock = 0; - memory->_writeLock = 0; + memory->_lock = CFSpinLockInit; + memory->_writeLock = CFSpinLockInit; memory->_socket = sock; - if (INVALID_SOCKET == sock || 0 != getsockopt(sock, SOL_SOCKET, SO_TYPE, (void *)&(memory->_socketType), &typeSize)) memory->_socketType = 0; // cast for WinSock bad API + 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 memory->_errorCode = 0; memory->_address = NULL; memory->_peerAddress = NULL; @@ -1218,22 +1186,21 @@ CFSocketRef CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHan memory->_runLoops = NULL; } memory->_callout = callout; -#if defined(USE_V1_RUN_LOOP_SOURCE) - memory->_event = CreateEvent(NULL, true, false, NULL); - CFAssert1(NULL != memory->_event, __kCFLogAssertion, "%s(): could not create event", __PRETTY_FUNCTION__); - memory->_oldEventMask = 0; - __CFSocketSetWholeEventMask(memory, FD_CLOSE|FD_CONNECT); // always listen for closes, connects - memory->_source1 = NULL; -#else // !USE_V1_RUN_LOOP_SOURCE memory->_dataQueue = NULL; memory->_addressQueue = NULL; - memory->_maxQueueLen = 0; -#endif // !USE_V1_RUN_LOOP_SOURCE memory->_context.info = 0; memory->_context.retain = 0; memory->_context.release = 0; memory->_context.copyDescription = 0; - if (INVALID_SOCKET != sock) CFDictionaryAddValue(__CFAllSockets, (void *)sock, memory); + timerclear(&memory->_readBufferTimeout); + memory->_readBuffer = NULL; + memory->_bytesToBuffer = 0; + memory->_bytesToBufferPos = 0; + memory->_bytesToBufferReadPos = 0; + memory->_atEOF = false; + memory->_bufferedReadError = 0; + + if (INVALID_SOCKET != sock) CFDictionaryAddValue(__CFAllSockets, (void *)(uintptr_t)sock, memory); __CFSpinUnlock(&__CFAllSocketsLock); if (NULL != context) { void *contextInfo = context->retain ? (void *)context->retain(context->info) : context->info; @@ -1247,32 +1214,17 @@ CFSocketRef CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHan return memory; } -CFSocketRef CFSocketCreateWithSocketSignature(CFAllocatorRef allocator, const CFSocketSignature *signature, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) { - CFSocketRef s = CFSocketCreate(allocator, signature->protocolFamily, signature->socketType, signature->protocol, callBackTypes, callout, context); - if (NULL != s && (!CFSocketIsValid(s) || kCFSocketSuccess != CFSocketSetAddress(s, signature->address))) { - CFSocketInvalidate(s); - CFRelease(s); - s = NULL; - } - return s; -} - -CFSocketRef CFSocketCreateConnectedToSocketSignature(CFAllocatorRef allocator, const CFSocketSignature *signature, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context, CFTimeInterval timeout) { - CFSocketRef s = CFSocketCreate(allocator, signature->protocolFamily, signature->socketType, signature->protocol, callBackTypes, callout, context); - if (NULL != s && (!CFSocketIsValid(s) || kCFSocketSuccess != CFSocketConnectToAddress(s, signature->address, timeout))) { - CFSocketInvalidate(s); - CFRelease(s); - s = NULL; - } - return s; +CFSocketRef CFSocketCreateWithNative(CFAllocatorRef allocator, CFSocketNativeHandle sock, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) { + return _CFSocketCreateWithNative(allocator, sock, callBackTypes, callout, context, TRUE); } -static void __CFSocketInvalidate(CFSocketRef s, Boolean wakeup) { +void CFSocketInvalidate(CFSocketRef s) { + CHECK_FOR_FORK(); UInt32 previousSocketManagerIteration; __CFGenericValidateType(s, __kCFSocketTypeID); #if defined(LOG_CFSOCKET) - fprintf(stdout, "invalidating socket %d with flags 0x%x disabled 0x%x connected 0x%x wakeup %d\n", s->_socket, s->_f.client, s->_f.disabled, s->_f.connected, wakeup); -#endif + fprintf(stdout, "invalidating socket %d with flags 0x%x disabled 0x%x connected 0x%x\n", s->_socket, s->_f.client, s->_f.disabled, s->_f.connected); +#endif /* LOG_CFSOCKET */ CFRetain(s); __CFSpinLock(&__CFAllSocketsLock); __CFSocketLock(s); @@ -1289,53 +1241,22 @@ static void __CFSocketInvalidate(CFSocketRef s, Boolean wakeup) { if (0 <= idx) { CFArrayRemoveValueAtIndex(__CFWriteSockets, idx); __CFSocketClearFDForWrite(s); -#if defined(__WIN32__) - __CFSocketFdClr(s->_socket, __CFExceptSocketsFds); -#endif } -#if !defined(USE_V1_RUN_LOOP_SOURCE) // No need to clear FD's for V1 sources, since we'll just throw the whole event away idx = CFArrayGetFirstIndexOfValue(__CFReadSockets, CFRangeMake(0, CFArrayGetCount(__CFReadSockets)), s); if (0 <= idx) { CFArrayRemoveValueAtIndex(__CFReadSockets, idx); __CFSocketClearFDForRead(s); } -#endif // !USE_V1_RUN_LOOP_SOURCE previousSocketManagerIteration = __CFSocketManagerIteration; __CFSpinUnlock(&__CFActiveSocketsLock); -#if 0 - if (wakeup && __CFSocketManagerThread) { - Boolean doneWaiting = false; - uint8_t c = 'i'; -#if defined(LOG_CFSOCKET) - fprintf(stdout, "invalidation wants socket iteration to change from %lu\n", previousSocketManagerIteration); -#endif - send(__CFWakeupSocketPair[0], &c, sizeof(c), 0); -#if !defined(__WIN32__) - while (!doneWaiting) { - __CFSpinLock(&__CFActiveSocketsLock); - if (previousSocketManagerIteration != __CFSocketManagerIteration) doneWaiting = true; -#if defined(LOG_CFSOCKET) - fprintf(stdout, "invalidation comparing socket iteration %lu to previous %lu\n", __CFSocketManagerIteration, previousSocketManagerIteration); -#endif - __CFSpinUnlock(&__CFActiveSocketsLock); - if (!doneWaiting) { - struct timespec ts = {0, 1}; - // ??? depress priority - nanosleep(&ts, NULL); - } - } -#endif - } -#endif - CFDictionaryRemoveValue(__CFAllSockets, (void *)(s->_socket)); + CFDictionaryRemoveValue(__CFAllSockets, (void *)(uintptr_t)(s->_socket)); if ((s->_f.client & kCFSocketCloseOnInvalidate) != 0) closesocket(s->_socket); s->_socket = INVALID_SOCKET; if (NULL != s->_peerAddress) { CFRelease(s->_peerAddress); s->_peerAddress = NULL; } -#if !defined(USE_V1_RUN_LOOP_SOURCE) if (NULL != s->_dataQueue) { CFRelease(s->_dataQueue); s->_dataQueue = NULL; @@ -1345,7 +1266,6 @@ static void __CFSocketInvalidate(CFSocketRef s, Boolean wakeup) { s->_addressQueue = NULL; } s->_socketSetCount = 0; -#endif // !USE_V1_RUN_LOOP_SOURCE for (idx = CFArrayGetCount(s->_runLoops); idx--;) { CFRunLoopWakeUp((CFRunLoopRef)CFArrayGetValueAtIndex(s->_runLoops, idx)); } @@ -1367,17 +1287,6 @@ static void __CFSocketInvalidate(CFSocketRef s, Boolean wakeup) { CFRunLoopSourceInvalidate(source0); CFRelease(source0); } -#if defined(USE_V1_RUN_LOOP_SOURCE) - // Important to do the v1 source after the v0 source, since cancelling the v0 source - // references the v1 source (since the v1 source is added/removed from RunLoops as a - // side-effect of the v0 source being added/removed). - if (NULL != s->_source1) { - CFRunLoopSourceInvalidate(s->_source1); - CFRelease(s->_source1); - s->_source1 = NULL; - } - CloseHandle(s->_event); -#endif } else { __CFSocketUnlock(s); } @@ -1385,19 +1294,20 @@ static void __CFSocketInvalidate(CFSocketRef s, Boolean wakeup) { CFRelease(s); } -void CFSocketInvalidate(CFSocketRef s) {__CFSocketInvalidate(s, true);} - Boolean CFSocketIsValid(CFSocketRef s) { + CHECK_FOR_FORK(); __CFGenericValidateType(s, __kCFSocketTypeID); return __CFSocketIsValid(s); } CFSocketNativeHandle CFSocketGetNative(CFSocketRef s) { + CHECK_FOR_FORK(); __CFGenericValidateType(s, __kCFSocketTypeID); return s->_socket; } CFDataRef CFSocketCopyAddress(CFSocketRef s) { + CHECK_FOR_FORK(); CFDataRef result = NULL; __CFGenericValidateType(s, __kCFSocketTypeID); __CFSocketLock(s); @@ -1410,6 +1320,7 @@ CFDataRef CFSocketCopyAddress(CFSocketRef s) { } CFDataRef CFSocketCopyPeerAddress(CFSocketRef s) { + CHECK_FOR_FORK(); CFDataRef result = NULL; __CFGenericValidateType(s, __kCFSocketTypeID); __CFSocketLock(s); @@ -1422,31 +1333,31 @@ CFDataRef CFSocketCopyPeerAddress(CFSocketRef s) { } void CFSocketGetContext(CFSocketRef s, CFSocketContext *context) { + CHECK_FOR_FORK(); __CFGenericValidateType(s, __kCFSocketTypeID); CFAssert1(0 == context->version, __kCFLogAssertion, "%s(): context version not initialized to 0", __PRETTY_FUNCTION__); *context = s->_context; } -__private_extern__ void CFSocketReschedule(CFSocketRef s) { - CFSocketEnableCallBacks(s, __CFSocketCallBackTypes(s)); -} - CFOptionFlags CFSocketGetSocketFlags(CFSocketRef s) { + CHECK_FOR_FORK(); __CFGenericValidateType(s, __kCFSocketTypeID); return s->_f.client; } void CFSocketSetSocketFlags(CFSocketRef s, CFOptionFlags flags) { + CHECK_FOR_FORK(); __CFGenericValidateType(s, __kCFSocketTypeID); __CFSocketLock(s); #if defined(LOG_CFSOCKET) fprintf(stdout, "setting flags for socket %d, from 0x%x to 0x%lx\n", s->_socket, s->_f.client, flags); -#endif +#endif /* LOG_CFSOCKET */ s->_f.client = flags; __CFSocketUnlock(s); } void CFSocketDisableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes) { + CHECK_FOR_FORK(); Boolean wakeup = false; uint8_t readCallBackType; __CFGenericValidateType(s, __kCFSocketTypeID); @@ -1457,7 +1368,7 @@ void CFSocketDisableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes) { s->_f.disabled |= callBackTypes; #if defined(LOG_CFSOCKET) fprintf(stdout, "unscheduling socket %d with flags 0x%x disabled 0x%x connected 0x%x for types 0x%lx\n", s->_socket, s->_f.client, s->_f.disabled, s->_f.connected, callBackTypes); -#endif +#endif /* LOG_CFSOCKET */ __CFSpinLock(&__CFActiveSocketsLock); if ((readCallBackType == kCFSocketAcceptCallBack) || !__CFSocketIsConnectionOriented(s)) s->_f.connected = TRUE; if (((callBackTypes & kCFSocketWriteCallBack) != 0) || (((callBackTypes & kCFSocketConnectCallBack) != 0) && !s->_f.connected)) { @@ -1466,17 +1377,12 @@ void CFSocketDisableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes) { CFOptionFlags writeCallBacksAvailable = __CFSocketCallBackTypes(s) & (kCFSocketWriteCallBack | kCFSocketConnectCallBack); if (s->_f.connected) writeCallBacksAvailable &= ~kCFSocketConnectCallBack; if ((s->_f.disabled & writeCallBacksAvailable) != writeCallBacksAvailable) wakeup = true; -#if defined(__WIN32__) - __CFSocketFdClr(s->_socket, __CFExceptSocketsFds); -#endif } } if (readCallBackType != kCFSocketNoCallBack && (callBackTypes & readCallBackType) != 0) { if (__CFSocketClearFDForRead(s)) { -#if !defined(USE_V1_RUN_LOOP_SOURCE) // do not wake up the socket manager thread if callback type is read if (readCallBackType != kCFSocketReadCallBack) wakeup = true; -#endif } } __CFSpinUnlock(&__CFActiveSocketsLock); @@ -1495,6 +1401,7 @@ void CFSocketDisableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes) { // enabled when the CFSocket is created (at which time we enable with force). // Called with SocketLock held, returns with it released! void __CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes, Boolean force, uint8_t wakeupChar) { + CHECK_FOR_FORK(); Boolean wakeup = FALSE; if (!callBackTypes) { __CFSocketUnlock(s); @@ -1507,7 +1414,7 @@ void __CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes, Boole if (force) s->_f.disabled &= ~callBackTypes; #if defined(LOG_CFSOCKET) fprintf(stdout, "rescheduling socket %d with flags 0x%x disabled 0x%x connected 0x%x for types 0x%lx\n", s->_socket, s->_f.client, s->_f.disabled, s->_f.connected, callBackTypes); -#endif +#endif /* LOG_CFSOCKET */ /* We will wait for connection only for connection-oriented, non-rendezvous sockets that are not already connected. Mark others as already connected. */ if ((readCallBackType == kCFSocketAcceptCallBack) || !__CFSocketIsConnectionOriented(s)) s->_f.connected = TRUE; @@ -1525,33 +1432,12 @@ void __CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes, Boole // Now turn on the callbacks we've determined that we want on if (turnOnRead || turnOnWrite || turnOnConnect) { __CFSpinLock(&__CFActiveSocketsLock); -#if defined(USE_V1_RUN_LOOP_SOURCE) - if (turnOnWrite) { - if (force) { - SInt32 idx = CFArrayGetFirstIndexOfValue(__CFWriteSockets, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets)), s); - if (kCFNotFound == idx) CFArrayAppendValue(__CFWriteSockets, s); - } - // If we can tell the socket is writable, just reschedule the v1 source. Else we need - // a real notification from the OS, so enable the SocketManager's listening. - if (__CFSocketCanAcceptBytes(s)) { - SetEvent(s->_event); - s->_f.writableHint = TRUE; - } else { - if (__CFSocketSetFDForWrite(s)) wakeup = true; - } - } - if (turnOnConnect) __CFSocketSetWholeEventMask(s, s->_oldEventMask | FD_CONNECT); - if (turnOnRead) __CFSocketSetFDForRead(s); -#else // !USE_V1_RUN_LOOP_SOURCE if (turnOnWrite || turnOnConnect) { if (force) { SInt32 idx = CFArrayGetFirstIndexOfValue(__CFWriteSockets, CFRangeMake(0, CFArrayGetCount(__CFWriteSockets)), s); if (kCFNotFound == idx) CFArrayAppendValue(__CFWriteSockets, s); } if (__CFSocketSetFDForWrite(s)) wakeup = true; -#if defined(__WIN32__) - if ((callBackTypes & kCFSocketConnectCallBack) != 0 && !s->_f.connected) __CFSocketFdSet(s->_socket, __CFExceptSocketsFds); -#endif } if (turnOnRead) { if (force) { @@ -1560,7 +1446,6 @@ void __CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes, Boole } if (__CFSocketSetFDForRead(s)) wakeup = true; } -#endif if (wakeup && NULL == __CFSocketManagerThread) __CFSocketManagerThread = __CFStartSimpleThread(__CFSocketManager, 0); __CFSpinUnlock(&__CFActiveSocketsLock); } @@ -1570,6 +1455,7 @@ void __CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes, Boole } void CFSocketEnableCallBacks(CFSocketRef s, CFOptionFlags callBackTypes) { + CHECK_FOR_FORK(); __CFGenericValidateType(s, __kCFSocketTypeID); __CFSocketLock(s); __CFSocketEnableCallBacks(s, callBackTypes, TRUE, 'r'); @@ -1588,16 +1474,10 @@ static void __CFSocketSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) { if (1 == s->_socketSetCount) { #if defined(LOG_CFSOCKET) fprintf(stdout, "scheduling socket %d\n", s->_socket); -#endif +#endif /* LOG_CFSOCKET */ __CFSocketEnableCallBacks(s, __CFSocketCallBackTypes(s), TRUE, 's'); // unlocks s } else __CFSocketUnlock(s); -#if defined(USE_V1_RUN_LOOP_SOURCE) - // Since the v1 source is listened to in rl on this thread, we need to add it to all modes - // the v0 source is added to. - CFRunLoopAddSource(rl, s->_source1, mode); - CFRunLoopWakeUp(rl); -#endif } else __CFSocketUnlock(s); } @@ -1613,26 +1493,14 @@ static void __CFSocketCancel(void *info, CFRunLoopRef rl, CFStringRef mode) { if (0 <= idx) { CFArrayRemoveValueAtIndex(__CFWriteSockets, idx); __CFSocketClearFDForWrite(s); -#if defined(__WIN32__) - __CFSocketFdClr(s->_socket, __CFExceptSocketsFds); -#endif } -#if !defined(USE_V1_RUN_LOOP_SOURCE) idx = CFArrayGetFirstIndexOfValue(__CFReadSockets, CFRangeMake(0, CFArrayGetCount(__CFReadSockets)), s); if (0 <= idx) { CFArrayRemoveValueAtIndex(__CFReadSockets, idx); __CFSocketClearFDForRead(s); } -#endif __CFSpinUnlock(&__CFActiveSocketsLock); } -#if defined(USE_V1_RUN_LOOP_SOURCE) - CFRunLoopRemoveSource(rl, s->_source1, mode); - CFRunLoopWakeUp(rl); - if (0 == s->_socketSetCount && s->_socket != INVALID_SOCKET) { - __CFSocketSetWholeEventMask(s, FD_CLOSE|FD_CONNECT); - } -#endif if (NULL != s->_runLoops) { idx = CFArrayGetFirstIndexOfValue(s->_runLoops, CFRangeMake(0, CFArrayGetCount(s->_runLoops)), rl); if (0 <= idx) CFArrayRemoveValueAtIndex(s->_runLoops, idx); @@ -1660,7 +1528,7 @@ static void __CFSocketDoCallback(CFSocketRef s, CFDataRef data, CFDataRef addres contextInfo = s->_context.info; #if defined(LOG_CFSOCKET) fprintf(stdout, "entering perform for socket %d with read signalled %d write signalled %d connect signalled %d callback types %d\n", s->_socket, readSignalled, writeSignalled, connectSignalled, callBackTypes); -#endif +#endif /* LOG_CFSOCKET */ if (writeSignalled) { errorCode = s->_errorCode; s->_f.connected = TRUE; @@ -1671,13 +1539,13 @@ static void __CFSocketDoCallback(CFSocketRef s, CFDataRef data, CFDataRef addres if (errorCode) { #if defined(LOG_CFSOCKET) fprintf(stdout, "perform calling out error %ld to socket %d\n", errorCode, s->_socket); -#endif +#endif /* LOG_CFSOCKET */ if (callout) callout(s, kCFSocketConnectCallBack, NULL, &errorCode, contextInfo); calledOut = true; } else { #if defined(LOG_CFSOCKET) fprintf(stdout, "perform calling out connect to socket %d\n", s->_socket); -#endif +#endif /* LOG_CFSOCKET */ if (callout) callout(s, kCFSocketConnectCallBack, NULL, NULL, contextInfo); calledOut = true; } @@ -1688,16 +1556,16 @@ static void __CFSocketDoCallback(CFSocketRef s, CFDataRef data, CFDataRef addres SInt32 datalen = CFDataGetLength(data); #if defined(LOG_CFSOCKET) fprintf(stdout, "perform calling out data of length %ld to socket %d\n", datalen, s->_socket); -#endif +#endif /* LOG_CFSOCKET */ if (callout) callout(s, kCFSocketDataCallBack, address, data, contextInfo); calledOut = true; - if (0 == datalen) __CFSocketInvalidate(s, true); + if (0 == datalen) CFSocketInvalidate(s); } } else if (kCFSocketAcceptCallBack == readCallBackType) { if (INVALID_SOCKET != sock && (!calledOut || CFSocketIsValid(s))) { #if defined(LOG_CFSOCKET) fprintf(stdout, "perform calling out accept of socket %d to socket %d\n", sock, s->_socket); -#endif +#endif /* LOG_CFSOCKET */ if (callout) callout(s, kCFSocketAcceptCallBack, address, &sock, contextInfo); calledOut = true; } @@ -1705,7 +1573,7 @@ static void __CFSocketDoCallback(CFSocketRef s, CFDataRef data, CFDataRef addres if (readSignalled && (!calledOut || CFSocketIsValid(s))) { #if defined(LOG_CFSOCKET) fprintf(stdout, "perform calling out read to socket %d\n", s->_socket); -#endif +#endif /* LOG_CFSOCKET */ if (callout) callout(s, kCFSocketReadCallBack, NULL, NULL, contextInfo); calledOut = true; } @@ -1714,80 +1582,13 @@ static void __CFSocketDoCallback(CFSocketRef s, CFDataRef data, CFDataRef addres if (writeSignalled && !errorCode && (!calledOut || CFSocketIsValid(s))) { #if defined(LOG_CFSOCKET) fprintf(stdout, "perform calling out write to socket %d\n", s->_socket); -#endif +#endif /* LOG_CFSOCKET */ if (callout) callout(s, kCFSocketWriteCallBack, NULL, NULL, contextInfo); calledOut = true; } } } -#if defined(USE_V1_RUN_LOOP_SOURCE) -static HANDLE __CFSocketGetPort(void *info) { - CFSocketRef s = info; - return s->_event; -} - -static void __CFSocketPerformV1(void *info) { - CFSocketRef s = info; - WSANETWORKEVENTS eventsTranspired; - uint8_t readCallBackType = __CFSocketReadCallBackType(s); - CFOptionFlags callBacksSignalled = 0; - - int err = WSAEnumNetworkEvents(s->_socket, s->_event, &eventsTranspired); - CFAssert2(0 == err, __kCFLogAssertion, "%s(): WSAEnumNetworkEvents failed: %d", __PRETTY_FUNCTION__, WSAGetLastError()); -#if defined(LOG_CFSOCKET) - fprintf(stdout, "socket %d with flags 0x%x disabled 0x%x connected 0x%x received NetworkEvents 0x%lx\n", s->_socket, s->_f.client, s->_f.disabled, s->_f.connected, eventsTranspired.lNetworkEvents); -#endif - // Get these bits cleared before any callouts, just as the SocketMgr thread used to - if (eventsTranspired.lNetworkEvents & FD_READ) { - __CFSpinLock(&__CFActiveSocketsLock); - __CFSocketClearFDForRead(s); - __CFSpinUnlock(&__CFActiveSocketsLock); - } - - if (eventsTranspired.lNetworkEvents & FD_READ || eventsTranspired.lNetworkEvents & FD_ACCEPT) callBacksSignalled |= readCallBackType; - if (eventsTranspired.lNetworkEvents & FD_CONNECT || s->_f.writableHint) callBacksSignalled |= kCFSocketWriteCallBack; - s->_f.writableHint = FALSE; - CFAssert2(0 == (eventsTranspired.lNetworkEvents & FD_WRITE), __kCFLogAssertion, "%s(): WSAEnumNetworkEvents returned unexpected events: %lx", __PRETTY_FUNCTION__, eventsTranspired.lNetworkEvents); - -#if defined(LOG_CFSOCKET) - // I believe all these errors will be re-found in __CFSocketHandleRead and __CFSocketHandleWrite - // so we don't need to check for them here. - if (eventsTranspired.lNetworkEvents & FD_READ && eventsTranspired.iErrorCode[FD_READ_BIT] != 0) - fprintf(stdout, "socket %d has error %d for FD_READ\n", s->_socket, eventsTranspired.iErrorCode[FD_READ_BIT]); - if (eventsTranspired.lNetworkEvents & FD_WRITE && eventsTranspired.iErrorCode[FD_WRITE_BIT] != 0) - fprintf(stdout, "socket %d has error %d for FD_WRITE\n", s->_socket, eventsTranspired.iErrorCode[FD_WRITE_BIT]); - if (eventsTranspired.lNetworkEvents & FD_CLOSE && eventsTranspired.iErrorCode[FD_CLOSE_BIT] != 0) - fprintf(stdout, "socket %d has error %d for FD_CLOSE\n", s->_socket, eventsTranspired.iErrorCode[FD_CLOSE_BIT]); - if (eventsTranspired.lNetworkEvents & FD_CONNECT && eventsTranspired.iErrorCode[FD_CONNECT_BIT] != 0) - fprintf(stdout, "socket %d has error %d for FD_CONNECT\n", s->_socket, eventsTranspired.iErrorCode[FD_CONNECT_BIT]); -#endif - - if (0 != (eventsTranspired.lNetworkEvents & FD_CLOSE)) s->_f.closeSignaled = TRUE; - if (0 != (callBacksSignalled & readCallBackType)) __CFSocketHandleRead(s); - if (0 != (callBacksSignalled & kCFSocketWriteCallBack)) __CFSocketHandleWrite(s, TRUE); - // FD_CLOSE is edge triggered (sent once). FD_READ is level triggered (sent as long as there are - // bytes). Event after we get FD_CLOSE, if there are still bytes to be read we'll keep getting - // FD_READ until the pipe is drained. However, an EOF condition on the socket will -not- - // trigger an FD_READ, so we must be careful not to stall out after the last bytes are read. - // Finally, a client may have already noticed the EOF in the Read callout just done, so we don't - // call him again if the socket has been invalidated. - // All this implies that once we have seen FD_CLOSE, we need to keep checking for EOF on the read - // side to give the client one last callback for that case. - if (__CFSocketIsValid(s) && (eventsTranspired.lNetworkEvents == FD_CLOSE || (s->_f.closeSignaled && !__CFSocketHasBytesToRead(s)))) { - if (readCallBackType != kCFSocketNoCallBack) { - __CFSocketHandleRead(s); - } else if ((__CFSocketCallBackTypes(s) & kCFSocketWriteCallBack) != 0) { - __CFSocketHandleWrite(s, TRUE); - } - } - - // Only reenable callbacks that are auto-reenabled - __CFSocketLock(s); - __CFSocketEnableCallBacks(s, callBacksSignalled & s->_f.client, FALSE, 'P'); // unlocks s -} -#endif // USE_V1_RUN_LOOP_SOURCE - static void __CFSocketPerformV0(void *info) { CFSocketRef s = info; CFDataRef data = NULL; @@ -1807,7 +1608,6 @@ static void __CFSocketPerformV0(void *info) { if (__CFSocketIsReadSignalled(s)) callBacksSignalled |= readCallBackType; if (__CFSocketIsWriteSignalled(s)) callBacksSignalled |= kCFSocketWriteCallBack; -#if !defined(USE_V1_RUN_LOOP_SOURCE) if (kCFSocketDataCallBack == readCallBackType) { if (NULL != s->_dataQueue && 0 < CFArrayGetCount(s->_dataQueue)) { data = CFArrayGetValueAtIndex(s->_dataQueue, 0); @@ -1819,32 +1619,29 @@ static void __CFSocketPerformV0(void *info) { } } else if (kCFSocketAcceptCallBack == readCallBackType) { if (NULL != s->_dataQueue && 0 < CFArrayGetCount(s->_dataQueue)) { - sock = (CFSocketNativeHandle)CFArrayGetValueAtIndex(s->_dataQueue, 0); + sock = (CFSocketNativeHandle)(uintptr_t)CFArrayGetValueAtIndex(s->_dataQueue, 0); CFArrayRemoveValueAtIndex(s->_dataQueue, 0); address = CFArrayGetValueAtIndex(s->_addressQueue, 0); CFRetain(address); CFArrayRemoveValueAtIndex(s->_addressQueue, 0); } } -#endif __CFSocketDoCallback(s, data, address, sock); // does __CFSocketUnlock(s) if (NULL != data) CFRelease(data); if (NULL != address) CFRelease(address); __CFSocketLock(s); -#if !defined(USE_V1_RUN_LOOP_SOURCE) if (__CFSocketIsValid(s) && kCFSocketNoCallBack != readCallBackType) { // if there's still more data, we want to wake back up right away if ((kCFSocketDataCallBack == readCallBackType || kCFSocketAcceptCallBack == readCallBackType) && NULL != s->_dataQueue && 0 < CFArrayGetCount(s->_dataQueue)) { CFRunLoopSourceSignal(s->_source0); #if defined(LOG_CFSOCKET) fprintf(stdout, "perform short-circuit signaling source for socket %d with flags 0x%x disabled 0x%x connected 0x%x\n", s->_socket, s->_f.client, s->_f.disabled, s->_f.connected); -#endif +#endif /* LOG_CFSOCKET */ rl = __CFSocketCopyRunLoopToWakeUp(s); } } -#endif // Only reenable callbacks that are auto-reenabled __CFSocketEnableCallBacks(s, callBacksSignalled & s->_f.client, FALSE, 'p'); // unlocks s @@ -1855,25 +1652,13 @@ static void __CFSocketPerformV0(void *info) { } CFRunLoopSourceRef CFSocketCreateRunLoopSource(CFAllocatorRef allocator, CFSocketRef s, CFIndex order) { + CHECK_FOR_FORK(); CFRunLoopSourceRef result = NULL; __CFGenericValidateType(s, __kCFSocketTypeID); __CFSocketLock(s); if (__CFSocketIsValid(s)) { if (NULL == s->_source0) { CFRunLoopSourceContext context; -#if defined(USE_V1_RUN_LOOP_SOURCE) - CFRunLoopSourceContext1 context1; - context1.version = 1; - context1.info = s; - context1.retain = CFRetain; - context1.release = CFRelease; - context1.copyDescription = CFCopyDescription; - context1.equal = CFEqual; - context1.hash = CFHash; - context1.getPort = __CFSocketGetPort; - context1.perform = __CFSocketPerformV1; - s->_source1 = CFRunLoopSourceCreate(allocator, order, (CFRunLoopSourceContext*)&context1); -#endif context.version = 0; context.info = s; context.retain = CFRetain; @@ -1893,22 +1678,34 @@ CFRunLoopSourceRef CFSocketCreateRunLoopSource(CFAllocatorRef allocator, CFSocke return result; } +#endif /* NEW_SOCKET */ + +static CFSpinLock_t __CFSocketWriteLock_ = CFSpinLockInit; +//#warning can only send on one socket at a time now + +CF_INLINE void __CFSocketWriteLock(CFSocketRef s) { + __CFSpinLock(& __CFSocketWriteLock_); +} + +CF_INLINE void __CFSocketWriteUnlock(CFSocketRef s) { + __CFSpinUnlock(& __CFSocketWriteLock_); +} + //??? need timeout, error handling, retries CFSocketError CFSocketSendData(CFSocketRef s, CFDataRef address, CFDataRef data, CFTimeInterval timeout) { + CHECK_FOR_FORK(); const uint8_t *dataptr, *addrptr = NULL; SInt32 datalen, addrlen = 0, size = 0; CFSocketNativeHandle sock = INVALID_SOCKET; struct timeval tv; - __CFGenericValidateType(s, __kCFSocketTypeID); + __CFGenericValidateType(s, CFSocketGetTypeID()); if (address) { addrptr = CFDataGetBytePtr(address); addrlen = CFDataGetLength(address); } dataptr = CFDataGetBytePtr(data); datalen = CFDataGetLength(data); - __CFSocketLock(s); - if (__CFSocketIsValid(s)) sock = s->_socket; - __CFSocketUnlock(s); + if (CFSocketIsValid(s)) sock = CFSocketGetNative(s); if (INVALID_SOCKET != sock) { CFRetain(s); __CFSocketWriteLock(s); @@ -1921,14 +1718,134 @@ CFSocketError CFSocketSendData(CFSocketRef s, CFDataRef address, CFDataRef data, size = send(sock, dataptr, datalen, 0); } #if defined(LOG_CFSOCKET) - fprintf(stdout, "wrote %ld bytes to socket %d\n", size, s->_socket); -#endif + fprintf(stdout, "wrote %ld bytes to socket %d\n", size, sock); +#endif /* LOG_CFSOCKET */ __CFSocketWriteUnlock(s); CFRelease(s); } return (size > 0) ? kCFSocketSuccess : kCFSocketError; } +CFSocketError CFSocketSetAddress(CFSocketRef s, CFDataRef address) { + CHECK_FOR_FORK(); + const uint8_t *name; + SInt32 namelen, result = 0; + __CFGenericValidateType(s, CFSocketGetTypeID()); + if (NULL == address) return -1; + if (!CFSocketIsValid(s)) return 0; + name = CFDataGetBytePtr(address); + namelen = CFDataGetLength(address); + if (!name || namelen <= 0) return 0; + CFSocketNativeHandle sock = CFSocketGetNative(s); + result = bind(sock, (struct sockaddr *)name, namelen); + if (0 == result) { + listen(sock, 256); + } + //??? should return errno + return result; +} + +CFSocketError CFSocketConnectToAddress(CFSocketRef s, CFDataRef address, CFTimeInterval timeout) { + CHECK_FOR_FORK(); + //??? need error handling, retries + const uint8_t *name; + SInt32 namelen, result = -1, connect_err = 0, select_err = 0; + UInt32 yes = 1, no = 0; + Boolean wasBlocking = true; + + __CFGenericValidateType(s, CFSocketGetTypeID()); + if (!CFSocketIsValid(s)) return 0; + name = CFDataGetBytePtr(address); + namelen = CFDataGetLength(address); + if (!name || namelen <= 0) return 0; + CFSocketNativeHandle sock = CFSocketGetNative(s); + { + SInt32 flags = fcntl(sock, F_GETFL, 0); + if (flags >= 0) wasBlocking = ((flags & O_NONBLOCK) == 0); + if (wasBlocking && (timeout > 0.0 || timeout < 0.0)) ioctlsocket(sock, FIONBIO, &yes); + result = connect(sock, (struct sockaddr *)name, namelen); + if (result != 0) { + connect_err = __CFSocketLastError(); + } +#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); +#endif /* LOG_CFSOCKET */ + if (EINPROGRESS == connect_err && timeout >= 0.0) { + /* select on socket */ + SInt32 nrfds; + int error_size = sizeof(select_err); + struct timeval tv; + CFMutableDataRef fds = CFDataCreateMutable(kCFAllocatorSystemDefault, 0); + __CFSocketFdSet(sock, fds); + tv.tv_sec = (0 >= timeout || INT_MAX <= timeout) ? INT_MAX : (int)(float)floor(timeout); + tv.tv_usec = (int)((timeout - floor(timeout)) * 1.0E6); + nrfds = select(__CFSocketFdGetSize(fds), NULL, (fd_set *)CFDataGetMutableBytePtr(fds), NULL, &tv); + if (nrfds < 0) { + 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; + 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); +#endif /* LOG_CFSOCKET */ + } + if (wasBlocking && (timeout > 0.0 || timeout < 0.0)) ioctlsocket(sock, FIONBIO, &no); + if (EINPROGRESS == connect_err && timeout < 0.0) { + result = 0; +#if defined(LOG_CFSOCKET) + fprintf(stdout, "connection attempt continues in background on socket %d\n", sock); +#endif /* LOG_CFSOCKET */ + } + } + //??? should return errno + return result; +} + +CFSocketRef CFSocketCreate(CFAllocatorRef allocator, SInt32 protocolFamily, SInt32 socketType, SInt32 protocol, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) { + CHECK_FOR_FORK(); + CFSocketNativeHandle sock = INVALID_SOCKET; + CFSocketRef s = NULL; + if (0 >= protocolFamily) protocolFamily = PF_INET; + if (PF_INET == protocolFamily) { + if (0 >= socketType) socketType = SOCK_STREAM; + if (0 >= protocol && SOCK_STREAM == socketType) protocol = IPPROTO_TCP; + if (0 >= protocol && SOCK_DGRAM == socketType) protocol = IPPROTO_UDP; + } + if (PF_LOCAL == protocolFamily && 0 >= socketType) socketType = SOCK_STREAM; + sock = socket(protocolFamily, socketType, protocol); + if (INVALID_SOCKET != sock) { + s = _CFSocketCreateWithNative(allocator, sock, callBackTypes, callout, context, FALSE); + } + return s; +} + +CFSocketRef CFSocketCreateWithSocketSignature(CFAllocatorRef allocator, const CFSocketSignature *signature, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context) { + CHECK_FOR_FORK(); + CFSocketRef s = CFSocketCreate(allocator, signature->protocolFamily, signature->socketType, signature->protocol, callBackTypes, callout, context); + if (NULL != s && (!CFSocketIsValid(s) || kCFSocketSuccess != CFSocketSetAddress(s, signature->address))) { + CFSocketInvalidate(s); + CFRelease(s); + s = NULL; + } + return s; +} + +CFSocketRef CFSocketCreateConnectedToSocketSignature(CFAllocatorRef allocator, const CFSocketSignature *signature, CFOptionFlags callBackTypes, CFSocketCallBack callout, const CFSocketContext *context, CFTimeInterval timeout) { + CHECK_FOR_FORK(); + CFSocketRef s = CFSocketCreate(allocator, signature->protocolFamily, signature->socketType, signature->protocol, callBackTypes, callout, context); + if (NULL != s && (!CFSocketIsValid(s) || kCFSocketSuccess != CFSocketConnectToAddress(s, signature->address, timeout))) { + CFSocketInvalidate(s); + CFRelease(s); + s = NULL; + } + return s; +} + typedef struct { CFSocketError *error; CFPropertyListRef *value; @@ -1940,13 +1857,13 @@ static void __CFSocketHandleNameRegistryReply(CFSocketRef s, CFSocketCallBackTyp __CFSocketNameRegistryResponse *response = (__CFSocketNameRegistryResponse *)info; CFDictionaryRef replyDictionary = NULL; CFPropertyListRef value; - replyDictionary = CFPropertyListCreateFromXMLData(NULL, replyData, kCFPropertyListImmutable, NULL); + replyDictionary = 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))) { if (NULL != response->error) *(response->error) = kCFSocketSuccess; if (NULL != response->value) *(response->value) = CFRetain(value); - if (NULL != response->address) *(response->address) = address ? CFDataCreateCopy(NULL, address) : NULL; + if (NULL != response->address) *(response->address) = address ? CFDataCreateCopy(kCFAllocatorSystemDefault, address) : NULL; } CFRelease(replyDictionary); } @@ -1959,13 +1876,13 @@ static void __CFSocketSendNameRegistryRequest(CFSocketSignature *signature, CFDi CFSocketRef s = NULL; CFRunLoopSourceRef source = NULL; if (NULL != response->error) *(response->error) = kCFSocketError; - requestData = CFPropertyListCreateXMLData(NULL, requestDictionary); + requestData = CFPropertyListCreateXMLData(kCFAllocatorSystemDefault, requestDictionary); if (NULL != requestData) { if (NULL != response->error) *(response->error) = kCFSocketTimeout; - s = CFSocketCreateConnectedToSocketSignature(NULL, signature, kCFSocketDataCallBack, __CFSocketHandleNameRegistryReply, &context, timeout); + s = CFSocketCreateConnectedToSocketSignature(kCFAllocatorSystemDefault, signature, kCFSocketDataCallBack, __CFSocketHandleNameRegistryReply, &context, timeout); if (NULL != s) { if (kCFSocketSuccess == CFSocketSendData(s, NULL, requestData, timeout)) { - source = CFSocketCreateRunLoopSource(NULL, s, 0); + source = CFSocketCreateRunLoopSource(kCFAllocatorSystemDefault, s, 0); CFRunLoopAddSource(CFRunLoopGetCurrent(), source, __kCFSocketRegistryRequestRunLoopMode); CFRunLoopRunInMode(__kCFSocketRegistryRequestRunLoopMode, timeout, false); CFRelease(source); @@ -1980,9 +1897,7 @@ 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 !defined(__WIN32__) sain.sin_len = sizeof(sain); -#endif sain.sin_family = AF_INET; sain.sin_port = htons(__CFSocketDefaultNameRegistryPortNumber); sain.sin_addr.s_addr = htonl(INADDR_LOOPBACK); @@ -1990,7 +1905,7 @@ static void __CFSocketValidateSignature(const CFSocketSignature *providedSignatu signature->protocolFamily = PF_INET; signature->socketType = SOCK_STREAM; signature->protocol = IPPROTO_TCP; - signature->address = CFDataCreate(NULL, (uint8_t *)&sain, sizeof(sain)); + signature->address = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)&sain, sizeof(sain)); } else { signature->protocolFamily = providedSignature->protocolFamily; signature->socketType = providedSignature->socketType; @@ -2002,19 +1917,17 @@ static void __CFSocketValidateSignature(const CFSocketSignature *providedSignatu if (0 >= signature->protocol && SOCK_DGRAM == signature->socketType) signature->protocol = IPPROTO_UDP; } if (NULL == providedSignature->address) { - signature->address = CFDataCreate(NULL, (uint8_t *)&sain, sizeof(sain)); + signature->address = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)&sain, sizeof(sain)); } 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 !defined(__WIN32__) 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); sain.sin_addr.s_addr = sainp->sin_addr.s_addr; if (htonl(INADDR_ANY) == sain.sin_addr.s_addr) sain.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - signature->address = CFDataCreate(NULL, (uint8_t *)&sain, sizeof(sain)); + signature->address = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)&sain, sizeof(sain)); } else { signature->address = CFRetain(providedSignature->address); } @@ -2024,7 +1937,7 @@ static void __CFSocketValidateSignature(const CFSocketSignature *providedSignatu CFSocketError CFSocketRegisterValue(const CFSocketSignature *nameServerSignature, CFTimeInterval timeout, CFStringRef name, CFPropertyListRef value) { CFSocketSignature signature; - CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFSocketError retval = kCFSocketError; __CFSocketNameRegistryResponse response = {&retval, NULL, NULL}; CFDictionaryAddValue(dictionary, kCFSocketCommandKey, kCFSocketRegisterCommand); @@ -2039,7 +1952,7 @@ CFSocketError CFSocketRegisterValue(const CFSocketSignature *nameServerSignature CFSocketError CFSocketCopyRegisteredValue(const CFSocketSignature *nameServerSignature, CFTimeInterval timeout, CFStringRef name, CFPropertyListRef *value, CFDataRef *serverAddress) { CFSocketSignature signature; - CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(NULL, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFMutableDictionaryRef dictionary = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFSocketError retval = kCFSocketError; __CFSocketNameRegistryResponse response = {&retval, value, serverAddress}; CFDictionaryAddValue(dictionary, kCFSocketCommandKey, kCFSocketRetrieveCommand); @@ -2064,7 +1977,7 @@ CFSocketError CFSocketRegisterSocketSignature(const CFSocketSignature *nameServe if (NULL == validatedSignature.address || 0 > validatedSignature.protocolFamily || 255 < validatedSignature.protocolFamily || 0 > validatedSignature.socketType || 255 < validatedSignature.socketType || 0 > validatedSignature.protocol || 255 < validatedSignature.protocol || 0 >= (length = CFDataGetLength(validatedSignature.address)) || 255 < length) { retval = kCFSocketError; } else { - data = CFDataCreateMutable(NULL, sizeof(bytes) + length); + data = CFDataCreateMutable(kCFAllocatorSystemDefault, sizeof(bytes) + length); bytes[0] = validatedSignature.protocolFamily; bytes[1] = validatedSignature.socketType; bytes[2] = validatedSignature.protocol; @@ -2093,12 +2006,12 @@ CFSocketError CFSocketCopyRegisteredSocketSignature(const CFSocketSignature *nam returnedSignature.socketType = (SInt32)*ptr++; returnedSignature.protocol = (SInt32)*ptr++; ptr++; - returnedSignature.address = CFDataCreate(NULL, ptr, length - 4); + returnedSignature.address = CFDataCreate(kCFAllocatorSystemDefault, ptr, length - 4); __CFSocketValidateSignature(&returnedSignature, signature, 0); CFRelease(returnedSignature.address); ptr = CFDataGetBytePtr(signature->address); if (CFDataGetLength(signature->address) >= (int)sizeof(struct sockaddr_in) && AF_INET == ((struct sockaddr *)ptr)->sa_family && NULL != serverAddress && CFDataGetLength(serverAddress) >= (int)sizeof(struct sockaddr_in) && NULL != (aptr = CFDataGetBytePtr(serverAddress)) && AF_INET == ((struct sockaddr *)aptr)->sa_family) { - CFMutableDataRef address = CFDataCreateMutableCopy(NULL, CFDataGetLength(signature->address), signature->address); + CFMutableDataRef address = CFDataCreateMutableCopy(kCFAllocatorSystemDefault, CFDataGetLength(signature->address), signature->address); mptr = CFDataGetMutableBytePtr(address); ((struct sockaddr_in *)mptr)->sin_addr = ((struct sockaddr_in *)aptr)->sin_addr; CFRelease(signature->address); @@ -2122,3 +2035,5 @@ CF_EXPORT void CFSocketSetDefaultNameRegistryPortNumber(uint16_t port) { CF_EXPORT uint16_t CFSocketGetDefaultNameRegistryPortNumber(void) { return __CFSocketDefaultNameRegistryPortNumber; } + + diff --git a/RunLoop.subproj/CFSocket.h b/CFSocket.h similarity index 96% rename from RunLoop.subproj/CFSocket.h rename to CFSocket.h index ffc9e2a..9d509be 100644 --- a/RunLoop.subproj/CFSocket.h +++ b/CFSocket.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFSocket.h - Copyright (c) 1999-2005, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSOCKET__) @@ -36,14 +36,10 @@ typedef SOCKET CFSocketNativeHandle; typedef int CFSocketNativeHandle; #endif -#include -#include -#include #include +#include -#if defined(__cplusplus) -extern "C" { -#endif /* __cplusplus */ +CF_EXTERN_C_BEGIN typedef struct __CFSocket * CFSocketRef; @@ -124,11 +120,13 @@ filled in properly when passing in an address. */ -typedef enum { +/* Values for CFSocketError */ +enum { kCFSocketSuccess = 0, kCFSocketError = -1, kCFSocketTimeout = -2 -} CFSocketError; +}; +typedef CFIndex CFSocketError; typedef struct { SInt32 protocolFamily; @@ -137,7 +135,8 @@ typedef struct { CFDataRef address; } CFSocketSignature; -typedef enum { +/* Values for CFSocketCallBackType */ +enum { kCFSocketNoCallBack = 0, kCFSocketReadCallBack = 1, kCFSocketAcceptCallBack = 2, @@ -147,7 +146,8 @@ typedef enum { , kCFSocketWriteCallBack = 8 #endif -} CFSocketCallBackType; +}; +typedef CFOptionFlags CFSocketCallBackType; #if MAC_OS_X_VERSION_10_2 <= MAC_OS_X_VERSION_MAX_ALLOWED /* Socket flags */ @@ -238,9 +238,7 @@ CF_EXPORT const CFStringRef kCFSocketErrorKey; CF_EXPORT const CFStringRef kCFSocketRegisterCommand; CF_EXPORT const CFStringRef kCFSocketRetrieveCommand; -#if defined(__cplusplus) -} -#endif /* __cplusplus */ +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFSOCKET__ */ diff --git a/Stream.subproj/CFSocketStream.c b/CFSocketStream.c similarity index 58% rename from Stream.subproj/CFSocketStream.c rename to CFSocketStream.c index e43ea15..ea699ae 100644 --- a/Stream.subproj/CFSocketStream.c +++ b/CFSocketStream.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -25,18 +25,13 @@ Responsibility: Jeremy Wyld */ // Original Author: Becky Willrich - - -#include +#include +#include #include "CFInternal.h" +#include "CFStreamInternal.h" #include "CFStreamPriv.h" -#if defined(__WIN32__) -#include -#elif defined(__MACH__) -#endif - -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX // On Mach these live in CF for historical reasons, even though they are declared in CFNetwork const int kCFStreamErrorDomainSSL = 3; @@ -60,7 +55,8 @@ CONST_STRING_DECL(kCFStreamSocketSecurityLevelSSLv2, "kCFStreamSocketSecurityLev CONST_STRING_DECL(kCFStreamSocketSecurityLevelSSLv3, "kCFStreamSocketSecurityLevelSSLv3"); CONST_STRING_DECL(kCFStreamSocketSecurityLevelTLSv1, "kCFStreamSocketSecurityLevelTLSv1"); CONST_STRING_DECL(kCFStreamSocketSecurityLevelNegotiatedSSL, "kCFStreamSocketSecurityLevelNegotiatedSSL"); -#endif // !__MACH__ + +#endif // These are duplicated in CFNetwork, who actually externs them in its headers CONST_STRING_DECL(kCFStreamPropertySocketSSLContext, "kCFStreamPropertySocketSSLContext") @@ -99,33 +95,41 @@ enum { }; static struct { - CFSpinLock_t lock; - UInt32 flags; - - const char* const path; -#if defined(__MACH__) -#elif defined(__WIN32__) - HMODULE image; -#endif - + CFSpinLock_t lock; + UInt32 flags; void (*_CFSocketStreamCreatePair)(CFAllocatorRef, CFStringRef, UInt32, CFSocketNativeHandle, const CFSocketSignature*, CFReadStreamRef*, CFWriteStreamRef*); + CFErrorRef (*_CFErrorCreateWithStreamError)(CFAllocatorRef, CFStreamError*); + CFStreamError (*_CFStreamErrorFromCFError)(CFErrorRef); } CFNetworkSupport = { - 0, + CFSpinLockInit, 0x0, - "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CFNetwork.framework/Versions/A/CFNetwork", + NULL, NULL, NULL }; #define CFNETWORK_CALL(sym, args) ((CFNetworkSupport.sym)args) -#if defined(__MACH__) - #define CFNETWORK_LOAD_SYM(sym) \ - __CFLookupCFNetworkFunction(#sym) -#elif defined(__WIN32__) - #define CFNETWORK_LOAD_SYM(sym) \ - (void *)GetProcAddress(CFNetworkSupport.image, #sym) + +#if DEPLOYMENT_TARGET_MACOSX +#define CFNETWORK_LOAD_SYM(sym) __CFLookupCFNetworkFunction(#sym) #endif +static void initializeCFNetworkSupport(void) { + __CFBitSet(CFNetworkSupport.flags, kTriedToLoad); + +#if DEPLOYMENT_TARGET_MACOSX + CFNetworkSupport._CFSocketStreamCreatePair = CFNETWORK_LOAD_SYM(_CFSocketStreamCreatePair); + CFNetworkSupport._CFErrorCreateWithStreamError = CFNETWORK_LOAD_SYM(_CFErrorCreateWithStreamError); + CFNetworkSupport._CFStreamErrorFromCFError = CFNETWORK_LOAD_SYM(_CFStreamErrorFromCFError); +#endif + + if (!CFNetworkSupport._CFSocketStreamCreatePair) CFLog(__kCFLogAssertion, CFSTR("CoreFoundation: failed to dynamically link symbol _CFSocketStreamCreatePair")); + if (!CFNetworkSupport._CFErrorCreateWithStreamError) CFLog(__kCFLogAssertion, CFSTR("CoreFoundation: failed to dynamically link symbol _CFErrorCreateWithStreamError")); + if (!CFNetworkSupport._CFStreamErrorFromCFError) CFLog(__kCFLogAssertion, CFSTR("CoreFoundation: failed to dynamically link symbol _CFStreamErrorFromCFError")); + + __CFBitSet(CFNetworkSupport.flags, kInitialized); +} + static void createPair(CFAllocatorRef alloc, CFStringRef host, UInt32 port, CFSocketNativeHandle sock, const CFSocketSignature* sig, CFReadStreamRef *readStream, CFWriteStreamRef *writeStream) { @@ -136,61 +140,7 @@ createPair(CFAllocatorRef alloc, CFStringRef host, UInt32 port, CFSocketNativeHa *writeStream = NULL; __CFSpinLock(&(CFNetworkSupport.lock)); - - if (!__CFBitIsSet(CFNetworkSupport.flags, kTriedToLoad)) { - - __CFBitSet(CFNetworkSupport.flags, kTriedToLoad); - -#if defined(__MACH__) - CFNetworkSupport._CFSocketStreamCreatePair = CFNETWORK_LOAD_SYM(_CFSocketStreamCreatePair); - -#elif defined(__WIN32__) - - // See if we can already find it in our address space. This let's us check without - // having to specify a filename. -#if defined(DEBUG) - CFNetworkSupport.image = GetModuleHandle("CFNetwork_debug.dll"); -#elif defined(PROFILE) - CFNetworkSupport.image = GetModuleHandle("CFNetwork_profile.dll"); -#endif - // In any case, look for the release version - if (!CFNetworkSupport.image) { - CFNetworkSupport.image = GetModuleHandle("CFNetwork.dll"); - } - - if (!CFNetworkSupport.image) { - // not loaded yet, try to load from the filesystem - char path[MAX_PATH+1]; -#if defined(DEBUG) - strcpy(path, _CFDLLPath()); - strcat(path, "\\CFNetwork_debug.dll"); - CFNetworkSupport.image = LoadLibrary(path); -#elif defined(PROFILE) - strcpy(path, _CFDLLPath()); - strcat(path, "\\CFNetwork_profile.dll"); - CFNetworkSupport.image = LoadLibrary(path); -#endif - if (!CFNetworkSupport.image) { - strcpy(path, _CFDLLPath()); - strcat(path, "\\CFNetwork.dll"); - CFNetworkSupport.image = LoadLibrary(path); - } - } - - if (!CFNetworkSupport.image) - CFLog(__kCFLogAssertion, CFSTR("_CFSocketStreamCreatePair(): failed to dynamically load CFNetwork")); - if (CFNetworkSupport.image) - CFNetworkSupport._CFSocketStreamCreatePair = CFNETWORK_LOAD_SYM(_CFSocketStreamCreatePair); -#else -#warning _CFSocketStreamCreatePair unimplemented -#endif - - if (!CFNetworkSupport._CFSocketStreamCreatePair) - CFLog(__kCFLogAssertion, CFSTR("_CFSocketStreamCreatePair(): failed to dynamically link symbol _CFSocketStreamCreatePair")); - - __CFBitSet(CFNetworkSupport.flags, kInitialized); - } - + if (!__CFBitIsSet(CFNetworkSupport.flags, kTriedToLoad)) initializeCFNetworkSupport(); __CFSpinUnlock(&(CFNetworkSupport.lock)); CFNETWORK_CALL(_CFSocketStreamCreatePair, (alloc, host, port, sock, sig, readStream, writeStream)); @@ -209,3 +159,57 @@ extern void CFStreamCreatePairWithPeerSocketSignature(CFAllocatorRef alloc, cons createPair(alloc, NULL, 0, 0, sig, readStream, writeStream); } +__private_extern__ CFStreamError _CFStreamErrorFromError(CFErrorRef error) { + CFStreamError result; + Boolean canUpCall; + + __CFSpinLock(&(CFNetworkSupport.lock)); + if (!__CFBitIsSet(CFNetworkSupport.flags, kTriedToLoad)) initializeCFNetworkSupport(); + canUpCall = (CFNetworkSupport._CFStreamErrorFromCFError != NULL); + __CFSpinUnlock(&(CFNetworkSupport.lock)); + + if (canUpCall) { + result = CFNETWORK_CALL(_CFStreamErrorFromCFError, (error)); + } else { + CFStringRef domain = CFErrorGetDomain(error); + if (CFEqual(domain, kCFErrorDomainPOSIX)) { + result.domain = kCFStreamErrorDomainPOSIX; + } else if (CFEqual(domain, kCFErrorDomainOSStatus)) { + result.domain = kCFStreamErrorDomainMacOSStatus; + } else if (CFEqual(domain, kCFErrorDomainMach)) { + result.domain = 11; // kCFStreamErrorDomainMach, but that symbol is in CFNetwork + } else { + result.domain = kCFStreamErrorDomainCustom; + } + result.error = CFErrorGetCode(error); + } + return result; +} + +__private_extern__ CFErrorRef _CFErrorFromStreamError(CFAllocatorRef alloc, CFStreamError *streamError) { + CFErrorRef result; + Boolean canUpCall; + + __CFSpinLock(&(CFNetworkSupport.lock)); + if (!__CFBitIsSet(CFNetworkSupport.flags, kTriedToLoad)) initializeCFNetworkSupport(); + canUpCall = (CFNetworkSupport._CFErrorCreateWithStreamError != NULL); + __CFSpinUnlock(&(CFNetworkSupport.lock)); + + if (canUpCall) { + result = CFNETWORK_CALL(_CFErrorCreateWithStreamError, (alloc, streamError)); + } else { + if (streamError->domain == kCFStreamErrorDomainPOSIX) { + return CFErrorCreate(alloc, kCFErrorDomainPOSIX, streamError->error, NULL); + } else if (streamError->domain == kCFStreamErrorDomainMacOSStatus) { + return CFErrorCreate(alloc, kCFErrorDomainOSStatus, streamError->error, NULL); + } else { + CFStringRef key = CFSTR("CFStreamErrorDomainKey"); + CFNumberRef value = CFNumberCreate(alloc, kCFNumberCFIndexType, &streamError->domain); + CFDictionaryRef dict = CFDictionaryCreate(alloc, (const void **)(&key), (const void **)(&value), 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + result = CFErrorCreate(alloc, CFSTR("BogusCFStreamErrorCompatibilityDomain"), streamError->error, dict); + CFRelease(value); + CFRelease(dict); + } + } + return result; +} diff --git a/CFSortFunctions.c b/CFSortFunctions.c new file mode 100644 index 0000000..6a1ce6b --- /dev/null +++ b/CFSortFunctions.c @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFSortFunctions.c + Copyright 1999-2007, Apple, Inc. All rights reserved. + Responsibility: Christopher Kane +*/ + +/* This file contains code copied from the Libc project's files + qsort.c and merge.c, and modified to suit the + needs of CF, which needs the comparison callback to have an + additional parameter. The code is collected into this one + file so that the individual BSD sort routines can remain + private and static. +*/ + +#include +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD +#include +#else +#define EINVAL 22 +#endif +#include "CFInternal.h" + + +/* stdlib.subproj/qsort.c ============================================== */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD: src/lib/libc/stdlib/qsort.c,v 1.12 2002/09/10 02:04:49 wollman Exp $"); +#endif + +#include + +#ifdef I_AM_QSORT_R +typedef int cmp_t(void *, const void *, const void *); +#else +typedef CFComparisonResult cmp_t(const void *, const void *, void *); +#endif +static inline char *med3(char *, char *, char *, cmp_t *, void *); +static inline void swapfunc(char *, char *, long, long); + +#if !defined(min) +#define min(a, b) (a) < (b) ? a : b +#endif +/* + * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function". + */ +#define swapcode(TYPE, parmi, parmj, n) { \ + long i = (n) / sizeof (TYPE); \ + TYPE *pi = (TYPE *) (parmi); \ + TYPE *pj = (TYPE *) (parmj); \ + do { \ + TYPE t = *pi; \ + *pi++ = *pj; \ + *pj++ = t; \ + } while (--i > 0); \ +} + +#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \ + es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1; + +static inline void +swapfunc(char *a, char *b, long n, long swaptype) +{ + if(swaptype <= 1) + swapcode(long, a, b, n) + else + swapcode(char, a, b, n) +} + +#define swap(a, b) \ + if (swaptype == 0) { \ + long t = *(long *)(a); \ + *(long *)(a) = *(long *)(b); \ + *(long *)(b) = t; \ + } else \ + swapfunc(a, b, es, swaptype) + +#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype) + +#ifdef I_AM_QSORT_R +#define CMP(t, x, y) (cmp((t), (x), (y))) +#else +#define CMP(t, x, y) (cmp((x), (y), (t))) +#endif + +static inline char * +med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk) +{ + return CMP(thunk, a, b) < 0 ? + (CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a )) + :(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c )); +} + +#ifdef I_AM_QSORT_R +void +qsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp) +#else +static void +bsd_qsort(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk) +#endif +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + long d, r, swaptype, swap_cnt; + +loop: SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) + for (pl = pm; + pl > (char *)a && CMP(thunk, pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + pm = (char *)a + (n / 2) * es; + if (n > 7) { + pl = a; + pn = (char *)a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk); + pm = med3(pm - d, pm, pm + d, cmp, thunk); + pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk); + } + pm = med3(pl, pm, pn, cmp, thunk); + } + swap(a, pm); + pa = pb = (char *)a + es; + + pc = pd = (char *)a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = CMP(thunk, pb, a)) <= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = CMP(thunk, pc, a)) >= 0) { + if (r == 0) { + swap_cnt = 1; + swap(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) + for (pl = pm; + pl > (char *)a && CMP(thunk, pl - es, pl) > 0; + pl -= es) + swap(pl, pl - es); + return; + } + + pn = (char *)a + n * es; + r = min(pa - (char *)a, pb - pa); + vecswap(a, pb - r, r); + r = min(pd - pc, pn - pd - es); + vecswap(pb, pn - r, r); + if ((r = pb - pa) > es) +#ifdef I_AM_QSORT_R + qsort_r(a, r / es, es, thunk, cmp); +#else + bsd_qsort(a, r / es, es, cmp, thunk); +#endif + if ((r = pd - pc) > es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +/* qsort(pn - r, r / es, es, cmp);*/ +} + + +/* And now for something not so completely different, a copy/paste version that uses write-barriers so as to notify GC as necessary of changes */ +#define ASSIGN __CFObjCStrongAssign +//#define ASSIGN objc_assign_strongCast + +#define swapcode_wb(TYPE, parmi, parmj, n) { \ + long i = (n) / sizeof (TYPE); \ + TYPE *pi = (TYPE *) (parmi); \ + TYPE *pj = (TYPE *) (parmj); \ + do { \ + TYPE t = *pi; \ + ASSIGN(*pj, pi++); \ + ASSIGN(t, pj++); \ + } while (--i > 0); \ +} + + +static inline void +swapfunc_wb(char *a, char *b, long n, long swaptype) +{ + if(swaptype <= 1) + swapcode_wb(void *, a, b, n) + else + swapcode(char, a, b, n) +} + +#define swap_wb(a, b) \ + if (swaptype == 0) { \ + const void *t = *(const void **)(a); \ + ASSIGN(*(void **)(b), (const void **)a); \ + ASSIGN(t, (const void **)(b)); \ + } else \ + printf("bad things happening\n"); + //swapfunc_wb(a, b, es, swaptype) + +#define vecswap_wb(a, b, n) if ((n) > 0) swapfunc_wb(a, b, n, swaptype) + +static void +bsd_qsort_wb(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk) +{ + char *pa, *pb, *pc, *pd, *pl, *pm, *pn; + long d, r, swaptype, swap_cnt; + +loop: SWAPINIT(a, es); + swap_cnt = 0; + if (n < 7) { + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) + for (pl = pm; + pl > (char *)a && CMP(thunk, pl - es, pl) > 0; + pl -= es) + swap_wb(pl, pl - es); + return; + } + pm = (char *)a + (n / 2) * es; + if (n > 7) { + pl = a; + pn = (char *)a + (n - 1) * es; + if (n > 40) { + d = (n / 8) * es; + pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk); + pm = med3(pm - d, pm, pm + d, cmp, thunk); + pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk); + } + pm = med3(pl, pm, pn, cmp, thunk); + } + swap_wb(a, pm); + pa = pb = (char *)a + es; + + pc = pd = (char *)a + (n - 1) * es; + for (;;) { + while (pb <= pc && (r = CMP(thunk, pb, a)) <= 0) { + if (r == 0) { + swap_cnt = 1; + swap_wb(pa, pb); + pa += es; + } + pb += es; + } + while (pb <= pc && (r = CMP(thunk, pc, a)) >= 0) { + if (r == 0) { + swap_cnt = 1; + swap_wb(pc, pd); + pd -= es; + } + pc -= es; + } + if (pb > pc) + break; + swap_wb(pb, pc); + swap_cnt = 1; + pb += es; + pc -= es; + } + if (swap_cnt == 0) { /* Switch to insertion sort */ + for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es) + for (pl = pm; + pl > (char *)a && CMP(thunk, pl - es, pl) > 0; + pl -= es) + swap_wb(pl, pl - es); + return; + } + + pn = (char *)a + n * es; + r = min(pa - (char *)a, pb - pa); + vecswap_wb(a, pb - r, r); + r = min(pd - pc, pn - pd - es); + vecswap_wb(pb, pn - r, r); + if ((r = pb - pa) > es) + bsd_qsort_wb(a, r / es, es, cmp, thunk); + if ((r = pd - pc) > es) { + /* Iterate rather than recurse to save stack space */ + a = pn - r; + n = r / es; + goto loop; + } +/* qsort(pn - r, r / es, es, cmp);*/ +} + +/* Comparator is passed the address of the values. */ +void CFQSortArray(void *list, CFIndex count, CFIndex elementSize, CFComparatorFunction comparator, void *context) { + if (CF_USING_COLLECTABLE_MEMORY && (auto_zone_get_layout_type(__CFCollectableZone, list) & AUTO_UNSCANNED) == 0) + bsd_qsort_wb(list, count, elementSize, comparator, context); + else + bsd_qsort(list, count, elementSize, comparator, context); +} + +#undef thunk +#undef CMP +#undef vecswap +//#undef swap +#undef SWAPINIT +#undef swapcode +#undef min + +/* stdlib.subproj/mergesort.c ========================================== */ + +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Peter McIlroy. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if 0 +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)merge.c 8.2 (Berkeley) 2/14/94"; +#endif /* LIBC_SCCS and not lint */ +#include +__FBSDID("$FreeBSD: src/lib/libc/stdlib/merge.c,v 1.6 2002/03/21 22:48:42 obrien Exp $"); +#endif + +/* + * Hybrid exponential search/linear search merge sort with hybrid + * natural/pairwise first pass. Requires about .3% more comparisons + * for random data than LSMS with pairwise first pass alone. + * It works for objects as small as two bytes. + */ + +#define NATURAL +#define THRESHOLD 16 /* Best choice for natural merge cut-off. */ + +/* #define NATURAL to get hybrid natural merge. + * (The default is pairwise merging.) + */ + +#include + +#include +#include +#include + +static void setup(u_char *, u_char *, size_t, size_t, CFComparisonResult (*)(), void *); +static void insertionsort(u_char *, size_t, size_t, CFComparisonResult (*)(), void *); + +#define ISIZE sizeof(long) +#define PSIZE sizeof(u_char *) +#define ICOPY_LIST(src, dst, last) \ + do \ + *(long*)dst = *(long*)src, src += ISIZE, dst += ISIZE; \ + while(src < last) +#define ICOPY_ELT(src, dst, i) \ + do \ + *(long*) dst = *(long*) src, src += ISIZE, dst += ISIZE; \ + while (i -= ISIZE) + +#define CCOPY_LIST(src, dst, last) \ + do \ + *dst++ = *src++; \ + while (src < last) +#define CCOPY_ELT(src, dst, i) \ + do \ + *dst++ = *src++; \ + while (i -= 1) + +/* + * Find the next possible pointer head. (Trickery for forcing an array + * to do double duty as a linked list when objects do not align with word + * boundaries. + */ +/* Assumption: PSIZE is a power of 2. */ +#define EVAL(p) (u_char **) \ + ((u_char *)0 + \ + (((u_char *)p + PSIZE - 1 - (u_char *) 0) & ~(PSIZE - 1))) + +/* + * Arguments are as for qsort. + */ +static int +bsd_mergesort(void *base, size_t nmemb, size_t size, CFComparisonResult (*cmp)(const void *, const void *, void *), void *context) +{ + long i, sense; + long big, iflag; + u_char *f1, *f2, *t, *b, *tp2, *q, *l1, *l2; + u_char *list2, *list1, *p2, *p, *last, **p1; + + if (size < PSIZE / 2) { /* Pointers must fit into 2 * size. */ + errno = EINVAL; + return (-1); + } + + if (nmemb == 0) + return (0); + + /* + * XXX + * Stupid subtraction for the Cray. + */ + iflag = 0; + if (!(size % ISIZE) && !(((char *)base - (char *)0) % ISIZE)) + iflag = 1; + + if ((list2 = malloc(nmemb * size + PSIZE)) == NULL) + return (-1); + + list1 = base; + setup(list1, list2, nmemb, size, cmp, context); + last = list2 + nmemb * size; + i = big = 0; + while (*EVAL(list2) != last) { + l2 = list1; + p1 = EVAL(list1); + for (tp2 = p2 = list2; p2 != last; p1 = EVAL(l2)) { + p2 = *EVAL(p2); + f1 = l2; + f2 = l1 = list1 + (p2 - list2); + if (p2 != last) + p2 = *EVAL(p2); + l2 = list1 + (p2 - list2); + while (f1 < l1 && f2 < l2) { + if ((*cmp)(f1, f2, context) <= 0) { + q = f2; + b = f1, t = l1; + sense = -1; + } else { + q = f1; + b = f2, t = l2; + sense = 0; + } + if (!big) { /* here i = 0 */ + while ((b += size) < t && cmp(q, b, context) >sense) + if (++i == 6) { + big = 1; + goto EXPONENTIAL; + } + } else { +EXPONENTIAL: for (i = size; ; i <<= 1) + if ((p = (b + i)) >= t) { + if ((p = t - size) > b && + (*cmp)(q, p, context) <= sense) + t = p; + else + b = p; + break; + } else if ((*cmp)(q, p, context) <= sense) { + t = p; + if (i == size) + big = 0; + goto FASTCASE; + } else + b = p; + while (t > b+size) { + i = (((t - b) / size) >> 1) * size; + if ((*cmp)(q, p = b + i, context) <= sense) + t = p; + else + b = p; + } + goto COPY; +FASTCASE: while (i > size) + if ((*cmp)(q, + p = b + (i >>= 1), context) <= sense) + t = p; + else + b = p; +COPY: b = t; + } + i = size; + if (q == f1) { + if (iflag) { + ICOPY_LIST(f2, tp2, b); + ICOPY_ELT(f1, tp2, i); + } else { + CCOPY_LIST(f2, tp2, b); + CCOPY_ELT(f1, tp2, i); + } + } else { + if (iflag) { + ICOPY_LIST(f1, tp2, b); + ICOPY_ELT(f2, tp2, i); + } else { + CCOPY_LIST(f1, tp2, b); + CCOPY_ELT(f2, tp2, i); + } + } + } + if (f2 < l2) { + if (iflag) + ICOPY_LIST(f2, tp2, l2); + else + CCOPY_LIST(f2, tp2, l2); + } else if (f1 < l1) { + if (iflag) + ICOPY_LIST(f1, tp2, l1); + else + CCOPY_LIST(f1, tp2, l1); + } + *p1 = l2; + } + tp2 = list1; /* swap list1, list2 */ + list1 = list2; + list2 = tp2; + last = list2 + nmemb*size; + } + if (base == list2) { + memmove(list2, list1, nmemb*size); + list2 = list1; + } + free(list2); + return (0); +} + +#define swap(a, b) { \ + s = b; \ + i = size; \ + do { \ + tmp = *a; *a++ = *s; *s++ = tmp; \ + } while (--i); \ + a -= size; \ + } +#define reverse(bot, top) { \ + s = top; \ + do { \ + i = size; \ + do { \ + tmp = *bot; *bot++ = *s; *s++ = tmp; \ + } while (--i); \ + s -= size2; \ + } while(bot < s); \ +} + +/* + * Optional hybrid natural/pairwise first pass. Eats up list1 in runs of + * increasing order, list2 in a corresponding linked list. Checks for runs + * when THRESHOLD/2 pairs compare with same sense. (Only used when NATURAL + * is defined. Otherwise simple pairwise merging is used.) + */ +static void +setup(u_char *list1, u_char *list2, size_t n, size_t size, CFComparisonResult (*cmp)(const void *, const void *, void *), void *context) +{ + long i, length, size2, tmp, sense; + u_char *f1, *f2, *s, *l2, *last, *p2; + + size2 = size*2; + if (n <= 5) { + insertionsort(list1, n, size, cmp, context); + *EVAL(list2) = (u_char*) list2 + n*size; + return; + } + /* + * Avoid running pointers out of bounds; limit n to evens + * for simplicity. + */ + i = 4 + (n & 1); + insertionsort(list1 + (n - i) * size, i, size, cmp, context); + last = list1 + size * (n - i); + *EVAL(list2 + (last - list1)) = list2 + n * size; + +#ifdef NATURAL + p2 = list2; + f1 = list1; + sense = (cmp(f1, f1 + size, context) > 0); + for (; f1 < last; sense = !sense) { + length = 2; + /* Find pairs with same sense. */ + for (f2 = f1 + size2; f2 < last; f2 += size2) { + if ((cmp(f2, f2+ size, context) > 0) != sense) + break; + length += 2; + } + if (length < THRESHOLD) { /* Pairwise merge */ + do { + p2 = *EVAL(p2) = f1 + size2 - list1 + list2; + if (sense > 0) + swap (f1, f1 + size); + } while ((f1 += size2) < f2); + } else { /* Natural merge */ + l2 = f2; + for (f2 = f1 + size2; f2 < l2; f2 += size2) { + if ((cmp(f2-size, f2, context) > 0) != sense) { + p2 = *EVAL(p2) = f2 - list1 + list2; + if (sense > 0) + reverse(f1, f2-size); + f1 = f2; + } + } + if (sense > 0) + reverse (f1, f2-size); + f1 = f2; + if (f2 < last || cmp(f2 - size, f2, context) > 0) + p2 = *EVAL(p2) = f2 - list1 + list2; + else + p2 = *EVAL(p2) = list2 + n*size; + } + } +#else /* pairwise merge only. */ + for (f1 = list1, p2 = list2; f1 < last; f1 += size2) { + p2 = *EVAL(p2) = p2 + size2; + if (cmp (f1, f1 + size, context) > 0) + swap(f1, f1 + size); + } +#endif /* NATURAL */ +} + +/* + * This is to avoid out-of-bounds addresses in sorting the + * last 4 elements. + */ +static void +insertionsort(u_char *a, size_t n, size_t size, CFComparisonResult (*cmp)(const void *, const void *, void *), void *context) +{ + u_char *ai, *s, *t, *u, tmp; + long i; + + for (ai = a+size; --n >= 1; ai += size) + for (t = ai; t > a; t -= size) { + u = t - size; + if (cmp(u, t, context) <= 0) + break; + swap(u, t); + } +} + +/* Another version, also not so completely different, in order to handle necessary write-barriers in the face of GC */ + +#undef ASSIGN +#define ASSIGN __CFObjCStrongAssign +//#define ASSIGN log_assign + +static void setup_wb(u_char *, u_char *, size_t, size_t, CFComparisonResult (*)(), void *); +static void insertionsort_wb(u_char *, size_t, size_t, CFComparisonResult (*)(), void *); + +#undef ICOPY_ELT + +#define ICOPY_ELT(src, dst, i) \ + do \ + ASSIGN(*(const void**)src, (const void *)dst), src += ISIZE, dst += ISIZE; \ + while (i -= ISIZE) + +#undef ICOPY_LIST + +#define ICOPY_LIST(src, dst, last) \ + do \ + ASSIGN(*(const void **)src, (const void *)dst), src += ISIZE, dst += ISIZE; \ + while (src < last) + + +/* + * Arguments are as for qsort. + */ +static int +bsd_mergesort_wb(void *base, size_t nmemb, size_t size, CFComparisonResult (*cmp)(const void *, const void *, void *), void *context) +{ + long i, sense; + long big, iflag; + u_char *f1, *f2, *t, *b, *tp2, *q, *l1, *l2; + u_char *list2, *list1, *p2, *p, *last, **p1; + + if (size < PSIZE / 2) { /* Pointers must fit into 2 * size. */ + errno = EINVAL; + return (-1); + } + + if (nmemb == 0) + return (0); + + /* + * XXX + * Stupid subtraction for the Cray. + */ + iflag = 0; + if (!(size % ISIZE) && !(((char *)base - (char *)0) % ISIZE)) + iflag = 1; + + if (!iflag) + return -1; // only set up for "integer" swaps, e.g. long integer + + if ((list2 = CFAllocatorAllocate(NULL, (nmemb * size + PSIZE), __kCFAllocatorGCScannedMemory)) == NULL) + return (-1); + + list1 = base; + setup_wb(list1, list2, nmemb, size, cmp, context); + last = list2 + nmemb * size; + i = big = 0; + while (*EVAL(list2) != last) { + l2 = list1; + p1 = EVAL(list1); + for (tp2 = p2 = list2; p2 != last; p1 = EVAL(l2)) { + p2 = *EVAL(p2); + f1 = l2; + f2 = l1 = list1 + (p2 - list2); + if (p2 != last) + p2 = *EVAL(p2); + l2 = list1 + (p2 - list2); + while (f1 < l1 && f2 < l2) { + if ((*cmp)(f1, f2, context) <= 0) { + q = f2; + b = f1, t = l1; + sense = -1; + } else { + q = f1; + b = f2, t = l2; + sense = 0; + } + if (!big) { /* here i = 0 */ + while ((b += size) < t && cmp(q, b, context) >sense) + if (++i == 6) { + big = 1; + goto EXPONENTIAL; + } + } else { +EXPONENTIAL: for (i = size; ; i <<= 1) + if ((p = (b + i)) >= t) { + if ((p = t - size) > b && + (*cmp)(q, p, context) <= sense) + t = p; + else + b = p; + break; + } else if ((*cmp)(q, p, context) <= sense) { + t = p; + if (i == size) + big = 0; + goto FASTCASE; + } else + b = p; + while (t > b+size) { + i = (((t - b) / size) >> 1) * size; + if ((*cmp)(q, p = b + i, context) <= sense) + t = p; + else + b = p; + } + goto COPY; +FASTCASE: while (i > size) + if ((*cmp)(q, + p = b + (i >>= 1), context) <= sense) + t = p; + else + b = p; +COPY: b = t; + } + i = size; + if (q == f1) { + if (iflag) { + ICOPY_LIST(f2, tp2, b); + ICOPY_ELT(f1, tp2, i); + } else { + CCOPY_LIST(f2, tp2, b); + CCOPY_ELT(f1, tp2, i); + } + } else { + if (iflag) { + ICOPY_LIST(f1, tp2, b); + ICOPY_ELT(f2, tp2, i); + } else { + CCOPY_LIST(f1, tp2, b); + CCOPY_ELT(f2, tp2, i); + } + } + } + if (f2 < l2) { + if (iflag) + ICOPY_LIST(f2, tp2, l2); + else + CCOPY_LIST(f2, tp2, l2); + } else if (f1 < l1) { + if (iflag) + ICOPY_LIST(f1, tp2, l1); + else + CCOPY_LIST(f1, tp2, l1); + } + *p1 = l2; + } + tp2 = list1; /* swap list1, list2 */ + list1 = list2; + list2 = tp2; + last = list2 + nmemb*size; + } + if (base == list2) { + CF_WRITE_BARRIER_MEMMOVE(list2, list1, nmemb*size); + list2 = list1; + } + free(list2); + return (0); +} + + +#define swap_wb(a, b) { \ + const void *object = *(void **)a; \ + ASSIGN(*(const void **)b, (const void *)a); \ + ASSIGN(object, (const void *)b); \ + } + +#define reverse_wb(bot, top) { \ + s = top; \ + do { \ + swap_wb(bot, s); \ + bot += size; \ + s -= size; \ + } while(bot < s); \ +} + +/* + * Optional hybrid natural/pairwise first pass. Eats up list1 in runs of + * increasing order, list2 in a corresponding linked list. Checks for runs + * when THRESHOLD/2 pairs compare with same sense. (Only used when NATURAL + * is defined. Otherwise simple pairwise merging is used.) + */ +static void +setup_wb(u_char *list1, u_char *list2, size_t n, size_t size, CFComparisonResult (*cmp)(const void *, const void *, void *), void *context) +{ + long i, length, size2, tmp, sense; + u_char *f1, *f2, *s, *l2, *last, *p2; + + size2 = size*2; + if (n <= 5) { + insertionsort_wb(list1, n, size, cmp, context); + *EVAL(list2) = (u_char*) list2 + n*size; + return; + } + /* + * Avoid running pointers out of bounds; limit n to evens + * for simplicity. + */ + i = 4 + (n & 1); + insertionsort_wb(list1 + (n - i) * size, i, size, cmp, context); + last = list1 + size * (n - i); + *EVAL(list2 + (last - list1)) = list2 + n * size; + +#ifdef NATURAL + p2 = list2; + f1 = list1; + sense = (cmp(f1, f1 + size, context) > 0); + for (; f1 < last; sense = !sense) { + length = 2; + /* Find pairs with same sense. */ + for (f2 = f1 + size2; f2 < last; f2 += size2) { + if ((cmp(f2, f2+ size, context) > 0) != sense) + break; + length += 2; + } + if (length < THRESHOLD) { /* Pairwise merge */ + do { + p2 = *EVAL(p2) = f1 + size2 - list1 + list2; + if (sense > 0) + swap (f1, f1 + size); + } while ((f1 += size2) < f2); + } else { /* Natural merge */ + l2 = f2; + for (f2 = f1 + size2; f2 < l2; f2 += size2) { + if ((cmp(f2-size, f2, context) > 0) != sense) { + p2 = *EVAL(p2) = f2 - list1 + list2; + if (sense > 0) { + reverse_wb(f1, f2-size); + } + f1 = f2; + } + } + if (sense > 0) { + reverse_wb (f1, f2-size); + } + f1 = f2; + if (f2 < last || cmp(f2 - size, f2, context) > 0) { + p2 = *EVAL(p2) = f2 - list1 + list2; + } + else { + p2 = *EVAL(p2) = list2 + n*size; + } + } + } +#else /* pairwise merge only. */ +#error unchanged + for (f1 = list1, p2 = list2; f1 < last; f1 += size2) { + p2 = *EVAL(p2) = p2 + size2; + if (cmp (f1, f1 + size, context) > 0) + swap_wb(f1, f1 + size); + } +#endif /* NATURAL */ +} + +/* + * This is to avoid out-of-bounds addresses in sorting the + * last 4 elements. + */ +static void +insertionsort_wb(u_char *a, size_t n, size_t size, CFComparisonResult (*cmp)(const void *, const void *, void *), void *context) +{ + u_char *ai, *s, *t, *u, tmp; + long i; + + for (ai = a+size; --n >= 1; ai += size) + for (t = ai; t > a; t -= size) { + u = t - size; + if (cmp(u, t, context) <= 0) + break; + swap(u, t); + } +} + +void CFMergeSortArray(void *list, CFIndex count, CFIndex elementSize, CFComparatorFunction comparator, void *context) { + if (CF_USING_COLLECTABLE_MEMORY && (auto_zone_get_layout_type(__CFCollectableZone, list) & AUTO_UNSCANNED) == 0) + bsd_mergesort_wb(list, count, elementSize, comparator, context); + else + bsd_mergesort(list, count, elementSize, comparator, context); +} + +#undef NATURAL +#undef THRESHOLD +#undef ISIZE +#undef PSIZE +#undef ICOPY_LIST +#undef ICOPY_ELT +#undef CCOPY_LIST +#undef CCOPY_ELT +#undef EVAL +#undef swap +#undef reverse + +/* ===================================================================== */ + +#undef EINVAL + diff --git a/Collections.subproj/CFStorage.c b/CFStorage.c similarity index 74% rename from Collections.subproj/CFStorage.c rename to CFStorage.c index 35b4b6e..ca96f9a 100644 --- a/Collections.subproj/CFStorage.c +++ b/CFStorage.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,37 +21,51 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFStorage.c - Copyright 1999-2002, Apple, Inc. All rights reserved. + Copyright 1999-2007, Apple, Inc. All rights reserved. Responsibility: Ali Ozer */ /* 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. */ #include "CFStorage.h" #include "CFInternal.h" -#if defined(__MACH__) -#include -#else -enum { - vm_page_size = 4096 -}; +#if !defined(PAGE_SIZE) +#define PAGE_SIZE 4096 #endif -enum { - __CFStorageMaxLeafCapacity = 65536 -}; +// Above 15K, malloc switches (??? or used to in early Leopard) to using vm allocates for blocks; it seems best to avoid that. +// 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) CF_WRITE_BARRIER_MEMMOVE((dst), (src), (n)) -#define PAGE_LIMIT ((CFIndex)vm_page_size / 2) +#define PAGE_LIMIT ((CFIndex)PAGE_SIZE / 2) -CF_INLINE int roundToPage(int num) { - return (num + vm_page_size - 1) & ~(vm_page_size - 1); +CF_INLINE int32_t roundToPage(int32_t num) { + return (num + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); } + + +/* 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 */ bool isLeaf; @@ -66,23 +80,43 @@ 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. +*/ +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; + +/* The CFStorage object. +*/ struct __CFStorage { CFRuntimeBase base; CFIndex valueSize; - CFRange cachedRange; // In terms of values, not bytes - CFStorageNode *cachedNode; // If cachedRange is valid, then either this or - uint8_t *cachedNodeMemory; // this should be non-NULL - CFIndex maxLeafCapacity; // In terms of bytes + CFSpinLock_t cacheReaderMemoryAllocationLock; + int cacheGenerationCount; + CFStorageAccessCacheParts cacheParts; + CFIndex maxLeafCapacity; // In terms of bytes CFStorageNode rootNode; - CFOptionFlags nodeHint; // auto_memory_type_t, AUTO_MEMORY_SCANNED or AUTO_MEMORY_UNSCANNED. + 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. + + + +/* 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) { - CF_WRITE_BARRIER_ASSIGN(allocator, node->info.leaf.memory, _CFAllocatorReallocateGC(allocator, node->info.leaf.memory, cap, storage->nodeHint)); // This will free... ??? Use allocator + __CFSpinLock(&(storage->cacheReaderMemoryAllocationLock)); + CF_WRITE_BARRIER_ASSIGN(allocator, 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)); } CF_INLINE void __CFStorageAllocLeafNodeMemory(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFIndex cap, bool compact) { @@ -95,30 +129,90 @@ CF_INLINE void __CFStorageAllocLeafNodeMemory(CFAllocatorRef allocator, CFStorag if (compact ? (cap != node->info.leaf.capacityInBytes) : (cap > node->info.leaf.capacityInBytes)) __CFStorageAllocLeafNodeMemoryAux(allocator, storage, node, cap); } -/* Sets the cache to point at the specified node or memory. loc and len are in terms of values, not bytes. To clear the cache set these two to 0. + + + +#if __LP64__ +#define genCountMask 0x00000000FFFFFFFFUL +#define dataMask 0xFFFFFFFF00000000UL +#define shiftLowWordBy 32 +#else +#define genCountMask 0x0000FFFFUL +#define dataMask 0xFFFF0000UL +#define shiftLowWordBy 16 +#endif + +/* 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, uint8_t *memory, CFIndex loc, CFIndex len) { - CFAllocatorRef allocator = __CFGetAllocator(storage); - storage->cachedRange.location = loc; - storage->cachedRange.length = len; - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, storage, storage->cachedNode, node); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, storage, storage->cachedNodeMemory, memory); +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; } -/* Gets the location for the specified absolute loc from the cached info; call only after verifying that the cache is OK to use. - Note that we assume if !storage->cachedNodeMemory, then storage->cachedNode must be non-NULL. - However, it is possible to have storage->cachedNodeMemory without storage->cachedNode. We check the memory before node. +/* Thread-safely get the cached range and node info. */ -CF_INLINE uint8_t *__CFStorageGetFromCache(CFStorageRef storage, CFIndex loc) { - if (!storage->cachedNodeMemory && !(storage->cachedNodeMemory = storage->cachedNode->info.leaf.memory)) { - CFAllocatorRef allocator = CFGetAllocator(storage); - __CFStorageAllocLeafNodeMemory(allocator, storage, storage->cachedNode, storage->cachedNode->numBytes, false); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, storage, storage->cachedNodeMemory, storage->cachedNode->info.leaf.memory); +CF_INLINE Boolean __CFStorageGetCache(CFStorageRef storage, CFRange *cachedRangePtr, CFStorageNode **cachedNodePtr) { + CFStorageAccessCacheParts cacheParts = storage->cacheParts; + + 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 + + return true; } - return storage->cachedNodeMemory + (loc - storage->cachedRange.location) * storage->valueSize; + 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; + + // If we can't get values from the cache, return NULL + if (!__CFStorageGetCache(storage, &cachedRange, &cachedNode)) return NULL; + + // 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; + + // 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; + + 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. @@ -143,17 +237,18 @@ CF_INLINE void __CFStorageFindChild(CFStorageNode *node, CFIndex byteNum, bool f 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, CFRange *validConsecutiveByteRange) { +static void *__CFStorageFindByte(CFStorageRef storage, CFStorageNode *node, CFIndex byteNum, CFStorageNode **resultNode, CFRange *validConsecutiveByteRange) { if (node->isLeaf) { if (validConsecutiveByteRange) *validConsecutiveByteRange = CFRangeMake(0, node->numBytes); __CFStorageAllocLeafNodeMemory(CFGetAllocator(storage), storage, node, node->numBytes, false); + if (resultNode) *resultNode = node; 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, validConsecutiveByteRange); + 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; @@ -167,19 +262,19 @@ static void *__CFStorageFindByte(CFStorageRef storage, CFStorageNode *node, CFIn */ CF_INLINE void *__CFStorageGetValueAtIndex(CFStorageRef storage, CFIndex idx, CFRange *validConsecutiveValueRange) { uint8_t *result; - if (idx < storage->cachedRange.location + storage->cachedRange.length && idx >= storage->cachedRange.location) { - result = __CFStorageGetFromCache(storage, idx); - } else { - CFRange range; - result = __CFStorageFindByte(storage, &storage->rootNode, idx * storage->valueSize, &range); - __CFStorageSetCache(storage, NULL, result - (idx * storage->valueSize - range.location), range.location / storage->valueSize, range.length / storage->valueSize); + if (!(result = __CFStorageGetFromCache(storage, idx, validConsecutiveValueRange))) { + CFRange rangeInBytes; + 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; } - *validConsecutiveValueRange = storage->cachedRange; return result; } static CFStorageNode *__CFStorageCreateNode(CFAllocatorRef allocator, bool isLeaf, CFIndex numBytes) { - CFStorageNode *newNode = _CFAllocatorAllocateGC(allocator, sizeof(CFStorageNode), 0); + CFStorageNode *newNode = (CFStorageNode *)_CFAllocatorAllocateGC(allocator, sizeof(CFStorageNode), __kCFAllocatorGCScannedMemory); if (__CFOASafe) __CFSetLastAllocationEventName(newNode, "CFStorage (node)"); newNode->isLeaf = isLeaf; newNode->numBytes = numBytes; @@ -318,7 +413,7 @@ static CFStorageNode *__CFStorageInsert(CFAllocatorRef allocator, CFStorageRef s 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, NULL, absoluteByteNum / storage->valueSize, size / storage->valueSize); + __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); @@ -327,7 +422,7 @@ static CFStorageNode *__CFStorageInsert(CFAllocatorRef allocator, CFStorageRef s node->numBytes = size; node->info.leaf.capacityInBytes = 0; node->info.leaf.memory = NULL; - __CFStorageSetCache(storage, node, NULL, absoluteByteNum / storage->valueSize, size / storage->valueSize); + __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 @@ -338,7 +433,7 @@ static CFStorageNode *__CFStorageInsert(CFAllocatorRef allocator, CFStorageRef s __CFStorageAllocLeafNodeMemory(allocator, storage, node, byteNum + size, false); } node->numBytes = byteNum + size; - __CFStorageSetCache(storage, node, node->info.leaf.memory, (absoluteByteNum - byteNum) / storage->valueSize, node->numBytes / storage->valueSize); + __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 @@ -348,8 +443,7 @@ static CFStorageNode *__CFStorageInsert(CFAllocatorRef allocator, CFStorageRef s __CFStorageAllocLeafNodeMemory(allocator, storage, node, storage->maxLeafCapacity, false); } node->numBytes = storage->maxLeafCapacity; - __CFStorageSetCache(storage, node, node->info.leaf.memory, (absoluteByteNum - byteNum) / storage->valueSize, node->numBytes / storage->valueSize); - //__CFStorageSetCache(storage, NULL, NULL, 0, 0); + __CFStorageSetCache(storage, node, (absoluteByteNum - byteNum) / storage->valueSize, node->numBytes / storage->valueSize); return newNode; } } else { // No need to create new nodes! @@ -358,7 +452,7 @@ static CFStorageNode *__CFStorageInsert(CFAllocatorRef allocator, CFStorageRef s COPYMEM(node->info.leaf.memory + byteNum, node->info.leaf.memory + byteNum + size, node->numBytes - byteNum); } node->numBytes += size; - __CFStorageSetCache(storage, node, node->info.leaf.memory, (absoluteByteNum - byteNum) / storage->valueSize, node->numBytes / storage->valueSize); + __CFStorageSetCache(storage, node, (absoluteByteNum - byteNum) / storage->valueSize, node->numBytes / storage->valueSize); return NULL; } } else { @@ -404,7 +498,7 @@ CF_INLINE CFIndex __CFStorageGetCount(CFStorageRef storage) { return storage->rootNode.numBytes / storage->valueSize; } -static bool __CFStorageEqual(CFTypeRef cf1, CFTypeRef cf2) { +static Boolean __CFStorageEqual(CFTypeRef cf1, CFTypeRef cf2) { CFStorageRef storage1 = (CFStorageRef)cf1; CFStorageRef storage2 = (CFStorageRef)cf2; CFIndex loc, count, valueSize; @@ -422,8 +516,8 @@ static bool __CFStorageEqual(CFTypeRef cf1, CFTypeRef cf2) { while (loc < count) { CFIndex cntThisTime; - if (loc >= range1.location + range1.length) ptr1 = CFStorageGetValueAtIndex(storage1, loc, &range1); - if (loc >= range2.location + range2.length) ptr2 = CFStorageGetValueAtIndex(storage2, loc, &range2); + if (loc >= range1.location + range1.length) ptr1 = (uint8_t *)CFStorageGetValueAtIndex(storage1, loc, &range1); + if (loc >= range2.location + range2.length) ptr2 = (uint8_t *)CFStorageGetValueAtIndex(storage2, loc, &range2); cntThisTime = range1.location + range1.length; if (range2.location + range2.length < cntThisTime) cntThisTime = range2.location + range2.length; cntThisTime -= loc; @@ -491,7 +585,7 @@ static const CFRuntimeClass __CFStorageClass = { NULL, // init NULL, // copy __CFStorageDeallocate, - (void *)__CFStorageEqual, + __CFStorageEqual, __CFStorageHash, NULL, // __CFStorageCopyDescription @@ -511,17 +605,23 @@ CFStorageRef CFStorageCreate(CFAllocatorRef allocator, CFIndex valueSize) { return NULL; } storage->valueSize = valueSize; - storage->cachedRange.location = 0; - storage->cachedRange.length = 0; - storage->cachedNode = NULL; - storage->cachedNodeMemory = NULL; + 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; +#endif + storage->cacheParts.lengthLo = 0; + storage->cacheParts.cachedNodeHi = 0; + storage->cacheParts.cachedNodeLo = 0; 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 = AUTO_MEMORY_SCANNED; + storage->nodeHint = __kCFAllocatorGCScannedMemory; if (__CFOASafe) __CFSetLastAllocationEventName(storage, "CFStorage"); return storage; } @@ -564,9 +664,13 @@ void CFStorageInsertValues(CFStorageRef storage, CFRange range) { CF_WRITE_BARRIER_BASE_ASSIGN(allocator, storage, storage->rootNode.info.notLeaf.child[1], newNode); storage->rootNode.info.notLeaf.child[2] = NULL; storage->rootNode.numBytes = tempRootNode->numBytes + newNode->numBytes; - if (storage->cachedNode == &(storage->rootNode)) - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, storage, storage->cachedNode, tempRootNode); // The cache should follow the node - } +#if 1 + // ??? + __CFStorageSetCache(storage, NULL, 0, 0); +#else + if (storage->cache.cachedNode == &(storage->rootNode)) CF_WRITE_BARRIER_BASE_ASSIGN(allocator, storage, storage->cache.cachedNode, tempRootNode); // The cache should follow the node +#endif + } numBytesToInsert -= insertThisTime; byteNum += insertThisTime; } @@ -590,8 +694,8 @@ void CFStorageDeleteValues(CFStorageRef storage, CFRange range) { storage->rootNode.info.leaf.capacityInBytes = 0; storage->rootNode.info.leaf.memory = NULL; } - // ??? Need to update the cache - storage->cachedRange = CFRangeMake(0, 0); + // !!! Need to update the cache + __CFStorageSetCache(storage, NULL, 0, 0); } void CFStorageGetValues(CFStorageRef storage, CFRange range, void *values) { @@ -601,12 +705,24 @@ void CFStorageGetValues(CFStorageRef storage, CFRange range, void *values) { 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); - ((uint8_t *)values) += cntThisTime * storage->valueSize; + values = (uint8_t *)values + (cntThisTime * storage->valueSize); range.location += cntThisTime; range.length -= cntThisTime; } } +unsigned long _CFStorageFastEnumeration(CFStorageRef storage, struct __objcFastEnumerationStateEquivalent *state, void *stackbuffer, unsigned long count) { + // without trying to understand the data structure, each time through search for block containing index + CFRange leafRange; + if (state->state == 0) { /* first time, get length */ + state->extra[0] = __CFStorageGetCount(storage); + } + if (state->state >= state->extra[0]) return 0; + state->itemsPtr = (unsigned long *)CFStorageGetValueAtIndex(storage, state->state, &leafRange); + state->state += leafRange.length; + return leafRange.length; +} + void CFStorageApplyFunction(CFStorageRef storage, CFRange range, CFStorageApplierFunction applier, void *context) { while (0 < range.length) { CFRange leafRange; @@ -630,7 +746,7 @@ void CFStorageReplaceValues(CFStorageRef storage, CFRange range, const void *val 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); - ((const uint8_t *)values) += cntThisTime * storage->valueSize; + values = (const uint8_t *)values + (cntThisTime * storage->valueSize); range.location += cntThisTime; range.length -= cntThisTime; } @@ -650,8 +766,8 @@ static void __CFStorageNodeSetLayoutType(CFStorageNode *node, auto_zone_t *zone, } __private_extern__ void _CFStorageSetWeak(CFStorageRef storage) { - storage->nodeHint = AUTO_MEMORY_UNSCANNED; - __CFStorageNodeSetLayoutType(&storage->rootNode, __CFCollectableZone, storage->nodeHint); + storage->nodeHint = 0; + __CFStorageNodeSetLayoutType(&storage->rootNode, __CFCollectableZone, CF_GET_GC_MEMORY_TYPE(storage->nodeHint)); } #undef COPYMEM diff --git a/Collections.subproj/CFStorage.h b/CFStorage.h similarity index 98% rename from Collections.subproj/CFStorage.h rename to CFStorage.h index 382cc47..91a3694 100644 --- a/Collections.subproj/CFStorage.h +++ b/CFStorage.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFStorage.h - Copyright (c) 1999-2005, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007, Apple Inc. All rights reserved. */ /*! @header CFStorage @@ -51,9 +51,7 @@ storage was a single block. #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN /*! @typedef CFStorageRef @@ -226,9 +224,7 @@ CF_EXPORT CFIndex __CFStorageGetCapacity(CFStorageRef storage); CF_EXPORT CFIndex __CFStorageGetValueSize(CFStorageRef storage); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFSTORAGE__ */ diff --git a/Stream.subproj/CFStream.c b/CFStream.c similarity index 79% rename from Stream.subproj/CFStream.c rename to CFStream.c index b02abb5..9c169af 100644 --- a/Stream.subproj/CFStream.c +++ b/CFStream.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,10 +26,10 @@ */ #include +#include #include -#include "CFStream.h" +#include "CFStreamInternal.h" #include "CFInternal.h" -#include "CFStreamPriv.h" #include @@ -59,7 +59,7 @@ enum { RunLoop+RunLoopMode pair that it's scheduled in. If the stream is scheduled in more than one loop or mode, it can't share RunLoopSources with others, and is not in this dict. */ -static CFSpinLock_t sSourceLock = 0; +static CFSpinLock_t sSourceLock = CFSpinLockInit; static CFMutableDictionaryRef sSharedSources = NULL; static CFTypeID __kCFReadStreamTypeID = _kCFRuntimeNotATypeID; @@ -94,9 +94,11 @@ CF_INLINE void _CFStreamScheduleEvent(struct _CFStream *stream, CFStreamEventTyp } } - -static CFHashCode __CFStreamHash(CFTypeRef cf) { - return (((int)cf) >> 5); +CF_INLINE void _CFStreamSetStreamError(struct _CFStream *stream, CFStreamError *err) { + if (!stream->error) { + stream->error = (CFErrorRef)CFAllocatorAllocate(CFGetAllocator(stream), sizeof(CFStreamError), 0); + } + memmove(stream->error, err, sizeof(CFStreamError)); } static CFStringRef __CFStreamCopyDescription(CFTypeRef cf) { @@ -111,12 +113,12 @@ static CFStringRef __CFStreamCopyDescription(CFTypeRef cf) { contextDescription = cb->copyDescription(stream, _CFStreamGetInfoPointer(stream)); } } else { - contextDescription = CFStringCreateWithFormat(CFGetAllocator(stream), NULL, CFSTR("info = 0x%lx"), (UInt32)((const void*)_CFStreamGetInfoPointer(stream))); + contextDescription = CFStringCreateWithFormat(CFGetAllocator(stream), NULL, CFSTR("info = %p"), _CFStreamGetInfoPointer(stream)); } if (CFGetTypeID(cf) == __kCFReadStreamTypeID) { - desc = CFStringCreateWithFormat(CFGetAllocator(stream), NULL, CFSTR("{%@}"), (UInt32)stream, contextDescription); + desc = CFStringCreateWithFormat(CFGetAllocator(stream), NULL, CFSTR("{%@}"), stream, contextDescription); } else { - desc = CFStringCreateWithFormat(CFGetAllocator(stream), NULL, CFSTR("{%@}"), (UInt32)stream, contextDescription); + desc = CFStringCreateWithFormat(CFGetAllocator(stream), NULL, CFSTR("{%@}"), stream, contextDescription); } CFRelease(contextDescription); return desc; @@ -126,7 +128,7 @@ __private_extern__ void _CFStreamClose(struct _CFStream *stream) { CFStreamStatus status = _CFStreamGetStatus(stream); const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream); if (status == kCFStreamStatusNotOpen || status == kCFStreamStatusClosed || (status == kCFStreamStatusError && __CFBitIsSet(stream->flags, HAVE_CLOSED))) { - // Stream is not open + // Stream is not open from the client's perspective; do not callout and do not update our status to "closed" return; } __CFBitSet(stream->flags, HAVE_CLOSED); @@ -159,6 +161,8 @@ __private_extern__ void _CFStreamClose(struct _CFStream *stream) { c--; } + CFAssert(CFArrayGetFirstIndexOfValue(list, CFRangeMake(0, CFArrayGetCount(list)), stream) == kCFNotFound, __kCFLogAssertion, "CFStreamClose: stream found twice in its shared source's list"); + if (!c) { CFRunLoopRemoveSource((CFRunLoopRef)CFArrayGetValueAtIndex(key, 0), stream->client->rlSource, (CFStringRef)CFArrayGetValueAtIndex(key, 1)); CFRunLoopSourceInvalidate(stream->client->rlSource); @@ -183,13 +187,12 @@ __private_extern__ void _CFStreamClose(struct _CFStream *stream) { static void __CFStreamDeallocate(CFTypeRef cf) { struct _CFStream *stream = (struct _CFStream *)cf; const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream); - CFStreamStatus status = _CFStreamGetStatus(stream); CFAllocatorRef alloc = CFGetAllocator(stream); // numStreamInstances --; - if ((status != kCFStreamStatusError || __CFBitIsSet(stream->flags, HAVE_CLOSED)) && status != kCFStreamStatusClosed && status != kCFStreamStatusNotOpen) { - // Close the stream - _CFStreamClose(stream); - } + + // Close the stream + _CFStreamClose(stream); + if (stream->client) { CFStreamClientContext *cbContext; cbContext = &(stream->client->cbContext); @@ -249,6 +252,13 @@ static void __CFStreamDeallocate(CFTypeRef cf) { cb->finalize(stream, _CFStreamGetInfoPointer(stream)); } } + if (stream->error) { + if (cb->version < 2) { + CFAllocatorDeallocate(alloc, stream->error); + } else { + CFRelease(stream->error); + } + } if (!__CFBitIsSet(stream->flags, CONSTANT_CALLBACKS)) { CFAllocatorDeallocate(alloc, (void *)stream->callBacks); } @@ -304,8 +314,7 @@ static struct _CFStream *_CFStreamCreate(CFAllocatorRef allocator, Boolean isRea // numStreamInstances ++; newStream->flags = 0; _CFStreamSetStatusCode(newStream, kCFStreamStatusNotOpen); - newStream->error.domain = 0; - newStream->error.error = 0; + newStream->error = NULL; newStream->client = NULL; newStream->info = NULL; newStream->callBacks = NULL; @@ -348,7 +357,7 @@ CF_EXPORT CFReadStreamRef CFReadStreamCreate(CFAllocatorRef alloc, const CFReadS struct _CFStream *newStream = _CFStreamCreate(alloc, TRUE); struct _CFStreamCallBacks *cb; if (!newStream) return NULL; - cb = CFAllocatorAllocate(alloc, sizeof(struct _CFStreamCallBacks), 0); + cb = (struct _CFStreamCallBacks *)CFAllocatorAllocate(alloc, sizeof(struct _CFStreamCallBacks), 0); if (!cb) { CFRelease(newStream); return NULL; @@ -361,11 +370,11 @@ CF_EXPORT CFReadStreamRef CFReadStreamCreate(CFAllocatorRef alloc, const CFReadS cb->create = (void *(*)(struct _CFStream *, void *))ctxt->retain; cb->finalize = (void(*)(struct _CFStream *, void *))ctxt->release; cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))ctxt->copyDescription; - cb->open = (Boolean(*)(struct _CFStream *, CFStreamError *, Boolean *, void *))cbV0->open; - cb->openCompleted = (Boolean (*)(struct _CFStream *, CFStreamError *, void *))cbV0->openCompleted; - cb->read = cbV0->read; - cb->getBuffer = cbV0->getBuffer; - cb->canRead = cbV0->canRead; + cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))cbV0->open; + cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))cbV0->openCompleted; + cb->read = (CFIndex (*)(CFReadStreamRef, UInt8 *, CFIndex, CFErrorRef *, Boolean *, void *))cbV0->read; + cb->getBuffer = (const UInt8 *(*)(CFReadStreamRef, CFIndex, CFIndex *, CFErrorRef *, Boolean *, void *))cbV0->getBuffer; + cb->canRead = (Boolean (*)(CFReadStreamRef, CFErrorRef*, void*))cbV0->canRead; cb->write = NULL; cb->canWrite = NULL; cb->close = (void (*)(struct _CFStream *, void *))cbV0->close; @@ -374,14 +383,34 @@ CF_EXPORT CFReadStreamRef CFReadStreamCreate(CFAllocatorRef alloc, const CFReadS cb->requestEvents = NULL; cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV0->schedule; cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV0->unschedule; + } else if (callbacks->version == 1) { + CFReadStreamCallBacksV1 *cbV1 = (CFReadStreamCallBacksV1 *)callbacks; + newStream->info = cbV1->create ? cbV1->create((CFReadStreamRef)newStream, info) : info; + cb->version = 1; + cb->create = (void *(*)(struct _CFStream *, void *))cbV1->create; + cb->finalize = (void(*)(struct _CFStream *, void *))cbV1->finalize; + cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))cbV1->copyDescription; + cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))cbV1->open; + cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))cbV1->openCompleted; + cb->read = (CFIndex (*)(CFReadStreamRef, UInt8 *, CFIndex, CFErrorRef *, Boolean *, void *))cbV1->read; + cb->getBuffer = (const UInt8 *(*)(CFReadStreamRef, CFIndex, CFIndex *, CFErrorRef *, Boolean *, void *))cbV1->getBuffer; + cb->canRead = (Boolean (*)(CFReadStreamRef, CFErrorRef*, void*))cbV1->canRead; + cb->write = NULL; + cb->canWrite = NULL; + cb->close = (void (*)(struct _CFStream *, void *))cbV1->close; + cb->copyProperty = (CFTypeRef (*)(struct _CFStream *, CFStringRef, void *))cbV1->copyProperty; + cb->setProperty = (Boolean(*)(struct _CFStream *, CFStringRef, CFTypeRef, void *))cbV1->setProperty; + cb->requestEvents = (void(*)(struct _CFStream *, CFOptionFlags, void *))cbV1->requestEvents; + cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV1->schedule; + cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV1->unschedule; } else { newStream->info = callbacks->create ? callbacks->create((CFReadStreamRef)newStream, info) : info; - cb->version = 1; + cb->version = 2; cb->create = (void *(*)(struct _CFStream *, void *))callbacks->create; cb->finalize = (void(*)(struct _CFStream *, void *))callbacks->finalize; cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))callbacks->copyDescription; - cb->open = (Boolean(*)(struct _CFStream *, CFStreamError *, Boolean *, void *))callbacks->open; - cb->openCompleted = (Boolean (*)(struct _CFStream *, CFStreamError *, void *))callbacks->openCompleted; + cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))callbacks->open; + cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))callbacks->openCompleted; cb->read = callbacks->read; cb->getBuffer = callbacks->getBuffer; cb->canRead = callbacks->canRead; @@ -393,7 +422,8 @@ CF_EXPORT CFReadStreamRef CFReadStreamCreate(CFAllocatorRef alloc, const CFReadS cb->requestEvents = (void(*)(struct _CFStream *, CFOptionFlags, void *))callbacks->requestEvents; cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))callbacks->schedule; cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))callbacks->unschedule; - } + } + newStream->callBacks = cb; return (CFReadStreamRef)newStream; } @@ -402,7 +432,7 @@ CF_EXPORT CFWriteStreamRef CFWriteStreamCreate(CFAllocatorRef alloc, const CFWri struct _CFStream *newStream = _CFStreamCreate(alloc, FALSE); struct _CFStreamCallBacks *cb; if (!newStream) return NULL; - cb = CFAllocatorAllocate(alloc, sizeof(struct _CFStreamCallBacks), 0); + cb = (struct _CFStreamCallBacks *)CFAllocatorAllocate(alloc, sizeof(struct _CFStreamCallBacks), 0); if (!cb) { CFRelease(newStream); return NULL; @@ -415,27 +445,47 @@ CF_EXPORT CFWriteStreamRef CFWriteStreamCreate(CFAllocatorRef alloc, const CFWri cb->create = (void *(*)(struct _CFStream *, void *))ctxt->retain; cb->finalize = (void(*)(struct _CFStream *, void *))ctxt->release; cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))ctxt->copyDescription; - cb->open = (Boolean(*)(struct _CFStream *, CFStreamError *, Boolean *, void *))cbV0->open; - cb->openCompleted = (Boolean (*)(struct _CFStream *, CFStreamError *, void *))cbV0->openCompleted; + cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))cbV0->open; + cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))cbV0->openCompleted; cb->read = NULL; cb->getBuffer = NULL; cb->canRead = NULL; - cb->write = cbV0->write; - cb->canWrite = cbV0->canWrite; + cb->write = (CFIndex(*)(CFWriteStreamRef stream, const UInt8 *buffer, CFIndex bufferLength, CFErrorRef *error, void *info))cbV0->write; + cb->canWrite = (Boolean(*)(CFWriteStreamRef stream, CFErrorRef *error, void *info))cbV0->canWrite; cb->close = (void (*)(struct _CFStream *, void *))cbV0->close; cb->copyProperty = (CFTypeRef (*)(struct _CFStream *, CFStringRef, void *))cbV0->copyProperty; cb->setProperty = NULL; cb->requestEvents = NULL; cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV0->schedule; cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV0->unschedule; + } else if (callbacks->version == 1) { + CFWriteStreamCallBacksV1 *cbV1 = (CFWriteStreamCallBacksV1 *)callbacks; + cb->version = 1; + newStream->info = cbV1->create ? cbV1->create((CFWriteStreamRef)newStream, info) : info; + cb->create = (void *(*)(struct _CFStream *, void *))cbV1->create; + cb->finalize = (void(*)(struct _CFStream *, void *))cbV1->finalize; + cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))cbV1->copyDescription; + cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))cbV1->open; + cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))cbV1->openCompleted; + cb->read = NULL; + cb->getBuffer = NULL; + cb->canRead = NULL; + cb->write = (CFIndex(*)(CFWriteStreamRef stream, const UInt8 *buffer, CFIndex bufferLength, CFErrorRef *error, void *info))cbV1->write; + cb->canWrite = (Boolean(*)(CFWriteStreamRef stream, CFErrorRef *error, void *info))cbV1->canWrite; + cb->close = (void (*)(struct _CFStream *, void *))cbV1->close; + cb->copyProperty = (CFTypeRef (*)(struct _CFStream *, CFStringRef, void *))cbV1->copyProperty; + cb->setProperty = (Boolean (*)(struct _CFStream *, CFStringRef, CFTypeRef, void *))cbV1->setProperty; + cb->requestEvents = (void(*)(struct _CFStream *, CFOptionFlags, void *))cbV1->requestEvents; + cb->schedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV1->schedule; + cb->unschedule = (void (*)(struct _CFStream *, CFRunLoopRef, CFStringRef, void *))cbV1->unschedule; } else { cb->version = callbacks->version; newStream->info = callbacks->create ? callbacks->create((CFWriteStreamRef)newStream, info) : info; cb->create = (void *(*)(struct _CFStream *, void *))callbacks->create; cb->finalize = (void(*)(struct _CFStream *, void *))callbacks->finalize; cb->copyDescription = (CFStringRef(*)(struct _CFStream *, void *))callbacks->copyDescription; - cb->open = (Boolean(*)(struct _CFStream *, CFStreamError *, Boolean *, void *))callbacks->open; - cb->openCompleted = (Boolean (*)(struct _CFStream *, CFStreamError *, void *))callbacks->openCompleted; + cb->open = (Boolean(*)(struct _CFStream *, CFErrorRef *, Boolean *, void *))callbacks->open; + cb->openCompleted = (Boolean (*)(struct _CFStream *, CFErrorRef *, void *))callbacks->openCompleted; cb->read = NULL; cb->getBuffer = NULL; cb->canRead = NULL; @@ -547,13 +597,14 @@ static void _wakeUpRunLoop(struct _CFStream *stream) { if (NULL != rl && CFRunLoopIsWaiting(rl)) CFRunLoopWakeUp(rl); } -__private_extern__ void _CFStreamSignalEvent(struct _CFStream *stream, CFStreamEventType event, CFStreamError *error, Boolean synchronousAllowed) { +__private_extern__ void _CFStreamSignalEvent(struct _CFStream *stream, CFStreamEventType event, CFErrorRef error, Boolean synchronousAllowed) { // Update our internal status; we must use the primitive __CFStreamGetStatus(), because CFStreamGetStatus() calls us, and we can end up in an infinite loop. CFStreamStatus status = __CFStreamGetStatus(stream); + // Sanity check the event if (status == kCFStreamStatusNotOpen) { // No events allowed; this is almost certainly a bug in the stream's implementation - CFLog(__kCFLogAssertion, CFSTR("Stream 0x%x is sending an event before being opened"), stream); + CFLog(__kCFLogAssertion, CFSTR("Stream %p is sending an event before being opened"), stream); event = 0; } else if (status == kCFStreamStatusClosed || status == kCFStreamStatusError) { // no further events are allowed @@ -574,8 +625,14 @@ __private_extern__ void _CFStreamSignalEvent(struct _CFStream *stream, CFStreamE _CFStreamSetStatusCode(stream, kCFStreamStatusAtEnd); } if (event & kCFStreamEventErrorOccurred) { - stream->error.domain = error->domain; - stream->error.error = error->error; + if (_CFStreamGetCallBackPtr(stream)->version < 2) { + _CFStreamSetStreamError(stream, (CFStreamError *)error); + } else { + CFAssert(error, __kCFLogAssertion, "CFStream: kCFStreamEventErrorOccurred signalled, but error is NULL!"); + CFRetain(error); + if (stream->error) CFRelease(stream->error); + stream->error = error; + } _CFStreamSetStatusCode(stream, kCFStreamStatusError); } @@ -610,27 +667,37 @@ __private_extern__ void _CFStreamSignalEvent(struct _CFStream *stream, CFStreamE } __private_extern__ CFStreamStatus _CFStreamGetStatus(struct _CFStream *stream) { - CFStreamStatus status = __CFStreamGetStatus(stream); - // Status code just represents the value when last we checked; if we were in the middle of doing work at that time, we need to find out if the work has completed, now. If we find out about a status change, we need to inform the client as well, so we call _CFStreamSignalEvent. This will take care of updating our internal status correctly, too. - __CFBitSet(stream->flags, CALLING_CLIENT); - if (status == kCFStreamStatusOpening) { - const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream); - if (cb->openCompleted && cb->openCompleted(stream, &(stream->error), _CFStreamGetInfoPointer(stream))) { - if (stream->error.error == 0) { - status = kCFStreamStatusOpen; - } else { - status = kCFStreamStatusError; - } - _CFStreamSetStatusCode(stream, status); - if (status == kCFStreamStatusOpen) { - _CFStreamScheduleEvent(stream, kCFStreamEventOpenCompleted); - } else { - _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred); - } - } + CFStreamStatus status = __CFStreamGetStatus(stream); + // Status code just represents the value when last we checked; if we were in the middle of doing work at that time, we need to find out if the work has completed, now. If we find out about a status change, we need to inform the client as well, so we call _CFStreamSignalEvent. This will take care of updating our internal status correctly, too. + __CFBitSet(stream->flags, CALLING_CLIENT); + if (status == kCFStreamStatusOpening) { + const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream); + if (cb->openCompleted) { + Boolean isComplete; + if (cb->version < 2) { + CFStreamError err = {0, 0}; + isComplete = ((_CFStreamCBOpenCompletedV1)(cb->openCompleted))(stream, &err, _CFStreamGetInfoPointer(stream)); + if (err.error != 0) _CFStreamSetStreamError(stream, &err); + } else { + isComplete = cb->openCompleted(stream, &(stream->error), _CFStreamGetInfoPointer(stream)); + } + if (isComplete) { + if (!stream->error) { + status = kCFStreamStatusOpen; + } else { + status = kCFStreamStatusError; + } + _CFStreamSetStatusCode(stream, status); + if (status == kCFStreamStatusOpen) { + _CFStreamScheduleEvent(stream, kCFStreamEventOpenCompleted); + } else { + _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred); + } + } } - __CFBitClear(stream->flags, CALLING_CLIENT); - return status; + } + __CFBitClear(stream->flags, CALLING_CLIENT); + return status; } CF_EXPORT CFStreamStatus CFReadStreamGetStatus(CFReadStreamRef stream) { @@ -643,14 +710,50 @@ CF_EXPORT CFStreamStatus CFWriteStreamGetStatus(CFWriteStreamRef stream) { return _CFStreamGetStatus((struct _CFStream *)stream); } +static CFStreamError _CFStreamGetStreamError(struct _CFStream *stream) { + CFStreamError result; + if (!stream->error) { + result.error = 0; + result.domain = 0; + } else if (_CFStreamGetCallBackPtr(stream)->version < 2) { + CFStreamError *streamError = (CFStreamError *)(stream->error); + result.error = streamError->error; + result.domain = streamError->domain; + } else { + result = _CFStreamErrorFromError(stream->error); + } + return result; +} + CF_EXPORT CFStreamError CFReadStreamGetError(CFReadStreamRef stream) { CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID, CFStreamError, stream, "_cfStreamError"); - return ((struct _CFStream *)stream)->error; + return _CFStreamGetStreamError((struct _CFStream *)stream); } CF_EXPORT CFStreamError CFWriteStreamGetError(CFWriteStreamRef stream) { CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID, CFStreamError, stream, "_cfStreamError"); - return ((struct _CFStream *)stream)->error; + return _CFStreamGetStreamError((struct _CFStream *)stream); +} + +static CFErrorRef _CFStreamCopyError(struct _CFStream *stream) { + if (!stream->error) { + return NULL; + } else if (_CFStreamGetCallBackPtr(stream)->version < 2) { + return _CFErrorFromStreamError(CFGetAllocator(stream), (CFStreamError *)(stream->error)); + } else { + CFRetain(stream->error); + return stream->error; + } +} + +CF_EXPORT CFErrorRef CFReadStreamCopyError(CFReadStreamRef stream) { + CF_OBJC_FUNCDISPATCH0(__kCFReadStreamTypeID, CFErrorRef, stream, "streamError"); + return _CFStreamCopyError((struct _CFStream *)stream); +} + +CF_EXPORT CFErrorRef CFWriteStreamCopyError(CFWriteStreamRef stream) { + return _CFStreamCopyError((struct _CFStream *)stream); + CF_OBJC_FUNCDISPATCH0(__kCFWriteStreamTypeID, CFErrorRef, stream, "streamError"); } __private_extern__ Boolean _CFStreamOpen(struct _CFStream *stream) { @@ -662,7 +765,13 @@ __private_extern__ Boolean _CFStreamOpen(struct _CFStream *stream) { __CFBitSet(stream->flags, CALLING_CLIENT); _CFStreamSetStatusCode(stream, kCFStreamStatusOpening); if (cb->open) { - success = cb->open(stream, &(stream->error), &openComplete, _CFStreamGetInfoPointer(stream)); + if (cb->version < 2) { + CFStreamError err = {0, 0}; + success = ((_CFStreamCBOpenV1)(cb->open))(stream, &err, &openComplete, _CFStreamGetInfoPointer(stream)); + if (err.error != 0) _CFStreamSetStreamError(stream, &err); + } else { + success = cb->open(stream, &(stream->error), &openComplete, _CFStreamGetInfoPointer(stream)); + } } else { success = TRUE; openComplete = TRUE; @@ -677,7 +786,6 @@ __private_extern__ Boolean _CFStreamOpen(struct _CFStream *stream) { } else { _CFStreamSetStatusCode(stream, kCFStreamStatusError); _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred); - __CFBitSet(stream->flags, HAVE_CLOSED); } } __CFBitClear(stream->flags, CALLING_CLIENT); @@ -724,7 +832,15 @@ CF_EXPORT Boolean CFReadStreamHasBytesAvailable(CFReadStreamRef readStream) { } else { Boolean result; __CFBitSet(stream->flags, CALLING_CLIENT); - result = cb->canRead((CFReadStreamRef)stream, _CFStreamGetInfoPointer(stream)); + if (cb->version < 2) { + result = ((_CFStreamCBCanReadV1)(cb->canRead))((CFReadStreamRef)stream, _CFStreamGetInfoPointer(stream)); + } else { + result = cb->canRead((CFReadStreamRef)stream, &(stream->error), _CFStreamGetInfoPointer(stream)); + if (stream->error) { + _CFStreamSetStatusCode(stream, kCFStreamStatusError); + _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred); + } + } __CFBitClear(stream->flags, CALLING_CLIENT); return result; } @@ -755,8 +871,14 @@ CFIndex CFReadStreamRead(CFReadStreamRef readStream, UInt8 *buffer, CFIndex buff stream->client->whatToSignal &= ~kCFStreamEventHasBytesAvailable; } _CFStreamSetStatusCode(stream, kCFStreamStatusReading); - bytesRead = cb->read((CFReadStreamRef)stream, buffer, bufferLength, &(stream->error), &atEOF, _CFStreamGetInfoPointer(stream)); - if (stream->error.error != 0) { + if (cb->version < 2) { + CFStreamError err = {0, 0}; + bytesRead = ((_CFStreamCBReadV1)(cb->read))((CFReadStreamRef)stream, buffer, bufferLength, &err, &atEOF, _CFStreamGetInfoPointer(stream)); + if (err.error != 0) _CFStreamSetStreamError(stream, &err); + } else { + bytesRead = cb->read((CFReadStreamRef)stream, buffer, bufferLength, &(stream->error), &atEOF, _CFStreamGetInfoPointer(stream)); + } + if (stream->error) { bytesRead = -1; _CFStreamSetStatusCode(stream, kCFStreamStatusError); _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred); @@ -806,8 +928,14 @@ CF_EXPORT const UInt8 *CFReadStreamGetBuffer(CFReadStreamRef readStream, CFIndex stream->client->whatToSignal &= ~kCFStreamEventHasBytesAvailable; } _CFStreamSetStatusCode(stream, kCFStreamStatusReading); - buffer = cb->getBuffer((CFReadStreamRef)stream, maxBytesToRead, numBytesRead, &(stream->error), &atEOF, _CFStreamGetInfoPointer(stream)); - if (stream->error.error != 0) { + if (cb->version < 2) { + CFStreamError err = {0, 0}; + buffer = ((_CFStreamCBGetBufferV1)(cb->getBuffer))((CFReadStreamRef)stream, maxBytesToRead, numBytesRead, &err, &atEOF, _CFStreamGetInfoPointer(stream)); + if (err.error != 0) _CFStreamSetStreamError(stream, &err); + } else { + buffer = cb->getBuffer((CFReadStreamRef)stream, maxBytesToRead, numBytesRead, &(stream->error), &atEOF, _CFStreamGetInfoPointer(stream)); + } + if (stream->error) { *numBytesRead = -1; _CFStreamSetStatusCode(stream, kCFStreamStatusError); buffer = NULL; @@ -840,7 +968,15 @@ CF_EXPORT Boolean CFWriteStreamCanAcceptBytes(CFWriteStreamRef writeStream) { } else { Boolean result; __CFBitSet(stream->flags, CALLING_CLIENT); - result = cb->canWrite((CFWriteStreamRef)stream, _CFStreamGetInfoPointer(stream)); + if (cb->version < 2) { + result = ((_CFStreamCBCanWriteV1)(cb->canWrite))((CFWriteStreamRef)stream, _CFStreamGetInfoPointer(stream)); + } else { + result = cb->canWrite((CFWriteStreamRef)stream, &(stream->error), _CFStreamGetInfoPointer(stream)); + if (stream->error) { + _CFStreamSetStatusCode(stream, kCFStreamStatusError); + _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred); + } + } __CFBitClear(stream->flags, CALLING_CLIENT); return result; } @@ -866,8 +1002,14 @@ CF_EXPORT CFIndex CFWriteStreamWrite(CFWriteStreamRef writeStream, const UInt8 * if (stream->client) { stream->client->whatToSignal &= ~kCFStreamEventCanAcceptBytes; } - result = cb->write((CFWriteStreamRef)stream, buffer, bufferLength, &(stream->error), _CFStreamGetInfoPointer(stream)); - if (stream->error.error != 0) { + if (cb->version < 2) { + CFStreamError err = {0, 0}; + result = ((_CFStreamCBWriteV1)(cb->write))((CFWriteStreamRef)stream, buffer, bufferLength, &err, _CFStreamGetInfoPointer(stream)); + if (err.error) _CFStreamSetStreamError(stream, &err); + } else { + result = cb->write((CFWriteStreamRef)stream, buffer, bufferLength, &(stream->error), _CFStreamGetInfoPointer(stream)); + } + if (stream->error) { _CFStreamSetStatusCode(stream, kCFStreamStatusError); _CFStreamScheduleEvent(stream, kCFStreamEventErrorOccurred); } else if (result == 0) { @@ -932,7 +1074,7 @@ Boolean CFWriteStreamSetProperty(CFWriteStreamRef stream, CFStringRef propertyNa static void _initializeClient(struct _CFStream *stream) { const struct _CFStreamCallBacks *cb = _CFStreamGetCallBackPtr(stream); if (!cb->schedule) return; // Do we wish to allow this? - stream->client = CFAllocatorAllocate(CFGetAllocator(stream), sizeof(struct _CFStreamClient), 0); + stream->client = (struct _CFStreamClient *)CFAllocatorAllocate(CFGetAllocator(stream), sizeof(struct _CFStreamClient), 0); memset(stream->client, 0, sizeof(struct _CFStreamClient)); } @@ -994,7 +1136,7 @@ CF_EXPORT Boolean CFWriteStreamSetClient(CFWriteStreamRef writeStream, CFOptionF return _CFStreamSetClient((struct _CFStream *)writeStream, streamEvents, (void (*)(struct _CFStream *, CFStreamEventType, void *))clientCB, clientContext); } -static inline void *_CFStreamGetClient(struct _CFStream *stream) { +CF_INLINE void *_CFStreamGetClient(struct _CFStream *stream) { if (stream->client) return stream->client->cbContext.info; else return NULL; } @@ -1025,12 +1167,12 @@ __private_extern__ void _CFStreamScheduleWithRunLoop(struct _CFStream *stream, C a[0] = runLoop; a[1] = runLoopMode; - key = CFArrayCreate(kCFAllocatorDefault, a, sizeof(a) / sizeof(a[0]), &kCFTypeArrayCallBacks); + key = CFArrayCreate(kCFAllocatorSystemDefault, a, sizeof(a) / sizeof(a[0]), &kCFTypeArrayCallBacks); __CFSpinLock(&sSourceLock); if (!sSharedSources) - sSharedSources = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + sSharedSources = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); list = (CFMutableArrayRef)CFDictionaryGetValue(sSharedSources, key); if (list) { @@ -1041,17 +1183,17 @@ __private_extern__ void _CFStreamScheduleWithRunLoop(struct _CFStream *stream, C CFRunLoopSourceContext ctxt = { 0, NULL, - NULL, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop - NULL, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop + NULL, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop + NULL, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop (CFStringRef(*)(const void *))CFCopyDescription, - /*(Boolean(*)(const void *, const void *))CFEqual*/ NULL, - (CFHashCode(*)(const void *))__CFStreamHash, + NULL, + NULL, NULL, NULL, (void(*)(void *))_CFStreamSignalEventSynch }; - list = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); + list = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); CFDictionaryAddValue(sSharedSources, key, list); ctxt.info = list; @@ -1085,8 +1227,8 @@ __private_extern__ void _CFStreamScheduleWithRunLoop(struct _CFStream *stream, C NULL, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop NULL, // Do not use CFRetain/CFRelease callbacks here; that will cause a retain loop (CFStringRef(*)(const void *))CFCopyDescription, - /*(Boolean(*)(const void *, const void *))CFEqual*/ NULL, - (CFHashCode(*)(const void *))__CFStreamHash, + NULL, + NULL, NULL, NULL, (void(*)(void *))_CFStreamSignalEventSynch @@ -1219,7 +1361,7 @@ static void waitForOpen(struct _CFStream *stream) { _CFStreamUnscheduleFromRunLoop(stream, runLoop, privateMode); } -static inline CFArrayRef _CFStreamGetRunLoopsAndModes(struct _CFStream *stream) { +CF_INLINE CFArrayRef _CFStreamGetRunLoopsAndModes(struct _CFStream *stream) { if (stream->client) return stream->client->runLoopsAndModes; else return NULL; } @@ -1232,20 +1374,27 @@ CF_EXPORT CFArrayRef _CFWriteStreamGetRunLoopsAndModes(CFWriteStreamRef writeStr return _CFStreamGetRunLoopsAndModes((struct _CFStream *)writeStream); } -CF_EXPORT void CFReadStreamSignalEvent(CFReadStreamRef stream, CFStreamEventType event, CFStreamError *error) { - _CFStreamSignalEvent((struct _CFStream *)stream, event, error, TRUE); +CF_EXPORT void CFReadStreamSignalEvent(CFReadStreamRef stream, CFStreamEventType event, const void *error) { + _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, TRUE); +} + +CF_EXPORT void CFWriteStreamSignalEvent(CFWriteStreamRef stream, CFStreamEventType event, const void *error) { + _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, TRUE); } -CF_EXPORT void CFWriteStreamSignalEvent(CFWriteStreamRef stream, CFStreamEventType event, CFStreamError *error) { - _CFStreamSignalEvent((struct _CFStream *)stream, event, error, TRUE); +CF_EXPORT void _CFReadStreamSignalEventDelayed(CFReadStreamRef stream, CFStreamEventType event, const void *error) { + _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, FALSE); } -CF_EXPORT void _CFReadStreamSignalEventDelayed(CFReadStreamRef stream, CFStreamEventType event, CFStreamError *error) { - _CFStreamSignalEvent((struct _CFStream *)stream, event, error, FALSE); +CF_EXPORT void _CFReadStreamClearEvent(CFReadStreamRef readStream, CFStreamEventType event) { + struct _CFStream *stream = (struct _CFStream *)readStream; + if (stream->client) { + stream->client->whatToSignal &= ~event; + } } -CF_EXPORT void _CFWriteStreamSignalEventDelayed(CFWriteStreamRef stream, CFStreamEventType event, CFStreamError *error) { - _CFStreamSignalEvent((struct _CFStream *)stream, event, error, FALSE); +CF_EXPORT void _CFWriteStreamSignalEventDelayed(CFWriteStreamRef stream, CFStreamEventType event, const void *error) { + _CFStreamSignalEvent((struct _CFStream *)stream, event, (CFErrorRef)error, FALSE); } CF_EXPORT void *CFReadStreamGetInfoPointer(CFReadStreamRef stream) { @@ -1256,11 +1405,6 @@ CF_EXPORT void *CFWriteStreamGetInfoPointer(CFWriteStreamRef stream) { return _CFStreamGetInfoPointer((struct _CFStream *)stream); } -#if defined(__MACH__) -#pragma mark - -#pragma mark Scheduling Convenience Routines -#endif - /* CF_EXPORT */ void _CFStreamSourceScheduleWithRunLoop(CFRunLoopSourceRef source, CFMutableArrayRef runLoopsAndModes, CFRunLoopRef runLoop, CFStringRef runLoopMode) { @@ -1384,24 +1528,8 @@ Boolean _CFStreamRemoveRunLoopAndModeFromArray(CFMutableArrayRef runLoopsAndMode return found; } - -#if defined(__WIN32__) - -void __CFStreamCleanup(void) { - __CFSpinLock(&sSourceLock); - if (sSharedSources) { - CFIndex count = CFDictionaryGetCount(sSharedSources); - if (count == 0) { - // Only release if empty. If it's still holding streams (which would be a client - // bug leak), freeing this dict would free the streams, which then need to access the - // dict to remove themselves, which leads to a deadlock. - CFRelease(sSharedSources); - sSharedSources = NULL; - } else - fprintf(stderr, "*** CFNetwork is shutting down, but %ld streams are still scheduled.\n", count); - } - __CFSpinUnlock(&sSourceLock); +// Used by NSStream to properly allocate the bridged objects +CF_EXPORT CFIndex _CFStreamInstanceSize(void) { + return sizeof(struct _CFStream); } -#endif - diff --git a/AppServices.subproj/CFStream.h b/CFStream.h similarity index 90% rename from AppServices.subproj/CFStream.h rename to CFStream.h index 471deaf..3f29456 100644 --- a/AppServices.subproj/CFStream.h +++ b/CFStream.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFStream.h - Copyright (c) 2000-2005, Apple, Inc. All rights reserved. + Copyright (c) 2000-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSTREAM__) @@ -33,12 +33,11 @@ #include #include #include +#include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN -typedef enum { +enum { kCFStreamStatusNotOpen = 0, kCFStreamStatusOpening, /* open is in-progress */ kCFStreamStatusOpen, @@ -47,27 +46,18 @@ typedef enum { kCFStreamStatusAtEnd, /* no further bytes can be read/written */ kCFStreamStatusClosed, kCFStreamStatusError -} CFStreamStatus; - -typedef enum { - kCFStreamErrorDomainCustom = -1, /* custom to the kind of stream in question */ - kCFStreamErrorDomainPOSIX = 1, /* POSIX errno; interpret using */ - kCFStreamErrorDomainMacOSStatus /* OSStatus type from Carbon APIs; interpret using */ -} CFStreamErrorDomain; - -typedef struct { - CFStreamErrorDomain domain; - SInt32 error; -} CFStreamError; +}; +typedef CFIndex CFStreamStatus; -typedef enum { +enum { kCFStreamEventNone = 0, kCFStreamEventOpenCompleted = 1, kCFStreamEventHasBytesAvailable = 2, kCFStreamEventCanAcceptBytes = 4, kCFStreamEventErrorOccurred = 8, kCFStreamEventEndEncountered = 16 -} CFStreamEventType; +}; +typedef CFOptionFlags CFStreamEventType; typedef struct { CFIndex version; @@ -111,6 +101,8 @@ CF_EXPORT CFReadStreamRef CFReadStreamCreateWithFile(CFAllocatorRef alloc, CFURLRef fileURL); CF_EXPORT CFWriteStreamRef CFWriteStreamCreateWithFile(CFAllocatorRef alloc, CFURLRef fileURL); +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 */ @@ -155,13 +147,11 @@ CFStreamStatus CFReadStreamGetStatus(CFReadStreamRef stream); CF_EXPORT CFStreamStatus CFWriteStreamGetStatus(CFWriteStreamRef stream); -/* 0 is returned if no error has occurred. errorDomain specifies the domain - in which the error code should be interpretted; pass NULL if you are not - interested. */ +/* Returns NULL if no error has occurred; otherwise returns the error. */ CF_EXPORT -CFStreamError CFReadStreamGetError(CFReadStreamRef stream); +CFErrorRef CFReadStreamCopyError(CFReadStreamRef stream) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; CF_EXPORT -CFStreamError CFWriteStreamGetError(CFWriteStreamRef stream); +CFErrorRef CFWriteStreamCopyError(CFWriteStreamRef stream) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; /* 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 @@ -253,9 +243,11 @@ Boolean CFWriteStreamSetProperty(CFWriteStreamRef stream, CFStringRef propertyNa run loops; It is the caller's responsibility to ensure that at least one of the scheduled run loops is being run. - NOTE: not all streams provide these notifications. If a stream does not support - asynchronous notification, CFStreamSetClient() will return NO; typically, such - streams will never block for device I/O (e.g. a stream on memory) + NOTE: Unlike other CoreFoundation APIs, pasing a NULL clientContext here will remove + the client. If you do not care about the client context (i.e. your only concern + is that your callback be called), you should pass in a valid context where every + entry is 0 or NULL. + */ CF_EXPORT @@ -273,8 +265,25 @@ void CFReadStreamUnscheduleFromRunLoop(CFReadStreamRef stream, CFRunLoopRef runL CF_EXPORT void CFWriteStreamUnscheduleFromRunLoop(CFWriteStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode); -#if defined(__cplusplus) -} -#endif + +/* The following API is deprecated starting in 10.5; please use CFRead/WriteStreamCopyError(), above, instead */ +enum { + kCFStreamErrorDomainCustom = -1, /* custom to the kind of stream in question */ + kCFStreamErrorDomainPOSIX = 1, /* POSIX errno; interpret using */ + kCFStreamErrorDomainMacOSStatus /* OSStatus type from Carbon APIs; interpret using */ +}; +typedef CFIndex CFStreamErrorDomain; + +typedef struct { + CFIndex domain; + SInt32 error; +} CFStreamError; +CF_EXPORT +CFStreamError CFReadStreamGetError(CFReadStreamRef stream); +CF_EXPORT +CFStreamError CFWriteStreamGetError(CFWriteStreamRef stream); + + +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFSTREAM__ */ diff --git a/Stream.subproj/CFStreamAbstract.h b/CFStreamAbstract.h similarity index 74% rename from Stream.subproj/CFStreamAbstract.h rename to CFStreamAbstract.h index d023244..b36fe11 100644 --- a/Stream.subproj/CFStreamAbstract.h +++ b/CFStreamAbstract.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFStreamAbstract.h - Copyright (c) 2000-2005, Apple, Inc. All rights reserved. + Copyright (c) 2000-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSTREAMABSTRACT__) @@ -29,60 +29,67 @@ #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN +/* During a stream's lifetime, the open callback will be called once, followed by any number of openCompleted calls (until openCompleted returns TRUE). Then any number of read/canRead or write/canWrite calls, then a single close call. copyProperty can be called at any time. prepareAsynch will be called exactly once when the stream's client is first configured. + + Expected semantics: + - open reserves any system resources that are needed. The stream may start the process of opening, returning TRUE immediately and setting openComplete to FALSE. When the open completes, _CFStreamSignalEvent should be called passing kCFStreamOpenCompletedEvent. openComplete should be set to TRUE only if the open operation completed in its entirety. + - openCompleted will only be called after open has been called, but before any kCFStreamOpenCompletedEvent has been received. Return TRUE, setting error.code to 0, if the open operation has completed. Return TRUE, setting error to the correct error code and domain if the open operation completed, but failed. Return FALSE if the open operation is still in-progress. If your open ever fails to complete (i.e. sets openComplete to FALSE), you must be implement the openCompleted callback. + - read should read into the given buffer, returning the number of bytes successfully read. read must block until at least one byte is available, but should not block until the entire buffer is filled; zero should only be returned if end-of-stream is encountered. atEOF should be set to true if the EOF is encountered, false otherwise. error.code should be set to zero if no error occurs; otherwise, error should be set to the appropriate values. + - getBuffer is an optimization to return an internal buffer of bytes read from the stream, and may return NULL. getBuffer itself may be NULL if the concrete implementation does not wish to provide an internal buffer. If implemented, it should set numBytesRead to the number of bytes available in the internal buffer (but should not exceed maxBytesToRead) and return a pointer to the base of the bytes. + - canRead will only be called once openCompleted reports that the stream has been successfully opened (or the initial open call succeeded). It should return whether there are bytes that can be read without blocking. + - write should write the bytes in the given buffer to the device, returning the number of bytes successfully written. write must block until at least one byte is written. error.code should be set to zero if no error occurs; otherwise, error should be set to the appropriate values. + - close should close the device, releasing any reserved system resources. close cannot fail (it may be called to abort the stream), and may be called at any time after open has been called. It will only be called once. + - copyProperty should return the value for the given property, or NULL if none exists. Composite streams (streams built on top of other streams) should take care to call CFStreamCopyProperty on the base stream if they do not recognize the property given, to give the underlying stream a chance to respond. + + In all cases, errors returned by reference will be initialized to NULL by the caller, and if they are set to non-NULL, will + be released by the caller +*/ + typedef struct { - CFIndex version; /* == 1 */ + CFIndex version; /* == 2 */ + void *(*create)(CFReadStreamRef stream, void *info); void (*finalize)(CFReadStreamRef stream, void *info); CFStringRef (*copyDescription)(CFReadStreamRef stream, void *info); - Boolean (*open)(CFReadStreamRef stream, CFStreamError *error, Boolean *openComplete, void *info); - Boolean (*openCompleted)(CFReadStreamRef stream, CFStreamError *error, void *info); - CFIndex (*read)(CFReadStreamRef stream, UInt8 *buffer, CFIndex bufferLength, CFStreamError *error, Boolean *atEOF, void *info); - const UInt8 *(*getBuffer)(CFReadStreamRef stream, CFIndex maxBytesToRead, CFIndex *numBytesRead, CFStreamError *error, Boolean *atEOF, void *info); - Boolean (*canRead)(CFReadStreamRef stream, void *info); + + Boolean (*open)(CFReadStreamRef stream, CFErrorRef *error, Boolean *openComplete, void *info); + Boolean (*openCompleted)(CFReadStreamRef stream, CFErrorRef *error, void *info); + CFIndex (*read)(CFReadStreamRef stream, UInt8 *buffer, CFIndex bufferLength, CFErrorRef *error, Boolean *atEOF, void *info); + const UInt8 *(*getBuffer)(CFReadStreamRef stream, CFIndex maxBytesToRead, CFIndex *numBytesRead, CFErrorRef *error, Boolean *atEOF, void *info); + Boolean (*canRead)(CFReadStreamRef stream, CFErrorRef *error, void *info); void (*close)(CFReadStreamRef stream, void *info); + CFTypeRef (*copyProperty)(CFReadStreamRef stream, CFStringRef propertyName, void *info); Boolean (*setProperty)(CFReadStreamRef stream, CFStringRef propertyName, CFTypeRef propertyValue, void *info); + void (*requestEvents)(CFReadStreamRef stream, CFOptionFlags streamEvents, void *info); void (*schedule)(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info); void (*unschedule)(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info); } CFReadStreamCallBacks; typedef struct { - CFIndex version; /* == 1 */ + CFIndex version; /* == 2 */ void *(*create)(CFWriteStreamRef stream, void *info); void (*finalize)(CFWriteStreamRef stream, void *info); CFStringRef (*copyDescription)(CFWriteStreamRef stream, void *info); - Boolean (*open)(CFWriteStreamRef stream, CFStreamError *error, Boolean *openComplete, void *info); - Boolean (*openCompleted)(CFWriteStreamRef stream, CFStreamError *error, void *info); - CFIndex (*write)(CFWriteStreamRef stream, const UInt8 *buffer, CFIndex bufferLength, CFStreamError *error, void *info); - Boolean (*canWrite)(CFWriteStreamRef stream, void *info); + Boolean (*open)(CFWriteStreamRef stream, CFErrorRef *error, Boolean *openComplete, void *info); + Boolean (*openCompleted)(CFWriteStreamRef stream, CFErrorRef *error, void *info); + CFIndex (*write)(CFWriteStreamRef stream, const UInt8 *buffer, CFIndex bufferLength, CFErrorRef *error, void *info); + Boolean (*canWrite)(CFWriteStreamRef stream, CFErrorRef *error, void *info); void (*close)(CFWriteStreamRef stream, void *info); + CFTypeRef (*copyProperty)(CFWriteStreamRef stream, CFStringRef propertyName, void *info); Boolean (*setProperty)(CFWriteStreamRef stream, CFStringRef propertyName, CFTypeRef propertyValue, void *info); + void (*requestEvents)(CFWriteStreamRef stream, CFOptionFlags streamEvents, void *info); void (*schedule)(CFWriteStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info); void (*unschedule)(CFWriteStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info); } CFWriteStreamCallBacks; -/* During a stream's lifetime, the open callback will be called once, followed by any number of openCompleted calls (until openCompleted returns TRUE). Then any number of read/canRead or write/canWrite calls, then a single close call. copyProperty can be called at any time. prepareAsynch will be called exactly once when the stream's client is first configured. - - Expected semantics: - - open reserves any system resources that are needed. The stream may start the process of opening, returning TRUE immediately and setting openComplete to FALSE. When the open completes, _CFStreamSignalEvent should be called passing kCFStreamOpenCompletedEvent. openComplete should be set to TRUE only if the open operation completed in its entirety. - - openCompleted will only be called after open has been called, but before any kCFStreamOpenCompletedEvent has been received. Return TRUE, setting error.code to 0, if the open operation has completed. Return TRUE, setting error to the correct error code and domain if the open operation completed, but failed. Return FALSE if the open operation is still in-progress. If your open ever fails to complete (i.e. sets openComplete to FALSE), you must be implement the openCompleted callback. - - read should read into the given buffer, returning the number of bytes successfully read. read must block until at least one byte is available, but should not block until the entire buffer is filled; zero should only be returned if end-of-stream is encountered. atEOF should be set to true if the EOF is encountered, false otherwise. error.code should be set to zero if no error occurs; otherwise, error should be set to the appropriate values. - - getBuffer is an optimization to return an internal buffer of bytes read from the stream, and may return NULL. getBuffer itself may be NULL if the concrete implementation does not wish to provide an internal buffer. If implemented, it should set numBytesRead to the number of bytes available in the internal buffer (but should not exceed maxBytesToRead) and return a pointer to the base of the bytes. - - canRead will only be called once openCompleted reports that the stream has been successfully opened (or the initial open call succeeded). It should return whether there are bytes that can be read without blocking. - - write should write the bytes in the given buffer to the device, returning the number of bytes successfully written. write must block until at least one byte is written. error.code should be set to zero if no error occurs; otherwise, error should be set to the appropriate values. - - close should close the device, releasing any reserved system resources. close cannot fail (it may be called to abort the stream), and may be called at any time after open has been called. It will only be called once. - - copyProperty should return the value for the given property, or NULL if none exists. Composite streams (streams built on top of other streams) should take care to call CFStreamCopyProperty on the base stream if they do not recognize the property given, to give the underlying stream a chance to respond. -*/ - // Primitive creation mechanisms. CF_EXPORT CFReadStreamRef CFReadStreamCreate(CFAllocatorRef alloc, const CFReadStreamCallBacks *callbacks, void *info); @@ -94,16 +101,24 @@ CFWriteStreamRef CFWriteStreamCreate(CFAllocatorRef alloc, const CFWriteStreamCa so the caller must be sure the argument passed is not such an object. */ // To be called by the concrete stream implementation (the callbacks) when an event occurs. error may be NULL if event != kCFStreamEventErrorOccurred +// error should be a CFErrorRef if the callbacks are version 2 or later; otherwise it should be a (CFStreamError *). +CF_EXPORT +void CFReadStreamSignalEvent(CFReadStreamRef stream, CFStreamEventType event, const void *error); CF_EXPORT -void CFReadStreamSignalEvent(CFReadStreamRef stream, CFStreamEventType event, CFStreamError *error); +void CFWriteStreamSignalEvent(CFWriteStreamRef stream, CFStreamEventType event, const void *error); + +// These require that the stream allow the run loop to run once before delivering the event to its client. +// See the comment above CFRead/WriteStreamSignalEvent for interpretation of the error argument. CF_EXPORT -void CFWriteStreamSignalEvent(CFWriteStreamRef stream, CFStreamEventType event, CFStreamError *error); +void _CFReadStreamSignalEventDelayed(CFReadStreamRef stream, CFStreamEventType event, const void *error); CF_EXPORT +void _CFWriteStreamSignalEventDelayed(CFWriteStreamRef stream, CFStreamEventType event, const void *error); -// These require that the stream allow the run loop to run once before delivering the event to its client. -void _CFReadStreamSignalEventDelayed(CFReadStreamRef stream, CFStreamEventType event, CFStreamError *error); CF_EXPORT -void _CFWriteStreamSignalEventDelayed(CFWriteStreamRef stream, CFStreamEventType event, CFStreamError *error); +void _CFReadStreamClearEvent(CFReadStreamRef stream, CFStreamEventType event); +// Write variant not currently needed +//CF_EXPORT +//void _CFWriteStreamClearEvent(CFWriteStreamRef stream, CFStreamEventType event); // Convenience for concrete implementations to extract the info pointer given the stream. CF_EXPORT @@ -123,7 +138,42 @@ CFArrayRef _CFReadStreamGetRunLoopsAndModes(CFReadStreamRef readStream); CF_EXPORT CFArrayRef _CFWriteStreamGetRunLoopsAndModes(CFWriteStreamRef writeStream); -/* Deprecated; here for backwards compatibility. Will be removed by Jaguar6D. */ +/* Deprecated versions; here for backwards compatibility. */ +typedef struct { + CFIndex version; /* == 1 */ + void *(*create)(CFReadStreamRef stream, void *info); + void (*finalize)(CFReadStreamRef stream, void *info); + CFStringRef (*copyDescription)(CFReadStreamRef stream, void *info); + Boolean (*open)(CFReadStreamRef stream, CFStreamError *error, Boolean *openComplete, void *info); + Boolean (*openCompleted)(CFReadStreamRef stream, CFStreamError *error, void *info); + CFIndex (*read)(CFReadStreamRef stream, UInt8 *buffer, CFIndex bufferLength, CFStreamError *error, Boolean *atEOF, void *info); + const UInt8 *(*getBuffer)(CFReadStreamRef stream, CFIndex maxBytesToRead, CFIndex *numBytesRead, CFStreamError *error, Boolean *atEOF, void *info); + Boolean (*canRead)(CFReadStreamRef stream, void *info); + void (*close)(CFReadStreamRef stream, void *info); + CFTypeRef (*copyProperty)(CFReadStreamRef stream, CFStringRef propertyName, void *info); + Boolean (*setProperty)(CFReadStreamRef stream, CFStringRef propertyName, CFTypeRef propertyValue, void *info); + void (*requestEvents)(CFReadStreamRef stream, CFOptionFlags streamEvents, void *info); + void (*schedule)(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info); + void (*unschedule)(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info); +} CFReadStreamCallBacksV1; + +typedef struct { + CFIndex version; /* == 1 */ + void *(*create)(CFWriteStreamRef stream, void *info); + void (*finalize)(CFWriteStreamRef stream, void *info); + CFStringRef (*copyDescription)(CFWriteStreamRef stream, void *info); + Boolean (*open)(CFWriteStreamRef stream, CFStreamError *error, Boolean *openComplete, void *info); + Boolean (*openCompleted)(CFWriteStreamRef stream, CFStreamError *error, void *info); + CFIndex (*write)(CFWriteStreamRef stream, const UInt8 *buffer, CFIndex bufferLength, CFStreamError *error, void *info); + Boolean (*canWrite)(CFWriteStreamRef stream, void *info); + void (*close)(CFWriteStreamRef stream, void *info); + CFTypeRef (*copyProperty)(CFWriteStreamRef stream, CFStringRef propertyName, void *info); + Boolean (*setProperty)(CFWriteStreamRef stream, CFStringRef propertyName, CFTypeRef propertyValue, void *info); + void (*requestEvents)(CFWriteStreamRef stream, CFOptionFlags streamEvents, void *info); + void (*schedule)(CFWriteStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info); + void (*unschedule)(CFWriteStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info); +} CFWriteStreamCallBacksV1; + typedef struct { CFIndex version; /* == 0 */ Boolean (*open)(CFReadStreamRef stream, CFStreamError *error, Boolean *openComplete, void *info); @@ -149,8 +199,6 @@ typedef struct { void (*unschedule)(CFWriteStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info); } CFWriteStreamCallBacksV0; -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFSTREAMABSTRACT__ */ diff --git a/CFStreamInternal.h b/CFStreamInternal.h new file mode 100644 index 0000000..ec92661 --- /dev/null +++ b/CFStreamInternal.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2008 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@ + */ +#if !defined(__COREFOUNDATION_CFSTREAMINTERNAL__) +#define __COREFOUNDATION_CFSTREAMINTERNAL__ 1 + +#include +#include +#include +#include + +CF_EXTERN_C_BEGIN + + +// Older versions of the callbacks; v0 callbacks match v1 callbacks, except that create, finalize, and copyDescription are missing. +typedef Boolean (*_CFStreamCBOpenV1)(struct _CFStream *stream, CFStreamError *error, Boolean *openComplete, void *info); +typedef Boolean (*_CFStreamCBOpenCompletedV1)(struct _CFStream *stream, CFStreamError *error, void *info); +typedef CFIndex (*_CFStreamCBReadV1)(CFReadStreamRef stream, UInt8 *buffer, CFIndex bufferLength, CFStreamError *error, Boolean *atEOF, void *info); +typedef const UInt8 *(*_CFStreamCBGetBufferV1)(CFReadStreamRef sream, CFIndex maxBytesToRead, CFIndex *numBytesRead, CFStreamError *error, Boolean *atEOF, void *info); +typedef Boolean (*_CFStreamCBCanReadV1)(CFReadStreamRef, void *info); +typedef CFIndex (*_CFStreamCBWriteV1)(CFWriteStreamRef, const UInt8 *buffer, CFIndex bufferLength, CFStreamError *error, void *info); +typedef Boolean (*_CFStreamCBCanWriteV1)(CFWriteStreamRef, void *info); + +struct _CFStreamCallBacksV1 { + CFIndex version; + void *(*create)(struct _CFStream *stream, void *info); + void (*finalize)(struct _CFStream *stream, void *info); + CFStringRef (*copyDescription)(struct _CFStream *stream, void *info); + + _CFStreamCBOpenV1 open; + _CFStreamCBOpenCompletedV1 openCompleted; + _CFStreamCBReadV1 read; + _CFStreamCBGetBufferV1 getBuffer; + _CFStreamCBCanReadV1 canRead; + _CFStreamCBWriteV1 write; + _CFStreamCBCanWriteV1 canWrite; + void (*close)(struct _CFStream *stream, void *info); + + CFTypeRef (*copyProperty)(struct _CFStream *stream, CFStringRef propertyName, void *info); + Boolean (*setProperty)(struct _CFStream *stream, CFStringRef propertyName, CFTypeRef propertyValue, void *info); + void (*requestEvents)(struct _CFStream *stream, CFOptionFlags events, void *info); + void (*schedule)(struct _CFStream *stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info); + void (*unschedule)(struct _CFStream *stream, CFRunLoopRef runLoop, CFStringRef runLoopMode, void *info); +}; + +// These two are defined in CFSocketStream.c because that's where the glue for CFNetwork is. +__private_extern__ CFErrorRef _CFErrorFromStreamError(CFAllocatorRef alloc, CFStreamError *err); +__private_extern__ CFStreamError _CFStreamErrorFromError(CFErrorRef error); + +CF_EXTERN_C_END + +#endif /* ! __COREFOUNDATION_CFSTREAMINTERNAL__ */ + + diff --git a/Stream.subproj/CFStreamPriv.h b/CFStreamPriv.h similarity index 78% rename from Stream.subproj/CFStreamPriv.h rename to CFStreamPriv.h index 3106dc5..79f2c65 100644 --- a/Stream.subproj/CFStreamPriv.h +++ b/CFStreamPriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,21 +21,17 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFStreamPriv.h - Copyright (c) 2000-2005, Apple, Inc. All rights reserved. + Copyright (c) 2000-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSTREAMPRIV__) #define __COREFOUNDATION_CFSTREAMPRIV__ 1 -#include -#include #include -#include #include +#include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN struct _CFStream; struct _CFStreamClient { @@ -47,20 +43,24 @@ struct _CFStreamClient { CFOptionFlags whatToSignal; }; +#define CFStreamCurrentVersion 2 + // A unified set of callbacks so we can use a single structure for all struct _CFStreams. struct _CFStreamCallBacks { CFIndex version; void *(*create)(struct _CFStream *stream, void *info); void (*finalize)(struct _CFStream *stream, void *info); CFStringRef (*copyDescription)(struct _CFStream *stream, void *info); - Boolean (*open)(struct _CFStream *stream, CFStreamError *error, Boolean *openComplete, void *info); - Boolean (*openCompleted)(struct _CFStream *stream, CFStreamError *error, void *info); - CFIndex (*read)(CFReadStreamRef stream, UInt8 *buffer, CFIndex bufferLength, CFStreamError *error, Boolean *atEOF, void *info); - const UInt8 *(*getBuffer)(CFReadStreamRef sream, CFIndex maxBytesToRead, CFIndex *numBytesRead, CFStreamError *error, Boolean *atEOF, void *info); - Boolean (*canRead)(CFReadStreamRef, void *info); - CFIndex (*write)(CFWriteStreamRef, const UInt8 *buffer, CFIndex bufferLength, CFStreamError *error, void *info); - Boolean (*canWrite)(CFWriteStreamRef, void *info); + + Boolean (*open)(struct _CFStream *stream, CFErrorRef *error, Boolean *openComplete, void *info); + Boolean (*openCompleted)(struct _CFStream *stream, CFErrorRef *error, void *info); + CFIndex (*read)(CFReadStreamRef stream, UInt8 *buffer, CFIndex bufferLength, CFErrorRef *error, Boolean *atEOF, void *info); + const UInt8 *(*getBuffer)(CFReadStreamRef sream, CFIndex maxBytesToRead, CFIndex *numBytesRead, CFErrorRef *error, Boolean *atEOF, void *info); + Boolean (*canRead)(CFReadStreamRef, CFErrorRef *error, void *info); + CFIndex (*write)(CFWriteStreamRef, const UInt8 *buffer, CFIndex bufferLength, CFErrorRef *error, void *info); + Boolean (*canWrite)(CFWriteStreamRef, CFErrorRef *error, void *info); void (*close)(struct _CFStream *stream, void *info); + CFTypeRef (*copyProperty)(struct _CFStream *stream, CFStringRef propertyName, void *info); Boolean (*setProperty)(struct _CFStream *stream, CFStringRef propertyName, CFTypeRef propertyValue, void *info); void (*requestEvents)(struct _CFStream *stream, CFOptionFlags events, void *info); @@ -71,24 +71,25 @@ struct _CFStreamCallBacks { struct _CFStream { CFRuntimeBase _cfBase; CFOptionFlags flags; - CFStreamError error; + CFErrorRef error; // if callBacks->version < 2, this is actually a pointer to a CFStreamError struct _CFStreamClient *client; void *info; const struct _CFStreamCallBacks *callBacks; // This will not exist (will not be allocated) if the callbacks are from our known, "blessed" set. void *_reserved1; }; + CF_INLINE void *_CFStreamGetInfoPointer(struct _CFStream *stream) { return stream->info; } -// cb version must be 1 + +// cb version must be > 0 CF_EXPORT struct _CFStream *_CFStreamCreateWithConstantCallbacks(CFAllocatorRef alloc, void *info, const struct _CFStreamCallBacks *cb, Boolean isReading); // Only available for streams created with _CFStreamCreateWithConstantCallbacks, above. cb's version must be 1 CF_EXPORT void _CFStreamSetInfoPointer(struct _CFStream *stream, void *info, const struct _CFStreamCallBacks *cb); - /* ** _CFStreamSourceScheduleWithRunLoop ** @@ -156,6 +157,13 @@ void _CFStreamSourceScheduleWithAllRunLoops(CFRunLoopSourceRef source, CFArrayRe CF_EXPORT void _CFStreamSourceUncheduleFromAllRunLoops(CFRunLoopSourceRef source, CFArrayRef runLoopsAndModes); +CF_EXPORT +CFReadStreamRef _CFReadStreamCreateFromFileDescriptor(CFAllocatorRef alloc, int fd); + +CF_EXPORT +CFWriteStreamRef _CFWriteStreamCreateFromFileDescriptor(CFAllocatorRef alloc, int fd); + + #define SECURITY_NONE (0) #define SECURITY_SSLv2 (1) @@ -163,11 +171,28 @@ void _CFStreamSourceUncheduleFromAllRunLoops(CFRunLoopSourceRef source, CFArrayR #define SECURITY_SSLv32 (3) #define SECURITY_TLS (4) +#if defined (__MACH__) +// This symbol is exported from CFNetwork (see CFSocketStream.i). Only __MACH__ systems will +// get this symbol from CoreFoundation. extern const int kCFStreamErrorDomainSSL; +#endif //__MACH__ -#if defined(__cplusplus) -} -#endif +/* + * Additional SPI for CFNetwork for select side read buffering + */ +CF_EXPORT +Boolean __CFSocketGetBytesAvailable(CFSocketRef s, CFIndex* ctBytesAvailable); + +CF_EXPORT +CFIndex __CFSocketRead(CFSocketRef s, UInt8* buffer, CFIndex length, int* error); + +CF_EXPORT +void __CFSocketSetReadBufferLength(CFSocketRef s, CFIndex length); + +CF_EXPORT +void __CFSocketSetReadBufferTimeout(CFSocketRef s, CFTimeInterval timeout); + +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFSTREAMPRIV__ */ diff --git a/String.subproj/CFString.c b/CFString.c similarity index 71% rename from String.subproj/CFString.c rename to CFString.c index 685075b..a9b5c50 100644 --- a/String.subproj/CFString.c +++ b/CFString.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -34,34 +34,81 @@ #include "CFUniChar.h" #include "CFUnicodeDecomposition.h" #include "CFUnicodePrecomposition.h" -#include "CFUtilitiesPriv.h" +#include "CFPriv.h" #include "CFInternal.h" #include #include #include -#if defined (__MACOS8__) - #include // For GetScriptManagerVariable - #include // For logging - #include -#include -#include -#elif defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__) +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD #include #endif -#if defined(__WIN32__) -#include -#endif /* __WIN32__ */ -#if defined(__MACH__) +#if defined(__GNUC__) +#define LONG_DOUBLE_SUPPORT 1 +#else +#define LONG_DOUBLE_SUPPORT 0 +#endif + + + +#define USE_STRING_ROM 0 + + +#ifndef INSTRUMENT_SHARED_STRINGS +#define INSTRUMENT_SHARED_STRINGS 0 +#endif + + +__private_extern__ CFStringRef __kCFLocaleCollatorID; + +#if INSTRUMENT_SHARED_STRINGS +#include /* for umask() */ + +static void __CFRecordStringAllocationEvent(const char *encoding, const char *bytes, CFIndex byteCount) { + static CFSpinLock_t lock = CFSpinLockInit; + + if (memchr(bytes, '\n', byteCount)) return; //never record string allocation events for strings with newlines, because those confuse our parser and because they'll never go into the ROM + + __CFSpinLock(&lock); + static int fd; + if (! fd) { + extern char **_NSGetProgname(void); + const char *name = *_NSGetProgname(); + if (! name) name = "UNKNOWN"; + umask(0); + char path[1024]; + sprintf(path, "/tmp/CFSharedStringInstrumentation_%s_%d.txt", name, getpid()); + fd = open(path, O_WRONLY | O_APPEND | O_CREAT, 0666); + if (fd <= 0) { + int error = errno; + const char *errString = strerror(error); + fprintf(stderr, "open() failed with error %d (%s)\n", error, errString); + } + } + if (fd > 0) { + char *buffer = NULL; + char formatString[256]; + sprintf(formatString, "%%-8d\t%%-16s\t%%.%lds\n", byteCount); + int resultCount = asprintf(&buffer, formatString, getpid(), encoding, bytes); + if (buffer && resultCount > 0) write(fd, buffer, resultCount); + else puts("Couldn't record allocation event"); + free(buffer); + } + __CFSpinUnlock(&lock); +} +#endif //INSTRUMENT_SHARED_STRINGS + + + +typedef Boolean (*UNI_CHAR_FUNC)(UInt32 flags, UInt8 ch, UniChar *unicodeChar); + +#if DEPLOYMENT_TARGET_MACOSX extern size_t malloc_good_size(size_t size); #endif extern void __CFStrConvertBytesToUnicode(const uint8_t *bytes, UniChar *buffer, CFIndex numChars); #if defined(DEBUG) -// Special allocator used by CFSTRs to catch deallocations -static CFAllocatorRef constantStringAllocatorForDebugging = NULL; - // We put this into C & Pascal strings if we can't convert #define CONVERSIONFAILURESTR "CFString conversion failed" @@ -90,7 +137,23 @@ CF_INLINE Boolean __CFStringGetCompatibility(CFOptionFlags mask) { // Two constant strings used by CFString; these are initialized in CFStringInitialize CONST_STRING_DECL(kCFEmptyString, "") -CONST_STRING_DECL(kCFNSDecimalSeparatorKey, "NSDecimalSeparator") + +// This is separate for C++ +struct __notInlineMutable { + void *buffer; + CFIndex length; + CFIndex capacity; // Capacity in bytes + unsigned int hasGap:1; // Currently unused + unsigned int isFixedCapacity:1; + unsigned int isExternalMutable:1; + unsigned int capacityProvidedExternally:1; +#if __LP64__ + unsigned long desiredCapacity:60; +#else + unsigned long desiredCapacity:28; +#endif + CFAllocatorRef contentsAllocator; // Optional +}; // The only mutable variant for CFString /* !!! Never do sizeof(CFString); the union is here just to make it easier to access some fields. @@ -98,26 +161,19 @@ CONST_STRING_DECL(kCFNSDecimalSeparatorKey, "NSDecimalSeparator") struct __CFString { CFRuntimeBase base; union { // In many cases the allocated structs are smaller than these - struct { - SInt32 length; - } inline1; - - struct { - void *buffer; - UInt32 length; - CFAllocatorRef contentsDeallocator; // Just the dealloc func is used - } notInlineImmutable1; - struct { + struct __inline1 { + CFIndex length; + } inline1; // Bytes follow the length + struct __notInlineImmutable1 { + void *buffer; // Note that the buffer is in the same place for all non-inline variants of CFString + CFIndex length; + CFAllocatorRef contentsDeallocator; // Optional; just the dealloc func is used + } notInlineImmutable1; // This is the usual not-inline immutable CFString + struct __notInlineImmutable2 { void *buffer; - CFAllocatorRef contentsDeallocator; // Just the dealloc func is used - } notInlineImmutable2; - struct { - void *buffer; - UInt32 length; - UInt32 capacityFields; // Currently only stores capacity - UInt32 gapEtc; // Stores some bits, plus desired or fixed capacity - CFAllocatorRef contentsAllocator; // Optional - } notInlineMutable; + CFAllocatorRef contentsDeallocator; // Optional; just the dealloc func is used + } notInlineImmutable2; // This is the not-inline immutable CFString when length is stored with the contents (first byte) + struct __notInlineMutable notInlineMutable; } variants; }; @@ -128,7 +184,8 @@ U = is Unicode N = has NULL byte L = has length byte D = explicit deallocator for contents (for mutable objects, allocator) -X = UNUSED +C = length field is CFIndex (rather than UInt32); only meaningful for 64-bit, really + if needed this bit (valuable real-estate) can be given up for another bit elsewhere, since this info is needed just for 64-bit Also need (only for mutable) F = is fixed @@ -136,7 +193,7 @@ G = has gap Cap, DesCap = capacity B7 B6 B5 B4 B3 B2 B1 B0 - U N L X I + U N L C I B6 B5 0 0 inline contents @@ -171,20 +228,6 @@ enum { __kCFHasLengthByteMask = 0x04, __kCFHasLengthByte = 0x04, // !!! Bit 0x02 has been freed up - // These are in variants.notInlineMutable.gapEtc - __kCFGapMask = 0x00ffffff, - __kCFGapBitNumber = 24, - __kCFDesiredCapacityMask = 0x00ffffff, // Currently gap and fixed share same bits as gap not implemented - __kCFDesiredCapacityBitNumber = 24, - __kCFIsFixedMask = 0x80000000, - __kCFIsFixed = 0x80000000, - __kCFHasGapMask = 0x40000000, - __kCFHasGap = 0x40000000, - __kCFCapacityProvidedExternallyMask = 0x20000000, // Set if the external buffer capacity is set explicitly by the developer - __kCFCapacityProvidedExternally = 0x20000000, - __kCFIsExternalMutableMask = 0x10000000, // Determines whether the buffer is controlled by the developer - __kCFIsExternalMutable = 0x10000000 - // 0x0f000000: 4 additional bits available for use in mutable strings }; @@ -197,24 +240,30 @@ enum { /* The following set of functions and macros need to be updated on change to the bit configuration */ -CF_INLINE Boolean __CFStrIsMutable(CFStringRef str) {return (str->base._info & __kCFIsMutableMask) == __kCFIsMutable;} -CF_INLINE Boolean __CFStrIsInline(CFStringRef str) {return (str->base._info & __kCFContentsMask) == __kCFHasInlineContents;} -CF_INLINE Boolean __CFStrFreeContentsWhenDone(CFStringRef str) {return (str->base._info & __kCFFreeContentsWhenDoneMask) == __kCFFreeContentsWhenDone;} -CF_INLINE Boolean __CFStrHasContentsDeallocator(CFStringRef str) {return (str->base._info & __kCFHasContentsDeallocatorMask) == __kCFHasContentsDeallocator;} -CF_INLINE Boolean __CFStrIsUnicode(CFStringRef str) {return (str->base._info & __kCFIsUnicodeMask) == __kCFIsUnicode;} -CF_INLINE Boolean __CFStrIsEightBit(CFStringRef str) {return (str->base._info & __kCFIsUnicodeMask) != __kCFIsUnicode;} -CF_INLINE Boolean __CFStrHasNullByte(CFStringRef str) {return (str->base._info & __kCFHasNullByteMask) == __kCFHasNullByte;} -CF_INLINE Boolean __CFStrHasLengthByte(CFStringRef str) {return (str->base._info & __kCFHasLengthByteMask) == __kCFHasLengthByte;} -CF_INLINE Boolean __CFStrHasExplicitLength(CFStringRef str) {return (str->base._info & (__kCFIsMutableMask | __kCFHasLengthByteMask)) != __kCFHasLengthByte;} // Has explicit length if (1) mutable or (2) not mutable and no length byte -CF_INLINE Boolean __CFStrIsConstant(CFStringRef str) {return (str->base._rc) == 0;} - -CF_INLINE SInt32 __CFStrSkipAnyLengthByte(CFStringRef str) {return ((str->base._info & __kCFHasLengthByteMask) == __kCFHasLengthByte) ? 1 : 0;} // Number of bytes to skip over the length byte in the contents +CF_INLINE Boolean __CFStrIsMutable(CFStringRef str) {return (str->base._cfinfo[CF_INFO_BITS] & __kCFIsMutableMask) == __kCFIsMutable;} +CF_INLINE Boolean __CFStrIsInline(CFStringRef str) {return (str->base._cfinfo[CF_INFO_BITS] & __kCFContentsMask) == __kCFHasInlineContents;} +CF_INLINE Boolean __CFStrFreeContentsWhenDone(CFStringRef str) {return (str->base._cfinfo[CF_INFO_BITS] & __kCFFreeContentsWhenDoneMask) == __kCFFreeContentsWhenDone;} +CF_INLINE Boolean __CFStrHasContentsDeallocator(CFStringRef str) {return (str->base._cfinfo[CF_INFO_BITS] & __kCFHasContentsDeallocatorMask) == __kCFHasContentsDeallocator;} +CF_INLINE Boolean __CFStrIsUnicode(CFStringRef str) {return (str->base._cfinfo[CF_INFO_BITS] & __kCFIsUnicodeMask) == __kCFIsUnicode;} +CF_INLINE Boolean __CFStrIsEightBit(CFStringRef str) {return (str->base._cfinfo[CF_INFO_BITS] & __kCFIsUnicodeMask) != __kCFIsUnicode;} +CF_INLINE Boolean __CFStrHasNullByte(CFStringRef str) {return (str->base._cfinfo[CF_INFO_BITS] & __kCFHasNullByteMask) == __kCFHasNullByte;} +CF_INLINE Boolean __CFStrHasLengthByte(CFStringRef str) {return (str->base._cfinfo[CF_INFO_BITS] & __kCFHasLengthByteMask) == __kCFHasLengthByte;} +CF_INLINE Boolean __CFStrHasExplicitLength(CFStringRef str) {return (str->base._cfinfo[CF_INFO_BITS] & (__kCFIsMutableMask | __kCFHasLengthByteMask)) != __kCFHasLengthByte;} // Has explicit length if (1) mutable or (2) not mutable and no length byte +CF_INLINE Boolean __CFStrIsConstant(CFStringRef str) { +#if __LP64__ + return str->base._rc == 0; +#else + return (str->base._cfinfo[CF_RC_BITS]) == 0; +#endif +} + +CF_INLINE SInt32 __CFStrSkipAnyLengthByte(CFStringRef str) {return ((str->base._cfinfo[CF_INFO_BITS] & __kCFHasLengthByteMask) == __kCFHasLengthByte) ? 1 : 0;} // Number of bytes to skip over the length byte in the contents /* Returns ptr to the buffer (which might include the length byte) */ CF_INLINE const void *__CFStrContents(CFStringRef str) { if (__CFStrIsInline(str)) { - return (const void *)(((UInt32)&(str->variants)) + (__CFStrHasExplicitLength(str) ? sizeof(UInt32) : 0)); + return (const void *)(((uintptr_t)&(str->variants)) + (__CFStrHasExplicitLength(str) ? sizeof(CFIndex) : 0)); } else { // Not inline; pointer is always word 2 return str->variants.notInlineImmutable1.buffer; } @@ -267,9 +316,9 @@ CF_INLINE CFIndex __CFStrLength2(CFStringRef str, const void *buffer) { if (__CFStrHasExplicitLength(str)) { if (__CFStrIsInline(str)) { return str->variants.inline1.length; - } else { + } else { return str->variants.notInlineImmutable1.length; - } + } } else { return (CFIndex)(*((uint8_t *)buffer)); } @@ -282,12 +331,11 @@ Boolean __CFStringIsEightBit(CFStringRef str) { /* Sets the content pointer for immutable or mutable strings. */ -CF_INLINE void __CFStrSetContentPtr(CFStringRef str, const void *p) -{ +CF_INLINE void __CFStrSetContentPtr(CFStringRef str, const void *p) { // XXX_PCB catch all writes for mutable string case. CF_WRITE_BARRIER_BASE_ASSIGN(__CFGetAllocator(str), str, ((CFMutableStringRef)str)->variants.notInlineImmutable1.buffer, (void *)p); } -CF_INLINE void __CFStrSetInfoBits(CFStringRef str, UInt32 v) {__CFBitfieldSetValue(((CFMutableStringRef)str)->base._info, 6, 0, v);} +CF_INLINE void __CFStrSetInfoBits(CFStringRef str, UInt32 v) {__CFBitfieldSetValue(((CFMutableStringRef)str)->base._cfinfo[CF_INFO_BITS], 6, 0, v);} CF_INLINE void __CFStrSetExplicitLength(CFStringRef str, CFIndex v) { if (__CFStrIsInline(str)) { @@ -297,24 +345,32 @@ CF_INLINE void __CFStrSetExplicitLength(CFStringRef str, CFIndex v) { } } -// Assumption: Called with mutable strings only -CF_INLINE Boolean __CFStrIsFixed(CFStringRef str) {return (str->variants.notInlineMutable.gapEtc & __kCFIsFixedMask) == __kCFIsFixed;} -CF_INLINE Boolean __CFStrHasContentsAllocator(CFStringRef str) {return (str->base._info & __kCFHasContentsAllocatorMask) == __kCFHasContentsAllocator;} -CF_INLINE Boolean __CFStrIsExternalMutable(CFStringRef str) {return (str->variants.notInlineMutable.gapEtc & __kCFIsExternalMutableMask) == __kCFIsExternalMutable;} +CF_INLINE void __CFStrSetUnicode(CFMutableStringRef str) {str->base._cfinfo[CF_INFO_BITS] |= __kCFIsUnicode;} +CF_INLINE void __CFStrClearUnicode(CFMutableStringRef str) {str->base._cfinfo[CF_INFO_BITS] &= ~__kCFIsUnicode;} +CF_INLINE void __CFStrSetHasLengthAndNullBytes(CFMutableStringRef str) {str->base._cfinfo[CF_INFO_BITS] |= (__kCFHasLengthByte | __kCFHasNullByte);} +CF_INLINE void __CFStrClearHasLengthAndNullBytes(CFMutableStringRef str) {str->base._cfinfo[CF_INFO_BITS] &= ~(__kCFHasLengthByte | __kCFHasNullByte);} + + +// Assumption: The following set of inlines (using str->variants.notInlineMutable) are called with mutable strings only +CF_INLINE Boolean __CFStrIsFixed(CFStringRef str) {return str->variants.notInlineMutable.isFixedCapacity;} +CF_INLINE Boolean __CFStrIsExternalMutable(CFStringRef str) {return str->variants.notInlineMutable.isExternalMutable;} +CF_INLINE Boolean __CFStrHasContentsAllocator(CFStringRef str) {return (str->base._cfinfo[CF_INFO_BITS] & __kCFHasContentsAllocatorMask) == __kCFHasContentsAllocator;} +CF_INLINE void __CFStrSetIsFixed(CFMutableStringRef str) {str->variants.notInlineMutable.isFixedCapacity = 1;} +CF_INLINE void __CFStrSetIsExternalMutable(CFMutableStringRef str) {str->variants.notInlineMutable.isExternalMutable = 1;} +CF_INLINE void __CFStrSetHasGap(CFMutableStringRef str) {str->variants.notInlineMutable.hasGap = 1;} // If capacity is provided externally, we only change it when we need to grow beyond it -CF_INLINE Boolean __CFStrCapacityProvidedExternally(CFStringRef str) {return (str->variants.notInlineMutable.gapEtc & __kCFCapacityProvidedExternallyMask) == __kCFCapacityProvidedExternally;} -CF_INLINE void __CFStrSetCapacityProvidedExternally(CFMutableStringRef str) {str->variants.notInlineMutable.gapEtc |= __kCFCapacityProvidedExternally;} -CF_INLINE void __CFStrClearCapacityProvidedExternally(CFMutableStringRef str) {str->variants.notInlineMutable.gapEtc &= ~__kCFCapacityProvidedExternally;} +CF_INLINE Boolean __CFStrCapacityProvidedExternally(CFStringRef str) {return str->variants.notInlineMutable.capacityProvidedExternally;} +CF_INLINE void __CFStrSetCapacityProvidedExternally(CFMutableStringRef str) {str->variants.notInlineMutable.capacityProvidedExternally = 1;} +CF_INLINE void __CFStrClearCapacityProvidedExternally(CFMutableStringRef str) {str->variants.notInlineMutable.capacityProvidedExternally = 0;} +// "Capacity" is stored in number of bytes, not characters. It indicates the total number of bytes in the contents buffer. +CF_INLINE CFIndex __CFStrCapacity(CFStringRef str) {return str->variants.notInlineMutable.capacity;} +CF_INLINE void __CFStrSetCapacity(CFMutableStringRef str, CFIndex cap) {str->variants.notInlineMutable.capacity = cap;} -CF_INLINE void __CFStrSetIsFixed(CFMutableStringRef str) {str->variants.notInlineMutable.gapEtc |= __kCFIsFixed;} -CF_INLINE void __CFStrSetIsExternalMutable(CFMutableStringRef str) {str->variants.notInlineMutable.gapEtc |= __kCFIsExternalMutable;} -CF_INLINE void __CFStrSetHasGap(CFMutableStringRef str) {str->variants.notInlineMutable.gapEtc |= __kCFHasGap;} -CF_INLINE void __CFStrSetUnicode(CFMutableStringRef str) {str->base._info |= __kCFIsUnicode;} -CF_INLINE void __CFStrClearUnicode(CFMutableStringRef str) {str->base._info &= ~__kCFIsUnicode;} -CF_INLINE void __CFStrSetHasLengthAndNullBytes(CFMutableStringRef str) {str->base._info |= (__kCFHasLengthByte | __kCFHasNullByte);} -CF_INLINE void __CFStrClearHasLengthAndNullBytes(CFMutableStringRef str) {str->base._info &= ~(__kCFHasLengthByte | __kCFHasNullByte);} +// "Desired capacity" is in number of characters; it is the client requested capacity; if fixed, it is the upper bound on the mutable string backing store. +CF_INLINE CFIndex __CFStrDesiredCapacity(CFStringRef str) {return str->variants.notInlineMutable.desiredCapacity;} +CF_INLINE void __CFStrSetDesiredCapacity(CFMutableStringRef str, CFIndex size) {str->variants.notInlineMutable.desiredCapacity = size;} static void *__CFStrAllocateMutableContents(CFMutableStringRef str, CFIndex size) { @@ -336,17 +392,6 @@ static void __CFStrDeallocateMutableContents(CFMutableStringRef str, void *buffe } -// The following set of functions should only be called on mutable strings - -/* "Capacity" is stored in number of bytes, not characters. It indicates the total number of bytes in the contents buffer. - "Desired capacity" is in number of characters; it is the client requested capacity; if fixed, it is the upper bound on the mutable string backing store. -*/ -CF_INLINE CFIndex __CFStrCapacity(CFStringRef str) {return str->variants.notInlineMutable.capacityFields;} -CF_INLINE void __CFStrSetCapacity(CFMutableStringRef str, CFIndex cap) {str->variants.notInlineMutable.capacityFields = cap;} -CF_INLINE CFIndex __CFStrDesiredCapacity(CFStringRef str) {return __CFBitfieldGetValue(str->variants.notInlineMutable.gapEtc, __kCFDesiredCapacityBitNumber, 0);} -CF_INLINE void __CFStrSetDesiredCapacity(CFMutableStringRef str, CFIndex size) {__CFBitfieldSetValue(str->variants.notInlineMutable.gapEtc, __kCFDesiredCapacityBitNumber, 0, size);} - - /* CFString specific init flags @@ -370,18 +415,18 @@ CFStringEncoding CFStringGetSystemEncoding(void) { if (__CFDefaultSystemEncoding == kCFStringEncodingInvalidId) { const CFStringEncodingConverter *converter = NULL; -#if defined(__MACOS8__) || defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX __CFDefaultSystemEncoding = kCFStringEncodingMacRoman; // MacRoman is built-in so always available #elif defined(__WIN32__) __CFDefaultSystemEncoding = kCFStringEncodingWindowsLatin1; // WinLatin1 is built-in so always available -#elif defined(__LINUX__) || defined(__FREEBSD__) +#elif DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD __CFDefaultSystemEncoding = kCFStringEncodingISOLatin1; // a reasonable default #else // Solaris && HP-UX ? __CFDefaultSystemEncoding = kCFStringEncodingISOLatin1; // a reasonable default #endif converter = CFStringEncodingGetConverter(__CFDefaultSystemEncoding); - __CFSetCharToUniCharFunc(converter->encodingClass == kCFStringEncodingConverterCheapEightBit ? converter->toUnicode : NULL); + __CFSetCharToUniCharFunc(converter->encodingClass == kCFStringEncodingConverterCheapEightBit ? (UNI_CHAR_FUNC)converter->toUnicode : NULL); } return __CFDefaultSystemEncoding; @@ -396,7 +441,7 @@ CF_INLINE CFStringEncoding __CFStringGetSystemEncoding(void) { CFStringEncoding CFStringFileSystemEncoding(void) { if (__CFDefaultFileSystemEncoding == kCFStringEncodingInvalidId) { -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX __CFDefaultFileSystemEncoding = kCFStringEncodingUTF8; #else __CFDefaultFileSystemEncoding = CFStringGetSystemEncoding(); @@ -502,7 +547,6 @@ CF_INLINE Boolean __CFCanUseLengthByte(CFIndex len) { #define __CFAssertIsString(cf) __CFGenericValidateType(cf, __kCFStringTypeID) #define __CFAssertIndexIsInStringBounds(cf, idx) CFAssert3((idx) >= 0 && (idx) < __CFStrLength(cf), __kCFLogAssertion, "%s(): string index %d out of bounds (length %d)", __PRETTY_FUNCTION__, idx, __CFStrLength(cf)) #define __CFAssertRangeIsInStringBounds(cf, idx, count) CFAssert4((idx) >= 0 && (idx + count) <= __CFStrLength(cf), __kCFLogAssertion, "%s(): string range %d,%d out of bounds (length %d)", __PRETTY_FUNCTION__, idx, count, __CFStrLength(cf)) -#define __CFAssertLengthIsOK(len) CFAssert2(len < __kCFMaxLength, __kCFLogAssertion, "%s(): length %d too large", __PRETTY_FUNCTION__, len) #define __CFAssertIsStringAndMutable(cf) {__CFGenericValidateType(cf, __kCFStringTypeID); CFAssert1(__CFStrIsMutable(cf), __kCFLogAssertion, "%s(): string not mutable", __PRETTY_FUNCTION__);} #define __CFAssertIsStringAndExternalMutable(cf) {__CFGenericValidateType(cf, __kCFStringTypeID); CFAssert1(__CFStrIsMutable(cf) && __CFStrIsExternalMutable(cf), __kCFLogAssertion, "%s(): string not external mutable", __PRETTY_FUNCTION__);} #define __CFAssertIsNotNegative(idx) CFAssert2(idx >= 0, __kCFLogAssertion, "%s(): index %d is negative", __PRETTY_FUNCTION__, idx) @@ -514,9 +558,15 @@ Additional complications are applied in the following order: - desiredCapacity, which is the minimum (except initially things can be at zero) - rounding up to factor of 8 - compressing (to fit the number if 16 bits), which effectively rounds up to factor of 256 +- we need to make sure GROWFACTOR computation doesn't suffer from overflow issues on 32-bit, hence the casting to unsigned. Normally for required capacity of C bytes, the allocated space is (3C+1)/2. If C > ULONG_MAX/3, we instead simply return LONG_MAX */ #define SHRINKFACTOR(c) (c / 2) + +#if __LP64__ #define GROWFACTOR(c) ((c * 3 + 1) / 2) +#else +#define GROWFACTOR(c) (((c) >= (ULONG_MAX / 3UL)) ? __CFMax(LONG_MAX - 4095, (c)) : (((unsigned long)c * 3 + 1) / 2)) +#endif CF_INLINE CFIndex __CFStrNewCapacity(CFMutableStringRef str, CFIndex reqCapacity, CFIndex capacity, Boolean leaveExtraRoom, CFIndex charSize) { if (capacity != 0 || reqCapacity != 0) { /* If initially zero, and space not needed, leave it at that... */ @@ -533,7 +583,7 @@ CF_INLINE CFIndex __CFStrNewCapacity(CFMutableStringRef str, CFIndex reqCapacity } if (__CFStrHasContentsAllocator(str)) { /* Also apply any preferred size from the allocator; should we do something for */ newCapacity = CFAllocatorGetPreferredSizeForSize(__CFStrContentsAllocator(str), newCapacity, 0); -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX } else { newCapacity = malloc_good_size(newCapacity); #endif @@ -560,14 +610,14 @@ if insertLength = 3, result = A ? ? ? C ? ? ? E ? ? ? Q ? ? ? S ? ? ? U */ typedef struct _CFStringDeferredRange { - int beginning; - int length; - int shift; + CFIndex beginning; + CFIndex length; + CFIndex shift; } CFStringDeferredRange; typedef struct _CFStringStackInfo { - int capacity; // Capacity (if capacity == count, need to realloc to add another) - int count; // Number of elements actually stored + CFIndex capacity; // Capacity (if capacity == count, need to realloc to add another) + CFIndex count; // Number of elements actually stored CFStringDeferredRange *stack; Boolean hasMalloced; // Indicates "stack" is allocated and needs to be deallocated when done char _padding[3]; @@ -583,9 +633,9 @@ CF_INLINE void push (CFStringStackInfo *si, const CFStringDeferredRange *newRang // increase size of the stack si->capacity = (si->capacity + 4) * 2; if (si->hasMalloced) { - si->stack = CFAllocatorReallocate(NULL, si->stack, si->capacity * sizeof(CFStringDeferredRange), 0); + si->stack = (CFStringDeferredRange *)CFAllocatorReallocate(kCFAllocatorSystemDefault, si->stack, si->capacity * sizeof(CFStringDeferredRange), 0); } else { - CFStringDeferredRange *newStack = (CFStringDeferredRange *)CFAllocatorAllocate(NULL, si->capacity * sizeof(CFStringDeferredRange), 0); + CFStringDeferredRange *newStack = (CFStringDeferredRange *)CFAllocatorAllocate(kCFAllocatorSystemDefault, si->capacity * sizeof(CFStringDeferredRange), 0); memmove(newStack, si->stack, si->count * sizeof(CFStringDeferredRange)); si->stack = newStack; si->hasMalloced = true; @@ -607,8 +657,8 @@ static void rearrangeBlocks( CFStringDeferredRange origStack[origStackSize]; CFStringStackInfo si = {origStackSize, 0, origStack, false, {0, 0, 0}}; CFStringDeferredRange currentNonRange = {0, 0, 0}; - int currentRange = 0; - int amountShifted = 0; + CFIndex currentRange = 0; + CFIndex amountShifted = 0; // must have at least 1 range left. @@ -643,7 +693,7 @@ static void rearrangeBlocks( pop (&si, ¤tNonRange); // currentNonRange now equals the top element of the stack. if (currentNonRange.shift && currentNonRange.length) memmove (&buffer[currentNonRange.beginning + currentNonRange.shift], &buffer[currentNonRange.beginning], currentNonRange.length); } - if (si.hasMalloced) CFAllocatorDeallocate (NULL, si.stack); + if (si.hasMalloced) CFAllocatorDeallocate (kCFAllocatorSystemDefault, si.stack); } /* See comments for rearrangeBlocks(); this is the same, but the string is assembled in another buffer (dstBuffer), so the algorithm is much easier. We also take care of the case where the source is not-Unicode but destination is. (The reverse case is not supported.) @@ -690,11 +740,20 @@ static void copyBlocks( } } +/* Call the callback; if it doesn't exist or returns false, then log +*/ +static void __CFStringHandleOutOfMemory(CFTypeRef obj) { + CFStringRef msg = CFSTR("Out of memory. We suggest restarting the application. If you have an unsaved document, create a backup copy in Finder, then try to save."); + CFBadErrorCallBack cb = _CFGetOutOfMemoryErrorCallBack(); + if (NULL == cb || !cb(obj, CFSTR("NS/CFString"), msg)) { + CFLog(kCFLogLevelCritical, CFSTR("%@"), msg); + } +} /* Reallocates the backing store of the string to accomodate the new length. Space is reserved or characters are deleted as indicated by insertLength and the ranges in deleteRanges. The length is updated to reflect the new state. Will also maintain a length byte and a null byte in 8-bit strings. If length cannot fit in length byte, the space will still be reserved, but will be 0. (Hence the reason the length byte should never be looked at as length unless there is no explicit length.) */ static void __CFStringChangeSizeMultiple(CFMutableStringRef str, const CFRange *deleteRanges, CFIndex numDeleteRanges, CFIndex insertLength, Boolean makeUnicode) { - const uint8_t *curContents = __CFStrContents(str); + const uint8_t *curContents = (uint8_t *)__CFStrContents(str); CFIndex curLength = curContents ? __CFStrLength2(str, curContents) : 0; CFIndex newLength; @@ -702,7 +761,7 @@ static void __CFStringChangeSizeMultiple(CFMutableStringRef str, const CFRange * if (numDeleteRanges == 1) { newLength = curLength + insertLength - deleteRanges[0].length; } else { - int cnt; + CFIndex cnt; newLength = curLength + insertLength * numDeleteRanges; for (cnt = 0; cnt < numDeleteRanges; cnt++) newLength -= deleteRanges[cnt].length; } @@ -746,7 +805,22 @@ static void __CFStringChangeSizeMultiple(CFMutableStringRef str, const CFRange * CFIndex curCapacity = __CFStrCapacity(str); CFIndex newCapacity = __CFStrNewCapacity(str, newLength * newCharSize + numExtraBytes, curCapacity, true, newCharSize); Boolean allocNewBuffer = (newCapacity != curCapacity) || (curLength > 0 && !oldIsUnicode && newIsUnicode); /* We alloc new buffer if oldIsUnicode != newIsUnicode because the contents have to be copied */ - uint8_t *newContents = allocNewBuffer ? __CFStrAllocateMutableContents(str, newCapacity) : (uint8_t *)curContents; + uint8_t *newContents; + if (allocNewBuffer) { + newContents = (uint8_t *)__CFStrAllocateMutableContents(str, newCapacity); + if (!newContents) { // Try allocating without extra room + newCapacity = __CFStrNewCapacity(str, newLength * newCharSize + numExtraBytes, curCapacity, false, newCharSize); + newContents = (uint8_t *)__CFStrAllocateMutableContents(str, newCapacity); + if (!newContents) { + __CFStringHandleOutOfMemory(str); + // Ideally control doesn't come here at all since we expect the above call to raise an exception. + // If control comes here, there isn't much we can do. + } + } + } else { + newContents = (uint8_t *)curContents; + } + Boolean hasLengthAndNullBytes = __CFStrHasLengthByte(str); CFAssert1(hasLengthAndNullBytes == __CFStrHasNullByte(str), __kCFLogAssertion, "%s(): Invalid state in 8-bit string", __PRETTY_FUNCTION__); @@ -765,7 +839,7 @@ static void __CFStringChangeSizeMultiple(CFMutableStringRef str, const CFRange * copyBlocks(curContents, newContents, curLength, oldIsUnicode, newIsUnicode, deleteRanges, numDeleteRanges, insertLength); } if (hasLengthAndNullBytes) curContents--; /* Undo the damage from above */ - if (allocNewBuffer) __CFStrDeallocateMutableContents(str, (void *)curContents); + if (allocNewBuffer && __CFStrFreeContentsWhenDone(str)) __CFStrDeallocateMutableContents(str, (void *)curContents); } if (!newIsUnicode) { @@ -799,17 +873,21 @@ CF_INLINE void __CFStringChangeSize(CFMutableStringRef str, CFRange range, CFInd } +#if defined(DEBUG) +static Boolean __CFStrIsConstantString(CFStringRef str); +#endif + static void __CFStringDeallocate(CFTypeRef cf) { - CFStringRef str = cf; + CFStringRef str = (CFStringRef)cf; - // constantStringAllocatorForDebugging is not around unless DEBUG is defined, but neither is CFAssert2()... - CFAssert1(__CFConstantStringTableBeingFreed || CFGetAllocator(str) != constantStringAllocatorForDebugging, __kCFLogAssertion, "Tried to deallocate CFSTR(\"%@\")", str); + // If in DEBUG mode, check to see if the string a CFSTR, and complain. + CFAssert1(__CFConstantStringTableBeingFreed || !__CFStrIsConstantString((CFStringRef)cf), __kCFLogAssertion, "Tried to deallocate CFSTR(\"%@\")", str); if (!__CFStrIsInline(str)) { uint8_t *contents; - Boolean mutable = __CFStrIsMutable(str); + Boolean isMutable = __CFStrIsMutable(str); if (__CFStrFreeContentsWhenDone(str) && (contents = (uint8_t *)__CFStrContents(str))) { - if (mutable) { + if (isMutable) { __CFStrDeallocateMutableContents((CFMutableStringRef)str, contents); } else { if (__CFStrHasContentsDeallocator(str)) { @@ -822,13 +900,13 @@ static void __CFStringDeallocate(CFTypeRef cf) { } } } - if (mutable && __CFStrHasContentsAllocator(str)) CFRelease(__CFStrContentsAllocator((CFMutableStringRef)str)); + if (isMutable && __CFStrHasContentsAllocator(str)) CFRelease(__CFStrContentsAllocator((CFMutableStringRef)str)); } } static Boolean __CFStringEqual(CFTypeRef cf1, CFTypeRef cf2) { - CFStringRef str1 = cf1; - CFStringRef str2 = cf2; + CFStringRef str1 = (CFStringRef)cf1; + CFStringRef str2 = (CFStringRef)cf2; const uint8_t *contents1; const uint8_t *contents2; CFIndex len1; @@ -836,8 +914,8 @@ static Boolean __CFStringEqual(CFTypeRef cf1, CFTypeRef cf2) { /* !!! We do not need IsString assertions, as the CFBase runtime assures this */ /* !!! We do not need == test, as the CFBase runtime assures this */ - contents1 = __CFStrContents(str1); - contents2 = __CFStrContents(str2); + contents1 = (uint8_t *)__CFStrContents(str1); + contents2 = (uint8_t *)__CFStrContents(str2); len1 = __CFStrLength2(str1, contents1); if (len1 != __CFStrLength2(str2, contents2)) return false; @@ -874,84 +952,71 @@ static Boolean __CFStringEqual(CFTypeRef cf1, CFTypeRef cf2) { /* String hashing: Should give the same results whatever the encoding; so we hash UniChars. -If the length is less than or equal to 24, then the hash function is simply the +If the length is less than or equal to 96, then the hash function is simply the following (n is the nth UniChar character, starting from 0): hash(-1) = length hash(n) = hash(n-1) * 257 + unichar(n); Hash = hash(length-1) * ((length & 31) + 1) -If the length is greater than 24, then the above algorithm applies to -characters 0..7 and length-16..length-1; thus the first 8 and last 16 characters. +If the length is greater than 96, then the above algorithm applies to +characters 0..31, (length/2)-16..(length/2)+15, and length-32..length-1, inclusive; +thus the first, middle, and last 32 characters. Note that the loops below are unrolled; and: 257^2 = 66049; 257^3 = 16974593; 257^4 = 4362470401; 67503105 is 257^4 - 256^4 -If hashcode is changed from UInt32 to something else, this last piece needs to be readjusted. +If hashcode is changed from UInt32 to something else, this last piece needs to be readjusted. +!!! We haven't updated for LP64 yet NOTE: The hash algorithm used to be duplicated in CF and Foundation; but now it should only be in the four functions below. + +Hash function was changed between Panther and Tiger, and Tiger and Leopard. */ +#define HashEverythingLimit 96 + +#define HashNextFourUniChars(accessStart, accessEnd, pointer) \ + {result = result * 67503105 + (accessStart 0 accessEnd) * 16974593 + (accessStart 1 accessEnd) * 66049 + (accessStart 2 accessEnd) * 257 + (accessStart 3 accessEnd); pointer += 4;} + +#define HashNextUniChar(accessStart, accessEnd, pointer) \ + {result = result * 257 + (accessStart 0 accessEnd); pointer++;} + /* In this function, actualLen is the length of the original string; but len is the number of characters in buffer. The buffer is expected to contain the parts of the string relevant to hashing. */ CF_INLINE CFHashCode __CFStrHashCharacters(const UniChar *uContents, CFIndex len, CFIndex actualLen) { CFHashCode result = actualLen; - if (len < 24) { + if (len <= HashEverythingLimit) { const UniChar *end4 = uContents + (len & ~3); const UniChar *end = uContents + len; - while (uContents < end4) { // First count in fours - result = result * 67503105 + uContents[0] * 16974593 + uContents[1] * 66049 + uContents[2] * 257 + uContents[3]; - uContents += 4; - } - while (uContents < end) { // Then for the last <4 chars, count in ones... - result = result * 257 + *uContents++; - } + while (uContents < end4) HashNextFourUniChars(uContents[, ], uContents); // First count in fours + while (uContents < end) HashNextUniChar(uContents[, ], uContents); // Then for the last <4 chars, count in ones... } else { - result = result * 67503105 + uContents[0] * 16974593 + uContents[1] * 66049 + uContents[2] * 257 + uContents[3]; - result = result * 67503105 + uContents[4] * 16974593 + uContents[5] * 66049 + uContents[6] * 257 + uContents[7]; - uContents += (len - 16); - result = result * 67503105 + uContents[0] * 16974593 + uContents[1] * 66049 + uContents[2] * 257 + uContents[3]; - result = result * 67503105 + uContents[4] * 16974593 + uContents[5] * 66049 + uContents[6] * 257 + uContents[7]; - result = result * 67503105 + uContents[8] * 16974593 + uContents[9] * 66049 + uContents[10] * 257 + uContents[11]; - result = result * 67503105 + uContents[12] * 16974593 + uContents[13] * 66049 + uContents[14] * 257 + uContents[15]; + const UniChar *contents, *end; + contents = uContents; + end = contents + 32; + while (contents < end) HashNextFourUniChars(contents[, ], contents); + contents = uContents + (len >> 1) - 16; + end = contents + 32; + while (contents < end) HashNextFourUniChars(contents[, ], contents); + end = uContents + len; + contents = end - 32; + while (contents < end) HashNextFourUniChars(contents[, ], contents); } return result + (result << (actualLen & 31)); } /* This hashes cString in the eight bit string encoding. It also includes the little debug-time sanity check. */ -CF_INLINE CFHashCode __CFStrHashEightBit(const uint8_t *contents, CFIndex len) { -#if defined(DEBUG) - const uint8_t *origContents = contents; -#endif - CFHashCode result = len; - if (len < 24) { - const uint8_t *end4 = contents + (len & ~3); - const uint8_t *end = contents + len; - while (contents < end4) { // First count in fours - result = result * 67503105 + __CFCharToUniCharTable[contents[0]] * 16974593 + __CFCharToUniCharTable[contents[1]] * 66049 + __CFCharToUniCharTable[contents[2]] * 257 + __CFCharToUniCharTable[contents[3]]; - contents += 4; - } - while (contents < end) { // Then for the last <4 chars, count single chars - result = result * 257 + __CFCharToUniCharTable[*contents++]; - } - } else { - result = result * 67503105 + __CFCharToUniCharTable[contents[0]] * 16974593 + __CFCharToUniCharTable[contents[1]] * 66049 + __CFCharToUniCharTable[contents[2]] * 257 + __CFCharToUniCharTable[contents[3]]; - result = result * 67503105 + __CFCharToUniCharTable[contents[4]] * 16974593 + __CFCharToUniCharTable[contents[5]] * 66049 + __CFCharToUniCharTable[contents[6]] * 257 + __CFCharToUniCharTable[contents[7]]; - contents += (len - 16); - result = result * 67503105 + __CFCharToUniCharTable[contents[0]] * 16974593 + __CFCharToUniCharTable[contents[1]] * 66049 + __CFCharToUniCharTable[contents[2]] * 257 + __CFCharToUniCharTable[contents[3]]; - result = result * 67503105 + __CFCharToUniCharTable[contents[4]] * 16974593 + __CFCharToUniCharTable[contents[5]] * 66049 + __CFCharToUniCharTable[contents[6]] * 257 + __CFCharToUniCharTable[contents[7]]; - result = result * 67503105 + __CFCharToUniCharTable[contents[8]] * 16974593 + __CFCharToUniCharTable[contents[9]] * 66049 + __CFCharToUniCharTable[contents[10]] * 257 + __CFCharToUniCharTable[contents[11]]; - result = result * 67503105 + __CFCharToUniCharTable[contents[12]] * 16974593 + __CFCharToUniCharTable[contents[13]] * 66049 + __CFCharToUniCharTable[contents[14]] * 257 + __CFCharToUniCharTable[contents[15]]; - } +CF_INLINE CFHashCode __CFStrHashEightBit(const uint8_t *cContents, CFIndex len) { #if defined(DEBUG) if (!__CFCharToUniCharFunc) { // A little sanity verification: If this is not set, trying to hash high byte chars would be a bad idea CFIndex cnt; Boolean err = false; - contents = origContents; - if (len <= 24) { - for (cnt = 0; cnt < len; cnt++) if (contents[cnt] >= 128) err = true; + if (len <= HashEverythingLimit) { + for (cnt = 0; cnt < len; cnt++) if (cContents[cnt] >= 128) err = true; } else { - for (cnt = 0; cnt < 8; cnt++) if (contents[cnt] >= 128) err = true; - for (cnt = len - 16; cnt < len; cnt++) if (contents[cnt] >= 128) err = true; + for (cnt = 0; cnt < 32; cnt++) if (cContents[cnt] >= 128) err = true; + for (cnt = (len >> 1) - 16; cnt < (len >> 1) + 16; cnt++) if (cContents[cnt] >= 128) err = true; + for (cnt = (len - 32); cnt < len; cnt++) if (cContents[cnt] >= 128) err = true; } if (err) { // Can't do log here, as it might be too early @@ -959,29 +1024,45 @@ CF_INLINE CFHashCode __CFStrHashEightBit(const uint8_t *contents, CFIndex len) { } } #endif + CFHashCode result = len; + if (len <= HashEverythingLimit) { + const uint8_t *end4 = cContents + (len & ~3); + const uint8_t *end = cContents + len; + while (cContents < end4) HashNextFourUniChars(__CFCharToUniCharTable[cContents[, ]], cContents); // First count in fours + while (cContents < end) HashNextUniChar(__CFCharToUniCharTable[cContents[, ]], cContents); // Then for the last <4 chars, count in ones... + } else { + const uint8_t *contents, *end; + contents = cContents; + end = contents + 32; + while (contents < end) HashNextFourUniChars(__CFCharToUniCharTable[contents[, ]], contents); + contents = cContents + (len >> 1) - 16; + end = contents + 32; + while (contents < end) HashNextFourUniChars(__CFCharToUniCharTable[contents[, ]], contents); + end = cContents + len; + contents = end - 32; + while (contents < end) HashNextFourUniChars(__CFCharToUniCharTable[contents[, ]], contents); + } return result + (result << (len & 31)); } CFHashCode CFStringHashISOLatin1CString(const uint8_t *bytes, CFIndex len) { CFHashCode result = len; - if (len < 24) { + if (len <= HashEverythingLimit) { const uint8_t *end4 = bytes + (len & ~3); const uint8_t *end = bytes + len; - while (bytes < end4) { // First count in fours - result = result * 67503105 + bytes[0] * 16974593 + bytes[1] * 66049 + bytes[2] * 257 + bytes[3]; - bytes += 4; - } - while (bytes < end) { // Then for the last <4 chars, count in ones... - result = result * 257 + *bytes++; - } + while (bytes < end4) HashNextFourUniChars(bytes[, ], bytes); // First count in fours + while (bytes < end) HashNextUniChar(bytes[, ], bytes); // Then for the last <4 chars, count in ones... } else { - result = result * 67503105 + bytes[0] * 16974593 + bytes[1] * 66049 + bytes[2] * 257 + bytes[3]; - result = result * 67503105 + bytes[4] * 16974593 + bytes[5] * 66049 + bytes[6] * 257 + bytes[7]; - bytes += (len - 16); - result = result * 67503105 + bytes[0] * 16974593 + bytes[1] * 66049 + bytes[2] * 257 + bytes[3]; - result = result * 67503105 + bytes[4] * 16974593 + bytes[5] * 66049 + bytes[6] * 257 + bytes[7]; - result = result * 67503105 + bytes[8] * 16974593 + bytes[9] * 66049 + bytes[10] * 257 + bytes[11]; - result = result * 67503105 + bytes[12] * 16974593 + bytes[13] * 66049 + bytes[14] * 257 + bytes[15]; + const uint8_t *contents, *end; + contents = bytes; + end = contents + 32; + while (contents < end) HashNextFourUniChars(contents[, ], contents); + contents = bytes + (len >> 1) - 16; + end = contents + 32; + while (contents < end) HashNextFourUniChars(contents[, ], contents); + end = bytes + len; + contents = end - 32; + while (contents < end) HashNextFourUniChars(contents[, ], contents); } return result + (result << (len & 31)); } @@ -997,26 +1078,27 @@ CFHashCode CFStringHashCharacters(const UniChar *characters, CFIndex len) { /* This is meant to be called from NSString or subclassers only. It is an error for this to be called without the ObjC runtime or an argument which is not an NSString or subclass. It can be called with NSCFString, although that would be inefficient (causing indirection) and won't normally happen anyway, as NSCFString overrides hash. */ CFHashCode CFStringHashNSString(CFStringRef str) { - UniChar buffer[24]; + UniChar buffer[HashEverythingLimit]; CFIndex bufLen; // Number of characters in the buffer for hashing - CFIndex len; // Actual length of the string + CFIndex len = 0; // Actual length of the string CF_OBJC_CALL0(CFIndex, len, str, "length"); - if (len <= 24) { + if (len <= HashEverythingLimit) { CF_OBJC_VOIDCALL2(str, "getCharacters:range:", buffer, CFRangeMake(0, len)); bufLen = len; } else { - CF_OBJC_VOIDCALL2(str, "getCharacters:range:", buffer, CFRangeMake(0, 8)); - CF_OBJC_VOIDCALL2(str, "getCharacters:range:", buffer+8, CFRangeMake(len-16, 16)); - bufLen = 24; + CF_OBJC_VOIDCALL2(str, "getCharacters:range:", buffer, CFRangeMake(0, 32)); + CF_OBJC_VOIDCALL2(str, "getCharacters:range:", buffer+32, CFRangeMake((len >> 1) - 16, 32)); + CF_OBJC_VOIDCALL2(str, "getCharacters:range:", buffer+64, CFRangeMake(len - 32, 32)); + bufLen = HashEverythingLimit; } return __CFStrHashCharacters(buffer, bufLen, len); } CFHashCode __CFStringHash(CFTypeRef cf) { /* !!! We do not need an IsString assertion here, as this is called by the CFBase runtime only */ - CFStringRef str = cf; - const uint8_t *contents = __CFStrContents(str); + CFStringRef str = (CFStringRef)cf; + const uint8_t *contents = (uint8_t *)__CFStrContents(str); CFIndex len = __CFStrLength2(str, contents); if (__CFStrIsEightBit(str)) { @@ -1029,20 +1111,22 @@ CFHashCode __CFStringHash(CFTypeRef cf) { static CFStringRef __CFStringCopyDescription(CFTypeRef cf) { - return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("{contents = \"%@\"}"), cf, __CFGetAllocator(cf), cf); + return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{contents = \"%@\"}"), cf, __CFGetAllocator(cf), cf); } static CFStringRef __CFStringCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { - return CFStringCreateCopy(__CFGetAllocator(cf), cf); + return (CFStringRef)CFStringCreateCopy(__CFGetAllocator(cf), (CFStringRef)cf); } static CFTypeID __kCFStringTypeID = _kCFRuntimeNotATypeID; +typedef CFTypeRef (*CF_STRING_CREATE_COPY)(CFAllocatorRef alloc, CFTypeRef theString); + static const CFRuntimeClass __CFStringClass = { 0, "CFString", NULL, // init - (void *)CFStringCreateCopy, + (CF_STRING_CREATE_COPY)CFStringCreateCopy, __CFStringDeallocate, __CFStringEqual, __CFStringHash, @@ -1066,7 +1150,7 @@ static Boolean CFStrIsUnicode(CFStringRef str) { -#define ALLOCATORSFREEFUNC ((void *)-1) +#define ALLOCATORSFREEFUNC ((CFAllocatorRef)-1) /* contentsDeallocator indicates how to free the data if it's noCopy == true: kCFAllocatorNull: don't free @@ -1094,6 +1178,19 @@ __private_extern__ CFStringRef __CFStringCreateImmutableFunnel3( Boolean useNullByte = false; Boolean useInlineData = false; +#if INSTRUMENT_SHARED_STRINGS + const char *recordedEncoding; + char encodingBuffer[128]; + if (encoding == kCFStringEncodingUnicode) recordedEncoding = "Unicode"; + else if (encoding == kCFStringEncodingASCII) recordedEncoding = "ASCII"; + else if (encoding == kCFStringEncodingUTF8) recordedEncoding = "UTF8"; + else if (encoding == kCFStringEncodingMacRoman) recordedEncoding = "MacRoman"; + else { + sprintf(encodingBuffer, "0x%lX", (unsigned long)encoding); + recordedEncoding = encodingBuffer; + } +#endif + if (alloc == NULL) alloc = __CFGetDefaultAllocator(); if (contentsDeallocator == ALLOCATORSFREEFUNC) { @@ -1106,38 +1203,51 @@ __private_extern__ CFStringRef __CFStringCreateImmutableFunnel3( 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); } - return CFRetain(kCFEmptyString); // Quick exit; won't catch all empty strings, but most + return (CFStringRef)CFRetain(kCFEmptyString); // Quick exit; won't catch all empty strings, but most } // At this point, contentsDeallocator is either same as alloc, or kCFAllocatorNull, or something else, but not NULL vBuf.shouldFreeChars = false; // We use this to remember to free the buffer possibly allocated by decode + // Record whether we're starting out with an ASCII-superset string, because we need to know this later for the string ROM; this may get changed later if we successfully convert down from Unicode. We only record this once because __CFCanUseEightBitCFStringForBytes() can be expensive. + Boolean stringSupportsEightBitCFRepresentation = encoding != kCFStringEncodingUnicode && __CFCanUseEightBitCFStringForBytes((const uint8_t *)bytes, numBytes, encoding); + + // We may also change noCopy within this function if we have to decode the string into an external buffer. We do not want to avoid the use of the string ROM merely because we tried to be efficient and reuse the decoded buffer for the CFString's external storage. Therefore, we use this variable to track whether we actually can ignore the noCopy flag (which may or may not be set anyways). + Boolean stringROMShouldIgnoreNoCopy = false; + // First check to see if the data needs to be converted... // ??? We could be more efficient here and in some cases (Unicode data) eliminate a copy - if ((encoding == kCFStringEncodingUnicode && possiblyExternalFormat) || (encoding != kCFStringEncodingUnicode && !__CFCanUseEightBitCFStringForBytes(bytes, numBytes, encoding))) { - const void *realBytes = (uint8_t*) bytes + (hasLengthByte ? 1 : 0); + if ((encoding == kCFStringEncodingUnicode && possiblyExternalFormat) || encoding != kCFStringEncodingUnicode && ! stringSupportsEightBitCFRepresentation) { + const void *realBytes = (uint8_t *) bytes + (hasLengthByte ? 1 : 0); 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.chars.unicode = NULL; // This will cause the decode function to allocate memory if necessary - if (!__CFStringDecodeByteStream3(realBytes, realNumBytes, encoding, false, &vBuf, &usingPassedInMemory, converterFlags)) { - return NULL; // !!! Is this acceptable failure mode? + if (!__CFStringDecodeByteStream3((const uint8_t *)realBytes, realNumBytes, encoding, false, &vBuf, &usingPassedInMemory, converterFlags)) { + // Note that if the string can't be created, we don't free the buffer, even if there is a contents deallocator. This is on purpose. + return NULL; } encoding = vBuf.isASCII ? kCFStringEncodingASCII : kCFStringEncodingUnicode; - + + // Update our flag according to whether the decoded buffer is ASCII + stringSupportsEightBitCFRepresentation = vBuf.isASCII; + if (!usingPassedInMemory) { + // Because __CFStringDecodeByteStream3() allocated our buffer, it's OK for us to free it if we can get the string from the ROM. + stringROMShouldIgnoreNoCopy = true; + // Make the parameters fit the new situation numBytes = vBuf.isASCII ? vBuf.numChars : (vBuf.numChars * sizeof(UniChar)); hasLengthByte = hasNullByte = false; // Get rid of the original buffer if its not being used - if (noCopy && contentsDeallocator != kCFAllocatorNull) { + if (noCopy && (contentsDeallocator != kCFAllocatorNull)) { CFAllocatorDeallocate(contentsDeallocator, (void *)bytes); } contentsDeallocator = alloc; // At this point we are using the string's allocator, as the original buffer is gone... @@ -1149,7 +1259,15 @@ __private_extern__ CFStringRef __CFStringCreateImmutableFunnel3( vBuf.shouldFreeChars = false; // Transferring ownership to the CFString bytes = CFAllocatorReallocate(vBuf.allocator, (void *)vBuf.chars.unicode, numBytes, 0); // Tighten up the storage noCopy = true; +#if INSTRUMENT_SHARED_STRINGS + if (encoding == kCFStringEncodingASCII) recordedEncoding = "ForeignASCII-NoCopy"; + else recordedEncoding = "ForeignUnicode-NoCopy"; +#endif } else { +#if INSTRUMENT_SHARED_STRINGS + if (encoding == kCFStringEncodingASCII) recordedEncoding = "ForeignASCII-Copy"; + else recordedEncoding = "ForeignUnicode-Copy"; +#endif bytes = vBuf.chars.unicode; noCopy = false; // Can't do noCopy anymore // If vBuf.shouldFreeChars is true, the buffer will be freed as intended near the end of this func @@ -1171,9 +1289,8 @@ __private_extern__ CFStringRef __CFStringCreateImmutableFunnel3( if (allASCII) { // Yes we can! uint8_t *ptr, *mem; - hasLengthByte = __CFCanUseLengthByte(len); - hasNullByte = true; - numBytes = (len + 1 + (hasLengthByte ? 1 : 0)) * sizeof(uint8_t); // NULL and possible length byte + Boolean newHasLengthByte = __CFCanUseLengthByte(len); + numBytes = (len + 1 + (newHasLengthByte ? 1 : 0)) * sizeof(uint8_t); // NULL and possible length byte // See if we can use that temporary local buffer in vBuf... if (numBytes >= __kCFVarWidthLocalBufferSize) { mem = ptr = (uint8_t *)CFAllocatorAllocate(alloc, numBytes, 0); @@ -1181,94 +1298,145 @@ __private_extern__ CFStringRef __CFStringCreateImmutableFunnel3( } else { mem = ptr = (uint8_t *)(vBuf.localBuffer); } - // Copy the Unicode bytes into the new ASCII buffer - if (hasLengthByte) *ptr++ = len; - for (cnt = 0; cnt < len; cnt++) ptr[cnt] = ((const UniChar *)bytes)[cnt]; - ptr[len] = 0; - if (noCopy && contentsDeallocator != kCFAllocatorNull) { - CFAllocatorDeallocate(contentsDeallocator, (void *)bytes); - } - // Now make everything look like we had an ASCII buffer to start with - bytes = mem; - encoding = kCFStringEncodingASCII; - contentsDeallocator = alloc; // At this point we are using the string's allocator, as the original buffer is gone... - noCopy = (numBytes >= __kCFVarWidthLocalBufferSize); // If we had to allocate it, make sure it's kept around - numBytes--; // Should not contain the NULL byte at end... + if (mem) { // If we can't allocate memory for some reason, use what we had (that is, as if we didn't have all ASCII) + // Copy the Unicode bytes into the new ASCII buffer + hasLengthByte = newHasLengthByte; + hasNullByte = true; + if (hasLengthByte) *ptr++ = (uint8_t)len; + for (cnt = 0; cnt < len; cnt++) ptr[cnt] = (uint8_t)(((const UniChar *)bytes)[cnt]); + ptr[len] = 0; + if (noCopy && (contentsDeallocator != kCFAllocatorNull)) { + CFAllocatorDeallocate(contentsDeallocator, (void *)bytes); + } + // Now make everything look like we had an ASCII buffer to start with + bytes = mem; + encoding = kCFStringEncodingASCII; + contentsDeallocator = alloc; // At this point we are using the string's allocator, as the original buffer is gone... + noCopy = (numBytes >= __kCFVarWidthLocalBufferSize); // If we had to allocate it, make sure it's kept around + numBytes--; // Should not contain the NULL byte at end... + stringSupportsEightBitCFRepresentation = true; // We're ASCII now! + stringROMShouldIgnoreNoCopy = true; // We allocated this buffer, so we should feel free to get rid of it if we can use the string ROM +#if INSTRUMENT_SHARED_STRINGS + recordedEncoding = "U->A"; +#endif + } } // At this point, all necessary input arguments have been changed to reflect the new state } // Now determine the necessary size + + Boolean stringSupportsROM = stringSupportsEightBitCFRepresentation; - if (noCopy) { +#if INSTRUMENT_SHARED_STRINGS + if (stringSupportsROM) { + const void *realBytes = (uint8_t *) bytes + (hasLengthByte ? 1 : 0); + CFIndex realNumBytes = numBytes - !! hasLengthByte; + __CFRecordStringAllocationEvent(recordedEncoding, realBytes, realNumBytes); + } +#endif - size = sizeof(void *); // Pointer to the buffer - if (contentsDeallocator != alloc && contentsDeallocator != kCFAllocatorNull) { - size += sizeof(void *); // The contentsDeallocator - } - if (!hasLengthByte) size += sizeof(SInt32); // Explicit length - useLengthByte = hasLengthByte; - useNullByte = hasNullByte; + CFStringRef romResult = NULL; - } else { // Inline data; reserve space for it +#if USE_STRING_ROM - useInlineData = true; - size = numBytes; + if (stringSupportsROM) { + // Disable the string ROM if necessary + static char sDisableStringROM = -1; + if (sDisableStringROM == -1) sDisableStringROM = !! getenv("CFStringDisableROM"); - if (hasLengthByte || (encoding != kCFStringEncodingUnicode && __CFCanUseLengthByte(numBytes))) { - useLengthByte = true; - if (!hasLengthByte) size += 1; - } else { - size += sizeof(SInt32); // Explicit length - } - if (hasNullByte || encoding != kCFStringEncodingUnicode) { - useNullByte = true; - size += 1; - } + if (sDisableStringROM == 0) romResult = _CFSearchStringROM(bytes + !! hasLengthByte, numBytes - !! hasLengthByte); } - -#ifdef STRING_SIZE_STATS - // Dump alloced CFString size info every so often - static int cnt = 0; - static unsigned sizes[256] = {0}; - int allocedSize = size + sizeof(CFRuntimeBase); - if (allocedSize < 255) sizes[allocedSize]++; else sizes[255]++; - if ((++cnt % 1000) == 0) { - printf ("\nTotal: %d\n", cnt); - int i; for (i = 0; i < 256; i++) printf("%03d: %5d%s", i, sizes[i], ((i % 8) == 7) ? "\n" : " "); + /* if we get a result from our ROM, and noCopy is set, then deallocate the buffer immediately */ + if (romResult) { + if (noCopy && (contentsDeallocator != kCFAllocatorNull)) { + CFAllocatorDeallocate(contentsDeallocator, (void *)bytes); + } + + /* these don't get used again, but clear them for consistency */ + noCopy = false; + bytes = NULL; + + /* set our result to the ROM result which is not really mutable, of course, but that's OK because we don't try to modify it. */ + str = (CFMutableStringRef)romResult; } #endif - - // Finally, allocate! - str = (CFMutableStringRef)_CFRuntimeCreateInstance(alloc, __kCFStringTypeID, size, NULL); - if (str) { - if (__CFOASafe) __CFSetLastAllocationEventName(str, "CFString (immutable)"); - - __CFStrSetInfoBits(str, - (useInlineData ? __kCFHasInlineContents : (contentsDeallocator == alloc ? __kCFNotInlineContentsDefaultFree : (contentsDeallocator == kCFAllocatorNull ? __kCFNotInlineContentsNoFree : __kCFNotInlineContentsCustomFree))) | - ((encoding == kCFStringEncodingUnicode) ? __kCFIsUnicode : 0) | - (useNullByte ? __kCFHasNullByte : 0) | - (useLengthByte ? __kCFHasLengthByte : 0)); - - if (!useLengthByte) { - CFIndex length = numBytes - (hasLengthByte ? 1 : 0); - if (encoding == kCFStringEncodingUnicode) length /= sizeof(UniChar); - __CFStrSetExplicitLength(str, length); + if (! romResult) { + // Now determine the necessary size + + if (noCopy) { + + size = sizeof(void *); // Pointer to the buffer + if (contentsDeallocator != alloc && contentsDeallocator != kCFAllocatorNull) { + size += sizeof(void *); // The contentsDeallocator + } + if (!hasLengthByte) size += sizeof(CFIndex); // Explicit length + useLengthByte = hasLengthByte; + useNullByte = hasNullByte; + + } else { // Inline data; reserve space for it + + useInlineData = true; + size = numBytes; + + if (hasLengthByte || (encoding != kCFStringEncodingUnicode && __CFCanUseLengthByte(numBytes))) { + useLengthByte = true; + if (!hasLengthByte) size += 1; + } else { + size += sizeof(CFIndex); // Explicit length + } + if (hasNullByte || encoding != kCFStringEncodingUnicode) { + useNullByte = true; + size += 1; + } + } + +#ifdef STRING_SIZE_STATS + // Dump alloced CFString size info every so often + static int cnt = 0; + static unsigned sizes[256] = {0}; + int allocedSize = size + sizeof(CFRuntimeBase); + if (allocedSize < 255) sizes[allocedSize]++; else sizes[255]++; + if ((++cnt % 1000) == 0) { + printf ("\nTotal: %d\n", cnt); + int i; for (i = 0; i < 256; i++) printf("%03d: %5d%s", i, sizes[i], ((i % 8) == 7) ? "\n" : " "); } +#endif + + // Finally, allocate! + + str = (CFMutableStringRef)_CFRuntimeCreateInstance(alloc, __kCFStringTypeID, size, NULL); + if (str) { + if (__CFOASafe) __CFSetLastAllocationEventName(str, "CFString (immutable)"); + + __CFStrSetInfoBits(str, + (useInlineData ? __kCFHasInlineContents : (contentsDeallocator == alloc ? __kCFNotInlineContentsDefaultFree : (contentsDeallocator == kCFAllocatorNull ? __kCFNotInlineContentsNoFree : __kCFNotInlineContentsCustomFree))) | + ((encoding == kCFStringEncodingUnicode) ? __kCFIsUnicode : 0) | + (useNullByte ? __kCFHasNullByte : 0) | + (useLengthByte ? __kCFHasLengthByte : 0)); + + if (!useLengthByte) { + CFIndex length = numBytes - (hasLengthByte ? 1 : 0); + if (encoding == kCFStringEncodingUnicode) length /= sizeof(UniChar); + __CFStrSetExplicitLength(str, length); + } - if (useInlineData) { - uint8_t *contents = (uint8_t *)__CFStrContents(str); - if (useLengthByte && !hasLengthByte) *contents++ = numBytes; - memmove(contents, bytes, numBytes); - if (useNullByte) contents[numBytes] = 0; + if (useInlineData) { + uint8_t *contents = (uint8_t *)__CFStrContents(str); + if (useLengthByte && !hasLengthByte) *contents++ = (uint8_t)numBytes; + memmove(contents, bytes, numBytes); + if (useNullByte) contents[numBytes] = 0; + } else { + __CFStrSetContentPtr(str, bytes); + if (contentsDeallocator != alloc && contentsDeallocator != kCFAllocatorNull) __CFStrSetContentsDeallocator(str, (CFAllocatorRef)CFRetain(contentsDeallocator)); + } } else { - __CFStrSetContentPtr(str, bytes); - if (contentsDeallocator != alloc && contentsDeallocator != kCFAllocatorNull) __CFStrSetContentsDeallocator(str, CFRetain(contentsDeallocator)); + if (noCopy && (contentsDeallocator != kCFAllocatorNull)) { + CFAllocatorDeallocate(contentsDeallocator, (void *)bytes); + } } - } else { - if (contentsDeallocator != kCFAllocatorNull) CFAllocatorDeallocate(contentsDeallocator, (void *)bytes); } if (vBuf.shouldFreeChars) CFAllocatorDeallocate(vBuf.allocator, (void *)bytes); @@ -1328,21 +1496,21 @@ CFStringRef _CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const uint8_t } CFStringRef CFStringCreateWithBytesNoCopy(CFAllocatorRef alloc, const uint8_t *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean externalFormat, CFAllocatorRef contentsDeallocator) { - return _CFStringCreateWithBytesNoCopy(alloc, bytes, numBytes, encoding, externalFormat, contentsDeallocator); + return __CFStringCreateImmutableFunnel3(alloc, bytes, numBytes, encoding, externalFormat, true, false, false, true, contentsDeallocator, 0); } CFStringRef CFStringCreateWithFormatAndArguments(CFAllocatorRef alloc, CFDictionaryRef formatOptions, CFStringRef format, va_list arguments) { return _CFStringCreateWithFormatAndArgumentsAux(alloc, NULL, formatOptions, format, arguments); } -CFStringRef _CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc, CFStringRef (*copyDescFunc)(void *, CFDictionaryRef), CFDictionaryRef formatOptions, CFStringRef format, va_list arguments) { +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 __CFStrSetDesiredCapacity(outputString, 120); // Given this will be tightened later, choosing a larger working string is fine _CFStringAppendFormatAndArgumentsAux(outputString, copyDescFunc, formatOptions, format, 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 = CFStringCreateCopy(alloc, outputString); + str = (CFStringRef)CFStringCreateCopy(alloc, outputString); CFRelease(outputString); return str; } @@ -1359,54 +1527,38 @@ CFStringRef CFStringCreateWithFormat(CFAllocatorRef alloc, CFDictionaryRef form } CFStringRef CFStringCreateWithSubstring(CFAllocatorRef alloc, CFStringRef str, CFRange range) { - if (CF_IS_OBJC(__kCFStringTypeID, str)) { - static SEL s = NULL; - CFStringRef (*func)(void *, SEL, ...) = (void *)__CFSendObjCMsg; - if (!s) s = sel_registerName("_createSubstringWithRange:"); - CFStringRef result = func((void *)str, s, CFRangeMake(range.location, range.length)); - if (result && CF_USING_COLLECTABLE_MEMORY) CFRetain(result); // needs hard retain. - return result; - } // CF_OBJC_FUNCDISPATCH1(__kCFStringTypeID, CFStringRef , str, "_createSubstringWithRange:", CFRangeMake(range.location, range.length)); __CFAssertIsString(str); __CFAssertRangeIsInStringBounds(str, range.location, range.length); if ((range.location == 0) && (range.length == __CFStrLength(str))) { /* The substring is the whole string... */ - return CFStringCreateCopy(alloc, str); + return (CFStringRef)CFStringCreateCopy(alloc, str); } else if (__CFStrIsEightBit(str)) { - const uint8_t *contents = __CFStrContents(str); + const uint8_t *contents = (const uint8_t *)__CFStrContents(str); return __CFStringCreateImmutableFunnel3(alloc, contents + range.location + __CFStrSkipAnyLengthByte(str), range.length, __CFStringGetEightBitStringEncoding(), false, false, false, false, false, ALLOCATORSFREEFUNC, 0); } else { - const UniChar *contents = __CFStrContents(str); + const UniChar *contents = (UniChar *)__CFStrContents(str); return __CFStringCreateImmutableFunnel3(alloc, contents + range.location, range.length * sizeof(UniChar), kCFStringEncodingUnicode, false, true, false, false, false, ALLOCATORSFREEFUNC, 0); } } -CFStringRef CFStringCreateCopy(CFAllocatorRef alloc, CFStringRef str) { - if (CF_IS_OBJC(__kCFStringTypeID, str)) { - static SEL s = NULL; - CFStringRef (*func)(void *, SEL, ...) = (void *)__CFSendObjCMsg; - if (!s) s = sel_registerName("copy"); - CFStringRef result = func((void *)str, s); - if (result && CF_USING_COLLECTABLE_MEMORY) CFRetain(result); // needs hard retain. - return result; - } +CFStringRef CFStringCreateCopy(CFAllocatorRef alloc, CFStringRef str) { // CF_OBJC_FUNCDISPATCH0(__kCFStringTypeID, CFStringRef, str, "copy"); __CFAssertIsString(str); - if (!__CFStrIsMutable(str) && // If the string is not mutable + 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 - (__CFStrIsInline(str) || __CFStrFreeContentsWhenDone(str) || __CFStrIsConstant(str))) { // and the characters are inline, or are owned by the string, or the string is constant + (__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 return str; } - if (__CFStrIsEightBit(str)) { - const uint8_t *contents = __CFStrContents(str); - return __CFStringCreateImmutableFunnel3(alloc, contents + __CFStrSkipAnyLengthByte(str), __CFStrLength2(str, contents), __CFStringGetEightBitStringEncoding(), false, false, false, false, false, ALLOCATORSFREEFUNC, 0); + if (__CFStrIsEightBit((CFStringRef)str)) { + const uint8_t *contents = (const uint8_t *)__CFStrContents((CFStringRef)str); + return __CFStringCreateImmutableFunnel3(alloc, contents + __CFStrSkipAnyLengthByte((CFStringRef)str), __CFStrLength2((CFStringRef)str, contents), __CFStringGetEightBitStringEncoding(), false, false, false, false, false, ALLOCATORSFREEFUNC, 0); } else { - const UniChar *contents = __CFStrContents(str); - return __CFStringCreateImmutableFunnel3(alloc, contents, __CFStrLength2(str, contents) * sizeof(UniChar), kCFStringEncodingUnicode, false, true, false, false, false, ALLOCATORSFREEFUNC, 0); + const UniChar *contents = (const UniChar *)__CFStrContents((CFStringRef)str); + return __CFStringCreateImmutableFunnel3(alloc, contents, __CFStrLength2((CFStringRef)str, contents) * sizeof(UniChar), kCFStringEncodingUnicode, false, true, false, false, false, ALLOCATORSFREEFUNC, 0); } } @@ -1414,13 +1566,13 @@ CFStringRef CFStringCreateCopy(CFAllocatorRef alloc, CFStringRef str) { /*** Constant string stuff... ***/ -static CFMutableDictionaryRef constantStringTable = NULL; - -/* For now we call a function to create a constant string and keep previously created constant strings in a dictionary. The keys are the 8-bit constant C-strings from the compiler; the values are the CFStrings created for them. +/* Table which holds constant strings created with CFSTR, when -fconstant-cfstrings option is not used. These dynamically created constant strings are stored in constantStringTable. The keys are the 8-bit constant C-strings from the compiler; the values are the CFStrings created for them. _CFSTRLock protects this table. */ +static CFMutableDictionaryRef constantStringTable = NULL; +static CFSpinLock_t _CFSTRLock = CFSpinLockInit; static CFStringRef __cStrCopyDescription(const void *ptr) { - return CFStringCreateWithCStringNoCopy(NULL, (const char *)ptr, __CFStringGetEightBitStringEncoding(), kCFAllocatorNull); + return CFStringCreateWithCStringNoCopy(kCFAllocatorSystemDefault, (const char *)ptr, __CFStringGetEightBitStringEncoding(), kCFAllocatorNull); } static Boolean __cStrEqual(const void *ptr1, const void *ptr2) { @@ -1429,7 +1581,7 @@ static Boolean __cStrEqual(const void *ptr1, const void *ptr2) { static CFHashCode __cStrHash(const void *ptr) { // It doesn't quite matter if we convert to Unicode correctly, as long as we do it consistently - const unsigned char *cStr = (const unsigned char *)ptr; + const char *cStr = (const char *)ptr; CFIndex len = strlen(cStr); CFHashCode result = 0; if (len <= 4) { // All chars @@ -1445,50 +1597,23 @@ static CFHashCode __cStrHash(const void *ptr) { return result; } -#if defined(DEBUG) -/* We use a special allocator (which simply calls through to the default) for constant strings so that we can catch them being freed... -*/ -static void *csRealloc(void *oPtr, CFIndex size, CFOptionFlags hint, void *info) { - return CFAllocatorReallocate(NULL, oPtr, size, hint); -} - -static void *csAlloc(CFIndex size, CFOptionFlags hint, void *info) { - return CFAllocatorAllocate(NULL, size, hint); -} - -static void csDealloc(void *ptr, void *info) { - CFAllocatorDeallocate(NULL, ptr); -} - -static CFStringRef csCopyDescription(const void *info) { - return CFRetain(CFSTR("Debug allocator for CFSTRs")); -} -#endif - -static CFSpinLock_t _CFSTRLock = 0; CFStringRef __CFStringMakeConstantString(const char *cStr) { CFStringRef result; #if defined(DEBUG) - //StringTest checks that we share kCFEmptyString, which is defeated by constantStringAllocatorForDebugging + // StringTest checks that we share kCFEmptyString, which is defeated by constantStringAllocatorForDebugging if ('\0' == *cStr) return kCFEmptyString; #endif if (constantStringTable == NULL) { CFDictionaryKeyCallBacks constantStringCallBacks = {0, NULL, NULL, __cStrCopyDescription, __cStrEqual, __cStrHash}; - CFMutableDictionaryRef table = CFDictionaryCreateMutable(NULL, 0, &constantStringCallBacks, &kCFTypeDictionaryValueCallBacks); - _CFDictionarySetCapacity(table, 2500); // avoid lots of rehashing + CFDictionaryValueCallBacks constantStringValueCallBacks = kCFTypeDictionaryValueCallBacks; + constantStringValueCallBacks.equal = NULL; // So that we only find strings that are == + CFMutableDictionaryRef table = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &constantStringCallBacks, &constantStringValueCallBacks); + _CFDictionarySetCapacity(table, 2500); // avoid lots of rehashing __CFSpinLock(&_CFSTRLock); if (constantStringTable == NULL) constantStringTable = table; __CFSpinUnlock(&_CFSTRLock); if (constantStringTable != table) CFRelease(table); -#if defined(DEBUG) - { - CFAllocatorContext context = {0, NULL, NULL, NULL, csCopyDescription, csAlloc, csRealloc, csDealloc, NULL}; - constantStringAllocatorForDebugging = _CFAllocatorCreateGC(NULL, &context); - } -#else -#define constantStringAllocatorForDebugging NULL -#endif } __CFSpinLock(&_CFSTRLock); @@ -1501,25 +1626,25 @@ CFStringRef __CFStringMakeConstantString(const char *cStr) { char *key; Boolean isASCII = true; // Given this code path is rarer these days, OK to do this extra work to verify the strings - const unsigned char *tmp = cStr; + const char *tmp = cStr; while (*tmp) { - if (*tmp++ > 127) { + if (*(tmp++) & 0x80) { isASCII = false; break; } } if (!isASCII) { - CFMutableStringRef ms = CFStringCreateMutable(NULL, 0); + CFMutableStringRef ms = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); tmp = cStr; while (*tmp) { - CFStringAppendFormat(ms, NULL, (*tmp > 127) ? CFSTR("\\%3o") : CFSTR("%1c"), *tmp); + CFStringAppendFormat(ms, NULL, (*tmp & 0x80) ? CFSTR("\\%3o") : CFSTR("%1c"), *tmp); tmp++; } - CFLog(0, CFSTR("WARNING: CFSTR(\"%@\") has non-7 bit chars, interpreting using MacOS Roman encoding for now, but this will change. Please eliminate usages of non-7 bit chars (including escaped characters above \\177 octal) in CFSTR()."), ms); + CFLog(kCFLogLevelWarning, CFSTR("WARNING: CFSTR(\"%@\") has non-7 bit chars, interpreting using MacOS Roman encoding for now, but this will change. Please eliminate usages of non-7 bit chars (including escaped characters above \\177 octal) in CFSTR()."), ms); CFRelease(ms); } // Treat non-7 bit chars in CFSTR() as MacOSRoman, for compatibility - result = CFStringCreateWithCString(constantStringAllocatorForDebugging, cStr, kCFStringEncodingMacRoman); + result = CFStringCreateWithCString(kCFAllocatorSystemDefault, cStr, kCFStringEncodingMacRoman); if (result == NULL) { CFLog(__kCFLogAssertion, CFSTR("Can't interpret CFSTR() as MacOS Roman, crashing")); HALT; @@ -1528,35 +1653,49 @@ CFStringRef __CFStringMakeConstantString(const char *cStr) { if (__CFStrIsEightBit(result)) { key = (char *)__CFStrContents(result) + __CFStrSkipAnyLengthByte(result); } else { // For some reason the string is not 8-bit! - key = CFAllocatorAllocate(NULL, strlen(cStr) + 1, 0); + key = (char *)CFAllocatorAllocate(kCFAllocatorSystemDefault, strlen(cStr) + 1, 0); if (__CFOASafe) __CFSetLastAllocationEventName((void *)key, "CFString (CFSTR key)"); - strcpy(key, cStr); // !!! We will leak this, if the string is removed from the table (or table is freed) + strlcpy(key, cStr, strlen(cStr) + 1); // !!! We will leak this, if the string is removed from the table (or table is freed) } { -#if !defined(DEBUG) CFStringRef resultToBeReleased = result; -#endif CFIndex count; __CFSpinLock(&_CFSTRLock); count = CFDictionaryGetCount(constantStringTable); CFDictionaryAddValue(constantStringTable, key, result); if (CFDictionaryGetCount(constantStringTable) == count) { // add did nothing, someone already put it there result = (CFStringRef)CFDictionaryGetValue(constantStringTable, key); + } else { +#if __LP64__ + ((struct __CFString *)result)->base._rc = 0; +#else + ((struct __CFString *)result)->base._cfinfo[CF_RC_BITS] = 0; +#endif } __CFSpinUnlock(&_CFSTRLock); -#if !defined(DEBUG) - // Can't release this in the DEBUG case; will get assertion failure + // This either eliminates the extra retain on the freshly created string, or frees it, if it was actually not inserted into the table CFRelease(resultToBeReleased); -#endif } } } return result; } -#if defined(__MACOS8__) || defined(__WIN32__) +#if defined(DEBUG) +static Boolean __CFStrIsConstantString(CFStringRef str) { + Boolean found = false; + if (constantStringTable) { + __CFSpinLock(&_CFSTRLock); + found = CFDictionaryContainsValue(constantStringTable, str); + __CFSpinUnlock(&_CFSTRLock); + } + return found; +} +#endif + +#if 0 void __CFStringCleanup (void) { /* in case library is unloaded, release store for the constant string table */ if (constantStringTable != NULL) { @@ -1568,11 +1707,7 @@ void __CFStringCleanup (void) { CFRelease(constantStringTable); #endif } -#if defined(DEBUG) - CFAllocatorDeallocate( constantStringAllocatorForDebugging, (void*) constantStringAllocatorForDebugging ); -#endif } - #endif @@ -1582,7 +1717,7 @@ void __CFStringCleanup (void) { static void __CFStringReplaceMultiple(CFMutableStringRef str, CFRange *ranges, CFIndex numRanges, CFStringRef replacement) { int cnt; CFStringRef copy = NULL; - if (replacement == str) copy = replacement = CFStringCreateCopy(NULL, replacement); // Very special and hopefully rare case + if (replacement == str) copy = replacement = CFStringCreateCopy(kCFAllocatorSystemDefault, replacement); // Very special and hopefully rare case CFIndex replacementLength = CFStringGetLength(replacement); __CFStringChangeSizeMultiple(str, ranges, numRanges, replacementLength, (replacementLength > 0) && CFStrIsUnicode(replacement)); @@ -1616,7 +1751,7 @@ static void __CFStringReplaceMultiple(CFMutableStringRef str, CFRange *ranges, C CF_INLINE void __CFStringReplace(CFMutableStringRef str, CFRange range, CFStringRef replacement) { CFStringRef copy = NULL; - if (replacement == str) copy = replacement = CFStringCreateCopy(NULL, replacement); // Very special and hopefully rare case + if (replacement == str) copy = replacement = (CFStringRef)CFStringCreateCopy(kCFAllocatorSystemDefault, replacement); // Very special and hopefully rare case CFIndex replacementLength = CFStringGetLength(replacement); __CFStringChangeSize(str, range, replacementLength, (replacementLength > 0) && CFStrIsUnicode(replacement)); @@ -1643,14 +1778,14 @@ CF_INLINE CFMutableStringRef __CFStringCreateMutableFunnel(CFAllocatorRef alloc, if (alloc == NULL) alloc = __CFGetDefaultAllocator(); // Note that if there is an externalContentsAllocator, then we also have the storage for the string allocator... - str = (CFMutableStringRef)_CFRuntimeCreateInstance(alloc, __kCFStringTypeID, sizeof(void *) + sizeof(UInt32) * 3 + (hasExternalContentsAllocator ? sizeof(CFAllocatorRef) : 0), NULL); + str = (CFMutableStringRef)_CFRuntimeCreateInstance(alloc, __kCFStringTypeID, sizeof(struct __notInlineMutable) - (hasExternalContentsAllocator ? 0 : sizeof(CFAllocatorRef)), NULL); if (str) { if (__CFOASafe) __CFSetLastAllocationEventName(str, "CFString (mutable)"); __CFStrSetInfoBits(str, __kCFIsMutable | additionalInfoBits); str->variants.notInlineMutable.buffer = NULL; __CFStrSetExplicitLength(str, 0); - str->variants.notInlineMutable.gapEtc = 0; + str->variants.notInlineMutable.hasGap = str->variants.notInlineMutable.isFixedCapacity = str->variants.notInlineMutable.isExternalMutable = str->variants.notInlineMutable.capacityProvidedExternally = 0; if (maxLength != 0) __CFStrSetIsFixed(str); __CFStrSetDesiredCapacity(str, (maxLength == 0) ? DEFAULTMINCAPACITY : maxLength); __CFStrSetCapacity(str, 0); @@ -1663,7 +1798,7 @@ CFMutableStringRef CFStringCreateMutableWithExternalCharactersNoCopy(CFAllocator CFMutableStringRef string = __CFStringCreateMutableFunnel(alloc, 0, contentsAllocationBits | __kCFIsUnicode); if (string) { __CFStrSetIsExternalMutable(string); - if (contentsAllocationBits == __kCFHasContentsAllocator) __CFStrSetContentsAllocator(string, CFRetain(externalCharactersAllocator)); + if (contentsAllocationBits == __kCFHasContentsAllocator) __CFStrSetContentsAllocator(string, (CFAllocatorRef)CFRetain(externalCharactersAllocator)); CFStringSetExternalCharactersNoCopy(string, chars, numChars, capacity); } return string; @@ -1676,14 +1811,6 @@ CFMutableStringRef CFStringCreateMutable(CFAllocatorRef alloc, CFIndex maxLength CFMutableStringRef CFStringCreateMutableCopy(CFAllocatorRef alloc, CFIndex maxLength, CFStringRef string) { CFMutableStringRef newString; - if (CF_IS_OBJC(__kCFStringTypeID, string)) { - static SEL s = NULL; - CFMutableStringRef (*func)(void *, SEL, ...) = (void *)__CFSendObjCMsg; - if (!s) s = sel_registerName("mutableCopy"); - newString = func((void *)string, s); - if (CF_USING_COLLECTABLE_MEMORY) auto_zone_retain(__CFCollectableZone, newString); // needs hard retain IF using GC - return newString; - } // CF_OBJC_FUNCDISPATCH0(__kCFStringTypeID, CFMutableStringRef, string, "mutableCopy"); __CFAssertIsString(string); @@ -1741,13 +1868,13 @@ UniChar CFStringGetCharacterAtIndex(CFStringRef str, CFIndex idx) { __CFAssertIsString(str); __CFAssertIndexIsInStringBounds(str, idx); - return __CFStringGetCharacterAtIndexGuts(str, idx, __CFStrContents(str)); + return __CFStringGetCharacterAtIndexGuts(str, idx, (const uint8_t *)__CFStrContents(str)); } /* This one is for NSCFString usage; it doesn't do ObjC dispatch; but it does do range check */ int _CFStringCheckAndGetCharacterAtIndex(CFStringRef str, CFIndex idx, UniChar *ch) { - const uint8_t *contents = __CFStrContents(str); + const uint8_t *contents = (const uint8_t *)__CFStrContents(str); if (idx >= __CFStrLength2(str, contents) && __CFStringNoteErrors()) return _CFStringErrBounds; *ch = __CFStringGetCharacterAtIndexGuts(str, idx, contents); return _CFStringErrNone; @@ -1772,13 +1899,13 @@ void CFStringGetCharacters(CFStringRef str, CFRange range, UniChar *buffer) { __CFAssertIsString(str); __CFAssertRangeIsInStringBounds(str, range.location, range.length); - __CFStringGetCharactersGuts(str, range, buffer, __CFStrContents(str)); + __CFStringGetCharactersGuts(str, range, buffer, (const uint8_t *)__CFStrContents(str)); } /* This one is for NSCFString usage; it doesn't do ObjC dispatch; but it does do range check */ int _CFStringCheckAndGetCharacters(CFStringRef str, CFRange range, UniChar *buffer) { - const uint8_t *contents = __CFStrContents(str); + const uint8_t *contents = (const uint8_t *)__CFStrContents(str); if (range.location + range.length > __CFStrLength2(str, contents) && __CFStringNoteErrors()) return _CFStringErrBounds; __CFStringGetCharactersGuts(str, range, buffer, contents); return _CFStringErrNone; @@ -1795,7 +1922,7 @@ CFIndex CFStringGetBytes(CFStringRef str, CFRange range, CFStringEncoding encodi __CFAssertRangeIsInStringBounds(str, range.location, range.length); if (__CFStrIsEightBit(str) && ((__CFStringGetEightBitStringEncoding() == encoding) || (__CFStringGetEightBitStringEncoding() == kCFStringEncodingASCII && __CFStringEncodingIsSupersetOfASCII(encoding)))) { // Requested encoding is equal to the encoding in string - const unsigned char *contents = __CFStrContents(str); + const unsigned char *contents = (const unsigned char *)__CFStrContents(str); CFIndex cLength = range.length; if (buffer) { @@ -1817,7 +1944,7 @@ ConstStringPtr CFStringGetPascalStringPtr (CFStringRef str, CFStringEncoding enc if (!CF_IS_OBJC(__kCFStringTypeID, str)) { /* ??? Hope the compiler optimizes this away if OBJC_MAPPINGS is not on */ __CFAssertIsString(str); if (__CFStrHasLengthByte(str) && __CFStrIsEightBit(str) && ((__CFStringGetEightBitStringEncoding() == encoding) || (__CFStringGetEightBitStringEncoding() == kCFStringEncodingASCII && __CFStringEncodingIsSupersetOfASCII(encoding)))) { // Requested encoding is equal to the encoding in string || the contents is in ASCII - const uint8_t *contents = __CFStrContents(str); + const uint8_t *contents = (const uint8_t *)__CFStrContents(str); if (__CFStrHasExplicitLength(str) && (__CFStrLength2(str, contents) != (SInt32)(*contents))) return NULL; // Invalid length byte return (ConstStringPtr)contents; } @@ -1837,6 +1964,8 @@ const char * CFStringGetCStringPtr(CFStringRef str, CFStringEncoding encoding) { __CFAssertIsString(str); if (__CFStrHasNullByte(str)) { + // Note: this is called a lot, 27000 times to open a small xcode project with one file open. + // Of these uses about 1500 are for cStrings/utf8strings. return (const char *)__CFStrContents(str) + __CFStrSkipAnyLengthByte(str); } else { return NULL; @@ -1869,7 +1998,7 @@ Boolean CFStringGetPascalString(CFStringRef str, Str255 buffer, CFIndex bufferSi __CFAssertIsString(str); - contents = __CFStrContents(str); + contents = (const uint8_t *)__CFStrContents(str); length = __CFStrLength2(str, contents); if (!__CFCanUseLengthByte(length)) return false; // Can't fit into pstring @@ -1877,23 +2006,24 @@ Boolean CFStringGetPascalString(CFStringRef str, Str255 buffer, CFIndex bufferSi if (__CFStrIsEightBit(str) && ((__CFStringGetEightBitStringEncoding() == encoding) || (__CFStringGetEightBitStringEncoding() == kCFStringEncodingASCII && __CFStringEncodingIsSupersetOfASCII(encoding)))) { // Requested encoding is equal to the encoding in string if (length >= bufferSize) return false; memmove((void*)(1 + (const char*)buffer), (__CFStrSkipAnyLengthByte(str) + contents), length); - *buffer = length; + *buffer = (unsigned char)length; return true; } } - if (__CFStringEncodeByteStream(str, 0, length, false, encoding, false, (void*)(1 + (uint8_t*)buffer), bufferSize - 1, &usedLen) != length) { + if (__CFStringEncodeByteStream(str, 0, length, false, encoding, false, (UInt8 *)(1 + (uint8_t *)buffer), bufferSize - 1, &usedLen) != length) { + #if defined(DEBUG) if (bufferSize > 0) { - strncpy((char *)buffer + 1, CONVERSIONFAILURESTR, bufferSize - 1); - buffer[0] = (CFIndex)sizeof(CONVERSIONFAILURESTR) < (bufferSize - 1) ? (CFIndex)sizeof(CONVERSIONFAILURESTR) : (bufferSize - 1); + strlcpy((char *)buffer + 1, CONVERSIONFAILURESTR, bufferSize - 1); + buffer[0] = (unsigned char)((CFIndex)sizeof(CONVERSIONFAILURESTR) < (bufferSize - 1) ? (CFIndex)sizeof(CONVERSIONFAILURESTR) : (bufferSize - 1)); } #else if (bufferSize > 0) buffer[0] = 0; #endif return false; } - *buffer = usedLen; + *buffer = (unsigned char)usedLen; return true; } @@ -1908,7 +2038,7 @@ Boolean CFStringGetCString(CFStringRef str, char *buffer, CFIndex bufferSize, CF __CFAssertIsString(str); - contents = __CFStrContents(str); + contents = (const uint8_t *)__CFStrContents(str); len = __CFStrLength2(str, contents); if (__CFStrIsEightBit(str) && ((__CFStringGetEightBitStringEncoding() == encoding) || (__CFStringGetEightBitStringEncoding() == kCFStringEncodingASCII && __CFStringEncodingIsSupersetOfASCII(encoding)))) { // Requested encoding is equal to the encoding in string @@ -1924,7 +2054,7 @@ Boolean CFStringGetCString(CFStringRef str, char *buffer, CFIndex bufferSize, CF return true; } else { #if defined(DEBUG) - strncpy(buffer, CONVERSIONFAILURESTR, bufferSize); + strlcpy(buffer, CONVERSIONFAILURESTR, bufferSize); #else if (bufferSize > 0) buffer[0] = 0; #endif @@ -1933,15 +2063,65 @@ Boolean CFStringGetCString(CFStringRef str, char *buffer, CFIndex bufferSize, CF } } +static const char *_CFStrGetLanguageIdentifierForLocale(CFLocaleRef locale) { + CFStringRef collatorID; + const char *langID = NULL; + static const void *lastLocale = NULL; + static const char *lastLangID = NULL; + static CFSpinLock_t lock = CFSpinLockInit; + + __CFSpinLock(&lock); + if ((NULL != lastLocale) && (lastLocale == locale)) { + __CFSpinUnlock(&lock); + return lastLangID; + } + __CFSpinUnlock(&lock); + + collatorID = CFLocaleGetValue(locale, __kCFLocaleCollatorID); + + // This is somewhat depending on CFLocale implementation always creating CFString for locale identifer ??? + if (__CFStrLength(collatorID) > 1) { + const void *contents = __CFStrContents(collatorID); + const char *string; + char buffer[2]; + + if (__CFStrIsEightBit(collatorID)) { + string = ((const char *)contents) + __CFStrSkipAnyLengthByte(collatorID); + } else { + const UTF16Char *characters = (const UTF16Char *)contents; + + buffer[0] = (char)*(characters++); + buffer[1] = (char)*characters; + string = buffer; + } + + if (!strncmp(string, "az", 2)) { // Azerbaijani + langID = "az"; + } else if (!strncmp(string, "lt", 2)) { // Lithuanian + langID = "lt"; + } else if (!strncmp(string, "tr", 2)) { // Turkish + langID = "tr"; + } + } + + __CFSpinLock(&lock); + lastLocale = locale; + lastLangID = langID; + __CFSpinUnlock(&lock); + + 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 false; } -static const char *_CFStrGetLanguageIdentifierForLocale(CFLocaleRef locale) { - return NULL; -} - #define MAX_CASE_MAPPING_BUF (8) #define ZERO_WIDTH_JOINER (0x200D) #define COMBINING_GRAPHEME_JOINER (0x034F) @@ -1958,7 +2138,7 @@ static const char *_CFStrGetLanguageIdentifierForLocale(CFLocaleRef locale) { // Returns the length of characters filled into outCharacters. If no change, returns 0. maxBufLen shoule be at least 8 -static inline CFIndex __CFStringFoldCharacterClusterAtIndex(UTF32Char character, CFStringInlineBuffer *buffer, CFIndex index, CFOptionFlags flags, const uint8_t *langCode, UTF32Char *outCharacters, CFIndex maxBufferLength, CFIndex *consumedLength) { +static CFIndex __CFStringFoldCharacterClusterAtIndex(UTF32Char character, CFStringInlineBuffer *buffer, CFIndex index, CFOptionFlags flags, const uint8_t *langCode, UTF32Char *outCharacters, CFIndex maxBufferLength, CFIndex *consumedLength) { CFIndex filledLength = 0, currentIndex = index; if (0 != character) { @@ -1966,11 +2146,11 @@ static inline CFIndex __CFStringFoldCharacterClusterAtIndex(UTF32Char character, CFIndex planeNo = (character >> 16); bool isTurkikCapitalI = false; static const uint8_t *decompBMP = NULL; - static const uint8_t *nonBaseBMP = NULL; + static const uint8_t *graphemeBMP = NULL; if (NULL == decompBMP) { decompBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet, 0); - nonBaseBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, 0); + graphemeBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharGraphemeExtendCharacterSet, 0); } ++currentIndex; @@ -1997,18 +2177,26 @@ static inline CFIndex __CFStringFoldCharacterClusterAtIndex(UTF32Char character, } // decompose - if (flags & (kCFCompareDiacriticsInsensitive|kCFCompareNonliteral)) { + if (flags & (kCFCompareDiacriticsInsensitiveCompatibilityMask|kCFCompareNonliteral)) { if (CFUniCharIsMemberOfBitmap(character, ((0 == planeNo) ? decompBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet, planeNo)))) { + UTF32Char original = character; + filledLength = CFUniCharDecomposeCharacter(character, outCharacters, maxBufferLength); character = *outCharacters; - if ((flags & kCFCompareDiacriticsInsensitive) && (character < 0x0510)) filledLength = 1; // reset if Roman, Greek, Cyrillic + + if ((flags & kCFCompareDiacriticsInsensitiveCompatibilityMask) && (character < 0x0510)) { + filledLength = 1; // reset if Roman, Greek, Cyrillic + } else if (0 == (flags & kCFCompareNonliteral)) { + character = original; + filledLength = 0; + } } } // fold case if (flags & kCFCompareCaseInsensitive) { const uint8_t *nonBaseBitmap; - bool filterNonBase = (((flags & kCFCompareDiacriticsInsensitive) && (character < 0x0510)) ? true : false); + bool filterNonBase = (((flags & kCFCompareDiacriticsInsensitiveCompatibilityMask) && (character < 0x0510)) ? true : false); static const uint8_t *lowerBMP = NULL; static const uint8_t *caseFoldBMP = NULL; @@ -2017,10 +2205,10 @@ static inline CFIndex __CFStringFoldCharacterClusterAtIndex(UTF32Char character, caseFoldBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharHasNonSelfCaseFoldingCharacterSet, 0); } - if ((NULL != langCode) && ('I' == character) && ((0 == strcmp(langCode, "tr")) || (0 == strcmp(langCode, "az")))) { // do Turkik special-casing + if ((NULL != langCode) && ('I' == character) && ((0 == strcmp((const char *)langCode, "tr")) || (0 == strcmp((const char *)langCode, "az")))) { // do Turkik special-casing if (filledLength > 1) { if (0x0307 == outCharacters[1]) { - memmove(&(outCharacters[index]), &(outCharacters[index + 1]), sizeof(UTF32Char) * (--filledLength)); + if (--filledLength > 1) memmove((outCharacters + 1), (outCharacters + 2), sizeof(UTF32Char) * (filledLength - 1)); character = *outCharacters = 'i'; isTurkikCapitalI = true; } @@ -2058,9 +2246,9 @@ static inline CFIndex __CFStringFoldCharacterClusterAtIndex(UTF32Char character, character = *(bufferP++); if (CFUniCharIsSurrogateHighCharacter(character) && (bufferP < bufferLimit) && CFUniCharIsSurrogateLowCharacter(*bufferP)) { character = CFUniCharGetLongCharacterForSurrogatePair(character, *(bufferP++)); - nonBaseBitmap = CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, (character >> 16)); + nonBaseBitmap = CFUniCharGetBitmapPtrForPlane(kCFUniCharGraphemeExtendCharacterSet, (character >> 16)); } else { - nonBaseBitmap = nonBaseBMP; + nonBaseBitmap = graphemeBMP; } if (!filterNonBase || !CFUniCharIsMemberOfBitmap(character, nonBaseBitmap)) { @@ -2073,36 +2261,40 @@ static inline CFIndex __CFStringFoldCharacterClusterAtIndex(UTF32Char character, } // collect following combining marks - if (flags & (kCFCompareDiacriticsInsensitive|kCFCompareNonliteral)) { + if (flags & (kCFCompareDiacriticsInsensitiveCompatibilityMask|kCFCompareNonliteral)) { const uint8_t *nonBaseBitmap; const uint8_t *decompBitmap; - bool doFill = (((flags & kCFCompareDiacriticsInsensitive) && (character < 0x0510)) ? false : true); - - if (doFill && (0 == filledLength)) { // check if really needs to fill - UTF32Char nonBaseCharacter = CFStringGetCharacterFromInlineBuffer(buffer, currentIndex); - - if (CFUniCharIsSurrogateHighCharacter(nonBaseCharacter) && CFUniCharIsSurrogateLowCharacter((lowSurrogate = CFStringGetCharacterFromInlineBuffer(buffer, currentIndex + 1)))) { - nonBaseCharacter = CFUniCharGetLongCharacterForSurrogatePair(nonBaseCharacter, lowSurrogate); - nonBaseBitmap = CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, (nonBaseCharacter >> 16)); - decompBitmap = CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet, (nonBaseCharacter >> 16)); - } else { - nonBaseBitmap = nonBaseBMP; - decompBitmap = decompBMP; - } + bool doFill = (((flags & kCFCompareDiacriticsInsensitiveCompatibilityMask) && (character < 0x0510)) ? false : true); + + if (0 == filledLength) { + *outCharacters = character; // filledLength will be updated below on demand - if (CFUniCharIsMemberOfBitmap(nonBaseCharacter, nonBaseBitmap)) { - outCharacters[filledLength++] = character; + if (doFill) { // check if really needs to fill + UTF32Char nonBaseCharacter = CFStringGetCharacterFromInlineBuffer(buffer, currentIndex); - if ((0 == (flags & kCFCompareDiacriticsInsensitive)) || (nonBaseCharacter > 0x050F)) { - if (CFUniCharIsMemberOfBitmap(nonBaseCharacter, decompBitmap)) { - filledLength += CFUniCharDecomposeCharacter(nonBaseCharacter, &(outCharacters[filledLength]), maxBufferLength - filledLength); - } else { - outCharacters[filledLength++] = nonBaseCharacter; + if (CFUniCharIsSurrogateHighCharacter(nonBaseCharacter) && CFUniCharIsSurrogateLowCharacter((lowSurrogate = CFStringGetCharacterFromInlineBuffer(buffer, currentIndex + 1)))) { + nonBaseCharacter = CFUniCharGetLongCharacterForSurrogatePair(nonBaseCharacter, lowSurrogate); + nonBaseBitmap = CFUniCharGetBitmapPtrForPlane(kCFUniCharGraphemeExtendCharacterSet, (nonBaseCharacter >> 16)); + decompBitmap = CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet, (nonBaseCharacter >> 16)); + } else { + nonBaseBitmap = graphemeBMP; + decompBitmap = decompBMP; + } + + if (CFUniCharIsMemberOfBitmap(nonBaseCharacter, nonBaseBitmap)) { + filledLength = 1; // For the base character + + if ((0 == (flags & kCFCompareDiacriticsInsensitiveCompatibilityMask)) || (nonBaseCharacter > 0x050F)) { + if (CFUniCharIsMemberOfBitmap(nonBaseCharacter, decompBitmap)) { + filledLength += CFUniCharDecomposeCharacter(nonBaseCharacter, &(outCharacters[filledLength]), maxBufferLength - filledLength); + } else { + outCharacters[filledLength++] = nonBaseCharacter; + } } + currentIndex += ((nonBaseBitmap == graphemeBMP) ? 1 : 2); + } else { + doFill = false; } - currentIndex += ((nonBaseBitmap == nonBaseBMP) ? 1 : 2); - } else { - doFill = false; } } @@ -2111,16 +2303,16 @@ static inline CFIndex __CFStringFoldCharacterClusterAtIndex(UTF32Char character, if (CFUniCharIsSurrogateHighCharacter(character) && CFUniCharIsSurrogateLowCharacter((lowSurrogate = CFStringGetCharacterFromInlineBuffer(buffer, currentIndex + 1)))) { character = CFUniCharGetLongCharacterForSurrogatePair(character, lowSurrogate); - nonBaseBitmap = CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, (character >> 16)); + nonBaseBitmap = CFUniCharGetBitmapPtrForPlane(kCFUniCharGraphemeExtendCharacterSet, (character >> 16)); decompBitmap = CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet, (character >> 16)); } else { - nonBaseBitmap = nonBaseBMP; + nonBaseBitmap = graphemeBMP; decompBitmap = decompBMP; } if (isTurkikCapitalI) { isTurkikCapitalI = false; } else if (CFUniCharIsMemberOfBitmap(character, nonBaseBitmap)) { - if (doFill && ((0 == (flags & kCFCompareDiacriticsInsensitive)) || (character > 0x050F))) { + if (doFill) { if (CFUniCharIsMemberOfBitmap(character, decompBitmap)) { CFIndex currentLength = CFUniCharDecomposeCharacter(character, &(outCharacters[filledLength]), maxBufferLength - filledLength); @@ -2130,14 +2322,23 @@ static inline CFIndex __CFStringFoldCharacterClusterAtIndex(UTF32Char character, } else { outCharacters[filledLength++] = character; } + } else if (0 == filledLength) { + filledLength = 1; // For the base character } - currentIndex += ((nonBaseBitmap == nonBaseBMP) ? 1 : 2); + currentIndex += ((nonBaseBitmap == graphemeBMP) ? 1 : 2); } else { break; } } - - if (filledLength > 1) CFUniCharPrioritySort(outCharacters, filledLength); // priority sort + + if (filledLength > 1) { + UTF32Char *sortCharactersLimit = outCharacters + filledLength; + UTF32Char *sortCharacters = sortCharactersLimit - 1; + + while ((outCharacters < sortCharacters) && CFUniCharIsMemberOfBitmap(*sortCharacters, ((*sortCharacters < 0x10000) ? graphemeBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharGraphemeExtendCharacterSet, (*sortCharacters >> 16))))) --sortCharacters; + + if ((sortCharactersLimit - sortCharacters) > 1) CFUniCharPrioritySort(sortCharacters, (sortCharactersLimit - sortCharacters)); // priority sort + } } } @@ -2146,213 +2347,313 @@ static inline CFIndex __CFStringFoldCharacterClusterAtIndex(UTF32Char character, return filledLength; } -/* Special casing for Uk sorting */ -#define DO_IGNORE_PUNCTUATION 1 -#if DO_IGNORE_PUNCTUATION -#define UKRAINIAN_LANG_CODE (45) -static bool __CFLocaleChecked = false; -static const uint8_t *__CFPunctSetBMP = NULL; -#endif /* DO_IGNORE_PUNCTUATION */ +#define kCFStringStackBufferLength (64) -/* ??? We need to implement some additional flags here - ??? Also, pay attention to flag 2, which is the NS flag (which CF has as flag 16, w/opposite meaning). -*/ -CFComparisonResult CFStringCompareWithOptions(CFStringRef string, CFStringRef string2, CFRange rangeToCompare, CFOptionFlags compareOptions) { -/* No objc dispatch needed here since CFStringInlineBuffer works with both CFString and NSString */ - CFStringInlineBuffer strBuf1, strBuf2; - UTF32Char ch1, ch2; - const uint8_t *punctBMP = NULL; - Boolean caseInsensitive = (compareOptions & kCFCompareCaseInsensitive ? true : false); - Boolean decompose = (compareOptions & kCFCompareNonliteral ? true : false); - Boolean numerically = (compareOptions & kCFCompareNumerically ? true : false); - Boolean localized = (compareOptions & kCFCompareLocalized ? true : false); - -#if DO_IGNORE_PUNCTUATION - if (localized) { - if (!__CFLocaleChecked) { - CFArrayRef locales = _CFBundleCopyUserLanguages(false); - - if (locales && (CFArrayGetCount(locales) > 0)) { - SInt32 langCode; - - if (CFBundleGetLocalizationInfoForLocalization((CFStringRef)CFArrayGetValueAtIndex(locales, 0), &langCode, NULL, NULL, NULL) && (langCode == UKRAINIAN_LANG_CODE)) { - __CFPunctSetBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharPunctuationCharacterSet, 0); +CFComparisonResult CFStringCompareWithOptionsAndLocale(CFStringRef string, CFStringRef string2, CFRange rangeToCompare, CFOptionFlags compareOptions, CFLocaleRef locale) { + /* No objc dispatch needed here since CFStringInlineBuffer works with both CFString and NSString */ + UTF32Char strBuf1[kCFStringStackBufferLength]; + UTF32Char strBuf2[kCFStringStackBufferLength]; + CFStringInlineBuffer inlineBuf1, inlineBuf2; + UTF32Char str1Char, str2Char; + CFIndex str1UsedLen, str2UsedLen; + CFIndex str1Index = 0, str2Index = 0, strBuf1Index = 0, strBuf2Index = 0, strBuf1Len = 0, strBuf2Len = 0; + CFIndex str2Len = CFStringGetLength(string2); + bool caseInsensitive = ((compareOptions & kCFCompareCaseInsensitive) ? true : false); + bool diacriticsInsensitive = ((compareOptions & kCFCompareDiacriticsInsensitiveCompatibilityMask) ? true : false); + bool equalityOptions = ((compareOptions & (kCFCompareCaseInsensitive|kCFCompareNonliteral|kCFCompareDiacriticsInsensitiveCompatibilityMask|kCFCompareWidthInsensitive)) ? true : false); + bool numerically = ((compareOptions & kCFCompareNumerically) ? true : false); + const uint8_t *graphemeBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharGraphemeExtendCharacterSet, 0); + const uint8_t *langCode; + CFComparisonResult compareResult = kCFCompareEqualTo; + UTF16Char otherChar; + Boolean freeLocale = false; + + #define _CFCompareStringsWithLocale(A, B, C, D, E, F) (0) + locale = NULL; + + if ((compareOptions & kCFCompareLocalized) && (NULL == locale)) { + locale = CFLocaleCopyCurrent(); + freeLocale = true; + } + + langCode = ((NULL == locale) ? NULL : (const uint8_t *)_CFStrGetLanguageIdentifierForLocale(locale)); + + if ((NULL == locale) && !numerically) { // could do binary comp (be careful when adding new flags) + CFStringEncoding eightBitEncoding = __CFStringGetEightBitStringEncoding(); + const uint8_t *str1Bytes = (const uint8_t *)CFStringGetCStringPtr(string, eightBitEncoding); + const uint8_t *str2Bytes = (const uint8_t *)CFStringGetCStringPtr(string2, eightBitEncoding); + CFIndex factor = sizeof(uint8_t); + + if ((NULL != str1Bytes) && (NULL != str2Bytes)) { + compareOptions &= ~kCFCompareNonliteral; // remove non-literal + + if (kCFStringEncodingASCII == eightBitEncoding) { + if (caseInsensitive) { + int cmpResult = strncasecmp_l((const char *)str1Bytes + rangeToCompare.location, (const char *)str2Bytes, __CFMin(rangeToCompare.length, str2Len), NULL); + + if (0 == cmpResult) cmpResult = rangeToCompare.length - str2Len; + + return ((0 == cmpResult) ? kCFCompareEqualTo : ((cmpResult < 0) ? kCFCompareLessThan : kCFCompareGreaterThan)); } + } else if (caseInsensitive || diacriticsInsensitive) { + CFIndex limitLength = __CFMin(rangeToCompare.length, str2Len); + + str1Bytes += rangeToCompare.location; + + while (str1Index < limitLength) { + str1Char = str1Bytes[str1Index]; + str2Char = str2Bytes[str1Index]; - CFRelease(locales); + if (str1Char != str2Char) { + if ((str1Char < 0x80) && (str2Char < 0x80)) { + 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 { + str1Bytes = NULL; + break; + } + } + ++str1Index; + } + + str2Index = str1Index; + + if (str1Index == limitLength) { + int cmpResult = rangeToCompare.length - str2Len; + + return ((0 == cmpResult) ? kCFCompareEqualTo : ((cmpResult < 0) ? kCFCompareLessThan : kCFCompareGreaterThan)); + } } - __CFLocaleChecked = true; + } else if (!equalityOptions && (NULL == str1Bytes) && (NULL == str2Bytes)) { + str1Bytes = (const uint8_t *)CFStringGetCharactersPtr(string); + str2Bytes = (const uint8_t *)CFStringGetCharactersPtr(string2); + factor = sizeof(UTF16Char); +#if __LITTLE_ENDIAN__ + if ((NULL != str1Bytes) && (NULL != str2Bytes)) { // we cannot use memcmp + const UTF16Char *str1 = ((const UTF16Char *)str1Bytes) + rangeToCompare.location; + const UTF16Char *str1Limit = str1 + __CFMin(rangeToCompare.length, str2Len); + const UTF16Char *str2 = (const UTF16Char *)str2Bytes; + CFIndex cmpResult = 0; + + while ((0 == cmpResult) && (str1 < str1Limit)) cmpResult = (CFIndex)*(str1++) - (CFIndex)*(str2++); + + if (0 == cmpResult) cmpResult = rangeToCompare.length - str2Len; + + return ((0 == cmpResult) ? kCFCompareEqualTo : ((cmpResult < 0) ? kCFCompareLessThan : kCFCompareGreaterThan)); + } +#endif /* __LITTLE_ENDIAN__ */ + } + if ((NULL != str1Bytes) && (NULL != str2Bytes)) { + int cmpResult = memcmp(str1Bytes + (rangeToCompare.location * factor), str2Bytes, __CFMin(rangeToCompare.length, str2Len) * factor); + + if (0 == cmpResult) cmpResult = rangeToCompare.length - str2Len; + + return ((0 == cmpResult) ? kCFCompareEqualTo : ((cmpResult < 0) ? kCFCompareLessThan : kCFCompareGreaterThan)); } - - punctBMP = __CFPunctSetBMP; } -#endif /* DO_IGNORE_PUNCTUATION */ - CFStringInitInlineBuffer(string, &strBuf1, CFRangeMake(rangeToCompare.location, rangeToCompare.length)); - CFIndex strBuf1_idx = 0; - CFIndex string2_len = CFStringGetLength(string2); - CFStringInitInlineBuffer(string2, &strBuf2, CFRangeMake(0, string2_len)); - CFIndex strBuf2_idx = 0; + CFStringInitInlineBuffer(string, &inlineBuf1, rangeToCompare); + CFStringInitInlineBuffer(string2, &inlineBuf2, CFRangeMake(0, str2Len)); - while (strBuf1_idx < rangeToCompare.length && strBuf2_idx < string2_len) { - ch1 = CFStringGetCharacterFromInlineBuffer(&strBuf1, strBuf1_idx); - ch2 = CFStringGetCharacterFromInlineBuffer(&strBuf2, strBuf2_idx); + while ((str1Index < rangeToCompare.length) && (str2Index < str2Len)) { + if (strBuf1Len == 0) { + str1Char = CFStringGetCharacterFromInlineBuffer(&inlineBuf1, str1Index); + if (caseInsensitive && (str1Char >= 'A') && (str1Char <= 'Z') && ((NULL == langCode) || (str1Char != 'I'))) str1Char += ('a' - 'A'); + str1UsedLen = 1; + } else { + str1Char = strBuf1[strBuf1Index++]; + } + if (strBuf2Len == 0) { + str2Char = CFStringGetCharacterFromInlineBuffer(&inlineBuf2, str2Index); + if (caseInsensitive && (str2Char >= 'A') && (str2Char <= 'Z') && ((NULL == langCode) || (str2Char != 'I'))) str2Char += ('a' - 'A'); + str2UsedLen = 1; + } else { + str2Char = strBuf2[strBuf2Index++]; + } + + 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 (numerically && (ch1 <= '9' && ch1 >= '0') && (ch2 <= '9' && ch2 >= '0')) { // If both are not digits, then don't do numerical comparison - uint64_t n1 = 0; // !!! Doesn't work if numbers are > max uint64_t - uint64_t n2 = 0; do { - n1 = n1 * 10 + (ch1 - '0'); - strBuf1_idx++; - if (rangeToCompare.length <= strBuf1_idx) break; - ch1 = CFStringGetCharacterFromInlineBuffer(&strBuf1, strBuf1_idx); - } while (ch1 <= '9' && ch1 >= '0'); + intValue1 = (intValue1 * 10) + (str1Char - '0'); + str1Char = CFStringGetCharacterFromInlineBuffer(&inlineBuf1, ++str1Index); + } while ((str1Char <= '9') && (str1Char >= '0')); + do { - n2 = n2 * 10 + (ch2 - '0'); - strBuf2_idx++; - if (string2_len <= strBuf2_idx) break; - ch2 = CFStringGetCharacterFromInlineBuffer(&strBuf2, strBuf2_idx); - } while (ch2 <= '9' && ch2 >= '0'); - if (n1 < n2) return kCFCompareLessThan; else if (n1 > n2) return kCFCompareGreaterThan; - continue; // If numbers were equal, go back to top without incrementing the buffer pointers - } - - if (CFUniCharIsSurrogateHighCharacter(ch1)) { - strBuf1_idx++; - if (strBuf1_idx < rangeToCompare.length && CFUniCharIsSurrogateLowCharacter(CFStringGetCharacterFromInlineBuffer(&strBuf1, strBuf1_idx))) { - ch1 = CFUniCharGetLongCharacterForSurrogatePair(ch1, CFStringGetCharacterFromInlineBuffer(&strBuf1, strBuf1_idx)); + intValue2 = intValue2 * 10 + (str2Char - '0'); + str2Char = CFStringGetCharacterFromInlineBuffer(&inlineBuf2, ++str2Index); + } while ((str2Char <= '9') && (str2Char >= '0')); + + if (intValue1 == intValue2) { + continue; + } else if (intValue1 < intValue2) { + if (freeLocale && locale) { + CFRelease(locale); + } + return kCFCompareLessThan; } else { - strBuf1_idx--; + if (freeLocale && locale) { + CFRelease(locale); + } + return kCFCompareGreaterThan; } } - if (CFUniCharIsSurrogateHighCharacter(ch2)) { - strBuf2_idx++; - if (strBuf2_idx < string2_len && CFUniCharIsSurrogateLowCharacter(CFStringGetCharacterFromInlineBuffer(&strBuf2, strBuf2_idx))) { - ch2 = CFUniCharGetLongCharacterForSurrogatePair(ch2, CFStringGetCharacterFromInlineBuffer(&strBuf2, strBuf2_idx)); - } else { - strBuf2_idx--; + + if (str1Char != str2Char) { + if (!equalityOptions) { + CFComparisonResult res = ((NULL == locale) ? ((str1Char < str2Char) ? kCFCompareLessThan : kCFCompareGreaterThan) : _CFCompareStringsWithLocale(&inlineBuf1, CFRangeMake(strBuf1Index, rangeToCompare.length - strBuf1Index), &inlineBuf2, CFRangeMake(strBuf2Index, str2Len - strBuf2Index), compareOptions, locale)); + if (freeLocale && locale) { + CFRelease(locale); + } + return res; + } + + if ((compareOptions & kCFCompareForcedOrdering) && (kCFCompareEqualTo == compareResult)) compareResult = ((str1Char < str2Char) ? kCFCompareLessThan : kCFCompareGreaterThan); + + if ((str1Char < 0x80) && (str2Char < 0x80)) { + if (NULL != locale) { + CFComparisonResult res = _CFCompareStringsWithLocale(&inlineBuf1, CFRangeMake(strBuf1Index, rangeToCompare.length - strBuf1Index), &inlineBuf2, CFRangeMake(strBuf2Index, str2Len - strBuf2Index), compareOptions, locale); + if (freeLocale && locale) { + CFRelease(locale); + } + return res; + } else if (!caseInsensitive) { + if (freeLocale && locale) { + CFRelease(locale); + } + return ((str1Char < str2Char) ? kCFCompareLessThan : kCFCompareGreaterThan); + } } - } - if (ch1 != ch2) { -#if DO_IGNORE_PUNCTUATION - if (punctBMP) { - if (CFUniCharIsMemberOfBitmap(ch1, (ch1 < 0x10000 ? punctBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharPunctuationCharacterSet, (ch1 >> 16))))) { - ++strBuf1_idx; continue; + if (CFUniCharIsSurrogateHighCharacter(str1Char) && CFUniCharIsSurrogateLowCharacter((otherChar = CFStringGetCharacterFromInlineBuffer(&inlineBuf1, str1Index + 1)))) { + str1Char = CFUniCharGetLongCharacterForSurrogatePair(str1Char, otherChar); + str1UsedLen = 2; + } + + if (CFUniCharIsSurrogateHighCharacter(str2Char) && CFUniCharIsSurrogateLowCharacter((otherChar = CFStringGetCharacterFromInlineBuffer(&inlineBuf2, str2Index + 1)))) { + str2Char = CFUniCharGetLongCharacterForSurrogatePair(str2Char, otherChar); + str2UsedLen = 2; + } + + if (diacriticsInsensitive && (str1Index > 0)) { + bool str1Skip = false; + bool str2Skip = false; + + if ((0 == strBuf1Len) && CFUniCharIsMemberOfBitmap(str1Char, ((str1Char < 0x10000) ? graphemeBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharGraphemeExtendCharacterSet, (str1Char >> 16))))) { + str1Char = str2Char; + str1Skip = true; } - if (CFUniCharIsMemberOfBitmap(ch2, (ch2 < 0x10000 ? punctBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharPunctuationCharacterSet, (ch2 >> 16))))) { - ++strBuf2_idx; continue; + if ((0 == strBuf2Len) && CFUniCharIsMemberOfBitmap(str2Char, ((str2Char < 0x10000) ? graphemeBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharGraphemeExtendCharacterSet, (str2Char >> 16))))) { + str2Char = str1Char; + str2Skip = true; + } + + if (str1Skip != str2Skip) { + if (str1Skip) str2Index -= str2UsedLen; + if (str2Skip) str1Index -= str1UsedLen; } } -#endif /* DO_IGNORE_PUNCTUATION */ - // We standardize to lowercase here since currently, as of Unicode 3.1.1, it's one-to-one mapping. - // Note we map to uppercase for both SMALL LETTER SIGMA and SMALL LETTER FINAL SIGMA - if (caseInsensitive) { - if (ch1 < 128) { - ch1 -= ((ch1 >= 'A' && ch1 <= 'Z') ? 'A' - 'a' : 0); - } else if (ch1 == 0x03C2 || ch1 == 0x03C3 || ch1 == 0x03A3) { // SMALL SIGMA - ch1 = 0x03A3; - } else { - UniChar buffer[MAX_CASE_MAPPING_BUF]; - - if (CFUniCharMapCaseTo(ch1, buffer, MAX_CASE_MAPPING_BUF, kCFUniCharToLowercase, 0, NULL) > 1) { // It's supposed to be surrogates - ch1 = CFUniCharGetLongCharacterForSurrogatePair(buffer[0], buffer[1]); - } else { - ch1 = *buffer; + + if (str1Char != str2Char) { + if (0 == strBuf1Len) { + strBuf1Len = __CFStringFoldCharacterClusterAtIndex(str1Char, &inlineBuf1, str1Index, compareOptions, langCode, strBuf1, kCFStringStackBufferLength, &str1UsedLen); + if (strBuf1Len > 0) { + str1Char = *strBuf1; + strBuf1Index = 1; } } - if (ch2 < 128) { - ch2 -= ((ch2 >= 'A' && ch2 <= 'Z') ? 'A' - 'a' : 0); - } else if (ch2 == 0x03C2 || ch2 == 0x03C3 || ch2 == 0x03A3) { // SMALL SIGMA - ch2 = 0x03A3; - } else { - UniChar buffer[MAX_CASE_MAPPING_BUF]; - - if (CFUniCharMapCaseTo(ch2, buffer, MAX_CASE_MAPPING_BUF, kCFUniCharToLowercase, 0, NULL) > 1) { // It's supposed to be surrogates - ch2 = CFUniCharGetLongCharacterForSurrogatePair(buffer[0], buffer[1]); - } else { - ch2 = *buffer; + + if ((0 == strBuf1Len) && (0 < strBuf2Len)) { + CFComparisonResult res = ((NULL == locale) ? ((str1Char < str2Char) ? kCFCompareLessThan : kCFCompareGreaterThan) : _CFCompareStringsWithLocale(&inlineBuf1, CFRangeMake(strBuf1Index, rangeToCompare.length - strBuf1Index), &inlineBuf2, CFRangeMake(strBuf2Index, str2Len - strBuf2Index), compareOptions, locale)); + if (freeLocale && locale) { + CFRelease(locale); + } + return res; + } + + if ((0 == strBuf2Len) && ((0 == strBuf1Len) || (str1Char != str2Char))) { + strBuf2Len = __CFStringFoldCharacterClusterAtIndex(str2Char, &inlineBuf2, str2Index, compareOptions, langCode, strBuf2, kCFStringStackBufferLength, &str2UsedLen); + if (strBuf2Len > 0) { + str2Char = *strBuf2; + strBuf2Index = 1; } + if ((0 == strBuf2Len) || (str1Char != str2Char)) { + CFComparisonResult res = ((NULL == locale) ? ((str1Char < str2Char) ? kCFCompareLessThan : kCFCompareGreaterThan) : _CFCompareStringsWithLocale(&inlineBuf1, CFRangeMake(strBuf1Index, rangeToCompare.length - strBuf1Index), &inlineBuf2, CFRangeMake(strBuf2Index, str2Len - strBuf2Index), compareOptions, locale)); + if (freeLocale && locale) { + CFRelease(locale); + } + return res; + } } } - - if (ch1 != ch2) { // still different - if (decompose) { // ??? This is not exactly the canonical comparison (We need to do priority sort) - Boolean isCh1Decomposable = (ch1 > 0x7F && CFUniCharIsMemberOf(ch1, kCFUniCharDecomposableCharacterSet)); - Boolean isCh2Decomposable = (ch2 > 0x7F && CFUniCharIsMemberOf(ch2, kCFUniCharDecomposableCharacterSet)); - - if (isCh1Decomposable != isCh2Decomposable) { - UTF32Char decomposedCharater[MAX_DECOMPOSED_LENGTH]; - UInt32 decomposedCharacterLength; - UInt32 idx; - - if (isCh1Decomposable) { - decomposedCharacterLength = CFUniCharDecomposeCharacter(ch1, decomposedCharater, MAX_DECOMPOSED_LENGTH); - if ((string2_len - strBuf2_idx) < decomposedCharacterLength) { // the remaining other length is shorter - if (ch1 < ch2) return kCFCompareLessThan; else if (ch1 > ch2) return kCFCompareGreaterThan; - } - for (idx = 0; idx < decomposedCharacterLength; idx++) { - ch1 = decomposedCharater[idx]; - if (ch1 < ch2) return kCFCompareLessThan; else if (ch1 > ch2) return kCFCompareGreaterThan; - strBuf2_idx++; ch2 = (strBuf2_idx < string2_len ? CFStringGetCharacterFromInlineBuffer(&strBuf2, strBuf2_idx) : 0xffff); - if (CFUniCharIsSurrogateHighCharacter(ch2)) { - strBuf2_idx++; - if (strBuf2_idx < string2_len && CFUniCharIsSurrogateLowCharacter(CFStringGetCharacterFromInlineBuffer(&strBuf2, strBuf2_idx))) { - ch2 = CFUniCharGetLongCharacterForSurrogatePair(ch2, CFStringGetCharacterFromInlineBuffer(&strBuf2, strBuf2_idx)); - } else { - strBuf2_idx--; - } - } - } - strBuf1_idx++; continue; - } else { // ch2 is decomposable, then - decomposedCharacterLength = CFUniCharDecomposeCharacter(ch2, decomposedCharater, MAX_DECOMPOSED_LENGTH); - if ((rangeToCompare.length - strBuf1_idx) < decomposedCharacterLength) { // the remaining other length is shorter - if (ch1 < ch2) return kCFCompareLessThan; else if (ch1 > ch2) return kCFCompareGreaterThan; - } - for (idx = 0; idx < decomposedCharacterLength && strBuf1_idx < rangeToCompare.length; idx++) { - ch2 = decomposedCharater[idx]; - if (ch1 < ch2) return kCFCompareLessThan; else if (ch1 > ch2) return kCFCompareGreaterThan; - strBuf1_idx++; ch1 = (strBuf1_idx < rangeToCompare.length ? CFStringGetCharacterFromInlineBuffer(&strBuf1, strBuf1_idx) : 0xffff); - if (CFUniCharIsSurrogateHighCharacter(ch1)) { - strBuf1_idx++; - if (strBuf1_idx < rangeToCompare.length && CFUniCharIsSurrogateLowCharacter(CFStringGetCharacterFromInlineBuffer(&strBuf1, strBuf1_idx))) { - ch1 = CFUniCharGetLongCharacterForSurrogatePair(ch1, CFStringGetCharacterFromInlineBuffer(&strBuf1, strBuf1_idx)); - } else { - strBuf1_idx--; - } - } - } - strBuf2_idx++; continue; - } - } + + if ((strBuf1Len > 0) && (strBuf2Len > 0)) { + while ((strBuf1Index < strBuf1Len) && (strBuf2Index < strBuf2Len)) { + if (strBuf1[strBuf1Index] != strBuf2[strBuf2Index]) break; + ++strBuf1Index; ++strBuf2Index; } - if (ch1 < ch2) return kCFCompareLessThan; else if (ch1 > ch2) return kCFCompareGreaterThan; + if ((strBuf1Index < strBuf1Len) && (strBuf2Index < strBuf2Len)) { + CFComparisonResult res = ((NULL == locale) ? ((str1Char < str2Char) ? kCFCompareLessThan : kCFCompareGreaterThan) : _CFCompareStringsWithLocale(&inlineBuf1, CFRangeMake(strBuf1Index, rangeToCompare.length - strBuf1Index), &inlineBuf2, CFRangeMake(strBuf2Index, str2Len - strBuf2Index), compareOptions, locale)); + if (freeLocale && locale) { + CFRelease(locale); + } + return res; + } } } - strBuf1_idx++; strBuf2_idx++; + + if ((strBuf1Len > 0) && (strBuf1Index == strBuf1Len)) strBuf1Len = 0; + if ((strBuf2Len > 0) && (strBuf2Index == strBuf2Len)) strBuf2Len = 0; + + if (strBuf1Len == 0) str1Index += str1UsedLen; + if (strBuf2Len == 0) str2Index += str2UsedLen; } - if (strBuf1_idx < rangeToCompare.length) { - return kCFCompareGreaterThan; - } else if (strBuf2_idx < string2_len) { - return kCFCompareLessThan; - } else { - return kCFCompareEqualTo; + + if (diacriticsInsensitive) { + while (str1Index < rangeToCompare.length) { + str1Char = CFStringGetCharacterFromInlineBuffer(&inlineBuf1, str1Index); + if (str1Char < 0x80) break; // found ASCII + + if (CFUniCharIsSurrogateHighCharacter(str1Char) && CFUniCharIsSurrogateLowCharacter((otherChar = CFStringGetCharacterFromInlineBuffer(&inlineBuf1, str1Index + 1)))) str1Char = CFUniCharGetLongCharacterForSurrogatePair(str1Char, otherChar); + + if (!CFUniCharIsMemberOfBitmap(str1Char, ((str1Char < 0x10000) ? graphemeBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharGraphemeExtendCharacterSet, (str1Char >> 16))))) break; + + str1Index += ((str1Char < 0x10000) ? 1 : 2); + } + + while (str2Index < str2Len) { + str2Char = CFStringGetCharacterFromInlineBuffer(&inlineBuf2, str2Index); + if (str2Char < 0x80) break; // found ASCII + + if (CFUniCharIsSurrogateHighCharacter(str2Char) && CFUniCharIsSurrogateLowCharacter((otherChar = CFStringGetCharacterFromInlineBuffer(&inlineBuf2, str2Index + 1)))) str2Char = CFUniCharGetLongCharacterForSurrogatePair(str2Char, otherChar); + + if (!CFUniCharIsMemberOfBitmap(str2Char, ((str2Char < 0x10000) ? graphemeBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharGraphemeExtendCharacterSet, (str2Char >> 16))))) break; + + str2Index += ((str2Char < 0x10000) ? 1 : 2); + } + } + + if (freeLocale && locale) { + CFRelease(locale); } + + return ((str1Index < rangeToCompare.length) ? kCFCompareGreaterThan : ((str2Index < str2Len) ? kCFCompareLessThan : compareResult)); } +CFComparisonResult CFStringCompareWithOptions(CFStringRef string, CFStringRef string2, CFRange rangeToCompare, CFOptionFlags compareOptions) { return CFStringCompareWithOptionsAndLocale(string, string2, rangeToCompare, compareOptions, NULL); } + CFComparisonResult CFStringCompare(CFStringRef string, CFStringRef str2, CFOptionFlags options) { return CFStringCompareWithOptions(string, str2, CFRangeMake(0, CFStringGetLength(string)), options); } -#define kCFStringStackBufferLength (64) - -Boolean CFStringFindWithOptions(CFStringRef string, CFStringRef stringToFind, CFRange rangeToSearch, CFOptionFlags compareOptions, CFRange *result) { +Boolean CFStringFindWithOptionsAndLocale(CFStringRef string, CFStringRef stringToFind, CFRange rangeToSearch, CFOptionFlags compareOptions, CFLocaleRef locale, CFRange *result) { /* No objc dispatch needed here since CFStringInlineBuffer works with both CFString and NSString */ CFIndex findStrLen = CFStringGetLength(stringToFind); Boolean didFind = false; - bool lengthVariants = ((compareOptions & (kCFCompareCaseInsensitive|kCFCompareNonliteral|kCFCompareDiacriticsInsensitive)) ? true : false); + bool lengthVariants = ((compareOptions & (kCFCompareCaseInsensitive|kCFCompareNonliteral|kCFCompareDiacriticsInsensitiveCompatibilityMask)) ? true : false); if ((findStrLen > 0) && (rangeToSearch.length > 0) && ((findStrLen <= rangeToSearch.length) || lengthVariants)) { UTF32Char strBuf1[kCFStringStackBufferLength]; @@ -2360,8 +2661,8 @@ Boolean CFStringFindWithOptions(CFStringRef string, CFStringRef stringToFind, CF CFStringInlineBuffer inlineBuf1, inlineBuf2; UTF32Char str1Char, str2Char; CFStringEncoding eightBitEncoding = __CFStringGetEightBitStringEncoding(); - const uint8_t *str1Bytes = CFStringGetCStringPtr(string, eightBitEncoding); - const uint8_t *str2Bytes = CFStringGetCStringPtr(stringToFind, eightBitEncoding); + const uint8_t *str1Bytes = (const uint8_t *)CFStringGetCStringPtr(string, eightBitEncoding); + const uint8_t *str2Bytes = (const uint8_t *)CFStringGetCStringPtr(stringToFind, eightBitEncoding); const UTF32Char *characters, *charactersLimit; const uint8_t *langCode = NULL; CFIndex fromLoc, toLoc; @@ -2371,6 +2672,15 @@ Boolean CFStringFindWithOptions(CFStringRef string, CFStringRef stringToFind, CF bool caseInsensitive = ((compareOptions & kCFCompareCaseInsensitive) ? true : false); int8_t delta; + if (NULL == locale) { + if (compareOptions & kCFCompareLocalized) { + CFLocaleRef currentLocale = CFLocaleCopyCurrent(); + langCode = (const uint8_t *)_CFStrGetLanguageIdentifierForLocale(currentLocale); + CFRelease(currentLocale); + } + } else { + langCode = (const uint8_t *)_CFStrGetLanguageIdentifierForLocale(locale); + } CFStringInitInlineBuffer(string, &inlineBuf1, CFRangeMake(0, rangeToSearch.location + rangeToSearch.length)); CFStringInitInlineBuffer(stringToFind, &inlineBuf2, CFRangeMake(0, findStrLen)); @@ -2483,14 +2793,9 @@ Boolean CFStringFindWithOptions(CFStringRef string, CFStringRef stringToFind, CF } else if (equalityOptions) { UTF16Char otherChar; CFIndex str1UsedLen, str2UsedLen, strBuf1Index = 0, strBuf2Index = 0; - bool diacriticsInsensitive = ((compareOptions & kCFCompareDiacriticsInsensitive) ? true : false); - static const uint8_t *nonBaseBMP = NULL; - static const uint8_t *combClassBMP = NULL; - - if (NULL == nonBaseBMP) { - nonBaseBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, 0); - combClassBMP = CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, 0); - } + bool diacriticsInsensitive = ((compareOptions & kCFCompareDiacriticsInsensitiveCompatibilityMask) ? true : false); + const uint8_t *graphemeBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharGraphemeExtendCharacterSet, 0); + const uint8_t *combClassBMP = (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, 0); while (1) { str1Index = fromLoc; @@ -2528,8 +2833,22 @@ Boolean CFStringFindWithOptions(CFStringRef string, CFStringRef stringToFind, CF } if (diacriticsInsensitive && (str1Index > fromLoc)) { - if ((0 == strBuf1Len) && CFUniCharIsMemberOfBitmap(str1Char, ((str1Char < 0x10000) ? nonBaseBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, (str1Char >> 16))))) str1Char = str2Char; - if ((0 == strBuf2Len) && CFUniCharIsMemberOfBitmap(str2Char, ((str2Char < 0x10000) ? nonBaseBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, (str2Char >> 16))))) str2Char = str1Char; + bool str1Skip = false; + bool str2Skip = false; + + if ((0 == strBuf1Len) && CFUniCharIsMemberOfBitmap(str1Char, ((str1Char < 0x10000) ? graphemeBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharGraphemeExtendCharacterSet, (str1Char >> 16))))) { + str1Char = str2Char; + str1Skip = true; + } + if ((0 == strBuf2Len) && CFUniCharIsMemberOfBitmap(str2Char, ((str2Char < 0x10000) ? graphemeBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharGraphemeExtendCharacterSet, (str2Char >> 16))))) { + str2Char = str1Char; + str2Skip = true; + } + + if (str1Skip != str2Skip) { + if (str1Skip) str2Index -= str2UsedLen; + if (str2Skip) str1Index -= str1UsedLen; + } } if (str1Char != str2Char) { @@ -2572,9 +2891,9 @@ Boolean CFStringFindWithOptions(CFStringRef string, CFStringRef stringToFind, CF if (strBuf1Len > 0) { match = false; - if ((compareOptions & kCFCompareDiacriticsInsensitive) && (strBuf1[0] < 0x0510)) { + if ((compareOptions & kCFCompareDiacriticsInsensitiveCompatibilityMask) && (strBuf1[0] < 0x0510)) { while (strBuf1Index < strBuf1Len) { - if (!CFUniCharIsMemberOfBitmap(strBuf1[strBuf1Index], ((strBuf1[strBuf1Index] < 0x10000) ? nonBaseBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet, (strBuf1[strBuf1Index] >> 16))))) break; + if (!CFUniCharIsMemberOfBitmap(strBuf1[strBuf1Index], ((strBuf1[strBuf1Index] < 0x10000) ? graphemeBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet, (strBuf1[strBuf1Index] >> 16))))) break; ++strBuf1Index; } @@ -2585,16 +2904,16 @@ Boolean CFStringFindWithOptions(CFStringRef string, CFStringRef stringToFind, CF } } - if (match && (compareOptions & (kCFCompareDiacriticsInsensitive|kCFCompareNonliteral)) && (str1Index < (rangeToSearch.location + rangeToSearch.length))) { + if (match && (compareOptions & (kCFCompareDiacriticsInsensitiveCompatibilityMask|kCFCompareNonliteral)) && (str1Index < (rangeToSearch.location + rangeToSearch.length))) { const uint8_t *nonBaseBitmap; str1Char = CFStringGetCharacterFromInlineBuffer(&inlineBuf1, str1Index); if (CFUniCharIsSurrogateHighCharacter(str1Char) && CFUniCharIsSurrogateLowCharacter((otherChar = CFStringGetCharacterFromInlineBuffer(&inlineBuf1, str1Index + 1)))) { str1Char = CFUniCharGetLongCharacterForSurrogatePair(str1Char, otherChar); - nonBaseBitmap = CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, (str1Char >> 16)); + nonBaseBitmap = CFUniCharGetBitmapPtrForPlane(kCFUniCharGraphemeExtendCharacterSet, (str1Char >> 16)); } else { - nonBaseBitmap = nonBaseBMP; + nonBaseBitmap = graphemeBMP; } if (CFUniCharIsMemberOfBitmap(str1Char, nonBaseBitmap)) { @@ -2604,12 +2923,12 @@ Boolean CFStringFindWithOptions(CFStringRef string, CFStringRef stringToFind, CF do { str1Char = CFStringGetCharacterFromInlineBuffer(&inlineBuf1, --index); - } while (CFUniCharIsMemberOfBitmap(str1Char, nonBaseBMP), (rangeToSearch.location < index)); + } while (CFUniCharIsMemberOfBitmap(str1Char, graphemeBMP), (rangeToSearch.location < index)); if (str1Char < 0x0510) { CFIndex maxIndex = (rangeToSearch.location + rangeToSearch.length); - while (++str1Index < maxIndex) if (!CFUniCharIsMemberOfBitmap(CFStringGetCharacterFromInlineBuffer(&inlineBuf1, str1Index), nonBaseBMP)) break; + while (++str1Index < maxIndex) if (!CFUniCharIsMemberOfBitmap(CFStringGetCharacterFromInlineBuffer(&inlineBuf1, str1Index), graphemeBMP)) break; } } } else { @@ -2620,7 +2939,7 @@ Boolean CFStringFindWithOptions(CFStringRef string, CFStringRef stringToFind, CF // this is assuming viramas are only in BMP ??? if ((str1Char == COMBINING_GRAPHEME_JOINER) || (otherChar == COMBINING_GRAPHEME_JOINER) || (otherChar == ZERO_WIDTH_JOINER) || ((otherChar >= HANGUL_CHOSEONG_START) && (otherChar <= HANGUL_JONGSEONG_END)) || (CFUniCharGetCombiningPropertyForCharacter(otherChar, combClassBMP) == 9)) { - CFRange clusterRange = CFStringGetRangeOfCharacterClusterAtIndex(string, str1Index - 1, kCFStringGramphemeCluster); + CFRange clusterRange = CFStringGetRangeOfCharacterClusterAtIndex(string, str1Index - 1, kCFStringGraphemeCluster); if (str1Index < (clusterRange.location + clusterRange.length)) match = false; } @@ -2665,6 +2984,8 @@ Boolean CFStringFindWithOptions(CFStringRef string, CFStringRef stringToFind, CF return didFind; } +Boolean CFStringFindWithOptions(CFStringRef string, CFStringRef stringToFind, CFRange rangeToSearch, CFOptionFlags compareOptions, CFRange *result) { return CFStringFindWithOptionsAndLocale(string, stringToFind, rangeToSearch, compareOptions, NULL, result); } + // Functions to deal with special arrays of CFRange, CFDataRef, created by CFStringCreateArrayWithFindResults() static const void *__rangeRetain(CFAllocatorRef allocator, const void *ptr) { @@ -2678,7 +2999,7 @@ static void __rangeRelease(CFAllocatorRef allocator, const void *ptr) { static CFStringRef __rangeCopyDescription(const void *ptr) { CFRange range = *(CFRange *)ptr; - return CFStringCreateWithFormat(NULL /* ??? allocator */, NULL, CFSTR("{%d, %d}"), range.location, range.length); + return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{%d, %d}"), range.location, range.length); } static Boolean __rangeEqual(const void *ptr1, const void *ptr2) { @@ -2690,7 +3011,7 @@ static Boolean __rangeEqual(const void *ptr1, const void *ptr2) { CFArrayRef CFStringCreateArrayWithFindResults(CFAllocatorRef alloc, CFStringRef string, CFStringRef stringToFind, CFRange rangeToSearch, CFOptionFlags compareOptions) { CFRange foundRange; - Boolean backwards = compareOptions & kCFCompareBackwards; + Boolean backwards = ((compareOptions & kCFCompareBackwards) != 0); UInt32 endIndex = rangeToSearch.location + rangeToSearch.length; CFMutableDataRef rangeStorage = NULL; // Basically an array of CFRange, CFDataRef (packed) uint8_t *rangeStorageBytes = NULL; @@ -2781,23 +3102,22 @@ enum { kCFStringHangulStateBreak }; -static CFRange _CFStringInlineBufferGetComposedRange(CFStringInlineBuffer *buffer, CFIndex start, CFStringCharacterClusterType type, const uint8_t *nonBaseBMP) { +static CFRange _CFStringInlineBufferGetComposedRange(CFStringInlineBuffer *buffer, CFIndex start, CFStringCharacterClusterType type, const uint8_t *bmpBitmap, CFIndex csetType) { CFIndex end = start + 1; - const uint8_t *nonBase = nonBaseBMP; + const uint8_t *bitmap = bmpBitmap; UTF32Char character; UTF16Char otherSurrogate; uint8_t step; character = CFStringGetCharacterFromInlineBuffer(buffer, start); - // We don't combine characters in Armenian ~ Limbu range for backward deletion if ((type != kCFStringBackwardDeletionCluster) || (character < 0x0530) || (character > 0x194F)) { // Check if the current is surrogate if (CFUniCharIsSurrogateHighCharacter(character) && CFUniCharIsSurrogateLowCharacter((otherSurrogate = CFStringGetCharacterFromInlineBuffer(buffer, start + 1)))) { ++end; character = CFUniCharGetLongCharacterForSurrogatePair(character, otherSurrogate); - nonBase = CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, (character >> 16)); + bitmap = CFUniCharGetBitmapPtrForPlane(csetType, (character >> 16)); } // Extend backward @@ -2807,14 +3127,14 @@ static CFRange _CFStringInlineBufferGetComposedRange(CFStringInlineBuffer *buffe if (character < 0x10000) { // the first round could be already be non-BMP if (CFUniCharIsSurrogateLowCharacter(character) && CFUniCharIsSurrogateHighCharacter((otherSurrogate = CFStringGetCharacterFromInlineBuffer(buffer, start - 1)))) { character = CFUniCharGetLongCharacterForSurrogatePair(otherSurrogate, character); - nonBase = CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, (character >> 16)); + bitmap = CFUniCharGetBitmapPtrForPlane(csetType, (character >> 16)); --start; } else { - nonBase = nonBaseBMP; + bitmap = bmpBitmap; } } - if (!CFUniCharIsMemberOfBitmap(character, nonBase) && (character != 0xFF9E) && (character != 0xFF9F) && ((character & 0x1FFFF0) != 0xF870)) break; + if (!CFUniCharIsMemberOfBitmap(character, bitmap) && (character != 0xFF9E) && (character != 0xFF9F) && ((character & 0x1FFFF0) != 0xF870)) break; --start; @@ -2912,14 +3232,14 @@ static CFRange _CFStringInlineBufferGetComposedRange(CFStringInlineBuffer *buffe if (CFUniCharIsSurrogateHighCharacter(character) && CFUniCharIsSurrogateLowCharacter((otherSurrogate = CFStringGetCharacterFromInlineBuffer(buffer, end + 1)))) { character = CFUniCharGetLongCharacterForSurrogatePair(character, otherSurrogate); - nonBase = CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, (character >> 16)); + bitmap = CFUniCharGetBitmapPtrForPlane(csetType, (character >> 16)); step = 2; } else { - nonBase = nonBaseBMP; + bitmap = bmpBitmap; step = 1; } - if (!CFUniCharIsMemberOfBitmap(character, nonBase) && (character != 0xFF9E) && (character != 0xFF9F) && ((character & 0x1FFFF0) != 0xF870)) break; + if (!CFUniCharIsMemberOfBitmap(character, bitmap) && (character != 0xFF9E) && (character != 0xFF9F) && ((character & 0x1FFFF0) != 0xF870)) break; end += step; } @@ -2928,19 +3248,20 @@ static CFRange _CFStringInlineBufferGetComposedRange(CFStringInlineBuffer *buffe } CF_INLINE bool _CFStringIsVirama(UTF32Char character, const uint8_t *combClassBMP) { - return ((character == COMBINING_GRAPHEME_JOINER) || (CFUniCharGetCombiningPropertyForCharacter(character, ((character < 0x10000) ? combClassBMP : CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, (character >> 16)))) == 9) ? true : false); + return ((character == COMBINING_GRAPHEME_JOINER) || (CFUniCharGetCombiningPropertyForCharacter(character, (const uint8_t *)((character < 0x10000) ? combClassBMP : CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, (character >> 16)))) == 9) ? true : false); } CFRange CFStringGetRangeOfCharacterClusterAtIndex(CFStringRef string, CFIndex charIndex, CFStringCharacterClusterType type) { CFRange range; CFIndex currentIndex; CFIndex length = CFStringGetLength(string); + CFIndex csetType = ((kCFStringGraphemeCluster == type) ? kCFUniCharGraphemeExtendCharacterSet : kCFUniCharNonBaseCharacterSet); CFStringInlineBuffer stringBuffer; + const uint8_t *bmpBitmap; + const uint8_t *letterBMP; + const uint8_t *combClassBMP; UTF32Char character; UTF16Char otherSurrogate; - static const uint8_t *nonBaseBMP = NULL; - static const uint8_t *letterBMP = NULL; - static const uint8_t *combClassBMP = NULL; if (charIndex >= length) return CFRangeMake(kCFNotFound, 0); @@ -2948,16 +3269,14 @@ CFRange CFStringGetRangeOfCharacterClusterAtIndex(CFStringRef string, CFIndex ch */ if (!CF_IS_OBJC(__kCFStringTypeID, string) && __CFStrIsEightBit(string)) return CFRangeMake(charIndex, 1); - if (NULL == nonBaseBMP) { - nonBaseBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, 0); - letterBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharLetterCharacterSet, 0); - combClassBMP = CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, 0); - } + bmpBitmap = CFUniCharGetBitmapPtrForPlane(csetType, 0); + letterBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharLetterCharacterSet, 0); + combClassBMP = (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, 0); CFStringInitInlineBuffer(string, &stringBuffer, CFRangeMake(0, length)); // Get composed character sequence first - range = _CFStringInlineBufferGetComposedRange(&stringBuffer, charIndex, type, nonBaseBMP); + range = _CFStringInlineBufferGetComposedRange(&stringBuffer, charIndex, type, bmpBitmap, csetType); // Do grapheme joiners if (type < kCFStringCursorMovementCluster) { @@ -2987,7 +3306,7 @@ CFRange CFStringGetRangeOfCharacterClusterAtIndex(CFStringRef string, CFIndex ch break; } - currentIndex = _CFStringInlineBufferGetComposedRange(&stringBuffer, currentIndex, type, nonBaseBMP).location; + currentIndex = _CFStringInlineBufferGetComposedRange(&stringBuffer, currentIndex, type, bmpBitmap, csetType).location; character = CFStringGetCharacterFromInlineBuffer(&stringBuffer, currentIndex); @@ -3008,9 +3327,9 @@ CFRange CFStringGetRangeOfCharacterClusterAtIndex(CFStringRef string, CFIndex ch // Check if followed by grapheme joiners if ((range.length > 1) && ((range.location + range.length) < length)) { otherRange = range; + currentIndex = otherRange.location + otherRange.length; do { - currentIndex = otherRange.location + otherRange.length; character = CFStringGetCharacterFromInlineBuffer(&stringBuffer, currentIndex - 1); // ??? We're assuming viramas only in BMP @@ -3029,7 +3348,8 @@ CFRange CFStringGetRangeOfCharacterClusterAtIndex(CFStringRef string, CFIndex ch // We only conjoin letters if (!CFUniCharIsMemberOfBitmap(character, letter)) break; - otherRange = _CFStringInlineBufferGetComposedRange(&stringBuffer, currentIndex, type, nonBaseBMP); + otherRange = _CFStringInlineBufferGetComposedRange(&stringBuffer, currentIndex, type, bmpBitmap, csetType); + currentIndex = otherRange.location + otherRange.length; } while ((otherRange.location + otherRange.length) < length); range.length = currentIndex - range.location; } @@ -3205,7 +3525,7 @@ CFRange CFStringGetRangeOfComposedCharactersAtIndex(CFStringRef theString, CFInd * The junk between had better contain "save"! */ if ((! (left <= save)) || (! (save <= current))) { - CFLog(0, CFSTR("CFString: CFStringGetRangeOfComposedCharactersAtIndex:%d returned invalid\n"), save); + CFLog(kCFLogLevelWarning, CFSTR("CFString: CFStringGetRangeOfComposedCharactersAtIndex:%d returned invalid\n"), save); } return CFRangeMake(left, current - left); } @@ -3243,6 +3563,7 @@ CFRange CFStringGetRangeOfComposedCharactersAtIndex(CFStringRef theString, CFInd CF_EXPORT Boolean CFStringFindCharacterFromSet(CFStringRef theString, CFCharacterSetRef theSet, CFRange rangeToSearch, CFOptionFlags searchOptions, CFRange *result) { CFStringInlineBuffer stringBuffer; + CFCharacterSetInlineBuffer csetBuffer; UniChar ch; CFIndex step; CFIndex fromLoc, toLoc, cnt; // fromLoc and toLoc are inclusive @@ -3268,6 +3589,7 @@ CF_EXPORT Boolean CFStringFindCharacterFromSet(CFStringRef theString, CFCharacte cnt = fromLoc; CFStringInitInlineBuffer(theString, &stringBuffer, rangeToSearch); + CFCharacterSetInitInlineBuffer(theSet, &csetBuffer); do { ch = CFStringGetCharacterFromInlineBuffer(&stringBuffer, cnt - rangeToSearch.location); @@ -3287,7 +3609,7 @@ CF_EXPORT Boolean CFStringFindCharacterFromSet(CFStringRef theString, CFCharacte lowChar = ch; } - if (CFUniCharIsSurrogateHighCharacter(highChar) && CFUniCharIsSurrogateLowCharacter(lowChar) && CFCharacterSetIsLongCharacterMember(theSet, CFUniCharGetLongCharacterForSurrogatePair(highChar, lowChar))) { + if (CFUniCharIsSurrogateHighCharacter(highChar) && CFUniCharIsSurrogateLowCharacter(lowChar) && CFCharacterSetInlineBufferIsLongCharacterMember(&csetBuffer, CFUniCharGetLongCharacterForSurrogatePair(highChar, lowChar))) { if (result) *result = CFRangeMake((cnt < otherCharIndex ? cnt : otherCharIndex), 2); return true; } else if (otherCharIndex == toLoc) { @@ -3296,7 +3618,7 @@ CF_EXPORT Boolean CFStringFindCharacterFromSet(CFStringRef theString, CFCharacte cnt = otherCharIndex + step; } } - } else if (CFCharacterSetIsCharacterMember(theSet, ch)) { + } else if (CFCharacterSetInlineBufferIsLongCharacterMember(&csetBuffer, ch)) { done = found = true; } else if (cnt == toLoc) { done = true; @@ -3317,18 +3639,16 @@ CF_EXPORT Boolean CFStringFindCharacterFromSet(CFStringRef theString, CFCharacte #define LineSeparator 0x2028 #define ParaSeparator 0x2029 -CF_INLINE Boolean isALineSeparatorTypeCharacter(UniChar ch) { +CF_INLINE Boolean isALineSeparatorTypeCharacter(UniChar ch, Boolean includeLineEndings) { if (ch > CarriageReturn && ch < NextLine) return false; /* Quick test to cover most chars */ - return (ch == NewLine || ch == CarriageReturn || ch == NextLine || ch == LineSeparator || ch == ParaSeparator) ? true : false; + return (ch == NewLine || ch == CarriageReturn || ch == ParaSeparator || (includeLineEndings && (ch == NextLine || ch == LineSeparator))) ? true : false; } -void CFStringGetLineBounds(CFStringRef string, CFRange range, CFIndex *lineBeginIndex, CFIndex *lineEndIndex, CFIndex *contentsEndIndex) { +static void __CFStringGetLineOrParagraphBounds(CFStringRef string, CFRange range, CFIndex *lineBeginIndex, CFIndex *lineEndIndex, CFIndex *contentsEndIndex, Boolean includeLineEndings) { CFIndex len; CFStringInlineBuffer buf; UniChar ch; - CF_OBJC_FUNCDISPATCH4(__kCFStringTypeID, void, string, "getLineStart:end:contentsEnd:forRange:", lineBeginIndex, lineEndIndex, contentsEndIndex, CFRangeMake(range.location, range.length)); - __CFAssertIsString(string); __CFAssertRangeIsInStringBounds(string, range.location, range.length); @@ -3352,7 +3672,7 @@ void CFStringGetLineBounds(CFStringRef string, CFRange range, CFIndex *lineBegin if (buf_idx < 0) { start = 0; break; - } else if (isALineSeparatorTypeCharacter(CFStringGetCharacterFromInlineBuffer(&buf, buf_idx))) { + } else if (isALineSeparatorTypeCharacter(CFStringGetCharacterFromInlineBuffer(&buf, buf_idx), includeLineEndings)) { start = buf_idx + 1; break; } else { @@ -3379,7 +3699,7 @@ void CFStringGetLineBounds(CFStringRef string, CFRange range, CFIndex *lineBegin } } else { while (1) { - if (isALineSeparatorTypeCharacter(ch)) { + if (isALineSeparatorTypeCharacter(ch, includeLineEndings)) { endOfContents = buf_idx; /* This is actually end of contentsRange */ buf_idx++; /* OK for this to go past the end */ if ((ch == CarriageReturn) && (__CFStringGetCharacterFromInlineBufferAux(&buf, buf_idx) == NewLine)) { @@ -3401,6 +3721,16 @@ void CFStringGetLineBounds(CFStringRef string, CFRange range, CFIndex *lineBegin } } +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)); + __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)); + __CFStringGetLineOrParagraphBounds(string, range, parBeginIndex, parEndIndex, contentsEndIndex, false); +} + CFStringRef CFStringCreateByCombiningStrings(CFAllocatorRef alloc, CFArrayRef array, CFStringRef separatorString) { CFIndex numChars; @@ -3417,7 +3747,7 @@ CFStringRef CFStringCreateByCombiningStrings(CFAllocatorRef alloc, CFArrayRef ar if (stringCount == 0) { return CFStringCreateWithCharacters(alloc, NULL, 0); } else if (stringCount == 1) { - return CFStringCreateCopy(alloc, CFArrayGetValueAtIndex(array, 0)); + return (CFStringRef)CFStringCreateCopy(alloc, (CFStringRef)CFArrayGetValueAtIndex(array, 0)); } if (alloc == NULL) alloc = __CFGetDefaultAllocator(); @@ -3430,7 +3760,8 @@ CFStringRef CFStringCreateByCombiningStrings(CFAllocatorRef alloc, CFArrayRef ar if (!CF_IS_OBJC(__kCFStringTypeID, otherString) && __CFStrIsUnicode(otherString)) canBeEightbit = false; } - bufPtr = buffer = CFAllocatorAllocate(alloc, canBeEightbit ? ((numChars + 1) * sizeof(uint8_t)) : (numChars * sizeof(UniChar)), 0); + buffer = (uint8_t *)CFAllocatorAllocate(alloc, canBeEightbit ? ((numChars + 1) * sizeof(uint8_t)) : (numChars * sizeof(UniChar)), 0); + bufPtr = (uint8_t *)buffer; if (__CFOASafe) __CFSetLastAllocationEventName(buffer, "CFString (store)"); separatorNumByte = CFStringGetLength(separatorString) * (canBeEightbit ? sizeof(uint8_t) : sizeof(UniChar)); @@ -3440,11 +3771,11 @@ CFStringRef CFStringCreateByCombiningStrings(CFAllocatorRef alloc, CFArrayRef ar memmove(bufPtr, separatorContents, separatorNumByte); } else { if (!isSepCFString) { // NSString - CFStringGetCharacters(separatorString, CFRangeMake(0, CFStringGetLength(separatorString)), (UniChar*)bufPtr); + CFStringGetCharacters(separatorString, CFRangeMake(0, CFStringGetLength(separatorString)), (UniChar *)bufPtr); } else if (canBeEightbit || __CFStrIsUnicode(separatorString)) { memmove(bufPtr, (const uint8_t *)__CFStrContents(separatorString) + __CFStrSkipAnyLengthByte(separatorString), separatorNumByte); } else { - __CFStrConvertBytesToUnicode((uint8_t*)__CFStrContents(separatorString) + __CFStrSkipAnyLengthByte(separatorString), (UniChar*)bufPtr, __CFStrLength(separatorString)); + __CFStrConvertBytesToUnicode((uint8_t *)__CFStrContents(separatorString) + __CFStrSkipAnyLengthByte(separatorString), (UniChar *)bufPtr, __CFStrLength(separatorString)); } separatorContents = bufPtr; } @@ -3454,16 +3785,16 @@ CFStringRef CFStringCreateByCombiningStrings(CFAllocatorRef alloc, CFArrayRef ar otherString = (CFStringRef )CFArrayGetValueAtIndex(array, idx); if (CF_IS_OBJC(__kCFStringTypeID, otherString)) { CFIndex otherLength = CFStringGetLength(otherString); - CFStringGetCharacters(otherString, CFRangeMake(0, otherLength), (UniChar*)bufPtr); + CFStringGetCharacters(otherString, CFRangeMake(0, otherLength), (UniChar *)bufPtr); bufPtr += otherLength * sizeof(UniChar); } else { - const uint8_t* otherContents = __CFStrContents(otherString); + const uint8_t * otherContents = (const uint8_t *)__CFStrContents(otherString); CFIndex otherNumByte = __CFStrLength2(otherString, otherContents) * (canBeEightbit ? sizeof(uint8_t) : sizeof(UniChar)); if (canBeEightbit || __CFStrIsUnicode(otherString)) { memmove(bufPtr, otherContents + __CFStrSkipAnyLengthByte(otherString), otherNumByte); } else { - __CFStrConvertBytesToUnicode(otherContents + __CFStrSkipAnyLengthByte(otherString), (UniChar*)bufPtr, __CFStrLength2(otherString, otherContents)); + __CFStrConvertBytesToUnicode(otherContents + __CFStrSkipAnyLengthByte(otherString), (UniChar *)bufPtr, __CFStrLength2(otherString, otherContents)); } bufPtr += otherNumByte; } @@ -3471,8 +3802,8 @@ CFStringRef CFStringCreateByCombiningStrings(CFAllocatorRef alloc, CFArrayRef ar if (canBeEightbit) *bufPtr = 0; // NULL byte; return canBeEightbit ? - CFStringCreateWithCStringNoCopy(alloc, buffer, __CFStringGetEightBitStringEncoding(), alloc) : - CFStringCreateWithCharactersNoCopy(alloc, buffer, numChars, alloc); + CFStringCreateWithCStringNoCopy(alloc, (const char*)buffer, __CFStringGetEightBitStringEncoding(), alloc) : + CFStringCreateWithCharactersNoCopy(alloc, (UniChar *)buffer, numChars, alloc); } @@ -3481,7 +3812,7 @@ CFArrayRef CFStringCreateArrayBySeparatingStrings(CFAllocatorRef alloc, CFString CFIndex length = CFStringGetLength(string); /* No objc dispatch needed here since CFStringCreateArrayWithFindResults() works with both CFString and NSString */ if (!(separatorRanges = CFStringCreateArrayWithFindResults(alloc, string, separatorString, CFRangeMake(0, length), 0))) { - return CFArrayCreate(alloc, (const void**)&string, 1, & kCFTypeArrayCallBacks); + return CFArrayCreate(alloc, (const void **)&string, 1, & kCFTypeArrayCallBacks); } else { CFIndex idx; CFIndex count = CFArrayGetCount(separatorRanges); @@ -3492,7 +3823,7 @@ CFArrayRef CFStringCreateArrayBySeparatingStrings(CFAllocatorRef alloc, CFString CFStringRef substring; for (idx = 0;idx < count;idx++) { - currentRange = CFArrayGetValueAtIndex(separatorRanges, idx); + currentRange = (const CFRange *)CFArrayGetValueAtIndex(separatorRanges, idx); numChars = currentRange->location - startIndex; substring = CFStringCreateWithSubstring(alloc, string, CFRangeMake(startIndex, numChars)); CFArrayAppendValue(array, substring); @@ -3527,33 +3858,34 @@ CFDataRef CFStringCreateExternalRepresentation(CFAllocatorRef alloc, CFStringRef __CFAssertIsString(string); length = __CFStrLength(string); if (__CFStrIsEightBit(string) && ((__CFStringGetEightBitStringEncoding() == encoding) || (__CFStringGetEightBitStringEncoding() == kCFStringEncodingASCII && __CFStringEncodingIsSupersetOfASCII(encoding)))) { // Requested encoding is equal to the encoding in string - return CFDataCreate(alloc, ((char *)__CFStrContents(string) + __CFStrSkipAnyLengthByte(string)), __CFStrLength(string)); + return CFDataCreate(alloc, ((uint8_t *)__CFStrContents(string) + __CFStrSkipAnyLengthByte(string)), __CFStrLength(string)); } } if (alloc == NULL) alloc = __CFGetDefaultAllocator(); - if (encoding == kCFStringEncodingUnicode) { - guessedByteLength = (length + 1) * sizeof(UniChar); + if (((encoding & 0x0FFF) == kCFStringEncodingUnicode) && ((encoding == kCFStringEncodingUnicode) || ((encoding > kCFStringEncodingUTF8) && (encoding <= kCFStringEncodingUTF32LE)))) { + guessedByteLength = (length + 1) * ((((encoding >> 26) & 2) == 0) ? sizeof(UTF16Char) : sizeof(UTF32Char)); // UTF32 format has the bit set } else if (((guessedByteLength = CFStringGetMaximumSizeForEncoding(length, encoding)) > length) && !CF_IS_OBJC(__kCFStringTypeID, string)) { // Multi byte encoding -#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__) +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD if (__CFStrIsUnicode(string)) { - guessedByteLength = CFStringEncodingByteLengthForCharacters(encoding, kCFStringEncodingPrependBOM, __CFStrContents(string), __CFStrLength(string)); + CFIndex aLength = CFStringEncodingByteLengthForCharacters(encoding, kCFStringEncodingPrependBOM, __CFStrContents(string), __CFStrLength(string)); + if (aLength > 0) guessedByteLength = aLength; } else { #endif - result = __CFStringEncodeByteStream(string, 0, length, true, encoding, lossByte, NULL, 0x7FFFFFFF, &guessedByteLength); + result = __CFStringEncodeByteStream(string, 0, length, true, encoding, lossByte, NULL, LONG_MAX, &guessedByteLength); // if result == length, we always succeed // otherwise, if result == 0, we fail // otherwise, if there was a lossByte but still result != length, we fail if ((result != length) && (!result || !lossByte)) return NULL; if (guessedByteLength == length && __CFStrIsEightBit(string) && __CFStringEncodingIsSupersetOfASCII(encoding)) { // It's all ASCII !! - return CFDataCreate(alloc, ((char *)__CFStrContents(string) + __CFStrSkipAnyLengthByte(string)), __CFStrLength(string)); + return CFDataCreate(alloc, ((uint8_t *)__CFStrContents(string) + __CFStrSkipAnyLengthByte(string)), __CFStrLength(string)); } -#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__) +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD } #endif } - bytes = CFAllocatorAllocate(alloc, guessedByteLength, 0); + bytes = (uint8_t *)CFAllocatorAllocate(alloc, guessedByteLength, 0); if (__CFOASafe) __CFSetLastAllocationEventName(bytes, "CFData (store)"); result = __CFStringEncodeByteStream(string, 0, length, true, encoding, lossByte, bytes, guessedByteLength, &usedLength); @@ -3563,7 +3895,7 @@ CFDataRef CFStringCreateExternalRepresentation(CFAllocatorRef alloc, CFStringRef return NULL; } - return CFDataCreateWithBytesNoCopy(alloc, (char const *)bytes, usedLength, alloc); + return CFDataCreateWithBytesNoCopy(alloc, (uint8_t *)bytes, usedLength, alloc); } @@ -3574,8 +3906,8 @@ CFStringEncoding CFStringGetSmallestEncoding(CFStringRef str) { if (__CFStrIsEightBit(str)) return __CFStringGetEightBitStringEncoding(); len = __CFStrLength(str); - if (__CFStringEncodeByteStream(str, 0, len, false, __CFStringGetEightBitStringEncoding(), 0, NULL, 0x7fffffff, NULL) == len) return __CFStringGetEightBitStringEncoding(); - if ((__CFStringGetEightBitStringEncoding() != __CFStringGetSystemEncoding()) && (__CFStringEncodeByteStream(str, 0, len, false, __CFStringGetSystemEncoding(), 0, NULL, 0x7fffffff, NULL) == len)) return __CFStringGetSystemEncoding(); + if (__CFStringEncodeByteStream(str, 0, len, false, __CFStringGetEightBitStringEncoding(), 0, NULL, LONG_MAX, NULL) == len) return __CFStringGetEightBitStringEncoding(); + if ((__CFStringGetEightBitStringEncoding() != __CFStringGetSystemEncoding()) && (__CFStringEncodeByteStream(str, 0, len, false, __CFStringGetSystemEncoding(), 0, NULL, LONG_MAX, NULL) == len)) return __CFStringGetSystemEncoding(); return kCFStringEncodingUnicode; /* ??? */ } @@ -3716,7 +4048,7 @@ static void __CFStringAppendBytes(CFMutableStringRef str, const char *cStr, CFIn vBuf.allocator = __CFGetDefaultAllocator(); // 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(cStr, appendedLength, encoding, __CFStrIsUnicode(str), &vBuf, &usingPassedInMemory, 0)) { + if (!__CFStringDecodeByteStream3((const uint8_t *)cStr, appendedLength, encoding, __CFStrIsUnicode(str), &vBuf, &usingPassedInMemory, 0)) { CFAssert1(0, __kCFLogAssertion, "Supplied bytes could not be converted specified encoding %d", encoding); return; } @@ -3724,7 +4056,7 @@ static void __CFStringAppendBytes(CFMutableStringRef str, const char *cStr, CFIn // If not ASCII, appendedLength now denotes length in UniChars appendedLength = vBuf.numChars; appendedIsUnicode = !vBuf.isASCII; - cStr = vBuf.chars.ascii; + cStr = (const char *)vBuf.chars.ascii; freeCStrWhenDone = !usingPassedInMemory && vBuf.shouldFreeChars; } @@ -3746,7 +4078,7 @@ static void __CFStringAppendBytes(CFMutableStringRef str, const char *cStr, CFIn if (appendedIsUnicode) { memmove(contents + strLength, cStr, appendedLength * sizeof(UniChar)); } else { - __CFStrConvertBytesToUnicode(cStr, contents + strLength, appendedLength); + __CFStrConvertBytesToUnicode((const uint8_t *)cStr, contents + strLength, appendedLength); } } else { if (demoteAppendedUnicode) { @@ -3765,7 +4097,7 @@ static void __CFStringAppendBytes(CFMutableStringRef str, const char *cStr, CFIn } void CFStringAppendPascalString(CFMutableStringRef str, ConstStringPtr pStr, CFStringEncoding encoding) { - __CFStringAppendBytes(str, pStr + 1, (CFIndex)*pStr, encoding); + __CFStringAppendBytes(str, (const char *)(pStr + 1), (CFIndex)*pStr, encoding); } void CFStringAppendCString(CFMutableStringRef str, const char *cStr, CFStringEncoding encoding) { @@ -3784,7 +4116,7 @@ void CFStringAppendFormat(CFMutableStringRef str, CFDictionaryRef formatOptions, CFIndex CFStringFindAndReplace(CFMutableStringRef string, CFStringRef stringToFind, CFStringRef replacementString, CFRange rangeToSearch, CFOptionFlags compareOptions) { CFRange foundRange; - Boolean backwards = compareOptions & kCFCompareBackwards; + Boolean backwards = ((compareOptions & kCFCompareBackwards) != 0); UInt32 endIndex = rangeToSearch.location + rangeToSearch.length; #define MAX_RANGES_ON_STACK (1000 / sizeof(CFRange)) CFRange rangeBuffer[MAX_RANGES_ON_STACK]; // Used to avoid allocating memory @@ -3810,7 +4142,7 @@ CFIndex CFStringFindAndReplace(CFMutableStringRef string, CFStringRef stringToFi bool firstAlloc = (ranges == rangeBuffer) ? true : false; capacity = (capacity + 4) * 2; // Note that reallocate with NULL previous pointer is same as allocate - ranges = CFAllocatorReallocate(NULL, firstAlloc ? NULL : ranges, capacity * sizeof(CFRange), 0); + ranges = (CFRange *)CFAllocatorReallocate(kCFAllocatorSystemDefault, firstAlloc ? NULL : ranges, capacity * sizeof(CFRange), 0); if (firstAlloc) memmove(ranges, rangeBuffer, MAX_RANGES_ON_STACK * sizeof(CFRange)); } ranges[foundCount] = foundRange; @@ -3830,7 +4162,7 @@ CFIndex CFStringFindAndReplace(CFMutableStringRef string, CFStringRef stringToFi } } __CFStringReplaceMultiple(string, ranges, foundCount, replacementString); - if (ranges != rangeBuffer) CFAllocatorDeallocate(NULL, ranges); + if (ranges != rangeBuffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, ranges); } return foundCount; @@ -3855,7 +4187,7 @@ int __CFStringCheckAndReplace(CFMutableStringRef str, CFRange range, CFStringRef // be ignored or not Boolean __CFStringNoteErrors(void) { - return _CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar) ? true : false; + return true; } @@ -3894,13 +4226,13 @@ void CFStringPad(CFMutableStringRef string, CFStringRef padString, CFIndex lengt __CFStringChangeSize(string, CFRangeMake(originalLength, 0), padRemaining, isUnicode); - contents = (uint8_t*)__CFStrContents(string) + charSize * originalLength + __CFStrSkipAnyLengthByte(string); + contents = (uint8_t *)__CFStrContents(string) + charSize * originalLength + __CFStrSkipAnyLengthByte(string); padLength = padStringLength - indexIntoPad; padLength = padRemaining < padLength ? padRemaining : padLength; while (padRemaining > 0) { if (isUnicode) { - CFStringGetCharacters(padString, CFRangeMake(indexIntoPad, padLength), (UniChar*)contents); + CFStringGetCharacters(padString, CFRangeMake(indexIntoPad, padLength), (UniChar *)contents); } else { CFStringGetBytes(padString, CFRangeMake(indexIntoPad, padLength), __CFStringGetEightBitStringEncoding(), 0, false, contents, padRemaining * charSize, NULL); } @@ -3931,7 +4263,7 @@ void CFStringTrim(CFMutableStringRef string, CFStringRef trimString) { if (newStartIndex < length) { CFIndex charSize = __CFStrIsUnicode(string) ? sizeof(UniChar) : sizeof(uint8_t); - uint8_t *contents = (uint8_t*)__CFStrContents(string) + __CFStrSkipAnyLengthByte(string); + uint8_t *contents = (uint8_t *)__CFStrContents(string) + __CFStrSkipAnyLengthByte(string); length -= newStartIndex; if (__CFStrLength(trimString) < length) { @@ -3966,7 +4298,7 @@ void CFStringTrimWhitespace(CFMutableStringRef string) { newStartIndex = buffer_idx; if (newStartIndex < length) { - uint8_t *contents = (uint8_t*)__CFStrContents(string) + __CFStrSkipAnyLengthByte(string); + uint8_t *contents = (uint8_t *)__CFStrContents(string) + __CFStrSkipAnyLengthByte(string); CFIndex charSize = (__CFStrIsUnicode(string) ? sizeof(UniChar) : sizeof(uint8_t)); buffer_idx = length - 1; @@ -3984,7 +4316,7 @@ void CFStringTrimWhitespace(CFMutableStringRef string) { void CFStringLowercase(CFMutableStringRef string, CFLocaleRef locale) { CFIndex currentIndex = 0; CFIndex length; - const char *langCode; + const uint8_t *langCode; Boolean isEightBit = __CFStrIsEightBit(string); CF_OBJC_FUNCDISPATCH1(__kCFStringTypeID, void, string, "_cfLowercase:", locale); @@ -3993,10 +4325,10 @@ void CFStringLowercase(CFMutableStringRef string, CFLocaleRef locale) { length = __CFStrLength(string); - langCode = (_CFCanUseLocale(locale) ? _CFStrGetLanguageIdentifierForLocale(locale) : NULL); + langCode = (const uint8_t *)(_CFCanUseLocale(locale) ? _CFStrGetLanguageIdentifierForLocale(locale) : NULL); if (!langCode && isEightBit) { - uint8_t *contents = (uint8_t*)__CFStrContents(string) + __CFStrSkipAnyLengthByte(string); + uint8_t *contents = (uint8_t *)__CFStrContents(string) + __CFStrSkipAnyLengthByte(string); for (;currentIndex < length;currentIndex++) { if (contents[currentIndex] >= 'A' && contents[currentIndex] <= 'Z') { contents[currentIndex] += 'a' - 'A'; @@ -4007,7 +4339,7 @@ void CFStringLowercase(CFMutableStringRef string, CFLocaleRef locale) { } if (currentIndex < length) { - UniChar *contents; + UTF16Char *contents; UniChar mappedCharacters[MAX_CASE_MAPPING_BUF]; CFIndex mappedLength; UTF32Char currentChar; @@ -4015,7 +4347,7 @@ void CFStringLowercase(CFMutableStringRef string, CFLocaleRef locale) { if (isEightBit) __CFStringChangeSize(string, CFRangeMake(0, 0), 0, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); for (;currentIndex < length;currentIndex++) { @@ -4033,13 +4365,13 @@ void CFStringLowercase(CFMutableStringRef string, CFLocaleRef locale) { switch (mappedLength) { case 0: __CFStringChangeSize(string, CFRangeMake(currentIndex, 2), 0, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); length -= 2; break; case 1: __CFStringChangeSize(string, CFRangeMake(currentIndex + 1, 1), 0, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); --length; break; @@ -4050,7 +4382,7 @@ void CFStringLowercase(CFMutableStringRef string, CFLocaleRef locale) { default: --mappedLength; // Skip the current char __CFStringChangeSize(string, CFRangeMake(currentIndex + 1, 0), mappedLength - 1, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); memmove(contents + currentIndex + 1, mappedCharacters + 1, mappedLength * sizeof(UniChar)); length += (mappedLength - 1); currentIndex += mappedLength; @@ -4058,12 +4390,12 @@ void CFStringLowercase(CFMutableStringRef string, CFLocaleRef locale) { } } else if (mappedLength == 0) { __CFStringChangeSize(string, CFRangeMake(currentIndex, 1), 0, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); --length; } else if (mappedLength > 1) { --mappedLength; // Skip the current char __CFStringChangeSize(string, CFRangeMake(currentIndex + 1, 0), mappedLength, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); memmove(contents + currentIndex + 1, mappedCharacters + 1, mappedLength * sizeof(UniChar)); length += mappedLength; currentIndex += mappedLength; @@ -4075,7 +4407,7 @@ void CFStringLowercase(CFMutableStringRef string, CFLocaleRef locale) { void CFStringUppercase(CFMutableStringRef string, CFLocaleRef locale) { CFIndex currentIndex = 0; CFIndex length; - const char *langCode; + const uint8_t *langCode; Boolean isEightBit = __CFStrIsEightBit(string); CF_OBJC_FUNCDISPATCH1(__kCFStringTypeID, void, string, "_cfUppercase:", locale); @@ -4084,10 +4416,10 @@ void CFStringUppercase(CFMutableStringRef string, CFLocaleRef locale) { length = __CFStrLength(string); - langCode = (_CFCanUseLocale(locale) ? _CFStrGetLanguageIdentifierForLocale(locale) : NULL); + langCode = (const uint8_t *)(_CFCanUseLocale(locale) ? _CFStrGetLanguageIdentifierForLocale(locale) : NULL); if (!langCode && isEightBit) { - uint8_t *contents = (uint8_t*)__CFStrContents(string) + __CFStrSkipAnyLengthByte(string); + uint8_t *contents = (uint8_t *)__CFStrContents(string) + __CFStrSkipAnyLengthByte(string); for (;currentIndex < length;currentIndex++) { if (contents[currentIndex] >= 'a' && contents[currentIndex] <= 'z') { contents[currentIndex] -= 'a' - 'A'; @@ -4106,7 +4438,7 @@ void CFStringUppercase(CFMutableStringRef string, CFLocaleRef locale) { if (isEightBit) __CFStringChangeSize(string, CFRangeMake(0, 0), 0, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); for (;currentIndex < length;currentIndex++) { if (CFUniCharIsSurrogateHighCharacter(contents[currentIndex]) && (currentIndex + 1 < length) && CFUniCharIsSurrogateLowCharacter(contents[currentIndex + 1])) { @@ -4124,13 +4456,13 @@ void CFStringUppercase(CFMutableStringRef string, CFLocaleRef locale) { switch (mappedLength) { case 0: __CFStringChangeSize(string, CFRangeMake(currentIndex, 2), 0, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); length -= 2; break; case 1: __CFStringChangeSize(string, CFRangeMake(currentIndex + 1, 1), 0, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); --length; break; @@ -4141,7 +4473,7 @@ void CFStringUppercase(CFMutableStringRef string, CFLocaleRef locale) { default: --mappedLength; // Skip the current char __CFStringChangeSize(string, CFRangeMake(currentIndex + 1, 0), mappedLength - 1, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); memmove(contents + currentIndex + 1, mappedCharacters + 1, mappedLength * sizeof(UniChar)); length += (mappedLength - 1); currentIndex += mappedLength; @@ -4149,12 +4481,12 @@ void CFStringUppercase(CFMutableStringRef string, CFLocaleRef locale) { } } else if (mappedLength == 0) { __CFStringChangeSize(string, CFRangeMake(currentIndex, 1), 0, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); --length; } else if (mappedLength > 1) { --mappedLength; // Skip the current char __CFStringChangeSize(string, CFRangeMake(currentIndex + 1, 0), mappedLength, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); memmove(contents + currentIndex + 1, mappedCharacters + 1, mappedLength * sizeof(UniChar)); length += mappedLength; currentIndex += mappedLength; @@ -4167,10 +4499,10 @@ void CFStringUppercase(CFMutableStringRef string, CFLocaleRef locale) { void CFStringCapitalize(CFMutableStringRef string, CFLocaleRef locale) { CFIndex currentIndex = 0; CFIndex length; - const char *langCode; + const uint8_t *langCode; Boolean isEightBit = __CFStrIsEightBit(string); Boolean isLastCased = false; - static const uint8_t *caseIgnorableForBMP = NULL; + const uint8_t *caseIgnorableForBMP; CF_OBJC_FUNCDISPATCH1(__kCFStringTypeID, void, string, "_cfCapitalize:", locale); @@ -4178,12 +4510,12 @@ void CFStringCapitalize(CFMutableStringRef string, CFLocaleRef locale) { length = __CFStrLength(string); - if (NULL == caseIgnorableForBMP) caseIgnorableForBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharCaseIgnorableCharacterSet, 0); + caseIgnorableForBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharCaseIgnorableCharacterSet, 0); - langCode = (_CFCanUseLocale(locale) ? _CFStrGetLanguageIdentifierForLocale(locale) : NULL); + langCode = (const uint8_t *)(_CFCanUseLocale(locale) ? _CFStrGetLanguageIdentifierForLocale(locale) : NULL); if (!langCode && isEightBit) { - uint8_t *contents = (uint8_t*)__CFStrContents(string) + __CFStrSkipAnyLengthByte(string); + uint8_t *contents = (uint8_t *)__CFStrContents(string) + __CFStrSkipAnyLengthByte(string); for (;currentIndex < length;currentIndex++) { if (contents[currentIndex] > 127) { break; @@ -4208,7 +4540,7 @@ void CFStringCapitalize(CFMutableStringRef string, CFLocaleRef locale) { if (isEightBit) __CFStringChangeSize(string, CFRangeMake(0, 0), 0, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); for (;currentIndex < length;currentIndex++) { if (CFUniCharIsSurrogateHighCharacter(contents[currentIndex]) && (currentIndex + 1 < length) && CFUniCharIsSurrogateLowCharacter(contents[currentIndex + 1])) { @@ -4225,13 +4557,13 @@ void CFStringCapitalize(CFMutableStringRef string, CFLocaleRef locale) { switch (mappedLength) { case 0: __CFStringChangeSize(string, CFRangeMake(currentIndex, 2), 0, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); length -= 2; break; case 1: __CFStringChangeSize(string, CFRangeMake(currentIndex + 1, 1), 0, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); --length; break; @@ -4242,7 +4574,7 @@ void CFStringCapitalize(CFMutableStringRef string, CFLocaleRef locale) { default: --mappedLength; // Skip the current char __CFStringChangeSize(string, CFRangeMake(currentIndex + 1, 0), mappedLength - 1, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); memmove(contents + currentIndex + 1, mappedCharacters + 1, mappedLength * sizeof(UniChar)); length += (mappedLength - 1); currentIndex += mappedLength; @@ -4250,12 +4582,12 @@ void CFStringCapitalize(CFMutableStringRef string, CFLocaleRef locale) { } } else if (mappedLength == 0) { __CFStringChangeSize(string, CFRangeMake(currentIndex, 1), 0, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); --length; } else if (mappedLength > 1) { --mappedLength; // Skip the current char __CFStringChangeSize(string, CFRangeMake(currentIndex + 1, 0), mappedLength, true); - contents = (UniChar*)__CFStrContents(string); + contents = (UniChar *)__CFStrContents(string); memmove(contents + currentIndex + 1, mappedCharacters + 1, mappedLength * sizeof(UniChar)); length += mappedLength; currentIndex += mappedLength; @@ -4322,7 +4654,7 @@ void CFStringNormalize(CFMutableStringRef string, CFStringNormalizationForm theF if (theForm == kCFStringNormalizationFormC) return; // 8bit form has no decomposition - contents = (uint8_t*)__CFStrContents(string) + __CFStrSkipAnyLengthByte(string); + contents = (uint8_t *)__CFStrContents(string) + __CFStrSkipAnyLengthByte(string); for (;currentIndex < length;currentIndex++) { if (contents[currentIndex] > 127) { @@ -4342,6 +4674,9 @@ void CFStringNormalize(CFMutableStringRef string, CFStringNormalizationForm theF CFIndex mappedLength; CFIndex currentLength; UTF32Char currentChar; + const uint8_t *decompBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet, 0); + const uint8_t *nonBaseBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, 0); + const uint8_t *combiningBMP = (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, 0); while (contents < limit) { if (CFUniCharIsSurrogateHighCharacter(*contents) && (contents + 1 < limit) && CFUniCharIsSurrogateLowCharacter(*(contents + 1))) { @@ -4355,7 +4690,7 @@ void CFStringNormalize(CFMutableStringRef string, CFStringNormalizationForm theF mappedLength = 0; - if (CFUniCharIsMemberOf(currentChar, kCFUniCharCanonicalDecomposableCharacterSet) && !CFUniCharIsMemberOf(currentChar, kCFUniCharNonBaseCharacterSet)) { + if (CFUniCharIsMemberOfBitmap(currentChar, ((currentChar < 0x10000) ? decompBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet, (currentChar >> 16)))) && (0 == CFUniCharGetCombiningPropertyForCharacter(currentChar, ((currentChar < 0x10000) ? combiningBMP : (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, (currentChar >> 16)))))) { if ((theForm & kCFStringNormalizationFormC) == 0 || currentChar < HANGUL_SBASE || currentChar > (HANGUL_SBASE + HANGUL_SCOUNT)) { // We don't have to decompose Hangul Syllables if we're precomposing again mappedLength = CFUniCharDecomposeCharacter(currentChar, mappedCharacters, MAX_DECOMP_BUF); } @@ -4370,7 +4705,7 @@ void CFStringNormalize(CFMutableStringRef string, CFStringNormalizationForm theF } } - if (CFUniCharIsMemberOf(currentChar, kCFUniCharNonBaseCharacterSet)) { + if (0 != CFUniCharGetCombiningPropertyForCharacter(currentChar, (const uint8_t *)((currentChar < 0x10000) ? combiningBMP : CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, (currentChar >> 16))))) { uint32_t decompLength; if (mappedLength == 0) { @@ -4392,7 +4727,7 @@ void CFStringNormalize(CFMutableStringRef string, CFStringNormalizationForm theF } contents += (currentChar & 0xFFFF0000 ? 2 : 1); - if (CFUniCharIsMemberOf(currentChar, kCFUniCharDecomposableCharacterSet)) { // Vietnamese accent, etc. + if (CFUniCharIsMemberOfBitmap(currentChar, ((currentChar < 0x10000) ? decompBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet, (currentChar >> 16))))) { // Vietnamese accent, etc. decompLength = CFUniCharDecomposeCharacter(currentChar, mappedCharacters + mappedLength, MAX_DECOMP_BUF - mappedLength); mappedLength += decompLength; } else { @@ -4405,7 +4740,7 @@ void CFStringNormalize(CFMutableStringRef string, CFStringNormalizationForm theF } else { currentChar = *contents; } - if (!CFUniCharIsMemberOf(currentChar, kCFUniCharNonBaseCharacterSet)) break; + if (0 == CFUniCharGetCombiningPropertyForCharacter(currentChar, (const uint8_t *)((currentChar < 0x10000) ? combiningBMP : CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, (currentChar >> 16))))) break; if (currentChar & 0xFFFF0000) { contents += 2; currentLength += 2; @@ -4416,13 +4751,13 @@ void CFStringNormalize(CFMutableStringRef string, CFStringNormalizationForm theF if (mappedLength == allocatedLength) { allocatedLength += MAX_DECOMP_BUF; if (mappedCharacters == buffer) { - mappedCharacters = (UTF32Char *)CFAllocatorAllocate(NULL, allocatedLength * sizeof(UTF32Char), 0); + mappedCharacters = (UTF32Char *)CFAllocatorAllocate(kCFAllocatorSystemDefault, allocatedLength * sizeof(UTF32Char), 0); memmove(mappedCharacters, buffer, MAX_DECOMP_BUF * sizeof(UTF32Char)); } else { - mappedCharacters = (UTF32Char *)CFAllocatorReallocate(NULL, mappedCharacters, allocatedLength * sizeof(UTF32Char), 0); + mappedCharacters = (UTF32Char *)CFAllocatorReallocate(kCFAllocatorSystemDefault, mappedCharacters, allocatedLength * sizeof(UTF32Char), 0); } } - if (CFUniCharIsMemberOf(currentChar, kCFUniCharDecomposableCharacterSet)) { // Vietnamese accent, etc. + if (CFUniCharIsMemberOfBitmap(currentChar, ((currentChar < 0x10000) ? decompBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet, (currentChar >> 16))))) { // Vietnamese accent, etc. decompLength = CFUniCharDecomposeCharacter(currentChar, mappedCharacters + mappedLength, MAX_DECOMP_BUF - mappedLength); mappedLength += decompLength; } else { @@ -4444,10 +4779,10 @@ void CFStringNormalize(CFMutableStringRef string, CFStringNormalizationForm theF if (newLength == 0) { allocatedLength += MAX_DECOMP_BUF; if (mappedCharacters == buffer) { - mappedCharacters = (UTF32Char *)CFAllocatorAllocate(NULL, allocatedLength * sizeof(UTF32Char), 0); + mappedCharacters = (UTF32Char *)CFAllocatorAllocate(kCFAllocatorSystemDefault, allocatedLength * sizeof(UTF32Char), 0); memmove(mappedCharacters, buffer, MAX_DECOMP_BUF * sizeof(UTF32Char)); } else { - mappedCharacters = (UTF32Char *)CFAllocatorReallocate(NULL, mappedCharacters, allocatedLength * sizeof(UTF32Char), 0); + mappedCharacters = (UTF32Char *)CFAllocatorReallocate(kCFAllocatorSystemDefault, mappedCharacters, allocatedLength * sizeof(UTF32Char), 0); } } } @@ -4455,19 +4790,19 @@ void CFStringNormalize(CFMutableStringRef string, CFStringNormalizationForm theF } if (theForm & kCFStringNormalizationFormC) { + UTF32Char nextChar; + if (mappedLength > 1) { CFIndex consumedLength = 1; - UTF32Char nextChar; UTF32Char *currentBase = mappedCharacters; uint8_t currentClass, lastClass = 0; - const uint8_t *bmpClassTable = CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, 0); bool didCombine = false; currentChar = *mappedCharacters; while (consumedLength < mappedLength) { nextChar = mappedCharacters[consumedLength]; - currentClass = (nextChar & 0xFFFF0000 ? CFUniCharGetUnicodeProperty(nextChar, kCFUniCharCombiningProperty) : CFUniCharGetCombiningPropertyForCharacter(nextChar, bmpClassTable)); + currentClass = CFUniCharGetCombiningPropertyForCharacter(nextChar, (const uint8_t *)((nextChar < 0x10000) ? combiningBMP : CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, (nextChar >> 16)))); if (theForm & kCFStringNormalizationFormKD) { if ((currentChar >= HANGUL_LBASE) && (currentChar < (HANGUL_LBASE + 0xFF))) { @@ -4507,7 +4842,7 @@ void CFStringNormalize(CFMutableStringRef string, CFStringNormalizationForm theF } } } - if (!CFUniCharIsMemberOf(nextChar, kCFUniCharNonBaseCharacterSet)) { + if (!CFUniCharIsMemberOfBitmap(nextChar, ((nextChar < 0x10000) ? nonBaseBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, (nextChar >> 16))))) { *currentBase = currentChar; currentBase = mappedCharacters + consumedLength; currentChar = nextChar; @@ -4515,7 +4850,8 @@ void CFStringNormalize(CFMutableStringRef string, CFStringNormalizationForm theF continue; } } - if ((lastClass == 0) || (currentClass != lastClass)) { + + if ((lastClass == 0) || (currentClass > lastClass)) { nextChar = CFUniCharPrecomposeCharacter(currentChar, nextChar); if (nextChar == 0xFFFD) { lastClass = currentClass; @@ -4523,7 +4859,6 @@ void CFStringNormalize(CFMutableStringRef string, CFStringNormalizationForm theF mappedCharacters[consumedLength] = 0xFFFD; didCombine = true; currentChar = nextChar; - lastClass = 0; } } ++consumedLength; @@ -4562,6 +4897,28 @@ void CFStringNormalize(CFMutableStringRef string, CFStringNormalizationForm theF mappedLength = 1; } } + } else { // collect class 0 non-base characters + while (contents < limit) { + nextChar = *contents; + if (CFUniCharIsSurrogateHighCharacter(nextChar) && ((contents + 1) < limit) && CFUniCharIsSurrogateLowCharacter(*(contents + 1))) { + nextChar = CFUniCharGetLongCharacterForSurrogatePair(nextChar, *(contents + 1)); + if (!CFUniCharIsMemberOfBitmap(nextChar, (const uint8_t *)CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, (nextChar >> 16))) || (0 != CFUniCharGetCombiningPropertyForCharacter(nextChar, (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, (nextChar >> 16))))) break; + } else { + if (!CFUniCharIsMemberOfBitmap(nextChar, nonBaseBMP) || (0 != CFUniCharGetCombiningPropertyForCharacter(nextChar, combiningBMP))) break; + } + currentChar = CFUniCharPrecomposeCharacter(currentChar, nextChar); + if (0xFFFD == currentChar) break; + + if (nextChar < 0x10000) { + ++contents; ++currentLength; + } else { + contents += 2; + currentLength += 2; + } + + *mappedCharacters = currentChar; + mappedLength = 1; + } } } @@ -4581,10 +4938,163 @@ void CFStringNormalize(CFMutableStringRef string, CFStringNormalizationForm theF currentIndex += currentLength; } - if (mappedCharacters != buffer) CFAllocatorDeallocate(NULL, mappedCharacters); + if (mappedCharacters != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, mappedCharacters); } } +void CFStringFold(CFMutableStringRef theString, CFStringCompareFlags theFlags, CFLocaleRef locale) { + CFStringInlineBuffer stringBuffer; + CFIndex length = CFStringGetLength(theString); + CFIndex currentIndex = 0; + CFIndex bufferLength = 0; + UTF32Char buffer[kCFStringStackBufferLength]; + const uint8_t *cString; + const uint8_t *langCode; + CFStringEncoding eightBitEncoding; + bool caseInsensitive = ((theFlags & kCFCompareCaseInsensitive) ? true : false); + bool isObjc = CF_IS_OBJC(__kCFStringTypeID, theString); + CFLocaleRef theLocale = locale; + + if ((theFlags & kCFCompareLocalized) && (NULL == locale)) { + theLocale = CFLocaleCopyCurrent(); + } + + theFlags &= (kCFCompareCaseInsensitive|kCFCompareDiacriticInsensitive|kCFCompareWidthInsensitive); + + if ((0 == theFlags) || (0 == length)) goto bail; // nothing to do + + langCode = ((NULL == theLocale) ? NULL : (const uint8_t *)_CFStrGetLanguageIdentifierForLocale(theLocale)); + + eightBitEncoding = __CFStringGetEightBitStringEncoding(); + cString = (const uint8_t *)CFStringGetCStringPtr(theString, eightBitEncoding); + + if ((NULL != cString) && !caseInsensitive && (kCFStringEncodingASCII == eightBitEncoding)) goto bail; // All ASCII + + CFStringInitInlineBuffer(theString, &stringBuffer, CFRangeMake(0, length)); + + if ((NULL != cString) && (theFlags & (kCFCompareCaseInsensitive|kCFCompareDiacriticInsensitive))) { + const uint8_t *cStringPtr = cString; + const uint8_t *cStringLimit = cString + length; + uint8_t *cStringContents = (isObjc ? NULL : (uint8_t *)__CFStrContents(theString) + __CFStrSkipAnyLengthByte(theString)); + + while (cStringPtr < cStringLimit) { + if ((*cStringPtr < 0x80) && (NULL == langCode)) { + if (caseInsensitive && (*cStringPtr >= 'A') && (*cStringPtr <= 'Z')) { + if (NULL == cStringContents) { + break; + } else { + cStringContents[cStringPtr - cString] += ('a' - 'A'); + } + } + } else { + if ((bufferLength = __CFStringFoldCharacterClusterAtIndex((UTF32Char)__CFCharToUniCharTable[*cStringPtr], &stringBuffer, cStringPtr - cString, theFlags, langCode, buffer, kCFStringStackBufferLength, NULL)) > 0) { + if ((*buffer > 0x7F) || (bufferLength > 1) || (NULL == cStringContents)) break; + cStringContents[cStringPtr - cString] = *buffer; + } + } + ++cStringPtr; + } + + currentIndex = cStringPtr - cString; + } + + if (currentIndex < length) { + UTF16Char *contents; + + if (isObjc) { + CFMutableStringRef cfString; + CFRange range = CFRangeMake(currentIndex, length - currentIndex); + + contents = (UTF16Char *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UTF16Char) * range.length, 0); + + CFStringGetCharacters(theString, range, contents); + + cfString = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorSystemDefault, contents, range.length, range.length, NULL); + + CFStringFold(cfString, theFlags, theLocale); + + CFStringReplace(theString, range, cfString); + + CFRelease(cfString); + } else { + const UTF32Char *characters; + const UTF32Char *charactersLimit; + UTF32Char character; + CFIndex consumedLength; + + contents = NULL; + + if (bufferLength > 0) { + __CFStringChangeSize(theString, CFRangeMake(currentIndex + 1, 0), bufferLength - 1, true); + length = __CFStrLength(theString); + CFStringInitInlineBuffer(theString, &stringBuffer, CFRangeMake(0, length)); + + contents = (UTF16Char *)__CFStrContents(theString) + currentIndex; + characters = buffer; + charactersLimit = characters + bufferLength; + while (characters < charactersLimit) *(contents++) = (UTF16Char)*(characters++); + ++currentIndex; + } + + while (currentIndex < length) { + character = __CFStringGetCharacterFromInlineBufferQuick(&stringBuffer, currentIndex); + + consumedLength = 0; + + if ((NULL == langCode) && (character < 0x80) && (0 == (theFlags & kCFCompareDiacriticInsensitive))) { + if (caseInsensitive && (character >= 'A') && (character <= 'Z')) { + consumedLength = 1; + bufferLength = 1; + *buffer = character + ('a' - 'A'); + } + } else { + if (CFUniCharIsSurrogateHighCharacter(character) && ((currentIndex + 1) < length)) { + UTF16Char lowSurrogate = __CFStringGetCharacterFromInlineBufferQuick(&stringBuffer, currentIndex + 1); + if (CFUniCharIsSurrogateLowCharacter(lowSurrogate)) character = CFUniCharGetLongCharacterForSurrogatePair(character, lowSurrogate); + } + + bufferLength = __CFStringFoldCharacterClusterAtIndex(character, &stringBuffer, currentIndex, theFlags, langCode, buffer, kCFStringStackBufferLength, &consumedLength); + } + + if (consumedLength > 0) { + CFIndex utf16Length = bufferLength; + + characters = buffer; + charactersLimit = characters + bufferLength; + + while (characters < charactersLimit) if (*(characters++) > 0xFFFF) ++utf16Length; // Extend bufferLength to the UTF-16 length + + if ((utf16Length != consumedLength) || __CFStrIsEightBit(theString)) { + CFRange range; + CFIndex insertLength; + + if (consumedLength < utf16Length) { // Need to expand + range = CFRangeMake(currentIndex + consumedLength, 0); + insertLength = utf16Length - consumedLength; + } else { + range = CFRangeMake(currentIndex + utf16Length, consumedLength - utf16Length); + insertLength = 0; + } + __CFStringChangeSize(theString, range, insertLength, true); + length = __CFStrLength(theString); + CFStringInitInlineBuffer(theString, &stringBuffer, CFRangeMake(0, length)); + } + + (void)CFUniCharFromUTF32(buffer, bufferLength, (UTF16Char *)__CFStrContents(theString) + currentIndex, true, __CF_BIG_ENDIAN__); + + currentIndex += utf16Length; + } else { + ++currentIndex; + } + } + } + } + + bail: + if (NULL == locale && theLocale) { + CFRelease(theLocale); + } +} enum { kCFStringFormatZeroFlag = (1 << 0), // if not, padding is space char @@ -4613,6 +5123,9 @@ typedef struct { union { int64_t int64Value; double doubleValue; +#if LONG_DOUBLE_SUPPORT + long double longDoubleValue; +#endif void *pointerValue; } value; } CFPrintValue; @@ -4623,9 +5136,18 @@ enum { CFFormatSize2 = 2, CFFormatSize4 = 3, CFFormatSize8 = 4, - CFFormatSize16 = 5, /* unused */ + CFFormatSize16 = 5, +#if __LP64__ + CFFormatSizeLong = CFFormatSize8, + CFFormatSizePointer = CFFormatSize8 +#else + CFFormatSizeLong = CFFormatSize4, + CFFormatSizePointer = CFFormatSize4 +#endif }; + + enum { CFFormatLiteralType = 32, CFFormatLongType = 33, @@ -4636,7 +5158,8 @@ enum { CFFormatUnicharsType = 38, /* handled specially */ CFFormatCharsType = 39, /* handled specially */ CFFormatPascalCharsType = 40, /* handled specially */ - CFFormatSingleUnicharType = 41 /* handled specially */ + CFFormatSingleUnicharType = 41, /* handled specially */ + CFFormatDummyPointerType = 42 /* special case for %n */ }; CF_INLINE void __CFParseFormatSpec(const UniChar *uformat, const uint8_t *cformat, SInt32 *fmtIdx, SInt32 fmtLen, CFFormatSpec *spec) { @@ -4675,33 +5198,49 @@ reswtch:switch (ch) { break; } } - spec->size = CFFormatSize4; + spec->size = CFFormatSizeLong; // 4 or 8 depending on LP64 break; +#if LONG_DOUBLE_SUPPORT + case 'L': + spec->size = CFFormatSize16; + break; +#endif case 'q': spec->size = CFFormatSize8; break; + case 't': case 'z': + spec->size = CFFormatSizeLong; // 4 or 8 depending on LP64 + break; + case 'j': + spec->size = CFFormatSize8; + break; case 'c': spec->type = CFFormatLongType; spec->size = CFFormatSize1; return; case 'O': case 'o': case 'D': case 'd': case 'i': case 'U': case 'u': case 'x': case 'X': spec->type = CFFormatLongType; + // Seems like if spec->size == 0, we should spec->size = CFFormatSize4. However, 0 is handled correctly. return; - case 'e': case 'E': case 'f': case 'g': case 'G': + case 'a': case 'A': case 'e': case 'E': case 'f': case 'F': case 'g': case 'G': spec->type = CFFormatDoubleType; - spec->size = CFFormatSize8; + if (spec->size != CFFormatSize16) spec->size = CFFormatSize8; return; - case 'n': case 'p': /* %n is not handled correctly currently */ + case 'n': /* %n is not handled correctly; for Leopard or newer apps, we disable it further */ + spec->type = _CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard) ? CFFormatDummyPointerType : CFFormatPointerType; + spec->size = CFFormatSizePointer; // 4 or 8 depending on LP64 + return; + case 'p': spec->type = CFFormatPointerType; - spec->size = CFFormatSize4; + spec->size = CFFormatSizePointer; // 4 or 8 depending on LP64 return; case 's': spec->type = CFFormatCharsType; - spec->size = CFFormatSize4; + spec->size = CFFormatSizePointer; // 4 or 8 depending on LP64 return; case 'S': spec->type = CFFormatUnicharsType; - spec->size = CFFormatSize4; + spec->size = CFFormatSizePointer; // 4 or 8 depending on LP64 return; case 'C': spec->type = CFFormatSingleUnicharType; @@ -4709,11 +5248,11 @@ reswtch:switch (ch) { return; case 'P': spec->type = CFFormatPascalCharsType; - spec->size = CFFormatSize4; + spec->size = CFFormatSizePointer; // 4 or 8 depending on LP64 return; case '@': spec->type = CFFormatCFType; - spec->size = CFFormatSize4; + 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; @@ -4723,11 +5262,11 @@ reswtch:switch (ch) { } while ((UInt32)(ch - '0') <= 9); if ('$' == ch) { if (-2 == spec->precArgNum) { - spec->precArgNum = number - 1; // Arg numbers start from 1 + spec->precArgNum = (int8_t)number - 1; // Arg numbers start from 1 } else if (-2 == spec->widthArgNum) { - spec->widthArgNum = number - 1; // Arg numbers start from 1 + spec->widthArgNum = (int8_t)number - 1; // Arg numbers start from 1 } else { - spec->mainArgNum = number - 1; // Arg numbers start from 1 + spec->mainArgNum = (int8_t)number - 1; // Arg numbers start from 1 } break; } else if (seenDot) { /* else it's either precision or width */ @@ -4755,17 +5294,6 @@ reswtch:switch (ch) { } } -#if defined(__WIN32__) -static int snprintf(char *b, size_t n, const char * f, ...) { - int retval; - va_list args; - va_start (args, f); - retval = _vsnprintf(b, n, f, args); - va_end(args); - return retval; -} -#endif - /* ??? It ignores the formatOptions argument. ??? %s depends on handling of encodings by __CFStringAppendBytes */ @@ -4773,6 +5301,7 @@ void CFStringAppendFormatAndArguments(CFMutableStringRef outputString, CFDiction _CFStringAppendFormatAndArgumentsAux(outputString, NULL, formatOptions, formatString, args); } +#if DEPLOYMENT_TARGET_MACOSX #define SNPRINTF(TYPE, WHAT) { \ TYPE value = (TYPE) WHAT; \ if (-1 != specs[curSpec].widthArgNum) { \ @@ -4788,8 +5317,25 @@ void CFStringAppendFormatAndArguments(CFMutableStringRef outputString, CFDiction snprintf_l(buffer, 255, NULL, formatBuffer, value); \ } \ }} +#else +#define SNPRINTF(TYPE, WHAT) { \ + TYPE value = (TYPE) WHAT; \ + if (-1 != specs[curSpec].widthArgNum) { \ + if (-1 != specs[curSpec].precArgNum) { \ + snprintf(buffer, 255, formatBuffer, width, precision, value); \ + } else { \ + snprintf(buffer, 255, formatBuffer, width, value); \ + } \ + } else { \ + if (-1 != specs[curSpec].precArgNum) { \ + snprintf(buffer, 255, formatBuffer, precision, value); \ + } else { \ + snprintf(buffer, 255, formatBuffer, value); \ + } \ + }} +#endif //__MACH__ -void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStringRef (*copyDescFunc)(void *, CFDictionaryRef), CFDictionaryRef formatOptions, CFStringRef formatString, va_list args) { +void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStringRef (*copyDescFunc)(void *, const void *), CFDictionaryRef formatOptions, CFStringRef formatString, va_list args) { SInt32 numSpecs, sizeSpecs, sizeArgNum, formatIdx, curSpec, argNum; CFIndex formatLen; #define FORMAT_BUFFER_LEN 400 @@ -4804,6 +5350,8 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr CFPrintValue localValuesBuffer[VPRINTF_BUFFER_LEN]; CFPrintValue *values; CFAllocatorRef tmpAlloc = NULL; + + intmax_t dummyLocation; // A place for %n to do its thing in; should be the widest possible int value numSpecs = 0; sizeSpecs = 0; @@ -4815,14 +5363,14 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr if (!CF_IS_OBJC(__kCFStringTypeID, formatString)) { __CFAssertIsString(formatString); if (!__CFStrIsUnicode(formatString)) { - cformat = __CFStrContents(formatString); + cformat = (const uint8_t *)__CFStrContents(formatString); if (cformat) cformat += __CFStrSkipAnyLengthByte(formatString); } else { - uformat = __CFStrContents(formatString); + uformat = (const UniChar *)__CFStrContents(formatString); } } if (!cformat && !uformat) { - formatChars = (formatLen > FORMAT_BUFFER_LEN) ? CFAllocatorAllocate(tmpAlloc = __CFGetDefaultAllocator(), formatLen * sizeof(UniChar), 0) : localFormatBuffer; + formatChars = (formatLen > FORMAT_BUFFER_LEN) ? (UniChar *)CFAllocatorAllocate(tmpAlloc = __CFGetDefaultAllocator(), formatLen * sizeof(UniChar), 0) : localFormatBuffer; if (formatChars != localFormatBuffer && __CFOASafe) __CFSetLastAllocationEventName(formatChars, "CFString (temp)"); CFStringGetCharacters(formatString, CFRangeMake(0, formatLen), formatChars); uformat = formatChars; @@ -4835,7 +5383,7 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr for (formatIdx = 0; formatIdx < formatLen; formatIdx++) if ('%' == uformat[formatIdx]) sizeSpecs++; } tmpAlloc = __CFGetDefaultAllocator(); - specs = ((2 * sizeSpecs + 1) > VPRINTF_BUFFER_LEN) ? CFAllocatorAllocate(tmpAlloc, (2 * sizeSpecs + 1) * sizeof(CFFormatSpec), 0) : localSpecsBuffer; + 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)"); /* Collect format specification information from the format string */ @@ -4876,7 +5424,7 @@ 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) ? CFAllocatorAllocate(tmpAlloc, (3 * sizeSpecs + 1) * sizeof(CFPrintValue), 0) : localValuesBuffer; + values = ((3 * sizeSpecs + 1) > VPRINTF_BUFFER_LEN) ? (CFPrintValue *)CFAllocatorAllocate(tmpAlloc, (3 * sizeSpecs + 1) * sizeof(CFPrintValue), 0) : localValuesBuffer; if (values != localValuesBuffer && __CFOASafe) __CFSetLastAllocationEventName(values, "CFString (temp)"); memset(values, 0, (3 * sizeSpecs + 1) * sizeof(CFPrintValue)); sizeArgNum = (3 * sizeSpecs + 1); @@ -4946,7 +5494,14 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr } break; case CFFormatDoubleType: - values[argNum].value.doubleValue = va_arg(args, double); +#if LONG_DOUBLE_SUPPORT + if (CFFormatSize16 == values[argNum].size) { + values[argNum].value.longDoubleValue = va_arg(args, long double); + } else +#endif + { + values[argNum].value.doubleValue = va_arg(args, double); + } break; case CFFormatPointerType: case CFFormatObjectType: @@ -4956,6 +5511,10 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr case CFFormatPascalCharsType: values[argNum].value.pointerValue = va_arg(args, void *); break; + case CFFormatDummyPointerType: + (void)va_arg(args, void *); // Skip the provided argument + values[argNum].value.pointerValue = &dummyLocation; + break; } } va_end(args); @@ -4988,15 +5547,15 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr case CFFormatLongType: case CFFormatDoubleType: case CFFormatPointerType: { - int8_t formatBuffer[128]; + char formatBuffer[128]; #if defined(__GNUC__) - int8_t buffer[256 + width + precision]; + char buffer[256 + width + precision]; #else - int8_t stackBuffer[512]; - int8_t *dynamicBuffer = NULL; - int8_t *buffer = stackBuffer; + char stackBuffer[512]; + char *dynamicBuffer = NULL; + char *buffer = stackBuffer; if (256+width+precision > 512) { - dynamicBuffer = CFAllocatorAllocate(NULL, 256+width+precision, 0); + dynamicBuffer = (char *)CFAllocatorAllocate(kCFAllocatorSystemDefault, 256+width+precision, 0); buffer = dynamicBuffer; } #endif @@ -5034,39 +5593,47 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr } break; case CFFormatPointerType: + case CFFormatDummyPointerType: SNPRINTF(void *, values[specs[curSpec].mainArgNum].value.pointerValue) break; case CFFormatDoubleType: - SNPRINTF(double, values[specs[curSpec].mainArgNum].value.doubleValue) +#if LONG_DOUBLE_SUPPORT + if (CFFormatSize16 == specs[curSpec].size) { + SNPRINTF(long double, values[specs[curSpec].mainArgNum].value.longDoubleValue) + } else +#endif + { + SNPRINTF(double, values[specs[curSpec].mainArgNum].value.doubleValue) + } // See if we need to localize the decimal point - if (formatOptions) { // We have a localization dictionary - CFStringRef decimalSeparator = CFDictionaryGetValue(formatOptions, kCFNSDecimalSeparatorKey); + if (formatOptions) { // We have localization info + CFStringRef decimalSeparator = (CFGetTypeID(formatOptions) == CFLocaleGetTypeID()) ? (CFStringRef)CFLocaleGetValue((CFLocaleRef)formatOptions, kCFLocaleDecimalSeparator) : (CFStringRef)CFDictionaryGetValue(formatOptions, CFSTR("NSDecimalSeparator")); if (decimalSeparator != NULL) { // We have a decimal separator in there CFIndex decimalPointLoc = 0; while (buffer[decimalPointLoc] != 0 && buffer[decimalPointLoc] != '.') decimalPointLoc++; if (buffer[decimalPointLoc] == '.') { // And we have a decimal point in the formatted string buffer[decimalPointLoc] = 0; - CFStringAppendCString(outputString, buffer, __CFStringGetEightBitStringEncoding()); + CFStringAppendCString(outputString, (const char *)buffer, __CFStringGetEightBitStringEncoding()); CFStringAppend(outputString, decimalSeparator); - CFStringAppendCString(outputString, buffer + decimalPointLoc + 1, __CFStringGetEightBitStringEncoding()); + CFStringAppendCString(outputString, (const char *)(buffer + decimalPointLoc + 1), __CFStringGetEightBitStringEncoding()); appended = true; } } } break; } - if (!appended) CFStringAppendCString(outputString, buffer, __CFStringGetEightBitStringEncoding()); - } + if (!appended) CFStringAppendCString(outputString, (const char *)buffer, __CFStringGetEightBitStringEncoding()); #if !defined(__GNUC__) - if (dynamicBuffer) { - CFAllocatorDeallocate(NULL, dynamicBuffer); - } -#endif + if (dynamicBuffer) { + CFAllocatorDeallocate(kCFAllocatorSystemDefault, dynamicBuffer); + } +#endif + } break; case CFFormatLiteralType: if (cformat) { - __CFStringAppendBytes(outputString, cformat+specs[curSpec].loc, specs[curSpec].len, __CFStringGetEightBitStringEncoding()); + __CFStringAppendBytes(outputString, (const char *)(cformat+specs[curSpec].loc), specs[curSpec].len, __CFStringGetEightBitStringEncoding()); } else { CFStringAppendCharacters(outputString, uformat+specs[curSpec].loc, specs[curSpec].len); } @@ -5077,7 +5644,7 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr CFStringAppendCString(outputString, "(null)", kCFStringEncodingASCII); } else { int len; - const char *str = values[specs[curSpec].mainArgNum].value.pointerValue; + 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++; @@ -5086,7 +5653,7 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr 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 = memchr(str, 0, precision); // Basically strlen() on only the first precision characters of str + 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 { @@ -5113,12 +5680,12 @@ void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStr } break; case CFFormatSingleUnicharType: - ch = values[specs[curSpec].mainArgNum].value.int64Value; + ch = (UniChar)values[specs[curSpec].mainArgNum].value.int64Value; CFStringAppendCharacters(outputString, &ch, 1); break; case CFFormatUnicharsType: //??? need to handle width, precision, and padding arguments - up = values[specs[curSpec].mainArgNum].value.pointerValue; + up = (UniChar *)values[specs[curSpec].mainArgNum].value.pointerValue; if (NULL == up) { CFStringAppendCString(outputString, "(null)", kCFStringEncodingASCII); } else { @@ -5217,3 +5784,13 @@ void CFShowStr(CFStringRef str) { +#undef HANGUL_SBASE +#undef HANGUL_LBASE +#undef HANGUL_VBASE +#undef HANGUL_TBASE +#undef HANGUL_SCOUNT +#undef HANGUL_LCOUNT +#undef HANGUL_VCOUNT +#undef HANGUL_TCOUNT +#undef HANGUL_NCOUNT + diff --git a/String.subproj/CFString.h b/CFString.h similarity index 83% rename from String.subproj/CFString.h rename to CFString.h index 2d3f7d4..7fdd126 100644 --- a/String.subproj/CFString.h +++ b/CFString.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFString.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSTRING__) @@ -35,9 +35,7 @@ #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN /* Please note: CFStrings are conceptually an array of Unicode characters. @@ -118,7 +116,7 @@ typedef UInt32 CFStringEncoding; Call CFStringGetSystemEncoding() to get the default system encoding. */ #define kCFStringEncodingInvalidId (0xffffffffU) -typedef enum { +enum { kCFStringEncodingMacRoman = 0, kCFStringEncodingWindowsLatin1 = 0x0500, /* ANSI codepage 1252 */ kCFStringEncodingISOLatin1 = 0x0201, /* ISO 8859-1 */ @@ -137,7 +135,8 @@ typedef enum { kCFStringEncodingUTF32BE = 0x18000100, /* kTextEncodingUnicodeDefault + kUnicodeUTF32BEFormat */ kCFStringEncodingUTF32LE = 0x1c000100 /* kTextEncodingUnicodeDefault + kUnicodeUTF32LEFormat */ #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 */ -} CFStringBuiltInEncodings; +}; +typedef CFStringEncoding CFStringBuiltInEncodings; /* CFString type ID */ CF_EXPORT @@ -171,16 +170,22 @@ it might not work for a user with a different language preference. /* Functions to create basic immutable strings. The provided allocator is used for all memory activity in these functions. */ -/* These functions copy the provided buffer into CFString's internal storage. */ +/* The following four functions copy the provided buffer into CFString's internal storage. */ CF_EXPORT CFStringRef CFStringCreateWithPascalString(CFAllocatorRef alloc, ConstStr255Param pStr, CFStringEncoding encoding); CF_EXPORT CFStringRef CFStringCreateWithCString(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding); +/* 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 CFStringCreateWithBytes(CFAllocatorRef alloc, const UInt8 *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean isExternalRepresentation); + CF_EXPORT CFStringRef CFStringCreateWithCharacters(CFAllocatorRef alloc, const UniChar *chars, CFIndex numChars); + /* These functions try not to copy the provided buffer. The buffer will be deallocated with the provided contentsDeallocator when it's no longer needed; to not free the buffer, specify kCFAllocatorNull here. As usual, NULL means default allocator. @@ -203,6 +208,13 @@ CFStringRef CFStringCreateWithPascalStringNoCopy(CFAllocatorRef alloc, ConstStr2 CF_EXPORT CFStringRef CFStringCreateWithCStringNoCopy(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding, CFAllocatorRef contentsDeallocator); +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 +/* 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 + CF_EXPORT CFStringRef CFStringCreateWithCharactersNoCopy(CFAllocatorRef alloc, const UniChar *chars, CFIndex numChars, CFAllocatorRef contentsDeallocator); @@ -266,7 +278,7 @@ These functions do zero-terminate or put the length byte; the provided bufferSiz space for this (so pass 256 for Str255). More sophisticated usages can go through CFStringGetBytes(). These functions are equivalent to calling CFStringGetBytes() with the range of the string; lossByte = 0; and isExternalRepresentation = false; -if successful, they then insert the leading length of terminating zero, as desired. +if successful, they then insert the leading length or terminating zero, as desired. */ CF_EXPORT Boolean CFStringGetPascalString(CFStringRef theString, StringPtr buffer, CFIndex bufferSize, CFStringEncoding encoding); @@ -303,15 +315,6 @@ const UniChar *CFStringGetCharactersPtr(CFStringRef theString); /* May retur CF_EXPORT CFIndex CFStringGetBytes(CFStringRef theString, CFRange range, CFStringEncoding encoding, UInt8 lossByte, Boolean isExternalRepresentation, UInt8 *buffer, CFIndex maxBufLen, CFIndex *usedBufLen); -/* This one goes the other way by creating a CFString from a bag of bytes. -This is much like CFStringCreateWithPascalString or CFStringCreateWithCString, -except the length is supplied explicitly. In addition, you can 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 CFStringCreateWithBytes(CFAllocatorRef alloc, const UInt8 *bytes, CFIndex numBytes, CFStringEncoding encoding, Boolean isExternalRepresentation); - /* Convenience functions String <-> Data. These generate "external" formats, that is, formats that can be written out to disk. For instance, if the encoding is Unicode, CFStringCreateFromExternalRepresentation() pays attention to the BOM character (if any) and does byte swapping if necessary. @@ -343,7 +346,7 @@ CFIndex CFStringGetMaximumSizeForEncoding(CFIndex length, CFStringEncoding encod /*** FileSystem path conversion functions ***/ -/* Extract the contents of the string as a NULL-terminated 8-bit string appropriate for passing to POSIX APIs. 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. +/* 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; @@ -364,19 +367,35 @@ CFStringRef CFStringCreateWithFileSystemRepresentation(CFAllocatorRef alloc, con /* Find and compare flags; these are OR'ed together as compareOptions or searchOptions in the various functions. This typedef doesn't appear in the functions; instead the argument is CFOptionFlags. */ -typedef enum { +enum { kCFCompareCaseInsensitive = 1, kCFCompareBackwards = 4, /* Starting from the end of the string */ kCFCompareAnchored = 8, /* Only at the specified starting point */ kCFCompareNonliteral = 16, /* If specified, loose equivalence is performed (o-umlaut == o, umlaut) */ kCFCompareLocalized = 32, /* User's default locale is used for the comparisons */ kCFCompareNumerically = 64 /* Numeric comparison is used; that is, Foo2.txt < Foo7.txt < Foo25.txt */ -} CFStringCompareFlags; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 + , + kCFCompareDiacriticInsensitive = 128, /* If specified, ignores diacritics (o-umlaut == o) */ + kCFCompareWidthInsensitive = 256, /* If specified, ignores width differences ('a' == UFF41) */ + kCFCompareForcedOrdering = 512 /* If specified, comparisons are forced to return either kCFCompareLessThan or kCFCompareGreaterThan if the strings are equivalent but not strictly equal, for stability when sorting (e.g. "aaa" > "AAA" with kCFCompareCaseInsensitive specified) */ +#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 */ +}; +typedef CFOptionFlags CFStringCompareFlags; /* The main comparison routine; compares specified range of the first string to (the full range of) the second string. - locale == NULL indicates canonical locale. - kCFCompareNumerically, added in 10.2, does not work if kCFCompareLocalized is specified on systems before 10.3 - kCFCompareBackwards and kCFCompareAnchored are not applicable. +locale == NULL indicates canonical locale (the return value from CFLocaleGetSystem()). +kCFCompareNumerically, added in 10.2, does not work if kCFCompareLocalized is specified on systems before 10.3 +kCFCompareBackwards and kCFCompareAnchored are not applicable. +*/ +#if !defined (__WIN32__) +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +CF_EXPORT +CFComparisonResult CFStringCompareWithOptionsAndLocale(CFStringRef theString1, CFStringRef theString2, CFRange rangeToCompare, CFOptionFlags compareOptions, CFLocaleRef locale) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 */ +#endif //__WIN32__ + +/* Comparison convenience. Uses the current user locale (the return value from CFLocaleCopyCurrent()) if kCFCompareLocalized. */ CF_EXPORT CFComparisonResult CFStringCompareWithOptions(CFStringRef theString1, CFStringRef theString2, CFRange rangeToCompare, CFOptionFlags compareOptions); @@ -388,9 +407,19 @@ CFComparisonResult CFStringCompareWithOptions(CFStringRef theString1, CFStringRe CF_EXPORT CFComparisonResult CFStringCompare(CFStringRef theString1, CFStringRef theString2, CFOptionFlags compareOptions); -/* CFStringFindWithOptions() returns the found range in the CFRange * argument; you can pass NULL for simple discovery check. - If stringToFind is the empty string (zero length), nothing is found. - Ignores the kCFCompareNumerically option. +/* CFStringFindWithOptionsAndLocale() returns the found range in the CFRange * argument; you can pass NULL for simple discovery check. + locale == NULL indicates canonical locale (the return value from CFLocaleGetSystem()). + If stringToFind is the empty string (zero length), nothing is found. + Ignores the kCFCompareNumerically option. +*/ +#if !defined (__WIN32__) +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +CF_EXPORT +Boolean CFStringFindWithOptionsAndLocale(CFStringRef theString, CFStringRef stringToFind, CFRange rangeToSearch, CFOptionFlags searchOptions, CFLocaleRef locale, CFRange *result) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 */ +#endif //__WIN32__ + +/* Find convenience. Uses the current user locale (the return value from CFLocaleCopyCurrent()) if kCFCompareLocalized. */ CF_EXPORT Boolean CFStringFindWithOptions(CFStringRef theString, CFStringRef stringToFind, CFRange rangeToSearch, CFOptionFlags searchOptions, CFRange *result); @@ -456,7 +485,8 @@ CF_EXPORT CFRange CFStringGetRangeOfComposedCharactersAtIndex(CFStringRef theStr is undefined. @param result The pointer to a CFRange supplied by the caller in which the search result is stored. Note that the length - of this range could be more than If a pointer to an invalid + of this range can be more than 1, if for instance the + result is a composed character. If a pointer to an invalid memory is specified, the behavior is undefined. @result true, if at least a character which is a member of the character set is found and result is filled, otherwise, false. @@ -465,17 +495,21 @@ CF_EXPORT Boolean CFStringFindCharacterFromSet(CFStringRef theString, CFCharacte #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 LS, PS). + taking into account various possible line separator sequences (CR, CRLF, LF, and Unicode NextLine, LineSeparator, ParagraphSeparator). All return values are "optional" (provide NULL if you don't want them) - lineStartIndex: index of first character in line + lineBeginIndex: index of first character in line lineEndIndex: index of first character of the next line (including terminating line separator characters) contentsEndIndex: index of the first line separator character - Thus, lineEndIndex - lineStartIndex is the number of chars in the line, including the line separators - contentsEndIndex - lineStartIndex is the number of chars in the line w/out the line separators + Thus, lineEndIndex - lineBeginIndex is the number of chars in the line, including the line separators + contentsEndIndex - lineBeginIndex is the number of chars in the line w/out the line separators */ CF_EXPORT void CFStringGetLineBounds(CFStringRef theString, CFRange range, CFIndex *lineBeginIndex, CFIndex *lineEndIndex, CFIndex *contentsEndIndex); +/* 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; /*** Exploding and joining strings with a separator string ***/ @@ -600,14 +634,16 @@ void CFStringCapitalize(CFMutableStringRef theString, const void *localeTBD); // /*! @typedef CFStringNormalizationForm This is the type of Unicode normalization forms as described in - Unicode Technical Report #15. + Unicode Technical Report #15. To normalize for use with file + system calls, use CFStringGetFileSystemRepresentation(). */ -typedef enum { +enum { kCFStringNormalizationFormD = 0, // Canonical Decomposition kCFStringNormalizationFormKD, // Compatibility Decomposition kCFStringNormalizationFormC, // Canonical Decomposition followed by Canonical Composition kCFStringNormalizationFormKC // Compatibility Decomposition followed by Canonical Composition -} CFStringNormalizationForm; +}; +typedef CFIndex CFStringNormalizationForm; /*! @function CFStringNormalize @@ -623,7 +659,38 @@ typedef enum { CF_EXPORT void CFStringNormalize(CFMutableStringRef theString, CFStringNormalizationForm theForm); #endif -/* Perform string transliteration. The transformation represented by transform (see below for the full list of transforms supported) 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. +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +/*! + @function CFStringFold + Folds the string into the form specified by the flags. + Character foldings are operations that convert any of a set of characters + sharing similar semantics into a single representative from that set. + This function can be used to preprocess strings that are to be compared, + searched, or indexed. + Note that folding does not include normalization, so it is necessary + to use CFStringNormalize in addition to CFStringFold in order to obtain + the effect of kCFCompareNonliteral. + @param theString The string which is to be folded. If this parameter is not + a valid mutable CFString, the behavior is undefined. + @param theFlag The equivalency flags which describes the character folding form. + Only those flags containing the word "insensitive" are recognized here; other flags are ignored. + Folding with kCFCompareCaseInsensitive removes case distinctions in accordance with the mapping + specified by ftp://ftp.unicode.org/Public/UNIDATA/CaseFolding.txt. Folding with + kCFCompareDiacriticInsensitive removes distinctions of accents and other diacritics. Folding + with kCFCompareWidthInsensitive removes character width distinctions by mapping characters in + the range U+FF00-U+FFEF to their ordinary equivalents. + @param theLocale The locale tailoring the character folding behavior. If NULL, + it's considered to be the system locale returned from CFLocaleGetSystem(). + If non-NULL and not a valid CFLocale object, the behavior is undefined. +*/ + +CF_EXPORT +void CFStringFold(CFMutableStringRef theString, CFOptionFlags theFlags, CFLocaleRef theLocale) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; +#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 */ + +/* 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. */ Boolean CFStringTransform(CFMutableStringRef string, CFRange *range, CFStringRef transform, Boolean reverse) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER; @@ -644,6 +711,7 @@ CF_EXPORT const CFStringRef kCFStringTransformLatinCyrillic AVAILABLE_MAC_OS_X_V 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; /*** General encoding related functionality ***/ @@ -666,10 +734,10 @@ CFStringRef CFStringGetNameOfEncoding(CFStringEncoding encoding); /* ID mapping functions from/to Cocoa NSStringEncoding. Returns kCFStringEncodingInvalidId if no mapping exists. */ CF_EXPORT -UInt32 CFStringConvertEncodingToNSStringEncoding(CFStringEncoding encoding); +unsigned long CFStringConvertEncodingToNSStringEncoding(CFStringEncoding encoding); CF_EXPORT -CFStringEncoding CFStringConvertNSStringEncodingToEncoding(UInt32 encoding); +CFStringEncoding CFStringConvertNSStringEncodingToEncoding(unsigned long encoding); /* ID mapping functions from/to Microsoft Windows codepage (covers both OEM & ANSI). Returns kCFStringEncodingInvalidId if no mapping exists. */ @@ -769,9 +837,7 @@ void CFShowStr(CFStringRef str); CF_EXPORT CFStringRef __CFStringMakeConstantString(const char *cStr); /* Private; do not use */ -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END -#endif /* !__COREFOUNDATION_CFSTRING__ */ +#endif /* ! __COREFOUNDATION_CFSTRING__ */ diff --git a/String.subproj/CFStringDefaultEncoding.h b/CFStringDefaultEncoding.h similarity index 63% rename from String.subproj/CFStringDefaultEncoding.h rename to CFStringDefaultEncoding.h index 976e06a..ad5c28a 100644 --- a/String.subproj/CFStringDefaultEncoding.h +++ b/CFStringDefaultEncoding.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,12 +21,16 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFStringDefaultEncoding.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ +#if !defined(__COREFOUNDATION_CFSTRINGDEFAULTENCODING__) +#define __COREFOUNDATION_CFSTRINGDEFAULTENCODING__ 1 + /* This file defines static inline functions used both by CarbonCore & CF. */ #include + #if defined(__MACH__) #include #include @@ -35,10 +39,9 @@ #include #include #include +#include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN #define __kCFUserEncodingEnvVariableName ("__CF_USER_TEXT_ENCODING") #define __kCFMaxDefaultEncodingFileLength (24) @@ -53,7 +56,7 @@ CF_INLINE void __CFStringGetUserDefaultEncoding(UInt32 *oScriptValue, UInt32 *oR int uid = getuid(); if ((stringValue = getenv(__kCFUserEncodingEnvVariableName)) != NULL) { - if ((uid == strtol(stringValue, &stringValue, 0)) && (':' == *stringValue)) { + if ((uid == strtol_l(stringValue, &stringValue, 0, NULL)) && (':' == *stringValue)) { ++stringValue; } else { stringValue = NULL; @@ -65,15 +68,24 @@ CF_INLINE void __CFStringGetUserDefaultEncoding(UInt32 *oScriptValue, UInt32 *oR if ((passwdp = getpwuid((uid_t)uid))) { char filename[MAXPATHLEN + 1]; - int fd; - strcpy(filename, passwdp->pw_dir); - strcat(filename, __kCFUserEncodingFileName); + const char *path = NULL; + if (!issetugid()) { + path = getenv("CFFIXED_USER_HOME"); + } + if (!path) { + path = passwdp->pw_dir; + } + + strlcpy(filename, path, sizeof(filename)); + strlcat(filename, __kCFUserEncodingFileName, sizeof(filename)); - if ((fd = open(filename, O_RDONLY, 0)) == -1) { + int no_hang_fd = open("/dev/autofs_nowait", 0); + int fd = open(filename, O_RDONLY, 0); + if (fd == -1) { // Cannot open the file. Let's fallback to smRoman/verUS - snprintf(filename, sizeof(filename), "%s=0x%X:0:0", __kCFUserEncodingEnvVariableName, uid); - putenv(filename); + snprintf(filename, sizeof(filename), "0x%X:0:0", uid); + setenv(__kCFUserEncodingEnvVariableName, filename, 1); } else { int readSize; @@ -86,16 +98,17 @@ CF_INLINE void __CFStringGetUserDefaultEncoding(UInt32 *oScriptValue, UInt32 *oR stringValue = buffer; // Well, we already have a buffer, let's reuse it - snprintf(filename, sizeof(filename), "%s=0x%X:%s", __kCFUserEncodingEnvVariableName, uid, buffer); - putenv(filename); + snprintf(filename, sizeof(filename), "0x%X:%s", uid, buffer); + setenv(__kCFUserEncodingEnvVariableName, filename, 1); } + close(no_hang_fd); } } if (stringValue) { - *oScriptValue = strtol(stringValue, &stringValue, 0); + *oScriptValue = strtol_l(stringValue, &stringValue, 0, NULL); if (*stringValue == ':') { - if (oRegionValue) *oRegionValue = strtol(++stringValue, NULL, 0); + if (oRegionValue) *oRegionValue = strtol_l(++stringValue, NULL, 0, NULL); return; } } @@ -112,12 +125,21 @@ CF_INLINE uint32_t __CFStringGetInstallationRegion() { if ((passwdp = getpwuid((uid_t)0))) { char filename[MAXPATHLEN + 1]; - int fd; - strcpy(filename, passwdp->pw_dir); - strcat(filename, __kCFUserEncodingFileName); + const char *path = NULL; + if (!issetugid()) { + path = getenv("CFFIXED_USER_HOME"); + } + if (!path) { + path = passwdp->pw_dir; + } + + strlcpy(filename, path, sizeof(filename)); + strlcat(filename, __kCFUserEncodingFileName, sizeof(filename)); - if ((fd = open(filename, O_RDONLY, 0)) != -1) { + int no_hang_fd = open("/dev/autofs_nowait", 0); + int fd = open(filename, O_RDONLY, 0); + if (fd == -1) { int readSize; // cjk: We do not turn on F_NOCACHE on the fd here, because @@ -128,11 +150,12 @@ CF_INLINE uint32_t __CFStringGetInstallationRegion() { close(fd); stringValue = buffer; } + close(no_hang_fd); } if (stringValue) { - (void)strtol(stringValue, &stringValue, 0); - if (*stringValue == ':') return strtol(++stringValue, NULL, 0); + (void)strtol_l(stringValue, &stringValue, 0, NULL); + if (*stringValue == ':') return strtol_l(++stringValue, NULL, 0, NULL); } return 0; // verUS @@ -147,27 +170,34 @@ CF_INLINE void __CFStringGetInstallationEncodingAndRegion(uint32_t *encoding, ui if ((passwdp = getpwuid((uid_t)0))) { char filename[MAXPATHLEN + 1]; - int fd; - - strcpy(filename, passwdp->pw_dir); - strcat(filename, __kCFUserEncodingFileName); + + const char *path = NULL; + if (!issetugid()) { + path = getenv("CFFIXED_USER_HOME"); + } + if (!path) { + path = passwdp->pw_dir; + } + + strlcpy(filename, path, sizeof(filename)); + strlcat(filename, __kCFUserEncodingFileName, sizeof(filename)); - if ((fd = open(filename, O_RDONLY, 0)) != -1) { + int no_hang_fd = open("/dev/autofs_nowait", 0); + int fd = open(filename, O_RDONLY, 0); + if (fd == -1) { int readSize; - // cjk: We do not turn on F_NOCACHE on the fd here, because - // many processes read this file on startup, and caching the - // is probably a good thing, for the system as a whole. readSize = read(fd, buffer, __kCFMaxDefaultEncodingFileLength - 1); buffer[(readSize < 0 ? 0 : readSize)] = '\0'; close(fd); stringValue = buffer; } + close(no_hang_fd); } if (stringValue) { - *encoding = strtol(stringValue, &stringValue, 0); - if (*stringValue == ':') *region = strtol(++stringValue, NULL, 0); + *encoding = strtol_l(stringValue, &stringValue, 0, NULL); + if (*stringValue == ':') *region = strtol_l(++stringValue, NULL, 0, NULL); } } @@ -176,15 +206,22 @@ CF_INLINE void __CFStringSaveUserDefaultEncoding(UInt32 iScriptValue, UInt32 iRe if ((passwdp = getpwuid(getuid()))) { char filename[MAXPATHLEN + 1]; - int fd; - - strcpy(filename, passwdp->pw_dir); - strcat(filename, __kCFUserEncodingFileName); - - // In case, file exists - (void)unlink(filename); - if ((fd = open(filename, O_WRONLY|O_CREAT, 0400)) != -1) { + const char *path = NULL; + if (!issetugid()) { + path = getenv("CFFIXED_USER_HOME"); + } + if (!path) { + path = passwdp->pw_dir; + } + + strlcpy(filename, path, sizeof(filename)); + strlcat(filename, __kCFUserEncodingFileName, sizeof(filename)); + + int no_hang_fd = open("/dev/autofs_nowait", 0); + (void)unlink(filename); // In case, file exists + int fd = open(filename, O_WRONLY|O_CREAT, 0400); + if (fd == -1) { char buffer[__kCFMaxDefaultEncodingFileLength]; unsigned int writeSize; @@ -192,11 +229,13 @@ CF_INLINE void __CFStringSaveUserDefaultEncoding(UInt32 iScriptValue, UInt32 iRe (void)write(fd, buffer, (writeSize > __kCFMaxDefaultEncodingFileLength ? __kCFMaxDefaultEncodingFileLength : writeSize)); close(fd); } + close(no_hang_fd); } } -#if defined(__cplusplus) -} +CF_EXTERN_C_END + #endif -#endif /* __MACH__ */ +#endif /* ! __COREFOUNDATION_CFSTRINGDEFAULTENCODING__ */ + diff --git a/StringEncodings.subproj/CFStringEncodingConverter.c b/CFStringEncodingConverter.c similarity index 82% rename from StringEncodings.subproj/CFStringEncodingConverter.c rename to CFStringEncodingConverter.c index 00a41cd..3e92768 100644 --- a/StringEncodings.subproj/CFStringEncodingConverter.c +++ b/CFStringEncodingConverter.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -29,18 +29,14 @@ #include #include #include "CFUniChar.h" -#include "CFUtilitiesPriv.h" +#include "CFPriv.h" #include "CFUnicodeDecomposition.h" #include "CFStringEncodingConverterExt.h" #include "CFStringEncodingConverterPriv.h" #include -#if !defined(__MACOS8__) -#ifdef __WIN32__ -#include -#else // Mach, HP-UX, Solaris +#if !defined(__WIN32__) #include #endif -#endif __MACOS8__ /* Macros @@ -48,8 +44,6 @@ #define TO_BYTE(conv,flags,chars,numChars,bytes,max,used) (conv->_toBytes ? conv->toBytes(conv,flags,chars,numChars,bytes,max,used) : ((CFStringEncodingToBytesProc)conv->toBytes)(flags,chars,numChars,bytes,max,used)) #define TO_UNICODE(conv,flags,bytes,numBytes,chars,max,used) (conv->_toUnicode ? (flags & (kCFStringEncodingUseCanonical|kCFStringEncodingUseHFSPlusCanonical) ? conv->toCanonicalUnicode(conv,flags,bytes,numBytes,chars,max,used) : conv->toUnicode(conv,flags,bytes,numBytes,chars,max,used)) : ((CFStringEncodingToUnicodeProc)conv->toUnicode)(flags,bytes,numBytes,chars,max,used)) -#define LineSeparator 0x2028 -#define ParagraphSeparator 0x2029 #define ASCIINewLine 0x0a #define kSurrogateHighStart 0xD800 #define kSurrogateHighEnd 0xDBFF @@ -159,10 +153,10 @@ static const struct { {{'y', 0, 0, 0}}, // LATIN SMALL LETTER Y WITH DIAERESIS }; -CF_INLINE UInt32 __CFToASCIILatin1Fallback(UniChar character, UInt8 *bytes, UInt32 maxByteLen) { - const char *losChars = (const unsigned char*)_toLossyASCIITable + (character - 0xA0) * sizeof(unsigned char[4]); - unsigned int numBytes = 0; - int idx, max = (maxByteLen && (maxByteLen < 4) ? maxByteLen : 4); +CF_INLINE CFIndex __CFToASCIILatin1Fallback(UniChar character, uint8_t *bytes, CFIndex maxByteLen) { + const uint8_t *losChars = (const uint8_t*)_toLossyASCIITable + (character - 0xA0) * sizeof(uint8_t[4]); + CFIndex numBytes = 0; + CFIndex idx, max = (maxByteLen && (maxByteLen < 4) ? maxByteLen : 4); for (idx = 0;idx < max;idx++) { if (losChars[idx]) { @@ -176,50 +170,48 @@ CF_INLINE UInt32 __CFToASCIILatin1Fallback(UniChar character, UInt8 *bytes, UInt return numBytes; } -static UInt32 __CFDefaultToBytesFallbackProc(const UniChar *characters, UInt32 numChars, uint8_t *bytes, UInt32 maxByteLen, UInt32 *usedByteLen) { +static CFIndex __CFDefaultToBytesFallbackProc(const UniChar *characters, CFIndex numChars, uint8_t *bytes, CFIndex maxByteLen, CFIndex *usedByteLen) { + CFIndex processCharLen = 1, filledBytesLen = 1; + uint8_t byte = '?'; + if (*characters < 0xA0) { // 0x80 to 0x9F maps to ASCII C0 range - if (maxByteLen) *bytes = (UInt8)(*characters - 0x80); - *usedByteLen = 1; - return 1; + byte = (uint8_t)(*characters - 0x80); } else if (*characters < 0x100) { *usedByteLen = __CFToASCIILatin1Fallback(*characters, bytes, maxByteLen); return 1; } else if (*characters >= kSurrogateHighStart && *characters <= kSurrogateLowEnd) { - if (maxByteLen) *bytes = '?'; - *usedByteLen = 1; - return (numChars > 1 && *characters <= kSurrogateLowStart && *(characters + 1) >= kSurrogateLowStart && *(characters + 1) <= kSurrogateLowEnd ? 2 : 1); + processCharLen = (numChars > 1 && *characters <= kSurrogateLowStart && *(characters + 1) >= kSurrogateLowStart && *(characters + 1) <= kSurrogateLowEnd ? 2 : 1); } else if (CFUniCharIsMemberOf(*characters, kCFUniCharWhitespaceCharacterSet)) { - if (maxByteLen) *bytes = ' '; - *usedByteLen = 1; - return 1; + byte = ' '; } else if (CFUniCharIsMemberOf(*characters, kCFUniCharWhitespaceAndNewlineCharacterSet)) { - if (maxByteLen) *bytes = ASCIINewLine; - *usedByteLen = 1; - return 1; - } else if (!CFUniCharIsMemberOf(*characters, kCFUniCharLetterCharacterSet)) { - *usedByteLen = 0; - return 1; + byte = ASCIINewLine; + } else if (*characters == 0x2026) { // ellipsis + if (0 == maxByteLen) { + filledBytesLen = 3; + } else if (maxByteLen > 2) { + memset(bytes, '.', 3); + *usedByteLen = 3; + return processCharLen; + } } else if (CFUniCharIsMemberOf(*characters, kCFUniCharDecomposableCharacterSet)) { UTF32Char decomposed[MAX_DECOMPOSED_LENGTH]; (void)CFUniCharDecomposeCharacter(*characters, decomposed, MAX_DECOMPOSED_LENGTH); if (*decomposed < 0x80) { - if (maxByteLen) *bytes = (UInt8)(*decomposed); - *usedByteLen = 1; - return 1; + byte = (uint8_t)(*decomposed); } else { UTF16Char theChar = *decomposed; return __CFDefaultToBytesFallbackProc(&theChar, 1, bytes, maxByteLen, usedByteLen); } - } else { - if (maxByteLen) *bytes = '?'; - *usedByteLen = 1; - return 1; } + + if (maxByteLen) *bytes = byte; + *usedByteLen = filledBytesLen; + return processCharLen; } -static UInt32 __CFDefaultToUnicodeFallbackProc(const uint8_t *bytes, UInt32 numBytes, UniChar *characters, UInt32 maxCharLen, UInt32 *usedCharLen) { +static CFIndex __CFDefaultToUnicodeFallbackProc(const uint8_t *bytes, CFIndex numBytes, UniChar *characters, CFIndex maxCharLen, CFIndex *usedCharLen) { if (maxCharLen) *characters = (UniChar)'?'; *usedCharLen = 1; return 1; @@ -232,9 +224,9 @@ static UInt32 __CFDefaultToUnicodeFallbackProc(const uint8_t *bytes, UInt32 numB /* Wrapper funcs for non-standard converters */ -static UInt32 __CFToBytesCheapEightBitWrapper(const void *converter, UInt32 flags, const UniChar *characters, UInt32 numChars, uint8_t *bytes, UInt32 maxByteLen, UInt32 *usedByteLen) { - UInt32 processedCharLen = 0; - UInt32 length = (maxByteLen && (maxByteLen < numChars) ? maxByteLen : numChars); +static CFIndex __CFToBytesCheapEightBitWrapper(const void *converter, uint32_t flags, const UniChar *characters, CFIndex numChars, uint8_t *bytes, CFIndex maxByteLen, CFIndex *usedByteLen) { + CFIndex processedCharLen = 0; + CFIndex length = (maxByteLen && (maxByteLen < numChars) ? maxByteLen : numChars); uint8_t byte; while (processedCharLen < length) { @@ -248,9 +240,9 @@ static UInt32 __CFToBytesCheapEightBitWrapper(const void *converter, UInt32 flag return processedCharLen; } -static UInt32 __CFToUnicodeCheapEightBitWrapper(const void *converter, UInt32 flags, const uint8_t *bytes, UInt32 numBytes, UniChar *characters, UInt32 maxCharLen, UInt32 *usedCharLen) { - UInt32 processedByteLen = 0; - UInt32 length = (maxCharLen && (maxCharLen < numBytes) ? maxCharLen : numBytes); +static CFIndex __CFToUnicodeCheapEightBitWrapper(const void *converter, uint32_t flags, const uint8_t *bytes, CFIndex numBytes, UniChar *characters, CFIndex maxCharLen, CFIndex *usedCharLen) { + CFIndex processedByteLen = 0; + CFIndex length = (maxCharLen && (maxCharLen < numBytes) ? maxCharLen : numBytes); UniChar character; while (processedByteLen < length) { @@ -264,11 +256,11 @@ static UInt32 __CFToUnicodeCheapEightBitWrapper(const void *converter, UInt32 fl return processedByteLen; } -static UInt32 __CFToCanonicalUnicodeCheapEightBitWrapper(const void *converter, UInt32 flags, const uint8_t *bytes, UInt32 numBytes, UniChar *characters, UInt32 maxCharLen, UInt32 *usedCharLen) { - UInt32 processedByteLen = 0; - UInt32 theUsedCharLen = 0; +static CFIndex __CFToCanonicalUnicodeCheapEightBitWrapper(const void *converter, uint32_t flags, const uint8_t *bytes, CFIndex numBytes, UniChar *characters, CFIndex maxCharLen, CFIndex *usedCharLen) { + CFIndex processedByteLen = 0; + CFIndex theUsedCharLen = 0; UTF32Char charBuffer[MAX_DECOMPOSED_LENGTH]; - UInt32 usedLen; + CFIndex usedLen; UniChar character; bool isHFSPlus = (flags & kCFStringEncodingUseHFSPlusCanonical ? true : false); @@ -276,7 +268,7 @@ static UInt32 __CFToCanonicalUnicodeCheapEightBitWrapper(const void *converter, if (!((CFStringEncodingCheapEightBitToUnicodeProc)((const _CFEncodingConverter*)converter)->_toUnicode)(flags, bytes[processedByteLen], &character)) break; if (CFUniCharIsDecomposableCharacter(character, isHFSPlus)) { - uint32_t idx; + CFIndex idx; usedLen = CFUniCharDecomposeCharacter(character, charBuffer, MAX_DECOMPOSED_LENGTH); *usedCharLen = theUsedCharLen; @@ -287,8 +279,8 @@ static UInt32 __CFToCanonicalUnicodeCheapEightBitWrapper(const void *converter, theUsedCharLen += 2; if (maxCharLen) { charBuffer[idx] = charBuffer[idx] - 0x10000; - *(characters++) = (charBuffer[idx] >> 10) + 0xD800UL; - *(characters++) = (charBuffer[idx] & 0x3FF) + 0xDC00UL; + *(characters++) = (UniChar)(charBuffer[idx] >> 10) + 0xD800UL; + *(characters++) = (UniChar)(charBuffer[idx] & 0x3FF) + 0xDC00UL; } } else { if (theUsedCharLen + 1 > maxCharLen) return processedByteLen; @@ -307,10 +299,10 @@ static UInt32 __CFToCanonicalUnicodeCheapEightBitWrapper(const void *converter, return processedByteLen; } -static UInt32 __CFToBytesStandardEightBitWrapper(const void *converter, UInt32 flags, const UniChar *characters, UInt32 numChars, uint8_t *bytes, UInt32 maxByteLen, UInt32 *usedByteLen) { - UInt32 processedCharLen = 0; +static CFIndex __CFToBytesStandardEightBitWrapper(const void *converter, uint32_t flags, const UniChar *characters, CFIndex numChars, uint8_t *bytes, CFIndex maxByteLen, CFIndex *usedByteLen) { + CFIndex processedCharLen = 0; uint8_t byte; - UInt32 usedLen; + CFIndex usedLen; *usedByteLen = 0; @@ -327,14 +319,14 @@ static UInt32 __CFToBytesStandardEightBitWrapper(const void *converter, UInt32 f return processedCharLen; } -static UInt32 __CFToUnicodeStandardEightBitWrapper(const void *converter, UInt32 flags, const uint8_t *bytes, UInt32 numBytes, UniChar *characters, UInt32 maxCharLen, UInt32 *usedCharLen) { - UInt32 processedByteLen = 0; -#if defined(__MACOS8__) || defined(__WIN32__) +static CFIndex __CFToUnicodeStandardEightBitWrapper(const void *converter, uint32_t flags, const uint8_t *bytes, CFIndex numBytes, UniChar *characters, CFIndex maxCharLen, CFIndex *usedCharLen) { + CFIndex processedByteLen = 0; +#if 0 || 0 UniChar charBuffer[20]; // Dynamic stack allocation is GNU specific #else UniChar charBuffer[((const _CFEncodingConverter*)converter)->maxLen]; #endif - UInt32 usedLen; + CFIndex usedLen; *usedCharLen = 0; @@ -342,7 +334,7 @@ static UInt32 __CFToUnicodeStandardEightBitWrapper(const void *converter, UInt32 if (!(usedLen = ((CFStringEncodingCheapEightBitToUnicodeProc)((const _CFEncodingConverter*)converter)->_toUnicode)(flags, bytes[processedByteLen], charBuffer))) break; if (maxCharLen) { - uint16_t idx; + CFIndex idx; if (*usedCharLen + usedLen > maxCharLen) break; @@ -357,19 +349,19 @@ static UInt32 __CFToUnicodeStandardEightBitWrapper(const void *converter, UInt32 return processedByteLen; } -static UInt32 __CFToCanonicalUnicodeStandardEightBitWrapper(const void *converter, UInt32 flags, const uint8_t *bytes, UInt32 numBytes, UniChar *characters, UInt32 maxCharLen, UInt32 *usedCharLen) { - UInt32 processedByteLen = 0; -#if defined(__MACOS8__) || defined(__WIN32__) +static CFIndex __CFToCanonicalUnicodeStandardEightBitWrapper(const void *converter, uint32_t flags, const uint8_t *bytes, CFIndex numBytes, UniChar *characters, CFIndex maxCharLen, CFIndex *usedCharLen) { + CFIndex processedByteLen = 0; +#if 0 || 0 UniChar charBuffer[20]; // Dynamic stack allocation is GNU specific #else UniChar charBuffer[((const _CFEncodingConverter*)converter)->maxLen]; #endif UTF32Char decompBuffer[MAX_DECOMPOSED_LENGTH]; - UInt32 usedLen; - UInt32 decompedLen; - UInt32 idx, decompIndex; + CFIndex usedLen; + CFIndex decompedLen; + CFIndex idx, decompIndex; bool isHFSPlus = (flags & kCFStringEncodingUseHFSPlusCanonical ? true : false); - UInt32 theUsedCharLen = 0; + CFIndex theUsedCharLen = 0; while ((processedByteLen < numBytes) && (!maxCharLen || (theUsedCharLen < maxCharLen))) { if (!(usedLen = ((CFStringEncodingCheapEightBitToUnicodeProc)((const _CFEncodingConverter*)converter)->_toUnicode)(flags, bytes[processedByteLen], charBuffer))) break; @@ -406,14 +398,14 @@ static UInt32 __CFToCanonicalUnicodeStandardEightBitWrapper(const void *converte return processedByteLen; } -static UInt32 __CFToBytesCheapMultiByteWrapper(const void *converter, UInt32 flags, const UniChar *characters, UInt32 numChars, uint8_t *bytes, UInt32 maxByteLen, UInt32 *usedByteLen) { - UInt32 processedCharLen = 0; -#if defined(__MACOS8__) || defined(__WIN32__) +static CFIndex __CFToBytesCheapMultiByteWrapper(const void *converter, uint32_t flags, const UniChar *characters, CFIndex numChars, uint8_t *bytes, CFIndex maxByteLen, CFIndex *usedByteLen) { + CFIndex processedCharLen = 0; +#if 0 || 0 uint8_t byteBuffer[20]; // Dynamic stack allocation is GNU specific #else uint8_t byteBuffer[((const _CFEncodingConverter*)converter)->maxLen]; #endif - UInt32 usedLen; + CFIndex usedLen; *usedByteLen = 0; @@ -421,7 +413,7 @@ static UInt32 __CFToBytesCheapMultiByteWrapper(const void *converter, UInt32 fla if (!(usedLen = ((CFStringEncodingCheapMultiByteToBytesProc)((const _CFEncodingConverter*)converter)->_toBytes)(flags, characters[processedCharLen], byteBuffer))) break; if (maxByteLen) { - uint16_t idx; + CFIndex idx; if (*usedByteLen + usedLen > maxByteLen) break; @@ -437,10 +429,10 @@ static UInt32 __CFToBytesCheapMultiByteWrapper(const void *converter, UInt32 fla return processedCharLen; } -static UInt32 __CFToUnicodeCheapMultiByteWrapper(const void *converter, UInt32 flags, const uint8_t *bytes, UInt32 numBytes, UniChar *characters, UInt32 maxCharLen, UInt32 *usedCharLen) { - UInt32 processedByteLen = 0; +static CFIndex __CFToUnicodeCheapMultiByteWrapper(const void *converter, uint32_t flags, const uint8_t *bytes, CFIndex numBytes, UniChar *characters, CFIndex maxCharLen, CFIndex *usedCharLen) { + CFIndex processedByteLen = 0; UniChar character; - UInt32 usedLen; + CFIndex usedLen; *usedCharLen = 0; @@ -457,20 +449,20 @@ static UInt32 __CFToUnicodeCheapMultiByteWrapper(const void *converter, UInt32 f return processedByteLen; } -static UInt32 __CFToCanonicalUnicodeCheapMultiByteWrapper(const void *converter, UInt32 flags, const uint8_t *bytes, UInt32 numBytes, UniChar *characters, UInt32 maxCharLen, UInt32 *usedCharLen) { - UInt32 processedByteLen = 0; +static CFIndex __CFToCanonicalUnicodeCheapMultiByteWrapper(const void *converter, uint32_t flags, const uint8_t *bytes, CFIndex numBytes, UniChar *characters, CFIndex maxCharLen, CFIndex *usedCharLen) { + CFIndex processedByteLen = 0; UTF32Char charBuffer[MAX_DECOMPOSED_LENGTH]; UniChar character; - UInt32 usedLen; - UInt32 decomposedLen; - UInt32 theUsedCharLen = 0; + CFIndex usedLen; + CFIndex decomposedLen; + CFIndex theUsedCharLen = 0; bool isHFSPlus = (flags & kCFStringEncodingUseHFSPlusCanonical ? true : false); while (numBytes && (!maxCharLen || (theUsedCharLen < maxCharLen))) { if (!(usedLen = ((CFStringEncodingCheapMultiByteToUnicodeProc)((const _CFEncodingConverter*)converter)->_toUnicode)(flags, bytes, numBytes, &character))) break; if (CFUniCharIsDecomposableCharacter(character, isHFSPlus)) { - uint32_t idx; + CFIndex idx; decomposedLen = CFUniCharDecomposeCharacter(character, charBuffer, MAX_DECOMPOSED_LENGTH); *usedCharLen = theUsedCharLen; @@ -481,8 +473,8 @@ static UInt32 __CFToCanonicalUnicodeCheapMultiByteWrapper(const void *converter, theUsedCharLen += 2; if (maxCharLen) { charBuffer[idx] = charBuffer[idx] - 0x10000; - *(characters++) = (charBuffer[idx] >> 10) + 0xD800UL; - *(characters++) = (charBuffer[idx] & 0x3FF) + 0xDC00UL; + *(characters++) = (UniChar)(charBuffer[idx] >> 10) + 0xD800UL; + *(characters++) = (UniChar)(charBuffer[idx] & 0x3FF) + 0xDC00UL; } } else { if (theUsedCharLen + 1 > maxCharLen) return processedByteLen; @@ -541,7 +533,7 @@ static _CFConverterEntry __CFConverterEntryUTF8 = { kCFStringEncodingUnicode // We use string encoding's script range here }; -CF_INLINE _CFConverterEntry *__CFStringEncodingConverterGetEntry(UInt32 encoding) { +CF_INLINE _CFConverterEntry *__CFStringEncodingConverterGetEntry(uint32_t encoding) { switch (encoding) { case kCFStringEncodingInvalidId: case kCFStringEncodingASCII: @@ -570,9 +562,9 @@ CF_INLINE _CFConverterEntry *__CFStringEncodingConverterGetEntry(UInt32 encoding CF_INLINE _CFEncodingConverter *__CFEncodingConverterFromDefinition(const CFStringEncodingConverter *definition) { #define NUM_OF_ENTRIES_CYCLE (10) - static CFSpinLock_t _indexLock = 0; - static UInt32 _currentIndex = 0; - static UInt32 _allocatedSize = 0; + static CFSpinLock_t _indexLock = CFSpinLockInit; + static uint32_t _currentIndex = 0; + static uint32_t _allocatedSize = 0; static _CFEncodingConverter *_allocatedEntries = NULL; _CFEncodingConverter *converter; @@ -584,7 +576,7 @@ CF_INLINE _CFEncodingConverter *__CFEncodingConverterFromDefinition(const CFStri _allocatedEntries = NULL; } if (_allocatedEntries == NULL) { // Not allocated yet - _allocatedEntries = (_CFEncodingConverter *)CFAllocatorAllocate(NULL, sizeof(_CFEncodingConverter) * NUM_OF_ENTRIES_CYCLE, 0); + _allocatedEntries = (_CFEncodingConverter *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(_CFEncodingConverter) * NUM_OF_ENTRIES_CYCLE, 0); _allocatedSize = NUM_OF_ENTRIES_CYCLE; converter = &(_allocatedEntries[_currentIndex]); } else { @@ -594,9 +586,9 @@ CF_INLINE _CFEncodingConverter *__CFEncodingConverterFromDefinition(const CFStri switch (definition->encodingClass) { case kCFStringEncodingConverterStandard: - converter->toBytes = definition->toBytes; - converter->toUnicode = definition->toUnicode; - converter->toCanonicalUnicode = definition->toUnicode; + converter->toBytes = (_CFToBytesProc)definition->toBytes; + converter->toUnicode = (_CFToUnicodeProc)definition->toUnicode; + converter->toCanonicalUnicode = (_CFToUnicodeProc)definition->toUnicode; converter->_toBytes = NULL; converter->_toUnicode = NULL; converter->maxLen = 2; @@ -648,8 +640,8 @@ CF_INLINE _CFEncodingConverter *__CFEncodingConverterFromDefinition(const CFStri return NULL; } - converter->toBytesLen = (definition->toBytesLen ? definition->toBytesLen : (CFStringEncodingToBytesLenProc)(UInt32)definition->maxBytesPerChar); - converter->toUnicodeLen = (definition->toUnicodeLen ? definition->toUnicodeLen : (CFStringEncodingToUnicodeLenProc)(UInt32)definition->maxDecomposedCharLen); + converter->toBytesLen = (definition->toBytesLen ? definition->toBytesLen : (CFStringEncodingToBytesLenProc)(uintptr_t)definition->maxBytesPerChar); + converter->toUnicodeLen = (definition->toUnicodeLen ? definition->toUnicodeLen : (CFStringEncodingToUnicodeLenProc)(uintptr_t)definition->maxDecomposedCharLen); converter->toBytesFallback = (definition->toBytesFallback ? definition->toBytesFallback : __CFDefaultToBytesFallbackProc); converter->toUnicodeFallback = (definition->toUnicodeFallback ? definition->toUnicodeFallback : __CFDefaultToUnicodeFallbackProc); converter->toBytesPrecompose = (definition->toBytesPrecompose ? definition->toBytesPrecompose : NULL); @@ -681,11 +673,11 @@ CF_INLINE const CFStringEncodingConverter *__CFStringEncodingConverterGetDefinit return &__CFConverterUTF8; default: - return NULL; + return NULL; } } -static const _CFEncodingConverter *__CFGetConverter(UInt32 encoding) { +static const _CFEncodingConverter *__CFGetConverter(uint32_t encoding) { _CFConverterEntry *entry = __CFStringEncodingConverterGetEntry(encoding); if (!entry) return NULL; @@ -705,11 +697,11 @@ static const _CFEncodingConverter *__CFGetConverter(UInt32 encoding) { /* Public API */ -UInt32 CFStringEncodingUnicodeToBytes(UInt32 encoding, UInt32 flags, const UniChar *characters, UInt32 numChars, UInt32 *usedCharLen, uint8_t *bytes, UInt32 maxByteLen, UInt32 *usedByteLen) { +uint32_t CFStringEncodingUnicodeToBytes(uint32_t encoding, uint32_t flags, const UniChar *characters, CFIndex numChars, CFIndex *usedCharLen, uint8_t *bytes, CFIndex maxByteLen, CFIndex *usedByteLen) { if (encoding == kCFStringEncodingUTF8) { static CFStringEncodingToBytesProc __CFToUTF8 = NULL; - uint32_t convertedCharLen; - uint32_t usedLen; + CFIndex convertedCharLen; + CFIndex usedLen; if ((flags & kCFStringEncodingUseCanonical) || (flags & kCFStringEncodingUseHFSPlusCanonical)) { @@ -719,7 +711,7 @@ UInt32 CFStringEncodingUnicodeToBytes(UInt32 encoding, UInt32 flags, const UniCh const CFStringEncodingConverter *utf8Converter = CFStringEncodingGetConverter(kCFStringEncodingUTF8); __CFToUTF8 = (CFStringEncodingToBytesProc)utf8Converter->toBytes; } - convertedCharLen = __CFToUTF8(0, characters, numChars, bytes, maxByteLen, (UInt32 *)&usedLen); + convertedCharLen = __CFToUTF8(0, characters, numChars, bytes, maxByteLen, &usedLen); } if (usedCharLen) *usedCharLen = convertedCharLen; if (usedByteLen) *usedByteLen = usedLen; @@ -733,10 +725,10 @@ UInt32 CFStringEncodingUnicodeToBytes(UInt32 encoding, UInt32 flags, const UniCh } } else { const _CFEncodingConverter *converter = __CFGetConverter(encoding); - UInt32 usedLen = 0; - UInt32 localUsedByteLen; - UInt32 theUsedByteLen = 0; - UInt32 theResult = kCFStringEncodingConversionSuccess; + CFIndex usedLen = 0; + CFIndex localUsedByteLen; + CFIndex theUsedByteLen = 0; + uint32_t theResult = kCFStringEncodingConversionSuccess; CFStringEncodingToBytesPrecomposeProc toBytesPrecompose = NULL; CFStringEncodingIsValidCombiningCharacterProc isValidCombiningChar = NULL; @@ -755,11 +747,11 @@ UInt32 CFStringEncodingUnicodeToBytes(UInt32 encoding, UInt32 flags, const UniCh while ((usedLen < numChars) && (!maxByteLen || (theUsedByteLen < maxByteLen))) { if ((usedLen += TO_BYTE(converter, flags, characters + usedLen, numChars - usedLen, bytes + theUsedByteLen, (maxByteLen ? maxByteLen - theUsedByteLen : 0), &localUsedByteLen)) < numChars) { - UInt32 dummy; + CFIndex dummy; if (isValidCombiningChar && (usedLen > 0) && isValidCombiningChar(characters[usedLen])) { if (toBytesPrecompose) { - UInt32 localUsedLen = usedLen; + CFIndex localUsedLen = usedLen; while (isValidCombiningChar(characters[--usedLen])); theUsedByteLen += localUsedByteLen; @@ -813,7 +805,7 @@ UInt32 CFStringEncodingUnicodeToBytes(UInt32 encoding, UInt32 flags, const UniCh theUsedByteLen += localUsedByteLen; if (flags & kCFStringEncodingAllowLossyConversion && !CFStringEncodingMaskToLossyByte(flags)) { - UInt32 localUsedLen; + CFIndex localUsedLen; localUsedByteLen = 0; while ((usedLen < numChars) && !localUsedByteLen && (localUsedLen = TO_BYTE_FALLBACK(converter, characters + usedLen, numChars - usedLen, NULL, 0, &localUsedByteLen))) usedLen += localUsedLen; @@ -842,7 +834,7 @@ UInt32 CFStringEncodingUnicodeToBytes(UInt32 encoding, UInt32 flags, const UniCh if (usedLen < numChars && maxByteLen && theResult == kCFStringEncodingConversionSuccess) { if (flags & kCFStringEncodingAllowLossyConversion && !CFStringEncodingMaskToLossyByte(flags)) { - UInt32 localUsedLen; + CFIndex localUsedLen; localUsedByteLen = 0; while ((usedLen < numChars) && !localUsedByteLen && (localUsedLen = TO_BYTE_FALLBACK(converter, characters + usedLen, numChars - usedLen, NULL, 0, &localUsedByteLen))) usedLen += localUsedLen; @@ -856,21 +848,21 @@ UInt32 CFStringEncodingUnicodeToBytes(UInt32 encoding, UInt32 flags, const UniCh } } -UInt32 CFStringEncodingBytesToUnicode(UInt32 encoding, UInt32 flags, const uint8_t *bytes, UInt32 numBytes, UInt32 *usedByteLen, UniChar *characters, UInt32 maxCharLen, UInt32 *usedCharLen) { +uint32_t CFStringEncodingBytesToUnicode(uint32_t encoding, uint32_t flags, const uint8_t *bytes, CFIndex numBytes, CFIndex *usedByteLen, UniChar *characters, CFIndex maxCharLen, CFIndex *usedCharLen) { const _CFEncodingConverter *converter = __CFGetConverter(encoding); - UInt32 usedLen = 0; - UInt32 theUsedCharLen = 0; - UInt32 localUsedCharLen; - UInt32 theResult = kCFStringEncodingConversionSuccess; + CFIndex usedLen = 0; + CFIndex theUsedCharLen = 0; + CFIndex localUsedCharLen; + uint32_t theResult = kCFStringEncodingConversionSuccess; if (!converter) return kCFStringEncodingConverterUnavailable; while ((usedLen < numBytes) && (!maxCharLen || (theUsedCharLen < maxCharLen))) { if ((usedLen += TO_UNICODE(converter, flags, bytes + usedLen, numBytes - usedLen, characters + theUsedCharLen, (maxCharLen ? maxCharLen - theUsedCharLen : 0), &localUsedCharLen)) < numBytes) { - UInt32 tempUsedCharLen; + CFIndex tempUsedCharLen; - if (maxCharLen && ((maxCharLen == theUsedCharLen + localUsedCharLen) || ((flags & (kCFStringEncodingUseCanonical|kCFStringEncodingUseHFSPlusCanonical)) && TO_UNICODE(converter, flags, bytes + usedLen, numBytes - usedLen, NULL, 0, &tempUsedCharLen)))) { // buffer was filled up + if (maxCharLen && ((maxCharLen == theUsedCharLen + localUsedCharLen) || (((flags & (kCFStringEncodingUseCanonical|kCFStringEncodingUseHFSPlusCanonical)) || (maxCharLen == theUsedCharLen + localUsedCharLen + 1)) && TO_UNICODE(converter, flags, bytes + usedLen, numBytes - usedLen, NULL, 0, &tempUsedCharLen)))) { // buffer was filled up theUsedCharLen += localUsedCharLen; theResult = kCFStringEncodingInsufficientOutputBufferLength; break; @@ -895,59 +887,61 @@ UInt32 CFStringEncodingBytesToUnicode(UInt32 encoding, UInt32 flags, const uint8 return theResult; } -__private_extern__ Boolean CFStringEncodingIsValidEncoding(UInt32 encoding) { +__private_extern__ bool CFStringEncodingIsValidEncoding(uint32_t encoding) { return (CFStringEncodingGetConverter(encoding) ? true : false); } -__private_extern__ const char *CFStringEncodingName(UInt32 encoding) { +__private_extern__ const char *CFStringEncodingName(uint32_t encoding) { _CFConverterEntry *entry = __CFStringEncodingConverterGetEntry(encoding); if (entry) return entry->encodingName; return NULL; } -__private_extern__ const char **CFStringEncodingCanonicalCharsetNames(UInt32 encoding) { +__private_extern__ const char **CFStringEncodingCanonicalCharsetNames(uint32_t encoding) { _CFConverterEntry *entry = __CFStringEncodingConverterGetEntry(encoding); if (entry) return entry->ianaNames; return NULL; } -__private_extern__ UInt32 CFStringEncodingGetScriptCodeForEncoding(CFStringEncoding encoding) { +__private_extern__ uint32_t CFStringEncodingGetScriptCodeForEncoding(CFStringEncoding encoding) { _CFConverterEntry *entry = __CFStringEncodingConverterGetEntry(encoding); return (entry ? entry->scriptCode : ((encoding & 0x0FFF) == kCFStringEncodingUnicode ? kCFStringEncodingUnicode : (encoding < 0xFF ? encoding : kCFStringEncodingInvalidId))); } -__private_extern__ UInt32 CFStringEncodingCharLengthForBytes(UInt32 encoding, UInt32 flags, const uint8_t *bytes, UInt32 numBytes) { +__private_extern__ CFIndex CFStringEncodingCharLengthForBytes(uint32_t encoding, uint32_t flags, const uint8_t *bytes, CFIndex numBytes) { const _CFEncodingConverter *converter = __CFGetConverter(encoding); if (converter) { - UInt32 switchVal = (UInt32)(converter->toUnicodeLen); + uintptr_t switchVal = (uintptr_t)(converter->toUnicodeLen); - if (switchVal < 0xFFFF) + if (switchVal < 0xFFFF) { return switchVal * numBytes; - else + } else { return converter->toUnicodeLen(flags, bytes, numBytes); + } } return 0; } -__private_extern__ UInt32 CFStringEncodingByteLengthForCharacters(UInt32 encoding, UInt32 flags, const UniChar *characters, UInt32 numChars) { +__private_extern__ CFIndex CFStringEncodingByteLengthForCharacters(uint32_t encoding, uint32_t flags, const UniChar *characters, CFIndex numChars) { const _CFEncodingConverter *converter = __CFGetConverter(encoding); if (converter) { - UInt32 switchVal = (UInt32)(converter->toBytesLen); + uintptr_t switchVal = (uintptr_t)(converter->toBytesLen); - if (switchVal < 0xFFFF) + if (switchVal < 0xFFFF) { return switchVal * numChars; - else + } else { return converter->toBytesLen(flags, characters, numChars); + } } return 0; } -__private_extern__ void CFStringEncodingRegisterFallbackProcedures(UInt32 encoding, CFStringEncodingToBytesFallbackProc toBytes, CFStringEncodingToUnicodeFallbackProc toUnicode) { +__private_extern__ void CFStringEncodingRegisterFallbackProcedures(uint32_t encoding, CFStringEncodingToBytesFallbackProc toBytes, CFStringEncodingToUnicodeFallbackProc toUnicode) { _CFConverterEntry *entry = __CFStringEncodingConverterGetEntry(encoding); if (entry && __CFGetConverter(encoding)) { @@ -956,11 +950,11 @@ __private_extern__ void CFStringEncodingRegisterFallbackProcedures(UInt32 encodi } } -__private_extern__ const CFStringEncodingConverter *CFStringEncodingGetConverter(UInt32 encoding) { +__private_extern__ const CFStringEncodingConverter *CFStringEncodingGetConverter(uint32_t encoding) { return __CFStringEncodingConverterGetDefinition(__CFStringEncodingConverterGetEntry(encoding)); } -static const UInt32 __CFBuiltinEncodings[] = { +static const uint32_t __CFBuiltinEncodings[] = { kCFStringEncodingMacRoman, kCFStringEncodingWindowsLatin1, kCFStringEncodingISOLatin1, @@ -982,7 +976,20 @@ static const UInt32 __CFBuiltinEncodings[] = { }; -__private_extern__ const UInt32 *CFStringEncodingListOfAvailableEncodings(void) { +__private_extern__ const uint32_t *CFStringEncodingListOfAvailableEncodings(void) { return __CFBuiltinEncodings; } + +#undef TO_BYTE +#undef TO_UNICODE +#undef ASCIINewLine +#undef kSurrogateHighStart +#undef kSurrogateHighEnd +#undef kSurrogateLowStart +#undef kSurrogateLowEnd +#undef TO_BYTE_FALLBACK +#undef TO_UNICODE_FALLBACK +#undef EXTRA_BASE +#undef NUM_OF_ENTRIES_CYCLE + diff --git a/StringEncodings.subproj/CFStringEncodingConverter.h b/CFStringEncodingConverter.h similarity index 66% rename from StringEncodings.subproj/CFStringEncodingConverter.h rename to CFStringEncodingConverter.h index 9513570..22cf1aa 100644 --- a/StringEncodings.subproj/CFStringEncodingConverter.h +++ b/CFStringEncodingConverter.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,18 +21,16 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFStringEncodingConverter.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ -#ifndef __CFSTRINGENCODINGCONVERTER__ -#define __CFSTRINGENCODINGCONVERTER__ 1 +#if !defined(__COREFOUNDATION_CFSTRINGENCODINGCONVERTER__) +#define __COREFOUNDATION_CFSTRINGENCODINGCONVERTER__ 1 #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN /* Values for flags argument for the conversion functions below. These can be combined, but the three NonSpacing behavior flags are exclusive. */ @@ -62,50 +60,48 @@ enum { /* Macro to shift lossByte argument. */ -#define CFStringEncodingLossyByteToMask(lossByte) ((UInt32)(lossByte << 24)|kCFStringEncodingAllowLossyConversion) -#define CFStringEncodingMaskToLossyByte(flags) ((UInt8)(flags >> 24)) +#define CFStringEncodingLossyByteToMask(lossByte) ((uint32_t)(lossByte << 24)|kCFStringEncodingAllowLossyConversion) +#define CFStringEncodingMaskToLossyByte(flags) ((uint8_t)(flags >> 24)) /* Converts characters into the specified encoding. Returns the constants defined above. If maxByteLen is 0, bytes is ignored. You can pass lossyByte by passing the value in flags argument. i.e. CFStringEncodingUnicodeToBytes(encoding, CFStringEncodingLossyByteToMask(lossByte), ....) */ -extern UInt32 CFStringEncodingUnicodeToBytes(UInt32 encoding, UInt32 flags, const UniChar *characters, UInt32 numChars, UInt32 *usedCharLen, UInt8 *bytes, UInt32 maxByteLen, UInt32 *usedByteLen); +extern uint32_t CFStringEncodingUnicodeToBytes(uint32_t encoding, uint32_t flags, const UniChar *characters, CFIndex numChars, CFIndex *usedCharLen, uint8_t *bytes, CFIndex maxByteLen, CFIndex *usedByteLen); /* Converts bytes in the specified encoding into unicode. Returns the constants defined above. maxCharLen & usdCharLen are in UniChar length, not byte length. If maxCharLen is 0, characters is ignored. */ -extern UInt32 CFStringEncodingBytesToUnicode(UInt32 encoding, UInt32 flags, const UInt8 *bytes, UInt32 numBytes, UInt32 *usedByteLen, UniChar *characters, UInt32 maxCharLen, UInt32 *usedCharLen); +extern uint32_t CFStringEncodingBytesToUnicode(uint32_t encoding, uint32_t flags, const uint8_t *bytes, CFIndex numBytes, CFIndex *usedByteLen, UniChar *characters, CFIndex maxCharLen, CFIndex *usedCharLen); /* Fallback functions used when allowLossy */ -typedef UInt32 (*CFStringEncodingToBytesFallbackProc)(const UniChar *characters, UInt32 numChars, UInt8 *bytes, UInt32 maxByteLen, UInt32 *usedByteLen); -typedef UInt32 (*CFStringEncodingToUnicodeFallbackProc)(const UInt8 *bytes, UInt32 numBytes, UniChar *characters, UInt32 maxCharLen, UInt32 *usedCharLen); +typedef CFIndex (*CFStringEncodingToBytesFallbackProc)(const UniChar *characters, CFIndex numChars, uint8_t *bytes, CFIndex maxByteLen, CFIndex *usedByteLen); +typedef CFIndex (*CFStringEncodingToUnicodeFallbackProc)(const uint8_t *bytes, CFIndex numBytes, UniChar *characters, CFIndex maxCharLen, CFIndex *usedCharLen); -extern Boolean CFStringEncodingIsValidEncoding(UInt32 encoding); +extern bool CFStringEncodingIsValidEncoding(uint32_t encoding); /* Returns kCFStringEncodingInvalidId terminated encoding list */ -extern const UInt32 *CFStringEncodingListOfAvailableEncodings(void); +extern const uint32_t *CFStringEncodingListOfAvailableEncodings(void); -extern const char *CFStringEncodingName(UInt32 encoding); +extern const char *CFStringEncodingName(uint32_t encoding); /* Returns NULL-terminated list of IANA registered canonical names */ -extern const char **CFStringEncodingCanonicalCharsetNames(UInt32 encoding); +extern const char **CFStringEncodingCanonicalCharsetNames(uint32_t encoding); /* Returns required length of destination buffer for conversion. These functions are faster than specifying 0 to maxByteLen (maxCharLen), but unnecessarily optimal length */ -extern UInt32 CFStringEncodingCharLengthForBytes(UInt32 encoding, UInt32 flags, const UInt8 *bytes, UInt32 numBytes); -extern UInt32 CFStringEncodingByteLengthForCharacters(UInt32 encoding, UInt32 flags, const UniChar *characters, UInt32 numChars); +extern CFIndex CFStringEncodingCharLengthForBytes(uint32_t encoding, uint32_t flags, const uint8_t *bytes, CFIndex numBytes); +extern CFIndex CFStringEncodingByteLengthForCharacters(uint32_t encoding, uint32_t flags, const UniChar *characters, CFIndex numChars); /* Can register functions used for lossy conversion. Reregisters default procs if NULL */ -extern void CFStringEncodingRegisterFallbackProcedures(UInt32 encoding, CFStringEncodingToBytesFallbackProc toBytes, CFStringEncodingToUnicodeFallbackProc toUnicode); +extern void CFStringEncodingRegisterFallbackProcedures(uint32_t encoding, CFStringEncodingToBytesFallbackProc toBytes, CFStringEncodingToUnicodeFallbackProc toUnicode); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END -#endif /* __CFSTRINGENCODINGCONVERTER__ */ +#endif /* ! __COREFOUNDATION_CFSTRINGENCODINGCONVERTER__ */ diff --git a/StringEncodings.subproj/CFStringEncodingConverterExt.h b/CFStringEncodingConverterExt.h similarity index 56% rename from StringEncodings.subproj/CFStringEncodingConverterExt.h rename to CFStringEncodingConverterExt.h index 6f6a18f..0df8580 100644 --- a/StringEncodings.subproj/CFStringEncodingConverterExt.h +++ b/CFStringEncodingConverterExt.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,17 +21,15 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFStringEncodingConverterExt.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ -#ifndef __CFSTRINGENCODINGCONVERETEREXT_H__ -#define __CFSTRINGENCODINGCONVERETEREXT_H__ 1 +#if !defined(__COREFOUNDATION_CFSTRINGENCODINGCONVERETEREXT__) +#define __COREFOUNDATION_CFSTRINGENCODINGCONVERETEREXT__ 1 #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN #define MAX_DECOMPOSED_LENGTH (10) @@ -44,31 +42,31 @@ enum { }; /* kCFStringEncodingConverterStandard */ -typedef UInt32 (*CFStringEncodingToBytesProc)(UInt32 flags, const UniChar *characters, UInt32 numChars, UInt8 *bytes, UInt32 maxByteLen, UInt32 *usedByteLen); -typedef UInt32 (*CFStringEncodingToUnicodeProc)(UInt32 flags, const UInt8 *bytes, UInt32 numBytes, UniChar *characters, UInt32 maxCharLen, UInt32 *usedCharLen); +typedef CFIndex (*CFStringEncodingToBytesProc)(uint32_t flags, const UniChar *characters, CFIndex numChars, uint8_t *bytes, CFIndex maxByteLen, CFIndex *usedByteLen); +typedef CFIndex (*CFStringEncodingToUnicodeProc)(uint32_t flags, const uint8_t *bytes, CFIndex numBytes, UniChar *characters, CFIndex maxCharLen, CFIndex *usedCharLen); /* kCFStringEncodingConverterCheapEightBit */ -typedef Boolean (*CFStringEncodingCheapEightBitToBytesProc)(UInt32 flags, UniChar character, UInt8 *byte); -typedef Boolean (*CFStringEncodingCheapEightBitToUnicodeProc)(UInt32 flags, UInt8 byte, UniChar *character); +typedef bool (*CFStringEncodingCheapEightBitToBytesProc)(uint32_t flags, UniChar character, uint8_t *byte); +typedef bool (*CFStringEncodingCheapEightBitToUnicodeProc)(uint32_t flags, uint8_t byte, UniChar *character); /* kCFStringEncodingConverterStandardEightBit */ -typedef UInt16 (*CFStringEncodingStandardEightBitToBytesProc)(UInt32 flags, const UniChar *characters, UInt32 numChars, UInt8 *byte); -typedef UInt16 (*CFStringEncodingStandardEightBitToUnicodeProc)(UInt32 flags, UInt8 byte, UniChar *characters); +typedef uint16_t (*CFStringEncodingStandardEightBitToBytesProc)(uint32_t flags, const UniChar *characters, CFIndex numChars, uint8_t *byte); +typedef uint16_t (*CFStringEncodingStandardEightBitToUnicodeProc)(uint32_t flags, uint8_t byte, UniChar *characters); /* kCFStringEncodingConverterCheapMultiByte */ -typedef UInt16 (*CFStringEncodingCheapMultiByteToBytesProc)(UInt32 flags, UniChar character, UInt8 *bytes); -typedef UInt16 (*CFStringEncodingCheapMultiByteToUnicodeProc)(UInt32 flags, const UInt8 *bytes, UInt32 numBytes, UniChar *character); +typedef uint16_t (*CFStringEncodingCheapMultiByteToBytesProc)(uint32_t flags, UniChar character, uint8_t *bytes); +typedef uint16_t (*CFStringEncodingCheapMultiByteToUnicodeProc)(uint32_t flags, const uint8_t *bytes, CFIndex numBytes, UniChar *character); -typedef UInt32 (*CFStringEncodingToBytesLenProc)(UInt32 flags, const UniChar *characters, UInt32 numChars); -typedef UInt32 (*CFStringEncodingToUnicodeLenProc)(UInt32 flags, const UInt8 *bytes, UInt32 numBytes); +typedef CFIndex (*CFStringEncodingToBytesLenProc)(uint32_t flags, const UniChar *characters, CFIndex numChars); +typedef CFIndex (*CFStringEncodingToUnicodeLenProc)(uint32_t flags, const uint8_t *bytes, CFIndex numBytes); -typedef UInt32 (*CFStringEncodingToBytesPrecomposeProc)(UInt32 flags, const UniChar *character, UInt32 numChars, UInt8 *bytes, UInt32 maxByteLen, UInt32 *usedByteLen); -typedef Boolean (*CFStringEncodingIsValidCombiningCharacterProc)(UniChar character); +typedef CFIndex (*CFStringEncodingToBytesPrecomposeProc)(uint32_t flags, const UniChar *character, CFIndex numChars, uint8_t *bytes, CFIndex maxByteLen, CFIndex *usedByteLen); +typedef bool (*CFStringEncodingIsValidCombiningCharacterProc)(UniChar character); typedef struct { void *toBytes; void *toUnicode; - UInt16 maxBytesPerChar; - UInt16 maxDecomposedCharLen; - UInt8 encodingClass; - UInt32 :24; + uint16_t maxBytesPerChar; + uint16_t maxDecomposedCharLen; + uint8_t encodingClass; + uint32_t :24; CFStringEncodingToBytesLenProc toBytesLen; CFStringEncodingToUnicodeLenProc toUnicodeLen; CFStringEncodingToBytesFallbackProc toBytesFallback; @@ -78,7 +76,7 @@ typedef struct { } CFStringEncodingConverter; -extern const CFStringEncodingConverter *CFStringEncodingGetConverter(UInt32 encoding); +extern const CFStringEncodingConverter *CFStringEncodingGetConverter(uint32_t encoding); enum { kCFStringEncodingGetConverterSelector = 0, @@ -88,28 +86,28 @@ enum { kCFStringEncodingPrecomposeLatin1CharacterSelector = 4 }; -extern const void *CFStringEncodingGetAddressForSelector(UInt32 selector); +extern const void *CFStringEncodingGetAddressForSelector(uint32_t selector); #define BOOTSTRAPFUNC_NAME CFStringEncodingBootstrap -typedef const CFStringEncodingConverter* (*CFStringEncodingBootstrapProc)(UInt32 encoding, const void *getSelector); +typedef const CFStringEncodingConverter* (*CFStringEncodingBootstrapProc)(uint32_t encoding, const void *getSelector); -extern UInt32 CFStringEncodingGetScriptCodeForEncoding(CFStringEncoding encoding); +extern uint32_t CFStringEncodingGetScriptCodeForEncoding(CFStringEncoding encoding); /* Latin precomposition */ /* This function does not precompose recursively nor to U+01E0 and U+01E1. */ -extern Boolean CFStringEncodingIsValidCombiningCharacterForLatin1(UniChar character); -extern UniChar CFStringEncodingPrecomposeLatinCharacter(const UniChar *character, UInt32 numChars, UInt32 *usedChars); +extern bool CFStringEncodingIsValidCombiningCharacterForLatin1(UniChar character); +extern UniChar CFStringEncodingPrecomposeLatinCharacter(const UniChar *character, CFIndex numChars, CFIndex *usedChars); /* Convenience functions for converter development */ typedef struct _CFStringEncodingUnicodeTo8BitCharMap { UniChar _u; - UInt8 _c; - UInt8 :8; + uint8_t _c; + uint8_t :8; } CFStringEncodingUnicodeTo8BitCharMap; /* Binary searches CFStringEncodingUnicodeTo8BitCharMap */ -CF_INLINE Boolean CFStringEncodingUnicodeTo8BitEncoding(const CFStringEncodingUnicodeTo8BitCharMap *theTable, UInt32 numElem, UniChar character, UInt8 *ch) { +CF_INLINE bool CFStringEncodingUnicodeTo8BitEncoding(const CFStringEncodingUnicodeTo8BitCharMap *theTable, CFIndex numElem, UniChar character, uint8_t *ch) { const CFStringEncodingUnicodeTo8BitCharMap *p, *q, *divider; if ((character < theTable[0]._u) || (character > theTable[numElem-1]._u)) { @@ -127,8 +125,7 @@ CF_INLINE Boolean CFStringEncodingUnicodeTo8BitEncoding(const CFStringEncodingUn } -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END + +#endif /* ! __COREFOUNDATION_CFSTRINGENCODINGCONVERETEREXT__ */ -#endif /* __CFSTRINGENCODINGCONVERETEREXT_H__ */ diff --git a/StringEncodings.subproj/CFStringEncodingConverterPriv.h b/CFStringEncodingConverterPriv.h similarity index 80% rename from StringEncodings.subproj/CFStringEncodingConverterPriv.h rename to CFStringEncodingConverterPriv.h index 4817a8b..c53f830 100644 --- a/StringEncodings.subproj/CFStringEncodingConverterPriv.h +++ b/CFStringEncodingConverterPriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,19 +21,19 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFStringEncodingConverterPriv.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSTRINGENCODINGCONVERTERPRIV__) #define __COREFOUNDATION_CFSTRINGENCODINGCONVERTERPRIV__ 1 #include -#include +#include "CFStringEncodingConverterExt.h" #define MAX_IANA_ALIASES (4) -typedef UInt32 (*_CFToBytesProc)(const void *converter, UInt32 flags, const UniChar *characters, UInt32 numChars, UInt8 *bytes, UInt32 maxByteLen, UInt32 *usedByteLen); -typedef UInt32 (*_CFToUnicodeProc)(const void *converter, UInt32 flags, const UInt8 *bytes, UInt32 numBytes, UniChar *characters, UInt32 maxCharLen, UInt32 *usedCharLen); +typedef CFIndex (*_CFToBytesProc)(const void *converter, uint32_t flags, const UniChar *characters, CFIndex numChars, uint8_t *bytes, CFIndex maxByteLen, CFIndex *usedByteLen); +typedef CFIndex (*_CFToUnicodeProc)(const void *converter, uint32_t flags, const uint8_t *bytes, CFIndex numBytes, UniChar *characters, CFIndex maxCharLen, CFIndex *usedCharLen); typedef struct { _CFToBytesProc toBytes; @@ -41,8 +41,8 @@ typedef struct { _CFToUnicodeProc toCanonicalUnicode; void *_toBytes; // original proc void *_toUnicode; // original proc - UInt16 maxLen; - UInt16 :16; + uint16_t maxLen; + uint16_t :16; CFStringEncodingToBytesLenProc toBytesLen; CFStringEncodingToUnicodeLenProc toUnicodeLen; CFStringEncodingToBytesFallbackProc toBytesFallback; @@ -52,7 +52,7 @@ typedef struct { } _CFEncodingConverter; typedef struct { - UInt32 encoding; + uint32_t encoding; _CFEncodingConverter *converter; const char *encodingName; const char *ianaNames[MAX_IANA_ALIASES]; @@ -60,7 +60,7 @@ typedef struct { CFStringEncodingBootstrapProc bootstrap; CFStringEncodingToBytesFallbackProc toBytesFallback; CFStringEncodingToUnicodeFallbackProc toUnicodeFallback; - UInt32 scriptCode; + uint32_t scriptCode; } _CFConverterEntry; extern const CFStringEncodingConverter __CFConverterASCII; diff --git a/String.subproj/CFStringEncodingExt.h b/CFStringEncodingExt.h similarity index 89% rename from String.subproj/CFStringEncodingExt.h rename to CFStringEncodingExt.h index d162980..79d7c24 100644 --- a/String.subproj/CFStringEncodingExt.h +++ b/CFStringEncodingExt.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFStringEncodingExt.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFSTRINGENCODINGEXT__) @@ -29,11 +29,9 @@ #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN -typedef enum { +enum { /* kCFStringEncodingMacRoman = 0L, defined in CoreFoundation/CFString.h */ kCFStringEncodingMacJapanese = 1, kCFStringEncodingMacChineseTrad = 2, @@ -102,9 +100,9 @@ typedef enum { kCFStringEncodingISOLatin7 = 0x020D, /* ISO 8859-13 */ kCFStringEncodingISOLatin8 = 0x020E, /* ISO 8859-14 */ kCFStringEncodingISOLatin9 = 0x020F, /* ISO 8859-15 */ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 +#if MAC_OS_X_VERSION_10_4 <= MAC_OS_X_VERSION_MAX_ALLOWED kCFStringEncodingISOLatin10 = 0x0210, /* ISO 8859-16 */ -#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 */ +#endif /* MS-DOS & Windows encodings begin at 0x400 */ kCFStringEncodingDOSLatinUS = 0x0400, /* code page 437 */ @@ -141,18 +139,20 @@ typedef enum { /* Various national standards begin at 0x600 */ /* kCFStringEncodingASCII = 0x0600, defined in CoreFoundation/CFString.h */ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 +#if MAC_OS_X_VERSION_10_4 <= MAC_OS_X_VERSION_MAX_ALLOWED kCFStringEncodingANSEL = 0x0601, /* ANSEL (ANSI Z39.47) */ -#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 */ +#endif kCFStringEncodingJIS_X0201_76 = 0x0620, kCFStringEncodingJIS_X0208_83 = 0x0621, kCFStringEncodingJIS_X0208_90 = 0x0622, kCFStringEncodingJIS_X0212_90 = 0x0623, kCFStringEncodingJIS_C6226_78 = 0x0624, - kCFStringEncodingShiftJIS_X0213_00 = 0x0628, /* Shift-JIS format encoding of JIS X0213 planes 1 and 2*/ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 +#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 /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 */ +#endif kCFStringEncodingGB_2312_80 = 0x0630, kCFStringEncodingGBK_95 = 0x0631, /* annex to GB 13000-93; for Windows 95 */ kCFStringEncodingGB_18030_2000 = 0x0632, @@ -184,26 +184,28 @@ typedef 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_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 +#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 /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 */ +#endif /* Other platform encodings*/ /* kCFStringEncodingNextStepLatin = 0x0B01, defined in CoreFoundation/CFString.h */ -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 +#if MAC_OS_X_VERSION_10_4 <= MAC_OS_X_VERSION_MAX_ALLOWED kCFStringEncodingNextStepJapanese = 0x0B02, /* NextStep Japanese encoding */ -#endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 */ +#endif /* EBCDIC & IBM host encodings begin at 0xC00 */ kCFStringEncodingEBCDIC_US = 0x0C01, /* basic EBCDIC-US */ - kCFStringEncodingEBCDIC_CP037 = 0x0C02 /* code page 037, extended EBCDIC (Latin-1 set) for US,Canada... */ -} CFStringEncodings; + kCFStringEncodingEBCDIC_CP037 = 0x0C02, /* code page 037, extended EBCDIC (Latin-1 set) for US,Canada... */ -#if defined(__cplusplus) -} -#endif + /* Deprecated constants */ + kCFStringEncodingShiftJIS_X0213_00 = 0x0628 /* Shift-JIS format encoding of JIS X0213 planes 1 and 2 (DEPRECATED) */ +}; +typedef CFIndex CFStringEncodings; + +CF_EXTERN_C_END -#endif /* !__COREFOUNDATION_CFSTRINGENCODINGEXT__ */ +#endif /* ! __COREFOUNDATION_CFSTRINGENCODINGEXT__ */ diff --git a/String.subproj/CFStringEncodings.c b/CFStringEncodings.c similarity index 88% rename from String.subproj/CFStringEncodings.c rename to CFStringEncodings.c index a3d999e..1814473 100644 --- a/String.subproj/CFStringEncodings.c +++ b/CFStringEncodings.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -28,7 +28,7 @@ #include "CFInternal.h" #include #include -#include "CFUtilitiesPriv.h" +#include "CFPriv.h" #include #include "CFStringEncodingConverterExt.h" #include "CFUniChar.h" @@ -118,7 +118,7 @@ enum { __NSNonLossyOctalFinalMode = __NSNonLossyHexFinalMode + 3 }; -Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, UInt32 len, CFStringEncoding encoding, Boolean alwaysUnicode, CFVarWidthCharBuffer *buffer, Boolean *useClientsMemoryPtr, UInt32 converterFlags) { +Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, CFIndex len, CFStringEncoding encoding, Boolean alwaysUnicode, CFVarWidthCharBuffer *buffer, Boolean *useClientsMemoryPtr, UInt32 converterFlags) { if (useClientsMemoryPtr) *useClientsMemoryPtr = false; @@ -138,14 +138,14 @@ Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, UInt32 len, CFStringEn if (kCFStringEncodingUTF16 == encoding) { UTF16Char bom = ((*src == 0xFFFE) || (*src == 0xFEFF) ? *(src++) : 0); -#if defined(__BIG_ENDIAN__) +#if __CF_BIG_ENDIAN__ if (bom == 0xFFFE) swap = true; #else if (bom != 0xFEFF) swap = true; #endif if (bom) useClientsMemoryPtr = NULL; } else { -#if defined(__BIG_ENDIAN__) +#if __CF_BIG_ENDIAN__ if (kCFStringEncodingUTF16LE == encoding) swap = true; #else if (kCFStringEncodingUTF16BE == encoding) swap = true; @@ -175,7 +175,7 @@ Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, UInt32 len, CFStringEn uint8_t *dst; if (NULL == buffer->chars.ascii) { // we never reallocate when buffer is supplied if (buffer->numChars > MAX_LOCAL_CHARS) { - buffer->chars.ascii = CFAllocatorAllocate(buffer->allocator, (buffer->numChars * sizeof(uint8_t)), 0); + buffer->chars.ascii = (UInt8 *)CFAllocatorAllocate(buffer->allocator, (buffer->numChars * sizeof(uint8_t)), 0); buffer->shouldFreeChars = true; } else { buffer->chars.ascii = (uint8_t *)buffer->localBuffer; @@ -186,14 +186,14 @@ Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, UInt32 len, CFStringEn if (swap) { while (src < limit) *(dst++) = (*(src++) >> 8); } else { - while (src < limit) *(dst++) = *(src++); + while (src < limit) *(dst++) = (uint8_t)*(src++); } } else { UTF16Char *dst; if (NULL == buffer->chars.unicode) { // we never reallocate when buffer is supplied if (buffer->numChars > MAX_LOCAL_UNICHARS) { - buffer->chars.unicode = CFAllocatorAllocate(buffer->allocator, (buffer->numChars * sizeof(UTF16Char)), 0); + buffer->chars.unicode = (UniChar *)CFAllocatorAllocate(buffer->allocator, (buffer->numChars * sizeof(UTF16Char)), 0); buffer->shouldFreeChars = true; } else { buffer->chars.unicode = (UTF16Char *)buffer->localBuffer; @@ -212,17 +212,20 @@ Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, UInt32 len, CFStringEn const UTF32Char *src = (const UTF32Char *)bytes; const UTF32Char *limit = (const UTF32Char *)(bytes + len); bool swap = false; + static bool strictUTF32 = (bool)-1; + + if ((bool)-1 == strictUTF32) strictUTF32 = (_CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard) != 0); if (kCFStringEncodingUTF32 == encoding) { UTF32Char bom = ((*src == 0xFFFE0000) || (*src == 0x0000FEFF) ? *(src++) : 0); -#if defined(__BIG_ENDIAN__) +#if __CF_BIG_ENDIAN__ if (bom == 0xFFFE0000) swap = true; #else if (bom != 0x0000FEFF) swap = true; #endif } else { -#if defined(__BIG_ENDIAN__) +#if __CF_BIG_ENDIAN__ if (kCFStringEncodingUTF32LE == encoding) swap = true; #else if (kCFStringEncodingUTF32BE == encoding) swap = true; @@ -240,7 +243,10 @@ Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, UInt32 len, CFStringEn while (characters < limit) { if (*characters & asciiMask) { buffer->isASCII = false; - if (*characters & bmpMask) ++(buffer->numChars); + if (*characters & bmpMask) { + if (strictUTF32 && ((swap ? (UTF32Char)CFSwapInt32(*characters) : *characters) > 0x10FFFF)) return false; // outside of Unicode Scaler Value + ++(buffer->numChars); + } } ++characters; } @@ -250,7 +256,7 @@ Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, UInt32 len, CFStringEn uint8_t *dst; if (NULL == buffer->chars.ascii) { // we never reallocate when buffer is supplied if (buffer->numChars > MAX_LOCAL_CHARS) { - buffer->chars.ascii = CFAllocatorAllocate(buffer->allocator, (buffer->numChars * sizeof(uint8_t)), 0); + buffer->chars.ascii = (UInt8 *)CFAllocatorAllocate(buffer->allocator, (buffer->numChars * sizeof(uint8_t)), 0); buffer->shouldFreeChars = true; } else { buffer->chars.ascii = (uint8_t *)buffer->localBuffer; @@ -266,22 +272,16 @@ Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, UInt32 len, CFStringEn } else { if (NULL == buffer->chars.unicode) { // we never reallocate when buffer is supplied if (buffer->numChars > MAX_LOCAL_UNICHARS) { - buffer->chars.unicode = CFAllocatorAllocate(buffer->allocator, (buffer->numChars * sizeof(UTF16Char)), 0); + buffer->chars.unicode = (UniChar *)CFAllocatorAllocate(buffer->allocator, (buffer->numChars * sizeof(UTF16Char)), 0); buffer->shouldFreeChars = true; } else { buffer->chars.unicode = (UTF16Char *)buffer->localBuffer; } } - CFUniCharFromUTF32(src, limit - src, buffer->chars.unicode, false, -#if defined(__BIG_ENDIAN__) - !swap -#else - swap -#endif - ); + return (CFUniCharFromUTF32(src, limit - src, buffer->chars.unicode, (strictUTF32 ? false : true), __CF_BIG_ENDIAN__ ? !swap : swap) ? TRUE : FALSE); } } else { - UInt32 idx; + CFIndex idx; const uint8_t *chars = (const uint8_t *)bytes; const uint8_t *end = chars + len; @@ -293,7 +293,7 @@ Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, UInt32 len, CFStringEn buffer->isASCII = false; buffer->shouldFreeChars = !buffer->chars.unicode && (len <= MAX_LOCAL_UNICHARS) ? false : true; - buffer->chars.unicode = (buffer->chars.unicode ? buffer->chars.unicode : (len <= MAX_LOCAL_UNICHARS) ? (UniChar *)buffer->localBuffer : CFAllocatorAllocate(buffer->allocator, len * sizeof(UniChar), 0)); + buffer->chars.unicode = (buffer->chars.unicode ? buffer->chars.unicode : (len <= MAX_LOCAL_UNICHARS) ? (UniChar *)buffer->localBuffer : (UniChar *)CFAllocatorAllocate(buffer->allocator, len * sizeof(UniChar), 0)); buffer->numChars = 0; while (chars < end) { @@ -376,10 +376,10 @@ Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, UInt32 len, CFStringEn if (buffer->isASCII) { buffer->numChars = len; buffer->shouldFreeChars = !buffer->chars.ascii && (len <= MAX_LOCAL_CHARS) ? false : true; - buffer->chars.ascii = (buffer->chars.ascii ? buffer->chars.ascii : (len <= MAX_LOCAL_CHARS) ? (uint8_t *)buffer->localBuffer : CFAllocatorAllocate(buffer->allocator, len * sizeof(uint8_t), 0)); + buffer->chars.ascii = (buffer->chars.ascii ? buffer->chars.ascii : (len <= MAX_LOCAL_CHARS) ? (uint8_t *)buffer->localBuffer : (UInt8 *)CFAllocatorAllocate(buffer->allocator, len * sizeof(uint8_t), 0)); memmove(buffer->chars.ascii, chars, len * sizeof(uint8_t)); } else { - UInt32 numDone; + CFIndex numDone; static CFStringEncodingToUnicodeProc __CFFromUTF8 = NULL; if (!__CFFromUTF8) { @@ -388,7 +388,7 @@ Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, UInt32 len, CFStringEn } buffer->shouldFreeChars = !buffer->chars.unicode && (len <= MAX_LOCAL_UNICHARS) ? false : true; - buffer->chars.unicode = (buffer->chars.unicode ? buffer->chars.unicode : (len <= MAX_LOCAL_UNICHARS) ? (UniChar *)buffer->localBuffer : CFAllocatorAllocate(buffer->allocator, len * sizeof(UniChar), 0)); + buffer->chars.unicode = (buffer->chars.unicode ? buffer->chars.unicode : (len <= MAX_LOCAL_UNICHARS) ? (UniChar *)buffer->localBuffer : (UniChar *)CFAllocatorAllocate(buffer->allocator, len * sizeof(UniChar), 0)); buffer->numChars = 0; while (chars < end) { numDone = 0; @@ -429,11 +429,11 @@ Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, UInt32 len, CFStringEn if (buffer->isASCII) { buffer->numChars = len; buffer->shouldFreeChars = !buffer->chars.ascii && (len <= MAX_LOCAL_CHARS) ? false : true; - buffer->chars.ascii = (buffer->chars.ascii ? buffer->chars.ascii : (len <= MAX_LOCAL_CHARS) ? (uint8_t *)buffer->localBuffer : CFAllocatorAllocate(buffer->allocator, len * sizeof(uint8_t), 0)); + buffer->chars.ascii = (buffer->chars.ascii ? buffer->chars.ascii : (len <= MAX_LOCAL_CHARS) ? (uint8_t *)buffer->localBuffer : (UInt8 *)CFAllocatorAllocate(buffer->allocator, len * sizeof(uint8_t), 0)); memmove(buffer->chars.ascii, chars, len * sizeof(uint8_t)); } else { buffer->shouldFreeChars = !buffer->chars.unicode && (len <= MAX_LOCAL_UNICHARS) ? false : true; - buffer->chars.unicode = (buffer->chars.unicode ? buffer->chars.unicode : (len <= MAX_LOCAL_UNICHARS) ? (UniChar *)buffer->localBuffer : CFAllocatorAllocate(buffer->allocator, len * sizeof(UniChar), 0)); + buffer->chars.unicode = (buffer->chars.unicode ? buffer->chars.unicode : (len <= MAX_LOCAL_UNICHARS) ? (UniChar *)buffer->localBuffer : (UniChar *)CFAllocatorAllocate(buffer->allocator, len * sizeof(UniChar), 0)); buffer->numChars = len; if (kCFStringEncodingASCII == encoding || kCFStringEncodingISOLatin1 == encoding) { for (idx = 0; idx < len; idx++) buffer->chars.unicode[idx] = (UniChar)chars[idx]; @@ -449,14 +449,14 @@ Boolean __CFStringDecodeByteStream3(const uint8_t *bytes, UInt32 len, CFStringEn if (buffer->isASCII) { buffer->numChars = len; buffer->shouldFreeChars = !buffer->chars.ascii && (len <= MAX_LOCAL_CHARS) ? false : true; - buffer->chars.ascii = (buffer->chars.ascii ? buffer->chars.ascii : (len <= MAX_LOCAL_CHARS) ? (uint8_t *)buffer->localBuffer : CFAllocatorAllocate(buffer->allocator, len * sizeof(uint8_t), 0)); + buffer->chars.ascii = (buffer->chars.ascii ? buffer->chars.ascii : (len <= MAX_LOCAL_CHARS) ? (uint8_t *)buffer->localBuffer : (UInt8 *)CFAllocatorAllocate(buffer->allocator, len * sizeof(uint8_t), 0)); memmove(buffer->chars.ascii, chars, len * sizeof(uint8_t)); } else { - UInt32 guessedLength = CFStringEncodingCharLengthForBytes(encoding, 0, bytes, len); + CFIndex guessedLength = CFStringEncodingCharLengthForBytes(encoding, 0, bytes, len); static UInt32 lossyFlag = (UInt32)-1; buffer->shouldFreeChars = !buffer->chars.unicode && (guessedLength <= MAX_LOCAL_UNICHARS) ? false : true; - buffer->chars.unicode = (buffer->chars.unicode ? buffer->chars.unicode : (guessedLength <= MAX_LOCAL_UNICHARS) ? (UniChar *)buffer->localBuffer : CFAllocatorAllocate(buffer->allocator, guessedLength * sizeof(UniChar), 0)); + 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 (lossyFlag == (UInt32)-1) lossyFlag = (_CFExecutableLinkedOnOrAfter(CFSystemVersionPanther) ? 0 : kCFStringEncodingAllowLossyConversion); @@ -518,7 +518,7 @@ CFIndex __CFStringEncodeByteStream(CFStringRef string, CFIndex rangeLoc, CFIndex ch = CFStringGetCharacterFromInlineBuffer(&buf, numCharsProcessed); if ((ch >= ' ' && ch <= '~' && ch != '\\') || (ch == '\n' || ch == '\r' || ch == '\t')) { reqLength = 1; - tmp[0] = ch; + tmp[0] = (char)ch; } else { if (ch == '\\') { tmp[1] = '\\'; @@ -557,20 +557,14 @@ CFIndex __CFStringEncodeByteStream(CFStringRef string, CFIndex rangeLoc, CFIndex totalBytesWritten = (numCharsProcessed * sizeof(UniChar)) + extraForBOM; if (buffer) { if (extraForBOM) { /* Generate BOM */ -#if defined(__BIG_ENDIAN__) +#if __CF_BIG_ENDIAN__ *buffer++ = 0xfe; *buffer++ = 0xff; #else *buffer++ = 0xff; *buffer++ = 0xfe; #endif } CFStringGetCharacters(string, CFRangeMake(rangeLoc, numCharsProcessed), (UniChar *)buffer); - if ( -#if defined(__BIG_ENDIAN__) - kCFStringEncodingUTF16LE -#else - kCFStringEncodingUTF16BE -#endif - == encoding) { // Need to swap + if ((__CF_BIG_ENDIAN__ ? kCFStringEncodingUTF16LE : kCFStringEncodingUTF16BE) == encoding) { // Need to swap UTF16Char *characters = (UTF16Char *)buffer; const UTF16Char *limit = characters + numCharsProcessed; @@ -585,23 +579,14 @@ CFIndex __CFStringEncodeByteStream(CFStringRef string, CFIndex rangeLoc, CFIndex CFStringInlineBuffer buf; UTF32Char *characters = (UTF32Char *)buffer; -#if defined(__BIG_ENDIAN__) - bool swap = (encoding == kCFStringEncodingUTF32LE ? true : false); -#else - bool swap = (encoding == kCFStringEncodingUTF32BE ? true : false); -#endif - + bool swap = (encoding == (__CF_BIG_ENDIAN__ ? kCFStringEncodingUTF32LE : kCFStringEncodingUTF32BE) ? true : false); if (generatingExternalFile && (encoding == kCFStringEncodingUTF32)) { totalBytesWritten += sizeof(UTF32Char); if (characters) { if (totalBytesWritten > max) { // insufficient buffer totalBytesWritten = 0; } else { -#if defined(__BIG_ENDIAN__) *(characters++) = 0x0000FEFF; -#else - *(characters++) = 0xFFFE0000; -#endif } } } @@ -644,11 +629,11 @@ CFIndex __CFStringEncodeByteStream(CFStringRef string, CFIndex rangeLoc, CFIndex CFIndex numChars; UInt32 flags; const unsigned char *cString = NULL; - BOOL isASCIISuperset = __CFStringEncodingIsSupersetOfASCII(encoding); + Boolean isASCIISuperset = __CFStringEncodingIsSupersetOfASCII(encoding); if (!CF_IS_OBJC(CFStringGetTypeID(), string) && isASCIISuperset) { // Checking for NSString to avoid infinite recursion const unsigned char *ptr; - if ((cString = CFStringGetCStringPtr(string, __CFStringGetEightBitStringEncoding()))) { + if ((cString = (const unsigned char *)CFStringGetCStringPtr(string, __CFStringGetEightBitStringEncoding()))) { ptr = (cString += rangeLoc); if (__CFStringGetEightBitStringEncoding() == encoding) { numCharsProcessed = (rangeLen < max || buffer == NULL ? rangeLen : max); @@ -708,17 +693,17 @@ CFIndex __CFStringEncodeByteStream(CFStringRef string, CFIndex rangeLoc, CFIndex // Aki 11/24/04 __CFGetASCIICompatibleFlag() is called only for non-ASCII superset encodings. Otherwise, it could lead to a deadlock (see 3890536). flags = (lossByte ? ((unsigned char)lossByte == 0xFF && encoding == kCFStringEncodingASCII ? kCFStringEncodingAllowLossyConversion : CFStringEncodingLossyByteToMask(lossByte)) : 0) | (generatingExternalFile ? kCFStringEncodingPrependBOM : 0) | (isASCIISuperset ? 0 : __CFGetASCIICompatibleFlag()); - if (!cString && (cString = (const char*)CFStringGetCharactersPtr(string))) { // Must be Unicode string + if (!cString && (cString = (const unsigned char *)CFStringGetCharactersPtr(string))) { // Must be Unicode string if (CFStringEncodingIsValidEncoding(encoding)) { // Converter available in CF - CFStringEncodingUnicodeToBytes(encoding, flags, (const UniChar*)cString + rangeLoc, rangeLen, &numCharsProcessed, buffer, max, &totalBytesWritten); + CFStringEncodingUnicodeToBytes(encoding, flags, (const UniChar *)cString + rangeLoc, rangeLen, &numCharsProcessed, buffer, max, &totalBytesWritten); } else { return 0; } } else { UniChar charBuf[kCFCharConversionBufferLength]; - UInt32 currentLength; - UInt32 usedLen; - uint32_t lastUsedLen = 0, lastNumChars = 0; + CFIndex currentLength; + CFIndex usedLen; + CFIndex lastUsedLen = 0, lastNumChars = 0; uint32_t result; Boolean isCFBuiltin = CFStringEncodingIsValidEncoding(encoding); #define MAX_DECOMP_LEN (6) @@ -821,47 +806,46 @@ CFIndex CFStringGetMaximumSizeOfFileSystemRepresentation(CFStringRef string) { } Boolean CFStringGetFileSystemRepresentation(CFStringRef string, char *buffer, CFIndex maxBufLen) { -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX #define MAX_STACK_BUFFER_LEN (255) const UTF16Char *characters = CFStringGetCharactersPtr(string); + const char *bufferLimit = buffer + maxBufLen; CFIndex length = CFStringGetLength(string); - uint32_t usedBufLen; + CFIndex usedBufLen; if (maxBufLen < length) return false; // Since we're using UTF-8, the byte length is never shorter than the char length. Also, it filters out 0 == maxBufLen if (NULL == characters) { - if (length > MAX_STACK_BUFFER_LEN) { - UTF16Char charactersBuffer[MAX_STACK_BUFFER_LEN]; - CFRange range = CFRangeMake(0, MAX_STACK_BUFFER_LEN); - uint32_t localUsedBufLen; + UTF16Char charactersBuffer[MAX_STACK_BUFFER_LEN]; + CFRange range = CFRangeMake(0, 0); + const char *bytes = CFStringGetCStringPtr(string, __CFStringGetEightBitStringEncoding()); - usedBufLen = 0; + if (NULL != bytes) { + const char *originalBytes = bytes; + const char *bytesLimit = bytes + length; - while ((length > 0) && (maxBufLen > usedBufLen)) { - CFStringGetCharacters(string, range, charactersBuffer); - if (CFUniCharIsSurrogateHighCharacter(charactersBuffer[range.length - 1])) --range.length; // Backup for a high surrogate + while ((bytes < bytesLimit) && (buffer < bufferLimit) && (0 == (*bytes & 0x80))) *(buffer++) = *(bytes++); - if (!CFUniCharDecompose(charactersBuffer, range.length, NULL, (void *)buffer, maxBufLen - usedBufLen, &localUsedBufLen, true, kCFUniCharUTF8Format, true)) return false; - buffer += localUsedBufLen; - usedBufLen += localUsedBufLen; + range.location = bytes - originalBytes; + } + while ((range.location < length) && (buffer < bufferLimit)) { + range.length = length - range.location; + if (range.length > MAX_STACK_BUFFER_LEN) range.length = MAX_STACK_BUFFER_LEN; - length -= range.length; - range.location += range.length; - range.length = (length < MAX_STACK_BUFFER_LEN ? length : MAX_STACK_BUFFER_LEN); - } - } else { - UTF16Char charactersBuffer[MAX_STACK_BUFFER_LEN]; + CFStringGetCharacters(string, range, charactersBuffer); + if ((range.length == MAX_STACK_BUFFER_LEN) && CFUniCharIsSurrogateHighCharacter(charactersBuffer[MAX_STACK_BUFFER_LEN - 1])) --range.length; // Backup for a high surrogate + + if (!CFUniCharDecompose(charactersBuffer, range.length, NULL, (void *)buffer, bufferLimit - buffer, &usedBufLen, true, kCFUniCharUTF8Format, true)) return false; - CFStringGetCharacters(string, CFRangeMake(0, length), charactersBuffer); - if (!CFUniCharDecompose(charactersBuffer, length, NULL, (void *)buffer, maxBufLen, &usedBufLen, true, kCFUniCharUTF8Format, true)) return false; buffer += usedBufLen; + range.location += range.length; } } else { if (!CFUniCharDecompose(characters, length, NULL, (void *)buffer, maxBufLen, &usedBufLen, true, kCFUniCharUTF8Format, true)) return false; buffer += usedBufLen; } - if (usedBufLen < (uint32_t)maxBufLen) { // Since the filename has its own limit, this is ok for now + if (buffer < bufferLimit) { // Since the filename has its own limit, this is ok for now *buffer = '\0'; return true; } else { @@ -873,6 +857,6 @@ Boolean CFStringGetFileSystemRepresentation(CFStringRef string, char *buffer, CF } Boolean _CFStringGetFileSystemRepresentation(CFStringRef string, uint8_t *buffer, CFIndex maxBufLen) { - return CFStringGetFileSystemRepresentation(string, buffer, maxBufLen); + return CFStringGetFileSystemRepresentation(string, (char *)buffer, maxBufLen); } diff --git a/String.subproj/CFStringScanner.c b/CFStringScanner.c similarity index 93% rename from String.subproj/CFStringScanner.c rename to CFStringScanner.c index 601e65c..4ae1461 100644 --- a/String.subproj/CFStringScanner.c +++ b/CFStringScanner.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -27,9 +27,7 @@ #include "CFInternal.h" #include -#if !defined(__MACOS8__) #include -#endif #include #include #include @@ -64,7 +62,7 @@ CF_INLINE UniChar __CFStringGetFirstNonSpaceCharacterFromInlineBuffer(CFStringIn /* result is int64_t or int, depending on doLonglong */ -__private_extern__ Boolean __CFStringScanInteger(CFStringInlineBuffer *buf, CFDictionaryRef locale, SInt32 *indexPtr, Boolean doLonglong, void *result) { +__private_extern__ Boolean __CFStringScanInteger(CFStringInlineBuffer *buf, CFTypeRef locale, SInt32 *indexPtr, Boolean doLonglong, void *result) { Boolean doingLonglong = false; /* Set to true if doLonglong, and we overflow an int... */ Boolean neg = false; int intResult = 0; @@ -157,14 +155,14 @@ __private_extern__ Boolean __CFStringScanHex(CFStringInlineBuffer *buf, SInt32 * } // Packed array of Boolean -static const char __CFNumberSet[16] = { +static const unsigned char __CFNumberSet[16] = { 0X00, // 0, 0, 0, 0, 0, 0, 0, 0, // nul soh stx etx eot enq ack bel 0X00, // 0, 0, 0, 0, 0, 0, 0, 0, // bs ht nl vt np cr so si 0X00, // 0, 0, 0, 0, 0, 0, 0, 0, // dle dc1 dc2 dc3 dc4 nak syn etb 0X00, // 0, 0, 0, 0, 0, 0, 0, 0, // can em sub esc fs gs rs us 0X00, // 0, 0, 0, 0, 0, 0, 0, 0, // sp ! " # $ % & ' 0X28, // 0, 0, 0, 1, 0, 1, 0, 0, // ( ) * + , - . / - 0XFF, // 1, 1, 1, 1, 1, 1, 1, 1, // 0 1 2 3 4 5 6 7 + 0xFF, // 1, 1, 1, 1, 1, 1, 1, 1, // 0 1 2 3 4 5 6 7 0X03, // 1, 1, 0, 0, 0, 0, 0, 0, // 8 9 : ; < = > ? 0X20, // 0, 0, 0, 0, 0, 1, 0, 0, // @ A B C D E F G 0X00, // 0, 0, 0, 0, 0, 0, 0, 0, // H I J K L M N O @@ -176,7 +174,7 @@ static const char __CFNumberSet[16] = { 0X00, // 0, 0, 0, 0, 0, 0, 0, 0 // x y z { | } ~ del }; -__private_extern__ Boolean __CFStringScanDouble(CFStringInlineBuffer *buf, CFDictionaryRef locale, SInt32 *indexPtr, double *resultPtr) { +__private_extern__ Boolean __CFStringScanDouble(CFStringInlineBuffer *buf, CFTypeRef locale, SInt32 *indexPtr, double *resultPtr) { #define STACK_BUFFER_SIZE 256 #define ALLOC_CHUNK_SIZE 256 // first and subsequent malloc size. Should be greater than STACK_BUFFER_SIZE char localCharBuffer[STACK_BUFFER_SIZE]; @@ -191,7 +189,7 @@ __private_extern__ Boolean __CFStringScanDouble(CFStringInlineBuffer *buf, CFDic #if 0 if (locale != NULL) { - CFStringRef decimalSeparator = [locale objectForKey: NSDecimalSeparator]; + CFStringRef decimalSeparator = [locale objectForKey: @"NSDecimalSeparator"]; if (decimalSeparator != nil) decimalChar = [decimalSeparator characterAtIndex:0]; } #endif @@ -200,9 +198,9 @@ __private_extern__ Boolean __CFStringScanDouble(CFStringInlineBuffer *buf, CFDic #if 0 #warning need to allow, case insensitively, all of: "nan", "inf", "-inf", "+inf", "-infinity", "+infinity", "infinity"; #warning -- strtod() will actually do most or all of that for us -#define BITSFORDOUBLENAN ((uint64_t)0x7ff8000000000000) -#define BITSFORDOUBLEPOSINF ((uint64_t)0x7ff0000000000000) -#define BITSFORDOUBLENEGINF ((uint64_t)0xfff0000000000000) +#define BITSFORDOUBLENAN ((uint64_t)0x7ff8000000000000ULL) +#define BITSFORDOUBLEPOSINF ((uint64_t)0x7ff0000000000000ULL) +#define BITSFORDOUBLENEGINF ((uint64_t)0xfff0000000000000ULL) if ('N' == ch || 'n' == ch) { // check for "NaN", case insensitively UniChar next1 = __CFStringGetCharacterFromInlineBufferAux(buf, *indexPtr + 1); UniChar next2 = __CFStringGetCharacterFromInlineBufferAux(buf, *indexPtr + 2); @@ -246,10 +244,10 @@ __private_extern__ Boolean __CFStringScanDouble(CFStringInlineBuffer *buf, CFDic capacity += ALLOC_CHUNK_SIZE; if (tmpAlloc == NULL) tmpAlloc = __CFGetDefaultAllocator(); if (charPtr == localCharBuffer) { - charPtr = CFAllocatorAllocate(tmpAlloc, capacity * sizeof(char), 0); + charPtr = (char *)CFAllocatorAllocate(tmpAlloc, capacity * sizeof(char), 0); memmove(charPtr, localCharBuffer, numChars * sizeof(char)); } else { - charPtr = CFAllocatorReallocate(tmpAlloc, charPtr, capacity * sizeof(char), 0); + charPtr = (char *)CFAllocatorReallocate(tmpAlloc, charPtr, capacity * sizeof(char), 0); } } charPtr[numChars++] = (char)ch; diff --git a/String.subproj/CFStringUtilities.c b/CFStringUtilities.c similarity index 89% rename from String.subproj/CFStringUtilities.c rename to CFStringUtilities.c index 27bea85..015a244 100644 --- a/String.subproj/CFStringUtilities.c +++ b/CFStringUtilities.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -29,8 +29,9 @@ #include "CFStringEncodingConverterExt.h" #include "CFUniChar.h" #include +#include #include -#if defined(__MACH__) || defined(__LINUX__) +#if (DEPLOYMENT_TARGET_MACOSX) || DEPLOYMENT_TARGET_LINUX #include #elif defined(__WIN32__) #include @@ -60,12 +61,12 @@ Boolean CFStringIsEncodingAvailable(CFStringEncoding theEncoding) { } const CFStringEncoding* CFStringGetListOfAvailableEncodings() { - return CFStringEncodingListOfAvailableEncodings(); + return (const CFStringEncoding *)CFStringEncodingListOfAvailableEncodings(); } CFStringRef CFStringGetNameOfEncoding(CFStringEncoding theEncoding) { static CFMutableDictionaryRef mappingTable = NULL; - CFStringRef theName = mappingTable ? CFDictionaryGetValue(mappingTable, (const void*)theEncoding) : NULL; + CFStringRef theName = mappingTable ? (CFStringRef)CFDictionaryGetValue(mappingTable, (const void*)(uintptr_t)theEncoding) : NULL; if (!theName) { switch (theEncoding) { @@ -79,19 +80,19 @@ CFStringRef CFStringGetNameOfEncoding(CFStringEncoding theEncoding) { case kCFStringEncodingNonLossyASCII: theName = CFSTR("Non-lossy ASCII"); break; default: { - const uint8_t *encodingName = CFStringEncodingName(theEncoding); + const char *encodingName = CFStringEncodingName(theEncoding); if (encodingName) { - theName = CFStringCreateWithCString(NULL, encodingName, kCFStringEncodingASCII); + theName = CFStringCreateWithCString(kCFAllocatorSystemDefault, encodingName, kCFStringEncodingASCII); } } break; } if (theName) { - if (!mappingTable) mappingTable = CFDictionaryCreateMutable(NULL, 0, (const CFDictionaryKeyCallBacks *)NULL, &kCFTypeDictionaryValueCallBacks); + if (!mappingTable) mappingTable = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, (const CFDictionaryKeyCallBacks *)NULL, &kCFTypeDictionaryValueCallBacks); - CFDictionaryAddValue(mappingTable, (const void*)theEncoding, (const void*)theName); + CFDictionaryAddValue(mappingTable, (const void*)(uintptr_t)theEncoding, (const void*)theName); CFRelease(theName); } } @@ -112,11 +113,11 @@ CFStringEncoding CFStringConvertIANACharSetNameToEncoding(CFStringRef charsetNa } /* Create lowercase copy */ - lowerCharsetName = CFStringCreateMutableCopy(NULL, 0, charsetName); + lowerCharsetName = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, 0, charsetName); CFStringLowercase(lowerCharsetName, NULL); if (mappingTable == NULL) { - CFMutableDictionaryRef table = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, (const CFDictionaryValueCallBacks *)NULL); + CFMutableDictionaryRef table = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, (const CFDictionaryValueCallBacks *)NULL); const CFStringEncoding *encodings = CFStringGetListOfAvailableEncodings(); while (*encodings != kCFStringEncodingInvalidId) { @@ -124,10 +125,10 @@ CFStringEncoding CFStringConvertIANACharSetNameToEncoding(CFStringRef charsetNa if (nameList) { while (*nameList) { - CFStringRef name = CFStringCreateWithCString(NULL, *nameList++, kCFStringEncodingASCII); + CFStringRef name = CFStringCreateWithCString(kCFAllocatorSystemDefault, *nameList++, kCFStringEncodingASCII); if (name) { - CFDictionaryAddValue(table, (const void*)name, (const void*)*encodings); + CFDictionaryAddValue(table, (const void*)name, (const void*)(uintptr_t)*encodings); CFRelease(name); } } @@ -148,7 +149,7 @@ CFStringEncoding CFStringConvertIANACharSetNameToEncoding(CFStringRef charsetNa } if (CFDictionaryContainsKey(mappingTable, (const void*)lowerCharsetName)) { - result = (CFStringEncoding)CFDictionaryGetValue(mappingTable, (const void*)lowerCharsetName); + result = (CFStringEncoding)(uintptr_t)CFDictionaryGetValue(mappingTable, (const void*)lowerCharsetName); } CFRelease(lowerCharsetName); @@ -158,7 +159,7 @@ CFStringEncoding CFStringConvertIANACharSetNameToEncoding(CFStringRef charsetNa CFStringRef CFStringConvertEncodingToIANACharSetName(CFStringEncoding encoding) { static CFMutableDictionaryRef mappingTable = NULL; - CFStringRef theName = mappingTable ? (CFStringRef)CFDictionaryGetValue(mappingTable, (const void*)encoding) : NULL; + CFStringRef theName = mappingTable ? (CFStringRef)CFDictionaryGetValue(mappingTable, (const void*)(uintptr_t)encoding) : NULL; if (!theName) { switch (encoding) { @@ -176,9 +177,9 @@ CFStringRef CFStringConvertEncodingToIANACharSetName(CFStringEncoding encoding) if (nameList && *nameList) { CFMutableStringRef upperCaseName; - theName = CFStringCreateWithCString(NULL, *nameList, kCFStringEncodingASCII); + theName = CFStringCreateWithCString(kCFAllocatorSystemDefault, *nameList, kCFStringEncodingASCII); if (theName) { - upperCaseName = CFStringCreateMutableCopy(NULL, 0, theName); + upperCaseName = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, 0, theName); CFStringUppercase(upperCaseName, 0); CFRelease(theName); theName = upperCaseName; @@ -189,9 +190,9 @@ CFStringRef CFStringConvertEncodingToIANACharSetName(CFStringEncoding encoding) } if (theName) { - if (!mappingTable) mappingTable = CFDictionaryCreateMutable(NULL, 0, (const CFDictionaryKeyCallBacks *)NULL, &kCFTypeDictionaryValueCallBacks); + if (!mappingTable) mappingTable = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, (const CFDictionaryKeyCallBacks *)NULL, &kCFTypeDictionaryValueCallBacks); - CFDictionaryAddValue(mappingTable, (const void*)encoding, (const void*)theName); + CFDictionaryAddValue(mappingTable, (const void*)(uintptr_t)encoding, (const void*)theName); CFRelease(theName); } } @@ -223,7 +224,7 @@ enum { #define NSENCODING_MASK (1 << 31) -UInt32 CFStringConvertEncodingToNSStringEncoding(CFStringEncoding theEncoding) { +unsigned long CFStringConvertEncodingToNSStringEncoding(CFStringEncoding theEncoding) { switch (theEncoding & 0xFFF) { case kCFStringEncodingASCII: return NSASCIIStringEncoding; case kCFStringEncodingNextStepLatin: return NSNEXTSTEPStringEncoding; @@ -231,7 +232,7 @@ UInt32 CFStringConvertEncodingToNSStringEncoding(CFStringEncoding theEncoding) { case kCFStringEncodingNonLossyASCII: return NSNonLossyASCIIStringEncoding; case kCFStringEncodingWindowsLatin1: return NSWindowsCP1252StringEncoding; case kCFStringEncodingMacRoman: return NSMacOSRomanStringEncoding; -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX case kCFStringEncodingEUC_JP: return NSJapaneseEUCStringEncoding; case kCFStringEncodingMacSymbol: return NSSymbolStringEncoding; case kCFStringEncodingDOSJapanese: return NSShiftJISStringEncoding; @@ -241,10 +242,12 @@ UInt32 CFStringConvertEncodingToNSStringEncoding(CFStringEncoding theEncoding) { case kCFStringEncodingWindowsLatin5: return NSWindowsCP1254StringEncoding; case kCFStringEncodingWindowsLatin2: return NSWindowsCP1250StringEncoding; case kCFStringEncodingISO_2022_JP: return NSISO2022JPStringEncoding; +#endif +#if DEPLOYMENT_TARGET_MACOSX case kCFStringEncodingUnicode: if (theEncoding == kCFStringEncodingUTF16) return NSUnicodeStringEncoding; else if (theEncoding == kCFStringEncodingUTF8) return NSUTF8StringEncoding; -#endif // __MACH__ +#endif /* fall-through for other encoding schemes */ default: @@ -252,7 +255,7 @@ UInt32 CFStringConvertEncodingToNSStringEncoding(CFStringEncoding theEncoding) { } } -CFStringEncoding CFStringConvertNSStringEncodingToEncoding(UInt32 theEncoding) { +CFStringEncoding CFStringConvertNSStringEncodingToEncoding(unsigned long theEncoding) { switch (theEncoding) { case NSASCIIStringEncoding: return kCFStringEncodingASCII; case NSNEXTSTEPStringEncoding: return kCFStringEncodingNextStepLatin; @@ -262,7 +265,7 @@ CFStringEncoding CFStringConvertNSStringEncodingToEncoding(UInt32 theEncoding) { case NSUnicodeStringEncoding: return kCFStringEncodingUTF16; case NSWindowsCP1252StringEncoding: return kCFStringEncodingWindowsLatin1; case NSMacOSRomanStringEncoding: return kCFStringEncodingMacRoman; -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX case NSSymbolStringEncoding: return kCFStringEncodingMacSymbol; case NSJapaneseEUCStringEncoding: return kCFStringEncodingEUC_JP; case NSShiftJISStringEncoding: return kCFStringEncodingDOSJapanese; @@ -272,7 +275,7 @@ CFStringEncoding CFStringConvertNSStringEncodingToEncoding(UInt32 theEncoding) { case NSWindowsCP1253StringEncoding: return kCFStringEncodingWindowsGreek; case NSWindowsCP1254StringEncoding: return kCFStringEncodingWindowsLatin5; case NSWindowsCP1250StringEncoding: return kCFStringEncodingWindowsLatin2; -#endif // __MACH__ +#endif default: return ((theEncoding & NSENCODING_MASK) ? theEncoding & ~NSENCODING_MASK : kCFStringEncodingInvalidId); } @@ -296,12 +299,12 @@ static const uint16_t _CFEUCToCodePage[] = { // 0x900 }; UInt32 CFStringConvertEncodingToWindowsCodepage(CFStringEncoding theEncoding) { -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX CFStringEncoding encodingBase = theEncoding & 0x0FFF; #endif switch (theEncoding & 0x0F00) { -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX case 0: // Mac OS script if (encodingBase <= kCFStringEncodingMacCentralEurRoman) { return MACCODEPAGE_BASE + encodingBase; @@ -325,7 +328,7 @@ UInt32 CFStringConvertEncodingToWindowsCodepage(CFStringEncoding theEncoding) { } break; -#if defined(__MACH__) +#if (DEPLOYMENT_TARGET_MACOSX) case 0x0200: // ISO 8859 series if (encodingBase <= kCFStringEncodingISOLatin10) return ISO8859CODEPAGE_BASE + (encodingBase - 0x200); break; @@ -368,13 +371,13 @@ UInt32 CFStringConvertEncodingToWindowsCodepage(CFStringEncoding theEncoding) { case 0x0C00: // IBM EBCDIC encodings if (encodingBase == kCFStringEncodingEBCDIC_CP037) return 37; break; -#endif // __MACH__ +#endif } return kCFStringEncodingInvalidId; } -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX static const struct { uint16_t acp; uint16_t encoding; @@ -447,7 +450,7 @@ CFStringEncoding CFStringConvertWindowsCodepageToEncoding(UInt32 theEncoding) { return CFStringGetSystemEncoding(); } else if ((theEncoding >= MACCODEPAGE_BASE) && (theEncoding < 20000)) { // Mac script if (theEncoding <= 10029) return theEncoding - MACCODEPAGE_BASE; // up to Mac Central European -#if defined(__MACH__) +#if (DEPLOYMENT_TARGET_MACOSX) else if (theEncoding == 10079) return kCFStringEncodingMacIcelandic; else if (theEncoding == 10081) return kCFStringEncodingMacTurkish; else if (theEncoding == 10082) return kCFStringEncodingMacCroatian; @@ -465,7 +468,7 @@ CFStringEncoding CFStringConvertWindowsCodepageToEncoding(UInt32 theEncoding) { } else if (theEncoding == 65006) { // UTF-32BE return kCFStringEncodingUTF32BE; } else { -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX return bsearchEncoding(theEncoding); #endif } diff --git a/Base.subproj/CFSystemDirectories.c b/CFSystemDirectories.c similarity index 77% rename from Base.subproj/CFSystemDirectories.c rename to CFSystemDirectories.c index 9c2ff9e..7104c2d 100644 --- a/Base.subproj/CFSystemDirectories.c +++ b/CFSystemDirectories.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -35,7 +35,7 @@ #include #include "CFInternal.h" -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX /* We use the System framework implementation on Mach. */ @@ -53,10 +53,10 @@ CFSearchPathEnumerationState __CFGetNextSearchPathEnumeration(CFSearchPathEnumer // NSGetNextSearchPathEnumeration requires a MAX_PATH size if (pathSize < PATH_MAX) { uint8_t tempPath[PATH_MAX]; - result = NSGetNextSearchPathEnumeration(state, tempPath); - strlcpy(path, tempPath, pathSize); + result = NSGetNextSearchPathEnumeration(state, (char *)tempPath); + strlcpy((char *)path, (char *)tempPath, pathSize); } else { - result = NSGetNextSearchPathEnumeration(state, path); + result = NSGetNextSearchPathEnumeration(state, (char *)path); } return result; } @@ -64,7 +64,7 @@ CFSearchPathEnumerationState __CFGetNextSearchPathEnumeration(CFSearchPathEnumer #endif -#if defined(__MACH__) || defined(__WIN32__) +#if DEPLOYMENT_TARGET_MACOSX CFArrayRef CFCopySearchPathForDirectoriesInDomains(CFSearchPathDirectory directory, CFSearchPathDomainMask domainMask, Boolean expandTilde) { CFMutableArrayRef array; @@ -72,26 +72,26 @@ CFArrayRef CFCopySearchPathForDirectoriesInDomains(CFSearchPathDirectory directo CFIndex homeLen = -1; char cPath[CFMaxPathSize], home[CFMaxPathSize]; - array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + array = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); state = __CFStartSearchPathEnumeration(directory, domainMask); - while ((state = __CFGetNextSearchPathEnumeration(state, cPath, sizeof(cPath)))) { + while ((state = __CFGetNextSearchPathEnumeration(state, (uint8_t *)cPath, sizeof(cPath)))) { CFURLRef url = NULL; if (expandTilde && (cPath[0] == '~')) { if (homeLen < 0) { CFURLRef homeURL = CFCopyHomeDirectoryURLForUser(NULL); if (homeURL) { - CFURLGetFileSystemRepresentation(homeURL, true, home, CFMaxPathSize); + CFURLGetFileSystemRepresentation(homeURL, true, (uint8_t *)home, CFMaxPathSize); homeLen = strlen(home); CFRelease(homeURL); } } if (homeLen + strlen(cPath) < CFMaxPathSize) { home[homeLen] = '\0'; - strcat(home, &cPath[1]); - url = CFURLCreateFromFileSystemRepresentation(NULL, home, strlen(home), true); + strlcat(home, &cPath[1], sizeof(home)); + url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)home, strlen(home), true); } } else { - url = CFURLCreateFromFileSystemRepresentation(NULL, cPath, strlen(cPath), true); + url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorSystemDefault, (uint8_t *)cPath, strlen(cPath), true); } if (url) { CFArrayAppendValue(array, url); diff --git a/CFTimeZone.c b/CFTimeZone.c new file mode 100644 index 0000000..a93584b --- /dev/null +++ b/CFTimeZone.c @@ -0,0 +1,1169 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFTimeZone.c + Copyright 1998-2002, Apple, Inc. All rights reserved. + Responsibility: Christopher Kane +*/ + +#include +#include +#include "CFPriv.h" +#include "CFInternal.h" +#include +#include +#include +#include +#include +#include +#include +#if DEPLOYMENT_TARGET_MACOSX +#include +#include +#include +#include +#endif + +#if DEPLOYMENT_TARGET_MACOSX +#define TZZONELINK TZDEFAULT +#define TZZONEINFO TZDIR "/" +#endif + +CONST_STRING_DECL(kCFTimeZoneSystemTimeZoneDidChangeNotification, "kCFTimeZoneSystemTimeZoneDidChangeNotification") + +static CFTimeZoneRef __CFTimeZoneSystem = NULL; +static CFTimeZoneRef __CFTimeZoneDefault = NULL; +static CFDictionaryRef __CFTimeZoneAbbreviationDict = NULL; +static CFSpinLock_t __CFTimeZoneAbbreviationLock = CFSpinLockInit; +static CFMutableDictionaryRef __CFTimeZoneCompatibilityMappingDict = NULL; +static CFSpinLock_t __CFTimeZoneCompatibilityMappingLock = CFSpinLockInit; +static CFArrayRef __CFKnownTimeZoneList = NULL; +static CFMutableDictionaryRef __CFTimeZoneCache = NULL; +static CFSpinLock_t __CFTimeZoneGlobalLock = CFSpinLockInit; + +CF_INLINE void __CFTimeZoneLockGlobal(void) { + __CFSpinLock(&__CFTimeZoneGlobalLock); +} + +CF_INLINE void __CFTimeZoneUnlockGlobal(void) { + __CFSpinUnlock(&__CFTimeZoneGlobalLock); +} + +CF_INLINE void __CFTimeZoneLockAbbreviations(void) { + __CFSpinLock(&__CFTimeZoneAbbreviationLock); +} + +CF_INLINE void __CFTimeZoneUnlockAbbreviations(void) { + __CFSpinUnlock(&__CFTimeZoneAbbreviationLock); +} + +CF_INLINE void __CFTimeZoneLockCompatibilityMapping(void) { + __CFSpinLock(&__CFTimeZoneCompatibilityMappingLock); +} + +CF_INLINE void __CFTimeZoneUnlockCompatibilityMapping(void) { + __CFSpinUnlock(&__CFTimeZoneCompatibilityMappingLock); +} + +#if DEPLOYMENT_TARGET_MACOSX +static CFMutableArrayRef __CFCopyRecursiveDirectoryList() { + CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeArrayCallBacks); + int fd = open(TZDIR "/zone.tab", O_RDONLY); + for (; 0 <= fd;) { + uint8_t buffer[4096]; + ssize_t len = read(fd, buffer, sizeof(buffer)); + if (len <= 0) break; + if (len < sizeof(buffer)) { + // assumes that partial read only occurs at the end of the file + buffer[len] = '\n'; + len++; + } + const uint8_t *bytes = buffer; + for (;;) { + const uint8_t *nextl = memchr(bytes, '\n', len); + if (!nextl) break; + nextl++; + if ('#' == *bytes) { + len -= (nextl - bytes); + bytes = nextl; + continue; + } + const uint8_t *tab1 = memchr(bytes, '\t', (nextl - bytes)); + if (!tab1) { + len -= (nextl - bytes); + bytes = nextl; + continue; + } + tab1++; + len -= (tab1 - bytes); + bytes = tab1; + const uint8_t *tab2 = memchr(bytes, '\t', (nextl - bytes)); + if (!tab2) { + len -= (nextl - bytes); + bytes = nextl; + continue; + } + tab2++; + len -= (tab2 - bytes); + bytes = tab2; + const uint8_t *tab3 = memchr(bytes, '\t', (nextl - bytes)); + int nmlen = tab3 ? (tab3 - bytes) : (nextl - 1 - bytes); + CFStringRef string = CFStringCreateWithBytes(kCFAllocatorSystemDefault, bytes, nmlen, kCFStringEncodingUTF8, false); + CFArrayAppendValue(result, string); + CFRelease(string); + len -= (nextl - bytes); + bytes = nextl; + } + lseek(fd, -len, SEEK_CUR); + } + close(fd); + return result; +} +#else +#error Unknown or unspecified DEPLOYMENT_TARGET +#endif + +typedef struct _CFTZPeriod { + int32_t startSec; + CFStringRef abbrev; + uint32_t info; +} CFTZPeriod; + +struct __CFTimeZone { + CFRuntimeBase _base; + CFStringRef _name; /* immutable */ + CFDataRef _data; /* immutable */ + CFTZPeriod *_periods; /* immutable */ + int32_t _periodCnt; /* immutable */ +}; + +/* startSec is the whole integer seconds from a CFAbsoluteTime, giving dates + * between 1933 and 2069; info outside these years is discarded on read-in */ +/* Bits 31-18 of the info are unused */ +/* Bit 17 of the info is used for the is-DST state */ +/* Bit 16 of the info is used for the sign of the offset (1 == negative) */ +/* Bits 15-0 of the info are used for abs(offset) in seconds from GMT */ + +CF_INLINE void __CFTZPeriodInit(CFTZPeriod *period, int32_t startTime, CFStringRef abbrev, int32_t offset, Boolean isDST) { + period->startSec = startTime; + period->abbrev = abbrev ? (CFStringRef)CFRetain(abbrev) : NULL; + __CFBitfieldSetValue(period->info, 15, 0, abs(offset)); + __CFBitfieldSetValue(period->info, 16, 16, (offset < 0 ? 1 : 0)); + __CFBitfieldSetValue(period->info, 17, 17, (isDST ? 1 : 0)); +} + +CF_INLINE int32_t __CFTZPeriodStartSeconds(const CFTZPeriod *period) { + return period->startSec; +} + +CF_INLINE CFStringRef __CFTZPeriodAbbreviation(const CFTZPeriod *period) { + return period->abbrev; +} + +CF_INLINE int32_t __CFTZPeriodGMTOffset(const CFTZPeriod *period) { + int32_t v = __CFBitfieldGetValue(period->info, 15, 0); + if (__CFBitfieldGetValue(period->info, 16, 16)) v = -v; + return v; +} + +CF_INLINE Boolean __CFTZPeriodIsDST(const CFTZPeriod *period) { + return (Boolean)__CFBitfieldGetValue(period->info, 17, 17); +} + +static CFComparisonResult __CFCompareTZPeriods(const void *val1, const void *val2, void *context) { + CFTZPeriod *tzp1 = (CFTZPeriod *)val1; + CFTZPeriod *tzp2 = (CFTZPeriod *)val2; + // we treat equal as less than, as the code which uses the + // result of the bsearch doesn't expect exact matches + // (they're pretty rare, so no point in over-coding for them) + if (__CFTZPeriodStartSeconds(tzp1) <= __CFTZPeriodStartSeconds(tzp2)) return kCFCompareLessThan; + return kCFCompareGreaterThan; +} + +static CFIndex __CFBSearchTZPeriods(CFTimeZoneRef tz, CFAbsoluteTime at) { + CFTZPeriod elem; + __CFTZPeriodInit(&elem, (int32_t)floor(at), NULL, 0, false); + CFIndex idx = CFBSearch(&elem, sizeof(CFTZPeriod), tz->_periods, tz->_periodCnt, __CFCompareTZPeriods, NULL); + if (tz->_periodCnt <= idx) { + idx = tz->_periodCnt; + } else if (0 == idx) { + idx = 1; + } + return idx - 1; +} + + +CF_INLINE int32_t __CFDetzcode(const unsigned char *bufp) { + int32_t result = (bufp[0] & 0x80) ? ~0L : 0L; + result = (result << 8) | (bufp[0] & 0xff); + result = (result << 8) | (bufp[1] & 0xff); + result = (result << 8) | (bufp[2] & 0xff); + result = (result << 8) | (bufp[3] & 0xff); + return result; +} + +CF_INLINE void __CFEntzcode(int32_t value, unsigned char *bufp) { + bufp[0] = (value >> 24) & 0xff; + bufp[1] = (value >> 16) & 0xff; + bufp[2] = (value >> 8) & 0xff; + bufp[3] = (value >> 0) & 0xff; +} + +#if DEPLOYMENT_TARGET_MACOSX +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; + CFStringRef *abbrs; + Boolean result = true; + + p = CFDataGetBytePtr(data); + len = CFDataGetLength(data); + if (len < (int32_t)sizeof(struct tzhead)) { + return false; + } + + if (!(p[0] == 'T' && p[1] == 'Z' && p[2] == 'i' && p[3] == 'f')) return false; /* Don't parse without TZif at head of file */ + + p += 20 + 4 + 4 + 4; /* skip reserved, ttisgmtcnt, ttisstdcnt, leapcnt */ + timecnt = __CFDetzcode(p); + p += 4; + typecnt = __CFDetzcode(p); + p += 4; + charcnt = __CFDetzcode(p); + p += 4; + if (typecnt <= 0 || timecnt < 0 || charcnt < 0) { + return false; + } + if (1024 < timecnt || 32 < typecnt || 128 < charcnt) { + // reject excessive timezones to avoid arithmetic overflows for + // security reasons and to reject potentially corrupt files + return false; + } + if (len - (int32_t)sizeof(struct tzhead) < (4 + 1) * timecnt + (4 + 1 + 1) * typecnt + charcnt) { + return false; + } + timep = p; + typep = timep + 4 * timecnt; + ttisp = typep + timecnt; + charp = ttisp + (4 + 1 + 1) * typecnt; + cnt = (0 < timecnt) ? timecnt : 1; + *tzpp = CFAllocatorAllocate(allocator, cnt * sizeof(CFTZPeriod), 0); + if (__CFOASafe) __CFSetLastAllocationEventName(*tzpp, "CFTimeZone (store)"); + memset(*tzpp, 0, cnt * sizeof(CFTZPeriod)); + abbrs = CFAllocatorAllocate(allocator, (charcnt + 1) * sizeof(CFStringRef), 0); + if (__CFOASafe) __CFSetLastAllocationEventName(abbrs, "CFTimeZone (temp)"); + for (idx = 0; idx < charcnt + 1; idx++) { + abbrs[idx] = NULL; + } + for (idx = 0; idx < cnt; idx++) { + CFAbsoluteTime at; + int32_t itime, offset; + uint8_t type, dst, abbridx; + + at = (CFAbsoluteTime)(__CFDetzcode(timep) + 0.0) - kCFAbsoluteTimeIntervalSince1970; + if (0 == timecnt) itime = INT_MIN; + else if (at < (CFAbsoluteTime)INT_MIN) itime = INT_MIN; + else if ((CFAbsoluteTime)INT_MAX < at) itime = INT_MAX; + else itime = (int32_t)at; + timep += 4; /* harmless if 0 == timecnt */ + type = (0 < timecnt) ? (uint8_t)*typep++ : 0; + if (typecnt <= type) { + result = false; + break; + } + offset = __CFDetzcode(ttisp + 6 * type); + dst = (uint8_t)*(ttisp + 6 * type + 4); + if (0 != dst && 1 != dst) { + result = false; + break; + } + abbridx = (uint8_t)*(ttisp + 6 * type + 5); + if (charcnt < abbridx) { + result = false; + break; + } + if (NULL == abbrs[abbridx]) { + abbrs[abbridx] = CFStringCreateWithCString(allocator, (char *)&charp[abbridx], kCFStringEncodingASCII); + } + __CFTZPeriodInit(*tzpp + idx, itime, abbrs[abbridx], offset, (dst ? true : false)); + } + for (idx = 0; idx < charcnt + 1; idx++) { + if (NULL != abbrs[idx]) { + CFRelease(abbrs[idx]); + } + } + CFAllocatorDeallocate(allocator, abbrs); + if (result) { + // dump all but the last INT_MIN and the first INT_MAX + for (idx = 0; idx < cnt; idx++) { + if (((*tzpp + idx)->startSec == INT_MIN) && (idx + 1 < cnt) && (((*tzpp + idx + 1)->startSec == INT_MIN))) { + if (NULL != (*tzpp + idx)->abbrev) CFRelease((*tzpp + idx)->abbrev); + cnt--; + memmove((*tzpp + idx), (*tzpp + idx + 1), sizeof(CFTZPeriod) * (cnt - idx)); + idx--; + } + } + // Don't combine these loops! Watch the idx decrementing... + for (idx = 0; idx < cnt; idx++) { + if (((*tzpp + idx)->startSec == INT_MAX) && (0 < idx) && (((*tzpp + idx - 1)->startSec == INT_MAX))) { + if (NULL != (*tzpp + idx)->abbrev) CFRelease((*tzpp + idx)->abbrev); + cnt--; + memmove((*tzpp + idx), (*tzpp + idx + 1), sizeof(CFTZPeriod) * (cnt - idx)); + idx--; + } + } + CFQSortArray(*tzpp, cnt, sizeof(CFTZPeriod), __CFCompareTZPeriods, NULL); + // if the first period is in DST and there is more than one period, drop it + if (1 < cnt && __CFTZPeriodIsDST(*tzpp + 0)) { + if (NULL != (*tzpp + 0)->abbrev) CFRelease((*tzpp + 0)->abbrev); + cnt--; + memmove((*tzpp + 0), (*tzpp + 0 + 1), sizeof(CFTZPeriod) * (cnt - 0)); + } + *cntp = cnt; + } else { + CFAllocatorDeallocate(allocator, *tzpp); + *tzpp = NULL; + } + return result; +} +#elif 0 || 0 +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; + CFTimeZoneRef tz2 = (CFTimeZoneRef)cf2; + if (!CFEqual(CFTimeZoneGetName(tz1), CFTimeZoneGetName(tz2))) return false; + if (!CFEqual(CFTimeZoneGetData(tz1), CFTimeZoneGetData(tz2))) return false; + return true; +} + +static CFHashCode __CFTimeZoneHash(CFTypeRef cf) { + CFTimeZoneRef tz = (CFTimeZoneRef)cf; + return CFHash(CFTimeZoneGetName(tz)); +} + +static CFStringRef __CFTimeZoneCopyDescription(CFTypeRef cf) { + CFTimeZoneRef tz = (CFTimeZoneRef)cf; + CFStringRef result, abbrev; + CFAbsoluteTime at; + at = CFAbsoluteTimeGetCurrent(); + abbrev = CFTimeZoneCopyAbbreviation(tz, at); + result = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("{name = %@; abbreviation = %@; GMT offset = %g; is DST = %s}"), cf, CFGetAllocator(tz), tz->_name, abbrev, CFTimeZoneGetSecondsFromGMT(tz, at), CFTimeZoneIsDaylightSavingTime(tz, at) ? "true" : "false"); + CFRelease(abbrev); + return result; +} + +static void __CFTimeZoneDeallocate(CFTypeRef cf) { + CFTimeZoneRef tz = (CFTimeZoneRef)cf; + CFAllocatorRef allocator = CFGetAllocator(tz); + CFIndex idx; + if (tz->_name) CFRelease(tz->_name); + if (tz->_data) CFRelease(tz->_data); + for (idx = 0; idx < tz->_periodCnt; idx++) { + if (NULL != tz->_periods[idx].abbrev) CFRelease(tz->_periods[idx].abbrev); + } + if (NULL != tz->_periods) CFAllocatorDeallocate(allocator, tz->_periods); +} + +static CFTypeID __kCFTimeZoneTypeID = _kCFRuntimeNotATypeID; + +static const CFRuntimeClass __CFTimeZoneClass = { + 0, + "CFTimeZone", + NULL, // init + NULL, // copy + __CFTimeZoneDeallocate, + __CFTimeZoneEqual, + __CFTimeZoneHash, + NULL, // + __CFTimeZoneCopyDescription +}; + +__private_extern__ void __CFTimeZoneInitialize(void) { + __kCFTimeZoneTypeID = _CFRuntimeRegisterClass(&__CFTimeZoneClass); +} + +CFTypeID CFTimeZoneGetTypeID(void) { + return __kCFTimeZoneTypeID; +} + + +#if DEPLOYMENT_TARGET_MACOSX +static CFTimeZoneRef __CFTimeZoneCreateSystem(void) { + CFTimeZoneRef result = NULL; + + + char *tzenv; + int ret; + char linkbuf[CFMaxPathSize]; + + tzenv = getenv("TZFILE"); + if (NULL != tzenv) { + CFStringRef name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)tzenv, strlen(tzenv), kCFStringEncodingUTF8, false); + result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false); + CFRelease(name); + if (result) return result; + } + tzenv = getenv("TZ"); + if (NULL != tzenv) { + CFStringRef name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)tzenv, strlen(tzenv), kCFStringEncodingUTF8, false); + result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, true); + CFRelease(name); + if (result) return result; + } + ret = readlink(TZZONELINK, linkbuf, sizeof(linkbuf)); + if (0 < ret) { + CFStringRef name; + linkbuf[ret] = '\0'; + if (strncmp(linkbuf, TZZONEINFO, sizeof(TZZONEINFO) - 1) == 0) { + name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)linkbuf + sizeof(TZZONEINFO) - 1, strlen(linkbuf) - sizeof(TZZONEINFO) + 1, kCFStringEncodingUTF8, false); + } else { + name = CFStringCreateWithBytes(kCFAllocatorSystemDefault, (uint8_t *)linkbuf, strlen(linkbuf), kCFStringEncodingUTF8, false); + } + result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false); + CFRelease(name); + if (result) return result; + } + return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault, 0.0); +} +#elif 0 || 0 +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; + __CFTimeZoneLockGlobal(); + if (NULL == __CFTimeZoneSystem) { + __CFTimeZoneUnlockGlobal(); + tz = __CFTimeZoneCreateSystem(); + __CFTimeZoneLockGlobal(); + if (NULL == __CFTimeZoneSystem) { + __CFTimeZoneSystem = tz; + } else { + if (tz) CFRelease(tz); + } + } + tz = __CFTimeZoneSystem ? (CFTimeZoneRef)CFRetain(__CFTimeZoneSystem) : NULL; + __CFTimeZoneUnlockGlobal(); + return tz; +} + +static CFIndex __noteCount = 0; + +void CFTimeZoneResetSystem(void) { + __CFTimeZoneLockGlobal(); + if (__CFTimeZoneDefault == __CFTimeZoneSystem) { + if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault); + __CFTimeZoneDefault = NULL; + } + CFTimeZoneRef tz = __CFTimeZoneSystem; + __CFTimeZoneSystem = NULL; + __CFTimeZoneUnlockGlobal(); + if (tz) CFRelease(tz); +} + +CFIndex _CFTimeZoneGetNoteCount(void) { + return __noteCount; +} + +CFTimeZoneRef CFTimeZoneCopyDefault(void) { + CFTimeZoneRef tz; + __CFTimeZoneLockGlobal(); + if (NULL == __CFTimeZoneDefault) { + __CFTimeZoneUnlockGlobal(); + tz = CFTimeZoneCopySystem(); + __CFTimeZoneLockGlobal(); + if (NULL == __CFTimeZoneDefault) { + __CFTimeZoneDefault = tz; + } else { + if (tz) CFRelease(tz); + } + } + tz = __CFTimeZoneDefault ? (CFTimeZoneRef)CFRetain(__CFTimeZoneDefault) : NULL; + __CFTimeZoneUnlockGlobal(); + return tz; +} + +void CFTimeZoneSetDefault(CFTimeZoneRef tz) { + if (tz) __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); + __CFTimeZoneLockGlobal(); + if (tz != __CFTimeZoneDefault) { + if (tz) CFRetain(tz); + if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault); + __CFTimeZoneDefault = tz; + } + __CFTimeZoneUnlockGlobal(); +} + +static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void); + +CFArrayRef CFTimeZoneCopyKnownNames(void) { + CFArrayRef tzs; + __CFTimeZoneLockGlobal(); + if (NULL == __CFKnownTimeZoneList) { + CFMutableArrayRef list; +/* TimeZone information locate in the registry for Win32 + * (Aleksey Dukhnyakov) + */ +#if DEPLOYMENT_TARGET_MACOSX + list = __CFCopyRecursiveDirectoryList(); +#else +#error Unknown or unspecified DEPLOYMENT_TARGET +#endif + // Remove undesirable ancient cruft + CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary(); + CFIndex idx; + for (idx = CFArrayGetCount(list); idx--; ) { + CFStringRef item = (CFStringRef)CFArrayGetValueAtIndex(list, idx); + if (CFDictionaryContainsKey(dict, item)) { + CFArrayRemoveValueAtIndex(list, idx); + } + } + __CFKnownTimeZoneList = CFArrayCreateCopy(kCFAllocatorSystemDefault, list); + CFRelease(list); + } + tzs = __CFKnownTimeZoneList ? (CFArrayRef)CFRetain(__CFKnownTimeZoneList) : NULL; + __CFTimeZoneUnlockGlobal(); + return tzs; +} + +#if DEPLOYMENT_TARGET_MACOSX +/* 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. + */ +static const char *__CFTimeZoneAbbreviationDefaults = +"" +" " +" " +" " +" ADT America/Halifax" +" AKDT America/Juneau" +" AKST America/Juneau" +" ART America/Argentina/Buenos_Aires" +" AST America/Halifax" +" BDT Asia/Dhaka" +" BRST America/Sao_Paulo" +" BRT America/Sao_Paulo" +" BST Europe/London" +" CAT Africa/Harare" +" CDT America/Chicago" +" CEST Europe/Paris" +" CET Europe/Paris" +" CLST America/Santiago" +" CLT America/Santiago" +" COT America/Bogota" +" CST America/Chicago" +" EAT Africa/Addis_Ababa" +" EDT America/New_York" +" EEST Europe/Istanbul" +" EET Europe/Istanbul" +" EST America/New_York" +" GMT GMT" +" GST Asia/Dubai" +" HKT Asia/Hong_Kong" +" HST Pacific/Honolulu" +" ICT Asia/Bangkok" +" IRST Asia/Tehran" +" IST Asia/Calcutta" +" JST Asia/Tokyo" +" KST Asia/Seoul" +" MDT America/Denver" +" MSD Europe/Moscow" +" MSK Europe/Moscow" +" MST America/Denver" +" NZDT Pacific/Auckland" +" NZST Pacific/Auckland" +" PDT America/Los_Angeles" +" PET America/Lima" +" PHT Asia/Manila" +" PKT Asia/Karachi" +" PST America/Los_Angeles" +" SGT Asia/Singapore" +" UTC UTC" +" WAT Africa/Lagos" +" WEST Europe/Lisbon" +" WET Europe/Lisbon" +" WIT Asia/Jakarta" +" " +" "; +#elif 0 || 0 +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; + __CFTimeZoneLockAbbreviations(); + if (NULL == __CFTimeZoneAbbreviationDict) { + CFDataRef data = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)__CFTimeZoneAbbreviationDefaults, strlen(__CFTimeZoneAbbreviationDefaults)); + __CFTimeZoneAbbreviationDict = (CFDictionaryRef)CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListImmutable, NULL); + CFRelease(data); + } + if (NULL == __CFTimeZoneAbbreviationDict) { + __CFTimeZoneAbbreviationDict = CFDictionaryCreate(kCFAllocatorSystemDefault, NULL, NULL, 0, NULL, NULL); + } + dict = __CFTimeZoneAbbreviationDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneAbbreviationDict) : NULL; + __CFTimeZoneUnlockAbbreviations(); + return dict; +} + +void CFTimeZoneSetAbbreviationDictionary(CFDictionaryRef dict) { + __CFGenericValidateType(dict, CFDictionaryGetTypeID()); + __CFTimeZoneLockGlobal(); + if (dict != __CFTimeZoneAbbreviationDict) { + if (dict) CFRetain(dict); + if (__CFTimeZoneAbbreviationDict) { + CFIndex count, idx; + count = CFDictionaryGetCount(__CFTimeZoneAbbreviationDict); + CFTypeRef *keys = (CFTypeRef *)malloc(sizeof(CFTypeRef *) * count); + for (idx = 0; idx < count; idx++) { + CFDictionaryRemoveValue(__CFTimeZoneCache, (CFStringRef)keys[idx]); + } + free(keys); + CFRelease(__CFTimeZoneAbbreviationDict); + } + __CFTimeZoneAbbreviationDict = dict; + } + __CFTimeZoneUnlockGlobal(); +} + +CFTimeZoneRef CFTimeZoneCreate(CFAllocatorRef allocator, CFStringRef name, CFDataRef data) { +// assert: (NULL != name && NULL != data); + CFTimeZoneRef memory; + uint32_t size; + CFTZPeriod *tzp = NULL; + CFIndex idx, cnt = 0; + + if (allocator == NULL) allocator = __CFGetDefaultAllocator(); + __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); + __CFGenericValidateType(name, CFStringGetTypeID()); + __CFGenericValidateType(data, CFDataGetTypeID()); + __CFTimeZoneLockGlobal(); + if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&memory)) { + __CFTimeZoneUnlockGlobal(); + return (CFTimeZoneRef)CFRetain(memory); + } + if (!__CFParseTimeZoneData(allocator, data, &tzp, &cnt)) { + __CFTimeZoneUnlockGlobal(); + return NULL; + } + size = sizeof(struct __CFTimeZone) - sizeof(CFRuntimeBase); + memory = (CFTimeZoneRef)_CFRuntimeCreateInstance(allocator, CFTimeZoneGetTypeID(), size, NULL); + if (NULL == memory) { + __CFTimeZoneUnlockGlobal(); + for (idx = 0; idx < cnt; idx++) { + if (NULL != tzp[idx].abbrev) CFRelease(tzp[idx].abbrev); + } + if (NULL != tzp) CFAllocatorDeallocate(allocator, tzp); + return NULL; + } + ((struct __CFTimeZone *)memory)->_name = (CFStringRef)CFStringCreateCopy(allocator, name); + ((struct __CFTimeZone *)memory)->_data = CFDataCreateCopy(allocator, data); + ((struct __CFTimeZone *)memory)->_periods = tzp; + ((struct __CFTimeZone *)memory)->_periodCnt = cnt; + if (NULL == __CFTimeZoneCache) { + __CFTimeZoneCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + } + CFDictionaryAddValue(__CFTimeZoneCache, ((struct __CFTimeZone *)memory)->_name, memory); + __CFTimeZoneUnlockGlobal(); + return memory; +} + +#if DEPLOYMENT_TARGET_MACOSX +static CFTimeZoneRef __CFTimeZoneCreateFixed(CFAllocatorRef allocator, int32_t seconds, CFStringRef name, int isDST) { + CFTimeZoneRef result; + CFDataRef data; + int32_t nameLen = CFStringGetLength(name); + unsigned char dataBytes[52 + nameLen + 1]; + memset(dataBytes, 0, sizeof(dataBytes)); + + // Put in correct magic bytes for timezone structures + dataBytes[0] = 'T'; + dataBytes[1] = 'Z'; + dataBytes[2] = 'i'; + dataBytes[3] = 'f'; + + __CFEntzcode(1, dataBytes + 20); + __CFEntzcode(1, dataBytes + 24); + __CFEntzcode(1, dataBytes + 36); + __CFEntzcode(nameLen + 1, dataBytes + 40); + __CFEntzcode(seconds, dataBytes + 44); + dataBytes[48] = isDST ? 1 : 0; + CFStringGetCString(name, (char *)dataBytes + 50, nameLen + 1, kCFStringEncodingASCII); + data = CFDataCreate(allocator, dataBytes, 52 + nameLen + 1); + result = CFTimeZoneCreate(allocator, name, data); + CFRelease(data); + return result; +} +#elif 0 || 0 +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) { + CFTimeZoneRef result; + CFStringRef name; + int32_t seconds, minute, hour; + if (allocator == NULL) allocator = __CFGetDefaultAllocator(); + __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); + if (ti < -18.0 * 3600 || 18.0 * 3600 < ti) return NULL; + ti = (ti < 0.0) ? ceil((ti / 60.0) - 0.5) * 60.0 : floor((ti / 60.0) + 0.5) * 60.0; + seconds = (int32_t)ti; + hour = (ti < 0) ? (-seconds / 3600) : (seconds / 3600); + seconds -= ((ti < 0) ? -hour : hour) * 3600; + minute = (ti < 0) ? (-seconds / 60) : (seconds / 60); + if (fabs(ti) < 1.0) { + name = (CFStringRef)CFRetain(CFSTR("GMT")); + } else { + name = CFStringCreateWithFormat(allocator, NULL, CFSTR("GMT%c%02d%02d"), (ti < 0.0 ? '-' : '+'), hour, minute); + } + result = __CFTimeZoneCreateFixed(allocator, (int32_t)ti, name, 0); + CFRelease(name); + return result; +} + +CFTimeZoneRef CFTimeZoneCreateWithName(CFAllocatorRef allocator, CFStringRef name, Boolean tryAbbrev) { + CFTimeZoneRef result = NULL; + CFStringRef tzName = NULL; + CFDataRef data = NULL; + + if (allocator == NULL) allocator = __CFGetDefaultAllocator(); + __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); + __CFGenericValidateType(name, CFStringGetTypeID()); + if (CFEqual(CFSTR(""), name)) { + // empty string is not a time zone name, just abort now, + // following stuff will fail anyway + return NULL; + } + __CFTimeZoneLockGlobal(); + if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&result)) { + __CFTimeZoneUnlockGlobal(); + return (CFTimeZoneRef)CFRetain(result); + } + __CFTimeZoneUnlockGlobal(); +#if DEPLOYMENT_TARGET_MACOSX + CFURLRef baseURL, tempURL; + void *bytes; + CFIndex length; + + baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, CFSTR(TZZONEINFO), kCFURLPOSIXPathStyle, true); + if (tryAbbrev) { + CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary(); + tzName = CFDictionaryGetValue(abbrevs, name); + if (NULL != tzName) { + tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, tzName, false); + if (NULL != tempURL) { + if (_CFReadBytesFromFile(kCFAllocatorSystemDefault, tempURL, &bytes, &length, 0)) { + data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, bytes, length, kCFAllocatorSystemDefault); + } + CFRelease(tempURL); + } + } + CFRelease(abbrevs); + } + if (NULL == data) { + CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary(); + CFStringRef mapping = CFDictionaryGetValue(dict, name); + if (mapping) { + name = mapping; + } else if (CFStringHasPrefix(name, CFSTR(TZZONEINFO))) { + CFMutableStringRef unprefixed = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, CFStringGetLength(name), name); + CFStringDelete(unprefixed, CFRangeMake(0, sizeof(TZZONEINFO))); + mapping = CFDictionaryGetValue(dict, unprefixed); + if (mapping) { + name = mapping; + } + CFRelease(unprefixed); + } + CFRelease(dict); + if (CFEqual(CFSTR(""), name)) { + return NULL; + } + } + if (NULL == data) { + tzName = name; + tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, baseURL, tzName, false); + if (NULL != tempURL) { + if (_CFReadBytesFromFile(kCFAllocatorSystemDefault, tempURL, &bytes, &length, 0)) { + data = CFDataCreateWithBytesNoCopy(kCFAllocatorSystemDefault, bytes, length, kCFAllocatorSystemDefault); + } + CFRelease(tempURL); + } + } + CFRelease(baseURL); + if (NULL != data) { + result = CFTimeZoneCreate(allocator, tzName, data); + if (name != tzName) { + CFStringRef nameCopy = (CFStringRef)CFStringCreateCopy(allocator, name); + __CFTimeZoneLockGlobal(); + CFDictionaryAddValue(__CFTimeZoneCache, nameCopy, result); + __CFTimeZoneUnlockGlobal(); + CFRelease(nameCopy); + } + CFRelease(data); + } + return result; +} +#elif 0 || 0 +/* 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"); + __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); + return tz->_name; +} + +CFDataRef CFTimeZoneGetData(CFTimeZoneRef tz) { + CF_OBJC_FUNCDISPATCH0(CFTimeZoneGetTypeID(), CFDataRef, tz, "data"); + __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); + return tz->_data; +} + +CFTimeInterval CFTimeZoneGetSecondsFromGMT(CFTimeZoneRef tz, CFAbsoluteTime at) { +#if DEPLOYMENT_TARGET_MACOSX + CFIndex idx; + CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval, tz, "_secondsFromGMTForAbsoluteTime:", at); + __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); + idx = __CFBSearchTZPeriods(tz, at); + return __CFTZPeriodGMTOffset(&(tz->_periods[idx])); +#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 + idx = __CFBSearchTZPeriods(tz, at); +#endif + result = __CFTZPeriodAbbreviation(&(tz->_periods[idx])); + return result ? (CFStringRef)CFRetain(result) : NULL; +} + +Boolean CFTimeZoneIsDaylightSavingTime(CFTimeZoneRef tz, CFAbsoluteTime at) { +#if DEPLOYMENT_TARGET_MACOSX + CFIndex idx; + CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), Boolean, tz, "_isDaylightSavingTimeForAbsoluteTime:", at); + __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); + idx = __CFBSearchTZPeriods(tz, at); + return __CFTZPeriodIsDST(&(tz->_periods[idx])); +#endif +} + +CFTimeInterval CFTimeZoneGetDaylightSavingTimeOffset(CFTimeZoneRef tz, CFAbsoluteTime at) { + CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval, tz, "_daylightSavingTimeOffsetForAbsoluteTime:", at); + __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); + CFIndex idx = __CFBSearchTZPeriods(tz, at); + if (__CFTZPeriodIsDST(&(tz->_periods[idx]))) { + CFTimeInterval offset = __CFTZPeriodGMTOffset(&(tz->_periods[idx])); + if (idx + 1 < tz->_periodCnt) { + return offset - __CFTZPeriodGMTOffset(&(tz->_periods[idx + 1])); + } else if (0 < idx) { + return offset - __CFTZPeriodGMTOffset(&(tz->_periods[idx - 1])); + } + } + return 0.0; +} + +CFAbsoluteTime CFTimeZoneGetNextDaylightSavingTimeTransition(CFTimeZoneRef tz, CFAbsoluteTime at) { + CF_OBJC_FUNCDISPATCH1(CFTimeZoneGetTypeID(), CFTimeInterval, tz, "_nextDaylightSavingTimeTransitionAfterAbsoluteTime:", at); + __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); + CFIndex idx = __CFBSearchTZPeriods(tz, at); + if (tz->_periodCnt <= idx + 1) { + return 0.0; + } + return (CFAbsoluteTime)__CFTZPeriodStartSeconds(&(tz->_periods[idx + 1])); +} + +enum { + kCFTimeZoneNameStyleGeneric = 4, + kCFTimeZoneNameStyleShortGeneric = 5 +}; + +extern UCalendar *__CFCalendarCreateUCalendar(CFStringRef calendarID, CFStringRef localeID, CFTimeZoneRef tz); + +#define BUFFER_SIZE 768 + +CFStringRef CFTimeZoneCopyLocalizedName(CFTimeZoneRef tz, CFTimeZoneNameStyle style, CFLocaleRef locale) { + CF_OBJC_FUNCDISPATCH2(CFTimeZoneGetTypeID(), CFStringRef, tz, "localizedName:locale:", style, locale); + __CFGenericValidateType(tz, CFTimeZoneGetTypeID()); + __CFGenericValidateType(locale, CFLocaleGetTypeID()); + + + CFStringRef localeID = CFLocaleGetIdentifier(locale); + UCalendar *cal = __CFCalendarCreateUCalendar(NULL, localeID, tz); + if (NULL == cal) { + return NULL; + } + + char buffer[BUFFER_SIZE]; + const char *cstr = CFStringGetCStringPtr(localeID, kCFStringEncodingASCII); + if (NULL == cstr) { + if (CFStringGetCString(localeID, buffer, BUFFER_SIZE, kCFStringEncodingASCII)) cstr = buffer; + } + if (NULL == cstr) { + ucal_close(cal); + return NULL; + } + + UChar ubuffer[BUFFER_SIZE]; + UErrorCode status = U_ZERO_ERROR; + int32_t cnt = ucal_getTimeZoneDisplayName(cal, (UCalendarDisplayNameType)style, cstr, ubuffer, BUFFER_SIZE, &status); + ucal_close(cal); + if (U_SUCCESS(status) && cnt <= BUFFER_SIZE) { + return CFStringCreateWithCharacters(CFGetAllocator(tz), (const UniChar *)ubuffer, cnt); + } + return NULL; +} + +static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void) { + CFDictionaryRef dict; + __CFTimeZoneLockCompatibilityMapping(); + if (NULL == __CFTimeZoneCompatibilityMappingDict) { + __CFTimeZoneCompatibilityMappingDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 112, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + + // Empty string means delete/ignore these + } + dict = __CFTimeZoneCompatibilityMappingDict ? (CFDictionaryRef)CFRetain(__CFTimeZoneCompatibilityMappingDict) : NULL; + __CFTimeZoneUnlockCompatibilityMapping(); + return dict; +} + +#undef TZZONEINFO +#undef TZZONELINK + diff --git a/NumberDate.subproj/CFTimeZone.h b/CFTimeZone.h similarity index 71% rename from NumberDate.subproj/CFTimeZone.h rename to CFTimeZone.h index 0e26e71..8b976fb 100644 --- a/NumberDate.subproj/CFTimeZone.h +++ b/CFTimeZone.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFTimeZone.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFTIMEZONE__) @@ -34,9 +34,7 @@ #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN CF_EXPORT CFTypeID CFTimeZoneGetTypeID(void); @@ -86,9 +84,29 @@ CFStringRef CFTimeZoneCopyAbbreviation(CFTimeZoneRef tz, CFAbsoluteTime at); CF_EXPORT Boolean CFTimeZoneIsDaylightSavingTime(CFTimeZoneRef tz, CFAbsoluteTime at); -#if defined(__cplusplus) -} +CF_EXPORT +CFTimeInterval CFTimeZoneGetDaylightSavingTimeOffset(CFTimeZoneRef tz, CFAbsoluteTime at) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; + +CF_EXPORT +CFAbsoluteTime CFTimeZoneGetNextDaylightSavingTimeTransition(CFTimeZoneRef tz, CFAbsoluteTime at) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; + +#if MAC_OS_X_VERSION_10_5 <= MAC_OS_X_VERSION_MAX_ALLOWED +enum { + kCFTimeZoneNameStyleStandard, + kCFTimeZoneNameStyleShortStandard, + kCFTimeZoneNameStyleDaylightSaving, + kCFTimeZoneNameStyleShortDaylightSaving +}; +typedef CFIndex CFTimeZoneNameStyle; + +CF_EXPORT +CFStringRef CFTimeZoneCopyLocalizedName(CFTimeZoneRef tz, CFTimeZoneNameStyle style, CFLocaleRef locale) AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; #endif +CF_EXPORT +const CFStringRef kCFTimeZoneSystemTimeZoneDidChangeNotification AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER; + +CF_EXTERN_C_END + #endif /* ! __COREFOUNDATION_CFTIMEZONE__ */ diff --git a/Collections.subproj/CFTree.c b/CFTree.c similarity index 95% rename from Collections.subproj/CFTree.c rename to CFTree.c index 476c7c2..a01feaf 100644 --- a/Collections.subproj/CFTree.c +++ b/CFTree.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -27,7 +27,7 @@ #include #include "CFInternal.h" -#include "CFUtilitiesPriv.h" +#include "CFPriv.h" struct __CFTreeCallBacks { CFTreeRetainCallBack retain; @@ -58,7 +58,7 @@ enum { /* Bits 0-1 */ }; CF_INLINE uint32_t __CFTreeGetCallBacksType(CFTreeRef tree) { - return (__CFBitfieldGetValue(tree->_base._info, 1, 0)); + return (__CFBitfieldGetValue(tree->_base._cfinfo[CF_INFO_BITS], 1, 0)); } CF_INLINE const struct __CFTreeCallBacks *__CFTreeGetCallBacks(CFTreeRef tree) { @@ -160,7 +160,7 @@ CFTreeRef CFTreeCreate(CFAllocatorRef allocator, const CFTreeContext *context) { memory->_rightmostChild = NULL; /* Start the context off in a recognizable state */ - __CFBitfieldSetValue(memory->_base._info, 1, 0, __kCFTreeHasNullCallBacks); + __CFBitfieldSetValue(memory->_base._cfinfo[CF_INFO_BITS], 1, 0, __kCFTreeHasNullCallBacks); CFTreeSetContext(memory, context); return memory; } @@ -206,15 +206,12 @@ void CFTreeGetContext(CFTreeRef tree, CFTreeContext *context) { cb = __CFTreeGetCallBacks(tree); context->version = 0; context->info = tree->_info; -#if defined(__ppc__) - context->retain = (void *)((uintptr_t)cb->retain & ~0x3); - context->release = (void *)((uintptr_t)cb->release & ~0x3); - context->copyDescription = (void *)((uintptr_t)cb->copyDescription & ~0x3); -#else context->retain = cb->retain; context->release = cb->release; context->copyDescription = cb->copyDescription; -#endif + UNFAULT_CALLBACK(context->retain); + UNFAULT_CALLBACK(context->release); + UNFAULT_CALLBACK(context->copyDescription); } void CFTreeSetContext(CFTreeRef tree, const CFTreeContext *context) { @@ -239,7 +236,7 @@ void CFTreeSetContext(CFTreeRef tree, const CFTreeContext *context) { FAULT_CALLBACK((void **)&(tree->_callbacks->release)); FAULT_CALLBACK((void **)&(tree->_callbacks->copyDescription)); } - __CFBitfieldSetValue(tree->_base._info, 1, 0, newtype); + __CFBitfieldSetValue(tree->_base._cfinfo[CF_INFO_BITS], 1, 0, newtype); newcb = (struct __CFTreeCallBacks *)__CFTreeGetCallBacks(tree); if (NULL != newcb->retain) { tree->_info = (void *)INVOKE_CALLBACK1(newcb->retain, context->info); @@ -446,7 +443,7 @@ void CFTreeSortChildren(CFTreeRef tree, CFComparatorFunction comparator, void *c CFTreeRef *list, buffer[128]; CFAllocatorRef allocator = __CFGetAllocator(tree); - list = (children < 128) ? buffer : CFAllocatorAllocate(kCFAllocatorDefault, children * sizeof(CFTreeRef), 0); // XXX_PCB GC OK + list = (children < 128) ? buffer : (CFTreeRef *)CFAllocatorAllocate(kCFAllocatorSystemDefault, children * sizeof(CFTreeRef), 0); // XXX_PCB GC OK if (__CFOASafe && list != buffer) __CFSetLastAllocationEventName(tree->_callbacks, "CFTree (temp)"); nextChild = tree->_child; for (idx = 0; NULL != nextChild; idx++) { @@ -464,7 +461,7 @@ void CFTreeSortChildren(CFTreeRef tree, CFComparatorFunction comparator, void *c } list[idx - 1]->_sibling = NULL; tree->_rightmostChild = list[children - 1]; - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorDefault, list); // XXX_PCB GC OK + if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); // XXX_PCB GC OK } } diff --git a/Collections.subproj/CFTree.h b/CFTree.h similarity index 98% rename from Collections.subproj/CFTree.h rename to CFTree.h index 31dcc53..1262498 100644 --- a/Collections.subproj/CFTree.h +++ b/CFTree.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFTree.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ /*! @header CFTree @@ -34,9 +34,7 @@ #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN /*! @typedef CFTreeRetainCallBack @@ -342,9 +340,7 @@ void CFTreeRemoveAllChildren(CFTreeRef tree); CF_EXPORT void CFTreeSortChildren(CFTreeRef tree, CFComparatorFunction comparator, void *context); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFTREE__ */ diff --git a/URL.subproj/CFURL.c b/CFURL.c similarity index 91% rename from URL.subproj/CFURL.c rename to CFURL.c index b446119..95a5872 100644 --- a/URL.subproj/CFURL.c +++ b/CFURL.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -31,27 +31,26 @@ #include #include "CFInternal.h" #include "CFStringEncodingConverter.h" -#include "CFUtilitiesPriv.h" +#include "CFPriv.h" #include #include #include #include -#if defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__) +#if DEPLOYMENT_TARGET_MACOSX #include +#include +#include #endif -#include -#include - static CFArrayRef HFSPathToURLComponents(CFStringRef path, CFAllocatorRef alloc, Boolean isDir); static CFArrayRef WindowsPathToURLComponents(CFStringRef path, CFAllocatorRef alloc, Boolean isDir); static CFStringRef WindowsPathToURLPath(CFStringRef path, CFAllocatorRef alloc, Boolean isDir); static CFStringRef POSIXPathToURLPath(CFStringRef path, CFAllocatorRef alloc, Boolean isDirectory); -static CFStringRef HFSPathToURLPath(CFStringRef path, CFAllocatorRef alloc, Boolean isDir); -static CFStringRef URLPathToHFSPath(CFStringRef path, CFAllocatorRef allocator, CFStringEncoding encoding); CFStringRef CFURLCreateStringWithFileSystemPath(CFAllocatorRef allocator, CFURLRef anURL, CFURLPathStyle fsType, Boolean resolveAgainstBase); extern CFURLRef _CFURLCreateCurrentDirectoryURL(CFAllocatorRef allocator); +#if DEPLOYMENT_TARGET_MACOSX + DEFINE_WEAK_CARBONCORE_FUNC(void, DisposeHandle, (Handle A), (A)) DEFINE_WEAK_CARBONCORE_FUNC(OSErr, FSNewAlias, (const FSRef *A, const FSRef *B, AliasHandle *C), (A, B, C), -3296) DEFINE_WEAK_CARBONCORE_FUNC(OSErr, FSGetVolumeInfo, (FSVolumeRefNum A, ItemCount B, FSVolumeRefNum *C, FSVolumeInfoBitmap D, FSVolumeInfo *E, HFSUniStr255*F, FSRef *G), (A, B, C, D, E, F, G), -3296) @@ -62,15 +61,11 @@ DEFINE_WEAK_CARBONCORE_FUNC(OSStatus, FSRefMakePath, (const FSRef *A, uint8_t *B DEFINE_WEAK_CARBONCORE_FUNC(OSErr, FSpMakeFSRef, (const FSSpec *A, FSRef *B), (A, B), -3296) DEFINE_WEAK_CARBONCORE_FUNC(Size, GetAliasSizeFromPtr, (AliasPtr A), (A), 0) DEFINE_WEAK_CARBONCORE_FUNC(OSErr, _FSGetFSRefInformationFast, (const FSRef* A, SInt16 *B, UInt32 *C, UInt32 *D, Boolean *E, Boolean *F, HFSUniStr255 *G), (A, B, C, D, E, F, G), -3296) -DEFINE_WEAK_CARBONCORE_FUNC(CFStringRef, _FSCopyStrippedPathString, (CFAllocatorRef A, CFStringRef B), (A, B), (B ? (CFStringRef)CFRetain(B) : NULL)) - DEFINE_WEAK_CARBONCORE_FUNC(OSErr, _FSGetVolumeByName, ( CFStringRef volumeNameRef, FSVolumeRefNum* vRefNumP), ( volumeNameRef, vRefNumP), -3296 ) - - -#if defined(__MACH__) -#include -#include +#elif 0 || 0 || 0 +#else +#error Unknown or unspecified DEPLOYMENT_TARGET #endif @@ -125,6 +120,7 @@ static UInt32 numURLsWithBaseURL = 0; // #define PARAMETERS_DIFFER (0x10000000) unused // #define QUERY_DIFFERS (0x20000000) unused // #define FRAGMENT_DIFfERS (0x40000000) unused +#define HAS_FILE_SCHEME (0x80000000) // Number of bits to shift to get from HAS_FOO to FOO_DIFFERS flag #define BIT_SHIFT_FROM_COMPONENT_TO_DIFFERS_FLAG (22) @@ -178,7 +174,7 @@ CF_INLINE CFMutableStringRef _getSanitizedString ( const struct __CFURL* url ) static void _CFURLAllocateExtraDataspace( struct __CFURL* url ) { if ( url && ! url->extra ) - { struct _CFURLAdditionalData* extra = (struct _CFURLAdditionalData*) CFAllocatorAllocate( CFGetAllocator( url), sizeof( struct _CFURLAdditionalData ), 0 ); + { struct _CFURLAdditionalData* extra = (struct _CFURLAdditionalData*) CFAllocatorAllocate( CFGetAllocator( url), sizeof( struct _CFURLAdditionalData ), __kCFAllocatorGCScannedMemory); extra->_reserved = _getReserved( url ); extra->_sanitizedString = _getSanitizedString( url ); @@ -200,7 +196,7 @@ CF_INLINE void _setReserved ( struct __CFURL* url, void* reserved ) _CFURLAllocateExtraDataspace( url ); if ( url->extra ) - url->extra->_reserved = reserved; + CF_WRITE_BARRIER_BASE_ASSIGN(CFGetAllocator(url), url->extra, url->extra->_reserved, reserved); } } @@ -237,10 +233,7 @@ CF_INLINE void _parseComponentsOfURL(CFURLRef url) { static Boolean _createOldUTF8StyleURLs = false; CF_INLINE Boolean createOldUTF8StyleURLs(void) { - if (_createOldUTF8StyleURLs) { - return true; - } - return !_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar); + return (_createOldUTF8StyleURLs); } // Our backdoor in case removing the UTF8 constraint for URLs creates unexpected problems. See radar 2902530 -- REW @@ -404,7 +397,7 @@ static CFArrayRef copyStringArrayWithTransformation(CFArrayRef array, StringTran CFMutableArrayRef mArray = NULL; CFIndex i, c = CFArrayGetCount(array); for (i = 0; i < c; i ++) { - CFStringRef origComp = CFArrayGetValueAtIndex(array, i); + CFStringRef origComp = (CFStringRef)CFArrayGetValueAtIndex(array, i); CFStringRef unescapedComp = transformation(alloc, origComp, i); if (!unescapedComp) { break; @@ -445,7 +438,7 @@ static CFStringRef escapePathComponent(CFAllocatorRef alloc, CFStringRef origCom static Boolean _hackToConvertSurrogates(UniChar highChar, UniChar lowChar, CFMutableStringRef str) { UniChar surrogate[2]; uint8_t bytes[6]; // Aki sez it should never take more than 6 bytes - UInt32 len; + CFIndex len; uint8_t *currByte; surrogate[0] = highChar; surrogate[1] = lowChar; @@ -467,7 +460,7 @@ static Boolean _hackToConvertSurrogates(UniChar highChar, UniChar lowChar, CFMut static Boolean _appendPercentEscapesForCharacter(UniChar ch, CFStringEncoding encoding, CFMutableStringRef str) { uint8_t bytes[6]; // 6 bytes is the maximum a single character could require in UTF8 (most common case); other encodings could require more uint8_t *bytePtr = bytes, *currByte; - UInt32 byteLength; + CFIndex byteLength; CFAllocatorRef alloc = NULL; if (CFStringEncodingUnicodeToBytes(encoding, 0, &ch, 1, NULL, bytePtr, 6, &byteLength) != kCFStringEncodingConversionSuccess) { byteLength = CFStringEncodingByteLengthForCharacters(encoding, 0, &ch, 1); @@ -476,7 +469,7 @@ static Boolean _appendPercentEscapesForCharacter(UniChar ch, CFStringEncoding en return false; } alloc = CFGetAllocator(str); - bytePtr = CFAllocatorAllocate(alloc, byteLength, 0); + bytePtr = (uint8_t *)CFAllocatorAllocate(alloc, byteLength, 0); if (!bytePtr || CFStringEncodingUnicodeToBytes(encoding, 0, &ch, 1, NULL, bytePtr, byteLength, &byteLength) != kCFStringEncodingConversionSuccess) { if (bytePtr) CFAllocatorDeallocate(alloc, bytePtr); return false; @@ -512,7 +505,7 @@ CFStringRef CFURLCreateStringByReplacingPercentEscapes(CFAllocatorRef alloc, CF if (!originalString) return NULL; if (charactersToLeaveEscaped == NULL) { - return CFStringCreateCopy(alloc, originalString); + return (CFStringRef)CFStringCreateCopy(alloc, originalString); } length = CFStringGetLength(originalString); @@ -620,7 +613,7 @@ CFStringRef CFURLCreateStringByReplacingPercentEscapes(CFAllocatorRef alloc, CF } return newStr; } else { - return CFStringCreateCopy(alloc, originalString); + return (CFStringRef)CFStringCreateCopy(alloc, originalString); } } @@ -643,7 +636,7 @@ CFStringRef CFURLCreateStringByReplacingPercentEscapesUsingEncoding(CFAllocatorR if (!originalString) return NULL; if (charactersToLeaveEscaped == NULL) { - return CFStringCreateCopy(alloc, originalString); + return (CFStringRef)CFStringCreateCopy(alloc, originalString); } length = CFStringGetLength(originalString); @@ -660,12 +653,16 @@ CFStringRef CFURLCreateStringByReplacingPercentEscapesUsingEncoding(CFAllocatorR if (numBytesUsed == capacityOfBytes) { if (bytes == byteBuffer) { - bytes = CFAllocatorAllocate(alloc, 16 * sizeof(uint8_t), 0); + bytes = (uint8_t *)CFAllocatorAllocate(alloc, 16 * sizeof(uint8_t), 0); memmove(bytes, byteBuffer, capacityOfBytes); capacityOfBytes = 16; } else { + void *oldbytes = bytes; + int oldcap = capacityOfBytes; capacityOfBytes = 2*capacityOfBytes; - bytes = CFAllocatorReallocate(alloc, bytes, capacityOfBytes * sizeof(uint8_t), 0); + bytes = (uint8_t *)CFAllocatorAllocate(alloc, capacityOfBytes * sizeof(uint8_t), 0); + memmove(bytes, oldbytes, oldcap); + CFAllocatorDeallocate(alloc, oldbytes); } } percentLoc ++; @@ -731,7 +728,7 @@ CFStringRef CFURLCreateStringByReplacingPercentEscapesUsingEncoding(CFAllocatorR } return newStr; } else { - return CFStringCreateCopy(alloc, originalString); + return (CFStringRef)CFStringCreateCopy(alloc, originalString); } } } @@ -744,7 +741,7 @@ static CFStringRef _addPercentEscapesToString(CFAllocatorRef allocator, CFString if (!originalString) return NULL; length = CFStringGetLength(originalString); - if (length == 0) return CFStringCreateCopy(allocator, originalString); + if (length == 0) return (CFStringRef)CFStringCreateCopy(allocator, originalString); CFStringInitInlineBuffer(originalString, &buf, CFRangeMake(0, length)); for (idx = 0; idx < length; idx ++) { @@ -807,7 +804,7 @@ static CFStringRef _addPercentEscapesToString(CFAllocatorRef allocator, CFString } else if (newString) { return newString; } else { - return CFStringCreateCopy(CFGetAllocator(originalString), originalString); + return (CFStringRef)CFStringCreateCopy(CFGetAllocator(originalString), originalString); } } @@ -842,8 +839,8 @@ CF_EXPORT CFStringRef CFURLCreateStringByAddingPercentEscapes(CFAllocatorRef all } static Boolean __CFURLEqual(CFTypeRef cf1, CFTypeRef cf2) { - CFURLRef url1 = cf1; - CFURLRef url2 = cf2; + CFURLRef url1 = (CFURLRef)cf1; + CFURLRef url2 = (CFURLRef)cf2; UInt32 pathType1, pathType2; __CFGenericValidateType(cf1, CFURLGetTypeID()); @@ -908,9 +905,9 @@ static Boolean __CFURLEqual(CFTypeRef cf1, CFTypeRef cf2) { } } -static UInt32 __CFURLHash(CFTypeRef cf) { +static CFHashCode __CFURLHash(CFTypeRef cf) { /* This is tricky, because we do not want the hash value to change as a file system URL is changed to its canonical representation, nor do we wish to force the conversion to the canonical representation. We choose instead to take the last path component (or "/" in the unlikely case that the path is empty), then hash on that. */ - CFURLRef url = cf; + CFURLRef url = (CFURLRef)cf; UInt32 result; if (CFURLCanBeDecomposed(url)) { CFStringRef lastComp = CFURLCopyLastPathComponent(url); @@ -935,7 +932,7 @@ static UInt32 __CFURLHash(CFTypeRef cf) { } static CFStringRef __CFURLCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { - CFURLRef url = cf; + CFURLRef url = (CFURLRef)cf; __CFGenericValidateType(cf, CFURLGetTypeID()); if (! url->_base) { CFRetain(url->_string); @@ -964,7 +961,7 @@ static CFStringRef __CFURLCopyDescription(CFTypeRef cf) { #if DEBUG_URL_MEMORY_USAGE extern __attribute((used)) void __CFURLDumpMemRecord(void) { - CFStringRef str = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d URLs created; %d destroyed\n%d file URLs created; %d converted; %d destroyed. %d urls had 'extra' data allocated, %d had base urls\n"), numURLs, numDealloced, numFileURLsCreated, numFileURLsConverted, numFileURLsDealloced, numExtraDataAllocated, numURLsWithBaseURL ); + CFStringRef str = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%d URLs created; %d destroyed\n%d file URLs created; %d converted; %d destroyed. %d urls had 'extra' data allocated, %d had base urls\n"), numURLs, numDealloced, numFileURLsCreated, numFileURLsConverted, numFileURLsDealloced, numExtraDataAllocated, numURLsWithBaseURL ); CFShow(str); CFRelease(str); // if (URLAllocator) CFCountingAllocatorPrintPointers(URLAllocator); @@ -972,7 +969,7 @@ extern __attribute((used)) void __CFURLDumpMemRecord(void) { #endif static void __CFURLDeallocate(CFTypeRef cf) { - CFURLRef url = cf; + CFURLRef url = (CFURLRef)cf; CFAllocatorRef alloc; __CFGenericValidateType(cf, CFURLGetTypeID()); alloc = CFGetAllocator(url); @@ -1005,9 +1002,19 @@ static const CFRuntimeClass __CFURLClass = { __CFURLCopyDescription }; +// When __CONSTANT_CFSTRINGS__ is not defined, we have separate macros for static and exported constant strings, but +// when it is defined, we must prefix with static to prevent the string from being exported +#ifdef __CONSTANT_CFSTRINGS__ +static CONST_STRING_DECL(kCFURLFileScheme, "file") +static CONST_STRING_DECL(kCFURLDataScheme, "data") +static CONST_STRING_DECL(kCFURLHTTPScheme, "http") +static CONST_STRING_DECL(kCFURLLocalhost, "localhost") +#else CONST_STRING_DECL(kCFURLFileScheme, "file") +CONST_STRING_DECL(kCFURLDataScheme, "data") +CONST_STRING_DECL(kCFURLHTTPScheme, "http") CONST_STRING_DECL(kCFURLLocalhost, "localhost") - +#endif __private_extern__ void __CFURLInitialize(void) { __kCFURLTypeID = _CFRuntimeRegisterClass(&__CFURLClass); } @@ -1058,14 +1065,14 @@ __private_extern__ void CFShowURL(CFURLRef url) { } else { fprintf(stdout, "(null)\n"); } - fprintf(stdout, "\tFlags: %p\n}\n", (const void*)url->_flags); + fprintf(stdout, "\tFlags: 0x%x\n}\n", (unsigned int)url->_flags); } /***************************************************/ /* URL creation and String/Data creation from URLS */ /***************************************************/ -static void constructBuffers(CFAllocatorRef alloc, CFStringRef string, const unsigned char **cstring, const UniChar **ustring, Boolean *useCString, Boolean *freeCharacters) { +static void constructBuffers(CFAllocatorRef alloc, CFStringRef string, const char **cstring, const UniChar **ustring, Boolean *useCString, Boolean *freeCharacters) { CFIndex neededLength; CFIndex length; CFRange rg; @@ -1090,12 +1097,12 @@ static void constructBuffers(CFAllocatorRef alloc, CFStringRef string, const uns rg = CFRangeMake(0, length); CFStringGetBytes(string, rg, kCFStringEncodingISOLatin1, 0, false, NULL, INT_MAX, &neededLength); if (neededLength == length) { - char *buf = CFAllocatorAllocate(alloc, length, 0); - CFStringGetBytes(string, rg, kCFStringEncodingISOLatin1, 0, false, buf, length, NULL); + char *buf = (char *)CFAllocatorAllocate(alloc, length, 0); + CFStringGetBytes(string, rg, kCFStringEncodingISOLatin1, 0, false, (uint8_t *)buf, length, NULL); *cstring = buf; *useCString = true; } else { - UniChar *buf = CFAllocatorAllocate(alloc, length * sizeof(UniChar), 0); + UniChar *buf = (UniChar *)CFAllocatorAllocate(alloc, length * sizeof(UniChar), 0); CFStringGetCharacters(string, rg, buf); *useCString = false; *ustring = buf; @@ -1112,7 +1119,7 @@ static void _parseComponents(CFAllocatorRef alloc, CFStringRef string, CFURLRef UInt32 flags = (IS_PARSED | *theFlags); Boolean useCString, freeCharacters, isCompliant; uint8_t numRanges = 0; - const unsigned char *cstring = NULL; + const char *cstring = NULL; const UniChar *ustring = NULL; string_length = CFStringGetLength(string); @@ -1146,6 +1153,12 @@ static void _parseComponents(CFAllocatorRef alloc, CFStringRef string, CFURLRef { flags |= HAS_HTTP_SCHEME; } + // optimization for file urls + if (idx == 4 && STRING_CHAR(0) == 'f' && STRING_CHAR(1) == 'i' && + STRING_CHAR(2) == 'l' && STRING_CHAR(3) == 'e') + { + flags |= HAS_FILE_SCHEME; + } break; } else if (!scheme_valid(ch)) { break; // invalid scheme character -- no scheme @@ -1172,7 +1185,7 @@ static void _parseComponents(CFAllocatorRef alloc, CFStringRef string, CFURLRef string_length = CFStringGetLength(string); } (*theFlags) = flags; - (*range) = CFAllocatorAllocate(alloc, sizeof(CFRange), 0); + (*range) = (CFRange *)CFAllocatorAllocate(alloc, sizeof(CFRange), 0); (*range)->location = ranges[0].location; (*range)->length = ranges[0].length; @@ -1334,7 +1347,7 @@ static void _parseComponents(CFAllocatorRef alloc, CFStringRef string, CFURLRef CFAllocatorDeallocate(alloc, useCString ? (void *)cstring : (void *)ustring); } (*theFlags) = flags; - (*range) = CFAllocatorAllocate(alloc, sizeof(CFRange)*numRanges, 0); + (*range) = (CFRange *)CFAllocatorAllocate(alloc, sizeof(CFRange)*numRanges, 0); numRanges = 0; for (idx = 0, flags = 1; flags != (1<<9); flags = (flags<<1), idx ++) { if ((*theFlags) & flags) { @@ -1344,7 +1357,7 @@ static void _parseComponents(CFAllocatorRef alloc, CFStringRef string, CFURLRef } } -static Boolean scanCharacters(CFAllocatorRef alloc, CFMutableStringRef *escapedString, UInt32 *flags, const unsigned char *cstring, const UniChar *ustring, Boolean useCString, CFIndex base, CFIndex end, CFIndex *mark, UInt32 componentFlag, CFStringEncoding encoding) { +static Boolean scanCharacters(CFAllocatorRef alloc, CFMutableStringRef *escapedString, UInt32 *flags, const char *cstring, const UniChar *ustring, Boolean useCString, CFIndex base, CFIndex end, CFIndex *mark, UInt32 componentFlag, CFStringEncoding encoding) { CFIndex idx; Boolean sawIllegalChar = false; for (idx = base; idx < end; idx ++) { @@ -1373,7 +1386,7 @@ static Boolean scanCharacters(CFAllocatorRef alloc, CFMutableStringRef *escapedS *escapedString = CFStringCreateMutable(alloc, 0); } if (useCString) { - CFStringRef tempString = CFStringCreateWithBytes(alloc, &(cstring[*mark]), idx - *mark, kCFStringEncodingISOLatin1, false); + CFStringRef tempString = CFStringCreateWithBytes(alloc, (uint8_t *)&(cstring[*mark]), idx - *mark, kCFStringEncodingISOLatin1, false); CFStringAppend(*escapedString, tempString); CFRelease(tempString); } else { @@ -1389,7 +1402,7 @@ static void computeSanitizedString(CFURLRef url) { CFAllocatorRef alloc = CFGetAllocator(url); CFIndex string_length = CFStringGetLength(url->_string); Boolean useCString, freeCharacters; - const unsigned char *cstring = NULL; + const char *cstring = NULL; const UniChar *ustring = NULL; CFIndex base; // where to scan from CFIndex mark; // first character not-yet copied to sanitized string @@ -1411,8 +1424,8 @@ static void computeSanitizedString(CFURLRef url) { } else { // Go component by component CFIndex currentComponent = HAS_USER; - mark = 0; CFMutableStringRef sanitizedString = NULL; + mark = 0; while (currentComponent < (HAS_FRAGMENT << 1)) { CFRange componentRange = _rangeForComponent(url->_flags, url->ranges, currentComponent); if (componentRange.location != kCFNotFound) { @@ -1428,7 +1441,7 @@ static void computeSanitizedString(CFURLRef url) { } if (_getSanitizedString(url) && mark != string_length) { if (useCString) { - CFStringRef tempString = CFStringCreateWithBytes(alloc, &(cstring[mark]), string_length - mark, kCFStringEncodingISOLatin1, false); + CFStringRef tempString = CFStringCreateWithBytes(alloc, (uint8_t *)&(cstring[mark]), string_length - mark, kCFStringEncodingISOLatin1, false); CFStringAppend(_getSanitizedString(url), tempString); CFRelease(tempString); } else { @@ -1445,7 +1458,7 @@ static CFStringRef correctedComponent(CFStringRef comp, UInt32 compFlag, CFStrin CFAllocatorRef alloc = CFGetAllocator(comp); CFIndex string_length = CFStringGetLength(comp); Boolean useCString, freeCharacters; - const unsigned char *cstring = NULL; + const char *cstring = NULL; const UniChar *ustring = NULL; CFIndex mark = 0; // first character not-yet copied to sanitized string CFMutableStringRef result = NULL; @@ -1455,7 +1468,7 @@ static CFStringRef correctedComponent(CFStringRef comp, UInt32 compFlag, CFStrin if (result) { if (mark < string_length) { if (useCString) { - CFStringRef tempString = CFStringCreateWithBytes(alloc, &(cstring[mark]), string_length - mark, kCFStringEncodingISOLatin1, false); + CFStringRef tempString = CFStringCreateWithBytes(alloc, (uint8_t *)&(cstring[mark]), string_length - mark, kCFStringEncodingISOLatin1, false); CFStringAppend(result, tempString); CFRelease(tempString); } else { @@ -1506,7 +1519,7 @@ static void _CFURLInit(struct __CFURL *url, CFStringRef URLString, UInt32 fsType CFAssert2((fsType == FULL_URL_REPRESENTATION) || (fsType == kCFURLPOSIXPathStyle) || (fsType == kCFURLWindowsPathStyle) || (fsType == kCFURLHFSPathStyle), __kCFLogAssertion, "%s(): Received bad fsType %d", __PRETTY_FUNCTION__, fsType); // Coming in, the url has its allocator flag properly set, and its base initialized, and nothing else. - url->_string = CFStringCreateCopy(CFGetAllocator(url), URLString); + url->_string = (CFStringRef)CFStringCreateCopy(CFGetAllocator(url), URLString); url->_flags |= (fsType << 16); url->_base = base ? CFURLCopyAbsoluteURL(base) : NULL; @@ -1520,6 +1533,7 @@ static void _CFURLInit(struct __CFURL *url, CFStringRef URLString, UInt32 fsType #endif } +#if DEPLOYMENT_TARGET_MACOSX CF_EXPORT void _CFURLInitFSPath(CFURLRef url, CFStringRef path) { CFIndex len = CFStringGetLength(path); if (len && CFStringGetCharacterAtIndex(path, 0) == '/') { @@ -1528,11 +1542,52 @@ CF_EXPORT void _CFURLInitFSPath(CFURLRef url, CFStringRef path) { } else { CFURLRef cwdURL = _CFURLCreateCurrentDirectoryURL(CFGetAllocator(url)); _CFURLInit((struct __CFURL *)url, path, kCFURLPOSIXPathStyle, cwdURL); - CFRelease(cwdURL); + if ( cwdURL ) + CFRelease(cwdURL); + } + if (!len || '/' == CFStringGetCharacterAtIndex(path, len - 1)) + ((struct __CFURL *)url)->_flags |= IS_DIRECTORY; +} +#elif 0 +CF_EXPORT void _CFURLInitFSPath(CFURLRef url, CFStringRef path) { + CFIndex len = CFStringGetLength(path); + if (len > 2) { + char firstChar = CFStringGetCharacterAtIndex(path, 0); + char secondChar = CFStringGetCharacterAtIndex(path, 1); + if (((((firstChar >= 'A') && (firstChar <= 'Z')) || ((firstChar >= 'a') && (firstChar <= 'z'))) && + ((secondChar == ':') || (secondChar == '|'))) || + ((firstChar == '\\') && (secondChar == '\\'))) + { + _CFURLInit((struct __CFURL *)url, path, kCFURLWindowsPathStyle, NULL); + ((struct __CFURL *)url)->_flags |= IS_ABSOLUTE; + } else { + CFURLRef cwdURL = _CFURLCreateCurrentDirectoryURL(CFGetAllocator(url)); + _CFURLInit((struct __CFURL *)url, path, kCFURLPOSIXPathStyle, cwdURL); + if ( cwdURL ) + CFRelease(cwdURL); + } } if (!len || '/' == CFStringGetCharacterAtIndex(path, len - 1)) ((struct __CFURL *)url)->_flags |= IS_DIRECTORY; } +#elif 0 +CF_EXPORT void _CFURLInitFSPath(CFURLRef url, CFStringRef path) { + CFIndex len = CFStringGetLength(path); + if (len && CFStringGetCharacterAtIndex(path, 0) == '/') { + _CFURLInit((struct __CFURL *)url, path, kCFURLPOSIXPathStyle, NULL); + ((struct __CFURL *)url)->_flags |= IS_ABSOLUTE; + } else { + CFURLRef cwdURL = _CFURLCreateCurrentDirectoryURL(CFGetAllocator(url)); + _CFURLInit((struct __CFURL *)url, path, kCFURLPOSIXPathStyle, cwdURL); + if ( cwdURL ) + CFRelease(cwdURL); + } + if (!len || '/' == CFStringGetCharacterAtIndex(path, len - 1)) + ((struct __CFURL *)url)->_flags |= IS_DIRECTORY; +} +#else +#error Unknown or unspecified DEPLOYMENT_TARGET +#endif // Exported for Foundation's use CF_EXPORT Boolean _CFStringIsLegalURLString(CFStringRef string) { @@ -1601,7 +1656,7 @@ CF_EXPORT void _CFURLInitWithString(CFURLRef myURL, CFStringRef string, CFURLRef isAbsolute = true; CFIndex i; for (i = 0; i < colon.location; i++) { - char ch = CFStringGetCharacterAtIndex(string, i); + char ch = (char)CFStringGetCharacterAtIndex(string, i); if (!scheme_valid(ch)) { isAbsolute = false; break; @@ -1740,7 +1795,7 @@ CFDataRef CFURLCreateData(CFAllocatorRef allocator, CFURLRef url, CFStringEncod CFStringRef newStr; CFDataRef result; if (url->_flags & IS_OLD_UTF8_STYLE) { - newStr = (encoding == kCFStringEncodingUTF8) ? CFRetain(myStr) : _convertPercentEscapes(myStr, kCFStringEncodingUTF8, encoding, true, false, escapeWhitespace ? whitespaceChars : NULL, escapeWhitespace ? 4 : 0); + newStr = (encoding == kCFStringEncodingUTF8) ? (CFStringRef)CFRetain(myStr) : _convertPercentEscapes(myStr, kCFStringEncodingUTF8, encoding, true, false, escapeWhitespace ? whitespaceChars : NULL, escapeWhitespace ? 4 : 0); } else { newStr=myStr; CFRetain(newStr); @@ -1863,7 +1918,7 @@ CFURLRef CFURLCreateAbsoluteURLWithBytes(CFAllocatorRef alloc, const UInt8 *rela if (absFlags & HAS_PATH) { CFRange pathRg = _rangeForComponent(absFlags, absRanges, HAS_PATH); // This is expensive, but it allows us to reuse _resolvedPath. It should be cleaned up to get this allocation removed at some point. - REW - UniChar *buf = CFAllocatorAllocate(alloc, sizeof(UniChar) * (pathRg.length + 1), 0); + UniChar *buf = (UniChar *)CFAllocatorAllocate(alloc, sizeof(UniChar) * (pathRg.length + 1), 0); CFStringRef newPath; CFStringGetCharacters(absString, pathRg, buf); buf[pathRg.length] = '\0'; @@ -1961,7 +2016,7 @@ static CFStringRef _resolvedPath(UniChar *pathStr, UniChar *end, UniChar pathDel static CFMutableStringRef resolveAbsoluteURLString(CFAllocatorRef alloc, CFStringRef relString, UInt32 relFlags, CFRange *relRanges, CFStringRef baseString, UInt32 baseFlags, CFRange *baseRanges) { CFMutableStringRef newString = CFStringCreateMutable(alloc, 0); CFIndex bufLen = CFStringGetLength(baseString) + CFStringGetLength(relString); // Overkill, but guarantees we never allocate again - UniChar *buf = CFAllocatorAllocate(alloc, bufLen * sizeof(UniChar), 0); + UniChar *buf = (UniChar *)CFAllocatorAllocate(alloc, bufLen * sizeof(UniChar), 0); CFRange rg; rg = _rangeForComponent(baseFlags, baseRanges, HAS_SCHEME); @@ -2002,7 +2057,7 @@ static CFMutableStringRef resolveAbsoluteURLString(CFAllocatorRef alloc, CFStrin newPath = CFStringCreateWithSubstring(alloc, baseString, basePathRg); } else { // #warning FIXME - Get rid of this allocation - UniChar *newPathBuf = CFAllocatorAllocate(alloc, sizeof(UniChar) * (relPathRg.length + basePathRg.length + 1), 0); + UniChar *newPathBuf = (UniChar *)CFAllocatorAllocate(alloc, sizeof(UniChar) * (relPathRg.length + basePathRg.length + 1), 0); UniChar *idx, *end; CFStringGetCharacters(baseString, basePathRg, newPathBuf); idx = newPathBuf + basePathRg.length - 1; @@ -2116,7 +2171,7 @@ CFURLRef CFURLCopyAbsoluteURL(CFURLRef relativeURL) { base = relativeURL->_base; if (!base) { - return CFRetain(relativeURL); + return (CFURLRef)CFRetain(relativeURL); } baseIsObjC = CF_IS_OBJC(__kCFURLTypeID, base); fsType = URL_PATH_TYPE(relativeURL); @@ -2255,7 +2310,11 @@ static CFStringRef _retainedComponentString(CFURLRef url, UInt32 compFlag, Boole rg = _rangeForComponent(url->_flags, url->ranges, compFlag); if (rg.location == kCFNotFound) return NULL; if (compFlag & HAS_SCHEME && url->_flags & HAS_HTTP_SCHEME) { - comp = CFSTR("http"); + comp = kCFURLHTTPScheme; + CFRetain(comp); + } else if (compFlag & HAS_SCHEME && url->_flags & HAS_FILE_SCHEME) { + comp = kCFURLFileScheme; + CFRetain(comp); } else { comp = CFStringCreateWithSubstring(alloc, url->_string, rg); } @@ -2297,9 +2356,14 @@ CFStringRef CFURLCopyScheme(CFURLRef anURL) { return kCFURLFileScheme; } } - if (anURL->_flags & IS_PARSED && anURL->_flags & HAS_HTTP_SCHEME) { - return(CFSTR("http")); - } + if (anURL->_flags & IS_PARSED && anURL->_flags & HAS_HTTP_SCHEME) { + CFRetain(kCFURLHTTPScheme); + return kCFURLHTTPScheme; + } + if (anURL->_flags & IS_PARSED && anURL->_flags & HAS_FILE_SCHEME) { + CFRetain(kCFURLFileScheme); + return kCFURLFileScheme; + } scheme = _retainedComponentString(anURL, HAS_SCHEME, true, false); if (scheme) { return scheme; @@ -2954,12 +3018,10 @@ static CFStringRef schemeSpecificString(CFURLRef url) { switch (URL_PATH_TYPE(url)) { case kCFURLPOSIXPathStyle: if (url->_flags & POSIX_AND_URL_PATHS_MATCH) { - return CFRetain(url->_string); + return (CFStringRef)CFRetain(url->_string); } else { return POSIXPathToURLPath(url->_string, CFGetAllocator(url), isDir); } - case kCFURLHFSPathStyle: - return HFSPathToURLPath(url->_string, CFGetAllocator(url), isDir); case kCFURLWindowsPathStyle: return WindowsPathToURLPath(url->_string, CFGetAllocator(url), isDir); case FULL_URL_REPRESENTATION: @@ -3052,9 +3114,6 @@ static Boolean decomposeToRFC1808(CFURLRef url, CFURLComponentsRFC1808 *componen CFRelease(pathStr); break; } - case kCFURLHFSPathStyle: - components->pathComponents = HFSPathToURLComponents(url->_string, alloc, ((url->_flags & IS_DIRECTORY) != 0)); - break; case kCFURLWindowsPathStyle: components->pathComponents = WindowsPathToURLComponents(url->_string, alloc, ((url->_flags & IS_DIRECTORY) != 0)); break; @@ -3064,10 +3123,10 @@ static Boolean decomposeToRFC1808(CFURLRef url, CFURLComponentsRFC1808 *componen if (!components->pathComponents) { return false; } - components->scheme = CFRetain(kCFURLFileScheme); + components->scheme = (CFStringRef)CFRetain(kCFURLFileScheme); components->user = NULL; components->password = NULL; - components->host = CFRetain(kCFURLLocalhost); + components->host = (CFStringRef)CFRetain(kCFURLLocalhost); components->port = kCFNotFound; components->parameterString = NULL; components->query = NULL; @@ -3109,7 +3168,7 @@ static CFURLRef composeFromRFC1808(CFAllocatorRef alloc, const CFURLComponentsRF hadPrePathComponent = true; } - if (hadPrePathComponent && (comp->pathComponents == NULL || CFStringGetLength(CFArrayGetValueAtIndex(comp->pathComponents, 0)) != 0)) { + if (hadPrePathComponent && (comp->pathComponents == NULL || CFStringGetLength((CFStringRef)CFArrayGetValueAtIndex(comp->pathComponents, 0)) != 0)) { CFStringAppend(urlString, CFSTR("/")); } if (comp->pathComponents) { @@ -3195,7 +3254,7 @@ static CFURLRef composeFromRFC2396(CFAllocatorRef alloc, const CFURLComponentsRF } hadPrePathComponent = true; } - if (hadPrePathComponent && (comp->pathComponents == NULL || CFStringGetLength(CFArrayGetValueAtIndex(comp->pathComponents, 0)) != 0)) { + if (hadPrePathComponent && (comp->pathComponents == NULL || CFStringGetLength((CFStringRef)CFArrayGetValueAtIndex(comp->pathComponents, 0)) != 0)) { CFStringAppend(urlString, CFSTR("/")); } if (comp->pathComponents) { @@ -3218,6 +3277,7 @@ static CFURLRef composeFromRFC2396(CFAllocatorRef alloc, const CFURLComponentsRF #undef CFURLCopyComponents #undef CFURLCreateFromComponents + CF_EXPORT Boolean _CFURLCopyComponents(CFURLRef url, CFURLComponentDecomposition decompositionType, void *components) { url = _CFURLFromNSURL(url); @@ -3268,14 +3328,14 @@ static CFArrayRef WindowsPathToURLComponents(CFStringRef path, CFAllocatorRef al urlComponents = CFArrayCreateMutableCopy(alloc, 0, tmp); CFRelease(tmp); - CFStringRef str = CFArrayGetValueAtIndex(urlComponents, 0); + CFStringRef str = (CFStringRef)CFArrayGetValueAtIndex(urlComponents, 0); if (CFStringGetLength(str) == 2 && CFStringGetCharacterAtIndex(str, 1) == ':') { CFArrayInsertValueAtIndex(urlComponents, 0, CFSTR("")); // So we get a leading '/' below i = 2; // Skip over the drive letter and the empty string we just inserted } CFIndex c; for (c = CFArrayGetCount(urlComponents); i < c; i ++) { - CFStringRef fileComp = CFArrayGetValueAtIndex(urlComponents,i); + CFStringRef fileComp = (CFStringRef)CFArrayGetValueAtIndex(urlComponents,i); CFStringRef urlComp = _replacePathIllegalCharacters(fileComp, alloc, false); if (!urlComp) { // Couldn't decode fileComp @@ -3289,7 +3349,7 @@ static CFArrayRef WindowsPathToURLComponents(CFStringRef path, CFAllocatorRef al } if (isDir) { - if (CFStringGetLength(CFArrayGetValueAtIndex(urlComponents, CFArrayGetCount(urlComponents) - 1)) != 0) + if (CFStringGetLength((CFStringRef)CFArrayGetValueAtIndex(urlComponents, CFArrayGetCount(urlComponents) - 1)) != 0) CFArrayAppendValue(urlComponents, CFSTR("")); } return urlComponents; @@ -3342,27 +3402,32 @@ static CFStringRef URLPathToWindowsPath(CFStringRef path, CFAllocatorRef allocat CFMutableArrayRef components = CFArrayCreateMutableCopy(allocator, count, tmp); CFStringRef newPath; + + CFRelease(tmp); - if (CFStringGetLength(CFArrayGetValueAtIndex(components,count-1)) == 0) { + if (CFStringGetLength((CFStringRef)CFArrayGetValueAtIndex(components,count-1)) == 0) { CFArrayRemoveValueAtIndex(components, count-1); count --; } - if (count > 1 && CFStringGetLength(CFArrayGetValueAtIndex(components, 0)) == 0) { + + if (count > 1 && CFStringGetLength((CFStringRef)CFArrayGetValueAtIndex(components, 0)) == 0) { // Absolute path; we need to check for a drive letter in the second component, and if so, remove the first component - CFStringRef firstComponent = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(allocator, CFArrayGetValueAtIndex(components, 1), CFSTR(""), encoding); + CFStringRef firstComponent = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(allocator, (CFStringRef)CFArrayGetValueAtIndex(components, 1), CFSTR(""), encoding); UniChar ch; - if (CFStringGetLength(firstComponent) == 2 && ((ch = CFStringGetCharacterAtIndex(firstComponent, 1)) == '|' || ch == ':')) { - // Drive letter - CFArrayRemoveValueAtIndex(components, 0); - if (ch == '|') { - CFStringRef driveStr = CFStringCreateWithFormat(allocator, NULL, CFSTR("%c:"), CFStringGetCharacterAtIndex(firstComponent, 0)); - CFArraySetValueAtIndex(components, 0, driveStr); - CFRelease(driveStr); + + { + if (CFStringGetLength(firstComponent) == 2 && ((ch = CFStringGetCharacterAtIndex(firstComponent, 1)) == '|' || ch == ':')) { + // Drive letter + CFArrayRemoveValueAtIndex(components, 0); + if (ch == '|') { + CFStringRef driveStr = CFStringCreateWithFormat(allocator, NULL, CFSTR("%c:"), CFStringGetCharacterAtIndex(firstComponent, 0)); + CFArraySetValueAtIndex(components, 0, driveStr); + CFRelease(driveStr); + } } + CFRelease(firstComponent); } - CFRelease(firstComponent); } - newPath = CFStringCreateByCombiningStrings(allocator, components, CFSTR("\\")); CFRelease(components); result = CFURLCreateStringByReplacingPercentEscapesUsingEncoding(allocator, newPath, CFSTR(""), encoding); @@ -3383,23 +3448,21 @@ static void _convertToURLRepresentation(struct __CFURL *url) { switch (URL_PATH_TYPE(url)) { case kCFURLPOSIXPathStyle: if (url->_flags & POSIX_AND_URL_PATHS_MATCH) { - path = CFRetain(url->_string); + path = (CFStringRef)CFRetain(url->_string); } else { path = POSIXPathToURLPath(url->_string, alloc, isDir); } break; - case kCFURLHFSPathStyle: - path = HFSPathToURLPath(url->_string, alloc, isDir); - break; case kCFURLWindowsPathStyle: path = WindowsPathToURLPath(url->_string, alloc, isDir); break; } CFAssert2(path != NULL, __kCFLogAssertion, "%s(): Encountered malformed file system URL %@", __PRETTY_FUNCTION__, url); if (!url->_base) { - CFStringRef str; - str = CFStringCreateWithFormat(alloc, NULL, CFSTR("file://localhost%@"), path); - url->_flags = (url->_flags & (IS_DIRECTORY)) | (FULL_URL_REPRESENTATION << 16) | IS_DECOMPOSABLE | IS_ABSOLUTE | IS_PARSED | HAS_SCHEME | HAS_HOST | HAS_PATH | ORIGINAL_AND_URL_STRINGS_MATCH; + CFMutableStringRef str = CFStringCreateMutable(alloc, 0); + CFStringAppend(str, 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; CFRelease(url->_string); url->_string = str; url->ranges = (CFRange *)CFAllocatorAllocate(alloc, sizeof(CFRange) * 3, 0); @@ -3432,7 +3495,7 @@ static CFStringRef _resolveFileSystemPaths(CFStringRef relativePath, CFStringRef CFIndex baseLen = CFStringGetLength(basePath); CFIndex relLen = CFStringGetLength(relativePath); UniChar pathDelimiter = PATH_DELIM_FOR_TYPE(fsType); - UniChar *buf = CFAllocatorAllocate(alloc, sizeof(UniChar)*(relLen + baseLen + 2), 0); + UniChar *buf = (UniChar *)CFAllocatorAllocate(alloc, sizeof(UniChar)*(relLen + baseLen + 2), 0); CFStringGetCharacters(basePath, CFRangeMake(0, baseLen), buf); if (baseIsDir) { if (buf[baseLen-1] != pathDelimiter) { @@ -3458,8 +3521,8 @@ static CFStringRef _resolveFileSystemPaths(CFStringRef relativePath, CFStringRef CFURLRef _CFURLCreateCurrentDirectoryURL(CFAllocatorRef allocator) { CFURLRef url = NULL; uint8_t buf[CFMaxPathSize + 1]; - if (_CFGetCurrentDirectory(buf, CFMaxPathLength)) { - url = CFURLCreateFromFileSystemRepresentation(allocator, buf, strlen(buf), true); + if (_CFGetCurrentDirectory((char *)buf, CFMaxPathLength)) { + url = CFURLCreateFromFileSystemRepresentation(allocator, buf, strlen((char *)buf), true); } return url; } @@ -3533,7 +3596,7 @@ CF_EXPORT CFURLRef CFURLCreateWithFileSystemPathRelativeToBase(CFAllocatorRef al if ( _CFExecutableLinkedOnOrAfter( CFSystemVersionTiger ) && filePath && CFStringFindWithOptions( filePath, CFSTR("::"), fullStrRange, 0, NULL ) ) { - UniChar* chars = (UniChar*) malloc( fullStrRange.length * sizeof( UniChar ) ); + UniChar * chars = (UniChar *) malloc( fullStrRange.length * sizeof( UniChar ) ); CFIndex index, writeIndex, firstColonOffset = -1; CFStringGetCharacters( filePath, fullStrRange, chars ); @@ -3564,6 +3627,8 @@ CF_EXPORT CFURLRef CFURLCreateWithFileSystemPathRelativeToBase(CFAllocatorRef al CFRelease( filePath ); filePath = CFStringCreateWithCharacters( allocator, chars, writeIndex ); + // reset len because a canonical HFS path can be a different length than the original CFString + len = CFStringGetLength(filePath); releaseFilePath = true; free( chars ); @@ -3577,7 +3642,9 @@ CF_EXPORT CFURLRef CFURLCreateWithFileSystemPathRelativeToBase(CFAllocatorRef al } if (isDirectory && len > 0 && CFStringGetCharacterAtIndex(filePath, len-1) != pathDelim) { - CFStringRef tempRef = CFStringCreateWithFormat(allocator, NULL, CFSTR("%@%c"), filePath, pathDelim); + CFMutableStringRef tempRef = CFStringCreateMutable(allocator, 0); + CFStringAppend(tempRef, filePath); + CFStringAppendCharacters(tempRef, &pathDelim, 1); if ( releaseFilePath && filePath ) CFRelease( filePath ); filePath = tempRef; releaseFilePath = true; @@ -3624,7 +3691,9 @@ CF_EXPORT CFURLRef CFURLCreateWithFileSystemPathRelativeToBase(CFAllocatorRef al ((struct __CFURL *)url)->_flags |= POSIX_AND_URL_PATHS_MATCH; } if (mustPrependDotSlash) { - CFStringRef newString = CFStringCreateWithFormat(allocator, NULL, CFSTR("./%@"), url->_string); + CFMutableStringRef newString = CFStringCreateMutable(allocator, 0); + CFStringAppend(newString, CFSTR("./")); + CFStringAppend(newString, url->_string); CFRelease(url->_string); ((struct __CFURL *)url)->_string = newString; } @@ -3647,7 +3716,7 @@ CFStringRef CFURLCreateStringWithFileSystemPath(CFAllocatorRef allocator, CFURLR // We can grope the ivars CFURLPathStyle myType = URL_PATH_TYPE(anURL); if (myType == fsType) { - relPath = CFRetain(anURL->_string); + relPath = (CFStringRef)CFRetain(anURL->_string); } else if (fsType == kCFURLPOSIXPathStyle && myType == FULL_URL_REPRESENTATION) { if (!(anURL->_flags & IS_PARSED)) { _parseComponentsOfURL(anURL); @@ -3667,7 +3736,7 @@ CFStringRef CFURLCreateStringWithFileSystemPath(CFAllocatorRef allocator, CFURLR relPath = URLPathToPOSIXPath(urlPath, allocator, enc); break; case kCFURLHFSPathStyle: - relPath = URLPathToHFSPath(urlPath, allocator, enc); + relPath = NULL; break; case kCFURLWindowsPathStyle: relPath = URLPathToWindowsPath(urlPath, allocator, enc); @@ -3679,7 +3748,7 @@ CFStringRef CFURLCreateStringWithFileSystemPath(CFAllocatorRef allocator, CFURLR } } - // For Tiger, leave this behavior in for all path types. For Chablis, it would be nice to remove this entirely + // 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. @@ -3705,27 +3774,14 @@ Boolean CFURLGetFileSystemRepresentation(CFURLRef url, Boolean resolveAgainstBas CFAllocatorRef alloc = CFGetAllocator(url); if (!url) return false; -#if defined(__WIN32__) - path = CFURLCreateStringWithFileSystemPath(alloc, url, kCFURLWindowsPathStyle, resolveAgainstBase); -#else +#if DEPLOYMENT_TARGET_MACOSX path = CFURLCreateStringWithFileSystemPath(alloc, url, kCFURLPOSIXPathStyle, resolveAgainstBase); -#endif if (path) { -#if defined(__MACH__) Boolean convResult = _CFStringGetFileSystemRepresentation(path, buffer, bufLen); CFRelease(path); return convResult; -#else - CFIndex usedLen; - CFIndex pathLen = CFStringGetLength(path); - CFIndex numConverted = CFStringGetBytes(path, CFRangeMake(0, pathLen), CFStringFileSystemEncoding(), 0, true, buffer, bufLen-1, &usedLen); // -1 because we need one byte to zero-terminate. - CFRelease(path); - if (numConverted == pathLen) { - buffer[usedLen] = '\0'; - return true; - } -#endif } +#endif return false; } @@ -3733,9 +3789,7 @@ CFURLRef CFURLCreateFromFileSystemRepresentation(CFAllocatorRef allocator, const CFStringRef path = CFStringCreateWithBytes(allocator, buffer, bufLen, CFStringFileSystemEncoding(), false); CFURLRef newURL; if (!path) return NULL; -#if defined(__WIN32__) - newURL = CFURLCreateWithFileSystemPath(allocator, path, kCFURLWindowsPathStyle, isDirectory); -#else +#if DEPLOYMENT_TARGET_MACOSX newURL = CFURLCreateWithFileSystemPath(allocator, path, kCFURLPOSIXPathStyle, isDirectory); #endif CFRelease(path); @@ -3746,9 +3800,7 @@ CF_EXPORT CFURLRef CFURLCreateFromFileSystemRepresentationRelativeToBase(CFAlloc CFStringRef path = CFStringCreateWithBytes(allocator, buffer, bufLen, CFStringFileSystemEncoding(), false); CFURLRef newURL; if (!path) return NULL; -#if defined(__WIN32__) - newURL = CFURLCreateWithFileSystemPathRelativeToBase(allocator, path, kCFURLWindowsPathStyle, isDirectory, baseURL); -#else +#if DEPLOYMENT_TARGET_MACOSX newURL = CFURLCreateWithFileSystemPathRelativeToBase(allocator, path, kCFURLPOSIXPathStyle, isDirectory, baseURL); #endif CFRelease(path); @@ -3812,17 +3864,17 @@ CFStringRef CFURLCopyLastPathComponent(CFURLRef url) { if (rg.location == 0 && rg.length == length) { result = path; } else { - result = CFStringCreateWithSubstring(NULL, path, rg); + result = CFStringCreateWithSubstring(CFGetAllocator(url), path, rg); CFRelease(path); } } else { CFRange rg = _rangeOfLastPathComponent(url); if (rg.location == kCFNotFound || rg.length == 0) { // No path - return CFRetain(CFSTR("")); + return (CFStringRef)CFRetain(CFSTR("")); } if (rg.length == 1 && CFStringGetCharacterAtIndex(url->_string, rg.location) == PATH_DELIM_FOR_TYPE(URL_PATH_TYPE(url))) { - return CFRetain(CFSTR("/")); + return (CFStringRef)CFRetain(CFSTR("/")); } result = CFStringCreateWithSubstring(CFGetAllocator(url), url->_string, rg); if (URL_PATH_TYPE(url) == FULL_URL_REPRESENTATION && !(url->_flags & POSIX_AND_URL_PATHS_MATCH)) { @@ -3851,7 +3903,7 @@ CFStringRef CFURLCopyPathExtension(CFURLRef url) { if (rg.length > 0) { ext = CFStringCreateWithSubstring(CFGetAllocator(url), lastPathComp, rg); } else { - ext = CFRetain(CFSTR("")); + ext = (CFStringRef)CFRetain(CFSTR("")); } } CFRelease(lastPathComp); @@ -4037,123 +4089,128 @@ CFURLRef CFURLCreateCopyDeletingPathExtension(CFAllocatorRef allocator, CFURLRef } CFRelease(newString); } else { - result = CFRetain(url); + result = (CFURLRef)CFRetain(url); } return result; } -// We deal in FSRefs because they handle Unicode strings. -// FSSpecs handle a much more limited set of characters. -static Boolean __CFFSRefForVolumeName(CFStringRef volName, FSRef *spec, CFAllocatorRef alloc) { - return false; -} -static CFArrayRef HFSPathToURLComponents(CFStringRef path, CFAllocatorRef alloc, Boolean isDir) { - CFArrayRef components = CFStringCreateArrayBySeparatingStrings(alloc, path, CFSTR(":")); - CFMutableArrayRef newComponents = CFArrayCreateMutableCopy(alloc, 0, components); - Boolean doSpecialLeadingColon = false; - UniChar firstChar = CFStringGetCharacterAtIndex(path, 0); - UInt32 i, cnt; - CFRelease(components); - if (!doSpecialLeadingColon && firstChar != ':') { - CFArrayInsertValueAtIndex(newComponents, 0, CFSTR("")); - } else if (firstChar != ':') { - // see what we need to add at the beginning. Under MacOS, if the - // first character isn't a ':', then the first component is the - // volume name, and we need to find the mount point. Bleah. If we - // don't find a mount point, we're going to have to lie, and make something up. - CFStringRef firstComp = CFArrayGetValueAtIndex(newComponents, 0); - if (CFStringGetLength(firstComp) == 1 && CFStringGetCharacterAtIndex(firstComp, 0) == '/') { - // "/" is the "magic" path for a UFS root directory - CFArrayRemoveValueAtIndex(newComponents, 0); - CFArrayInsertValueAtIndex(newComponents, 0, CFSTR("")); + +// keys and vals must have space for at least 4 key/value pairs. No argument can be NULL. +// Caller must release values, but not keys +static void __CFURLCopyPropertyListKeysAndValues(CFURLRef url, CFTypeRef *keys, CFTypeRef *vals, CFIndex *count) { + CFAllocatorRef alloc = CFGetAllocator(url); + CFURLRef base = CFURLGetBaseURL(url); + keys[0] = CFSTR("_CFURLStringType"); + keys[1] = CFSTR("_CFURLString"); + keys[2] = CFSTR("_CFURLBaseStringType"); + keys[3] = CFSTR("_CFURLBaseURLString"); + if (CF_IS_OBJC(__kCFURLTypeID, url)) { + SInt32 urlType = FULL_URL_REPRESENTATION; + vals[0] = CFNumberCreate(alloc, kCFNumberSInt32Type, &urlType); + vals[1] = CFURLGetString(url); + } else { + SInt32 urlType = URL_PATH_TYPE(url); + vals[0] = CFNumberCreate(alloc, kCFNumberSInt32Type, &urlType); + if (url->_flags & IS_DIRECTORY) { + if (CFStringGetCharacterAtIndex(url->_string, CFStringGetLength(url->_string) - 1) == PATH_DELIM_FOR_TYPE(urlType)) { + vals[1] = CFRetain(url->_string); + } else { + vals[1] = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%c"), url->_string, PATH_DELIM_FOR_TYPE(urlType)); + } + } else { + if (CFStringGetCharacterAtIndex(url->_string, CFStringGetLength(url->_string) - 1) != PATH_DELIM_FOR_TYPE(urlType)) { + vals[1] = CFRetain(url->_string); + } else { + vals[1] = CFStringCreateWithSubstring(alloc, url->_string, CFRangeMake(0, CFStringGetLength(url->_string) - 1)); + } + } + } + if (base != NULL) { + if (CF_IS_OBJC(__kCFURLTypeID, base)) { + SInt32 urlType = FULL_URL_REPRESENTATION; + vals[2] = CFNumberCreate(alloc, kCFNumberSInt32Type, &urlType); + vals[3] = CFURLGetString(base); } else { - // See if we can get a mount point. - Boolean foundMountPoint = false; - uint8_t buf[CFMaxPathLength]; - FSRef volSpec; - // Now produce an FSSpec from the volume, then try and get the mount point - if (__CFFSRefForVolumeName(firstComp, &volSpec, alloc) && (__CFCarbonCore_FSRefMakePath(&volSpec, buf, CFMaxPathLength) == noErr)) { - // We win! Ladies and gentlemen, we have a mount point. - if (buf[0] == '/' && buf[1] == '\0') { - // Special case this common case - foundMountPoint = true; - CFArrayRemoveValueAtIndex(newComponents, 0); - CFArrayInsertValueAtIndex(newComponents, 0, CFSTR("")); + SInt32 urlType = URL_PATH_TYPE(base); + vals[2] = CFNumberCreate(alloc, kCFNumberSInt32Type, &urlType); + if (base->_flags & IS_DIRECTORY) { + if (CFStringGetCharacterAtIndex(base->_string, CFStringGetLength(base->_string) - 1) == PATH_DELIM_FOR_TYPE(urlType)) { + vals[3] = CFRetain(base->_string); } else { - // This is pretty inefficient; we can do better. - CFStringRef mountPoint = CFStringCreateWithCString(alloc, buf, CFStringFileSystemEncoding()); - CFArrayRef mountComponents = mountPoint ? CFStringCreateArrayBySeparatingStrings(alloc, mountPoint, CFSTR("/")) : NULL; - if (mountComponents) { - CFIndex idx = CFArrayGetCount(mountComponents) - 1; - CFArrayRemoveValueAtIndex(newComponents, 0); - for ( ; idx >= 0; idx --) { - CFArrayInsertValueAtIndex(newComponents, 0, CFArrayGetValueAtIndex(mountComponents, idx)); - } - CFRelease(mountComponents); - foundMountPoint = true; - } - if (mountPoint) CFRelease(mountPoint); + vals[3] = CFStringCreateWithFormat(alloc, NULL, CFSTR("%@%c"), base->_string, PATH_DELIM_FOR_TYPE(urlType)); + } + } else { + if (CFStringGetCharacterAtIndex(base->_string, CFStringGetLength(base->_string) - 1) != PATH_DELIM_FOR_TYPE(urlType)) { + vals[3] = CFRetain(base->_string); + } else { + vals[3] = CFStringCreateWithSubstring(alloc, base->_string, CFRangeMake(0, CFStringGetLength(base->_string) - 1)); } - } - if (!foundMountPoint) { - // Fall back to treating the volume name as the top level directory - CFArrayInsertValueAtIndex(newComponents, 0, CFSTR("")); } } + *count = 4; } else { - CFArrayRemoveValueAtIndex(newComponents, 0); - } - - cnt = CFArrayGetCount(newComponents); - for (i = 0; i < cnt; i ++) { - CFStringRef comp = CFArrayGetValueAtIndex(newComponents, i); - CFStringRef newComp = NULL; - CFRange searchRg, slashRg; - searchRg.location = 0; - searchRg.length = CFStringGetLength(comp); - while (CFStringFindWithOptions(comp, CFSTR("/"), searchRg, 0, &slashRg)) { - if (!newComp) { - newComp = CFStringCreateMutableCopy(alloc, searchRg.location + searchRg.length, comp); - } - CFStringReplace((CFMutableStringRef)newComp, slashRg, CFSTR(":")); - searchRg.length = searchRg.location + searchRg.length - slashRg.location - 1; - searchRg.location = slashRg.location + 1; - } - if (newComp) { - CFArraySetValueAtIndex(newComponents, i, newComp); - CFRelease(newComp); - } + *count = 2; } - if (isDir && CFStringGetLength(CFArrayGetValueAtIndex(newComponents, cnt-1)) != 0) { - CFArrayAppendValue(newComponents, CFSTR("")); - } - return newComponents; } -static CFStringRef HFSPathToURLPath(CFStringRef path, CFAllocatorRef alloc, Boolean isDir) { - CFArrayRef components = HFSPathToURLComponents(path, alloc, isDir); - CFArrayRef newComponents = components ? copyStringArrayWithTransformation(components, escapePathComponent) : NULL; - CFIndex cnt; - CFStringRef result; - if (components) CFRelease(components); - if (!newComponents) return NULL; - - cnt = CFArrayGetCount(newComponents); - if (cnt == 1 && CFStringGetLength(CFArrayGetValueAtIndex(newComponents, 0)) == 0) { - result = CFRetain(CFSTR("/")); - } else { - result = CFStringCreateByCombiningStrings(alloc, newComponents, CFSTR("/")); - } - CFRelease(newComponents); - return result; +// Private API for Finder to use +CFPropertyListRef _CFURLCopyPropertyListRepresentation(CFURLRef url) { + CFTypeRef keys[4], vals[4]; + CFDictionaryRef dict; + CFIndex count, idx; + __CFURLCopyPropertyListKeysAndValues(url, keys, vals, &count); + dict = CFDictionaryCreate(CFGetAllocator(url), keys, vals, count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + for (idx = 0; idx < count; idx ++) { + CFRelease(vals[idx]); + } + return dict; } +CFURLRef _CFURLCreateFromPropertyListRepresentation(CFAllocatorRef alloc, CFPropertyListRef pListRepresentation) { + CFStringRef baseString, string; + CFNumberRef baseTypeNum, urlTypeNum; + SInt32 baseType, urlType; + CFURLRef baseURL = NULL, url; + CFDictionaryRef dict = (CFDictionaryRef)pListRepresentation; -static CFStringRef URLPathToHFSPath(CFStringRef path, CFAllocatorRef allocator, CFStringEncoding encoding) { - return NULL; + // Start by getting all the pieces and verifying they're of the correct type. + if (CFGetTypeID(pListRepresentation) != CFDictionaryGetTypeID()) { + return NULL; + } + string = (CFStringRef)CFDictionaryGetValue(dict, CFSTR("_CFURLString")); + if (!string || CFGetTypeID(string) != CFStringGetTypeID()) { + return NULL; + } + urlTypeNum = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("_CFURLStringType")); + if (!urlTypeNum || CFGetTypeID(urlTypeNum) != CFNumberGetTypeID() || !CFNumberGetValue(urlTypeNum, kCFNumberSInt32Type, &urlType) || (urlType != FULL_URL_REPRESENTATION && urlType != kCFURLPOSIXPathStyle && urlType != kCFURLHFSPathStyle && urlType != kCFURLWindowsPathStyle)) { + return NULL; + } + baseString = (CFStringRef)CFDictionaryGetValue(dict, CFSTR("_CFURLBaseURLString")); + if (baseString) { + if (CFGetTypeID(baseString) != CFStringGetTypeID()) { + return NULL; + } + baseTypeNum = (CFNumberRef)CFDictionaryGetValue(dict, CFSTR("_CFURLBaseStringType")); + if (!baseTypeNum || CFGetTypeID(baseTypeNum) != CFNumberGetTypeID() || !CFNumberGetValue(baseTypeNum, kCFNumberSInt32Type, &baseType) || + (baseType != FULL_URL_REPRESENTATION && baseType != kCFURLPOSIXPathStyle && baseType != kCFURLHFSPathStyle && baseType != kCFURLWindowsPathStyle)) { + return NULL; + } + if (baseType == FULL_URL_REPRESENTATION) { + baseURL = _CFURLCreateWithArbitraryString(alloc, baseString, NULL); + } else { + baseURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, baseString, (CFURLPathStyle)baseType, CFStringGetCharacterAtIndex(baseString, CFStringGetLength(baseString)-1) == PATH_DELIM_FOR_TYPE(baseType), NULL); + } + } + if (urlType == FULL_URL_REPRESENTATION) { + url = _CFURLCreateWithArbitraryString(alloc, string, baseURL); + } else { + url = CFURLCreateWithFileSystemPathRelativeToBase(alloc, string, (CFURLPathStyle)urlType, CFStringGetCharacterAtIndex(string, CFStringGetLength(string)-1) == PATH_DELIM_FOR_TYPE(urlType), baseURL); + } + if (baseURL) CFRelease(baseURL); + return url; } diff --git a/URL.subproj/CFURL.h b/CFURL.h similarity index 97% rename from URL.subproj/CFURL.h rename to CFURL.h index 18fedb2..0f1d294 100644 --- a/URL.subproj/CFURL.h +++ b/CFURL.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFURL.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFURL__) @@ -31,15 +31,14 @@ #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN -typedef enum { +enum { kCFURLPOSIXPathStyle = 0, kCFURLHFSPathStyle, kCFURLWindowsPathStyle -} CFURLPathStyle; +}; +typedef CFIndex CFURLPathStyle; typedef const struct __CFURL * CFURLRef; @@ -293,7 +292,7 @@ CFURLRef CFURLCreateCopyDeletingPathExtension(CFAllocatorRef allocator, CFURLRef CF_EXPORT CFIndex CFURLGetBytes(CFURLRef url, UInt8 *buffer, CFIndex bufferLength) AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; -typedef enum { +enum { kCFURLComponentScheme = 1, kCFURLComponentNetLocation = 2, kCFURLComponentPath = 3, @@ -307,7 +306,8 @@ typedef enum { kCFURLComponentParameterString = 10, kCFURLComponentQuery = 11, kCFURLComponentFragment = 12 -} CFURLComponentType; +}; +typedef CFIndex CFURLComponentType; /* Gets the range of the requested component in the bytes of url, as @@ -404,14 +404,12 @@ CFStringRef CFURLCreateStringByReplacingPercentEscapesUsingEncoding(CFAllocatorR /* charactersToLeaveUnescaped. To simply correct any non-URL characters */ /* in an otherwise correct URL string, do: */ -/* newString = CFURLCreateStringByAddingPercentEscapes(NULL, origString, NULL, NULL, kCFStringEncodingUTF8); */ +/* newString = CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, origString, NULL, NULL, kCFStringEncodingUTF8); */ CF_EXPORT CFStringRef CFURLCreateStringByAddingPercentEscapes(CFAllocatorRef allocator, CFStringRef originalString, CFStringRef charactersToLeaveUnescaped, CFStringRef legalURLCharactersToBeEscaped, CFStringEncoding encoding); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END -#endif /* !__COREFOUNDATION_CFURL__ */ +#endif /* ! __COREFOUNDATION_CFURL__ */ diff --git a/URL.subproj/CFURLAccess.c b/CFURLAccess.c similarity index 53% rename from URL.subproj/CFURLAccess.c rename to CFURLAccess.c index 2559602..9f1dc61 100644 --- a/URL.subproj/CFURLAccess.c +++ b/CFURLAccess.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -37,20 +37,7 @@ CFData read/write routines #include #include #include - -#if defined(__WIN32__) -#include -#include -#include -#include -#include -#include -#define timeval xxx_timeval -#define BOOLEAN xxx_BOOLEAN -#include -#undef BOOLEAN -#undef timeval -#else +#if DEPLOYMENT_TARGET_MACOSX #include #include #include @@ -61,14 +48,15 @@ CFData read/write routines #include #endif -#if defined(__MACH__) + +#if DEPLOYMENT_TARGET_MACOSX DEFINE_WEAK_CFNETWORK_FUNC(Boolean, _CFURLCreateDataAndPropertiesFromResource, (CFAllocatorRef A, CFURLRef B, CFDataRef *C, CFDictionaryRef *D, CFArrayRef E, SInt32 *F), (A, B, C, D, E, F), false) DEFINE_WEAK_CFNETWORK_FUNC(Boolean, _CFURLWriteDataAndPropertiesToResource, (CFURLRef A, CFDataRef B, CFDictionaryRef C, SInt32 *D), (A, B, C, D), false) DEFINE_WEAK_CFNETWORK_FUNC(Boolean, _CFURLDestroyResource, (CFURLRef A, SInt32 *B), (A, B), false) #endif - + CONST_STRING_DECL(kCFURLFileExists, "kCFURLFileExists") CONST_STRING_DECL(kCFURLFilePOSIXMode, "kCFURLFilePOSIXMode") @@ -79,6 +67,10 @@ CONST_STRING_DECL(kCFURLFileOwnerID, "kCFURLFileOwnerID") CONST_STRING_DECL(kCFURLHTTPStatusCode, "kCFURLHTTPStatusCode") CONST_STRING_DECL(kCFURLHTTPStatusLine, "kCFURLHTTPStatusLine") +CONST_STRING_DECL(kCFDataURLDataLength, "kCFDataURLDataLength") +CONST_STRING_DECL(kCFDataURLMimeType, "kCFDataURLMimeType") +CONST_STRING_DECL(kCFDataURLTextEncodingName, "kCFDataURLTextEncodingName") + // Compatibility property strings -- we obsoleted these names pre-DP4. REW, 5/22/2000 CONST_STRING_DECL(kCFFileURLExists, "kCFURLFileExists") CONST_STRING_DECL(kCFFileURLPOSIXMode, "kCFURLFilePOSIXMode") @@ -121,7 +113,7 @@ static CFDictionaryRef _CFFileURLCreatePropertiesFromResource(CFAllocatorRef all values[3] = kCFURLFileLength; values[4] = kCFURLFileLastModificationTime; values[5] = kCFURLFileOwnerID; - _allProps = CFArrayCreate(NULL, values, 6, &kCFTypeArrayCallBacks); + _allProps = CFArrayCreate(kCFAllocatorSystemDefault, values, 6, &kCFTypeArrayCallBacks); } desiredProperties = _allProps; } @@ -200,9 +192,6 @@ static CFDictionaryRef _CFFileURLCreatePropertiesFromResource(CFAllocatorRef all } static Boolean _CFFileURLWritePropertiesToResource(CFURLRef url, CFDictionaryRef propertyDict, SInt32 *errorCode) { -#if defined(__MACOS8__) - return false; // No properties are writable on OS 8 -#else CFTypeRef buffer[16]; CFTypeRef *keys; CFTypeRef *values; @@ -210,23 +199,23 @@ static Boolean _CFFileURLWritePropertiesToResource(CFURLRef url, CFDictionaryRef SInt32 idx, count; char cPath[CFMaxPathSize]; - if (!CFURLGetFileSystemRepresentation(url, true, cPath, CFMaxPathSize)) { + if (!CFURLGetFileSystemRepresentation(url, true, (unsigned char *)cPath, CFMaxPathSize)) { if (errorCode) *errorCode = kCFURLImproperArgumentsError; return false; } count = CFDictionaryGetCount(propertyDict); if (count < 8) { - (CFTypeRef)keys = buffer; - (CFTypeRef)values = buffer+8; + keys = buffer; + values = buffer+8; } else { - keys = CFAllocatorAllocate(CFGetAllocator(url), sizeof(void *) * count * 2, 0); + keys = (CFTypeRef *)CFAllocatorAllocate(CFGetAllocator(url), sizeof(void *) * count * 2, 0); values = keys + count; } CFDictionaryGetKeysAndValues(propertyDict, keys, values); for (idx = 0; idx < count; idx ++) { - CFStringRef key = keys[idx]; + CFStringRef key = (CFStringRef)keys[idx]; CFTypeRef value = values[idx]; if (key == kCFURLFilePOSIXMode || CFEqual(kCFURLFilePOSIXMode, key)) { SInt32 mode; @@ -235,11 +224,10 @@ static Boolean _CFFileURLWritePropertiesToResource(CFURLRef url, CFDictionaryRef CFNumberRef modeNum = (CFNumberRef)value; CFNumberGetValue(modeNum, kCFNumberSInt32Type, &mode); } else { -#if defined(__WIN32__) - const uint16_t *modePtr = (const uint16_t *)CFDataGetBytePtr((CFDataRef)value); -#else - const mode_t *modePtr = (const mode_t *)CFDataGetBytePtr((CFDataRef)value); +#if DEPLOYMENT_TARGET_MACOSX +#define MODE_TYPE mode_t #endif + const MODE_TYPE *modePtr = (const MODE_TYPE *)CFDataGetBytePtr((CFDataRef)value); mode = *modePtr; } err = chmod(cPath, mode); @@ -253,7 +241,6 @@ static Boolean _CFFileURLWritePropertiesToResource(CFURLRef url, CFDictionaryRef if (errorCode) *errorCode = result ? 0 : kCFURLUnknownError; return result; -#endif } static Boolean _CFFileURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFDataRef *fetchedData, CFArrayRef desiredProperties, CFDictionaryRef *fetchedProperties, SInt32 *errorCode) { @@ -268,7 +255,7 @@ static Boolean _CFFileURLCreateDataAndPropertiesFromResource(CFAllocatorRef allo if (alloc == NULL) { // We need a real allocator to pass to _CFReadBytesFromFile so that the CFDataRef we create with // CFDataCreateWithBytesNoCopy() can free up the object _CFReadBytesFromFile() returns. - alloc = CFRetain(__CFGetDefaultAllocator()); + alloc = (CFAllocatorRef)CFRetain(__CFGetDefaultAllocator()); releaseAlloc = true; } if (!_CFReadBytesFromFile(alloc, url, &bytes, &length, 0)) { @@ -276,7 +263,7 @@ static Boolean _CFFileURLCreateDataAndPropertiesFromResource(CFAllocatorRef allo *fetchedData = NULL; success = false; } else { - *fetchedData = CFDataCreateWithBytesNoCopy(alloc, bytes, length, alloc); + *fetchedData = CFDataCreateWithBytesNoCopy(alloc, (const UInt8 *)bytes, length, alloc); } if (releaseAlloc) { // Now the CFData should be hanging on to it. @@ -291,6 +278,401 @@ static Boolean _CFFileURLCreateDataAndPropertiesFromResource(CFAllocatorRef allo return success; } + +/* + * Support for data: URLs - RFC 2397 + * Currently this is spi for CFNetwork, to make it API, just put these constants in CFURLAccess.h + */ + +/* +CF_EXPORT +const CFStringRef kCFDataURLDataLength; +CF_EXPORT +const CFStringRef kCFDataURLMimeType; +CF_EXPORT +const CFStringRef kCFDataURLTextEncodingName; +*/ + +/* Properties for the data: scheme. */ +/* kCFDataURLDataLength is a CFNumber giving the data's length in bytes. */ +/* kCFDataURLMimeType is a CFString. */ +/* kCFDataURLTextEncodingName is a CFString. */ + +/* REMINDSMZ: From CFURLResponse.c */ +static CFStringRef mimeTypeFromContentTypeComponent(CFStringRef component) { + CFIndex compLen = CFStringGetLength(component); + CFStringInlineBuffer buf; + CFIndex idx; + CFIndex firstChar = -1, lastChar = -1; + CFCharacterSetRef whitespaceSet = CFCharacterSetGetPredefined(kCFCharacterSetWhitespace); + CFStringInitInlineBuffer(component, &buf, CFRangeMake(0, compLen)); + + for (idx = 0; idx < compLen; idx ++) { + UniChar ch = CFStringGetCharacterFromInlineBuffer(&buf, idx); + if (ch == ';') { + // Delimits the charset + break; + } else if (firstChar == -1) { + if (!CFCharacterSetIsCharacterMember(whitespaceSet, ch)) { + firstChar = idx; + } + } else if (!CFCharacterSetIsCharacterMember(whitespaceSet, ch)) { + lastChar = idx; + } + } + if (firstChar != -1 && lastChar != -1) { + CFMutableStringRef newContentType = CFStringCreateMutableCopy(CFGetAllocator(component), compLen, component); + if (lastChar != compLen - 1) { + CFStringDelete(newContentType, CFRangeMake(lastChar + 1, compLen - lastChar - 1)); + } + if (firstChar > 0) { + CFStringDelete(newContentType, CFRangeMake(0, firstChar)); + } + CFStringLowercase(newContentType, NULL); + return newContentType; + } + return NULL; +} + +/* REMINDSMZ: From CFURLResponse.c */ +static CFStringRef charsetFromContentTypeHeader(CFStringRef contentType) { + // FIXME: Should this use KeyValuePair parsing to handle quoting properly? + CFRange range; + CFIndex compLen = CFStringGetLength(contentType); + CFIndex start, end, idx; + CFCharacterSetRef whitespaceSet; + CFMutableStringRef result; + + CFStringRef kCFURLResponseCharsetPrefix = CFSTR("charset="); + + if (!CFStringFindWithOptions(contentType, kCFURLResponseCharsetPrefix, CFRangeMake(0, compLen), kCFCompareCaseInsensitive, &range) || range.length == 0) return NULL; + + whitespaceSet = CFCharacterSetGetPredefined(kCFCharacterSetWhitespace); + start = -1; + end = -1; + for (idx = range.location + range.length; idx < compLen; idx ++) { + UniChar ch = CFStringGetCharacterAtIndex(contentType, idx); + if (ch == ';' || ch == ',') break; + if (start == -1) { + if (!CFCharacterSetIsCharacterMember(whitespaceSet, ch)) { + start = idx; + end = idx; + } + } else if (!CFCharacterSetIsCharacterMember(whitespaceSet,ch)) { + end = idx; + } + } + + if (start == -1) return NULL; + + result = CFStringCreateMutableCopy(CFGetAllocator(contentType), compLen,contentType); + if (end != compLen) { + CFStringDelete(result, CFRangeMake(end+1, compLen-end-1)); + } + CFStringDelete(result, CFRangeMake(0, start)); + CFStringLowercase(result, NULL); + return result; +} + +#define STATIC_BUFFER_SIZE 1024 + +static BOOL isHexDigit(char c) +{ + return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); +} + +static UInt8 hexDigitValue(char c) +{ + if (c >= '0' && c <= '9') { + return c - '0'; + } + if (c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } + if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } + // NSURL_ERROR("illegal hex digit"); + return 0; +} + +static CFDataRef percentEscapeDecodeBuffer(CFAllocatorRef alloc, const UInt8* srcBuffer, CFRange range, Boolean stripWhitespace) +{ + UInt8* dstBuffer; + UInt8 staticDstBuffer[STATIC_BUFFER_SIZE]; + + if (range.length > STATIC_BUFFER_SIZE) { + dstBuffer = (UInt8*) malloc(range.length); + } else { + dstBuffer = staticDstBuffer; + } + + CFIndex end = range.location + range.length; + + CFIndex i; + CFIndex j; + for (i = range.location, j = 0; i < end; ++i) { + char value; + + if (srcBuffer[i] == '%' && end > i + 2 && isHexDigit(srcBuffer[i+1]) && isHexDigit(srcBuffer[i+2])) { + value = hexDigitValue(srcBuffer[i+1]) * 16 + hexDigitValue(srcBuffer[i+2]); + i += 2; + } else { + value = srcBuffer[i]; + } + + if (!stripWhitespace || !isspace(value)) { + dstBuffer[j++] = value; + } + } + + CFDataRef result = CFDataCreate(alloc, dstBuffer, j); + + if (dstBuffer != staticDstBuffer) { + free(dstBuffer); + } + + return result; +} + + +// base 64 digits: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" + +static BOOL isBase64Digit(char c) +{ + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '+') || (c == '/'); +} + +static BOOL isBase64DigitOrEqualSign(char c) +{ + return isBase64Digit(c) || c == '='; +} + +static UInt8 base64DigitValue(char c) +{ + if (c >= 'A' && c <= 'Z') { + return c - 'A'; + } else if (c >= 'a' && c <= 'z') { + return 26 + c - 'a'; + } else if (c >= '0' && c <= '9') { + return 52 + c - '0'; + } else if (c == '+') { + return 62; + } else if (c == '/') { + return 63; + } else { + return 0; + } +} + +static CFDataRef base64DecodeData(CFAllocatorRef alloc, CFDataRef data) +{ + const UInt8 *srcBuffer = CFDataGetBytePtr(data); + CFIndex length = CFDataGetLength(data); + UInt8 *dstBuffer = NULL; + UInt8 staticDstBuffer[STATIC_BUFFER_SIZE]; + CFDataRef result = NULL; + + // base64 encoded data length must be multiple of 4 + if (length % 4 != 0) { + goto done; + } + + if (length > STATIC_BUFFER_SIZE) { + dstBuffer = (UInt8*) malloc(length); + } else { + dstBuffer = staticDstBuffer; + } + + CFIndex i; + CFIndex j; + for (i = 0, j = 0; i < length; i+=4) { + if (!(isBase64Digit(srcBuffer[i]) && + isBase64Digit(srcBuffer[i+1]) && + isBase64DigitOrEqualSign(srcBuffer[i+2]) && + isBase64DigitOrEqualSign(srcBuffer[i+3]))) { + if (dstBuffer != staticDstBuffer) { + free(dstBuffer); + } + return NULL; + } + + dstBuffer[j++] = (base64DigitValue(srcBuffer[i]) << 2) + (base64DigitValue(srcBuffer[i+1]) >> 4); + if (srcBuffer[i+2] != '=') { + dstBuffer[j++] = ((base64DigitValue(srcBuffer[i+1]) & 0xf) << 4) + (base64DigitValue(srcBuffer[i+2]) >> 2); + } + if (srcBuffer[i+3] != '=') { + dstBuffer[j++] = ((base64DigitValue(srcBuffer[i+2]) & 0x3) << 6) + (base64DigitValue(srcBuffer[i+3])); + } + } + + result = CFDataCreate(alloc, dstBuffer, j); + +done: + if (dstBuffer != staticDstBuffer) { + free(dstBuffer); + } + + return result; +} + +static inline CFStringRef percentExpandAndTrimContentType(CFAllocatorRef alloc, CFStringRef str, CFRange range) +{ + CFStringRef contentTypeUnexpanded = CFStringCreateWithSubstring(alloc, str, range); + CFStringRef contentTypeExpanded = CFURLCreateStringByReplacingPercentEscapes(alloc, contentTypeUnexpanded, CFSTR("")); + CFRelease(contentTypeUnexpanded); + + CFMutableStringRef contentTypeHeader = CFStringCreateMutableCopy(alloc, 0, contentTypeExpanded); + CFRelease(contentTypeExpanded); + CFStringTrimWhitespace(contentTypeHeader); + + return contentTypeHeader; +} + +static Boolean parseDataRequestURL(CFURLRef url, CFDataRef* outData, CFStringRef* outMimeType, CFStringRef* outTextEncodingName) +{ + Boolean result = FALSE; + CFAllocatorRef alloc = CFGetAllocator(url); + CFStringRef str = CFURLCopyResourceSpecifier(url); + if (str != NULL) { + CFRange commaRange = CFStringFind(str, CFSTR(","), 0); + + if (commaRange.location != kCFNotFound) { + CFStringRef contentTypeHeader = percentExpandAndTrimContentType(alloc, str, CFRangeMake(0, commaRange.location)); + CFStringRef mimeType = mimeTypeFromContentTypeComponent(contentTypeHeader); + CFStringRef textEncodingName = charsetFromContentTypeHeader(contentTypeHeader); + + Boolean base64 = CFStringFind(contentTypeHeader, CFSTR(";base64"), kCFCompareCaseInsensitive).location != kCFNotFound; + + if (mimeType == NULL) { + mimeType = (CFStringRef) CFRetain(CFSTR("text/plain")); + } + + if (textEncodingName == NULL) { + textEncodingName = (CFStringRef) CFRetain(CFSTR("us-ascii")); + } + + CFIndex bufferSize = CFURLGetBytes(url, NULL, 0); + UInt8* srcBuffer = (UInt8*) malloc(bufferSize); + CFURLGetBytes(url, srcBuffer, bufferSize); + + CFRange dataRange = CFURLGetByteRangeForComponent(url, kCFURLComponentResourceSpecifier, NULL); + while (srcBuffer[dataRange.location] != ',') { + dataRange.location++; + dataRange.length--; + } + dataRange.location++; + dataRange.length--; + + CFDataRef dataRef = NULL; + + if (! base64) { + dataRef = percentEscapeDecodeBuffer(alloc, srcBuffer, dataRange, false); + } else { + CFDataRef unescapedAndStripped = percentEscapeDecodeBuffer(alloc, srcBuffer, dataRange, true); + if (unescapedAndStripped) { + dataRef = base64DecodeData(alloc, unescapedAndStripped); + CFRelease(unescapedAndStripped); + } + } + + if (dataRef != NULL) { + *outData = dataRef; + *outMimeType = (CFStringRef) mimeType == NULL? NULL : CFStringCreateCopy(alloc, mimeType); + *outTextEncodingName = (CFStringRef) textEncodingName == NULL? NULL : CFStringCreateCopy(alloc, textEncodingName); + result = true; + } + + free(srcBuffer); + + if (contentTypeHeader) CFRelease(contentTypeHeader); + if (mimeType) CFRelease(mimeType); + if (textEncodingName) CFRelease(textEncodingName); + } + + CFRelease(str); + } + + return result; +} + +static Boolean _CFDataURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef url, CFDataRef *fetchedData, CFArrayRef desiredProperties, CFDictionaryRef *fetchedProperties, SInt32 *errorCode) { + Boolean success = true; + + if (errorCode) *errorCode = 0; + + // We always need to fetch the data... + CFDataRef data = NULL; + CFStringRef mimeType = NULL; + CFStringRef textEncodingName = NULL; + + if (! parseDataRequestURL(url, &data, &mimeType, &textEncodingName)) { + if (errorCode) + *errorCode = kCFURLUnknownError; + *fetchedData = NULL; + success = false; + } else { + if (fetchedData) { + *fetchedData = CFDataCreateCopy(alloc, data); + } + + if (fetchedProperties) { + const void* propKeys[] = { + kCFDataURLDataLength, + kCFDataURLMimeType, + kCFDataURLTextEncodingName, + }; + const CFIndex propKeysCount = sizeof(propKeys) / sizeof(propKeys[0]); + + if (desiredProperties == NULL) { + static CFArrayRef sAllProps = NULL; + if (sAllProps == NULL) { + sAllProps = CFArrayCreate(kCFAllocatorSystemDefault, propKeys, propKeysCount, &kCFTypeArrayCallBacks); + } + desiredProperties = sAllProps; + } + + const void* vals[propKeysCount]; + const void* keys[propKeysCount]; + int ixVal = 0; + + CFIndex count = CFArrayGetCount(desiredProperties); + for (CFIndex i = 0; i < count; i++) { + CFStringRef key = (CFStringRef) CFArrayGetValueAtIndex(desiredProperties, i); + + if (CFEqual(key, kCFDataURLDataLength)) { + CFIndex len = CFDataGetLength(data); + keys[ixVal] = key; + vals[ixVal++] = CFNumberCreate(alloc, kCFNumberCFIndexType, &len); + } else if (CFEqual(key, kCFDataURLMimeType)) { + if (mimeType != NULL) { + keys[ixVal] = key; + vals[ixVal++] = CFStringCreateCopy(alloc, mimeType); + } + } else if (CFEqual(key, kCFDataURLTextEncodingName)) { + if (textEncodingName != NULL) { + keys[ixVal] = key; + vals[ixVal++] = CFStringCreateCopy(alloc, textEncodingName); + } + } + } + + *fetchedProperties = CFDictionaryCreate(alloc, keys, vals, ixVal, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + for (CFIndex i = 0; i < ixVal; i++) + CFRelease(vals[i]); + if (*fetchedProperties == NULL) + success = false; + } + + if (data) CFRelease(data); + if (mimeType) CFRelease(mimeType); + if (textEncodingName) CFRelease(textEncodingName); + } + + + return success; +} + /*************************/ /* Public routines */ /*************************/ @@ -307,19 +689,16 @@ Boolean CFURLCreateDataAndPropertiesFromResource(CFAllocatorRef alloc, CFURLRef Boolean result; if (CFStringCompare(scheme, CFSTR("file"), 0) == kCFCompareEqualTo) { result = _CFFileURLCreateDataAndPropertiesFromResource(alloc, url, fetchedData, desiredProperties, fetchedProperties, errorCode); - } else { -#if defined(__MACH__) + } else if (CFStringCompare(scheme, CFSTR("data"), 0) == kCFCompareEqualTo) { + result = _CFDataURLCreateDataAndPropertiesFromResource(alloc, url, fetchedData, desiredProperties, fetchedProperties, errorCode); + } else { +#if DEPLOYMENT_TARGET_MACOSX result = __CFNetwork__CFURLCreateDataAndPropertiesFromResource(alloc, url, fetchedData, fetchedProperties, desiredProperties, errorCode); if (!result) { if (fetchedData) *fetchedData = NULL; if (fetchedProperties) *fetchedProperties = NULL; if (errorCode) *errorCode = kCFURLUnknownSchemeError; } -#else - if (fetchedData) *fetchedData = NULL; - if (fetchedProperties) *fetchedProperties = NULL; - if (errorCode) *errorCode = kCFURLUnknownSchemeError; - result = false; #endif } CFRelease(scheme); @@ -357,7 +736,7 @@ Boolean CFURLWriteDataAndPropertiesToResource(CFURLRef url, CFDataRef data, CFDi if (CFURLHasDirectoryPath(url)) { // Create a directory char cPath[CFMaxPathSize]; - if (!CFURLGetFileSystemRepresentation(url, true, cPath, CFMaxPathSize)) { + if (!CFURLGetFileSystemRepresentation(url, true, (unsigned char *)cPath, CFMaxPathSize)) { if (errorCode) *errorCode = kCFURLImproperArgumentsError; success = false; } else { @@ -379,15 +758,12 @@ Boolean CFURLWriteDataAndPropertiesToResource(CFURLRef url, CFDataRef data, CFDi return success; } else { CFRelease(scheme); -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX Boolean result = __CFNetwork__CFURLWriteDataAndPropertiesToResource(url, data, propertyDict, errorCode); if (!result) { if (errorCode) *errorCode = kCFURLUnknownSchemeError; } return result; -#else - if (errorCode) *errorCode = kCFURLUnknownSchemeError; - return false; #endif } } @@ -401,7 +777,7 @@ Boolean CFURLDestroyResource(CFURLRef url, SInt32 *errorCode) { return false; } else if (CFStringCompare(scheme, CFSTR("file"), 0) == kCFCompareEqualTo) { CFRelease(scheme); - if (!CFURLGetFileSystemRepresentation(url, true, cPath, CFMaxPathSize)) { + if (!CFURLGetFileSystemRepresentation(url, true, (unsigned char *)cPath, CFMaxPathSize)) { if (errorCode) *errorCode = kCFURLImproperArgumentsError; return false; } @@ -425,15 +801,12 @@ Boolean CFURLDestroyResource(CFURLRef url, SInt32 *errorCode) { } } else { CFRelease(scheme); -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX Boolean result = __CFNetwork__CFURLDestroyResource(url, errorCode); if (!result) { if (errorCode) *errorCode = kCFURLUnknownSchemeError; } return result; -#else - if (errorCode) *errorCode = kCFURLUnknownSchemeError; - return false; #endif } } diff --git a/URL.subproj/CFURLAccess.h b/CFURLAccess.h similarity index 95% rename from URL.subproj/CFURLAccess.h rename to CFURLAccess.h index b1d094b..ab55127 100644 --- a/URL.subproj/CFURLAccess.h +++ b/CFURLAccess.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFURLAccess.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFURLACCESS__) @@ -34,9 +34,7 @@ #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN /* Attempts to read the data and properties for the given URL. If only interested in one of the resourceData and properties, pass NULL @@ -85,7 +83,7 @@ CF_EXPORT CFTypeRef CFURLCreatePropertyFromResource(CFAllocatorRef alloc, CFURLRef url, CFStringRef property, SInt32 *errorCode); /* Common error codes; this list is expected to grow */ -typedef enum { +enum { kCFURLUnknownError = -10, kCFURLUnknownSchemeError = -11, kCFURLResourceNotFoundError = -12, @@ -95,7 +93,8 @@ typedef enum { kCFURLUnknownPropertyKeyError = -16, kCFURLPropertyKeyUnavailableError = -17, kCFURLTimeoutError = -18 -} CFURLError; +}; +typedef CFIndex CFURLError; /* Property keys */ @@ -127,9 +126,7 @@ const CFStringRef kCFURLHTTPStatusLine; /* The value of kCFURLHTTPStatusCode is a CFNumber */ /* The value of kCFURLHTTPStatusLine is a CFString */ -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END -#endif /* !__COREFOUNDATION_CFURLACCESS__ */ +#endif /* ! __COREFOUNDATION_CFURLACCESS__ */ diff --git a/Base.subproj/CFUUID.c b/CFUUID.c similarity index 85% rename from Base.subproj/CFUUID.c rename to CFUUID.c index aca6d47..ad8d89e 100644 --- a/Base.subproj/CFUUID.c +++ b/CFUUID.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,17 +21,18 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFUUID.c - Copyright 1999-2002, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007 Apple Inc. All rights reserved. Responsibility: Doug Davidson */ #include #include "CFInternal.h" - -extern uint32_t _CFGenerateUUID(uint8_t *uuid_bytes); +#if DEPLOYMENT_TARGET_MACOSX +#include +#endif static CFMutableDictionaryRef _uniquedUUIDs = NULL; -static CFSpinLock_t CFUUIDGlobalDataLock = 0; +static CFSpinLock_t CFUUIDGlobalDataLock = CFSpinLockInit; struct __CFUUID { CFRuntimeBase _base; @@ -49,15 +50,26 @@ static CFHashCode __CFhashUUIDBytes(const void *ptr) { return CFHashBytes((uint8_t *)ptr, 16); } -static CFDictionaryKeyCallBacks __CFUUIDBytesDictionaryKeyCallBacks = {0, NULL, NULL, NULL, __CFisEqualUUIDBytes, __CFhashUUIDBytes}; -static CFDictionaryValueCallBacks __CFnonRetainedUUIDDictionaryValueCallBacks = {0, NULL, NULL, CFCopyDescription, CFEqual}; +#import "auto_stubs.h" + +#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) + + +/***** end of weak set */ static void __CFUUIDAddUniqueUUID(CFUUIDRef uuid) { __CFSpinLock(&CFUUIDGlobalDataLock); + + CFDictionaryKeyCallBacks __CFUUIDBytesDictionaryKeyCallBacks = {0, NULL, NULL, NULL, __CFisEqualUUIDBytes, __CFhashUUIDBytes}; + CFDictionaryValueCallBacks __CFnonRetainedUUIDDictionaryValueCallBacks = {0, NULL, NULL, CFCopyDescription, CFEqual}; + if (_uniquedUUIDs == NULL) { - /* Allocate table from default allocator */ - // XXX_PCB these need to weakly hold the UUIDs, otherwise, they will never be collected. - _uniquedUUIDs = CFDictionaryCreateMutable(kCFAllocatorMallocZone, 0, &__CFUUIDBytesDictionaryKeyCallBacks, &__CFnonRetainedUUIDDictionaryValueCallBacks); + _uniquedUUIDs = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &__CFUUIDBytesDictionaryKeyCallBacks, &__CFnonRetainedUUIDDictionaryValueCallBacks); } CFDictionarySetValue(_uniquedUUIDs, &(uuid->_bytes), uuid); __CFSpinUnlock(&CFUUIDGlobalDataLock); @@ -75,20 +87,20 @@ static CFUUIDRef __CFUUIDGetUniquedUUID(CFUUIDBytes *bytes) { CFUUIDRef uuid = NULL; __CFSpinLock(&CFUUIDGlobalDataLock); if (_uniquedUUIDs != NULL) { - uuid = CFDictionaryGetValue(_uniquedUUIDs, bytes); + uuid = (CFUUIDRef)CFDictionaryGetValue(_uniquedUUIDs, bytes); } __CFSpinUnlock(&CFUUIDGlobalDataLock); return uuid; } -static void __CFUUIDDeallocate(CFTypeRef cf) { +static void __CFUUIDDeallocate(CFTypeRef cf) { struct __CFUUID *uuid = (struct __CFUUID *)cf; __CFUUIDRemoveUniqueUUID(uuid); } static CFStringRef __CFUUIDCopyDescription(CFTypeRef cf) { CFStringRef uuidStr = CFUUIDCreateString(CFGetAllocator(cf), (CFUUIDRef)cf); - CFStringRef desc = CFStringCreateWithFormat(NULL, NULL, CFSTR(" %@"), cf, uuidStr); + CFStringRef desc = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR(" %@"), cf, uuidStr); CFRelease(uuidStr); return desc; } @@ -123,7 +135,7 @@ static CFUUIDRef __CFUUIDCreateWithBytesPrimitive(CFAllocatorRef allocator, CFUU struct __CFUUID *uuid = (struct __CFUUID *)__CFUUIDGetUniquedUUID(&bytes); if (uuid == NULL) { - UInt32 size; + size_t size; size = sizeof(struct __CFUUID) - sizeof(CFRuntimeBase); uuid = (struct __CFUUID *)_CFRuntimeCreateInstance(allocator, __kCFUUIDTypeID, size, NULL); @@ -145,7 +157,23 @@ CFUUIDRef CFUUIDCreate(CFAllocatorRef alloc) { uint32_t retval = 0; __CFSpinLock(&CFUUIDGlobalDataLock); - retval = _CFGenerateUUID((uint8_t *)&bytes); +#if (DEPLOYMENT_TARGET_MACOSX) + static Boolean useV1UUIDs = false, checked = false; + uuid_t uuid; + if (!checked) { + const char *value = getenv("CFUUIDVersionNumber"); + if (value) { + if (1 == strtoul_l(value, NULL, 0, NULL)) useV1UUIDs = true; + } else { + if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionTiger)) useV1UUIDs = true; + } + checked = true; + } + if (useV1UUIDs) uuid_generate_time(uuid); else uuid_generate_random(uuid); + memcpy(&bytes, uuid, sizeof(uuid)); +#else + retval = 1; +#endif __CFSpinUnlock(&CFUUIDGlobalDataLock); return (retval == 0) ? __CFUUIDCreateWithBytesPrimitive(alloc, bytes, false) : NULL; diff --git a/Base.subproj/CFUUID.h b/CFUUID.h similarity index 94% rename from Base.subproj/CFUUID.h rename to CFUUID.h index 13f265a..d98ec21 100644 --- a/Base.subproj/CFUUID.h +++ b/CFUUID.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFUUID.h - Copyright (c) 1999-2005, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFUUID__) @@ -30,9 +30,7 @@ #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN typedef const struct __CFUUID * CFUUIDRef; @@ -89,9 +87,7 @@ CFUUIDBytes CFUUIDGetUUIDBytes(CFUUIDRef uuid); CF_EXPORT CFUUIDRef CFUUIDCreateFromUUIDBytes(CFAllocatorRef alloc, CFUUIDBytes bytes); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFUUID__ */ diff --git a/StringEncodings.subproj/CFUniChar.c b/CFUniChar.c similarity index 62% rename from StringEncodings.subproj/CFUniChar.c rename to CFUniChar.c index 35de0a7..7f41056 100644 --- a/StringEncodings.subproj/CFUniChar.c +++ b/CFUniChar.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -27,21 +27,12 @@ #include #include "CFInternal.h" +#include "CFBundle_Internal.h" #include "CFUniChar.h" #include "CFStringEncodingConverterExt.h" #include "CFUnicodeDecomposition.h" #include "CFUniCharPriv.h" -#if defined(__MACOS8__) -#include -#elif defined(__WIN32__) -#include -#include -#include -#include -#elif defined(__MACH__) || defined(__LINUX__) || defined(__FREEBSD__) -#if defined(__MACH__) -#include -#endif +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD #include #include #include @@ -50,202 +41,204 @@ #include #include #endif +#if DEPLOYMENT_TARGET_MACOSX +#include +#endif -#if defined(__MACOS8__) -#define MAXPATHLEN FILENAME_MAX -#elif defined WIN32 -#define MAXPATHLEN MAX_PATH +#if DEPLOYMENT_TARGET_MACOSX +#define __kCFCharacterSetDir "/System/Library/CoreServices" +#elif DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD +#define __kCFCharacterSetDir "/usr/local/share/CoreFoundation" +#elif defined(__WIN32__) +#define __kCFCharacterSetDir "\\Windows\\CoreFoundation" #endif +#if DEPLOYMENT_TARGET_MACOSX +#define USE_MACHO_SEGMENT 1 +#endif //__MACH__ + +enum { + kCFUniCharLastExternalSet = kCFUniCharNewlineCharacterSet, + kCFUniCharFirstInternalSet = kCFUniCharCompatibilityDecomposableCharacterSet, + kCFUniCharLastInternalSet = kCFUniCharGraphemeExtendCharacterSet, + kCFUniCharFirstBitmapSet = kCFUniCharDecimalDigitCharacterSet +}; + +CF_INLINE uint32_t __CFUniCharMapExternalSetToInternalIndex(uint32_t cset) { return ((kCFUniCharFirstInternalSet <= cset) ? ((cset - kCFUniCharFirstInternalSet) + kCFUniCharLastExternalSet) : cset) - kCFUniCharFirstBitmapSet; } +CF_INLINE uint32_t __CFUniCharMapCompatibilitySetID(uint32_t cset) { return ((cset == kCFUniCharControlCharacterSet) ? kCFUniCharControlAndFormatterCharacterSet : (((cset > kCFUniCharLastExternalSet) && (cset < kCFUniCharFirstInternalSet)) ? ((cset - kCFUniCharLastExternalSet) + kCFUniCharFirstInternalSet) : cset)); } + +#if (DEPLOYMENT_TARGET_MACOSX) && USE_MACHO_SEGMENT + +#include +#include +#include + +static const void *__CFGetSectDataPtr(const char *segname, const char *sectname, uint64_t *sizep) { + uint32_t idx, cnt = _dyld_image_count(); + for (idx = 0; idx < cnt; idx++) { + void *mh = (void *)_dyld_get_image_header(idx); + if (mh != &_mh_dylib_header) continue; +#if __LP64__ + const struct section_64 *sect = getsectbynamefromheader_64((struct mach_header_64 *)mh, segname, sectname); +#else + const struct section *sect = getsectbynamefromheader((struct mach_header *)mh, segname, sectname); +#endif + if (!sect) break; + if (sizep) *sizep = (uint64_t)sect->size; + return (char *)sect->addr + _dyld_get_image_vmaddr_slide(idx); + } + if (sizep) *sizep = 0ULL; + return NULL; +} + +#endif + +#if !USE_MACHO_SEGMENT + // Memory map the file -#if !defined(__MACOS8__) CF_INLINE void __CFUniCharCharacterSetPath(char *cpath) { -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX strlcpy(cpath, __kCFCharacterSetDir, MAXPATHLEN); -#elif defined(__WIN32__) - strlcpy(cpath, _CFDLLPath(), MAXPATHLEN); #else strlcpy(cpath, __kCFCharacterSetDir, MAXPATHLEN); #endif -#if defined(__WIN32__) - strlcat(cpath, "\\CharacterSets\\", MAXPATHLEN); +#if 0 || 0 +#if 0 + strncat(cpath, "\\Resources\\", MAXPATHLEN - strlen(cpath)); +#else + strncat(cpath, "\\CoreFoundation.resources\\CharacterSets\\", MAXPATHLEN - strlen(cpath)); +#endif #else strlcat(cpath, "/CharacterSets/", MAXPATHLEN); #endif } -static bool __CFUniCharLoadBytesFromFile(const char *fileName, const void **bytes) { -#if defined(__WIN32__) - HANDLE bitmapFileHandle; - HANDLE mappingHandle; +#if defined (__WIN32__) +#define MAX_BITMAP_STATE 512 +// +// If a string is placed into this array, then it has been previously +// determined that the bitmap-file cannot be found. Thus, we make +// the assumption it won't be there in future calls and we avoid +// hitting the disk un-necessarily. This assumption isn't 100% +// correct, as bitmap-files can be added. We would have to re-start +// the application in order to pick-up the new bitmap info. +// +// We should probably re-visit this. +// +static char *mappedBitmapState[MAX_BITMAP_STATE]; +static int __nNumStateEntries = -1; +CRITICAL_SECTION __bitmapStateLock = {0}; + +bool __GetBitmapStateForName(char *bitmapName) { + if (NULL == __bitmapStateLock.DebugInfo) + InitializeCriticalSection(&__bitmapStateLock); + EnterCriticalSection(&__bitmapStateLock); + if (__nNumStateEntries >= 0) { + for (int i = 0; i < __nNumStateEntries; i++) { + if (strcmp(mappedBitmapState[i], bitmapName) == 0) { + LeaveCriticalSection(&__bitmapStateLock); + return true; + } + } + } + LeaveCriticalSection(&__bitmapStateLock); + return false; +} +void __AddBitmapStateForName(char *bitmapName) { + if (NULL == __bitmapStateLock.DebugInfo) + InitializeCriticalSection(&__bitmapStateLock); + EnterCriticalSection(&__bitmapStateLock); + __nNumStateEntries++; + mappedBitmapState[__nNumStateEntries] = (char *)malloc((strlen(bitmapName)+1) * sizeof(char)); + strcpy(mappedBitmapState[__nNumStateEntries], bitmapName); + LeaveCriticalSection(&__bitmapStateLock); +} +#endif //__WIN32__ - if ((bitmapFileHandle = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) return false; - mappingHandle = CreateFileMapping(bitmapFileHandle, NULL, PAGE_READONLY, 0, 0, NULL); - CloseHandle(bitmapFileHandle); - if (!mappingHandle) return false; +static bool __CFUniCharLoadBytesFromFile(const char *fileName, const void **bytes) { +#if 0 || 0 + HANDLE bitmapFileHandle = NULL; + HANDLE mappingHandle = NULL; + + if (__GetBitmapStateForName((char *)fileName)) { + // The fileName has been tried in the past, so just return false + // and move on. + *bytes = NULL; + return false; + } + mappingHandle = OpenFileMappingA(FILE_MAP_READ, TRUE, fileName); + if (NULL == mappingHandle) { + if ((bitmapFileHandle = CreateFileA(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) { + // We tried to get the bitmap file for mapping, but it's not there. Add to list of non-existant bitmap-files so + // we don't have to try this again in the future. + __AddBitmapStateForName((char *)fileName); + return false; + } + mappingHandle = CreateFileMappingA(bitmapFileHandle, NULL, PAGE_READONLY, 0, 0, NULL); + CloseHandle(bitmapFileHandle); + if (!mappingHandle) return false; - *bytes = MapViewOfFileEx(mappingHandle, FILE_MAP_READ, 0, 0, 0, NULL); - CloseHandle(mappingHandle); + *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); + } return (*bytes ? true : false); #else struct stat statBuf; int fd = -1; - if ((fd = open(fileName, O_RDONLY, 0)) < 0) return false; - + int no_hang_fd = open("/dev/autofs_nowait", 0); + if ((fd = open(fileName, O_RDONLY, 0)) < 0) { + close(no_hang_fd); + return false; + } if (fstat(fd, &statBuf) < 0 || (*bytes = mmap(0, statBuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == (void *)-1) { close(fd); return false; } close(fd); + close(no_hang_fd); return true; #endif } +#endif // USE_MACHO_SEGMENT + static bool __CFUniCharLoadFile(const char *bitmapName, const void **bytes) { +#if USE_MACHO_SEGMENT + *bytes = __CFGetSectDataPtr("__UNICODE", bitmapName, NULL); + return *bytes ? true : false; +#else char cpath[MAXPATHLEN]; - __CFUniCharCharacterSetPath(cpath); - strlcat(cpath, bitmapName, MAXPATHLEN); - + strlcat(cpath, bitmapName, MAXPATHLEN); return __CFUniCharLoadBytesFromFile(cpath, bytes); +#endif } -#endif !defined(__MACOS8__) // Bitmap functions CF_INLINE bool isControl(UTF32Char theChar, uint16_t charset, const void *data) { // ISO Control - if ((theChar <= 0x001F) || (theChar >= 0x007F && theChar <= 0x009F)) return true; - return false; + return (((theChar <= 0x001F) || (theChar >= 0x007F && theChar <= 0x009F)) ? true : false); } CF_INLINE bool isWhitespace(UTF32Char theChar, uint16_t charset, const void *data) { // Space - if ((theChar == 0x0020) || (theChar == 0x0009) || (theChar == 0x00A0) || (theChar == 0x1680) || (theChar >= 0x2000 && theChar <= 0x200B) || (theChar == 0x202F) || (theChar == 0x205F) || (theChar == 0x3000)) return true; - return false; + return (((theChar == 0x0020) || (theChar == 0x0009) || (theChar == 0x00A0) || (theChar == 0x1680) || (theChar >= 0x2000 && theChar <= 0x200B) || (theChar == 0x202F) || (theChar == 0x205F) || (theChar == 0x3000)) ? true : false); } -CF_INLINE bool isWhitespaceAndNewLine(UTF32Char theChar, uint16_t charset, const void *data) { // White space - if (isWhitespace(theChar, charset, data) || (theChar >= 0x000A && theChar <= 0x000D) || (theChar == 0x0085) || (theChar == 0x2028) || (theChar == 0x2029)) return true; - return false; +CF_INLINE bool isNewline(UTF32Char theChar, uint16_t charset, const void *data) { // White space + return (((theChar >= 0x000A && theChar <= 0x000D) || (theChar == 0x0085) || (theChar == 0x2028) || (theChar == 0x2029)) ? true : false); } -#if defined(__MACOS8__) -/* This structure MUST match the sets in NSRulebook.h The "__CFCSetIsMemberSet()" function is a modified version of the one in Text shlib. -*/ -typedef struct _CFCharSetPrivateStruct { - int issorted; /* 1=sorted or 0=unsorted ; 2=is_property_table */ - int bitrange[4]; /* bitmap (each bit is a 1k range in space of 2^17) */ - int nsingles; /* number of single elements */ - int nranges; /* number of ranges */ - int singmin; /* minimum single element */ - int singmax; /* maximum single element */ - int array[1]; /* actually bunch of singles followed by ranges */ -} CFCharSetPrivateStruct; - -/* Membership function for complex sets -*/ -CF_INLINE bool __CFCSetIsMemberSet(const CFCharSetPrivateStruct *set, UTF16Char theChar) { - int *tmp, *tmp2; - int i, nel; - int *p, *q, *wari; - - if (set->issorted != 1) { - return false; - } - theChar &= 0x0001FFFF; /* range 1-131k */ - if (__CFCSetBitsInRange(theChar, set->bitrange)) { - if (theChar >= set->singmin && theChar <= set->singmax) { - tmp = (int *) &(set->array[0]); - if ((nel = set->nsingles) < __kCFSetBreakeven) { - for (i = 0; i < nel; i++) { - if (*tmp == theChar) return true; - ++tmp; - } - } - else { // this does a binary search - p = tmp; q = tmp + (nel-1); - while (p <= q) { - wari = (p + ((q-p)>>1)); - if (theChar < *wari) q = wari - 1; - else if (theChar > *wari) p = wari + 1; - else return true; - } - } - } - tmp = (int *) &(set->array[0]) + set->nsingles; - if ((nel = set->nranges) < __kCFSetBreakeven) { - i = nel; - tmp2 = tmp+1; - while (i) { - if (theChar <= *tmp2) { - if (theChar >= *tmp) return true; - } - tmp += 2; - tmp2 = tmp+1; - --i; - } - } else { /* binary search the ranges */ - p = tmp; q = tmp + (2*nel-2); - while (p <= q) { - i = (q - p) >> 1; /* >>1 means divide by 2 */ - wari = p + (i & 0xFFFFFFFE); /* &fffffffe make it an even num */ - if (theChar < *wari) q = wari - 2; - else if (theChar > *(wari + 1)) p = wari + 2; - else return true; - } - } - return false; - /* fall through & return zero */ - } - return false; /* not a member */ -} - -/* Take a private "set" structure and make a bitmap from it. Return the bitmap. THE CALLER MUST RELEASE THE RETURNED MEMORY as necessary. -*/ - -CF_INLINE void __CFCSetBitmapProcessManyCharacters(unsigned char *map, unsigned n, unsigned m) { - unsigned tmp; - for (tmp = n; tmp <= m; tmp++) CFUniCharAddCharacterToBitmap(tmp, map); +CF_INLINE bool isWhitespaceAndNewline(UTF32Char theChar, uint16_t charset, const void *data) { // White space + return ((isWhitespace(theChar, charset, data) || isNewline(theChar, charset, data)) ? true : false); } -CF_INLINE void __CFCSetMakeSetBitmapFromSet(const CFCharSetPrivateStruct *theSet, uint8_t *map) -{ - int *ip; - UTF16Char ctmp; - int cnt; - - for (cnt = 0; cnt < theSet->nsingles; cnt++) { - ctmp = theSet->array[cnt]; - CFUniCharAddCharacterToBitmap(tmp, map); - } - ip = (int *) (&(theSet->array[0]) + theSet->nsingles); - cnt = theSet->nranges; - while (cnt) { - /* This could be more efficient: turn on whole bytes at a time - when there are such cases as 8 characters in a row... */ - __CFCSetBitmapProcessManyCharacters((unsigned char *)map, *ip, *(ip+1)); - ip += 2; - --cnt; - } -} - -extern const CFCharSetPrivateStruct *_CFdecimalDigitCharacterSetData; -extern const CFCharSetPrivateStruct *_CFletterCharacterSetData; -extern const CFCharSetPrivateStruct *_CFlowercaseLetterCharacterSetData; -extern const CFCharSetPrivateStruct *_CFuppercaseLetterCharacterSetData; -extern const CFCharSetPrivateStruct *_CFnonBaseCharacterSetData; -extern const CFCharSetPrivateStruct *_CFdecomposableCharacterSetData; -extern const CFCharSetPrivateStruct *_CFpunctuationCharacterSetData; -extern const CFCharSetPrivateStruct *_CFalphanumericCharacterSetData; -extern const CFCharSetPrivateStruct *_CFillegalCharacterSetData; -extern const CFCharSetPrivateStruct *_CFhasNonSelfLowercaseMappingData; -extern const CFCharSetPrivateStruct *_CFhasNonSelfUppercaseMappingData; -extern const CFCharSetPrivateStruct *_CFhasNonSelfTitlecaseMappingData; - -#else __MACOS8__ typedef struct { uint32_t _numPlanes; const uint8_t **_planes; @@ -256,13 +249,18 @@ static char __CFUniCharUnicodeVersionString[8] = {0, 0, 0, 0, 0, 0, 0, 0}; static uint32_t __CFUniCharNumberOfBitmaps = 0; static __CFUniCharBitmapData *__CFUniCharBitmapDataArray = NULL; -static CFSpinLock_t __CFUniCharBitmapLock = 0; +static CFSpinLock_t __CFUniCharBitmapLock = CFSpinLockInit; -#ifndef CF_UNICHAR_BITMAP_FILE +#if !defined(CF_UNICHAR_BITMAP_FILE) +#if USE_MACHO_SEGMENT +#define CF_UNICHAR_BITMAP_FILE "__csbitmaps" +#else #define CF_UNICHAR_BITMAP_FILE "CFCharacterSetBitmaps.bitmap" -#endif CF_UNICHAR_BITMAP_FILE +#endif +#endif static bool __CFUniCharLoadBitmapData(void) { + __CFUniCharBitmapData *array; uint32_t headerSize; uint32_t bitmapSize; int numPlanes; @@ -287,35 +285,42 @@ static bool __CFUniCharLoadBitmapData(void) { headerSize = CFSwapInt32BigToHost(*((uint32_t *)((char *)bytes + 4))); - bitmapBase = (char *)bytes + headerSize; - (char *)bytes += (sizeof(uint32_t) * 2); + bitmapBase = (uint8_t *)bytes + headerSize; + bytes = (uint8_t *)bytes + (sizeof(uint32_t) * 2); headerSize -= (sizeof(uint32_t) * 2); __CFUniCharNumberOfBitmaps = headerSize / (sizeof(uint32_t) * 2); - __CFUniCharBitmapDataArray = (__CFUniCharBitmapData *)CFAllocatorAllocate(NULL, sizeof(__CFUniCharBitmapData) * __CFUniCharNumberOfBitmaps, 0); + array = (__CFUniCharBitmapData *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFUniCharBitmapData) * __CFUniCharNumberOfBitmaps, 0); for (idx = 0;idx < (int)__CFUniCharNumberOfBitmaps;idx++) { - bitmap = (char *)bitmapBase + CFSwapInt32BigToHost(*(((uint32_t *)bytes)++)); - bitmapSize = CFSwapInt32BigToHost(*(((uint32_t *)bytes)++)); + bitmap = (uint8_t *)bitmapBase + CFSwapInt32BigToHost(*((uint32_t *)bytes)); bytes = (uint8_t *)bytes + sizeof(uint32_t); + bitmapSize = CFSwapInt32BigToHost(*((uint32_t *)bytes)); bytes = (uint8_t *)bytes + sizeof(uint32_t); numPlanes = bitmapSize / (8 * 1024); numPlanes = *(const uint8_t *)((char *)bitmap + (((numPlanes - 1) * ((8 * 1024) + 1)) - 1)) + 1; - __CFUniCharBitmapDataArray[idx]._planes = (const uint8_t **)CFAllocatorAllocate(NULL, sizeof(const void *) * numPlanes, 0); - __CFUniCharBitmapDataArray[idx]._numPlanes = numPlanes; + array[idx]._planes = (const uint8_t **)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(const void *) * numPlanes, 0); + array[idx]._numPlanes = numPlanes; currentPlane = 0; for (bitmapIndex = 0;bitmapIndex < numPlanes;bitmapIndex++) { if (bitmapIndex == currentPlane) { - __CFUniCharBitmapDataArray[idx]._planes[bitmapIndex] = bitmap; - (char *)bitmap += (8 * 1024); - currentPlane = *(((const uint8_t *)bitmap)++); + array[idx]._planes[bitmapIndex] = (const uint8_t *)bitmap; + bitmap = (uint8_t *)bitmap + (8 * 1024); +#if defined (__cplusplus) + currentPlane = *(((const uint8_t*&)bitmap)++); +#else + currentPlane = *((const uint8_t *)bitmap++); +#endif //C++ + } else { - __CFUniCharBitmapDataArray[idx]._planes[bitmapIndex] = NULL; + array[idx]._planes[bitmapIndex] = NULL; } } } + __CFUniCharBitmapDataArray = array; + __CFSpinUnlock(&__CFUniCharBitmapLock); return true; @@ -326,58 +331,26 @@ __private_extern__ const char *__CFUniCharGetUnicodeVersionString(void) { return __CFUniCharUnicodeVersionString; } -#endif __MACOS8__ - -#define CONTROLSET_HAS_FORMATTER 1 - bool CFUniCharIsMemberOf(UTF32Char theChar, uint32_t charset) { -#if CONTROLSET_HAS_FORMATTER - if (charset == kCFUniCharControlCharacterSet) charset = kCFUniCharControlAndFormatterCharacterSet; -#endif CONTROLSET_HAS_FORMATTER + charset = __CFUniCharMapCompatibilitySetID(charset); switch (charset) { - case kCFUniCharControlCharacterSet: - return isControl(theChar, charset, NULL); - case kCFUniCharWhitespaceCharacterSet: return isWhitespace(theChar, charset, NULL); case kCFUniCharWhitespaceAndNewlineCharacterSet: - return isWhitespaceAndNewLine(theChar, charset, NULL); - -#if defined(__MACOS8__) - case kCFUniCharDecimalDigitCharacterSet: -return __CFCSetIsMemberSet((const CFCharSetPrivateStruct *)&_CFdecimalDigitCharacterSetData, theChar); - case kCFUniCharLetterCharacterSet: -return __CFCSetIsMemberSet((const CFCharSetPrivateStruct *)&_CFletterCharacterSetData, theChar); - case kCFUniCharLowercaseLetterCharacterSet: -return __CFCSetIsMemberSet((const CFCharSetPrivateStruct *)&_CFlowercaseLetterCharacterSetData, theChar); - case kCFUniCharUppercaseLetterCharacterSet: -return __CFCSetIsMemberSet((const CFCharSetPrivateStruct *)&_CFuppercaseLetterCharacterSetData, theChar); - case kCFUniCharNonBaseCharacterSet: -return __CFCSetIsMemberSet((const CFCharSetPrivateStruct *)&_CFnonBaseCharacterSetData, theChar); - case kCFUniCharAlphaNumericCharacterSet: -return __CFCSetIsMemberSet((const CFCharSetPrivateStruct *)&_CFalphanumericCharacterSetData, theChar); - case kCFUniCharDecomposableCharacterSet: -return __CFCSetIsMemberSet((const CFCharSetPrivateStruct *)&_CFdecomposableCharacterSetData, theChar); - case kCFUniCharPunctuationCharacterSet: -return __CFCSetIsMemberSet((const CFCharSetPrivateStruct *)&_CFpunctuationCharacterSetData, theChar); - case kCFUniCharIllegalCharacterSet: -return __CFCSetIsMemberSet((const CFCharSetPrivateStruct *)&_CFillegalCharacterSetData, theChar); - case kCFUniCharHasNonSelfLowercaseMapping: -return __CFCSetIsMemberSet((const CFCharSetPrivateStruct *)&_CFhasNonSelfLowercaseMappingData, theChar); - case kCFUniCharHasNonSelfUppercaseMapping: -return __CFCSetIsMemberSet((const CFCharSetPrivateStruct *)&_CFhasNonSelfUppercaseMappingData, theChar); - case kCFUniCharHasNonSelfTitlecaseMapping: -return __CFCSetIsMemberSet((const CFCharSetPrivateStruct *)&_CFhasNonSelfTitlecaseMappingData, theChar); - default: - return false; -#else - default: + return isWhitespaceAndNewline(theChar, charset, NULL); + + case kCFUniCharNewlineCharacterSet: + return isNewline(theChar, charset, NULL); + + default: { + uint32_t tableIndex = __CFUniCharMapExternalSetToInternalIndex(charset); + if (NULL == __CFUniCharBitmapDataArray) __CFUniCharLoadBitmapData(); - if ((charset - kCFUniCharDecimalDigitCharacterSet) < __CFUniCharNumberOfBitmaps) { - __CFUniCharBitmapData *data = __CFUniCharBitmapDataArray + (charset - kCFUniCharDecimalDigitCharacterSet); + if (tableIndex < __CFUniCharNumberOfBitmaps) { + __CFUniCharBitmapData *data = __CFUniCharBitmapDataArray + tableIndex; uint8_t planeNo = (theChar >> 16) & 0xFF; // The bitmap data for kCFUniCharIllegalCharacterSet is actually LEGAL set less Plane 14 ~ 16 @@ -402,21 +375,23 @@ return __CFCSetIsMemberSet((const CFCharSetPrivateStruct *)&_CFhasNonSelfTitleca } } return false; -#endif + } } } const uint8_t *CFUniCharGetBitmapPtrForPlane(uint32_t charset, uint32_t plane) { if (NULL == __CFUniCharBitmapDataArray) __CFUniCharLoadBitmapData(); -#if CONTROLSET_HAS_FORMATTER - if (charset == kCFUniCharControlCharacterSet) charset = kCFUniCharControlAndFormatterCharacterSet; -#endif CONTROLSET_HAS_FORMATTER + charset = __CFUniCharMapCompatibilitySetID(charset); - if (charset > kCFUniCharWhitespaceAndNewlineCharacterSet && (charset - kCFUniCharDecimalDigitCharacterSet) < __CFUniCharNumberOfBitmaps && charset != kCFUniCharIllegalCharacterSet) { - __CFUniCharBitmapData *data = __CFUniCharBitmapDataArray + (charset - kCFUniCharDecimalDigitCharacterSet); + if ((charset > kCFUniCharWhitespaceAndNewlineCharacterSet) && (charset != kCFUniCharIllegalCharacterSet) && (charset != kCFUniCharNewlineCharacterSet)) { + uint32_t tableIndex = __CFUniCharMapExternalSetToInternalIndex(charset); - return (plane < data->_numPlanes ? data->_planes[plane] : NULL); + if (tableIndex < __CFUniCharNumberOfBitmaps) { + __CFUniCharBitmapData *data = __CFUniCharBitmapDataArray + tableIndex; + + return (plane < data->_numPlanes ? data->_planes[plane] : NULL); + } } return NULL; } @@ -427,19 +402,35 @@ __private_extern__ uint8_t CFUniCharGetBitmapForPlane(uint32_t charset, uint32_t if (src) { if (isInverted) { - while (numBytes-- > 0) *(((uint8_t *)bitmap)++) = ~(*(src++)); +#if defined (__cplusplus) + while (numBytes-- > 0) *(((uint8_t *&)bitmap)++) = ~(*(src++)); +#else + while (numBytes-- > 0) *((uint8_t *)bitmap++) = ~(*(src++)); +#endif //C++ } else { - while (numBytes-- > 0) *(((uint8_t *)bitmap)++) = *(src++); +#if defined (__cplusplus) + while (numBytes-- > 0) *(((uint8_t *&)bitmap)++) = *(src++); +#else + while (numBytes-- > 0) *((uint8_t *)bitmap++) = *(src++); +#endif //C++ } return kCFUniCharBitmapFilled; } else if (charset == kCFUniCharIllegalCharacterSet) { - __CFUniCharBitmapData *data = __CFUniCharBitmapDataArray + (charset - kCFUniCharDecimalDigitCharacterSet); + __CFUniCharBitmapData *data = __CFUniCharBitmapDataArray + __CFUniCharMapExternalSetToInternalIndex(__CFUniCharMapCompatibilitySetID(charset)); if (plane < data->_numPlanes && (src = data->_planes[plane])) { if (isInverted) { - while (numBytes-- > 0) *(((uint8_t *)bitmap)++) = *(src++); +#if defined (__cplusplus) + while (numBytes-- > 0) *(((uint8_t *&)bitmap)++) = *(src++); +#else + while (numBytes-- > 0) *((uint8_t *)bitmap++) = *(src++); +#endif //C++ } else { - while (numBytes-- > 0) *(((uint8_t *)bitmap)++) = ~(*(src++)); +#if defined (__cplusplus) + while (numBytes-- > 0) *(((uint8_t *&)bitmap)++) = ~(*(src++)); +#else + while (numBytes-- > 0) *((uint8_t *)bitmap++) = ~(*(src++)); +#endif //C++ } return kCFUniCharBitmapFilled; } else if (plane == 0x0E) { // Plane 14 @@ -447,94 +438,85 @@ __private_extern__ uint8_t CFUniCharGetBitmapForPlane(uint32_t charset, uint32_t uint8_t asciiRange = (isInverted ? (uint8_t)0xFF : (uint8_t)0); uint8_t otherRange = (isInverted ? (uint8_t)0 : (uint8_t)0xFF); - *(((uint8_t *)bitmap)++) = 0x02; // UE0001 LANGUAGE TAG +#if defined (__cplusplus) + *(((uint8_t *&)bitmap)++) = 0x02; // UE0001 LANGUAGE TAG +#else + *((uint8_t *)bitmap++) = 0x02; // UE0001 LANGUAGE TAG +#endif //C++ for (idx = 1;idx < numBytes;idx++) { - *(((uint8_t *)bitmap)++) = ((idx >= (0x20 / 8) && (idx < (0x80 / 8))) ? asciiRange : otherRange); +#if defined (__cplusplus) + *(((uint8_t *&)bitmap)++) = ((idx >= (0x20 / 8) && (idx < (0x80 / 8))) ? asciiRange : otherRange); +#else + *((uint8_t *)bitmap++) = ((idx >= (0x20 / 8) && (idx < (0x80 / 8))) ? asciiRange : otherRange); +#endif //C++ } return kCFUniCharBitmapFilled; } else if (plane == 0x0F || plane == 0x10) { // Plane 15 & 16 - uint32_t value = (isInverted ? 0xFFFFFFFF : 0); + uint32_t value = (isInverted ? ~0 : 0); numBytes /= 4; // for 32bit - while (numBytes-- > 0) *(((uint32_t *)bitmap)++) = value; + while (numBytes-- > 0) { + *((uint32_t *)bitmap) = value; +#if defined (__cplusplus) + bitmap = (uint8_t *)bitmap + sizeof(uint32_t); +#else + bitmap += sizeof(uint32_t); +#endif //C++ + } *(((uint8_t *)bitmap) - 5) = (isInverted ? 0x3F : 0xC0); // 0xFFFE & 0xFFFF return kCFUniCharBitmapFilled; } return (isInverted ? kCFUniCharBitmapEmpty : kCFUniCharBitmapAll); -#if CONTROLSET_HAS_FORMATTER - } else if ((charset == kCFUniCharControlCharacterSet) && (plane == 0x0E)) { // Language tags - int idx; - uint8_t asciiRange = (isInverted ? (uint8_t)0 : (uint8_t)0xFF); - uint8_t otherRange = (isInverted ? (uint8_t)0xFF : (uint8_t)0); - - *(((uint8_t *)bitmap)++) = 0x02; // UE0001 LANGUAGE TAG - for (idx = 1;idx < numBytes;idx++) { - *(((uint8_t *)bitmap)++) = ((idx >= (0x20 / 8) && (idx < (0x80 / 8))) ? asciiRange : otherRange); - } - return kCFUniCharBitmapFilled; -#endif CONTROLSET_HAS_FORMATTER - } else if (charset < kCFUniCharDecimalDigitCharacterSet) { + } else if ((charset < kCFUniCharDecimalDigitCharacterSet) || (charset == kCFUniCharNewlineCharacterSet)) { if (plane) return (isInverted ? kCFUniCharBitmapAll : kCFUniCharBitmapEmpty); - if (charset == kCFUniCharControlCharacterSet) { - int idx; - uint8_t nonFillValue = (isInverted ? (uint8_t)0xFF : (uint8_t)0); - uint8_t fillValue = (isInverted ? (uint8_t)0 : (uint8_t)0xFF); - uint8_t *bitmapP = (uint8_t *)bitmap; + uint8_t *bitmapBase = (uint8_t *)bitmap; + CFIndex idx; + uint8_t nonFillValue = (isInverted ? (uint8_t)0xFF : (uint8_t)0); - for (idx = 0;idx < numBytes;idx++) { - *(bitmapP++) = (idx < (0x20 / 8) || (idx >= (0x80 / 8) && idx < (0xA0 / 8)) ? fillValue : nonFillValue); - } - - // DEL - if (isInverted) { - CFUniCharRemoveCharacterFromBitmap(0x007F, bitmap); - } else { - CFUniCharAddCharacterToBitmap(0x007F, bitmap); - } - } else { - uint8_t *bitmapBase = (uint8_t *)bitmap; - int idx; - uint8_t nonFillValue = (isInverted ? (uint8_t)0xFF : (uint8_t)0); - - while (numBytes-- > 0) *(((uint8_t *)bitmap)++) = nonFillValue; +#if defined (__cplusplus) + while (numBytes-- > 0) *(((uint8_t *&)bitmap)++) = nonFillValue; +#else + while (numBytes-- > 0) *((uint8_t *)bitmap++) = nonFillValue; +#endif //C++ - if (charset == kCFUniCharWhitespaceAndNewlineCharacterSet) { - static const UniChar newlines[] = {0x000A, 0x000B, 0x000C, 0x000D, 0x0085, 0x2028, 0x2029}; + if ((charset == kCFUniCharWhitespaceAndNewlineCharacterSet) || (charset == kCFUniCharNewlineCharacterSet)) { + const UniChar newlines[] = {0x000A, 0x000B, 0x000C, 0x000D, 0x0085, 0x2028, 0x2029}; - for (idx = 0;idx < (int)(sizeof(newlines) / sizeof(*newlines)); idx++) { - if (isInverted) { - CFUniCharRemoveCharacterFromBitmap(newlines[idx], bitmapBase); - } else { - CFUniCharAddCharacterToBitmap(newlines[idx], bitmapBase); - } + for (idx = 0;idx < (int)(sizeof(newlines) / sizeof(*newlines)); idx++) { + if (isInverted) { + CFUniCharRemoveCharacterFromBitmap(newlines[idx], bitmapBase); + } else { + CFUniCharAddCharacterToBitmap(newlines[idx], bitmapBase); } } + if (charset == kCFUniCharNewlineCharacterSet) return kCFUniCharBitmapFilled; + } + + if (isInverted) { + CFUniCharRemoveCharacterFromBitmap(0x0009, bitmapBase); + CFUniCharRemoveCharacterFromBitmap(0x0020, bitmapBase); + CFUniCharRemoveCharacterFromBitmap(0x00A0, bitmapBase); + CFUniCharRemoveCharacterFromBitmap(0x1680, bitmapBase); + CFUniCharRemoveCharacterFromBitmap(0x202F, bitmapBase); + CFUniCharRemoveCharacterFromBitmap(0x205F, bitmapBase); + CFUniCharRemoveCharacterFromBitmap(0x3000, bitmapBase); + } else { + CFUniCharAddCharacterToBitmap(0x0009, bitmapBase); + CFUniCharAddCharacterToBitmap(0x0020, bitmapBase); + CFUniCharAddCharacterToBitmap(0x00A0, bitmapBase); + CFUniCharAddCharacterToBitmap(0x1680, bitmapBase); + CFUniCharAddCharacterToBitmap(0x202F, bitmapBase); + CFUniCharAddCharacterToBitmap(0x205F, bitmapBase); + CFUniCharAddCharacterToBitmap(0x3000, bitmapBase); + } + + for (idx = 0x2000;idx <= 0x200B;idx++) { if (isInverted) { - CFUniCharRemoveCharacterFromBitmap(0x0009, bitmapBase); - CFUniCharRemoveCharacterFromBitmap(0x0020, bitmapBase); - CFUniCharRemoveCharacterFromBitmap(0x00A0, bitmapBase); - CFUniCharRemoveCharacterFromBitmap(0x1680, bitmapBase); - CFUniCharRemoveCharacterFromBitmap(0x202F, bitmapBase); - CFUniCharRemoveCharacterFromBitmap(0x205F, bitmapBase); - CFUniCharRemoveCharacterFromBitmap(0x3000, bitmapBase); + CFUniCharRemoveCharacterFromBitmap(idx, bitmapBase); } else { - CFUniCharAddCharacterToBitmap(0x0009, bitmapBase); - CFUniCharAddCharacterToBitmap(0x0020, bitmapBase); - CFUniCharAddCharacterToBitmap(0x00A0, bitmapBase); - CFUniCharAddCharacterToBitmap(0x1680, bitmapBase); - CFUniCharAddCharacterToBitmap(0x202F, bitmapBase); - CFUniCharAddCharacterToBitmap(0x205F, bitmapBase); - CFUniCharAddCharacterToBitmap(0x3000, bitmapBase); - } - - for (idx = 0x2000;idx <= 0x200B;idx++) { - if (isInverted) { - CFUniCharRemoveCharacterFromBitmap(idx, bitmapBase); - } else { - CFUniCharAddCharacterToBitmap(idx, bitmapBase); - } + CFUniCharAddCharacterToBitmap(idx, bitmapBase); } } return kCFUniCharBitmapFilled; @@ -543,14 +525,9 @@ __private_extern__ uint8_t CFUniCharGetBitmapForPlane(uint32_t charset, uint32_t } __private_extern__ uint32_t CFUniCharGetNumberOfPlanes(uint32_t charset) { -#if defined(__MACOS8__) - return 1; -#else __MACOS8__ -#if CONTROLSET_HAS_FORMATTER - if (charset == kCFUniCharControlCharacterSet) return 15; // 0 to 14 -#endif CONTROLSET_HAS_FORMATTER - - if (charset < kCFUniCharDecimalDigitCharacterSet) { + if ((charset == kCFUniCharControlCharacterSet) || (charset == kCFUniCharControlAndFormatterCharacterSet)) { + return 15; // 0 to 14 + } else if (charset < kCFUniCharDecimalDigitCharacterSet) { return 1; } else if (charset == kCFUniCharIllegalCharacterSet) { return 17; @@ -559,23 +536,30 @@ __private_extern__ uint32_t CFUniCharGetNumberOfPlanes(uint32_t charset) { if (NULL == __CFUniCharBitmapDataArray) __CFUniCharLoadBitmapData(); - numPlanes = __CFUniCharBitmapDataArray[charset - kCFUniCharDecimalDigitCharacterSet]._numPlanes; + numPlanes = __CFUniCharBitmapDataArray[__CFUniCharMapExternalSetToInternalIndex(__CFUniCharMapCompatibilitySetID(charset))]._numPlanes; return numPlanes; } -#endif __MACOS8__ } // Mapping data loading static const void **__CFUniCharMappingTables = NULL; -static CFSpinLock_t __CFUniCharMappingTableLock = 0; +static CFSpinLock_t __CFUniCharMappingTableLock = CFSpinLockInit; -#if defined(__BIG_ENDIAN__) +#if __CF_BIG_ENDIAN__ +#if USE_MACHO_SEGMENT +#define MAPPING_TABLE_FILE "__data" +#else #define MAPPING_TABLE_FILE "CFUnicodeData-B.mapping" -#else __BIG_ENDIAN__ +#endif +#else +#if USE_MACHO_SEGMENT +#define MAPPING_TABLE_FILE "__data" +#else #define MAPPING_TABLE_FILE "CFUnicodeData-L.mapping" -#endif __BIG_ENDIAN__ +#endif +#endif __private_extern__ const void *CFUniCharGetMappingData(uint32_t type) { @@ -592,17 +576,26 @@ __private_extern__ const void *CFUniCharGetMappingData(uint32_t type) { return NULL; } - (char *)bytes += 4; // Skip Unicode version - headerSize = *(((uint32_t *)bytes)++); +#if defined (__cplusplus) + bytes = (uint8_t *)bytes + 4; // Skip Unicode version + headerSize = *((uint8_t *)bytes); bytes = (uint8_t *)bytes + sizeof(uint32_t); +#else + bytes += 4; // Skip Unicode version + headerSize = *((uint32_t *)bytes); bytes += sizeof(uint32_t); +#endif //C++ headerSize -= (sizeof(uint32_t) * 2); bodyBase = (char *)bytes + headerSize; count = headerSize / sizeof(uint32_t); - __CFUniCharMappingTables = (const void **)CFAllocatorAllocate(NULL, sizeof(const void *) * count, 0); + __CFUniCharMappingTables = (const void **)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(const void *) * count, 0); for (idx = 0;idx < count;idx++) { - __CFUniCharMappingTables[idx] = (char *)bodyBase + *(((uint32_t *)bytes)++); +#if defined (__cplusplus) + __CFUniCharMappingTables[idx] = (char *)bodyBase + *((uint32_t *)bytes); bytes = (uint8_t *)bytes + sizeof(uint32_t); +#else + __CFUniCharMappingTables[idx] = (char *)bodyBase + *((uint32_t *)bytes); bytes += sizeof(uint32_t); +#endif //C++ } } @@ -644,6 +637,7 @@ static uint32_t __CFUniCharGetMappedCase(const __CFUniCharCaseMappings *theTable #define NUM_CASE_MAP_DATA (kCFUniCharCaseFold + 1) static bool __CFUniCharLoadCaseMappingTable(void) { + uint32_t *countArray; int idx; if (NULL == __CFUniCharMappingTables) (void)CFUniCharGetMappingData(kCFUniCharToLowercase); @@ -656,31 +650,33 @@ static bool __CFUniCharLoadCaseMappingTable(void) { return true; } - __CFUniCharCaseMappingTableCounts = (uint32_t *)CFAllocatorAllocate(NULL, sizeof(uint32_t) * NUM_CASE_MAP_DATA + sizeof(uint32_t *) * NUM_CASE_MAP_DATA * 2, 0); - __CFUniCharCaseMappingTable = (uint32_t **)((char *)__CFUniCharCaseMappingTableCounts + sizeof(uint32_t) * NUM_CASE_MAP_DATA); + countArray = (uint32_t *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(uint32_t) * NUM_CASE_MAP_DATA + sizeof(uint32_t *) * NUM_CASE_MAP_DATA * 2, 0); + __CFUniCharCaseMappingTable = (uint32_t **)((char *)countArray + sizeof(uint32_t) * NUM_CASE_MAP_DATA); __CFUniCharCaseMappingExtraTable = (const uint32_t **)__CFUniCharCaseMappingTable + NUM_CASE_MAP_DATA; for (idx = 0;idx < NUM_CASE_MAP_DATA;idx++) { - __CFUniCharCaseMappingTableCounts[idx] = *((uint32_t *)__CFUniCharMappingTables[idx]) / (sizeof(uint32_t) * 2); + countArray[idx] = *((uint32_t *)__CFUniCharMappingTables[idx]) / (sizeof(uint32_t) * 2); __CFUniCharCaseMappingTable[idx] = ((uint32_t *)__CFUniCharMappingTables[idx]) + 1; __CFUniCharCaseMappingExtraTable[idx] = (const uint32_t *)((char *)__CFUniCharCaseMappingTable[idx] + *((uint32_t *)__CFUniCharMappingTables[idx])); } + __CFUniCharCaseMappingTableCounts = countArray; + __CFSpinUnlock(&__CFUniCharMappingTableLock); return true; } -#if __BIG_ENDIAN__ +#if __CF_BIG_ENDIAN__ #define TURKISH_LANG_CODE (0x7472) // tr #define LITHUANIAN_LANG_CODE (0x6C74) // lt #define AZERI_LANG_CODE (0x617A) // az -#else __BIG_ENDIAN__ +#else #define TURKISH_LANG_CODE (0x7274) // tr #define LITHUANIAN_LANG_CODE (0x746C) // lt #define AZERI_LANG_CODE (0x7A61) // az -#endif __BIG_ENDIAN__ +#endif -uint32_t CFUniCharMapCaseTo(UTF32Char theChar, UTF16Char *convertedChar, uint32_t maxLength, uint32_t ctype, uint32_t flags, const uint8_t *langCode) { +CFIndex CFUniCharMapCaseTo(UTF32Char theChar, UTF16Char *convertedChar, CFIndex maxLength, uint32_t ctype, uint32_t flags, const uint8_t *langCode) { __CFUniCharBitmapData *data; uint8_t planeNo = (theChar >> 16) & 0xFF; @@ -769,7 +765,7 @@ caseFoldRetry: if (NULL == __CFUniCharBitmapDataArray) __CFUniCharLoadBitmapData(); - data = __CFUniCharBitmapDataArray + ((ctype + kCFUniCharHasNonSelfLowercaseCharacterSet) - kCFUniCharDecimalDigitCharacterSet); + data = __CFUniCharBitmapDataArray + __CFUniCharMapExternalSetToInternalIndex(__CFUniCharMapCompatibilitySetID(ctype + kCFUniCharHasNonSelfLowercaseCharacterSet)); if (planeNo < data->_numPlanes && data->_planes[planeNo] && CFUniCharIsMemberOfBitmap(theChar, data->_planes[planeNo]) && (__CFUniCharCaseMappingTableCounts || __CFUniCharLoadCaseMappingTable())) { uint32_t value = __CFUniCharGetMappedCase((const __CFUniCharCaseMappings *)__CFUniCharCaseMappingTable[ctype], __CFUniCharCaseMappingTableCounts[ctype], theChar); @@ -780,41 +776,41 @@ caseFoldRetry: } if (value) { - int count = CFUniCharConvertFlagToCount(value); + CFIndex count = CFUniCharConvertFlagToCount(value); if (count == 1) { if (value & kCFUniCharNonBmpFlag) { if (maxLength > 1) { value = (value & 0xFFFFFF) - 0x10000; - *(convertedChar++) = (value >> 10) + 0xD800UL; - *(convertedChar++) = (value & 0x3FF) + 0xDC00UL; + *(convertedChar++) = (UTF16Char)(value >> 10) + 0xD800UL; + *(convertedChar++) = (UTF16Char)(value & 0x3FF) + 0xDC00UL; return 2; } } else { *convertedChar = (UTF16Char)value; return 1; } - } else if (count < (int)maxLength) { + } else if (count < maxLength) { const uint32_t *extraMapping = __CFUniCharCaseMappingExtraTable[ctype] + (value & 0xFFFFFF); if (value & kCFUniCharNonBmpFlag) { - int copiedLen = 0; + CFIndex copiedLen = 0; while (count-- > 0) { value = *(extraMapping++); if (value > 0xFFFF) { - if (copiedLen + 2 >= (int)maxLength) break; + if (copiedLen + 2 >= maxLength) break; value = (value & 0xFFFFFF) - 0x10000; - convertedChar[copiedLen++] = (value >> 10) + 0xD800UL; - convertedChar[copiedLen++] = (value & 0x3FF) + 0xDC00UL; + convertedChar[copiedLen++] = (UTF16Char)(value >> 10) + 0xD800UL; + convertedChar[copiedLen++] = (UTF16Char)(value & 0x3FF) + 0xDC00UL; } else { - if (copiedLen + 1 >= (int)maxLength) break; + if (copiedLen + 1 >= maxLength) break; convertedChar[copiedLen++] = value; } } if (!count) return copiedLen; } else { - int idx; + CFIndex idx; for (idx = 0;idx < count;idx++) *(convertedChar++) = (UTF16Char)*(extraMapping++); return count; @@ -828,8 +824,8 @@ caseFoldRetry: if (theChar > 0xFFFF) { // non-BMP theChar = (theChar & 0xFFFFFF) - 0x10000; - *(convertedChar++) = (theChar >> 10) + 0xD800UL; - *(convertedChar++) = (theChar & 0x3FF) + 0xDC00UL; + *(convertedChar++) = (UTF16Char)(theChar >> 10) + 0xD800UL; + *(convertedChar++) = (UTF16Char)(theChar & 0x3FF) + 0xDC00UL; return 2; } else { *convertedChar = theChar; @@ -837,7 +833,7 @@ caseFoldRetry: } } -UInt32 CFUniCharMapTo(UniChar theChar, UniChar *convertedChar, UInt32 maxLength, uint16_t ctype, UInt32 flags) { +CFIndex CFUniCharMapTo(UniChar theChar, UniChar *convertedChar, CFIndex maxLength, uint16_t ctype, uint32_t flags) { if (ctype == kCFUniCharCaseFold + 1) { // kCFUniCharDecompose if (CFUniCharIsDecomposableCharacter(theChar, false)) { UTF32Char buffer[MAX_DECOMPOSED_LENGTH]; @@ -855,7 +851,7 @@ UInt32 CFUniCharMapTo(UniChar theChar, UniChar *convertedChar, UInt32 maxLength, } } -CF_INLINE bool __CFUniCharIsMoreAbove(UTF16Char *buffer, uint32_t length) { +CF_INLINE bool __CFUniCharIsMoreAbove(UTF16Char *buffer, CFIndex length) { UTF32Char currentChar; uint32_t property; @@ -867,19 +863,19 @@ CF_INLINE bool __CFUniCharIsMoreAbove(UTF16Char *buffer, uint32_t length) { } if (!CFUniCharIsMemberOf(currentChar, kCFUniCharNonBaseCharacterSet)) break; - property = CFUniCharGetCombiningPropertyForCharacter(currentChar, CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, (currentChar >> 16) & 0xFF)); + property = CFUniCharGetCombiningPropertyForCharacter(currentChar, (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, (currentChar >> 16) & 0xFF)); if (property == 230) return true; // Above priority } return false; } -CF_INLINE bool __CFUniCharIsAfter_i(UTF16Char *buffer, uint32_t length) { +CF_INLINE bool __CFUniCharIsAfter_i(UTF16Char *buffer, CFIndex length) { UTF32Char currentChar = 0; uint32_t property; UTF32Char decomposed[MAX_DECOMPOSED_LENGTH]; - uint32_t decompLength; - uint32_t idx; + CFIndex decompLength; + CFIndex idx; if (length < 1) return 0; @@ -896,7 +892,7 @@ CF_INLINE bool __CFUniCharIsAfter_i(UTF16Char *buffer, uint32_t length) { } if (!CFUniCharIsMemberOf(currentChar, kCFUniCharNonBaseCharacterSet)) break; - property = CFUniCharGetCombiningPropertyForCharacter(currentChar, CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, (currentChar >> 16) & 0xFF)); + property = CFUniCharGetCombiningPropertyForCharacter(currentChar, (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, (currentChar >> 16) & 0xFF)); if (property == 230) return false; // Above priority } @@ -912,14 +908,14 @@ CF_INLINE bool __CFUniCharIsAfter_i(UTF16Char *buffer, uint32_t length) { for (idx = 1;idx < decompLength;idx++) { currentChar = decomposed[idx]; - property = CFUniCharGetCombiningPropertyForCharacter(currentChar, CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, (currentChar >> 16) & 0xFF)); + property = CFUniCharGetCombiningPropertyForCharacter(currentChar, (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, (currentChar >> 16) & 0xFF)); if (property == 230) return false; // Above priority } return true; } -__private_extern__ uint32_t CFUniCharGetConditionalCaseMappingFlags(UTF32Char theChar, UTF16Char *buffer, uint32_t currentIndex, uint32_t length, uint32_t type, const uint8_t *langCode, uint32_t lastFlags) { +__private_extern__ uint32_t CFUniCharGetConditionalCaseMappingFlags(UTF32Char theChar, UTF16Char *buffer, CFIndex currentIndex, CFIndex length, uint32_t type, const uint8_t *langCode, uint32_t lastFlags) { if (theChar == 0x03A3) { // GREEK CAPITAL LETTER SIGMA if ((type == kCFUniCharToLowercase) && (currentIndex > 0)) { UTF16Char *start = buffer; @@ -981,15 +977,20 @@ __private_extern__ uint32_t CFUniCharGetConditionalCaseMappingFlags(UTF32Char th static __CFUniCharBitmapData *__CFUniCharUnicodePropertyTable = NULL; static int __CFUniCharUnicodePropertyTableCount = 0; -static CFSpinLock_t __CFUniCharPropTableLock = 0; +static CFSpinLock_t __CFUniCharPropTableLock = CFSpinLockInit; +#if USE_MACHO_SEGMENT +#define PROP_DB_FILE "__properties" +#else #define PROP_DB_FILE "CFUniCharPropertyDatabase.data" +#endif const void *CFUniCharGetUnicodePropertyDataForPlane(uint32_t propertyType, uint32_t plane) { __CFSpinLock(&__CFUniCharPropTableLock); if (NULL == __CFUniCharUnicodePropertyTable) { + __CFUniCharBitmapData *table; const void *bytes; const void *bodyBase; const void *planeBase; @@ -1003,33 +1004,50 @@ const void *CFUniCharGetUnicodePropertyDataForPlane(uint32_t propertyType, uint3 return NULL; } - (char *)bytes += 4; // Skip Unicode version - headerSize = CFSwapInt32BigToHost(*(((uint32_t *)bytes)++)); +#if defined (__cplusplus) + bytes = (uint8_t*)bytes + 4; // Skip Unicode version + headerSize = CFSwapInt32BigToHost(*((uint32_t *)bytes)); bytes = (uint8_t *)bytes + sizeof(uint32_t); +#else + bytes += 4; // Skip Unicode version + headerSize = CFSwapInt32BigToHost(*((uint32_t *)bytes)); bytes += sizeof(uint32_t); +#endif //C++ + headerSize -= (sizeof(uint32_t) * 2); bodyBase = (char *)bytes + headerSize; count = headerSize / sizeof(uint32_t); __CFUniCharUnicodePropertyTableCount = count; - __CFUniCharUnicodePropertyTable = (__CFUniCharBitmapData *)CFAllocatorAllocate(NULL, sizeof(__CFUniCharBitmapData) * count, 0); + table = (__CFUniCharBitmapData *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFUniCharBitmapData) * count, 0); for (idx = 0;idx < count;idx++) { planeCount = *((const uint8_t *)bodyBase); - (char *)planeBase = (char *)bodyBase + planeCount + (planeCount % 4 ? 4 - (planeCount % 4) : 0); - __CFUniCharUnicodePropertyTable[idx]._planes = (const uint8_t **)CFAllocatorAllocate(NULL, sizeof(const void *) * planeCount, 0); + planeBase = (char *)bodyBase + planeCount + (planeCount % 4 ? 4 - (planeCount % 4) : 0); + table[idx]._planes = (const uint8_t **)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(const void *) * planeCount, 0); for (planeIndex = 0;planeIndex < planeCount;planeIndex++) { if ((planeSize = ((const uint8_t *)bodyBase)[planeIndex + 1])) { - __CFUniCharUnicodePropertyTable[idx]._planes[planeIndex] = planeBase; - (char *)planeBase += (planeSize * 256); + table[idx]._planes[planeIndex] = (const uint8_t *)planeBase; +#if defined (__cplusplus) + planeBase = (char*)planeBase + (planeSize * 256); +#else + planeBase += (planeSize * 256); +#endif //C++ } else { - __CFUniCharUnicodePropertyTable[idx]._planes[planeIndex] = NULL; + table[idx]._planes[planeIndex] = NULL; } } - __CFUniCharUnicodePropertyTable[idx]._numPlanes = planeCount; - (char *)bodyBase += (CFSwapInt32BigToHost(*(((uint32_t *)bytes)++))); + table[idx]._numPlanes = planeCount; +#if defined (__cplusplus) + bodyBase = (const uint8_t *)bodyBase + (CFSwapInt32BigToHost(*(uint32_t *)bytes)); + ((uint32_t *&)bytes) ++; +#else + bodyBase += (CFSwapInt32BigToHost(*((uint32_t *)bytes++))); +#endif //C++ } + + __CFUniCharUnicodePropertyTable = table; } __CFSpinUnlock(&__CFUniCharPropTableLock); @@ -1044,9 +1062,9 @@ __private_extern__ uint32_t CFUniCharGetNumberOfPlanesForUnicodePropertyData(uin __private_extern__ uint32_t CFUniCharGetUnicodeProperty(UTF32Char character, uint32_t propertyType) { if (propertyType == kCFUniCharCombiningProperty) { - return CFUniCharGetCombiningPropertyForCharacter(character, CFUniCharGetUnicodePropertyDataForPlane(propertyType, (character >> 16) & 0xFF)); + return CFUniCharGetCombiningPropertyForCharacter(character, (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(propertyType, (character >> 16) & 0xFF)); } else if (propertyType == kCFUniCharBidiProperty) { - return CFUniCharGetBidiPropertyForCharacter(character, CFUniCharGetUnicodePropertyDataForPlane(propertyType, (character >> 16) & 0xFF)); + return CFUniCharGetBidiPropertyForCharacter(character, (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(propertyType, (character >> 16) & 0xFF)); } else { return 0; } @@ -1080,9 +1098,9 @@ __private_extern__ uint32_t CFUniCharGetUnicodeProperty(UTF32Char character, uin */ #define UNI_REPLACEMENT_CHAR (0x0000FFFDUL) -bool CFUniCharFillDestinationBuffer(const UTF32Char *src, uint32_t srcLength, void **dst, uint32_t dstLength, uint32_t *filledLength, uint32_t dstFormat) { +bool CFUniCharFillDestinationBuffer(const UTF32Char *src, CFIndex srcLength, void **dst, CFIndex dstLength, CFIndex *filledLength, uint32_t dstFormat) { UTF32Char currentChar; - uint32_t usedLength = *filledLength; + CFIndex usedLength = *filledLength; if (dstFormat == kCFUniCharUTF16Format) { UTF16Char *dstBuffer = (UTF16Char *)*dst; @@ -1170,7 +1188,7 @@ bool CFUniCharFillDestinationBuffer(const UTF32Char *src, uint32_t srcLength, vo return true; } -#if defined(__WIN32__) +#if 0 || 0 void __CFUniCharCleanup(void) { int idx; @@ -1179,12 +1197,12 @@ void __CFUniCharCleanup(void) __CFSpinLock(&__CFUniCharBitmapLock); if (__CFUniCharBitmapDataArray != NULL) { - for (idx = 0; idx < __CFUniCharNumberOfBitmaps; idx++) { - CFAllocatorDeallocate(NULL, __CFUniCharBitmapDataArray[idx]._planes); + for (idx = 0; idx < (int)__CFUniCharNumberOfBitmaps; idx++) { + CFAllocatorDeallocate(kCFAllocatorSystemDefault, __CFUniCharBitmapDataArray[idx]._planes); __CFUniCharBitmapDataArray[idx]._planes = NULL; } - CFAllocatorDeallocate(NULL, __CFUniCharBitmapDataArray); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, __CFUniCharBitmapDataArray); __CFUniCharBitmapDataArray = NULL; __CFUniCharNumberOfBitmaps = 0; } @@ -1195,13 +1213,13 @@ void __CFUniCharCleanup(void) __CFSpinLock(&__CFUniCharMappingTableLock); if (__CFUniCharMappingTables != NULL) { - CFAllocatorDeallocate(NULL, __CFUniCharMappingTables); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, __CFUniCharMappingTables); __CFUniCharMappingTables = NULL; } // cleanup memory allocated by __CFUniCharLoadCaseMappingTable() if (__CFUniCharCaseMappingTableCounts != NULL) { - CFAllocatorDeallocate(NULL, __CFUniCharCaseMappingTableCounts); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, __CFUniCharCaseMappingTableCounts); __CFUniCharCaseMappingTableCounts = NULL; __CFUniCharCaseMappingTable = NULL; @@ -1215,11 +1233,11 @@ void __CFUniCharCleanup(void) if (__CFUniCharUnicodePropertyTable != NULL) { for (idx = 0; idx < __CFUniCharUnicodePropertyTableCount; idx++) { - CFAllocatorDeallocate(NULL, __CFUniCharUnicodePropertyTable[idx]._planes); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, __CFUniCharUnicodePropertyTable[idx]._planes); __CFUniCharUnicodePropertyTable[idx]._planes = NULL; } - CFAllocatorDeallocate(NULL, __CFUniCharUnicodePropertyTable); + CFAllocatorDeallocate(kCFAllocatorSystemDefault, __CFUniCharUnicodePropertyTable); __CFUniCharUnicodePropertyTable = NULL; __CFUniCharUnicodePropertyTableCount = 0; } @@ -1228,3 +1246,5 @@ void __CFUniCharCleanup(void) } #endif // __WIN32__ +#undef USE_MACHO_SEGMENT + diff --git a/StringEncodings.subproj/CFUniChar.h b/CFUniChar.h similarity index 91% rename from StringEncodings.subproj/CFUniChar.h rename to CFUniChar.h index 87cedfd..b9b8c39 100644 --- a/StringEncodings.subproj/CFUniChar.h +++ b/CFUniChar.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFUniChar.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFUNICHAR__) @@ -31,18 +31,16 @@ #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN #define kCFUniCharBitShiftForByte (3) #define kCFUniCharBitShiftForMask (7) -CF_INLINE Boolean CFUniCharIsSurrogateHighCharacter(UniChar character) { +CF_INLINE bool CFUniCharIsSurrogateHighCharacter(UniChar character) { return ((character >= 0xD800UL) && (character <= 0xDBFFUL) ? true : false); } -CF_INLINE Boolean CFUniCharIsSurrogateLowCharacter(UniChar character) { +CF_INLINE bool CFUniCharIsSurrogateLowCharacter(UniChar character) { return ((character >= 0xDC00UL) && (character <= 0xDFFFUL) ? true : false); } @@ -85,7 +83,9 @@ enum { kCFUniCharIllegalCharacterSet, kCFUniCharTitlecaseLetterCharacterSet, kCFUniCharSymbolAndOperatorCharacterSet, - kCFUniCharCompatibilityDecomposableCharacterSet, + kCFUniCharNewlineCharacterSet, + + kCFUniCharCompatibilityDecomposableCharacterSet = 100, // internal character sets begins here kCFUniCharHFSPlusDecomposableCharacterSet, kCFUniCharStrongRightToLeftCharacterSet, kCFUniCharHasNonSelfLowercaseCharacterSet, @@ -94,7 +94,8 @@ enum { kCFUniCharHasNonSelfCaseFoldingCharacterSet, kCFUniCharHasNonSelfMirrorMappingCharacterSet, kCFUniCharControlAndFormatterCharacterSet, - kCFUniCharCaseIgnorableCharacterSet + kCFUniCharCaseIgnorableCharacterSet, + kCFUniCharGraphemeExtendCharacterSet }; CF_EXPORT bool CFUniCharIsMemberOf(UTF32Char theChar, uint32_t charset); @@ -125,9 +126,9 @@ enum { kCFUniCharCaseMapMoreAbove = (1 << 2) }; -CF_EXPORT uint32_t CFUniCharMapCaseTo(UTF32Char theChar, UTF16Char *convertedChar, uint32_t maxLength, uint32_t ctype, uint32_t flags, const uint8_t *langCode); +CF_EXPORT CFIndex CFUniCharMapCaseTo(UTF32Char theChar, UTF16Char *convertedChar, CFIndex maxLength, uint32_t ctype, uint32_t flags, const uint8_t *langCode); -CF_EXPORT uint32_t CFUniCharGetConditionalCaseMappingFlags(UTF32Char theChar, UTF16Char *buffer, uint32_t currentIndex, uint32_t length, uint32_t type, const uint8_t *langCode, uint32_t lastFlags); +CF_EXPORT uint32_t CFUniCharGetConditionalCaseMappingFlags(UTF32Char theChar, UTF16Char *buffer, CFIndex currentIndex, CFIndex length, uint32_t type, const uint8_t *langCode, uint32_t lastFlags); enum { kCFUniCharBiDiPropertyON = 0, @@ -187,7 +188,7 @@ CF_EXPORT const void *CFUniCharGetUnicodePropertyDataForPlane(uint32_t propertyT CF_EXPORT uint32_t CFUniCharGetNumberOfPlanesForUnicodePropertyData(uint32_t propertyType); CF_EXPORT uint32_t CFUniCharGetUnicodeProperty(UTF32Char character, uint32_t propertyType); -CF_EXPORT bool CFUniCharFillDestinationBuffer(const UTF32Char *src, uint32_t srcLength, void **dst, uint32_t dstLength, uint32_t *filledLength, uint32_t dstFormat); +CF_EXPORT bool CFUniCharFillDestinationBuffer(const UTF32Char *src, CFIndex srcLength, void **dst, CFIndex dstLength, CFIndex *filledLength, uint32_t dstFormat); // UTF32 support @@ -260,9 +261,7 @@ CF_INLINE bool CFUniCharFromUTF32(const UTF32Char *src, CFIndex length, UTF16Cha return true; } -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFUNICHAR__ */ diff --git a/StringEncodings.subproj/CFUniCharPriv.h b/CFUniCharPriv.h similarity index 85% rename from StringEncodings.subproj/CFUniCharPriv.h rename to CFUniCharPriv.h index cb243b6..f9667fa 100644 --- a/StringEncodings.subproj/CFUniCharPriv.h +++ b/CFUniCharPriv.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,11 +21,11 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFUniCharPriv.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ -#if !defined __UCHAR_PRIVATE__ -#define __UCHAR_PRIVATE__ 1 +#if !defined(__COREFOUNDATION_CFUNICHARPRIV__) +#define __COREFOUNDATION_CFUNICHARPRIV__ 1 #include #include @@ -43,4 +43,5 @@ enum { CF_EXPORT const void *CFUniCharGetMappingData(uint32_t type); -#endif /* __UCHAR_PRIVATE__ */ +#endif /* ! __COREFOUNDATION_CFUNICHARPRIV__ */ + diff --git a/CharacterSets/CFUniCharPropertyDatabase.data b/CFUniCharPropertyDatabase.data similarity index 64% rename from CharacterSets/CFUniCharPropertyDatabase.data rename to CFUniCharPropertyDatabase.data index 9155094b735a25bc59357e110be01388878acb1d..6898045aa88a56d403a64ab6493289d404c108a3 100644 GIT binary patch delta 1529 zcmbVMOKclO7@k@0uGf$Fop^U0yEb{Zar{UVI}azZAyTReNQ!uiXv+b5DuoCE2cSsh z0u``)LaLw=Ek#IxQUz8>RV7+-0rh|y4u~GC@K9v6f&;mr-par0O&d-iK6!Tj`Df;v z|DXAOpL&CT{3V|sD;60c!dOORY$_t?)G@{dk0>$OtN8qZU$F$w zLYKMp0#BMtheVYz4RQXcbiLVZ-LRhJ^Fn{qL95klwKlg}HeJYJiYGd|Sdyt4Yc*NS zTv|Y{ctCDB3#}FLBv;6`(ZqJ>fVC)J^P0v%vcJNnKTGYXX%wjoSlgjV;a#Z@M&u?I zKcSp3jZg4W*9WH2z-#={J>jCV>n@ll&MC2^stJ0kJDu5+ z&2fGg=RLiB{R4x1i0|DuoF6H$Vu>?W9_9PT#w*nctS2=-iKzCFG{yOJjmC$h8EJN| zZmH@c0*bndW4dUa)Vl>PAgAa3f-K1GA4>H!=ISA89XK)-^m`@7WCt+QW4M$FU|9EY z2`{G4i;`cG$(?cC5wagAI~bDwfgRGWHW7UV!A?_fz`^rLtYt^6Yx|>wU{+GI?bKIJAEPsY57L7hqhkEkNcjJy*?YL%URR#=YxI%cVJt7 zzeu*|K(U|6wQYx@z$hkgVK|0whchm}7X>{=S1lo53qZ}6Imf}g=B1rBP%qTl@vm?N zhn3@|aSlIE&bNI563qjYm)ahxWNw?r>sT#^v0Curr*f1+ui@>ggiQG&&KCl>sfBR5 z5QQ*GD(s*g61FOzQ_4EWikh&QkS#?~u8h;((w&1IqqRY2dQJF_V$jJBT8Z%-M^-!M zOl(fxN6#|q+G#vEK4x91-0!|X&^hd{Y7XC|)+L#;lksaVL#o1C)q5$(r|G~(2kGoK z6jv2KlG&3uQ+pm~(n*p9%-RVugZO1Si{Ga@2ACw>){Sf2sS)QUorlKPm6T~jaikUt zwV#Lie9ld~i~+&VF`+Kw`-&H@%zUH>iB2aPe34rBQk4;xM#VCOur}-Dxv_r%A66fx z&||pXouZl$IolDlTP1d-{O1<7rEjaBV5j181r*zF`~C;H4?heYC5cOTvvE} delta 1175 zcmYjQU1$_n6uxJ6c4l`HHQhhMvixyFf%~MfI z1wm*j&G6+xDAG!;Po-3+eeglzgQ5ruzKM!PkUWTB{J~dy?o4*^+dKE3bM86kp1-|x zmCpZ2TPp*Df?*1gSB3aojb#Z2nI8-T)sBm`nZVd->qHd4ljeUBip)S}4QqzSo9{+!Nm`1Ve>a^6ECM z(gMC~{dF|9UK45J2lIs@mDaYlS!LTHiS`b+GbFm!t?%ynO!W22$V33A}@xUrl z1y`JX^o88xBk}6!hQKX7`8mdn6I|*)7{i6JR<1hC2^Hpe zh7JD2^O0}0#-s!$HM>eAR)cOd7!fTg!%&$~LnM>j_f=X7*!FojgPYYBJgSzkQZ3_r zB@1_S$fCE<|tU1s>l|!b@Ry7 zk*rgappYYZ%7vrbj^X`w8<;+ps#hwk8|J5{5o4sf@YlbS7$>;6u6!EeL0}owJAxZVit>*q@}H)Duyo<*wtwMjNv;_b7ua?RWGn z<=8sUf0=HSx7^~)#*8Q#;so%fqt}o*NQRW)Vr3oiP(Jp(Y^_jS?ODRxy+i*4s_Zcu(f^SdBz^EF|s@A#t4J`8V$=?vwp( zJh>$nGCr8oy23||kBa^bA>$bTVhKxG#&UXb#@}4l~_nt4Ix>LCl>dp*fLgB zWpOMN_|#RNW{gW1=QB)jDKq#ilU&A3KF2IBXEvW_4p%UjFR%hvvLat(C9Yy+zQhwk zQK+(7P{qW{^yaFpVKo->M6P9ZzQU8Zjy1TRCvyX9@>QO~jjYAjn8!`5&DWXF&8)*W zSl5NGVkHY)-zsmiKDV*~-(o{?tb^~ss_?-fp&bD;X( zqEwIpeqbubGZ|+~CYWXhTQSMAn8~x5#dDa=*399#%w-!^U|UwCj7wGGd92L#Jb~w1 z%9QJy>R_TOJJNMdNyXHOynxl&i6`+w)?jCzOevYF$u2yFQZrSHU71HInySri%%@aM z)nRwmJdV(IT&&%0>J=u^~un~K)F|TA3_U5U)icP8PQm3&mo3S5H=haNHKV@p_ z8aC$u4rI}Ff->Zqz20nIFC7>x&mQej+>BUF&H%r&V)Z zNWRv;ch1`8x=;&G(9lz7GRBtF&{Jt9*oqlEi%FhM4Lx-Zv)Gy%dg@%}unjfzR9jY{ zbx&2~d91|t)X-DsGivCm4g&8w)sa={0;M$c)CD||ov5LwEL!R$c4iH_fT@$&g&KOw zg-o5ouGG*|E@&!`QKD(+DHk@CPs@|ay{4a zRc_#G+{o9tiEnT--{cm)#jSjs+xQN*^Ih)Xd)&$Qxr?eQwVNMu4?ijr>=k^>ef)&` z`6&9Sf}$+J zbAoJIvVt5w&sWsR7u2GqFUX?}prAHgf`WY72ny=Zr6{ON8$v-n zx+Del`6e6Cr737g8$>}PxnXjCPB{(<6(9hOuq%FB$0 zMC}mrvRQ|@tjCIMz{+gIYHY%`Y|8W4j2)O_M>gjLY!N~ozcA5~F}7lyXEVXp%wQW0 zsZLVR&P4P^+B1tCm|YkWh0I|mMsKV$E3gZrH`tYx*p1N}?amX}gH_m*RoRQt2k6Zc z*@x8&L!zICROci?f7ajtp3H%)84rm;JcWZlp{!jP62q9!;jCkR1nY7n>v0t8 zb2J-p3>$JR8?k7dps`>)n{Wb8{%+`e=v4rPxDchJ|#wZ7tvmIA3%7v9| z&s991s~P3S8b-OXmW5o$C`UH1Q@ki7WPP0rO>AOkZstYY!Y7_pvAU^9mkducCNJd?vV(2icon@+yAKK0L&}{Eq#2m{;?A z_Ad;HBfN$`a)9}tc`bkCK>o(-_y-5^D6i)+77Z>8i4wsLEaMO!=Z%FSBXB6=yoo02 z42y@1Oy10F4reZJVMUH$W!}mv9LZ|Djnz4dHF!H~YDjfP3u>9TgS9z^b$BQ1acp78 zXu!MJh~wCVce5$S$3sRl-oq3pusN-4Mhi}4OHN`dPUhLXm#w4vpCV{u;y$+HRJP~+ z?7(R(Fmr0*@ZLMl@GBSXRt4oXy^x!#+{{&lU9JqwLRl9Kgpo zkn=f+k8?1e;1Dk6P(ICJT*Bdeh9kJNFl3D6vmC``9L?uAhRazrR`9%F99M8WU*H6; zs-Rkg&|`p-{3NC;c~vo72L{|e2c5NjjQ=K*Kj-6@*S?@4)ve0LGW%oWNhS4 zZsL2~%w62V_qmn3xs4xiJNFcZj2--tJGqy;_z`z=ANTNM?&W^&<0stD14V)Zf=~Gw zKjT4u&M$e8U-Jtd;+Oo6U-2-%=J))DM|g-o@>~AQ@8TijSN@B?@i713zj>5J-xvP# zHKWddSYqM`%lHG2^T)!F4E%|4{>%*i!c6|kZ2p(I{4E}m75O_W^AA?x|5%MjS)G5f zMpXaD1T{_k#abcM4Xn)=>o8szlJ%Hi1FFSjBPQ8|nQY1|He+@?BvZ^`bLN_F!3u22 zifqM7JX`(Ott@D5;smx~m3TE#*+{nK1kle(pjW_ceZsE1u z%7Gr=#_PD9gUs*X_1ww9+{GKXn?tyVH*znB#zS%+Zz>Y(7Yy^j0p85dIGhK03%}$D ze$88Xh$G`6`5kZT_|KhB-BHGejc+&heWC7XGVKR-3JBPCT1{~53wR=vN9iL70zNcKEmpp%^IA;nw-m8e3Z30k9GJM>v29C@NqWc z0yc^2{|P};6ARglPcp?tY|f|Hf{WRbPqP)5@N7QA)?CUqe3tFFjP3axJJ5EUSxCEW zW+$#-=cxW)5Om>6cIAug##QXjm)L`=;~}#rUuG|^G2ffT#(lWfxF6RU_vd=!0o-6b zkgswO?XsDJ`I<{xG*z(4#1L+dg@o^db>B1|%B_VVa~R(;9?osXBe>moB;PR}#T~|@ z`K}*0jdsz@F?`SX0q!y$%lA2syE&d8sQ=6ff;}cC@xv zn2Y)E!jQRy-y1LGf4GcCxST(Dee?!?G+x1(|5nZsSI$lYwjJ#50g?8trW#QnU82Y4|*<3Jwdpy&dADY(VN*Brq^ zyp`W^BoFg8eot*F^9b+Yj~vUNc^7}>ME=G}{DV_?l=tx%r?G?&u#79+z-1m6yciEz zfmR?Z&X<@$S3E0|u6R~94>6bDvLao;tjhd>Rp|^Fy;zUE*?@i6i2c}v{n?ZQ*o>AmD@9A1)too51#e_a z-o#e4qFHCtie|ND(d~jZ0!y3Kj$_!Kcd`R5ZB`-2u@lF$Gw)#+&Sh6FVmGd2cSbAO zgR9w-YuJlx*_-RwM+0xMLD0{{M)v0>4&Y`EqLPuZ(B0)Jxh)nhcWzcPir!?&?Xhr~pH(v2_(I;nXzYx(=R3TUB^(7|&BOi-} zTRL)nER6V^kMlh)h=p4l@QGL$sW3_w#=>nbZ^@IfaOZPe6bqxy;!`YgYf`c}7H(G& zB~Qn~=-ap?7VgO8Gi=MHu`tHLe#x_}%Vpe2r_p1gU%Z@u@Oi&LVwbF72fh#sV|Q_7 zER1txTH=)Y?k!vu3*+zROOD6yxmvI~7Ve3Dz{@67QpuWFn3!a7EZnOSO4jlhz7h-f zM=P){79NN``FhH$k`0{4S7TxN8{Eiae2vkHY>EX}Bb2;ue4Mu3=|Axe$Kwy4E7;-* z)A?pBJQQ8at+DX1S}%Dk7G|l0l5Mf@$m4uF7G|r2lI^iDPvVz24xjfecf`VD(ItA9 z(TeQk-+V6?=2ze@wxwh8C#rFGEIhT49~4cBH;tBT52LL7a8f+|G55wo+bF9)iiHj} zxsTBs{diKm=f&JVDc*k%KbaJt;E#JH2mHVb_$eh}X}$`Z!Mcpb%{Ysvb2d|jA!{y+ z3Ivv}w7Cc7^9(Lv3wnp8XL1o+axv3f!d6_$v$%|Bb2(dc1<&P5w&5zajb9@LKNWz^x%`U$`vx;dO%jCI;~UujgkR%!7Pwa>)9UoA@*1o0wPJ?#bbmQhCX|%)G3;?7W=3+`I~T z74s_PRnDuLS1qqiUfaBOdFSP|&+CwPeqP7C!n_OSEMIXXKJ-}e+!uz$Gpm&O`@zBD zvKJ4{95WH@$0CQ#BZQZ z5+6#PB(A6C>m>1E)JgL1rcM%<_W3$V{1(kQUn|MK&xBSIe~Ma3T#L%rO5!7_mBdF; zD~aDuog_Y*I!XKv>Ll^8)Jfu#sguO-rA`uifjUX_kAd=alK6D$B>A6YF5MU;>T^9CaswOlRi4U?JdLmMbh=+i6!3MPLH7-bGx-M7bpMc$y)EB# zvza(Y;6@^$`?P$E+E~kNlol=BSR|xq%kAt)Hy8kAR7*P}Pe`S7 z()bo;Qf8#Hk|7}@(%Bxj>ggQwe+4x1)^tv@X#rPH0q6U}F^ZGYf+v9IB zpW9i7@3OAPHL!HOq(7PL5!5&FF&lWor)bMs|9BM~yBY`TRzZmS&9_JZgy5$Tr6kde)FM#!kdR>nG6 z`YbP~!LyC!Yx*3|ufx{n>+xL5&vY9$VOz?}bUUVao}VWl)9sDrVfuWp*Y46q9Za+q zbfo-C7gCE%U*HAuF5SskzNIf@7k1_)yvQ5r&MuyJ1??Fb@+;ldd|%o#qI3UrH;)hG zr5w!eUaw81FXPQNsdNv)2oslkg7%Z{>4kUj3iEfemwDYGeWm#c?Clp!$re}{NO10uIE!6%qaP8 z;IkaU<-C#lTzV*N!|9v&GKbOjo4%RrIh;{a-on>8f?Iei--^m*q#(-9+Zbi%C~qXn zPG5$ibNBRU^HGxCVf+!tFiO@t`3c8*JWATT7$xmE^HI{?&2KoK-|`;*i&|jDzgc8u zi~b{+Xd=qmNpvrmp3ML9UjEK0jI#JX{>iEQi}$mX)BNIcK9CWTfz#vv9IK}vWR%o1 zn9YZn%bBdmht+?wvS5~pDtsjI&$)VfHcv91!^`Pouj80`vqt5X%9rzu*A3xpP_D?Udj%9*5kTxdYSQs ze2!hX+$WE!;(3o>#uer-=L_t`mAr~CvL9C^L-HEFRFoN#g9NL+a428qFxr=*WAC(m zDLI1nrQ}Gy!cnv@MaSN0`%-cY?MudZ+D6$%(WtB`4Fq zl$^pM8&h=bo!-J}e3MZbZS{#}(7u$MMf*}RDj)k&GAf_#9-qf|e4+)kFD0L(FTlyD zYIgEzzQ<>1UrI*R^FE^%ZeL11AJzW{f~bu4FzV^PF(+T*UOzZ0r;m)Ia@xmr{Mh^k z?&oX##QbI+@P@YVQ}f&SnfZ74IispN$oKdK-{+T}_d!(uUkUb__}T+eS$)H(tPU|M zt8e)^zvCDD7o+kz%&5Hn&8WP-XH;JQ@$;hcI>ICTfl+n+$Y1#rqpJFuN2B`xMG%$K zuZ%W_|MGACmI#?~{!Vq3{)5^4A1m-Eqw4vSRe6ln`4>-S32U*G`7C2pHRWu`@VF`|&7dkNO&0!hNL=dOMTf+tC$b%F*U=$y=}A;A zr8QW{li6v`%8#y!buP}>_d%ja$&~(JvMYaNH#($>4v0&CW)J?tp8S=)_+R$sZ|uY0 z*^hs)KmW%8Jj#LmlPat97zgt&4q-_=TE`fI+xL+D!8&}QRg#S)CH``g*=6eSc{99$0e-IrOf9t*5Pv2YG@_23*aCT*F3O%f?iIWlg96%TDD+x(CYK#M8K$&A5f9b1PHa#sY3lsZ8$0n2UdW^D%wxQWCG5g7Ud-d{8V^~4moUz5%;2TWWOrus zGUn=mWjzEHODC-;!_QE#2f$cbi?Rg_Ra3~9T6FYGjJM(6C z;c#~4E$qe-?9N-+Lk}z)Dd@@D*o&jso42zMN3$RAV1JI`0N%-g9Lqtxi-S3iLwGlb zay*Ce9uDUOj-cGjDjF%6C>X^_9L>ob!+SZFQ#g+IaXhDT0`KQUPUB=gz$u*0seF*r zID^yq5NB{EXYyh79~~c+%`!2Yk8mz$a~|h#KId`)ALT;M<03xB#hlM2e4IOVR@DqCz~4WH&(F5x;p!wp=@jeM4yxQv_m9Jg>exAJ*z;|gx) z3*5n#+{qWYi>tVsFGbg2k6<XC|6c?>_$zzzzwAZ#K-skfk zj5qKv-pCT(#8TeOGTy>+-pb=Fx=rx6;Pw#81MgsrcQVeqnBd*a;5|&z8!yk~Bxdnm zN`UP9n8W*-%LiD253(X3VkJJz%IZJ+5y1&2=CBGMWmP`LYJ8k0@(EU_8}0Iw_!MjK zX`akySd-846h6mVe4crHfwlP}^XWdjypH>|ou_@o?X?%yx_%2W9dra|t7VrZ$FA{txID;Rt1wZDQ{Ddv}DbsW#Ufzmd z@GO4Cv-u6r;kRtffAL)Yn{D_Xw&f3O$Deo}e_@d$i0uCgE~mOL@5w*u2qIg(m-k{h zuS|p-bza_^2|9wvQQzf#=z;RSRM+MGcml7caxU-BlXwl4ak=d`Cy%z@9OYY7Zu`xt zZ^HJQqi)M>zd5JU_M4+#%N;@F6wnbwjxsHG1d)^GjZ~iHjv#W*r6Y(OWm)bBBIkTM zg2+*h<&Ge7E~F!f9A#MU2qNbaI)cdQuKvp%LF8O+!VyG{vMV3Ot9U#6aWt>t9URCp zyq+(btZIm0=QxAJa|;&|S{dpMR8csGkUp-3=MFo}~mg_C(d@8xt(;X}NS zvpAJewcO8nbOezTRmlTf$mx8F4{`}-Fsh1&xSTT?Rl~z9vJIBc7DQDrhif^PQT9K| zjhx3Q>mTD5&S#YEk8?X0@LfK^U0lcy_$2po5u>DjiU+uuQ8GWB2t_$x3YM6NviKQ( zM@J4hQT9H|BXs1D6J_ml{FTf3JD=xKuHavMfn{9DzxiS!=s}@;6_b34*<8&EeAyXD zu3e~njftu(W_7OR$$W*ixQ_W;&wAXzhJ2MxxRIyvHKw?UXYh5l+h zQxfFbM9R0aBj2LUqkJ1L;@j-X?Yxxl&|XpQ`*Q9T^nE$k9#Q^VM#$~U-x($AAH0tL z;|)B@C`te1Ej-5CSoD`45M^gcwU8TSXK8lGjgqd+6K02Syh)o4kN zpJ>pA)#;NQKZ*5OgUavt$(~n(HEAV}pVBeZvr@-furbe!g?d)Hc;4YxVnwp}_-($M z&gUpD;AqO`<72ppcXBbuQdS?oi%U6<%Xl|s_wn&u!F#xp6DY}#>$JJ6IWZP8qc=K< z4LCU#ig$khc;ehO2Da2(6>!{^n!Ap+)Z7iUrRJ)H1Gec~D^f#z;)@NkLPRyy~@3oH7W1skYZQ_gd)vLx1SIVp^@v4qkf2>YyWu5;6 D!XZaW delta 11740 zcmW;Qdw@*!7Xa|PGdsIGn^%$~)-$ifwj(4-nVKr>-CBEU?2I=#omZ^R_4)VKX_S&b^Rj6f zdDk{b=51)OHE(6hZuvc%R4)~2nw>ws_3UEFtRNCZD+EDS3bPntWky+*sr092#aM%B zti^QJVMcBct;;y;F;hO9=P`%H*nq{^kR{ldCD|lM23e&9O(o7}GnS_FnRNkkStd7# zw%~_jG?$pc z>o}9SoW<)on=LqpH*hXnavpEwe752O-o%A$&BeT#OV}nih%V(VT*kIs!CP~aL3E{{ zoy02M#?@@kHN2hc*dY=`*Ygf;U`KA`o!rDu+|0YUg`K&TcXJ!N=~l)WQC^cWxJarWT}KEjji z%hOCgDmW|X$3i~FbL<}pQUgBD2nSFi>j|cDAT#(RGdUt8XV19e2#TEhIRQo>v1fzIgU9T z&jx&f4LO00!~TC!&_rS)oAM<#<0Lj`9&4r%Q=E8B0=g%e#lW=$m{c1GtS@!&gAEu#f_05bvD1?9B$%Ve#v><%=!F^3%G>~ z`85}FYi^Lbgx_!}w{aQ2)&Hq01luK6@;k2L4zA|+T*IAQ#~-+!ySRZrawB(h6My1n z?%@{x%&pwZZQRH0+|M2SB`Me`I1mX^ckx&5=0Wb^Z`{j6xk2iF{>}qD%!B-chj@gC z`6rL?D39_l9^)|{=ifZR`NcW@RvayIYe9NrZPVsm-7^*r9g`Mj44*v;{UypN07U49Ag=Ti32 z|FLC)2P9UoCs*=8u41o95L?ZMxQ4yu*YRPlXCH3hBizWo+{8z@nf)R`YzrT|?!Oz9 zO8u?3T0d_69tR{Pwh5k)2tVmS>+O8fdJzX%@8DqT@CAoh@8na~Uva4QE)KH}-)KZ` z5ZleCxrZaUm(OrNNAUokgSHOYlQtjS5QmhZPuafHmxpgw`uh_pV@quIb6U7e2)#ekd3*B zO}ID`q&4OHY{n(>&6#hV%ca&WxXij`*#FBVT5*L$YktT!w9Tfq(2b#x(hd2cjXseZw&3CX~}MaFD0JmW{K|niaof6 zJ^3|zaVvZC8}{M0+#szlzxDiy+#%nO-^=&sPU`{ufdjdVgZQJzkL6GLKW&I$j{`&b zGlz38M{plUa(`}+Hj2M^;$j|<56{T24F8gY3}5g!j~mZJ))V+U!w+_tllX_{hxsGc zllf=l{vd6N;HU%7@~@O22+zpz+#qc#?T%^FdBS=IPg>99DeGB0Z9SW3JU@Knv(|H1 zVErNst>@;o>DeebF9@o*BTSpmg!t=Z&2&$%XDdSwmVqC%MT*(?- z#p}45Ex3j^avg8tdUoRmb`Q_x z&8NACqqvvPazDrL0H5bUE{G(9v_pdTBn~q?14p=sN4b~B7=Gc$xt}Na3r{lq0#EY~ zo@Mw27V=M?3xaC3Q-bUa)?qvd>guly!51^x?dm zBUn#ErMli%N0S&H(f^t z=_`3JSFzi=AbmCO;~IA7I^NIq?7C%vT96&R+ZQ!G$c&E5U;l2O;(1*@JREtjRDP?K zy(9T6SM5#7-}K48l>Bekc1y{>`qLZJ^2dJhck%pZz8{~Gyf6rI)Nb@5=JR5z;pip& zfEB5hqm{UvRk(uH_#rRlO4j5@tW6~zy^J68aw_#`eSShC)Ep%rO>nL2W7J=gqxPeX z_$jaAdR|Sv5WR*QcrEor^g7y6qu29`s39mfQBUQ3$(y;^alMrDm9<{V*WNa}Nq9+czC<2Nd!Q0eTtKCrDC5H`>BNQJ za2Cs^1<|*7k@dSQ=Xpvsaj|ti%X0-U@%)cj!SS`M$o0(P=d9%TCRUCa#%&Q)k@%KX zJ>Yv*<1SX`PrTFz*~=Q-&zd~IT0F?w9(Ra!_y;fZL5{Mn^*_Aa>z`yj`LnDq|37Bi zBvK;+R|RJ~NaVzVaMqPbqz0+yv4M3-UK#ywmX&B|tzHw2JiY=O%V+T_s?S6dR_E2M z$)>EsYrLL%Of<7rhly)F-?crFY%bAIa2?fOB9~2hy(g%)x@30qLKNAme5qr~hGx0D#U>}A> z`3OH^U#{k(T$>d16RhWB46C!h4-!_V{X3lOBnHTbMf!yGHyp^YSfAu~9OQUdw1XKI z?GX8}XrJQG9Ljwh#$Py`zcT5}CVvx*kO-^xY5vKP{EN@GUe1(-cl~p;7Vf9aE4Zg}+oWZaQUSnO(WIetf^vH_Wzf z%s1(3oS4IAe9Q6cIM+JtinrO4^HPIY*cI4ptKOrEsv4urI|1(!LbVRTB24 zaITWDFNJfJgncQTt0e48u@ST{#YQq|V~ULu*qCCYxt3uYt@9U+rF|(Js3g`iY#;kl zENq_*j!)+2{-UY0FU4M^d$w5EHJkW4zvLUVFU7*{`HJBs+`bfhJM90j1z{U)Wq3_@ zlNWoB+q`htPTyLG?X;as`JMbS?%;>~UVasK`arAsgZw(~lK+f9GVH3|{DMF6OYZTw zufqQSS+G@NuLEIQ?PJ(h`x&;?FZ_WA_#=O1*j@)2w%2bA+v^a+_WIrHh3$2ihxiA> z?mEJw{F7l<9p#Cz|Njz%?R1Rc=I}R*csv@U1^kCmo}fhHU&eWoVfUP3NuFkDp5cW& z%W^E>B`jpvHASq#b4-Tq@;^aMH+F%aHrk{hh1#SbLTyqIbzGMeq*9j@#B%=|LlmSr z-q`vAHlgi0977abNZnFUmd$w)b6Gj%zll&m6*}VuRa1hzqrY62(jq_mz}L}aOQ}CR zv=xuAHN#(9ZFrPz`4`*q7~Au2cHnV#1fU@JwjG!gLN|2DM*doZ7E2lf!u) zwO?T|j%0D_zQPh5&63o8g{8uu&)To>e2MWa%?S)o^+blJdJ@A^tqlvqQ$2;@sh-Mm zoX(3mgXKAsmv9y2!N53m^z@>(8Zvbo@};5r^*E|2nh9%Bn0=M6l;mORND zd77LhFY5nr8c;Yv6ZFx4NG$y z%kW#4<#v|icP!5xtibP?#ht9oA6S*USe-wz26wX-e_|c(VcoF*e-_k}*voA0V-EMT z0e@jb9$;hs$|gL>ru>b~c!|xM_H<{I z(Sh!aGVY{1qm0h{*YSIJlK1iy@8fCS&og|0XZaut_z(;EFpKyI&oTL^;D3V0f}kki z<4oZbjPOZDIhd(@iZKpj8vOx9>3o{L_>5;5=d;Y@b3BjFvlz#*IA351{h#roprpi0 zEX6#Y&zD)6ukZp+V;Q>rF1nDfu`FNbMSO$h_$DvrTP)AFc?sWP1-{FQboX79rT;S) z2`Wjv&&tea6@I{~T+V8A8(vhMAMsLt%o_ZJHMy3x_$h1iGuGkfyo_J4F2CgE{EGFG zg0BVj`3`4b!RXEx$KHs&w9iodc6f8*8solW@%ui>9e z8cbyTCAf|HzNkI_rNKmoelP040^UJ=Ueqxf#8YT65!c^EotVzMsIQAUvpDajb}s6| z3wRH;agpseelcyoaqXKdvi-&@N!Whl`nJgS8^4sc-?)A)GMI>8MuUmCHZ3xkh+jd2 ziMaMGGMI=rqQOL5TNW8i#IK>jL|i)-8BD~lr@=&A8x|Q%#BZX(M7)juFEW^j-zs4+ z5!ZG_{dor;XD1He-F$*wIgt19N%o+@MEpS-OvHP02p{27?8l*eoWnSf!#S8q4owP1 z2tuFcNRH&Qe1>B)gRv z42$`VXpoHW7R;6itN2asr$IzKtlqbHhz1eyuxbq=;zv1;fAbxlpg~0Z6yN1pE?^Pg ziw0^kC|bxU7cq^C8Rz>ZBbj!gq9qa~na|Q($_x1c%W)Ym;c{ki1*`BwR_99A-*-7@Dv9A-dZ`neU zP)RD^k|gQ>p5H&Om)HCA`8?;Gd+*FW&wTFl+7guogS3C$X-2Jq}f` z&(ZS7IgSnZ1RL^6HsVuk%%|Ce&!ilV9~3}|n|JvS@A2Q{%$e$C&Keg4+2VpQJMT|(;nZoxPiI3k$Jd@4{$T{atjl=mHD`h`MI41xPt}DlncUCK_P|D zSeQFmgu7UjyIG8%vv`@5A(_v`$Coc01WgJjx5zO(?j7NX2AR$@FWGaVme0;@1Rt1<(tF(a!p6KgOtYcdOK@jlir?MInaP)8vflbD@# zc|Yqh2kSE@A7?H$U~WFaJZ#7Z_$2eP5fk|o^RY4W^Jx}f6Bgt%rK3SuNYGTFFrQ@+ zHe*pf$6{>G;(VSZ*n$u81(sw>KEzfm#nyb7FS0b-unb>fS+-?6wvP%r2)et4Ug6vM zgRoki#cvp5~clKaE_UBLz<8Z#i5qy^;`5s4cG{jng@UGdYX1IftKcE&Vu~ejz$u}?whbG&=q#K%41CwiLQVmS5p-D9`xrQdyz~mY}!zRgp<$o^TdnD*k zI=NASyq&x~0&kOWC>NNm-{E48;tHC%12cFyhO6acxrS!)z>FSFZHK1oz_cCy%X`U% zi`C0)x(-a+;r+~>(!N;rFu@x;@CFZ4W)z>2kkG{ZV>$|xE0!G^H$w7G^6IiDqUHP; z0|!0IkmVU+1;(%aHe(S!$D(Y`Vtk&(*@7kb0v}{cmSihF#MUgu7x^&Turyy{8Mb9vwr9Jjpp!ta z5O${CAnd|d)w{7Pd$2qEvmb|XDBt05zRMAOk0Uvnqd1mh_&&$+1CHm1oWNv8Ckj3i zOyb9!%&DBh>72%yoWa?g#ZNegpK>nea~>CR0T*)-mvRZ0a~W511y^$wQ_?1*HG*{t zYq^2zxrrOOg`2sJTe*YV`59BWi#z!_cXKcIa6k9)AP?{`5Ai6E@CzQ}3BUi~xZsq+ zNq))GJj*luis$$>&+{8z;J3WU%e+LLQJ_N#bw+^>DbyJSI;2o%6zGsbol&4e3Ux+- z4k^?b1v;cKT~we&3bjUo7Ae#k1zMy~YZPdaLakAtMGCb>ffgy$8UDbyJSI;2o%6zGt`sMaXZB86I`K#LS= zjRGxFs5J_-NTJp!&?1FeqdDbyJSI;2o% z6zGsbol&4e3X4;R6b64A_cyS1jaDgF9x0YJa;A1lhB|XIMdK6QuQ5R+fd!a>g_wy& zn1#idoh4YEC0UcDScj#V#Imf%atsQX{}{3&Bdp9AR$(lw#RSnvoS=q6JZmu>>o9?J zV}iQrS)Uo$Ks_THG7}pyGaEAtoA5q1WmYz0Ha2H=w&4A2$sBAQ6AkL-6twXGx!9Ju z*^YVG!GRC3BlEH|6WN9N*v)bI*@FexQ@tR2u@L*PF#ECy`?DwquowqM1;qvaEJaFi z2p{B7mgI0g#1SmTk$jk=Sej#4hT~Y4<2{i_IDzFjQT4@2RyN-d5BGTgwOC8oANlH*z}J|GJ(-2CGb?*BJ9{$+`!E;ZU>-*M z3i1m2F(3Q00N-RG4qy=v{1%IGAWLu%OL8zvIqq$i<`9-;+6ybkp)Ai~tjOW4%y(EN z*8M+1P)*@o*5F9i;(M&aQLM|+tj{rQz_Dz|acso**_h+mgdeaeC$JemWOGhr3nsH= zY&3{W60}zMh;2BTZTT_VaSA(dDm!vIJ97@Z@Dq09T=w9n?8$lTFpZlzgIhR@TRDf@IG5Ww&xt#@fT>)>&$xs;xs1EGg1fnjpK}fOa4q+8J@=*E z{~KL+zrto7;8q^wb{=9X4|6Ava5s-~507!53w^-@JkCQr!6Q7$V?4#me!|!>KSNSck@e;4|GJoL}-ta`f<8S<)H~9l^ z@oL&_a@&DF@(!=@E`Q=ZUS|*&)cu(e{=!)P%6Q&j0{_Ph{EeC7g2?a8!khFtCGrO? zFGX%K2mfR)MsEx92>xPT1_jLn3|W8?7INVj7GW%lF^(k|&yq~XQcPfJ=cQ*^W?(t> zj4aPgtjNr)92Z3EW)W0TxR2GCl{K80jkTDab=2=?UFKkY=41orVME6~z(&l=#_EY| z!hCGX{A|WTZ0@+iY!T=FFCu7ZpeS3j7~8No+p+}P@j-TANp^IBhuE2=*hT$ec4KMw zU>WvgS@z;1?89>G>%2$VKPo6M7+|0R2eKjuvl54}GKcap4rdjPa9&l8WHpXbug)>7 z!Evm~@vOxOtj&q6!%5CdVsx^gu3(CRdYs1koWaLAiw!x)aZhqC8*!fcQ(VBtT*Rlj zgiX23anEuEn{k!;b6msbT+8PRy8qV;S}1Jf3*5|B-0H*^xn2GeQ~5G?vK@CDZ_hpK zz+-jv0-a0JK>ngIh==8ac|-m-bu>vs z`I`qG#+w|@TYQJNIf8fiF7I+A@9{kb@j=~DjBqq#Ifn6!juj*b#xVomXC{tk7Jk62 zoWSh-kU2P!xtPp6oW#8Ri1|2~1^6)waSDrYDvNO%OT@eXrwd9d%wQ?bWNFS~SB%KVg7IFHphpEbCEwYZRVxQKPRnDx1Y4dV6xO9c%Tma!3+voTk&30JZy zSFu@q5LwOUT*DUXDQqcU%hvMsY$M;mw(^Z^C*Q;l+{}*L!jby_q^*L^3fsBK($r_{ zBHzhwF0hL|2pES0rr<4>9%Xch;Fw@2 zzu<5l=Li=*K_4WNPIILCmmH;jhGXPsIgaNzo?oTa9se~a$S-grzu_cav!2I)tg)+zs0rkKe=9hn;YeSah$8%;b!^Y{6Kz}Ta$ag_*iti>U3*)sa(OGJj~rZ z!aY37eT*$)E@FBfVkRD8F&<+H9%m9yvOZ7q37+ATJjZrC&kjX`XmCOBn!-i)j*ExW{@GaipQ2xeYyvY%~#dmp|qj-m-d6&zIM9nFJW#~pV%Q`q$SY{d zd~C)7Y|cV#!6IzQVrmF3x$71@iG*_%}ueM3-9(3dsX zpSAcV>+mhs`%{K!uRDG_O@gpD*F77Aeb|L>aOg8Z*q4vX z`=#aV&%Mop@J-&~0M2|q2;buK9LT90#7i8^)-A2{GlfG~zm+vOHg9Dqe5jy9YYV(A z`CR zmHJp%=E|sGj-b>VR+!nlZxGI9d_ODAtj>AN z-`|Qe3vvMua3R0qBHrX;Hu3;VScgk_Xh0AyzOp#$~8xFBPVkccZ>Eq(Jc_p!yt zmcaQH5Aa_eWX35$c!v1#db1NHgJD*@G8*(R~mg%>Q)% znf^aB{%7X@%=Vwv{pvFXTF}fbX;P5V!FhH#Po?75;G=dO3a*?B{5rK_QYz5)e~zZ)=aFGSSPV| zVp3w=#CnOziaA3+J;d7qA-_a*%HXEaFW0V!jqJIWG~sYhWp7 z8(7BPT+Uux!9HBcH@J#@xtjgBh69+w;ap35$l*FJ4b3F9ha7I8J>+mB^Le~Y92#-DR1x9>TpW)z2j^diPoq*kXB(L*D^oX zu^`v8FgLI$H?lZ4@j-6pL)^lLxs_$OjgN3UALR~KU@9x|v-0N2#{@eSs&W^rb2n@9 zbJpe_CUGz8aUX5HNA~lHm>}i=8}T5Y<{>sUewfYVNBF$_C|{5t<6J%97v)nf?C%ps zTgL>kVFk?&BkaH!c6MwmyUOGEnmnGpn2vA61aS!*U_3nst7o9kT`?IsoSFEp@yzsj zDK-n=SHF)w{={Uh;D?ax$z@acNFh6?IPiYXU=GePo|AJuU@k6<3F32exjYZ;gTy?* zb@IHl?GcyA9nR0kUB>g%_C`zr?q@+-9EdGc!5@obPAIH!N}&kPI-n?RTf`LOH!RLe zo=6F%ZC5Mc0b1H8a@jkn||^;Wc4 zA8E~Te39eXh8F81FVSLsq%AGhM_%USSj&{{1XC2+a~eC)VtvdjoXw83NFURQ^Vyk; z_$rsO3saH$2KL})zQ%3r$yC11UA8G=dI|QhH}|s-Ew)GA;1Twv#rBwf zJR$GTQ+$(Oasba7e~Z@GV+QgY^+EiWgL#>6^E(dV4@`USMSt|89V+-)VHkhqaQ=_) z@OO^jAAFa8awL6|C-NSBlP5BYzR43ann7F;JBG2=*v2xR){3>>F;%au|8unlcdvYy%aUJ_`J^OM4`*R})a1#e|GY4}Ehj1&0 zavO(pJ4Z0OLoia1%2E7`W4M#!yrNy4Am7c2{G5}xhm(!(L3Yvm`oo~O7`{WQ1mOKw*`!&Fb`EO)D) z<6iZzxS!{FkYDpKFYstwG>G{|aNG$OdCI`I{F0Y=mY4YzukdSr$8Y#OzvU0S%&Yv4 zKk^6HyT)t$i9ho?Z}4aS&R=-THbu;@g1>l!mY8Gy$A9@7Bk@7Z?~LP3Ch!ktU@hik9p++P=4O2s;w9hhE6igo@^_HD<3v)}ASFC`G$z{6AwL;v#OrL# zpV@@Juql6KGu~ix{*NvA8(Z>sw&qQ?;U8?vTWrTa*@3s&k$@BAHP_`kK`zZJSA zw>tA+w1;wd*X_p$dohN67|XtlV}HhT0Ml_G6F8XZIfNNFlo>gknK*)(Ig(j8iuZ90 zv)(l`juT{47|-mS!23CoIXHS;TQCn_U|zOlKDJ^3wq_x|$RcdRVtk1u*p?;J1u-x4 z;dExkc7n1B?fED>up(dKW9-OkPVB@Q?95txm37#Kb=j5m*^Ld@oekN8jrbZHvnQMI zbvBI(dI_4bH=DB$Tks9GWM8&sKel0iw&j~_#{ulXx7d*b*_ngbg@f6RZ?gx7uqV^r zd(mEkp@Kdf#=acR{(Of6ID!NDE(dcYhwwcPSj=~y#!nK^s_573@Iggt;pIfjGD+`_Be%4^)l>)g&?7~LVb zAxPzK{ERoblef5wx4D~l_&M)#5ASg=gM=Wmj}h)?EDtcA2bsV_%)rCU#3Rg-kk%Oq zvML;7c7DMeJkDG^!8|<4ygbExJk0|9l7)DNMR=CQc#b9b6-)9wOYv)#<^`5b@X6>K zK{+;EmC>ex z|9MkA%bRS*KlvQ*usQ$X^9<4lF)bLw7Z}f$OwU%##MZozFETsZFehJP9=2s7UuJ>y zRz}(h3M;f{F?QgCe1)ahk!9G4<=B}O_$n*23#+m#Yp@$@vpegu2OsBaY{;H`im$Ut zdVl|W37%Ex&F1XG7x)HSvoBv_Kel6kzQQ-znFH9BZ?Ojl@^ubk9}Z?ezRdv~!a+>? z)engZh6;vp7)Nk8-{U(R!x4O+?{Wf1GMVpjGDmSLM{@?pa5l$sF2`{`-{&HZ=Td&a z=nBC^!D=RREhljUKjLOi<~DxJR8HY8PURj><9<%(A(70%-ioX=}qz@NF0H@Jwub1`pm3IF0!-sLj>%jJw@un@sGu4DpNF(X%} z-TzqxYZS6Eg*mvExw(#cxt{sCfrYq{MY)M3xS0=e3rlk=AK^BZ=XO@&4pw0*tMjw8 zH$g4IP9|{|>vK1s;OA__J$#yb*_1c<9RJ4_{Ee+L1hK#KCEjFv{=rVX#jgC5ukki} zGy0dHp9|dKfDA$Qzd0sDkZ_k19gy{&R}=(cHilNzvopf`SxqSit1~C*WU0)fpBGk{|8;tMBD%X delta 11739 zcmXBZdti?B|3C0+_r1+5Bq2G>X*n!3$3~J%OkH?XzR%--xbIE4g}*82tbLX5SSA z4QmI%!IU64`A`t_niT|nmjuC-yFRb5I5smS&-kd!gK@_~=^Jm$iMbjb1lQ8P$k!w@ zE`M@VX0O{1#-=wfnwFkZG$-?P@nWG+a`DVisYBuPlVwse6U$Z#rH?7!CjD^vV(B-_ z7b`U(6a=3~1yK{3!Kqxshr>beLFUtmXQR_wRh|)Z&5K-3&zsaFvrAG+ROak^XT+t~ zua%a*rB+UQRA;P!wQULCFWrg z<5(peG|tOvjAyd`ZLGn3ti}AS!vaj0Tui$+;?WjUs@Ji9TG-FXjt zumXFrBKxos`?50oF^L0sF9)#-hp;M#vKohZBlmGcL`W7!8mP`utid$aG&k0Q7B*&@C$*jjI`VVj_>vI|(&v)5?Q`wN| zY|LqF%J;ata|kmyl$jhB5mpH!_ytFDHAis`)0oB4 z-tk(F;X01vdXDD?PT-fE#B5Hs?ki5=Mo#4>PUB`y=huwP5Vi<2`3+}tE9Y<<=W;ve zIqck(EA^B3mu829j3?&ERp=ZW0&|DbSE2j8J^-|NFY>bE{*!z9T@^0zI{)QOUgj-c zVGt99t}?`HjAl^Ub%0TfV~FuFzA%}O(Ja6i7Gx|7F%Jtfjzz7DQ zCNMwCumH>Pb|$hQD_D02E3puh^zUR97G^aTVKR%chIx0h7K^h^Ob}^YLP#;8B$40Sm{^t#S&ohM%d;sH*^KwFIV-RwE3y?Uv9)!T*@j7MtA8)su?joHM1saug^n84 z*opVC3zON^!s<+A4R+J7$?mMh9<0q?tiwLMpM9Cae%96H0M_Fm{RcRN^*J;mJSYrf z1CHQB9La_pWnm+xu`x&MH{lpI&P9IF*la8rv{3-NYw^ z8Eng$2Aw&NVO=UjH+JU+$we3}ca>&%7fXSkTpaw$`}-1u``$!^Thf1az@y>t)> zRtqm^WU&X=u_rgM7qczw&5i8C&H68L3;S{_U*dN5;|})cP7dI1>ju&dN~1x{Q4i)a z^^npL7Y2=&HQc#08p?g@SGYnwjQiEY=?0_G2p&|w%3bP_Jfwb&Zaf;L@vs+uokuyE z$M^=1a|};%EKhMb26{;9bV@Y-sHQy#iM zP(PE6)vMT4y_(HpegCf!nrmdSr3q`*=<;(FV3rXLD^hh}y)q>dkCt{nzZE z-olRRt?Z=U#xCmZ?5h5jZr>a2U}{9;JK-&jo$RLG#qQkA9{irYn8QB&fql7${Tz5N z-S0Qr&jI=eI7t5>hp2zzP#)qi{!GsejgBxfLgT0~lD}{ik1>tEax{-~j02va`}#&F zIZppKj^`;(;P0Gd-f2!&|G_Cd!>K%*+qeE4r>Xxe9drw(3+FY)8u*K;K@fG3GaTq2 z&NP0Bv(=Y5M}38J)mJ%BeT|c>zs~vU8+=E7lMB*Y^teB=Pe(mo#>;A9u1pcXI%9 zIFNfdg!}k1_j4EzaySn$jfeRJWuj1p5oGS5my;unZ_9|=Q*z6c^=~h z{>qCy&PzPO%RIxYJj?4m$D90TtoQ}46!ky1BYP_#;O7?U`H_i`kwa8w?5R!n0xj@G}AW0=fw ztj_VQ!3nI%Nvy@mtj#H`!>LT+wA>G~t}tDr9%t|Y&SZVgW&_S)L(XL*&SMkKXHza< zGcM#KT+HTN$`)MCmR!k4nZZ_EmB)9+W5Q~U*34qpAEJVFd4kc;asyMDohR7*95=EX zH}iRJVRvrjdTuv=19$LC?$pobZhplaZsZ;YS3|*rnZt*7E|pp3{bPk<>^lbSGVfSC zD=Pm7em|YV$-zuc%-po3fBy6?Yfpy?_RMUyu1_d4Ys0aq%ySa)b_ytRGHA{01%QB1Qxt8~E9V>D@D{}+y<(I6= zY~IJOSe+YLlbdR|Jk}OAYuwMTS(jV*0Kegb+{%Zzjg7dSP53QsfrfXmIltqh+{xC) zcd?CnH=k60&-UsZ&U3Z;p+;u>p+QlRj^Q9Ws;1M3A*M3S?&e0br#gl&s$3%I#BjlyK7@C@xjQt{H41UMiFa})3p00b zt_bIP!J_;$9K_zmCF)}I-5kD~nd;)S#}-q9Us_+1n~ayDt+a3gx3M&Bp+%Re={sV# z1!Xn%YLw#v6Ux&TSvZkLcn^qO)gR#*;OikVv9YojS?dsYr936z~@GkZJENOlU6ZGq{ zEbB3m53nNZGl>tfs^c|ab@fB6WqqWfP)DN?>#{NHvk4!vpedWEA7(Q)V+%gQR^CW+ zK4D%9ws*jmd`kaOc2T!tSL2Vd8(Xu7^^dc+t*~$#p|8dh>~BI_4z}<~zO3Jl!}Qy8 zq<#mE@&Zrs4dWd-PXB4?Ugw`2&A<2t|K=F}!?FCA<9LN{(!aZe#`A_3ev7vpZvsOe5GOL4lNigl z8OOe$H>u`iYzM5AhrQpSg{P`7Mv|J09h(m`D)*MaZ$>821|Zl|S-05AXzk;z|C@ z-*|+l_zQpMuRP5Y{DZ$a-Wi_eS)S!Np68$Zo9B7SR#^Bi;R-L%c1HMb{>O_9VuSEM z4D%9W`7iVGGV}2YZ|7AO;x!iGbr$0dmf%e$@IRL2Ek+WB{|OZtxUoy}WD~_I46z!+ zOg0|Pnv7u`Pol9*F@7iOu`uhi2pg~{8}cqTW*Huj38KoXrYqwF;SP;SEX2vYlT%ojQ(1)5Sd`Ow7iX{-XYy{&W^vA83C?9n z&SNRgX95?nG#9eWO;^UnLRpQaEXU<6&y`GM2Jhi2R^Vz@WELxN9V>GKlbFqWxsg@4 znN_)k)wq@SaXXVE!VaN2cd`a|vnF#`i+fm``&ftjc|Q*_g@;&|hgpwD`2dfxK9BQ3 zo@4`_;zK;mNJHU_(1_>QnCIDq7ub{+`7kfB887n@US)G$XA9nBOWxw6404~V7~*4$ z&V8(6EFWiF?gL*NAztGN=3`qH;FB!Kb}Yp9%-tvGz@mJL#n_R>`7}$i6BF2(W!Qz~ z_zV--l@;;?;b&Rd17A2*sG{*4?_)RC;Pb4_?o6@p1=eE^)@M&PU@tagZ#HHhHsy-7!KoDj^H?s#vfUn`&p6)n81T9!=G4=hnUEpS%HUH ziAR{kqpT9=$>x_+>uJD}0Vu`8==j1zu-Q-e7Ou zS-pR)`zS(ab09M`Zs*D{goc@Mv21%Abf+{8-!nw9wtlemrd z@>^EncdW`?tQHZz7w+Q^Oy*uz=Z~zx1FXrPSc^ZiHjl6lf8qW7l_@;Iy8Mmx_&Xoq zAFR)_e2{-K(nk2pAJr4Q$hQ2KPx30;@dn%T7CSI1ZxDWp(d@`Pe46p>#Qf~cg6zUO z`3#G)EAQsBEScBNNUBg;<2jaNH{QeNS&7|wFJE9a_F#4PWG(jM{p`(p?8687A{(+V zoA4zzV?VZFf40i&`+tD&xW+)X4zQf2;VXCl#>CE6Xe!=&c#pztn_nFNZ+{6#Kg)_O0v$%t^xr-k%hjX}> zA8|kD@+W?rd;T95=4t%GPk5a3`5QmwX)fSde#Y}$$iKOWm$;Z$xP;fal>c!VJ@JH> zGt3o?DbUE#BSfE%#y^#2FmInH(uDs5GovzF diff --git a/CFUnicodeDecomposition.c b/CFUnicodeDecomposition.c new file mode 100644 index 0000000..f32f3db --- /dev/null +++ b/CFUnicodeDecomposition.c @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFUnicodeDecomposition.c + Copyright 1999-2002, Apple, Inc. All rights reserved. + Responsibility: Aki Inoue +*/ + +#include +#include +#include +#include +#include +#include "CFInternal.h" +#include "CFUniCharPriv.h" + +// Canonical Decomposition +static UTF32Char *__CFUniCharDecompositionTable = NULL; +static uint32_t __CFUniCharDecompositionTableLength = 0; +static UTF32Char *__CFUniCharMultipleDecompositionTable = NULL; + +static const uint8_t *__CFUniCharDecomposableBitmapForBMP = NULL; +static const uint8_t *__CFUniCharHFSPlusDecomposableBitmapForBMP = NULL; + +static CFSpinLock_t __CFUniCharDecompositionTableLock = CFSpinLockInit; + +static const uint8_t **__CFUniCharCombiningPriorityTable = NULL; +static uint8_t __CFUniCharCombiningPriorityTableNumPlane = 0; + +static void __CFUniCharLoadDecompositionTable(void) { + + __CFSpinLock(&__CFUniCharDecompositionTableLock); + + if (NULL == __CFUniCharDecompositionTable) { + const uint32_t *bytes = (uint32_t *)CFUniCharGetMappingData(kCFUniCharCanonicalDecompMapping); + + if (NULL == bytes) { + __CFSpinUnlock(&__CFUniCharDecompositionTableLock); + return; + } + + __CFUniCharDecompositionTableLength = *(bytes++); + __CFUniCharDecompositionTable = (UTF32Char *)bytes; + __CFUniCharMultipleDecompositionTable = (UTF32Char *)((intptr_t)bytes + __CFUniCharDecompositionTableLength); + + __CFUniCharDecompositionTableLength /= (sizeof(uint32_t) * 2); + __CFUniCharDecomposableBitmapForBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet, 0); + __CFUniCharHFSPlusDecomposableBitmapForBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharHFSPlusDecomposableCharacterSet, 0); + + CFIndex idx; + + __CFUniCharCombiningPriorityTableNumPlane = CFUniCharGetNumberOfPlanesForUnicodePropertyData(kCFUniCharCombiningProperty); + __CFUniCharCombiningPriorityTable = (const uint8_t **)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(uint8_t *) * __CFUniCharCombiningPriorityTableNumPlane, 0); + for (idx = 0;idx < __CFUniCharCombiningPriorityTableNumPlane;idx++) __CFUniCharCombiningPriorityTable[idx] = (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, idx); + } + + __CFSpinUnlock(&__CFUniCharDecompositionTableLock); +} + +static CFSpinLock_t __CFUniCharCompatibilityDecompositionTableLock = CFSpinLockInit; +static UTF32Char *__CFUniCharCompatibilityDecompositionTable = NULL; +static uint32_t __CFUniCharCompatibilityDecompositionTableLength = 0; +static UTF32Char *__CFUniCharCompatibilityMultipleDecompositionTable = NULL; + +static void __CFUniCharLoadCompatibilityDecompositionTable(void) { + + __CFSpinLock(&__CFUniCharCompatibilityDecompositionTableLock); + + if (NULL == __CFUniCharCompatibilityDecompositionTable) { + const uint32_t *bytes = (uint32_t *)CFUniCharGetMappingData(kCFUniCharCompatibilityDecompMapping); + + if (NULL == bytes) { + __CFSpinUnlock(&__CFUniCharCompatibilityDecompositionTableLock); + return; + } + + __CFUniCharCompatibilityDecompositionTableLength = *(bytes++); + __CFUniCharCompatibilityDecompositionTable = (UTF32Char *)bytes; + __CFUniCharCompatibilityMultipleDecompositionTable = (UTF32Char *)((intptr_t)bytes + __CFUniCharCompatibilityDecompositionTableLength); + + __CFUniCharCompatibilityDecompositionTableLength /= (sizeof(uint32_t) * 2); + } + + __CFSpinUnlock(&__CFUniCharCompatibilityDecompositionTableLock); +} + +CF_INLINE bool __CFUniCharIsDecomposableCharacterWithFlag(UTF32Char character, bool isHFSPlus) { + return CFUniCharIsMemberOfBitmap(character, (character < 0x10000 ? (isHFSPlus ? __CFUniCharHFSPlusDecomposableBitmapForBMP : __CFUniCharDecomposableBitmapForBMP) : CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet, ((character >> 16) & 0xFF)))); +} + +CF_INLINE uint8_t __CFUniCharGetCombiningPropertyForCharacter(UTF32Char character) { return CFUniCharGetCombiningPropertyForCharacter(character, (((character) >> 16) < __CFUniCharCombiningPriorityTableNumPlane ? __CFUniCharCombiningPriorityTable[(character) >> 16] : NULL)); } + +CF_INLINE bool __CFUniCharIsNonBaseCharacter(UTF32Char character) { return ((0 == __CFUniCharGetCombiningPropertyForCharacter(character)) ? false : true); } // the notion of non-base in normalization is characters with non-0 combining class + +typedef struct { + uint32_t _key; + uint32_t _value; +} __CFUniCharDecomposeMappings; + +static uint32_t __CFUniCharGetMappedValue(const __CFUniCharDecomposeMappings *theTable, uint32_t numElem, UTF32Char character) { + const __CFUniCharDecomposeMappings *p, *q, *divider; + + if ((character < theTable[0]._key) || (character > theTable[numElem-1]._key)) { + return 0; + } + p = theTable; + q = p + (numElem-1); + while (p <= q) { + divider = p + ((q - p) >> 1); /* divide by 2 */ + if (character < divider->_key) { q = divider - 1; } + else if (character > divider->_key) { p = divider + 1; } + else { return divider->_value; } + } + return 0; +} + +static void __CFUniCharPrioritySort(UTF32Char *characters, CFIndex length) { + UTF32Char *end = characters + length; + + while ((characters < end) && (0 == __CFUniCharGetCombiningPropertyForCharacter(*characters))) ++characters; + + if ((end - characters) > 1) { + uint32_t p1, p2; + UTF32Char *ch1, *ch2; + bool changes = true; + + do { + changes = false; + ch1 = characters; ch2 = characters + 1; + p2 = __CFUniCharGetCombiningPropertyForCharacter(*ch1); + while (ch2 < end) { + p1 = p2; p2 = __CFUniCharGetCombiningPropertyForCharacter(*ch2); + if (p1 > p2) { + UTF32Char tmp = *ch1; *ch1 = *ch2; *ch2 = tmp; + changes = true; + } + ++ch1; ++ch2; + } + } while (changes); + } +} + +static CFIndex __CFUniCharRecursivelyDecomposeCharacter(UTF32Char character, UTF32Char *convertedChars, CFIndex maxBufferLength) { + uint32_t value = __CFUniCharGetMappedValue((const __CFUniCharDecomposeMappings *)__CFUniCharDecompositionTable, __CFUniCharDecompositionTableLength, character); + CFIndex length = CFUniCharConvertFlagToCount(value); + UTF32Char firstChar = value & 0xFFFFFF; + UTF32Char *mappings = (length > 1 ? __CFUniCharMultipleDecompositionTable + firstChar : &firstChar); + CFIndex usedLength = 0; + + if (maxBufferLength < length) return 0; + + if (value & kCFUniCharRecursiveDecompositionFlag) { + usedLength = __CFUniCharRecursivelyDecomposeCharacter(*mappings, convertedChars, maxBufferLength - length); + + --length; // Decrement for the first char + if (!usedLength || usedLength + length > maxBufferLength) return 0; + ++mappings; + convertedChars += usedLength; + } + + usedLength += length; + + while (length--) *(convertedChars++) = *(mappings++); + + return usedLength; +} + +#define HANGUL_SBASE 0xAC00 +#define HANGUL_LBASE 0x1100 +#define HANGUL_VBASE 0x1161 +#define HANGUL_TBASE 0x11A7 +#define HANGUL_SCOUNT 11172 +#define HANGUL_LCOUNT 19 +#define HANGUL_VCOUNT 21 +#define HANGUL_TCOUNT 28 +#define HANGUL_NCOUNT (HANGUL_VCOUNT * HANGUL_TCOUNT) + +CFIndex CFUniCharDecomposeCharacter(UTF32Char character, UTF32Char *convertedChars, CFIndex maxBufferLength) { + if (NULL == __CFUniCharDecompositionTable) __CFUniCharLoadDecompositionTable(); + if (character >= HANGUL_SBASE && character <= (HANGUL_SBASE + HANGUL_SCOUNT)) { + CFIndex length; + + character -= HANGUL_SBASE; + + length = (character % HANGUL_TCOUNT ? 3 : 2); + + if (maxBufferLength < length) return 0; + + *(convertedChars++) = character / HANGUL_NCOUNT + HANGUL_LBASE; + *(convertedChars++) = (character % HANGUL_NCOUNT) / HANGUL_TCOUNT + HANGUL_VBASE; + if (length > 2) *convertedChars = (character % HANGUL_TCOUNT) + HANGUL_TBASE; + return length; + } else { + return __CFUniCharRecursivelyDecomposeCharacter(character, convertedChars, maxBufferLength); + } +} + +CF_INLINE bool __CFProcessReorderBuffer(UTF32Char *buffer, CFIndex length, void **dst, CFIndex dstLength, CFIndex *filledLength, uint32_t dstFormat) { + if (length > 1) __CFUniCharPrioritySort(buffer, length); + return CFUniCharFillDestinationBuffer(buffer, length, dst, dstLength, filledLength, dstFormat); +} + +#define MAX_BUFFER_LENGTH (32) +bool CFUniCharDecompose(const UTF16Char *src, CFIndex length, CFIndex *consumedLength, void *dst, CFIndex maxLength, CFIndex *filledLength, bool needToReorder, uint32_t dstFormat, bool isHFSPlus) { + CFIndex usedLength = 0; + CFIndex originalLength = length; + UTF32Char buffer[MAX_BUFFER_LENGTH]; + UTF32Char *decompBuffer = buffer; + CFIndex decompBufferSize = MAX_BUFFER_LENGTH; + CFIndex decompBufferLen = 0; + CFIndex segmentLength = 0; + UTF32Char currentChar; + + if (NULL == __CFUniCharDecompositionTable) __CFUniCharLoadDecompositionTable(); + + while ((length - segmentLength) > 0) { + currentChar = *(src++); + + if (currentChar < 0x80) { + if (decompBufferLen > 0) { + if (!__CFProcessReorderBuffer(decompBuffer, decompBufferLen, &dst, maxLength, &usedLength, dstFormat)) break; + length -= segmentLength; + segmentLength = 0; + decompBufferLen = 0; + } + + if (maxLength > 0) { + if (usedLength >= maxLength) break; + switch (dstFormat) { + case kCFUniCharUTF8Format: *(uint8_t *)dst = currentChar; dst = (uint8_t *)dst + sizeof(uint8_t); break; + case kCFUniCharUTF16Format: *(UTF16Char *)dst = currentChar; dst = (uint8_t *)dst + sizeof(UTF16Char); break; + case kCFUniCharUTF32Format: *(UTF32Char *)dst = currentChar; dst = (uint8_t *)dst + sizeof(UTF32Char); break; + } + } + + --length; + ++usedLength; + } else { + if (CFUniCharIsSurrogateLowCharacter(currentChar)) { // Stray surrogagte + if (dstFormat != kCFUniCharUTF16Format) break; + } else if (CFUniCharIsSurrogateHighCharacter(currentChar)) { + if (((length - segmentLength) > 1) && CFUniCharIsSurrogateLowCharacter(*src)) { + currentChar = CFUniCharGetLongCharacterForSurrogatePair(currentChar, *(src++)); + } else { + if (dstFormat != kCFUniCharUTF16Format) break; + } + } + + if (needToReorder && __CFUniCharIsNonBaseCharacter(currentChar)) { + if ((decompBufferLen + 1) >= decompBufferSize) { + UTF32Char *newBuffer; + + decompBufferSize += MAX_BUFFER_LENGTH; + newBuffer = (UTF32Char *)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(UTF32Char) * decompBufferSize, 0); + memmove(newBuffer, decompBuffer, (decompBufferSize - MAX_BUFFER_LENGTH) * sizeof(UTF32Char)); + if (decompBuffer != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, decompBuffer); + decompBuffer = newBuffer; + } + + if (__CFUniCharIsDecomposableCharacterWithFlag(currentChar, isHFSPlus)) { // Vietnamese accent, etc. + decompBufferLen += CFUniCharDecomposeCharacter(currentChar, decompBuffer + decompBufferLen, decompBufferSize - decompBufferLen); + } else { + decompBuffer[decompBufferLen++] = currentChar; + } + } else { + if (decompBufferLen > 0) { + if (!__CFProcessReorderBuffer(decompBuffer, decompBufferLen, &dst, maxLength, &usedLength, dstFormat)) break; + length -= segmentLength; + segmentLength = 0; + } + + if (__CFUniCharIsDecomposableCharacterWithFlag(currentChar, isHFSPlus)) { + decompBufferLen = CFUniCharDecomposeCharacter(currentChar, decompBuffer, MAX_BUFFER_LENGTH); + } else { + decompBufferLen = 1; + *decompBuffer = currentChar; + } + + if (!needToReorder || (decompBufferLen == 1)) { + if (!CFUniCharFillDestinationBuffer(decompBuffer, decompBufferLen, &dst, maxLength, &usedLength, dstFormat)) break; + length -= ((currentChar > 0xFFFF) ? 2 : 1); + decompBufferLen = 0; + continue; + } + } + + segmentLength += ((currentChar > 0xFFFF) ? 2 : 1); + } + } + + if ((decompBufferLen > 0) && __CFProcessReorderBuffer(decompBuffer, decompBufferLen, &dst, maxLength, &usedLength, dstFormat)) length -= segmentLength; + + if (decompBuffer != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, decompBuffer); + + if (consumedLength) *consumedLength = originalLength - length; + if (filledLength) *filledLength = usedLength; + + return ((length > 0) ? false : true); +} + +#define MAX_COMP_DECOMP_LEN (32) + +static CFIndex __CFUniCharRecursivelyCompatibilityDecomposeCharacter(UTF32Char character, UTF32Char *convertedChars) { + uint32_t value = __CFUniCharGetMappedValue((const __CFUniCharDecomposeMappings *)__CFUniCharCompatibilityDecompositionTable, __CFUniCharCompatibilityDecompositionTableLength, character); + CFIndex length = CFUniCharConvertFlagToCount(value); + UTF32Char firstChar = value & 0xFFFFFF; + const UTF32Char *mappings = (length > 1 ? __CFUniCharCompatibilityMultipleDecompositionTable + firstChar : &firstChar); + CFIndex usedLength = length; + UTF32Char currentChar; + CFIndex currentLength; + + while (length-- > 0) { + currentChar = *(mappings++); + if (__CFUniCharIsDecomposableCharacterWithFlag(currentChar, false)) { + currentLength = __CFUniCharRecursivelyDecomposeCharacter(currentChar, convertedChars, MAX_COMP_DECOMP_LEN - length); + convertedChars += currentLength; + usedLength += (currentLength - 1); + } else if (CFUniCharIsMemberOf(currentChar, kCFUniCharCompatibilityDecomposableCharacterSet)) { + currentLength = __CFUniCharRecursivelyCompatibilityDecomposeCharacter(currentChar, convertedChars); + convertedChars += currentLength; + usedLength += (currentLength - 1); + } else { + *(convertedChars++) = currentChar; + } + } + + return usedLength; +} + +CF_INLINE void __CFUniCharMoveBufferFromEnd1(UTF32Char *convertedChars, CFIndex length, CFIndex delta) { + const UTF32Char *limit = convertedChars; + UTF32Char *dstP; + + convertedChars += length; + dstP = convertedChars + delta; + + while (convertedChars > limit) *(--dstP) = *(--convertedChars); +} + +__private_extern__ CFIndex CFUniCharCompatibilityDecompose(UTF32Char *convertedChars, CFIndex length, CFIndex maxBufferLength) { + UTF32Char currentChar; + UTF32Char buffer[MAX_COMP_DECOMP_LEN]; + const UTF32Char *bufferP; + const UTF32Char *limit = convertedChars + length; + CFIndex filledLength; + + if (NULL == __CFUniCharCompatibilityDecompositionTable) __CFUniCharLoadCompatibilityDecompositionTable(); + + while (convertedChars < limit) { + currentChar = *convertedChars; + + if (CFUniCharIsMemberOf(currentChar, kCFUniCharCompatibilityDecomposableCharacterSet)) { + filledLength = __CFUniCharRecursivelyCompatibilityDecomposeCharacter(currentChar, buffer); + + if (filledLength + length - 1 > maxBufferLength) return 0; + + if (filledLength > 1) __CFUniCharMoveBufferFromEnd1(convertedChars + 1, limit - convertedChars - 1, filledLength - 1); + + bufferP = buffer; + length += (filledLength - 1); + while (filledLength-- > 0) *(convertedChars++) = *(bufferP++); + } else { + ++convertedChars; + } + } + + return length; +} + +CF_EXPORT void CFUniCharPrioritySort(UTF32Char *characters, CFIndex length) { + __CFUniCharPrioritySort(characters, length); +} + +#undef MAX_BUFFER_LENGTH +#undef MAX_COMP_DECOMP_LEN +#undef HANGUL_SBASE +#undef HANGUL_LBASE +#undef HANGUL_VBASE +#undef HANGUL_TBASE +#undef HANGUL_SCOUNT +#undef HANGUL_LCOUNT +#undef HANGUL_VCOUNT +#undef HANGUL_TCOUNT +#undef HANGUL_NCOUNT + diff --git a/StringEncodings.subproj/CFUnicodeDecomposition.h b/CFUnicodeDecomposition.h similarity index 67% rename from StringEncodings.subproj/CFUnicodeDecomposition.h rename to CFUnicodeDecomposition.h index 442a58e..7846344 100644 --- a/StringEncodings.subproj/CFUnicodeDecomposition.h +++ b/CFUnicodeDecomposition.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -25,7 +25,7 @@ * CoreFoundation * * Created by aki on Wed Oct 03 2001. - * Copyright (c) 2001-2005, Apple Inc. All rights reserved. + * Copyright (c) 2001-2007, Apple Inc. All rights reserved. * */ @@ -34,9 +34,7 @@ #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN CF_INLINE bool CFUniCharIsDecomposableCharacter(UTF32Char character, bool isHFSPlusCanonical) { if (isHFSPlusCanonical && !isHFSPlusCanonical) return false; // hack to get rid of "unused" warning @@ -44,16 +42,14 @@ CF_INLINE bool CFUniCharIsDecomposableCharacter(UTF32Char character, bool isHFSP return CFUniCharIsMemberOf(character, kCFUniCharHFSPlusDecomposableCharacterSet); } -CF_EXPORT uint32_t CFUniCharDecomposeCharacter(UTF32Char character, UTF32Char *convertedChars, uint32_t maxBufferLength); -CF_EXPORT uint32_t CFUniCharCompatibilityDecompose(UTF32Char *convertedChars, uint32_t length, uint32_t maxBufferLength); +CF_EXPORT CFIndex CFUniCharDecomposeCharacter(UTF32Char character, UTF32Char *convertedChars, CFIndex maxBufferLength); +CF_EXPORT CFIndex CFUniCharCompatibilityDecompose(UTF32Char *convertedChars, CFIndex length, CFIndex maxBufferLength); -CF_EXPORT bool CFUniCharDecompose(const UTF16Char *src, uint32_t length, uint32_t *consumedLength, void *dst, uint32_t maxLength, uint32_t *filledLength, bool needToReorder, uint32_t dstFormat, bool isHFSPlus); +CF_EXPORT bool CFUniCharDecompose(const UTF16Char *src, CFIndex length, CFIndex *consumedLength, void *dst, CFIndex maxLength, CFIndex *filledLength, bool needToReorder, uint32_t dstFormat, bool isHFSPlus); -CF_EXPORT void CFUniCharPrioritySort(UTF32Char *characters, uint32_t length); +CF_EXPORT void CFUniCharPrioritySort(UTF32Char *characters, CFIndex length); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFUNICODEDECOMPOSITION__ */ diff --git a/StringEncodings.subproj/CFUnicodePrecomposition.c b/CFUnicodePrecomposition.c similarity index 89% rename from StringEncodings.subproj/CFUnicodePrecomposition.c rename to CFUnicodePrecomposition.c index c2cc29f..9dac3e3 100644 --- a/StringEncodings.subproj/CFUnicodePrecomposition.c +++ b/CFUnicodePrecomposition.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -42,14 +42,14 @@ static uint32_t *__CFUniCharNonBMPPrecompDestinationTable = NULL; static const uint8_t *__CFUniCharNonBaseBitmapForBMP_P = NULL; // Adding _P so the symbol name is different from the one in CFUnicodeDecomposition.c static const uint8_t *__CFUniCharCombiningClassForBMP = NULL; -static CFSpinLock_t __CFUniCharPrecompositionTableLock = 0; +static CFSpinLock_t __CFUniCharPrecompositionTableLock = CFSpinLockInit; static void __CFUniCharLoadPrecompositionTable(void) { __CFSpinLock(&__CFUniCharPrecompositionTableLock); if (NULL == __CFUniCharPrecompSourceTable) { - const void *bytes = CFUniCharGetMappingData(kCFUniCharCanonicalPrecompMapping); + const uint32_t *bytes = (const uint32_t *)CFUniCharGetMappingData(kCFUniCharCanonicalPrecompMapping); uint32_t bmpMappingLength; if (NULL == bytes) { @@ -57,14 +57,14 @@ static void __CFUniCharLoadPrecompositionTable(void) { return; } - __CFUniCharPrecompositionTableLength = *(((uint32_t *)bytes)++); - bmpMappingLength = *(((uint32_t *)bytes)++); + __CFUniCharPrecompositionTableLength = *(bytes++); + bmpMappingLength = *(bytes++); __CFUniCharPrecompSourceTable = (UTF32Char *)bytes; __CFUniCharBMPPrecompDestinationTable = (uint16_t *)((intptr_t)bytes + (__CFUniCharPrecompositionTableLength * sizeof(UTF32Char) * 2)); __CFUniCharNonBMPPrecompDestinationTable = (uint32_t *)(((intptr_t)__CFUniCharBMPPrecompDestinationTable) + bmpMappingLength); __CFUniCharNonBaseBitmapForBMP_P = CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, 0); - __CFUniCharCombiningClassForBMP = CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, 0); + __CFUniCharCombiningClassForBMP = (const uint8_t *)CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, 0); } __CFSpinUnlock(&__CFUniCharPrecompositionTableLock); @@ -147,7 +147,7 @@ UTF32Char CFUniCharPrecomposeCharacter(UTF32Char base, UTF32Char combining) { #define HANGUL_TCOUNT 28 #define HANGUL_NCOUNT (HANGUL_VCOUNT * HANGUL_TCOUNT) -CF_INLINE void __CFUniCharMoveBufferFromEnd(UTF16Char *convertedChars, uint32_t length, uint32_t delta) { +CF_INLINE void __CFUniCharMoveBufferFromEnd0(UTF16Char *convertedChars, CFIndex length, CFIndex delta) { const UTF16Char *limit = convertedChars; UTF16Char *dstP; @@ -157,9 +157,9 @@ CF_INLINE void __CFUniCharMoveBufferFromEnd(UTF16Char *convertedChars, uint32_t while (convertedChars > limit) *(--dstP) = *(--convertedChars); } -bool CFUniCharPrecompose(const UTF16Char *characters, uint32_t length, uint32_t *consumedLength, UTF16Char *precomposed, uint32_t maxLength, uint32_t *filledLength) { +bool CFUniCharPrecompose(const UTF16Char *characters, CFIndex length, CFIndex *consumedLength, UTF16Char *precomposed, CFIndex maxLength, CFIndex *filledLength) { UTF32Char currentChar = 0, lastChar = 0, precomposedChar = 0xFFFD; - uint32_t originalLength = length, usedLength = 0; + CFIndex originalLength = length, usedLength = 0; UTF16Char *currentBase = precomposed; uint8_t currentClass, lastClass = 0; bool currentBaseIsBMP = true; @@ -182,12 +182,11 @@ bool CFUniCharPrecompose(const UTF16Char *characters, uint32_t length, uint32_t currentClass = (currentChar > 0xFFFF ? CFUniCharGetUnicodeProperty(currentChar, kCFUniCharCombiningProperty) : CFUniCharGetCombiningPropertyForCharacter(currentChar, __CFUniCharCombiningClassForBMP)); - if ((lastClass == 0) || (currentClass != lastClass)) { + if ((lastClass == 0) || (currentClass > lastClass)) { if ((precomposedChar = CFUniCharPrecomposeCharacter(lastChar, currentChar)) == 0xFFFD) { if (isPrecomposed) precomposedChar = lastChar; lastClass = currentClass; } else { - lastClass = 0; continue; } } @@ -238,7 +237,7 @@ bool CFUniCharPrecompose(const UTF16Char *characters, uint32_t length, uint32_t if (lastChar < 0x10000) { // Last char was BMP ++usedLength; if (usedLength > maxLength) break; - __CFUniCharMoveBufferFromEnd(currentBase + 1, precomposed - (currentBase + 1), 1); + __CFUniCharMoveBufferFromEnd0(currentBase + 1, precomposed - (currentBase + 1), 1); } precomposedChar -= 0x10000; *currentBase = (UTF16Char)((precomposedChar >> 10) + 0xD800UL); @@ -276,7 +275,7 @@ bool CFUniCharPrecompose(const UTF16Char *characters, uint32_t length, uint32_t if (filledLength) *filledLength = usedLength; return false; } - __CFUniCharMoveBufferFromEnd(currentBase + 1, precomposed - (currentBase + 1), 1); + __CFUniCharMoveBufferFromEnd0(currentBase + 1, precomposed - (currentBase + 1), 1); } precomposedChar -= 0x10000; *currentBase = (UTF16Char)((precomposedChar >> 10) + 0xD800UL); @@ -296,3 +295,14 @@ bool CFUniCharPrecompose(const UTF16Char *characters, uint32_t length, uint32_t return true; } +#undef __CFUniCharIsNonBaseCharacter +#undef HANGUL_SBASE +#undef HANGUL_LBASE +#undef HANGUL_VBASE +#undef HANGUL_TBASE +#undef HANGUL_SCOUNT +#undef HANGUL_LCOUNT +#undef HANGUL_VCOUNT +#undef HANGUL_TCOUNT +#undef HANGUL_NCOUNT + diff --git a/StringEncodings.subproj/CFUnicodePrecomposition.h b/CFUnicodePrecomposition.h similarity index 78% rename from StringEncodings.subproj/CFUnicodePrecomposition.h rename to CFUnicodePrecomposition.h index 4882dc4..efa0428 100644 --- a/StringEncodings.subproj/CFUnicodePrecomposition.h +++ b/CFUnicodePrecomposition.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -25,7 +25,7 @@ * CoreFoundation * * Created by aki on Wed Oct 03 2001. - * Copyright (c) 2001-2005, Apple Inc. All rights reserved. + * Copyright (c) 2001-2007, Apple Inc. All rights reserved. * */ @@ -34,18 +34,14 @@ #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN // As you can see, this function cannot precompose Hangul Jamo CF_EXPORT UTF32Char CFUniCharPrecomposeCharacter(UTF32Char base, UTF32Char combining); -CF_EXPORT bool CFUniCharPrecompose(const UTF16Char *characters, uint32_t length, uint32_t *consumedLength, UTF16Char *precomposed, uint32_t maxLength, uint32_t *filledLength); +CF_EXPORT bool CFUniCharPrecompose(const UTF16Char *characters, CFIndex length, CFIndex *consumedLength, UTF16Char *precomposed, CFIndex maxLength, CFIndex *filledLength); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END -#endif /* ! __COREFOUNDATION_CFUNICODEDECOMPOSITION__ */ +#endif /* ! __COREFOUNDATION_CFUNICODEPRECOMPOSITION__ */ diff --git a/AppServices.subproj/CFUserNotification.c b/CFUserNotification.c similarity index 81% rename from AppServices.subproj/CFUserNotification.c rename to CFUserNotification.c index e915640..68f86c3 100644 --- a/AppServices.subproj/CFUserNotification.c +++ b/CFUserNotification.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,20 +21,28 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFUserNotification.c - Copyright 2000-2002, Apple, Inc. All rights reserved. + Copyright (c) 2000-2007 Apple Inc. All rights reserved. Responsibility: Doug Davidson */ #include #include #include -#include #include #include "CFInternal.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#define __kCFLogUserNotification 20 -#define CFUserNotificationLog(alertHeader, alertMessage) CFLog(__kCFLogUserNotification, CFSTR("%@: %@"), alertHeader, alertMessage); +#define CFUserNotificationLog(alertHeader, alertMessage) CFLog(3, CFSTR("%@: %@"), alertHeader, alertMessage); enum { kCFUserNotificationCancelFlag = (1 << 3), @@ -65,6 +73,7 @@ CONST_STRING_DECL(kCFUserNotificationTextFieldTitlesKey, "TextFieldTitles") CONST_STRING_DECL(kCFUserNotificationCheckBoxTitlesKey, "CheckBoxTitles") CONST_STRING_DECL(kCFUserNotificationTextFieldValuesKey, "TextFieldValues") CONST_STRING_DECL(kCFUserNotificationPopUpSelectionKey, "PopUpSelection") +CONST_STRING_DECL(kCFUserNotificationKeyboardTypesKey, "KeyboardTypes") static CFTypeID __kCFUserNotificationTypeID = _kCFRuntimeNotATypeID; @@ -77,39 +86,30 @@ struct __CFUserNotification { CFOptionFlags _responseFlags; CFStringRef _sessionID; CFDictionaryRef _responseDictionary; -#if defined(__MACH__) CFMachPortRef _machPort; -#endif CFUserNotificationCallBack _callout; }; static CFStringRef __CFUserNotificationCopyDescription(CFTypeRef cf) { CFMutableStringRef result; result = CFStringCreateMutable(CFGetAllocator(cf), 0); - CFStringAppendFormat(result, NULL, CFSTR(""), (UInt32)cf); + CFStringAppendFormat(result, NULL, CFSTR(""), cf); return result; } -#if defined(__MACH__) - -#include -#include -#include -#include -#include -#include -#include -#include - #define MAX_STRING_LENGTH PATH_MAX #define MAX_STRING_COUNT 16 #define MAX_PORT_NAME_LENGTH 63 -#define NOTIFICATION_PORT_NAME "com.apple.UNCUserNotification" -#define NOTIFICATION_PORT_NAME_OLD "UNCUserNotification" #define NOTIFICATION_PORT_NAME_SUFFIX ".session." #define MESSAGE_TIMEOUT 100 +#if DEPLOYMENT_TARGET_MACOSX +#define NOTIFICATION_PORT_NAME "com.apple.UNCUserNotification" +#elif 0 +#define NOTIFICATION_PORT_NAME "com.apple.SBUserNotification" +#else +#error Unknown or unspecified DEPLOYMENT_TARGET +#endif -#endif /* __MACH__ */ static void __CFUserNotificationDeallocate(CFTypeRef cf); @@ -130,11 +130,10 @@ __private_extern__ void __CFUserNotificationInitialize(void) { } CFTypeID CFUserNotificationGetTypeID(void) { + if (_kCFRuntimeNotATypeID == __kCFUserNotificationTypeID) __CFUserNotificationInitialize(); return __kCFUserNotificationTypeID; } -#if defined(__MACH__) - static void __CFUserNotificationDeallocate(CFTypeRef cf) { CFUserNotificationRef userNotification = (CFUserNotificationRef)cf; if (userNotification->_machPort) { @@ -206,26 +205,19 @@ static SInt32 _CFUserNotificationSendRequest(CFAllocatorRef allocator, CFStringR mach_msg_base_t *msg = NULL; mach_port_t bootstrapPort = MACH_PORT_NULL, serverPort = MACH_PORT_NULL; CFIndex size; - char namebuffer[MAX_PORT_NAME_LENGTH + 1], oldnamebuffer[MAX_PORT_NAME_LENGTH + 1]; - size_t namelen; - - strcpy(namebuffer, NOTIFICATION_PORT_NAME); - strcpy(oldnamebuffer, NOTIFICATION_PORT_NAME_OLD); + char namebuffer[MAX_PORT_NAME_LENGTH + 1]; + strlcpy(namebuffer, NOTIFICATION_PORT_NAME, sizeof(namebuffer)); if (sessionID) { - strcat(namebuffer, NOTIFICATION_PORT_NAME_SUFFIX); - namelen = strlen(namebuffer); - CFStringGetBytes(sessionID, CFRangeMake(0, CFStringGetLength(sessionID)), kCFStringEncodingUTF8, 0, false, namebuffer + namelen, MAX_PORT_NAME_LENGTH - namelen, &size); - namebuffer[namelen + size] = '\0'; - - strcat(oldnamebuffer, NOTIFICATION_PORT_NAME_SUFFIX); - namelen = strlen(oldnamebuffer); - CFStringGetBytes(sessionID, CFRangeMake(0, CFStringGetLength(sessionID)), kCFStringEncodingUTF8, 0, false, oldnamebuffer + namelen, MAX_PORT_NAME_LENGTH - namelen, &size); - oldnamebuffer[namelen + size] = '\0'; + char sessionid[MAX_PORT_NAME_LENGTH + 1]; + CFIndex len = MAX_PORT_NAME_LENGTH - sizeof(NOTIFICATION_PORT_NAME) - sizeof(NOTIFICATION_PORT_NAME_SUFFIX); + CFStringGetBytes(sessionID, CFRangeMake(0, CFStringGetLength(sessionID)), kCFStringEncodingUTF8, 0, false, (uint8_t *)sessionid, len, &size); + sessionid[len - 1] = '\0'; + strlcat(namebuffer, NOTIFICATION_PORT_NAME_SUFFIX, sizeof(namebuffer)); + strlcat(namebuffer, sessionid, sizeof(namebuffer)); } retval = task_get_bootstrap_port(mach_task_self(), &bootstrapPort); - if (ERR_SUCCESS == retval && MACH_PORT_NULL != bootstrapPort) retval = bootstrap_look_up(bootstrapPort, namebuffer, &serverPort); - if (ERR_SUCCESS != retval || MACH_PORT_NULL == serverPort) retval = bootstrap_look_up(bootstrapPort, oldnamebuffer, &serverPort); + if (ERR_SUCCESS == retval && MACH_PORT_NULL != bootstrapPort) retval = bootstrap_look_up2(bootstrapPort, namebuffer, &serverPort, 0, 0); if (ERR_SUCCESS == retval && MACH_PORT_NULL != serverPort) { modifiedDictionary = _CFUserNotificationModifiedDictionary(allocator, dictionary, token, itimeout, _CFProcessNameString()); if (modifiedDictionary) { @@ -243,7 +235,7 @@ static SInt32 _CFUserNotificationSendRequest(CFAllocatorRef allocator, CFStringR msg->header.msgh_id = flags; msg->body.msgh_descriptor_count = 0; CFDataGetBytes(data, CFRangeMake(0, CFDataGetLength(data)), (uint8_t *)msg + sizeof(mach_msg_base_t)); - //CFShow(CFStringCreateWithBytes(NULL, (UInt8 *)msg + sizeof(mach_msg_base_t), CFDataGetLength(data), kCFStringEncodingUTF8, false)); + //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); } else { @@ -262,6 +254,7 @@ static SInt32 _CFUserNotificationSendRequest(CFAllocatorRef allocator, CFStringR } CFUserNotificationRef CFUserNotificationCreate(CFAllocatorRef allocator, CFTimeInterval timeout, CFOptionFlags flags, SInt32 *error, CFDictionaryRef dictionary) { + CHECK_FOR_FORK(); CFUserNotificationRef userNotification = NULL; SInt32 retval = ERR_SUCCESS; static uint16_t tokenCounter = 0; @@ -274,7 +267,7 @@ CFUserNotificationRef CFUserNotificationCreate(CFAllocatorRef allocator, CFTimeI retval = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &replyPort); if (ERR_SUCCESS == retval && MACH_PORT_NULL != replyPort) retval = _CFUserNotificationSendRequest(allocator, sessionID, replyPort, token, timeout, flags, dictionary); if (ERR_SUCCESS == retval) { - userNotification = (CFUserNotificationRef)_CFRuntimeCreateInstance(allocator, __kCFUserNotificationTypeID, sizeof(struct __CFUserNotification) - sizeof(CFRuntimeBase), NULL); + userNotification = (CFUserNotificationRef)_CFRuntimeCreateInstance(allocator, CFUserNotificationGetTypeID(), sizeof(struct __CFUserNotification) - sizeof(CFRuntimeBase), NULL); if (userNotification) { userNotification->_replyPort = replyPort; userNotification->_token = token; @@ -302,9 +295,9 @@ static void _CFUserNotificationMachPortCallBack(CFMachPortRef port, void *m, CFI mach_msg_base_t *msg = (mach_msg_base_t *)m; CFOptionFlags responseFlags = msg->header.msgh_id; if (msg->header.msgh_size > sizeof(mach_msg_base_t)) { - CFDataRef responseData = CFDataCreate(NULL, (uint8_t *)msg + sizeof(mach_msg_base_t), msg->header.msgh_size - sizeof(mach_msg_base_t)); + CFDataRef responseData = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)msg + sizeof(mach_msg_base_t), msg->header.msgh_size - sizeof(mach_msg_base_t)); if (responseData) { - userNotification->_responseDictionary = CFPropertyListCreateFromXMLData(NULL, responseData, kCFPropertyListImmutable, NULL); + userNotification->_responseDictionary = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, responseData, kCFPropertyListImmutable, NULL); CFRelease(responseData); } } @@ -317,6 +310,7 @@ static void _CFUserNotificationMachPortCallBack(CFMachPortRef port, void *m, CFI } SInt32 CFUserNotificationReceiveResponse(CFUserNotificationRef userNotification, CFTimeInterval timeout, CFOptionFlags *responseFlags) { + CHECK_FOR_FORK(); SInt32 retval = ERR_SUCCESS; mach_msg_timeout_t msgtime = (timeout > 0.0 && 1000.0 * timeout < INT_MAX) ? (mach_msg_timeout_t)(1000.0 * timeout) : 0; mach_msg_base_t *msg = NULL; @@ -337,9 +331,9 @@ SInt32 CFUserNotificationReceiveResponse(CFUserNotificationRef userNotification, if (ERR_SUCCESS == retval) { if (responseFlags) *responseFlags = msg->header.msgh_id; if (msg->header.msgh_size > sizeof(mach_msg_base_t)) { - responseData = CFDataCreate(NULL, (uint8_t *)msg + sizeof(mach_msg_base_t), msg->header.msgh_size - sizeof(mach_msg_base_t)); + responseData = CFDataCreate(kCFAllocatorSystemDefault, (uint8_t *)msg + sizeof(mach_msg_base_t), msg->header.msgh_size - sizeof(mach_msg_base_t)); if (responseData) { - userNotification->_responseDictionary = CFPropertyListCreateFromXMLData(NULL, responseData, kCFPropertyListImmutable, NULL); + userNotification->_responseDictionary = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, responseData, kCFPropertyListImmutable, NULL); CFRelease(responseData); } } @@ -360,6 +354,7 @@ SInt32 CFUserNotificationReceiveResponse(CFUserNotificationRef userNotification, } CFStringRef CFUserNotificationGetResponseValue(CFUserNotificationRef userNotification, CFStringRef key, CFIndex idx) { + CHECK_FOR_FORK(); CFStringRef retval = NULL; CFTypeRef value = NULL; if (userNotification && userNotification->_responseDictionary) { @@ -378,10 +373,12 @@ CFStringRef CFUserNotificationGetResponseValue(CFUserNotificationRef userNotific } CFDictionaryRef CFUserNotificationGetResponseDictionary(CFUserNotificationRef userNotification) { + CHECK_FOR_FORK(); return userNotification ? userNotification->_responseDictionary : NULL; } SInt32 CFUserNotificationUpdate(CFUserNotificationRef userNotification, CFTimeInterval timeout, CFOptionFlags flags, CFDictionaryRef dictionary) { + CHECK_FOR_FORK(); SInt32 retval = ERR_SUCCESS; if (userNotification && MACH_PORT_NULL != userNotification->_replyPort) { retval = _CFUserNotificationSendRequest(CFGetAllocator(userNotification), userNotification->_sessionID, userNotification->_replyPort, userNotification->_token, timeout, flags|kCFUserNotificationUpdateFlag, dictionary); @@ -390,6 +387,7 @@ SInt32 CFUserNotificationUpdate(CFUserNotificationRef userNotification, CFTimeIn } SInt32 CFUserNotificationCancel(CFUserNotificationRef userNotification) { + CHECK_FOR_FORK(); SInt32 retval = ERR_SUCCESS; if (userNotification && MACH_PORT_NULL != userNotification->_replyPort) { retval = _CFUserNotificationSendRequest(CFGetAllocator(userNotification), userNotification->_sessionID, userNotification->_replyPort, userNotification->_token, 0, kCFUserNotificationCancelFlag, NULL); @@ -398,6 +396,7 @@ SInt32 CFUserNotificationCancel(CFUserNotificationRef userNotification) { } CFRunLoopSourceRef CFUserNotificationCreateRunLoopSource(CFAllocatorRef allocator, CFUserNotificationRef userNotification, CFUserNotificationCallBack callout, CFIndex order) { + CHECK_FOR_FORK(); CFRunLoopSourceRef source = NULL; if (userNotification && callout && !userNotification->_machPort && MACH_PORT_NULL != userNotification->_replyPort) { CFMachPortContext context = {0, userNotification, NULL, NULL, NULL}; @@ -411,25 +410,28 @@ CFRunLoopSourceRef CFUserNotificationCreateRunLoopSource(CFAllocatorRef allocato } SInt32 CFUserNotificationDisplayNotice(CFTimeInterval timeout, CFOptionFlags flags, CFURLRef iconURL, CFURLRef soundURL, CFURLRef localizationURL, CFStringRef alertHeader, CFStringRef alertMessage, CFStringRef defaultButtonTitle) { + CHECK_FOR_FORK(); CFUserNotificationRef userNotification; SInt32 retval = ERR_SUCCESS; - CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (iconURL) CFDictionaryAddValue(dict, kCFUserNotificationIconURLKey, iconURL); if (soundURL) CFDictionaryAddValue(dict, kCFUserNotificationSoundURLKey, soundURL); if (localizationURL) CFDictionaryAddValue(dict, kCFUserNotificationLocalizationURLKey, localizationURL); if (alertHeader) CFDictionaryAddValue(dict, kCFUserNotificationAlertHeaderKey, alertHeader); if (alertMessage) CFDictionaryAddValue(dict, kCFUserNotificationAlertMessageKey, alertMessage); if (defaultButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey, defaultButtonTitle); - userNotification = CFUserNotificationCreate(NULL, timeout, flags, &retval, dict); + userNotification = CFUserNotificationCreate(kCFAllocatorSystemDefault, timeout, flags, &retval, dict); if (userNotification) CFRelease(userNotification); CFRelease(dict); return retval; } + CF_EXPORT SInt32 CFUserNotificationDisplayAlert(CFTimeInterval timeout, CFOptionFlags flags, CFURLRef iconURL, CFURLRef soundURL, CFURLRef localizationURL, CFStringRef alertHeader, CFStringRef alertMessage, CFStringRef defaultButtonTitle, CFStringRef alternateButtonTitle, CFStringRef otherButtonTitle, CFOptionFlags *responseFlags) { + CHECK_FOR_FORK(); CFUserNotificationRef userNotification; SInt32 retval = ERR_SUCCESS; - CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); + CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (iconURL) CFDictionaryAddValue(dict, kCFUserNotificationIconURLKey, iconURL); if (soundURL) CFDictionaryAddValue(dict, kCFUserNotificationSoundURLKey, soundURL); if (localizationURL) CFDictionaryAddValue(dict, kCFUserNotificationLocalizationURLKey, localizationURL); @@ -438,7 +440,7 @@ CF_EXPORT SInt32 CFUserNotificationDisplayAlert(CFTimeInterval timeout, CFOption if (defaultButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationDefaultButtonTitleKey, defaultButtonTitle); if (alternateButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationAlternateButtonTitleKey, alternateButtonTitle); if (otherButtonTitle) CFDictionaryAddValue(dict, kCFUserNotificationOtherButtonTitleKey, otherButtonTitle); - userNotification = CFUserNotificationCreate(NULL, timeout, flags, &retval, dict); + userNotification = CFUserNotificationCreate(kCFAllocatorSystemDefault, timeout, flags, &retval, dict); if (userNotification) { retval = CFUserNotificationReceiveResponse(userNotification, timeout, responseFlags); if (MACH_RCV_TIMED_OUT == retval) { @@ -451,55 +453,10 @@ CF_EXPORT SInt32 CFUserNotificationDisplayAlert(CFTimeInterval timeout, CFOption return retval; } -#else /* __MACH__ */ - -#warning CFUserNotification functions not fully implemented - -void __CFUserNotificationDeallocate(CFTypeRef cf) { -} - -CFUserNotificationRef CFUserNotificationCreate(CFAllocatorRef allocator, CFTimeInterval timeout, CFOptionFlags flags, SInt32 *error, CFDictionaryRef dictionary) { - CFUserNotificationLog(CFDictionaryGetValue(dictionary, kCFUserNotificationAlertHeaderKey), CFDictionaryGetValue(dictionary, kCFUserNotificationAlertMessageKey)); - return NULL; -} - -SInt32 CFUserNotificationReceiveResponse(CFUserNotificationRef userNotification, CFTimeInterval timeout, CFOptionFlags *responseFlags) { - return -1; -} - -CFDictionaryRef CFUserNotificationCopyResponseDictionary(CFUserNotificationRef userNotification) { - return NULL; -} - -SInt32 CFUserNotificationUpdate(CFUserNotificationRef userNotification, CFTimeInterval timeout, CFOptionFlags flags, CFDictionaryRef dictionary) { - return -1; -} - -SInt32 CFUserNotificationCancel(CFUserNotificationRef userNotification) { - return -1; -} - -CFRunLoopSourceRef CFUserNotificationCreateRunLoopSource(CFAllocatorRef allocator, CFUserNotificationRef userNotification, CFUserNotificationCallBack callout, CFIndex order) { - return NULL; -} - -SInt32 CFUserNotificationDisplayNotice(CFTimeInterval timeout, CFOptionFlags flags, CFURLRef iconURL, CFURLRef soundURL, CFURLRef localizationURL, CFStringRef alertHeader, CFStringRef alertMessage, CFStringRef defaultButtonTitle) { - CFUserNotificationLog(alertHeader, alertMessage); - return -1; -} - -SInt32 CFUserNotificationDisplayAlert(CFTimeInterval timeout, CFOptionFlags flags, CFURLRef iconURL, CFURLRef soundURL, CFURLRef localizationURL, CFStringRef alertHeader, CFStringRef alertMessage, CFStringRef defaultButtonTitle, CFStringRef alternateButtonTitle, CFStringRef otherButtonTitle, CFOptionFlags *responseFlags) { - CFUserNotificationLog(alertHeader, alertMessage); - return -1; -} - -#endif /* __MACH__ */ - -#undef __kCFLogUserNotification -#undef CFUserNotificationLog #undef MAX_STRING_LENGTH #undef MAX_STRING_COUNT #undef NOTIFICATION_PORT_NAME -#undef NOTIFICATION_PORT_NAME_OLD #undef MESSAGE_TIMEOUT +#undef MAX_PORT_NAME_LENGTH +#undef NOTIFICATION_PORT_NAME_SUFFIX diff --git a/AppServices.subproj/CFUserNotification.h b/CFUserNotification.h similarity index 97% rename from AppServices.subproj/CFUserNotification.h rename to CFUserNotification.h index 417cdd5..e3a8d55 100644 --- a/AppServices.subproj/CFUserNotification.h +++ b/CFUserNotification.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFUserNotification.h - Copyright (c) 2000-2005, Apple, Inc. All rights reserved. + Copyright (c) 2000-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFUSERNOTIFICATION__) @@ -34,9 +34,7 @@ #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN typedef struct __CFUserNotification * CFUserNotificationRef; @@ -192,9 +190,7 @@ CF_EXPORT const CFStringRef kCFUserNotificationPopUpSelectionKey AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; #endif -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFUSERNOTIFICATION__ */ diff --git a/CFUtilities.c b/CFUtilities.c new file mode 100644 index 0000000..5131e68 --- /dev/null +++ b/CFUtilities.c @@ -0,0 +1,453 @@ +/* + * Copyright (c) 2008 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@ + */ +/* CFUtilities.c + Copyright 1998-2002, Apple, Inc. All rights reserved. + Responsibility: Christopher Kane +*/ + +#include "CFPriv.h" +#include "CFInternal.h" +#include "CFPriv.h" +#include +#include +#include +#include +#include +#if (DEPLOYMENT_TARGET_MACOSX) +#include +#include +#include +#endif +#include +#include +#include +#include +#if DEPLOYMENT_TARGET_MACOSX + #include + #include + #include + #include + #include + #include + #include + #include + #include +#include +#include +#include +#include +#endif +#if DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD + #include + #include +#endif + + +/* Comparator is passed the address of the values. */ +/* Binary searches a sorted-increasing array of some type. + Return value is either 1) the index of the element desired, + if the target value exists in the list, 2) greater than or + equal to count, if the element is greater than all the values + in the list, or 3) the index of the element greater than the + target value. + + For example, a search in the list of integers: + 2 3 5 7 11 13 17 + + For... Will Return... + 2 0 + 5 2 + 23 7 + 1 0 + 9 4 + + For instance, if you just care about found/not found: + index = CFBSearch(list, count, elem); + if (count <= index || list[index] != elem) { + * Not found * + } else { + * Found * + } + +*/ +__private_extern__ CFIndex CFBSearch(const void *element, CFIndex elementSize, const void *list, CFIndex count, CFComparatorFunction comparator, void *context) { + const char *ptr = (const char *)list; + while (0 < count) { + CFIndex half = count / 2; + const char *probe = ptr + elementSize * half; + CFComparisonResult cr = comparator(element, probe, context); + if (0 == cr) return (probe - (const char *)list) / elementSize; + ptr = (cr < 0) ? ptr : probe + elementSize; + count = (cr < 0) ? half : (half + (count & 1) - 1); + } + return (ptr - (const char *)list) / elementSize; +} + + +#define ELF_STEP(B) T1 = (H << 4) + B; T2 = T1 & 0xF0000000; if (T2) T1 ^= (T2 >> 24); T1 &= (~T2); H = T1; + +CFHashCode CFHashBytes(uint8_t *bytes, CFIndex length) { + /* The ELF hash algorithm, used in the ELF object file format */ + UInt32 H = 0, T1, T2; + SInt32 rem = length; + while (3 < rem) { + ELF_STEP(bytes[length - rem]); + ELF_STEP(bytes[length - rem + 1]); + ELF_STEP(bytes[length - rem + 2]); + ELF_STEP(bytes[length - rem + 3]); + rem -= 4; + } + switch (rem) { + case 3: ELF_STEP(bytes[length - 3]); + case 2: ELF_STEP(bytes[length - 2]); + case 1: ELF_STEP(bytes[length - 1]); + case 0: ; + } + return H; +} + +#undef ELF_STEP + + +#if DEPLOYMENT_TARGET_MACOSX +__private_extern__ uintptr_t __CFFindPointer(uintptr_t ptr, uintptr_t start) { + vm_map_t task = mach_task_self(); + mach_vm_address_t address = start; + for (;;) { + mach_vm_size_t size = 0; + vm_region_basic_info_data_64_t info; + mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64; + mach_port_t object_name; + kern_return_t ret = mach_vm_region(task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &count, &object_name); + if (KERN_SUCCESS != ret) break; + boolean_t scan = (info.protection & VM_PROT_WRITE) ? 1 : 0; + if (scan) { + uintptr_t *addr = (uintptr_t *)((uintptr_t)address); + uintptr_t *end = (uintptr_t *)((uintptr_t)address + (uintptr_t)size); + while (addr < end) { + if ((uintptr_t *)start <= addr && *addr == ptr) { + return (uintptr_t)addr; + } + addr++; + } + } + address += size; + } + return 0; +} +#endif + + +__private_extern__ void *__CFStartSimpleThread(void *func, void *arg) { +#if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_LINUX || DEPLOYMENT_TARGET_FREEBSD + pthread_attr_t attr; + pthread_t tid = 0; + pthread_attr_init(&attr); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_attr_setstacksize(&attr, 60 * 1024); // 60K stack for our internal threads is sufficient + OSMemoryBarrier(); // ensure arg is fully initialized and set in memory + pthread_create(&tid, &attr, func, arg); + pthread_attr_destroy(&attr); +//warning CF: we dont actually know that a pthread_t is the same size as void * + return (void *)tid; +#else + unsigned tid; + struct _args *args = (struct _args*)CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(struct _args), 0); + if (__CFOASafe) __CFSetLastAllocationEventName(args, "CFUtilities (thread-args)"); + HANDLE handle; + args->func = func; + args->arg = arg; + /* The thread is created suspended, because otherwise there would be a race between the assignment below of the handle field, and it's possible use in the thread func above. */ + args->handle = (HANDLE)_beginthreadex(NULL, 0, __CFWinThreadFunc, args, CREATE_SUSPENDED, &tid); + handle = args->handle; + ResumeThread(handle); + return handle; +#endif +} + +__private_extern__ CFStringRef _CFCreateLimitedUniqueString() { + /* this unique string is only unique to the current host during the current boot */ + uint64_t tsr = __CFReadTSR(); + UInt32 tsrh = (UInt32)(tsr >> 32), tsrl = (UInt32)(tsr & (int64_t)0xFFFFFFFF); + return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("CFUniqueString-%lu%lu$"), tsrh, tsrl); +} + + +// Looks for localized version of "nonLocalized" in the SystemVersion bundle +// If not found, and returnNonLocalizedFlag == true, will return the non localized string (retained of course), otherwise NULL +// If bundlePtr != NULL, will use *bundlePtr and will return the bundle in there; otherwise bundle is created and released + +static CFStringRef _CFCopyLocalizedVersionKey(CFBundleRef *bundlePtr, CFStringRef nonLocalized) { + CFStringRef localized = NULL; + CFBundleRef locBundle = bundlePtr ? *bundlePtr : NULL; + if (!locBundle) { + CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, CFSTR("/System/Library/CoreServices/SystemVersion.bundle"), kCFURLPOSIXPathStyle, false); + if (url) { + locBundle = CFBundleCreate(kCFAllocatorSystemDefault, url); + CFRelease(url); + } + } + if (locBundle) { + localized = CFBundleCopyLocalizedString(locBundle, nonLocalized, nonLocalized, CFSTR("SystemVersion")); + if (bundlePtr) *bundlePtr = locBundle; else CFRelease(locBundle); + } + return localized ? localized : (CFStringRef)CFRetain(nonLocalized); +} + +static CFDictionaryRef _CFCopyVersionDictionary(CFStringRef path) { + CFPropertyListRef plist = NULL; + CFDataRef data; + CFURLRef url; + + url = CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault, path, kCFURLPOSIXPathStyle, false); + if (url && CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, url, &data, NULL, NULL, NULL)) { + plist = CFPropertyListCreateFromXMLData(kCFAllocatorSystemDefault, data, kCFPropertyListMutableContainers, NULL); + CFRelease(data); + } + if (url) CFRelease(url); + + if (plist) { +#if DEPLOYMENT_TARGET_MACOSX + CFBundleRef locBundle = NULL; + CFStringRef fullVersion, vers, versExtra, build; + CFStringRef versionString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionProductVersionStringKey); + CFStringRef buildString = _CFCopyLocalizedVersionKey(&locBundle, _kCFSystemVersionBuildStringKey); + CFStringRef fullVersionString = _CFCopyLocalizedVersionKey(&locBundle, CFSTR("FullVersionString")); + if (locBundle) CFRelease(locBundle); + + // Now build the full version string + if (CFEqual(fullVersionString, CFSTR("FullVersionString"))) { + CFRelease(fullVersionString); + fullVersionString = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@ %%@ (%@ %%@)"), versionString, buildString); + } + vers = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionProductVersionKey); + versExtra = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionProductVersionExtraKey); + if (vers && versExtra) vers = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%@ %@"), vers, versExtra); + build = (CFStringRef)CFDictionaryGetValue((CFDictionaryRef)plist, _kCFSystemVersionBuildVersionKey); + fullVersion = CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, fullVersionString, (vers ? vers : CFSTR("?")), build ? build : CFSTR("?")); + if (vers && versExtra) CFRelease(vers); + + CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionProductVersionStringKey, versionString); + CFDictionarySetValue((CFMutableDictionaryRef)plist, _kCFSystemVersionBuildStringKey, buildString); + CFDictionarySetValue((CFMutableDictionaryRef)plist, CFSTR("FullVersionString"), fullVersion); + CFRelease(versionString); + CFRelease(buildString); + CFRelease(fullVersionString); + CFRelease(fullVersion); +#endif + } + return (CFDictionaryRef)plist; +} + +#if defined (__MACH__) || 0 +CFStringRef CFCopySystemVersionString(void) { + CFStringRef versionString; + CFDictionaryRef dict = _CFCopyServerVersionDictionary(); + if (!dict) dict = _CFCopySystemVersionDictionary(); + versionString = CFDictionaryGetValue(dict, CFSTR("FullVersionString")); + if (versionString) CFRetain(versionString); + CFRelease(dict); + return versionString; +} + +// Obsolete: These two functions cache the dictionaries to avoid calling _CFCopyVersionDictionary() more than once per dict desired +// In fact, they do not cache any more, because the file can change after +// apps are running in some situations, and apps need the new info. +// Proper caching and testing to see if the file has changed, without race +// conditions, would require semi-convoluted use of fstat(). + +CFDictionaryRef _CFCopySystemVersionDictionary(void) { + CFPropertyListRef plist = NULL; + plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/SystemVersion.plist")); + return plist; +} + +CFDictionaryRef _CFCopyServerVersionDictionary(void) { + CFPropertyListRef plist = NULL; + plist = _CFCopyVersionDictionary(CFSTR("/System/Library/CoreServices/ServerVersion.plist")); + return plist; +} + +CONST_STRING_DECL(_kCFSystemVersionProductNameKey, "ProductName") +CONST_STRING_DECL(_kCFSystemVersionProductCopyrightKey, "ProductCopyright") +CONST_STRING_DECL(_kCFSystemVersionProductVersionKey, "ProductVersion") +CONST_STRING_DECL(_kCFSystemVersionProductVersionExtraKey, "ProductVersionExtra") +CONST_STRING_DECL(_kCFSystemVersionProductUserVisibleVersionKey, "ProductUserVisibleVersion") +CONST_STRING_DECL(_kCFSystemVersionBuildVersionKey, "ProductBuildVersion") +CONST_STRING_DECL(_kCFSystemVersionProductVersionStringKey, "Version") +CONST_STRING_DECL(_kCFSystemVersionBuildStringKey, "Build") +#endif //__MACH__ + +CF_EXPORT Boolean _CFExecutableLinkedOnOrAfter(CFSystemVersion version) { + return true; +} + +#if DEPLOYMENT_TARGET_MACOSX +__private_extern__ void *__CFLookupCFNetworkFunction(const char *name) { + static void *image = NULL; + if (NULL == image) { + const char *path = NULL; + if (!issetugid()) { + path = getenv("CFNETWORK_LIBRARY_PATH"); + } + if (!path) { + path = "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CFNetwork.framework/Versions/A/CFNetwork"; + } + image = dlopen(path, RTLD_LAZY | RTLD_LOCAL); + } + void *dyfunc = NULL; + if (image) { + dyfunc = dlsym(image, name); + } + return dyfunc; +} +#endif //__MACH__ + + +#ifndef __CFGetSessionID_defined + +__private_extern__ uint32_t __CFGetSessionID(void) { + return 0; +} + +#endif + +const char *_CFPrintForDebugger(const void *obj) { + static char *result = NULL; + CFStringRef str; + CFIndex cnt = 0; + + free(result); // Let go of result from previous call. + result = NULL; + if (obj) { + if (CFGetTypeID(obj) == CFStringGetTypeID()) { + // Makes Ali marginally happier + str = __CFCopyFormattingDescription(obj, NULL); + if (!str) str = CFCopyDescription(obj); + } else { + str = CFCopyDescription(obj); + } + } else { + str = (CFStringRef)CFRetain(CFSTR("(null)")); + } + + if (str != NULL) { + CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, 0, FALSE, NULL, 0, &cnt); + } + result = (char *) malloc(cnt + 2); // 1 for '\0', 1 for an optional '\n' + if (str != NULL) { + CFStringGetBytes(str, CFRangeMake(0, CFStringGetLength(str)), kCFStringEncodingUTF8, 0, FALSE, (UInt8 *) result, cnt, &cnt); + } + result[cnt] = '\0'; + + if (str) CFRelease(str); + return result; +} + +static void _CFShowToFile(FILE *file, Boolean flush, const void *obj) { + CFStringRef str; + CFIndex idx, cnt; + CFStringInlineBuffer buffer; + bool lastNL = false; + + if (obj) { + if (CFGetTypeID(obj) == CFStringGetTypeID()) { + // Makes Ali marginally happier + str = __CFCopyFormattingDescription(obj, NULL); + if (!str) str = CFCopyDescription(obj); + } else { + str = CFCopyDescription(obj); + } + } else { + str = (CFStringRef)CFRetain(CFSTR("(null)")); + } + cnt = CFStringGetLength(str); + + // iTunes used OutputDebugStringW(theString); + + CFStringInitInlineBuffer(str, &buffer, CFRangeMake(0, cnt)); +#if defined (__WIN32__) + TCHAR *accumulatedBuffer = (TCHAR *)malloc((cnt+1) * sizeof(TCHAR)); +#endif + for (idx = 0; idx < cnt; idx++) { + UniChar ch = __CFStringGetCharacterFromInlineBufferQuick(&buffer, idx); + +#if DEPLOYMENT_TARGET_MACOSX + if (ch < 128) { + fprintf_l(file, NULL, "%c", ch); + lastNL = (ch == '\n'); + } else { + fprintf_l(file, NULL, "\\u%04x", ch); + } +#elif defined (__WIN32__) + if (ch < 128) { + _fprintf_l(file, "%c", NULL, ch); + lastNL = (ch == '\n'); + } else { + _fprintf_l(file, "\\u%04x", NULL, ch); + } +#endif + } +#if defined(__WIN32__) + } +#endif + if (!lastNL) { +#if DEPLOYMENT_TARGET_MACOSX + fprintf_l(file, NULL, "\n"); +#endif + if (flush) fflush(file); + } + + if (str) CFRelease(str); +} + +void CFShow(const void *obj) { + _CFShowToFile(stderr, true, obj); +} + + + +void CFLog(int32_t lev, CFStringRef format, ...) { + CFStringRef result; + va_list argList; + static CFSpinLock_t lock = CFSpinLockInit; + + va_start(argList, format); + result = CFStringCreateWithFormatAndArguments(kCFAllocatorSystemDefault, NULL, format, argList); + va_end(argList); + + __CFSpinLock(&lock); + CFTimeZoneRef tz = CFTimeZoneCopySystem(); // specifically choose system time zone for logs + CFGregorianDate gdate = CFAbsoluteTimeGetGregorianDate(CFAbsoluteTimeGetCurrent(), tz); + CFRelease(tz); + gdate.second = gdate.second + 0.0005; + // Date format: YYYY '-' MM '-' DD ' ' hh ':' mm ':' ss.fff + fprintf_l(stderr, NULL, "%04d-%02d-%02d %02d:%02d:%06.3f %s[%d:%x] CFLog: ", (int)gdate.year, gdate.month, gdate.day, gdate.hour, gdate.minute, gdate.second, *_CFGetProgname(), getpid(), pthread_mach_thread_np(pthread_self())); + CFShow(result); + + __CFSpinUnlock(&lock); + CFRelease(result); +} + + diff --git a/version.c b/CFVersion.c similarity index 65% rename from version.c rename to CFVersion.c index 2e80f3e..1290230 100644 --- a/version.c +++ b/CFVersion.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -20,16 +20,5 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - Note that this file is only used to build the CFLite version of CF using the makefile, but not the version that ships with OS X. - */ - -#define _STRINGIFY(X) #X -#define STRINGIFY(V) _STRINGIFY(V) - -const unsigned char kCFCoreFoundationVersionString[] = "@(#)PROGRAM:CoreFoundation PROJECT:CoreFoundation-" STRINGIFY(VERSION) " SYSTEM:Darwin DEVELOPER:" STRINGIFY(USER) " BUILT:" __DATE__ " " __TIME__ "\n"; -const double kCFCoreFoundationVersionNumber = (double)VERSION; - -#undef _STRINGIFY -#undef STRINGIFY - +const unsigned char kCFCoreFoundationVersionString[] = "@(#)PROGRAM:CoreFoundation PROJECT:CoreFoundation-476 SYSTEM:Darwin DEVELOPER:unknown BUILT:" __DATE__ " " __TIME__ "\n"; +const double kCFCoreFoundationVersionNumber = (double)476.10; diff --git a/RunLoop.subproj/CFWindowsMessageQueue.c b/CFWindowsMessageQueue.c similarity index 87% rename from RunLoop.subproj/CFWindowsMessageQueue.c rename to CFWindowsMessageQueue.c index 91ad7d4..77eece0 100644 --- a/RunLoop.subproj/CFWindowsMessageQueue.c +++ b/CFWindowsMessageQueue.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -30,8 +30,8 @@ #include "CFWindowsMessageQueue.h" #include "CFInternal.h" -extern uint32_t __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef mode); -extern void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, uint32_t mask, CFStringRef mode); +extern DWORD __CFRunLoopGetWindowsMessageQueueMask(CFRunLoopRef rl, CFStringRef mode); +extern void __CFRunLoopSetWindowsMessageQueueMask(CFRunLoopRef rl, DWORD mask, CFStringRef mode); struct __CFWindowsMessageQueue { CFRuntimeBase _base; @@ -45,15 +45,15 @@ struct __CFWindowsMessageQueue { /* Bit 3 in the base reserved bits is used for invalid state */ CF_INLINE Boolean __CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq) { - return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)wmq)->_info, 3, 3); + return (Boolean)__CFBitfieldGetValue(((const CFRuntimeBase *)wmq)->_cfinfo[CF_INFO_BITS], 3, 3); } CF_INLINE void __CFWindowsMessageQueueSetValid(CFWindowsMessageQueueRef wmq) { - __CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_info, 3, 3, 1); + __CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_cfinfo[CF_INFO_BITS], 3, 3, 1); } CF_INLINE void __CFWindowsMessageQueueUnsetValid(CFWindowsMessageQueueRef wmq) { - __CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_info, 3, 3, 0); + __CFBitfieldSetValue(((CFRuntimeBase *)wmq)->_cfinfo[CF_INFO_BITS], 3, 3, 0); } CF_INLINE void __CFWindowsMessageQueueLock(CFWindowsMessageQueueRef wmq) { @@ -91,7 +91,7 @@ static CFStringRef __CFWindowsMessageQueueCopyDescription(CFTypeRef cf) { #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 = %@}"), (UInt32)cf, (UInt32)CFGetAllocator(wmq), (wmq->_lock ? "Yes" : "No"), (__CFWindowsMessageQueueIsValid(wmq) ? "Yes" : "No"), (UInt32)wmq->_mask, wmq->_runLoops); + CFStringAppendFormat(result, NULL, CFSTR("{locked = %s, valid = %s, mask = 0x%x,\n run loops = %@}"), cf, CFGetAllocator(wmq), (wmq->_lock.LockCount ? "Yes" : "No"), (__CFWindowsMessageQueueIsValid(wmq) ? "Yes" : "No"), (UInt32)wmq->_mask, wmq->_runLoops); __CFWindowsMessageQueueUnlock(wmq); return result; } @@ -106,6 +106,7 @@ static void __CFWindowsMessageQueueDeallocate(CFTypeRef cf) { CFAllocatorRef allocator = CFGetAllocator(wmq); CFAllocatorDeallocate(allocator, wmq); CFRelease(allocator); + DeleteCriticalSection(&(wmq->_lock)); } static CFTypeID __kCFWindowsMessageQueueTypeID = _kCFRuntimeNotATypeID; @@ -138,8 +139,9 @@ CFWindowsMessageQueueRef CFWindowsMessageQueueCreate(CFAllocatorRef allocator, D return NULL; } __CFWindowsMessageQueueSetValid(memory); - memory->_lock = 0; - memory->_mask = mask; + + CF_SPINLOCK_INIT_FOR_STRUCTS(memory->_lock); + memory->_mask = mask; memory->_source = NULL; memory->_runLoops = CFArrayCreateMutable(allocator, 0, NULL); return memory; @@ -178,7 +180,7 @@ DWORD CFWindowsMessageQueueGetMask(CFWindowsMessageQueueRef wmq) { } static void __CFWindowsMessageQueueSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) { - CFWindowsMessageQueueRef wmq = info; + CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)info; __CFWindowsMessageQueueLock(wmq); if (__CFWindowsMessageQueueIsValid(wmq)) { uint32_t mask; @@ -191,11 +193,17 @@ static void __CFWindowsMessageQueueSchedule(void *info, CFRunLoopRef rl, CFStrin } static void __CFWindowsMessageQueueCancel(void *info, CFRunLoopRef rl, CFStringRef mode) { - CFWindowsMessageQueueRef wmq = info; + CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)info; __CFWindowsMessageQueueLock(wmq); +#if defined (__WIN32__) +//#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 +#else #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 +#endif //__WIN32__ if (NULL != wmq->_runLoops) { SInt32 idx = CFArrayGetFirstIndexOfValue(wmq->_runLoops, CFRangeMake(0, CFArrayGetCount(wmq->_runLoops)), rl); if (0 <= idx) CFArrayRemoveValueAtIndex(wmq->_runLoops, idx); @@ -204,7 +212,7 @@ static void __CFWindowsMessageQueueCancel(void *info, CFRunLoopRef rl, CFStringR } static void __CFWindowsMessageQueuePerform(void *info) { - CFWindowsMessageQueueRef wmq = info; + CFWindowsMessageQueueRef wmq = (CFWindowsMessageQueueRef)info; MSG msg; __CFWindowsMessageQueueLock(wmq); if (!__CFWindowsMessageQueueIsValid(wmq)) { diff --git a/RunLoop.subproj/CFWindowsMessageQueue.h b/CFWindowsMessageQueue.h similarity index 90% rename from RunLoop.subproj/CFWindowsMessageQueue.h rename to CFWindowsMessageQueue.h index 521e7c6..d0c2e08 100644 --- a/RunLoop.subproj/CFWindowsMessageQueue.h +++ b/CFWindowsMessageQueue.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFWindowsMessageQueue.h - Copyright (c) 1999-2005, Apple, Inc. All rights reserved. + Copyright (c) 1999-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFWINDOWSMESSAGEQUEUE__) @@ -33,9 +33,8 @@ #include #include -#if defined(__cplusplus) -extern "C" { -#endif + +CF_EXTERN_C_BEGIN typedef struct __CFWindowsMessageQueue * CFWindowsMessageQueueRef; @@ -49,9 +48,7 @@ CF_EXPORT Boolean CFWindowsMessageQueueIsValid(CFWindowsMessageQueueRef wmq); CF_EXPORT CFRunLoopSourceRef CFWindowsMessageQueueCreateRunLoopSource(CFAllocatorRef allocator, CFWindowsMessageQueueRef wmq, CFIndex order); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* __WIN32__ */ diff --git a/Parsing.subproj/CFXMLInputStream.c b/CFXMLInputStream.c similarity index 95% rename from Parsing.subproj/CFXMLInputStream.c rename to CFXMLInputStream.c index 1234ae7..c599722 100644 --- a/Parsing.subproj/CFXMLInputStream.c +++ b/CFXMLInputStream.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -25,12 +25,11 @@ Responsibility: Chris Parker */ +#include "CFXMLInputStream.h" #include -#include #include #include "CFStringEncodingConverter.h" #include "CFUniChar.h" -#include "CFXMLInputStream.h" /* Utility functions used in parsing */ static Boolean determineEncoding(_CFXMLInputStream *stream) { @@ -45,14 +44,22 @@ static Boolean determineEncoding(_CFXMLInputStream *stream) { if (length > 2) { // This clause checks for the unicode byte order mark, or a Unicode sequence lacking the BOM; technically an error, but this check is recommended by the XML spec if ((*bytes == 0xFF && *(bytes+1) == 0xFE) ||*(bytes+1) == 0x00) { +#if __BIG_ENDIAN__ stream->flags |= ENCODING_IS_UNICODE_SWAPPED; +#else + stream->flags |= ENCODING_IS_UNICODE_NATURAL; +#endif if (*bytes == 0xFF) { stream->currentByte = bytes + 2; } stream->encoding = kCFStringEncodingUnicode; return true; } else if ((*bytes == 0xFE && *(bytes+1) == 0xFF) || *bytes == 0x00) { +#if __BIG_ENDIAN__ stream->flags |= ENCODING_IS_UNICODE_NATURAL; +#else + stream->flags |= ENCODING_IS_UNICODE_SWAPPED; +#endif if (*bytes == 0xFE) { stream->currentByte = bytes + 2; } @@ -138,12 +145,6 @@ CF_INLINE void _fillStringWithCharacters(CFMutableStringRef string, UniChar *cha } __private_extern__ Boolean _openInputStream(_CFXMLInputStream *stream) { - if (NULL == stream->data && NULL != stream->url) { - CFDataRef data = NULL; - if (CFURLCreateDataAndPropertiesFromResource(stream->allocator, stream->url, &data, NULL, NULL, NULL)) { - stream->data = data; - } - } if (NULL == stream->data) { return false; } else { @@ -158,12 +159,12 @@ __private_extern__ Boolean _openInputStream(_CFXMLInputStream *stream) { } __private_extern__ void _initializeInputStream(_CFXMLInputStream *stream, CFAllocatorRef alloc, CFURLRef dataSource, CFDataRef xmlData) { - stream->data = xmlData ? CFRetain(xmlData) : NULL; - stream->url = dataSource ? CFRetain(dataSource) : NULL; + stream->data = xmlData ? (CFDataRef)CFRetain(xmlData) : NULL; + stream->url = dataSource ? (CFURLRef)CFRetain(dataSource) : NULL; stream->encoding = kCFStringEncodingInvalidId; stream->currentByte = NULL; - stream->allocator = CFRetain(alloc); + stream->allocator = (CFAllocatorRef)CFRetain(alloc); stream->charBuffer = NULL; stream->currentChar = NULL; stream->mark = NULL; @@ -215,13 +216,13 @@ __private_extern__ Boolean _inputStreamComposingErrorOccurred(_CFXMLInputStream #define INITIAL_BUFFER_SIZE 64 static void growCharacterBuffer(_CFXMLInputStream *stream) { if (!stream->charBuffer) { - stream->charBuffer = CFAllocatorAllocate(stream->allocator, INITIAL_BUFFER_SIZE*sizeof(UniChar), 0); + stream->charBuffer = (UniChar *)CFAllocatorAllocate(stream->allocator, INITIAL_BUFFER_SIZE*sizeof(UniChar), 0); stream->bufferCapacity = INITIAL_BUFFER_SIZE; } else { CFIndex currCharDelta = stream->currentChar ? stream->currentChar - stream->charBuffer : -1; CFIndex markDelta = stream->mark ? stream->mark - stream->charBuffer: -1; CFIndex parserMarkDelta = stream->parserMark ? stream->parserMark - stream->charBuffer: -1; - UniChar *newBuffer = CFAllocatorReallocate(stream->allocator, stream->charBuffer, stream->bufferCapacity * 2 * sizeof(UniChar), 0); + UniChar *newBuffer = (UniChar *)CFAllocatorReallocate(stream->allocator, stream->charBuffer, stream->bufferCapacity * 2 * sizeof(UniChar), 0); stream->bufferCapacity *= 2; if (newBuffer != stream->charBuffer) { stream->charBuffer = newBuffer; @@ -260,7 +261,8 @@ static CFIndex loadCharacters(UniChar *base, CFIndex maxLength, _CFXMLInputStrea } return charsToTranslate; } else { - CFIndex lengthConsumed = 0, usedByteLength, usedCharLength; + CFIndex lengthConsumed = 0; + CFIndex usedByteLength, usedCharLength; UInt32 conversionResult; if (stream->flags & ENCODING_MATCHES_ASCII) { while (stream->currentByte < dataEnd && lengthConsumed < maxLength) { @@ -347,7 +349,7 @@ static void fillCharacterBuffer(_CFXMLInputStream *stream) { } // Now try to fill the newly-opened space done = (fillToCapacity(stream) != 0); - delta = loadCharacters(stream->charBuffer+stream->bufferLength, stream->bufferCapacity - stream->bufferLength, stream); + delta = loadCharacters(stream->charBuffer + stream->bufferLength, stream->bufferCapacity - stream->bufferLength, stream); } } if (!done) { @@ -373,15 +375,13 @@ static Boolean getCharacterGuts(_CFXMLInputStream *stream, UniChar *ch, Boolean stream->currentByte ++; } } else if (stream->flags & ENCODING_IS_UNICODE_NATURAL) { - *ch = (*stream->currentByte) << 8; - *ch += *(stream->currentByte + 1); + *ch = *(UniChar *)(stream->currentByte); if (advanceStream) { stream->currentByte += 2; } } else { // Unicode with swapped bytes - *ch = (*(stream->currentByte + 1)) << 8; - *ch += *stream->currentByte; + *ch = CFSwapInt16(*(UniChar *)(stream->currentByte)); if (advanceStream) { stream->currentByte += 2; } @@ -705,7 +705,7 @@ __private_extern__ Boolean _inputStreamScanXMLName(_CFXMLInputStream *stream, Bo break; } } - if (stream->currentChar == stream->parserMark) { + if (NULL == stream->currentChar || stream->currentChar == stream->parserMark) { success = false; // Must have processed at least one character } } @@ -717,7 +717,7 @@ __private_extern__ Boolean _inputStreamScanXMLName(_CFXMLInputStream *stream, Bo } CFStringSetExternalCharactersNoCopy(stream->tempString, stream->parserMark, stream->currentChar-stream->parserMark, stream->currentChar-stream->parserMark); if (!CFSetGetValueIfPresent(stream->nameSet, stream->tempString, (const void **)str)) { - *str = CFStringCreateCopy(stream->allocator, stream->tempString); + *str = (CFStringRef)CFStringCreateCopy(stream->allocator, stream->tempString); CFSetAddValue(stream->nameSet, *str); CFRelease(*str); } @@ -729,3 +729,4 @@ __private_extern__ Boolean _inputStreamScanXMLName(_CFXMLInputStream *stream, Bo return success; } + diff --git a/Parsing.subproj/CFXMLInputStream.h b/CFXMLInputStream.h similarity index 97% rename from Parsing.subproj/CFXMLInputStream.h rename to CFXMLInputStream.h index e38e21a..b18b70c 100644 --- a/Parsing.subproj/CFXMLInputStream.h +++ b/CFXMLInputStream.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFXMLInputStream.h - Copyright (c) 2000-2005, Apple, Inc. All rights reserved. + Copyright (c) 2000-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFXMLINPUTSTREAM__) diff --git a/Parsing.subproj/CFXMLNode.c b/CFXMLNode.c similarity index 88% rename from Parsing.subproj/CFXMLNode.c rename to CFXMLNode.c index 91e7b4c..6a69614 100644 --- a/Parsing.subproj/CFXMLNode.c +++ b/CFXMLNode.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -122,23 +122,23 @@ static Boolean __CFXMLNodeEqual(CFTypeRef cf1, CFTypeRef cf2) { return true; } -static UInt32 __CFXMLNodeHash(CFTypeRef cf) { +static CFHashCode __CFXMLNodeHash(CFTypeRef cf) { CFXMLNodeRef node = (CFXMLNodeRef)cf; if (node->dataString) { return CFHash(node->dataString); } if (node->dataTypeID == kCFXMLNodeTypeDocument) { CFURLRef url = ((CFXMLDocumentInfo *)node->additionalData)->sourceURL; - return url ? CFHash(url) : (UInt32)cf; + return url ? CFHash(url) : (CFHashCode)cf; } else { CFAssert2(false, __kCFLogAssertion, "%s(): Saw unexpected XML type code %d", __PRETTY_FUNCTION__, node->dataTypeID); - return (UInt32)cf; + return (CFHashCode)cf; } } static CFStringRef __CFXMLNodeCopyDescription(CFTypeRef cf) { struct __CFXMLNode *node = (struct __CFXMLNode *)cf; - return CFStringCreateWithFormat(NULL, NULL, CFSTR("CFXMLNode 0x%x>{typeID = %d, string = %@}"), (UInt32)cf, node->dataTypeID, node->dataString); + return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("CFXMLNode %p>{typeID = %d, string = %@}"), cf, node->dataTypeID, node->dataString); } static void __CFXMLNodeDeallocate(CFTypeRef cf) { @@ -222,11 +222,12 @@ static const CFRuntimeClass __CFXMLNodeClass = { __CFXMLNodeCopyDescription }; -__private_extern__ void __CFXMLNodeInitialize(void) { +static void __CFXMLNodeInitialize(void) { __kCFXMLNodeTypeID = _CFRuntimeRegisterClass(&__CFXMLNodeClass); } CFTypeID CFXMLNodeGetTypeID(void) { + if (_kCFRuntimeNotATypeID == __kCFXMLNodeTypeID) __CFXMLNodeInitialize(); return __kCFXMLNodeTypeID; } @@ -239,7 +240,7 @@ static void _copyAddlDataForType(CFAllocatorRef alloc, CFXMLNodeTypeCode xmlType case kCFXMLNodeTypeDocument: { CFXMLDocumentInfo *srcData = (CFXMLDocumentInfo *)src; CFXMLDocumentInfo *destData = (CFXMLDocumentInfo *)dest; - destData->sourceURL = srcData->sourceURL ? CFRetain(srcData->sourceURL) : NULL; + destData->sourceURL = srcData->sourceURL ? (CFURLRef)CFRetain(srcData->sourceURL) : NULL; destData->encoding = srcData->encoding; break; } @@ -247,8 +248,8 @@ static void _copyAddlDataForType(CFAllocatorRef alloc, CFXMLNodeTypeCode xmlType CFXMLElementInfo *srcData = (CFXMLElementInfo *)src; CFXMLElementInfo *destData = (CFXMLElementInfo *)dest; if (srcData->attributes && CFDictionaryGetCount(srcData->attributes) != 0) { - destData->attributes = CFPropertyListCreateDeepCopy(alloc, srcData->attributes, kCFPropertyListImmutable); - destData->attributeOrder = CFPropertyListCreateDeepCopy(alloc, srcData->attributeOrder, kCFPropertyListImmutable); + destData->attributes = (CFDictionaryRef)CFPropertyListCreateDeepCopy(alloc, srcData->attributes, kCFPropertyListImmutable); + destData->attributeOrder = (CFArrayRef)CFPropertyListCreateDeepCopy(alloc, srcData->attributeOrder, kCFPropertyListImmutable); } else { destData->attributes = NULL; destData->attributeOrder = NULL; @@ -259,7 +260,7 @@ static void _copyAddlDataForType(CFAllocatorRef alloc, CFXMLNodeTypeCode xmlType case kCFXMLNodeTypeProcessingInstruction: { CFXMLProcessingInstructionInfo *srcData = (CFXMLProcessingInstructionInfo *)src; CFXMLProcessingInstructionInfo *destData = (CFXMLProcessingInstructionInfo *)dest; - destData->dataString = srcData->dataString ? CFStringCreateCopy(alloc, srcData->dataString) : NULL; + destData->dataString = srcData->dataString ? (CFStringRef)CFStringCreateCopy(alloc, srcData->dataString) : NULL; break; } case kCFXMLNodeTypeEntity: @@ -267,10 +268,10 @@ static void _copyAddlDataForType(CFAllocatorRef alloc, CFXMLNodeTypeCode xmlType CFXMLEntityInfo *sourceData = (CFXMLEntityInfo *)src; CFXMLEntityInfo *destData = (CFXMLEntityInfo *)dest; destData->entityType = sourceData->entityType; - destData->replacementText = sourceData->replacementText ? CFStringCreateCopy(alloc, sourceData->replacementText) : NULL; - destData->entityID.systemID = sourceData->entityID.systemID ? CFRetain(sourceData->entityID.systemID) : NULL; - destData->entityID.publicID = sourceData->entityID.publicID ? CFStringCreateCopy(alloc, sourceData->entityID.publicID) : NULL; - destData->notationName = sourceData->notationName ? CFStringCreateCopy(alloc, sourceData->notationName) : NULL; + destData->replacementText = sourceData->replacementText ? (CFStringRef)CFStringCreateCopy(alloc, sourceData->replacementText) : NULL; + destData->entityID.systemID = sourceData->entityID.systemID ? (CFURLRef)CFRetain(sourceData->entityID.systemID) : NULL; + destData->entityID.publicID = sourceData->entityID.publicID ? (CFStringRef)CFStringCreateCopy(alloc, sourceData->entityID.publicID) : NULL; + destData->notationName = sourceData->notationName ? (CFStringRef)CFStringCreateCopy(alloc, sourceData->notationName) : NULL; break; } case kCFXMLNodeTypeEntityReference: @@ -286,14 +287,14 @@ static void _copyAddlDataForType(CFAllocatorRef alloc, CFXMLNodeTypeCode xmlType // We can get away with this because the structures of CFXMLNotationInfo and CFXMLDocumentTypeInfo match. -- REW, 3/8/2000 CFXMLNotationInfo *srcData = (CFXMLNotationInfo *)src; CFXMLNotationInfo *destData = (CFXMLNotationInfo *)dest; - destData->externalID.systemID = srcData->externalID.systemID ? CFRetain(srcData->externalID.systemID) : NULL; - destData->externalID.publicID = srcData->externalID.publicID ? CFStringCreateCopy(alloc, srcData->externalID.publicID) : NULL; + destData->externalID.systemID = srcData->externalID.systemID ? (CFURLRef)CFRetain(srcData->externalID.systemID) : NULL; + destData->externalID.publicID = srcData->externalID.publicID ? (CFStringRef)CFStringCreateCopy(alloc, srcData->externalID.publicID) : NULL; break; } case kCFXMLNodeTypeElementTypeDeclaration: { CFXMLElementTypeDeclarationInfo *srcData = (CFXMLElementTypeDeclarationInfo *)src; CFXMLElementTypeDeclarationInfo *destData = (CFXMLElementTypeDeclarationInfo *)dest; - destData->contentDescription = srcData->contentDescription ? CFStringCreateCopy(alloc, srcData->contentDescription) : NULL; + destData->contentDescription = srcData->contentDescription ? (CFStringRef)CFStringCreateCopy(alloc, srcData->contentDescription) : NULL; break; } case kCFXMLNodeTypeAttributeListDeclaration: @@ -302,13 +303,13 @@ static void _copyAddlDataForType(CFAllocatorRef alloc, CFXMLNodeTypeCode xmlType CFXMLAttributeListDeclarationInfo *destData = (CFXMLAttributeListDeclarationInfo *)dest; CFIndex idx; destData->numberOfAttributes = sourceData->numberOfAttributes; - destData->attributes = sourceData->numberOfAttributes ? CFAllocatorAllocate(alloc, sizeof(CFXMLAttributeDeclarationInfo)*sourceData->numberOfAttributes, 0) : NULL; + destData->attributes = sourceData->numberOfAttributes ? (CFXMLAttributeDeclarationInfo *)CFAllocatorAllocate(alloc, sizeof(CFXMLAttributeDeclarationInfo)*sourceData->numberOfAttributes, 0) : NULL; for (idx = 0; idx < sourceData->numberOfAttributes; idx ++) { CFXMLAttributeDeclarationInfo sourceAttr = sourceData->attributes[idx]; CFXMLAttributeDeclarationInfo *destAttr = &(destData->attributes[idx]); - destAttr->attributeName = CFStringCreateCopy(alloc, sourceAttr.attributeName); - destAttr->typeString = CFStringCreateCopy(alloc, sourceAttr.typeString); - destAttr->defaultString = CFStringCreateCopy(alloc, sourceAttr.defaultString); + destAttr->attributeName = (CFStringRef)CFStringCreateCopy(alloc, sourceAttr.attributeName); + destAttr->typeString = (CFStringRef)CFStringCreateCopy(alloc, sourceAttr.typeString); + destAttr->defaultString = (CFStringRef)CFStringCreateCopy(alloc, sourceAttr.defaultString); } break; } @@ -335,12 +336,12 @@ CFXMLNodeRef CFXMLNodeCreate(CFAllocatorRef alloc, CFXMLNodeTypeCode xmlType, CF default: extraSize = 0; } - node = (struct __CFXMLNode *)_CFRuntimeCreateInstance(alloc, __kCFXMLNodeTypeID, sizeof(struct __CFXMLNode) + extraSize - sizeof(CFRuntimeBase), NULL); + node = (struct __CFXMLNode *)_CFRuntimeCreateInstance(alloc, CFXMLNodeGetTypeID(), sizeof(struct __CFXMLNode) + extraSize - sizeof(CFRuntimeBase), NULL); if (node) { alloc = CFGetAllocator(node); node->version = version; node->dataTypeID = xmlType; - node->dataString = dataString ? CFStringCreateCopy(alloc, dataString) : NULL; + node->dataString = dataString ? (CFStringRef)CFStringCreateCopy(alloc, dataString) : NULL; if (extraSize != 0) { node->additionalData = (void *)((uint8_t *)node + sizeof(struct __CFXMLNode)); _copyAddlDataForType(alloc, xmlType, additionalData, node->additionalData); @@ -366,3 +367,5 @@ const void *CFXMLNodeGetInfoPtr(CFXMLNodeRef node) { CFIndex CFXMLNodeGetVersion(CFXMLNodeRef node) { return node->version; } + + diff --git a/Parsing.subproj/CFXMLNode.h b/CFXMLNode.h similarity index 96% rename from Parsing.subproj/CFXMLNode.h rename to CFXMLNode.h index 7bb0b62..d927a58 100644 --- a/Parsing.subproj/CFXMLNode.h +++ b/CFXMLNode.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFXMLNode.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFXMLNODE__) @@ -33,9 +33,7 @@ #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN enum { kCFXMLNodeCurrentVersion = 1 @@ -65,7 +63,7 @@ typedef CFTreeRef CFXMLTreeRef; */ /* Type codes for the different possible XML nodes; this list may grow.*/ -typedef enum { +enum { kCFXMLNodeTypeDocument = 1, kCFXMLNodeTypeElement = 2, kCFXMLNodeTypeAttribute = 3, @@ -81,7 +79,8 @@ typedef enum { kCFXMLNodeTypeNotation = 13, kCFXMLNodeTypeElementTypeDeclaration = 14, kCFXMLNodeTypeAttributeListDeclaration = 15 -} CFXMLNodeTypeCode; +}; +typedef CFIndex CFXMLNodeTypeCode; typedef struct { CFDictionaryRef attributes; @@ -129,13 +128,14 @@ typedef struct { CFXMLAttributeDeclarationInfo *attributes; } CFXMLAttributeListDeclarationInfo; -typedef enum { +enum { kCFXMLEntityTypeParameter, /* Implies parsed, internal */ kCFXMLEntityTypeParsedInternal, kCFXMLEntityTypeParsedExternal, kCFXMLEntityTypeUnparsed, kCFXMLEntityTypeCharacter -} CFXMLEntityTypeCode; +}; +typedef CFIndex CFXMLEntityTypeCode; typedef struct { CFXMLEntityTypeCode entityType; @@ -201,9 +201,7 @@ CFXMLTreeRef CFXMLTreeCreateWithNode(CFAllocatorRef allocator, CFXMLNodeRef node CF_EXPORT CFXMLNodeRef CFXMLTreeGetNode(CFXMLTreeRef xmlTree); -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFXMLNODE__ */ diff --git a/Parsing.subproj/CFXMLParser.c b/CFXMLParser.c similarity index 97% rename from Parsing.subproj/CFXMLParser.c rename to CFXMLParser.c index 9caaf5b..7e97ba0 100644 --- a/Parsing.subproj/CFXMLParser.c +++ b/CFXMLParser.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -26,8 +26,8 @@ */ #include -#include "CFXMLInputStream.h" #include +#include "CFXMLInputStream.h" #include "CFUniChar.h" #include "CFInternal.h" @@ -53,8 +53,8 @@ struct __CFXMLParser { }; static CFStringRef __CFXMLParserCopyDescription(CFTypeRef cf) { - const struct __CFXMLParser *parser = cf; - return CFStringCreateWithFormat(CFGetAllocator(cf), NULL, CFSTR(""), parser); + const struct __CFXMLParser *parser = (const struct __CFXMLParser *)cf; + return CFStringCreateWithFormat(CFGetAllocator(cf), NULL, CFSTR(""), parser); } static void __CFXMLParserDeallocate(CFTypeRef cf) { @@ -85,65 +85,66 @@ static const CFRuntimeClass __CFXMLParserClass = { __CFXMLParserCopyDescription }; -__private_extern__ void __CFXMLParserInitialize(void) { +static void __CFXMLParserInitialize(void) { __kCFXMLParserTypeID = _CFRuntimeRegisterClass(&__CFXMLParserClass); } CFTypeID CFXMLParserGetTypeID(void) { + if (_kCFRuntimeNotATypeID == __kCFXMLParserTypeID) __CFXMLParserInitialize(); return __kCFXMLParserTypeID; } -#if defined(__ppc__) -#define __mask ~0x3 -#else -#define __mask ~0x0 -#endif - void CFXMLParserGetContext(CFXMLParserRef parser, CFXMLParserContext *context) { CFAssert1(parser != NULL, __kCFLogAssertion, "%s(): NULL parser not permitted", __PRETTY_FUNCTION__); - __CFGenericValidateType(parser, __kCFXMLParserTypeID); + __CFGenericValidateType(parser, CFXMLParserGetTypeID()); if (context) { context->version = parser->context.version; context->info = parser->context.info; - context->retain = (void *)((uintptr_t)parser->context.retain & __mask); - context->release = (void *)((uintptr_t)parser->context.release & __mask); - context->copyDescription = (void *)((uintptr_t)parser->context.copyDescription & __mask); + context->retain = parser->context.retain; + context->release = parser->context.release; + context->copyDescription = parser->context.copyDescription; + UNFAULT_CALLBACK(context->retain); + UNFAULT_CALLBACK(context->release); + UNFAULT_CALLBACK(context->copyDescription); } } void CFXMLParserGetCallBacks(CFXMLParserRef parser, CFXMLParserCallBacks *callBacks) { - __CFGenericValidateType(parser, __kCFXMLParserTypeID); + __CFGenericValidateType(parser, CFXMLParserGetTypeID()); if (callBacks) { callBacks->version = parser->callBacks.version; - callBacks->createXMLStructure = (void *)((uintptr_t)parser->callBacks.createXMLStructure & __mask); - callBacks->addChild = (void *)((uintptr_t)parser->callBacks.addChild & __mask); - callBacks->endXMLStructure = (void *)((uintptr_t)parser->callBacks.endXMLStructure & __mask); - callBacks->resolveExternalEntity = (void *)((uintptr_t)parser->callBacks.resolveExternalEntity & __mask); - callBacks->handleError = (void *)((uintptr_t)parser->callBacks.handleError & __mask); + callBacks->createXMLStructure = parser->callBacks.createXMLStructure; + callBacks->addChild = parser->callBacks.addChild; + callBacks->endXMLStructure = parser->callBacks.endXMLStructure; + callBacks->resolveExternalEntity = parser->callBacks.resolveExternalEntity; + callBacks->handleError = parser->callBacks.handleError; + UNFAULT_CALLBACK(callBacks->createXMLStructure); + UNFAULT_CALLBACK(callBacks->addChild); + UNFAULT_CALLBACK(callBacks->endXMLStructure); + UNFAULT_CALLBACK(callBacks->resolveExternalEntity); + UNFAULT_CALLBACK(callBacks->handleError); } } -#undef __mask - CFURLRef CFXMLParserGetSourceURL(CFXMLParserRef parser) { - __CFGenericValidateType(parser, __kCFXMLParserTypeID); + __CFGenericValidateType(parser, CFXMLParserGetTypeID()); return parser->input.url; } /* Returns the character index or line number of the current parse location */ CFIndex CFXMLParserGetLocation(CFXMLParserRef parser) { - __CFGenericValidateType(parser, __kCFXMLParserTypeID); + __CFGenericValidateType(parser, CFXMLParserGetTypeID()); return _inputStreamCurrentLocation(&parser->input); } CFIndex CFXMLParserGetLineNumber(CFXMLParserRef parser) { - __CFGenericValidateType(parser, __kCFXMLParserTypeID); + __CFGenericValidateType(parser, CFXMLParserGetTypeID()); return _inputStreamCurrentLine(&parser->input); } /* Returns the top-most object returned by the createXMLStructure callback */ void *CFXMLParserGetDocument(CFXMLParserRef parser) { - __CFGenericValidateType(parser, __kCFXMLParserTypeID); + __CFGenericValidateType(parser, CFXMLParserGetTypeID()); if (parser->capacity > 0) return parser->stack[0]; else @@ -151,24 +152,24 @@ void *CFXMLParserGetDocument(CFXMLParserRef parser) { } CFXMLParserStatusCode CFXMLParserGetStatusCode(CFXMLParserRef parser) { - __CFGenericValidateType(parser, __kCFXMLParserTypeID); + __CFGenericValidateType(parser, CFXMLParserGetTypeID()); return parser->status; } CFStringRef CFXMLParserCopyErrorDescription(CFXMLParserRef parser) { - __CFGenericValidateType(parser, __kCFXMLParserTypeID); - return CFRetain(parser->errorString); + __CFGenericValidateType(parser, CFXMLParserGetTypeID()); + return (CFStringRef)CFRetain(parser->errorString); } void CFXMLParserAbort(CFXMLParserRef parser, CFXMLParserStatusCode errorCode, CFStringRef errorDescription) { - __CFGenericValidateType(parser, __kCFXMLParserTypeID); + __CFGenericValidateType(parser, CFXMLParserGetTypeID()); CFAssert1(errorCode > 0, __kCFLogAssertion, "%s(): errorCode must be greater than zero", __PRETTY_FUNCTION__); CFAssert1(errorDescription != NULL, __kCFLogAssertion, "%s(): errorDescription may not be NULL", __PRETTY_FUNCTION__); __CFGenericValidateType(errorDescription, CFStringGetTypeID()); parser->status = errorCode; if (parser->errorString) CFRelease(parser->errorString); - parser->errorString = CFStringCreateCopy(NULL, errorDescription); + parser->errorString = (CFStringRef)CFStringCreateCopy(kCFAllocatorSystemDefault, errorDescription); } @@ -199,7 +200,7 @@ static Boolean reportNewLeaf(CFXMLParserRef parser); // Assumes parser->node has static void pushXMLNode(CFXMLParserRef parser, void *node); static CFXMLParserRef __CFXMLParserInit(CFAllocatorRef alloc, CFURLRef dataSource, CFOptionFlags options, CFDataRef xmlData, CFIndex version, CFXMLParserCallBacks *callBacks, CFXMLParserContext *context) { - struct __CFXMLParser *parser = (struct __CFXMLParser *)_CFRuntimeCreateInstance(alloc, __kCFXMLParserTypeID, sizeof(struct __CFXMLParser) - sizeof(CFRuntimeBase), NULL); + struct __CFXMLParser *parser = (struct __CFXMLParser *)_CFRuntimeCreateInstance(alloc, CFXMLParserGetTypeID(), sizeof(struct __CFXMLParser) - sizeof(CFRuntimeBase), NULL); struct __CFXMLNode *node = (struct __CFXMLNode *)_CFRuntimeCreateInstance(alloc, CFXMLNodeGetTypeID(), sizeof(struct __CFXMLNode) - sizeof(CFRuntimeBase), NULL); UniChar *buf; if (parser && node) { @@ -209,7 +210,7 @@ static CFXMLParserRef __CFXMLParserInit(CFAllocatorRef alloc, CFURLRef dataSourc parser->stack = NULL; parser->capacity = 0; - buf = CFAllocatorAllocate(alloc, 128*sizeof(UniChar), 0); + buf = (UniChar *)CFAllocatorAllocate(alloc, 128*sizeof(UniChar), 0); parser->node = node; parser->node->dataString = CFStringCreateMutableWithExternalCharactersNoCopy(alloc, buf, 0, 128, alloc); parser->node->additionalData = NULL; @@ -269,7 +270,7 @@ CFXMLParserRef CFXMLParserCreateWithDataFromURL(CFAllocatorRef allocator, CFURLR Boolean CFXMLParserParse(CFXMLParserRef parser) { CFXMLDocumentInfo docData; - __CFGenericValidateType(parser, __kCFXMLParserTypeID); + __CFGenericValidateType(parser, CFXMLParserGetTypeID()); if (parser->status != kCFXMLStatusParseNotBegun) return false; parser->status = kCFXMLStatusParseInProgress; @@ -291,7 +292,7 @@ Boolean CFXMLParserParse(CFXMLParserRef parser) { } // Create the document - parser->stack = CFAllocatorAllocate(CFGetAllocator(parser), 16 * sizeof(void *), 0); + parser->stack = (void **)CFAllocatorAllocate(CFGetAllocator(parser), 16 * sizeof(void *), 0); parser->capacity = 16; parser->node->dataTypeID = kCFXMLNodeTypeDocument; docData.encoding = _inputStreamGetEncoding(&parser->input); @@ -655,9 +656,9 @@ static Boolean parseAttributeListDeclaration(CFXMLParserRef parser) { if (capacity == attListData.numberOfAttributes) { capacity = 2*capacity; if (attributes != attributeArray) { - attributes = CFAllocatorReallocate(CFGetAllocator(parser), attributes, capacity * sizeof(CFXMLAttributeDeclarationInfo), 0); + attributes = (CFXMLAttributeDeclarationInfo *)CFAllocatorReallocate(CFGetAllocator(parser), attributes, capacity * sizeof(CFXMLAttributeDeclarationInfo), 0); } else { - attributes = CFAllocatorAllocate(CFGetAllocator(parser), capacity * sizeof(CFXMLAttributeDeclarationInfo), 0); + attributes = (CFXMLAttributeDeclarationInfo *)CFAllocatorAllocate(CFGetAllocator(parser), capacity * sizeof(CFXMLAttributeDeclarationInfo), 0); } } attribute = &(attributes[attListData.numberOfAttributes]); @@ -1770,7 +1771,7 @@ static Boolean reportNewLeaf(CFXMLParserRef parser) { static void pushXMLNode(CFXMLParserRef parser, void *node) { parser->top ++; if ((unsigned)(parser->top - parser->stack) == parser->capacity) { - parser->stack = CFAllocatorReallocate(CFGetAllocator(parser), parser->stack, 2 * parser->capacity * sizeof(void *), 0); + parser->stack = (void **)CFAllocatorReallocate(CFGetAllocator(parser), parser->stack, 2 * parser->capacity * sizeof(void *), 0); parser->top = parser->stack + parser->capacity; parser->capacity = 2*parser->capacity; } @@ -1827,8 +1828,6 @@ CFXMLTreeRef CFXMLTreeCreateFromData(CFAllocatorRef allocator, CFDataRef xmlData return CFXMLTreeCreateFromDataWithError(allocator, xmlData, dataSource, parseOptions, parserVersion, NULL); } -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3 - CONST_STRING_DECL(kCFXMLTreeErrorDescription, "kCFXMLTreeErrorDescription"); CONST_STRING_DECL(kCFXMLTreeErrorLineNumber, "kCFXMLTreeErrorLineNumber"); CONST_STRING_DECL(kCFXMLTreeErrorLocation, "kCFXMLTreeErrorLocation"); @@ -2032,7 +2031,7 @@ CFStringRef CFXMLCreateStringByUnescapingEntities(CFAllocatorRef allocator, CFSt } } else { // it wasn't numeric. sub = CFStringCreateWithSubstring(allocator, string, CFRangeMake(entityStart + 1, (i - entityStart - 2))); // This trims off the & and ; from the string, so we can use it against the dictionary itself. - CFStringRef replacementString = CFDictionaryGetValue(fullReplDict, sub); + CFStringRef replacementString = (CFStringRef)CFDictionaryGetValue(fullReplDict, sub); if(replacementString) { CFStringAppend(newString, replacementString); } else { @@ -2058,5 +2057,4 @@ CFStringRef CFXMLCreateStringByUnescapingEntities(CFAllocatorRef allocator, CFSt return newString; } -#endif diff --git a/Parsing.subproj/CFXMLParser.h b/CFXMLParser.h similarity index 98% rename from Parsing.subproj/CFXMLParser.h rename to CFXMLParser.h index d035979..6f494ba 100644 --- a/Parsing.subproj/CFXMLParser.h +++ b/CFXMLParser.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CFXMLParser.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_CFXMLPARSER__) @@ -35,9 +35,7 @@ #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN typedef struct __CFXMLParser * CFXMLParserRef; @@ -71,7 +69,7 @@ kCFXMLParserAddImpliedAttributes - Currently not supported. */ -typedef enum { +enum { kCFXMLParserValidateDocument = (1 << 0), kCFXMLParserSkipMetaData = (1 << 1), kCFXMLParserReplacePhysicalEntities = (1 << 2), @@ -80,10 +78,11 @@ typedef enum { kCFXMLParserAddImpliedAttributes = (1 << 5), kCFXMLParserAllOptions = 0x00FFFFFF, kCFXMLParserNoOptions = 0 -} CFXMLParserOptions; +}; +typedef CFOptionFlags CFXMLParserOptions; /* This list is expected to grow */ -typedef enum { +enum { kCFXMLStatusParseNotBegun = -2, kCFXMLStatusParseInProgress = -1, kCFXMLStatusParseSuccessful = 0, @@ -102,7 +101,8 @@ typedef enum { kCFXMLErrorMalformedCharacterReference, kCFXMLErrorMalformedParsedCharacterData, kCFXMLErrorNoData -} CFXMLParserStatusCode; +}; +typedef CFIndex CFXMLParserStatusCode; /* These functions are called as a parse progresses. @@ -285,9 +285,7 @@ CF_EXPORT const CFStringRef kCFXMLTreeErrorLocation AVAILABLE_MAC_OS_X_VERSION_ CF_EXPORT const CFStringRef kCFXMLTreeErrorStatusCode AVAILABLE_MAC_OS_X_VERSION_10_3_AND_LATER; /* value is a CFNumber containing the error status code. */ -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_CFXMLPARSER__ */ diff --git a/Preferences.subproj/CFXMLPreferencesDomain.c b/CFXMLPreferencesDomain.c similarity index 82% rename from Preferences.subproj/CFXMLPreferencesDomain.c rename to CFXMLPreferencesDomain.c index c2473b9..7878668 100644 --- a/Preferences.subproj/CFXMLPreferencesDomain.c +++ b/CFXMLPreferencesDomain.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -25,8 +25,6 @@ Responsibility: Chris Parker */ -#if !defined(__WIN32__) - #include #include #include @@ -34,11 +32,13 @@ #include #include "CFInternal.h" #include +#if DEPLOYMENT_TARGET_MACOSX #include #include #include #include #include +#endif Boolean __CFPreferencesShouldWriteXML(void); @@ -64,11 +64,9 @@ __private_extern__ const _CFPreferencesDomainCallBacks __kCFXMLPropertyListDomai // Directly ripped from Foundation.... static void __CFMilliSleep(uint32_t msecs) { -#if defined(__WIN32__) - SleepEx(msecs, false); -#elif defined(__svr4__) || defined(__hpux__) +#if defined(__svr4__) || defined(__hpux__) sleep((msecs + 900) / 1000); -#elif defined(__MACH__) +#elif DEPLOYMENT_TARGET_MACOSX struct timespec input; input.tv_sec = msecs / 1000; input.tv_nsec = (msecs - input.tv_sec * 1000) * 1000000; @@ -78,7 +76,7 @@ static void __CFMilliSleep(uint32_t msecs) { #endif } -static CFSpinLock_t _propDictLock = 0; // Annoying that we need this, but otherwise we have a multithreading risk +static CFSpinLock_t _propDictLock = CFSpinLockInit; // Annoying that we need this, but otherwise we have a multithreading risk CF_INLINE CFDictionaryRef URLPropertyDictForPOSIXMode(SInt32 mode) { static CFMutableDictionaryRef _propertyDict = NULL; @@ -100,7 +98,7 @@ CF_INLINE void URLPropertyDictRelease(void) { static Boolean _createDirectory(CFURLRef dirURL, Boolean worldReadable) { CFAllocatorRef alloc = __CFPreferencesAllocator(); CFURLRef parentURL = CFURLCreateCopyDeletingLastPathComponent(alloc, dirURL); - CFBooleanRef val = CFURLCreatePropertyFromResource(alloc, parentURL, kCFURLFileExists, NULL); + CFBooleanRef val = (CFBooleanRef) CFURLCreatePropertyFromResource(alloc, parentURL, kCFURLFileExists, NULL); Boolean parentExists = (val && CFBooleanGetValue(val)); SInt32 mode; Boolean result; @@ -109,7 +107,7 @@ static Boolean _createDirectory(CFURLRef dirURL, Boolean worldReadable) { CFStringRef path = CFURLCopyPath(parentURL); if (!CFEqual(path, CFSTR("/"))) { _createDirectory(parentURL, worldReadable); - val = CFURLCreatePropertyFromResource(alloc, parentURL, kCFURLFileExists, NULL); + val = (CFBooleanRef) CFURLCreatePropertyFromResource(alloc, parentURL, kCFURLFileExists, NULL); parentExists = (val && CFBooleanGetValue(val)); if (val) CFRelease(val); } @@ -118,7 +116,11 @@ static Boolean _createDirectory(CFURLRef dirURL, Boolean worldReadable) { if (parentURL) CFRelease(parentURL); if (!parentExists) return false; +#if DEPLOYMENT_TARGET_MACOSX mode = worldReadable ? S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH : S_IRWXU; +#else + mode = 0666; +#endif result = CFURLWriteDataAndPropertiesToResource(dirURL, (CFDataRef)dirURL, URLPropertyDictForPOSIXMode(mode), NULL); URLPropertyDictRelease(); @@ -128,11 +130,12 @@ static Boolean _createDirectory(CFURLRef dirURL, Boolean worldReadable) { /* XML - context is the CFURL where the property list is stored on disk; domain is an _CFXMLPreferencesDomain */ static void *createXMLDomain(CFAllocatorRef allocator, CFTypeRef context) { - _CFXMLPreferencesDomain *domain = CFAllocatorAllocate(allocator, sizeof(_CFXMLPreferencesDomain), 0); + _CFXMLPreferencesDomain *domain = (_CFXMLPreferencesDomain*) CFAllocatorAllocate(allocator, sizeof(_CFXMLPreferencesDomain), 0); domain->_lastReadTime = 0.0; domain->_domainDict = NULL; domain->_dirtyKeys = CFArrayCreateMutable(allocator, 0, & kCFTypeArrayCallBacks); - domain->_lock = 0; + const CFSpinLock_t lock = CFSpinLockInit; + domain->_lock = lock; domain->_isWorldReadable = false; return domain; } @@ -221,67 +224,8 @@ static CFTypeRef fetchXMLValue(CFTypeRef context, void *xmlDomain, CFStringRef k } -#if defined(__MACH__) +#if DEPLOYMENT_TARGET_MACOSX #include -#if 0 -// appends a unique 8.3 path name to the directory name specified in fn, -// atomically determining uniqueness and opening the file. The file -// descriptor is returned by reference in the second parameter. 0 is -// returned on success, -1 on failure. -// We don't currently handle the case where the directory name is very -// long and adding an 8.3 name makes the path too long. -static int __CFmkstemp83(char *fn, char *prefix, int mode, int *fd) { - static CFSpinLock_t counter_lock = 0; - static unsigned int extension_counter = 0; - int origlen = strlen(fn); - char idbuf[6], extbuf[6], prebuf[5]; - uint16_t pid, origpid, ext, origext; - - __CFSpinLock(&counter_lock); - ext = extension_counter++; - if (0xFFF < extension_counter) extension_counter = 0; - __CFSpinUnlock(&counter_lock); - origext = ext; - do { - char *s1 = prebuf; - const char *s2 = prefix; - int n = 0; - for (; (*s1 = *s2) && (n < 4); s1++, s2++, n++); - } while (0); - prebuf[4] = '\0'; - if (0 < origlen && fn[origlen - 1] != '/') - fn[origlen++] = '/'; - pid = getpid() & 0xFFFF; - origpid = pid; - snprintf(idbuf, 6, "%04x", pid); - snprintf(extbuf, 6, ".%03x", ext); - fn[origlen] = '\0'; - strcat(fn, prebuf); - strcat(fn, idbuf); - strcat(fn, extbuf); - for (;;) { - *fd = open(fn, O_CREAT|O_EXCL|O_RDWR, mode); - if (0 <= *fd) - return 0; - if (EEXIST != thread_errno()) - return -1; - ext = (ext + 1) & 0xFFF; - if (origext == ext) { - // bump the number and start over with extension - pid = (pid + 1) & 0xFFFF; - if (pid == origpid) - return -1; // 2^28 file names tried! errno == EEXIST - snprintf(idbuf, 6, "%04x", pid); - } - snprintf(extbuf, 6, ".%03x", ext); - fn[origlen] = '\0'; - strcat(fn, prebuf); - strcat(fn, idbuf); - strcat(fn, extbuf); - } - return -1; -} -#endif /* __CFWriteBytesToFileWithAtomicity is a "safe save" facility. Write the bytes using the specified mode on the file to the provided URL. If the atomic flag is true, try to do it in a fashion that will enable a safe save. */ @@ -292,13 +236,13 @@ static Boolean __CFWriteBytesToFileWithAtomicity(CFURLRef url, const void *bytes uid_t owner = getuid(); gid_t group = getgid(); Boolean writingFileAsRoot = ((getuid() != geteuid()) && (geteuid() == 0)); - - if (!CFURLGetFileSystemRepresentation(url, true, cpath, CFMaxPathSize)) { + + if (!CFURLGetFileSystemRepresentation(url, true, (uint8_t *)cpath, CFMaxPathSize)) { return false; } if (-1 == mode || writingFileAsRoot) { - struct stat statBuf; + struct stat statBuf; if (0 == stat(cpath, &statBuf)) { mode = statBuf.st_mode; owner = statBuf.st_uid; @@ -313,10 +257,10 @@ static Boolean __CFWriteBytesToFileWithAtomicity(CFURLRef url, const void *bytes } if (atomic) { - CFURLRef dir = CFURLCreateCopyDeletingLastPathComponent(NULL, url); - CFURLRef tempFile = CFURLCreateCopyAppendingPathComponent(NULL, dir, CFSTR("cf#XXXXX"), false); + CFURLRef dir = CFURLCreateCopyDeletingLastPathComponent(kCFAllocatorSystemDefault, url); + CFURLRef tempFile = CFURLCreateCopyAppendingPathComponent(kCFAllocatorSystemDefault, dir, CFSTR("cf#XXXXX"), false); CFRelease(dir); - if (!CFURLGetFileSystemRepresentation(tempFile, true, auxPath, CFMaxPathSize)) { + if (!CFURLGetFileSystemRepresentation(tempFile, true, (uint8_t *)auxPath, CFMaxPathSize)) { CFRelease(tempFile); return false; } @@ -342,7 +286,7 @@ static Boolean __CFWriteBytesToFileWithAtomicity(CFURLRef url, const void *bytes if (atomic) { // preserve the mode as passed in originally chmod(auxPath, mode); - + if (0 != rename(auxPath, cpath)) { unlink(auxPath); return false; @@ -364,7 +308,7 @@ static Boolean _writeXMLFile(CFURLRef url, CFMutableDictionaryRef dict, Boolean *tryAgain = false; if (CFDictionaryGetCount(dict) == 0) { // Destroy the file - CFBooleanRef val = CFURLCreatePropertyFromResource(alloc, url, kCFURLFileExists, NULL); + CFBooleanRef val = (CFBooleanRef) CFURLCreatePropertyFromResource(alloc, url, kCFURLFileExists, NULL); if (val && CFBooleanGetValue(val)) { success = CFURLDestroyResource(url, NULL); } else { @@ -377,37 +321,41 @@ static Boolean _writeXMLFile(CFURLRef url, CFMutableDictionaryRef dict, Boolean CFWriteStreamOpen(binStream); CFPropertyListWriteToStream(dict, binStream, desiredFormat, NULL); CFWriteStreamClose(binStream); - CFDataRef data = CFWriteStreamCopyProperty(binStream, kCFStreamPropertyDataWritten); + CFDataRef data = (CFDataRef) CFWriteStreamCopyProperty(binStream, kCFStreamPropertyDataWritten); CFRelease(binStream); if (data) { SInt32 mode; +#if DEPLOYMENT_TARGET_MACOSX mode = isWorldReadable ? S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH : S_IRUSR|S_IWUSR; -#if 1 && defined(__MACH__) - { // Try quick atomic way first, then fallback to slower ways and error cases - CFStringRef scheme = CFURLCopyScheme(url); - if (!scheme) { - *tryAgain = false; - CFRelease(data); - return false; - } else if (CFStringCompare(scheme, CFSTR("file"), 0) == kCFCompareEqualTo) { - SInt32 length = CFDataGetLength(data); - const void *bytes = (0 == length) ? (const void *)"" : CFDataGetBytePtr(data); - Boolean atomicWriteSuccess = __CFWriteBytesToFileWithAtomicity(url, bytes, length, mode, true); - if (atomicWriteSuccess) { - CFRelease(scheme); - *tryAgain = false; - CFRelease(data); - return true; - } - if (!atomicWriteSuccess && thread_errno() == ENOSPC) { - CFRelease(scheme); - *tryAgain = false; - CFRelease(data); - return false; - } - } - CFRelease(scheme); - } +#else + mode = 0666; +#endif +#if DEPLOYMENT_TARGET_MACOSX + { // Try quick atomic way first, then fallback to slower ways and error cases + CFStringRef scheme = CFURLCopyScheme(url); + if (!scheme) { + *tryAgain = false; + CFRelease(data); + return false; + } else if (CFStringCompare(scheme, CFSTR("file"), 0) == kCFCompareEqualTo) { + SInt32 length = CFDataGetLength(data); + const void *bytes = (0 == length) ? (const void *)"" : CFDataGetBytePtr(data); + Boolean atomicWriteSuccess = __CFWriteBytesToFileWithAtomicity(url, bytes, length, mode, true); + if (atomicWriteSuccess) { + CFRelease(scheme); + *tryAgain = false; + CFRelease(data); + return true; + } + if (!atomicWriteSuccess && thread_errno() == ENOSPC) { + CFRelease(scheme); + *tryAgain = false; + CFRelease(data); + return false; + } + } + CFRelease(scheme); + } #endif success = CFURLWriteDataAndPropertiesToResource(url, data, URLPropertyDictForPOSIXMode(mode), NULL); URLPropertyDictRelease(); @@ -419,13 +367,13 @@ static Boolean _writeXMLFile(CFURLRef url, CFMutableDictionaryRef dict, Boolean } if (readData) CFRelease(readData); } else { - CFBooleanRef val = CFURLCreatePropertyFromResource(alloc, url, kCFURLFileExists, NULL); + CFBooleanRef val = (CFBooleanRef) CFURLCreatePropertyFromResource(alloc, url, kCFURLFileExists, NULL); if (!val || !CFBooleanGetValue(val)) { CFURLRef tmpURL = CFURLCreateWithFileSystemPathRelativeToBase(alloc, CFSTR("."), kCFURLPOSIXPathStyle, true, url); // Just "." because url is not a directory URL CFURLRef parentURL = tmpURL ? CFURLCopyAbsoluteURL(tmpURL) : NULL; if (tmpURL) CFRelease(tmpURL); if (val) CFRelease(val); - val = CFURLCreatePropertyFromResource(alloc, parentURL, kCFURLFileExists, NULL); + val = (CFBooleanRef) CFURLCreatePropertyFromResource(alloc, parentURL, kCFURLFileExists, NULL); if ((!val || !CFBooleanGetValue(val)) && _createDirectory(parentURL, isWorldReadable)) { // parent directory didn't exist; now it does; try again to write success = CFURLWriteDataAndPropertiesToResource(url, data, URLPropertyDictForPOSIXMode(mode), NULL); @@ -510,7 +458,7 @@ static void getXMLKeysAndValues(CFAllocatorRef alloc, CFTypeRef context, void *x values = *buf + count; CFDictionaryGetKeysAndValues(domain->_domainDict, (const void **)*buf, (const void **)values); } else if (alloc != kCFAllocatorNull) { - *buf = CFAllocatorReallocate(alloc, (*buf ? *buf : NULL), count * 2 * sizeof(void *), 0); + *buf = (void**) CFAllocatorReallocate(alloc, (*buf ? *buf : NULL), count * 2 * sizeof(void *), 0); if (*buf) { values = *buf + count; CFDictionaryGetKeysAndValues(domain->_domainDict, (const void **)*buf, (const void **)values); @@ -568,7 +516,7 @@ static Boolean synchronizeXMLDomain(CFTypeRef context, void *xmlDomain) { _loadXMLDomainIfStale((CFURLRef )context, domain); // now cachedDict holds our changes; domain->_domainDict has the latest version from the disk for (idx = 0; idx < count; idx ++) { - CFStringRef key = CFArrayGetValueAtIndex(changedKeys, idx); + CFStringRef key = (CFStringRef) CFArrayGetValueAtIndex(changedKeys, idx); CFTypeRef value = CFDictionaryGetValue(cachedDict, key); if (value) CFDictionarySetValue(domain->_domainDict, key, value); @@ -577,7 +525,7 @@ static Boolean synchronizeXMLDomain(CFTypeRef context, void *xmlDomain) { } success = _writeXMLFile((CFURLRef )context, domain->_domainDict, domain->_isWorldReadable, &tryAgain); if (tryAgain) { - __CFMilliSleep(((__CFReadTSR() & 0xf) + 1) * 50); + __CFMilliSleep((((uint32_t)__CFReadTSR() & 0xf) + 1) * 50); } } while (tryAgain); CFRelease(cachedDict); @@ -589,5 +537,4 @@ static Boolean synchronizeXMLDomain(CFTypeRef context, void *xmlDomain) { return success; } -#endif /* !defined(__WIN32__) */ diff --git a/Parsing.subproj/CFXMLTree.c b/CFXMLTree.c similarity index 96% rename from Parsing.subproj/CFXMLTree.c rename to CFXMLTree.c index 267eafc..75fbcae 100644 --- a/Parsing.subproj/CFXMLTree.c +++ b/CFXMLTree.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -78,7 +78,7 @@ CFDataRef CFXMLTreeCreateXMLData(CFAllocatorRef allocator, CFXMLTreeRef xmlTree) xmlStr = CFStringCreateMutable(allocator, 0); _CFAppendXML(xmlStr, xmlTree); if (CFXMLNodeGetTypeCode(CFXMLTreeGetNode(xmlTree)) == kCFXMLNodeTypeDocument) { - const CFXMLDocumentInfo *docData = CFXMLNodeGetInfoPtr(CFXMLTreeGetNode(xmlTree)); + const CFXMLDocumentInfo *docData = (CFXMLDocumentInfo *)CFXMLNodeGetInfoPtr(CFXMLTreeGetNode(xmlTree)); encoding = docData ? docData->encoding : kCFStringEncodingUTF8; } else { encoding = kCFStringEncodingUTF8; @@ -120,13 +120,13 @@ static void appendExternalID(CFMutableStringRef str, CFXMLExternalID *extID) { } static void appendElementProlog(CFMutableStringRef str, CFXMLTreeRef tree) { - const CFXMLElementInfo *data = CFXMLNodeGetInfoPtr(CFXMLTreeGetNode(tree)); + const CFXMLElementInfo *data = (CFXMLElementInfo *)CFXMLNodeGetInfoPtr(CFXMLTreeGetNode(tree)); CFStringAppendFormat(str, NULL, CFSTR("<%@"), CFXMLNodeGetString(CFXMLTreeGetNode(tree))); if (data->attributeOrder) { CFIndex i, c = CFArrayGetCount(data->attributeOrder); for (i = 0; i < c; i ++) { - CFStringRef attr = CFArrayGetValueAtIndex(data->attributeOrder, i); - CFStringRef value = CFDictionaryGetValue(data->attributes, attr); + CFStringRef attr = (CFStringRef)CFArrayGetValueAtIndex(data->attributeOrder, i); + CFStringRef value = (CFStringRef)CFDictionaryGetValue(data->attributes, attr); CFStringAppendFormat(str, NULL, CFSTR(" %@="), attr); appendQuotedString(str, value); } @@ -254,3 +254,5 @@ static void _CFAppendXMLEpilog(CFMutableStringRef str, CFXMLTreeRef tree) { CFStringAppendCString(str, ">", kCFStringEncodingASCII); } } + + diff --git a/Collections.subproj/CFBag.c b/Collections.subproj/CFBag.c deleted file mode 100644 index 9aaf404..0000000 --- a/Collections.subproj/CFBag.c +++ /dev/null @@ -1,848 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFBag.c - Copyright 1998-2002, Apple, Inc. All rights reserved. - Responsibility: Christopher Kane -*/ - -#include -#include "CFInternal.h" - -const CFBagCallBacks kCFTypeBagCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; -const CFBagCallBacks kCFCopyStringBagCallBacks = {0, (void *)CFStringCreateCopy, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; -static const CFBagCallBacks __kCFNullBagCallBacks = {0, NULL, NULL, NULL, NULL, NULL}; - - -static const uint32_t __CFBagCapacities[42] = { - 4, 8, 17, 29, 47, 76, 123, 199, 322, 521, 843, 1364, 2207, 3571, 5778, 9349, - 15127, 24476, 39603, 64079, 103682, 167761, 271443, 439204, 710647, 1149851, 1860498, - 3010349, 4870847, 7881196, 12752043, 20633239, 33385282, 54018521, 87403803, 141422324, - 228826127, 370248451, 599074578, 969323029, 1568397607, 2537720636U -}; - -static const uint32_t __CFBagBuckets[42] = { // primes - 5, 11, 23, 41, 67, 113, 199, 317, 521, 839, 1361, 2207, 3571, 5779, 9349, 15121, - 24473, 39607, 64081, 103681, 167759, 271429, 439199, 710641, 1149857, 1860503, 3010349, - 4870843, 7881193, 12752029, 20633237, 33385273, 54018521, 87403763, 141422317, 228826121, - 370248451, 599074561, 969323023, 1568397599, 2537720629U, 4106118251U -}; - -CF_INLINE CFIndex __CFBagRoundUpCapacity(CFIndex capacity) { - CFIndex idx; - for (idx = 0; idx < 42 && __CFBagCapacities[idx] < (uint32_t)capacity; idx++); - if (42 <= idx) HALT; - return __CFBagCapacities[idx]; -} - -CF_INLINE CFIndex __CFBagNumBucketsForCapacity(CFIndex capacity) { - CFIndex idx; - for (idx = 0; idx < 42 && __CFBagCapacities[idx] < (uint32_t)capacity; idx++); - if (42 <= idx) HALT; - return __CFBagBuckets[idx]; -} - -enum { /* Bits 1-0 */ - __kCFBagImmutable = 0, /* unchangable and fixed capacity */ - __kCFBagMutable = 1, /* changeable and variable capacity */ - __kCFBagFixedMutable = 3 /* changeable and fixed capacity */ -}; - -enum { /* Bits 3-2 */ - __kCFBagHasNullCallBacks = 0, - __kCFBagHasCFTypeCallBacks = 1, - __kCFBagHasCustomCallBacks = 3 /* callbacks are at end of header */ -}; - -enum { /* Bit 4 */ - __kCFCollectionIsWeak = 0, - __kCFCollectionIsStrong = 1, -}; - - -struct __CFBagBucket { - const void *_key; - CFIndex _count; -}; - -struct __CFBag { - CFRuntimeBase _base; - CFIndex _count; /* number of values */ - CFIndex _capacity; /* maximum number of values */ - CFIndex _bucketsUsed; /* number of slots used */ - CFIndex _bucketsNum; /* number of slots */ - const void *_emptyMarker; - const void *_deletedMarker; - void *_context; /* private */ - struct __CFBagBucket *_buckets; /* can be NULL if not allocated yet */ -}; - -CF_INLINE bool __CFBagBucketIsEmpty(CFBagRef bag, const struct __CFBagBucket *bucket) { - return (bag->_emptyMarker == bucket->_key); -} - -CF_INLINE bool __CFBagBucketIsDeleted(CFBagRef bag, const struct __CFBagBucket *bucket) { - return (bag->_deletedMarker == bucket->_key); -} - -CF_INLINE bool __CFBagBucketIsOccupied(CFBagRef bag, const struct __CFBagBucket *bucket) { - return (bag->_emptyMarker != bucket->_key && bag->_deletedMarker != bucket->_key); -} - -/* Bits 1-0 of the base reserved bits are used for mutability variety */ -/* Bits 3-2 of the base reserved bits are used for callback indicator bits */ -/* Bits 4-5 are used by GC */ - -static bool isStrongMemory(CFTypeRef collection) { - return ! __CFBitfieldGetValue(((const CFRuntimeBase *)collection)->_info, 4, 4); -} - -static bool needsRestore(CFTypeRef collection) { - return __CFBitfieldGetValue(((const CFRuntimeBase *)collection)->_info, 5, 5); -} - - -CF_INLINE CFIndex __CFBagGetType(CFBagRef bag) { - return __CFBitfieldGetValue(((const CFRuntimeBase *)bag)->_info, 1, 0); -} - -CF_INLINE CFIndex __CFBagGetSizeOfType(CFIndex t) { - CFIndex size = sizeof(struct __CFBag); - if (__CFBitfieldGetValue(t, 3, 2) == __kCFBagHasCustomCallBacks) { - size += sizeof(CFBagCallBacks); - } - return size; -} - -CF_INLINE const CFBagCallBacks *__CFBagGetCallBacks(CFBagRef bag) { - CFBagCallBacks *result = NULL; - switch (__CFBitfieldGetValue(((const CFRuntimeBase *)bag)->_info, 3, 2)) { - case __kCFBagHasNullCallBacks: - return &__kCFNullBagCallBacks; - case __kCFBagHasCFTypeCallBacks: - return &kCFTypeBagCallBacks; - case __kCFBagHasCustomCallBacks: - break; - } - result = (CFBagCallBacks *)((uint8_t *)bag + sizeof(struct __CFBag)); - return result; -} - -CF_INLINE bool __CFBagCallBacksMatchNull(const CFBagCallBacks *c) { - return (NULL == c || - (c->retain == __kCFNullBagCallBacks.retain && - c->release == __kCFNullBagCallBacks.release && - c->copyDescription == __kCFNullBagCallBacks.copyDescription && - c->equal == __kCFNullBagCallBacks.equal && - c->hash == __kCFNullBagCallBacks.hash)); -} - -CF_INLINE bool __CFBagCallBacksMatchCFType(const CFBagCallBacks *c) { - return (&kCFTypeBagCallBacks == c || - (c->retain == kCFTypeBagCallBacks.retain && - c->release == kCFTypeBagCallBacks.release && - c->copyDescription == kCFTypeBagCallBacks.copyDescription && - c->equal == kCFTypeBagCallBacks.equal && - c->hash == kCFTypeBagCallBacks.hash)); -} - - -static void __CFBagFindBuckets1(CFBagRef bag, const void *key, struct __CFBagBucket **match) { - const CFBagCallBacks *cb = __CFBagGetCallBacks(bag); - struct __CFBagBucket *buckets = bag->_buckets; - CFHashCode keyHash = cb->hash ? (CFHashCode)INVOKE_CALLBACK2(((CFHashCode (*)(const void *, void *))cb->hash), key, bag->_context) : (CFHashCode)key; - UInt32 start = keyHash % bag->_bucketsNum; - UInt32 probe = start; - UInt32 probeskip = 1; - *match = NULL; - for (;;) { - struct __CFBagBucket *currentBucket = buckets + probe; - if (__CFBagBucketIsEmpty(bag, currentBucket)) { - return; - } else if (__CFBagBucketIsDeleted(bag, currentBucket)) { - /* do nothing */ - } else if (currentBucket->_key == key || (cb->equal && INVOKE_CALLBACK3((Boolean (*)(const void *, const void *, void *))cb->equal, currentBucket->_key, key, bag->_context))) { - *match = currentBucket; - return; - } - probe = (probe + probeskip) % bag->_bucketsNum; - if (start == probe) return; - } -} - -static void __CFBagFindBuckets2(CFBagRef bag, const void *key, struct __CFBagBucket **match, struct __CFBagBucket **nomatch) { - const CFBagCallBacks *cb = __CFBagGetCallBacks(bag); - struct __CFBagBucket *buckets = bag->_buckets; - CFHashCode keyHash = cb->hash ? (CFHashCode)INVOKE_CALLBACK2(((CFHashCode (*)(const void *, void *))cb->hash), key, bag->_context) : (CFHashCode)key; - UInt32 start = keyHash % bag->_bucketsNum; - UInt32 probe = start; - UInt32 probeskip = 1; - *match = NULL; - *nomatch = NULL; - for (;;) { - struct __CFBagBucket *currentBucket = buckets + probe; - if (__CFBagBucketIsEmpty(bag, currentBucket)) { - if (!*nomatch) *nomatch = currentBucket; - return; - } else if (__CFBagBucketIsDeleted(bag, currentBucket)) { - if (!*nomatch) *nomatch = currentBucket; - } else if (!*match && (currentBucket->_key == key || (cb->equal && INVOKE_CALLBACK3((Boolean (*)(const void *, const void *, void *))cb->equal, currentBucket->_key, key, bag->_context)))) { - *match = currentBucket; - return; - } - probe = (probe + probeskip) % bag->_bucketsNum; - if (start == probe) return; - } -} - -static void __CFBagFindNewEmptyMarker(CFBagRef bag) { - struct __CFBagBucket *buckets; - const void *newEmpty; - bool hit; - CFIndex idx, nbuckets; - buckets = bag->_buckets; - nbuckets = bag->_bucketsNum; - newEmpty = bag->_emptyMarker; - do { - (intptr_t)newEmpty -= 2; - hit = false; - for (idx = 0; idx < nbuckets; idx++) { - if (newEmpty == buckets[idx]._key) { - hit = true; - break; - } - } - } while (hit); - for (idx = 0; idx < nbuckets; idx++) { - if (bag->_emptyMarker == buckets[idx]._key) { - buckets[idx]._key = newEmpty; - } - } - ((struct __CFBag *)bag)->_emptyMarker = newEmpty; -} - -static void __CFBagFindNewDeletedMarker(CFBagRef bag) { - struct __CFBagBucket *buckets; - const void *newDeleted; - bool hit; - CFIndex idx, nbuckets; - buckets = bag->_buckets; - nbuckets = bag->_bucketsNum; - newDeleted = bag->_deletedMarker; - do { - (intptr_t)newDeleted += 2; - hit = false; - for (idx = 0; idx < nbuckets; idx++) { - if (newDeleted == buckets[idx]._key) { - hit = true; - break; - } - } - } while (hit); - for (idx = 0; idx < nbuckets; idx++) { - if (bag->_deletedMarker == buckets[idx]._key) { - buckets[idx]._key = newDeleted; - } - } - ((struct __CFBag *)bag)->_deletedMarker = newDeleted; -} - -static bool __CFBagEqual(CFTypeRef cf1, CFTypeRef cf2) { - CFBagRef bag1 = (CFBagRef)cf1; - CFBagRef bag2 = (CFBagRef)cf2; - const CFBagCallBacks *cb1, *cb2; - const struct __CFBagBucket *buckets; - CFIndex idx, nbuckets; - if (bag1 == bag2) return true; - if (bag1->_count != bag2->_count) return false; - cb1 = __CFBagGetCallBacks(bag1); - cb2 = __CFBagGetCallBacks(bag2); - if (cb1->equal != cb2->equal) return false; - if (0 == bag1->_count) return true; /* after function comparison! */ - buckets = bag1->_buckets; - nbuckets = bag1->_bucketsNum; - for (idx = 0; idx < nbuckets; idx++) { - if (__CFBagBucketIsOccupied(bag1, &buckets[idx])) { - if (buckets[idx]._count != CFBagGetCountOfValue(bag2, buckets[idx]._key)) { - return false; - } - } - } - return true; -} - -static CFHashCode __CFBagHash(CFTypeRef cf) { - CFBagRef bag = (CFBagRef)cf; - return bag->_count; -} - -static CFStringRef __CFBagCopyDescription(CFTypeRef cf) { - CFBagRef bag = (CFBagRef)cf; - const CFBagCallBacks *cb; - const struct __CFBagBucket *buckets; - CFIndex idx, nbuckets; - CFMutableStringRef result; - cb = __CFBagGetCallBacks(bag); - buckets = bag->_buckets; - nbuckets = bag->_bucketsNum; - result = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); - CFStringAppendFormat(result, NULL, CFSTR("{count = %u, capacity = %u, values = (\n"), bag, CFGetAllocator(bag), bag->_count, bag->_capacity); - for (idx = 0; idx < nbuckets; idx++) { - if (__CFBagBucketIsOccupied(bag, &buckets[idx])) { - CFStringRef desc = NULL; - if (NULL != cb->copyDescription) { - desc = (CFStringRef)INVOKE_CALLBACK2(((CFStringRef (*)(const void *, void *))cb->copyDescription), buckets[idx]._key, bag->_context); - } - if (NULL != desc) { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@ (%d)\n"), idx, desc, buckets[idx]._count); - CFRelease(desc); - } else { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p> (%d)\n"), idx, buckets[idx]._key, buckets[idx]._count); - } - } - } - CFStringAppend(result, CFSTR(")}")); - return result; -} - -static void __CFBagDeallocate(CFTypeRef cf) { - CFMutableBagRef bag = (CFMutableBagRef)cf; - CFAllocatorRef allocator = CFGetAllocator(bag); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - const CFBagCallBacks *cb = __CFBagGetCallBacks(bag); - if (cb->retain == NULL && cb->release == NULL) - return; // XXX_PCB keep bag intact during finalization. - } - if (__CFBagGetType(bag) == __kCFBagImmutable) { - __CFBitfieldSetValue(((CFRuntimeBase *)bag)->_info, 1, 0, __kCFBagFixedMutable); - } - CFBagRemoveAllValues(bag); - if (__CFBagGetType(bag) == __kCFBagMutable && bag->_buckets) { - _CFAllocatorDeallocateGC(allocator, bag->_buckets); - } -} - -static CFTypeID __kCFBagTypeID = _kCFRuntimeNotATypeID; - -static const CFRuntimeClass __CFBagClass = { - _kCFRuntimeScannedObject, - "CFBag", - NULL, // init - NULL, // copy - __CFBagDeallocate, - (void *)__CFBagEqual, - __CFBagHash, - NULL, // - __CFBagCopyDescription -}; - -__private_extern__ void __CFBagInitialize(void) { - __kCFBagTypeID = _CFRuntimeRegisterClass(&__CFBagClass); -} - -CFTypeID CFBagGetTypeID(void) { - return __kCFBagTypeID; -} - -static CFBagRef __CFBagInit(CFAllocatorRef allocator, UInt32 flags, CFIndex capacity, const CFBagCallBacks *callBacks) { - struct __CFBag *memory; - UInt32 size; - CFIndex idx; - CFBagCallBacks nonRetainingCallbacks; - __CFBitfieldSetValue(flags, 31, 2, 0); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - if (!callBacks || (callBacks->retain == NULL && callBacks->release == NULL)) { - __CFBitfieldSetValue(flags, 4, 4, 1); // setWeak - } - else { - if (callBacks->retain == __CFTypeCollectionRetain && callBacks->release == __CFTypeCollectionRelease) { - nonRetainingCallbacks = *callBacks; - nonRetainingCallbacks.retain = NULL; - nonRetainingCallbacks.release = NULL; - callBacks = &nonRetainingCallbacks; - __CFBitfieldSetValue(flags, 5, 5, 1); // setNeedsRestore - } - } - } - if (__CFBagCallBacksMatchNull(callBacks)) { - __CFBitfieldSetValue(flags, 3, 2, __kCFBagHasNullCallBacks); - } else if (__CFBagCallBacksMatchCFType(callBacks)) { - __CFBitfieldSetValue(flags, 3, 2, __kCFBagHasCFTypeCallBacks); - } else { - __CFBitfieldSetValue(flags, 3, 2, __kCFBagHasCustomCallBacks); - } - size = __CFBagGetSizeOfType(flags) - sizeof(CFRuntimeBase); - switch (__CFBitfieldGetValue(flags, 1, 0)) { - case __kCFBagImmutable: - case __kCFBagFixedMutable: - size += __CFBagNumBucketsForCapacity(capacity) * sizeof(struct __CFBagBucket); - break; - case __kCFBagMutable: - break; - } - memory = (struct __CFBag *)_CFRuntimeCreateInstance(allocator, __kCFBagTypeID, size, NULL); - if (NULL == memory) { - return NULL; - } - __CFBitfieldSetValue(memory->_base._info, 6, 0, flags); - memory->_count = 0; - memory->_bucketsUsed = 0; - memory->_emptyMarker = (const void *)0xa1b1c1d3; - memory->_deletedMarker = (const void *)0xa1b1c1d5; - memory->_context = NULL; - switch (__CFBitfieldGetValue(flags, 1, 0)) { - case __kCFBagImmutable: - if (!isStrongMemory(memory)) { // if weak, don't scan - auto_zone_set_layout_type(__CFCollectableZone, memory, AUTO_OBJECT_UNSCANNED); - } - if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFBag (immutable)"); - memory->_capacity = capacity; /* Don't round up capacity */ - memory->_bucketsNum = __CFBagNumBucketsForCapacity(memory->_capacity); - memory->_buckets = (struct __CFBagBucket *)((uint8_t *)memory + __CFBagGetSizeOfType(flags)); - for (idx = memory->_bucketsNum; idx--;) { - memory->_buckets[idx]._key = memory->_emptyMarker; - } - break; - case __kCFBagFixedMutable: - if (!isStrongMemory(memory)) { // if weak, don't scan - auto_zone_set_layout_type(__CFCollectableZone, memory, AUTO_OBJECT_UNSCANNED); - } - if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFBag (mutable-fixed)"); - memory->_capacity = capacity; /* Don't round up capacity */ - memory->_bucketsNum = __CFBagNumBucketsForCapacity(memory->_capacity); - memory->_buckets = (struct __CFBagBucket *)((uint8_t *)memory + __CFBagGetSizeOfType(flags)); - for (idx = memory->_bucketsNum; idx--;) { - memory->_buckets[idx]._key = memory->_emptyMarker; - } - break; - case __kCFBagMutable: - if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFBag (mutable-variable)"); - memory->_capacity = __CFBagRoundUpCapacity(1); - memory->_bucketsNum = 0; - memory->_buckets = NULL; - break; - } - if (__kCFBagHasCustomCallBacks == __CFBitfieldGetValue(flags, 3, 2)) { - const CFBagCallBacks *cb = __CFBagGetCallBacks((CFBagRef)memory); - *(CFBagCallBacks *)cb = *callBacks; - FAULT_CALLBACK((void **)&(cb->retain)); - FAULT_CALLBACK((void **)&(cb->release)); - FAULT_CALLBACK((void **)&(cb->copyDescription)); - FAULT_CALLBACK((void **)&(cb->equal)); - FAULT_CALLBACK((void **)&(cb->hash)); - } - return (CFBagRef)memory; -} - -CFBagRef CFBagCreate(CFAllocatorRef allocator, const void **values, CFIndex numValues, const CFBagCallBacks *callBacks) { - CFBagRef result; - UInt32 flags; - CFIndex idx; - CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%d) cannot be less than zero", __PRETTY_FUNCTION__, numValues); - result = __CFBagInit(allocator, __kCFBagImmutable, numValues, callBacks); - flags = __CFBitfieldGetValue(((const CFRuntimeBase *)result)->_info, 1, 0); - if (flags == __kCFBagImmutable) { - __CFBitfieldSetValue(((CFRuntimeBase *)result)->_info, 1, 0, __kCFBagFixedMutable); - } - for (idx = 0; idx < numValues; idx++) { - CFBagAddValue((CFMutableBagRef)result, values[idx]); - } - __CFBitfieldSetValue(((CFRuntimeBase *)result)->_info, 1, 0, flags); - return result; -} - -CFMutableBagRef CFBagCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFBagCallBacks *callBacks) { - CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%d) cannot be less than zero", __PRETTY_FUNCTION__, capacity); - return (CFMutableBagRef)__CFBagInit(allocator, (0 == capacity) ? __kCFBagMutable : __kCFBagFixedMutable, capacity, callBacks); -} - -CFBagRef CFBagCreateCopy(CFAllocatorRef allocator, CFBagRef bag) { - CFBagRef result; - const CFBagCallBacks *cb; - CFIndex numValues = CFBagGetCount(bag); - const void **list, *buffer[256]; - list = (numValues <= 256) ? buffer : CFAllocatorAllocate(allocator, numValues * sizeof(void *), 0); // XXX_PCB GC OK - if (list != buffer && __CFOASafe) __CFSetLastAllocationEventName(list, "CFBag (temp)"); - CFBagGetValues(bag, list); - CFBagCallBacks patchedCB; - if (CF_IS_OBJC(__kCFBagTypeID, bag)) { - cb = &kCFTypeBagCallBacks; - } - else { - cb = __CFBagGetCallBacks(bag); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - if (needsRestore(bag)) { - patchedCB = *cb; // copy - cb = &patchedCB; // reset to copy - patchedCB.retain = __CFTypeCollectionRetain; - patchedCB.release = __CFTypeCollectionRelease; - } - } - } - result = CFBagCreate(allocator, list, numValues, cb); - if (list != buffer) CFAllocatorDeallocate(allocator, list); // XXX_PCB GC OK - return result; -} - -CFMutableBagRef CFBagCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFBagRef bag) { - CFMutableBagRef result; - const CFBagCallBacks *cb; - CFIndex idx, numValues = CFBagGetCount(bag); - const void **list, *buffer[256]; - CFAssert3(0 == capacity || numValues <= capacity, __kCFLogAssertion, "%s(): for fixed-mutable bags, capacity (%d) must be greater than or equal to initial number of values (%d)", __PRETTY_FUNCTION__, capacity, numValues); - list = (numValues <= 256) ? buffer : CFAllocatorAllocate(allocator, numValues * sizeof(void *), 0); // XXX_PCB GC OK - if (list != buffer && __CFOASafe) __CFSetLastAllocationEventName(list, "CFBag (temp)"); - CFBagGetValues(bag, list); - CFBagCallBacks patchedCB; - if (CF_IS_OBJC(__kCFBagTypeID, bag)) { - cb = &kCFTypeBagCallBacks; - } - else { - cb = __CFBagGetCallBacks(bag); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - if (needsRestore(bag)) { - patchedCB = *cb; // copy - cb = &patchedCB; // reset to copy - patchedCB.retain = __CFTypeCollectionRetain; - patchedCB.release = __CFTypeCollectionRelease; - } - } - } - result = CFBagCreateMutable(allocator, capacity, cb); - if (0 == capacity) _CFBagSetCapacity(result, numValues); - for (idx = 0; idx < numValues; idx++) { - CFBagAddValue(result, list[idx]); - } - if (list != buffer) CFAllocatorDeallocate(allocator, list); // GC OK - return result; -} - - -void _CFBagSetContext(CFBagRef bag, void *context) { - CFAllocatorRef allocator = CFGetAllocator(bag); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, bag, bag->_context, context); -} - -CFIndex CFBagGetCount(CFBagRef bag) { - __CFGenericValidateType(bag, __kCFBagTypeID); - return bag->_count; -} - -CFIndex CFBagGetCountOfValue(CFBagRef bag, const void *value) { - struct __CFBagBucket *match; - __CFGenericValidateType(bag, __kCFBagTypeID); - if (0 == bag->_count) return 0; - __CFBagFindBuckets1(bag, value, &match); - return (match ? match->_count : 0); -} - -Boolean CFBagContainsValue(CFBagRef bag, const void *value) { - struct __CFBagBucket *match; - __CFGenericValidateType(bag, __kCFBagTypeID); - if (0 == bag->_count) return false; - __CFBagFindBuckets1(bag, value, &match); - return (match ? true : false); -} - -const void *CFBagGetValue(CFBagRef bag, const void *value) { - struct __CFBagBucket *match; - __CFGenericValidateType(bag, __kCFBagTypeID); - if (0 == bag->_count) return NULL; - __CFBagFindBuckets1(bag, value, &match); - return (match ? match->_key : NULL); -} - -Boolean CFBagGetValueIfPresent(CFBagRef bag, const void *candidate, const void **value) { - struct __CFBagBucket *match; - __CFGenericValidateType(bag, __kCFBagTypeID); - if (0 == bag->_count) return false; - __CFBagFindBuckets1(bag, candidate, &match); - return (match ? ((value ? __CFObjCStrongAssign(match->_key, value) : NULL), true) : false); -} - -void CFBagGetValues(CFBagRef bag, const void **values) { - struct __CFBagBucket *buckets; - CFIndex idx, cnt, nbuckets; - __CFGenericValidateType(bag, __kCFBagTypeID); - if (CF_USING_COLLECTABLE_MEMORY) { - // GC: speculatively issue a write-barrier on the copied to buffers (3743553). - __CFObjCWriteBarrierRange(values, bag->_count * sizeof(void *)); - } - buckets = bag->_buckets; - nbuckets = bag->_bucketsNum; - for (idx = 0; idx < nbuckets; idx++) { - if (__CFBagBucketIsOccupied(bag, &buckets[idx])) { - for (cnt = buckets[idx]._count; cnt--;) { - if (values) *values++ = buckets[idx]._key; - } - } - } -} - -void CFBagApplyFunction(CFBagRef bag, CFBagApplierFunction applier, void *context) { - struct __CFBagBucket *buckets; - CFIndex idx, cnt, nbuckets; - FAULT_CALLBACK((void **)&(applier)); - __CFGenericValidateType(bag, __kCFBagTypeID); - buckets = bag->_buckets; - nbuckets = bag->_bucketsNum; - for (idx = 0; idx < nbuckets; idx++) { - if (__CFBagBucketIsOccupied(bag, &buckets[idx])) { - for (cnt = buckets[idx]._count; cnt--;) { - INVOKE_CALLBACK2(applier, buckets[idx]._key, context); - } - } - } -} - -static void __CFBagGrow(CFMutableBagRef bag, CFIndex numNewValues) { - struct __CFBagBucket *oldbuckets = bag->_buckets; - CFIndex idx, oldnbuckets = bag->_bucketsNum; - CFIndex oldCount = bag->_count; - CFAllocatorRef allocator = CFGetAllocator(bag); - bag->_capacity = __CFBagRoundUpCapacity(oldCount + numNewValues); - bag->_bucketsNum = __CFBagNumBucketsForCapacity(bag->_capacity); - void *bucket = _CFAllocatorAllocateGC(allocator, bag->_bucketsNum * sizeof(struct __CFBagBucket), isStrongMemory(bag) ? AUTO_MEMORY_SCANNED : AUTO_MEMORY_UNSCANNED); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, bag, bag->_buckets, bucket); - if (__CFOASafe) __CFSetLastAllocationEventName(bag->_buckets, "CFBag (store)"); - if (NULL == bag->_buckets) HALT; - for (idx = bag->_bucketsNum; idx--;) { - bag->_buckets[idx]._key = bag->_emptyMarker; - } - if (NULL == oldbuckets) return; - for (idx = 0; idx < oldnbuckets; idx++) { - if (__CFBagBucketIsOccupied(bag, &oldbuckets[idx])) { - struct __CFBagBucket *match, *nomatch; - __CFBagFindBuckets2(bag, oldbuckets[idx]._key, &match, &nomatch); - CFAssert3(!match, __kCFLogAssertion, "%s(): two values (%p, %p) now hash to the same slot; mutable value changed while in table or hash value is not immutable", __PRETTY_FUNCTION__, oldbuckets[idx]._key, match->_key); - if (nomatch) { - CF_WRITE_BARRIER_ASSIGN(allocator, nomatch->_key, oldbuckets[idx]._key); - nomatch->_count = oldbuckets[idx]._count; - } - } - } - CFAssert1(bag->_count == oldCount, __kCFLogAssertion, "%s(): bag count differs after rehashing; error", __PRETTY_FUNCTION__); - _CFAllocatorDeallocateGC(CFGetAllocator(bag), oldbuckets); -} - -// This function is for Foundation's benefit; no one else should use it. -void _CFBagSetCapacity(CFMutableBagRef bag, CFIndex cap) { - if (CF_IS_OBJC(__kCFBagTypeID, bag)) return; -#if defined(DEBUG) - __CFGenericValidateType(bag, __kCFBagTypeID); - CFAssert1(__CFBagGetType(bag) != __kCFBagImmutable && __CFBagGetType(bag) != __kCFBagFixedMutable, __kCFLogAssertion, "%s(): bag is immutable or fixed-mutable", __PRETTY_FUNCTION__); - CFAssert3(bag->_count <= cap, __kCFLogAssertion, "%s(): desired capacity (%d) is less than count (%d)", __PRETTY_FUNCTION__, cap, bag->_count); -#endif - __CFBagGrow(bag, cap - bag->_count); -} - -void CFBagAddValue(CFMutableBagRef bag, const void *value) { - struct __CFBagBucket *match, *nomatch; - CFAllocatorRef allocator; - const CFBagCallBacks *cb; - const void *newValue; - __CFGenericValidateType(bag, __kCFBagTypeID); - switch (__CFBagGetType(bag)) { - case __kCFBagMutable: - if (bag->_bucketsUsed == bag->_capacity || NULL == bag->_buckets) { - __CFBagGrow(bag, 1); - } - break; - case __kCFBagFixedMutable: - CFAssert3(bag->_count < bag->_capacity, __kCFLogAssertion, "%s(): capacity exceeded on fixed-capacity bag %p (capacity = %d)", __PRETTY_FUNCTION__, bag, bag->_capacity); - break; - default: - CFAssert2(__CFBagGetType(bag) != __kCFBagImmutable, __kCFLogAssertion, "%s(): immutable bag %p passed to mutating operation", __PRETTY_FUNCTION__, bag); - break; - } - __CFBagFindBuckets2(bag, value, &match, &nomatch); - if (match) { - match->_count++; bag->_count++; - } else { - allocator = CFGetAllocator(bag); - cb = __CFBagGetCallBacks(bag); - if (cb->retain) { - newValue = (void *)INVOKE_CALLBACK3(((const void *(*)(CFAllocatorRef, const void *, void *))cb->retain), allocator, value, bag->_context); - } else { - newValue = value; - } - if (bag->_emptyMarker == newValue) { - __CFBagFindNewEmptyMarker(bag); - } - if (bag->_deletedMarker == newValue) { - __CFBagFindNewDeletedMarker(bag); - } - CF_WRITE_BARRIER_ASSIGN(allocator, nomatch->_key, newValue); - nomatch->_count = 1; - bag->_bucketsUsed++; - bag->_count++; - } -} - -void CFBagReplaceValue(CFMutableBagRef bag, const void *value) { - struct __CFBagBucket *match; - CFAllocatorRef allocator; - const CFBagCallBacks *cb; - const void *newValue; - __CFGenericValidateType(bag, __kCFBagTypeID); - switch (__CFBagGetType(bag)) { - case __kCFBagMutable: - case __kCFBagFixedMutable: - break; - default: - CFAssert2(__CFBagGetType(bag) != __kCFBagImmutable, __kCFLogAssertion, "%s(): immutable bag %p passed to mutating operation", __PRETTY_FUNCTION__, bag); - break; - } - if (0 == bag->_count) return; - __CFBagFindBuckets1(bag, value, &match); - if (!match) return; - allocator = CFGetAllocator(bag); - cb = __CFBagGetCallBacks(bag); - if (cb->retain) { - newValue = (void *)INVOKE_CALLBACK3(((const void *(*)(CFAllocatorRef, const void *, void *))cb->retain), allocator, value, bag->_context); - } else { - newValue = value; - } - if (cb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))cb->release), allocator, match->_key, bag->_context); - match->_key = bag->_deletedMarker; - } - if (bag->_emptyMarker == newValue) { - __CFBagFindNewEmptyMarker(bag); - } - if (bag->_deletedMarker == newValue) { - __CFBagFindNewDeletedMarker(bag); - } - CF_WRITE_BARRIER_ASSIGN(allocator, match->_key, newValue); -} - -void CFBagSetValue(CFMutableBagRef bag, const void *value) { - struct __CFBagBucket *match, *nomatch; - CFAllocatorRef allocator; - const CFBagCallBacks *cb; - const void *newValue; - __CFGenericValidateType(bag, __kCFBagTypeID); - switch (__CFBagGetType(bag)) { - case __kCFBagMutable: - if (bag->_bucketsUsed == bag->_capacity || NULL == bag->_buckets) { - __CFBagGrow(bag, 1); - } - break; - case __kCFBagFixedMutable: - break; - default: - CFAssert2(__CFBagGetType(bag) != __kCFBagImmutable, __kCFLogAssertion, "%s(): immutable bag %p passed to mutating operation", __PRETTY_FUNCTION__, bag); - break; - } - __CFBagFindBuckets2(bag, value, &match, &nomatch); - allocator = CFGetAllocator(bag); - cb = __CFBagGetCallBacks(bag); - if (cb->retain) { - newValue = (void *)INVOKE_CALLBACK3(((const void *(*)(CFAllocatorRef, const void *, void *))cb->retain), allocator, value, bag->_context); - } else { - newValue = value; - } - if (match) { - if (cb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))cb->release), allocator, match->_key, bag->_context); - match->_key = bag->_deletedMarker; - } - if (bag->_emptyMarker == newValue) { - __CFBagFindNewEmptyMarker(bag); - } - if (bag->_deletedMarker == newValue) { - __CFBagFindNewDeletedMarker(bag); - } - CF_WRITE_BARRIER_ASSIGN(allocator, match->_key, newValue); - } else { - CFAssert3(__kCFBagFixedMutable != __CFBagGetType(bag) || bag->_count < bag->_capacity, __kCFLogAssertion, "%s(): capacity exceeded on fixed-capacity bag %p (capacity = %d)", __PRETTY_FUNCTION__, bag, bag->_capacity); - if (bag->_emptyMarker == newValue) { - __CFBagFindNewEmptyMarker(bag); - } - if (bag->_deletedMarker == newValue) { - __CFBagFindNewDeletedMarker(bag); - } - CF_WRITE_BARRIER_ASSIGN(allocator, nomatch->_key, newValue); - nomatch->_count = 1; - bag->_bucketsUsed++; - bag->_count++; - } -} - -void CFBagRemoveValue(CFMutableBagRef bag, const void *value) { - struct __CFBagBucket *match; - const CFBagCallBacks *cb; - __CFGenericValidateType(bag, __kCFBagTypeID); - switch (__CFBagGetType(bag)) { - case __kCFBagMutable: - case __kCFBagFixedMutable: - break; - default: - CFAssert2(__CFBagGetType(bag) != __kCFBagImmutable, __kCFLogAssertion, "%s(): immutable bag %p passed to mutating operation", __PRETTY_FUNCTION__, bag); - break; - } - if (0 == bag->_count) return; - __CFBagFindBuckets1(bag, value, &match); - if (!match) return; - match->_count--; bag->_count--; - if (0 == match->_count) { - cb = __CFBagGetCallBacks(bag); - if (cb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))cb->release), CFGetAllocator(bag), match->_key, bag->_context); - } - match->_key = bag->_deletedMarker; - bag->_bucketsUsed--; - } -} - -void CFBagRemoveAllValues(CFMutableBagRef bag) { - struct __CFBagBucket *buckets; - const CFBagCallBacks *cb; - CFAllocatorRef allocator; - CFIndex idx, nbuckets; - __CFGenericValidateType(bag, __kCFBagTypeID); - switch (__CFBagGetType(bag)) { - case __kCFBagMutable: - case __kCFBagFixedMutable: - break; - default: - CFAssert2(__CFBagGetType(bag) != __kCFBagImmutable, __kCFLogAssertion, "%s(): immutable bag %p passed to mutating operation", __PRETTY_FUNCTION__, bag); - break; - } - if (0 == bag->_count) return; - buckets = bag->_buckets; - nbuckets = bag->_bucketsNum; - cb = __CFBagGetCallBacks(bag); - allocator = CFGetAllocator(bag); - for (idx = 0; idx < nbuckets; idx++) { - if (__CFBagBucketIsOccupied(bag, &buckets[idx])) { - if (cb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))cb->release), allocator, buckets[idx]._key, bag->_context); - } - buckets[idx]._key = bag->_emptyMarker; - buckets[idx]._count = 0; - } - } - bag->_bucketsUsed = 0; - bag->_count = 0; -} - diff --git a/Collections.subproj/CFDictionary.c b/Collections.subproj/CFDictionary.c deleted file mode 100644 index 706d3e9..0000000 --- a/Collections.subproj/CFDictionary.c +++ /dev/null @@ -1,1337 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFDictionary.c - Copyright 1998-2002, Apple, Inc. All rights reserved. - Responsibility: Christopher Kane -*/ - -#include -#include "CFInternal.h" - -const CFDictionaryKeyCallBacks kCFTypeDictionaryKeyCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; -const CFDictionaryKeyCallBacks kCFCopyStringDictionaryKeyCallBacks = {0, (void *)CFStringCreateCopy, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; -const CFDictionaryValueCallBacks kCFTypeDictionaryValueCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual}; -static const CFDictionaryKeyCallBacks __kCFNullDictionaryKeyCallBacks = {0, NULL, NULL, NULL, NULL, NULL}; -static const CFDictionaryValueCallBacks __kCFNullDictionaryValueCallBacks = {0, NULL, NULL, NULL, NULL}; - -static const uint32_t __CFDictionaryCapacities[42] = { - 4, 8, 17, 29, 47, 76, 123, 199, 322, 521, 843, 1364, 2207, 3571, 5778, 9349, - 15127, 24476, 39603, 64079, 103682, 167761, 271443, 439204, 710647, 1149851, 1860498, - 3010349, 4870847, 7881196, 12752043, 20633239, 33385282, 54018521, 87403803, 141422324, - 228826127, 370248451, 599074578, 969323029, 1568397607, 2537720636U -}; - -static const uint32_t __CFDictionaryBuckets[42] = { // primes - 5, 11, 23, 41, 67, 113, 199, 317, 521, 839, 1361, 2207, 3571, 5779, 9349, 15121, - 24473, 39607, 64081, 103681, 167759, 271429, 439199, 710641, 1149857, 1860503, 3010349, - 4870843, 7881193, 12752029, 20633237, 33385273, 54018521, 87403763, 141422317, 228826121, - 370248451, 599074561, 969323023, 1568397599, 2537720629U, 4106118251U -}; - -CF_INLINE CFIndex __CFDictionaryRoundUpCapacity(CFIndex capacity) { - CFIndex idx; - for (idx = 0; idx < 42 && __CFDictionaryCapacities[idx] < (uint32_t)capacity; idx++); - if (42 <= idx) HALT; - return __CFDictionaryCapacities[idx]; -} - -CF_INLINE CFIndex __CFDictionaryNumBucketsForCapacity(CFIndex capacity) { - CFIndex idx; - for (idx = 0; idx < 42 && __CFDictionaryCapacities[idx] < (uint32_t)capacity; idx++); - if (42 <= idx) HALT; - return __CFDictionaryBuckets[idx]; -} - -enum { /* Bits 1-0 */ - __kCFDictionaryImmutable = 0, /* unchangable and fixed capacity */ - __kCFDictionaryMutable = 1, /* changeable and variable capacity */ - __kCFDictionaryFixedMutable = 3 /* changeable and fixed capacity */ -}; - -enum { /* Bits 5-4 (value), 3-2 (key) */ - __kCFDictionaryHasNullCallBacks = 0, - __kCFDictionaryHasCFTypeCallBacks = 1, - __kCFDictionaryHasCustomCallBacks = 3 /* callbacks are at end of header */ -}; - -// Under GC, we fudge the key/value memory in two ways -// First, if we had null callbacks or null for both retain/release, we use unscanned memory -// This means that if people were doing addValue:[xxx new] and never removing, well, that doesn't work -// -// Second, if we notice standard retain/release implementations we substitute scanned memory -// and zero out the retain/release callbacks. This is fine, but when copying we need to restore them - -enum { - __kCFDictionaryRestoreKeys = (1 << 0), - __kCFDictionaryRestoreValues = (1 << 1), - __kCFDictionaryRestoreStringKeys = (1 << 2), - __kCFDictionaryWeakKeys = (1 << 3), - __kCFDictionaryWeakValues = (1 << 4) -}; - -struct __CFDictionary { - CFRuntimeBase _base; - CFIndex _count; /* number of values */ - CFIndex _capacity; /* maximum number of values */ - CFIndex _bucketsNum; /* number of slots */ - uintptr_t _marker; - void *_context; /* private */ - CFIndex _deletes; - CFOptionFlags _xflags; /* bits for GC */ - const void **_keys; /* can be NULL if not allocated yet */ - const void **_values; /* can be NULL if not allocated yet */ -}; - -/* Bits 1-0 of the base reserved bits are used for mutability variety */ -/* Bits 3-2 of the base reserved bits are used for key callback indicator bits */ -/* Bits 5-4 of the base reserved bits are used for value callback indicator bits */ -/* Bit 6 is special KVO actions bit */ - -CF_INLINE CFIndex __CFDictionaryGetType(CFDictionaryRef dict) { - return __CFBitfieldGetValue(((const CFRuntimeBase *)dict)->_info, 1, 0); -} - -CF_INLINE CFIndex __CFDictionaryGetSizeOfType(CFIndex t) { - CFIndex size = sizeof(struct __CFDictionary); - if (__CFBitfieldGetValue(t, 3, 2) == __kCFDictionaryHasCustomCallBacks) { - size += sizeof(CFDictionaryKeyCallBacks); - } - if (__CFBitfieldGetValue(t, 5, 4) == __kCFDictionaryHasCustomCallBacks) { - size += sizeof(CFDictionaryValueCallBacks); - } - return size; -} - -CF_INLINE const CFDictionaryKeyCallBacks *__CFDictionaryGetKeyCallBacks(CFDictionaryRef dict) { - CFDictionaryKeyCallBacks *result = NULL; - switch (__CFBitfieldGetValue(((const CFRuntimeBase *)dict)->_info, 3, 2)) { - case __kCFDictionaryHasNullCallBacks: - return &__kCFNullDictionaryKeyCallBacks; - case __kCFDictionaryHasCFTypeCallBacks: - return &kCFTypeDictionaryKeyCallBacks; - case __kCFDictionaryHasCustomCallBacks: - break; - } - result = (CFDictionaryKeyCallBacks *)((uint8_t *)dict + sizeof(struct __CFDictionary)); - return result; -} - -CF_INLINE bool __CFDictionaryKeyCallBacksMatchNull(const CFDictionaryKeyCallBacks *c) { - return (NULL == c || - (c->retain == __kCFNullDictionaryKeyCallBacks.retain && - c->release == __kCFNullDictionaryKeyCallBacks.release && - c->copyDescription == __kCFNullDictionaryKeyCallBacks.copyDescription && - c->equal == __kCFNullDictionaryKeyCallBacks.equal && - c->hash == __kCFNullDictionaryKeyCallBacks.hash)); -} - -CF_INLINE bool __CFDictionaryKeyCallBacksMatchCFType(const CFDictionaryKeyCallBacks *c) { - return (&kCFTypeDictionaryKeyCallBacks == c || - (c->retain == kCFTypeDictionaryKeyCallBacks.retain && - c->release == kCFTypeDictionaryKeyCallBacks.release && - c->copyDescription == kCFTypeDictionaryKeyCallBacks.copyDescription && - c->equal == kCFTypeDictionaryKeyCallBacks.equal && - c->hash == kCFTypeDictionaryKeyCallBacks.hash)); -} - -CF_INLINE const CFDictionaryValueCallBacks *__CFDictionaryGetValueCallBacks(CFDictionaryRef dict) { - CFDictionaryValueCallBacks *result = NULL; - switch (__CFBitfieldGetValue(((const CFRuntimeBase *)dict)->_info, 5, 4)) { - case __kCFDictionaryHasNullCallBacks: - return &__kCFNullDictionaryValueCallBacks; - case __kCFDictionaryHasCFTypeCallBacks: - return &kCFTypeDictionaryValueCallBacks; - case __kCFDictionaryHasCustomCallBacks: - break; - } - if (__CFBitfieldGetValue(((const CFRuntimeBase *)dict)->_info, 3, 2) == __kCFDictionaryHasCustomCallBacks) { - result = (CFDictionaryValueCallBacks *)((uint8_t *)dict + sizeof(struct __CFDictionary) + sizeof(CFDictionaryKeyCallBacks)); - } else { - result = (CFDictionaryValueCallBacks *)((uint8_t *)dict + sizeof(struct __CFDictionary)); - } - return result; -} - -CF_INLINE bool __CFDictionaryValueCallBacksMatchNull(const CFDictionaryValueCallBacks *c) { - return (NULL == c || - (c->retain == __kCFNullDictionaryValueCallBacks.retain && - c->release == __kCFNullDictionaryValueCallBacks.release && - c->copyDescription == __kCFNullDictionaryValueCallBacks.copyDescription && - c->equal == __kCFNullDictionaryValueCallBacks.equal)); -} - -CF_INLINE bool __CFDictionaryValueCallBacksMatchCFType(const CFDictionaryValueCallBacks *c) { - return (&kCFTypeDictionaryValueCallBacks == c || - (c->retain == kCFTypeDictionaryValueCallBacks.retain && - c->release == kCFTypeDictionaryValueCallBacks.release && - c->copyDescription == kCFTypeDictionaryValueCallBacks.copyDescription && - c->equal == kCFTypeDictionaryValueCallBacks.equal)); -} - -CFIndex _CFDictionaryGetKVOBit(CFDictionaryRef dict) { - return __CFBitfieldGetValue(((const CFRuntimeBase *)dict)->_info, 6, 6); -} - -void _CFDictionarySetKVOBit(CFDictionaryRef dict, CFIndex bit) { - __CFBitfieldSetValue(((CFRuntimeBase *)dict)->_info, 6, 6, (bit & 0x1)); -} - -CF_INLINE bool _CFDictionaryIsSplit(CFDictionaryRef dict) { - return ((dict->_xflags & (__kCFDictionaryWeakKeys|__kCFDictionaryWeakValues)) != 0); -} - - -#define CF_OBJC_KVO_WILLCHANGE(obj, sel) -#define CF_OBJC_KVO_DIDCHANGE(obj, sel) - - - -static CFIndex __CFDictionaryFindBuckets1a(CFDictionaryRef dict, const void *key) { - CFHashCode keyHash = (CFHashCode)key; - const void **keys = dict->_keys; - uintptr_t marker = dict->_marker; - CFIndex probe = keyHash % dict->_bucketsNum; - CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value - CFIndex start = probe; - for (;;) { - uintptr_t currKey = (uintptr_t)keys[probe]; - if (marker == currKey) { /* empty */ - return kCFNotFound; - } else if (~marker == currKey) { /* deleted */ - /* do nothing */ - } else if (currKey == (uintptr_t)key) { - return probe; - } - probe = probe + probeskip; - // This alternative to probe % buckets assumes that - // probeskip is always positive and less than the - // number of buckets. - if (dict->_bucketsNum <= probe) { - probe -= dict->_bucketsNum; - } - if (start == probe) { - return kCFNotFound; - } - } -} - -static CFIndex __CFDictionaryFindBuckets1b(CFDictionaryRef dict, const void *key) { - const CFDictionaryKeyCallBacks *cb = __CFDictionaryGetKeyCallBacks(dict); - CFHashCode keyHash = cb->hash ? (CFHashCode)INVOKE_CALLBACK2(((CFHashCode (*)(const void *, void *))cb->hash), key, dict->_context) : (CFHashCode)key; - const void **keys = dict->_keys; - uintptr_t marker = dict->_marker; - CFIndex probe = keyHash % dict->_bucketsNum; - CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value - CFIndex start = probe; - for (;;) { - uintptr_t currKey = (uintptr_t)keys[probe]; - if (marker == currKey) { /* empty */ - return kCFNotFound; - } else if (~marker == currKey) { /* deleted */ - /* do nothing */ - } else if (currKey == (uintptr_t)key || (cb->equal && INVOKE_CALLBACK3((Boolean (*)(const void *, const void *, void*))cb->equal, (void *)currKey, key, dict->_context))) { - return probe; - } - probe = probe + probeskip; - // This alternative to probe % buckets assumes that - // probeskip is always positive and less than the - // number of buckets. - if (dict->_bucketsNum <= probe) { - probe -= dict->_bucketsNum; - } - if (start == probe) { - return kCFNotFound; - } - } -} - -static void __CFDictionaryFindBuckets2(CFDictionaryRef dict, const void *key, CFIndex *match, CFIndex *nomatch) { - const CFDictionaryKeyCallBacks *cb = __CFDictionaryGetKeyCallBacks(dict); - CFHashCode keyHash = cb->hash ? (CFHashCode)INVOKE_CALLBACK2(((CFHashCode (*)(const void *, void *))cb->hash), key, dict->_context) : (CFHashCode)key; - const void **keys = dict->_keys; - uintptr_t marker = dict->_marker; - CFIndex probe = keyHash % dict->_bucketsNum; - CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value - CFIndex start = probe; - *match = kCFNotFound; - *nomatch = kCFNotFound; - for (;;) { - uintptr_t currKey = (uintptr_t)keys[probe]; - if (marker == currKey) { /* empty */ - if (nomatch) *nomatch = probe; - return; - } else if (~marker == currKey) { /* deleted */ - if (nomatch) { - *nomatch = probe; - nomatch = NULL; - } - } else if (currKey == (uintptr_t)key || (cb->equal && INVOKE_CALLBACK3((Boolean (*)(const void *, const void *, void*))cb->equal, (void *)currKey, key, dict->_context))) { - *match = probe; - return; - } - probe = probe + probeskip; - // This alternative to probe % buckets assumes that - // probeskip is always positive and less than the - // number of buckets. - if (dict->_bucketsNum <= probe) { - probe -= dict->_bucketsNum; - } - if (start == probe) { - return; - } - } -} - -static void __CFDictionaryFindNewMarker(CFDictionaryRef dict) { - const void **keys = dict->_keys; - uintptr_t newMarker; - CFIndex idx, nbuckets; - bool hit; - - nbuckets = dict->_bucketsNum; - newMarker = dict->_marker; - do { - newMarker--; - hit = false; - for (idx = 0; idx < nbuckets; idx++) { - if (newMarker == (uintptr_t)keys[idx] || ~newMarker == (uintptr_t)keys[idx]) { - hit = true; - break; - } - } - } while (hit); - for (idx = 0; idx < nbuckets; idx++) { - if (dict->_marker == (uintptr_t)keys[idx]) { - keys[idx] = (const void *)newMarker; - } else if (~dict->_marker == (uintptr_t)keys[idx]) { - keys[idx] = (const void *)~newMarker; - } - } - ((struct __CFDictionary *)dict)->_marker = newMarker; -} - -static bool __CFDictionaryEqual(CFTypeRef cf1, CFTypeRef cf2) { - CFDictionaryRef dict1 = (CFDictionaryRef)cf1; - CFDictionaryRef dict2 = (CFDictionaryRef)cf2; - const CFDictionaryKeyCallBacks *cb1, *cb2; - const CFDictionaryValueCallBacks *vcb1, *vcb2; - const void **keys; - CFIndex idx, nbuckets; - if (dict1 == dict2) return true; - if (dict1->_count != dict2->_count) return false; - cb1 = __CFDictionaryGetKeyCallBacks(dict1); - cb2 = __CFDictionaryGetKeyCallBacks(dict2); - if (cb1->equal != cb2->equal) return false; - vcb1 = __CFDictionaryGetValueCallBacks(dict1); - vcb2 = __CFDictionaryGetValueCallBacks(dict2); - if (vcb1->equal != vcb2->equal) return false; - if (0 == dict1->_count) return true; /* after function comparison! */ - keys = dict1->_keys; - nbuckets = dict1->_bucketsNum; - for (idx = 0; idx < nbuckets; idx++) { - if (dict1->_marker != (uintptr_t)keys[idx] && ~dict1->_marker != (uintptr_t)keys[idx]) { - const void *value; - if (!CFDictionaryGetValueIfPresent(dict2, keys[idx], &value)) return false; - if (dict1->_values[idx] != value && vcb1->equal && !INVOKE_CALLBACK3((Boolean (*)(const void *, const void *, void*))vcb1->equal, dict1->_values[idx], value, dict1->_context)) { - return false; - } - } - } - return true; -} - -static CFHashCode __CFDictionaryHash(CFTypeRef cf) { - CFDictionaryRef dict = (CFDictionaryRef)cf; - return dict->_count; -} - -static CFStringRef __CFDictionaryCopyDescription(CFTypeRef cf) { - CFDictionaryRef dict = (CFDictionaryRef)cf; - CFAllocatorRef allocator; - const CFDictionaryKeyCallBacks *cb; - const CFDictionaryValueCallBacks *vcb; - const void **keys; - CFIndex idx, nbuckets; - CFMutableStringRef result; - cb = __CFDictionaryGetKeyCallBacks(dict); - vcb = __CFDictionaryGetValueCallBacks(dict); - keys = dict->_keys; - nbuckets = dict->_bucketsNum; - allocator = CFGetAllocator(dict); - result = CFStringCreateMutable(allocator, 0); - switch (__CFDictionaryGetType(dict)) { - case __kCFDictionaryImmutable: - CFStringAppendFormat(result, NULL, CFSTR("{type = immutable, count = %u, capacity = %u, pairs = (\n"), cf, allocator, dict->_count, dict->_capacity); - break; - case __kCFDictionaryFixedMutable: - CFStringAppendFormat(result, NULL, CFSTR("{type = fixed-mutable, count = %u, capacity = %u, pairs = (\n"), cf, allocator, dict->_count, dict->_capacity); - break; - case __kCFDictionaryMutable: - CFStringAppendFormat(result, NULL, CFSTR("{type = mutable, count = %u, capacity = %u, pairs = (\n"), cf, allocator, dict->_count, dict->_capacity); - break; - } - for (idx = 0; idx < nbuckets; idx++) { - if (dict->_marker != (uintptr_t)keys[idx] && ~dict->_marker != (uintptr_t)keys[idx]) { - CFStringRef kDesc = NULL, vDesc = NULL; - if (NULL != cb->copyDescription) { - kDesc = (CFStringRef)INVOKE_CALLBACK2(((CFStringRef (*)(const void *, void *))cb->copyDescription), keys[idx], dict->_context); - } - if (NULL != vcb->copyDescription) { - vDesc = (CFStringRef)INVOKE_CALLBACK2(((CFStringRef (*)(const void *, void *))vcb->copyDescription), dict->_values[idx], dict->_context); - } - if (NULL != kDesc && NULL != vDesc) { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@ = %@\n"), idx, kDesc, vDesc); - CFRelease(kDesc); - CFRelease(vDesc); - } else if (NULL != kDesc) { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@ = <%p>\n"), idx, kDesc, dict->_values[idx]); - CFRelease(kDesc); - } else if (NULL != vDesc) { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p> = %@\n"), idx, keys[idx], vDesc); - CFRelease(vDesc); - } else { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p> = <%p>\n"), idx, keys[idx], dict->_values[idx]); - } - } - } - CFStringAppend(result, CFSTR(")}")); - return result; -} - -static void __CFDictionaryDeallocate(CFTypeRef cf) { - CFMutableDictionaryRef dict = (CFMutableDictionaryRef)cf; - CFAllocatorRef allocator = __CFGetAllocator(dict); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - const CFDictionaryKeyCallBacks *kcb = __CFDictionaryGetKeyCallBacks(dict); - const CFDictionaryValueCallBacks *vcb = __CFDictionaryGetValueCallBacks(dict); - if (kcb->retain == NULL && kcb->release == NULL && vcb->retain == NULL && vcb->release == NULL) - return; // XXX_PCB keep dictionary intact during finalization. - } - if (__CFDictionaryGetType(dict) == __kCFDictionaryImmutable) { - __CFBitfieldSetValue(((CFRuntimeBase *)dict)->_info, 1, 0, __kCFDictionaryFixedMutable); - } - - const CFDictionaryKeyCallBacks *cb = __CFDictionaryGetKeyCallBacks(dict); - const CFDictionaryValueCallBacks *vcb = __CFDictionaryGetValueCallBacks(dict); - if (vcb->release || cb->release) { - const void **keys = dict->_keys; - CFIndex idx, nbuckets = dict->_bucketsNum; - for (idx = 0; idx < nbuckets; idx++) { - if (dict->_marker != (uintptr_t)keys[idx] && ~dict->_marker != (uintptr_t)keys[idx]) { - const void *oldkey = keys[idx]; - if (vcb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))vcb->release), allocator, dict->_values[idx], dict->_context); - } - if (cb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))cb->release), allocator, oldkey, dict->_context); - } - } - } - } - - if (__CFDictionaryGetType(dict) == __kCFDictionaryMutable && dict->_keys) { - _CFAllocatorDeallocateGC(allocator, dict->_keys); - if (_CFDictionaryIsSplit(dict)) { // iff GC, split allocations - _CFAllocatorDeallocateGC(allocator, dict->_values); - } - dict->_keys = NULL; - dict->_values = NULL; - } -} - -/* - * When running under GC, we suss up dictionaries with standard string copy to hold - * onto everything, including the copies of incoming keys, in strong memory without retain counts. - * This is the routine that makes that copy. - * Not for inputs of constant strings we'll get a constant string back, and so the result - * is not guaranteed to be from the auto zone, hence the call to CFRelease since it will figure - * out where the refcount really is. - */ -static CFStringRef _CFStringCreateCopyCollected(CFAllocatorRef allocator, CFStringRef theString) { - return CFMakeCollectable(CFStringCreateCopy(NULL, theString)); -} - -static CFTypeID __kCFDictionaryTypeID = _kCFRuntimeNotATypeID; - -static const CFRuntimeClass __CFDictionaryClass = { - _kCFRuntimeScannedObject, - "CFDictionary", - NULL, // init - NULL, // copy - __CFDictionaryDeallocate, - (void *)__CFDictionaryEqual, - __CFDictionaryHash, - NULL, // - __CFDictionaryCopyDescription -}; - -__private_extern__ void __CFDictionaryInitialize(void) { - __kCFDictionaryTypeID = _CFRuntimeRegisterClass(&__CFDictionaryClass); -} - -CFTypeID CFDictionaryGetTypeID(void) { - return __kCFDictionaryTypeID; -} - -static CFDictionaryRef __CFDictionaryInit(CFAllocatorRef allocator, uint32_t flags, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks) { - struct __CFDictionary *memory; - uint32_t size; - CFIndex idx; - __CFBitfieldSetValue(flags, 31, 2, 0); - CFDictionaryKeyCallBacks nonRetainingKeyCallbacks; - CFDictionaryValueCallBacks nonRetainingValueCallbacks; - CFOptionFlags xflags = 0; - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - // preserve NULL for key or value CB, otherwise fix up. - if (!keyCallBacks || (keyCallBacks->retain == NULL && keyCallBacks->release == NULL)) { - xflags = __kCFDictionaryWeakKeys; - } - else { - if (keyCallBacks->retain == __CFTypeCollectionRetain && keyCallBacks->release == __CFTypeCollectionRelease) { - // copy everything - nonRetainingKeyCallbacks = *keyCallBacks; - nonRetainingKeyCallbacks.retain = NULL; - nonRetainingKeyCallbacks.release = NULL; - keyCallBacks = &nonRetainingKeyCallbacks; - xflags = __kCFDictionaryRestoreKeys; - } - else if (keyCallBacks->retain == CFStringCreateCopy && keyCallBacks->release == __CFTypeCollectionRelease) { - // copy everything - nonRetainingKeyCallbacks = *keyCallBacks; - nonRetainingKeyCallbacks.retain = (void *)_CFStringCreateCopyCollected; // XXX fix with better cast - nonRetainingKeyCallbacks.release = NULL; - keyCallBacks = &nonRetainingKeyCallbacks; - xflags = (__kCFDictionaryRestoreKeys | __kCFDictionaryRestoreStringKeys); - } - } - if (!valueCallBacks || (valueCallBacks->retain == NULL && valueCallBacks->release == NULL)) { - xflags |= __kCFDictionaryWeakValues; - } - else { - if (valueCallBacks->retain == __CFTypeCollectionRetain && valueCallBacks->release == __CFTypeCollectionRelease) { - nonRetainingValueCallbacks = *valueCallBacks; - nonRetainingValueCallbacks.retain = NULL; - nonRetainingValueCallbacks.release = NULL; - valueCallBacks = &nonRetainingValueCallbacks; - xflags |= __kCFDictionaryRestoreValues; - } - } - } - if (__CFDictionaryKeyCallBacksMatchNull(keyCallBacks)) { - __CFBitfieldSetValue(flags, 3, 2, __kCFDictionaryHasNullCallBacks); - } else if (__CFDictionaryKeyCallBacksMatchCFType(keyCallBacks)) { - __CFBitfieldSetValue(flags, 3, 2, __kCFDictionaryHasCFTypeCallBacks); - } else { - __CFBitfieldSetValue(flags, 3, 2, __kCFDictionaryHasCustomCallBacks); - } - if (__CFDictionaryValueCallBacksMatchNull(valueCallBacks)) { - __CFBitfieldSetValue(flags, 5, 4, __kCFDictionaryHasNullCallBacks); - } else if (__CFDictionaryValueCallBacksMatchCFType(valueCallBacks)) { - __CFBitfieldSetValue(flags, 5, 4, __kCFDictionaryHasCFTypeCallBacks); - } else { - __CFBitfieldSetValue(flags, 5, 4, __kCFDictionaryHasCustomCallBacks); - } - size = __CFDictionaryGetSizeOfType(flags) - sizeof(CFRuntimeBase); - switch (__CFBitfieldGetValue(flags, 1, 0)) { - case __kCFDictionaryImmutable: - case __kCFDictionaryFixedMutable: - size += 2 * __CFDictionaryNumBucketsForCapacity(capacity) * sizeof(const void *); - break; - case __kCFDictionaryMutable: - break; - } - memory = (struct __CFDictionary *)_CFRuntimeCreateInstance(allocator, __kCFDictionaryTypeID, size, NULL); - if (NULL == memory) { - return NULL; - } - __CFBitfieldSetValue(memory->_base._info, 6, 0, flags); - memory->_count = 0; - memory->_marker = (uintptr_t)0xa1b1c1d3; - memory->_context = NULL; - memory->_deletes = 0; - memory->_xflags = xflags; - switch (__CFBitfieldGetValue(flags, 1, 0)) { - case __kCFDictionaryImmutable: - // GC note: we can't support weak part of mixed weak/strong in fixed case, we treat it as strong XXX blaine - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator) - && (xflags & (__kCFDictionaryWeakKeys|__kCFDictionaryWeakValues)) == (__kCFDictionaryWeakKeys|__kCFDictionaryWeakValues)) { // if both weak, don't scan - auto_zone_set_layout_type(__CFCollectableZone, memory, AUTO_OBJECT_UNSCANNED); - } - if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFDictionary (immutable)"); - memory->_capacity = capacity; /* Don't round up capacity */ - memory->_bucketsNum = __CFDictionaryNumBucketsForCapacity(memory->_capacity); - memory->_keys = (const void **)((uint8_t *)memory + __CFDictionaryGetSizeOfType(flags)); - memory->_values = (const void **)(memory->_keys + memory->_bucketsNum); - for (idx = memory->_bucketsNum; idx--;) { - memory->_keys[idx] = (const void *)memory->_marker; - } - break; - case __kCFDictionaryFixedMutable: - // GC note: we can't support weak part of mixed weak/strong in fixed case, we treat it as strong XXX blaine - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator) - && (xflags & (__kCFDictionaryWeakKeys|__kCFDictionaryWeakValues)) == (__kCFDictionaryWeakKeys|__kCFDictionaryWeakValues)) { // if both weak, don't scan - auto_zone_set_layout_type(__CFCollectableZone, memory, AUTO_OBJECT_UNSCANNED); - } - if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFDictionary (mutable-fixed)"); - memory->_capacity = capacity; /* Don't round up capacity */ - memory->_bucketsNum = __CFDictionaryNumBucketsForCapacity(memory->_capacity); - memory->_keys = (const void **)((uint8_t *)memory + __CFDictionaryGetSizeOfType(flags)); - memory->_values = (const void **)(memory->_keys + memory->_bucketsNum); - for (idx = memory->_bucketsNum; idx--;) { - memory->_keys[idx] = (const void *)memory->_marker; - } - break; - case __kCFDictionaryMutable: - if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFDictionary (mutable-variable)"); - memory->_capacity = __CFDictionaryRoundUpCapacity(1); - memory->_bucketsNum = 0; - memory->_keys = NULL; - memory->_values = NULL; - break; - } - if (__kCFDictionaryHasCustomCallBacks == __CFBitfieldGetValue(flags, 3, 2)) { - CFDictionaryKeyCallBacks *cb = (CFDictionaryKeyCallBacks *)__CFDictionaryGetKeyCallBacks((CFDictionaryRef)memory); - *cb = *keyCallBacks; - FAULT_CALLBACK((void **)&(cb->retain)); - FAULT_CALLBACK((void **)&(cb->release)); - FAULT_CALLBACK((void **)&(cb->copyDescription)); - FAULT_CALLBACK((void **)&(cb->equal)); - FAULT_CALLBACK((void **)&(cb->hash)); - } - if (__kCFDictionaryHasCustomCallBacks == __CFBitfieldGetValue(flags, 5, 4)) { - CFDictionaryValueCallBacks *vcb = (CFDictionaryValueCallBacks *)__CFDictionaryGetValueCallBacks((CFDictionaryRef)memory); - *vcb = *valueCallBacks; - FAULT_CALLBACK((void **)&(vcb->retain)); - FAULT_CALLBACK((void **)&(vcb->release)); - FAULT_CALLBACK((void **)&(vcb->copyDescription)); - FAULT_CALLBACK((void **)&(vcb->equal)); - } - return (CFDictionaryRef)memory; -} - -CFDictionaryRef CFDictionaryCreate(CFAllocatorRef allocator, const void **keys, const void **values, CFIndex numValues, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks) { - CFDictionaryRef result; - uint32_t flags; - CFIndex idx; - CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%d) cannot be less than zero", __PRETTY_FUNCTION__, numValues); - result = __CFDictionaryInit(allocator, __kCFDictionaryImmutable, numValues, keyCallBacks, valueCallBacks); - flags = __CFBitfieldGetValue(((const CFRuntimeBase *)result)->_info, 1, 0); - if (flags == __kCFDictionaryImmutable) { - // tweak flags so that we can add our immutable values - __CFBitfieldSetValue(((CFRuntimeBase *)result)->_info, 1, 0, __kCFDictionaryFixedMutable); - } - for (idx = 0; idx < numValues; idx++) { - CFDictionaryAddValue((CFMutableDictionaryRef)result, keys[idx], values[idx]); - } - __CFBitfieldSetValue(((CFRuntimeBase *)result)->_info, 1, 0, flags); - return result; -} - -CFMutableDictionaryRef CFDictionaryCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFDictionaryKeyCallBacks *keyCallBacks, const CFDictionaryValueCallBacks *valueCallBacks) { - CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%d) cannot be less than zero", __PRETTY_FUNCTION__, capacity); - return (CFMutableDictionaryRef)__CFDictionaryInit(allocator, (0 == capacity) ? __kCFDictionaryMutable : __kCFDictionaryFixedMutable, capacity, keyCallBacks, valueCallBacks); -} - -static void __CFDictionaryGrow(CFMutableDictionaryRef dict, CFIndex numNewValues); - -// This creates a dictionary which is for CFTypes or NSObjects, with an ownership transfer -- -// the dictionary does not take a retain, and the caller does not need to release the inserted objects. -// The incoming objects must also be collectable if allocated out of a collectable allocator. -CFDictionaryRef _CFDictionaryCreate_ex(CFAllocatorRef allocator, bool mutable, const void **keys, const void **values, CFIndex numValues) { - CFDictionaryRef result; - void *bucketsBase; - uint32_t flags; - CFIndex idx; - result = __CFDictionaryInit(allocator, mutable ? __kCFDictionaryMutable : __kCFDictionaryImmutable, numValues, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - flags = __CFBitfieldGetValue(((const CFRuntimeBase *)result)->_info, 1, 0); - if (!mutable) { - __CFBitfieldSetValue(((CFRuntimeBase *)result)->_info, 1, 0, __kCFDictionaryFixedMutable); - } - if (mutable) { - if (result->_count == result->_capacity || NULL == result->_keys) { - __CFDictionaryGrow((CFMutableDictionaryRef)result, numValues); - } - } - // GC: since kCFTypeDictionaryKeyCallBacks & kCFTypeDictionaryValueCallBacks are used, the keys - // and values will be allocated contiguously. - bool collectableContainer = CF_IS_COLLECTABLE_ALLOCATOR(allocator); - bucketsBase = (collectableContainer ? auto_zone_base_pointer(__CFCollectableZone, result->_keys) : NULL); - for (idx = 0; idx < numValues; idx++) { - CFIndex match, nomatch; - const void *newKey; - __CFDictionaryFindBuckets2(result, keys[idx], &match, &nomatch); - if (kCFNotFound != match) { - if (!collectableContainer) CFRelease(result->_values[match]); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, bucketsBase, result->_values[match], values[idx]); - // GC: generation(_values) <= generation(values), but added for completeness. - } else { - newKey = keys[idx]; - if (result->_marker == (uintptr_t)newKey || ~result->_marker == (uintptr_t)newKey) { - __CFDictionaryFindNewMarker(result); - } - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, bucketsBase, result->_keys[nomatch], newKey); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, bucketsBase, result->_values[nomatch], values[idx]); - // GC: generation(_keys/_values) <= generation(keys/values), but added for completeness. - ((CFMutableDictionaryRef)result)->_count++; - } - } - __CFBitfieldSetValue(((CFRuntimeBase *)result)->_info, 1, 0, flags); - return result; -} - -CFDictionaryRef CFDictionaryCreateCopy(CFAllocatorRef allocator, CFDictionaryRef dict) { - CFDictionaryRef result; - const CFDictionaryKeyCallBacks *cb; - const CFDictionaryValueCallBacks *vcb; - CFIndex numValues = CFDictionaryGetCount(dict); - const void **list, *buffer[256]; - const void **vlist, *vbuffer[256]; - list = (numValues <= 256) ? buffer : CFAllocatorAllocate(allocator, numValues * sizeof(void *), 0); // XXX_PCB GC OK - if (list != buffer && __CFOASafe) __CFSetLastAllocationEventName(list, "CFDictionary (temp)"); - vlist = (numValues <= 256) ? vbuffer : CFAllocatorAllocate(allocator, numValues * sizeof(void *), 0); // XXX_PCB GC OK - if (vlist != vbuffer && __CFOASafe) __CFSetLastAllocationEventName(vlist, "CFDictionary (temp)"); - CFDictionaryGetKeysAndValues(dict, list, vlist); - CFDictionaryKeyCallBacks patchedKeyCB; - CFDictionaryValueCallBacks patchedValueCB; - if (CF_IS_OBJC(__kCFDictionaryTypeID, dict)) { - cb = &kCFTypeDictionaryKeyCallBacks; - vcb = &kCFTypeDictionaryValueCallBacks; - } - else { - cb = __CFDictionaryGetKeyCallBacks(dict); - vcb = __CFDictionaryGetValueCallBacks(dict); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - if (dict->_xflags & __kCFDictionaryRestoreKeys) { - patchedKeyCB = *cb; // copy - cb = &patchedKeyCB; // reset to copy - patchedKeyCB.retain = (dict->_xflags & __kCFDictionaryRestoreStringKeys) ? CFStringCreateCopy : __CFTypeCollectionRetain; - patchedKeyCB.release = __CFTypeCollectionRelease; - } - if (dict->_xflags & __kCFDictionaryRestoreValues) { - patchedValueCB = *vcb; // copy - vcb = &patchedValueCB; // reset to copy - patchedValueCB.retain = __CFTypeCollectionRetain; - patchedValueCB.release = __CFTypeCollectionRelease; - } - } - } - result = CFDictionaryCreate(allocator, list, vlist, numValues, cb, vcb); - if (list != buffer) CFAllocatorDeallocate(allocator, list); // GC OK - if (vlist != vbuffer) CFAllocatorDeallocate(allocator, vlist); // GC OK - return result; -} - -CFMutableDictionaryRef CFDictionaryCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFDictionaryRef dict) { - CFMutableDictionaryRef result; - const CFDictionaryKeyCallBacks *cb; - const CFDictionaryValueCallBacks *vcb; - CFIndex idx, numValues = CFDictionaryGetCount(dict); - const void **list, *buffer[256]; - const void **vlist, *vbuffer[256]; - CFAssert3(0 == capacity || numValues <= capacity, __kCFLogAssertion, "%s(): for fixed-mutable dicts, capacity (%d) must be greater than or equal to initial number of values (%d)", __PRETTY_FUNCTION__, capacity, numValues); - list = (numValues <= 256) ? buffer : CFAllocatorAllocate(allocator, numValues * sizeof(void *), 0); // XXX_PCB GC OK - if (list != buffer && __CFOASafe) __CFSetLastAllocationEventName(list, "CFDictionary (temp)"); - vlist = (numValues <= 256) ? vbuffer : CFAllocatorAllocate(allocator, numValues * sizeof(void *), 0); // XXX_PCB GC OK - if (vlist != vbuffer && __CFOASafe) __CFSetLastAllocationEventName(vlist, "CFDictionary (temp)"); - CFDictionaryGetKeysAndValues(dict, list, vlist); - CFDictionaryKeyCallBacks patchedKeyCB; - CFDictionaryValueCallBacks patchedValueCB; - if (CF_IS_OBJC(__kCFDictionaryTypeID, dict)) { - cb = &kCFTypeDictionaryKeyCallBacks; - vcb = &kCFTypeDictionaryValueCallBacks; - } - else { - cb = __CFDictionaryGetKeyCallBacks(dict); - vcb = __CFDictionaryGetValueCallBacks(dict); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - if (dict->_xflags & __kCFDictionaryRestoreKeys) { - patchedKeyCB = *cb; // copy - cb = &patchedKeyCB; // reset to copy - patchedKeyCB.retain = (dict->_xflags & __kCFDictionaryRestoreStringKeys) ? CFStringCreateCopy : __CFTypeCollectionRetain; - patchedKeyCB.release = __CFTypeCollectionRelease; - } - if (dict->_xflags & __kCFDictionaryRestoreValues) { - patchedValueCB = *vcb; // copy - vcb = &patchedValueCB; // reset to copy - patchedValueCB.retain = __CFTypeCollectionRetain; - patchedValueCB.release = __CFTypeCollectionRelease; - } - } - } - result = CFDictionaryCreateMutable(allocator, capacity, cb, vcb); - if (0 == capacity) _CFDictionarySetCapacity(result, numValues); - for (idx = 0; idx < numValues; idx++) { - CFDictionaryAddValue(result, list[idx], vlist[idx]); - } - if (list != buffer) CFAllocatorDeallocate(allocator, list); // XXX_PCB GC OK - if (vlist != vbuffer) CFAllocatorDeallocate(allocator, vlist); // XXX_PCB GC OK - return result; -} - - - -// Used by NSMapTables and KVO -void _CFDictionarySetContext(CFDictionaryRef dict, void *context) { - CFAllocatorRef allocator = CFGetAllocator(dict); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, dict, dict->_context, context); -} - -void *_CFDictionaryGetContext(CFDictionaryRef dict) { - return ((struct __CFDictionary *)dict)->_context; -} - -CFIndex CFDictionaryGetCount(CFDictionaryRef dict) { - CF_OBJC_FUNCDISPATCH0(__kCFDictionaryTypeID, CFIndex, dict, "count"); - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - return dict->_count; -} - -CFIndex CFDictionaryGetCountOfKey(CFDictionaryRef dict, const void *key) { - CFIndex match; - CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, CFIndex, dict, "countForKey:", key); - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - if (0 == dict->_count) return 0; - if (__kCFDictionaryHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)dict)->_info, 3, 2)) { - match = __CFDictionaryFindBuckets1a(dict, key); - } else { - match = __CFDictionaryFindBuckets1b(dict, key); - } - return (kCFNotFound != match ? 1 : 0); -} - -CFIndex CFDictionaryGetCountOfValue(CFDictionaryRef dict, const void *value) { - const void **keys; - const CFDictionaryValueCallBacks *vcb; - CFIndex idx, cnt = 0, nbuckets; - CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, CFIndex, dict, "countForObject:", value); - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - if (0 == dict->_count) return 0; - keys = dict->_keys; - nbuckets = dict->_bucketsNum; - vcb = __CFDictionaryGetValueCallBacks(dict); - for (idx = 0; idx < nbuckets; idx++) { - if (dict->_marker != (uintptr_t)keys[idx] && ~dict->_marker != (uintptr_t)keys[idx]) { - if ((dict->_values[idx] == value) || (vcb->equal && INVOKE_CALLBACK3((Boolean (*)(const void *, const void *, void*))vcb->equal, dict->_values[idx], value, dict->_context))) { - cnt++; - } - } - } - return cnt; -} - -Boolean CFDictionaryContainsKey(CFDictionaryRef dict, const void *key) { - CFIndex match; - CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, char, dict, "containsKey:", key); - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - if (0 == dict->_count) return false; - if (__kCFDictionaryHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)dict)->_info, 3, 2)) { - match = __CFDictionaryFindBuckets1a(dict, key); - } else { - match = __CFDictionaryFindBuckets1b(dict, key); - } - return (kCFNotFound != match ? true : false); -} - -Boolean CFDictionaryContainsValue(CFDictionaryRef dict, const void *value) { - const void **keys; - const CFDictionaryValueCallBacks *vcb; - CFIndex idx, nbuckets; - CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, char, dict, "containsObject:", value); - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - if (0 == dict->_count) return false; - keys = dict->_keys; - nbuckets = dict->_bucketsNum; - vcb = __CFDictionaryGetValueCallBacks(dict); - for (idx = 0; idx < nbuckets; idx++) { - if (dict->_marker != (uintptr_t)keys[idx] && ~dict->_marker != (uintptr_t)keys[idx]) { - if ((dict->_values[idx] == value) || (vcb->equal && INVOKE_CALLBACK3((Boolean (*)(const void *, const void *, void*))vcb->equal, dict->_values[idx], value, dict->_context))) { - return true; - } - } - } - return false; -} - -const void *CFDictionaryGetValue(CFDictionaryRef dict, const void *key) { - CFIndex match; - CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, const void *, dict, "objectForKey:", key); - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - if (0 == dict->_count) return NULL; - if (__kCFDictionaryHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)dict)->_info, 3, 2)) { - match = __CFDictionaryFindBuckets1a(dict, key); - } else { - match = __CFDictionaryFindBuckets1b(dict, key); - } - return (kCFNotFound != match ? dict->_values[match] : NULL); -} - -Boolean CFDictionaryGetValueIfPresent(CFDictionaryRef dict, const void *key, const void **value) { - CFIndex match; - CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, char, dict, "_getValue:forKey:", (void * *)value, key); - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - if (0 == dict->_count) return false; - if (__kCFDictionaryHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)dict)->_info, 3, 2)) { - match = __CFDictionaryFindBuckets1a(dict, key); - } else { - match = __CFDictionaryFindBuckets1b(dict, key); - } - return (kCFNotFound != match ? ((value ? __CFObjCStrongAssign(dict->_values[match], value) : NULL), true) : false); -} - -bool CFDictionaryGetKeyIfPresent(CFDictionaryRef dict, const void *key, const void **actualkey) { - CFIndex match; -//#warning CF: not toll-free bridged - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - if (0 == dict->_count) return false; - if (__kCFDictionaryHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)dict)->_info, 3, 2)) { - match = __CFDictionaryFindBuckets1a(dict, key); - } else { - match = __CFDictionaryFindBuckets1b(dict, key); - } - return (kCFNotFound != match ? ((actualkey ? __CFObjCStrongAssign(dict->_keys[match], actualkey) : NULL), true) : false); -} - -void CFDictionaryGetKeysAndValues(CFDictionaryRef dict, const void **keys, const void **values) { - CFIndex idx, cnt, nbuckets; - CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, void, dict, "getObjects:andKeys:", (void * *)values, (void * *)keys); - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - if (CF_USING_COLLECTABLE_MEMORY) { - // GC: speculatively issue a write-barrier on the copied to buffers (3743553). - __CFObjCWriteBarrierRange(keys, dict->_count * sizeof(void *)); - __CFObjCWriteBarrierRange(values, dict->_count * sizeof(void *)); - } - nbuckets = dict->_bucketsNum; - for (idx = 0; idx < nbuckets; idx++) { - if (dict->_marker != (uintptr_t)dict->_keys[idx] && ~dict->_marker != (uintptr_t)dict->_keys[idx]) { - for (cnt = 1; cnt--;) { - if (keys) *keys++ = dict->_keys[idx]; - if (values) *values++ = dict->_values[idx]; - } - } - } -} - -void CFDictionaryApplyFunction(CFDictionaryRef dict, CFDictionaryApplierFunction applier, void *context) { - const void **keys; - CFIndex idx, cnt, nbuckets; - FAULT_CALLBACK((void **)&(applier)); - CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, void, dict, "_apply:context:", applier, context); - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - keys = dict->_keys; - nbuckets = dict->_bucketsNum; - for (idx = 0; idx < nbuckets; idx++) { - if (dict->_marker != (uintptr_t)keys[idx] && ~dict->_marker != (uintptr_t)keys[idx]) { - for (cnt = 1; cnt--;) { - INVOKE_CALLBACK3(applier, keys[idx], dict->_values[idx], context); - } - } - } -} - -static void __CFDictionaryGrow(CFMutableDictionaryRef dict, CFIndex numNewValues) { - const void **oldkeys = dict->_keys; - const void **oldvalues = dict->_values; - CFIndex idx, oldnbuckets = dict->_bucketsNum; - CFIndex oldCount = dict->_count; - CFAllocatorRef allocator = __CFGetAllocator(dict), keysAllocator, valuesAllocator; - void *keysBase, *valuesBase; - dict->_capacity = __CFDictionaryRoundUpCapacity(oldCount + numNewValues); - dict->_bucketsNum = __CFDictionaryNumBucketsForCapacity(dict->_capacity); - dict->_deletes = 0; - if (_CFDictionaryIsSplit(dict)) { // iff GC, use split memory sometimes unscanned memory - unsigned weakOrStrong = (dict->_xflags & __kCFDictionaryWeakKeys) ? AUTO_MEMORY_UNSCANNED : AUTO_MEMORY_SCANNED; - void *mem = _CFAllocatorAllocateGC(allocator, dict->_bucketsNum * sizeof(const void *), weakOrStrong); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, dict, dict->_keys, mem); - keysAllocator = (dict->_xflags & __kCFDictionaryWeakKeys) ? kCFAllocatorNull : allocator; // GC: avoids write-barrier in weak case. - keysBase = mem; - - weakOrStrong = (dict->_xflags & __kCFDictionaryWeakValues) ? AUTO_MEMORY_UNSCANNED : AUTO_MEMORY_SCANNED; - mem = _CFAllocatorAllocateGC(allocator, dict->_bucketsNum * sizeof(const void *), weakOrStrong); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, dict, dict->_values, mem); - valuesAllocator = (dict->_xflags & __kCFDictionaryWeakValues) ? kCFAllocatorNull : allocator; // GC: avoids write-barrier in weak case. - valuesBase = mem; - } else { - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, dict, dict->_keys, _CFAllocatorAllocateGC(allocator, 2 * dict->_bucketsNum * sizeof(const void *), AUTO_MEMORY_SCANNED)); - dict->_values = (const void **)(dict->_keys + dict->_bucketsNum); - keysAllocator = valuesAllocator = allocator; - keysBase = valuesBase = dict->_keys; - } - if (NULL == dict->_keys || NULL == dict->_values) HALT; - if (__CFOASafe) __CFSetLastAllocationEventName(dict->_keys, "CFDictionary (store)"); - for (idx = dict->_bucketsNum; idx--;) { - dict->_keys[idx] = (const void *)dict->_marker; - dict->_values[idx] = 0; - } - if (NULL == oldkeys) return; - for (idx = 0; idx < oldnbuckets; idx++) { - if (dict->_marker != (uintptr_t)oldkeys[idx] && ~dict->_marker != (uintptr_t)oldkeys[idx]) { - CFIndex match, nomatch; - __CFDictionaryFindBuckets2(dict, oldkeys[idx], &match, &nomatch); - CFAssert3(kCFNotFound == match, __kCFLogAssertion, "%s(): two values (%p, %p) now hash to the same slot; mutable value changed while in table or hash value is not immutable", __PRETTY_FUNCTION__, oldkeys[idx], dict->_keys[match]); - if (kCFNotFound != nomatch) { - CF_WRITE_BARRIER_BASE_ASSIGN(keysAllocator, keysBase, dict->_keys[nomatch], oldkeys[idx]); - CF_WRITE_BARRIER_BASE_ASSIGN(valuesAllocator, valuesBase, dict->_values[nomatch], oldvalues[idx]); - } - } - } - CFAssert1(dict->_count == oldCount, __kCFLogAssertion, "%s(): dict count differs after rehashing; error", __PRETTY_FUNCTION__); - _CFAllocatorDeallocateGC(allocator, oldkeys); - if (_CFDictionaryIsSplit(dict)) _CFAllocatorDeallocateGC(allocator, oldvalues); -} - -// This function is for Foundation's benefit; no one else should use it. -void _CFDictionarySetCapacity(CFMutableDictionaryRef dict, CFIndex cap) { - if (CF_IS_OBJC(__kCFDictionaryTypeID, dict)) return; -#if defined(DEBUG) - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - CFAssert1(__CFDictionaryGetType(dict) != __kCFDictionaryImmutable && __CFDictionaryGetType(dict) != __kCFDictionaryFixedMutable, __kCFLogAssertion, "%s(): dict is immutable or fixed-mutable", __PRETTY_FUNCTION__); - CFAssert3(dict->_count <= cap, __kCFLogAssertion, "%s(): desired capacity (%d) is less than count (%d)", __PRETTY_FUNCTION__, cap, dict->_count); -#endif - __CFDictionaryGrow(dict, cap - dict->_count); -} - - -void CFDictionaryAddValue(CFMutableDictionaryRef dict, const void *key, const void *value) { - CFIndex match, nomatch; - const CFDictionaryKeyCallBacks *cb; - const CFDictionaryValueCallBacks *vcb; - const void *newKey, *newValue; - CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, void, dict, "_addObject:forKey:", value, key); - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - switch (__CFDictionaryGetType(dict)) { - case __kCFDictionaryMutable: - if (dict->_count == dict->_capacity || NULL == dict->_keys) { - __CFDictionaryGrow(dict, 1); - } - break; - case __kCFDictionaryFixedMutable: - CFAssert3(dict->_count < dict->_capacity, __kCFLogAssertion, "%s(): capacity exceeded on fixed-capacity dict %p (capacity = %d)", __PRETTY_FUNCTION__, dict, dict->_capacity); - break; - default: - CFAssert2(__CFDictionaryGetType(dict) != __kCFDictionaryImmutable, __kCFLogAssertion, "%s(): immutable dict %p passed to mutating operation", __PRETTY_FUNCTION__, dict); - break; - } - __CFDictionaryFindBuckets2(dict, key, &match, &nomatch); - if (kCFNotFound != match) { - } else { - CFAllocatorRef allocator = __CFGetAllocator(dict); - CFAllocatorRef keysAllocator = (dict->_xflags & __kCFDictionaryWeakKeys) ? kCFAllocatorNull : allocator; - CFAllocatorRef valuesAllocator = (dict->_xflags & __kCFDictionaryWeakValues) ? kCFAllocatorNull : allocator; - cb = __CFDictionaryGetKeyCallBacks(dict); - vcb = __CFDictionaryGetValueCallBacks(dict); - if (cb->retain) { - newKey = (void *)INVOKE_CALLBACK3(((const void *(*)(CFAllocatorRef, const void *, void *))cb->retain), allocator, key, dict->_context); - } else { - newKey = key; - } - if (vcb->retain) { - newValue = (void *)INVOKE_CALLBACK3(((const void *(*)(CFAllocatorRef, const void *, void *))vcb->retain), allocator, value, dict->_context); - } else { - newValue = value; - } - if (dict->_marker == (uintptr_t)newKey || ~dict->_marker == (uintptr_t)newKey) { - __CFDictionaryFindNewMarker(dict); - } - CF_OBJC_KVO_WILLCHANGE(dict, key); - CF_WRITE_BARRIER_ASSIGN(keysAllocator, dict->_keys[nomatch], newKey); - CF_WRITE_BARRIER_ASSIGN(valuesAllocator, dict->_values[nomatch], newValue); - dict->_count++; - CF_OBJC_KVO_DIDCHANGE(dict, key); - } -} - -void CFDictionaryReplaceValue(CFMutableDictionaryRef dict, const void *key, const void *value) { - CFIndex match; - const CFDictionaryValueCallBacks *vcb; - const void *newValue; - CFAllocatorRef allocator, valuesAllocator; - CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, void, dict, "_replaceObject:forKey:", value, key); - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - switch (__CFDictionaryGetType(dict)) { - case __kCFDictionaryMutable: - case __kCFDictionaryFixedMutable: - break; - default: - CFAssert2(__CFDictionaryGetType(dict) != __kCFDictionaryImmutable, __kCFLogAssertion, "%s(): immutable dict %p passed to mutating operation", __PRETTY_FUNCTION__, dict); - break; - } - if (0 == dict->_count) return; - if (__kCFDictionaryHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)dict)->_info, 3, 2)) { - match = __CFDictionaryFindBuckets1a(dict, key); - } else { - match = __CFDictionaryFindBuckets1b(dict, key); - } - if (kCFNotFound == match) return; - vcb = __CFDictionaryGetValueCallBacks(dict); - allocator = __CFGetAllocator(dict); - valuesAllocator = (dict->_xflags & __kCFDictionaryWeakValues) ? kCFAllocatorNull : allocator; - if (vcb->retain) { - newValue = (void *)INVOKE_CALLBACK3(((const void *(*)(CFAllocatorRef, const void *, void *))vcb->retain), allocator, value, dict->_context); - } else { - newValue = value; - } - CF_OBJC_KVO_WILLCHANGE(dict, key); - if (vcb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))vcb->release), allocator, dict->_values[match], dict->_context); - } - CF_WRITE_BARRIER_ASSIGN(valuesAllocator, dict->_values[match], newValue); - CF_OBJC_KVO_DIDCHANGE(dict, key); -} - -void CFDictionarySetValue(CFMutableDictionaryRef dict, const void *key, const void *value) { - CFIndex match, nomatch; - const CFDictionaryKeyCallBacks *cb; - const CFDictionaryValueCallBacks *vcb; - const void *newKey, *newValue; - CFAllocatorRef allocator, keysAllocator, valuesAllocator; - CF_OBJC_FUNCDISPATCH2(__kCFDictionaryTypeID, void, dict, "setObject:forKey:", value, key); - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - switch (__CFDictionaryGetType(dict)) { - case __kCFDictionaryMutable: - if (dict->_count == dict->_capacity || NULL == dict->_keys) { - __CFDictionaryGrow(dict, 1); - } - break; - case __kCFDictionaryFixedMutable: - break; - default: - CFAssert2(__CFDictionaryGetType(dict) != __kCFDictionaryImmutable, __kCFLogAssertion, "%s(): immutable dict %p passed to mutating operation", __PRETTY_FUNCTION__, dict); - break; - } - __CFDictionaryFindBuckets2(dict, key, &match, &nomatch); - vcb = __CFDictionaryGetValueCallBacks(dict); - allocator = __CFGetAllocator(dict); - keysAllocator = (dict->_xflags & __kCFDictionaryWeakKeys) ? kCFAllocatorNull : allocator; - valuesAllocator = (dict->_xflags & __kCFDictionaryWeakValues) ? kCFAllocatorNull : allocator; - if (vcb->retain) { - newValue = (void *)INVOKE_CALLBACK3(((const void *(*)(CFAllocatorRef, const void *, void *))vcb->retain), allocator, value, dict->_context); - } else { - newValue = value; - } - if (kCFNotFound != match) { - CF_OBJC_KVO_WILLCHANGE(dict, key); - if (vcb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))vcb->release), allocator, dict->_values[match], dict->_context); - } - CF_WRITE_BARRIER_ASSIGN(valuesAllocator, dict->_values[match], newValue); - CF_OBJC_KVO_DIDCHANGE(dict, key); - } else { - CFAssert3(__kCFDictionaryFixedMutable != __CFDictionaryGetType(dict) || dict->_count < dict->_capacity, __kCFLogAssertion, "%s(): capacity exceeded on fixed-capacity dict %p (capacity = %d)", __PRETTY_FUNCTION__, dict, dict->_capacity); - cb = __CFDictionaryGetKeyCallBacks(dict); - if (cb->retain) { - newKey = (void *)INVOKE_CALLBACK3(((const void *(*)(CFAllocatorRef, const void *, void *))cb->retain), allocator, key, dict->_context); - } else { - newKey = key; - } - if (dict->_marker == (uintptr_t)newKey || ~dict->_marker == (uintptr_t)newKey) { - __CFDictionaryFindNewMarker(dict); - } - CF_OBJC_KVO_WILLCHANGE(dict, key); - CF_WRITE_BARRIER_ASSIGN(keysAllocator, dict->_keys[nomatch], newKey); - CF_WRITE_BARRIER_ASSIGN(valuesAllocator, dict->_values[nomatch], newValue); - dict->_count++; - CF_OBJC_KVO_DIDCHANGE(dict, key); - } -} - -void CFDictionaryRemoveValue(CFMutableDictionaryRef dict, const void *key) { - CFIndex match; - const CFDictionaryKeyCallBacks *cb; - const CFDictionaryValueCallBacks *vcb; - CF_OBJC_FUNCDISPATCH1(__kCFDictionaryTypeID, void, dict, "removeObjectForKey:", key); - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - switch (__CFDictionaryGetType(dict)) { - case __kCFDictionaryMutable: - case __kCFDictionaryFixedMutable: - break; - default: - CFAssert2(__CFDictionaryGetType(dict) != __kCFDictionaryImmutable, __kCFLogAssertion, "%s(): immutable dict %p passed to mutating operation", __PRETTY_FUNCTION__, dict); - break; - } - if (0 == dict->_count) return; - if (__kCFDictionaryHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)dict)->_info, 3, 2)) { - match = __CFDictionaryFindBuckets1a(dict, key); - } else { - match = __CFDictionaryFindBuckets1b(dict, key); - } - if (kCFNotFound == match) return; - if (1) { - cb = __CFDictionaryGetKeyCallBacks(dict); - vcb = __CFDictionaryGetValueCallBacks(dict); - const void *oldkey = dict->_keys[match]; - CFAllocatorRef allocator = CFGetAllocator(dict); - CF_OBJC_KVO_WILLCHANGE(dict, oldkey); - if (vcb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))vcb->release), allocator, dict->_values[match], dict->_context); - } - dict->_keys[match] = (const void *)~dict->_marker; - dict->_values[match] = 0; - dict->_count--; - CF_OBJC_KVO_DIDCHANGE(dict, oldkey); - if (cb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))cb->release), __CFGetAllocator(dict), oldkey, dict->_context); - } - dict->_deletes++; - // _CFDictionaryDecrementValue() below has this same code. - if ((__kCFDictionaryMutable == __CFDictionaryGetType(dict)) && (dict->_bucketsNum < 4 * dict->_deletes || (512 < dict->_capacity && 3.236067 * dict->_count < dict->_capacity))) { - // 3.236067 == 2 * golden_mean; this comes about because we're trying to resize down - // when the count is less than 2 capacities smaller, but not right away when count - // is just less than 2 capacities smaller, because an add would then force growth; - // well, the ratio between one capacity and the previous is close to the golden - // mean currently, so (cap / m / m) would be two smaller; but so we're not close, - // we take the average of that and the prior cap (cap / m / m / m). Well, after one - // does the algebra, and uses the convenient fact that m^(x+2) = m^(x+1) + m^x if m - // is the golden mean, this reduces to cap / 2m for the threshold. In general, the - // possible threshold constant is 1 / (2 * m^k), k = 0, 1, 2, ... under this scheme. - // Rehash; currently only for mutable-variable dictionaries - __CFDictionaryGrow(dict, 0); - } else { - // When the probeskip == 1 always and only, a DELETED slot followed by an EMPTY slot - // can be converted to an EMPTY slot. By extension, a chain of DELETED slots followed - // by an EMPTY slot can be converted to EMPTY slots, which is what we do here. - // _CFDictionaryDecrementValue() below has this same code. - if (match < dict->_bucketsNum - 1 && dict->_keys[match + 1] == (const void *)dict->_marker) { - while (0 <= match && dict->_keys[match] == (const void *)~dict->_marker) { - dict->_keys[match] = (const void *)dict->_marker; - dict->_deletes--; - match--; - } - } - } - } -} - -void CFDictionaryRemoveAllValues(CFMutableDictionaryRef dict) { - const void **keys; - const CFDictionaryKeyCallBacks *cb; - const CFDictionaryValueCallBacks *vcb; - CFAllocatorRef allocator; - CFIndex idx, nbuckets; - CF_OBJC_FUNCDISPATCH0(__kCFDictionaryTypeID, void, dict, "removeAllObjects"); - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - switch (__CFDictionaryGetType(dict)) { - case __kCFDictionaryMutable: - case __kCFDictionaryFixedMutable: - break; - default: - CFAssert2(__CFDictionaryGetType(dict) != __kCFDictionaryImmutable, __kCFLogAssertion, "%s(): immutable dict %p passed to mutating operation", __PRETTY_FUNCTION__, dict); - break; - } - if (0 == dict->_count) return; - keys = dict->_keys; - nbuckets = dict->_bucketsNum; - cb = __CFDictionaryGetKeyCallBacks(dict); - vcb = __CFDictionaryGetValueCallBacks(dict); - allocator = __CFGetAllocator(dict); - for (idx = 0; idx < nbuckets; idx++) { - if (dict->_marker != (uintptr_t)keys[idx] && ~dict->_marker != (uintptr_t)keys[idx]) { - const void *oldkey = keys[idx]; - CF_OBJC_KVO_WILLCHANGE(dict, oldkey); - if (vcb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))vcb->release), allocator, dict->_values[idx], dict->_context); - } - keys[idx] = (const void *)~dict->_marker; - dict->_values[idx] = 0; - dict->_count--; - CF_OBJC_KVO_DIDCHANGE(dict, oldkey); - if (cb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))cb->release), allocator, oldkey, dict->_context); - } - } - } - // XXX need memset here - for (idx = 0; idx < nbuckets; idx++) { - keys[idx] = (const void *)dict->_marker; - dict->_values[idx] = 0; - } - dict->_count = 0; - dict->_deletes = 0; - if ((__kCFDictionaryMutable == __CFDictionaryGetType(dict)) && (512 < dict->_capacity)) { - __CFDictionaryGrow(dict, 256); - } -} - -void _CFDictionaryIncrementValue(CFMutableDictionaryRef dict, const void *key) { - CFIndex match, nomatch; - - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - CFAssert1(__CFDictionaryGetType(dict) == __kCFDictionaryMutable, __kCFLogAssertion, "%s(): invalid dict type passed to increment operation", __PRETTY_FUNCTION__); - CFAssert1(__kCFDictionaryHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)dict)->_info, 3, 2), __kCFLogAssertion, "%s(): invalid dict passed to increment operation", __PRETTY_FUNCTION__); - CFAssert1(__kCFDictionaryHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)dict)->_info, 5, 4), __kCFLogAssertion, "%s(): invalid dict passed to increment operation", __PRETTY_FUNCTION__); - - match = kCFNotFound; - if (NULL != dict->_keys) { - __CFDictionaryFindBuckets2(dict, key, &match, &nomatch); - } - if (kCFNotFound != match) { - if (dict->_values[match] != (void *)UINT_MAX) { - dict->_values[match] = (void *)((uintptr_t)dict->_values[match] + 1); - } - } else { - if (dict->_marker == (uintptr_t)key || ~dict->_marker == (uintptr_t)key) { - __CFDictionaryFindNewMarker(dict); - } - if (dict->_count == dict->_capacity || NULL == dict->_keys) { - __CFDictionaryGrow(dict, 1); - __CFDictionaryFindBuckets2(dict, key, &match, &nomatch); - } - dict->_keys[nomatch] = key; - dict->_values[nomatch] = (void *)1; - dict->_count++; - } -} - -int _CFDictionaryDecrementValue(CFMutableDictionaryRef dict, const void *key) { - CFIndex match; - - __CFGenericValidateType(dict, __kCFDictionaryTypeID); - CFAssert1(__CFDictionaryGetType(dict) == __kCFDictionaryMutable, __kCFLogAssertion, "%s(): invalid dict type passed to increment operation", __PRETTY_FUNCTION__); - CFAssert1(__kCFDictionaryHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)dict)->_info, 3, 2), __kCFLogAssertion, "%s(): invalid dict passed to increment operation", __PRETTY_FUNCTION__); - CFAssert1(__kCFDictionaryHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)dict)->_info, 5, 4), __kCFLogAssertion, "%s(): invalid dict passed to increment operation", __PRETTY_FUNCTION__); - - if (0 == dict->_count) return -1; - match = __CFDictionaryFindBuckets1a(dict, key); - if (kCFNotFound == match) return -1; - if (1 == (uintptr_t)dict->_values[match]) { - dict->_count--; - dict->_values[match] = 0; - dict->_keys[match] = (const void *)~dict->_marker; - dict->_deletes++; - if ((__kCFDictionaryMutable == __CFDictionaryGetType(dict)) && (dict->_bucketsNum < 4 * dict->_deletes || (512 < dict->_capacity && 3.236067 * dict->_count < dict->_capacity))) { - __CFDictionaryGrow(dict, 0); - } else { - if (match < dict->_bucketsNum - 1 && dict->_keys[match + 1] == (const void *)dict->_marker) { - while (0 <= match && dict->_keys[match] == (const void *)~dict->_marker) { - dict->_keys[match] = (const void *)dict->_marker; - dict->_deletes--; - match--; - } - } - } - return 0; - } else if (dict->_values[match] != (void *)UINT_MAX) { - dict->_values[match] = (void *)((uintptr_t)dict->_values[match] - 1); - } - return 1; -} - diff --git a/Collections.subproj/CFSet.c b/Collections.subproj/CFSet.c deleted file mode 100644 index 7c58ff7..0000000 --- a/Collections.subproj/CFSet.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFSet.c - Copyright 1998-2002, Apple, Inc. All rights reserved. - Responsibility: Christopher Kane -*/ - -#include -#include "CFInternal.h" - -const CFSetCallBacks kCFTypeSetCallBacks = {0, __CFTypeCollectionRetain, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; -const CFSetCallBacks kCFCopyStringSetCallBacks = {0, (void *)CFStringCreateCopy, __CFTypeCollectionRelease, CFCopyDescription, CFEqual, CFHash}; -static const CFSetCallBacks __kCFNullSetCallBacks = {0, NULL, NULL, NULL, NULL, NULL}; - -static const uint32_t __CFSetCapacities[42] = { - 4, 8, 17, 29, 47, 76, 123, 199, 322, 521, 843, 1364, 2207, 3571, 5778, 9349, - 15127, 24476, 39603, 64079, 103682, 167761, 271443, 439204, 710647, 1149851, 1860498, - 3010349, 4870847, 7881196, 12752043, 20633239, 33385282, 54018521, 87403803, 141422324, - 228826127, 370248451, 599074578, 969323029, 1568397607, 2537720636U -}; - -static const uint32_t __CFSetBuckets[42] = { // primes - 5, 11, 23, 41, 67, 113, 199, 317, 521, 839, 1361, 2207, 3571, 5779, 9349, 15121, - 24473, 39607, 64081, 103681, 167759, 271429, 439199, 710641, 1149857, 1860503, 3010349, - 4870843, 7881193, 12752029, 20633237, 33385273, 54018521, 87403763, 141422317, 228826121, - 370248451, 599074561, 969323023, 1568397599, 2537720629U, 4106118251U -}; - -CF_INLINE CFIndex __CFSetRoundUpCapacity(CFIndex capacity) { - CFIndex idx; - for (idx = 0; idx < 42 && __CFSetCapacities[idx] < (uint32_t)capacity; idx++); - if (42 <= idx) HALT; - return __CFSetCapacities[idx]; -} - -CF_INLINE CFIndex __CFSetNumBucketsForCapacity(CFIndex capacity) { - CFIndex idx; - for (idx = 0; idx < 42 && __CFSetCapacities[idx] < (uint32_t)capacity; idx++); - if (42 <= idx) HALT; - return __CFSetBuckets[idx]; -} - -enum { /* Bits 1-0 */ - __kCFSetImmutable = 0, /* unchangable and fixed capacity */ - __kCFSetMutable = 1, /* changeable and variable capacity */ - __kCFSetFixedMutable = 3 /* changeable and fixed capacity */ -}; - -enum { /* Bits 5-4 (value), 3-2 (key) */ - __kCFSetHasNullCallBacks = 0, - __kCFSetHasCFTypeCallBacks = 1, - __kCFSetHasCustomCallBacks = 3 /* callbacks are at end of header */ -}; - -// Under GC, we fudge the key/value memory in two ways -// First, if we had null callbacks or null for both retain/release, we use unscanned memory -// This means that if people were doing addValue:[xxx new] and never removing, well, that doesn't work -// -// Second, if we notice standard retain/release implementations we substitute scanned memory -// and zero out the retain/release callbacks. This is fine, but when copying we need to restore them - -enum { - __kCFSetRestoreKeys = (1 << 0), - __kCFSetRestoreValues = (1 << 1), - __kCFSetRestoreStringKeys = (1 << 2), - __kCFSetWeakKeys = (1 << 3) -}; - -struct __CFSet { - CFRuntimeBase _base; - CFIndex _count; /* number of values */ - CFIndex _capacity; /* maximum number of values */ - CFIndex _bucketsNum; /* number of slots */ - uintptr_t _marker; - void *_context; /* private */ - CFIndex _deletes; - CFOptionFlags _xflags; /* bits for GC */ - const void **_keys; /* can be NULL if not allocated yet */ -}; - -/* Bits 1-0 of the base reserved bits are used for mutability variety */ -/* Bits 3-2 of the base reserved bits are used for key callback indicator bits */ -/* Bits 5-4 of the base reserved bits are used for value callback indicator bits */ -/* Bit 6 is special KVO actions bit */ - -CF_INLINE CFIndex __CFSetGetType(CFSetRef set) { - return __CFBitfieldGetValue(((const CFRuntimeBase *)set)->_info, 1, 0); -} - -CF_INLINE CFIndex __CFSetGetSizeOfType(CFIndex t) { - CFIndex size = sizeof(struct __CFSet); - if (__CFBitfieldGetValue(t, 3, 2) == __kCFSetHasCustomCallBacks) { - size += sizeof(CFSetCallBacks); - } - return size; -} - -CF_INLINE const CFSetCallBacks *__CFSetGetKeyCallBacks(CFSetRef set) { - CFSetCallBacks *result = NULL; - switch (__CFBitfieldGetValue(((const CFRuntimeBase *)set)->_info, 3, 2)) { - case __kCFSetHasNullCallBacks: - return &__kCFNullSetCallBacks; - case __kCFSetHasCFTypeCallBacks: - return &kCFTypeSetCallBacks; - case __kCFSetHasCustomCallBacks: - break; - } - result = (CFSetCallBacks *)((uint8_t *)set + sizeof(struct __CFSet)); - return result; -} - -CF_INLINE bool __CFSetCallBacksMatchNull(const CFSetCallBacks *c) { - return (NULL == c || - (c->retain == __kCFNullSetCallBacks.retain && - c->release == __kCFNullSetCallBacks.release && - c->copyDescription == __kCFNullSetCallBacks.copyDescription && - c->equal == __kCFNullSetCallBacks.equal && - c->hash == __kCFNullSetCallBacks.hash)); -} - -CF_INLINE bool __CFSetCallBacksMatchCFType(const CFSetCallBacks *c) { - return (&kCFTypeSetCallBacks == c || - (c->retain == kCFTypeSetCallBacks.retain && - c->release == kCFTypeSetCallBacks.release && - c->copyDescription == kCFTypeSetCallBacks.copyDescription && - c->equal == kCFTypeSetCallBacks.equal && - c->hash == kCFTypeSetCallBacks.hash)); -} - -#define CF_OBJC_KVO_WILLCHANGE(obj, sel) -#define CF_OBJC_KVO_DIDCHANGE(obj, sel) - -static CFIndex __CFSetFindBuckets1a(CFSetRef set, const void *key) { - CFHashCode keyHash = (CFHashCode)key; - const void **keys = set->_keys; - uintptr_t marker = set->_marker; - CFIndex probe = keyHash % set->_bucketsNum; - CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value - CFIndex start = probe; - for (;;) { - uintptr_t currKey = (uintptr_t)keys[probe]; - if (marker == currKey) { /* empty */ - return kCFNotFound; - } else if (~marker == currKey) { /* deleted */ - /* do nothing */ - } else if (currKey == (uintptr_t)key) { - return probe; - } - probe = probe + probeskip; - // This alternative to probe % buckets assumes that - // probeskip is always positive and less than the - // number of buckets. - if (set->_bucketsNum <= probe) { - probe -= set->_bucketsNum; - } - if (start == probe) { - return kCFNotFound; - } - } -} - -static CFIndex __CFSetFindBuckets1b(CFSetRef set, const void *key) { - const CFSetCallBacks *cb = __CFSetGetKeyCallBacks(set); - CFHashCode keyHash = cb->hash ? (CFHashCode)INVOKE_CALLBACK2(((CFHashCode (*)(const void *, void *))cb->hash), key, set->_context) : (CFHashCode)key; - const void **keys = set->_keys; - uintptr_t marker = set->_marker; - CFIndex probe = keyHash % set->_bucketsNum; - CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value - CFIndex start = probe; - for (;;) { - uintptr_t currKey = (uintptr_t)keys[probe]; - if (marker == currKey) { /* empty */ - return kCFNotFound; - } else if (~marker == currKey) { /* deleted */ - /* do nothing */ - } else if (currKey == (uintptr_t)key || (cb->equal && INVOKE_CALLBACK3((Boolean (*)(const void *, const void *, void*))cb->equal, (void *)currKey, key, set->_context))) { - return probe; - } - probe = probe + probeskip; - // This alternative to probe % buckets assumes that - // probeskip is always positive and less than the - // number of buckets. - if (set->_bucketsNum <= probe) { - probe -= set->_bucketsNum; - } - if (start == probe) { - return kCFNotFound; - } - } -} - -static void __CFSetFindBuckets2(CFSetRef set, const void *key, CFIndex *match, CFIndex *nomatch) { - const CFSetCallBacks *cb = __CFSetGetKeyCallBacks(set); - CFHashCode keyHash = cb->hash ? (CFHashCode)INVOKE_CALLBACK2(((CFHashCode (*)(const void *, void *))cb->hash), key, set->_context) : (CFHashCode)key; - const void **keys = set->_keys; - uintptr_t marker = set->_marker; - CFIndex probe = keyHash % set->_bucketsNum; - CFIndex probeskip = 1; // See RemoveValue() for notes before changing this value - CFIndex start = probe; - *match = kCFNotFound; - *nomatch = kCFNotFound; - for (;;) { - uintptr_t currKey = (uintptr_t)keys[probe]; - if (marker == currKey) { /* empty */ - if (nomatch) *nomatch = probe; - return; - } else if (~marker == currKey) { /* deleted */ - if (nomatch) { - *nomatch = probe; - nomatch = NULL; - } - } else if (currKey == (uintptr_t)key || (cb->equal && INVOKE_CALLBACK3((Boolean (*)(const void *, const void *, void*))cb->equal, (void *)currKey, key, set->_context))) { - *match = probe; - return; - } - probe = probe + probeskip; - // This alternative to probe % buckets assumes that - // probeskip is always positive and less than the - // number of buckets. - if (set->_bucketsNum <= probe) { - probe -= set->_bucketsNum; - } - if (start == probe) { - return; - } - } -} - -static void __CFSetFindNewMarker(CFSetRef set) { - const void **keys = set->_keys; - uintptr_t newMarker; - CFIndex idx, nbuckets; - bool hit; - - nbuckets = set->_bucketsNum; - newMarker = set->_marker; - do { - newMarker--; - hit = false; - for (idx = 0; idx < nbuckets; idx++) { - if (newMarker == (uintptr_t)keys[idx] || ~newMarker == (uintptr_t)keys[idx]) { - hit = true; - break; - } - } - } while (hit); - for (idx = 0; idx < nbuckets; idx++) { - if (set->_marker == (uintptr_t)keys[idx]) { - keys[idx] = (const void *)newMarker; - } else if (~set->_marker == (uintptr_t)keys[idx]) { - keys[idx] = (const void *)~newMarker; - } - } - ((struct __CFSet *)set)->_marker = newMarker; -} - -static bool __CFSetEqual(CFTypeRef cf1, CFTypeRef cf2) { - CFSetRef set1 = (CFSetRef)cf1; - CFSetRef set2 = (CFSetRef)cf2; - const CFSetCallBacks *cb1, *cb2; - const void **keys; - CFIndex idx, nbuckets; - if (set1 == set2) return true; - if (set1->_count != set2->_count) return false; - cb1 = __CFSetGetKeyCallBacks(set1); - cb2 = __CFSetGetKeyCallBacks(set2); - if (cb1->equal != cb2->equal) return false; - if (0 == set1->_count) return true; /* after function comparison! */ - keys = set1->_keys; - nbuckets = set1->_bucketsNum; - for (idx = 0; idx < nbuckets; idx++) { - if (set1->_marker != (uintptr_t)keys[idx] && ~set1->_marker != (uintptr_t)keys[idx]) { - const void *value; - if (!CFSetGetValueIfPresent(set2, keys[idx], &value)) return false; - } - } - return true; -} - -static CFHashCode __CFSetHash(CFTypeRef cf) { - CFSetRef set = (CFSetRef)cf; - return set->_count; -} - -static CFStringRef __CFSetCopyDescription(CFTypeRef cf) { - CFSetRef set = (CFSetRef)cf; - CFAllocatorRef allocator; - const CFSetCallBacks *cb; - const void **keys; - CFIndex idx, nbuckets; - CFMutableStringRef result; - cb = __CFSetGetKeyCallBacks(set); - keys = set->_keys; - nbuckets = set->_bucketsNum; - allocator = CFGetAllocator(set); - result = CFStringCreateMutable(allocator, 0); - switch (__CFSetGetType(set)) { - case __kCFSetImmutable: - CFStringAppendFormat(result, NULL, CFSTR("{type = immutable, count = %u, capacity = %u, pairs = (\n"), cf, allocator, set->_count, set->_capacity); - break; - case __kCFSetFixedMutable: - CFStringAppendFormat(result, NULL, CFSTR("{type = fixed-mutable, count = %u, capacity = %u, pairs = (\n"), cf, allocator, set->_count, set->_capacity); - break; - case __kCFSetMutable: - CFStringAppendFormat(result, NULL, CFSTR("{type = mutable, count = %u, capacity = %u, pairs = (\n"), cf, allocator, set->_count, set->_capacity); - break; - } - for (idx = 0; idx < nbuckets; idx++) { - if (set->_marker != (uintptr_t)keys[idx] && ~set->_marker != (uintptr_t)keys[idx]) { - CFStringRef kDesc = NULL; - if (NULL != cb->copyDescription) { - kDesc = (CFStringRef)INVOKE_CALLBACK2(((CFStringRef (*)(const void *, void *))cb->copyDescription), keys[idx], set->_context); - } - if (NULL != kDesc) { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : %@\n"), idx, kDesc); - CFRelease(kDesc); - } else { - CFStringAppendFormat(result, NULL, CFSTR("\t%u : <%p>\n"), idx, keys[idx]); - } - } - } - CFStringAppend(result, CFSTR(")}")); - return result; -} - -static void __CFSetDeallocate(CFTypeRef cf) { - CFMutableSetRef set = (CFMutableSetRef)cf; - CFAllocatorRef allocator = __CFGetAllocator(set); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - const CFSetCallBacks *kcb = __CFSetGetKeyCallBacks(set); - if (kcb->retain == NULL && kcb->release == NULL) - return; // XXX_PCB keep set intact during finalization. - } - if (__CFSetGetType(set) == __kCFSetImmutable) { - __CFBitfieldSetValue(((CFRuntimeBase *)set)->_info, 1, 0, __kCFSetFixedMutable); - } - - const CFSetCallBacks *cb = __CFSetGetKeyCallBacks(set); - if (cb->release) { - const void **keys = set->_keys; - CFIndex idx, nbuckets = set->_bucketsNum; - for (idx = 0; idx < nbuckets; idx++) { - if (set->_marker != (uintptr_t)keys[idx] && ~set->_marker != (uintptr_t)keys[idx]) { - const void *oldkey = keys[idx]; - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))cb->release), allocator, oldkey, set->_context); - } - } - } - - if (__CFSetGetType(set) == __kCFSetMutable && set->_keys) { - _CFAllocatorDeallocateGC(allocator, set->_keys); - set->_keys = NULL; - } -} - -/* - * When running under GC, we suss up sets with standard string copy to hold - * onto everything, including the copies of incoming keys, in strong memory without retain counts. - * This is the routine that makes that copy. - * Not for inputs of constant strings we'll get a constant string back, and so the result - * is not guaranteed to be from the auto zone, hence the call to CFRelease since it will figure - * out where the refcount really is. - */ -static CFStringRef _CFStringCreateCopyCollected(CFAllocatorRef allocator, CFStringRef theString) { - return CFMakeCollectable(CFStringCreateCopy(NULL, theString)); -} - -static CFTypeID __kCFSetTypeID = _kCFRuntimeNotATypeID; - -static const CFRuntimeClass __CFSetClass = { - _kCFRuntimeScannedObject, - "CFSet", - NULL, // init - NULL, // copy - __CFSetDeallocate, - (void *)__CFSetEqual, - __CFSetHash, - NULL, // - __CFSetCopyDescription -}; - -__private_extern__ void __CFSetInitialize(void) { - __kCFSetTypeID = _CFRuntimeRegisterClass(&__CFSetClass); -} - -CFTypeID CFSetGetTypeID(void) { - return __kCFSetTypeID; -} - -static CFSetRef __CFSetInit(CFAllocatorRef allocator, uint32_t flags, CFIndex capacity, const CFSetCallBacks *keyCallBacks) { - struct __CFSet *memory; - uint32_t size; - CFIndex idx; - __CFBitfieldSetValue(flags, 31, 2, 0); - CFSetCallBacks nonRetainingKeyCallbacks; - CFOptionFlags xflags = 0; - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - // preserve NULL for key or value CB, otherwise fix up. - if (!keyCallBacks || (keyCallBacks->retain == NULL && keyCallBacks->release == NULL)) { - xflags = __kCFSetWeakKeys; - } - else { - if (keyCallBacks->retain == __CFTypeCollectionRetain && keyCallBacks->release == __CFTypeCollectionRelease) { - // copy everything - nonRetainingKeyCallbacks = *keyCallBacks; - nonRetainingKeyCallbacks.retain = NULL; - nonRetainingKeyCallbacks.release = NULL; - keyCallBacks = &nonRetainingKeyCallbacks; - xflags = __kCFSetRestoreKeys; - } - else if (keyCallBacks->retain == CFStringCreateCopy && keyCallBacks->release == __CFTypeCollectionRelease) { - // copy everything - nonRetainingKeyCallbacks = *keyCallBacks; - nonRetainingKeyCallbacks.retain = (void *)_CFStringCreateCopyCollected; // XXX fix with better cast - nonRetainingKeyCallbacks.release = NULL; - keyCallBacks = &nonRetainingKeyCallbacks; - xflags = (__kCFSetRestoreKeys | __kCFSetRestoreStringKeys); - } - } - } - if (__CFSetCallBacksMatchNull(keyCallBacks)) { - __CFBitfieldSetValue(flags, 3, 2, __kCFSetHasNullCallBacks); - } else if (__CFSetCallBacksMatchCFType(keyCallBacks)) { - __CFBitfieldSetValue(flags, 3, 2, __kCFSetHasCFTypeCallBacks); - } else { - __CFBitfieldSetValue(flags, 3, 2, __kCFSetHasCustomCallBacks); - } - size = __CFSetGetSizeOfType(flags) - sizeof(CFRuntimeBase); - switch (__CFBitfieldGetValue(flags, 1, 0)) { - case __kCFSetImmutable: - case __kCFSetFixedMutable: - size += __CFSetNumBucketsForCapacity(capacity) * sizeof(const void *); - break; - case __kCFSetMutable: - break; - } - memory = (struct __CFSet *)_CFRuntimeCreateInstance(allocator, __kCFSetTypeID, size, NULL); - if (NULL == memory) { - return NULL; - } - __CFBitfieldSetValue(memory->_base._info, 6, 0, flags); - memory->_count = 0; - memory->_marker = (uintptr_t)0xa1b1c1d3; - memory->_context = NULL; - memory->_deletes = 0; - memory->_xflags = xflags; - switch (__CFBitfieldGetValue(flags, 1, 0)) { - case __kCFSetImmutable: - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator) && (xflags & __kCFSetWeakKeys)) { // if weak, don't scan - auto_zone_set_layout_type(__CFCollectableZone, memory, AUTO_OBJECT_UNSCANNED); - } - if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFSet (immutable)"); - memory->_capacity = capacity; /* Don't round up capacity */ - memory->_bucketsNum = __CFSetNumBucketsForCapacity(memory->_capacity); - memory->_keys = (const void **)((uint8_t *)memory + __CFSetGetSizeOfType(flags)); - for (idx = memory->_bucketsNum; idx--;) { - memory->_keys[idx] = (const void *)memory->_marker; - } - break; - case __kCFSetFixedMutable: - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator) && (xflags & __kCFSetWeakKeys)) { // if weak, don't scan - auto_zone_set_layout_type(__CFCollectableZone, memory, AUTO_OBJECT_UNSCANNED); - } - if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFSet (mutable-fixed)"); - memory->_capacity = capacity; /* Don't round up capacity */ - memory->_bucketsNum = __CFSetNumBucketsForCapacity(memory->_capacity); - memory->_keys = (const void **)((uint8_t *)memory + __CFSetGetSizeOfType(flags)); - for (idx = memory->_bucketsNum; idx--;) { - memory->_keys[idx] = (const void *)memory->_marker; - } - break; - case __kCFSetMutable: - if (__CFOASafe) __CFSetLastAllocationEventName(memory, "CFSet (mutable-variable)"); - memory->_capacity = __CFSetRoundUpCapacity(1); - memory->_bucketsNum = 0; - memory->_keys = NULL; - break; - } - if (__kCFSetHasCustomCallBacks == __CFBitfieldGetValue(flags, 3, 2)) { - CFSetCallBacks *cb = (CFSetCallBacks *)__CFSetGetKeyCallBacks((CFSetRef)memory); - *cb = *keyCallBacks; - FAULT_CALLBACK((void **)&(cb->retain)); - FAULT_CALLBACK((void **)&(cb->release)); - FAULT_CALLBACK((void **)&(cb->copyDescription)); - FAULT_CALLBACK((void **)&(cb->equal)); - FAULT_CALLBACK((void **)&(cb->hash)); - } - return (CFSetRef)memory; -} - -CFSetRef CFSetCreate(CFAllocatorRef allocator, const void **keys, CFIndex numValues, const CFSetCallBacks *keyCallBacks) { - CFSetRef result; - uint32_t flags; - CFIndex idx; - CFAssert2(0 <= numValues, __kCFLogAssertion, "%s(): numValues (%d) cannot be less than zero", __PRETTY_FUNCTION__, numValues); - result = __CFSetInit(allocator, __kCFSetImmutable, numValues, keyCallBacks); - flags = __CFBitfieldGetValue(((const CFRuntimeBase *)result)->_info, 1, 0); - if (flags == __kCFSetImmutable) { - // tweak flags so that we can add our immutable values - __CFBitfieldSetValue(((CFRuntimeBase *)result)->_info, 1, 0, __kCFSetFixedMutable); - } - for (idx = 0; idx < numValues; idx++) { - CFSetAddValue((CFMutableSetRef)result, keys[idx]); - } - __CFBitfieldSetValue(((CFRuntimeBase *)result)->_info, 1, 0, flags); - return result; -} - -CFMutableSetRef CFSetCreateMutable(CFAllocatorRef allocator, CFIndex capacity, const CFSetCallBacks *keyCallBacks) { - CFAssert2(0 <= capacity, __kCFLogAssertion, "%s(): capacity (%d) cannot be less than zero", __PRETTY_FUNCTION__, capacity); - return (CFMutableSetRef)__CFSetInit(allocator, (0 == capacity) ? __kCFSetMutable : __kCFSetFixedMutable, capacity, keyCallBacks); -} - - -static void __CFSetGrow(CFMutableSetRef set, CFIndex numNewValues); - -// This creates a set which is for CFTypes or NSObjects, with an ownership transfer -- -// the set does not take a retain, and the caller does not need to release the inserted objects. -// The incoming objects must also be collectable if allocated out of a collectable allocator. -CFSetRef _CFSetCreate_ex(CFAllocatorRef allocator, bool mutable, const void **keys, CFIndex numValues) { - CFSetRef result; - void *bucketsBase; - uint32_t flags; - CFIndex idx; - result = __CFSetInit(allocator, mutable ? __kCFSetMutable : __kCFSetImmutable, numValues, &kCFTypeSetCallBacks); - flags = __CFBitfieldGetValue(((const CFRuntimeBase *)result)->_info, 1, 0); - if (!mutable) { - __CFBitfieldSetValue(((CFRuntimeBase *)result)->_info, 1, 0, __kCFSetFixedMutable); - } - if (mutable) { - if (result->_count == result->_capacity || NULL == result->_keys) { - __CFSetGrow((CFMutableSetRef)result, numValues); - } - } - // GC: since kCFTypeSetCallBacks are used, the keys - // and values will be allocated contiguously. - bool collectableContainer = CF_IS_COLLECTABLE_ALLOCATOR(allocator); - bucketsBase = (collectableContainer ? (void *)auto_zone_base_pointer(__CFCollectableZone, result->_keys) : NULL); - for (idx = 0; idx < numValues; idx++) { - CFIndex match, nomatch; - const void *newKey; - __CFSetFindBuckets2(result, keys[idx], &match, &nomatch); - if (kCFNotFound != match) { - } else { - newKey = keys[idx]; - if (result->_marker == (uintptr_t)newKey || ~result->_marker == (uintptr_t)newKey) { - __CFSetFindNewMarker(result); - } - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, bucketsBase, result->_keys[nomatch], newKey); - // GC: generation(_keys/_values) <= generation(keys/values), but added for completeness. - ((CFMutableSetRef)result)->_count++; - } - } - __CFBitfieldSetValue(((CFRuntimeBase *)result)->_info, 1, 0, flags); - return result; -} - -CFSetRef CFSetCreateCopy(CFAllocatorRef allocator, CFSetRef set) { - CFSetRef result; - const CFSetCallBacks *cb; - CFIndex numValues = CFSetGetCount(set); - const void **list, *buffer[256]; - list = (numValues <= 256) ? buffer : CFAllocatorAllocate(allocator, numValues * sizeof(void *), 0); // XXX_PCB GC OK - if (list != buffer && __CFOASafe) __CFSetLastAllocationEventName(list, "CFSet (temp)"); - CFSetGetValues(set, list); - CFSetCallBacks patchedKeyCB; - if (CF_IS_OBJC(__kCFSetTypeID, set)) { - cb = &kCFTypeSetCallBacks; - } - else { - cb = __CFSetGetKeyCallBacks(set); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - if (set->_xflags & __kCFSetRestoreKeys) { - patchedKeyCB = *cb; // copy - cb = &patchedKeyCB; // reset to copy - patchedKeyCB.retain = (set->_xflags & __kCFSetRestoreStringKeys) ? CFStringCreateCopy : __CFTypeCollectionRetain; - patchedKeyCB.release = __CFTypeCollectionRelease; - } - } - } - result = CFSetCreate(allocator, list, numValues, cb); - if (list != buffer) CFAllocatorDeallocate(allocator, list); // GC OK - return result; -} - -CFMutableSetRef CFSetCreateMutableCopy(CFAllocatorRef allocator, CFIndex capacity, CFSetRef set) { - CFMutableSetRef result; - const CFSetCallBacks *cb; - CFIndex idx, numValues = CFSetGetCount(set); - const void **list, *buffer[256]; - CFAssert3(0 == capacity || numValues <= capacity, __kCFLogAssertion, "%s(): for fixed-mutable sets, capacity (%d) must be greater than or equal to initial number of values (%d)", __PRETTY_FUNCTION__, capacity, numValues); - list = (numValues <= 256) ? buffer : CFAllocatorAllocate(allocator, numValues * sizeof(void *), 0); // XXX_PCB GC OK - if (list != buffer && __CFOASafe) __CFSetLastAllocationEventName(list, "CFSet (temp)"); - CFSetGetValues(set, list); - CFSetCallBacks patchedKeyCB; - if (CF_IS_OBJC(__kCFSetTypeID, set)) { - cb = &kCFTypeSetCallBacks; - } - else { - cb = __CFSetGetKeyCallBacks(set); - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - if (set->_xflags & __kCFSetRestoreKeys) { - patchedKeyCB = *cb; // copy - cb = &patchedKeyCB; // reset to copy - patchedKeyCB.retain = (set->_xflags & __kCFSetRestoreStringKeys) ? CFStringCreateCopy : __CFTypeCollectionRetain; - patchedKeyCB.release = __CFTypeCollectionRelease; - } - } - } - result = CFSetCreateMutable(allocator, capacity, cb); - if (0 == capacity) _CFSetSetCapacity(result, numValues); - for (idx = 0; idx < numValues; idx++) { - CFSetAddValue(result, list[idx]); - } - if (list != buffer) CFAllocatorDeallocate(allocator, list); // XXX_PCB GC OK - return result; -} - -// Used by NSHashTables and KVO -void _CFSetSetContext(CFSetRef set, void *context) { - CFAllocatorRef allocator = CFGetAllocator(set); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, set, set->_context, context); -} - -void *_CFSetGetContext(CFSetRef set) { - return ((struct __CFSet *)set)->_context; -} - -CFIndex CFSetGetCount(CFSetRef set) { - CF_OBJC_FUNCDISPATCH0(__kCFSetTypeID, CFIndex, set, "count"); - __CFGenericValidateType(set, __kCFSetTypeID); - return set->_count; -} - -CFIndex CFSetGetCountOfValue(CFSetRef set, const void *key) { - CFIndex match; - CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, CFIndex, set, "countForObject:", key); - __CFGenericValidateType(set, __kCFSetTypeID); - if (0 == set->_count) return 0; - if (__kCFSetHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)set)->_info, 3, 2)) { - match = __CFSetFindBuckets1a(set, key); - } else { - match = __CFSetFindBuckets1b(set, key); - } - return (kCFNotFound != match ? 1 : 0); -} - -Boolean CFSetContainsValue(CFSetRef set, const void *key) { - CFIndex match; - CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, char, set, "containsObject:", key); - __CFGenericValidateType(set, __kCFSetTypeID); - if (0 == set->_count) return false; - if (__kCFSetHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)set)->_info, 3, 2)) { - match = __CFSetFindBuckets1a(set, key); - } else { - match = __CFSetFindBuckets1b(set, key); - } - return (kCFNotFound != match ? true : false); -} - -const void *CFSetGetValue(CFSetRef set, const void *key) { - CFIndex match; - CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, const void *, set, "member:", key); - __CFGenericValidateType(set, __kCFSetTypeID); - if (0 == set->_count) return NULL; - if (__kCFSetHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)set)->_info, 3, 2)) { - match = __CFSetFindBuckets1a(set, key); - } else { - match = __CFSetFindBuckets1b(set, key); - } - return (kCFNotFound != match ? set->_keys[match] : NULL); -} - -Boolean CFSetGetValueIfPresent(CFSetRef set, const void *key, const void **actualkey) { - CFIndex match; - CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, char, set, "_getValue:forObj:", (void * *) actualkey, key); - __CFGenericValidateType(set, __kCFSetTypeID); - if (0 == set->_count) return false; - if (__kCFSetHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)set)->_info, 3, 2)) { - match = __CFSetFindBuckets1a(set, key); - } else { - match = __CFSetFindBuckets1b(set, key); - } - return (kCFNotFound != match ? ((actualkey ? __CFObjCStrongAssign(set->_keys[match], actualkey) : NULL), true) : false); -} - -void CFSetGetValues(CFSetRef set, const void **keys) { - CFIndex idx, cnt, nbuckets; - CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, void, set, "getObjects:", (void * *) keys); - __CFGenericValidateType(set, __kCFSetTypeID); - if (CF_USING_COLLECTABLE_MEMORY) { - // GC: speculatively issue a write-barrier on the copied to buffers (3743553). - __CFObjCWriteBarrierRange(keys, set->_count * sizeof(void *)); - } - nbuckets = set->_bucketsNum; - for (idx = 0; idx < nbuckets; idx++) { - if (set->_marker != (uintptr_t)set->_keys[idx] && ~set->_marker != (uintptr_t)set->_keys[idx]) { - for (cnt = 1; cnt--;) { - if (keys) CF_WRITE_BARRIER_ASSIGN(NULL, *keys++, set->_keys[idx]); - } - } - } -} - -void CFSetApplyFunction(CFSetRef set, CFSetApplierFunction applier, void *context) { - const void **keys; - CFIndex idx, cnt, nbuckets; - FAULT_CALLBACK((void **)&(applier)); - CF_OBJC_FUNCDISPATCH2(__kCFSetTypeID, void, set, "_applyValues:context:", applier, context); - __CFGenericValidateType(set, __kCFSetTypeID); - keys = set->_keys; - nbuckets = set->_bucketsNum; - for (idx = 0; idx < nbuckets; idx++) { - if (set->_marker != (uintptr_t)keys[idx] && ~set->_marker != (uintptr_t)keys[idx]) { - for (cnt = 1; cnt--;) { - INVOKE_CALLBACK2(applier, keys[idx], context); - } - } - } -} - - -static void __CFSetGrow(CFMutableSetRef set, CFIndex numNewValues) { - const void **oldkeys = set->_keys; - CFIndex idx, oldnbuckets = set->_bucketsNum; - CFIndex oldCount = set->_count; - CFAllocatorRef allocator = __CFGetAllocator(set), keysAllocator; - void *keysBase; - set->_capacity = __CFSetRoundUpCapacity(oldCount + numNewValues); - set->_bucketsNum = __CFSetNumBucketsForCapacity(set->_capacity); - set->_deletes = 0; - void *buckets = _CFAllocatorAllocateGC(allocator, set->_bucketsNum * sizeof(const void *), (set->_xflags & __kCFSetWeakKeys) ? AUTO_MEMORY_UNSCANNED : AUTO_MEMORY_SCANNED); - CF_WRITE_BARRIER_BASE_ASSIGN(allocator, set, set->_keys, buckets); - keysAllocator = allocator; - keysBase = set->_keys; - if (NULL == set->_keys) HALT; - if (__CFOASafe) __CFSetLastAllocationEventName(set->_keys, "CFSet (store)"); - for (idx = set->_bucketsNum; idx--;) { - set->_keys[idx] = (const void *)set->_marker; - } - if (NULL == oldkeys) return; - for (idx = 0; idx < oldnbuckets; idx++) { - if (set->_marker != (uintptr_t)oldkeys[idx] && ~set->_marker != (uintptr_t)oldkeys[idx]) { - CFIndex match, nomatch; - __CFSetFindBuckets2(set, oldkeys[idx], &match, &nomatch); - CFAssert3(kCFNotFound == match, __kCFLogAssertion, "%s(): two values (%p, %p) now hash to the same slot; mutable value changed while in table or hash value is not immutable", __PRETTY_FUNCTION__, oldkeys[idx], set->_keys[match]); - if (kCFNotFound != nomatch) { - CF_WRITE_BARRIER_BASE_ASSIGN(keysAllocator, keysBase, set->_keys[nomatch], oldkeys[idx]); - } - } - } - CFAssert1(set->_count == oldCount, __kCFLogAssertion, "%s(): set count differs after rehashing; error", __PRETTY_FUNCTION__); - _CFAllocatorDeallocateGC(allocator, oldkeys); -} - -// This function is for Foundation's benefit; no one else should use it. -void _CFSetSetCapacity(CFMutableSetRef set, CFIndex cap) { - if (CF_IS_OBJC(__kCFSetTypeID, set)) return; -#if defined(DEBUG) - __CFGenericValidateType(set, __kCFSetTypeID); - CFAssert1(__CFSetGetType(set) != __kCFSetImmutable && __CFSetGetType(set) != __kCFSetFixedMutable, __kCFLogAssertion, "%s(): set is immutable or fixed-mutable", __PRETTY_FUNCTION__); - CFAssert3(set->_count <= cap, __kCFLogAssertion, "%s(): desired capacity (%d) is less than count (%d)", __PRETTY_FUNCTION__, cap, set->_count); -#endif - __CFSetGrow(set, cap - set->_count); -} - - -void CFSetAddValue(CFMutableSetRef set, const void *key) { - CFIndex match, nomatch; - const CFSetCallBacks *cb; - const void *newKey; - CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, void, set, "addObject:", key); - __CFGenericValidateType(set, __kCFSetTypeID); - switch (__CFSetGetType(set)) { - case __kCFSetMutable: - if (set->_count == set->_capacity || NULL == set->_keys) { - __CFSetGrow(set, 1); - } - break; - case __kCFSetFixedMutable: - CFAssert3(set->_count < set->_capacity, __kCFLogAssertion, "%s(): capacity exceeded on fixed-capacity set %p (capacity = %d)", __PRETTY_FUNCTION__, set, set->_capacity); - break; - default: - CFAssert2(__CFSetGetType(set) != __kCFSetImmutable, __kCFLogAssertion, "%s(): immutable set %p passed to mutating operation", __PRETTY_FUNCTION__, set); - break; - } - __CFSetFindBuckets2(set, key, &match, &nomatch); - if (kCFNotFound != match) { - } else { - CFAllocatorRef allocator = __CFGetAllocator(set); - CFAllocatorRef keysAllocator = (set->_xflags & __kCFSetWeakKeys) ? kCFAllocatorNull : allocator; - cb = __CFSetGetKeyCallBacks(set); - if (cb->retain) { - newKey = (void *)INVOKE_CALLBACK3(((const void *(*)(CFAllocatorRef, const void *, void *))cb->retain), allocator, key, set->_context); - } else { - newKey = key; - } - if (set->_marker == (uintptr_t)newKey || ~set->_marker == (uintptr_t)newKey) { - __CFSetFindNewMarker(set); - } - CF_OBJC_KVO_WILLCHANGE(set, key); - CF_WRITE_BARRIER_ASSIGN(keysAllocator, set->_keys[nomatch], newKey); - set->_count++; - CF_OBJC_KVO_DIDCHANGE(set, key); - } -} - -__private_extern__ const void *__CFSetAddValueAndReturn(CFMutableSetRef set, const void *key) { - CFIndex match, nomatch; - const CFSetCallBacks *cb; - const void *newKey; -// #warning not toll-free bridged, but internal - __CFGenericValidateType(set, __kCFSetTypeID); - switch (__CFSetGetType(set)) { - case __kCFSetMutable: - if (set->_count == set->_capacity || NULL == set->_keys) { - __CFSetGrow(set, 1); - } - break; - case __kCFSetFixedMutable: - CFAssert3(set->_count < set->_capacity, __kCFLogAssertion, "%s(): capacity exceeded on fixed-capacity set %p (capacity = %d)", __PRETTY_FUNCTION__, set, set->_capacity); - break; - default: - CFAssert2(__CFSetGetType(set) != __kCFSetImmutable, __kCFLogAssertion, "%s(): immutable set %p passed to mutating operation", __PRETTY_FUNCTION__, set); - break; - } - __CFSetFindBuckets2(set, key, &match, &nomatch); - if (kCFNotFound != match) { - return set->_keys[match]; - } else { - CFAllocatorRef allocator = __CFGetAllocator(set); - CFAllocatorRef keysAllocator = (set->_xflags & __kCFSetWeakKeys) ? kCFAllocatorNull : allocator; - cb = __CFSetGetKeyCallBacks(set); - if (cb->retain) { - newKey = (void *)INVOKE_CALLBACK3(((const void *(*)(CFAllocatorRef, const void *, void *))cb->retain), allocator, key, set->_context); - } else { - newKey = key; - } - if (set->_marker == (uintptr_t)newKey || ~set->_marker == (uintptr_t)newKey) { - __CFSetFindNewMarker(set); - } - CF_OBJC_KVO_WILLCHANGE(set, key); - CF_WRITE_BARRIER_ASSIGN(keysAllocator, set->_keys[nomatch], newKey); - set->_count++; - CF_OBJC_KVO_DIDCHANGE(set, key); - return newKey; - } -} - -void CFSetReplaceValue(CFMutableSetRef set, const void *key) { - CFIndex match; - const CFSetCallBacks *cb; - const void *newKey; - CFAllocatorRef allocator; - CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, void, set, "_replaceObject:", key); - __CFGenericValidateType(set, __kCFSetTypeID); - switch (__CFSetGetType(set)) { - case __kCFSetMutable: - case __kCFSetFixedMutable: - break; - default: - CFAssert2(__CFSetGetType(set) != __kCFSetImmutable, __kCFLogAssertion, "%s(): immutable set %p passed to mutating operation", __PRETTY_FUNCTION__, set); - break; - } - if (0 == set->_count) return; - if (__kCFSetHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)set)->_info, 3, 2)) { - match = __CFSetFindBuckets1a(set, key); - } else { - match = __CFSetFindBuckets1b(set, key); - } - if (kCFNotFound == match) return; - cb = __CFSetGetKeyCallBacks(set); - allocator = (set->_xflags & __kCFSetWeakKeys) ? kCFAllocatorNull : __CFGetAllocator(set); - if (cb->retain) { - newKey = (void *)INVOKE_CALLBACK3(((const void *(*)(CFAllocatorRef, const void *, void *))cb->retain), allocator, key, set->_context); - } else { - newKey = key; - } - CF_OBJC_KVO_WILLCHANGE(set, key); - if (cb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))cb->release), allocator, set->_keys[match], set->_context); - } - CF_WRITE_BARRIER_ASSIGN(allocator, set->_keys[match], newKey); - CF_OBJC_KVO_DIDCHANGE(set, key); -} - -void CFSetSetValue(CFMutableSetRef set, const void *key) { - CFIndex match, nomatch; - const CFSetCallBacks *cb; - const void *newKey; - CFAllocatorRef allocator; - CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, void, set, "_setObject:", key); - __CFGenericValidateType(set, __kCFSetTypeID); - switch (__CFSetGetType(set)) { - case __kCFSetMutable: - if (set->_count == set->_capacity || NULL == set->_keys) { - __CFSetGrow(set, 1); - } - break; - case __kCFSetFixedMutable: - break; - default: - CFAssert2(__CFSetGetType(set) != __kCFSetImmutable, __kCFLogAssertion, "%s(): immutable set %p passed to mutating operation", __PRETTY_FUNCTION__, set); - break; - } - __CFSetFindBuckets2(set, key, &match, &nomatch); - cb = __CFSetGetKeyCallBacks(set); - allocator = (set->_xflags & __kCFSetWeakKeys) ? kCFAllocatorNull : __CFGetAllocator(set); - if (cb->retain) { - newKey = (void *)INVOKE_CALLBACK3(((const void *(*)(CFAllocatorRef, const void *, void *))cb->retain), allocator, key, set->_context); - } else { - newKey = key; - } - if (kCFNotFound != match) { - CF_OBJC_KVO_WILLCHANGE(set, key); - if (cb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))cb->release), allocator, set->_keys[match], set->_context); - } - CF_WRITE_BARRIER_ASSIGN(allocator, set->_keys[match], newKey); - CF_OBJC_KVO_DIDCHANGE(set, key); - } else { - CFAssert3(__kCFSetFixedMutable != __CFSetGetType(set) || set->_count < set->_capacity, __kCFLogAssertion, "%s(): capacity exceeded on fixed-capacity set %p (capacity = %d)", __PRETTY_FUNCTION__, set, set->_capacity); - if (set->_marker == (uintptr_t)newKey || ~set->_marker == (uintptr_t)newKey) { - __CFSetFindNewMarker(set); - } - CF_OBJC_KVO_WILLCHANGE(set, key); - CF_WRITE_BARRIER_ASSIGN(allocator, set->_keys[nomatch], newKey); - set->_count++; - CF_OBJC_KVO_DIDCHANGE(set, key); - } -} - -void CFSetRemoveValue(CFMutableSetRef set, const void *key) { - CFIndex match; - const CFSetCallBacks *cb; - CF_OBJC_FUNCDISPATCH1(__kCFSetTypeID, void, set, "removeObject:", key); - __CFGenericValidateType(set, __kCFSetTypeID); - switch (__CFSetGetType(set)) { - case __kCFSetMutable: - case __kCFSetFixedMutable: - break; - default: - CFAssert2(__CFSetGetType(set) != __kCFSetImmutable, __kCFLogAssertion, "%s(): immutable set %p passed to mutating operation", __PRETTY_FUNCTION__, set); - break; - } - if (0 == set->_count) return; - if (__kCFSetHasNullCallBacks == __CFBitfieldGetValue(((const CFRuntimeBase *)set)->_info, 3, 2)) { - match = __CFSetFindBuckets1a(set, key); - } else { - match = __CFSetFindBuckets1b(set, key); - } - if (kCFNotFound == match) return; - cb = __CFSetGetKeyCallBacks(set); - if (1) { - const void *oldkey = set->_keys[match]; - CF_OBJC_KVO_WILLCHANGE(set, oldkey); - set->_keys[match] = (const void *)~set->_marker; - set->_count--; - CF_OBJC_KVO_DIDCHANGE(set, oldkey); - if (cb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))cb->release), __CFGetAllocator(set), oldkey, set->_context); - } - set->_deletes++; - if ((__kCFSetMutable == __CFSetGetType(set)) && (set->_bucketsNum < 4 * set->_deletes || (512 < set->_capacity && 3.236067 * set->_count < set->_capacity))) { - // 3.236067 == 2 * golden_mean; this comes about because we're trying to resize down - // when the count is less than 2 capacities smaller, but not right away when count - // is just less than 2 capacities smaller, because an add would then force growth; - // well, the ratio between one capacity and the previous is close to the golden - // mean currently, so (cap / m / m) would be two smaller; but so we're not close, - // we take the average of that and the prior cap (cap / m / m / m). Well, after one - // does the algebra, and uses the convenient fact that m^(x+2) = m^(x+1) + m^x if m - // is the golden mean, this reduces to cap / 2m for the threshold. In general, the - // possible threshold constant is 1 / (2 * m^k), k = 0, 1, 2, ... under this scheme. - // Rehash; currently only for mutable-variable sets - __CFSetGrow(set, 0); - } else { - // When the probeskip == 1 always and only, a DELETED slot followed by an EMPTY slot - // can be converted to an EMPTY slot. By extension, a chain of DELETED slots followed - // by an EMPTY slot can be converted to EMPTY slots, which is what we do here. - // _CFSetDecrementValue() below has this same code. - if (match < set->_bucketsNum - 1 && set->_keys[match + 1] == (const void *)set->_marker) { - while (0 <= match && set->_keys[match] == (const void *)~set->_marker) { - set->_keys[match] = (const void *)set->_marker; - set->_deletes--; - match--; - } - } - } - } -} - -void CFSetRemoveAllValues(CFMutableSetRef set) { - const void **keys; - const CFSetCallBacks *cb; - CFAllocatorRef allocator; - CFIndex idx, nbuckets; - CF_OBJC_FUNCDISPATCH0(__kCFSetTypeID, void, set, "removeAllObjects"); - __CFGenericValidateType(set, __kCFSetTypeID); - switch (__CFSetGetType(set)) { - case __kCFSetMutable: - case __kCFSetFixedMutable: - break; - default: - CFAssert2(__CFSetGetType(set) != __kCFSetImmutable, __kCFLogAssertion, "%s(): immutable set %p passed to mutating operation", __PRETTY_FUNCTION__, set); - break; - } - if (0 == set->_count) return; - keys = set->_keys; - nbuckets = set->_bucketsNum; - cb = __CFSetGetKeyCallBacks(set); - allocator = __CFGetAllocator(set); - for (idx = 0; idx < nbuckets; idx++) { - if (set->_marker != (uintptr_t)keys[idx] && ~set->_marker != (uintptr_t)keys[idx]) { - const void *oldkey = keys[idx]; - CF_OBJC_KVO_WILLCHANGE(set, oldkey); - keys[idx] = (const void *)~set->_marker; - set->_count--; - CF_OBJC_KVO_DIDCHANGE(set, oldkey); - if (cb->release) { - INVOKE_CALLBACK3(((void (*)(CFAllocatorRef, const void *, void *))cb->release), allocator, oldkey, set->_context); - } - } - } - // XXX need memset here - for (idx = 0; idx < nbuckets; idx++) { - keys[idx] = (const void *)set->_marker; - } - set->_count = 0; - set->_deletes = 0; - if ((__kCFSetMutable == __CFSetGetType(set)) && (512 < set->_capacity)) { - __CFSetGrow(set, 256); - } -} - diff --git a/Base.subproj/CoreFoundation.h b/CoreFoundation.h similarity index 89% rename from Base.subproj/CoreFoundation.h rename to CoreFoundation.h index 7492d7b..6f95a98 100644 --- a/Base.subproj/CoreFoundation.h +++ b/CoreFoundation.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* CoreFoundation.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !defined(__COREFOUNDATION_COREFOUNDATION__) @@ -60,48 +60,39 @@ #include #include #include +#include +#include +#include +#include +#include #include #include #include +#include #include +#include +#include +#include +#include +#include #include +#include +#include +#include #include +#include #include +#include +#include #include #include #include #include #include -#include -#include - -#if defined(__MACH__) || defined(__WIN32__) -#include -#include -#include -#include -#endif - -#include -#include -#include -#include -#include -#include #include #include - -#include - -#include - -#if defined(__MACH__) - - -#include - - -#endif // __MACH__ +#include +#include #endif /* ! __COREFOUNDATION_COREFOUNDATION__ */ diff --git a/Base.subproj/ForFoundationOnly.h b/ForFoundationOnly.h similarity index 76% rename from Base.subproj/ForFoundationOnly.h rename to ForFoundationOnly.h index 1c25d45..f213eb4 100644 --- a/Base.subproj/ForFoundationOnly.h +++ b/ForFoundationOnly.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2008 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -21,7 +21,7 @@ * @APPLE_LICENSE_HEADER_END@ */ /* ForFoundationOnly.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. + Copyright (c) 1998-2007, Apple Inc. All rights reserved. */ #if !CF_BUILDING_CF && !NSBUILDINGFOUNDATION @@ -38,38 +38,38 @@ #include #include #include +#include +#include +#include // NOTE: miscellaneous declarations are at the end // ---- CFRuntime material ---------------------------------------- -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN +#if DEPLOYMENT_TARGET_MACOSX || 0 #include +#endif //__MACH__ -CF_EXPORT -void __CFSetupFoundationBridging(void *, void *, void *, void *); - -#if defined(__cplusplus) -} -#endif +CF_EXTERN_C_END // ---- CFBundle material ---------------------------------------- #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN CF_EXPORT const CFStringRef _kCFBundleExecutablePathKey; 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); @@ -78,12 +78,13 @@ CF_EXPORT UInt8 _CFBundleLayoutVersion(CFBundleRef bundle); CF_EXPORT CFArrayRef _CFBundleCopyLanguageSearchListInDirectory(CFAllocatorRef alloc, CFURLRef url, UInt8 *version); CF_EXPORT CFArrayRef _CFBundleGetLanguageSearchList(CFBundleRef bundle); -#if defined(__cplusplus) -} -#endif +CF_EXPORT Boolean _CFBundleLoadExecutableAndReturnError(CFBundleRef bundle, Boolean forceGlobal, CFErrorRef *error); +CF_EXPORT CFErrorRef _CFBundleCreateError(CFAllocatorRef allocator, CFBundleRef bundle, CFIndex code); +CF_EXTERN_C_END -#if defined(__MACH__) + +#if (DEPLOYMENT_TARGET_MACOSX || 0) || defined (__WIN32__) // ---- CFPreferences material ---------------------------------------- #define DEBUG_PREFERENCES_MEMORY 0 @@ -92,9 +93,7 @@ CF_EXPORT CFArrayRef _CFBundleGetLanguageSearchList(CFBundleRef bundle); #include "../Tests/CFCountingAllocator.h" #endif -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN extern void _CFPreferencesPurgeDomainCache(void); @@ -112,12 +111,7 @@ typedef struct { CF_EXPORT CFAllocatorRef __CFPreferencesAllocator(void); CF_EXPORT const _CFPreferencesDomainCallBacks __kCFVolatileDomainCallBacks; - -#if defined(__WIN32__) -CF_EXPORT const _CFPreferencesDomainCallBacks __kCFWindowsRegistryDomainCallBacks; -#else CF_EXPORT const _CFPreferencesDomainCallBacks __kCFXMLPropertyListDomainCallBacks; -#endif typedef struct __CFPreferencesDomain * CFPreferencesDomainRef; @@ -128,14 +122,10 @@ CF_EXPORT CFTypeRef _CFPreferencesDomainCreateValueForKey(CFPreferencesDomainRef CF_EXPORT void _CFPreferencesDomainSet(CFPreferencesDomainRef domain, CFStringRef key, CFTypeRef value); CF_EXPORT Boolean _CFPreferencesDomainSynchronize(CFPreferencesDomainRef domain); -/* If buf is NULL, no allocation occurs. *numKeyValuePairs should be set to the current size of buf; alloc should be allocator to allocate/reallocate buf, or kCFAllocatorNull if buf is not to be (re)allocated. No matter what happens, *numKeyValuePairs is always set to the number of pairs in the domain */ -CF_EXPORT void _CFPreferencesDomainGetKeysAndValues(CFAllocatorRef alloc, CFPreferencesDomainRef domain, void **buf[], CFIndex *numKeyValuePairs); - CF_EXPORT CFArrayRef _CFPreferencesCreateDomainList(CFStringRef userName, CFStringRef hostName); CF_EXPORT Boolean _CFSynchronizeDomainCache(void); CF_EXPORT void _CFPreferencesDomainSetDictionary(CFPreferencesDomainRef domain, CFDictionaryRef dict); -CF_EXPORT CFDictionaryRef _CFPreferencesDomainCopyDictionary(CFPreferencesDomainRef domain); CF_EXPORT CFDictionaryRef _CFPreferencesDomainDeepCopyDictionary(CFPreferencesDomainRef domain); CF_EXPORT Boolean _CFPreferencesDomainExists(CFStringRef domainName, CFStringRef userName, CFStringRef hostName); @@ -159,7 +149,6 @@ CF_EXPORT void _CFApplicationPreferencesUpdate(_CFApplicationPreferences *self); CF_EXPORT CFDictionaryRef _CFApplicationPreferencesCopyRepresentation3(_CFApplicationPreferences *self, CFDictionaryRef hint, CFDictionaryRef insertion, CFPreferencesDomainRef afterDomain); CF_EXPORT CFDictionaryRef _CFApplicationPreferencesCopyRepresentationWithHint(_CFApplicationPreferences *self, CFDictionaryRef hint); // same as dictRep CF_EXPORT void _CFApplicationPreferencesSetStandardSearchList(_CFApplicationPreferences *appPreferences); -CF_EXPORT void _CFApplicationPreferencesSetSearchList(_CFApplicationPreferences *self, CFArrayRef newSearchList); CF_EXPORT void _CFApplicationPreferencesSetCacheForApp(_CFApplicationPreferences *appPrefs, CFStringRef appName); CF_EXPORT void _CFApplicationPreferencesAddSuitePreferences(_CFApplicationPreferences *appPrefs, CFStringRef suiteName); CF_EXPORT void _CFApplicationPreferencesRemoveSuitePreferences(_CFApplicationPreferences *appPrefs, CFStringRef suiteName); @@ -171,21 +160,82 @@ CF_EXPORT void _CFApplicationPreferencesRemoveDomain(_CFApplicationPreferences * CF_EXPORT CFTypeRef _CFApplicationPreferencesSearchDownToDomain(_CFApplicationPreferences *self, CFPreferencesDomainRef stopper, CFStringRef key); -#if defined(__cplusplus) -} +CF_EXTERN_C_END + #endif -#endif // __MACH__ +#if DEPLOYMENT_TARGET_MACOSX || 0 || 0 +// ---- CFNotification material ---------------------------------------- +#include +CF_EXTERN_C_BEGIN -// ---- CFString material ---------------------------------------- +enum { + kCFXNotificationSuspensionBehaviorDeliverImmediately = 1, + kCFXNotificationSuspensionBehaviorDrop = 2, + kCFXNotificationSuspensionBehaviorCoalesce = 4, + kCFXNotificationSuspensionBehaviorHold = 8, + kCFXNotificationSuspensionBehaviorAny = 0x0000FFFF +}; +typedef CFOptionFlags CFXNotificationSuspensionBehavior; + +CF_EXPORT const CFStringRef kCFNotificationAnyName; +CF_EXPORT const CFStringRef kCFNotificationAnyObject; + +typedef void (*CFXNotificationCallBack)(CFNotificationCenterRef nc, CFStringRef name, const void *object, CFDictionaryRef userInfo, void *info); + +// operations: 1==retain, 2==release, 3==copyDescription +typedef void * (*CFXNotificationInfoCallBack)(int operation, void *info); +typedef bool (*CFXNotificationEqualCallBack)(const void *info1, const void *info2); + +// 'object' is treated as an arbitrary unretained pointer for a local notification +// center, and as a retained CFStringRef or NULL for a distributed notification center. +typedef struct { // version 0 + CFIndex version; + CFXNotificationCallBack callback; + CFXNotificationSuspensionBehavior behavior; + CFStringRef name; + const void * object; + void * info; + CFXNotificationInfoCallBack info_callback; +} CFNotificationRegistrationData; + +typedef struct { // version 0 + CFIndex version; + CFXNotificationCallBack callback; + CFXNotificationSuspensionBehavior behaviorFlags; + CFStringRef name; + const void * object; + void * info; + CFXNotificationEqualCallBack info_equal; +} CFNotificationUnregistrationData; + + +CF_EXPORT CFNotificationCenterRef _CFXNotificationGetTaskCenter(void); +CF_EXPORT CFNotificationCenterRef _CFXNotificationGetHostCenter(void); + +CF_EXPORT CFNotificationCenterRef _CFXNotificationCenterCreate(CFAllocatorRef allocator, bool distributed); +CF_EXPORT void _CFXNotificationRegister(CFNotificationCenterRef nc, CFNotificationRegistrationData *data); +CF_EXPORT void _CFXNotificationUnregister(CFNotificationCenterRef nc, CFNotificationUnregistrationData *data); + +CF_EXPORT void _CFXNotificationPost(CFNotificationCenterRef nc, CFStringRef name, const void *object, CFDictionaryRef userInfo, CFOptionFlags options); +CF_EXPORT void _CFXNotificationPostNotification(CFNotificationCenterRef nc, CFStringRef name, const void *object, CFDictionaryRef userInfo, CFOptionFlags options, void *note); + +CF_EXPORT bool _CFXNotificationGetSuspended(CFNotificationCenterRef nc); +CF_EXPORT void _CFXNotificationSetSuspended(CFNotificationCenterRef nc, bool suspended); + +CF_EXTERN_C_END -#if defined(__cplusplus) -extern "C" { #endif + +// ---- CFString material ---------------------------------------- + + +CF_EXTERN_C_BEGIN + /* Create a byte stream from a CFString backing. Can convert a string piece at a time into a fixed size buffer. Returns number of characters converted. Characters that cannot be converted to the specified encoding are represented @@ -254,7 +304,7 @@ typedef struct { /* A simple struct to maintain ASCII/Unicode versions of t Boolean _unused1; Boolean _unused2; CFAllocatorRef allocator; /* Use this allocator to allocate, reallocate, and deallocate the bytes */ - UInt32 numChars; /* This is in terms of ascii or unicode; that is, if isASCII, it is number of 7-bit chars; otherwise it is number of UniChars; note that the actual allocated space might be larger */ + CFIndex numChars; /* This is in terms of ascii or unicode; that is, if isASCII, it is number of 7-bit chars; otherwise it is number of UniChars; note that the actual allocated space might be larger */ UInt8 localBuffer[__kCFVarWidthLocalBufferSize]; /* private; 168 ISO2022JP chars, 504 Unicode chars, 1008 ASCII chars */ } CFVarWidthCharBuffer; @@ -264,7 +314,7 @@ typedef struct { /* A simple struct to maintain ASCII/Unicode versions of t !!! __CFStringDecodeByteStream2() needs to be deprecated and removed post-Jaguar. */ CF_EXPORT Boolean __CFStringDecodeByteStream2(const UInt8 *bytes, UInt32 len, CFStringEncoding encoding, Boolean alwaysUnicode, CFVarWidthCharBuffer *buffer, Boolean *useClientsMemoryPtr); -CF_EXPORT Boolean __CFStringDecodeByteStream3(const UInt8 *bytes, UInt32 len, CFStringEncoding encoding, Boolean alwaysUnicode, CFVarWidthCharBuffer *buffer, Boolean *useClientsMemoryPtr, UInt32 converterFlags); +CF_EXPORT Boolean __CFStringDecodeByteStream3(const UInt8 *bytes, CFIndex len, CFStringEncoding encoding, Boolean alwaysUnicode, CFVarWidthCharBuffer *buffer, Boolean *useClientsMemoryPtr, UInt32 converterFlags); /* Convert single byte to Unicode; assumes one-to-one correspondence (that is, can only be used with 1-byte encodings). You can use the function if it's not NULL. The table is always safe to use; calling __CFSetCharToUniCharFunc() updates it. @@ -312,8 +362,8 @@ CF_INLINE UniChar __CFStringGetCharacterFromInlineBufferQuick(CFStringInlineBuff /* These two allow specifying an alternate description function (instead of CFCopyDescription); used by NSString */ -CF_EXPORT void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStringRef (*copyDescFunc)(void *, CFDictionaryRef), CFDictionaryRef formatOptions, CFStringRef formatString, va_list args); -CF_EXPORT CFStringRef _CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc, CFStringRef (*copyDescFunc)(void *, CFDictionaryRef), CFDictionaryRef formatOptions, CFStringRef format, va_list arguments); +CF_EXPORT void _CFStringAppendFormatAndArgumentsAux(CFMutableStringRef outputString, CFStringRef (*copyDescFunc)(void *, const void *loc), CFDictionaryRef formatOptions, CFStringRef formatString, va_list args); +CF_EXPORT CFStringRef _CFStringCreateWithFormatAndArgumentsAux(CFAllocatorRef alloc, CFStringRef (*copyDescFunc)(void *, const void *loc), CFDictionaryRef formatOptions, CFStringRef format, va_list arguments); /* For NSString (and NSAttributedString) usage, mutate with isMutable check */ @@ -336,10 +386,17 @@ CF_EXPORT CFHashCode CFStringHashCString(const uint8_t *bytes, CFIndex len); CF_EXPORT CFHashCode CFStringHashCharacters(const UniChar *characters, CFIndex len); CF_EXPORT CFHashCode CFStringHashNSString(CFStringRef str); +/* Currently for CFString usage, for handling out-of-memory conditions. + The callback might not return; if it does, true indicates the error was potentially dealt with; false means no. + Typically true means OK to continue executing. +*/ +typedef Boolean (*CFBadErrorCallBack)(CFTypeRef obj, CFStringRef domain, CFStringRef msg); +CF_EXPORT CFBadErrorCallBack _CFGetOutOfMemoryErrorCallBack(void); +CF_EXPORT void _CFSetOutOfMemoryErrorCallBack(CFBadErrorCallBack callback); + -#if defined(__cplusplus) -} -#endif + +CF_EXTERN_C_END // ---- Binary plist material ---------------------------------------- @@ -363,6 +420,7 @@ enum { kCFBinaryPlistMarkerUnicode16String = 0x60, kCFBinaryPlistMarkerUID = 0x80, kCFBinaryPlistMarkerArray = 0xA0, + kCFBinaryPlistMarkerSet = 0xC0, kCFBinaryPlistMarkerDict = 0xD0 }; @@ -381,8 +439,8 @@ typedef struct { } CFBinaryPlistTrailer; extern bool __CFBinaryPlistGetTopLevelInfo(const uint8_t *databytes, uint64_t datalen, uint8_t *marker, uint64_t *offset, CFBinaryPlistTrailer *trailer); -extern bool __CFBinaryPlistGetOffsetForValueFromArray(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFIndex idx, uint64_t *offset); -extern bool __CFBinaryPlistGetOffsetForValueFromDictionary(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFTypeRef key, uint64_t *koffset, uint64_t *voffset); +extern bool __CFBinaryPlistGetOffsetForValueFromArray2(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFIndex idx, uint64_t *offset, CFMutableDictionaryRef objects); +extern bool __CFBinaryPlistGetOffsetForValueFromDictionary2(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFTypeRef key, uint64_t *koffset, uint64_t *voffset, CFMutableDictionaryRef objects); extern bool __CFBinaryPlistCreateObject(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFAllocatorRef allocator, CFOptionFlags mutabilityOption, CFMutableDictionaryRef objects, CFPropertyListRef *plist); extern CFIndex __CFBinaryPlistWriteToStream(CFPropertyListRef plist, CFTypeRef stream); @@ -398,9 +456,7 @@ extern CFTypeRef _CFPropertyListCreateFromXMLData(CFAllocatorRef allocator, CFDa #include #include -#if defined(__cplusplus) -extern "C" { -#endif +CF_EXTERN_C_BEGIN CF_EXPORT CFTypeID CFTypeGetTypeID(void); @@ -433,33 +489,45 @@ CF_EXPORT CFSearchPathEnumerationState __CFGetNextSearchPathEnumeration(CFSearch /* For use by NSNumber and CFNumber. Hashing algorithm for CFNumber: M = Max CFHashCode (assumed to be unsigned) - For positive integral values: N mod M - For negative integral values: (-N) mod M + For positive integral values: (N * HASHFACTOR) mod M + For negative integral values: ((-N) * HASHFACTOR) mod M For floating point numbers that are not integral: hash(integral part) + hash(float part * M) + HASHFACTOR is 2654435761, from Knuth's multiplicative method */ -CF_INLINE CFHashCode _CFHashInt(int i) { - return (i > 0) ? (CFHashCode)(i) : (CFHashCode)(-i); +#define HASHFACTOR 2654435761U + +CF_INLINE CFHashCode _CFHashInt(long i) { + return ((i > 0) ? (CFHashCode)(i) : (CFHashCode)(-i)) * HASHFACTOR; } CF_INLINE CFHashCode _CFHashDouble(double d) { double dInt; if (d < 0) d = -d; dInt = rint(d); - return (CFHashCode)(fmod(dInt, (double)0xFFFFFFFF) + ((d - dInt) * 0xFFFFFFFF)); + return (CFHashCode)((HASHFACTOR * (CFHashCode)fmod(dInt, (double)ULONG_MAX)) + ((d - dInt) * ULONG_MAX)); } + +/* These four functions are used by NSError in formatting error descriptions. They take NS or CFError as arguments and return a retained CFString or NULL. +*/ +CF_EXPORT CFStringRef _CFErrorCreateLocalizedDescription(CFErrorRef err); +CF_EXPORT CFStringRef _CFErrorCreateLocalizedFailureReason(CFErrorRef err); +CF_EXPORT CFStringRef _CFErrorCreateLocalizedRecoverySuggestion(CFErrorRef err); +CF_EXPORT CFStringRef _CFErrorCreateDebugDescription(CFErrorRef err); + CF_EXPORT CFURLRef _CFURLAlloc(CFAllocatorRef allocator); CF_EXPORT void _CFURLInitWithString(CFURLRef url, CFStringRef string, CFURLRef baseURL); CF_EXPORT void _CFURLInitFSPath(CFURLRef url, CFStringRef path); CF_EXPORT Boolean _CFStringIsLegalURLString(CFStringRef string); CF_EXPORT void *__CFURLReservedPtr(CFURLRef url); CF_EXPORT void __CFURLSetReservedPtr(CFURLRef url, void *ptr); +CF_EXPORT CFStringEncoding _CFURLGetEncoding(CFURLRef url); -typedef void (*CFRunLoopPerformCallBack)(void *info); -CF_EXPORT void _CFRunLoopPerformEnqueue(CFRunLoopRef rl, CFStringRef mode, CFRunLoopPerformCallBack callout, void *info); CF_EXPORT Boolean _CFRunLoopFinished(CFRunLoopRef rl, CFStringRef mode); -#if defined(__MACH__) +CF_EXPORT CFIndex _CFStreamInstanceSize(void); + +#if (DEPLOYMENT_TARGET_MACOSX || 0) #if !defined(__CFReadTSR) #include #define __CFReadTSR() mach_absolute_time() @@ -470,40 +538,18 @@ CF_INLINE UInt64 __CFReadTSR(void) { QueryPerformanceCounter(&freq); return freq.QuadPart; } -#else -CF_INLINE UInt64 __CFReadTSR(void) { - union { - UInt64 time64; - UInt32 word[2]; - } now; -#if defined(__i386__) - /* Read from Pentium and Pentium Pro 64-bit timestamp counter. */ - /* The counter is set to 0 at processor reset and increments on */ - /* every clock cycle. */ - __asm__ volatile("rdtsc" : : : "eax", "edx"); - __asm__ volatile("movl %%eax,%0" : "=m" (now.word[0]) : : "eax"); - __asm__ volatile("movl %%edx,%0" : "=m" (now.word[1]) : : "edx"); -#elif defined(__ppc__) || defined(__ppc64__) - /* Read from PowerPC 64-bit time base register. The increment */ - /* rate of the time base is implementation-dependent, but is */ - /* 1/4th the bus clock cycle on 603/604/750 processors. */ - UInt32 t3; - do { - __asm__ volatile("mftbu %0" : "=r" (now.word[0])); - __asm__ volatile("mftb %0" : "=r" (now.word[1])); - __asm__ volatile("mftbu %0" : "=r" (t3)); - } while (now.word[0] != t3); -#else -#error Do not know how to read a time stamp register on this architecture - now.time64 = (uint64_t)0; -#endif - return now.time64; -} #endif -#if defined(__cplusplus) -} -#endif +#define CF_HAS_NSOBJECT 1 +#define CF_HAS_NSARRAY 1 +#define CF_HAS_NSMUTABLEARRAY 1 +#define CF_HAS_NSDICTIONARY 1 +#define CF_HAS_NSMUTABLEDICTIONARY 1 +#define CF_HAS_NSSET 1 +#define CF_HAS_NSMUTABLESET 1 +#define CF_HAS_NSBATCH2 1 + +CF_EXTERN_C_END #endif /* ! __COREFOUNDATION_FORFOUNDATIONONLY__ */ diff --git a/Info.plist b/Info.plist new file mode 100644 index 0000000..7400609 --- /dev/null +++ b/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + en_US + CFBundleExecutable + CoreFoundation + CFBundleIdentifier + com.apple.CoreFoundation + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + CoreFoundation + CFBundlePackageType + FMWK + CFBundleShortVersionString + 6.5 + CFBundleSignature + ???? + CFBundleVersion + 476 + CarbonLazyValues + + CodeFragmentManager + + CoreFoundation + CFMPriv_CoreFoundation + + + + diff --git a/Locale.subproj/CFLocale.h b/Locale.subproj/CFLocale.h deleted file mode 100644 index 6f175c3..0000000 --- a/Locale.subproj/CFLocale.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFLocale.h - Copyright (c) 2002-2005, Apple, Inc. All rights reserved. -*/ - -#if !defined(__COREFOUNDATION_CFLOCALE__) -#define __COREFOUNDATION_CFLOCALE__ 1 - -#include -#include -#include - -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3 - -#if defined(__cplusplus) -extern "C" { -#endif - -typedef const struct __CFLocale *CFLocaleRef; - - - -#if defined(__cplusplus) -} -#endif - -#endif - -#endif /* ! __COREFOUNDATION_CFLOCALE__ */ - diff --git a/Makefile b/Makefile index a2c1e5e..632a4d1 100644 --- a/Makefile +++ b/Makefile @@ -1,150 +1,2 @@ -# -# Define sets of files to build, other info specific to this project. -# - -NAME = CoreFoundation - -SUBPROJECTS = AppServices Base Collections Locale NumberDate Parsing PlugIn Preferences \ - RunLoop Stream String StringEncodings URL - -AppServices_PUBHEADERS = CFUserNotification.h -AppServices_SOURCES = CFUserNotification.c -Base_PROJHEADERS = CFInternal.h ForFoundationOnly.h auto_stubs.h CFRuntime.h CFUtilities.h -Base_PRIVHEADERS = CFPriv.h CFRuntime.h CFUtilities.h CFUtilitiesPriv.h -Base_PUBHEADERS = CFBase.h CFByteOrder.h CoreFoundation.h CFUUID.h -Base_SOURCES = CFBase.c CFUtilities.c CFSortFunctions.c CFSystemDirectories.c \ - CFRuntime.c CFFileUtilities.c CFPlatform.c CFUUID.c uuid.c -Collections_PRIVHEADERS = CFStorage.h -Collections_PUBHEADERS = CFArray.h CFBag.h CFBinaryHeap.h CFBitVector.h \ - CFData.h CFDictionary.h CFSet.h CFStorage.h CFTree.h -Collections_SOURCES = CFArray.c CFBag.c CFBinaryHeap.c CFBitVector.c \ - CFData.c CFDictionary.c CFSet.c CFStorage.c CFTree.c -Locale_PUBHEADERS = CFLocale.h -NumberDate_PUBHEADERS = CFDate.h CFNumber.h CFTimeZone.h -NumberDate_SOURCES = CFDate.c CFNumber.c CFTimeZone.c -Parsing_PROJHEADERS = CFXMLInputStream.h -Parsing_PUBHEADERS = CFPropertyList.h CFXMLParser.h CFXMLNode.h -Parsing_SOURCES = CFBinaryPList.c CFPropertyList.c CFXMLParser.c \ - CFXMLInputStream.c CFXMLNode.c CFXMLTree.c -PlugIn_PROJHEADERS = CFBundle_BinaryTypes.h CFBundle_Internal.h CFPlugIn_Factory.h -PlugIn_PRIVHEADERS = CFBundlePriv.h -PlugIn_PUBHEADERS = CFBundle.h CFPlugIn.h CFPlugInCOM.h -PlugIn_SOURCES = CFBundle.c CFBundle_Resources.c CFPlugIn.c CFPlugIn_Factory.c \ - CFPlugIn_Instance.c CFPlugIn_PlugIn.c -Preferences_PUBHEADERS = CFPreferences.h -Preferences_SOURCES = CFApplicationPreferences.c CFPreferences.c CFXMLPreferencesDomain.c -RunLoop_PUBHEADERS = CFMachPort.h CFMessagePort.h CFRunLoop.h CFSocket.h -RunLoop_PRIVHEADERS = CFRunLoopPriv.h -RunLoop_SOURCES = CFMachPort.c CFMessagePort.c CFRunLoop.c CFSocket.c -ifeq "$(PLATFORM)" "CYGWIN" -RunLoop_PUBHEADERS += CFWindowsMessageQueue.h -RunLoop_SOURCES += CFWindowsMessageQueue.c -endif -Stream_PRIVHEADERS = CFStreamPriv.h CFStreamAbstract.h -Stream_PUBHEADERS = CFStream.h -Stream_SOURCES = CFStream.c CFConcreteStreams.c CFSocketStream.c -String_PRIVHEADERS = CFCharacterSetPriv.h CFStringDefaultEncoding.h -String_PUBHEADERS = CFCharacterSet.h CFString.h CFStringEncodingExt.h -String_SOURCES = CFCharacterSet.c CFString.c CFStringEncodings.c \ - CFStringScanner.c CFStringUtilities.c -StringEncodings_PROJHEADERS = CFUniCharPriv.h CFStringEncodingConverterPriv.h -StringEncodings_PRIVHEADERS = CFUniChar.h CFStringEncodingConverter.h \ - CFUnicodeDecomposition.h CFUnicodePrecomposition.h \ - CFStringEncodingConverterExt.h -StringEncodings_SOURCES = CFStringEncodingConverter.c CFBuiltinConverters.c \ - CFUnicodeDecomposition.c CFUnicodePrecomposition.c CFUniChar.c -URL_PUBHEADERS = CFURL.h CFURLAccess.h -URL_SOURCES = CFURL.c CFURLAccess.c - -OTHER_SOURCES = version.c Makefile APPLE_LICENSE PropertyList.dtd - -# These are the actual vars that are used by framework.make -PUBLIC_HFILES = $(foreach S, $(SUBPROJECTS), $(foreach F, $($(S)_PUBHEADERS), $(SRCROOT)/$(S).subproj/$(F))) -PRIVATE_HFILES = $(foreach S, $(SUBPROJECTS), $(foreach F, $($(S)_PRIVHEADERS), $(SRCROOT)/$(S).subproj/$(F))) -PROJECT_HFILES = $(foreach S, $(SUBPROJECTS), $(foreach F, $($(S)_PROJHEADERS), $(SRCROOT)/$(S).subproj/$(F))) -CFILES = $(foreach S, $(SUBPROJECTS), $(foreach F, $($(S)_SOURCES), $(SRCROOT)/$(S).subproj/$(F))) - - --include nonOpenSource.make - -include framework.make - - -# -# Misc additional options -# - -CURRENT_PROJECT_VERSION = 368.27 - -# common items all build styles should be defining -CFLAGS += -DCF_BUILDING_CF=1 -CPPFLAGS += -DCF_BUILDING_CF=1 - -# base addr is set to come before CFNetwork - use the rebase MS command to see the sizes -# more info at http://msdn.microsoft.com/library/en-us/tools/tools/rebase.asp -ifeq "$(PLATFORM)" "CYGWIN" -C_WARNING_FLAGS += -Wno-endif-labels -CPP_WARNING_FLAGS += -Wno-endif-labels -LIBS += -lole32 -lws2_32 -LFLAGS += -Wl,--image-base=0x66000000 -endif - -ifeq "$(PLATFORM)" "Darwin" -CFLAGS += -F/System/Library/Frameworks/CoreServices.framework/Frameworks -CPPFLAGS += -F/System/Library/Frameworks/CoreServices.framework/Frameworks -LIBS += -licucore -lobjc -LFLAGS += -compatibility_version 150 -current_version $(CURRENT_PROJECT_VERSION) -Wl,-init,___CFInitialize -endif - -ifeq "$(PLATFORM)" "FreeBSD" -LFLAGS += -shared -endif - -ifeq "$(PLATFORM)" "Linux" -LIBS += -lpthread -endif - -ifeq "$(LIBRARY_STYLE)" "Library" -CHARACTERSETS_INSTALLDIR = /usr/local/share/$(NAME) -else -CHARACTERSETS_INSTALLDIR = /System/Library/CoreServices -endif - -# -# Additional steps we add to predefined targets -# - -install_after:: - $(SILENT) $(MKDIRS) $(DSTROOT)/$(CHARACTERSETS_INSTALLDIR) - -$(SILENT) $(CHMOD) 755 $(DSTROOT)/$(CHARACTERSETS_INSTALLDIR) - $(SILENT) $(MKDIRS) $(DSTROOT)/$(CHARACTERSETS_INSTALLDIR)/CharacterSets - -$(SILENT) $(CHMOD) -R +w $(DSTROOT)/$(CHARACTERSETS_INSTALLDIR)/CharacterSets - $(SILENT) $(REMOVE_RECUR) $(DSTROOT)/$(CHARACTERSETS_INSTALLDIR)/CharacterSets - $(SILENT) $(COPY_RECUR) $(SRCROOT)/CharacterSets $(DSTROOT)/$(CHARACTERSETS_INSTALLDIR) - $(SILENT) $(REMOVE_RECUR) $(DSTROOT)/$(CHARACTERSETS_INSTALLDIR)/CharacterSets/CVS - $(SILENT) $(CHOWN) -R root:wheel $(DSTROOT)/$(CHARACTERSETS_INSTALLDIR)/CharacterSets - $(SILENT) $(CHMOD) 444 $(DSTROOT)/$(CHARACTERSETS_INSTALLDIR)/CharacterSets/* #*/ - $(SILENT) $(CHMOD) 755 $(DSTROOT)/$(CHARACTERSETS_INSTALLDIR)/CharacterSets - -prebuild_after:: -ifeq "$(LIBRARY_STYLE)" "Library" - $(SILENT) $(COPY_RECUR) CharacterSets $(RESOURCE_DIR) - $(SILENT) $(REMOVE_RECUR) $(RESOURCE_DIR)/CharacterSets/CVS -ifneq "$(PLATFORM)" "Darwin" -# All other platforms need the compatibility headers - $(SILENT) $(COPY) OSXCompatibilityHeaders/*.h $(PUBLIC_HEADER_DIR)/.. #*/ - $(SILENT) $(MKDIRS) $(PUBLIC_HEADER_DIR)/../GNUCompatibility - $(SILENT) $(COPY) OSXCompatibilityHeaders/GNUCompatibility/*.h $(PUBLIC_HEADER_DIR)/../GNUCompatibility #*/ -endif -endif - -ifeq "$(LIBRARY_STYLE)" "Library" -clean_after:: - $(REMOVE_RECUR) -f $(RESOURCE_DIR)/CharacterSets -endif - -compile-after:: - $(SILENT) $(CC) $(CFLAGS) $(SRCROOT)/version.c -DVERSION=$(CURRENT_PROJECT_VERSION) -DUSER=$(USER) -c -o $(OFILE_DIR)/version.o - -test: - cd Tests; $(MAKE) test SYMROOT=$(SYMROOT) USE_OBJC=NO +install: + DSTBASE="$(DSTROOT)/System/Library/Frameworks" ./BuildCFLite diff --git a/NumberDate.subproj/CFNumber.c b/NumberDate.subproj/CFNumber.c deleted file mode 100644 index e63376d..0000000 --- a/NumberDate.subproj/CFNumber.c +++ /dev/null @@ -1,620 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFNumber.c - Copyright 1999-2002, Apple, Inc. All rights reserved. - Responsibility: Ali Ozer -*/ - -#include -#include "CFInternal.h" -#include "CFUtilitiesPriv.h" -#include -#include -#if defined(__WIN32__) && !defined(__MINGW32__) && !defined(__CYGWIN__) -#define isnan _isnan -#define isinf !_finite -#endif - -/* Various assertions -*/ -#define __CFAssertIsBoolean(cf) __CFGenericValidateType(cf, __kCFBooleanTypeID) -#define __CFAssertIsNumber(cf) __CFGenericValidateType(cf, __kCFNumberTypeID) -#define __CFAssertIsValidNumberType(type) CFAssert2((type > 0 && type <= kCFNumberMaxType && __CFNumberCanonicalType[type]), __kCFLogAssertion, "%s(): bad CFNumber type %d", __PRETTY_FUNCTION__, type); -#define __CFInvalidNumberStorageType(type) CFAssert2(true, __kCFLogAssertion, "%s(): bad CFNumber storage type %d", __PRETTY_FUNCTION__, type); - -/* The IEEE bit patterns... Also have: -0x7f800000 float +Inf -0x7fc00000 float NaN -0xff800000 float -Inf -*/ -#define BITSFORDOUBLENAN ((uint64_t)0x7ff8000000000000ULL) -#define BITSFORDOUBLEPOSINF ((uint64_t)0x7ff0000000000000ULL) -#define BITSFORDOUBLENEGINF ((uint64_t)0xfff0000000000000ULL) - -struct __CFBoolean { - CFRuntimeBase _base; -}; - -static struct __CFBoolean __kCFBooleanTrue = { - INIT_CFRUNTIME_BASE(NULL, 0, 0x0080) -}; -const CFBooleanRef kCFBooleanTrue = &__kCFBooleanTrue; - -static struct __CFBoolean __kCFBooleanFalse = { - INIT_CFRUNTIME_BASE(NULL, 0, 0x0080) -}; -const CFBooleanRef kCFBooleanFalse = &__kCFBooleanFalse; - -static CFStringRef __CFBooleanCopyDescription(CFTypeRef cf) { - CFBooleanRef boolean = (CFBooleanRef)cf; - return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("{value = %s}"), cf, CFGetAllocator(cf), (boolean == kCFBooleanTrue) ? "true" : "false"); -} - -static CFStringRef __CFBooleanCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { - CFBooleanRef boolean = (CFBooleanRef)cf; - return CFRetain((boolean == kCFBooleanTrue) ? CFSTR("true") : CFSTR("false")); -} - -static void __CFBooleanDeallocate(CFTypeRef cf) { - CFAssert(false, __kCFLogAssertion, "Deallocated CFBoolean!"); -} - -static CFTypeID __kCFBooleanTypeID = _kCFRuntimeNotATypeID; - -static const CFRuntimeClass __CFBooleanClass = { - 0, - "CFBoolean", - NULL, // init - NULL, // copy - __CFBooleanDeallocate, - NULL, - NULL, - __CFBooleanCopyFormattingDescription, - __CFBooleanCopyDescription -}; - -__private_extern__ void __CFBooleanInitialize(void) { - __kCFBooleanTypeID = _CFRuntimeRegisterClass(&__CFBooleanClass); - _CFRuntimeSetInstanceTypeID(&__kCFBooleanTrue, __kCFBooleanTypeID); - __kCFBooleanTrue._base._isa = __CFISAForTypeID(__kCFBooleanTypeID); - _CFRuntimeSetInstanceTypeID(&__kCFBooleanFalse, __kCFBooleanTypeID); - __kCFBooleanFalse._base._isa = __CFISAForTypeID(__kCFBooleanTypeID); -} - -CFTypeID CFBooleanGetTypeID(void) { - return __kCFBooleanTypeID; -} - -Boolean CFBooleanGetValue(CFBooleanRef boolean) { - CF_OBJC_FUNCDISPATCH0(__kCFBooleanTypeID, Boolean, boolean, "boolValue"); - return (boolean == kCFBooleanTrue) ? true : false; -} - - -/*** CFNumber ***/ - -typedef union { - SInt32 valSInt32; - int64_t valSInt64; - Float32 valFloat32; - Float64 valFloat64; -} __CFNumberValue; - -struct __CFNumber { /* Only as many bytes as necessary are allocated */ - CFRuntimeBase _base; - __CFNumberValue value; -}; - -static struct __CFNumber __kCFNumberNaN = { - INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), {0} -}; -const CFNumberRef kCFNumberNaN = &__kCFNumberNaN; - -static struct __CFNumber __kCFNumberNegativeInfinity = { - INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), {0} -}; -const CFNumberRef kCFNumberNegativeInfinity = &__kCFNumberNegativeInfinity; - -static struct __CFNumber __kCFNumberPositiveInfinity = { - INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), {0} -}; -const CFNumberRef kCFNumberPositiveInfinity = &__kCFNumberPositiveInfinity; - - -/* Seven bits in base: - Bits 4..0: CFNumber type - Bit 6: is unsigned number -*/ - - -/* ??? These tables should be changed on different architectures, depending on the actual sizes of basic C types such as int, long, float; also size of CFIndex. We can probably compute these tables at runtime. -*/ - -/* Canonical types are the types that the implementation knows how to deal with. There should be one for each type that is distinct; so this table basically is a type equivalence table. All functions that take a type from the outside world should call __CFNumberGetCanonicalTypeForType() before doing anything with it. -*/ -static const unsigned char __CFNumberCanonicalType[kCFNumberMaxType + 1] = { - 0, kCFNumberSInt8Type, kCFNumberSInt16Type, kCFNumberSInt32Type, kCFNumberSInt64Type, kCFNumberFloat32Type, kCFNumberFloat64Type, - kCFNumberSInt8Type, kCFNumberSInt16Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt64Type, kCFNumberFloat32Type, kCFNumberFloat64Type, - kCFNumberSInt32Type -}; - -/* This table determines what storage format is used for any given type. - !!! These are the only types that can occur in the types field of a CFNumber. - !!! If the number or kind of types returned by this array changes, also need to fix NSNumber and NSCFNumber. -*/ -static const unsigned char __CFNumberStorageType[kCFNumberMaxType + 1] = { - 0, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt64Type, kCFNumberFloat32Type, kCFNumberFloat64Type, - kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt64Type, kCFNumberFloat32Type, kCFNumberFloat64Type, - kCFNumberSInt32Type -}; - -// Returns the type that is used to store the specified type -CF_INLINE CFNumberType __CFNumberGetStorageTypeForType(CFNumberType type) { - return __CFNumberStorageType[type]; -} - -// Returns the canonical type used to represent the specified type -CF_INLINE CFNumberType __CFNumberGetCanonicalTypeForType(CFNumberType type) { - return __CFNumberCanonicalType[type]; -} - -// Extracts and returns the type out of the CFNumber -CF_INLINE CFNumberType __CFNumberGetType(CFNumberRef num) { - return __CFBitfieldGetValue(num->_base._info, 4, 0); -} - -// Returns true if the argument type is float or double -CF_INLINE Boolean __CFNumberTypeIsFloat(CFNumberType type) { - return (type == kCFNumberFloat64Type) || (type == kCFNumberFloat32Type) || (type == kCFNumberDoubleType) || (type == kCFNumberFloatType); -} - -// Returns the number of bytes necessary to store the specified type -// Needs to handle all canonical types -CF_INLINE CFIndex __CFNumberSizeOfType(CFNumberType type) { - switch (type) { - case kCFNumberSInt8Type: return sizeof(int8_t); - case kCFNumberSInt16Type: return sizeof(int16_t); - case kCFNumberSInt32Type: return sizeof(SInt32); - case kCFNumberSInt64Type: return sizeof(int64_t); - case kCFNumberFloat32Type: return sizeof(Float32); - case kCFNumberFloat64Type: return sizeof(Float64); - default: return 0; - } -} - -// Copies an external value of a given type into the appropriate slot in the union (does no type conversion) -// Needs to handle all canonical types -#define SET_VALUE(valueUnion, type, valuePtr) \ - switch (type) { \ - case kCFNumberSInt8Type: (valueUnion)->valSInt32 = *(int8_t *)(valuePtr); break; \ - case kCFNumberSInt16Type: (valueUnion)->valSInt32 = *(int16_t *)(valuePtr); break; \ - case kCFNumberSInt32Type: (valueUnion)->valSInt32 = *(SInt32 *)(valuePtr); break; \ - case kCFNumberSInt64Type: (valueUnion)->valSInt64 = *(int64_t *)(valuePtr); break; \ - case kCFNumberFloat32Type: (valueUnion)->valFloat32 = *(Float32 *)(valuePtr); break; \ - case kCFNumberFloat64Type: (valueUnion)->valFloat64 = *(Float64 *)(valuePtr); break; \ - default: break; \ - } - -// Casts the specified value into the specified type and copies it into the provided memory -// Needs to handle all canonical types -#define GET_VALUE(value, type, resultPtr) \ - switch (type) { \ - case kCFNumberSInt8Type: *(int8_t *)(resultPtr) = (int8_t)value; break; \ - case kCFNumberSInt16Type: *(int16_t *)(resultPtr) = (int16_t)value; break; \ - case kCFNumberSInt32Type: *(SInt32 *)(resultPtr) = (SInt32)value; break; \ - case kCFNumberSInt64Type: *(int64_t *)(resultPtr) = (int64_t)value; break; \ - case kCFNumberFloat32Type: *(Float32 *)(resultPtr) = (Float32)value; break; \ - case kCFNumberFloat64Type: *(Float64 *)(resultPtr) = (Float64)value; break; \ - default: break; \ - } - -// Extracts the stored type out of the union and copies it in the desired type into the provided memory -// Needs to handle all storage types -CF_INLINE void __CFNumberGetValue(const __CFNumberValue *value, CFNumberType numberType, CFNumberType typeToGet, void *valuePtr) { - switch (numberType) { - case kCFNumberSInt32Type: GET_VALUE(value->valSInt32, typeToGet, valuePtr); break; - case kCFNumberSInt64Type: GET_VALUE(value->valSInt64, typeToGet, valuePtr); break; - case kCFNumberFloat32Type: GET_VALUE(value->valFloat32, typeToGet, valuePtr); break; - case kCFNumberFloat64Type: GET_VALUE(value->valFloat64, typeToGet, valuePtr); break; - default: break; \ - } -} - -// Sees if two value union structs have the same value (will do type conversion) -static Boolean __CFNumberEqualValue(const __CFNumberValue *value1, CFNumberType type1, const __CFNumberValue *value2, CFNumberType type2) { - if (__CFNumberTypeIsFloat(type1) || __CFNumberTypeIsFloat(type2)) { - Float64 d1, d2; - __CFNumberGetValue(value1, type1, kCFNumberFloat64Type, &d1); - __CFNumberGetValue(value2, type2, kCFNumberFloat64Type, &d2); - if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { - if (isnan(d1) && isnan(d2)) return true; // Not mathematically sound, but required - } - return d1 == d2; - } else { - int64_t i1, i2; - __CFNumberGetValue(value1, type1, kCFNumberSInt64Type, &i1); - __CFNumberGetValue(value2, type2, kCFNumberSInt64Type, &i2); - return i1 == i2; - } -} - -static Boolean __CFNumberEqual(CFTypeRef cf1, CFTypeRef cf2) { - CFNumberRef number1 = (CFNumberRef)cf1; - CFNumberRef number2 = (CFNumberRef)cf2; - return __CFNumberEqualValue(&(number1->value), __CFNumberGetType(number1), &(number2->value), __CFNumberGetType(number2)); -} - -static CFHashCode __CFNumberHash(CFTypeRef cf) { - CFNumberRef number = (CFNumberRef)cf; - switch (__CFNumberGetType(cf)) { - case kCFNumberSInt32Type: return _CFHashInt(number->value.valSInt32); - case kCFNumberSInt64Type: return _CFHashDouble((double)(number->value.valSInt64)); - case kCFNumberFloat32Type: return _CFHashDouble((double)(number->value.valFloat32)); - case kCFNumberFloat64Type: return _CFHashDouble((double)(number->value.valFloat64)); - default: - __CFInvalidNumberStorageType(__CFNumberGetType(cf)); - return 0; - } -} - -#define bufSize 100 -#define emitChar(ch) \ - {if (buf - stackBuf == bufSize) {CFStringAppendCharacters(mstr, stackBuf, bufSize); buf = stackBuf;} *buf++ = ch;} - -static void __CFNumberEmitInt64(CFMutableStringRef mstr, int64_t value, int32_t width, UniChar pad, bool explicitPlus) { - UniChar stackBuf[bufSize], *buf = stackBuf; - uint64_t uvalue, factor, tmp; - int32_t w; - bool neg; - - neg = (value < 0) ? true : false; - uvalue = (neg) ? -value : value; - if (neg || explicitPlus) width--; - width--; - factor = 1; - tmp = uvalue; - while (9 < tmp) { - width--; - factor *= 10; - tmp /= 10; - } - for (w = 0; w < width; w++) emitChar(pad); - if (neg) { - emitChar('-'); - } else if (explicitPlus) { - emitChar('+'); - } - while (0 < factor) { - UniChar ch = '0' + (uvalue / factor); - uvalue %= factor; - emitChar(ch); - factor /= 10; - } - if (buf > stackBuf) CFStringAppendCharacters(mstr, stackBuf, buf - stackBuf); -} - -static CFStringRef __CFNumberCopyDescription(CFTypeRef cf) { - CFNumberRef number = (CFNumberRef)cf; - CFMutableStringRef mstr = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); - CFStringAppendFormat(mstr, NULL, CFSTR("{value = "), cf, CFGetAllocator(cf)); - switch (__CFNumberGetType(number)) { - case kCFNumberSInt32Type: - __CFNumberEmitInt64(mstr, number->value.valSInt32, 0, ' ', true); - CFStringAppendFormat(mstr, NULL, CFSTR(", type = kCFNumberSInt32Type}")); - break; - case kCFNumberSInt64Type: - __CFNumberEmitInt64(mstr, number->value.valSInt64, 0, ' ', true); - CFStringAppendFormat(mstr, NULL, CFSTR(", type = kCFNumberSInt64Type}")); - break; - case kCFNumberFloat32Type: - // debugging formatting is intentionally more verbose and explicit about the value of the number - if (isnan(number->value.valFloat32)) { - CFStringAppend(mstr, CFSTR("nan")); - } else if (isinf(number->value.valFloat32)) { - CFStringAppend(mstr, (0.0f < number->value.valFloat32) ? CFSTR("+infinity") : CFSTR("-infinity")); - } else if (0.0f == number->value.valFloat32) { - CFStringAppend(mstr, (copysign(1.0, number->value.valFloat32) < 0.0) ? CFSTR("-0.0") : CFSTR("+0.0")); - } else { - CFStringAppendFormat(mstr, NULL, CFSTR("%+.10f"), number->value.valFloat32); - } - CFStringAppend(mstr, CFSTR(", type = kCFNumberFloat32Type}")); - break; - case kCFNumberFloat64Type: - // debugging formatting is intentionally more verbose and explicit about the value of the number - if (isnan(number->value.valFloat64)) { - CFStringAppend(mstr, CFSTR("nan")); - } else if (isinf(number->value.valFloat64)) { - CFStringAppend(mstr, (0.0 < number->value.valFloat64) ? CFSTR("+infinity") : CFSTR("-infinity")); - } else if (0.0 == number->value.valFloat64) { - CFStringAppend(mstr, (copysign(1.0, number->value.valFloat64) < 0.0) ? CFSTR("-0.0") : CFSTR("+0.0")); - } else { - CFStringAppendFormat(mstr, NULL, CFSTR("%+.20f"), number->value.valFloat64); - } - CFStringAppend(mstr, CFSTR(", type = kCFNumberFloat64Type}")); - break; - default: - __CFInvalidNumberStorageType(__CFNumberGetType(number)); - CFRelease(mstr); - return NULL; - } - return mstr; -} - -// This function separated out from __CFNumberCopyFormattingDescription() so the plist creation can use it as well. - -__private_extern__ CFStringRef __CFNumberCopyFormattingDescriptionAsFloat64(CFTypeRef cf) { - double d; - CFNumberGetValue(cf, kCFNumberFloat64Type, &d); - if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { - if (isnan(d)) { - return CFRetain(CFSTR("nan")); - } - if (isinf(d)) { - return CFRetain((0.0 < d) ? CFSTR("+infinity") : CFSTR("-infinity")); - } - if (0.0 == d) { - return 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(kCFAllocatorDefault, NULL, CFSTR("%.*g"), DBL_DIG + 2, d); - } - return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%lf"), d); -} - -static CFStringRef __CFNumberCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { - CFNumberRef number = (CFNumberRef)cf; - CFMutableStringRef mstr; - int64_t value; - switch (__CFNumberGetType(number)) { - case kCFNumberSInt32Type: - case kCFNumberSInt64Type: - value = (__CFNumberGetType(number) == kCFNumberSInt32Type) ? number->value.valSInt32 : number->value.valSInt64; - mstr = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); - __CFNumberEmitInt64(mstr, value, 0, ' ', false); - return mstr; - case kCFNumberFloat32Type: - if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { - if (isnan(number->value.valFloat32)) { - return CFRetain(CFSTR("nan")); - } - if (isinf(number->value.valFloat32)) { - return CFRetain((0.0f < number->value.valFloat32) ? CFSTR("+infinity") : CFSTR("-infinity")); - } - if (0.0f == number->value.valFloat32) { - return CFRetain(CFSTR("0.0")); - } - // if %g is used here, need to use FLT_DIG + 2 on Mac OS X, but %f needs +1 - return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%.*g"), FLT_DIG + 2, number->value.valFloat32); - } - return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%f"), number->value.valFloat32); - break; - case kCFNumberFloat64Type: - return __CFNumberCopyFormattingDescriptionAsFloat64(number); - break; - default: - __CFInvalidNumberStorageType(__CFNumberGetType(number)); - return NULL; - } -} - -static CFTypeID __kCFNumberTypeID = _kCFRuntimeNotATypeID; - -static const CFRuntimeClass __CFNumberClass = { - 0, - "CFNumber", - NULL, // init - NULL, // copy - NULL, - __CFNumberEqual, - __CFNumberHash, - __CFNumberCopyFormattingDescription, - __CFNumberCopyDescription -}; - -__private_extern__ void __CFNumberInitialize(void) { - uint64_t dnan = BITSFORDOUBLENAN; - uint64_t negInf = BITSFORDOUBLENEGINF; - uint64_t posInf = BITSFORDOUBLEPOSINF; - - __kCFNumberTypeID = _CFRuntimeRegisterClass(&__CFNumberClass); - - _CFRuntimeSetInstanceTypeID(&__kCFNumberNaN, __kCFNumberTypeID); - __kCFNumberNaN._base._isa = __CFISAForTypeID(__kCFNumberTypeID); - __CFBitfieldSetValue(__kCFNumberNaN._base._info, 4, 0, kCFNumberFloat64Type); - __kCFNumberNaN.value.valFloat64 = *(double *)&dnan; - - _CFRuntimeSetInstanceTypeID(& __kCFNumberNegativeInfinity, __kCFNumberTypeID); - __kCFNumberNegativeInfinity._base._isa = __CFISAForTypeID(__kCFNumberTypeID); - __CFBitfieldSetValue(__kCFNumberNegativeInfinity._base._info, 4, 0, kCFNumberFloat64Type); - __kCFNumberNegativeInfinity.value.valFloat64 = *(double *)&negInf; - - _CFRuntimeSetInstanceTypeID(& __kCFNumberPositiveInfinity, __kCFNumberTypeID); - __kCFNumberPositiveInfinity._base._isa = __CFISAForTypeID(__kCFNumberTypeID); - __CFBitfieldSetValue(__kCFNumberPositiveInfinity._base._info, 4, 0, kCFNumberFloat64Type); - __kCFNumberPositiveInfinity.value.valFloat64 = *(double *)&posInf; -} - -Boolean _CFNumberIsU(CFNumberRef num) { - return __CFBitfieldGetValue(__kCFNumberPositiveInfinity._base._info, 6, 6); -} - -void _CFNumberSetU(CFNumberRef num, Boolean unsign) { - __CFBitfieldSetValue(__kCFNumberPositiveInfinity._base._info, 6, 6, (unsign ? 1 : 0)); -} - -CFTypeID CFNumberGetTypeID(void) { - return __kCFNumberTypeID; -} - -#define MinCachedInt (-1) -#define MaxCachedInt (12) -#define NotToBeCached (MinCachedInt - 1) -static CFNumberRef _CFNumberCache[MaxCachedInt - MinCachedInt + 1] = {NULL}; // Storing CFNumberRefs for SInt32 range MinCachedInt..MaxCachedInt -static CFSpinLock_t _CFNumberCacheLock = 0; - -CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType type, const void *valuePtr) { - CFNumberRef num; - CFNumberType equivType, storageType; - int32_t valToBeCached = NotToBeCached; - - equivType = __CFNumberGetCanonicalTypeForType(type); - - // Take care of some special cases; in some cases we will return here without actually creating a new CFNumber - switch (equivType) { - case kCFNumberFloat32Type: { - Float32 val = *(Float32 *)(valuePtr); - if (isnan(val)) return CFRetain(kCFNumberNaN); - if (isinf(val)) return CFRetain((val < 0.0) ? kCFNumberNegativeInfinity : kCFNumberPositiveInfinity); - break; - } - case kCFNumberFloat64Type: { - Float64 val = *(Float64 *)(valuePtr); - if (isnan(val)) return CFRetain(kCFNumberNaN); - if (isinf(val)) return CFRetain((val < 0.0) ? kCFNumberNegativeInfinity : kCFNumberPositiveInfinity); - break; - } - default: { - switch (equivType) { - case kCFNumberSInt64Type: {SInt64 val = *(SInt64 *)(valuePtr); if (val >= MinCachedInt && val <= MaxCachedInt) valToBeCached = val; break;} - case kCFNumberSInt32Type: {SInt32 val = *(SInt32 *)(valuePtr); if (val >= MinCachedInt && val <= MaxCachedInt) valToBeCached = val; break;} - case kCFNumberSInt16Type: {SInt16 val = *(SInt16 *)(valuePtr); if (val >= MinCachedInt && val <= MaxCachedInt) valToBeCached = val; break;} - case kCFNumberSInt8Type: {SInt8 val = *(SInt8 *)(valuePtr); if (val >= MinCachedInt && val <= MaxCachedInt) valToBeCached = val; break;} - default:; - } - if (valToBeCached != NotToBeCached) { // Even if not yet cached, this will assure that we cache it after the number is created - __CFSpinLock(&_CFNumberCacheLock); - CFNumberRef result = _CFNumberCache[valToBeCached - MinCachedInt]; - __CFSpinUnlock(&_CFNumberCacheLock); - if (result) return CFRetain(result); - // Turns out it's a number we want do cache, but don't have cached yet; so let's normalize it so we're only caching 32-bit int - valuePtr = &valToBeCached; - type = kCFNumberSInt32Type; - equivType = __CFNumberGetCanonicalTypeForType(type); - } - break; - } - } - - storageType = __CFNumberGetStorageTypeForType(type); - - num = (CFNumberRef)_CFRuntimeCreateInstance(allocator, __kCFNumberTypeID, __CFNumberSizeOfType(storageType), NULL); - if (NULL == num) { - return NULL; - } - SET_VALUE((__CFNumberValue *)&(num->value), equivType, valuePtr); - __CFBitfieldSetValue(((struct __CFNumber *)num)->_base._info, 6, 0, storageType); - - // If this was a number worth caching, cache it - if (valToBeCached != NotToBeCached) { - int slot = valToBeCached - MinCachedInt; - __CFSpinLock(&_CFNumberCacheLock); - if (_CFNumberCache[slot] == NULL) _CFNumberCache[slot] = num; - __CFSpinUnlock(&_CFNumberCacheLock); - if (_CFNumberCache[slot] == num) CFRetain(num); // Extra retain for the cached number - } - return num; -} - -CFNumberType CFNumberGetType(CFNumberRef number) { - CF_OBJC_FUNCDISPATCH0(__kCFNumberTypeID, CFNumberType, number, "_cfNumberType"); - - __CFAssertIsNumber(number); - return __CFNumberGetType(number); -} - -CFIndex CFNumberGetByteSize(CFNumberRef number) { - __CFAssertIsNumber(number); - return __CFNumberSizeOfType(CFNumberGetType(number)); -} - -Boolean CFNumberIsFloatType(CFNumberRef number) { - __CFAssertIsNumber(number); - return __CFNumberTypeIsFloat(CFNumberGetType(number)); -} - -Boolean CFNumberGetValue(CFNumberRef number, CFNumberType type, void *valuePtr) { - uint8_t localMemory[sizeof(__CFNumberValue)]; - __CFNumberValue localValue; - CFNumberType numType; - CFNumberType storageTypeForType; - - CF_OBJC_FUNCDISPATCH2(__kCFNumberTypeID, Boolean, number, "_getValue:forType:", valuePtr, __CFNumberGetCanonicalTypeForType(type)); - - __CFAssertIsNumber(number); - __CFAssertIsValidNumberType(type); - - storageTypeForType = __CFNumberGetStorageTypeForType(type); - type = __CFNumberGetCanonicalTypeForType(type); - if (!valuePtr) valuePtr = &localMemory; - - numType = __CFNumberGetType(number); - __CFNumberGetValue((__CFNumberValue *)&(number->value), numType, type, valuePtr); - - // If the types match, then we're fine! - if (numType == storageTypeForType) return true; - - // Test to see if the returned value is intact... - SET_VALUE(&localValue, type, valuePtr); - return __CFNumberEqualValue(&localValue, storageTypeForType, &(number->value), numType); -} - -CFComparisonResult CFNumberCompare(CFNumberRef number1, CFNumberRef number2, void *context) { - CFNumberType type1, type2; - - CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID, CFComparisonResult, number1, "compare:", number2); - CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID, CFComparisonResult, number2, "_reverseCompare:", number1); - - __CFAssertIsNumber(number1); - __CFAssertIsNumber(number2); - - type1 = __CFNumberGetType(number1); - type2 = __CFNumberGetType(number2); - - if (__CFNumberTypeIsFloat(type1) || __CFNumberTypeIsFloat(type2)) { - Float64 d1, d2; - double s1, s2; - __CFNumberGetValue(&(number1->value), type1, kCFNumberFloat64Type, &d1); - __CFNumberGetValue(&(number2->value), type2, kCFNumberFloat64Type, &d2); - s1 = copysign(1.0, d1); - s2 = copysign(1.0, d2); - if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { - return (d1 > d2) ? kCFCompareGreaterThan : ((d1 < d2) ? kCFCompareLessThan : kCFCompareEqualTo); - } - if (isnan(d1) && isnan(d2)) return kCFCompareEqualTo; - if (isnan(d1)) return (s2 < 0.0) ? kCFCompareGreaterThan : kCFCompareLessThan; - if (isnan(d2)) return (s1 < 0.0) ? kCFCompareLessThan : kCFCompareGreaterThan; - // at this point, we know we don't have any NaNs - if (s1 < s2) return kCFCompareLessThan; - if (s2 < s1) return kCFCompareGreaterThan; - // at this point, we know the signs are the same; do not combine these tests - if (d1 < d2) return kCFCompareLessThan; - if (d2 < d1) return kCFCompareGreaterThan; - return kCFCompareEqualTo; - } else { - int64_t i1, i2; - __CFNumberGetValue(&(number1->value), type1, kCFNumberSInt64Type, &i1); - __CFNumberGetValue(&(number2->value), type2, kCFNumberSInt64Type, &i2); - return (i1 > i2) ? kCFCompareGreaterThan : ((i1 < i2) ? kCFCompareLessThan : kCFCompareEqualTo); - } -} - diff --git a/NumberDate.subproj/CFTimeZone.c b/NumberDate.subproj/CFTimeZone.c deleted file mode 100644 index f57c60a..0000000 --- a/NumberDate.subproj/CFTimeZone.c +++ /dev/null @@ -1,1474 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFTimeZone.c - Copyright 1998-2002, Apple, Inc. All rights reserved. - Responsibility: Christopher Kane -*/ - -#include -#include -#include "CFUtilitiesPriv.h" -#include "CFInternal.h" -#include -#include -#include -#if !defined(__WIN32__) -#include -#else -#include -#include -#include -#include -#endif -#include -#include -#include - -#if defined(__WIN32__) -#include -#endif - -// For Windows(TM) time zone information, see registry key: -// HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Time Zones - -#if defined(__WIN32__) -#define TZZONEINFO "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones" -#else -#define TZZONELINK "/etc/localtime" -#define TZZONEINFO "/usr/share/zoneinfo/" -#endif - -static CFTimeZoneRef __CFTimeZoneSystem = NULL; -static CFTimeZoneRef __CFTimeZoneDefault = NULL; -static CFDictionaryRef __CFTimeZoneAbbreviationDict = NULL; -static CFSpinLock_t __CFTimeZoneAbbreviationLock = 0; -static CFMutableDictionaryRef __CFTimeZoneCompatibilityMappingDict = NULL; -static CFMutableDictionaryRef __CFTimeZoneCompatibilityMappingDict2 = NULL; -static CFSpinLock_t __CFTimeZoneCompatibilityMappingLock = 0; -static CFArrayRef __CFKnownTimeZoneList = NULL; -static CFMutableDictionaryRef __CFTimeZoneCache = NULL; -static CFSpinLock_t __CFTimeZoneGlobalLock = 0; - -CF_INLINE void __CFTimeZoneLockGlobal(void) { - __CFSpinLock(&__CFTimeZoneGlobalLock); -} - -CF_INLINE void __CFTimeZoneUnlockGlobal(void) { - __CFSpinUnlock(&__CFTimeZoneGlobalLock); -} - -CF_INLINE void __CFTimeZoneLockAbbreviations(void) { - __CFSpinLock(&__CFTimeZoneAbbreviationLock); -} - -CF_INLINE void __CFTimeZoneUnlockAbbreviations(void) { - __CFSpinUnlock(&__CFTimeZoneAbbreviationLock); -} - -CF_INLINE void __CFTimeZoneLockCompatibilityMapping(void) { - __CFSpinLock(&__CFTimeZoneCompatibilityMappingLock); -} - -CF_INLINE void __CFTimeZoneUnlockCompatibilityMapping(void) { - __CFSpinUnlock(&__CFTimeZoneCompatibilityMappingLock); -} - -/* This function should be used for WIN32 instead of - * __CFCopyRecursiveDirectoryList function. - * It takes TimeZone names from the registry - * (Aleksey Dukhnyakov) - */ -#if defined(__WIN32__) -static CFMutableArrayRef __CFCopyWindowsTimeZoneList() { - CFMutableArrayRef result = NULL; - HKEY hkResult; - TCHAR lpName[MAX_PATH+1]; - DWORD dwIndex, retCode; - - if (RegOpenKey(HKEY_LOCAL_MACHINE,_T(TZZONEINFO),&hkResult) != - ERROR_SUCCESS ) - return NULL; - - result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - - for (dwIndex=0; (retCode = RegEnumKey(hkResult,dwIndex,lpName,MAX_PATH)) != ERROR_NO_MORE_ITEMS ; dwIndex++) { - - if (retCode != ERROR_SUCCESS) { - RegCloseKey(hkResult); - CFRelease(result); - return NULL; - } - else { -#if defined(UNICODE) - CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault, lpName, _tcslen(lpName), kCFStringEncodingUnicode, false); -#else - CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault, lpName, _tcslen(lpName), CFStringGetSystemEncoding(), false); -#endif - CFArrayAppendValue(result, string); - CFRelease(string); - } - } - - RegCloseKey(hkResult); - return result; -} -#endif - -#if !defined(__WIN32__) -static CFMutableArrayRef __CFCopyRecursiveDirectoryList(const char *topDir) { - CFMutableArrayRef result = NULL, temp; - long fd, numread, plen, basep = 0; - CFIndex idx, cnt, usedLen; - char *dirge, path[CFMaxPathSize]; - -// No d_namlen in dirent struct on Linux -#if defined(__LINUX__) - #define dentDNameLen strlen(dent->d_name) -#else - #define dentDNameLen dent->d_namlen -#endif - fd = open(topDir, O_RDONLY, 0); - if (fd < 0) { - return NULL; - } - dirge = malloc(8192); - result = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); - numread = getdirentries(fd, dirge, 8192, &basep); - while (0 < numread) { - struct dirent *dent = (struct dirent *)dirge; - for (; dent < (struct dirent *)(dirge + numread); dent = (struct dirent *)((char *)dent + dent->d_reclen)) { - if (0 == dent->d_fileno) continue; - if (1 == dentDNameLen && '.' == dent->d_name[0]) continue; - if (2 == dentDNameLen && '.' == dent->d_name[0] && '.' == dent->d_name[1]) continue; - if (dent->d_type == DT_UNKNOWN) { - struct stat statbuf; - strcpy(path, topDir); - strcat(path, "/"); - plen = strlen(path); - memmove(path + plen, dent->d_name, dentDNameLen); - path[plen + dentDNameLen] = '\0'; - if (0 <= stat(path, &statbuf) && (statbuf.st_mode & S_IFMT) == S_IFDIR) { - dent->d_type = DT_DIR; - } - } - if (DT_DIR == dent->d_type) { - strcpy(path, topDir); - strcat(path, "/"); - plen = strlen(path); - memmove(path + plen, dent->d_name, dentDNameLen); - path[plen + dentDNameLen] = '\0'; - temp = __CFCopyRecursiveDirectoryList(path); - for (idx = 0, cnt = CFArrayGetCount(temp); idx < cnt; idx++) { - CFStringRef string, item = CFArrayGetValueAtIndex(temp, idx); - memmove(path, dent->d_name, dentDNameLen); - path[dentDNameLen] = '/'; - CFStringGetBytes(item, CFRangeMake(0, CFStringGetLength(item)), kCFStringEncodingUTF8, 0, false, path + dentDNameLen + 1, CFMaxPathLength - dentDNameLen - 2, &usedLen); - string = CFStringCreateWithBytes(kCFAllocatorDefault, path, dentDNameLen + 1 + usedLen, kCFStringEncodingUTF8, false); - CFArrayAppendValue(result, string); - CFRelease(string); - } - CFRelease(temp); - } else { - CFStringRef string = CFStringCreateWithBytes(kCFAllocatorDefault, dent->d_name, dentDNameLen, kCFStringEncodingUTF8, false); - CFArrayAppendValue(result, string); - CFRelease(string); - } - } - numread = getdirentries(fd, dirge, 8192, &basep); - } - close(fd); - free(dirge); - if (-1 == numread) { - CFRelease(result); - return NULL; - } - return result; -} -#endif - -typedef struct _CFTZPeriod { - int32_t startSec; - CFStringRef abbrev; - uint32_t info; -} CFTZPeriod; - -struct __CFTimeZone { - CFRuntimeBase _base; - CFStringRef _name; /* immutable */ - CFDataRef _data; /* immutable */ - CFTZPeriod *_periods; /* immutable */ - int32_t _periodCnt; /* immutable */ -}; - -/* startSec is the whole integer seconds from a CFAbsoluteTime, giving dates - * between 1933 and 2069; info outside these years is discarded on read-in */ -/* Bits 31-18 of the info are unused */ -/* Bit 17 of the info is used for the is-DST state */ -/* Bit 16 of the info is used for the sign of the offset (1 == negative) */ -/* Bits 15-0 of the info are used for abs(offset) in seconds from GMT */ - -CF_INLINE void __CFTZPeriodInit(CFTZPeriod *period, int32_t startTime, CFStringRef abbrev, int32_t offset, Boolean isDST) { - period->startSec = startTime; - period->abbrev = abbrev ? CFRetain(abbrev) : NULL; - __CFBitfieldSetValue(period->info, 15, 0, abs(offset)); - __CFBitfieldSetValue(period->info, 16, 16, (offset < 0 ? 1 : 0)); - __CFBitfieldSetValue(period->info, 17, 17, (isDST ? 1 : 0)); -} - -CF_INLINE int32_t __CFTZPeriodStartSeconds(const CFTZPeriod *period) { - return period->startSec; -} - -CF_INLINE CFStringRef __CFTZPeriodAbbreviation(const CFTZPeriod *period) { - return period->abbrev; -} - -CF_INLINE int32_t __CFTZPeriodGMTOffset(const CFTZPeriod *period) { - int32_t v = __CFBitfieldGetValue(period->info, 15, 0); - if (__CFBitfieldGetValue(period->info, 16, 16)) v = -v; - return v; -} - -CF_INLINE Boolean __CFTZPeriodIsDST(const CFTZPeriod *period) { - return (Boolean)__CFBitfieldGetValue(period->info, 17, 17); -} - -static CFComparisonResult __CFCompareTZPeriods(const void *val1, const void *val2, void *context) { - CFTZPeriod *tzp1 = (CFTZPeriod *)val1; - CFTZPeriod *tzp2 = (CFTZPeriod *)val2; - // we treat equal as less than, as the code which uses the - // result of the bsearch doesn't expect exact matches - // (they're pretty rare, so no point in over-coding for them) - if (__CFTZPeriodStartSeconds(tzp1) <= __CFTZPeriodStartSeconds(tzp2)) return kCFCompareLessThan; - return kCFCompareGreaterThan; -} - -static CFIndex __CFBSearchTZPeriods(CFTimeZoneRef tz, CFAbsoluteTime at) { - CFTZPeriod elem; - CFIndex idx; - __CFTZPeriodInit(&elem, (int32_t)(float)floor(at), NULL, 0, false); - idx = CFBSearch(&elem, sizeof(CFTZPeriod), tz->_periods, tz->_periodCnt, __CFCompareTZPeriods, NULL); - if (tz->_periodCnt <= idx) { - idx = tz->_periodCnt; - } else if (0 == idx) { - // We want anything before the time zone records start to be not in DST; - // we assume that if period[0] is DST, then period[1] is not; could do a search instead. - idx = __CFTZPeriodIsDST(&(tz->_periods[0])) ? 2 : 1; - } - return idx - 1; -} - -/* -** Each time zone data file begins with. . . -*/ - -struct tzhead { - char tzh_reserved[20]; /* 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 */ -}; - -/* -** . . .followed by. . . -** -** tzh_timecnt (char [4])s coded transition times a la time(2) -** tzh_timecnt (UInt8)s types of local time starting at above -** tzh_typecnt repetitions of -** one (char [4]) coded GMT offset in seconds -** one (UInt8) used to set tm_isdst -** one (UInt8) that's an abbreviation list index -** tzh_charcnt (char)s '\0'-terminated zone abbreviations -** tzh_leapcnt repetitions of -** one (char [4]) coded leap second transition times -** one (char [4]) total correction after above -** tzh_ttisstdcnt (char)s indexed by type; if 1, transition -** time is standard time, if 0, -** transition time is wall clock time -** if absent, transition times are -** assumed to be wall clock time -** tzh_ttisgmtcnt (char)s indexed by type; if 1, transition -** time is GMT, if 0, -** transition time is local time -** if absent, transition times are -** assumed to be local time -*/ - -CF_INLINE int32_t __CFDetzcode(const unsigned char *bufp) { - int32_t result = (bufp[0] & 0x80) ? ~0L : 0L; - result = (result << 8) | (bufp[0] & 0xff); - result = (result << 8) | (bufp[1] & 0xff); - result = (result << 8) | (bufp[2] & 0xff); - result = (result << 8) | (bufp[3] & 0xff); - return result; -} - -CF_INLINE void __CFEntzcode(int32_t value, unsigned char *bufp) { - bufp[0] = (value >> 24) & 0xff; - bufp[1] = (value >> 16) & 0xff; - bufp[2] = (value >> 8) & 0xff; - bufp[3] = (value >> 0) & 0xff; -} - -static Boolean __CFParseTimeZoneData(CFAllocatorRef allocator, CFDataRef data, CFTZPeriod **tzpp, CFIndex *cntp) { -#if !defined(__WIN32__) - int32_t len, timecnt, typecnt, charcnt, idx, cnt; - const char *p, *timep, *typep, *ttisp, *charp; - CFStringRef *abbrs; - Boolean result = true; - - p = CFDataGetBytePtr(data); - len = CFDataGetLength(data); - if (len < (int32_t)sizeof(struct tzhead)) { - return false; - } - - if (!(p[0] == 'T' && p[1] == 'Z' && p[2] == 'i' && p[3] == 'f')) return false; /* Don't parse without TZif at head of file */ - - p += 20 + 4 + 4 + 4; /* skip reserved, ttisgmtcnt, ttisstdcnt, leapcnt */ - timecnt = __CFDetzcode(p); - p += 4; - typecnt = __CFDetzcode(p); - p += 4; - charcnt = __CFDetzcode(p); - p += 4; - if (typecnt <= 0 || timecnt < 0 || charcnt < 0) { - return false; - } - if (len - (int32_t)sizeof(struct tzhead) < (4 + 1) * timecnt + (4 + 1 + 1) * typecnt + charcnt) { - return false; - } - timep = p; - typep = timep + 4 * timecnt; - ttisp = typep + timecnt; - charp = ttisp + (4 + 1 + 1) * typecnt; - cnt = (0 < timecnt) ? timecnt : 1; - *tzpp = CFAllocatorAllocate(allocator, cnt * sizeof(CFTZPeriod), 0); - if (__CFOASafe) __CFSetLastAllocationEventName(*tzpp, "CFTimeZone (store)"); - memset(*tzpp, 0, cnt * sizeof(CFTZPeriod)); - abbrs = CFAllocatorAllocate(allocator, (charcnt + 1) * sizeof(CFStringRef), 0); - if (__CFOASafe) __CFSetLastAllocationEventName(abbrs, "CFTimeZone (temp)"); - for (idx = 0; idx < charcnt + 1; idx++) { - abbrs[idx] = NULL; - } - for (idx = 0; idx < cnt; idx++) { - CFAbsoluteTime at; - int32_t itime, offset; - uint8_t type, dst, abbridx; - - at = (CFAbsoluteTime)(__CFDetzcode(timep) + 0.0) - kCFAbsoluteTimeIntervalSince1970; - if (0 == timecnt) itime = INT_MIN; - else if (at < (CFAbsoluteTime)INT_MIN) itime = INT_MIN; - else if ((CFAbsoluteTime)INT_MAX < at) itime = INT_MAX; - else itime = (int32_t)at; - timep += 4; /* harmless if 0 == timecnt */ - type = (0 < timecnt) ? (uint8_t)*typep++ : 0; - if (typecnt <= type) { - result = false; - break; - } - offset = __CFDetzcode(ttisp + 6 * type); - dst = (uint8_t)*(ttisp + 6 * type + 4); - if (0 != dst && 1 != dst) { - result = false; - break; - } - abbridx = (uint8_t)*(ttisp + 6 * type + 5); - if (charcnt < abbridx) { - result = false; - break; - } - if (NULL == abbrs[abbridx]) { - abbrs[abbridx] = CFStringCreateWithCString(allocator, &charp[abbridx], kCFStringEncodingASCII); - } - __CFTZPeriodInit(*tzpp + idx, itime, abbrs[abbridx], offset, (dst ? true : false)); - } - for (idx = 0; idx < charcnt + 1; idx++) { - if (NULL != abbrs[idx]) { - CFRelease(abbrs[idx]); - } - } - CFAllocatorDeallocate(allocator, abbrs); - if (result) { - // dump all but the last INT_MIN and the first INT_MAX - for (idx = 0; idx < cnt; idx++) { - if (((*tzpp + idx)->startSec == INT_MIN) && (idx + 1 < cnt) && (((*tzpp + idx + 1)->startSec == INT_MIN))) { - if (NULL != (*tzpp + idx)->abbrev) CFRelease((*tzpp + idx)->abbrev); - cnt--; - memmove((*tzpp + idx), (*tzpp + idx + 1), sizeof(CFTZPeriod) * (cnt - idx)); - idx--; - } - } - // Don't combine these loops! Watch the idx decrementing... - for (idx = 0; idx < cnt; idx++) { - if (((*tzpp + idx)->startSec == INT_MAX) && (0 < idx) && (((*tzpp + idx - 1)->startSec == INT_MAX))) { - if (NULL != (*tzpp + idx)->abbrev) CFRelease((*tzpp + idx)->abbrev); - cnt--; - memmove((*tzpp + idx), (*tzpp + idx + 1), sizeof(CFTZPeriod) * (cnt - idx)); - idx--; - } - } - CFQSortArray(*tzpp, cnt, sizeof(CFTZPeriod), __CFCompareTZPeriods, NULL); - *cntp = cnt; - } else { - CFAllocatorDeallocate(allocator, *tzpp); - *tzpp = NULL; - } - return result; -#else -/* We use Win32 function to find TimeZone - * (Aleksey Dukhnyakov) - */ - *tzpp = CFAllocatorAllocate(allocator, sizeof(CFTZPeriod), 0); - __CFTZPeriodInit(*tzpp, 0, NULL, 0, false); - *cntp = 1; - return TRUE; -#endif -} - -static Boolean __CFTimeZoneEqual(CFTypeRef cf1, CFTypeRef cf2) { - CFTimeZoneRef tz1 = (CFTimeZoneRef)cf1; - CFTimeZoneRef tz2 = (CFTimeZoneRef)cf2; - if (!CFEqual(CFTimeZoneGetName(tz1), CFTimeZoneGetName(tz2))) return false; - if (!CFEqual(CFTimeZoneGetData(tz1), CFTimeZoneGetData(tz2))) return false; - return true; -} - -static CFHashCode __CFTimeZoneHash(CFTypeRef cf) { - CFTimeZoneRef tz = (CFTimeZoneRef)cf; - return CFHash(CFTimeZoneGetName(tz)); -} - -static CFStringRef __CFTimeZoneCopyDescription(CFTypeRef cf) { - CFTimeZoneRef tz = (CFTimeZoneRef)cf; - CFStringRef result, abbrev; - CFAbsoluteTime at; - at = CFAbsoluteTimeGetCurrent(); - abbrev = CFTimeZoneCopyAbbreviation(tz, at); - result = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("{name = %@; abbreviation = %@; GMT offset = %g; is DST = %s}"), cf, CFGetAllocator(tz), tz->_name, abbrev, CFTimeZoneGetSecondsFromGMT(tz, at), CFTimeZoneIsDaylightSavingTime(tz, at) ? "true" : "false"); - CFRelease(abbrev); - return result; -} - -static void __CFTimeZoneDeallocate(CFTypeRef cf) { - CFTimeZoneRef tz = (CFTimeZoneRef)cf; - CFAllocatorRef allocator = CFGetAllocator(tz); - CFIndex idx; - if (tz->_name) CFRelease(tz->_name); - if (tz->_data) CFRelease(tz->_data); - for (idx = 0; idx < tz->_periodCnt; idx++) { - if (NULL != tz->_periods[idx].abbrev) CFRelease(tz->_periods[idx].abbrev); - } - if (NULL != tz->_periods) CFAllocatorDeallocate(allocator, tz->_periods); -} - -static CFTypeID __kCFTimeZoneTypeID = _kCFRuntimeNotATypeID; - -static const CFRuntimeClass __CFTimeZoneClass = { - 0, - "CFTimeZone", - NULL, // init - NULL, // copy - __CFTimeZoneDeallocate, - __CFTimeZoneEqual, - __CFTimeZoneHash, - NULL, // - __CFTimeZoneCopyDescription -}; - -__private_extern__ void __CFTimeZoneInitialize(void) { - __kCFTimeZoneTypeID = _CFRuntimeRegisterClass(&__CFTimeZoneClass); -} - -CFTypeID CFTimeZoneGetTypeID(void) { - return __kCFTimeZoneTypeID; -} - -static CFTimeZoneRef __CFTimeZoneCreateSystem(void) { - CFTimeZoneRef result = NULL; -#if defined(__WIN32__) -/* 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(kCFAllocatorDefault, tz.StandardName, wcslen(tz.StandardName)); - data = CFDataCreate(kCFAllocatorDefault, (UInt8*)&tz, sizeof(tz)); - result = CFTimeZoneCreate(kCFAllocatorSystemDefault, name, data); - CFRelease(name); - CFRelease(data); - if (result) return result; - } -#else - char *tzenv; - int ret; - char linkbuf[CFMaxPathSize]; - - tzenv = getenv("TZFILE"); - if (NULL != tzenv) { - CFStringRef name = CFStringCreateWithBytes(kCFAllocatorDefault, tzenv, strlen(tzenv), kCFStringEncodingUTF8, false); - result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false); - CFRelease(name); - if (result) return result; - } - tzenv = getenv("TZ"); - if (NULL != tzenv) { - CFStringRef name = CFStringCreateWithBytes(kCFAllocatorDefault, tzenv, strlen(tzenv), kCFStringEncodingUTF8, false); - result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, true); - CFRelease(name); - if (result) return result; - } - ret = readlink(TZZONELINK, linkbuf, sizeof(linkbuf)); - if (0 < ret) { - CFStringRef name; - linkbuf[ret] = '\0'; - if (strncmp(linkbuf, TZZONEINFO, sizeof(TZZONEINFO) - 1) == 0) { - name = CFStringCreateWithBytes(kCFAllocatorDefault, linkbuf + sizeof(TZZONEINFO) - 1, strlen(linkbuf) - sizeof(TZZONEINFO) + 1, kCFStringEncodingUTF8, false); - } else { - name = CFStringCreateWithBytes(kCFAllocatorDefault, linkbuf, strlen(linkbuf), kCFStringEncodingUTF8, false); - } - result = CFTimeZoneCreateWithName(kCFAllocatorSystemDefault, name, false); - CFRelease(name); - if (result) return result; - } -#endif - return CFTimeZoneCreateWithTimeIntervalFromGMT(kCFAllocatorSystemDefault, 0.0); -} - -CFTimeZoneRef CFTimeZoneCopySystem(void) { - CFTimeZoneRef tz; - __CFTimeZoneLockGlobal(); - if (NULL == __CFTimeZoneSystem) { - __CFTimeZoneUnlockGlobal(); - tz = __CFTimeZoneCreateSystem(); - __CFTimeZoneLockGlobal(); - if (NULL == __CFTimeZoneSystem) { - __CFTimeZoneSystem = tz; - } else { - if (tz) CFRelease(tz); - } - } - tz = __CFTimeZoneSystem ? CFRetain(__CFTimeZoneSystem) : NULL; - __CFTimeZoneUnlockGlobal(); - return tz; -} - -void CFTimeZoneResetSystem(void) { - __CFTimeZoneLockGlobal(); - if (__CFTimeZoneDefault == __CFTimeZoneSystem) { - if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault); - __CFTimeZoneDefault = NULL; - } - if (__CFTimeZoneSystem) CFRelease(__CFTimeZoneSystem); - __CFTimeZoneSystem = NULL; - __CFTimeZoneUnlockGlobal(); -} - -CFTimeZoneRef CFTimeZoneCopyDefault(void) { - CFTimeZoneRef tz; - __CFTimeZoneLockGlobal(); - if (NULL == __CFTimeZoneDefault) { - __CFTimeZoneUnlockGlobal(); - tz = CFTimeZoneCopySystem(); - __CFTimeZoneLockGlobal(); - if (NULL == __CFTimeZoneDefault) { - __CFTimeZoneDefault = tz; - } else { - if (tz) CFRelease(tz); - } - } - tz = __CFTimeZoneDefault ? CFRetain(__CFTimeZoneDefault) : NULL; - __CFTimeZoneUnlockGlobal(); - return tz; -} - -void CFTimeZoneSetDefault(CFTimeZoneRef tz) { - __CFGenericValidateType(tz, __kCFTimeZoneTypeID); - __CFTimeZoneLockGlobal(); - if (tz != __CFTimeZoneDefault) { - if (tz) CFRetain(tz); - if (__CFTimeZoneDefault) CFRelease(__CFTimeZoneDefault); - __CFTimeZoneDefault = tz; - } - __CFTimeZoneUnlockGlobal(); -} - -static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void); - -CFArrayRef CFTimeZoneCopyKnownNames(void) { - CFArrayRef tzs; - __CFTimeZoneLockGlobal(); - if (NULL == __CFKnownTimeZoneList) { - CFMutableArrayRef list; -/* TimeZone information locate in the registry for Win32 - * (Aleksey Dukhnyakov) - */ -#if !defined(__WIN32__) - list = __CFCopyRecursiveDirectoryList(TZZONEINFO); -#else - list = __CFCopyWindowsTimeZoneList(); -#endif - // Remove undesirable ancient cruft - CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary(); - CFIndex idx; - for (idx = CFArrayGetCount(list); idx--; ) { - CFStringRef item = CFArrayGetValueAtIndex(list, idx); - if (CFDictionaryContainsKey(dict, item)) { - CFArrayRemoveValueAtIndex(list, idx); - } - } - __CFKnownTimeZoneList = CFArrayCreateCopy(kCFAllocatorSystemDefault, list); - CFRelease(list); - } - tzs = __CFKnownTimeZoneList ? CFRetain(__CFKnownTimeZoneList) : NULL; - __CFTimeZoneUnlockGlobal(); - return tzs; -} - -static const unsigned char *__CFTimeZoneAbbreviationDefaults = -#if defined(__WIN32__) -/* - * TimeZone abbreviations for Win32 - * (Andrew Dzubandovsky) - * - */ -"" -" " -" " -" " -" AFG Afghanistan Standard Time" -" ALS Alaskan Standard Time" -" ARA Arab Standard Time" -" ARB Arabian Standard Time" -" ARC Arabic Standard Time" -" ATL Atlantic Standard Time" -" ASC AUS Central Standard Time" -" ASE AUS Eastern Standard Time" -" AZS Azores Standard Time" -" CND Canada Central Standard Time" -" CPV Cape Verde Standard Time" -" CCS Caucasus Standard Time" -" CNAS Cen. Australia Standard Time" -" CAMR Central America Standard Time" -" CAS Central Asia Standard Time" -" CER Central Europe Standard Time" -" CEPN Central European Standard Time" -" CPC Central Pacific Standard Time" -" CSTD Central Standard Time" -" CHN China Standard Time" -" DTLN Dateline Standard Time" -" EAFR E. Africa Standard Time" -" EAS E. Australia Standard Time" -" ERP E. Europe Standard Time" -" ESTH E. South America Standard Time" -" ESTM Eastern Standard Time" -" EGP Egypt Standard Time" -" EKT Ekaterinburg Standard Time" -" FST Fiji Standard Time" -" FLE FLE Standard Time" -" GMT GMT Standard Time" -" GRLD Greenland Standard Time" -" GRW Greenwich Standard Time" -" GTB GTB Standard Time" -" HWT Hawaiian Standard Time" -" INT India Standard Time" -" IRT Iran Standard Time" -" ISL Israel Standard Time" -" KRT Korea Standard Time" -" MXST Mexico Standard Time" -" MTL Mid-Atlantic Standard Time" -" MNT Mountain Standard Time" -" MNM Myanmar Standard Time" -" NCNA N. Central Asia Standard Time" -" MPL Nepal Standard Time" -" NWZ New Zealand Standard Time" -" NWF Newfoundland Standard Time" -" NTAE North Asia East Standard Time" -" NTAS North Asia Standard Time" -" HSAT Pacific SA Standard Time" -" PST Pacific Standard Time" -" RMC Romance Standard Time" -" MSK Russian Standard Time" -" SSS SA Eastern Standard Time" -" SPS SA Pacific Standard Time" -" SWS SA Western Standard Time" -" SMS Samoa Standard Time" -" SAS SE Asia Standard Time" -" SNG Singapore Standard Time" -" STAF South Africa Standard Time" -" SRLK Sri Lanka Standard Time" -" TPS Taipei Standard Time" -" TSM Tasmania Standard Time" -" JPN Tokyo Standard Time" -" TNG Tonga Standard Time" -" AEST US Eastern Standard Time" -" AMST US Mountain Standard Time" -" VLD Vladivostok Standard Time" -" AUSW W. Australia Standard Time" -" AFCW W. Central Africa Standard Time" -" EWS W. Europe Standard Time" -" ASW West Asia Standard Time" -" PWS West Pacific Standard Time" -" RKS Yakutsk Standard Time" -" " -" "; -#else -"" -" " -" " -" " -" ADT America/Halifax" -" AFT Asia/Kabul" -" AKDT America/Juneau" -" AKST America/Juneau" -" AST America/Halifax" -" CDT America/Chicago" -" CEST Europe/Rome" -" CET Europe/Rome" -" CST America/Chicago" -" EDT America/New_York" -" EEST Europe/Warsaw" -" EET Europe/Warsaw" -" EST America/New_York" -" GMT GMT" -" HKST Asia/Hong_Kong" -" HST Pacific/Honolulu" -" JST Asia/Tokyo" -" MDT America/Denver" -" MSD Europe/Moscow" -" MSK Europe/Moscow" -" MST America/Denver" -" NZDT Pacific/Auckland" -" NZST Pacific/Auckland" -" PDT America/Los_Angeles" -" PST America/Los_Angeles" -" UTC UTC" -" WEST Europe/Paris" -" WET Europe/Paris" -" YDT America/Yakutat" -" YST America/Yakutat" -" " -" "; -#endif - -CFDictionaryRef CFTimeZoneCopyAbbreviationDictionary(void) { - CFDictionaryRef dict; - __CFTimeZoneLockAbbreviations(); - if (NULL == __CFTimeZoneAbbreviationDict) { - CFDataRef data = CFDataCreate(kCFAllocatorDefault, __CFTimeZoneAbbreviationDefaults, strlen(__CFTimeZoneAbbreviationDefaults)); - __CFTimeZoneAbbreviationDict = CFPropertyListCreateFromXMLData(kCFAllocatorDefault, data, kCFPropertyListImmutable, NULL); - CFRelease(data); - } - if (NULL == __CFTimeZoneAbbreviationDict) { - __CFTimeZoneAbbreviationDict = CFDictionaryCreate(kCFAllocatorDefault, NULL, NULL, 0, NULL, NULL); - } - dict = __CFTimeZoneAbbreviationDict ? CFRetain(__CFTimeZoneAbbreviationDict) : NULL; - __CFTimeZoneUnlockAbbreviations(); - return dict; -} - -void CFTimeZoneSetAbbreviationDictionary(CFDictionaryRef dict) { - __CFGenericValidateType(dict, CFDictionaryGetTypeID()); - __CFTimeZoneLockGlobal(); - if (dict != __CFTimeZoneAbbreviationDict) { - if (dict) CFRetain(dict); - if (__CFTimeZoneAbbreviationDict) CFRelease(__CFTimeZoneAbbreviationDict); - __CFTimeZoneAbbreviationDict = dict; - } - __CFTimeZoneUnlockGlobal(); -} - -CFTimeZoneRef CFTimeZoneCreate(CFAllocatorRef allocator, CFStringRef name, CFDataRef data) { -// assert: (NULL != name && NULL != data); - CFTimeZoneRef memory; - uint32_t size; - CFTZPeriod *tzp; - CFIndex idx, cnt; - - if (allocator == NULL) allocator = __CFGetDefaultAllocator(); - __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); - __CFGenericValidateType(name, CFStringGetTypeID()); - __CFGenericValidateType(data, CFDataGetTypeID()); - __CFTimeZoneLockGlobal(); - if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&memory)) { - __CFTimeZoneUnlockGlobal(); - return (CFTimeZoneRef)CFRetain(memory); - } - if (!__CFParseTimeZoneData(allocator, data, &tzp, &cnt)) { - __CFTimeZoneUnlockGlobal(); - return NULL; - } - size = sizeof(struct __CFTimeZone) - sizeof(CFRuntimeBase); - memory = _CFRuntimeCreateInstance(allocator, __kCFTimeZoneTypeID, size, NULL); - if (NULL == memory) { - __CFTimeZoneUnlockGlobal(); - for (idx = 0; idx < cnt; idx++) { - if (NULL != tzp[idx].abbrev) CFRelease(tzp[idx].abbrev); - } - if (NULL != tzp) CFAllocatorDeallocate(allocator, tzp); - return NULL; - } - ((struct __CFTimeZone *)memory)->_name = CFStringCreateCopy(allocator, name); - ((struct __CFTimeZone *)memory)->_data = CFDataCreateCopy(allocator, data); - ((struct __CFTimeZone *)memory)->_periods = tzp; - ((struct __CFTimeZone *)memory)->_periodCnt = cnt; - if (NULL == __CFTimeZoneCache) { - CFDictionaryKeyCallBacks kcb = kCFTypeDictionaryKeyCallBacks; - kcb.retain = kcb.release = NULL; - __CFTimeZoneCache = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, &kcb, &kCFTypeDictionaryValueCallBacks); - } - CFDictionaryAddValue(__CFTimeZoneCache, ((struct __CFTimeZone *)memory)->_name, memory); - __CFTimeZoneUnlockGlobal(); - return memory; -} - -#if !defined(__WIN32__) -static CFTimeZoneRef __CFTimeZoneCreateFixed(CFAllocatorRef allocator, int32_t seconds, CFStringRef name, int isDST) { - CFTimeZoneRef result; - CFDataRef data; - int32_t nameLen = CFStringGetLength(name); -#if defined(__WIN32__) - unsigned char *dataBytes = CFAllocatorAllocate(allocator, 52 + nameLen + 1, 0); - if (!dataBytes) return NULL; - if (__CFOASafe) __CFSetLastAllocationEventName(dataBytes, "CFTimeZone (temp)"); -#else - unsigned char dataBytes[52 + nameLen + 1]; -#endif - memset(dataBytes, 0, sizeof(dataBytes)); - - // Put in correct magic bytes for timezone structures - dataBytes[0] = 'T'; - dataBytes[1] = 'Z'; - dataBytes[2] = 'i'; - dataBytes[3] = 'f'; - - __CFEntzcode(1, dataBytes + 20); - __CFEntzcode(1, dataBytes + 24); - __CFEntzcode(1, dataBytes + 36); - __CFEntzcode(nameLen + 1, dataBytes + 40); - __CFEntzcode(seconds, dataBytes + 44); - dataBytes[48] = isDST ? 1 : 0; - CFStringGetCString(name, dataBytes + 50, nameLen + 1, kCFStringEncodingASCII); - data = CFDataCreate(allocator, dataBytes, 52 + nameLen + 1); - result = CFTimeZoneCreate(allocator, name, data); - CFRelease(data); -#if defined(__WIN32__) - CFAllocatorDeallocate(allocator, dataBytes); -#endif - return result; -} -#endif - -// rounds offset to nearest minute -CFTimeZoneRef CFTimeZoneCreateWithTimeIntervalFromGMT(CFAllocatorRef allocator, CFTimeInterval ti) { - CFTimeZoneRef result; - CFStringRef name; - int32_t seconds, minute, hour; - if (allocator == NULL) allocator = __CFGetDefaultAllocator(); - __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); - if (ti < -18.0 * 3600 || 18.0 * 3600 < ti) return NULL; - ti = (ti < 0.0) ? ceil((ti / 60.0) - 0.5) * 60.0 : floor((ti / 60.0) + 0.5) * 60.0; - seconds = (int32_t)ti; - hour = (ti < 0) ? (-seconds / 3600) : (seconds / 3600); - seconds -= ((ti < 0) ? -hour : hour) * 3600; - minute = (ti < 0) ? (-seconds / 60) : (seconds / 60); - if (fabs(ti) < 1.0) { - name = CFRetain(CFSTR("GMT")); - } else { - name = CFStringCreateWithFormat(allocator, NULL, CFSTR("GMT%c%02d%02d"), (ti < 0.0 ? '-' : '+'), hour, minute); - } -#if !defined(__WIN32__) - result = __CFTimeZoneCreateFixed(allocator, (int32_t)ti, name, 0); -#else -/* CFTimeZoneRef->_data will contain TIME_ZONE_INFORMATION structure - * to find current timezone - * (Aleksey Dukhnyakov) - */ - { - TIME_ZONE_INFORMATION tzi; - CFDataRef data; - CFIndex length = CFStringGetLength(name); - - memset(&tzi,0,sizeof(tzi)); - tzi.Bias=(long)(-ti/60); - CFStringGetCharacters(name, CFRangeMake(0, length < 31 ? length : 31 ), tzi.StandardName); - data = CFDataCreate(allocator,(UInt8*)&tzi, sizeof(tzi)); - result = CFTimeZoneCreate(allocator, name, data); - CFRelease(data); - } -#endif - CFRelease(name); - return result; -} - -CFTimeZoneRef CFTimeZoneCreateWithName(CFAllocatorRef allocator, CFStringRef name, Boolean tryAbbrev) { - CFTimeZoneRef result = NULL; - CFStringRef tzName = NULL; - CFDataRef data = NULL; - - if (allocator == NULL) allocator = __CFGetDefaultAllocator(); - __CFGenericValidateType(allocator, CFAllocatorGetTypeID()); - __CFGenericValidateType(name, CFStringGetTypeID()); - if (CFEqual(CFSTR(""), name)) { - // empty string is not a time zone name, just abort now, - // following stuff will fail anyway - return NULL; - } - __CFTimeZoneLockGlobal(); - if (NULL != __CFTimeZoneCache && CFDictionaryGetValueIfPresent(__CFTimeZoneCache, name, (const void **)&result)) { - __CFTimeZoneUnlockGlobal(); - return (CFTimeZoneRef)CFRetain(result); - } - __CFTimeZoneUnlockGlobal(); -#if !defined(__WIN32__) - CFURLRef baseURL, tempURL; - void *bytes; - CFIndex length; - - baseURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, CFSTR(TZZONEINFO), kCFURLPOSIXPathStyle, true); - if (tryAbbrev) { - CFDictionaryRef abbrevs = CFTimeZoneCopyAbbreviationDictionary(); - tzName = CFDictionaryGetValue(abbrevs, name); - if (NULL != tzName) { - tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, baseURL, tzName, false); - if (NULL != tempURL) { - if (_CFReadBytesFromFile(kCFAllocatorDefault, tempURL, &bytes, &length, 0)) { - data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, length, kCFAllocatorDefault); - } - CFRelease(tempURL); - } - } - CFRelease(abbrevs); - } - if (NULL == data) { - CFDictionaryRef dict = __CFTimeZoneCopyCompatibilityDictionary(); - CFStringRef mapping = CFDictionaryGetValue(dict, name); - if (mapping) { - name = mapping; - } else if (CFStringHasPrefix(name, CFSTR(TZZONEINFO))) { - CFMutableStringRef unprefixed = CFStringCreateMutableCopy(kCFAllocatorDefault, CFStringGetLength(name), name); - CFStringDelete(unprefixed, CFRangeMake(0, sizeof(TZZONEINFO))); - mapping = CFDictionaryGetValue(dict, unprefixed); - if (mapping) { - name = mapping; - } - CFRelease(unprefixed); - } - CFRelease(dict); - if (CFEqual(CFSTR(""), name)) { - return NULL; - } - } - if (NULL == data) { - tzName = name; - tempURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, baseURL, tzName, false); - if (NULL != tempURL) { - if (_CFReadBytesFromFile(kCFAllocatorDefault, tempURL, &bytes, &length, 0)) { - data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, length, kCFAllocatorDefault); - } - CFRelease(tempURL); - } - } - CFRelease(baseURL); - if (NULL == data) { - tzName = name; - tempURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, tzName, kCFURLPOSIXPathStyle, false); - if (NULL != tempURL) { - if (_CFReadBytesFromFile(kCFAllocatorDefault, tempURL, &bytes, &length, 0)) { - data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, length, kCFAllocatorDefault); - } - CFRelease(tempURL); - } - } - if (NULL != data) { - result = CFTimeZoneCreate(allocator, tzName, data); - CFRelease(data); - } -#else -/* 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 = CFDictionaryGetValue(abbrevs, name); - if (NULL == tzName) { - 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) - if (RegOpenKey(hkResult,CFStringGetCharactersPtr(name) ,&hkResult) != - ERROR_SUCCESS ) { -#else - if (RegOpenKey(hkResult,CFStringGetCStringPtr(name, CFStringGetSystemEncoding()),&hkResult) != ERROR_SUCCESS ) { -#endif - return NULL; - } -/* 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 = CFStringCreateCopy(allocator,safeName); - else { - } - } - CFRelease(data); - } -#endif - return result; -} - -CFStringRef CFTimeZoneGetName(CFTimeZoneRef tz) { - CF_OBJC_FUNCDISPATCH0(__kCFTimeZoneTypeID, CFStringRef, tz, "name"); - __CFGenericValidateType(tz, __kCFTimeZoneTypeID); - return tz->_name; -} - -CFDataRef CFTimeZoneGetData(CFTimeZoneRef tz) { - CF_OBJC_FUNCDISPATCH0(__kCFTimeZoneTypeID, CFDataRef, tz, "data"); - __CFGenericValidateType(tz, __kCFTimeZoneTypeID); - return tz->_data; -} - -/* This function converts CFAbsoluteTime to (Win32) SYSTEMTIME - * (Aleksey Dukhnyakov) - */ -#if defined(__WIN32__) -BOOL __CFTimeZoneGetWin32SystemTime(SYSTEMTIME * sys_time, CFAbsoluteTime time) -{ - LONGLONG l; - FILETIME * ftime=(FILETIME*)&l; - - /* seconds between 1601 and 1970 : 11644473600, - * seconds between 1970 and 2001 : 978307200, - * FILETIME - number of 100-nanosecond intervals since January 1, 1601 - */ - l=(time+11644473600LL+978307200)*10000000; - if (FileTimeToSystemTime(ftime,sys_time)) - return TRUE; - else - return FALSE; -} -#endif - -CFTimeInterval _CFTimeZoneGetDSTOffset(CFTimeZoneRef tz, CFAbsoluteTime at) { -#if !defined(__WIN32__) -// #warning this does not work for non-CFTimeZoneRefs - CFIndex idx; - idx = __CFBSearchTZPeriods(tz, at); - // idx 0 is never returned if it is in DST - if (__CFTZPeriodIsDST(&(tz->_periods[idx]))) { - return __CFTZPeriodGMTOffset(&(tz->_periods[idx])) - __CFTZPeriodGMTOffset(&(tz->_periods[idx - 1])); - } -#endif - return 0.0; -} - -// returns 0.0 if there is no data for the next switch after 'at' -CFAbsoluteTime _CFTimeZoneGetNextDSTSwitch(CFTimeZoneRef tz, CFAbsoluteTime at) { -#if !defined(__WIN32__) -// #warning this does not work for non-CFTimeZoneRefs - CFIndex idx; - idx = __CFBSearchTZPeriods(tz, at); - if (tz->_periodCnt <= idx + 1) { - return 0.0; - } - return (CFAbsoluteTime)__CFTZPeriodStartSeconds(&(tz->_periods[idx + 1])); -#endif - return 0.0; -} - -CFTimeInterval CFTimeZoneGetSecondsFromGMT(CFTimeZoneRef tz, CFAbsoluteTime at) { -#if !defined(__WIN32__) - CFIndex idx; - CF_OBJC_FUNCDISPATCH1(__kCFTimeZoneTypeID, CFTimeInterval, tz, "_secondsFromGMTForAbsoluteTime:", at); - __CFGenericValidateType(tz, __kCFTimeZoneTypeID); - idx = __CFBSearchTZPeriods(tz, at); - return __CFTZPeriodGMTOffset(&(tz->_periods[idx])); -#else -/* 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(__kCFTimeZoneTypeID, 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; -#endif -} - -#if defined(__WIN32__) -/* - * 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 = 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 = CFStringCreateCopy(kCFAllocatorDefault, abbr.tzAbbr); - else - tz->_periods->abbrev = CFStringCreateCopy(kCFAllocatorDefault, tz->_name); -/* We should return name of TimeZone if couldn't find abbrevation. - * (Ala on MACOSX) - * - * old line : tz->_periods->abbrev = - * CFStringCreateWithCString(kCFAllocatorDefault,"UNKNOWN", - * CFStringGetSystemEncoding()); - * - * (Aleksey Dukhnyakov) -*/ - CFRelease( abbrevs ); - } - - return 0; -} -#endif - -CFStringRef CFTimeZoneCopyAbbreviation(CFTimeZoneRef tz, CFAbsoluteTime at) { - CFStringRef result; - CFIndex idx; - CF_OBJC_FUNCDISPATCH1(__kCFTimeZoneTypeID, CFStringRef, tz, "_abbreviationForAbsoluteTime:", at); - __CFGenericValidateType(tz, __kCFTimeZoneTypeID); -#if !defined(__WIN32__) - idx = __CFBSearchTZPeriods(tz, at); -#else -/* - * Initialize abbreviation for this TimeZone - * (Aleksey Dukhnyakov) - */ - idx = __CFTimeZoneInitAbbrev(tz); -#endif - result = __CFTZPeriodAbbreviation(&(tz->_periods[idx])); - return result ? CFRetain(result) : NULL; -} - -Boolean CFTimeZoneIsDaylightSavingTime(CFTimeZoneRef tz, CFAbsoluteTime at) { -#if !defined(__WIN32__) - CFIndex idx; - CF_OBJC_FUNCDISPATCH1(__kCFTimeZoneTypeID, Boolean, tz, "_isDaylightSavingTimeForAbsoluteTime:", at); - __CFGenericValidateType(tz, __kCFTimeZoneTypeID); - idx = __CFBSearchTZPeriods(tz, at); - return __CFTZPeriodIsDST(&(tz->_periods[idx])); -#else -/* 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(__kCFTimeZoneTypeID, 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; -#endif -} - -CFTimeInterval _CFTimeZoneGetDSTDelta(CFTimeZoneRef tz, CFAbsoluteTime at) { - CFIndex idx; - __CFGenericValidateType(tz, __kCFTimeZoneTypeID); - idx = __CFBSearchTZPeriods(tz, at); - CFTimeInterval delta = __CFTZPeriodGMTOffset(&(tz->_periods[idx])); - if (idx + 1 < tz->_periodCnt) { - return fabs(delta - __CFTZPeriodGMTOffset(&(tz->_periods[idx + 1]))); - } else if (0 < idx) { - return fabs(delta - __CFTZPeriodGMTOffset(&(tz->_periods[idx - 1]))); - } - return 0.0; -} - -static CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary(void) { - CFDictionaryRef dict; - __CFTimeZoneLockCompatibilityMapping(); - if (NULL == __CFTimeZoneCompatibilityMappingDict) { - __CFTimeZoneCompatibilityMappingDict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 112, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - - // Empty string means delete/ignore these - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Factory"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/Pacific-New"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Mideast/Riyadh87"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Mideast/Riyadh88"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Mideast/Riyadh89"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/AST4"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/AST4ADT"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/CST6"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/CST6CDT"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/EST5"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/EST5EDT"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/HST10"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/MST7"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/MST7MDT"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/PST8"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/PST8PDT"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/YST9"), CFSTR("")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("SystemV/YST9YDT"), CFSTR("")); - - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Atka"), CFSTR("America/Adak")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Ensenada"), CFSTR("America/Tijuana")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Fort_Wayne"), CFSTR("America/Indianapolis")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Indiana/Indianapolis"), CFSTR("America/Indianapolis")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Kentucky/Louisville"), CFSTR("America/Louisville")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Knox_IN"), CFSTR("America/Indiana/Knox")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Porto_Acre"), CFSTR("America/Rio_Branco")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Rosario"), CFSTR("America/Cordoba")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Shiprock"), CFSTR("America/Denver")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("America/Virgin"), CFSTR("America/St_Thomas")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Antarctica/South_Pole"), CFSTR("Antarctica/McMurdo")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Asia/Ashkhabad"), CFSTR("Asia/Ashgabat")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Asia/Chungking"), CFSTR("Asia/Chongqing")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Asia/Macao"), CFSTR("Asia/Macau")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Asia/Tel_Aviv"), CFSTR("Asia/Jerusalem")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Asia/Thimbu"), CFSTR("Asia/Thimphu")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Asia/Ujung_Pandang"), CFSTR("Asia/Makassar")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Asia/Ulan_Bator"), CFSTR("Asia/Ulaanbaatar")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/ACT"), CFSTR("Australia/Sydney")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/LHI"), CFSTR("Australia/Lord_Howe")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/NSW"), CFSTR("Australia/Sydney")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/North"), CFSTR("Australia/Darwin")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/Queensland"), CFSTR("Australia/Brisbane")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/South"), CFSTR("Australia/Adelaide")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/Tasmania"), CFSTR("Australia/Hobart")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/Victoria"), CFSTR("Australia/Melbourne")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/West"), CFSTR("Australia/Perth")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Australia/Yancowinna"), CFSTR("Australia/Broken_Hill")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Brazil/Acre"), CFSTR("America/Porto_Acre")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Brazil/DeNoronha"), CFSTR("America/Noronha")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Brazil/West"), CFSTR("America/Manaus")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("CST6CDT"), CFSTR("America/Chicago")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Canada/Central"), CFSTR("America/Winnipeg")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Canada/East-Saskatchewan"), CFSTR("America/Regina")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Canada/Pacific"), CFSTR("America/Vancouver")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Canada/Yukon"), CFSTR("America/Whitehorse")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Chile/Continental"), CFSTR("America/Santiago")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Chile/EasterIsland"), CFSTR("Pacific/Easter")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Cuba"), CFSTR("America/Havana")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("EST5EDT"), CFSTR("America/New_York")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Egypt"), CFSTR("Africa/Cairo")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Eire"), CFSTR("Europe/Dublin")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Etc/GMT+0"), CFSTR("GMT")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Etc/GMT-0"), CFSTR("GMT")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Etc/GMT0"), CFSTR("GMT")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Etc/Greenwich"), CFSTR("GMT")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Etc/Universal"), CFSTR("UTC")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Etc/Zulu"), CFSTR("UTC")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Europe/Nicosia"), CFSTR("Asia/Nicosia")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Europe/Tiraspol"), CFSTR("Europe/Chisinau")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("GB-Eire"), CFSTR("Europe/London")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("GB"), CFSTR("Europe/London")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("GMT+0"), CFSTR("GMT")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("GMT-0"), CFSTR("GMT")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("GMT0"), CFSTR("GMT")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Greenwich"), CFSTR("GMT")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Hongkong"), CFSTR("Asia/Hong_Kong")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Iceland"), CFSTR("Atlantic/Reykjavik")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Iran"), CFSTR("Asia/Tehran")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Israel"), CFSTR("Asia/Jerusalem")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Jamaica"), CFSTR("America/Jamaica")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Kwajalein"), CFSTR("Pacific/Kwajalein")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Libya"), CFSTR("Africa/Tripoli")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("MST7MDT"), CFSTR("America/Denver")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Mexico/BajaNorte"), CFSTR("America/Tijuana")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Mexico/BajaSur"), CFSTR("America/Mazatlan")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Mexico/General"), CFSTR("America/Mexico_City")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("NZ-CHAT"), CFSTR("Pacific/Chatham")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("NZ"), CFSTR("Pacific/Auckland")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Navajo"), CFSTR("America/Denver")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("PRC"), CFSTR("Asia/Shanghai")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("PST8PDT"), CFSTR("America/Los_Angeles")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Pacific/Samoa"), CFSTR("Pacific/Pago_Pago")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Poland"), CFSTR("Europe/Warsaw")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Portugal"), CFSTR("Europe/Lisbon")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("ROC"), CFSTR("Asia/Taipei")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("ROK"), CFSTR("Asia/Seoul")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Singapore"), CFSTR("Asia/Singapore")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Turkey"), CFSTR("Europe/Istanbul")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("UCT"), CFSTR("UTC")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/Alaska"), CFSTR("America/Anchorage")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/Aleutian"), CFSTR("America/Adak")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/Arizona"), CFSTR("America/Phoenix")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/East-Indiana"), CFSTR("America/Indianapolis")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/Hawaii"), CFSTR("Pacific/Honolulu")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/Indiana-Starke"), CFSTR("America/Indiana/Knox")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/Michigan"), CFSTR("America/Detroit")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("US/Samoa"), CFSTR("Pacific/Pago_Pago")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Universal"), CFSTR("UTC")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("W-SU"), CFSTR("Europe/Moscow")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict, CFSTR("Zulu"), CFSTR("UTC")); - } - dict = __CFTimeZoneCompatibilityMappingDict ? CFRetain(__CFTimeZoneCompatibilityMappingDict) : NULL; - __CFTimeZoneUnlockCompatibilityMapping(); - return dict; -} - -__private_extern__ CFDictionaryRef __CFTimeZoneCopyCompatibilityDictionary2(void) { - CFDictionaryRef dict; - __CFTimeZoneLockCompatibilityMapping(); - if (NULL == __CFTimeZoneCompatibilityMappingDict2) { - __CFTimeZoneCompatibilityMappingDict2 = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 16, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Asia/Dacca"), CFSTR("Asia/Dhaka")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Asia/Istanbul"), CFSTR("Europe/Istanbul")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Australia/Canberra"), CFSTR("Australia/Sydney")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Brazil/East"), CFSTR("America/Sao_Paulo")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Canada/Atlantic"), CFSTR("America/Halifax")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Canada/Eastern"), CFSTR("America/Montreal")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Canada/Mountain"), CFSTR("America/Edmonton")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Canada/Newfoundland"), CFSTR("America/St_Johns")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Canada/Saskatchewan"), CFSTR("America/Regina")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("Japan"), CFSTR("Asia/Tokyo")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("US/Central"), CFSTR("America/Chicago")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("US/Eastern"), CFSTR("America/New_York")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("US/Mountain"), CFSTR("America/Denver")); - CFDictionaryAddValue(__CFTimeZoneCompatibilityMappingDict2, CFSTR("US/Pacific"), CFSTR("America/Los_Angeles")); - } - dict = __CFTimeZoneCompatibilityMappingDict2 ? CFRetain(__CFTimeZoneCompatibilityMappingDict2) : NULL; - __CFTimeZoneUnlockCompatibilityMapping(); - return dict; -} - - diff --git a/Parsing.subproj/CFBinaryPList.c b/Parsing.subproj/CFBinaryPList.c deleted file mode 100644 index 9495ad1..0000000 --- a/Parsing.subproj/CFBinaryPList.c +++ /dev/null @@ -1,930 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFBinaryPList.c - Copyright 2000-2002, Apple, Inc. All rights reserved. - Responsibility: Christopher Kane -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "CFInternal.h" - - -CF_INLINE CFTypeID __CFGenericTypeID_genericobj_inline(const void *cf) { - CFTypeID typeID = __CFBitfieldGetValue(((const CFRuntimeBase *)cf)->_info, 15, 8); - return CF_IS_OBJC(typeID, cf) ? CFGetTypeID(cf) : typeID; -} - -struct __CFKeyedArchiverUID { - CFRuntimeBase _base; - uint32_t _value; -}; - -static CFStringRef __CFKeyedArchiverUIDCopyDescription(CFTypeRef cf) { - CFKeyedArchiverUIDRef uid = (CFKeyedArchiverUIDRef)cf; - return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("{value = %u}"), cf, CFGetAllocator(cf), uid->_value); -} - -static CFStringRef __CFKeyedArchiverUIDCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { - CFKeyedArchiverUIDRef uid = (CFKeyedArchiverUIDRef)cf; - return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("@%u@"), uid->_value); -} - -static CFTypeID __kCFKeyedArchiverUIDTypeID = _kCFRuntimeNotATypeID; - -static const CFRuntimeClass __CFKeyedArchiverUIDClass = { - 0, - "CFKeyedArchiverUID", - NULL, // init - NULL, // copy - NULL, // finalize - NULL, // equal -- pointer equality only - NULL, // hash -- pointer hashing only - __CFKeyedArchiverUIDCopyFormattingDescription, - __CFKeyedArchiverUIDCopyDescription -}; - -__private_extern__ void __CFKeyedArchiverUIDInitialize(void) { - __kCFKeyedArchiverUIDTypeID = _CFRuntimeRegisterClass(&__CFKeyedArchiverUIDClass); -} - -CFTypeID _CFKeyedArchiverUIDGetTypeID(void) { - return __kCFKeyedArchiverUIDTypeID; -} - -CFKeyedArchiverUIDRef _CFKeyedArchiverUIDCreate(CFAllocatorRef allocator, uint32_t value) { - CFKeyedArchiverUIDRef uid; - uid = (CFKeyedArchiverUIDRef)_CFRuntimeCreateInstance(allocator, __kCFKeyedArchiverUIDTypeID, sizeof(struct __CFKeyedArchiverUID) - sizeof(CFRuntimeBase), NULL); - if (NULL == uid) { - return NULL; - } - ((struct __CFKeyedArchiverUID *)uid)->_value = value; - return uid; -} - - -uint32_t _CFKeyedArchiverUIDGetValue(CFKeyedArchiverUIDRef uid) { - return uid->_value; -} - - -typedef struct { - CFTypeRef stream; - bool streamIsData; - uint64_t written; - int32_t used; - uint8_t buffer[8192 - 16]; -} __CFBinaryPlistWriteBuffer; - -CF_INLINE void writeBytes(__CFBinaryPlistWriteBuffer *buf, const UInt8 *bytes, CFIndex length) { - if (buf->streamIsData) { - CFDataAppendBytes((CFMutableDataRef)buf->stream, bytes, length); - } else { - CFWriteStreamWrite((CFWriteStreamRef)buf->stream, bytes, length); - } -} - -static void bufferWrite(__CFBinaryPlistWriteBuffer *buf, const uint8_t *buffer, CFIndex count) { - CFIndex copyLen; - if ((CFIndex)sizeof(buf->buffer) <= count) { - writeBytes(buf, buf->buffer, buf->used); - buf->written += buf->used; - buf->used = 0; - writeBytes(buf, buffer, count); - buf->written += count; - return; - } - copyLen = __CFMin(count, (CFIndex)sizeof(buf->buffer) - buf->used); - memmove(buf->buffer + buf->used, buffer, copyLen); - buf->used += copyLen; - if (sizeof(buf->buffer) == buf->used) { - writeBytes(buf, buf->buffer, sizeof(buf->buffer)); - buf->written += sizeof(buf->buffer); - memmove(buf->buffer, buffer + copyLen, count - copyLen); - buf->used = count - copyLen; - } -} - -static void bufferFlush(__CFBinaryPlistWriteBuffer *buf) { - writeBytes(buf, buf->buffer, buf->used); - buf->written += buf->used; - buf->used = 0; -} - -/* -HEADER - magic number ("bplist") - file format version - -OBJECT TABLE - variable-sized objects - - Object Formats (marker byte followed by additional info in some cases) - null 0000 0000 - bool 0000 1000 // false - bool 0000 1001 // true - fill 0000 1111 // fill byte - int 0001 nnnn ... // # of bytes is 2^nnnn, big-endian bytes - real 0010 nnnn ... // # of bytes is 2^nnnn, big-endian bytes - date 0011 0011 ... // 8 byte float follows, big-endian bytes - data 0100 nnnn [int] ... // nnnn is number of bytes unless 1111 then int count follows, followed by bytes - string 0101 nnnn [int] ... // ASCII string, nnnn is # of chars, else 1111 then int count, then bytes - string 0110 nnnn [int] ... // Unicode string, nnnn is # of chars, else 1111 then int count, then big-endian 2-byte uint16_t - 0111 xxxx // unused - uid 1000 nnnn ... // nnnn+1 is # of bytes - 1001 xxxx // unused - array 1010 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows - 1011 xxxx // unused - 1100 xxxx // unused - dict 1101 nnnn [int] keyref* objref* // nnnn is count, unless '1111', then int count follows - 1110 xxxx // unused - 1111 xxxx // unused - -OFFSET TABLE - list of ints, byte size of which is given in trailer - -- these are the byte offsets into the file - -- number of these is in the trailer - -TRAILER - byte size of offset ints in offset table - byte size of object refs in arrays and dicts - number of offsets in offset table (also is number of objects) - element # in offset table which is top level object - -*/ - - -static CFTypeID stringtype = -1, datatype = -1, numbertype = -1, datetype = -1; -static CFTypeID booltype = -1, dicttype = -1, arraytype = -1; - -static void _appendInt(__CFBinaryPlistWriteBuffer *buf, uint64_t bigint) { - uint8_t marker; - uint8_t *bytes; - CFIndex nbytes; - if (bigint <= (uint64_t)0xff) { - nbytes = 1; - marker = kCFBinaryPlistMarkerInt | 0; - } else if (bigint <= (uint64_t)0xffff) { - nbytes = 2; - marker = kCFBinaryPlistMarkerInt | 1; - } else if (bigint <= (uint64_t)0xffffffff) { - nbytes = 4; - marker = kCFBinaryPlistMarkerInt | 2; - } else { - nbytes = 8; - marker = kCFBinaryPlistMarkerInt | 3; - } - bigint = CFSwapInt64HostToBig(bigint); - bytes = (uint8_t *)&bigint + sizeof(bigint) - nbytes; - bufferWrite(buf, &marker, 1); - bufferWrite(buf, bytes, nbytes); -} - -static void _appendUID(__CFBinaryPlistWriteBuffer *buf, CFKeyedArchiverUIDRef uid) { - uint8_t marker; - uint8_t *bytes; - CFIndex nbytes; - uint64_t bigint = _CFKeyedArchiverUIDGetValue(uid); - if (bigint <= (uint64_t)0xff) { - nbytes = 1; - } else if (bigint <= (uint64_t)0xffff) { - nbytes = 2; - } else if (bigint <= (uint64_t)0xffffffff) { - nbytes = 4; - } else { - nbytes = 8; - } - marker = kCFBinaryPlistMarkerUID | (nbytes - 1); - bigint = CFSwapInt64HostToBig(bigint); - bytes = (uint8_t *)&bigint + sizeof(bigint) - nbytes; - bufferWrite(buf, &marker, 1); - bufferWrite(buf, bytes, nbytes); -} - -static Boolean __plistUniquingEqual(CFTypeRef cf1, CFTypeRef cf2) { - // As long as this equals function is more restrictive than the - // existing one, for any given type, the hash function need not - // also be provided for the uniquing set. - if (__CFGenericTypeID_genericobj_inline(cf1) != __CFGenericTypeID_genericobj_inline(cf2)) return false; - if (__CFGenericTypeID_genericobj_inline(cf1) == numbertype) { - if (CFNumberIsFloatType(cf1) != CFNumberIsFloatType(cf2)) return false; - return CFEqual(cf1, cf2); - } - return CFEqual(cf1, cf2); -} - -static void _flattenPlist(CFPropertyListRef plist, CFMutableArrayRef objlist, CFMutableDictionaryRef objtable, CFMutableSetRef uniquingsets[]) { - CFPropertyListRef unique; - uint32_t refnum; - CFTypeID type = __CFGenericTypeID_genericobj_inline(plist); - CFIndex idx; - CFPropertyListRef *list, buffer[256]; - - // Do not unique dictionaries or arrays, because: they - // are slow to compare, and have poor hash codes. - // Uniquing bools is unnecessary. - int which = -1; - if (stringtype == type) { - which = 0; - } else if (numbertype == type) { - which = 1; - } else if (datatype == type) { - which = 2; - } else if (datetype == type) { - which = 3; - } - if (1 && -1 != which) { - CFMutableSetRef uniquingset = uniquingsets[which]; - CFIndex before = CFSetGetCount(uniquingset); - CFSetAddValue(uniquingset, plist); - CFIndex after = CFSetGetCount(uniquingset); - if (after == before) { // already in set - unique = CFSetGetValue(uniquingset, plist); - if (unique != plist) { - refnum = (uint32_t)CFDictionaryGetValue(objtable, unique); - CFDictionaryAddValue(objtable, plist, (const void *)refnum); - } - return; - } - } - refnum = CFArrayGetCount(objlist); - CFArrayAppendValue(objlist, plist); - CFDictionaryAddValue(objtable, plist, (const void *)refnum); - if (dicttype == type) { - CFIndex count = CFDictionaryGetCount(plist); - list = (count <= 128) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, 2 * count * sizeof(CFTypeRef), 0); - CFDictionaryGetKeysAndValues(plist, list, list + count); - for (idx = 0; idx < 2 * count; idx++) { - _flattenPlist(list[idx], objlist, objtable, uniquingsets); - } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); - } else if (arraytype == type) { - CFIndex count = CFArrayGetCount(plist); - list = (count <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, count * sizeof(CFTypeRef), 0); - CFArrayGetValues(plist, CFRangeMake(0, count), list); - for (idx = 0; idx < count; idx++) { - _flattenPlist(list[idx], objlist, objtable, uniquingsets); - } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); - } -} - -// stream can be a CFWriteStreamRef or a CFMutableDataRef -CFIndex __CFBinaryPlistWriteToStream(CFPropertyListRef plist, CFTypeRef stream) { - CFMutableDictionaryRef objtable; - CFMutableArrayRef objlist; - CFBinaryPlistTrailer trailer; - uint64_t *offsets, length_so_far; - uint64_t mask, refnum; - int64_t idx, idx2, cnt; - __CFBinaryPlistWriteBuffer *buf; - CFSetCallBacks cb = kCFTypeSetCallBacks; - - if ((CFTypeID)-1 == stringtype) { - stringtype = CFStringGetTypeID(); - datatype = CFDataGetTypeID(); - numbertype = CFNumberGetTypeID(); - booltype = CFBooleanGetTypeID(); - datetype = CFDateGetTypeID(); - dicttype = CFDictionaryGetTypeID(); - arraytype = CFArrayGetTypeID(); - } - objtable = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, NULL); - _CFDictionarySetCapacity(objtable, 640); - objlist = CFArrayCreateMutable(kCFAllocatorSystemDefault, 0, NULL); - _CFArraySetCapacity(objlist, 640); - cb.equal = __plistUniquingEqual; - CFMutableSetRef uniquingsets[4]; - uniquingsets[0] = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &cb); - _CFSetSetCapacity(uniquingsets[0], 1000); - uniquingsets[1] = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &cb); - _CFSetSetCapacity(uniquingsets[1], 500); - uniquingsets[2] = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &cb); - _CFSetSetCapacity(uniquingsets[2], 250); - uniquingsets[3] = CFSetCreateMutable(kCFAllocatorSystemDefault, 0, &cb); - _CFSetSetCapacity(uniquingsets[3], 250); - - _flattenPlist(plist, objlist, objtable, uniquingsets); - - CFRelease(uniquingsets[0]); - CFRelease(uniquingsets[1]); - CFRelease(uniquingsets[2]); - CFRelease(uniquingsets[3]); - - cnt = CFArrayGetCount(objlist); - offsets = CFAllocatorAllocate(kCFAllocatorSystemDefault, cnt * sizeof(*offsets), 0); - - buf = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__CFBinaryPlistWriteBuffer), 0); - buf->stream = stream; - buf->streamIsData = (CFGetTypeID(stream) == CFDataGetTypeID()); - buf->written = 0; - buf->used = 0; - bufferWrite(buf, "bplist00", 8); // header - - memset(&trailer, 0, sizeof(trailer)); - trailer._numObjects = CFSwapInt64HostToBig(cnt); - trailer._topObject = 0; // true for this implementation - mask = ~(uint64_t)0; - while (cnt & mask) { - trailer._objectRefSize++; - mask = mask << 8; - } - - for (idx = 0; idx < cnt; idx++) { - CFPropertyListRef obj = CFArrayGetValueAtIndex(objlist, idx); - CFTypeID type = CFGetTypeID(obj); - offsets[idx] = buf->written + buf->used; - if (stringtype == type) { - CFIndex ret, count = CFStringGetLength(obj); - CFIndex needed; - uint8_t *bytes, buffer[1024]; - bytes = (count <= 1024) ? buffer : CFAllocatorAllocate(kCFAllocatorDefault, count, 0); - // presumption, believed to be true, is that ASCII encoding may need - // less bytes, but will not need greater, than the # of unichars - ret = CFStringGetBytes(obj, CFRangeMake(0, count), kCFStringEncodingASCII, 0, false, bytes, count, &needed); - if (ret == count) { - uint8_t marker = kCFBinaryPlistMarkerASCIIString | (needed < 15 ? needed : 0xf); - bufferWrite(buf, &marker, 1); - if (15 <= needed) { - _appendInt(buf, (uint64_t)needed); - } - bufferWrite(buf, bytes, needed); - } else { - UniChar *chars; - uint8_t marker = kCFBinaryPlistMarkerUnicode16String | (count < 15 ? count : 0xf); - bufferWrite(buf, &marker, 1); - if (15 <= count) { - _appendInt(buf, (uint64_t)count); - } - chars = CFAllocatorAllocate(kCFAllocatorDefault, count * sizeof(UniChar), 0); - CFStringGetCharacters(obj, CFRangeMake(0, count), chars); - for (idx2 = 0; idx2 < count; idx2++) { - chars[idx2] = CFSwapInt16HostToBig(chars[idx2]); - } - bufferWrite(buf, (uint8_t *)chars, count * sizeof(UniChar)); - CFAllocatorDeallocate(kCFAllocatorDefault, chars); - } - if (bytes != buffer) CFAllocatorDeallocate(kCFAllocatorDefault, bytes); - } else if (numbertype == type) { - uint8_t marker; - CFSwappedFloat64 swapped64; - CFSwappedFloat32 swapped32; - uint64_t bigint; - uint8_t *bytes; - CFIndex nbytes; - if (CFNumberIsFloatType(obj)) { - if (CFNumberGetByteSize(obj) <= (CFIndex)sizeof(float)) { - float v; - CFNumberGetValue(obj, kCFNumberFloat32Type, &v); - swapped32 = CFConvertFloat32HostToSwapped(v); - bytes = (uint8_t *)&swapped32; - nbytes = sizeof(float); - marker = kCFBinaryPlistMarkerReal | 2; - } else { - double v; - CFNumberGetValue(obj, kCFNumberFloat64Type, &v); - swapped64 = CFConvertFloat64HostToSwapped(v); - bytes = (uint8_t *)&swapped64; - nbytes = sizeof(double); - marker = kCFBinaryPlistMarkerReal | 3; - } - bufferWrite(buf, &marker, 1); - bufferWrite(buf, bytes, nbytes); - } else { - CFNumberGetValue(obj, kCFNumberSInt64Type, &bigint); - _appendInt(buf, bigint); - } - } else if (_CFKeyedArchiverUIDGetTypeID() == type) { - _appendUID(buf, (CFKeyedArchiverUIDRef)obj); - } else if (booltype == type) { - uint8_t marker = CFBooleanGetValue(obj) ? kCFBinaryPlistMarkerTrue : kCFBinaryPlistMarkerFalse; - bufferWrite(buf, &marker, 1); - } else if (datatype == type) { - CFIndex count = CFDataGetLength(obj); - uint8_t marker = kCFBinaryPlistMarkerData | (count < 15 ? count : 0xf); - bufferWrite(buf, &marker, 1); - if (15 <= count) { - _appendInt(buf, (uint64_t)count); - } - bufferWrite(buf, CFDataGetBytePtr(obj), count); - } else if (datetype == type) { - CFSwappedFloat64 swapped; - uint8_t marker = kCFBinaryPlistMarkerDate; - bufferWrite(buf, &marker, 1); - swapped = CFConvertFloat64HostToSwapped(CFDateGetAbsoluteTime(obj)); - bufferWrite(buf, (uint8_t *)&swapped, sizeof(swapped)); - } else if (dicttype == type) { - CFIndex count = CFDictionaryGetCount(obj); - CFPropertyListRef *list, buffer[512]; - uint8_t marker = kCFBinaryPlistMarkerDict | (count < 15 ? count : 0xf); - bufferWrite(buf, &marker, 1); - if (15 <= count) { - _appendInt(buf, (uint64_t)count); - } - list = (count <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, 2 * count * sizeof(CFTypeRef), 0); - CFDictionaryGetKeysAndValues(obj, list, list + count); - for (idx2 = 0; idx2 < 2 * count; idx2++) { - CFPropertyListRef value = list[idx2]; - uint32_t swapped = 0; - uint8_t *source = (uint8_t *)&swapped; - refnum = (uint32_t)CFDictionaryGetValue(objtable, value); - swapped = CFSwapInt32HostToBig(refnum); - bufferWrite(buf, source + sizeof(swapped) - trailer._objectRefSize, trailer._objectRefSize); - } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); - } else if (arraytype == type) { - CFIndex count = CFArrayGetCount(obj); - CFPropertyListRef *list, buffer[256]; - uint8_t marker = kCFBinaryPlistMarkerArray | (count < 15 ? count : 0xf); - bufferWrite(buf, &marker, 1); - if (15 <= count) { - _appendInt(buf, (uint64_t)count); - } - list = (count <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, count * sizeof(CFTypeRef), 0); - CFArrayGetValues(obj, CFRangeMake(0, count), list); - for (idx2 = 0; idx2 < count; idx2++) { - CFPropertyListRef value = list[idx2]; - uint32_t swapped = 0; - uint8_t *source = (uint8_t *)&swapped; - refnum = (uint32_t)CFDictionaryGetValue(objtable, value); - swapped = CFSwapInt32HostToBig(refnum); - bufferWrite(buf, source + sizeof(swapped) - trailer._objectRefSize, trailer._objectRefSize); - } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); - } else { - CFRelease(objtable); - CFRelease(objlist); - CFAllocatorDeallocate(kCFAllocatorSystemDefault, buf); - CFAllocatorDeallocate(kCFAllocatorSystemDefault, offsets); - return 0; - } - } - CFRelease(objtable); - CFRelease(objlist); - - length_so_far = buf->written + buf->used; - trailer._offsetTableOffset = CFSwapInt64HostToBig(length_so_far); - trailer._offsetIntSize = 0; - mask = ~(uint64_t)0; - while (length_so_far & mask) { - trailer._offsetIntSize++; - mask = mask << 8; - } - - for (idx = 0; idx < cnt; idx++) { - uint64_t swapped = CFSwapInt64HostToBig(offsets[idx]); - uint8_t *source = (uint8_t *)&swapped; - bufferWrite(buf, source + sizeof(*offsets) - trailer._offsetIntSize, trailer._offsetIntSize); - } - length_so_far += cnt * trailer._offsetIntSize; - - bufferWrite(buf, (uint8_t *)&trailer, sizeof(trailer)); - bufferFlush(buf); - length_so_far += sizeof(trailer); - CFAllocatorDeallocate(kCFAllocatorSystemDefault, buf); - CFAllocatorDeallocate(kCFAllocatorSystemDefault, offsets); - return (CFIndex)length_so_far; -} - -bool __CFBinaryPlistGetTopLevelInfo(const uint8_t *databytes, uint64_t datalen, uint8_t *marker, uint64_t *offset, CFBinaryPlistTrailer *trailer) { - const uint8_t *bytesptr; - CFBinaryPlistTrailer trail; - uint64_t off; - CFIndex idx; - - if ((CFTypeID)-1 == stringtype) { - stringtype = CFStringGetTypeID(); - datatype = CFDataGetTypeID(); - numbertype = CFNumberGetTypeID(); - booltype = CFBooleanGetTypeID(); - datetype = CFDateGetTypeID(); - dicttype = CFDictionaryGetTypeID(); - arraytype = CFArrayGetTypeID(); - } - if (!databytes || datalen < 8 || 0 != memcmp("bplist00", databytes, 8)) return false; - if (datalen < sizeof(trail) + 8 + 1) return false; - memmove(&trail, databytes + datalen - sizeof(trail), sizeof(trail)); - trail._numObjects = CFSwapInt64BigToHost(trail._numObjects); - trail._topObject = CFSwapInt64BigToHost(trail._topObject); - if (trail._numObjects < trail._topObject) return false; - trail._offsetTableOffset = CFSwapInt64BigToHost(trail._offsetTableOffset); - if (datalen < trail._offsetTableOffset + trail._numObjects * trail._offsetIntSize + sizeof(trail)) return false; - bytesptr = databytes + trail._offsetTableOffset + trail._topObject * trail._offsetIntSize; - off = 0; - for (idx = 0; idx < trail._offsetIntSize; idx++) { - off = (off << 8) + bytesptr[idx]; - } - if (trail._offsetTableOffset <= off) return false; - if (trailer) *trailer = trail; - if (offset) *offset = off; - if (marker) *marker = *(databytes + off); - return true; -} - -static bool _readInt(const uint8_t *ptr, uint64_t *bigint, const uint8_t **newptr) { - uint8_t marker; - CFIndex idx, cnt; - marker = *ptr++; - if ((marker & 0xf0) != kCFBinaryPlistMarkerInt) return false; - cnt = 1 << (marker & 0xf); - *bigint = 0; - for (idx = 0; idx < cnt; idx++) { - *bigint = (*bigint << 8) + *ptr++; - } - if (newptr) *newptr = ptr; - return true; -} - -static uint64_t _getOffsetOfRefAt(const uint8_t *databytes, const uint8_t *bytesptr, const CFBinaryPlistTrailer *trailer) { - uint64_t ref = 0, off = 0; - CFIndex idx; - for (idx = 0; idx < trailer->_objectRefSize; idx++) { - ref = (ref << 8) + bytesptr[idx]; - } - bytesptr = databytes + trailer->_offsetTableOffset + ref * trailer->_offsetIntSize; - for (idx = 0; idx < trailer->_offsetIntSize; idx++) { - off = (off << 8) + bytesptr[idx]; - } - return off; -} - -bool __CFBinaryPlistGetOffsetForValueFromArray(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFIndex idx, uint64_t *offset) { - const uint8_t *bytesptr; - uint8_t marker; - CFIndex cnt; - uint64_t off; - - marker = *(databytes + startOffset); - if ((marker & 0xf0) != kCFBinaryPlistMarkerArray) return false; - cnt = (marker & 0x0f); - if (cnt < 15 && cnt <= idx) return false; - bytesptr = databytes + startOffset + 1; - if (0xf == cnt) { - uint64_t bigint; - if (!_readInt(bytesptr, &bigint, &bytesptr)) return false; - if (INT_MAX < bigint) return false; - cnt = (CFIndex)bigint; - } - if (cnt <= idx) return false; - off = _getOffsetOfRefAt(databytes, bytesptr + idx * trailer->_objectRefSize, trailer); - if (datalen <= off) return false; - if (offset) *offset = off; - return true; -} - -bool __CFBinaryPlistGetOffsetForValueFromDictionary(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFTypeRef key, uint64_t *koffset, uint64_t *voffset) { - const uint8_t *refsptr, *bytesptr; - uint64_t off; - uint8_t marker; - CFTypeID keytype = CFGetTypeID(key); - CFIndex idx, keyn, cnt, cnt2; - - marker = *(databytes + startOffset); - if ((marker & 0xf0) != kCFBinaryPlistMarkerDict) return false; - cnt = (marker & 0x0f); - refsptr = databytes + startOffset + 1 + 0; - if (0xf == cnt) { - uint64_t bigint; - if (!_readInt(refsptr, &bigint, &refsptr)) return false; - if (INT_MAX < bigint) return false; - cnt = (CFIndex)bigint; - } - for (keyn = 0; keyn < cnt; keyn++) { - off = _getOffsetOfRefAt(databytes, refsptr, trailer); - if (datalen <= off) return false; - refsptr += trailer->_objectRefSize; - bytesptr = databytes + off; - marker = *bytesptr & 0xf0; - cnt2 = *bytesptr & 0x0f; - if (kCFBinaryPlistMarkerASCIIString == marker || kCFBinaryPlistMarkerUnicode16String == marker) { - CFStringInlineBuffer strbuf; - UniChar uchar; - if (keytype != stringtype) goto miss; - if (0xf == cnt2 && CFStringGetLength(key) < 15) goto miss; - bytesptr++; - if (0xf == cnt2) { - uint64_t bigint; - if (!_readInt(bytesptr, &bigint, &bytesptr)) return false; - if (INT_MAX < bigint) return false; - cnt2 = (CFIndex)bigint; - } - if (cnt2 != CFStringGetLength(key)) goto miss; - uchar = (kCFBinaryPlistMarkerASCIIString == marker) ? (UniChar)bytesptr[0] : (UniChar)(bytesptr[0] * 256 + bytesptr[1]); - if (uchar != CFStringGetCharacterAtIndex(key, 0)) goto miss; - bytesptr += (kCFBinaryPlistMarkerASCIIString == marker) ? 1 : 2; - CFStringInitInlineBuffer(key, &strbuf, CFRangeMake(0, cnt2)); - for (idx = 1; idx < cnt2; idx++) { - uchar = (kCFBinaryPlistMarkerASCIIString == marker) ? (UniChar)bytesptr[0] : (UniChar)(bytesptr[0] * 256 + bytesptr[1]); - if (uchar != __CFStringGetCharacterFromInlineBufferQuick(&strbuf, idx)) goto miss; - bytesptr += (kCFBinaryPlistMarkerASCIIString == marker) ? 1 : 2; - } - if (koffset) *koffset = off; - off = _getOffsetOfRefAt(databytes, refsptr + (cnt - 1) * trailer->_objectRefSize, trailer); - if (datalen <= off) return false; - if (voffset) *voffset = off; - return true; - } else { -//#warning the other primitive types should be allowed as keys in a binary plist dictionary, I think - return false; - } - miss: ; - } - return false; -} - -extern CFArrayRef _CFArrayCreate_ex(CFAllocatorRef allocator, bool mutable, const void **values, CFIndex numValues); - -extern CFDictionaryRef _CFDictionaryCreate_ex(CFAllocatorRef allocator, bool mutable, const void **keys, const void **values, CFIndex numValues); - -#if 0 -static bool _getUIDFromData(const uint8_t *datap, uint64_t *vp) { - int32_t idx, cnt; - uint8_t marker = *datap; - uint64_t bigint; - if ((marker & 0xf0) != kCFBinaryPlistMarkerUID) return false; - cnt = (marker & 0x0f) + 1; - datap++; - bigint = 0; - for (idx = 0; idx < cnt; idx++) { - bigint = (bigint << 8) + *datap++; - } - *vp = bigint; - return true; -} -#endif - -static bool _getFloatFromData(const uint8_t *datap, float *vp) { - CFSwappedFloat32 swapped32; - if (*datap != (kCFBinaryPlistMarkerReal | 2)) return false; - datap++; - memmove(&swapped32, datap, sizeof(swapped32)); - *vp = CFConvertFloat32SwappedToHost(swapped32); - return true; -} - -static bool _getDoubleFromData(const uint8_t *datap, double *vp) { - CFSwappedFloat64 swapped64; - if (*datap != (kCFBinaryPlistMarkerReal | 3)) return false; - datap++; - memmove(&swapped64, datap, sizeof(swapped64)); - *vp = CFConvertFloat64SwappedToHost(swapped64); - return true; -} - -bool __CFBinaryPlistCreateObject(const uint8_t *databytes, uint64_t datalen, uint64_t startOffset, const CFBinaryPlistTrailer *trailer, CFAllocatorRef allocator, CFOptionFlags mutabilityOption, CFMutableDictionaryRef objects, CFPropertyListRef *plist) { - const uint8_t *bytesptr; - uint64_t off; - uint8_t marker; - CFIndex idx, cnt; - uint64_t bigint; - UniChar *chars; - CFPropertyListRef *list, buffer[256]; - CFAllocatorRef listAllocator; - - if (objects) { - *plist = CFDictionaryGetValue(objects, (const void *)(intptr_t)startOffset); - if (*plist) { - CFRetain(*plist); - return true; - } - } - - marker = *(databytes + startOffset); - switch (marker & 0xf0) { - case kCFBinaryPlistMarkerNull: - switch (marker) { - case kCFBinaryPlistMarkerNull: - *plist = NULL; - return true; - case kCFBinaryPlistMarkerFalse: - *plist = CFRetain(kCFBooleanFalse); - return true; - case kCFBinaryPlistMarkerTrue: - *plist = CFRetain(kCFBooleanTrue); - return true; - } - return false; - case kCFBinaryPlistMarkerInt: - if (!_readInt(databytes + startOffset, &bigint, NULL)) return false; - *plist = CFNumberCreate(allocator, kCFNumberSInt64Type, &bigint); - if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist); - return (*plist) ? true : false; - case kCFBinaryPlistMarkerReal: - cnt = marker & 0x0f; - if (2 == cnt) { - float f; - _getFloatFromData(databytes + startOffset, &f); - *plist = CFNumberCreate(allocator, kCFNumberFloat32Type, &f); - if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist); - return (*plist) ? true : false; - } else if (3 == cnt) { - double d; - _getDoubleFromData(databytes + startOffset, &d); - *plist = CFNumberCreate(allocator, kCFNumberFloat64Type, &d); - if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist); - return (*plist) ? true : false; - } - return false; - case kCFBinaryPlistMarkerDate & 0xf0: { - CFSwappedFloat64 swapped64; - double d; - cnt = marker & 0x0f; - if (3 != cnt) return false; - memmove(&swapped64, databytes + startOffset + 1, sizeof(swapped64)); - d = CFConvertFloat64SwappedToHost(swapped64); - *plist = CFDateCreate(allocator, d); - if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist); - return (*plist) ? true : false; - } - case kCFBinaryPlistMarkerData: - cnt = marker & 0x0f; - bytesptr = databytes + startOffset + 1; - if (0xf == cnt) { - if (!_readInt(bytesptr, &bigint, &bytesptr)) return false; - if (INT_MAX < bigint) return false; - cnt = (CFIndex)bigint; - } - if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) { - *plist = CFDataCreateMutable(allocator, 0); - CFDataAppendBytes((CFMutableDataRef)*plist, bytesptr, cnt); - } else { - *plist = CFDataCreate(allocator, bytesptr, cnt); - } - if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist); - return (*plist) ? true : false; - case kCFBinaryPlistMarkerASCIIString: - cnt = marker & 0x0f; - bytesptr = databytes + startOffset + 1; - if (0xf == cnt) { - if (!_readInt(bytesptr, &bigint, &bytesptr)) return false; - if (INT_MAX < bigint) return false; - cnt = (CFIndex)bigint; - } - if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) { - CFStringRef str = CFStringCreateWithBytes(allocator, bytesptr, cnt, kCFStringEncodingASCII, false); - *plist = CFStringCreateMutableCopy(allocator, 0, str); - CFRelease(str); - } else { - *plist = CFStringCreateWithBytes(allocator, bytesptr, cnt, kCFStringEncodingASCII, false); - } - if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist); - return (*plist) ? true : false; - case kCFBinaryPlistMarkerUnicode16String: - cnt = marker & 0x0f; - bytesptr = databytes + startOffset + 1; - if (0xf == cnt) { - if (!_readInt(bytesptr, &bigint, &bytesptr)) return false; - if (INT_MAX < bigint) return false; - cnt = (CFIndex)bigint; - } - chars = CFAllocatorAllocate(allocator, cnt * sizeof(UniChar), 0); - memmove(chars, bytesptr, cnt * sizeof(UniChar)); - for (idx = 0; idx < cnt; idx++) { - chars[idx] = CFSwapInt16BigToHost(chars[idx]); - } - if (mutabilityOption == kCFPropertyListMutableContainersAndLeaves) { - CFStringRef str = CFStringCreateWithCharactersNoCopy(allocator, chars, cnt, allocator); - *plist = CFStringCreateMutableCopy(allocator, 0, str); - CFRelease(str); - } else { - *plist = CFStringCreateWithCharactersNoCopy(allocator, chars, cnt, allocator); - } - if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist); - return (*plist) ? true : false; - case kCFBinaryPlistMarkerUID: - cnt = (marker & 0x0f) + 1; - bytesptr = databytes + startOffset + 1; - bigint = 0; - for (idx = 0; idx < cnt; idx++) { - bigint = (bigint << 8) + *bytesptr++; - } - if (UINT_MAX < bigint) return false; - *plist = _CFKeyedArchiverUIDCreate(allocator, (uint32_t)bigint); - if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist); - return (*plist) ? true : false; - case kCFBinaryPlistMarkerArray: - cnt = marker & 0x0f; - bytesptr = databytes + startOffset + 1; - if (0xf == cnt) { - if (!_readInt(bytesptr, &bigint, &bytesptr)) return false; - if (INT_MAX < bigint) return false; - cnt = (CFIndex)bigint; - } - list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(CFPropertyListRef) * cnt, 0); - listAllocator = (list == buffer ? kCFAllocatorNull : kCFAllocatorSystemDefault); - for (idx = 0; idx < cnt; idx++) { - CFPropertyListRef pl; - off = _getOffsetOfRefAt(databytes, bytesptr, trailer); - if (datalen <= off) return false; - if (!__CFBinaryPlistCreateObject(databytes, datalen, off, trailer, allocator, mutabilityOption, objects, &pl)) { - if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - while (idx--) { - CFRelease(list[idx]); - } - } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); - return false; - } - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - CF_WRITE_BARRIER_BASE_ASSIGN(listAllocator, list, list[idx], CFMakeCollectable(pl)); - } else { - list[idx] = pl; - } - bytesptr += trailer->_objectRefSize; - } - *plist = _CFArrayCreate_ex(allocator, (mutabilityOption != kCFPropertyListImmutable), list, cnt); - if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist); - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); - return (*plist) ? true : false; - case kCFBinaryPlistMarkerDict: - cnt = marker & 0x0f; - bytesptr = databytes + startOffset + 1; - if (0xf == cnt) { - if (!_readInt(bytesptr, &bigint, &bytesptr)) return false; - if (INT_MAX < bigint) return false; - cnt = (CFIndex)bigint; - } - cnt *= 2; - list = (cnt <= 256) ? buffer : CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(CFPropertyListRef) * cnt, 0); - listAllocator = (list == buffer ? kCFAllocatorNull : kCFAllocatorSystemDefault); - for (idx = 0; idx < cnt; idx++) { - CFPropertyListRef pl; - off = _getOffsetOfRefAt(databytes, bytesptr, trailer); - if (datalen <= off) return false; - if (!__CFBinaryPlistCreateObject(databytes, datalen, off, trailer, allocator, mutabilityOption, objects, &pl)) { - if (!CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - while (idx--) { - CFRelease(list[idx]); - } - } - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); - return false; - } - if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) { - CF_WRITE_BARRIER_BASE_ASSIGN(listAllocator, list, list[idx], CFMakeCollectable(pl)); - } else { - list[idx] = pl; - } - bytesptr += trailer->_objectRefSize; - } - *plist = _CFDictionaryCreate_ex(allocator, (mutabilityOption != kCFPropertyListImmutable), list, list + cnt / 2, cnt / 2); - if (objects) CFDictionarySetValue(objects, (const void *)(intptr_t)startOffset, *plist); - if (list != buffer) CFAllocatorDeallocate(kCFAllocatorSystemDefault, list); - return (*plist) ? true : false; - } - return false; -} - -__private_extern__ bool __CFTryParseBinaryPlist(CFAllocatorRef allocator, CFDataRef data, CFOptionFlags option, CFPropertyListRef *plist, CFStringRef *errorString) { - uint8_t marker; - CFBinaryPlistTrailer trailer; - uint64_t offset; - CFPropertyListRef pl; - const uint8_t *databytes = CFDataGetBytePtr(data); - uint64_t datalen = CFDataGetLength(data); - - if (8 <= datalen && __CFBinaryPlistGetTopLevelInfo(databytes, datalen, &marker, &offset, &trailer)) { - if (__CFBinaryPlistCreateObject(databytes, datalen, offset, &trailer, allocator, option, NULL, &pl)) { - if (plist) *plist = pl; - } else { - if (plist) *plist = NULL; - if (errorString) *errorString = CFRetain(CFSTR("binary data is corrupt")); - } - return true; - } - return false; -} - diff --git a/README b/README index 8abe9a8..b6f4b2d 100644 --- a/README +++ b/README @@ -3,6 +3,9 @@ sometimes also known as "CF-lite", because it does not contain every facility available from the CoreFoundation framework in Mac OS X. +This CoreFoundation corresponds to the Mac OS X 10.5.2 version +of CF (CF-476.10) + The purpose of this README file is to share "what needs doing", "how to do things", and Q&A information about CF-lite, as this information is discovered. diff --git a/RunLoop.subproj/CFRunLoop.h b/RunLoop.subproj/CFRunLoop.h deleted file mode 100644 index 1b5a132..0000000 --- a/RunLoop.subproj/CFRunLoop.h +++ /dev/null @@ -1,435 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFRunLoop.h - Copyright (c) 1998-2005, Apple, Inc. All rights reserved. -*/ - -/*! - @header CFRunLoop - CFRunLoops monitor sources of input to a task and dispatch control - when sources become ready for processing. Examples of input sources - might include user input devices, network connections, periodic - or time-delayed events, and asynchronous callbacks. Input sources - are registered with a run loop, and when a run loop is "run", - callback functions associated with each source are called when - the sources have some activity. - - There is one run loop per thread. Each run loop has different - sets of input sources, called modes, which are named with strings. - A run loop is run -- in a named mode -- to have it monitor the - sources that have been registered in that mode, and the run loop - blocks there until something happens. Examples of modes include - the default mode, which a process would normally spend most of - its time in, and a modal panel mode, which might be run when - a modal panel is up, to restrict the set of input sources that - are allowed to "fire". This is not to the granularity of, for - example, what type of user input events are interesting, however. - That sort of finer-grained granularity is given by UI-level - frameworks with "get next event matching mask" or similar - functionality. - - The CFRunLoopSource type is an abstraction of input sources that - can be put in a run loop. An input source type would normally - define an API for creating and operating on instances of the type, - as if it were a separate entity from the run loop, then provide a - function to create a CFRunLoopSource for an instance. The - CFRunLoopSource can then be registered with the run loop, - represents the input source to the run loop, and acts as - intermediary between the run loop and the actual input source - type instance. Examples include CFMachPort and CFSocket. - - A CFRunLoopTimer is a specialization of run loop sources, a way - to generate either a one-shot delayed action, or a recurrent - action. - - While being run, a run loop goes through a cycle of activities. - Input sources are checked, timers which need firing are fired, - and then the run loop blocks, waiting for something to happen - (or in the case of timers, waiting for it to be time for - something to happen). When something does happen, the run loop - wakes up, processes the activity (usually by calling a callback - function for an input source), checks other sources, fires timers, - and goes back to sleep. And so on. CFRunLoopObservers can be - used to do processing at special points in this cycle. - - - - -*/ - -#if !defined(__COREFOUNDATION_CFRUNLOOP__) -#define __COREFOUNDATION_CFRUNLOOP__ 1 - -#include -#include -#include -#include -#if defined(__MACH__) - #include -#endif - -#if defined(__cplusplus) -extern "C" { -#endif - -/*! - @typedef CFRunLoopRef - This is the type of a reference to a run loop. -*/ -typedef struct __CFRunLoop * CFRunLoopRef; - -/*! - @typedef CFRunLoopSourceRef - This is the type of a reference to general run loop input sources. -*/ -typedef struct __CFRunLoopSource * CFRunLoopSourceRef; - -/*! - @typedef CFRunLoopObserverRef - This is the type of a reference to a run loop observer. -*/ -typedef struct __CFRunLoopObserver * CFRunLoopObserverRef; - -/*! - @typedef CFRunLoopTimerRef - This is the type of a reference to a run loop timer. -*/ -typedef struct __CFRunLoopTimer * CFRunLoopTimerRef; - -/* Reasons for CFRunLoopRunInMode() to Return */ -enum { - kCFRunLoopRunFinished = 1, - kCFRunLoopRunStopped = 2, - kCFRunLoopRunTimedOut = 3, - kCFRunLoopRunHandledSource = 4 -}; - -/* Run Loop Observer Activities */ -typedef enum { - kCFRunLoopEntry = (1 << 0), - kCFRunLoopBeforeTimers = (1 << 1), - kCFRunLoopBeforeSources = (1 << 2), - kCFRunLoopBeforeWaiting = (1 << 5), - kCFRunLoopAfterWaiting = (1 << 6), - kCFRunLoopExit = (1 << 7), - kCFRunLoopAllActivities = 0x0FFFFFFFU -} CFRunLoopActivity; - -CF_EXPORT const CFStringRef kCFRunLoopDefaultMode; -CF_EXPORT const CFStringRef kCFRunLoopCommonModes; - -/*! - @function CFRunLoopGetTypeID - Returns the type identifier of all CFRunLoop instances. -*/ -CF_EXPORT CFTypeID CFRunLoopGetTypeID(void); - -/*! - @function CFRunLoopGetCurrent - Returns the run loop for the current thread. There is exactly - one run loop per thread. -*/ -CF_EXPORT CFRunLoopRef CFRunLoopGetCurrent(void); - -/*! - @function CFRunLoopCopyCurrentMode - Returns the name of the mode in which the run loop is running. - NULL is returned if the run loop is not running. - @param rl The run loop for which the current mode should be - reported. -*/ -CF_EXPORT CFStringRef CFRunLoopCopyCurrentMode(CFRunLoopRef rl); - -/*! - @function CFRunLoopCopyAllModes - Returns an array of all the names of the modes known to the run - loop. - @param rl The run loop for which the mode list should be returned. -*/ -CF_EXPORT CFArrayRef CFRunLoopCopyAllModes(CFRunLoopRef rl); - -/*! - @function CFRunLoopAddCommonMode - Makes the named mode a "common mode" for the run loop. The set of - common modes are collectively accessed with the global constant - kCFRunLoopCommonModes. Input sources previously added to the - common modes are added to the new common mode. - @param rl The run loop for which the mode should be made common. - @param mode The name of the mode to mark as a common mode. -*/ -CF_EXPORT void CFRunLoopAddCommonMode(CFRunLoopRef rl, CFStringRef mode); - -/*! - @function CFRunLoopGetNextTimerFireDate - Returns the time at which the next timer will fire. - @param rl The run loop for which the next timer fire date should - be reported. - @param mode The name of the mode to query. -*/ -CF_EXPORT CFAbsoluteTime CFRunLoopGetNextTimerFireDate(CFRunLoopRef rl, CFStringRef mode); - - - - - -CF_EXPORT void CFRunLoopRun(void); -CF_EXPORT SInt32 CFRunLoopRunInMode(CFStringRef mode, CFTimeInterval seconds, Boolean returnAfterSourceHandled); -CF_EXPORT Boolean CFRunLoopIsWaiting(CFRunLoopRef rl); -CF_EXPORT void CFRunLoopWakeUp(CFRunLoopRef rl); -CF_EXPORT void CFRunLoopStop(CFRunLoopRef rl); - -CF_EXPORT Boolean CFRunLoopContainsSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef mode); -CF_EXPORT void CFRunLoopAddSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef mode); -CF_EXPORT void CFRunLoopRemoveSource(CFRunLoopRef rl, CFRunLoopSourceRef source, CFStringRef mode); - -CF_EXPORT Boolean CFRunLoopContainsObserver(CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef mode); -CF_EXPORT void CFRunLoopAddObserver(CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef mode); -CF_EXPORT void CFRunLoopRemoveObserver(CFRunLoopRef rl, CFRunLoopObserverRef observer, CFStringRef mode); - -CF_EXPORT Boolean CFRunLoopContainsTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode); -CF_EXPORT void CFRunLoopAddTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode); -CF_EXPORT void CFRunLoopRemoveTimer(CFRunLoopRef rl, CFRunLoopTimerRef timer, CFStringRef mode); - -/*! - @typedef CFRunLoopSourceContext - Structure containing the callbacks of a CFRunLoopSource. - @field version The version number of the structure type being - passed in as a parameter to the CFArray creation - functions. Valid version numbers are currently 0 and 1. - Version 0 sources are fairly generic, but may require a - bit more implementation, or may require a separate - thread as part of the implementation, for a complex - source. Version 1 sources are available on Mach and Windows, - and have performance advantages when the source type can - be described with this style. - @field info An arbitrary pointer to client-defined data, which - can be associated with the source at creation time, and - is passed to the callbacks. - @field retain The callback used to add a retain for the source on - the info pointer for the life of the source, and may be - used for temporary references the source needs to take. - This callback returns the actual info pointer to store in - the source, almost always just the pointer passed as the - parameter. - @field release The callback used to remove a retain previously - added for the source on the info pointer. - @field copyDescription The callback used to create a descriptive - string representation of the info pointer (or the data - pointed to by the info pointer) for debugging purposes. - This is used by the CFCopyDescription() function. - @field equal The callback used to compare the info pointers of - two sources, to determine equality of sources. - @field hash The callback used to compute a hash code for the info - pointer for the source. The source uses this hash code - information to produce its own hash code. - @field schedule For a version 0 source, this callback is called - whenever the source is added to a run loop mode. This - information is often needed to implement complex sources. - @field cancel For a version 0 source, this callback is called - whenever the source is removed from a run loop mode. This - information is often needed to implement complex sources. - @field getPort Defined in version 1 sources, this function returns - the Mach port or Windows HANDLE of a kernel object to - represent the source to the run loop. This function - must return the same result every time it is called, for the - lifetime of the source, and should be quick. - @field perform This callback is the workhorse of a run loop source. - It is called when the source needs to be "handled" or - processing is needed for input or conditions relating to - the source. For version 0 sources, this function is called - when the source has been marked "signaled" with the - CFRunLoopSourceSignal() function, and should do whatever - handling is required for the source. For a version 1 source - on Mach, this function is called when a Mach message arrives - on the source's Mach port, with the message, its - length, an allocator, and the source's info pointer. A - version 1 source performs whatever processing is required - on the Mach message, then can return a pointer to a Mach - message (or NULL if none) to be sent (usually this is a - "reply" message), which should be allocated with the - allocator (and will be deallocated by the run loop after - sending). For a version 1 source on Windows the function - is called when the kernel object is in the signaled state. -*/ -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 (*schedule)(void *info, CFRunLoopRef rl, CFStringRef mode); - void (*cancel)(void *info, CFRunLoopRef rl, CFStringRef mode); - void (*perform)(void *info); -} CFRunLoopSourceContext; - -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); -#if defined(__MACH__) - mach_port_t (*getPort)(void *info); - void * (*perform)(void *msg, CFIndex size, CFAllocatorRef allocator, void *info); -#else - HANDLE (*getPort)(void *info); - void (*perform)(void *info); -#endif -} CFRunLoopSourceContext1; - -/*! - @function CFRunLoopSourceGetTypeID - Returns the type identifier of all CFRunLoopSource instances. -*/ -CF_EXPORT CFTypeID CFRunLoopSourceGetTypeID(void); - -/*! - @function CFRunLoopSourceCreate - Creates a new run loop source with the given context. - @param allocator The CFAllocator which should be used to allocate - memory for the array and its storage for values. If this - reference is not a valid CFAllocator, the behavior is - undefined. - @param order On platforms which support it, for source versions - which support it, this parameter determines the order in - which the sources which are ready to be processed are - handled. A lower order number causes processing before - higher order number sources. It is inadvisable to depend - on the order number for any architectural or design aspect - of code. In the absence of any reason to do otherwise, - zero should be used. - @param context A pointer to the context structure for the source. -*/ -CF_EXPORT CFRunLoopSourceRef CFRunLoopSourceCreate(CFAllocatorRef allocator, CFIndex order, CFRunLoopSourceContext *context); - -/*! - @function CFRunLoopSourceGetOrder - Returns the ordering parameter of the run loop source. - @param source The run loop source for which the order number - should be returned. -*/ -CF_EXPORT CFIndex CFRunLoopSourceGetOrder(CFRunLoopSourceRef source); - -/*! - @function CFRunLoopSourceInvalidate - Invalidates the run loop source. The run loop source is never - performed again after it becomes invalid, and will automatically - be removed from any run loops and modes which contain it. The - source is not destroyed by this operation, however -- the memory - is still valid; only the release of all references on the source - through the reference counting system can do that. But note, that - if the only retains on the source were held by run loops, those - retains may all be released by the time this function returns, - and the source may actually be destroyed through that process. - @param source The run loop source which should be invalidated. -*/ -CF_EXPORT void CFRunLoopSourceInvalidate(CFRunLoopSourceRef source); - -/*! - @function CFRunLoopSourceIsValid - Reports whether or not the source is valid. - @param source The run loop source for which the validity should - be returned. -*/ -CF_EXPORT Boolean CFRunLoopSourceIsValid(CFRunLoopSourceRef source); - -/*! - @function CFRunLoopSourceGetContext - Fills the memory pointed to by the context parameter with the - context structure of the source. - @param source The run loop source for which the context structure - should be returned. - @param context A pointer to a context structure to be filled. -*/ -CF_EXPORT void CFRunLoopSourceGetContext(CFRunLoopSourceRef source, CFRunLoopSourceContext *context); - -/*! - @function CFRunLoopSourceSignal - Marks the source as signalled, ready for handling by the run loop. - Has no effect on version 1 sources, which are automatically - handled when Mach messages for them come in. - @param source The run loop source which should be signalled. -*/ -CF_EXPORT void CFRunLoopSourceSignal(CFRunLoopSourceRef source); - -typedef struct { - CFIndex version; - void * info; - const void *(*retain)(const void *info); - void (*release)(const void *info); - CFStringRef (*copyDescription)(const void *info); -} CFRunLoopObserverContext; - -typedef void (*CFRunLoopObserverCallBack)(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info); - -/*! - @function CFRunLoopObserverGetTypeID - Returns the type identifier of all CFRunLoopObserver instances. -*/ -CF_EXPORT CFTypeID CFRunLoopObserverGetTypeID(void); - -CF_EXPORT CFRunLoopObserverRef CFRunLoopObserverCreate(CFAllocatorRef allocator, CFOptionFlags activities, Boolean repeats, CFIndex order, CFRunLoopObserverCallBack callout, CFRunLoopObserverContext *context); - -CF_EXPORT CFOptionFlags CFRunLoopObserverGetActivities(CFRunLoopObserverRef observer); -CF_EXPORT Boolean CFRunLoopObserverDoesRepeat(CFRunLoopObserverRef observer); -CF_EXPORT CFIndex CFRunLoopObserverGetOrder(CFRunLoopObserverRef observer); -CF_EXPORT void CFRunLoopObserverInvalidate(CFRunLoopObserverRef observer); -CF_EXPORT Boolean CFRunLoopObserverIsValid(CFRunLoopObserverRef observer); -CF_EXPORT void CFRunLoopObserverGetContext(CFRunLoopObserverRef observer, CFRunLoopObserverContext *context); - -typedef struct { - CFIndex version; - void * info; - const void *(*retain)(const void *info); - void (*release)(const void *info); - CFStringRef (*copyDescription)(const void *info); -} CFRunLoopTimerContext; - -typedef void (*CFRunLoopTimerCallBack)(CFRunLoopTimerRef timer, void *info); - -/*! - @function CFRunLoopTimerGetTypeID - Returns the type identifier of all CFRunLoopTimer instances. -*/ -CF_EXPORT CFTypeID CFRunLoopTimerGetTypeID(void); - -CF_EXPORT CFRunLoopTimerRef CFRunLoopTimerCreate(CFAllocatorRef allocator, CFAbsoluteTime fireDate, CFTimeInterval interval, CFOptionFlags flags, CFIndex order, CFRunLoopTimerCallBack callout, CFRunLoopTimerContext *context); -CF_EXPORT CFAbsoluteTime CFRunLoopTimerGetNextFireDate(CFRunLoopTimerRef timer); -CF_EXPORT void CFRunLoopTimerSetNextFireDate(CFRunLoopTimerRef timer, CFAbsoluteTime fireDate); -CF_EXPORT CFTimeInterval CFRunLoopTimerGetInterval(CFRunLoopTimerRef timer); -CF_EXPORT Boolean CFRunLoopTimerDoesRepeat(CFRunLoopTimerRef timer); -CF_EXPORT CFIndex CFRunLoopTimerGetOrder(CFRunLoopTimerRef timer); -CF_EXPORT void CFRunLoopTimerInvalidate(CFRunLoopTimerRef timer); -CF_EXPORT Boolean CFRunLoopTimerIsValid(CFRunLoopTimerRef timer); -CF_EXPORT void CFRunLoopTimerGetContext(CFRunLoopTimerRef timer, CFRunLoopTimerContext *context); - -#if defined(__cplusplus) -} -#endif - -#endif /* ! __COREFOUNDATION_CFRUNLOOP__ */ - diff --git a/RunLoop.subproj/CFRunLoopPriv.h b/RunLoop.subproj/CFRunLoopPriv.h deleted file mode 100644 index 60a7a78..0000000 --- a/RunLoop.subproj/CFRunLoopPriv.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* -*/ - -#include -#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). - diff --git a/Stream.subproj/CFStream.h b/Stream.subproj/CFStream.h deleted file mode 100644 index 471deaf..0000000 --- a/Stream.subproj/CFStream.h +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFStream.h - Copyright (c) 2000-2005, Apple, Inc. All rights reserved. -*/ - -#if !defined(__COREFOUNDATION_CFSTREAM__) -#define __COREFOUNDATION_CFSTREAM__ 1 - -#include -#include -#include -#include -#include -#include - -#if defined(__cplusplus) -extern "C" { -#endif - -typedef enum { - kCFStreamStatusNotOpen = 0, - kCFStreamStatusOpening, /* open is in-progress */ - kCFStreamStatusOpen, - kCFStreamStatusReading, - kCFStreamStatusWriting, - kCFStreamStatusAtEnd, /* no further bytes can be read/written */ - kCFStreamStatusClosed, - kCFStreamStatusError -} CFStreamStatus; - -typedef enum { - kCFStreamErrorDomainCustom = -1, /* custom to the kind of stream in question */ - kCFStreamErrorDomainPOSIX = 1, /* POSIX errno; interpret using */ - kCFStreamErrorDomainMacOSStatus /* OSStatus type from Carbon APIs; interpret using */ -} CFStreamErrorDomain; - -typedef struct { - CFStreamErrorDomain domain; - SInt32 error; -} CFStreamError; - -typedef enum { - kCFStreamEventNone = 0, - kCFStreamEventOpenCompleted = 1, - kCFStreamEventHasBytesAvailable = 2, - kCFStreamEventCanAcceptBytes = 4, - kCFStreamEventErrorOccurred = 8, - kCFStreamEventEndEncountered = 16 -} CFStreamEventType; - -typedef struct { - CFIndex version; - void *info; - void *(*retain)(void *info); - void (*release)(void *info); - CFStringRef (*copyDescription)(void *info); -} CFStreamClientContext; - -typedef struct __CFReadStream * CFReadStreamRef; -typedef struct __CFWriteStream * CFWriteStreamRef; - -typedef void (*CFReadStreamClientCallBack)(CFReadStreamRef stream, CFStreamEventType type, void *clientCallBackInfo); -typedef void (*CFWriteStreamClientCallBack)(CFWriteStreamRef stream, CFStreamEventType type, void *clientCallBackInfo); - -CF_EXPORT -CFTypeID CFReadStreamGetTypeID(void); -CF_EXPORT -CFTypeID CFWriteStreamGetTypeID(void); - -/* Memory streams */ - -/* Value will be a CFData containing all bytes thusfar written; used to recover the data written to a memory write stream. */ -CF_EXPORT -const CFStringRef kCFStreamPropertyDataWritten; - -/* Pass kCFAllocatorNull for bytesDeallocator to prevent CFReadStream from deallocating bytes; otherwise, CFReadStream will deallocate bytes when the stream is destroyed */ -CF_EXPORT -CFReadStreamRef CFReadStreamCreateWithBytesNoCopy(CFAllocatorRef alloc, const UInt8 *bytes, CFIndex length, CFAllocatorRef bytesDeallocator); - -/* The stream writes into the buffer given; when bufferCapacity is exhausted, the stream is exhausted (status becomes kCFStreamStatusAtEnd) */ -CF_EXPORT -CFWriteStreamRef CFWriteStreamCreateWithBuffer(CFAllocatorRef alloc, UInt8 *buffer, CFIndex bufferCapacity); - -/* New buffers are allocated from bufferAllocator as bytes are written to the stream. At any point, you can recover the bytes thusfar written by asking for the property kCFStreamPropertyDataWritten, above */ -CF_EXPORT -CFWriteStreamRef CFWriteStreamCreateWithAllocatedBuffers(CFAllocatorRef alloc, CFAllocatorRef bufferAllocator); - -/* File streams */ -CF_EXPORT -CFReadStreamRef CFReadStreamCreateWithFile(CFAllocatorRef alloc, CFURLRef fileURL); -CF_EXPORT -CFWriteStreamRef CFWriteStreamCreateWithFile(CFAllocatorRef alloc, CFURLRef fileURL); - -#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 - -#endif - -/* Socket stream properties */ - -/* Value will be a CFData containing the native handle */ -CF_EXPORT -const CFStringRef kCFStreamPropertySocketNativeHandle; - -/* Value will be a CFString, or NULL if unknown */ -CF_EXPORT -const CFStringRef kCFStreamPropertySocketRemoteHostName; - -/* Value will be a CFNumber, or NULL if unknown */ -CF_EXPORT -const CFStringRef kCFStreamPropertySocketRemotePortNumber; - -/* Socket streams; the returned streams are paired such that they use the same socket; pass NULL if you want only the read stream or the write stream */ -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 */ -CF_EXPORT -CFStreamStatus CFReadStreamGetStatus(CFReadStreamRef stream); -CF_EXPORT -CFStreamStatus CFWriteStreamGetStatus(CFWriteStreamRef stream); - -/* 0 is returned if no error has occurred. errorDomain specifies the domain - in which the error code should be interpretted; pass NULL if you are not - interested. */ -CF_EXPORT -CFStreamError CFReadStreamGetError(CFReadStreamRef stream); -CF_EXPORT -CFStreamError CFWriteStreamGetError(CFWriteStreamRef stream); - -/* 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 - return TRUE; listen to the run loop source to find out when the open completes - and whether it was successful, or poll using CFRead/WriteStreamGetStatus(), waiting - for a status of kCFStreamStatusOpen or kCFStreamStatusError. */ -CF_EXPORT -Boolean CFReadStreamOpen(CFReadStreamRef stream); -CF_EXPORT -Boolean CFWriteStreamOpen(CFWriteStreamRef stream); - -/* Terminates the flow of bytes; releases any system resources required by the - stream. The stream may not fail to close. You may call CFStreamClose() to - effectively abort a stream. */ -CF_EXPORT -void CFReadStreamClose(CFReadStreamRef stream); -CF_EXPORT -void CFWriteStreamClose(CFWriteStreamRef stream); - -/* Whether there is data currently available for reading; returns TRUE if it's - impossible to tell without trying */ -CF_EXPORT -Boolean CFReadStreamHasBytesAvailable(CFReadStreamRef stream); - -/* Returns the number of bytes read, or -1 if an error occurs preventing any - bytes from being read, or 0 if the stream's end was encountered. - It is an error to try and read from a stream that hasn't been opened first. - This call will block until at least one byte is available; it will NOT block - until the entire buffer can be filled. To avoid blocking, either poll using - CFReadStreamHasBytesAvailable() or use the run loop and listen for the - kCFStreamCanRead event for notification of data available. */ -CF_EXPORT -CFIndex CFReadStreamRead(CFReadStreamRef stream, UInt8 *buffer, CFIndex bufferLength); - -/* Returns a pointer to an internal buffer if possible (setting *numBytesRead - to the length of the returned buffer), otherwise returns NULL; guaranteed - to return in O(1). Bytes returned in the buffer are considered read from - the stream; if maxBytesToRead is greater than 0, not more than maxBytesToRead - will be returned. If maxBytesToRead is less than or equal to zero, as many bytes - as are readily available will be returned. The returned buffer is good only - until the next stream operation called on the stream. Caller should neither - change the contents of the returned buffer nor attempt to deallocate the buffer; - it is still owned by the stream. */ -CF_EXPORT -const UInt8 *CFReadStreamGetBuffer(CFReadStreamRef stream, CFIndex maxBytesToRead, CFIndex *numBytesRead); - -/* Whether the stream can currently be written to without blocking; - returns TRUE if it's impossible to tell without trying */ -CF_EXPORT -Boolean CFWriteStreamCanAcceptBytes(CFWriteStreamRef stream); - -/* Returns the number of bytes successfully written, -1 if an error has - occurred, or 0 if the stream has been filled to capacity (for fixed-length - streams). If the stream is not full, this call will block until at least - one byte is written. To avoid blocking, either poll via CFWriteStreamCanAcceptBytes - or use the run loop and listen for the kCFStreamCanWrite event. */ -CF_EXPORT -CFIndex CFWriteStreamWrite(CFWriteStreamRef stream, const UInt8 *buffer, CFIndex bufferLength); - -/* Particular streams can name properties and assign meanings to them; you - access these properties through the following calls. A property is any interesting - information about the stream other than the data being transmitted itself. - Examples include the headers from an HTTP transmission, or the expected - number of bytes, or permission information, etc. Properties that can be set - configure the behavior of the stream, and may only be settable at particular times - (like before the stream has been opened). See the documentation for particular - properties to determine their get- and set-ability. */ -CF_EXPORT -CFTypeRef CFReadStreamCopyProperty(CFReadStreamRef stream, CFStringRef propertyName); -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 - per stream is allowed; registering a new client replaces the previous one. - - Once you have set a client, you need to schedule a run loop on which that client - can be notified. You may schedule multiple run loops (for instance, if you are - using a thread pool). The client callback will be triggered via one of the scheduled - run loops; It is the caller's responsibility to ensure that at least one of the - scheduled run loops is being run. - - NOTE: not all streams provide these notifications. If a stream does not support - asynchronous notification, CFStreamSetClient() will return NO; typically, such - streams will never block for device I/O (e.g. a stream on memory) -*/ - -CF_EXPORT -Boolean CFReadStreamSetClient(CFReadStreamRef stream, CFOptionFlags streamEvents, CFReadStreamClientCallBack clientCB, CFStreamClientContext *clientContext); -CF_EXPORT -Boolean CFWriteStreamSetClient(CFWriteStreamRef stream, CFOptionFlags streamEvents, CFWriteStreamClientCallBack clientCB, CFStreamClientContext *clientContext); - -CF_EXPORT -void CFReadStreamScheduleWithRunLoop(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode); -CF_EXPORT -void CFWriteStreamScheduleWithRunLoop(CFWriteStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode); - -CF_EXPORT -void CFReadStreamUnscheduleFromRunLoop(CFReadStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode); -CF_EXPORT -void CFWriteStreamUnscheduleFromRunLoop(CFWriteStreamRef stream, CFRunLoopRef runLoop, CFStringRef runLoopMode); - -#if defined(__cplusplus) -} -#endif - -#endif /* ! __COREFOUNDATION_CFSTREAM__ */ diff --git a/StringEncodings.subproj/CFUnicodeDecomposition.c b/StringEncodings.subproj/CFUnicodeDecomposition.c deleted file mode 100644 index 8d6f315..0000000 --- a/StringEncodings.subproj/CFUnicodeDecomposition.c +++ /dev/null @@ -1,517 +0,0 @@ -/* - * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. - * - * @APPLE_LICENSE_HEADER_START@ - * - * This file contains Original Code and/or Modifications of Original Code - * as defined in and that are subject to the Apple Public Source License - * Version 2.0 (the 'License'). You may not use this file except in - * compliance with the License. Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. - * - * The Original Code and all software distributed under the License are - * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER - * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and - * limitations under the License. - * - * @APPLE_LICENSE_HEADER_END@ - */ -/* CFUnicodeDecomposition.c - Copyright 1999-2002, Apple, Inc. All rights reserved. - Responsibility: Aki Inoue -*/ - -#include -#include -#include -#include -#include -#include "CFInternal.h" -#include "CFUniCharPriv.h" - -// Canonical Decomposition -static UTF32Char *__CFUniCharDecompositionTable = NULL; -static uint32_t __CFUniCharDecompositionTableLength = 0; -static UTF32Char *__CFUniCharMultipleDecompositionTable = NULL; - -static const uint8_t *__CFUniCharDecomposableBitmapForBMP = NULL; -static const uint8_t *__CFUniCharHFSPlusDecomposableBitmapForBMP = NULL; -static const uint8_t *__CFUniCharNonBaseBitmapForBMP = NULL; - -static CFSpinLock_t __CFUniCharDecompositionTableLock = 0; - -static const uint8_t **__CFUniCharCombiningPriorityTable = NULL; -static uint8_t __CFUniCharCombiningPriorityTableNumPlane = 0; - -static void __CFUniCharLoadDecompositionTable(void) { - - __CFSpinLock(&__CFUniCharDecompositionTableLock); - - if (NULL == __CFUniCharDecompositionTable) { - const void *bytes = CFUniCharGetMappingData(kCFUniCharCanonicalDecompMapping); - - if (NULL == bytes) { - __CFSpinUnlock(&__CFUniCharDecompositionTableLock); - return; - } - - __CFUniCharDecompositionTableLength = *(((uint32_t *)bytes)++); - __CFUniCharDecompositionTable = (UTF32Char *)bytes; - __CFUniCharMultipleDecompositionTable = (UTF32Char *)((intptr_t)bytes + __CFUniCharDecompositionTableLength); - - __CFUniCharDecompositionTableLength /= (sizeof(uint32_t) * 2); - __CFUniCharDecomposableBitmapForBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet, 0); - __CFUniCharHFSPlusDecomposableBitmapForBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharHFSPlusDecomposableCharacterSet, 0); - __CFUniCharNonBaseBitmapForBMP = CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, 0); - } - - __CFSpinUnlock(&__CFUniCharDecompositionTableLock); -} - -static CFSpinLock_t __CFUniCharCompatibilityDecompositionTableLock = 0; -static UTF32Char *__CFUniCharCompatibilityDecompositionTable = NULL; -static uint32_t __CFUniCharCompatibilityDecompositionTableLength = 0; -static UTF32Char *__CFUniCharCompatibilityMultipleDecompositionTable = NULL; - -static void __CFUniCharLoadCompatibilityDecompositionTable(void) { - - __CFSpinLock(&__CFUniCharCompatibilityDecompositionTableLock); - - if (NULL == __CFUniCharCompatibilityDecompositionTable) { - const void *bytes = CFUniCharGetMappingData(kCFUniCharCompatibilityDecompMapping); - - if (NULL == bytes) { - __CFSpinUnlock(&__CFUniCharCompatibilityDecompositionTableLock); - return; - } - - __CFUniCharCompatibilityDecompositionTableLength = *(((uint32_t *)bytes)++); - __CFUniCharCompatibilityDecompositionTable = (UTF32Char *)bytes; - __CFUniCharCompatibilityMultipleDecompositionTable = (UTF32Char *)((intptr_t)bytes + __CFUniCharCompatibilityDecompositionTableLength); - - __CFUniCharCompatibilityDecompositionTableLength /= (sizeof(uint32_t) * 2); - } - - __CFSpinUnlock(&__CFUniCharCompatibilityDecompositionTableLock); -} - -CF_INLINE bool __CFUniCharIsDecomposableCharacterWithFlag(UTF32Char character, bool isHFSPlus) { - return CFUniCharIsMemberOfBitmap(character, (character < 0x10000 ? (isHFSPlus ? __CFUniCharHFSPlusDecomposableBitmapForBMP : __CFUniCharDecomposableBitmapForBMP) : CFUniCharGetBitmapPtrForPlane(kCFUniCharCanonicalDecomposableCharacterSet, ((character >> 16) & 0xFF)))); -} - -CF_INLINE bool __CFUniCharIsNonBaseCharacter(UTF32Char character) { - return CFUniCharIsMemberOfBitmap(character, (character < 0x10000 ? __CFUniCharNonBaseBitmapForBMP : CFUniCharGetBitmapPtrForPlane(kCFUniCharNonBaseCharacterSet, ((character >> 16) & 0xFF)))); -} - -typedef struct { - uint32_t _key; - uint32_t _value; -} __CFUniCharDecomposeMappings; - -static uint32_t __CFUniCharGetMappedValue(const __CFUniCharDecomposeMappings *theTable, uint32_t numElem, UTF32Char character) { - const __CFUniCharDecomposeMappings *p, *q, *divider; - - if ((character < theTable[0]._key) || (character > theTable[numElem-1]._key)) { - return 0; - } - p = theTable; - q = p + (numElem-1); - while (p <= q) { - divider = p + ((q - p) >> 1); /* divide by 2 */ - if (character < divider->_key) { q = divider - 1; } - else if (character > divider->_key) { p = divider + 1; } - else { return divider->_value; } - } - return 0; -} - -#define __CFUniCharGetCombiningPropertyForCharacter(character) CFUniCharGetCombiningPropertyForCharacter(character, (((character) >> 16) < __CFUniCharCombiningPriorityTableNumPlane ? __CFUniCharCombiningPriorityTable[(character) >> 16] : NULL)) - -static void __CFUniCharPrioritySort(UTF32Char *characters, uint32_t length) { - uint32_t p1, p2; - UTF32Char *ch1, *ch2; - bool changes = true; - UTF32Char *end = characters + length; - - if (NULL == __CFUniCharCombiningPriorityTable) { - __CFSpinLock(&__CFUniCharDecompositionTableLock); - if (NULL == __CFUniCharCombiningPriorityTable) { - uint32_t numPlanes = CFUniCharGetNumberOfPlanesForUnicodePropertyData(kCFUniCharCombiningProperty); - uint32_t idx; - - __CFUniCharCombiningPriorityTable = (const uint8_t **)CFAllocatorAllocate(NULL, sizeof(uint8_t *) * numPlanes, 0); - for (idx = 0;idx < numPlanes;idx++) __CFUniCharCombiningPriorityTable[idx] = CFUniCharGetUnicodePropertyDataForPlane(kCFUniCharCombiningProperty, idx); - __CFUniCharCombiningPriorityTableNumPlane = numPlanes; - } - __CFSpinUnlock(&__CFUniCharDecompositionTableLock); - } - - if (length < 2) return; - - do { - changes = false; - ch1 = characters; ch2 = characters + 1; - p2 = __CFUniCharGetCombiningPropertyForCharacter(*ch1); - while (ch2 < end) { - p1 = p2; p2 = __CFUniCharGetCombiningPropertyForCharacter(*ch2); - if (p1 > p2) { - UTF32Char tmp = *ch1; *ch1 = *ch2; *ch2 = tmp; - changes = true; - } - ++ch1; ++ch2; - } - } while (changes); -} - -static uint32_t __CFUniCharRecursivelyDecomposeCharacter(UTF32Char character, UTF32Char *convertedChars, uint32_t maxBufferLength) { - uint32_t value = __CFUniCharGetMappedValue((const __CFUniCharDecomposeMappings *)__CFUniCharDecompositionTable, __CFUniCharDecompositionTableLength, character); - uint32_t length = CFUniCharConvertFlagToCount(value); - UTF32Char firstChar = value & 0xFFFFFF; - UTF32Char *mappings = (length > 1 ? __CFUniCharMultipleDecompositionTable + firstChar : &firstChar); - uint32_t usedLength = 0; - - if (maxBufferLength < length) return 0; - - if (value & kCFUniCharRecursiveDecompositionFlag) { - usedLength = __CFUniCharRecursivelyDecomposeCharacter(*mappings, convertedChars, maxBufferLength - length); - - --length; // Decrement for the first char - if (!usedLength || usedLength + length > maxBufferLength) return 0; - ++mappings; - convertedChars += usedLength; - } - - usedLength += length; - - while (length--) *(convertedChars++) = *(mappings++); - - return usedLength; -} - -#define HANGUL_SBASE 0xAC00 -#define HANGUL_LBASE 0x1100 -#define HANGUL_VBASE 0x1161 -#define HANGUL_TBASE 0x11A7 -#define HANGUL_SCOUNT 11172 -#define HANGUL_LCOUNT 19 -#define HANGUL_VCOUNT 21 -#define HANGUL_TCOUNT 28 -#define HANGUL_NCOUNT (HANGUL_VCOUNT * HANGUL_TCOUNT) - -uint32_t CFUniCharDecomposeCharacter(UTF32Char character, UTF32Char *convertedChars, uint32_t maxBufferLength) { - if (NULL == __CFUniCharDecompositionTable) __CFUniCharLoadDecompositionTable(); - if (character >= HANGUL_SBASE && character <= (HANGUL_SBASE + HANGUL_SCOUNT)) { - uint32_t length; - - character -= HANGUL_SBASE; - - length = (character % HANGUL_TCOUNT ? 3 : 2); - - if (maxBufferLength < length) return 0; - - *(convertedChars++) = character / HANGUL_NCOUNT + HANGUL_LBASE; - *(convertedChars++) = (character % HANGUL_NCOUNT) / HANGUL_TCOUNT + HANGUL_VBASE; - if (length > 2) *convertedChars = (character % HANGUL_TCOUNT) + HANGUL_TBASE; - return length; - } else { - return __CFUniCharRecursivelyDecomposeCharacter(character, convertedChars, maxBufferLength); - } -} - -#define MAX_BUFFER_LENGTH (32) -bool CFUniCharDecompose(const UTF16Char *src, uint32_t length, uint32_t *consumedLength, void *dst, uint32_t maxLength, uint32_t *filledLength, bool needToReorder, uint32_t dstFormat, bool isHFSPlus) { - uint32_t usedLength = 0; - uint32_t originalLength = length; - UTF32Char buffer[MAX_BUFFER_LENGTH]; - UTF32Char *decompBuffer = buffer; - uint32_t decompBufferLen = MAX_BUFFER_LENGTH; - UTF32Char currentChar; - uint32_t idx; - bool isDecomp = false; - bool isNonBase = false; - - if (NULL == __CFUniCharDecompositionTable) __CFUniCharLoadDecompositionTable(); - - while (length > 0) { - currentChar = *(src++); - --length; - - if (currentChar < 0x80) { - if (maxLength) { - if (usedLength < maxLength) { - switch (dstFormat) { - case kCFUniCharUTF8Format: *(((uint8_t *)dst)++) = currentChar; break; - case kCFUniCharUTF16Format: *(((UTF16Char *)dst)++) = currentChar; break; - case kCFUniCharUTF32Format: *(((UTF32Char *)dst)++) = currentChar; break; - } - } else { - if (decompBuffer != buffer) CFAllocatorDeallocate(NULL, decompBuffer); - if (consumedLength) *consumedLength = originalLength - length - 1; - if (filledLength) *filledLength = usedLength; - return false; - } - } - ++usedLength; - continue; - } - - if (CFUniCharIsSurrogateHighCharacter(currentChar) && (length > 0) && CFUniCharIsSurrogateLowCharacter(*src)) { - currentChar = CFUniCharGetLongCharacterForSurrogatePair(currentChar, *(src++)); - --length; - } - - isDecomp = __CFUniCharIsDecomposableCharacterWithFlag(currentChar, isHFSPlus); - isNonBase = (needToReorder && __CFUniCharIsNonBaseCharacter(currentChar)); - - if (!isDecomp || isNonBase) { - if (isNonBase) { - if (isDecomp) { - idx = CFUniCharDecomposeCharacter(currentChar, decompBuffer, MAX_BUFFER_LENGTH); - } else { - idx = 1; - *decompBuffer = currentChar; - } - - while (length > 0) { - if (CFUniCharIsSurrogateHighCharacter(*src) && ((length + 1) > 0) && CFUniCharIsSurrogateLowCharacter(*(src + 1))) { - currentChar = CFUniCharGetLongCharacterForSurrogatePair(*src, *(src + 1)); - } else { - currentChar = *src; - } - if (__CFUniCharIsNonBaseCharacter(currentChar)) { - if (currentChar > 0xFFFF) { // Non-BMP - length -= 2; - src += 2; - } else { - --length; - ++src; - } - if ((idx + 1) >= decompBufferLen) { - UTF32Char *newBuffer; - - decompBufferLen += MAX_BUFFER_LENGTH; - newBuffer = (UTF32Char *)CFAllocatorAllocate(NULL, sizeof(UTF32Char) * decompBufferLen, 0); - memmove(newBuffer, decompBuffer, (decompBufferLen - MAX_BUFFER_LENGTH) * sizeof(UTF32Char)); - if (decompBuffer != buffer) CFAllocatorDeallocate(NULL, decompBuffer); - decompBuffer = newBuffer; - } - - if (__CFUniCharIsDecomposableCharacterWithFlag(currentChar, isHFSPlus)) { // Vietnamese accent, etc. - idx += CFUniCharDecomposeCharacter(currentChar, decompBuffer + idx, MAX_BUFFER_LENGTH - idx); - } else { - decompBuffer[idx++] = currentChar; - } - } else { - break; - } - } - - if (idx > 1) { // Need to reorder - __CFUniCharPrioritySort(decompBuffer, idx); - } - if (!CFUniCharFillDestinationBuffer(decompBuffer, idx, &dst, maxLength, &usedLength, dstFormat)) { - if (decompBuffer != buffer) CFAllocatorDeallocate(NULL, decompBuffer); - if (consumedLength) *consumedLength = originalLength - length; - if (filledLength) *filledLength = usedLength; - return false; - } - } else { - if (dstFormat == kCFUniCharUTF32Format) { - ++usedLength; - if (maxLength) { - if (usedLength > maxLength) { - if (decompBuffer != buffer) CFAllocatorDeallocate(NULL, decompBuffer); - if (consumedLength) *consumedLength = originalLength - length; - if (filledLength) *filledLength = usedLength; - return false; - } - *(((UTF32Char *)dst)++) = currentChar; - } - } else { - if (!CFUniCharFillDestinationBuffer(¤tChar, 1, &dst, maxLength, &usedLength, dstFormat)) { - if (decompBuffer != buffer) CFAllocatorDeallocate(NULL, decompBuffer); - if (consumedLength) *consumedLength = originalLength - length; - if (filledLength) *filledLength = usedLength; - return false; - } - } - } - } else { - if (dstFormat == kCFUniCharUTF32Format && maxLength) { - idx = CFUniCharDecomposeCharacter(currentChar, dst, maxLength - usedLength); - - if (idx == 0) { - if (decompBuffer != buffer) CFAllocatorDeallocate(NULL, decompBuffer); - if (consumedLength) *consumedLength = originalLength - length; - if (filledLength) *filledLength = usedLength; - return false; - } else if (needToReorder && (idx > 1)) { // Need to reorder - bool moreCombiningMarks = false; - ++((UTF32Char *)dst); --idx; ++usedLength; // Skip the base - - while (length > 0) { - if (CFUniCharIsSurrogateHighCharacter(*src) && ((length + 1) > 0) && CFUniCharIsSurrogateLowCharacter(*(src + 1))) { - currentChar = CFUniCharGetLongCharacterForSurrogatePair(*src, *(src + 1)); - } else { - currentChar = *src; - } - if (__CFUniCharIsNonBaseCharacter(currentChar)) { - if (currentChar > 0xFFFF) { // Non-BMP - length -= 2; - src += 2; - } else { - --length; - ++src; - } - if ((idx + usedLength + 1) >= maxLength) { - if (decompBuffer != buffer) CFAllocatorDeallocate(NULL, decompBuffer); - if (consumedLength) *consumedLength = originalLength - length; - if (filledLength) *filledLength = usedLength; - return false; - } - ((UTF32Char *)dst)[idx++] = currentChar; - moreCombiningMarks = true; - } else { - break; - } - } - if (moreCombiningMarks) __CFUniCharPrioritySort(((UTF32Char *)dst), idx); - - } - usedLength += idx; - ((UTF32Char *)dst) += idx; - } else { - idx = CFUniCharDecomposeCharacter(currentChar, decompBuffer, decompBufferLen); - - if (maxLength && idx + usedLength > maxLength) { - if (decompBuffer != buffer) CFAllocatorDeallocate(NULL, decompBuffer); - if (consumedLength) *consumedLength = originalLength - length; - if (filledLength) *filledLength = usedLength; - return false; - } else if (needToReorder && (idx > 1)) { // Need to reorder - bool moreCombiningMarks = false; - - while (length > 0) { - if (CFUniCharIsSurrogateHighCharacter(*src) && ((length + 1) > 0) && CFUniCharIsSurrogateLowCharacter(*(src + 1))) { - currentChar = CFUniCharGetLongCharacterForSurrogatePair(*src, *(src + 1)); - } else { - currentChar = *src; - } - if (__CFUniCharIsNonBaseCharacter(currentChar)) { - if (currentChar > 0xFFFF) { // Non-BMP - length -= 2; - src += 2; - } else { - --length; - ++src; - } - if ((idx + 1) >= decompBufferLen) { - UTF32Char *newBuffer; - - decompBufferLen += MAX_BUFFER_LENGTH; - newBuffer = (UTF32Char *)CFAllocatorAllocate(NULL, sizeof(UTF32Char) * decompBufferLen, 0); - memmove(newBuffer, decompBuffer, (decompBufferLen - MAX_BUFFER_LENGTH) * sizeof(UTF32Char)); - if (decompBuffer != buffer) CFAllocatorDeallocate(NULL, decompBuffer); - decompBuffer = newBuffer; - } - decompBuffer[idx++] = currentChar; - moreCombiningMarks = true; - } else { - break; - } - } - if (moreCombiningMarks) __CFUniCharPrioritySort(decompBuffer + 1, idx - 1); - } - if (!CFUniCharFillDestinationBuffer(decompBuffer, idx, &dst, maxLength, &usedLength, dstFormat)) { - if (decompBuffer != buffer) CFAllocatorDeallocate(NULL, decompBuffer); - if (consumedLength) *consumedLength = originalLength - length; - if (filledLength) *filledLength = usedLength; - return false; - } - } - } - } - if (decompBuffer != buffer) CFAllocatorDeallocate(NULL, decompBuffer); - - if (consumedLength) *consumedLength = originalLength - length; - if (filledLength) *filledLength = usedLength; - - return true; -} - -#define MAX_COMP_DECOMP_LEN (32) - -static uint32_t __CFUniCharRecursivelyCompatibilityDecomposeCharacter(UTF32Char character, UTF32Char *convertedChars) { - uint32_t value = __CFUniCharGetMappedValue((const __CFUniCharDecomposeMappings *)__CFUniCharCompatibilityDecompositionTable, __CFUniCharCompatibilityDecompositionTableLength, character); - uint32_t length = CFUniCharConvertFlagToCount(value); - UTF32Char firstChar = value & 0xFFFFFF; - const UTF32Char *mappings = (length > 1 ? __CFUniCharCompatibilityMultipleDecompositionTable + firstChar : &firstChar); - uint32_t usedLength = length; - UTF32Char currentChar; - uint32_t currentLength; - - while (length-- > 0) { - currentChar = *(mappings++); - if (__CFUniCharIsDecomposableCharacterWithFlag(currentChar, false)) { - currentLength = __CFUniCharRecursivelyDecomposeCharacter(currentChar, convertedChars, MAX_COMP_DECOMP_LEN - length); - convertedChars += currentLength; - usedLength += (currentLength - 1); - } else if (CFUniCharIsMemberOf(currentChar, kCFUniCharCompatibilityDecomposableCharacterSet)) { - currentLength = __CFUniCharRecursivelyCompatibilityDecomposeCharacter(currentChar, convertedChars); - convertedChars += currentLength; - usedLength += (currentLength - 1); - } else { - *(convertedChars++) = currentChar; - } - } - - return usedLength; -} - -CF_INLINE void __CFUniCharMoveBufferFromEnd(UTF32Char *convertedChars, uint32_t length, uint32_t delta) { - const UTF32Char *limit = convertedChars; - UTF32Char *dstP; - - convertedChars += length; - dstP = convertedChars + delta; - - while (convertedChars > limit) *(--dstP) = *(--convertedChars); -} - -__private_extern__ uint32_t CFUniCharCompatibilityDecompose(UTF32Char *convertedChars, uint32_t length, uint32_t maxBufferLength) { - UTF32Char currentChar; - UTF32Char buffer[MAX_COMP_DECOMP_LEN]; - const UTF32Char *bufferP; - const UTF32Char *limit = convertedChars + length; - uint32_t filledLength; - - if (NULL == __CFUniCharCompatibilityDecompositionTable) __CFUniCharLoadCompatibilityDecompositionTable(); - - while (convertedChars < limit) { - currentChar = *convertedChars; - - if (CFUniCharIsMemberOf(currentChar, kCFUniCharCompatibilityDecomposableCharacterSet)) { - filledLength = __CFUniCharRecursivelyCompatibilityDecomposeCharacter(currentChar, buffer); - - if (filledLength + length - 1 > maxBufferLength) return 0; - - if (filledLength > 1) __CFUniCharMoveBufferFromEnd(convertedChars + 1, limit - convertedChars - 1, filledLength - 1); - - bufferP = buffer; - length += (filledLength - 1); - while (filledLength-- > 0) *(convertedChars++) = *(bufferP++); - } else { - ++convertedChars; - } - } - - return length; -} - -CF_EXPORT void CFUniCharPrioritySort(UTF32Char *characters, uint32_t length) { - __CFUniCharPrioritySort(characters, length); -} diff --git a/auto_stubs.h b/auto_stubs.h new file mode 100644 index 0000000..9bea7af --- /dev/null +++ b/auto_stubs.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2008 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@ + */ +/* auto_stubs.h + Copyright 2005-2007, Apple Inc. All rights reserved. +*/ + +#if !defined(AUTO_STUBS_H) +#define AUTO_STUBS_H 1 + +#include +#include +#include +#include +#include + +/* Stubs for functions in libauto. */ + +typedef malloc_zone_t auto_zone_t; + +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 }; +typedef unsigned long auto_memory_type_t; + +CF_INLINE void *auto_zone(void) { return 0; } +CF_INLINE void *auto_zone_allocate_object(void *zone, size_t size, auto_memory_type_t type, boolean_t rc, boolean_t clear) { return 0; } +CF_INLINE const void *auto_zone_base_pointer(void *zone, const void *ptr) { return 0; } +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_layout_type(void *zone, void *ptr, auto_memory_type_t type) {} +CF_INLINE void auto_zone_write_barrier_range(void *zone, void *address, size_t size) {} +CF_INLINE boolean_t 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 boolean_t auto_zone_is_valid_pointer(void *zone, const void *ptr) { return 0; } +CF_INLINE auto_memory_type_t auto_zone_get_layout_type(auto_zone_t *zone, void *ptr) { return AUTO_UNSCANNED; } + +CF_INLINE void objc_collect_if_needed(unsigned long options) {} +CF_INLINE BOOL objc_collecting_enabled(void) { return 0; } +CF_INLINE id objc_allocate_object(Class cls, int extra) { return 0; } +CF_INLINE id objc_assign_strongCast(id val, id *dest) { return (*dest = val); } +CF_INLINE id objc_assign_global(id val, id *dest) { return (*dest = val); } +CF_INLINE id objc_assign_ivar(id val, id dest, unsigned int offset) { id *d = (id *)((char *)dest + offset); return (*d = val); } +CF_INLINE void *objc_memmove_collectable(void *dst, const void *src, size_t size) { return memmove(dst, src, size); } +CF_INLINE BOOL objc_is_finalized(void *ptr) { return 0; } + +#endif /* ! AUTO_STUBS_H */ + diff --git a/framework.make b/framework.make deleted file mode 100755 index 34431c8..0000000 --- a/framework.make +++ /dev/null @@ -1,626 +0,0 @@ -# Simple makefile for building a framework or library on platforms other than OS X. -# the open source subset used in Darwin. -# -# These make variables (or environment variables) are used -# if defined: -# SRCROOT path location of root of source hierarchy; -# defaults to ".", but must be set to a -# destination path for installsrc target. -# OBJROOT path location where .o files will be put; -# defaults to "/tmp/CoreFoundation.obj". -# SYMROOT path location where build products will be -# put; defaults to "/tmp/CoreFoundation.sym". -# DSTROOT path location where installed products will -# be put; defaults to "/tmp/CoreFoundation.dst". -# -# Interesting variables to be set by the including Makefile: -# NAME base name of the framework or library -# CFILES .c to build -# CPP_FILES .cpp to build -# PUBLIC_HFILES .h files that will be installed for clients of API -# PRIVATE_HFILES .h files that will be installed for clients of SPI -# PROJECT_HFILES the rest of the .h files in the project -# PUBLIC_IFILES .i with API -# PRIVATE_IFILES .i files with SPI -# IFILES_DIR directory holding all the .i files -# MASTER_INTERFACE_DIR location of .i files we depend on -# -# We now follow the model of modern PB builds, which allow SYMROOT and OBJROOT to be shared -# across projects during development. This provides the benefit that one set of build flags -# (-F on Mach, -I and -L on Unix or Cygwin) can be used to share build products across projects. -# For release builds, the directories are always separate per project. -# -# PLATFORM name of platform being built on -# USER name of user building the project -# ARCHS list of archs for which to build -# RC_ARCHS more archs for which to build (build system) -# OTHER_CFLAGS other flags to be passed to compiler -# RC_CFLAGS more flags to be passed to compiler (build system) -# OTHER_LFLAGS other flags to be passed to the link stage -# -# (Note: lame "#*/" tacked onto some lines is to get PB to stop syntax coloring the entire rest of the file as a comment.) - -# First figure out the platform if not specified, so we can use it in the -# rest of this file. Currently defined values: Darwin, Linux, FreeBSD, variants of CYGWIN -ifeq "$(PLATFORM)" "" -PLATFORM := $(shell uname) -endif - -ifeq "$(PLATFORM)" "Darwin" -# Darwin platforms always define __MACH__ -else -ifneq "" "$(findstring CYGWIN, $(PLATFORM))" -# The windows platforms all define one cpp symbol or another, which CFBase.h funnels to __WIN32__. -# Simplify later checks, since we don't care about different versions of CYGWIN. -PLATFORM = CYGWIN -else -ifeq "$(PLATFORM)" "Linux" -PLATFORM_CFLAGS = -D__LINUX__=1 -else -ifeq "$(PLATFORM)" "FreeBSD" -PLATFORM_CFLAGS = -D__FREEBSD__=1 -else -$(error Platform could not be identified. Neither $$PLATFORM was set, nor the result of uname was recognized) -endif -endif -endif -endif - -# -# Set up basic variables, commands we use -# - -ifndef SRCROOT -SRCROOT = . -endif - -ifndef OBJROOT -OBJROOT = /tmp/$(NAME).obj -endif - -ifndef SYMROOT -SYMROOT = /tmp/$(NAME).sym -endif - -ifndef DSTROOT -DSTROOT = /tmp/$(NAME).dst -endif - -SILENT = @ -ifeq "$(PLATFORM)" "CYGWIN" -CC = gcc -CPLUSPLUS = g++ -ECHO = echo -MKDIRS = mkdir -p -COPY = cp -COPY_RECUR = cp -r -REMOVE = rm -REMOVE_RECUR = rm -rf -SYMLINK = ln -sfh -CHMOD = chmod -CHOWN = chown -TAR = tar -TOUCH = touch -STRIP = strip -DLLTOOL = dlltool -INTERFACER = Interfacer -else -ifeq "$(PLATFORM)" "Darwin" -CC = /usr/bin/cc -else -CC = /usr/bin/gcc -endif -CPLUSPLUS = /usr/bin/g++ -ECHO = /bin/echo -MKDIRS = /bin/mkdir -p -COPY = /bin/cp -COPY_RECUR = /bin/cp -r -REMOVE = /bin/rm -REMOVE_RECUR = /bin/rm -rf -SYMLINK = /bin/ln -sfh -CHMOD = /bin/chmod -CHOWN = /usr/sbin/chown -TAR = /usr/bin/tar -TOUCH = /usr/bin/touch -STRIP = /usr/bin/strip -INTERFACER = /AppleInternal/Developer/Tools/Interfacer -endif - -# -# Set up CC flags -# - -ifeq "$(PLATFORM)" "Darwin" -C_WARNING_FLAGS += -Wno-precomp -Wno-four-char-constants -Wall -CPP_WARNING_FLAGS += -Wno-precomp -Wno-four-char-constants -Wall -endif - -ifeq "$(PLATFORM)" "CYGWIN" -C_WARNING_FLAGS += -Wall -CPP_WARNING_FLAGS += -Wall -endif - -ifeq "$(PLATFORM)" "Darwin" -ifneq "$(ARCHS)" "" -ARCH_FLAGS = $(foreach A, $(ARCHS), $(addprefix -arch , $(A))) -else -ifneq "$(RC_ARCHS)" "" -ARCH_FLAGS = $(foreach A, $(RC_ARCHS), $(addprefix -arch , $(A))) -else -ARCH_FLAGS = -arch ppc -endif -endif -endif - -ifeq "$(PLATFORM)" "FreeBSD" -ARCH_FLAGS = -march=i386 -endif - -ifeq "$(PLATFORM)" "Linux" -ARCH_FLAGS = -endif - -ifeq "$(USER)" "" -USER = unknown -endif - -CFLAGS = -fno-common -pipe $(PLATFORM_CFLAGS) $(C_WARNING_FLAGS) -I. -CPPFLAGS = -fno-common -pipe $(PLATFORM_CFLAGS) $(CPP_WARNING_FLAGS) -I. - -ifeq "$(PLATFORM)" "Darwin" -CFLAGS += $(ARCH_FLAGS) -F$(SYMROOT) -fconstant-cfstrings -CPPFLAGS += $(ARCH_FLAGS) -F$(SYMROOT) -fconstant-cfstrings -endif - -ifeq "$(PLATFORM)" "CYGWIN" -# -mno-cygwin can be left out to build using the CYGWIN unix emulation libs -CFLAGS += -mno-cygwin -CPPFLAGS += -mno-cygwin -endif - - - -# -# Set style of building the library/framework, and the linker flags -# - -ifeq "$(wildcard /System/Library/Frameworks)" "" -LIBRARY_STYLE = Library -LIBRARY_EXT = .so -RELEASE_LIB = lib$(NAME)$(LIBRARY_EXT) -DEBUG_LIB = lib$(NAME)_debug$(LIBRARY_EXT) -PROFILE_LIB = lib$(NAME)_profile$(LIBRARY_EXT) -ifeq "$(PLATFORM)" "Linux" -LIBRARY_EXT = .a -endif -INSTALLDIR = /usr/local/lib -ifeq "$(PLATFORM)" "CYGWIN" -LIBRARY_EXT = .dll -RELEASE_LIB = $(NAME)$(LIBRARY_EXT) -DEBUG_LIB = $(NAME)_debug$(LIBRARY_EXT) -PROFILE_LIB = $(NAME)_profile$(LIBRARY_EXT) -RELEASE_IMPLIB = lib$(RELEASE_LIB:.dll=.a) -DEBUG_IMPLIB = lib$(DEBUG_LIB:.dll=.a) -PROFILE_IMPLIB = lib$(PROFILE_LIB:.dll=.a) -INSTALLDIR = /usr/local/bin -LIB_INSTALLDIR = /usr/local/lib -endif -HEADER_INSTALLDIR = /usr/local/include/$(NAME) -INSTALLDIR = /usr/local/lib -MASTER_INTERFACE_DIR = $(SYMROOT)/interfaces -# Next four dirs are used at build time, but not install time -PUBLIC_HEADER_DIR = $(SYMROOT)/Headers/$(NAME) -PRIVATE_HEADER_DIR = $(SYMROOT)/PrivateHeaders/$(NAME) -PROJECT_HEADER_DIR = $(OBJROOT)/$(NAME).build/ProjectHeaders/$(NAME) -RESOURCE_DIR = $(SYMROOT) -else -LIBRARY_STYLE = Framework -RELEASE_LIB = $(NAME) -DEBUG_LIB = $(NAME)_debug -PROFILE_LIB = $(NAME)_profile -INSTALLDIR = /System/Library/Frameworks -FRAMEWORK_DIR = /System/Library/Frameworks/$(NAME).framework -MASTER_INTERFACE_DIR = /AppleInternal/Carbon/interfaces -# Next three dirs are used at build time, but not install time -PUBLIC_HEADER_DIR = $(SYMROOT)/$(NAME).framework/Versions/A/Headers -PRIVATE_HEADER_DIR = $(SYMROOT)/$(NAME).framework/Versions/A/PrivateHeaders -PROJECT_HEADER_DIR = $(OBJROOT)/$(NAME).build/ProjectHeaders -endif - -ifeq "$(PLATFORM)" "Darwin" -LFLAGS = $(ARCH_FLAGS) -dynamiclib -dynamic -endif - -ifeq "$(PLATFORM)" "FreeBSD" -LFLAGS = -shared -endif - -ifeq "$(PLATFORM)" "CYGWIN" -# -mno-cygwin can be left out to build using the CYGWIN unix emulation libs -LFLAGS = -mno-cygwin -L$(SYMROOT) -endif - -# other flags passed in from the make command line, and RC -CFLAGS += $(OTHER_CFLAGS) $(RC_CFLAGS) -CPPFLAGS += $(OTHER_CPPFLAGS) $(RC_CFLAGS) -LFLAGS += $(OTHER_LFLAGS) - - -# Needed to find Project Headers, which work in PB because of the fancy -header-mapfile feature. -CFLAGS += -I$(PROJECT_HEADER_DIR) -CPPFLAGS += -I$(PROJECT_HEADER_DIR) -# Needed for cases when a private header is included as "Foo.h" instead of -CFLAGS += -I$(PRIVATE_HEADER_DIR) -CPPFLAGS += -I$(PRIVATE_HEADER_DIR) -ifeq "$(LIBRARY_STYLE)" "Library" -# Needed for headers included as , since there is no -FframeworkDir mechanism at work -CFLAGS += -I$(PUBLIC_HEADER_DIR)/.. -I$(PRIVATE_HEADER_DIR)/.. -CPPFLAGS += -I$(PUBLIC_HEADER_DIR)/.. -I$(PRIVATE_HEADER_DIR)/.. -endif - - -.PHONY: build all prebuild release debug profile debug-build release-build profile-build build-realwork test -default: build -all: build -build: prebuild debug-build release-build profile-build -release: prebuild release-build -debug: prebuild debug-build -profile: prebuild profile-build - -# These are the main targets: -# build builds the library to OBJROOT and SYMROOT -# installsrc copies the sources to SRCROOT -# installhdrs install only the headers to DSTROOT -# install build, then install the headers and library to DSTROOT -# clean removes build products in OBJROOT and SYMROOT -# test invoke items in Tests subdirectory - -#-------------------------------------------------------------------------------- -# INSTALL -#-------------------------------------------------------------------------------- - -installsrc: - $(SILENT) $(ECHO) "Installing source..." -ifeq "$(SRCROOT)" "." - $(SILENT) $(ECHO) "SRCROOT must be defined to be the destination directory; it cannot be '.'" - exit 1 -endif - $(SILENT) $(MKDIRS) $(SRCROOT) - $(SILENT) $(MKDIRS) $(foreach S, $(SUBPROJECTS), $(SRCROOT)/$(S).subproj) - -$(SILENT) $(foreach S, $(SUBPROJECTS), $(COPY) $(foreach F, $($(S)_SOURCES), $(S).subproj/$(F)) $(SRCROOT)/$(S).subproj;) - -$(SILENT) $(foreach S, $(SUBPROJECTS), $(COPY) $(foreach F, $($(S)_PROJHEADERS), $(S).subproj/$(F)) $(SRCROOT)/$(S).subproj;) - -$(SILENT) $(foreach S, $(SUBPROJECTS), $(COPY) $(foreach F, $($(S)_PRIVHEADERS), $(S).subproj/$(F)) $(SRCROOT)/$(S).subproj;) - -$(SILENT) $(foreach S, $(SUBPROJECTS), $(COPY) $(foreach F, $($(S)_PUBHEADERS), $(S).subproj/$(F)) $(SRCROOT)/$(S).subproj;) - $(SILENT) $(COPY) $(OTHER_SOURCES) $(SRCROOT) - $(SILENT) $(COPY_RECUR) CharacterSets $(SRCROOT) - $(SILENT) $(REMOVE_RECUR) $(SRCROOT)/CharacterSets/CVS - -installhdrs: - $(SILENT) $(ECHO) "Installing headers..." -ifeq "$(LIBRARY_STYLE)" "Framework" - $(SILENT) $(REMOVE) -f $(DSTROOT)/$(FRAMEWORK_DIR)/Headers - $(SILENT) $(REMOVE) -f $(DSTROOT)/$(FRAMEWORK_DIR)/PrivateHeaders - $(SILENT) $(REMOVE) -f $(DSTROOT)/$(FRAMEWORK_DIR)/Versions/Current - $(SILENT) $(MKDIRS) $(DSTROOT)/$(FRAMEWORK_DIR)/Versions/A/Headers - $(SILENT) $(MKDIRS) $(DSTROOT)/$(FRAMEWORK_DIR)/Versions/A/PrivateHeaders - $(SILENT) $(SYMLINK) A $(DSTROOT)/$(FRAMEWORK_DIR)/Versions/Current - $(SILENT) $(SYMLINK) Versions/Current/Headers $(DSTROOT)/$(FRAMEWORK_DIR)/Headers - $(SILENT) $(SYMLINK) Versions/Current/PrivateHeaders $(DSTROOT)/$(FRAMEWORK_DIR)/PrivateHeaders - -$(SILENT) $(CHMOD) +w $(DSTROOT)/$(FRAMEWORK_DIR)/Versions/A/Headers/*.h #*/ - -$(SILENT) $(CHMOD) +w $(DSTROOT)/$(FRAMEWORK_DIR)/Versions/A/PrivateHeaders/*.h #*/ - $(SILENT) $(COPY) $(PUBLIC_HFILES) $(DSTROOT)/$(FRAMEWORK_DIR)/Versions/A/Headers -# Install two private headers for internal Apple projects' use - $(SILENT) $(COPY) Base.subproj/CFPriv.h Base.subproj/CFRuntime.h PlugIn.subproj/CFBundlePriv.h $(DSTROOT)/$(FRAMEWORK_DIR)/Versions/A/PrivateHeaders - $(SILENT) $(CHOWN) -R root:wheel $(DSTROOT)/$(FRAMEWORK_DIR) - -$(SILENT) $(CHMOD) -w $(DSTROOT)/$(FRAMEWORK_DIR)/Versions/A/Headers/*.h #*/ - -$(SILENT) $(CHMOD) -w $(DSTROOT)/$(FRAMEWORK_DIR)/Versions/A/PrivateHeaders/*.h #*/ -endif -ifeq "$(LIBRARY_STYLE)" "Library" - $(SILENT) $(MKDIRS) $(DSTROOT)/$(HEADER_INSTALLDIR) - -$(SILENT) $(CHMOD) +w $(DSTROOT)/$(HEADER_INSTALLDIR)/*.h #*/ - $(SILENT) $(COPY) $(PUBLIC_HFILES) $(DSTROOT)/$(HEADER_INSTALLDIR) - $(SILENT) $(CHMOD) -w $(DSTROOT)/$(HEADER_INSTALLDIR)/*.h #*/ -endif - -install: build install_before install_builtin install_after -install_before:: -install_after:: - -install_builtin: - $(SILENT) $(ECHO) "Installing..." -ifeq "$(LIBRARY_STYLE)" "Framework" - $(SILENT) $(REMOVE_RECUR) $(DSTROOT)/$(FRAMEWORK_DIR) - $(SILENT) $(MKDIRS) $(DSTROOT)/$(FRAMEWORK_DIR) - -$(SILENT) $(CHMOD) -R +w $(DSTROOT)/$(FRAMEWORK_DIR) - $(SILENT) (cd $(SYMROOT) && $(TAR) -cf - $(NAME).framework) | (cd $(DSTROOT)/$(INSTALLDIR) && $(TAR) -xf -) - $(SILENT) $(STRIP) -S $(DSTROOT)/$(FRAMEWORK_DIR)/Versions/A/$(RELEASE_LIB) - $(SILENT) $(STRIP) -S $(DSTROOT)/$(FRAMEWORK_DIR)/Versions/A/$(DEBUG_LIB) - $(SILENT) $(STRIP) -S $(DSTROOT)/$(FRAMEWORK_DIR)/Versions/A/$(PROFILE_LIB) - $(SILENT) $(CHMOD) -R ugo-w $(DSTROOT)/$(FRAMEWORK_DIR) - $(SILENT) $(CHMOD) -R o+rX $(DSTROOT)/$(FRAMEWORK_DIR) - $(SILENT) $(CHOWN) -R root:wheel $(DSTROOT)/$(FRAMEWORK_DIR) -endif -ifeq "$(LIBRARY_STYLE)" "Library" - $(SILENT) $(MKDIRS) $(DSTROOT)/$(INSTALLDIR) - -$(SILENT) $(CHMOD) +w $(DSTROOT)/$(INSTALLDIR) - $(SILENT) $(REMOVE) -f $(DSTROOT)/$(INSTALLDIR)/$(RELEASE_LIB) - $(SILENT) $(REMOVE) -f $(DSTROOT)/$(INSTALLDIR)/$(DEBUG_LIB) - $(SILENT) $(REMOVE) -f $(DSTROOT)/$(INSTALLDIR)/$(PROFILE_LIB) - $(SILENT) $(COPY) $(SYMROOT)/$(RELEASE_LIB) $(DSTROOT)/$(INSTALLDIR)/$(RELEASE_LIB) - $(SILENT) $(COPY) $(SYMROOT)/$(DEBUG_LIB) $(DSTROOT)/$(INSTALLDIR)/$(DEBUG_LIB) - $(SILENT) $(COPY) $(SYMROOT)/$(PROFILE_LIB) $(DSTROOT)/$(INSTALLDIR)/$(PROFILE_LIB) -ifneq "$(PLATFORM)" "CYGWIN" - -$(SILENT) $(CHOWN) root:wheel $(DSTROOT)/$(INSTALLDIR)/$(RELEASE_LIB) - -$(SILENT) $(CHOWN) root:wheel $(DSTROOT)/$(INSTALLDIR)/$(DEBUG_LIB) - -$(SILENT) $(CHOWN) root:wheel $(DSTROOT)/$(INSTALLDIR)/$(PROFILE_LIB) -endif - $(SILENT) $(CHMOD) 755 $(DSTROOT)/$(INSTALLDIR)/$(RELEASE_LIB) - $(SILENT) $(CHMOD) 755 $(DSTROOT)/$(INSTALLDIR)/$(DEBUG_LIB) - $(SILENT) $(CHMOD) 755 $(DSTROOT)/$(INSTALLDIR)/$(PROFILE_LIB) -ifeq "$(PLATFORM)" "CYGWIN" - $(SILENT) $(MKDIRS) $(DSTROOT)/$(LIB_INSTALLDIR) - -$(SILENT) $(CHMOD) +w $(DSTROOT)/$(LIB_INSTALLDIR) - $(SILENT) $(REMOVE) -f $(DSTROOT)/$(LIB_INSTALLDIR)/$(RELEASE_IMPLIB) - $(SILENT) $(REMOVE) -f $(DSTROOT)/$(LIB_INSTALLDIR)/$(DEBUG_IMPLIB) - $(SILENT) $(REMOVE) -f $(DSTROOT)/$(LIB_INSTALLDIR)/$(PROFILE_IMPLIB) - $(SILENT) $(COPY) $(SYMROOT)/$(RELEASE_IMPLIB) $(DSTROOT)/$(LIB_INSTALLDIR)/$(RELEASE_IMPLIB) - $(SILENT) $(COPY) $(SYMROOT)/$(DEBUG_IMPLIB) $(DSTROOT)/$(LIB_INSTALLDIR)/$(DEBUG_IMPLIB) - $(SILENT) $(COPY) $(SYMROOT)/$(PROFILE_IMPLIB) $(DSTROOT)/$(LIB_INSTALLDIR)/$(PROFILE_IMPLIB) - $(SILENT) $(CHMOD) 755 $(DSTROOT)/$(LIB_INSTALLDIR)/$(RELEASE_IMPLIB) - $(SILENT) $(CHMOD) 755 $(DSTROOT)/$(LIB_INSTALLDIR)/$(DEBUG_IMPLIB) - $(SILENT) $(CHMOD) 755 $(DSTROOT)/$(LIB_INSTALLDIR)/$(PROFILE_IMPLIB) -endif - $(SILENT) $(MKDIRS) $(DSTROOT)/$(HEADER_INSTALLDIR) - -$(SILENT) $(CHMOD) +w $(DSTROOT)/$(HEADER_INSTALLDIR)/*.h #*/ - $(SILENT) $(COPY) $(PUBLIC_HFILES) $(DSTROOT)/$(HEADER_INSTALLDIR) - -$(SILENT) $(CHMOD) -w $(DSTROOT)/$(HEADER_INSTALLDIR)/*.h #*/ -endif - -#-------------------------------------------------------------------------------- -# CLEAN -#-------------------------------------------------------------------------------- - -clean: clean_before clean_builtin clean_after -clean_before:: -clean_after:: - -clean_builtin: - $(SILENT) $(ECHO) "Deleting build products..." - $(REMOVE_RECUR) $(OBJROOT)/$(NAME).build -ifeq "$(LIBRARY_STYLE)" "Framework" - $(REMOVE_RECUR) $(SYMROOT)/$(NAME).framework -endif -ifeq "$(LIBRARY_STYLE)" "Library" - $(REMOVE) -f $(SYMROOT)/$(RELEASE_LIB) - $(REMOVE) -f $(SYMROOT)/$(DEBUG_LIB) - $(REMOVE) -f $(SYMROOT)/$(PROFILE_LIB) - $(REMOVE_RECUR) -f $(PUBLIC_HEADER_DIR) $(PRIVATE_HEADER_DIR) -ifeq "$(PLATFORM)" "CYGWIN" - $(REMOVE) -f $(SYMROOT)/$(RELEASE_IMPLIB) - $(REMOVE) -f $(SYMROOT)/$(DEBUG_IMPLIB) - $(REMOVE) -f $(SYMROOT)/$(PROFILE_IMPLIB) - $(REMOVE) -f $(SYMROOT)/$(RELEASE_LIB:.dll=.lib) - $(REMOVE) -f $(SYMROOT)/$(DEBUG_LIB:.dll=.lib) - $(REMOVE) -f $(SYMROOT)/$(PROFILE_LIB:.dll=.lib) - $(REMOVE) -f $(SYMROOT)/$(RELEASE_LIB:.dll=.defs) - $(REMOVE) -f $(SYMROOT)/$(DEBUG_LIB:.dll=.defs) - $(REMOVE) -f $(SYMROOT)/$(PROFILE_LIB:.dll=.exp) - $(REMOVE) -f $(SYMROOT)/$(RELEASE_LIB:.dll=.exp) - $(REMOVE) -f $(SYMROOT)/$(DEBUG_LIB:.dll=.exp) - $(REMOVE) -f $(SYMROOT)/$(PROFILE_LIB:.dll=.defs) -endif -endif - -#-------------------------------------------------------------------------------- -# PREBUILD -#-------------------------------------------------------------------------------- - -prebuild: prebuild_before prebuild_setup prebuild_headers prebuild_after -prebuild_before:: -prebuild_after:: - -# build the framework, or other basic dir structure -prebuild_setup:: - $(SILENT) $(ECHO) "Prebuild-setup..." - $(SILENT) $(MKDIRS) $(SYMROOT) -ifeq "$(LIBRARY_STYLE)" "Framework" -prebuild_setup:: - $(SILENT) $(MKDIRS) $(SYMROOT)/$(NAME).framework/Versions/A/Resources - $(SILENT) $(SYMLINK) A $(SYMROOT)/$(NAME).framework/Versions/Current - $(SILENT) $(SYMLINK) Versions/Current/Headers $(SYMROOT)/$(NAME).framework/Headers - $(SILENT) $(SYMLINK) Versions/Current/PrivateHeaders $(SYMROOT)/$(NAME).framework/PrivateHeaders - $(SILENT) $(SYMLINK) Versions/Current/Resources $(SYMROOT)/$(NAME).framework/Resources -endif - -ifeq "$(LIBRARY_STYLE)" "Framework" -PLATFORM_IFLAGS = -framework $(NAME) -frameworkInterfaces $(IFILES_DIR) -ALL_IFILES = $(foreach F,$(PUBLIC_IFILES) $(PRIVATE_IFILES),$(IFILES_DIR)/$(F)) - -# Since they share output directories, if either the ifiles or hfiles change we must redo both -prebuild_headers: $(OBJROOT)/$(NAME).build/Headers.touch -$(OBJROOT)/$(NAME).build/Headers.touch: $(PUBLIC_HFILES) $(PRIVATE_HFILES) $(PROJECT_HFILES) $(ALL_IFILES) - $(SILENT) $(REMOVE_RECUR) $(PUBLIC_HEADER_DIR) - $(SILENT) $(REMOVE_RECUR) $(PRIVATE_HEADER_DIR) - $(SILENT) $(REMOVE_RECUR) $(PROJECT_HEADER_DIR) - $(SILENT) $(MKDIRS) $(PUBLIC_HEADER_DIR) - $(SILENT) $(MKDIRS) $(PRIVATE_HEADER_DIR) - $(SILENT) $(MKDIRS) $(PROJECT_HEADER_DIR) - $(SILENT) $(MAKE) prebuild_copy_headers -ifneq "$(ALL_IFILES)" "" - $(SILENT) $(MAKE) prebuild_gen_headers -endif - $(SILENT) $(TOUCH) $(OBJROOT)/$(NAME).build/Headers.touch -else - -ALL_IFILES = $(foreach F,$(PUBLIC_IFILES) $(PRIVATE_IFILES),$(IFILES_DIR)/$(F)) - -# Since they share output directories, if either the ifiles or hfiles change we must redo both -prebuild_headers: $(OBJROOT)/$(NAME).build/Headers.touch -$(OBJROOT)/$(NAME).build/Headers.touch: $(PUBLIC_HFILES) $(PRIVATE_HFILES) $(PROJECT_HFILES) $(ALL_IFILES) - $(SILENT) $(REMOVE_RECUR) $(PUBLIC_HEADER_DIR) - $(SILENT) $(REMOVE_RECUR) $(PRIVATE_HEADER_DIR) - $(SILENT) $(REMOVE_RECUR) $(PROJECT_HEADER_DIR) - $(SILENT) $(MKDIRS) $(PUBLIC_HEADER_DIR) - $(SILENT) $(MKDIRS) $(PRIVATE_HEADER_DIR) - $(SILENT) $(MKDIRS) $(PROJECT_HEADER_DIR) - $(SILENT) $(MAKE) prebuild_copy_headers -ifneq "$(ALL_IFILES)" "" - $(SILENT) $(MAKE) prebuild_gen_headers -endif - $(SILENT) $(TOUCH) $(OBJROOT)/$(NAME).build/Headers.touch - -# First try was not using -framework, so we get EXTERN_API to leverage for __declspec trickery. -# But that didn't help us for externed data, and the imports changed to omit the framework name. -# As best I can tell, when not using -framework you need to cd into the IFILES_DIR for the -# inter-file references to work. -# -update and -deepUpdate don't seem to work on WIN32, so just use a touch file -#ALL_IFILES = $(PUBLIC_IFILES) $(PRIVATE_IFILES) -#PLATFORM_IFLAGS = $(foreach F, $(ALL_IFILES), `cygpath -w $(F)`) -PLATFORM_IFLAGS = -framework $(NAME) -frameworkInterfaces `cygpath -w $(IFILES_DIR)/` -endif -prebuild_gen_headers: - $(SILENT) $(ECHO) "Processing interface files..." - $(SILENT) $(INTERFACER) $(PLATFORM_IFLAGS) -c -rez -update \ - -masterInterfaces `cygpath -w $(MASTER_INTERFACE_DIR)/` \ - -cacheFolder `cygpath -w $(OBJROOT)/$(NAME).build/InterfacerCache/` \ - -generated c=`cygpath -w $(PUBLIC_HEADER_DIR)/` \ - -generatedPriv c=`cygpath -w $(PRIVATE_HEADER_DIR)/` \ - -generated rez=`cygpath -w $(PUBLIC_HEADER_DIR)/` \ - -generatedPriv rez=`cygpath -w $(PRIVATE_HEADER_DIR)/` -ifeq "$(PLATFORM)" "CYGWIN" -# Replace externs with a symbol we can use for declspec purposes, except not extern "C" -# Get rid of non-standard pragma - $(SILENT) perl -p -i \ - -e 's/^extern ([^"].[^"])/$(NAME)_EXPORT $$1/ ;' \ - -e 's/^(#pragma options)/\/\/$$1/' \ - $(PUBLIC_HEADER_DIR)/*.h $(PRIVATE_HEADER_DIR)/*.h #*/ - $(SILENT) $(REMOVE) -f $(PUBLIC_HEADER_DIR)/*.bak $(PRIVATE_HEADER_DIR)/*.bak #*/ -endif - -# This is the line from a CFNetwork build in PB -# /AppleInternal/Developer/Tools/Interfacer -masterInterfaces "/AppleInternal/Carbon/interfaces/" -cacheFolder "/Volumes/Whopper/symroots/CFNetwork.build/CFNetwork.build/InterfacerCache/" -c -rez -framework "CFNetwork" -p -generated "c=/Volumes/Whopper/symroots/CFNetwork.framework/Versions/A/Headers/" -generatedPriv "c=/Volumes/Whopper/symroots/CFNetwork.framework/Versions/A/PrivateHeaders/" -generated "rez=/Volumes/Whopper/symroots/CFNetwork.framework/Versions/A/Headers/" -generatedPriv "rez=/Volumes/Whopper/symroots/CFNetwork.framework/Versions/A/PrivateHeaders/" -frameworkInterfaces /Volumes/Whale/trey/CFNetwork-Windows/Interfaces/ -installMasterInterfaces /tmp/CFNetwork.dst/AppleInternal/Carbon/interfaces/ - - -prebuild_copy_headers: - $(SILENT) $(ECHO) "Copying headers..." -ifneq "$(strip $(PUBLIC_HFILES))" "" - $(SILENT) $(COPY) $(PUBLIC_HFILES) $(PUBLIC_HEADER_DIR) -endif -ifneq "$(strip $(PRIVATE_HFILES))" "" - $(SILENT) $(COPY) $(PRIVATE_HFILES) $(PRIVATE_HEADER_DIR) -endif -ifneq "$(strip $(PROJECT_HFILES))" "" - $(SILENT) $(COPY) $(PROJECT_HFILES) $(PROJECT_HEADER_DIR) -endif - - -#-------------------------------------------------------------------------------- -# BUILD -#-------------------------------------------------------------------------------- - -# ??? should use VPATH, should use generic rules -# ??? should use cc -MM to generate dependencies -# ??? should separate private from project headers, for proper installation - -# Set some parameters of the build-realwork target, then call it with a recursive make -release-build: - $(SILENT) $(MAKE) \ - BUILD_TYPE=release \ - BUILD_PRODUCT=$(RELEASE_LIB) \ - BUILD_IMPLIB=$(RELEASE_IMPLIB) \ - OTHER_CFLAGS="-O $(OTHER_CFLAGS)" \ - OTHER_CPPFLAGS="-O $(OTHER_CPPFLAGS)" \ - OTHER_LFLAGS="-O $(OTHER_LFLAGS)" \ - build-realwork -debug-build: - $(SILENT) $(MAKE) \ - BUILD_TYPE=debug \ - BUILD_PRODUCT=$(DEBUG_LIB) \ - BUILD_IMPLIB=$(DEBUG_IMPLIB) \ - LIBRARY_SUFFIX=_debug \ - OTHER_CFLAGS="-DDEBUG -g $(OTHER_CFLAGS)" \ - OTHER_CPPFLAGS="-DDEBUG -g $(OTHER_CPPFLAGS)" \ - OTHER_LFLAGS="-g $(OTHER_LFLAGS)" \ - build-realwork -profile-build: - $(SILENT) $(MAKE) \ - BUILD_TYPE=profile \ - BUILD_PRODUCT=$(PROFILE_LIB) \ - BUILD_IMPLIB=$(PROFILE_IMPLIB) \ - LIBRARY_SUFFIX=_profile \ - OTHER_CFLAGS="-DPROFILE -pg -O $(OTHER_CFLAGS)" \ - OTHER_CPPFLAGS="-DPROFILE -pg -O $(OTHER_CPPFLAGS)" \ - OTHER_LFLAGS="-pg -O $(OTHER_LFLAGS)" \ - build-realwork - -OFILE_DIR = $(OBJROOT)/$(NAME).build/$(BUILD_TYPE)_ofiles - -build-realwork: check-vars-defined compile-before build-compile compile-after build-link -compile-before:: -compile-after:: - -build-compile: - $(SILENT) $(ECHO) "Building $(BUILD_TYPE)..." - $(SILENT) $(MKDIRS) $(OFILE_DIR) - $(SILENT) cumulativeError=0; \ - for x in $(CFILES) ; do \ - ofile=$(OFILE_DIR)/`basename $$x .c`.o ; \ - if [ ! $$ofile -nt $$x ] ; then \ - $(ECHO) " ..." $$x " ($(BUILD_TYPE))" ; \ - $(CC) $(CFLAGS) -c $$x -o $$ofile ; \ - ccError=$$? ; \ - if [ $$ccError != 0 ] ; then cumulativeError=$$ccError; fi;\ - fi ; \ - done; \ - exit $$cumulativeError - $(SILENT) cumulativeError=0; \ - for x in $(CPP_FILES) ; do \ - ofile=$(OFILE_DIR)/`basename $$x .c`.o ; \ - if [ ! $$ofile -nt $$x ] ; then \ - $(ECHO) " ..." $$x " ($(BUILD_TYPE))" ; \ - $(CPLUSPLUS) $(CPPFLAGS) -c $$x -o $$ofile ; \ - ccError=$$? ; \ - if [ $$ccError != 0 ] ; then cumulativeError=$$ccError; fi;\ - fi ; \ - done; \ - exit $$cumulativeError - -ifeq "$(CPP_FILES)" "" -LINKER_CMD = $(CC) -else -LINKER_CMD = $(CPLUSPLUS) -endif - -build-link: - $(SILENT) $(ECHO) "Linking..." -ifeq "$(PLATFORM)" "Darwin" - $(SILENT) $(LINKER_CMD) $(LFLAGS) -O -install_name $(FRAMEWORK_DIR)/Versions/A/$(BUILD_PRODUCT) $(LIBS) -o $(SYMROOT)/$(NAME).framework/Versions/A/$(BUILD_PRODUCT) $(OFILE_DIR)/*.o #*/ - $(SILENT) $(SYMLINK) Versions/Current/$(BUILD_PRODUCT) $(SYMROOT)/$(NAME).framework/$(BUILD_PRODUCT) -endif -ifeq "$(PLATFORM)" "Linux" - $(SILENT) $(ECHO) "NOTE: Producing static libraries on Linux" - $(SILENT) ar cr $(SYMROOT)/$(BUILD_PRODUCT) $(OFILE_DIR)/*.o #*/ -endif -ifeq "$(PLATFORM)" "FreeBSD" - $(SILENT) $(LINKER_CMD) $(LFLAGS) -O -o $(SYMROOT)/$(BUILD_PRODUCT) $(OFILE_DIR)/*.o $(LIBS) #*/ -endif -ifeq "$(PLATFORM)" "CYGWIN" - $(SILENT) $(DLLTOOL) --no-export-all-symbols -z $(SYMROOT)/$(BUILD_PRODUCT:.dll=.defs) -e $(OFILE_DIR)/$(BUILD_PRODUCT:.dll=.exports.o) -l $(SYMROOT)/$(BUILD_IMPLIB) -D $(BUILD_PRODUCT) $(OFILE_DIR)/*.o #*/ - $(SILENT) $(LINKER_CMD) $(LFLAGS) -mdll $(OFILE_DIR)/*.o $(OFILE_DIR)/$(BUILD_PRODUCT:.dll=.exports.o) $(LIBS) -o $(SYMROOT)/$(BUILD_PRODUCT) #*/ -# generate a MS VC compatible import library - $(SILENT) if [ "$$MSVCDIR" != "" ] ; then \ - defFile=`cygpath -w $(SYMROOT)/$(BUILD_PRODUCT:.dll=.defs)`; \ - outFile=`cygpath -w $(SYMROOT)/$(BUILD_PRODUCT:.dll=.lib)`; \ - cmd /C "$$MSVCDIR\BIN\VCVARS32" "&&" lib /MACHINE:i386 "/DEF:$$defFile" "/OUT:$$outFile"; \ - else \ - $(ECHO) WARNING: \$$MSVCDIR is not set - no MS Visual C++ compatible import lib will be generated; \ - fi -endif - $(SILENT) $(ECHO) "Done!" - -# Make sure a couple variables are defined. -check-vars-defined: - $(SILENT) if [ "" = "$(BUILD_TYPE)" ] || [ "" = "$(BUILD_PRODUCT)" ]; then \ - echo ERROR: That target cannot be directly invoked. It is used only internally for recursive makes.; \ - exit 1; \ - fi -- 2.45.2