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 <wtf/text/CString.h> 32#include <wtf/text/StringHash.h> 33#include <wtf/text/WTFString.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 41class LocalizedString; 42 43WebLocalizableStringsBundle WebKitLocalizableStringsBundle = { "com.apple.WebKit", 0 }; 44 45typedef HashMap<String, LocalizedString*> LocalizedStringMap; 46 47static Mutex& mainBundleLocStringsMutex() 48{ 49 DEFINE_STATIC_LOCAL(Mutex, mutex, ()); 50 return mutex; 51} 52 53static LocalizedStringMap& mainBundleLocStrings() 54{ 55 DEFINE_STATIC_LOCAL(LocalizedStringMap, map, ()); 56 return map; 57} 58 59static Mutex& frameworkLocStringsMutex() 60{ 61 DEFINE_STATIC_LOCAL(Mutex, mutex, ()); 62 return mutex; 63} 64 65static LocalizedStringMap frameworkLocStrings() 66{ 67 DEFINE_STATIC_LOCAL(LocalizedStringMap, map, ()); 68 return map; 69} 70 71class LocalizedString { 72 WTF_MAKE_NONCOPYABLE(LocalizedString); 73public: 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 83private: 84 CFStringRef m_cfString; 85 mutable String m_string; 86}; 87 88LocalizedString::operator LPCTSTR() const 89{ 90 if (!m_string.isEmpty()) 91 return m_string.charactersWithNullTermination(); 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(); 100} 101 102static 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 147static 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 161static 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 175static LocalizedString* findCachedString(WebLocalizableStringsBundle* stringsBundle, const String& key) 176{ 177 if (!stringsBundle) { 178 MutexLocker lock(mainBundleLocStringsMutex()); 179 return mainBundleLocStrings().get(key); 180 } 181 182 if (stringsBundle->bundle == WebKitLocalizableStringsBundle.bundle) { 183 MutexLocker lock(frameworkLocStringsMutex()); 184 return frameworkLocStrings().get(key); 185 } 186 187 return 0; 188} 189 190static void cacheString(WebLocalizableStringsBundle* stringsBundle, const String& key, LocalizedString* value) 191{ 192 if (!stringsBundle) { 193 MutexLocker lock(mainBundleLocStringsMutex()); 194 mainBundleLocStrings().set(key, value); 195 return; 196 } 197 198 MutexLocker lock(frameworkLocStringsMutex()); 199 frameworkLocStrings().set(key, value); 200} 201 202static 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 214CFStringRef WebLocalizedStringUTF8(WebLocalizableStringsBundle* stringsBundle, LPCSTR key) 215{ 216 if (!key) 217 return 0; 218 219 return localizedString(stringsBundle, String::fromUTF8(key)); 220} 221 222LPCTSTR 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 232CFStringRef WebLocalizedString(WebLocalizableStringsBundle* stringsBundle, LPCTSTR key) 233{ 234 if (!key) 235 return 0; 236 237 return localizedString(stringsBundle, String(key)); 238} 239 240LPCTSTR WebLocalizedLPCTSTR(WebLocalizableStringsBundle* stringsBundle, LPCTSTR key) 241{ 242 if (!key) 243 return 0; 244 245 return localizedString(stringsBundle, String(key)); 246} 247 248void SetWebLocalizedStringMainBundle(CFBundleRef) 249{ 250} 251