1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
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
16#include <dirent.h>
17#include <fcntl.h>
18#include <stdlib.h>
19#include <unistd.h>
20#include "update_geocoding.h"
21
22namespace i18n {
23namespace phonenumbers {
24GeocodingInfo* UpdateGeocoding::geocodingInfo = nullptr;
25
26std::map<std::string, PrefixDescriptions>* UpdateGeocoding::prefixDescriptionsMap = new std::map<std::string, PrefixDescriptions>();
27std::map<std::string, PrefixesInfo>* UpdateGeocoding::prefixesInfoMap = new std::map<std::string, PrefixesInfo>();
28const PrefixDescriptions** UpdateGeocoding::prefixDescriptionsArray = nullptr;
29LanguageCodeInfo* UpdateGeocoding::languageCodeInfo = nullptr;
30bool UpdateGeocoding::isupdatedLanguageCodes = false;
31const char** UpdateGeocoding::preLanguageCodes = nullptr;
32const char** UpdateGeocoding::curLanguageCodes = nullptr;
33int UpdateGeocoding::curLanguageCodesSize = 0;
34int UpdateGeocoding::preLanguageCodesSize = 0;
35
36std::map<int, CountryLanguages>* UpdateGeocoding::countryLanguagesMap = new std::map<int, CountryLanguages>();
37std::map<int, CountriesInfo>* UpdateGeocoding::countriesInfoMap = new std::map<int, CountriesInfo>();
38const CountryLanguages** UpdateGeocoding::countryLanguagesArray = nullptr;
39CountryCodeInfo* UpdateGeocoding::countryCodeInfo = nullptr;
40bool UpdateGeocoding::isupdatedCountryCodes = false;
41const int* UpdateGeocoding::preCountryCodes = nullptr;
42int* UpdateGeocoding::curCountryCodes = nullptr;
43int UpdateGeocoding::curCountryCodesSize = 0;
44int UpdateGeocoding::preCountryCodesSize = 0;
45
46void UpdateGeocoding::LoadGeocodingData(int fd)
47{
48    if (geocodingInfo != nullptr) {
49        return;
50    }
51    if (fd == -1) {
52        return;
53    }
54    geocodingInfo = new GeocodingInfo();
55    geocodingInfo->ParseFromFileDescriptor(fd);
56    languageCodeInfo = new  LanguageCodeInfo(geocodingInfo->language_code_info());
57    countryCodeInfo = new CountryCodeInfo(geocodingInfo->country_code_info());
58    for (int i = 0; i < geocodingInfo->languages_size(); i++) {
59        prefixesInfoMap->insert(std::make_pair(geocodingInfo->languages(i), geocodingInfo->prefixes_info(i)));
60    }
61    for (int i = 0; i < geocodingInfo->countries_size(); i++) {
62        countriesInfoMap->insert(std::make_pair(geocodingInfo->countries(i), geocodingInfo->countries_info(i)));
63    }
64}
65
66const PrefixDescriptions* UpdateGeocoding::UpdatePrefixDescriptions(
67    const PrefixDescriptions** prePrefixDescriptionsArray, int index)
68{
69    prefixDescriptionsArray = prePrefixDescriptionsArray;
70    std::string languageCode = isupdatedLanguageCodes ? curLanguageCodes[index] : preLanguageCodes[index];
71    if (prefixDescriptionsMap->find(languageCode) != prefixDescriptionsMap->end()) {
72        return &prefixDescriptionsMap->at(languageCode);
73    }
74    int preIndex = isupdatedLanguageCodes ? FindLanguageCode(languageCode) : index;
75    AddPrefixDescriptions(languageCode, preIndex);
76
77    if (prefixDescriptionsMap->find(languageCode) == prefixDescriptionsMap->end()) {
78        prefixDescriptionsMap->insert(std::make_pair(languageCode, *(prefixDescriptionsArray[preIndex])));
79    }
80    return &prefixDescriptionsMap->at(languageCode);
81}
82
83const char** UpdateGeocoding::UpdateLanguageCodes(const char** languageCodes, int languageCodesSize)
84{
85    preLanguageCodes = languageCodes;
86    preLanguageCodesSize = languageCodesSize;
87    if (languageCodeInfo == nullptr || languageCodeInfo->language_codes_size() == 0) {
88        return preLanguageCodes;
89    }
90    int curLength = languageCodeInfo->language_codes_num();
91    curLanguageCodesSize = curLength;
92    curLanguageCodes = (const char **)malloc(sizeof(char*) * curLength);
93    if (!curLanguageCodes) {
94        return preLanguageCodes;
95    }
96    int preIndex = 0;
97    int curIndex = 0;
98    int mdyIndex = 0;
99    while (preIndex < preLanguageCodesSize && mdyIndex < languageCodeInfo->language_codes_size()) {
100        if (strcmp(languageCodeInfo->language_codes(mdyIndex).c_str(), preLanguageCodes[preIndex]) < 0) {
101            curLanguageCodes[curIndex] = WriteStr(languageCodeInfo->language_codes(mdyIndex));
102            curIndex++;
103            mdyIndex++;
104        } else if (strcmp(languageCodeInfo->language_codes(mdyIndex).c_str(), preLanguageCodes[preIndex]) == 0) {
105            preIndex++;
106            mdyIndex++;
107        } else {
108            curLanguageCodes[curIndex] = preLanguageCodes[preIndex];
109            curIndex++;
110            preIndex++;
111        }
112    }
113
114    while (preIndex < preLanguageCodesSize) {
115        curLanguageCodes[curIndex] = preLanguageCodes[preIndex];
116        curIndex++;
117        preIndex++;
118    }
119
120    while (mdyIndex < languageCodeInfo->language_codes_size()) {
121        curLanguageCodes[curIndex] = WriteStr(languageCodeInfo->language_codes(mdyIndex));
122        curIndex++;
123        mdyIndex++;
124    }
125    isupdatedLanguageCodes = true;
126    return curLanguageCodes;
127}
128
129int UpdateGeocoding::UpdateLanguageCodesSize()
130{
131    if (isupdatedLanguageCodes) {
132        return curLanguageCodesSize;
133    }
134    return preLanguageCodesSize;
135}
136
137void UpdateGeocoding::AddPrefixDescriptions(const std::string& languageCode, int index)
138{
139    if (prefixesInfoMap->find(languageCode) == prefixesInfoMap->end()) {
140        return;
141    }
142    PrefixesInfo prefixesInfo = prefixesInfoMap->at(languageCode);
143    int prefixesSize = static_cast<int>(prefixesInfo.prefixes_num());
144    int32_t* prefixes = (int32_t*)malloc(sizeof(int32_t) * prefixesSize);
145    if (!prefixes) {
146        return;
147    }
148    memset(prefixes, 0, sizeof(int32_t) * prefixesSize);
149    const char** descriptions = (const char **)malloc(sizeof(char*) * prefixesSize);
150    if (!descriptions) {
151        return;
152    }
153    ModifyPrefixDescriptions(prefixes, descriptions, prefixesInfo, index);
154
155    int lengthsSize = prefixesInfo.lengths_num();
156    int32_t* possibleLengths = (int32_t*)malloc(sizeof(int32_t) * lengthsSize);
157    if (!possibleLengths) {
158        return;
159    }
160    ModifyPossibleLengths(possibleLengths, prefixesInfo, index);
161
162    PrefixDescriptions prefixDescriptions = {
163        prefixes,
164        prefixesSize,
165        descriptions,
166        possibleLengths,
167        lengthsSize
168    };
169    prefixDescriptionsMap->insert(std::make_pair(languageCode, prefixDescriptions));
170}
171
172void UpdateGeocoding::ModifyPrefixDescriptions(int32_t* prefixes, const char** descriptions,
173    PrefixesInfo& prefixesInfo, int index)
174{
175    int curIndex = 0;
176    int preIndex = 0;
177    int mdyIndex = 0;
178    const PrefixDescriptions* prefixDescriptions = nullptr;
179    std::string description;
180    int prefixesSize = 0;
181    if (index != -1) {
182        prefixDescriptions = prefixDescriptionsArray[index];
183        prefixesSize = prefixDescriptions->prefixes_size;
184    }
185    while (preIndex < prefixesSize && mdyIndex < prefixesInfo.prefixes_size()) {
186        int prePrefix = prefixDescriptions->prefixes[preIndex];
187        int mdyPrefix = static_cast<int>(prefixesInfo.prefixes(mdyIndex));
188        if (prePrefix == mdyPrefix) {
189            if (prefixesInfo.descriptions(mdyIndex) == "NULL") {
190                preIndex++;
191                mdyIndex++;
192                continue;
193            } else {
194                prefixes[curIndex] = mdyPrefix;
195                descriptions[curIndex] = WriteStr(prefixesInfo.descriptions(mdyIndex));
196                preIndex++;
197                mdyIndex++;
198            }
199        } else if (prePrefix > mdyPrefix) {
200            prefixes[curIndex] = mdyPrefix;
201            descriptions[curIndex] = WriteStr(prefixesInfo.descriptions(mdyIndex));
202            mdyIndex++;
203        } else {
204            prefixes[curIndex] = prePrefix;
205            descriptions[curIndex] = prefixDescriptions->descriptions[preIndex];
206            preIndex++;
207        }
208        curIndex++;
209    }
210    while (preIndex < prefixesSize) {
211        prefixes[curIndex] = prefixDescriptions->prefixes[preIndex];
212        descriptions[curIndex] = prefixDescriptions->descriptions[preIndex];
213        preIndex++;
214        curIndex++;
215    }
216    while (mdyIndex < prefixesInfo.prefixes_size()) {
217        prefixes[curIndex] = static_cast<int>(prefixesInfo.prefixes(mdyIndex));
218        descriptions[curIndex] = WriteStr(prefixesInfo.descriptions(mdyIndex));
219        mdyIndex++;
220        curIndex++;
221    }
222}
223
224void UpdateGeocoding::ModifyPossibleLengths(int32_t* possibleLengths, PrefixesInfo& prefixesInfo, int index)
225{
226    if (index == -1) {
227        for (int i = 0; i < prefixesInfo.lengths_size(); i++) {
228            possibleLengths[i] = prefixesInfo.lengths(i);
229        }
230    } else {
231        for (int i = 0; i < prefixDescriptionsArray[index]->possible_lengths_size; i++) {
232            possibleLengths[i] = prefixDescriptionsArray[index]->possible_lengths[i];
233        }
234    }
235}
236
237const CountryLanguages* UpdateGeocoding::UpdateCountryLanguages(const CountryLanguages** preCountryLanguagesArray, int index)
238{
239    countryLanguagesArray = preCountryLanguagesArray;
240    int countryCode = isupdatedCountryCodes ? curCountryCodes[index] : preCountryCodes[index];
241    if (countryLanguagesMap->find(countryCode) != countryLanguagesMap->end()) {
242        return &countryLanguagesMap->at(countryCode);
243    }
244    int preIndex = isupdatedCountryCodes ? FindCountryCode(countryCode) : index;
245    AddCountryLanguages(countryCode);
246    if (countryLanguagesMap->find(countryCode) == countryLanguagesMap->end() && preIndex != -1) {
247        countryLanguagesMap->insert(std::make_pair(countryCode, *(countryLanguagesArray[preIndex])));
248    }
249    return &countryLanguagesMap->at(countryCode);
250}
251
252const int* UpdateGeocoding::UpdateCountryCodes(const int* countryCodes, int countryCodesSize)
253{
254    preCountryCodes = countryCodes;
255    preCountryCodesSize = countryCodesSize;
256    if (countryCodeInfo == nullptr || countryCodeInfo->country_codes_size() == 0) {
257        return preCountryCodes;
258    }
259    int curLength = countryCodeInfo->country_codes_num();
260    curCountryCodesSize = curLength;
261    curCountryCodes = (int *)malloc(sizeof(int) * curLength);
262    if (!curCountryCodes) {
263        return preCountryCodes;
264    }
265    int preIndex = 0;
266    int curIndex = 0;
267    int mdyIndex = 0;
268    while (preIndex < preCountryCodesSize && mdyIndex < countryCodeInfo->country_codes_size()) {
269        int preCountryCode = preCountryCodes[preIndex];
270        int mdyCountryCode = static_cast<int>(countryCodeInfo->country_codes(mdyIndex));
271        if (preCountryCode > mdyCountryCode) {
272            curCountryCodes[curIndex] = mdyCountryCode;
273            curIndex++;
274            mdyIndex++;
275        } else if (mdyCountryCode == preCountryCode) {
276            preIndex++;
277            mdyIndex++;
278        } else {
279            curCountryCodes[curIndex] = preCountryCode;
280            curIndex++;
281            preIndex++;
282        }
283    }
284    while (preIndex < preCountryCodesSize) {
285        curCountryCodes[curIndex] = preCountryCodes[preIndex];
286        curIndex++;
287        preIndex++;
288    }
289    while (mdyIndex < countryCodeInfo->country_codes_size()) {
290        curCountryCodes[curIndex] = static_cast<int>(countryCodeInfo->country_codes(mdyIndex));
291        curIndex++;
292        mdyIndex++;
293    }
294    isupdatedCountryCodes = true;
295    return curCountryCodes;
296}
297
298int UpdateGeocoding::UpdateCountryCodesSize()
299{
300    if (isupdatedCountryCodes) {
301        return curCountryCodesSize;
302    }
303    return preCountryCodesSize;
304}
305
306void UpdateGeocoding::AddCountryLanguages(int countryCode)
307{
308    if (countriesInfoMap->find(countryCode) == countriesInfoMap->end()) {
309        return;
310    }
311    CountriesInfo countriesInfo = countriesInfoMap->at(countryCode);
312
313    int availableLanguagesSize = static_cast<int>(countriesInfo.country_languages_num());
314    const char** availableLanguages = (const char **)malloc(sizeof(char*) * availableLanguagesSize);
315    if (!availableLanguages) {
316        return;
317    }
318    for (int i = 0; i < countriesInfo.country_languages_size(); i++) {
319        std::string language = countriesInfo.country_languages(i);
320        int len = sizeof(char) * (language.length() + 1);
321        char* temp = (char *)malloc(len);
322        if (!temp) {
323            return;
324        }
325        memset(temp, '\0', len);
326        strncpy(temp, language.c_str(), len);
327        availableLanguages[i] = temp;
328    }
329    CountryLanguages countryLanguages = {
330        availableLanguages,
331        availableLanguagesSize
332    };
333    countryLanguagesMap->insert(std::make_pair(countryCode, countryLanguages));
334}
335
336int UpdateGeocoding::FindLanguageCode(const std::string& languageCode)
337{
338    const char** const preLanguageCodesEnd = preLanguageCodes + preLanguageCodesSize;
339    const char** const preIndex = std::lower_bound(preLanguageCodes,
340                                                   preLanguageCodesEnd,
341                                                   languageCode.c_str(),
342                                                   IsLowerThan);
343    if (preIndex == preLanguageCodesEnd || languageCode.compare(*preIndex) != 0) {
344        return -1;
345    }
346    return preIndex - preLanguageCodes;
347}
348
349int UpdateGeocoding::FindCountryCode(int countryCode)
350{
351    const int* const preCountryCodesEnd = preCountryCodes + preCountryCodesSize;
352    const int* const preIndex = std::lower_bound(preCountryCodes,
353                                                 preCountryCodesEnd,
354                                                 countryCode);
355    if (preIndex == preCountryCodesEnd || *preIndex != countryCode) {
356        return -1;
357    }
358    return preIndex - preCountryCodes;
359}
360
361bool UpdateGeocoding::IsLowerThan(const char* s1, const char* s2)
362{
363    return strcmp(s1, s2) < 0;
364}
365
366char* UpdateGeocoding::WriteStr(const std::string& str)
367{
368    int len = sizeof(char) * (str.length() + 1);
369    char* result = (char*)malloc(len);
370    if (!result) {
371        return nullptr;
372    }
373    memset(result, '\0', len);
374    strncpy(result, str.c_str(), len);
375    return result;
376}
377}
378}