// Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "flutter/fml/icu_util.h" #include #include #include "flutter/fml/build_config.h" #include "flutter/fml/logging.h" #include "flutter/fml/mapping.h" #include "flutter/fml/native_library.h" #include "flutter/fml/paths.h" #include "third_party/icu/source/common/unicode/udata.h" namespace fml { namespace icu { class ICUContext { public: explicit ICUContext(const std::string& icu_data_path) : valid_(false) { valid_ = SetupMapping(icu_data_path) && SetupICU(); } explicit ICUContext(std::unique_ptr mapping) : mapping_(std::move(mapping)) { valid_ = SetupICU(); } ~ICUContext() = default; bool SetupMapping(const std::string& icu_data_path) { // Check if the path exists and it readable directly. auto fd = fml::OpenFile(icu_data_path.c_str(), false, fml::FilePermission::kRead); // Check the path relative to the current executable. if (!fd.is_valid()) { auto directory = fml::paths::GetExecutableDirectoryPath(); if (!directory.first) { return false; } std::string path_relative_to_executable = paths::JoinPaths({directory.second, icu_data_path}); fd = fml::OpenFile(path_relative_to_executable.c_str(), false, fml::FilePermission::kRead); } if (!fd.is_valid()) { return false; } std::initializer_list protection = { fml::FileMapping::Protection::kRead}; auto file_mapping = std::make_unique(fd, protection); if (file_mapping->GetSize() != 0) { mapping_ = std::move(file_mapping); return true; } return false; } bool SetupICU() { if (GetSize() == 0) { return false; } UErrorCode err_code = U_ZERO_ERROR; udata_setCommonData(GetMapping(), &err_code); return (err_code == U_ZERO_ERROR); } const uint8_t* GetMapping() const { return mapping_ ? mapping_->GetMapping() : nullptr; } size_t GetSize() const { return mapping_ ? mapping_->GetSize() : 0; } bool IsValid() const { return valid_; } private: bool valid_; std::unique_ptr mapping_; FML_DISALLOW_COPY_AND_ASSIGN(ICUContext); }; void InitializeICUOnce(const std::string& icu_data_path) { static ICUContext* context = new ICUContext(icu_data_path); FML_CHECK(context->IsValid()) << "Must be able to initialize the ICU context. Tried: " << icu_data_path; } std::once_flag g_icu_init_flag; void InitializeICU(const std::string& icu_data_path) { std::call_once(g_icu_init_flag, [&icu_data_path]() { InitializeICUOnce(icu_data_path); }); } void InitializeICUFromMappingOnce(std::unique_ptr mapping) { static ICUContext* context = new ICUContext(std::move(mapping)); FML_CHECK(context->IsValid()) << "Unable to initialize the ICU context from a mapping."; } void InitializeICUFromMapping(std::unique_ptr mapping) { std::call_once(g_icu_init_flag, [mapping = std::move(mapping)]() mutable { InitializeICUFromMappingOnce(std::move(mapping)); }); } } // namespace icu } // namespace fml