icu_util.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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/file_util.h" 16#include "base/files/file_path.h" 17#include "base/files/memory_mapped_file.h" 18#include "base/logging.h" 19#include "base/path_service.h" 20#include "base/string_util.h" 21#include "base/strings/sys_string_conversions.h" 22#include "third_party/icu/public/common/unicode/putil.h" 23#include "third_party/icu/public/common/unicode/udata.h" 24 25#if defined(OS_MACOSX) 26#include "base/mac/foundation_util.h" 27#endif 28 29#define ICU_UTIL_DATA_FILE 0 30#define ICU_UTIL_DATA_SHARED 1 31#define ICU_UTIL_DATA_STATIC 2 32 33#ifndef ICU_UTIL_DATA_IMPL 34 35#if defined(OS_WIN) 36#define ICU_UTIL_DATA_IMPL ICU_UTIL_DATA_SHARED 37#elif defined(OS_IOS) 38#define ICU_UTIL_DATA_IMPL ICU_UTIL_DATA_FILE 39#else 40#define ICU_UTIL_DATA_IMPL ICU_UTIL_DATA_STATIC 41#endif 42 43#endif // ICU_UTIL_DATA_IMPL 44 45#if ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE 46#define ICU_UTIL_DATA_FILE_NAME "icudt" U_ICU_VERSION_SHORT "l.dat" 47#elif ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED 48#define ICU_UTIL_DATA_SYMBOL "icudt" U_ICU_VERSION_SHORT "_dat" 49#if defined(OS_WIN) 50#define ICU_UTIL_DATA_SHARED_MODULE_NAME "icudt.dll" 51#endif 52#endif 53 54using base::FilePath; 55 56namespace icu_util { 57 58bool Initialize() { 59#ifndef NDEBUG 60 // Assert that we are not called more than once. Even though calling this 61 // function isn't harmful (ICU can handle it), being called twice probably 62 // indicates a programming error. 63 static bool called_once = false; 64 DCHECK(!called_once); 65 called_once = true; 66#endif 67 68#if (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_SHARED) 69 // We expect to find the ICU data module alongside the current module. 70 FilePath data_path; 71 PathService::Get(base::DIR_MODULE, &data_path); 72 data_path = data_path.AppendASCII(ICU_UTIL_DATA_SHARED_MODULE_NAME); 73 74 HMODULE module = LoadLibrary(data_path.value().c_str()); 75 if (!module) { 76 DLOG(ERROR) << "Failed to load " << ICU_UTIL_DATA_SHARED_MODULE_NAME; 77 return false; 78 } 79 80 FARPROC addr = GetProcAddress(module, ICU_UTIL_DATA_SYMBOL); 81 if (!addr) { 82 DLOG(ERROR) << ICU_UTIL_DATA_SYMBOL << ": not found in " 83 << ICU_UTIL_DATA_SHARED_MODULE_NAME; 84 return false; 85 } 86 87 UErrorCode err = U_ZERO_ERROR; 88 udata_setCommonData(reinterpret_cast<void*>(addr), &err); 89 return err == U_ZERO_ERROR; 90#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_STATIC) 91 // Mac/Linux bundle the ICU data in. 92 return true; 93#elif (ICU_UTIL_DATA_IMPL == ICU_UTIL_DATA_FILE) 94#if !defined(OS_MACOSX) 95 // For now, expect the data file to be alongside the executable. 96 // This is sufficient while we work on unit tests, but will eventually 97 // likely live in a data directory. 98 FilePath data_path; 99 bool path_ok = PathService::Get(base::DIR_EXE, &data_path); 100 DCHECK(path_ok); 101 u_setDataDirectory(data_path.value().c_str()); 102 // Only look for the packaged data file; 103 // the default behavior is to look for individual files. 104 UErrorCode err = U_ZERO_ERROR; 105 udata_setFileAccess(UDATA_ONLY_PACKAGES, &err); 106 return err == U_ZERO_ERROR; 107#else 108 // If the ICU data directory is set, ICU won't actually load the data until 109 // it is needed. This can fail if the process is sandboxed at that time. 110 // Instead, Mac maps the file in and hands off the data so the sandbox won't 111 // cause any problems. 112 113 // Chrome doesn't normally shut down ICU, so the mapped data shouldn't ever 114 // be released. 115 CR_DEFINE_STATIC_LOCAL(base::MemoryMappedFile, mapped_file, ()); 116 if (!mapped_file.IsValid()) { 117 // Assume it is in the framework bundle's Resources directory. 118 FilePath data_path = 119 base::mac::PathForFrameworkBundleResource(CFSTR(ICU_UTIL_DATA_FILE_NAME)); 120 if (data_path.empty()) { 121 DLOG(ERROR) << ICU_UTIL_DATA_FILE_NAME << " not found in bundle"; 122 return false; 123 } 124 if (!mapped_file.Initialize(data_path)) { 125 DLOG(ERROR) << "Couldn't mmap " << data_path.value(); 126 return false; 127 } 128 } 129 UErrorCode err = U_ZERO_ERROR; 130 udata_setCommonData(const_cast<uint8*>(mapped_file.data()), &err); 131 return err == U_ZERO_ERROR; 132#endif // OS check 133#endif 134} 135 136} // namespace icu_util 137