Home | History | Annotate | Download | only in win
      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 
     51 static Mutex& mainBundleLocStringsMutex()
     52 {
     53     DEFINE_STATIC_LOCAL(Mutex, mutex, ());
     54     return mutex;
     55 }
     56 
     57 static LocalizedStringMap& mainBundleLocStrings()
     58 {
     59     DEFINE_STATIC_LOCAL(LocalizedStringMap, map, ());
     60     return map;
     61 }
     62 
     63 static Mutex& frameworkLocStringsMutex()
     64 {
     65     DEFINE_STATIC_LOCAL(Mutex, mutex, ());
     66     return mutex;
     67 }
     68 
     69 static LocalizedStringMap frameworkLocStrings()
     70 {
     71     DEFINE_STATIC_LOCAL(LocalizedStringMap, map, ());
     72     return map;
     73 }
     74 
     75 class LocalizedString : public Noncopyable {
     76 public:
     77     LocalizedString(CFStringRef string)
     78         : m_cfString(string)
     79     {
     80         ASSERT_ARG(string, string);
     81     }
     82 
     83     operator LPCTSTR() const;
     84     operator CFStringRef() const { return m_cfString; }
     85 
     86 private:
     87     CFStringRef m_cfString;
     88     mutable String m_string;
     89 };
     90 
     91 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 
    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 
    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 
    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 
    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 
    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 
    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 
    220 CFStringRef WebLocalizedStringUTF8(WebLocalizableStringsBundle* stringsBundle, LPCSTR key)
    221 {
    222     if (!key)
    223         return 0;
    224 
    225     return localizedString(stringsBundle, String::fromUTF8(key));
    226 }
    227 
    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 
    238 CFStringRef WebLocalizedString(WebLocalizableStringsBundle* stringsBundle, LPCTSTR key)
    239 {
    240     if (!key)
    241         return 0;
    242 
    243     return localizedString(stringsBundle, String(key));
    244 }
    245 
    246 LPCTSTR WebLocalizedLPCTSTR(WebLocalizableStringsBundle* stringsBundle, LPCTSTR key)
    247 {
    248     if (!key)
    249         return 0;
    250 
    251     return localizedString(stringsBundle, String(key));
    252 }
    253 
    254 void SetWebLocalizedStringMainBundle(CFBundleRef)
    255 {
    256 }
    257