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