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 #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 
     49 static Mutex& mainBundleLocStringsMutex()
     50 {
     51     DEFINE_STATIC_LOCAL(Mutex, mutex, ());
     52     return mutex;
     53 }
     54 
     55 static LocalizedStringMap& mainBundleLocStrings()
     56 {
     57     DEFINE_STATIC_LOCAL(LocalizedStringMap, map, ());
     58     return map;
     59 }
     60 
     61 static Mutex& frameworkLocStringsMutex()
     62 {
     63     DEFINE_STATIC_LOCAL(Mutex, mutex, ());
     64     return mutex;
     65 }
     66 
     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:
     76     LocalizedString(CFStringRef string)
     77         : m_cfString(string)
     78     {
     79         ASSERT_ARG(string, string);
     80     }
     81 
     82     operator LPCTSTR() const;
     83     operator CFStringRef() const { return m_cfString; }
     84 
     85 private:
     86     CFStringRef m_cfString;
     87     mutable String m_string;
     88 };
     89 
     90 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 
    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 
    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 
    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 
    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 
    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 
    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 
    219 CFStringRef WebLocalizedStringUTF8(WebLocalizableStringsBundle* stringsBundle, LPCSTR key)
    220 {
    221     if (!key)
    222         return 0;
    223 
    224     return localizedString(stringsBundle, String::fromUTF8(key));
    225 }
    226 
    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 
    237 CFStringRef WebLocalizedString(WebLocalizableStringsBundle* stringsBundle, LPCTSTR key)
    238 {
    239     if (!key)
    240         return 0;
    241 
    242     return localizedString(stringsBundle, String(key));
    243 }
    244 
    245 LPCTSTR WebLocalizedLPCTSTR(WebLocalizableStringsBundle* stringsBundle, LPCTSTR key)
    246 {
    247     if (!key)
    248         return 0;
    249 
    250     return localizedString(stringsBundle, String(key));
    251 }
    252 
    253 void SetWebLocalizedStringMainBundle(CFBundleRef)
    254 {
    255 }
    256