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