11767c5feSopenharmony_ci// Copyright (C) 2012 The Libphonenumber Authors 21767c5feSopenharmony_ci// 31767c5feSopenharmony_ci// Licensed under the Apache License, Version 2.0 (the "License"); 41767c5feSopenharmony_ci// you may not use this file except in compliance with the License. 51767c5feSopenharmony_ci// You may obtain a copy of the License at 61767c5feSopenharmony_ci// 71767c5feSopenharmony_ci// http://www.apache.org/licenses/LICENSE-2.0 81767c5feSopenharmony_ci// 91767c5feSopenharmony_ci// Unless required by applicable law or agreed to in writing, software 101767c5feSopenharmony_ci// distributed under the License is distributed on an "AS IS" BASIS, 111767c5feSopenharmony_ci// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 121767c5feSopenharmony_ci// See the License for the specific language governing permissions and 131767c5feSopenharmony_ci// limitations under the License. 141767c5feSopenharmony_ci 151767c5feSopenharmony_ci// Author: Patrick Mezard 161767c5feSopenharmony_ci 171767c5feSopenharmony_ci#include "phonenumbers/geocoding/phonenumber_offline_geocoder.h" 181767c5feSopenharmony_ci 191767c5feSopenharmony_ci#include <algorithm> 201767c5feSopenharmony_ci#include <string> 211767c5feSopenharmony_ci 221767c5feSopenharmony_ci#include <unicode/unistr.h> // NOLINT(build/include_order) 231767c5feSopenharmony_ci 241767c5feSopenharmony_ci#include "phonenumbers/geocoding/area_code_map.h" 251767c5feSopenharmony_ci#include "phonenumbers/geocoding/geocoding_data.h" 261767c5feSopenharmony_ci#include "phonenumbers/geocoding/mapping_file_provider.h" 271767c5feSopenharmony_ci#include "phonenumbers/phonenumberutil.h" 281767c5feSopenharmony_ci#include "phonenumbers/stl_util.h" 291767c5feSopenharmony_ci 301767c5feSopenharmony_ci 311767c5feSopenharmony_cinamespace i18n { 321767c5feSopenharmony_cinamespace phonenumbers { 331767c5feSopenharmony_ci 341767c5feSopenharmony_ciusing icu::UnicodeString; 351767c5feSopenharmony_ciusing std::string; 361767c5feSopenharmony_ci 371767c5feSopenharmony_cinamespace { 381767c5feSopenharmony_ci 391767c5feSopenharmony_ci// Returns true if s1 comes strictly before s2 in lexicographic order. 401767c5feSopenharmony_cibool IsLowerThan(const char* s1, const char* s2) { 411767c5feSopenharmony_ci return strcmp(s1, s2) < 0; 421767c5feSopenharmony_ci} 431767c5feSopenharmony_ci 441767c5feSopenharmony_ci} // namespace 451767c5feSopenharmony_ci 461767c5feSopenharmony_ciPhoneNumberOfflineGeocoder::PhoneNumberOfflineGeocoder() { 471767c5feSopenharmony_ci Init(get_country_calling_codes(), get_country_calling_codes_size(), 481767c5feSopenharmony_ci get_country_languages, get_prefix_language_code_pairs(), 491767c5feSopenharmony_ci get_prefix_language_code_pairs_size(), get_prefix_descriptions); 501767c5feSopenharmony_ci} 511767c5feSopenharmony_ci 521767c5feSopenharmony_ciPhoneNumberOfflineGeocoder::PhoneNumberOfflineGeocoder( 531767c5feSopenharmony_ci const int* country_calling_codes, int country_calling_codes_size, 541767c5feSopenharmony_ci country_languages_getter get_country_languages, 551767c5feSopenharmony_ci const char** prefix_language_code_pairs, 561767c5feSopenharmony_ci int prefix_language_code_pairs_size, 571767c5feSopenharmony_ci prefix_descriptions_getter get_prefix_descriptions) { 581767c5feSopenharmony_ci Init(country_calling_codes, country_calling_codes_size, 591767c5feSopenharmony_ci get_country_languages, prefix_language_code_pairs, 601767c5feSopenharmony_ci prefix_language_code_pairs_size, get_prefix_descriptions); 611767c5feSopenharmony_ci} 621767c5feSopenharmony_ci 631767c5feSopenharmony_civoid PhoneNumberOfflineGeocoder::Init( 641767c5feSopenharmony_ci const int* country_calling_codes, int country_calling_codes_size, 651767c5feSopenharmony_ci country_languages_getter get_country_languages, 661767c5feSopenharmony_ci const char** prefix_language_code_pairs, 671767c5feSopenharmony_ci int prefix_language_code_pairs_size, 681767c5feSopenharmony_ci prefix_descriptions_getter get_prefix_descriptions) { 691767c5feSopenharmony_ci phone_util_ = PhoneNumberUtil::GetInstance(); 701767c5feSopenharmony_ci provider_.reset(new MappingFileProvider(country_calling_codes, 711767c5feSopenharmony_ci country_calling_codes_size, 721767c5feSopenharmony_ci get_country_languages)); 731767c5feSopenharmony_ci prefix_language_code_pairs_ = prefix_language_code_pairs; 741767c5feSopenharmony_ci prefix_language_code_pairs_size_ = prefix_language_code_pairs_size; 751767c5feSopenharmony_ci get_prefix_descriptions_ = get_prefix_descriptions; 761767c5feSopenharmony_ci} 771767c5feSopenharmony_ci 781767c5feSopenharmony_ciPhoneNumberOfflineGeocoder::~PhoneNumberOfflineGeocoder() { 791767c5feSopenharmony_ci gtl::STLDeleteContainerPairSecondPointers( 801767c5feSopenharmony_ci available_maps_.begin(), available_maps_.end()); 811767c5feSopenharmony_ci} 821767c5feSopenharmony_ci 831767c5feSopenharmony_ciconst AreaCodeMap* PhoneNumberOfflineGeocoder::GetPhonePrefixDescriptions( 841767c5feSopenharmony_ci int prefix, const string& language, const string& script, 851767c5feSopenharmony_ci const string& region) const { 861767c5feSopenharmony_ci string filename; 871767c5feSopenharmony_ci provider_->GetFileName(prefix, language, script, region, &filename); 881767c5feSopenharmony_ci if (filename.empty()) { 891767c5feSopenharmony_ci return NULL; 901767c5feSopenharmony_ci } 911767c5feSopenharmony_ci AreaCodeMaps::const_iterator it = available_maps_.find(filename); 921767c5feSopenharmony_ci if (it == available_maps_.end()) { 931767c5feSopenharmony_ci return LoadAreaCodeMapFromFile(filename); 941767c5feSopenharmony_ci } 951767c5feSopenharmony_ci return it->second; 961767c5feSopenharmony_ci} 971767c5feSopenharmony_ci 981767c5feSopenharmony_ciconst AreaCodeMap* PhoneNumberOfflineGeocoder::LoadAreaCodeMapFromFile( 991767c5feSopenharmony_ci const string& filename) const { 1001767c5feSopenharmony_ci const char** const prefix_language_code_pairs_end = 1011767c5feSopenharmony_ci prefix_language_code_pairs_ + prefix_language_code_pairs_size_; 1021767c5feSopenharmony_ci const char** const prefix_language_code_pair = 1031767c5feSopenharmony_ci std::lower_bound(prefix_language_code_pairs_, 1041767c5feSopenharmony_ci prefix_language_code_pairs_end, 1051767c5feSopenharmony_ci filename.c_str(), IsLowerThan); 1061767c5feSopenharmony_ci if (prefix_language_code_pair != prefix_language_code_pairs_end && 1071767c5feSopenharmony_ci filename.compare(*prefix_language_code_pair) == 0) { 1081767c5feSopenharmony_ci AreaCodeMap* const m = new AreaCodeMap(); 1091767c5feSopenharmony_ci m->ReadAreaCodeMap(get_prefix_descriptions_( 1101767c5feSopenharmony_ci prefix_language_code_pair - prefix_language_code_pairs_)); 1111767c5feSopenharmony_ci return available_maps_.insert(AreaCodeMaps::value_type(filename, m)) 1121767c5feSopenharmony_ci .first->second; 1131767c5feSopenharmony_ci } 1141767c5feSopenharmony_ci return NULL; 1151767c5feSopenharmony_ci} 1161767c5feSopenharmony_ci 1171767c5feSopenharmony_cistring PhoneNumberOfflineGeocoder::GetCountryNameForNumber( 1181767c5feSopenharmony_ci const PhoneNumber& number, const Locale& language) const { 1191767c5feSopenharmony_ci string region_code; 1201767c5feSopenharmony_ci phone_util_->GetRegionCodeForNumber(number, ®ion_code); 1211767c5feSopenharmony_ci return GetRegionDisplayName(®ion_code, language); 1221767c5feSopenharmony_ci} 1231767c5feSopenharmony_ci 1241767c5feSopenharmony_cistring PhoneNumberOfflineGeocoder::GetRegionDisplayName( 1251767c5feSopenharmony_ci const string* region_code, const Locale& language) const { 1261767c5feSopenharmony_ci if (region_code == NULL || region_code->compare("ZZ") == 0 || 1271767c5feSopenharmony_ci region_code->compare( 1281767c5feSopenharmony_ci PhoneNumberUtil::kRegionCodeForNonGeoEntity) == 0) { 1291767c5feSopenharmony_ci return ""; 1301767c5feSopenharmony_ci } 1311767c5feSopenharmony_ci UnicodeString udisplay_country; 1321767c5feSopenharmony_ci icu::Locale("", region_code->c_str()).getDisplayCountry( 1331767c5feSopenharmony_ci language, udisplay_country); 1341767c5feSopenharmony_ci string display_country; 1351767c5feSopenharmony_ci udisplay_country.toUTF8String(display_country); 1361767c5feSopenharmony_ci return display_country; 1371767c5feSopenharmony_ci} 1381767c5feSopenharmony_ci 1391767c5feSopenharmony_cistring PhoneNumberOfflineGeocoder::GetDescriptionForValidNumber( 1401767c5feSopenharmony_ci const PhoneNumber& number, const Locale& language) const { 1411767c5feSopenharmony_ci const char* const description = GetAreaDescription( 1421767c5feSopenharmony_ci number, language.getLanguage(), "", language.getCountry()); 1431767c5feSopenharmony_ci return *description != '\0' 1441767c5feSopenharmony_ci ? description 1451767c5feSopenharmony_ci : GetCountryNameForNumber(number, language); 1461767c5feSopenharmony_ci} 1471767c5feSopenharmony_ci 1481767c5feSopenharmony_cistring PhoneNumberOfflineGeocoder::GetDescriptionForValidNumber( 1491767c5feSopenharmony_ci const PhoneNumber& number, const Locale& language, 1501767c5feSopenharmony_ci const string& user_region) const { 1511767c5feSopenharmony_ci // If the user region matches the number's region, then we just show the 1521767c5feSopenharmony_ci // lower-level description, if one exists - if no description exists, we will 1531767c5feSopenharmony_ci // show the region(country) name for the number. 1541767c5feSopenharmony_ci string region_code; 1551767c5feSopenharmony_ci phone_util_->GetRegionCodeForNumber(number, ®ion_code); 1561767c5feSopenharmony_ci if (user_region.compare(region_code) == 0) { 1571767c5feSopenharmony_ci return GetDescriptionForValidNumber(number, language); 1581767c5feSopenharmony_ci } 1591767c5feSopenharmony_ci // Otherwise, we just show the region(country) name for now. 1601767c5feSopenharmony_ci return GetRegionDisplayName(®ion_code, language); 1611767c5feSopenharmony_ci} 1621767c5feSopenharmony_ci 1631767c5feSopenharmony_cistring PhoneNumberOfflineGeocoder::GetDescriptionForNumber( 1641767c5feSopenharmony_ci const PhoneNumber& number, const Locale& locale) const { 1651767c5feSopenharmony_ci PhoneNumberUtil::PhoneNumberType number_type = 1661767c5feSopenharmony_ci phone_util_->GetNumberType(number); 1671767c5feSopenharmony_ci if (number_type == PhoneNumberUtil::UNKNOWN) { 1681767c5feSopenharmony_ci return ""; 1691767c5feSopenharmony_ci } else if (!phone_util_->IsNumberGeographical(number_type, 1701767c5feSopenharmony_ci number.country_code())) { 1711767c5feSopenharmony_ci return GetCountryNameForNumber(number, locale); 1721767c5feSopenharmony_ci } 1731767c5feSopenharmony_ci return GetDescriptionForValidNumber(number, locale); 1741767c5feSopenharmony_ci} 1751767c5feSopenharmony_ci 1761767c5feSopenharmony_cistring PhoneNumberOfflineGeocoder::GetDescriptionForNumber( 1771767c5feSopenharmony_ci const PhoneNumber& number, const Locale& language, 1781767c5feSopenharmony_ci const string& user_region) const { 1791767c5feSopenharmony_ci PhoneNumberUtil::PhoneNumberType number_type = 1801767c5feSopenharmony_ci phone_util_->GetNumberType(number); 1811767c5feSopenharmony_ci if (number_type == PhoneNumberUtil::UNKNOWN) { 1821767c5feSopenharmony_ci return ""; 1831767c5feSopenharmony_ci } else if (!phone_util_->IsNumberGeographical(number_type, 1841767c5feSopenharmony_ci number.country_code())) { 1851767c5feSopenharmony_ci return GetCountryNameForNumber(number, language); 1861767c5feSopenharmony_ci } 1871767c5feSopenharmony_ci return GetDescriptionForValidNumber(number, language, user_region); 1881767c5feSopenharmony_ci} 1891767c5feSopenharmony_ci 1901767c5feSopenharmony_ciconst char* PhoneNumberOfflineGeocoder::GetAreaDescription( 1911767c5feSopenharmony_ci const PhoneNumber& number, const string& lang, const string& script, 1921767c5feSopenharmony_ci const string& region) const { 1931767c5feSopenharmony_ci const int country_calling_code = number.country_code(); 1941767c5feSopenharmony_ci // NANPA area is not split in C++ code. 1951767c5feSopenharmony_ci const int phone_prefix = country_calling_code; 1961767c5feSopenharmony_ci const AreaCodeMap* const descriptions = GetPhonePrefixDescriptions( 1971767c5feSopenharmony_ci phone_prefix, lang, script, region); 1981767c5feSopenharmony_ci const char* description = descriptions ? descriptions->Lookup(number) : NULL; 1991767c5feSopenharmony_ci // When a location is not available in the requested language, fall back to 2001767c5feSopenharmony_ci // English. 2011767c5feSopenharmony_ci if ((!description || *description == '\0') && MayFallBackToEnglish(lang)) { 2021767c5feSopenharmony_ci const AreaCodeMap* default_descriptions = GetPhonePrefixDescriptions( 2031767c5feSopenharmony_ci phone_prefix, "en", "", ""); 2041767c5feSopenharmony_ci if (!default_descriptions) { 2051767c5feSopenharmony_ci return ""; 2061767c5feSopenharmony_ci } 2071767c5feSopenharmony_ci description = default_descriptions->Lookup(number); 2081767c5feSopenharmony_ci } 2091767c5feSopenharmony_ci return description ? description : ""; 2101767c5feSopenharmony_ci} 2111767c5feSopenharmony_ci 2121767c5feSopenharmony_ci// Don't fall back to English if the requested language is among the following: 2131767c5feSopenharmony_ci// - Chinese 2141767c5feSopenharmony_ci// - Japanese 2151767c5feSopenharmony_ci// - Korean 2161767c5feSopenharmony_cibool PhoneNumberOfflineGeocoder::MayFallBackToEnglish( 2171767c5feSopenharmony_ci const string& lang) const { 2181767c5feSopenharmony_ci return lang.compare("zh") && lang.compare("ja") && lang.compare("ko"); 2191767c5feSopenharmony_ci} 2201767c5feSopenharmony_ci 2211767c5feSopenharmony_ci} // namespace phonenumbers 2221767c5feSopenharmony_ci} // namespace i18n 223