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