1 // Copyright (C) 2014 Google Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <libaddressinput/region_data_builder.h> 16 17 #include <libaddressinput/address_data.h> 18 #include <libaddressinput/preload_supplier.h> 19 #include <libaddressinput/region_data.h> 20 21 #include <cassert> 22 #include <cstddef> 23 #include <string> 24 #include <utility> 25 #include <vector> 26 27 #include "language.h" 28 #include "lookup_key.h" 29 #include "region_data_constants.h" 30 #include "rule.h" 31 32 namespace i18n { 33 namespace addressinput { 34 35 namespace { 36 37 // Does not take ownership of |supplier| or |parent_region|, neither of which is 38 // allowed to be NULL. 39 void BuildRegionTreeRecursively(PreloadSupplier* supplier, 40 const LookupKey& parent_key, 41 RegionData* parent_region, 42 const std::vector<std::string>& keys, 43 bool prefer_latin_name) { 44 assert(supplier != NULL); 45 assert(parent_region != NULL); 46 47 LookupKey lookup_key; 48 for (std::vector<std::string>::const_iterator key_it = keys.begin(); 49 key_it != keys.end(); ++key_it) { 50 lookup_key.FromLookupKey(parent_key, *key_it); 51 const Rule* rule = supplier->GetRule(lookup_key); 52 if (rule == NULL) { 53 return; 54 } 55 const std::string& local_name = rule->GetName().empty() 56 ? *key_it : rule->GetName(); 57 const std::string& name = 58 prefer_latin_name && !rule->GetLatinName().empty() 59 ? rule->GetLatinName() : local_name; 60 RegionData* region = parent_region->AddSubRegion(*key_it, name); 61 if (!rule->GetSubKeys().empty()) { 62 BuildRegionTreeRecursively(supplier, lookup_key, region, 63 rule->GetSubKeys(), prefer_latin_name); 64 } 65 } 66 } 67 68 // Does not take ownership of |supplier|, which cannot be NULL. The caller owns 69 // the result. 70 RegionData* BuildRegion(PreloadSupplier* supplier, 71 const std::string& region_code, 72 const Language& language) { 73 assert(supplier != NULL); 74 75 AddressData address; 76 address.region_code = region_code; 77 78 LookupKey lookup_key; 79 lookup_key.FromAddress(address); 80 81 const Rule* const rule = supplier->GetRule(lookup_key); 82 assert(rule != NULL); 83 84 RegionData* region = new RegionData(region_code); 85 BuildRegionTreeRecursively(supplier, lookup_key, region, 86 rule->GetSubKeys(), language.has_latin_script); 87 88 return region; 89 } 90 91 } // namespace 92 93 RegionDataBuilder::RegionDataBuilder(PreloadSupplier* supplier) 94 : supplier_(supplier), 95 cache_() { 96 assert(supplier_ != NULL); 97 } 98 99 RegionDataBuilder::~RegionDataBuilder() { 100 for (RegionCodeDataMap::const_iterator region_it = cache_.begin(); 101 region_it != cache_.end(); ++region_it) { 102 for (LanguageRegionMap::const_iterator 103 language_it = region_it->second->begin(); 104 language_it != region_it->second->end(); ++language_it) { 105 delete language_it->second; 106 } 107 delete region_it->second; 108 } 109 } 110 111 const RegionData& RegionDataBuilder::Build( 112 const std::string& region_code, 113 const std::string& ui_language_tag, 114 std::string* best_region_tree_language_tag) { 115 assert(supplier_->IsLoaded(region_code)); 116 assert(best_region_tree_language_tag != NULL); 117 118 // Look up the region tree in cache first before building it. 119 RegionCodeDataMap::const_iterator region_it = cache_.find(region_code); 120 if (region_it == cache_.end()) { 121 region_it = 122 cache_.insert(std::make_pair(region_code, new LanguageRegionMap)).first; 123 } 124 125 // No need to copy from default rule first, because only languages and Latin 126 // format are going to be used, which do not exist in the default rule. 127 Rule rule; 128 rule.ParseSerializedRule(RegionDataConstants::GetRegionData(region_code)); 129 static const Language kUndefinedLanguage("und"); 130 const Language& best_language = rule.GetLanguages().empty() 131 ? kUndefinedLanguage 132 : ChooseBestAddressLanguage(rule, Language(ui_language_tag)); 133 *best_region_tree_language_tag = best_language.tag; 134 135 LanguageRegionMap::const_iterator language_it = 136 region_it->second->find(best_language.tag); 137 if (language_it == region_it->second->end()) { 138 language_it = region_it->second->insert(std::make_pair( 139 best_language.tag, 140 BuildRegion(supplier_, region_code, best_language))).first; 141 } 142 143 return *language_it->second; 144 } 145 146 } // namespace addressinput 147 } // namespace i18n 148