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