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