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