xref: /aosp_15_r20/external/skia/third_party/icu/SkLoadICU.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker // Copyright 2019 Google LLC.
2*c8dee2aaSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
3*c8dee2aaSAndroid Build Coastguard Worker 
4*c8dee2aaSAndroid Build Coastguard Worker #include "SkLoadICU.h"
5*c8dee2aaSAndroid Build Coastguard Worker 
6*c8dee2aaSAndroid Build Coastguard Worker #if defined(_WIN32) && defined(SK_USING_THIRD_PARTY_ICU)
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef WIN32_LEAN_AND_MEAN
9*c8dee2aaSAndroid Build Coastguard Worker #define WIN32_LEAN_AND_MEAN
10*c8dee2aaSAndroid Build Coastguard Worker #endif
11*c8dee2aaSAndroid Build Coastguard Worker #include <windows.h>
12*c8dee2aaSAndroid Build Coastguard Worker #include <io.h>
13*c8dee2aaSAndroid Build Coastguard Worker 
14*c8dee2aaSAndroid Build Coastguard Worker #include <cstdio>
15*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
16*c8dee2aaSAndroid Build Coastguard Worker #include <mutex>
17*c8dee2aaSAndroid Build Coastguard Worker #include <string>
18*c8dee2aaSAndroid Build Coastguard Worker 
19*c8dee2aaSAndroid Build Coastguard Worker #include "unicode/udata.h"
20*c8dee2aaSAndroid Build Coastguard Worker 
win_mmap(const wchar_t * dataFile)21*c8dee2aaSAndroid Build Coastguard Worker static void* win_mmap(const wchar_t* dataFile) {
22*c8dee2aaSAndroid Build Coastguard Worker     if (!dataFile) {
23*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
24*c8dee2aaSAndroid Build Coastguard Worker     }
25*c8dee2aaSAndroid Build Coastguard Worker     struct FCloseWrapper { void operator()(FILE* f) { fclose(f); } };
26*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<FILE, FCloseWrapper> stream(_wfopen(dataFile, L"rb"));
27*c8dee2aaSAndroid Build Coastguard Worker     if (!stream) {
28*c8dee2aaSAndroid Build Coastguard Worker         fprintf(stderr, "SkIcuLoader: datafile missing: %ls.\n", dataFile);
29*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
30*c8dee2aaSAndroid Build Coastguard Worker     }
31*c8dee2aaSAndroid Build Coastguard Worker     int fileno = _fileno(stream.get());
32*c8dee2aaSAndroid Build Coastguard Worker     if (fileno < 0) {
33*c8dee2aaSAndroid Build Coastguard Worker         fprintf(stderr, "SkIcuLoader: datafile fileno error.\n");
34*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
35*c8dee2aaSAndroid Build Coastguard Worker     }
36*c8dee2aaSAndroid Build Coastguard Worker     HANDLE file = (HANDLE)_get_osfhandle(fileno);
37*c8dee2aaSAndroid Build Coastguard Worker     if ((HANDLE)INVALID_HANDLE_VALUE == file) {
38*c8dee2aaSAndroid Build Coastguard Worker         fprintf(stderr, "SkIcuLoader: datafile handle error.\n");
39*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
40*c8dee2aaSAndroid Build Coastguard Worker     }
41*c8dee2aaSAndroid Build Coastguard Worker     struct CloseHandleWrapper { void operator()(HANDLE h) { CloseHandle(h); } };
42*c8dee2aaSAndroid Build Coastguard Worker     std::unique_ptr<void, CloseHandleWrapper> mmapHandle(
43*c8dee2aaSAndroid Build Coastguard Worker         CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr));
44*c8dee2aaSAndroid Build Coastguard Worker     if (!mmapHandle) {
45*c8dee2aaSAndroid Build Coastguard Worker         fprintf(stderr, "SkIcuLoader: datafile mmap error.\n");
46*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
47*c8dee2aaSAndroid Build Coastguard Worker     }
48*c8dee2aaSAndroid Build Coastguard Worker     void* addr = MapViewOfFile(mmapHandle.get(), FILE_MAP_READ, 0, 0, 0);
49*c8dee2aaSAndroid Build Coastguard Worker     if (nullptr == addr) {
50*c8dee2aaSAndroid Build Coastguard Worker         fprintf(stderr, "SkIcuLoader: datafile view error.\n");
51*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
52*c8dee2aaSAndroid Build Coastguard Worker     }
53*c8dee2aaSAndroid Build Coastguard Worker     return addr;
54*c8dee2aaSAndroid Build Coastguard Worker }
55*c8dee2aaSAndroid Build Coastguard Worker 
init_icu(void * addr)56*c8dee2aaSAndroid Build Coastguard Worker static bool init_icu(void* addr) {
57*c8dee2aaSAndroid Build Coastguard Worker     UErrorCode err = U_ZERO_ERROR;
58*c8dee2aaSAndroid Build Coastguard Worker     udata_setCommonData(addr, &err);
59*c8dee2aaSAndroid Build Coastguard Worker     if (err != U_ZERO_ERROR) {
60*c8dee2aaSAndroid Build Coastguard Worker         fprintf(stderr, "udata_setCommonData() returned %d.\n", (int)err);
61*c8dee2aaSAndroid Build Coastguard Worker         return false;
62*c8dee2aaSAndroid Build Coastguard Worker     }
63*c8dee2aaSAndroid Build Coastguard Worker     udata_setFileAccess(UDATA_ONLY_PACKAGES, &err);
64*c8dee2aaSAndroid Build Coastguard Worker     if (err != U_ZERO_ERROR) {
65*c8dee2aaSAndroid Build Coastguard Worker         fprintf(stderr, "udata_setFileAccess() returned %d.\n", (int)err);
66*c8dee2aaSAndroid Build Coastguard Worker         return false;
67*c8dee2aaSAndroid Build Coastguard Worker     }
68*c8dee2aaSAndroid Build Coastguard Worker     return true;
69*c8dee2aaSAndroid Build Coastguard Worker }
70*c8dee2aaSAndroid Build Coastguard Worker 
get_module_path(HMODULE module)71*c8dee2aaSAndroid Build Coastguard Worker static std::wstring get_module_path(HMODULE module) {
72*c8dee2aaSAndroid Build Coastguard Worker     DWORD len;
73*c8dee2aaSAndroid Build Coastguard Worker     std::wstring path;
74*c8dee2aaSAndroid Build Coastguard Worker     path.resize(MAX_PATH);
75*c8dee2aaSAndroid Build Coastguard Worker 
76*c8dee2aaSAndroid Build Coastguard Worker     len = GetModuleFileNameW(module, (LPWSTR)path.data(), (DWORD)path.size());
77*c8dee2aaSAndroid Build Coastguard Worker     if (len > path.size()) {
78*c8dee2aaSAndroid Build Coastguard Worker         path.resize(len);
79*c8dee2aaSAndroid Build Coastguard Worker         len = GetModuleFileNameW(module, (LPWSTR)path.data(), (DWORD)path.size());
80*c8dee2aaSAndroid Build Coastguard Worker     }
81*c8dee2aaSAndroid Build Coastguard Worker     path.resize(len);
82*c8dee2aaSAndroid Build Coastguard Worker     std::size_t end = path.rfind('\\');
83*c8dee2aaSAndroid Build Coastguard Worker     if (end == std::wstring::npos) {
84*c8dee2aaSAndroid Build Coastguard Worker         return std::wstring();
85*c8dee2aaSAndroid Build Coastguard Worker     }
86*c8dee2aaSAndroid Build Coastguard Worker     path.resize(end);
87*c8dee2aaSAndroid Build Coastguard Worker     return path;
88*c8dee2aaSAndroid Build Coastguard Worker }
89*c8dee2aaSAndroid Build Coastguard Worker 
library_directory()90*c8dee2aaSAndroid Build Coastguard Worker static std::wstring library_directory() {
91*c8dee2aaSAndroid Build Coastguard Worker     HMODULE hModule = NULL;
92*c8dee2aaSAndroid Build Coastguard Worker     GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
93*c8dee2aaSAndroid Build Coastguard Worker         reinterpret_cast<LPCSTR>(&library_directory), &hModule);
94*c8dee2aaSAndroid Build Coastguard Worker     return get_module_path(hModule);
95*c8dee2aaSAndroid Build Coastguard Worker }
96*c8dee2aaSAndroid Build Coastguard Worker 
executable_directory()97*c8dee2aaSAndroid Build Coastguard Worker static std::wstring executable_directory() {
98*c8dee2aaSAndroid Build Coastguard Worker     HMODULE hModule = GetModuleHandleA(NULL);
99*c8dee2aaSAndroid Build Coastguard Worker     return get_module_path(hModule);
100*c8dee2aaSAndroid Build Coastguard Worker }
101*c8dee2aaSAndroid Build Coastguard Worker 
load_from(const std::wstring & dir)102*c8dee2aaSAndroid Build Coastguard Worker static bool load_from(const std::wstring& dir) {
103*c8dee2aaSAndroid Build Coastguard Worker     auto sPath = dir + L"\\icudtl.dat";
104*c8dee2aaSAndroid Build Coastguard Worker     if (void* addr = win_mmap(sPath.c_str())) {
105*c8dee2aaSAndroid Build Coastguard Worker         if (init_icu(addr)) {
106*c8dee2aaSAndroid Build Coastguard Worker             return true;
107*c8dee2aaSAndroid Build Coastguard Worker         }
108*c8dee2aaSAndroid Build Coastguard Worker     }
109*c8dee2aaSAndroid Build Coastguard Worker     return false;
110*c8dee2aaSAndroid Build Coastguard Worker }
111*c8dee2aaSAndroid Build Coastguard Worker 
SkLoadICU()112*c8dee2aaSAndroid Build Coastguard Worker bool SkLoadICU() {
113*c8dee2aaSAndroid Build Coastguard Worker     static bool good = false;
114*c8dee2aaSAndroid Build Coastguard Worker     static std::once_flag flag;
115*c8dee2aaSAndroid Build Coastguard Worker     std::call_once(flag, []() {
116*c8dee2aaSAndroid Build Coastguard Worker         good = load_from(executable_directory()) || load_from(library_directory());
117*c8dee2aaSAndroid Build Coastguard Worker     });
118*c8dee2aaSAndroid Build Coastguard Worker     return good;
119*c8dee2aaSAndroid Build Coastguard Worker }
120*c8dee2aaSAndroid Build Coastguard Worker 
121*c8dee2aaSAndroid Build Coastguard Worker #endif  // defined(_WIN32) && defined(SK_USING_THIRD_PARTY_ICU)
122