| /* |
| * Copyright 2021 Google Inc. |
| * |
| * Use of this source code is governed by a BSD-style license that can be |
| * found in the LICENSE file. |
| */ |
| |
| #include "include/core/SkString.h" |
| #include "include/core/SkTypes.h" |
| #include "modules/skunicode/src/SkUnicode_icu.h" |
| |
| #include <dlfcn.h> |
| |
| #define SK_RUNTIME_ICU_PATHS "libicuuc.so" |
| |
| std::unique_ptr<SkICULib> SkLoadICULib() { |
| static constexpr char const* gLibPaths[] = { SK_RUNTIME_ICU_PATHS }; |
| |
| void* dlhnd = nullptr; |
| for (const auto path : gLibPaths) { |
| dlhnd = dlopen(path, RTLD_LAZY); |
| if (dlhnd) { |
| break; |
| } |
| } |
| |
| if (!dlhnd) { |
| SkDEBUGF("ICU loader: failed to open libicuuc.\n"); |
| return nullptr; |
| } |
| |
| int icu_ver = -1; |
| |
| bool resolved_required_syms = true; |
| |
| auto resolve_sym = [&](void* hnd, const char name[], bool required = false) -> void* { |
| static constexpr int kMinVer = 44, |
| kMaxVer = 100; |
| |
| // First call performs a search to determine the actual lib version. |
| // Subsequent calls are pinned to the version found. |
| const auto search_to = icu_ver > 0 ? icu_ver : kMaxVer; |
| icu_ver = icu_ver > 0 ? icu_ver : kMinVer; |
| |
| for (;;) { |
| const auto sym = SkStringPrintf("%s_%d", name, icu_ver); |
| if (auto* addr = dlsym(dlhnd, sym.c_str())) { |
| return addr; |
| } |
| |
| if (icu_ver == search_to) { |
| break; |
| } |
| |
| icu_ver++; |
| } |
| |
| if (required) { |
| resolved_required_syms = false; |
| } |
| return nullptr; |
| }; |
| |
| SkICULib lib {}; |
| |
| // When using dlsym |
| // *(void**)(&procPtr) = dlsym(self, "proc"); |
| // is non-standard, but safe for POSIX. Cannot write |
| // *reinterpret_cast<void**>(&procPtr) = dlsym(self, "proc"); |
| // because clang has not implemented DR573. See http://clang.llvm.org/cxx_dr_status.html . |
| #define SKICU_FUNC(fname) *(void**)(&lib.f_##fname) = resolve_sym(dlhnd, #fname, true); |
| SKICU_EMIT_FUNCS |
| |
| *(void**)(&lib.f_ubrk_clone_) = resolve_sym(dlhnd, "ubrk_clone"); |
| *(void**)(&lib.f_ubrk_safeClone_) = resolve_sym(dlhnd, "ubrk_safeClone"); |
| |
| if (!resolved_required_syms || (!lib.f_ubrk_clone_ && !lib.f_ubrk_safeClone_)) { |
| SkDEBUGF("ICU loader: failed to resolve required symbols."); |
| dlclose(dlhnd); |
| return nullptr; |
| } |
| |
| return std::make_unique<SkICULib>(lib); |
| } |