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