• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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 #include "i18n_timezone.h"
16 
17 #include <dlfcn.h>
18 #include <filesystem>
19 #include <fstream>
20 #include <sys/stat.h>
21 #include "i18n_hilog.h"
22 #include "libxml/globals.h"
23 #include "libxml/tree.h"
24 #include "libxml/xmlstring.h"
25 #include "locale_config.h"
26 #include "locale_matcher.h"
27 #include "locale_info.h"
28 #include "map"
29 #include "securec.h"
30 #include "set"
31 #include "string"
32 #include "type_traits"
33 #include "unicode/umachine.h"
34 #include "utility"
35 #include "utils.h"
36 #include "unicode/utypes.h"
37 #include "vector"
38 #include "unicode/locid.h"
39 #include "unicode/unistr.h"
40 #include "utils.h"
41 #include <cstdio>
42 #include <cstdlib>
43 #include <iostream>
44 #include <regex>
45 
46 namespace OHOS {
47 namespace Global {
48 namespace I18n {
49 using namespace std::filesystem;
50 
51 const char *I18nTimeZone::TIMEZONE_KEY = "persist.time.timezone";
52 const char *I18nTimeZone::DEFAULT_TIMEZONE = "GMT";
53 
54 const char *I18nTimeZone::CITY_TIMEZONE_DATA_PATH = "/system/usr/ohos_timezone/ohos_timezones.xml";
55 const char *I18nTimeZone::DEVICE_CITY_TIMEZONE_DATA_PATH = "/system/usr/ohos_timezone/device_timezones.xml";
56 const char *I18nTimeZone::DISTRO_DEVICE_CITY_TIMEZONE_DATA_PATH = "/system/etc/tzdata_distro/device_timezones.xml";
57 const char *I18nTimeZone::TZ_PIXEL_PATH = "/system/usr/ohos_timezone";
58 const char *I18nTimeZone::DISTRO_TZ_PIXEL_PATH = "/system/etc/tzdata_distro";
59 const char *I18nTimeZone::DEFAULT_LOCALE = "root";
60 const char *I18nTimeZone::CITY_DISPLAYNAME_PATH = "/system/usr/ohos_timezone/ohos_city_dispname/";
61 const char *I18nTimeZone::BASE_DEVICE_CITY_DISPLAYNAME_PATH = "/system/usr/ohos_timezone/device_city_dispname/";
62 const char *I18nTimeZone::DISTRO_DEVICE_CITY_DISPLAYNAME_PATH = "/system/etc/tzdata_distro/device_city_dispname/";
63 const char *I18nTimeZone::DISTRO_ROOT_DISPLAYNAME_PATH = "/system/etc/tzdata_distro/device_city_dispname/root.xml";
64 const char *I18nTimeZone::TIMEZONE_ROOT_TAG = "timezones";
65 const char *I18nTimeZone::TIMEZONE_SECOND_ROOT_TAG = "timezone";
66 const char *I18nTimeZone::CITY_DISPLAYNAME_ROOT_TAG = "display_names";
67 const char *I18nTimeZone::CITY_DISPLAYNAME_SECOND_ROOT_TAG = "display_name";
68 
69 std::set<std::string> I18nTimeZone::supportedLocales {};
70 std::unordered_set<std::string> I18nTimeZone::availableZoneCityIDs {};
71 std::unordered_map<std::string, std::string> I18nTimeZone::city2TimeZoneID {};
72 std::unordered_map<std::string, std::string> I18nTimeZone::cityDisplayNameCache {};
73 std::string I18nTimeZone::cityDisplayNameCacheLocale = "";
74 std::map<std::string, std::string> I18nTimeZone::BEST_MATCH_LOCALE {};
75 std::mutex I18nTimeZone::matchLocaleMutex;
76 std::mutex I18nTimeZone::initZoneInfoMutex;
77 std::mutex I18nTimeZone::initSupportedLocalesMutex;
78 std::mutex I18nTimeZone::cityDisplayNameMutex;
79 bool I18nTimeZone::initAvailableZoneInfo = false;
80 bool I18nTimeZone::initSupportedLocales = false;
81 
82 std::map<int, std::string> I18nTimeZone::categoryNum2TimezoneWN {
83     {0, "Africa/Abidjan"},
84     {2, "Africa/Algiers"},
85     {5, "Africa/Bissau"},
86     {6, "Africa/Casablanca"},
87     {7, "Africa/Ceuta"},
88     {10, "Africa/El_Aaiun"},
89     {13, "Africa/Monrovia"},
90     {16, "America/Adak"},
91     {17, "America/Anchorage"},
92     {22, "America/Bahia_Banderas"},
93     {23, "America/Barbados"},
94     {24, "America/Belem"},
95     {25, "America/Belize"},
96     {27, "America/Boa_Vista"},
97     {28, "America/Bogota"},
98     {29, "America/Boise"},
99     {30, "America/Cambridge_Bay"},
100     {31, "America/Cancun"},
101     {32, "America/Caracas"},
102     {33, "America/Cayenne"},
103     {35, "America/Chicago"},
104     {36, "America/Chihuahua"},
105     {37, "America/Ciudad_Juarez"},
106     {38, "America/Costa_Rica"},
107     {41, "America/Danmarkshavn"},
108     {42, "America/Dawson"},
109     {43, "America/Dawson_Creek"},
110     {44, "America/Denver"},
111     {45, "America/Detroit"},
112     {47, "America/Edmonton"},
113     {48, "America/El_Salvador"},
114     {49, "America/Fort_Nelson"},
115     {50, "America/Glace_Bay"},
116     {51, "America/Goose_Bay"},
117     {52, "America/Grand_Turk"},
118     {55, "America/Guatemala"},
119     {56, "America/Guayaquil"},
120     {57, "America/Guyana"},
121     {58, "America/Halifax"},
122     {59, "America/Havana"},
123     {60, "America/Hermosillo"},
124     {61, "America/Indiana/Indianapolis"},
125     {62, "America/Indiana/Knox"},
126     {63, "America/Indiana/Marengo"},
127     {64, "America/Indiana/Petersburg"},
128     {65, "America/Indiana/Tell_City"},
129     {66, "America/Indiana/Vevay"},
130     {67, "America/Indiana/Vincennes"},
131     {68, "America/Indiana/Winamac"},
132     {69, "America/Inuvik"},
133     {70, "America/Iqaluit"},
134     {71, "America/Jamaica"},
135     {72, "America/Juneau"},
136     {73, "America/Kentucky/Louisville"},
137     {74, "America/Kentucky/Monticello"},
138     {76, "America/Los_Angeles"},
139     {78, "America/Managua"},
140     {79, "America/Manaus"},
141     {81, "America/Martinique"},
142     {82, "America/Matamoros"},
143     {83, "America/Mazatlan"},
144     {84, "America/Menominee"},
145     {85, "America/Merida"},
146     {86, "America/Metlakatla"},
147     {87, "America/Mexico_City"},
148     {88, "America/Miquelon"},
149     {89, "America/Moncton"},
150     {90, "America/Monterrey"},
151     {93, "America/New_York"},
152     {94, "America/Nome"},
153     {95, "America/Noronha"},
154     {96, "America/North_Dakota/Beulah"},
155     {97, "America/North_Dakota/Center"},
156     {98, "America/North_Dakota/New_Salem"},
157     {99, "America/Nuuk"},
158     {100, "America/Ojinaga"},
159     {101, "America/Panama"},
160     {102, "America/Paramaribo"},
161     {103, "America/Phoenix"},
162     {104, "America/Port-au-Prince"},
163     {106, "America/Puerto_Rico"},
164     {107, "America/Rankin_Inlet"},
165     {108, "America/Regina"},
166     {109, "America/Resolute"},
167     {110, "America/Santarem"},
168     {111, "America/Santo_Domingo"},
169     {112, "America/Scoresbysund"},
170     {113, "America/Sitka"},
171     {115, "America/St_Johns"},
172     {120, "America/Swift_Current"},
173     {121, "America/Tegucigalpa"},
174     {122, "America/Thule"},
175     {123, "America/Tijuana"},
176     {124, "America/Toronto"},
177     {126, "America/Vancouver"},
178     {127, "America/Whitehorse"},
179     {128, "America/Winnipeg"},
180     {129, "America/Yakutat"},
181     {130, "Asia/Anadyr"},
182     {131, "Atlantic/Azores"},
183     {132, "Atlantic/Bermuda"},
184     {133, "Atlantic/Canary"},
185     {134, "Atlantic/Cape_Verde"},
186     {135, "Atlantic/Faroe"},
187     {136, "Atlantic/Madeira"},
188     {138, "Etc/GMT"},
189     {139, "Etc/GMT+1"},
190     {140, "Etc/GMT+10"},
191     {141, "Etc/GMT+11"},
192     {142, "Etc/GMT+12"},
193     {143, "Etc/GMT+2"},
194     {144, "Etc/GMT+3"},
195     {145, "Etc/GMT+4"},
196     {146, "Etc/GMT+5"},
197     {147, "Etc/GMT+6"},
198     {148, "Etc/GMT+7"},
199     {149, "Etc/GMT+8"},
200     {150, "Etc/GMT+9"},
201     {151, "Etc/GMT-12"},
202     {152, "Europe/Dublin"},
203     {153, "Europe/Gibraltar"},
204     {154, "Europe/Berlin"},
205     {157, "Europe/Lisbon"},
206     {158, "Europe/London"},
207     {159, "Europe/Madrid"},
208     {161, "Europe/Paris"},
209     {162, "Pacific/Galapagos"},
210     {163, "Pacific/Honolulu"},
211     {164, "Pacific/Kiritimati"},
212     {165, "Pacific/Pago_Pago"}
213 };
214 std::map<int, std::string> I18nTimeZone::categoryNum2TimezoneEN {
215     {0, "Africa/Abidjan"},
216     {2, "Africa/Algiers"},
217     {3, "Africa/Johannesburg"},
218     {7, "Africa/Cairo"},
219     {10, "Africa/Juba"},
220     {12, "Africa/Khartoum"},
221     {14, "Africa/Lagos"},
222     {21, "Africa/Ndjamena"},
223     {25, "Africa/Sao_Tome"},
224     {26, "Africa/Tripoli"},
225     {27, "Africa/Tunis"},
226     {28, "America/Adak"},
227     {31, "Asia/Almaty"},
228     {32, "Asia/Amman"},
229     {33, "Asia/Anadyr"},
230     {34, "Asia/Aqtau"},
231     {35, "Asia/Aqtobe"},
232     {36, "Asia/Ashgabat"},
233     {37, "Asia/Atyrau"},
234     {38, "Asia/Baghdad"},
235     {40, "Asia/Baku"},
236     {42, "Asia/Barnaul"},
237     {43, "Asia/Beirut"},
238     {44, "Asia/Bishkek"},
239     {46, "Asia/Chita"},
240     {48, "Asia/Colombo"},
241     {49, "Asia/Damascus"},
242     {50, "Asia/Dhaka"},
243     {51, "Asia/Dubai"},
244     {52, "Asia/Dushanbe"},
245     {53, "Asia/Famagusta"},
246     {54, "Asia/Gaza"},
247     {55, "Asia/Hebron"},
248     {56, "Asia/Ho_Chi_Minh"},
249     {57, "Asia/Hong_Kong"},
250     {58, "Asia/Hovd"},
251     {59, "Asia/Irkutsk"},
252     {60, "Asia/Jakarta"},
253     {62, "Asia/Jerusalem"},
254     {63, "Asia/Kabul"},
255     {64, "Asia/Kamchatka"},
256     {65, "Asia/Karachi"},
257     {66, "Asia/Kathmandu"},
258     {67, "Asia/Khandyga"},
259     {68, "Asia/Kolkata"},
260     {69, "Asia/Krasnoyarsk"},
261     {73, "Asia/Macau"},
262     {74, "Asia/Magadan"},
263     {75, "Asia/Makassar"},
264     {76, "Asia/Manila"},
265     {78, "Asia/Nicosia"},
266     {79, "Asia/Novokuznetsk"},
267     {80, "Asia/Novosibirsk"},
268     {81, "Asia/Omsk"},
269     {82, "Asia/Oral"},
270     {84, "Asia/Pontianak"},
271     {85, "Asia/Pyongyang"},
272     {86, "Asia/Qatar"},
273     {87, "Asia/Qostanay"},
274     {88, "Asia/Qyzylorda"},
275     {89, "Asia/Riyadh"},
276     {90, "Asia/Sakhalin"},
277     {91, "Asia/Samarkand"},
278     {92, "Asia/Seoul"},
279     {93, "Asia/Shanghai"},
280     {94, "Asia/Singapore"},
281     {95, "Asia/Srednekolymsk"},
282     {96, "Asia/Taipei"},
283     {97, "Asia/Tashkent"},
284     {98, "Asia/Tbilisi"},
285     {99, "Asia/Tehran"},
286     {100, "Asia/Thimbu"},
287     {101, "Asia/Tokyo"},
288     {102, "Asia/Tomsk"},
289     {103, "Asia/Ulaanbaatar"},
290     {104, "Asia/Urumqi"},
291     {105, "Asia/Ust-Nera"},
292     {107, "Asia/Vladivostok"},
293     {108, "Asia/Yakutsk"},
294     {109, "Asia/Yangon"},
295     {110, "Asia/Yekaterinburg"},
296     {111, "Asia/Yerevan"},
297     {112, "Etc/GMT"},
298     {113, "Etc/GMT-1"},
299     {114, "Etc/GMT-10"},
300     {115, "Etc/GMT-11"},
301     {116, "Etc/GMT-12"},
302     {117, "Etc/GMT-2"},
303     {118, "Etc/GMT-3"},
304     {119, "Etc/GMT-4"},
305     {120, "Etc/GMT-5"},
306     {121, "Etc/GMT-6"},
307     {122, "Etc/GMT-7"},
308     {123, "Etc/GMT-8"},
309     {124, "Etc/GMT-9"},
310     {126, "Europe/Andorra"},
311     {127, "Europe/Astrakhan"},
312     {128, "Europe/Athens"},
313     {129, "Europe/Belgrade"},
314     {130, "Europe/Berlin"},
315     {132, "Europe/Brussels"},
316     {133, "Europe/Bucharest"},
317     {134, "Europe/Budapest"},
318     {135, "Pacific/Port_Moresby"},
319     {136, "Europe/Chisinau"},
320     {138, "Europe/Helsinki"},
321     {139, "Europe/Istanbul"},
322     {140, "Europe/Kaliningrad"},
323     {141, "Europe/Kirov"},
324     {142, "Europe/Kiev"},
325     {144, "Europe/London"},
326     {146, "Europe/Madrid"},
327     {147, "Europe/Malta"},
328     {149, "Europe/Minsk"},
329     {151, "Europe/Moscow"},
330     {153, "Europe/Paris"},
331     {155, "Europe/Prague"},
332     {156, "Europe/Riga"},
333     {157, "Europe/Rome"},
334     {158, "Europe/Samara"},
335     {161, "Europe/Saratov"},
336     {162, "Europe/Simferopol"},
337     {163, "Europe/Skopje"},
338     {164, "Europe/Sofia"},
339     {166, "Europe/Tallinn"},
340     {167, "Europe/Tirane"},
341     {168, "Europe/Ulyanovsk"},
342     {170, "Europe/Vienna"},
343     {171, "Europe/Vilnius"},
344     {172, "Europe/Volgograd"},
345     {173, "Europe/Warsaw"},
346     {175, "Europe/Zurich"},
347     {176, "Indian/Maldives"},
348     {177, "Pacific/Chuuk"},
349     {178, "Pacific/Guam"},
350     {179, "Pacific/Kosrae"},
351     {180, "Pacific/Kwajalein"},
352     {181, "Pacific/Guadalcanal"},
353     {185, "Pacific/Tarawa"}
354 };
355 std::map<int, std::string> I18nTimeZone::categoryNum2TimezoneWS {
356     {0, "Africa/Johannesburg"},
357     {1, "America/Araguaina"},
358     {2, "America/Argentina/Buenos_Aires"},
359     {3, "America/Argentina/Catamarca"},
360     {4, "America/Argentina/Cordoba"},
361     {5, "America/Argentina/Jujuy"},
362     {6, "America/Argentina/La_Rioja"},
363     {7, "America/Argentina/Mendoza"},
364     {8, "America/Argentina/Rio_Gallegos"},
365     {9, "America/Argentina/Salta"},
366     {10, "America/Argentina/San_Juan"},
367     {11, "America/Argentina/San_Luis"},
368     {12, "America/Argentina/Tucuman"},
369     {13, "America/Argentina/Ushuaia"},
370     {14, "America/Asuncion"},
371     {15, "America/Bahia"},
372     {16, "America/Belem"},
373     {17, "America/Boa_Vista"},
374     {18, "America/Bogota"},
375     {19, "America/Campo_Grande"},
376     {20, "America/Cuiaba"},
377     {21, "America/Eirunepe"},
378     {22, "America/Fortaleza"},
379     {23, "America/Guayaquil"},
380     {24, "America/Coyhaique"},
381     {25, "America/Lima"},
382     {26, "America/Maceio"},
383     {27, "America/Manaus"},
384     {28, "America/Montevideo"},
385     {29, "America/Noronha"},
386     {30, "America/Porto_Velho"},
387     {31, "America/Punta_Arenas"},
388     {32, "America/Recife"},
389     {33, "America/Rio_Branco"},
390     {34, "America/Santarem"},
391     {35, "America/Santiago"},
392     {36, "America/Sao_Paulo"},
393     {37, "Africa/Abidjan"},
394     {38, "Antarctica/Palmer"},
395     {39, "Antarctica/Rothera"},
396     {40, "Atlantic/South_Georgia"},
397     {41, "America/Puerto_Rico"},
398     {42, "Atlantic/Stanley"},
399     {43, "Etc/GMT"},
400     {44, "Etc/GMT+1"},
401     {45, "Etc/GMT+10"},
402     {46, "Etc/GMT+11"},
403     {47, "Etc/GMT+12"},
404     {48, "Etc/GMT+2"},
405     {49, "Etc/GMT+3"},
406     {50, "Etc/GMT+4"},
407     {51, "Etc/GMT+5"},
408     {52, "Etc/GMT+6"},
409     {53, "Etc/GMT+7"},
410     {54, "Etc/GMT+8"},
411     {55, "Etc/GMT+9"},
412     {56, "Etc/GMT-12"},
413     {57, "Etc/UTC"},
414     {58, "Pacific/Apia"},
415     {59, "Pacific/Auckland"},
416     {60, "Pacific/Chatham"},
417     {61, "Pacific/Easter"},
418     {62, "Pacific/Fakaofo"},
419     {63, "Pacific/Fiji"},
420     {64, "Pacific/Honolulu"},
421     {65, "Pacific/Galapagos"},
422     {66, "Pacific/Gambier"},
423     {67, "Pacific/Kanton"},
424     {68, "Pacific/Kiritimati"},
425     {69, "Pacific/Marquesas"},
426     {71, "Pacific/Pago_Pago"},
427     {72, "Pacific/Pitcairn"},
428     {73, "Pacific/Rarotonga"},
429     {74, "Pacific/Tarawa"},
430     {75, "Pacific/Tongatapu"},
431 };
432 std::map<int, std::string> I18nTimeZone::categoryNum2TimezoneES {
433     {6, "Africa/Johannesburg"},
434     {7, "Africa/Lagos"},
435     {8, "Asia/Riyadh"},
436     {9, "Asia/Tokyo"},
437     {10, "Asia/Yangon"},
438     {20, "Africa/Sao_Tome"},
439     {21, "Africa/Windhoek"},
440     {22, "Antarctica/Casey"},
441     {23, "Antarctica/Davis"},
442     {25, "Antarctica/Macquarie"},
443     {26, "Antarctica/Mawson"},
444     {29, "Antarctica/Troll"},
445     {30, "Antarctica/Vostok"},
446     {31, "Asia/Dili"},
447     {32, "Asia/Dubai"},
448     {33, "Asia/Jakarta"},
449     {34, "Asia/Makassar"},
450     {35, "Asia/Pontianak"},
451     {36, "Australia/Adelaide"},
452     {37, "Australia/Brisbane"},
453     {38, "Australia/Broken_Hill"},
454     {39, "Australia/Darwin"},
455     {40, "Australia/Eucla"},
456     {41, "Australia/Hobart"},
457     {42, "Australia/Lindeman"},
458     {43, "Australia/Lord_Howe"},
459     {44, "Australia/Melbourne"},
460     {45, "Australia/Perth"},
461     {46, "Australia/Sydney"},
462     {47, "Etc/GMT"},
463     {48, "Etc/GMT-1"},
464     {49, "Etc/GMT-10"},
465     {50, "Etc/GMT-11"},
466     {51, "Etc/GMT-12"},
467     {52, "Etc/GMT-2"},
468     {53, "Etc/GMT-3"},
469     {54, "Etc/GMT-4"},
470     {55, "Etc/GMT-5"},
471     {56, "Etc/GMT-6"},
472     {57, "Etc/GMT-7"},
473     {58, "Etc/GMT-8"},
474     {59, "Etc/GMT-9"},
475     {61, "Indian/Chagos"},
476     {67, "Indian/Maldives"},
477     {68, "Indian/Mauritius"},
478     {71, "Pacific/Auckland"},
479     {72, "Pacific/Bougainville"},
480     {73, "Pacific/Efate"},
481     {74, "Pacific/Fiji"},
482     {76, "Pacific/Guadalcanal"},
483     {77, "Pacific/Nauru"},
484     {78, "Pacific/Norfolk"},
485     {79, "Pacific/Noumea"},
486     {80, "Pacific/Port_Moresby"},
487     {81, "Pacific/Tarawa"}
488 };
489 
I18nTimeZone(std::string & id,bool isZoneID)490 I18nTimeZone::I18nTimeZone(std::string &id, bool isZoneID)
491 {
492     if (isZoneID) {
493         if (id.empty()) {
494             std::string systemTimezone = ReadSystemParameter(TIMEZONE_KEY, SYS_PARAM_LEN);
495             if (systemTimezone.empty()) {
496                 HILOG_ERROR_I18N("I18nTimeZone::I18nTimeZone: Read system time zone failed.");
497                 systemTimezone = DEFAULT_TIMEZONE;
498             }
499             icu::UnicodeString unicodeZoneID(systemTimezone.data(), systemTimezone.length());
500             timezone = icu::TimeZone::createTimeZone(unicodeZoneID);
501         } else {
502             icu::UnicodeString unicodeZoneID(id.data(), id.length());
503             timezone = icu::TimeZone::createTimeZone(unicodeZoneID);
504         }
505     } else {
506         GetAvailableZoneCityIDs();
507         if (city2TimeZoneID.find(id) == city2TimeZoneID.end()) {
508             timezone = icu::TimeZone::createDefault();
509         } else {
510             std::string timezoneID = city2TimeZoneID.at(id);
511             icu::UnicodeString unicodeZoneID(timezoneID.data(), timezoneID.length());
512             timezone = icu::TimeZone::createTimeZone(unicodeZoneID);
513         }
514     }
515 }
516 
~I18nTimeZone()517 I18nTimeZone::~I18nTimeZone()
518 {
519     if (timezone != nullptr) {
520         delete timezone;
521         timezone = nullptr;
522     }
523 }
524 
GetTimeZone()525 icu::TimeZone* I18nTimeZone::GetTimeZone()
526 {
527     return timezone;
528 }
529 
CreateInstance(std::string & id,bool isZoneID)530 std::unique_ptr<I18nTimeZone> I18nTimeZone::CreateInstance(std::string &id, bool isZoneID)
531 {
532     std::unique_ptr<I18nTimeZone> i18nTimeZone = std::make_unique<I18nTimeZone>(id, isZoneID);
533     if (i18nTimeZone == nullptr) {
534         return nullptr;
535     }
536     if (i18nTimeZone->GetTimeZone() == nullptr) {
537         return nullptr;
538     }
539     return i18nTimeZone;
540 }
541 
GetOffset(double date)542 int32_t I18nTimeZone::GetOffset(double date)
543 {
544     if (timezone == nullptr) {
545         return 0;
546     }
547     int32_t rawOffset = 0;
548     int32_t dstOffset = 0;
549     bool local = false;
550     UErrorCode status = U_ZERO_ERROR;
551     timezone->getOffset(date, (UBool)local, rawOffset, dstOffset, status);
552     if (U_FAILURE(status)) {
553         return 0;
554     }
555     return rawOffset + dstOffset;
556 }
557 
GetRawOffset()558 int32_t I18nTimeZone::GetRawOffset()
559 {
560     if (timezone == nullptr) {
561         return 0;
562     }
563     return timezone->getRawOffset();
564 }
565 
GetID()566 std::string I18nTimeZone::GetID()
567 {
568     if (timezone == nullptr) {
569         return "";
570     }
571     icu::UnicodeString zoneID;
572     timezone->getID(zoneID);
573     std::string result;
574     zoneID.toUTF8String(result);
575     return result;
576 }
577 
GetDisplayName()578 std::string I18nTimeZone::GetDisplayName()
579 {
580     if (timezone == nullptr) {
581         return "";
582     }
583     std::string localeStr = LocaleConfig::GetEffectiveLocale();
584     return GetDisplayName(localeStr, false);
585 }
586 
GetDisplayName(bool isDST)587 std::string I18nTimeZone::GetDisplayName(bool isDST)
588 {
589     std::string localeStr = LocaleConfig::GetEffectiveLocale();
590     return GetDisplayName(localeStr, isDST);
591 }
592 
GetDisplayName(std::string localeStr)593 std::string I18nTimeZone::GetDisplayName(std::string localeStr)
594 {
595     return GetDisplayName(localeStr, false);
596 }
597 
GetDisplayName(std::string localeStr,bool isDST)598 std::string I18nTimeZone::GetDisplayName(
599     std::string localeStr, bool isDST)
600 {
601     icu::TimeZone::EDisplayType style = icu::TimeZone::EDisplayType::LONG_GENERIC;
602     UErrorCode status = U_ZERO_ERROR;
603     icu::Locale locale;
604     std::string result;
605     if (LocaleConfig::IsValidTag(localeStr)) {
606         locale = icu::Locale::forLanguageTag(localeStr, status);
607     } else {
608         std::string systemLocale = LocaleConfig::GetEffectiveLocale();
609         locale = icu::Locale::forLanguageTag(systemLocale, status);
610     }
611     if (U_FAILURE(status)) {
612         HILOG_ERROR_I18N("create icu Locale for %{public}s failed.", localeStr.c_str());
613         return PseudoLocalizationProcessor(result);
614     }
615     icu::UnicodeString name;
616     if (timezone == nullptr) {
617         return PseudoLocalizationProcessor(result);
618     }
619     timezone->getDisplayName((UBool)isDST, style, locale, name);
620     name.toUTF8String(result);
621     return PseudoLocalizationProcessor(GetDisplayNameByTaboo(localeStr, result));
622 }
623 
GetDisplayNameByTaboo(const std::string & localeStr,const std::string & result)624 std::string I18nTimeZone::GetDisplayNameByTaboo(
625     const std::string& localeStr, const std::string& result)
626 {
627     TabooUtils* tabooUtils = TabooUtils::GetInstance();
628     if (tabooUtils == nullptr) {
629         HILOG_ERROR_I18N("I18nTimeZone::GetDisplayNameByTaboo: tabooUtils is nullptr.");
630         return result;
631     }
632     return tabooUtils->ReplaceTimeZoneName(GetID(), localeStr, result);
633 }
634 
ReadTimeZoneData(const char * xmlPath)635 bool I18nTimeZone::ReadTimeZoneData(const char *xmlPath)
636 {
637     xmlKeepBlanksDefault(0);
638     if (xmlPath == nullptr) {
639         return false;
640     }
641     xmlDocPtr doc = xmlParseFile(xmlPath);
642     if (!doc) {
643         return false;
644     }
645     xmlNodePtr cur = xmlDocGetRootElement(doc);
646     if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(TIMEZONE_ROOT_TAG))) {
647         xmlFreeDoc(doc);
648         return false;
649     }
650     cur = cur->xmlChildrenNode;
651     while (cur != nullptr && !xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(TIMEZONE_SECOND_ROOT_TAG))) {
652         xmlNodePtr value = cur->xmlChildrenNode;
653         xmlChar *contents[ELEMENT_NUM] = { 0 }; // 2 represent cityid, zoneid;
654         bool xmlNodeIsNull = false;
655         for (size_t i = 0; i < ELEMENT_NUM && value != nullptr; i++) {
656             contents[i] = xmlNodeGetContent(value);
657             value = value->next;
658             if (contents[i] == nullptr) {
659                 xmlNodeIsNull = true;
660             }
661         }
662         if (!xmlNodeIsNull) {
663             // 0 represents cityid index, 1 represents zoneid index
664             availableZoneCityIDs.insert(reinterpret_cast<const char *>(contents[0]));
665             const char* pairKey = reinterpret_cast<const char *>(contents[0]);
666             const char* pairVal = reinterpret_cast<const char *>(contents[1]);
667             city2TimeZoneID.insert(std::make_pair<std::string, std::string>(pairKey, pairVal));
668         }
669         for (size_t i = 0; i < ELEMENT_NUM; i++) {
670             if (contents[i] != nullptr) {
671                 xmlFree(contents[i]);
672             }
673         }
674         cur = cur->next;
675     }
676     xmlFreeDoc(doc);
677     return true;
678 }
679 
GetTimezoneIDFromZoneInfo(std::set<std::string> & availableIDs,std::string & parentPath,std::string & parentName)680 void I18nTimeZone::GetTimezoneIDFromZoneInfo(std::set<std::string> &availableIDs, std::string &parentPath,
681     std::string &parentName)
682 {
683     using std::filesystem::directory_iterator;
684 
685     struct stat s;
686     for (const auto &dirEntry : directory_iterator{parentPath}) {
687         std::string zonePath = dirEntry.path();
688         if (stat(zonePath.c_str(), &s) != 0) {
689             HILOG_ERROR_I18N("GetTimezoneIDFromZoneInfo: zoneinfo path %{public}s not exist.", parentPath.c_str());
690             return;
691         }
692         std::string zoneName = zonePath.substr(parentPath.length() + 1); // 1 add length of path splitor
693         std::string finalZoneName = parentName + "/" + zoneName;
694         if (s.st_mode & S_IFDIR) {
695             GetTimezoneIDFromZoneInfo(availableIDs, zonePath, finalZoneName);
696         } else {
697             availableIDs.insert(finalZoneName);
698         }
699     }
700 }
701 
GetAvailableIDs(I18nErrorCode & errorCode)702 std::set<std::string> I18nTimeZone::GetAvailableIDs(I18nErrorCode &errorCode)
703 {
704     return GetTimeZoneAvailableIDs(errorCode);
705 }
706 
GetAvailableZoneCityIDs()707 std::unordered_set<std::string> I18nTimeZone::GetAvailableZoneCityIDs()
708 {
709     if (initAvailableZoneInfo) {
710         return availableZoneCityIDs;
711     }
712     std::lock_guard<std::mutex> lock(initZoneInfoMutex);
713     if (initAvailableZoneInfo) {
714         return availableZoneCityIDs;
715     }
716     struct stat s;
717     if (stat(DISTRO_DEVICE_CITY_TIMEZONE_DATA_PATH, &s) == 0) {
718         ReadTimeZoneData(DISTRO_DEVICE_CITY_TIMEZONE_DATA_PATH);
719     } else if (stat(DEVICE_CITY_TIMEZONE_DATA_PATH, &s) == 0) {
720         ReadTimeZoneData(DEVICE_CITY_TIMEZONE_DATA_PATH);
721     } else {
722         ReadTimeZoneData(CITY_TIMEZONE_DATA_PATH);
723     }
724     TabooUtils* tabooUtils = TabooUtils::GetInstance();
725     if (tabooUtils == nullptr) {
726         HILOG_ERROR_I18N("I18nTimeZone::GetAvailableZoneCityIDs: tabooUtils is nullptr.");
727         return availableZoneCityIDs;
728     }
729     std::unordered_set<std::string> blockedCities = tabooUtils->GetBlockedCities();
730     for (const auto& city : blockedCities) {
731         if (availableZoneCityIDs.find(city) != availableZoneCityIDs.end()) {
732             availableZoneCityIDs.erase(city);
733             city2TimeZoneID.erase(city);
734         }
735     }
736     initAvailableZoneInfo = true;
737     return availableZoneCityIDs;
738 }
739 
FindCityDisplayNameFromXml(std::string & cityID,std::string & locale)740 std::string I18nTimeZone::FindCityDisplayNameFromXml(std::string &cityID, std::string &locale)
741 {
742     if (cityDisplayNameCacheLocale.compare(locale) == 0) {
743         return GetCityDisplayNameFromCache(cityID);
744     }
745     std::lock_guard<std::mutex> lock(cityDisplayNameMutex);
746     if (cityDisplayNameCacheLocale.compare(locale) == 0) {
747         return GetCityDisplayNameFromCache(cityID);
748     }
749     std::string displayName = FindCityDisplayNameFromXmlInner(cityID, locale);
750     return displayName;
751 }
752 
FindCityDisplayNameFromXmlInner(std::string & cityID,std::string & locale)753 std::string I18nTimeZone::FindCityDisplayNameFromXmlInner(std::string &cityID, std::string &locale)
754 {
755     xmlKeepBlanksDefault(0);
756     std::string xmlPath = GetCityDisplayNameXmlPath(locale);
757     xmlDocPtr doc = xmlParseFile(xmlPath.c_str());
758     if (!doc) {
759         HILOG_ERROR_I18N("FindCityDisplayNameFromXml: can't parse city displayname: %{public}s", xmlPath.c_str());
760         return "";
761     }
762     xmlNodePtr cur = xmlDocGetRootElement(doc);
763     if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(CITY_DISPLAYNAME_ROOT_TAG))) {
764         xmlFreeDoc(doc);
765         HILOG_ERROR_I18N(
766             "FindCityDisplayNameFromXml: city displayname file %{public}s has wrong root tag.", xmlPath.c_str());
767         return "";
768     }
769     cur = cur->xmlChildrenNode;
770     cityDisplayNameCache.clear();
771     while (cur != nullptr && !xmlStrcmp(cur->name,
772         reinterpret_cast<const xmlChar *>(CITY_DISPLAYNAME_SECOND_ROOT_TAG))) {
773         xmlNodePtr value = cur->xmlChildrenNode;
774         xmlChar *contents[ELEMENT_NUM] = { 0 }; // 2 represent cityid, displayName;
775         bool xmlNodeIsNull = false;
776         for (size_t i = 0; i < ELEMENT_NUM && value != nullptr; i++) {
777             contents[i] = xmlNodeGetContent(value);
778             if (contents[i] == nullptr) {
779                 xmlNodeIsNull = true;
780                 break;
781             }
782             value = value->next;
783         }
784         if (!xmlNodeIsNull) {
785             const char* xmlKey = reinterpret_cast<const char *>(contents[0]);
786             const char* xmlValue = reinterpret_cast<const char *>(contents[1]);
787             AddCityDisplayNameCache(xmlKey, xmlValue);
788         }
789         for (size_t i = 0; i < ELEMENT_NUM; i++) {
790             if (contents[i] != nullptr) {
791                 xmlFree(contents[i]);
792             }
793         }
794         cur = cur->next;
795     }
796     xmlFreeDoc(doc);
797     return ResetCityDisplayNameCache(cityID, locale);
798 }
799 
ResetCityDisplayNameCache(std::string & cityID,std::string & locale)800 std::string I18nTimeZone::ResetCityDisplayNameCache(std::string &cityID, std::string &locale)
801 {
802     cityDisplayNameCacheLocale = locale;
803     if (cityDisplayNameCache.find(cityID) != cityDisplayNameCache.end()) {
804         return cityDisplayNameCache.at(cityID);
805     }
806     HILOG_ERROR_I18N("I18nTimeZone::ResetCityDisplayNameCache: not found cityID:%{public}s in locale:%{public}s",
807         cityID.c_str(), locale.c_str());
808     return "";
809 }
810 
AddCityDisplayNameCache(const char * xmlCityId,const char * xmlValue)811 void I18nTimeZone::AddCityDisplayNameCache(const char* xmlCityId, const char* xmlValue)
812 {
813     if (xmlCityId == nullptr) {
814         HILOG_ERROR_I18N("I18nTimeZone::AddCityDisplayNameCache: xmlCityId is NULL.");
815         return;
816     }
817     if (xmlValue == nullptr) {
818         HILOG_ERROR_I18N("I18nTimeZone::AddCityDisplayNameCache: xmlValue is NULL.");
819         return;
820     }
821     std::string cityId(xmlCityId);
822     std::string cityDispName(xmlValue);
823     if (!cityId.empty() && !cityDispName.empty()) {
824         cityDisplayNameCache.insert(std::make_pair(cityId, cityDispName));
825     }
826 }
827 
GetCityDisplayNameFromCache(std::string & cityID)828 std::string I18nTimeZone::GetCityDisplayNameFromCache(std::string &cityID)
829 {
830     if (cityDisplayNameCache.find(cityID) != cityDisplayNameCache.end()) {
831         return cityDisplayNameCache.at(cityID);
832     }
833     HILOG_ERROR_I18N("I18nTimeZone::GetCityDisplayNameFromCache: not found cityID:%{public}s in locale:%{public}s",
834         cityID.c_str(), cityDisplayNameCacheLocale.c_str());
835     return "";
836 }
837 
GetCityDisplayNameXmlPath(const std::string & locale)838 std::string I18nTimeZone::GetCityDisplayNameXmlPath(const std::string &locale)
839 {
840     const char *deviceCityDisplayNamePath = GetDeviceCityDisplayNamePath();
841     if (strlen(deviceCityDisplayNamePath) != 0) {
842         return deviceCityDisplayNamePath + locale + ".xml";
843     } else {
844         return CITY_DISPLAYNAME_PATH + locale + ".xml";
845     }
846 }
847 
FindCityDisplayNameMap(std::string & locale)848 std::map<std::string, std::string> I18nTimeZone::FindCityDisplayNameMap(std::string &locale)
849 {
850     xmlKeepBlanksDefault(0);
851     std::map<std::string, std::string> resultMap;
852     std::string xmlPath = GetCityDisplayNameXmlPath(locale);
853     xmlDocPtr doc = xmlParseFile(xmlPath.c_str());
854     if (!doc) {
855         HILOG_ERROR_I18N("FindCityDisplayNameMap: can't parse city displayname file %{public}s", xmlPath.c_str());
856         return resultMap;
857     }
858     xmlNodePtr cur = xmlDocGetRootElement(doc);
859     if (!cur || xmlStrcmp(cur->name, reinterpret_cast<const xmlChar *>(CITY_DISPLAYNAME_ROOT_TAG))) {
860         xmlFreeDoc(doc);
861         HILOG_ERROR_I18N(
862             "FindCityDisplayNameMap: city displayname file %{public}s has wrong root tag.", xmlPath.c_str());
863         return resultMap;
864     }
865     cur = cur->xmlChildrenNode;
866     while (cur != nullptr && !xmlStrcmp(cur->name,
867         reinterpret_cast<const xmlChar *>(CITY_DISPLAYNAME_SECOND_ROOT_TAG))) {
868         xmlNodePtr value = cur->xmlChildrenNode;
869         xmlChar *contents[ELEMENT_NUM] = { 0 }; // 2 represent cityid, displayName;
870         bool xmlNodeIsNull = false;
871         for (size_t i = 0; i < ELEMENT_NUM && value != nullptr; i++) {
872             contents[i] = xmlNodeGetContent(value);
873             value = value->next;
874             if (contents[i] == nullptr) {
875                 xmlNodeIsNull = true;
876             }
877         }
878         if (!xmlNodeIsNull) {
879             const char* key = reinterpret_cast<const char *>(contents[0]);
880             const char* displayName = reinterpret_cast<const char *>(contents[1]);
881             resultMap.insert(std::make_pair<std::string, std::string>(key, displayName));
882         }
883         for (size_t i = 0; i < ELEMENT_NUM; i++) {
884             if (contents[i] != nullptr) {
885                 xmlFree(contents[i]);
886             }
887         }
888         cur = cur->next;
889     }
890     xmlFreeDoc(doc);
891     return resultMap;
892 }
893 
GetSupportedLocales()894 bool I18nTimeZone::GetSupportedLocales()
895 {
896     if (initSupportedLocales) {
897         return true;
898     }
899     std::lock_guard<std::mutex> lock(initSupportedLocalesMutex);
900     if (initSupportedLocales) {
901         return true;
902     }
903 
904     using std::filesystem::directory_iterator;
905     struct stat s;
906     std::string displayNamePath = GetDeviceCityDisplayNamePath();
907     if (displayNamePath.length() == 0) {
908         displayNamePath = CITY_DISPLAYNAME_PATH;
909     }
910     for (const auto &dirEntry : directory_iterator{displayNamePath}) {
911         std::string xmlPath = dirEntry.path();
912         if (stat(xmlPath.c_str(), &s) != 0) {
913             HILOG_ERROR_I18N("city displayname file %{public}s not exist.", xmlPath.c_str());
914             return false;
915         }
916         int32_t localeStrLen = static_cast<int32_t>(xmlPath.length()) - static_cast<int32_t>(
917             displayNamePath.length()) - 4;  // 4 is the length of ".xml"
918         std::string localeStr = xmlPath.substr(displayNamePath.length(), localeStrLen);
919         supportedLocales.insert(localeStr);
920     }
921     initSupportedLocales = true;
922     return true;
923 }
924 
GetFallBack(std::string & requestLocaleStr)925 std::string I18nTimeZone::GetFallBack(std::string &requestLocaleStr)
926 {
927     auto iter = BEST_MATCH_LOCALE.find(requestLocaleStr);
928     if (iter != BEST_MATCH_LOCALE.end()) {
929         return iter->second;
930     }
931     std::vector<LocaleInfo*> matchLocaleList;
932     std::unique_ptr<LocaleInfo> requestLocale = std::make_unique<LocaleInfo>(requestLocaleStr);
933     for (auto it = supportedLocales.begin(); it != supportedLocales.end(); ++it) {
934         std::string tempLocaleStr = it->data();
935         tempLocaleStr = StrReplaceAll(tempLocaleStr, "_", "-");
936         LocaleInfo* tempLocale = new LocaleInfo(tempLocaleStr);
937         if (LocaleMatcher::Match(requestLocale.get(), tempLocale)) {
938             matchLocaleList.push_back(tempLocale);
939         } else {
940             delete tempLocale;
941         }
942     }
943     std::string bestMatchLocaleTag = DEFAULT_LOCALE;
944     if (matchLocaleList.size() == 0) {
945         return bestMatchLocaleTag;
946     }
947     LocaleInfo *bestMatch = matchLocaleList[0];
948     for (size_t i = 1; i < matchLocaleList.size(); ++i) {
949         if (LocaleMatcher::IsMoreSuitable(bestMatch, matchLocaleList[i], requestLocale.get()) < 0) {
950             bestMatch = matchLocaleList[i];
951         }
952     }
953     bestMatchLocaleTag = bestMatch->ToString();
954     for (size_t i = 0; i < matchLocaleList.size(); ++i) {
955         delete matchLocaleList[i];
956     }
957     bestMatchLocaleTag = StrReplaceAll(bestMatchLocaleTag, "-", "_");
958     SetBestMatchLocale(requestLocaleStr, bestMatchLocaleTag);
959     return bestMatchLocaleTag;
960 }
961 
SetBestMatchLocale(const std::string & key,const std::string & value)962 void I18nTimeZone::SetBestMatchLocale(const std::string& key, const std::string& value)
963 {
964     std::lock_guard<std::mutex> matchLocaleLock(matchLocaleMutex);
965     BEST_MATCH_LOCALE.insert(std::make_pair(key, value));
966 }
967 
GetCityDisplayName(std::string & cityID,std::string & localeStr)968 std::string I18nTimeZone::GetCityDisplayName(std::string &cityID, std::string &localeStr)
969 {
970     GetAvailableZoneCityIDs();
971     if (availableZoneCityIDs.find(cityID) == availableZoneCityIDs.end()) {
972         HILOG_ERROR_I18N("I18nTimeZone::GetCityDisplayName: %{public}s is not supported cityID.", cityID.c_str());
973         return PseudoLocalizationProcessor("");
974     }
975     std::string requestLocaleStr = GetLocaleBaseName(localeStr);
976     if (requestLocaleStr.empty()) {
977         HILOG_ERROR_I18N("I18nTimeZone::GetCityDisplayName: requestLocaleStr is empty.");
978         return PseudoLocalizationProcessor("");
979     }
980     std::string displayName = FindCityDisplayNameFromXml(cityID, requestLocaleStr);
981     TabooUtils* tabooUtils = TabooUtils::GetInstance();
982     if (tabooUtils == nullptr) {
983         HILOG_ERROR_I18N("I18nTimeZone::GetCityDisplayName: tabooUtils is nullptr.");
984         return PseudoLocalizationProcessor(displayName);
985     }
986     requestLocaleStr = StrReplaceAll(requestLocaleStr, "_", "-");
987     displayName = tabooUtils->ReplaceCityName(cityID, requestLocaleStr, displayName);
988     return PseudoLocalizationProcessor(displayName);
989 }
990 
GetLocaleBaseName(std::string & localeStr)991 std::string I18nTimeZone::GetLocaleBaseName(std::string &localeStr)
992 {
993     bool status = GetSupportedLocales();
994     if (!status) {
995         HILOG_ERROR_I18N("get supported Locales failed");
996         return "";
997     }
998     UErrorCode errorCode = U_ZERO_ERROR;
999     icu::Locale locale = icu::Locale::forLanguageTag(localeStr, errorCode);
1000     if (U_FAILURE(errorCode)) {
1001         HILOG_ERROR_I18N("create icu Locale for %{public}s failed", localeStr.c_str());
1002         return "";
1003     }
1004     std::string requestLocaleStr = locale.getBaseName();
1005     requestLocaleStr = StrReplaceAll(requestLocaleStr, "_", "-");
1006     return GetFallBack(requestLocaleStr);
1007 }
1008 
GetTimezoneIdByCityId(const std::string & cityId)1009 std::string I18nTimeZone::GetTimezoneIdByCityId(const std::string &cityId)
1010 {
1011     GetAvailableZoneCityIDs();
1012     if (city2TimeZoneID.find(cityId) == city2TimeZoneID.end()) {
1013         return "";
1014     }
1015     return city2TimeZoneID.at(cityId);
1016 }
1017 
GetTimezoneIdByLocation(const double x,const double y)1018 std::vector<std::string> I18nTimeZone::GetTimezoneIdByLocation(const double x, const double y)
1019 {
1020     std::vector<std::string> tzIdList;
1021 #ifdef SUPPORT_GRAPHICS
1022     if (!CheckLatitudeAndLongitude(x, y)) {
1023         return tzIdList;
1024     }
1025     std::map<int, std::string> categoryMap = GetTimeZoneCategoryMap(x, y);
1026     std::vector<std::string> filePaths = FindTzData();
1027     size_t fileCount = filePaths.size();
1028     if (fileCount < 1) {
1029         return tzIdList;
1030     }
1031     std::string preferredPath = GetPreferredPath(x, filePaths);
1032     if (preferredPath.empty()) {
1033         return tzIdList;
1034     }
1035     uint32_t width = 0;
1036     uint32_t height = 0;
1037     std::tie(width, height) = GetTzDataWidth(filePaths);
1038     double calculateX = y * width / (TZ_X_PLUS * 1.0) + width / (TZ_HALF_OF_SIZE * 1.0);
1039     double calculateY = x * ((height * fileCount) / (TZ_X_PLUS * TZ_HALF_OF_SIZE * 1.0)) +
1040                         (height * fileCount) / (TZ_HALF_OF_SIZE * 1.0);
1041     uint16_t fixedX = static_cast<uint16_t>(calculateX);
1042     uint16_t fixedY = static_cast<uint16_t>(calculateY);
1043     if (ParamExceedScope(fixedX, fixedY, width, height * fileCount)) {
1044         HILOG_ERROR_I18N("invalid width:%{public}d or height: %{public}d", fixedX, fixedY);
1045         return tzIdList;
1046     }
1047     uint16_t actualHeight = fileCount > 1 ? (fixedY % height) : fixedY;
1048     std::vector<int> pixel = GetColorData(fixedX, fixedY, actualHeight, preferredPath);
1049     for (size_t i = 0; i < pixel.size(); i++) {
1050         //255 is invalid pixel value required
1051         if (pixel[i] != TZ_MAX_PIXEL_VALUE && categoryMap.find(pixel[i]) != categoryMap.end()) {
1052             std::string zdId = categoryMap[pixel[i]];
1053             tzIdList.push_back(zdId);
1054         }
1055     }
1056 #endif
1057     return tzIdList;
1058 }
1059 
GetTimeZoneCategoryMap(const double x,const double y)1060 std::map<int, std::string> I18nTimeZone::GetTimeZoneCategoryMap(const double x, const double y)
1061 {
1062     if (x < 0 && Geq(y, 0)) {
1063         return categoryNum2TimezoneWN;
1064     } else if (Geq(x, 0) && Geq(y, 0)) {
1065         return categoryNum2TimezoneEN;
1066     } else if (x < 0 && y < 0) {
1067         return categoryNum2TimezoneWS;
1068     } else {
1069         return categoryNum2TimezoneES;
1070     }
1071 }
1072 
CheckLatitudeAndLongitude(const double x,const double y)1073 bool I18nTimeZone::CheckLatitudeAndLongitude(const double x, const double y)
1074 {
1075     if (x < -1.0 * TZ_X_PLUS) {
1076         return false;
1077     }
1078     if (Geq(x, TZ_X_PLUS * 1.0 - NUM_PRECISION)) {
1079         return false;
1080     }
1081     if (y < -1.0 * TZ_X_PLUS/TZ_HALF_OF_SIZE) {
1082         return false;
1083     }
1084     if (Geq(y, TZ_X_PLUS * 1.0/TZ_HALF_OF_SIZE - NUM_PRECISION)) {
1085         return false;
1086     }
1087     return true;
1088 }
1089 
GetColorData(const uint16_t x,const uint16_t y,uint16_t actualHeight,std::string preferredPath)1090 std::vector<int> I18nTimeZone::GetColorData(const uint16_t x, const uint16_t y,
1091                                             uint16_t actualHeight, std::string preferredPath)
1092 {
1093     std::vector<int> result;
1094     FILE *fp;
1095     png_structp png_ptr;
1096     png_infop info_ptr;
1097     png_bytep row_pointers;
1098     int code = InitPngptr(png_ptr, info_ptr, &fp, preferredPath);
1099     if (code != 0) {
1100         return result;
1101     }
1102     try {
1103         rewind(fp);
1104         png_init_io(png_ptr, fp);
1105         png_read_info(png_ptr, info_ptr);
1106         unsigned int rowbytes = png_get_rowbytes(png_ptr, info_ptr);
1107         row_pointers = (png_bytep)png_malloc(png_ptr, rowbytes);
1108         if (row_pointers == nullptr) {
1109             png_destroy_read_struct(&png_ptr, &info_ptr, 0);
1110             CloseFile(fp);
1111             HILOG_ERROR_I18N("malloc rowbytes failed.");
1112             return result;
1113         }
1114         png_start_read_image(png_ptr);
1115         for (int i = 0; i < (actualHeight + 1); i++) {
1116             png_read_row(png_ptr, row_pointers, NULL);
1117         }
1118         for (size_t i = 0; i < 3; i++) { // 3 is RGB color pixel length
1119             std::string pixel = std::to_string(*(row_pointers + x * 3 + i)); // 3 is RGB color pixel length
1120             result.push_back(atoi(pixel.c_str()));
1121         }
1122         png_free(png_ptr, row_pointers);
1123         CloseFile(fp);
1124     } catch (...) {
1125         png_destroy_read_struct(&png_ptr, &info_ptr, 0);
1126         CloseFile(fp);
1127     }
1128     return result;
1129 }
1130 
GetTzDataWidth(std::vector<std::string> filePaths)1131 std::tuple<uint32_t, uint32_t> I18nTimeZone::GetTzDataWidth(std::vector<std::string> filePaths)
1132 {
1133     if (filePaths.size() == 0) {
1134         HILOG_ERROR_I18N("I18nTimeZone::GetTzDataWidth: filePaths is empty.");
1135         return std::make_tuple(0, 0);
1136     }
1137     std::string firstPath = filePaths.at(0);
1138     firstPath = GetAbsoluteFilePath(firstPath.c_str());
1139     if (firstPath.empty()) {
1140         HILOG_ERROR_I18N("I18nTimeZone::GetTzDataWidth: firstPath %{public}s is invalid.", firstPath.c_str());
1141         return std::make_tuple(0, 0);
1142     }
1143     FILE* fp;
1144     png_structp png_ptr;
1145     png_infop info_ptr;
1146     fp = fopen(firstPath.c_str(), "rb");
1147     if (fp == NULL) {
1148         HILOG_ERROR_I18N("I18nTimeZone::GetTzDataWidth: fopen(%{public}s) return NULL.", firstPath.c_str());
1149         return std::make_tuple(0, 0);
1150     }
1151     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1152     if (!png_ptr) {
1153         CloseFile(fp);
1154         HILOG_ERROR_I18N("I18nTimeZone::GetTzDataWidth: create read_struct failed.");
1155         return std::make_tuple(0, 0);
1156     }
1157     info_ptr = png_create_info_struct(png_ptr);
1158     if (!info_ptr) {
1159         png_destroy_read_struct(&png_ptr, &info_ptr, 0);
1160         CloseFile(fp);
1161         HILOG_ERROR_I18N("I18nTimeZone::GetTzDataWidth: create info_struct failed.");
1162         return std::make_tuple(0, 0);
1163     }
1164     rewind(fp);
1165     png_init_io(png_ptr, fp);
1166     png_read_info(png_ptr, info_ptr);
1167     unsigned int w;
1168     unsigned int h;
1169     png_get_IHDR(png_ptr, info_ptr, &w, &h, NULL, NULL, NULL, NULL, NULL);
1170     png_destroy_read_struct(&png_ptr, &info_ptr, 0);
1171     CloseFile(fp);
1172     return std::make_tuple(w, h);
1173 }
1174 
InitPngptr(png_structp & png_ptr,png_infop & info_ptr,FILE ** fp,std::string preferredPath)1175 int I18nTimeZone::InitPngptr(png_structp &png_ptr, png_infop &info_ptr, FILE **fp,
1176                              std::string preferredPath)
1177 {
1178     std::string validFilePath = GetAbsoluteFilePath(preferredPath);
1179     if (validFilePath.empty()) {
1180         HILOG_ERROR_I18N("timezone data filepath invalid.");
1181         return 1;
1182     }
1183     *fp = fopen(validFilePath.c_str(), "rb");
1184     if (*fp == NULL) {
1185         HILOG_ERROR_I18N("timezone data resource file not exists.");
1186         return 1;
1187     }
1188     png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
1189     if (!png_ptr) {
1190         png_destroy_read_struct(&png_ptr, &info_ptr, 0);
1191         CloseFile(*fp);
1192         HILOG_ERROR_I18N("create read_struct failed.");
1193         return 1;
1194     }
1195     info_ptr = png_create_info_struct(png_ptr);
1196     if (!info_ptr) {
1197         png_destroy_read_struct(&png_ptr, &info_ptr, 0);
1198         CloseFile(*fp);
1199         HILOG_ERROR_I18N("create info_struct failed.");
1200         return 1;
1201     }
1202     return 0;
1203 }
1204 
GetPreferredPath(const double x,const std::vector<std::string> & filePaths)1205 std::string I18nTimeZone::GetPreferredPath(const double x,
1206                                            const std::vector<std::string> &filePaths)
1207 {
1208     if (filePaths.size() == 1) {
1209         return filePaths.at(0);
1210     }
1211     int fixedX = static_cast<int>(x + TZ_X_PLUS);
1212     for (unsigned int i = 0; i < filePaths.size(); i++) {
1213         std::string path = filePaths.at(i);
1214         std::string left = path.substr(path.find("-") + 1, 3);
1215         std::string right = path.substr(path.find("-") + 4, 3);
1216         if (fixedX >= atoi(left.c_str()) && fixedX < atoi(right.c_str())) {
1217             return path;
1218         }
1219     }
1220     return "";
1221 }
1222 
FindTzData()1223 std::vector<std::string> I18nTimeZone::FindTzData()
1224 {
1225     using std::filesystem::directory_iterator;
1226     std::map<std::string, std::vector<std::string>> pathMap;
1227     std::regex reg("tz_[0-9]{7}-(\\d{6})\\.dat");
1228     std::regex regVersion("_[0-9]{7}");
1229     const std::vector<std::filesystem::path> pixelPaths = {TZ_PIXEL_PATH, DISTRO_TZ_PIXEL_PATH};
1230     for (const auto& pixelPath : pixelPaths) {
1231         if (!FileExist(pixelPath)) {
1232             HILOG_INFO_I18N("pixelPaths does not exists: %{public}s.", pixelPath.c_str());
1233             continue;
1234         }
1235 
1236         for (const auto& entry : directory_iterator{pixelPath}) {
1237             const std::string path = entry.path();
1238             std::smatch match;
1239             bool found = RegexSearchNoExcept(path, match, reg);
1240             bool hasVerison = RegexSearchNoExcept(path, match, regVersion);
1241             if (found && hasVerison) {
1242                 std::string version = match[0].str();
1243                 SetVersionPathMap(version, path, &pathMap);
1244             }
1245         }
1246     }
1247     std::vector<std::string> filePaths;
1248     std::map<std::string, std::vector<std::string>>::reverse_iterator iter;
1249     for (iter = pathMap.rbegin(); iter != pathMap.rend(); ++iter) {
1250         if (ValidateDataIntegrity(iter->second)) {
1251             return iter->second;
1252         }
1253     }
1254     return filePaths;
1255 }
1256 
ValidateDataIntegrity(const std::vector<std::string> & pathList)1257 bool I18nTimeZone::ValidateDataIntegrity(const std::vector<std::string> &pathList)
1258 {
1259     size_t total = 0;
1260     for (unsigned int i = 0; i < pathList.size(); i++) {
1261         std::string path = pathList.at(i);
1262         std::string left = path.substr(path.find("-") + 1, 3);
1263         std::string right = path.substr(path.find("-") + 4, 3);
1264         int height = abs(atoi(right.c_str()) - atoi(left.c_str()));
1265         total += static_cast<size_t>(height);
1266     }
1267     return total == TZ_X_PLUS * TZ_HALF_OF_SIZE;
1268 }
1269 
SetVersionPathMap(std::string verison,std::string path,std::map<std::string,std::vector<std::string>> * pathMap)1270 void I18nTimeZone::SetVersionPathMap(std::string verison, std::string path,
1271                                      std::map<std::string, std::vector<std::string>> *pathMap)
1272 {
1273     if (pathMap == nullptr) {
1274         return;
1275     }
1276     if (pathMap->find(verison) != pathMap->end()) {
1277         std::vector<std::string> *list = &(pathMap->find(verison)->second);
1278         list->push_back(path);
1279     } else {
1280         std::vector<std::string> list;
1281         list.push_back(path);
1282         pathMap->insert(std::pair<std::string, std::vector<std::string>>(verison, list));
1283     }
1284 }
1285 
CloseFile(FILE * fp)1286 void I18nTimeZone::CloseFile(FILE *fp)
1287 {
1288     if (fp != nullptr && fp != NULL) {
1289         fclose(fp);
1290     }
1291 }
1292 
ParamExceedScope(const int x,const int y,int fixedX,int fixedY)1293 bool I18nTimeZone::ParamExceedScope(const int x, const int y, int fixedX, int fixedY)
1294 {
1295     if (x < 0 || y < 0 || fixedX == 0 || fixedY == 0) {
1296         return true;
1297     }
1298     if (x > (fixedX - 1) || y > (fixedY - 1)) {
1299         return true;
1300     }
1301     return false;
1302 }
1303 
GetDeviceCityDisplayNamePath()1304 const char *I18nTimeZone::GetDeviceCityDisplayNamePath()
1305 {
1306     struct stat s;
1307     if (stat(DISTRO_ROOT_DISPLAYNAME_PATH, &s) == 0) {
1308         return DISTRO_DEVICE_CITY_DISPLAYNAME_PATH;
1309     } else if (stat(BASE_DEVICE_CITY_DISPLAYNAME_PATH, &s) == 0) {
1310         return BASE_DEVICE_CITY_DISPLAYNAME_PATH;
1311     } else {
1312         return "";
1313     }
1314 }
1315 }
1316 }
1317 }
1318