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