xref: /aosp_15_r20/external/libtextclassifier/native/utils/resources.cc (revision 993b0882672172b81d12fad7a7ac0c3e5c824a12)
1*993b0882SAndroid Build Coastguard Worker /*
2*993b0882SAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*993b0882SAndroid Build Coastguard Worker  *
4*993b0882SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*993b0882SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*993b0882SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*993b0882SAndroid Build Coastguard Worker  *
8*993b0882SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*993b0882SAndroid Build Coastguard Worker  *
10*993b0882SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*993b0882SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*993b0882SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*993b0882SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*993b0882SAndroid Build Coastguard Worker  * limitations under the License.
15*993b0882SAndroid Build Coastguard Worker  */
16*993b0882SAndroid Build Coastguard Worker 
17*993b0882SAndroid Build Coastguard Worker #include "utils/resources.h"
18*993b0882SAndroid Build Coastguard Worker 
19*993b0882SAndroid Build Coastguard Worker #include "utils/base/logging.h"
20*993b0882SAndroid Build Coastguard Worker #include "utils/zlib/buffer_generated.h"
21*993b0882SAndroid Build Coastguard Worker 
22*993b0882SAndroid Build Coastguard Worker namespace libtextclassifier3 {
23*993b0882SAndroid Build Coastguard Worker namespace {
isWildcardMatch(const flatbuffers::String * left,const std::string & right)24*993b0882SAndroid Build Coastguard Worker bool isWildcardMatch(const flatbuffers::String* left,
25*993b0882SAndroid Build Coastguard Worker                      const std::string& right) {
26*993b0882SAndroid Build Coastguard Worker   return (left == nullptr || right.empty());
27*993b0882SAndroid Build Coastguard Worker }
28*993b0882SAndroid Build Coastguard Worker 
isExactMatch(const flatbuffers::String * left,const std::string & right)29*993b0882SAndroid Build Coastguard Worker bool isExactMatch(const flatbuffers::String* left, const std::string& right) {
30*993b0882SAndroid Build Coastguard Worker   if (left == nullptr) {
31*993b0882SAndroid Build Coastguard Worker     return right.empty();
32*993b0882SAndroid Build Coastguard Worker   }
33*993b0882SAndroid Build Coastguard Worker   return left->str() == right;
34*993b0882SAndroid Build Coastguard Worker }
35*993b0882SAndroid Build Coastguard Worker 
NormalizeLanguageCode(const std::string & language_code)36*993b0882SAndroid Build Coastguard Worker std::string NormalizeLanguageCode(const std::string& language_code) {
37*993b0882SAndroid Build Coastguard Worker   if (language_code == "id") {
38*993b0882SAndroid Build Coastguard Worker     return "in";
39*993b0882SAndroid Build Coastguard Worker   } else if (language_code == "iw") {
40*993b0882SAndroid Build Coastguard Worker     return "he";
41*993b0882SAndroid Build Coastguard Worker   } else if (language_code == "no") {
42*993b0882SAndroid Build Coastguard Worker     return "nb";
43*993b0882SAndroid Build Coastguard Worker   } else if (language_code == "tl") {
44*993b0882SAndroid Build Coastguard Worker     return "fil";
45*993b0882SAndroid Build Coastguard Worker   }
46*993b0882SAndroid Build Coastguard Worker   return language_code;
47*993b0882SAndroid Build Coastguard Worker }
48*993b0882SAndroid Build Coastguard Worker 
49*993b0882SAndroid Build Coastguard Worker }  // namespace
50*993b0882SAndroid Build Coastguard Worker 
LocaleMatch(const Locale & locale,const LanguageTag * entry_locale) const51*993b0882SAndroid Build Coastguard Worker int Resources::LocaleMatch(const Locale& locale,
52*993b0882SAndroid Build Coastguard Worker                            const LanguageTag* entry_locale) const {
53*993b0882SAndroid Build Coastguard Worker   int match = LOCALE_NO_MATCH;
54*993b0882SAndroid Build Coastguard Worker   if (isExactMatch(entry_locale->language(),
55*993b0882SAndroid Build Coastguard Worker                    NormalizeLanguageCode(locale.Language()))) {
56*993b0882SAndroid Build Coastguard Worker     match |= LOCALE_LANGUAGE_MATCH;
57*993b0882SAndroid Build Coastguard Worker   } else if (isWildcardMatch(entry_locale->language(), locale.Language())) {
58*993b0882SAndroid Build Coastguard Worker     match |= LOCALE_LANGUAGE_WILDCARD_MATCH;
59*993b0882SAndroid Build Coastguard Worker   }
60*993b0882SAndroid Build Coastguard Worker 
61*993b0882SAndroid Build Coastguard Worker   if (isExactMatch(entry_locale->script(), locale.Script())) {
62*993b0882SAndroid Build Coastguard Worker     match |= LOCALE_SCRIPT_MATCH;
63*993b0882SAndroid Build Coastguard Worker   } else if (isWildcardMatch(entry_locale->script(), locale.Script())) {
64*993b0882SAndroid Build Coastguard Worker     match |= LOCALE_SCRIPT_WILDCARD_MATCH;
65*993b0882SAndroid Build Coastguard Worker   }
66*993b0882SAndroid Build Coastguard Worker 
67*993b0882SAndroid Build Coastguard Worker   if (isExactMatch(entry_locale->region(), locale.Region())) {
68*993b0882SAndroid Build Coastguard Worker     match |= LOCALE_REGION_MATCH;
69*993b0882SAndroid Build Coastguard Worker   } else if (isWildcardMatch(entry_locale->region(), locale.Region())) {
70*993b0882SAndroid Build Coastguard Worker     match |= LOCALE_REGION_WILDCARD_MATCH;
71*993b0882SAndroid Build Coastguard Worker   }
72*993b0882SAndroid Build Coastguard Worker 
73*993b0882SAndroid Build Coastguard Worker   return match;
74*993b0882SAndroid Build Coastguard Worker }
75*993b0882SAndroid Build Coastguard Worker 
FindResource(const StringPiece resource_name) const76*993b0882SAndroid Build Coastguard Worker const ResourceEntry* Resources::FindResource(
77*993b0882SAndroid Build Coastguard Worker     const StringPiece resource_name) const {
78*993b0882SAndroid Build Coastguard Worker   if (resources_ == nullptr || resources_->resource_entry() == nullptr) {
79*993b0882SAndroid Build Coastguard Worker     TC3_LOG(ERROR) << "No resources defined.";
80*993b0882SAndroid Build Coastguard Worker     return nullptr;
81*993b0882SAndroid Build Coastguard Worker   }
82*993b0882SAndroid Build Coastguard Worker   const ResourceEntry* entry =
83*993b0882SAndroid Build Coastguard Worker       resources_->resource_entry()->LookupByKey(resource_name.data());
84*993b0882SAndroid Build Coastguard Worker   if (entry == nullptr) {
85*993b0882SAndroid Build Coastguard Worker     TC3_LOG(ERROR) << "Resource " << resource_name.ToString() << " not found";
86*993b0882SAndroid Build Coastguard Worker     return nullptr;
87*993b0882SAndroid Build Coastguard Worker   }
88*993b0882SAndroid Build Coastguard Worker   return entry;
89*993b0882SAndroid Build Coastguard Worker }
90*993b0882SAndroid Build Coastguard Worker 
BestResourceForLocales(const ResourceEntry * resource,const std::vector<Locale> & locales) const91*993b0882SAndroid Build Coastguard Worker int Resources::BestResourceForLocales(
92*993b0882SAndroid Build Coastguard Worker     const ResourceEntry* resource, const std::vector<Locale>& locales) const {
93*993b0882SAndroid Build Coastguard Worker   // Find best match based on locale.
94*993b0882SAndroid Build Coastguard Worker   int resource_id = -1;
95*993b0882SAndroid Build Coastguard Worker   int locale_match = LOCALE_NO_MATCH;
96*993b0882SAndroid Build Coastguard Worker   const auto* resources = resource->resource();
97*993b0882SAndroid Build Coastguard Worker   for (int user_locale = 0; user_locale < locales.size(); user_locale++) {
98*993b0882SAndroid Build Coastguard Worker     if (!locales[user_locale].IsValid()) {
99*993b0882SAndroid Build Coastguard Worker       continue;
100*993b0882SAndroid Build Coastguard Worker     }
101*993b0882SAndroid Build Coastguard Worker     for (int i = 0; i < resources->size(); i++) {
102*993b0882SAndroid Build Coastguard Worker       for (const int locale_id : *resources->Get(i)->locale()) {
103*993b0882SAndroid Build Coastguard Worker         const int candidate_match = LocaleMatch(
104*993b0882SAndroid Build Coastguard Worker             locales[user_locale], resources_->locale()->Get(locale_id));
105*993b0882SAndroid Build Coastguard Worker 
106*993b0882SAndroid Build Coastguard Worker         // Only consider if at least the language matches.
107*993b0882SAndroid Build Coastguard Worker         if ((candidate_match & LOCALE_LANGUAGE_MATCH) == 0 &&
108*993b0882SAndroid Build Coastguard Worker             (candidate_match & LOCALE_LANGUAGE_WILDCARD_MATCH) == 0) {
109*993b0882SAndroid Build Coastguard Worker           continue;
110*993b0882SAndroid Build Coastguard Worker         }
111*993b0882SAndroid Build Coastguard Worker 
112*993b0882SAndroid Build Coastguard Worker         if (candidate_match > locale_match) {
113*993b0882SAndroid Build Coastguard Worker           locale_match = candidate_match;
114*993b0882SAndroid Build Coastguard Worker           resource_id = i;
115*993b0882SAndroid Build Coastguard Worker         }
116*993b0882SAndroid Build Coastguard Worker       }
117*993b0882SAndroid Build Coastguard Worker     }
118*993b0882SAndroid Build Coastguard Worker 
119*993b0882SAndroid Build Coastguard Worker     // If the language matches exactly, we are already finished.
120*993b0882SAndroid Build Coastguard Worker     // We found an exact language match.
121*993b0882SAndroid Build Coastguard Worker     if (locale_match & LOCALE_LANGUAGE_MATCH) {
122*993b0882SAndroid Build Coastguard Worker       return resource_id;
123*993b0882SAndroid Build Coastguard Worker     }
124*993b0882SAndroid Build Coastguard Worker   }
125*993b0882SAndroid Build Coastguard Worker   return resource_id;
126*993b0882SAndroid Build Coastguard Worker }
127*993b0882SAndroid Build Coastguard Worker 
GetResourceContent(const std::vector<Locale> & locales,const StringPiece resource_name,std::string * result) const128*993b0882SAndroid Build Coastguard Worker bool Resources::GetResourceContent(const std::vector<Locale>& locales,
129*993b0882SAndroid Build Coastguard Worker                                    const StringPiece resource_name,
130*993b0882SAndroid Build Coastguard Worker                                    std::string* result) const {
131*993b0882SAndroid Build Coastguard Worker   const ResourceEntry* entry = FindResource(resource_name);
132*993b0882SAndroid Build Coastguard Worker   if (entry == nullptr || entry->resource() == nullptr) {
133*993b0882SAndroid Build Coastguard Worker     return false;
134*993b0882SAndroid Build Coastguard Worker   }
135*993b0882SAndroid Build Coastguard Worker 
136*993b0882SAndroid Build Coastguard Worker   int resource_id = BestResourceForLocales(entry, locales);
137*993b0882SAndroid Build Coastguard Worker   if (resource_id < 0) {
138*993b0882SAndroid Build Coastguard Worker     return false;
139*993b0882SAndroid Build Coastguard Worker   }
140*993b0882SAndroid Build Coastguard Worker   const auto* resource = entry->resource()->Get(resource_id);
141*993b0882SAndroid Build Coastguard Worker   if (resource->content() != nullptr) {
142*993b0882SAndroid Build Coastguard Worker     *result = resource->content()->str();
143*993b0882SAndroid Build Coastguard Worker     return true;
144*993b0882SAndroid Build Coastguard Worker   }
145*993b0882SAndroid Build Coastguard Worker   return false;
146*993b0882SAndroid Build Coastguard Worker }
147*993b0882SAndroid Build Coastguard Worker 
148*993b0882SAndroid Build Coastguard Worker }  // namespace libtextclassifier3
149