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