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