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/CString.h>
33 #include <WebCore/PlatformString.h>
34 #include <WebCore/StringHash.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
mainBundleLocStringsMutex()51 static Mutex& mainBundleLocStringsMutex()
52 {
53 DEFINE_STATIC_LOCAL(Mutex, mutex, ());
54 return mutex;
55 }
56
mainBundleLocStrings()57 static LocalizedStringMap& mainBundleLocStrings()
58 {
59 DEFINE_STATIC_LOCAL(LocalizedStringMap, map, ());
60 return map;
61 }
62
frameworkLocStringsMutex()63 static Mutex& frameworkLocStringsMutex()
64 {
65 DEFINE_STATIC_LOCAL(Mutex, mutex, ());
66 return mutex;
67 }
68
frameworkLocStrings()69 static LocalizedStringMap frameworkLocStrings()
70 {
71 DEFINE_STATIC_LOCAL(LocalizedStringMap, map, ());
72 return map;
73 }
74
75 class LocalizedString : public Noncopyable {
76 public:
LocalizedString(CFStringRef string)77 LocalizedString(CFStringRef string)
78 : m_cfString(string)
79 {
80 ASSERT_ARG(string, string);
81 }
82
83 operator LPCTSTR() const;
operator CFStringRef() const84 operator CFStringRef() const { return m_cfString; }
85
86 private:
87 CFStringRef m_cfString;
88 mutable String m_string;
89 };
90
operator LPCTSTR() const91 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
createWebKitBundle()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
cfBundleForStringsBundle(WebLocalizableStringsBundle * stringsBundle)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
copyLocalizedStringFromBundle(WebLocalizableStringsBundle * stringsBundle,const String & key)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
findCachedString(WebLocalizableStringsBundle * stringsBundle,const String & key)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
cacheString(WebLocalizableStringsBundle * stringsBundle,const String & key,LocalizedString * value)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
localizedString(WebLocalizableStringsBundle * stringsBundle,const String & key)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
WebLocalizedStringUTF8(WebLocalizableStringsBundle * stringsBundle,LPCSTR key)220 CFStringRef WebLocalizedStringUTF8(WebLocalizableStringsBundle* stringsBundle, LPCSTR key)
221 {
222 if (!key)
223 return 0;
224
225 return localizedString(stringsBundle, String::fromUTF8(key));
226 }
227
WebLocalizedLPCTSTRUTF8(WebLocalizableStringsBundle * stringsBundle,LPCSTR key)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
WebLocalizedString(WebLocalizableStringsBundle * stringsBundle,LPCTSTR key)238 CFStringRef WebLocalizedString(WebLocalizableStringsBundle* stringsBundle, LPCTSTR key)
239 {
240 if (!key)
241 return 0;
242
243 return localizedString(stringsBundle, String(key));
244 }
245
WebLocalizedLPCTSTR(WebLocalizableStringsBundle * stringsBundle,LPCTSTR key)246 LPCTSTR WebLocalizedLPCTSTR(WebLocalizableStringsBundle* stringsBundle, LPCTSTR key)
247 {
248 if (!key)
249 return 0;
250
251 return localizedString(stringsBundle, String(key));
252 }
253
SetWebLocalizedStringMainBundle(CFBundleRef)254 void SetWebLocalizedStringMainBundle(CFBundleRef)
255 {
256 }
257