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