1// Copyright (C) 2012 The Libphonenumber Authors 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// Author: Patrick Mezard 16 17#include "phonenumbers/geocoding/mapping_file_provider.h" 18 19#include <algorithm> 20#include <cstddef> 21#include <cstring> 22#include <sstream> 23#include <string> 24 25#include "phonenumbers/geocoding/geocoding_data.h" 26 27namespace i18n { 28namespace phonenumbers { 29 30using std::string; 31 32namespace { 33 34struct NormalizedLocale { 35 const char* locale; 36 const char* normalized_locale; 37}; 38 39const NormalizedLocale kNormalizedLocales[] = { 40 {"zh_TW", "zh_Hant"}, 41 {"zh_HK", "zh_Hant"}, 42 {"zh_MO", "zh_Hant"}, 43}; 44 45const char* GetNormalizedLocale(const string& full_locale) { 46 const int size = sizeof(kNormalizedLocales) / sizeof(*kNormalizedLocales); 47 for (int i = 0; i != size; ++i) { 48 if (full_locale.compare(kNormalizedLocales[i].locale) == 0) { 49 return kNormalizedLocales[i].normalized_locale; 50 } 51 } 52 return NULL; 53} 54 55void AppendLocalePart(const string& part, string* full_locale) { 56 if (!part.empty()) { 57 full_locale->append("_"); 58 full_locale->append(part); 59 } 60} 61 62void ConstructFullLocale(const string& language, const string& script, const 63 string& region, string* full_locale) { 64 full_locale->assign(language); 65 AppendLocalePart(script, full_locale); 66 AppendLocalePart(region, full_locale); 67} 68 69// Returns true if s1 comes strictly before s2 in lexicographic order. 70bool IsLowerThan(const char* s1, const char* s2) { 71 return strcmp(s1, s2) < 0; 72} 73 74// Returns true if languages contains language. 75bool HasLanguage(const CountryLanguages* languages, const string& language) { 76 const char** const start = languages->available_languages; 77 const char** const end = start + languages->available_languages_size; 78 const char** const it = 79 std::lower_bound(start, end, language.c_str(), IsLowerThan); 80 return it != end && strcmp(language.c_str(), *it) == 0; 81} 82 83} // namespace 84 85MappingFileProvider::MappingFileProvider( 86 const int* country_calling_codes, int country_calling_codes_size, 87 country_languages_getter get_country_languages) 88 : country_calling_codes_(country_calling_codes), 89 country_calling_codes_size_(country_calling_codes_size), 90 get_country_languages_(get_country_languages) { 91} 92 93const string& MappingFileProvider::GetFileName(int country_calling_code, 94 const string& language, 95 const string& script, 96 const string& region, 97 string* filename) const { 98 filename->clear(); 99 if (language.empty()) { 100 return *filename; 101 } 102 const int* const country_calling_codes_end = country_calling_codes_ + 103 country_calling_codes_size_; 104 const int* const it = 105 std::lower_bound(country_calling_codes_, 106 country_calling_codes_end, 107 country_calling_code); 108 if (it == country_calling_codes_end || *it != country_calling_code) { 109 return *filename; 110 } 111 const CountryLanguages* const langs = 112 get_country_languages_(it - country_calling_codes_); 113 if (langs->available_languages_size > 0) { 114 string language_code; 115 FindBestMatchingLanguageCode(langs, language, script, region, 116 &language_code); 117 if (!language_code.empty()) { 118 std::stringstream filename_buf; 119 filename_buf << country_calling_code << "_" << language_code; 120 *filename = filename_buf.str(); 121 } 122 } 123 return *filename; 124} 125 126void MappingFileProvider::FindBestMatchingLanguageCode( 127 const CountryLanguages* languages, const string& language, 128 const string& script, const string& region, string* best_match) const { 129 string full_locale; 130 ConstructFullLocale(language, script, region, &full_locale); 131 const char* const normalized_locale = GetNormalizedLocale(full_locale); 132 if (normalized_locale != NULL) { 133 string normalized_locale_str(normalized_locale); 134 if (HasLanguage(languages, normalized_locale_str)) { 135 best_match->swap(normalized_locale_str); 136 return; 137 } 138 } 139 140 if (HasLanguage(languages, full_locale)) { 141 best_match->swap(full_locale); 142 return; 143 } 144 145 if (script.empty() != region.empty()) { 146 if (HasLanguage(languages, language)) { 147 *best_match = language; 148 return; 149 } 150 } else if (!script.empty() && !region.empty()) { 151 string lang_with_script(language); 152 lang_with_script.append("_"); 153 lang_with_script.append(script); 154 if (HasLanguage(languages, lang_with_script)) { 155 best_match->swap(lang_with_script); 156 return; 157 } 158 } 159 160 string lang_with_region(language); 161 lang_with_region.append("_"); 162 lang_with_region.append(region); 163 if (HasLanguage(languages, lang_with_region)) { 164 best_match->swap(lang_with_region); 165 return; 166 } 167 if (HasLanguage(languages, language)) { 168 *best_match = language; 169 return; 170 } 171 best_match->clear(); 172} 173 174} // namespace phonenumbers 175} // namespace i18n 176