summaryrefslogtreecommitdiff
path: root/externals
diff options
context:
space:
mode:
Diffstat (limited to 'externals')
-rw-r--r--externals/CMakeLists.txt3
-rw-r--r--externals/tz/tz/tz.cpp1636
-rw-r--r--externals/tz/tz/tz.h81
3 files changed, 1720 insertions, 0 deletions
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index 407c5c640..15b444338 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -178,6 +178,9 @@ if (NOT TARGET stb::headers)
178 add_library(stb::headers ALIAS stb) 178 add_library(stb::headers ALIAS stb)
179endif() 179endif()
180 180
181add_library(tz tz/tz/tz.cpp)
182target_include_directories(tz PUBLIC ./tz)
183
181add_library(bc_decoder bc_decoder/bc_decoder.cpp) 184add_library(bc_decoder bc_decoder/bc_decoder.cpp)
182target_include_directories(bc_decoder PUBLIC ./bc_decoder) 185target_include_directories(bc_decoder PUBLIC ./bc_decoder)
183 186
diff --git a/externals/tz/tz/tz.cpp b/externals/tz/tz/tz.cpp
new file mode 100644
index 000000000..0c8b68217
--- /dev/null
+++ b/externals/tz/tz/tz.cpp
@@ -0,0 +1,1636 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-FileCopyrightText: 1996 Arthur David Olson
3// SPDX-License-Identifier: BSD-2-Clause
4
5#include <climits>
6#include <cstring>
7#include <ctime>
8
9#include "tz.h"
10
11namespace Tz {
12
13namespace {
14#define EINVAL 22
15
16static Rule gmtmem{};
17static Rule* const gmtptr = &gmtmem;
18
19struct TzifHeader {
20 std::array<char, 4> tzh_magic; // "TZif"
21 std::array<char, 1> tzh_version;
22 std::array<char, 15> tzh_reserved;
23 std::array<char, 4> tzh_ttisutcnt;
24 std::array<char, 4> tzh_ttisstdcnt;
25 std::array<char, 4> tzh_leapcnt;
26 std::array<char, 4> tzh_timecnt;
27 std::array<char, 4> tzh_typecnt;
28 std::array<char, 4> tzh_charcnt;
29};
30static_assert(sizeof(TzifHeader) == 0x2C, "TzifHeader has the wrong size!");
31
32struct local_storage {
33 // Binary layout:
34 // char buf[2 * sizeof(TzifHeader) + 2 * sizeof(Rule) + 4 * TZ_MAX_TIMES];
35 std::span<const u8> binary;
36 Rule state;
37};
38static local_storage tzloadbody_local_storage;
39
40enum rtype : s32 {
41 JULIAN_DAY = 0,
42 DAY_OF_YEAR = 1,
43 MONTH_NTH_DAY_OF_WEEK = 2,
44};
45
46struct tzrule {
47 rtype r_type;
48 int r_day;
49 int r_week;
50 int r_mon;
51 s64 r_time;
52};
53static_assert(sizeof(tzrule) == 0x18, "tzrule has the wrong size!");
54
55constexpr static char UNSPEC[] = "-00";
56constexpr static char TZDEFRULESTRING[] = ",M3.2.0,M11.1.0";
57
58enum {
59 SECSPERMIN = 60,
60 MINSPERHOUR = 60,
61 SECSPERHOUR = SECSPERMIN * MINSPERHOUR,
62 HOURSPERDAY = 24,
63 DAYSPERWEEK = 7,
64 DAYSPERNYEAR = 365,
65 DAYSPERLYEAR = DAYSPERNYEAR + 1,
66 MONSPERYEAR = 12,
67 YEARSPERREPEAT = 400 /* years before a Gregorian repeat */
68};
69
70#define SECSPERDAY ((s64)SECSPERHOUR * HOURSPERDAY)
71
72#define DAYSPERREPEAT ((s64)400 * 365 + 100 - 4 + 1)
73#define SECSPERREPEAT ((int_fast64_t)DAYSPERREPEAT * SECSPERDAY)
74#define AVGSECSPERYEAR (SECSPERREPEAT / YEARSPERREPEAT)
75
76enum {
77 TM_SUNDAY,
78 TM_MONDAY,
79 TM_TUESDAY,
80 TM_WEDNESDAY,
81 TM_THURSDAY,
82 TM_FRIDAY,
83 TM_SATURDAY,
84};
85
86enum {
87 TM_JANUARY,
88 TM_FEBRUARY,
89 TM_MARCH,
90 TM_APRIL,
91 TM_MAY,
92 TM_JUNE,
93 TM_JULY,
94 TM_AUGUST,
95 TM_SEPTEMBER,
96 TM_OCTOBER,
97 TM_NOVEMBER,
98 TM_DECEMBER,
99};
100
101constexpr s32 TM_YEAR_BASE = 1900;
102constexpr s32 TM_WDAY_BASE = TM_MONDAY;
103constexpr s32 EPOCH_YEAR = 1970;
104constexpr s32 EPOCH_WDAY = TM_THURSDAY;
105
106#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
107
108static constexpr std::array<std::array<int, MONSPERYEAR>, 2> mon_lengths = { {
109 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
110 {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
111} };
112
113static constexpr std::array<int, 2> year_lengths = {
114 DAYSPERNYEAR,
115 DAYSPERLYEAR,
116};
117
118constexpr static time_t leaps_thru_end_of_nonneg(time_t y) {
119 return y / 4 - y / 100 + y / 400;
120}
121
122constexpr static time_t leaps_thru_end_of(time_t y) {
123 return (y < 0 ? -1 - leaps_thru_end_of_nonneg(-1 - y) : leaps_thru_end_of_nonneg(y));
124}
125
126#define TWOS_COMPLEMENT(t) ((t) ~(t)0 < 0)
127
128s32 detzcode(const char* const codep) {
129 s32 result;
130 int i;
131 s32 one = 1;
132 s32 halfmaxval = one << (32 - 2);
133 s32 maxval = halfmaxval - 1 + halfmaxval;
134 s32 minval = -1 - maxval;
135
136 result = codep[0] & 0x7f;
137 for (i = 1; i < 4; ++i) {
138 result = (result << 8) | (codep[i] & 0xff);
139 }
140
141 if (codep[0] & 0x80) {
142 /* Do two's-complement negation even on non-two's-complement machines.
143 If the result would be minval - 1, return minval. */
144 result -= !TWOS_COMPLEMENT(s32) && result != 0;
145 result += minval;
146 }
147 return result;
148}
149
150int_fast64_t detzcode64(const char* const codep) {
151 int_fast64_t result;
152 int i;
153 int_fast64_t one = 1;
154 int_fast64_t halfmaxval = one << (64 - 2);
155 int_fast64_t maxval = halfmaxval - 1 + halfmaxval;
156 int_fast64_t minval = -static_cast<int_fast64_t>(TWOS_COMPLEMENT(int_fast64_t)) - maxval;
157
158 result = codep[0] & 0x7f;
159 for (i = 1; i < 8; ++i) {
160 result = (result << 8) | (codep[i] & 0xff);
161 }
162
163 if (codep[0] & 0x80) {
164 /* Do two's-complement negation even on non-two's-complement machines.
165 If the result would be minval - 1, return minval. */
166 result -= !TWOS_COMPLEMENT(int_fast64_t) && result != 0;
167 result += minval;
168 }
169 return result;
170}
171
172/* Initialize *S to a value based on UTOFF, ISDST, and DESIGIDX. */
173constexpr void init_ttinfo(ttinfo* s, s64 utoff, bool isdst, int desigidx) {
174 s->tt_utoff = static_cast<s32>(utoff);
175 s->tt_isdst = isdst;
176 s->tt_desigidx = desigidx;
177 s->tt_ttisstd = false;
178 s->tt_ttisut = false;
179}
180
181/* Return true if SP's time type I does not specify local time. */
182bool ttunspecified(struct Rule const* sp, int i) {
183 char const* abbr = &sp->chars[sp->ttis[i].tt_desigidx];
184 /* memcmp is likely faster than strcmp, and is safe due to CHARS_EXTRA. */
185 return memcmp(abbr, UNSPEC, sizeof(UNSPEC)) == 0;
186}
187
188bool typesequiv(const Rule* sp, int a, int b) {
189 bool result;
190
191 if (sp == nullptr || a < 0 || a >= sp->typecnt || b < 0 || b >= sp->typecnt) {
192 result = false;
193 }
194 else {
195 /* Compare the relevant members of *AP and *BP.
196 Ignore tt_ttisstd and tt_ttisut, as they are
197 irrelevant now and counting them could cause
198 sp->goahead to mistakenly remain false. */
199 const ttinfo* ap = &sp->ttis[a];
200 const ttinfo* bp = &sp->ttis[b];
201 result = (ap->tt_utoff == bp->tt_utoff && ap->tt_isdst == bp->tt_isdst &&
202 (strcmp(&sp->chars[ap->tt_desigidx], &sp->chars[bp->tt_desigidx]) == 0));
203 }
204 return result;
205}
206
207constexpr const char* getqzname(const char* strp, const int delim) {
208 int c;
209
210 while ((c = *strp) != '\0' && c != delim) {
211 ++strp;
212 }
213 return strp;
214}
215
216/* Is C an ASCII digit? */
217constexpr bool is_digit(char c) {
218 return '0' <= c && c <= '9';
219}
220
221/*
222** Given a pointer into a timezone string, scan until a character that is not
223** a valid character in a time zone abbreviation is found.
224** Return a pointer to that character.
225*/
226
227constexpr const char* getzname(const char* strp) {
228 char c;
229
230 while ((c = *strp) != '\0' && !is_digit(c) && c != ',' && c != '-' && c != '+') {
231 ++strp;
232 }
233 return strp;
234}
235
236static const char* getnum(const char* strp, int* const nump, const int min, const int max) {
237 char c;
238 int num;
239
240 if (strp == nullptr || !is_digit(c = *strp)) {
241 return nullptr;
242 }
243 num = 0;
244 do {
245 num = num * 10 + (c - '0');
246 if (num > max) {
247 return nullptr; /* illegal value */
248 }
249 c = *++strp;
250 } while (is_digit(c));
251 if (num < min) {
252 return nullptr; /* illegal value */
253 }
254 *nump = num;
255 return strp;
256}
257
258/*
259** Given a pointer into a timezone string, extract a number of seconds,
260** in hh[:mm[:ss]] form, from the string.
261** If any error occurs, return NULL.
262** Otherwise, return a pointer to the first character not part of the number
263** of seconds.
264*/
265
266const char* getsecs(const char* strp, s64* const secsp) {
267 int num;
268 s64 secsperhour = SECSPERHOUR;
269
270 /*
271 ** 'HOURSPERDAY * DAYSPERWEEK - 1' allows quasi-Posix rules like
272 ** "M10.4.6/26", which does not conform to Posix,
273 ** but which specifies the equivalent of
274 ** "02:00 on the first Sunday on or after 23 Oct".
275 */
276 strp = getnum(strp, &num, 0, HOURSPERDAY * DAYSPERWEEK - 1);
277 if (strp == nullptr) {
278 return nullptr;
279 }
280 *secsp = num * secsperhour;
281 if (*strp == ':') {
282 ++strp;
283 strp = getnum(strp, &num, 0, MINSPERHOUR - 1);
284 if (strp == nullptr) {
285 return nullptr;
286 }
287 *secsp += num * SECSPERMIN;
288 if (*strp == ':') {
289 ++strp;
290 /* 'SECSPERMIN' allows for leap seconds. */
291 strp = getnum(strp, &num, 0, SECSPERMIN);
292 if (strp == nullptr) {
293 return nullptr;
294 }
295 *secsp += num;
296 }
297 }
298 return strp;
299}
300
301/*
302** Given a pointer into a timezone string, extract an offset, in
303** [+-]hh[:mm[:ss]] form, from the string.
304** If any error occurs, return NULL.
305** Otherwise, return a pointer to the first character not part of the time.
306*/
307
308const char* getoffset(const char* strp, s64* const offsetp) {
309 bool neg = false;
310
311 if (*strp == '-') {
312 neg = true;
313 ++strp;
314 }
315 else if (*strp == '+') {
316 ++strp;
317 }
318 strp = getsecs(strp, offsetp);
319 if (strp == nullptr) {
320 return nullptr; /* illegal time */
321 }
322 if (neg) {
323 *offsetp = -*offsetp;
324 }
325 return strp;
326}
327
328constexpr const char* getrule(const char* strp, tzrule* const rulep) {
329 if (*strp == 'J') {
330 /*
331 ** Julian day.
332 */
333 rulep->r_type = JULIAN_DAY;
334 ++strp;
335 strp = getnum(strp, &rulep->r_day, 1, DAYSPERNYEAR);
336 }
337 else if (*strp == 'M') {
338 /*
339 ** Month, week, day.
340 */
341 rulep->r_type = MONTH_NTH_DAY_OF_WEEK;
342 ++strp;
343 strp = getnum(strp, &rulep->r_mon, 1, MONSPERYEAR);
344 if (strp == nullptr) {
345 return nullptr;
346 }
347 if (*strp++ != '.') {
348 return nullptr;
349 }
350 strp = getnum(strp, &rulep->r_week, 1, 5);
351 if (strp == nullptr) {
352 return nullptr;
353 }
354 if (*strp++ != '.') {
355 return nullptr;
356 }
357 strp = getnum(strp, &rulep->r_day, 0, DAYSPERWEEK - 1);
358 }
359 else if (is_digit(*strp)) {
360 /*
361 ** Day of year.
362 */
363 rulep->r_type = DAY_OF_YEAR;
364 strp = getnum(strp, &rulep->r_day, 0, DAYSPERLYEAR - 1);
365 }
366 else {
367 return nullptr;
368 } /* invalid format */
369 if (strp == nullptr) {
370 return nullptr;
371 }
372 if (*strp == '/') {
373 /*
374 ** Time specified.
375 */
376 ++strp;
377 strp = getoffset(strp, &rulep->r_time);
378 }
379 else {
380 rulep->r_time = 2 * SECSPERHOUR; /* default = 2:00:00 */
381 }
382 return strp;
383}
384
385constexpr bool increment_overflow(int* ip, int j) {
386 int const i = *ip;
387
388 /*
389 ** If i >= 0 there can only be overflow if i + j > INT_MAX
390 ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow.
391 ** If i < 0 there can only be overflow if i + j < INT_MIN
392 ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow.
393 */
394 if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i)) {
395 return true;
396 }
397 *ip += j;
398 return false;
399}
400
401constexpr bool increment_overflow32(s64* const lp, int const m) {
402 s64 const l = *lp;
403
404 if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l))
405 return true;
406 *lp += m;
407 return false;
408}
409
410constexpr bool increment_overflow_time(time_t* tp, s64 j) {
411 /*
412 ** This is like
413 ** 'if (! (TIME_T_MIN <= *tp + j && *tp + j <= TIME_T_MAX)) ...',
414 ** except that it does the right thing even if *tp + j would overflow.
415 */
416 if (!(j < 0 ? (std::is_signed_v<time_t> ? TIME_T_MIN - j <= *tp : -1 - j < *tp)
417 : *tp <= TIME_T_MAX - j)) {
418 return true;
419 }
420 *tp += j;
421 return false;
422}
423
424CalendarTimeInternal* timesub(const time_t* timep, s64 offset, const Rule* sp,
425 CalendarTimeInternal* tmp) {
426 time_t tdays;
427 const int* ip;
428 s64 idays, rem, dayoff, dayrem;
429 time_t y;
430
431 /* Calculate the year, avoiding integer overflow even if
432 time_t is unsigned. */
433 tdays = *timep / SECSPERDAY;
434 rem = *timep % SECSPERDAY;
435 rem += offset % SECSPERDAY + 3 * SECSPERDAY;
436 dayoff = offset / SECSPERDAY + rem / SECSPERDAY - 3;
437 rem %= SECSPERDAY;
438 /* y = (EPOCH_YEAR
439 + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT),
440 sans overflow. But calculate against 1570 (EPOCH_YEAR -
441 YEARSPERREPEAT) instead of against 1970 so that things work
442 for localtime values before 1970 when time_t is unsigned. */
443 dayrem = tdays % DAYSPERREPEAT;
444 dayrem += dayoff % DAYSPERREPEAT;
445 y = (EPOCH_YEAR - YEARSPERREPEAT +
446 ((1ull + dayoff / DAYSPERREPEAT + dayrem / DAYSPERREPEAT - ((dayrem % DAYSPERREPEAT) < 0) +
447 tdays / DAYSPERREPEAT) *
448 YEARSPERREPEAT));
449 /* idays = (tdays + dayoff) mod DAYSPERREPEAT, sans overflow. */
450 idays = tdays % DAYSPERREPEAT;
451 idays += dayoff % DAYSPERREPEAT + 2 * DAYSPERREPEAT;
452 idays %= DAYSPERREPEAT;
453 /* Increase Y and decrease IDAYS until IDAYS is in range for Y. */
454 while (year_lengths[isleap(y)] <= idays) {
455 s64 tdelta = idays / DAYSPERLYEAR;
456 s64 ydelta = tdelta + !tdelta;
457 time_t newy = y + ydelta;
458 int leapdays;
459 leapdays = static_cast<s32>(leaps_thru_end_of(newy - 1) - leaps_thru_end_of(y - 1));
460 idays -= ydelta * DAYSPERNYEAR;
461 idays -= leapdays;
462 y = newy;
463 }
464
465 if constexpr (!std::is_signed_v<time_t> && y < TM_YEAR_BASE) {
466 int signed_y = static_cast<s32>(y);
467 tmp->tm_year = signed_y - TM_YEAR_BASE;
468 }
469 else if ((!std::is_signed_v<time_t> || std::numeric_limits<s32>::min() + TM_YEAR_BASE <= y) &&
470 y - TM_YEAR_BASE <= std::numeric_limits<s32>::max()) {
471 tmp->tm_year = static_cast<s32>(y - TM_YEAR_BASE);
472 }
473 else {
474 // errno = EOVERFLOW;
475 return nullptr;
476 }
477
478 tmp->tm_yday = static_cast<s32>(idays);
479 /*
480 ** The "extra" mods below avoid overflow problems.
481 */
482 tmp->tm_wday = static_cast<s32>(
483 TM_WDAY_BASE + ((tmp->tm_year % DAYSPERWEEK) * (DAYSPERNYEAR % DAYSPERWEEK)) +
484 leaps_thru_end_of(y - 1) - leaps_thru_end_of(TM_YEAR_BASE - 1) + idays);
485 tmp->tm_wday %= DAYSPERWEEK;
486 if (tmp->tm_wday < 0) {
487 tmp->tm_wday += DAYSPERWEEK;
488 }
489 tmp->tm_hour = static_cast<s32>(rem / SECSPERHOUR);
490 rem %= SECSPERHOUR;
491 tmp->tm_min = static_cast<s32>(rem / SECSPERMIN);
492 tmp->tm_sec = static_cast<s32>(rem % SECSPERMIN);
493
494 ip = mon_lengths[isleap(y)].data();
495 for (tmp->tm_mon = 0; idays >= ip[tmp->tm_mon]; ++(tmp->tm_mon)) {
496 idays -= ip[tmp->tm_mon];
497 }
498 tmp->tm_mday = static_cast<s32>(idays + 1);
499 tmp->tm_isdst = 0;
500 return tmp;
501}
502
503CalendarTimeInternal* gmtsub([[maybe_unused]] Rule const* sp, time_t const* timep,
504 s64 offset, CalendarTimeInternal* tmp) {
505 CalendarTimeInternal* result;
506
507 result = timesub(timep, offset, gmtptr, tmp);
508 return result;
509}
510
511CalendarTimeInternal* localsub(Rule const* sp, time_t const* timep, s64 setname,
512 CalendarTimeInternal* const tmp) {
513 const ttinfo* ttisp;
514 int i;
515 CalendarTimeInternal* result;
516 const time_t t = *timep;
517
518 if (sp == nullptr) {
519 /* Don't bother to set tzname etc.; tzset has already done it. */
520 return gmtsub(gmtptr, timep, 0, tmp);
521 }
522 if ((sp->goback && t < sp->ats[0]) || (sp->goahead && t > sp->ats[sp->timecnt - 1])) {
523 time_t newt;
524 time_t seconds;
525 time_t years;
526
527 if (t < sp->ats[0]) {
528 seconds = sp->ats[0] - t;
529 }
530 else {
531 seconds = t - sp->ats[sp->timecnt - 1];
532 }
533 --seconds;
534
535 /* Beware integer overflow, as SECONDS might
536 be close to the maximum time_t. */
537 years = seconds / SECSPERREPEAT * YEARSPERREPEAT;
538 seconds = years * AVGSECSPERYEAR;
539 years += YEARSPERREPEAT;
540 if (t < sp->ats[0]) {
541 newt = t + seconds + SECSPERREPEAT;
542 }
543 else {
544 newt = t - seconds - SECSPERREPEAT;
545 }
546
547 if (newt < sp->ats[0] || newt > sp->ats[sp->timecnt - 1]) {
548 return nullptr; /* "cannot happen" */
549 }
550 result = localsub(sp, &newt, setname, tmp);
551 if (result) {
552 int_fast64_t newy;
553
554 newy = result->tm_year;
555 if (t < sp->ats[0]) {
556 newy -= years;
557 }
558 else {
559 newy += years;
560 }
561 if (!(std::numeric_limits<s32>::min() <= newy &&
562 newy <= std::numeric_limits<s32>::max())) {
563 return nullptr;
564 }
565 result->tm_year = static_cast<s32>(newy);
566 }
567 return result;
568 }
569 if (sp->timecnt == 0 || t < sp->ats[0]) {
570 i = sp->defaulttype;
571 }
572 else {
573 int lo = 1;
574 int hi = sp->timecnt;
575
576 while (lo < hi) {
577 int mid = (lo + hi) >> 1;
578
579 if (t < sp->ats[mid])
580 hi = mid;
581 else
582 lo = mid + 1;
583 }
584 i = sp->types[lo - 1];
585 }
586 ttisp = &sp->ttis[i];
587 /*
588 ** To get (wrong) behavior that's compatible with System V Release 2.0
589 ** you'd replace the statement below with
590 ** t += ttisp->tt_utoff;
591 ** timesub(&t, 0L, sp, tmp);
592 */
593 result = timesub(&t, ttisp->tt_utoff, sp, tmp);
594 if (result) {
595 result->tm_isdst = ttisp->tt_isdst;
596
597 if (ttisp->tt_desigidx > static_cast<s32>(sp->chars.size() - CHARS_EXTRA)) {
598 return nullptr;
599 }
600
601 auto num_chars_to_copy{
602 std::min(sp->chars.size() - ttisp->tt_desigidx, result->tm_zone.size()) - 1 };
603 std::strncpy(result->tm_zone.data(), &sp->chars[ttisp->tt_desigidx], num_chars_to_copy);
604 result->tm_zone[num_chars_to_copy] = '\0';
605
606 auto original_size{ std::strlen(&sp->chars[ttisp->tt_desigidx]) };
607 if (original_size > num_chars_to_copy) {
608 return nullptr;
609 }
610
611 result->tm_utoff = ttisp->tt_utoff;
612 result->time_index = i;
613 }
614 return result;
615}
616
617/*
618** Given a year, a rule, and the offset from UT at the time that rule takes
619** effect, calculate the year-relative time that rule takes effect.
620*/
621
622constexpr s64 transtime(const int year, const tzrule* const rulep,
623 const s64 offset) {
624 bool leapyear;
625 s64 value;
626 int i;
627 int d, m1, yy0, yy1, yy2, dow;
628
629 leapyear = isleap(year);
630 switch (rulep->r_type) {
631 case JULIAN_DAY:
632 /*
633 ** Jn - Julian day, 1 == January 1, 60 == March 1 even in leap
634 ** years.
635 ** In non-leap years, or if the day number is 59 or less, just
636 ** add SECSPERDAY times the day number-1 to the time of
637 ** January 1, midnight, to get the day.
638 */
639 value = (rulep->r_day - 1) * SECSPERDAY;
640 if (leapyear && rulep->r_day >= 60) {
641 value += SECSPERDAY;
642 }
643 break;
644
645 case DAY_OF_YEAR:
646 /*
647 ** n - day of year.
648 ** Just add SECSPERDAY times the day number to the time of
649 ** January 1, midnight, to get the day.
650 */
651 value = rulep->r_day * SECSPERDAY;
652 break;
653
654 case MONTH_NTH_DAY_OF_WEEK:
655 /*
656 ** Mm.n.d - nth "dth day" of month m.
657 */
658
659 /*
660 ** Use Zeller's Congruence to get day-of-week of first day of
661 ** month.
662 */
663 m1 = (rulep->r_mon + 9) % 12 + 1;
664 yy0 = (rulep->r_mon <= 2) ? (year - 1) : year;
665 yy1 = yy0 / 100;
666 yy2 = yy0 % 100;
667 dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
668 if (dow < 0) {
669 dow += DAYSPERWEEK;
670 }
671
672 /*
673 ** "dow" is the day-of-week of the first day of the month. Get
674 ** the day-of-month (zero-origin) of the first "dow" day of the
675 ** month.
676 */
677 d = rulep->r_day - dow;
678 if (d < 0) {
679 d += DAYSPERWEEK;
680 }
681 for (i = 1; i < rulep->r_week; ++i) {
682 if (d + DAYSPERWEEK >= mon_lengths[leapyear][rulep->r_mon - 1]) {
683 break;
684 }
685 d += DAYSPERWEEK;
686 }
687
688 /*
689 ** "d" is the day-of-month (zero-origin) of the day we want.
690 */
691 value = d * SECSPERDAY;
692 for (i = 0; i < rulep->r_mon - 1; ++i) {
693 value += mon_lengths[leapyear][i] * SECSPERDAY;
694 }
695 break;
696
697 default:
698 //UNREACHABLE();
699 break;
700 }
701
702 /*
703 ** "value" is the year-relative time of 00:00:00 UT on the day in
704 ** question. To get the year-relative time of the specified local
705 ** time on that day, add the transition time and the current offset
706 ** from UT.
707 */
708 return value + rulep->r_time + offset;
709}
710
711bool tzparse(const char* name, Rule* sp) {
712 const char* stdname{};
713 const char* dstname{};
714 s64 stdoffset;
715 s64 dstoffset;
716 char* cp;
717 ptrdiff_t stdlen;
718 ptrdiff_t dstlen{};
719 ptrdiff_t charcnt;
720 time_t atlo = TIME_T_MIN, leaplo = TIME_T_MIN;
721
722 stdname = name;
723 if (*name == '<') {
724 name++;
725 stdname = name;
726 name = getqzname(name, '>');
727 if (*name != '>') {
728 return false;
729 }
730 stdlen = name - stdname;
731 name++;
732 }
733 else {
734 name = getzname(name);
735 stdlen = name - stdname;
736 }
737 if (!(0 < stdlen && stdlen <= TZNAME_MAXIMUM)) {
738 return false;
739 }
740 name = getoffset(name, &stdoffset);
741 if (name == nullptr) {
742 return false;
743 }
744 charcnt = stdlen + 1;
745 if (charcnt > TZ_MAX_CHARS) {
746 return false;
747 }
748 if (*name != '\0') {
749 if (*name == '<') {
750 dstname = ++name;
751 name = getqzname(name, '>');
752 if (*name != '>')
753 return false;
754 dstlen = name - dstname;
755 name++;
756 }
757 else {
758 dstname = name;
759 name = getzname(name);
760 dstlen = name - dstname; /* length of DST abbr. */
761 }
762 if (!(0 < dstlen && dstlen <= TZNAME_MAXIMUM)) {
763 return false;
764 }
765 charcnt += dstlen + 1;
766 if (charcnt > TZ_MAX_CHARS) {
767 return false;
768 }
769 if (*name != '\0' && *name != ',' && *name != ';') {
770 name = getoffset(name, &dstoffset);
771 if (name == nullptr) {
772 return false;
773 }
774 }
775 else {
776 dstoffset = stdoffset - SECSPERHOUR;
777 }
778 if (*name == '\0') {
779 name = TZDEFRULESTRING;
780 }
781 if (*name == ',' || *name == ';') {
782 struct tzrule start;
783 struct tzrule end;
784 int year;
785 int timecnt;
786 time_t janfirst;
787 s64 janoffset = 0;
788 int yearbeg, yearlim;
789
790 ++name;
791 if ((name = getrule(name, &start)) == nullptr) {
792 return false;
793 }
794 if (*name++ != ',') {
795 return false;
796 }
797 if ((name = getrule(name, &end)) == nullptr) {
798 return false;
799 }
800 if (*name != '\0') {
801 return false;
802 }
803 sp->typecnt = 2; /* standard time and DST */
804 /*
805 ** Two transitions per year, from EPOCH_YEAR forward.
806 */
807 init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
808 init_ttinfo(&sp->ttis[1], -dstoffset, true, static_cast<s32>(stdlen + 1));
809 sp->defaulttype = 0;
810 timecnt = 0;
811 janfirst = 0;
812 yearbeg = EPOCH_YEAR;
813
814 do {
815 s64 yearsecs = year_lengths[isleap(yearbeg - 1)] * SECSPERDAY;
816 yearbeg--;
817 if (increment_overflow_time(&janfirst, -yearsecs)) {
818 janoffset = -yearsecs;
819 break;
820 }
821 } while (atlo < janfirst && EPOCH_YEAR - YEARSPERREPEAT / 2 < yearbeg);
822
823 while (true) {
824 s64 yearsecs = year_lengths[isleap(yearbeg)] * SECSPERDAY;
825 int yearbeg1 = yearbeg;
826 time_t janfirst1 = janfirst;
827 if (increment_overflow_time(&janfirst1, yearsecs) ||
828 increment_overflow(&yearbeg1, 1) || atlo <= janfirst1) {
829 break;
830 }
831 yearbeg = yearbeg1;
832 janfirst = janfirst1;
833 }
834
835 yearlim = yearbeg;
836 if (increment_overflow(&yearlim, YEARSPERREPEAT + 1)) {
837 yearlim = INT_MAX;
838 }
839 for (year = yearbeg; year < yearlim; year++) {
840 s64 starttime = transtime(year, &start, stdoffset),
841 endtime = transtime(year, &end, dstoffset);
842 s64 yearsecs = (year_lengths[isleap(year)] * SECSPERDAY);
843 bool reversed = endtime < starttime;
844 if (reversed) {
845 s64 swap = starttime;
846 starttime = endtime;
847 endtime = swap;
848 }
849 if (reversed || (starttime < endtime && endtime - starttime < yearsecs)) {
850 if (TZ_MAX_TIMES - 2 < timecnt) {
851 break;
852 }
853 sp->ats[timecnt] = janfirst;
854 if (!increment_overflow_time(reinterpret_cast<time_t*>(&sp->ats[timecnt]), janoffset + starttime) &&
855 atlo <= sp->ats[timecnt]) {
856 sp->types[timecnt++] = !reversed;
857 }
858 sp->ats[timecnt] = janfirst;
859 if (!increment_overflow_time(reinterpret_cast<time_t*>(&sp->ats[timecnt]), janoffset + endtime) &&
860 atlo <= sp->ats[timecnt]) {
861 sp->types[timecnt++] = reversed;
862 }
863 }
864 if (endtime < leaplo) {
865 yearlim = year;
866 if (increment_overflow(&yearlim, YEARSPERREPEAT + 1)) {
867 yearlim = INT_MAX;
868 }
869 }
870 if (increment_overflow_time(&janfirst, janoffset + yearsecs)) {
871 break;
872 }
873 janoffset = 0;
874 }
875 sp->timecnt = timecnt;
876 if (!timecnt) {
877 sp->ttis[0] = sp->ttis[1];
878 sp->typecnt = 1; /* Perpetual DST. */
879 }
880 else if (YEARSPERREPEAT < year - yearbeg) {
881 sp->goback = sp->goahead = true;
882 }
883 }
884 else {
885 s64 theirstdoffset;
886 s64 theirdstoffset;
887 s64 theiroffset;
888 bool isdst;
889 int i;
890 int j;
891
892 if (*name != '\0') {
893 return false;
894 }
895 /*
896 ** Initial values of theirstdoffset and theirdstoffset.
897 */
898 theirstdoffset = 0;
899 for (i = 0; i < sp->timecnt; ++i) {
900 j = sp->types[i];
901 if (!sp->ttis[j].tt_isdst) {
902 theirstdoffset = -sp->ttis[j].tt_utoff;
903 break;
904 }
905 }
906 theirdstoffset = 0;
907 for (i = 0; i < sp->timecnt; ++i) {
908 j = sp->types[i];
909 if (sp->ttis[j].tt_isdst) {
910 theirdstoffset = -sp->ttis[j].tt_utoff;
911 break;
912 }
913 }
914 /*
915 ** Initially we're assumed to be in standard time.
916 */
917 isdst = false;
918 /*
919 ** Now juggle transition times and types
920 ** tracking offsets as you do.
921 */
922 for (i = 0; i < sp->timecnt; ++i) {
923 j = sp->types[i];
924 sp->types[i] = sp->ttis[j].tt_isdst;
925 if (sp->ttis[j].tt_ttisut) {
926 /* No adjustment to transition time */
927 }
928 else {
929 /*
930 ** If daylight saving time is in
931 ** effect, and the transition time was
932 ** not specified as standard time, add
933 ** the daylight saving time offset to
934 ** the transition time; otherwise, add
935 ** the standard time offset to the
936 ** transition time.
937 */
938 /*
939 ** Transitions from DST to DDST
940 ** will effectively disappear since
941 ** POSIX provides for only one DST
942 ** offset.
943 */
944 if (isdst && !sp->ttis[j].tt_ttisstd) {
945 sp->ats[i] += dstoffset - theirdstoffset;
946 }
947 else {
948 sp->ats[i] += stdoffset - theirstdoffset;
949 }
950 }
951 theiroffset = -sp->ttis[j].tt_utoff;
952 if (sp->ttis[j].tt_isdst) {
953 theirdstoffset = theiroffset;
954 }
955 else {
956 theirstdoffset = theiroffset;
957 }
958 }
959 /*
960 ** Finally, fill in ttis.
961 */
962 init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
963 init_ttinfo(&sp->ttis[1], -dstoffset, true, static_cast<s32>(stdlen + 1));
964 sp->typecnt = 2;
965 sp->defaulttype = 0;
966 }
967 }
968 else {
969 dstlen = 0;
970 sp->typecnt = 1; /* only standard time */
971 sp->timecnt = 0;
972 init_ttinfo(&sp->ttis[0], -stdoffset, false, 0);
973 sp->defaulttype = 0;
974 }
975 sp->charcnt = static_cast<s32>(charcnt);
976 cp = &sp->chars[0];
977 memcpy(cp, stdname, stdlen);
978 cp += stdlen;
979 *cp++ = '\0';
980 if (dstlen != 0) {
981 memcpy(cp, dstname, dstlen);
982 *(cp + dstlen) = '\0';
983 }
984 return true;
985}
986
987int tzloadbody(Rule* sp, local_storage& local_storage) {
988 int i;
989 int stored;
990 size_t nread{ local_storage.binary.size_bytes() };
991 int tzheadsize = sizeof(struct TzifHeader);
992 TzifHeader header{};
993
994 //ASSERT(local_storage.binary.size_bytes() >= sizeof(TzifHeader));
995 std::memcpy(&header, local_storage.binary.data(), sizeof(TzifHeader));
996
997 sp->goback = sp->goahead = false;
998
999 for (stored = 8; stored <= 8; stored *= 2) {
1000 s64 datablock_size;
1001 s32 ttisstdcnt = detzcode(header.tzh_ttisstdcnt.data());
1002 s32 ttisutcnt = detzcode(header.tzh_ttisutcnt.data());
1003 s32 leapcnt = detzcode(header.tzh_leapcnt.data());
1004 s32 timecnt = detzcode(header.tzh_timecnt.data());
1005 s32 typecnt = detzcode(header.tzh_typecnt.data());
1006 s32 charcnt = detzcode(header.tzh_charcnt.data());
1007 /* Although tzfile(5) currently requires typecnt to be nonzero,
1008 support future formats that may allow zero typecnt
1009 in files that have a TZ string and no transitions. */
1010 if (!(0 <= leapcnt && leapcnt < TZ_MAX_LEAPS && 0 <= typecnt && typecnt < TZ_MAX_TYPES &&
1011 0 <= timecnt && timecnt < TZ_MAX_TIMES && 0 <= charcnt && charcnt < TZ_MAX_CHARS &&
1012 0 <= ttisstdcnt && ttisstdcnt < TZ_MAX_TYPES && 0 <= ttisutcnt &&
1013 ttisutcnt < TZ_MAX_TYPES)) {
1014 return EINVAL;
1015 }
1016 datablock_size = (timecnt * stored /* ats */
1017 + timecnt /* types */
1018 + typecnt * 6 /* ttinfos */
1019 + charcnt /* chars */
1020 + leapcnt * (stored + 4) /* lsinfos */
1021 + ttisstdcnt /* ttisstds */
1022 + ttisutcnt); /* ttisuts */
1023 if (static_cast<s32>(local_storage.binary.size_bytes()) < tzheadsize + datablock_size) {
1024 return EINVAL;
1025 }
1026 if (!((ttisstdcnt == typecnt || ttisstdcnt == 0) &&
1027 (ttisutcnt == typecnt || ttisutcnt == 0))) {
1028 return EINVAL;
1029 }
1030
1031 char const* p = (const char*)local_storage.binary.data() + tzheadsize;
1032
1033 sp->timecnt = timecnt;
1034 sp->typecnt = typecnt;
1035 sp->charcnt = charcnt;
1036
1037 /* Read transitions, discarding those out of time_t range.
1038 But pretend the last transition before TIME_T_MIN
1039 occurred at TIME_T_MIN. */
1040 timecnt = 0;
1041 for (i = 0; i < sp->timecnt; ++i) {
1042 int_fast64_t at = stored == 4 ? detzcode(p) : detzcode64(p);
1043 sp->types[i] = at <= TIME_T_MAX;
1044 if (sp->types[i]) {
1045 time_t attime =
1046 ((std::is_signed_v<time_t> ? at < TIME_T_MIN : at < 0) ? TIME_T_MIN : at);
1047 if (timecnt && attime <= sp->ats[timecnt - 1]) {
1048 if (attime < sp->ats[timecnt - 1])
1049 return EINVAL;
1050 sp->types[i - 1] = 0;
1051 timecnt--;
1052 }
1053 sp->ats[timecnt++] = attime;
1054 }
1055 p += stored;
1056 }
1057
1058 timecnt = 0;
1059 for (i = 0; i < sp->timecnt; ++i) {
1060 unsigned char typ = *p++;
1061 if (sp->typecnt <= typ) {
1062 return EINVAL;
1063 }
1064 if (sp->types[i]) {
1065 sp->types[timecnt++] = typ;
1066 }
1067 }
1068 sp->timecnt = timecnt;
1069 for (i = 0; i < sp->typecnt; ++i) {
1070 struct ttinfo* ttisp;
1071 unsigned char isdst, desigidx;
1072
1073 ttisp = &sp->ttis[i];
1074 ttisp->tt_utoff = detzcode(p);
1075 p += 4;
1076 isdst = *p++;
1077 if (!(isdst < 2)) {
1078 return EINVAL;
1079 }
1080 ttisp->tt_isdst = isdst != 0;
1081 desigidx = *p++;
1082 if (!(desigidx < sp->charcnt)) {
1083 return EINVAL;
1084 }
1085 ttisp->tt_desigidx = desigidx;
1086 }
1087 for (i = 0; i < sp->charcnt; ++i) {
1088 sp->chars[i] = *p++;
1089 }
1090 /* Ensure '\0'-terminated, and make it safe to call
1091 ttunspecified later. */
1092 memset(&sp->chars[i], 0, CHARS_EXTRA);
1093
1094 for (i = 0; i < sp->typecnt; ++i) {
1095 struct ttinfo* ttisp;
1096
1097 ttisp = &sp->ttis[i];
1098 if (ttisstdcnt == 0) {
1099 ttisp->tt_ttisstd = false;
1100 }
1101 else {
1102 if (*(bool*)p != true && *(bool*)p != false) {
1103 return EINVAL;
1104 }
1105 ttisp->tt_ttisstd = *(bool*)p++;
1106 }
1107 }
1108 for (i = 0; i < sp->typecnt; ++i) {
1109 struct ttinfo* ttisp;
1110
1111 ttisp = &sp->ttis[i];
1112 if (ttisutcnt == 0) {
1113 ttisp->tt_ttisut = false;
1114 }
1115 else {
1116 if (*(bool*)p != true && *(bool*)p != false) {
1117 return EINVAL;
1118 }
1119 ttisp->tt_ttisut = *(bool*)p++;
1120 }
1121 }
1122
1123 nread += (ptrdiff_t)local_storage.binary.data() - (ptrdiff_t)p;
1124 if (nread < 0) {
1125 return EINVAL;
1126 }
1127 }
1128
1129 std::array<char, 256> buf{};
1130 if (nread > buf.size()) {
1131 //ASSERT(false);
1132 return EINVAL;
1133 }
1134 memmove(buf.data(), &local_storage.binary[local_storage.binary.size_bytes() - nread], nread);
1135
1136 if (nread > 2 && buf[0] == '\n' && buf[nread - 1] == '\n' && sp->typecnt + 2 <= TZ_MAX_TYPES) {
1137 Rule* ts = &local_storage.state;
1138
1139 buf[nread - 1] = '\0';
1140 if (tzparse(&buf[1], ts) && local_storage.state.typecnt == 2) {
1141
1142 /* Attempt to reuse existing abbreviations.
1143 Without this, America/Anchorage would be right on
1144 the edge after 2037 when TZ_MAX_CHARS is 50, as
1145 sp->charcnt equals 40 (for LMT AST AWT APT AHST
1146 AHDT YST AKDT AKST) and ts->charcnt equals 10
1147 (for AKST AKDT). Reusing means sp->charcnt can
1148 stay 40 in this example. */
1149 int gotabbr = 0;
1150 int charcnt = sp->charcnt;
1151 for (i = 0; i < ts->typecnt; i++) {
1152 char* tsabbr = &ts->chars[ts->ttis[i].tt_desigidx];
1153 int j;
1154 for (j = 0; j < charcnt; j++)
1155 if (strcmp(&sp->chars[j], tsabbr) == 0) {
1156 ts->ttis[i].tt_desigidx = j;
1157 gotabbr++;
1158 break;
1159 }
1160 if (!(j < charcnt)) {
1161 int tsabbrlen = static_cast<s32>(strlen(tsabbr));
1162 if (j + tsabbrlen < TZ_MAX_CHARS) {
1163 strcpy(&sp->chars[j], tsabbr);
1164 charcnt = j + tsabbrlen + 1;
1165 ts->ttis[i].tt_desigidx = j;
1166 gotabbr++;
1167 }
1168 }
1169 }
1170 if (gotabbr == ts->typecnt) {
1171 sp->charcnt = charcnt;
1172
1173 /* Ignore any trailing, no-op transitions generated
1174 by zic as they don't help here and can run afoul
1175 of bugs in zic 2016j or earlier. */
1176 while (1 < sp->timecnt &&
1177 (sp->types[sp->timecnt - 1] == sp->types[sp->timecnt - 2])) {
1178 sp->timecnt--;
1179 }
1180
1181 for (i = 0; i < ts->timecnt && sp->timecnt < TZ_MAX_TIMES; i++) {
1182 time_t t = ts->ats[i];
1183 if (0 < sp->timecnt && t <= sp->ats[sp->timecnt - 1]) {
1184 continue;
1185 }
1186 sp->ats[sp->timecnt] = t;
1187 sp->types[sp->timecnt] = static_cast<u8>(sp->typecnt + ts->types[i]);
1188 sp->timecnt++;
1189 }
1190 for (i = 0; i < ts->typecnt; i++) {
1191 sp->ttis[sp->typecnt++] = ts->ttis[i];
1192 }
1193 }
1194 }
1195 }
1196 if (sp->typecnt == 0) {
1197 return EINVAL;
1198 }
1199
1200 if (sp->timecnt > 1) {
1201 if (sp->ats[0] <= TIME_T_MAX - SECSPERREPEAT) {
1202 time_t repeatat = sp->ats[0] + SECSPERREPEAT;
1203 int repeattype = sp->types[0];
1204 for (i = 1; i < sp->timecnt; ++i) {
1205 if (sp->ats[i] == repeatat && typesequiv(sp, sp->types[i], repeattype)) {
1206 sp->goback = true;
1207 break;
1208 }
1209 }
1210 }
1211 if (TIME_T_MIN + SECSPERREPEAT <= sp->ats[sp->timecnt - 1]) {
1212 time_t repeatat = sp->ats[sp->timecnt - 1] - SECSPERREPEAT;
1213 int repeattype = sp->types[sp->timecnt - 1];
1214 for (i = sp->timecnt - 2; i >= 0; --i) {
1215 if (sp->ats[i] == repeatat && typesequiv(sp, sp->types[i], repeattype)) {
1216 sp->goahead = true;
1217 break;
1218 }
1219 }
1220 }
1221 }
1222
1223 /* Infer sp->defaulttype from the data. Although this default
1224 type is always zero for data from recent tzdb releases,
1225 things are trickier for data from tzdb 2018e or earlier.
1226
1227 The first set of heuristics work around bugs in 32-bit data
1228 generated by tzdb 2013c or earlier. The workaround is for
1229 zones like Australia/Macquarie where timestamps before the
1230 first transition have a time type that is not the earliest
1231 standard-time type. See:
1232 https://mm.icann.org/pipermail/tz/2013-May/019368.html */
1233 /*
1234 ** If type 0 does not specify local time, or is unused in transitions,
1235 ** it's the type to use for early times.
1236 */
1237 for (i = 0; i < sp->timecnt; ++i) {
1238 if (sp->types[i] == 0) {
1239 break;
1240 }
1241 }
1242 i = i < sp->timecnt && !ttunspecified(sp, 0) ? -1 : 0;
1243 /*
1244 ** Absent the above,
1245 ** if there are transition times
1246 ** and the first transition is to a daylight time
1247 ** find the standard type less than and closest to
1248 ** the type of the first transition.
1249 */
1250 if (i < 0 && sp->timecnt > 0 && sp->ttis[sp->types[0]].tt_isdst) {
1251 i = sp->types[0];
1252 while (--i >= 0) {
1253 if (!sp->ttis[i].tt_isdst) {
1254 break;
1255 }
1256 }
1257 }
1258 /* The next heuristics are for data generated by tzdb 2018e or
1259 earlier, for zones like EST5EDT where the first transition
1260 is to DST. */
1261 /*
1262 ** If no result yet, find the first standard type.
1263 ** If there is none, punt to type zero.
1264 */
1265 if (i < 0) {
1266 i = 0;
1267 while (sp->ttis[i].tt_isdst) {
1268 if (++i >= sp->typecnt) {
1269 i = 0;
1270 break;
1271 }
1272 }
1273 }
1274 /* A simple 'sp->defaulttype = 0;' would suffice here if we
1275 didn't have to worry about 2018e-or-earlier data. Even
1276 simpler would be to remove the defaulttype member and just
1277 use 0 in its place. */
1278 sp->defaulttype = i;
1279
1280 return 0;
1281}
1282
1283constexpr int tmcomp(const CalendarTimeInternal* const atmp,
1284 const CalendarTimeInternal* const btmp) {
1285 int result;
1286
1287 if (atmp->tm_year != btmp->tm_year) {
1288 return atmp->tm_year < btmp->tm_year ? -1 : 1;
1289 }
1290 if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
1291 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
1292 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
1293 (result = (atmp->tm_min - btmp->tm_min)) == 0) {
1294 result = atmp->tm_sec - btmp->tm_sec;
1295 }
1296 return result;
1297}
1298
1299/* Copy to *DEST from *SRC. Copy only the members needed for mktime,
1300 as other members might not be initialized. */
1301constexpr void mktmcpy(struct CalendarTimeInternal* dest, struct CalendarTimeInternal const* src) {
1302 dest->tm_sec = src->tm_sec;
1303 dest->tm_min = src->tm_min;
1304 dest->tm_hour = src->tm_hour;
1305 dest->tm_mday = src->tm_mday;
1306 dest->tm_mon = src->tm_mon;
1307 dest->tm_year = src->tm_year;
1308 dest->tm_isdst = src->tm_isdst;
1309 dest->tm_zone = src->tm_zone;
1310 dest->tm_utoff = src->tm_utoff;
1311 dest->time_index = src->time_index;
1312}
1313
1314constexpr bool normalize_overflow(int* const tensptr, int* const unitsptr, const int base) {
1315 int tensdelta;
1316
1317 tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base);
1318 *unitsptr -= tensdelta * base;
1319 return increment_overflow(tensptr, tensdelta);
1320}
1321
1322constexpr bool normalize_overflow32(s64* tensptr, int* unitsptr, int base) {
1323 int tensdelta;
1324
1325 tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base);
1326 *unitsptr -= tensdelta * base;
1327 return increment_overflow32(tensptr, tensdelta);
1328}
1329
1330int time2sub(time_t* out_time, CalendarTimeInternal* const tmp,
1331 CalendarTimeInternal* (*funcp)(Rule const*, time_t const*, s64,
1332 CalendarTimeInternal*),
1333 Rule const* sp, const s64 offset, bool* okayp, bool do_norm_secs) {
1334 int dir;
1335 int i, j;
1336 int saved_seconds;
1337 s64 li;
1338 time_t lo;
1339 time_t hi;
1340 s64 y;
1341 time_t newt;
1342 time_t t;
1343 CalendarTimeInternal yourtm, mytm;
1344
1345 *okayp = false;
1346 mktmcpy(&yourtm, tmp);
1347
1348 if (do_norm_secs) {
1349 if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN)) {
1350 return 1;
1351 }
1352 }
1353 if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) {
1354 return 1;
1355 }
1356 if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) {
1357 return 1;
1358 }
1359 y = yourtm.tm_year;
1360 if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR)) {
1361 return 1;
1362 }
1363 /*
1364 ** Turn y into an actual year number for now.
1365 ** It is converted back to an offset from TM_YEAR_BASE later.
1366 */
1367 if (increment_overflow32(&y, TM_YEAR_BASE)) {
1368 return 1;
1369 }
1370 while (yourtm.tm_mday <= 0) {
1371 if (increment_overflow32(&y, -1)) {
1372 return 1;
1373 }
1374 li = y + (1 < yourtm.tm_mon);
1375 yourtm.tm_mday += year_lengths[isleap(li)];
1376 }
1377 while (yourtm.tm_mday > DAYSPERLYEAR) {
1378 li = y + (1 < yourtm.tm_mon);
1379 yourtm.tm_mday -= year_lengths[isleap(li)];
1380 if (increment_overflow32(&y, 1)) {
1381 return 1;
1382 }
1383 }
1384 for (;;) {
1385 i = mon_lengths[isleap(y)][yourtm.tm_mon];
1386 if (yourtm.tm_mday <= i) {
1387 break;
1388 }
1389 yourtm.tm_mday -= i;
1390 if (++yourtm.tm_mon >= MONSPERYEAR) {
1391 yourtm.tm_mon = 0;
1392 if (increment_overflow32(&y, 1)) {
1393 return 1;
1394 }
1395 }
1396 }
1397
1398 if (increment_overflow32(&y, -TM_YEAR_BASE)) {
1399 return 1;
1400 }
1401 if (!(INT_MIN <= y && y <= INT_MAX)) {
1402 return 1;
1403 }
1404 yourtm.tm_year = static_cast<s32>(y);
1405
1406 if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) {
1407 saved_seconds = 0;
1408 }
1409 else if (yourtm.tm_year < EPOCH_YEAR - TM_YEAR_BASE) {
1410 /*
1411 ** We can't set tm_sec to 0, because that might push the
1412 ** time below the minimum representable time.
1413 ** Set tm_sec to 59 instead.
1414 ** This assumes that the minimum representable time is
1415 ** not in the same minute that a leap second was deleted from,
1416 ** which is a safer assumption than using 58 would be.
1417 */
1418 if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) {
1419 return 1;
1420 }
1421 saved_seconds = yourtm.tm_sec;
1422 yourtm.tm_sec = SECSPERMIN - 1;
1423 }
1424 else {
1425 saved_seconds = yourtm.tm_sec;
1426 yourtm.tm_sec = 0;
1427 }
1428 /*
1429 ** Do a binary search (this works whatever time_t's type is).
1430 */
1431 lo = TIME_T_MIN;
1432 hi = TIME_T_MAX;
1433 for (;;) {
1434 t = lo / 2 + hi / 2;
1435 if (t < lo) {
1436 t = lo;
1437 }
1438 else if (t > hi) {
1439 t = hi;
1440 }
1441 if (!funcp(sp, &t, offset, &mytm)) {
1442 /*
1443 ** Assume that t is too extreme to be represented in
1444 ** a struct tm; arrange things so that it is less
1445 ** extreme on the next pass.
1446 */
1447 dir = (t > 0) ? 1 : -1;
1448 }
1449 else {
1450 dir = tmcomp(&mytm, &yourtm);
1451 }
1452 if (dir != 0) {
1453 if (t == lo) {
1454 if (t == TIME_T_MAX) {
1455 return 2;
1456 }
1457 ++t;
1458 ++lo;
1459 }
1460 else if (t == hi) {
1461 if (t == TIME_T_MIN) {
1462 return 2;
1463 }
1464 --t;
1465 --hi;
1466 }
1467 if (lo > hi) {
1468 return 2;
1469 }
1470 if (dir > 0) {
1471 hi = t;
1472 }
1473 else {
1474 lo = t;
1475 }
1476 continue;
1477 }
1478
1479 if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) {
1480 break;
1481 }
1482 /*
1483 ** Right time, wrong type.
1484 ** Hunt for right time, right type.
1485 ** It's okay to guess wrong since the guess
1486 ** gets checked.
1487 */
1488 if (sp == nullptr) {
1489 return 2;
1490 }
1491 for (i = sp->typecnt - 1; i >= 0; --i) {
1492 if (sp->ttis[i].tt_isdst != static_cast<bool>(yourtm.tm_isdst)) {
1493 continue;
1494 }
1495 for (j = sp->typecnt - 1; j >= 0; --j) {
1496 if (sp->ttis[j].tt_isdst == static_cast<bool>(yourtm.tm_isdst)) {
1497 continue;
1498 }
1499 if (ttunspecified(sp, j)) {
1500 continue;
1501 }
1502 newt = (t + sp->ttis[j].tt_utoff - sp->ttis[i].tt_utoff);
1503 if (!funcp(sp, &newt, offset, &mytm)) {
1504 continue;
1505 }
1506 if (tmcomp(&mytm, &yourtm) != 0) {
1507 continue;
1508 }
1509 if (mytm.tm_isdst != yourtm.tm_isdst) {
1510 continue;
1511 }
1512 /*
1513 ** We have a match.
1514 */
1515 t = newt;
1516 goto label;
1517 }
1518 }
1519 return 2;
1520 }
1521label:
1522 newt = t + saved_seconds;
1523 t = newt;
1524 if (funcp(sp, &t, offset, tmp) || *okayp) {
1525 *okayp = true;
1526 *out_time = t;
1527 return 0;
1528 }
1529 return 2;
1530}
1531
1532int time2(time_t* out_time, struct CalendarTimeInternal* const tmp,
1533 struct CalendarTimeInternal* (*funcp)(struct Rule const*, time_t const*, s64,
1534 struct CalendarTimeInternal*),
1535 struct Rule const* sp, const s64 offset, bool* okayp) {
1536 int res;
1537
1538 /*
1539 ** First try without normalization of seconds
1540 ** (in case tm_sec contains a value associated with a leap second).
1541 ** If that fails, try with normalization of seconds.
1542 */
1543 res = time2sub(out_time, tmp, funcp, sp, offset, okayp, false);
1544 return *okayp ? res : time2sub(out_time, tmp, funcp, sp, offset, okayp, true);
1545}
1546
1547int time1(time_t* out_time, CalendarTimeInternal* const tmp,
1548 CalendarTimeInternal* (*funcp)(Rule const*, time_t const*, s64,
1549 CalendarTimeInternal*),
1550 Rule const* sp, const s64 offset) {
1551 int samei, otheri;
1552 int sameind, otherind;
1553 int i;
1554 int nseen;
1555 char seen[TZ_MAX_TYPES];
1556 unsigned char types[TZ_MAX_TYPES];
1557 bool okay;
1558
1559 if (tmp->tm_isdst > 1) {
1560 tmp->tm_isdst = 1;
1561 }
1562 auto res = time2(out_time, tmp, funcp, sp, offset, &okay);
1563 if (res == 0) {
1564 return res;
1565 }
1566 if (tmp->tm_isdst < 0) {
1567 return res;
1568 }
1569 /*
1570 ** We're supposed to assume that somebody took a time of one type
1571 ** and did some math on it that yielded a "struct tm" that's bad.
1572 ** We try to divine the type they started from and adjust to the
1573 ** type they need.
1574 */
1575 for (i = 0; i < sp->typecnt; ++i) {
1576 seen[i] = false;
1577 }
1578
1579 if (sp->timecnt < 1) {
1580 return 2;
1581 }
1582
1583 nseen = 0;
1584 for (i = sp->timecnt - 1; i >= 0; --i) {
1585 if (!seen[sp->types[i]] && !ttunspecified(sp, sp->types[i])) {
1586 seen[sp->types[i]] = true;
1587 types[nseen++] = sp->types[i];
1588 }
1589 }
1590
1591 if (nseen < 1) {
1592 return 2;
1593 }
1594
1595 for (sameind = 0; sameind < nseen; ++sameind) {
1596 samei = types[sameind];
1597 if (sp->ttis[samei].tt_isdst != static_cast<bool>(tmp->tm_isdst)) {
1598 continue;
1599 }
1600 for (otherind = 0; otherind < nseen; ++otherind) {
1601 otheri = types[otherind];
1602 if (sp->ttis[otheri].tt_isdst == static_cast<bool>(tmp->tm_isdst)) {
1603 continue;
1604 }
1605 tmp->tm_sec += (sp->ttis[otheri].tt_utoff - sp->ttis[samei].tt_utoff);
1606 tmp->tm_isdst = !tmp->tm_isdst;
1607 res = time2(out_time, tmp, funcp, sp, offset, &okay);
1608 if (res == 0) {
1609 return res;
1610 }
1611 tmp->tm_sec -= (sp->ttis[otheri].tt_utoff - sp->ttis[samei].tt_utoff);
1612 tmp->tm_isdst = !tmp->tm_isdst;
1613 }
1614 }
1615 return 2;
1616}
1617
1618} // namespace
1619
1620s32 ParseTimeZoneBinary(Rule& out_rule, std::span<const u8> binary) {
1621 tzloadbody_local_storage.binary = binary;
1622 if (tzloadbody(&out_rule, tzloadbody_local_storage)) {
1623 return 3;
1624 }
1625 return 0;
1626}
1627
1628bool localtime_rz(CalendarTimeInternal* tmp, Rule* sp, time_t* timep) {
1629 return localsub(sp, timep, 0, tmp) == nullptr;
1630}
1631
1632u32 mktime_tzname(time_t* out_time, Rule* sp, CalendarTimeInternal* tmp) {
1633 return time1(out_time, tmp, localsub, sp, 0);
1634}
1635
1636} // namespace Tz
diff --git a/externals/tz/tz/tz.h b/externals/tz/tz/tz.h
new file mode 100644
index 000000000..38605cfb1
--- /dev/null
+++ b/externals/tz/tz/tz.h
@@ -0,0 +1,81 @@
1// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
2// SPDX-FileCopyrightText: 1996 Arthur David Olson
3// SPDX-License-Identifier: BSD-2-Clause
4
5#pragma once
6
7#include <cstdint>
8#include <limits>
9#include <span>
10#include <array>
11#include <time.h>
12
13namespace Tz {
14using u8 = uint8_t;
15using s8 = int8_t;
16using u16 = uint16_t;
17using s16 = int16_t;
18using u32 = uint32_t;
19using s32 = int32_t;
20using u64 = uint64_t;
21using s64 = int64_t;
22
23constexpr size_t TZ_MAX_TIMES = 1000;
24constexpr size_t TZ_MAX_TYPES = 128;
25constexpr size_t TZ_MAX_CHARS = 50;
26constexpr size_t MY_TZNAME_MAX = 255;
27constexpr size_t TZNAME_MAXIMUM = 255;
28constexpr size_t TZ_MAX_LEAPS = 50;
29constexpr s64 TIME_T_MAX = std::numeric_limits<s64>::max();
30constexpr s64 TIME_T_MIN = std::numeric_limits<s64>::min();
31constexpr size_t CHARS_EXTRA = 3;
32constexpr size_t MAX_ZONE_CHARS = std::max(TZ_MAX_CHARS + CHARS_EXTRA, sizeof("UTC"));
33constexpr size_t MAX_TZNAME_CHARS = 2 * (MY_TZNAME_MAX + 1);
34
35struct ttinfo {
36 s32 tt_utoff;
37 bool tt_isdst;
38 s32 tt_desigidx;
39 bool tt_ttisstd;
40 bool tt_ttisut;
41};
42static_assert(sizeof(ttinfo) == 0x10, "ttinfo has the wrong size!");
43
44struct Rule {
45 s32 timecnt;
46 s32 typecnt;
47 s32 charcnt;
48 bool goback;
49 bool goahead;
50 std::array <u8, 0x2> padding0;
51 std::array<s64, TZ_MAX_TIMES> ats;
52 std::array<u8, TZ_MAX_TIMES> types;
53 std::array<ttinfo, TZ_MAX_TYPES> ttis;
54 std::array<char, std::max(MAX_ZONE_CHARS, MAX_TZNAME_CHARS)> chars;
55 s32 defaulttype;
56 std::array <u8, 0x12C4> padding1;
57};
58static_assert(sizeof(Rule) == 0x4000, "Rule has the wrong size!");
59
60struct CalendarTimeInternal {
61 s32 tm_sec;
62 s32 tm_min;
63 s32 tm_hour;
64 s32 tm_mday;
65 s32 tm_mon;
66 s32 tm_year;
67 s32 tm_wday;
68 s32 tm_yday;
69 s32 tm_isdst;
70 std::array<char, 16> tm_zone;
71 s32 tm_utoff;
72 s32 time_index;
73};
74static_assert(sizeof(CalendarTimeInternal) == 0x3C, "CalendarTimeInternal has the wrong size!");
75
76s32 ParseTimeZoneBinary(Rule& out_rule, std::span<const u8> binary);
77
78bool localtime_rz(CalendarTimeInternal* tmp, Rule* sp, time_t* timep);
79u32 mktime_tzname(time_t* out_time, Rule* sp, CalendarTimeInternal* tmp);
80
81} // namespace Tz