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