• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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