/* * 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 #define SK_RUNTIME_ICU_PATHS "libicuuc.so" std::unique_ptr 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(&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(lib); }