]> git.saurik.com Git - apple/cf.git/blob - CFBundle_Strings.c
CF-1151.16.tar.gz
[apple/cf.git] / CFBundle_Strings.c
1 /*
2 * Copyright (c) 2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /* CFBundle_Strings.c
25 Copyright (c) 1999-2014, Apple Inc. All rights reserved.
26 Responsibility: Tony Parker
27 */
28
29 #include "CFBundle_Internal.h"
30 #if DEPLOYMENT_TARGET_MACOSX
31
32 #endif
33
34 #include <CoreFoundation/CFPreferences.h>
35 #include <CoreFoundation/CFURLAccess.h>
36
37 #pragma mark -
38 #pragma mark Localized Strings
39
40
41 CF_EXPORT CFStringRef CFBundleCopyLocalizedString(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName) {
42 return CFBundleCopyLocalizedStringForLocalization(bundle, key, value, tableName, NULL);
43 }
44
45 CF_EXPORT CFStringRef CFBundleCopyLocalizedStringForLocalization(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName, CFStringRef localizationName) {
46 CFStringRef result = NULL;
47 CFDictionaryRef stringTable = NULL;
48
49 if (!key) return (value ? (CFStringRef)CFRetain(value) : (CFStringRef)CFRetain(CFSTR("")));
50
51 // Make sure to check the mixed localizations key early -- if the main bundle has not yet been cached, then we need to create the cache of the Info.plist before we start asking for resources (11172381)
52 (void)CFBundleAllowMixedLocalizations();
53
54 if (!tableName || CFEqual(tableName, CFSTR(""))) tableName = _CFBundleDefaultStringTableName;
55
56 __CFLock(&bundle->_lock);
57 // Only consult the cache when a specific localization has not been requested. We only cache results for the preferred language as determined by normal bundle lookup rules.
58 if (!localizationName && bundle->_stringTable) {
59 stringTable = (CFDictionaryRef)CFDictionaryGetValue(bundle->_stringTable, tableName);
60 if (stringTable) CFRetain(stringTable);
61 }
62
63 if (!stringTable) {
64 // Go load the table. First, unlock so we don't hold the lock across file system access.
65 __CFUnlock(&bundle->_lock);
66
67 CFURLRef tableURL = NULL;
68 if (localizationName) {
69 tableURL = CFBundleCopyResourceURLForLocalization(bundle, tableName, _CFBundleStringTableType, NULL, localizationName);
70 } else {
71 tableURL = CFBundleCopyResourceURL(bundle, tableName, _CFBundleStringTableType, NULL);
72 }
73
74 if (tableURL) {
75 CFStringRef nameForSharing = NULL;
76 if (!stringTable) {
77 CFDataRef tableData = NULL;
78 SInt32 errCode;
79 #pragma GCC diagnostic push
80 #pragma GCC diagnostic ignored "-Wdeprecated"
81 if (CFURLCreateDataAndPropertiesFromResource(kCFAllocatorSystemDefault, tableURL, &tableData, NULL, NULL, &errCode)) {
82 #pragma GCC diagnostic pop
83 CFErrorRef error = NULL;
84 stringTable = (CFDictionaryRef)CFPropertyListCreateWithData(CFGetAllocator(bundle), tableData, kCFPropertyListImmutable, NULL, &error);
85 if (stringTable && CFDictionaryGetTypeID() != CFGetTypeID(stringTable)) {
86 CFRelease(stringTable);
87 stringTable = NULL;
88 }
89 if (!stringTable && error) {
90 CFLog(kCFLogLevelError, CFSTR("Unable to load string table file: %@ / %@: %@"), bundle, tableName, error);
91 CFRelease(error);
92 error = NULL;
93 }
94 CFRelease(tableData);
95
96 }
97 }
98 if (nameForSharing) CFRelease(nameForSharing);
99 if (tableURL) CFRelease(tableURL);
100 }
101 if (!stringTable) stringTable = CFDictionaryCreate(CFGetAllocator(bundle), NULL, NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
102
103 if ((!CFStringHasSuffix(tableName, CFSTR(".nocache")) || !_CFExecutableLinkedOnOrAfter(CFSystemVersionLeopard)) && localizationName == NULL) {
104 // Take lock again, because this we will unlock after getting the value out of the table.
105 __CFLock(&bundle->_lock);
106 if (!bundle->_stringTable) bundle->_stringTable = CFDictionaryCreateMutable(CFGetAllocator(bundle), 0, &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
107
108 // If another thread beat us to setting this tableName, then we'll just replace it here.
109 CFDictionarySetValue(bundle->_stringTable, tableName, stringTable);
110 } else {
111 // Take lock again, because this we will unlock after getting the value out of the table.
112 __CFLock(&bundle->_lock);
113 }
114 }
115
116 result = (CFStringRef)CFDictionaryGetValue(stringTable, key);
117 if (result) {
118 CFRetain(result);
119 }
120
121 __CFUnlock(&bundle->_lock);
122 CFRelease(stringTable);
123
124 if (!result) {
125 if (!value) {
126 result = (CFStringRef)CFRetain(key);
127 } else if (CFEqual(value, CFSTR(""))) {
128 result = (CFStringRef)CFRetain(key);
129 } else {
130 result = (CFStringRef)CFRetain(value);
131 }
132 static Boolean capitalize = false;
133 if (capitalize) {
134 CFMutableStringRef capitalizedResult = CFStringCreateMutableCopy(kCFAllocatorSystemDefault, 0, result);
135 CFLog(__kCFLogBundle, CFSTR("Localizable string \"%@\" not found in strings table \"%@\" of bundle %@."), key, tableName, bundle);
136 CFStringUppercase(capitalizedResult, NULL);
137 CFRelease(result);
138 result = capitalizedResult;
139 }
140 }
141
142 return result;
143 }
144