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 <CoreFoundation/CoreFoundation.h>
41
42 class LocalizedString;
43
44 using namespace WebCore;
45
46 WebLocalizableStringsBundle WebKitLocalizableStringsBundle = { "com.apple.WebKit", 0 };
47
48 static HashMap<String, LocalizedString*> mainBundleLocStrings;
49 static HashMap<String, LocalizedString*> frameworkLocStrings;
50
51 class LocalizedString : public Noncopyable {
52 public:
LocalizedString(CFStringRef string)53 LocalizedString(CFStringRef string)
54 : m_cfString(string)
55 {
56 ASSERT_ARG(string, string);
57 }
58
59 operator LPCTSTR() const;
operator CFStringRef() const60 operator CFStringRef() const { return m_cfString; }
61
62 private:
63 CFStringRef m_cfString;
64 mutable String m_string;
65 };
66
operator LPCTSTR() const67 LocalizedString::operator LPCTSTR() const
68 {
69 if (!m_string.isEmpty())
70 return m_string.charactersWithNullTermination();
71
72 m_string = m_cfString;
73
74 for (unsigned int i = 1; i < m_string.length(); i++)
75 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] == '%')))
76 m_string.replace(i, 1, "s");
77
78 return m_string.charactersWithNullTermination();
79 }
80
createWebKitBundle()81 static CFBundleRef createWebKitBundle()
82 {
83 static CFBundleRef bundle;
84 static bool initialized;
85
86 if (initialized)
87 return bundle;
88 initialized = true;
89
90 WCHAR pathStr[MAX_PATH];
91 DWORD length = ::GetModuleFileNameW(gInstance, pathStr, MAX_PATH);
92 if (!length || (length == MAX_PATH && GetLastError() == ERROR_INSUFFICIENT_BUFFER))
93 return 0;
94
95 bool found = false;
96 for (int i = length - 1; i >= 0; i--) {
97 // warning C6385: Invalid data: accessing 'pathStr', the readable size is '520' bytes, but '2000' bytes might be read
98 #pragma warning(suppress: 6385)
99 if (pathStr[i] == L'\\') {
100 // warning C6386: Buffer overrun: accessing 'pathStr', the writable size is '520' bytes, but '1996' bytes might be written
101 #pragma warning(suppress: 6386)
102 pathStr[i] = 0;
103 found = true;
104 break;
105 }
106 }
107 if (!found)
108 return 0;
109
110 if (wcscat_s(pathStr, MAX_PATH, L"\\WebKit.resources"))
111 return 0;
112
113 String bundlePathString(pathStr);
114 CFStringRef bundlePathCFString = bundlePathString.createCFString();
115 if (!bundlePathCFString)
116 return 0;
117
118 CFURLRef bundleURLRef = CFURLCreateWithFileSystemPath(0, bundlePathCFString, kCFURLWindowsPathStyle, true);
119 CFRelease(bundlePathCFString);
120 if (!bundleURLRef)
121 return 0;
122
123 bundle = CFBundleCreate(0, bundleURLRef);
124 CFRelease(bundleURLRef);
125 return bundle;
126 }
127
cfBundleForStringsBundle(WebLocalizableStringsBundle * stringsBundle)128 static CFBundleRef cfBundleForStringsBundle(WebLocalizableStringsBundle* stringsBundle)
129 {
130 if (!stringsBundle) {
131 static CFBundleRef mainBundle = CFBundleGetMainBundle();
132 return mainBundle;
133 }
134
135 createWebKitBundle();
136
137 if (!stringsBundle->bundle)
138 stringsBundle->bundle = CFBundleGetBundleWithIdentifier(RetainPtr<CFStringRef>(AdoptCF, CFStringCreateWithCString(0, stringsBundle->identifier, kCFStringEncodingASCII)).get());
139 return stringsBundle->bundle;
140 }
141
copyLocalizedStringFromBundle(WebLocalizableStringsBundle * stringsBundle,const String & key)142 static CFStringRef copyLocalizedStringFromBundle(WebLocalizableStringsBundle* stringsBundle, const String& key)
143 {
144 static CFStringRef notFound = CFSTR("localized string not found");
145
146 CFBundleRef bundle = cfBundleForStringsBundle(stringsBundle);
147 if (!bundle)
148 return notFound;
149
150 RetainPtr<CFStringRef> keyString(AdoptCF, key.createCFString());
151 CFStringRef result = CFCopyLocalizedStringWithDefaultValue(keyString.get(), 0, bundle, notFound, 0);
152
153 ASSERT_WITH_MESSAGE(result != notFound, "could not find localizable string %s in bundle", key);
154 return result;
155 }
156
findCachedString(WebLocalizableStringsBundle * stringsBundle,const String & key)157 static LocalizedString* findCachedString(WebLocalizableStringsBundle* stringsBundle, const String& key)
158 {
159 if (!stringsBundle)
160 return mainBundleLocStrings.get(key);
161
162 if (stringsBundle->bundle == WebKitLocalizableStringsBundle.bundle)
163 return frameworkLocStrings.get(key);
164
165 return 0;
166 }
167
cacheString(WebLocalizableStringsBundle * stringsBundle,const String & key,LocalizedString * value)168 static void cacheString(WebLocalizableStringsBundle* stringsBundle, const String& key, LocalizedString* value)
169 {
170 if (!stringsBundle) {
171 mainBundleLocStrings.set(key, value);
172 return;
173 }
174
175 frameworkLocStrings.set(key, value);
176 }
177
localizedString(WebLocalizableStringsBundle * stringsBundle,const String & key)178 static const LocalizedString& localizedString(WebLocalizableStringsBundle* stringsBundle, const String& key)
179 {
180 LocalizedString* string = findCachedString(stringsBundle, key);
181 if (string)
182 return *string;
183
184 string = new LocalizedString(copyLocalizedStringFromBundle(stringsBundle, key));
185 cacheString(stringsBundle, key, string);
186
187 return *string;
188 }
189
WebLocalizedStringUTF8(WebLocalizableStringsBundle * stringsBundle,LPCSTR key)190 CFStringRef WebLocalizedStringUTF8(WebLocalizableStringsBundle* stringsBundle, LPCSTR key)
191 {
192 if (!key)
193 return 0;
194
195 return localizedString(stringsBundle, String::fromUTF8(key));
196 }
197
WebLocalizedLPCTSTRUTF8(WebLocalizableStringsBundle * stringsBundle,LPCSTR key)198 LPCTSTR WebLocalizedLPCTSTRUTF8(WebLocalizableStringsBundle* stringsBundle, LPCSTR key)
199 {
200 if (!key)
201 return 0;
202
203 return localizedString(stringsBundle, String::fromUTF8(key));
204 }
205
206 // These functions are deprecated.
207
WebLocalizedString(WebLocalizableStringsBundle * stringsBundle,LPCTSTR key)208 CFStringRef WebLocalizedString(WebLocalizableStringsBundle* stringsBundle, LPCTSTR key)
209 {
210 if (!key)
211 return 0;
212
213 return localizedString(stringsBundle, String(key));
214 }
215
WebLocalizedLPCTSTR(WebLocalizableStringsBundle * stringsBundle,LPCTSTR key)216 LPCTSTR WebLocalizedLPCTSTR(WebLocalizableStringsBundle* stringsBundle, LPCTSTR key)
217 {
218 if (!key)
219 return 0;
220
221 return localizedString(stringsBundle, String(key));
222 }
223
SetWebLocalizedStringMainBundle(CFBundleRef)224 void SetWebLocalizedStringMainBundle(CFBundleRef)
225 {
226 }
227