|
1 /* |
|
2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. |
|
3 * |
|
4 * Redistribution and use in source and binary forms, with or without |
|
5 * modification, are permitted provided that the following conditions |
|
6 * are met: |
|
7 * 1. Redistributions of source code must retain the above copyright |
|
8 * notice, this list of conditions and the following disclaimer. |
|
9 * 2. Redistributions in binary form must reproduce the above copyright |
|
10 * notice, this list of conditions and the following disclaimer in the |
|
11 * documentation and/or other materials provided with the distribution. |
|
12 * |
|
13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
|
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
|
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
|
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
24 */ |
|
25 |
|
26 #include "config.h" |
|
27 #include "WebKitDLL.h" |
|
28 |
|
29 #include "WebLocalizableStrings.h" |
|
30 |
|
31 #pragma warning(push, 0) |
|
32 #include <WebCore/PlatformString.h> |
|
33 #include <WebCore/StringHash.h> |
|
34 #include <wtf/text/CString.h> |
|
35 #pragma warning(pop) |
|
36 |
|
37 #include <wtf/Assertions.h> |
|
38 #include <wtf/HashMap.h> |
|
39 #include <wtf/RetainPtr.h> |
|
40 #include <wtf/StdLibExtras.h> |
|
41 #include <CoreFoundation/CoreFoundation.h> |
|
42 |
|
43 class LocalizedString; |
|
44 |
|
45 using namespace WebCore; |
|
46 |
|
47 WebLocalizableStringsBundle WebKitLocalizableStringsBundle = { "com.apple.WebKit", 0 }; |
|
48 |
|
49 typedef HashMap<String, LocalizedString*> LocalizedStringMap; |
|
50 |
|
51 static Mutex& mainBundleLocStringsMutex() |
|
52 { |
|
53 DEFINE_STATIC_LOCAL(Mutex, mutex, ()); |
|
54 return mutex; |
|
55 } |
|
56 |
|
57 static LocalizedStringMap& mainBundleLocStrings() |
|
58 { |
|
59 DEFINE_STATIC_LOCAL(LocalizedStringMap, map, ()); |
|
60 return map; |
|
61 } |
|
62 |
|
63 static Mutex& frameworkLocStringsMutex() |
|
64 { |
|
65 DEFINE_STATIC_LOCAL(Mutex, mutex, ()); |
|
66 return mutex; |
|
67 } |
|
68 |
|
69 static LocalizedStringMap frameworkLocStrings() |
|
70 { |
|
71 DEFINE_STATIC_LOCAL(LocalizedStringMap, map, ()); |
|
72 return map; |
|
73 } |
|
74 |
|
75 class LocalizedString : public Noncopyable { |
|
76 public: |
|
77 LocalizedString(CFStringRef string) |
|
78 : m_cfString(string) |
|
79 { |
|
80 ASSERT_ARG(string, string); |
|
81 } |
|
82 |
|
83 operator LPCTSTR() const; |
|
84 operator CFStringRef() const { return m_cfString; } |
|
85 |
|
86 private: |
|
87 CFStringRef m_cfString; |
|
88 mutable String m_string; |
|
89 }; |
|
90 |
|
91 LocalizedString::operator LPCTSTR() const |
|
92 { |
|
93 if (!m_string.isEmpty()) |
|
94 return m_string.charactersWithNullTermination(); |
|
95 |
|
96 m_string = m_cfString; |
|
97 |
|
98 for (unsigned int i = 1; i < m_string.length(); i++) |
|
99 if (m_string[i] == '@' && (m_string[i - 1] == '%' || (i > 2 && m_string[i - 1] == '$' && m_string[i - 2] >= '1' && m_string[i - 2] <= '9' && m_string[i - 3] == '%'))) |
|
100 m_string.replace(i, 1, "s"); |
|
101 |
|
102 return m_string.charactersWithNullTermination(); |
|
103 } |
|
104 |
|
105 static CFBundleRef createWebKitBundle() |
|
106 { |
|
107 static CFBundleRef bundle; |
|
108 static bool initialized; |
|
109 |
|
110 if (initialized) |
|
111 return bundle; |
|
112 initialized = true; |
|
113 |
|
114 WCHAR pathStr[MAX_PATH]; |
|
115 DWORD length = ::GetModuleFileNameW(gInstance, pathStr, MAX_PATH); |
|
116 if (!length || (length == MAX_PATH && GetLastError() == ERROR_INSUFFICIENT_BUFFER)) |
|
117 return 0; |
|
118 |
|
119 bool found = false; |
|
120 for (int i = length - 1; i >= 0; i--) { |
|
121 // warning C6385: Invalid data: accessing 'pathStr', the readable size is '520' bytes, but '2000' bytes might be read |
|
122 #pragma warning(suppress: 6385) |
|
123 if (pathStr[i] == L'\\') { |
|
124 // warning C6386: Buffer overrun: accessing 'pathStr', the writable size is '520' bytes, but '1996' bytes might be written |
|
125 #pragma warning(suppress: 6386) |
|
126 pathStr[i] = 0; |
|
127 found = true; |
|
128 break; |
|
129 } |
|
130 } |
|
131 if (!found) |
|
132 return 0; |
|
133 |
|
134 if (wcscat_s(pathStr, MAX_PATH, L"\\WebKit.resources")) |
|
135 return 0; |
|
136 |
|
137 String bundlePathString(pathStr); |
|
138 CFStringRef bundlePathCFString = bundlePathString.createCFString(); |
|
139 if (!bundlePathCFString) |
|
140 return 0; |
|
141 |
|
142 CFURLRef bundleURLRef = CFURLCreateWithFileSystemPath(0, bundlePathCFString, kCFURLWindowsPathStyle, true); |
|
143 CFRelease(bundlePathCFString); |
|
144 if (!bundleURLRef) |
|
145 return 0; |
|
146 |
|
147 bundle = CFBundleCreate(0, bundleURLRef); |
|
148 CFRelease(bundleURLRef); |
|
149 return bundle; |
|
150 } |
|
151 |
|
152 static CFBundleRef cfBundleForStringsBundle(WebLocalizableStringsBundle* stringsBundle) |
|
153 { |
|
154 if (!stringsBundle) { |
|
155 static CFBundleRef mainBundle = CFBundleGetMainBundle(); |
|
156 return mainBundle; |
|
157 } |
|
158 |
|
159 createWebKitBundle(); |
|
160 |
|
161 if (!stringsBundle->bundle) |
|
162 stringsBundle->bundle = CFBundleGetBundleWithIdentifier(RetainPtr<CFStringRef>(AdoptCF, CFStringCreateWithCString(0, stringsBundle->identifier, kCFStringEncodingASCII)).get()); |
|
163 return stringsBundle->bundle; |
|
164 } |
|
165 |
|
166 static CFStringRef copyLocalizedStringFromBundle(WebLocalizableStringsBundle* stringsBundle, const String& key) |
|
167 { |
|
168 static CFStringRef notFound = CFSTR("localized string not found"); |
|
169 |
|
170 CFBundleRef bundle = cfBundleForStringsBundle(stringsBundle); |
|
171 if (!bundle) |
|
172 return notFound; |
|
173 |
|
174 RetainPtr<CFStringRef> keyString(AdoptCF, key.createCFString()); |
|
175 CFStringRef result = CFCopyLocalizedStringWithDefaultValue(keyString.get(), 0, bundle, notFound, 0); |
|
176 |
|
177 ASSERT_WITH_MESSAGE(result != notFound, "could not find localizable string %s in bundle", key); |
|
178 return result; |
|
179 } |
|
180 |
|
181 static LocalizedString* findCachedString(WebLocalizableStringsBundle* stringsBundle, const String& key) |
|
182 { |
|
183 if (!stringsBundle) { |
|
184 MutexLocker lock(mainBundleLocStringsMutex()); |
|
185 return mainBundleLocStrings().get(key); |
|
186 } |
|
187 |
|
188 if (stringsBundle->bundle == WebKitLocalizableStringsBundle.bundle) { |
|
189 MutexLocker lock(frameworkLocStringsMutex()); |
|
190 return frameworkLocStrings().get(key); |
|
191 } |
|
192 |
|
193 return 0; |
|
194 } |
|
195 |
|
196 static void cacheString(WebLocalizableStringsBundle* stringsBundle, const String& key, LocalizedString* value) |
|
197 { |
|
198 if (!stringsBundle) { |
|
199 MutexLocker lock(mainBundleLocStringsMutex()); |
|
200 mainBundleLocStrings().set(key, value); |
|
201 return; |
|
202 } |
|
203 |
|
204 MutexLocker lock(frameworkLocStringsMutex()); |
|
205 frameworkLocStrings().set(key, value); |
|
206 } |
|
207 |
|
208 static const LocalizedString& localizedString(WebLocalizableStringsBundle* stringsBundle, const String& key) |
|
209 { |
|
210 LocalizedString* string = findCachedString(stringsBundle, key); |
|
211 if (string) |
|
212 return *string; |
|
213 |
|
214 string = new LocalizedString(copyLocalizedStringFromBundle(stringsBundle, key)); |
|
215 cacheString(stringsBundle, key, string); |
|
216 |
|
217 return *string; |
|
218 } |
|
219 |
|
220 CFStringRef WebLocalizedStringUTF8(WebLocalizableStringsBundle* stringsBundle, LPCSTR key) |
|
221 { |
|
222 if (!key) |
|
223 return 0; |
|
224 |
|
225 return localizedString(stringsBundle, String::fromUTF8(key)); |
|
226 } |
|
227 |
|
228 LPCTSTR WebLocalizedLPCTSTRUTF8(WebLocalizableStringsBundle* stringsBundle, LPCSTR key) |
|
229 { |
|
230 if (!key) |
|
231 return 0; |
|
232 |
|
233 return localizedString(stringsBundle, String::fromUTF8(key)); |
|
234 } |
|
235 |
|
236 // These functions are deprecated. |
|
237 |
|
238 CFStringRef WebLocalizedString(WebLocalizableStringsBundle* stringsBundle, LPCTSTR key) |
|
239 { |
|
240 if (!key) |
|
241 return 0; |
|
242 |
|
243 return localizedString(stringsBundle, String(key)); |
|
244 } |
|
245 |
|
246 LPCTSTR WebLocalizedLPCTSTR(WebLocalizableStringsBundle* stringsBundle, LPCTSTR key) |
|
247 { |
|
248 if (!key) |
|
249 return 0; |
|
250 |
|
251 return localizedString(stringsBundle, String(key)); |
|
252 } |
|
253 |
|
254 void SetWebLocalizedStringMainBundle(CFBundleRef) |
|
255 { |
|
256 } |