• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
27 namespace i18n {
28 namespace phonenumbers {
29 
30 using std::string;
31 
32 namespace {
33 
34 struct NormalizedLocale {
35   const char* locale;
36   const char* normalized_locale;
37 };
38 
39 const NormalizedLocale kNormalizedLocales[] = {
40   {"zh_TW", "zh_Hant"},
41   {"zh_HK", "zh_Hant"},
42   {"zh_MO", "zh_Hant"},
43 };
44 
GetNormalizedLocale(const string & full_locale)45 const 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 
AppendLocalePart(const string & part,string * full_locale)55 void AppendLocalePart(const string& part, string* full_locale) {
56   if (!part.empty()) {
57     full_locale->append("_");
58     full_locale->append(part);
59   }
60 }
61 
ConstructFullLocale(const string & language,const string & script,const string & region,string * full_locale)62 void 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.
IsLowerThan(const char * s1,const char * s2)70 bool IsLowerThan(const char* s1, const char* s2) {
71   return strcmp(s1, s2) < 0;
72 }
73 
74 // Returns true if languages contains language.
HasLanguage(const CountryLanguages * languages,const string & language)75 bool 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 
MappingFileProvider(const int * country_calling_codes,int country_calling_codes_size,country_languages_getter get_country_languages)85 MappingFileProvider::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 
GetFileName(int country_calling_code,const string & language,const string & script,const string & region,string * filename) const93 const 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 
FindBestMatchingLanguageCode(const CountryLanguages * languages,const string & language,const string & script,const string & region,string * best_match) const126 void 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