Home | History | Annotate | Download | only in i18n
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "base/i18n/icu_util.h"
      6 
      7 #include "build/build_config.h"
      8 
      9 #if defined(OS_WIN)
     10 #include <windows.h>
     11 #endif
     12 
     13 #include <string>
     14 
     15 #include "base/files/file_path.h"
     16 #include "base/files/memory_mapped_file.h"
     17 #include "base/logging.h"
     18 #include "base/path_service.h"
     19 #include "base/strings/string_util.h"
     20 #include "base/strings/sys_string_conversions.h"
     21 #include "third_party/icu/source/common/unicode/putil.h"
     22 #include "third_party/icu/source/common/unicode/udata.h"
     23 
     24 #if defined(OS_MACOSX)
     25 #include "base/mac/foundation_util.h"
     26 #endif
     27 
     28 #define ICU_UTIL_DATA_FILE   0
     29 #define ICU_UTIL_DATA_SHARED 1
     30 #define ICU_UTIL_DATA_STATIC 2
     31 
     32 #if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE
     33 #define ICU_UTIL_DATA_FILE_NAME "icudt" U_ICU_VERSION_SHORT "l.dat"
     34 #elif ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED
     35 #define ICU_UTIL_DATA_SYMBOL "icudt" U_ICU_VERSION_SHORT "_dat"
     36 #if defined(OS_WIN)
     37 #define ICU_UTIL_DATA_SHARED_MODULE_NAME "icudt.dll"
     38 #endif
     39 #endif
     40 
     41 namespace base {
     42 namespace i18n {
     43 
     44 bool InitializeICU() {
     45 #ifndef NDEBUG
     46   // Assert that we are not called more than once.  Even though calling this
     47   // function isn't harmful (ICU can handle it), being called twice probably
     48   // indicates a programming error.
     49   static bool called_once = false;
     50   DCHECK(!called_once);
     51   called_once = true;
     52 #endif
     53 
     54 #if (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED)
     55   // We expect to find the ICU data module alongside the current module.
     56   FilePath data_path;
     57   PathService::Get(base::DIR_MODULE, &data_path);
     58   data_path = data_path.AppendASCII(ICU_UTIL_DATA_SHARED_MODULE_NAME);
     59 
     60   HMODULE module = LoadLibrary(data_path.value().c_str());
     61   if (!module) {
     62     DLOG(ERROR) << "Failed to load " << ICU_UTIL_DATA_SHARED_MODULE_NAME;
     63     return false;
     64   }
     65 
     66   FARPROC addr = GetProcAddress(module, ICU_UTIL_DATA_SYMBOL);
     67   if (!addr) {
     68     DLOG(ERROR) << ICU_UTIL_DATA_SYMBOL << ": not found in "
     69                << ICU_UTIL_DATA_SHARED_MODULE_NAME;
     70     return false;
     71   }
     72 
     73   UErrorCode err = U_ZERO_ERROR;
     74   udata_setCommonData(reinterpret_cast<void*>(addr), &err);
     75   return err == U_ZERO_ERROR;
     76 #elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC)
     77   // The ICU data is statically linked.
     78   return true;
     79 #elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE)
     80   // If the ICU data directory is set, ICU won't actually load the data until
     81   // it is needed.  This can fail if the process is sandboxed at that time.
     82   // Instead, we map the file in and hand off the data so the sandbox won't
     83   // cause any problems.
     84 
     85   // Chrome doesn't normally shut down ICU, so the mapped data shouldn't ever
     86   // be released.
     87   CR_DEFINE_STATIC_LOCAL(base::MemoryMappedFile, mapped_file, ());
     88   if (!mapped_file.IsValid()) {
     89     // Assume it is in the framework bundle's Resources directory.
     90 #if !defined(OS_MACOSX)
     91     // For now, expect the data file to be alongside the executable.
     92     // This is sufficient while we work on unit tests, but will eventually
     93     // likely live in a data directory.
     94     FilePath data_path;
     95     bool path_ok = PathService::Get(base::DIR_EXE, &data_path);
     96     DCHECK(path_ok);
     97     data_path = data_path.AppendASCII(ICU_UTIL_DATA_FILE_NAME);
     98 #else
     99     FilePath data_path =
    100       base::mac::PathForFrameworkBundleResource(CFSTR(ICU_UTIL_DATA_FILE_NAME));
    101     if (data_path.empty()) {
    102       DLOG(ERROR) << ICU_UTIL_DATA_FILE_NAME << " not found in bundle";
    103       return false;
    104     }
    105 #endif  // OS check
    106     if (!mapped_file.Initialize(data_path)) {
    107       DLOG(ERROR) << "Couldn't mmap " << data_path.value();
    108       return false;
    109     }
    110   }
    111   UErrorCode err = U_ZERO_ERROR;
    112   udata_setCommonData(const_cast<uint8*>(mapped_file.data()), &err);
    113   return err == U_ZERO_ERROR;
    114 #endif
    115 }
    116 
    117 }  // namespace i18n
    118 }  // namespace base
    119