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