2 * Copyright (c) 2009 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 Copyright 2006-2009, Apple Inc. All rights reserved.
26 Responsibility: Ali Ozer
29 #include <CoreFoundation/CFError.h>
30 #include <CoreFoundation/CFError_Private.h>
31 #include "CFInternal.h"
32 #include <CoreFoundation/CFPriv.h>
33 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
34 #include <objc/runtime.h>
35 #include <mach/mach_error.h>
36 #elif DEPLOYMENT_TARGET_WINDOWS
38 #error Unknown or unspecified DEPLOYMENT_TARGET
41 /* Pre-defined userInfo keys
43 CONST_STRING_DECL(kCFErrorLocalizedDescriptionKey
, "NSLocalizedDescription");
44 CONST_STRING_DECL(kCFErrorLocalizedFailureReasonKey
, "NSLocalizedFailureReason");
45 CONST_STRING_DECL(kCFErrorLocalizedRecoverySuggestionKey
, "NSLocalizedRecoverySuggestion");
46 CONST_STRING_DECL(kCFErrorDescriptionKey
, "NSDescription");
47 CONST_STRING_DECL(kCFErrorDebugDescriptionKey
, "NSDebugDescription");
48 CONST_STRING_DECL(kCFErrorUnderlyingErrorKey
, "NSUnderlyingError");
50 /* Pre-defined error domains
52 CONST_STRING_DECL(kCFErrorDomainPOSIX
, "NSPOSIXErrorDomain");
53 CONST_STRING_DECL(kCFErrorDomainOSStatus
, "NSOSStatusErrorDomain");
54 CONST_STRING_DECL(kCFErrorDomainMach
, "NSMachErrorDomain");
55 CONST_STRING_DECL(kCFErrorDomainCocoa
, "NSCocoaErrorDomain");
57 /* 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.
59 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.")
60 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.")
61 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.")
62 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.")
63 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.")
68 /* Forward declarations
70 static CFDictionaryRef
_CFErrorGetUserInfo(CFErrorRef err
);
71 static CFStringRef
_CFErrorCopyUserInfoKey(CFErrorRef err
, CFStringRef key
);
72 static CFDictionaryRef
_CFErrorCreateEmptyDictionary(CFAllocatorRef allocator
);
74 /* Assertions and other macros/inlines
76 #define __CFAssertIsError(cf) __CFGenericValidateType(cf, __kCFErrorTypeID)
78 /* 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
80 static CFSpinLock_t _CFErrorSpinlock
= CFSpinLockInit
;
85 /**** CFError CF runtime stuff ****/
87 struct __CFError
{ // Potentially interesting to keep layout same as NSError (but currently not a requirement)
90 CFStringRef domain
; // !!! Could compress well-known domains down to few bits, but probably not worth its weight in code since CFErrors are rare
91 CFDictionaryRef userInfo
; // !!! Could avoid allocating this slot if userInfo is NULL, but probably not worth its weight in code since CFErrors are rare
94 /* CFError equal checks for equality of domain, code, and userInfo.
96 static Boolean
__CFErrorEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
97 CFErrorRef err1
= (CFErrorRef
)cf1
;
98 CFErrorRef err2
= (CFErrorRef
)cf2
;
100 // First do quick checks of code and domain (in that order for performance)
101 if (CFErrorGetCode(err1
) != CFErrorGetCode(err2
)) return false;
102 if (!CFEqual(CFErrorGetDomain(err1
), CFErrorGetDomain(err2
))) return false;
104 // If those are equal, then check the dictionaries
105 CFDictionaryRef dict1
= CFErrorCopyUserInfo(err1
);
106 CFDictionaryRef dict2
= CFErrorCopyUserInfo(err2
);
108 Boolean result
= false;
110 if (dict1
== dict2
) {
112 } else if (dict1
&& dict2
&& CFEqual(dict1
, dict2
)) {
116 if (dict1
) CFRelease(dict1
);
117 if (dict2
) CFRelease(dict2
);
122 /* CFError hash code is hash(domain) + code
124 static CFHashCode
__CFErrorHash(CFTypeRef cf
) {
125 CFErrorRef err
= (CFErrorRef
)cf
;
126 /* !!! We do not need an assertion here, as this is called by the CFBase runtime only */
127 return CFHash(err
->domain
) + err
->code
;
130 /* 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.
132 static CFStringRef
__CFErrorCopyDescription(CFTypeRef cf
) {
133 return _CFErrorCreateDebugDescription((CFErrorRef
)cf
);
136 /* This is the description you get for %@; we tone it down a bit from what you get in __CFErrorCopyDescription().
138 static CFStringRef
__CFErrorCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
139 CFErrorRef err
= (CFErrorRef
)cf
;
140 return CFErrorCopyDescription(err
); // No need to release, since we are returning from a Copy function
143 static void __CFErrorDeallocate(CFTypeRef cf
) {
144 CFErrorRef err
= (CFErrorRef
)cf
;
145 CFRelease(err
->domain
);
146 CFRelease(err
->userInfo
);
150 static CFTypeID __kCFErrorTypeID
= _kCFRuntimeNotATypeID
;
152 static const CFRuntimeClass __CFErrorClass
= {
160 __CFErrorCopyFormattingDescription
,
161 __CFErrorCopyDescription
164 __private_extern__
void __CFErrorInitialize(void) {
165 __kCFErrorTypeID
= _CFRuntimeRegisterClass(&__CFErrorClass
);
168 CFTypeID
CFErrorGetTypeID(void) {
169 return __kCFErrorTypeID
;
175 /**** CFError support functions ****/
177 /* Returns a shared empty dictionary (unless the allocator is not kCFAllocatorSystemDefault, in which case returns a newly allocated one).
179 static CFDictionaryRef
_CFErrorCreateEmptyDictionary(CFAllocatorRef allocator
) {
180 if (allocator
== NULL
) allocator
= __CFGetDefaultAllocator();
181 if (allocator
== kCFAllocatorSystemDefault
) {
182 static CFDictionaryRef emptyErrorDictionary
= NULL
;
183 if (emptyErrorDictionary
== NULL
) {
184 CFDictionaryRef tmp
= CFDictionaryCreate(allocator
, NULL
, NULL
, 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
185 __CFSpinLock(&_CFErrorSpinlock
);
186 if (emptyErrorDictionary
== NULL
) {
187 emptyErrorDictionary
= tmp
;
188 __CFSpinUnlock(&_CFErrorSpinlock
);
190 __CFSpinUnlock(&_CFErrorSpinlock
);
194 return (CFDictionaryRef
)CFRetain(emptyErrorDictionary
);
196 return CFDictionaryCreate(allocator
, NULL
, NULL
, 0, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
200 /* 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.
202 static CFDictionaryRef
_CFErrorGetUserInfo(CFErrorRef err
) {
203 CF_OBJC_FUNCDISPATCH0(__kCFErrorTypeID
, CFDictionaryRef
, err
, "userInfo");
204 __CFAssertIsError(err
);
205 return err
->userInfo
;
208 /* This function retrieves the value of the specified key from the userInfo, or from the callback. It works with a CF or NSError.
210 static CFStringRef
_CFErrorCopyUserInfoKey(CFErrorRef err
, CFStringRef key
) {
211 CFStringRef result
= NULL
;
212 // First consult the userInfo dictionary
213 CFDictionaryRef userInfo
= _CFErrorGetUserInfo(err
);
214 if (userInfo
) result
= (CFStringRef
)CFDictionaryGetValue(userInfo
, key
);
215 // If that doesn't work, consult the callback
219 CFErrorUserInfoKeyCallBack callBack
= CFErrorGetCallBackForDomain(CFErrorGetDomain(err
));
220 if (callBack
) result
= (CFStringRef
)callBack(err
, key
);
225 /* 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.
227 CFStringRef
_CFErrorCreateLocalizedDescription(CFErrorRef err
) {
228 // First look for kCFErrorLocalizedDescriptionKey; if non-NULL, return that as-is.
229 CFStringRef localizedDesc
= _CFErrorCopyUserInfoKey(err
, kCFErrorLocalizedDescriptionKey
);
230 if (localizedDesc
) return localizedDesc
;
232 // Cache the CF bundle since we will be using it for localized strings.
233 CFBundleRef cfBundle
= CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreFoundation"));
235 if (!cfBundle
) { // This should be rare, but has been observed in the wild, due to running out of file descriptors. Normally we might not go to such extremes, but since we want to be able to present reasonable errors even in the case of errors such as running out of file descriptors, why not. This is CFError after all. !!! Be sure to have the same logic here as below for going through various options for fetching the strings.
237 CFStringRef result
= NULL
, reasonOrDesc
;
239 if ((reasonOrDesc
= _CFErrorCopyUserInfoKey(err
, kCFErrorLocalizedFailureReasonKey
))) { // First look for kCFErrorLocalizedFailureReasonKey
240 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("The operation couldn\\U2019t be completed. %@"), reasonOrDesc
);
241 } else if ((reasonOrDesc
= _CFErrorCopyUserInfoKey(err
, kCFErrorDescriptionKey
))) { // Then try kCFErrorDescriptionKey
242 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("The operation couldn\\U2019t be completed. (%@ error %ld - %@)"), CFErrorGetDomain(err
), (long)CFErrorGetCode(err
), reasonOrDesc
);
243 } else { // Last resort, just the domain and code
244 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("The operation couldn\\U2019t be completed. (%@ error %ld.)"), CFErrorGetDomain(err
), (long)CFErrorGetCode(err
));
246 if (reasonOrDesc
) CFRelease(reasonOrDesc
);
250 // Then look for kCFErrorLocalizedFailureReasonKey; if there, create a full sentence from that.
251 CFStringRef reason
= _CFErrorCopyUserInfoKey(err
, kCFErrorLocalizedFailureReasonKey
);
253 CFStringRef operationFailedStr
= CFCopyLocalizedStringFromTableInBundle(CFSTR("The operation couldn\\U2019t 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.");
254 CFStringRef result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, operationFailedStr
, reason
);
255 CFRelease(operationFailedStr
);
260 // Otherwise, generate a semi-user presentable string from the domain, code, and if available, the presumably non-localized kCFErrorDescriptionKey.
262 CFStringRef desc
= _CFErrorCopyUserInfoKey(err
, kCFErrorDescriptionKey
);
263 CFStringRef localizedDomain
= CFCopyLocalizedStringFromTableInBundle(CFErrorGetDomain(err
), CFSTR("Error"), cfBundle
, "These are localized in the comment above");
264 if (desc
) { // We have kCFErrorDescriptionKey, so include that with the error domain and code
265 CFStringRef operationFailedStr
= CFCopyLocalizedStringFromTableInBundle(CFSTR("The operation couldn\\U2019t 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.");
266 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, operationFailedStr
, localizedDomain
, (long)CFErrorGetCode(err
), desc
);
267 CFRelease(operationFailedStr
);
269 } else { // We don't have kCFErrorDescriptionKey, so just use error domain and code
270 CFStringRef operationFailedStr
= CFCopyLocalizedStringFromTableInBundle(CFSTR("The operation couldn\\U2019t 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.");
271 result
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, operationFailedStr
, localizedDomain
, (long)CFErrorGetCode(err
));
272 CFRelease(operationFailedStr
);
274 CFRelease(localizedDomain
);
278 /* 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.
280 CFStringRef
_CFErrorCreateLocalizedFailureReason(CFErrorRef err
) {
281 // We simply return the value of kCFErrorLocalizedFailureReasonKey; no other searching takes place
282 return _CFErrorCopyUserInfoKey(err
, kCFErrorLocalizedFailureReasonKey
);
285 /* 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.
287 CFStringRef
_CFErrorCreateLocalizedRecoverySuggestion(CFErrorRef err
) {
288 // We simply return the value of kCFErrorLocalizedRecoverySuggestionKey; no other searching takes place
289 return _CFErrorCopyUserInfoKey(err
, kCFErrorLocalizedRecoverySuggestionKey
);
292 /* The "debug" description, used by CFCopyDescription and -[NSObject description].
294 CFStringRef
_CFErrorCreateDebugDescription(CFErrorRef err
) {
295 CFStringRef desc
= CFErrorCopyDescription(err
);
296 CFStringRef debugDesc
= _CFErrorCopyUserInfoKey(err
, kCFErrorDebugDescriptionKey
);
297 CFDictionaryRef userInfo
= _CFErrorGetUserInfo(err
);
298 CFErrorRef underlyingError
= NULL
;
299 CFMutableStringRef result
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
300 CFStringAppendFormat(result
, NULL
, CFSTR("Error Domain=%@ Code=%d"), CFErrorGetDomain(err
), (long)CFErrorGetCode(err
));
302 CFStringAppendFormat(result
, NULL
, CFSTR(" UserInfo=%p"), userInfo
);
303 underlyingError
= (CFErrorRef
)CFDictionaryGetValue(userInfo
, kCFErrorUnderlyingErrorKey
);
305 CFStringAppendFormat(result
, NULL
, CFSTR(" \"%@\""), desc
);
306 if (debugDesc
&& CFStringGetLength(debugDesc
) > 0) CFStringAppendFormat(result
, NULL
, CFSTR(" (%@)"), debugDesc
);
307 if (underlyingError
) {
308 CFStringRef underlyingErrorDesc
= _CFErrorCreateDebugDescription(underlyingError
);
309 CFStringAppendFormat(result
, NULL
, CFSTR(" Underlying Error=(%@)"), underlyingErrorDesc
);
310 CFRelease(underlyingErrorDesc
);
312 if (debugDesc
) CFRelease(debugDesc
);
313 if (desc
) CFRelease(desc
);
320 /**** CFError API/SPI ****/
322 /* Note that there are two entry points for creating CFErrors. This one does it with a presupplied userInfo dictionary.
324 CFErrorRef
CFErrorCreate(CFAllocatorRef allocator
, CFStringRef domain
, CFIndex code
, CFDictionaryRef userInfo
) {
325 __CFGenericValidateType(domain
, CFStringGetTypeID());
326 if (userInfo
) __CFGenericValidateType(userInfo
, CFDictionaryGetTypeID());
328 CFErrorRef err
= (CFErrorRef
)_CFRuntimeCreateInstance(allocator
, __kCFErrorTypeID
, sizeof(struct __CFError
) - sizeof(CFRuntimeBase
), NULL
);
329 if (NULL
== err
) return NULL
;
331 err
->domain
= CFStringCreateCopy(allocator
, domain
);
333 err
->userInfo
= userInfo
? CFDictionaryCreateCopy(allocator
, userInfo
) : _CFErrorCreateEmptyDictionary(allocator
);
338 /* 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.
340 CFErrorRef
CFErrorCreateWithUserInfoKeysAndValues(CFAllocatorRef allocator
, CFStringRef domain
, CFIndex code
, const void *const *userInfoKeys
, const void *const *userInfoValues
, CFIndex numUserInfoValues
) {
341 __CFGenericValidateType(domain
, CFStringGetTypeID());
343 CFErrorRef err
= (CFErrorRef
)_CFRuntimeCreateInstance(allocator
, __kCFErrorTypeID
, sizeof(struct __CFError
) - sizeof(CFRuntimeBase
), NULL
);
344 if (NULL
== err
) return NULL
;
346 err
->domain
= CFStringCreateCopy(allocator
, domain
);
348 err
->userInfo
= CFDictionaryCreate(allocator
, (const void **)userInfoKeys
, (const void **)userInfoValues
, numUserInfoValues
, &kCFCopyStringDictionaryKeyCallBacks
, &kCFTypeDictionaryValueCallBacks
);
353 CFStringRef
CFErrorGetDomain(CFErrorRef err
) {
354 CF_OBJC_FUNCDISPATCH0(__kCFErrorTypeID
, CFStringRef
, err
, "domain");
355 __CFAssertIsError(err
);
359 CFIndex
CFErrorGetCode(CFErrorRef err
) {
360 CF_OBJC_FUNCDISPATCH0(__kCFErrorTypeID
, CFIndex
, err
, "code");
361 __CFAssertIsError(err
);
365 /* This accessor never returns NULL. For usage inside this file, consider __CFErrorGetUserInfo().
367 CFDictionaryRef
CFErrorCopyUserInfo(CFErrorRef err
) {
368 CFDictionaryRef userInfo
= _CFErrorGetUserInfo(err
);
369 return userInfo
? (CFDictionaryRef
)CFRetain(userInfo
) : _CFErrorCreateEmptyDictionary(CFGetAllocator(err
));
372 CFStringRef
CFErrorCopyDescription(CFErrorRef err
) {
373 if (CF_IS_OBJC(__kCFErrorTypeID
, err
)) { // Since we have to return a retained result, we need to treat the toll-free bridging specially
375 CF_OBJC_CALL0(CFStringRef
, desc
, err
, "localizedDescription");
376 return desc
? (CFStringRef
)CFRetain(desc
) : NULL
; // !!! It really should never return nil.
378 __CFAssertIsError(err
);
379 return _CFErrorCreateLocalizedDescription(err
);
382 CFStringRef
CFErrorCopyFailureReason(CFErrorRef err
) {
383 if (CF_IS_OBJC(__kCFErrorTypeID
, err
)) { // Since we have to return a retained result, we need to treat the toll-free bridging specially
385 CF_OBJC_CALL0(CFStringRef
, str
, err
, "localizedFailureReason");
386 return str
? (CFStringRef
)CFRetain(str
) : NULL
; // It's possible for localizedFailureReason to return nil
388 __CFAssertIsError(err
);
389 return _CFErrorCreateLocalizedFailureReason(err
);
392 CFStringRef
CFErrorCopyRecoverySuggestion(CFErrorRef err
) {
393 if (CF_IS_OBJC(__kCFErrorTypeID
, err
)) { // Since we have to return a retained result, we need to treat the toll-free bridging specially
395 CF_OBJC_CALL0(CFStringRef
, str
, err
, "localizedRecoverySuggestion");
396 return str
? (CFStringRef
)CFRetain(str
) : NULL
; // It's possible for localizedRecoverySuggestion to return nil
398 __CFAssertIsError(err
);
399 return _CFErrorCreateLocalizedRecoverySuggestion(err
);
403 /**** CFError CallBack management ****/
405 /* Domain-to-callback mapping dictionary
407 static CFMutableDictionaryRef _CFErrorCallBackTable
= NULL
;
410 /* 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.
412 static CFTypeRef
_CFErrorPOSIXCallBack(CFErrorRef err
, CFStringRef key
) {
413 if (!CFEqual(key
, kCFErrorDescriptionKey
) && !CFEqual(key
, kCFErrorLocalizedFailureReasonKey
)) return NULL
;
415 const char *errCStr
= strerror(CFErrorGetCode(err
));
416 CFStringRef errStr
= (errCStr
&& strlen(errCStr
)) ? CFStringCreateWithCString(kCFAllocatorSystemDefault
, errCStr
, kCFStringEncodingUTF8
) : NULL
;
418 if (!errStr
) return NULL
;
419 if (CFEqual(key
, kCFErrorDescriptionKey
)) return errStr
; // If all we wanted was the non-localized description, we're done
421 // We need a kCFErrorLocalizedFailureReasonKey, so look up a possible localization for the error message
422 // Look for the bundle in /System/Library/CoreServices/CoreTypes.bundle
423 CFArrayRef paths
= CFCopySearchPathForDirectoriesInDomains(kCFLibraryDirectory
, kCFSystemDomainMask
, false);
425 if (CFArrayGetCount(paths
) > 0) {
426 CFStringRef path
= CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%@/CoreServices/CoreTypes.bundle"), CFArrayGetValueAtIndex(paths
, 0));
427 CFURLRef url
= CFURLCreateWithFileSystemPath(kCFAllocatorSystemDefault
, path
, kCFURLPOSIXPathStyle
, false /* not a directory */);
429 CFBundleRef bundle
= CFBundleCreate(kCFAllocatorSystemDefault
, url
);
431 // We only want to return a result if there was a localization
432 CFStringRef localizedErrStr
= CFBundleCopyLocalizedString(bundle
, errStr
, errStr
, CFSTR("ErrnoErrors"));
433 if (localizedErrStr
== errStr
) {
434 CFRelease(localizedErrStr
);
439 errStr
= localizedErrStr
;
453 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
454 /* Built-in callback for Mach domain.
456 static CFTypeRef
_CFErrorMachCallBack(CFErrorRef err
, CFStringRef key
) {
457 if (CFEqual(key
, kCFErrorDescriptionKey
)) {
458 const char *errStr
= mach_error_string(CFErrorGetCode(err
));
459 if (errStr
&& strlen(errStr
)) return CFStringCreateWithCString(kCFAllocatorSystemDefault
, errStr
, kCFStringEncodingUTF8
);
463 #elif DEPLOYMENT_TARGET_WINDOWS
465 #error Unknown or unspecified DEPLOYMENT_TARGET
469 /* 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.
471 static void _CFErrorInitializeCallBackTable(void) {
472 // Create the table outside the lock
473 CFMutableDictionaryRef table
= CFDictionaryCreateMutable(kCFAllocatorSystemDefault
, 0, &kCFCopyStringDictionaryKeyCallBacks
, NULL
);
474 __CFSpinLock(&_CFErrorSpinlock
);
475 if (!_CFErrorCallBackTable
) {
476 _CFErrorCallBackTable
= table
;
477 __CFSpinUnlock(&_CFErrorSpinlock
);
479 __CFSpinUnlock(&_CFErrorSpinlock
);
481 // 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.
483 CFErrorSetCallBackForDomain(kCFErrorDomainPOSIX
, _CFErrorPOSIXCallBack
);
484 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED
485 CFErrorSetCallBackForDomain(kCFErrorDomainMach
, _CFErrorMachCallBack
);
486 #elif DEPLOYMENT_TARGET_WINDOWS
488 #error Unknown or unspecified DEPLOYMENT_TARGET
492 void CFErrorSetCallBackForDomain(CFStringRef domainName
, CFErrorUserInfoKeyCallBack callBack
) {
493 if (!_CFErrorCallBackTable
) _CFErrorInitializeCallBackTable();
494 __CFSpinLock(&_CFErrorSpinlock
);
496 CFDictionarySetValue(_CFErrorCallBackTable
, domainName
, callBack
);
498 CFDictionaryRemoveValue(_CFErrorCallBackTable
, domainName
);
500 __CFSpinUnlock(&_CFErrorSpinlock
);
503 CFErrorUserInfoKeyCallBack
CFErrorGetCallBackForDomain(CFStringRef domainName
) {
504 if (!_CFErrorCallBackTable
) _CFErrorInitializeCallBackTable();
505 __CFSpinLock(&_CFErrorSpinlock
);
506 CFErrorUserInfoKeyCallBack callBack
= (CFErrorUserInfoKeyCallBack
)CFDictionaryGetValue(_CFErrorCallBackTable
, domainName
);
507 __CFSpinUnlock(&_CFErrorSpinlock
);