Coverage Report

Created: 2026-09-14 06:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/date/lib/parse_tz.c
Line
Count
Source
1
/*
2
 * The MIT License (MIT)
3
 *
4
 * Copyright (c) 2015-2019 Derick Rethans
5
 * Copyright (c) 2018 MongoDB, Inc.
6
 *
7
 * Permission is hereby granted, free of charge, to any person obtaining a copy
8
 * of this software and associated documentation files (the "Software"), to deal
9
 * in the Software without restriction, including without limitation the rights
10
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 * copies of the Software, and to permit persons to whom the Software is
12
 * furnished to do so, subject to the following conditions:
13
 *
14
 * The above copyright notice and this permission notice shall be included in
15
 * all copies or substantial portions of the Software.
16
 *
17
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
 * THE SOFTWARE.
24
 */
25
26
#include "timelib.h"
27
#include "timelib_private.h"
28
29
#define TIMELIB_SUPPORTS_V2DATA
30
#define TIMELIB_SUPPORT_SLIM_FILE
31
#include "timezonedb.h"
32
33
#if (defined(__APPLE__) || defined(__APPLE_CC__)) && (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__))
34
# if defined(__LITTLE_ENDIAN__)
35
#  undef WORDS_BIGENDIAN
36
# else
37
#  if defined(__BIG_ENDIAN__)
38
#   define WORDS_BIGENDIAN
39
#  endif
40
# endif
41
#endif
42
43
#if (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN))
44
# if __BYTE_ORDER == __BIG_ENDIAN
45
#  define WORDS_BIGENDIAN
46
# endif
47
#endif
48
49
#if defined(__s390__)
50
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
51
#  define WORDS_BIGENDIAN
52
# else
53
#  undef WORDS_BIGENDIAN
54
# endif
55
#endif
56
57
#ifdef WORDS_BIGENDIAN
58
static inline uint32_t timelib_conv_int_unsigned(uint32_t value)
59
{
60
  return value;
61
}
62
63
static inline uint64_t timelib_conv_int64_unsigned(uint64_t value)
64
{
65
  return value;
66
}
67
#else
68
static inline uint32_t timelib_conv_int_unsigned(uint32_t value)
69
86.6k
{
70
86.6k
  return
71
86.6k
    ((value & 0x000000ff) << 24) +
72
86.6k
    ((value & 0x0000ff00) <<  8) +
73
86.6k
    ((value & 0x00ff0000) >>  8) +
74
86.6k
    ((value & 0xff000000) >> 24);
75
86.6k
}
76
77
static inline uint64_t timelib_conv_int64_unsigned(uint64_t value)
78
96.3k
{
79
96.3k
  return
80
96.3k
    ((value & 0x00000000000000ff) << 56) +
81
96.3k
    ((value & 0x000000000000ff00) << 40) +
82
96.3k
    ((value & 0x0000000000ff0000) << 24) +
83
96.3k
    ((value & 0x00000000ff000000) <<  8) +
84
96.3k
    ((value & 0x000000ff00000000) >>  8) +
85
96.3k
    ((value & 0x0000ff0000000000) >> 24) +
86
96.3k
    ((value & 0x00ff000000000000) >> 40) +
87
96.3k
    ((value & 0xff00000000000000) >> 56);
88
96.3k
}
89
#endif
90
91
0
#define timelib_conv_int_signed(value) ((int32_t) timelib_conv_int_unsigned((int32_t) value))
92
96.3k
#define timelib_conv_int64_signed(value) ((int64_t) timelib_conv_int64_unsigned((int64_t) value))
93
94
static int read_php_preamble(const unsigned char **tzf, timelib_tzinfo *tz)
95
5.77k
{
96
5.77k
  uint32_t version;
97
98
  /* read ID */
99
5.77k
  version = (*tzf)[3] - '0';
100
5.77k
  *tzf += 4;
101
102
  /* read BC flag */
103
5.77k
  tz->bc = (**tzf == '\1');
104
5.77k
  *tzf += 1;
105
106
  /* read country code */
107
5.77k
  memcpy(tz->location.country_code, *tzf, 2);
108
5.77k
  tz->location.country_code[2] = '\0';
109
5.77k
  *tzf += 2;
110
111
  /* skip rest of preamble */
112
5.77k
  *tzf += 13;
113
114
5.77k
  return version;
115
5.77k
}
116
117
static int read_tzif_preamble(const unsigned char **tzf, timelib_tzinfo *tz)
118
0
{
119
0
  uint32_t version;
120
121
  /* read ID */
122
0
  switch ((*tzf)[4]) {
123
0
    case '\0':
124
0
      version = 0;
125
0
      break;
126
0
    case '2':
127
0
      version = 2;
128
0
      break;
129
0
    case '3':
130
0
      version = 3;
131
0
      break;
132
0
    case '4':
133
0
      version = 4;
134
0
      break;
135
0
    default:
136
0
      return -1;
137
0
  }
138
0
  *tzf += 5;
139
140
  /* set BC flag and country code to default */
141
0
  tz->bc = 0;
142
0
  tz->location.country_code[0] = '?';
143
0
  tz->location.country_code[1] = '?';
144
0
  tz->location.country_code[2] = '\0';
145
146
  /* skip rest of preamble */
147
0
  *tzf += 15;
148
149
0
  return version;
150
0
}
151
152
static int read_preamble(const unsigned char **tzf, timelib_tzinfo *tz, unsigned int *type)
153
5.77k
{
154
  /* read marker (TZif) or (PHP) */
155
5.77k
  if (memcmp(*tzf, "PHP", 3) == 0) {
156
5.77k
    *type = TIMELIB_TZINFO_PHP;
157
5.77k
    return read_php_preamble(tzf, tz);
158
5.77k
  } else if (memcmp(*tzf, "TZif", 4) == 0) {
159
0
    *type = TIMELIB_TZINFO_ZONEINFO;
160
0
    return read_tzif_preamble(tzf, tz);
161
0
  } else {
162
0
    return -1;
163
0
  }
164
5.77k
}
165
166
static void read_32bit_header(const unsigned char **tzf, timelib_tzinfo *tz)
167
5.77k
{
168
5.77k
  uint32_t buffer[6];
169
170
5.77k
  memcpy(&buffer, *tzf, sizeof(buffer));
171
5.77k
  tz->_bit32.ttisgmtcnt = timelib_conv_int_unsigned(buffer[0]);
172
5.77k
  tz->_bit32.ttisstdcnt = timelib_conv_int_unsigned(buffer[1]);
173
5.77k
  tz->_bit32.leapcnt    = timelib_conv_int_unsigned(buffer[2]);
174
5.77k
  tz->_bit32.timecnt    = timelib_conv_int_unsigned(buffer[3]);
175
5.77k
  tz->_bit32.typecnt    = timelib_conv_int_unsigned(buffer[4]);
176
5.77k
  tz->_bit32.charcnt    = timelib_conv_int_unsigned(buffer[5]);
177
178
5.77k
  *tzf += sizeof(buffer);
179
5.77k
}
180
181
static int detect_slim_file(timelib_tzinfo *tz)
182
0
{
183
0
  if (
184
0
    (tz->_bit32.ttisgmtcnt == 0) &&
185
0
    (tz->_bit32.ttisstdcnt == 0) &&
186
0
    (tz->_bit32.leapcnt    == 0) &&
187
0
    (tz->_bit32.timecnt    == 0) &&
188
0
    (tz->_bit32.typecnt    == 1) &&
189
0
    (tz->_bit32.charcnt    == 1)
190
0
  ) {
191
0
    return 1;
192
0
  }
193
194
0
  return 0;
195
0
}
196
197
static int read_64bit_transitions(const unsigned char **tzf, timelib_tzinfo *tz)
198
5.77k
{
199
5.77k
  int64_t *buffer = NULL;
200
5.77k
  uint32_t i;
201
5.77k
  unsigned char *cbuffer = NULL;
202
203
5.77k
  if (tz->bit64.timecnt) {
204
721
    buffer = (int64_t*) timelib_malloc(tz->bit64.timecnt * sizeof(int64_t));
205
721
    if (!buffer) {
206
0
      return TIMELIB_ERROR_CANNOT_ALLOCATE;
207
0
    }
208
721
    memcpy(buffer, *tzf, sizeof(int64_t) * tz->bit64.timecnt);
209
721
    *tzf += (sizeof(int64_t) * tz->bit64.timecnt);
210
97.0k
    for (i = 0; i < tz->bit64.timecnt; i++) {
211
96.3k
      buffer[i] = timelib_conv_int64_signed(buffer[i]);
212
      /* Sanity check to see whether TS is just increasing */
213
96.3k
      if (i > 0 && !(buffer[i] > buffer[i - 1])) {
214
0
        timelib_free(buffer);
215
0
        return TIMELIB_ERROR_CORRUPT_TRANSITIONS_DONT_INCREASE;
216
0
      }
217
96.3k
    }
218
219
721
    cbuffer = (unsigned char*) timelib_malloc(tz->bit64.timecnt * sizeof(unsigned char));
220
721
    if (!cbuffer) {
221
0
      timelib_free(buffer);
222
0
      return TIMELIB_ERROR_CANNOT_ALLOCATE;
223
0
    }
224
721
    memcpy(cbuffer, *tzf, sizeof(unsigned char) * tz->bit64.timecnt);
225
721
    *tzf += sizeof(unsigned char) * tz->bit64.timecnt;
226
721
  }
227
228
5.77k
  tz->trans = buffer;
229
5.77k
  tz->trans_idx = cbuffer;
230
231
5.77k
  return 0;
232
5.77k
}
233
234
static void skip_32bit_transitions(const unsigned char **tzf, timelib_tzinfo *tz)
235
5.77k
{
236
5.77k
  if (tz->_bit32.timecnt) {
237
0
    *tzf += (sizeof(int32_t) * tz->_bit32.timecnt);
238
0
    *tzf += sizeof(unsigned char) * tz->_bit32.timecnt;
239
0
  }
240
5.77k
}
241
242
static int read_64bit_types(const unsigned char **tzf, timelib_tzinfo *tz)
243
5.77k
{
244
5.77k
  unsigned char *buffer;
245
5.77k
  int32_t *leap_buffer;
246
5.77k
  unsigned int i, j;
247
248
  /* Offset Types */
249
5.77k
  buffer = (unsigned char*) timelib_malloc(tz->bit64.typecnt * sizeof(unsigned char) * 6);
250
5.77k
  if (!buffer) {
251
0
    return TIMELIB_ERROR_CANNOT_ALLOCATE;
252
0
  }
253
5.77k
  memcpy(buffer, *tzf, sizeof(unsigned char) * 6 * tz->bit64.typecnt);
254
5.77k
  *tzf += sizeof(unsigned char) * 6 * tz->bit64.typecnt;
255
256
  // We add two extra to have space for potential new ttinfo entries due to new types defined in the
257
  // POSIX string
258
5.77k
  tz->type = (ttinfo*) timelib_calloc(1, (tz->bit64.typecnt + 2) * sizeof(ttinfo));
259
5.77k
  if (!tz->type) {
260
0
    timelib_free(buffer);
261
0
    return TIMELIB_ERROR_CANNOT_ALLOCATE;
262
0
  }
263
264
14.3k
  for (i = 0; i < tz->bit64.typecnt; i++) {
265
8.55k
    j = i * 6;
266
8.55k
    tz->type[i].offset = 0;
267
8.55k
    tz->type[i].offset += (int32_t) (((uint32_t) buffer[j]) << 24) + (buffer[j + 1] << 16) + (buffer[j + 2] << 8) + tz->type[i].offset + buffer[j + 3];
268
8.55k
    tz->type[i].isdst = buffer[j + 4];
269
8.55k
    tz->type[i].abbr_idx = buffer[j + 5];
270
8.55k
  }
271
5.77k
  timelib_free(buffer);
272
273
  /* Abbreviations */
274
5.77k
  tz->timezone_abbr = (char*) timelib_malloc(tz->bit64.charcnt);
275
5.77k
  if (!tz->timezone_abbr) {
276
0
    return TIMELIB_ERROR_CORRUPT_NO_ABBREVIATION;
277
0
  }
278
5.77k
  memcpy(tz->timezone_abbr, *tzf, sizeof(char) * tz->bit64.charcnt);
279
5.77k
  *tzf += sizeof(char) * tz->bit64.charcnt;
280
281
  /* Leap seconds (only use in 'right/') format */
282
5.77k
  if (tz->bit64.leapcnt) {
283
0
    leap_buffer = (int32_t *) timelib_malloc(tz->bit64.leapcnt * (sizeof(int64_t) + sizeof(int32_t)));
284
0
    if (!leap_buffer) {
285
0
      return TIMELIB_ERROR_CANNOT_ALLOCATE;
286
0
    }
287
0
    memcpy(leap_buffer, *tzf, tz->bit64.leapcnt * (sizeof(int64_t) + sizeof(int32_t)));
288
0
    *tzf += tz->bit64.leapcnt * (sizeof(int64_t) + sizeof(int32_t));
289
290
0
    tz->leap_times = (tlinfo*) timelib_malloc(tz->bit64.leapcnt * sizeof(tlinfo));
291
0
    if (!tz->leap_times) {
292
0
      timelib_free(leap_buffer);
293
0
      return TIMELIB_ERROR_CANNOT_ALLOCATE;
294
0
    }
295
0
    for (i = 0; i < tz->bit64.leapcnt; i++) {
296
0
      tz->leap_times[i].trans = timelib_conv_int64_signed(leap_buffer[i * 3 + 1] * 4294967296 + leap_buffer[i * 3]);
297
0
      tz->leap_times[i].offset = timelib_conv_int_signed(leap_buffer[i * 3 + 2]);
298
0
    }
299
0
    timelib_free(leap_buffer);
300
0
  }
301
302
  /* Standard/Wall Indicators (unused) */
303
5.77k
  if (tz->bit64.ttisstdcnt) {
304
0
    buffer = (unsigned char*) timelib_malloc(tz->bit64.ttisstdcnt * sizeof(unsigned char));
305
0
    if (!buffer) {
306
0
      return TIMELIB_ERROR_CANNOT_ALLOCATE;
307
0
    }
308
0
    memcpy(buffer, *tzf, sizeof(unsigned char) * tz->bit64.ttisstdcnt);
309
0
    *tzf += sizeof(unsigned char) * tz->bit64.ttisstdcnt;
310
311
0
    for (i = 0; i < tz->bit64.ttisstdcnt; i++) {
312
0
      tz->type[i].isstdcnt = buffer[i];
313
0
    }
314
0
    timelib_free(buffer);
315
0
  }
316
317
  /* UT/Local Time Indicators (unused) */
318
5.77k
  if (tz->bit64.ttisgmtcnt) {
319
0
    buffer = (unsigned char*) timelib_malloc(tz->bit64.ttisgmtcnt * sizeof(unsigned char));
320
0
    if (!buffer) {
321
0
      return TIMELIB_ERROR_CANNOT_ALLOCATE;
322
0
    }
323
0
    memcpy(buffer, *tzf, sizeof(unsigned char) * tz->bit64.ttisgmtcnt);
324
0
    *tzf += sizeof(unsigned char) * tz->bit64.ttisgmtcnt;
325
326
0
    for (i = 0; i < tz->bit64.ttisgmtcnt; i++) {
327
0
      tz->type[i].isgmtcnt = buffer[i];
328
0
    }
329
0
    timelib_free(buffer);
330
0
  }
331
332
5.77k
  return 0;
333
5.77k
}
334
335
static void skip_32bit_types(const unsigned char **tzf, timelib_tzinfo *tz)
336
5.77k
{
337
  /* Offset Types */
338
5.77k
  *tzf += sizeof(unsigned char) * 6 * tz->_bit32.typecnt;
339
340
  /* Abbreviations */
341
5.77k
  *tzf += sizeof(char) * tz->_bit32.charcnt;
342
343
  /* Leap seconds (only use in 'right/') format */
344
5.77k
  if (tz->_bit32.leapcnt) {
345
0
    *tzf += sizeof(int32_t) * tz->_bit32.leapcnt * 2;
346
0
  }
347
348
  /* Standard/Wall Indicators (unused) */
349
5.77k
  if (tz->_bit32.ttisstdcnt) {
350
0
    *tzf += sizeof(unsigned char) * tz->_bit32.ttisstdcnt;
351
0
  }
352
353
  /* UT/Local Time Indicators (unused) */
354
5.77k
  if (tz->_bit32.ttisgmtcnt) {
355
0
    *tzf += sizeof(unsigned char) * tz->_bit32.ttisgmtcnt;
356
0
  }
357
5.77k
}
358
359
static void read_posix_string(const unsigned char **tzf, timelib_tzinfo *tz)
360
5.77k
{
361
5.77k
  const unsigned char *begin;
362
363
  // POSIX string is delimited by \n
364
5.77k
  (*tzf)++;
365
5.77k
  begin = *tzf;
366
367
41.1k
  while (*tzf[0] != '\n') {
368
35.3k
    (*tzf)++;
369
35.3k
  }
370
371
5.77k
  tz->posix_string = timelib_calloc(1, *tzf - begin + 1);
372
5.77k
  memcpy(tz->posix_string, begin, *tzf - begin);
373
374
  // skip over closing \n
375
5.77k
  (*tzf)++;
376
5.77k
}
377
378
static signed int find_ttinfo_index(timelib_tzinfo *tz, int32_t offset, int isdst, char *abbr)
379
6.37k
{
380
6.37k
  uint64_t i;
381
382
8.73k
  for (i = 0; i < tz->bit64.typecnt; i++) {
383
8.73k
    if (
384
8.73k
      (offset == tz->type[i].offset) &&
385
6.44k
      (isdst == tz->type[i].isdst) &&
386
6.39k
      (strcmp(abbr, &tz->timezone_abbr[tz->type[i].abbr_idx]) == 0)
387
8.73k
    ) {
388
6.37k
      return i;
389
6.37k
    }
390
8.73k
  }
391
392
0
  return TIMELIB_UNSET;
393
6.37k
}
394
395
static unsigned int add_abbr(timelib_tzinfo *tz, char *abbr)
396
0
{
397
0
  size_t old_length = tz->bit64.charcnt;
398
0
  size_t new_length = old_length + strlen(abbr) + 1;
399
0
  tz->timezone_abbr = (char*) timelib_realloc(tz->timezone_abbr, new_length);
400
0
  memcpy(tz->timezone_abbr + old_length, abbr, strlen(abbr));
401
0
  tz->bit64.charcnt = new_length;
402
0
  tz->timezone_abbr[new_length - 1] = '\0';
403
404
0
  return old_length;
405
0
}
406
407
static signed int add_new_ttinfo_index(timelib_tzinfo *tz, int32_t offset, int isdst, char *abbr)
408
0
{
409
0
  tz->type[tz->bit64.typecnt].offset = offset;
410
0
  tz->type[tz->bit64.typecnt].isdst = isdst;
411
0
  tz->type[tz->bit64.typecnt].abbr_idx = add_abbr(tz, abbr);
412
0
  tz->type[tz->bit64.typecnt].isstdcnt = 0;
413
0
  tz->type[tz->bit64.typecnt].isgmtcnt = 0;
414
415
0
  ++tz->bit64.typecnt;
416
417
0
  return tz->bit64.typecnt - 1;
418
0
}
419
420
static int integrate_posix_string(timelib_tzinfo *tz)
421
5.77k
{
422
5.77k
  tz->posix_info = timelib_parse_posix_str(tz->posix_string);
423
5.77k
  if (!tz->posix_info) {
424
0
    return 0;
425
0
  }
426
427
5.77k
  tz->posix_info->type_index_std_type = find_ttinfo_index(tz, tz->posix_info->std_offset, 0, tz->posix_info->std);
428
5.77k
  if (tz->posix_info->type_index_std_type == TIMELIB_UNSET) {
429
0
    tz->posix_info->type_index_std_type = add_new_ttinfo_index(tz, tz->posix_info->std_offset, 0, tz->posix_info->std);
430
0
    return 1;
431
0
  }
432
433
  /* If there is no DST set for this zone, return */
434
5.77k
  if (!tz->posix_info->dst) {
435
5.17k
    return 1;
436
5.17k
  }
437
438
600
  tz->posix_info->type_index_dst_type = find_ttinfo_index(tz, tz->posix_info->dst_offset, 1, tz->posix_info->dst);
439
600
  if (tz->posix_info->type_index_dst_type == TIMELIB_UNSET) {
440
0
    tz->posix_info->type_index_dst_type = add_new_ttinfo_index(tz, tz->posix_info->dst_offset, 1, tz->posix_info->dst);
441
0
    return 1;
442
0
  }
443
444
600
  return 1;
445
600
}
446
447
static void read_location(const unsigned char **tzf, timelib_tzinfo *tz)
448
5.77k
{
449
5.77k
  uint32_t buffer[3];
450
5.77k
  uint32_t comments_len;
451
452
5.77k
  memcpy(&buffer, *tzf, sizeof(buffer));
453
5.77k
  tz->location.latitude = timelib_conv_int_unsigned(buffer[0]);
454
5.77k
  tz->location.latitude = (tz->location.latitude / 100000) - 90;
455
5.77k
  tz->location.longitude = timelib_conv_int_unsigned(buffer[1]);
456
5.77k
  tz->location.longitude = (tz->location.longitude / 100000) - 180;
457
5.77k
  comments_len = timelib_conv_int_unsigned(buffer[2]);
458
5.77k
  *tzf += sizeof(buffer);
459
460
5.77k
  tz->location.comments = timelib_malloc(comments_len + 1);
461
5.77k
  memcpy(tz->location.comments, *tzf, comments_len);
462
5.77k
  tz->location.comments[comments_len] = '\0';
463
5.77k
  *tzf += comments_len;
464
5.77k
}
465
466
static void set_default_location_and_comments(const unsigned char **tzf, timelib_tzinfo *tz)
467
0
{
468
0
  tz->location.latitude = 0;
469
0
  tz->location.longitude = 0;
470
0
  tz->location.comments = timelib_malloc(2);
471
0
  tz->location.comments[0] = '?';
472
0
  tz->location.comments[1] = '\0';
473
0
}
474
475
static char *format_ut_time(timelib_sll ts, timelib_tzinfo *tz)
476
0
{
477
0
  char *tmp = timelib_calloc(1, 64);
478
0
  timelib_time *t = timelib_time_ctor();
479
480
0
  timelib_unixtime2gmt(t, ts);
481
0
  snprintf(
482
0
    tmp, 64,
483
0
    "%04lld-%02lld-%02lld %02lld:%02lld:%02lld UT",
484
0
    t->y, t->m, t->d,
485
0
    t->h, t->i, t->s
486
0
  );
487
488
0
  timelib_time_dtor(t);
489
0
  return tmp;
490
0
}
491
492
static char *format_offset_type(timelib_tzinfo *tz, int i)
493
0
{
494
0
  char *tmp = timelib_calloc(1, 64);
495
496
0
  snprintf(
497
0
    tmp, 64,
498
0
    "%3d [%6ld %1d %3d '%s' (%d,%d)]",
499
0
    i,
500
0
    (long int) tz->type[i].offset,
501
0
    tz->type[i].isdst,
502
0
    tz->type[i].abbr_idx,
503
0
    &tz->timezone_abbr[tz->type[i].abbr_idx],
504
0
    tz->type[i].isstdcnt,
505
0
    tz->type[i].isgmtcnt
506
0
  );
507
508
0
  return tmp;
509
0
}
510
511
void timelib_dump_tzinfo(timelib_tzinfo *tz)
512
0
{
513
0
  uint32_t  i;
514
0
  char     *date_str, *trans_str;
515
516
0
  printf("Country Code:      %s\n", tz->location.country_code);
517
0
  printf("Geo Location:      %f,%f\n", tz->location.latitude, tz->location.longitude);
518
0
  printf("Comments:\n%s\n",          tz->location.comments);
519
0
  printf("BC:                %s\n",  tz->bc ? "no" : "yes");
520
0
  printf("Slim File:         %s\n",  detect_slim_file(tz) ? "yes" : "no");
521
522
0
  printf("\n64-bit:\n");
523
0
  printf("UTC/Local count:   " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit64.ttisgmtcnt);
524
0
  printf("Std/Wall count:    " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit64.ttisstdcnt);
525
0
  printf("Leap.sec. count:   " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit64.leapcnt);
526
0
  printf("Trans. count:      " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit64.timecnt);
527
0
  printf("Local types count: " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit64.typecnt);
528
0
  printf("Zone Abbr. count:  " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit64.charcnt);
529
530
0
  trans_str = format_offset_type(tz, 0);
531
0
  printf("%22s (%20s) = %s\n", "", "", trans_str);
532
0
  timelib_free(trans_str);
533
534
0
  for (i = 0; i < tz->bit64.timecnt; i++) {
535
0
    date_str = format_ut_time(tz->trans[i], tz);
536
0
    trans_str = format_offset_type(tz, tz->trans_idx[i]);
537
0
    printf(
538
0
      "%s (%20" PRId64 ") = %s\n",
539
0
      date_str,
540
0
      tz->trans[i],
541
0
      trans_str
542
0
    );
543
0
    timelib_free(date_str);
544
0
    timelib_free(trans_str);
545
0
  }
546
0
  for (i = 0; i < tz->bit64.leapcnt; i++) {
547
0
    date_str = format_ut_time(tz->leap_times[i].trans, tz);
548
0
    printf (
549
0
      "%s (%20ld) = %d\n",
550
0
      date_str,
551
0
      (long) tz->leap_times[i].trans,
552
0
      tz->leap_times[i].offset
553
0
    );
554
0
    timelib_free(date_str);
555
0
  }
556
557
0
  if (!tz->posix_string) {
558
0
    printf("\n%43sNo POSIX string\n", "");
559
0
    return;
560
0
  }
561
562
0
  if (strcmp("", tz->posix_string) == 0) {
563
0
    printf("\n%43sEmpty POSIX string\n", "");
564
0
    return;
565
0
  }
566
567
0
  printf("\n%43sPOSIX string: %s\n", "", tz->posix_string);
568
0
  if (tz->posix_info && tz->posix_info->std) {
569
0
    trans_str = format_offset_type(tz, tz->posix_info->type_index_std_type);
570
0
    printf("%43sstd: %s\n", "", trans_str);
571
0
    timelib_free(trans_str);
572
573
0
    if (tz->posix_info->dst) {
574
0
      trans_str = format_offset_type(tz, tz->posix_info->type_index_dst_type);
575
0
      printf("%43sdst: %s\n", "", trans_str);
576
0
      timelib_free(trans_str);
577
0
    }
578
0
  }
579
0
}
580
581
static int seek_to_tz_position(const unsigned char **tzf, const char *timezone, const timelib_tzdb *tzdb)
582
272k
{
583
272k
  int left = 0, right = tzdb->index_size - 1;
584
585
272k
  if (tzdb->index_size == 0) {
586
0
    return 0;
587
0
  }
588
589
2.55M
  do {
590
2.55M
    int mid = ((unsigned)left + right) >> 1;
591
2.55M
    int cmp = timelib_strcasecmp(timezone, tzdb->index[mid].id);
592
593
2.55M
    if (cmp < 0) {
594
1.06M
      right = mid - 1;
595
1.49M
    } else if (cmp > 0) {
596
1.48M
      left = mid + 1;
597
1.48M
    } else { /* (cmp == 0) */
598
5.79k
      (*tzf) = &(tzdb->data[tzdb->index[mid].pos]);
599
5.79k
      return 1;
600
5.79k
    }
601
602
2.55M
  } while (left <= right);
603
604
266k
  return 0;
605
272k
}
606
607
const timelib_tzdb *timelib_builtin_db(void)
608
440k
{
609
440k
  return &timezonedb_builtin;
610
440k
}
611
612
const timelib_tzdb_index_entry *timelib_timezone_identifiers_list(const timelib_tzdb *tzdb, int *count)
613
3
{
614
3
  *count = tzdb->index_size;
615
3
  return tzdb->index;
616
3
}
617
618
int timelib_timezone_id_is_valid(const char *timezone, const timelib_tzdb *tzdb)
619
19
{
620
19
  const unsigned char *tzf;
621
19
  return (seek_to_tz_position(&tzf, timezone, tzdb));
622
19
}
623
624
static int skip_64bit_preamble(const unsigned char **tzf, timelib_tzinfo *tz)
625
5.77k
{
626
5.77k
  if (memcmp(*tzf, "TZif2", 5) == 0) {
627
5.77k
    *tzf += 20;
628
5.77k
    return 1;
629
5.77k
  } else if (memcmp(*tzf, "TZif3", 5) == 0) {
630
0
    *tzf += 20;
631
0
    return 1;
632
0
  } else if (memcmp(*tzf, "TZif4", 5) == 0) {
633
0
    *tzf += 20;
634
0
    return 1;
635
0
  } else {
636
0
    return 0;
637
0
  }
638
5.77k
}
639
640
static void read_64bit_header(const unsigned char **tzf, timelib_tzinfo *tz)
641
5.77k
{
642
5.77k
  uint32_t buffer[6];
643
644
5.77k
  memcpy(&buffer, *tzf, sizeof(buffer));
645
5.77k
  tz->bit64.ttisgmtcnt = timelib_conv_int_unsigned(buffer[0]);
646
5.77k
  tz->bit64.ttisstdcnt = timelib_conv_int_unsigned(buffer[1]);
647
5.77k
  tz->bit64.leapcnt    = timelib_conv_int_unsigned(buffer[2]);
648
5.77k
  tz->bit64.timecnt    = timelib_conv_int_unsigned(buffer[3]);
649
5.77k
  tz->bit64.typecnt    = timelib_conv_int_unsigned(buffer[4]);
650
5.77k
  tz->bit64.charcnt    = timelib_conv_int_unsigned(buffer[5]);
651
5.77k
  *tzf += sizeof(buffer);
652
5.77k
}
653
654
static timelib_tzinfo* timelib_tzinfo_ctor(const char *name)
655
5.77k
{
656
5.77k
  timelib_tzinfo *t;
657
5.77k
  t = timelib_calloc(1, sizeof(timelib_tzinfo));
658
5.77k
  t->name = timelib_strdup(name);
659
660
5.77k
  return t;
661
5.77k
}
662
663
timelib_tzinfo *timelib_parse_tzfile(const char *timezone, const timelib_tzdb *tzdb, int *error_code)
664
272k
{
665
272k
  const unsigned char *tzf;
666
272k
  timelib_tzinfo *tmp;
667
272k
  int version;
668
272k
  int transitions_result, types_result;
669
272k
  unsigned int type = TIMELIB_TZINFO_ZONEINFO; /* TIMELIB_TZINFO_PHP or TIMELIB_TZINFO_ZONEINFO */
670
671
272k
  *error_code = TIMELIB_ERROR_NO_ERROR;
672
673
272k
  if (seek_to_tz_position(&tzf, timezone, tzdb)) {
674
5.77k
    tmp = timelib_tzinfo_ctor(timezone);
675
676
5.77k
    version = read_preamble(&tzf, tmp, &type);
677
5.77k
    if (version < 2 || version > 4) {
678
0
      *error_code = TIMELIB_ERROR_UNSUPPORTED_VERSION;
679
0
      timelib_tzinfo_dtor(tmp);
680
0
      return NULL;
681
0
    }
682
//printf("- timezone: %s, version: %0d\n", timezone, version);
683
684
5.77k
    read_32bit_header(&tzf, tmp);
685
5.77k
    skip_32bit_transitions(&tzf, tmp);
686
5.77k
    skip_32bit_types(&tzf, tmp);
687
688
5.77k
    if (!skip_64bit_preamble(&tzf, tmp)) {
689
      /* 64 bit preamble is not in place */
690
0
      *error_code = TIMELIB_ERROR_CORRUPT_NO_64BIT_PREAMBLE;
691
0
      timelib_tzinfo_dtor(tmp);
692
0
      return NULL;
693
0
    }
694
5.77k
    read_64bit_header(&tzf, tmp);
695
5.77k
    if ((transitions_result = read_64bit_transitions(&tzf, tmp)) != 0) {
696
      /* Corrupt file as transitions do not increase */
697
0
      *error_code = transitions_result;
698
0
      timelib_tzinfo_dtor(tmp);
699
0
      return NULL;
700
0
    }
701
5.77k
    if ((types_result = read_64bit_types(&tzf, tmp)) != 0) {
702
0
      *error_code = types_result;
703
0
      timelib_tzinfo_dtor(tmp);
704
0
      return NULL;
705
0
    }
706
707
5.77k
    read_posix_string(&tzf, tmp);
708
5.77k
    if (strcmp("", tmp->posix_string) == 0) {
709
0
      *error_code = TIMELIB_ERROR_EMPTY_POSIX_STRING;
710
5.77k
    } else if (!integrate_posix_string(tmp)) {
711
0
      *error_code = TIMELIB_ERROR_CORRUPT_POSIX_STRING;
712
0
      timelib_tzinfo_dtor(tmp);
713
0
      return NULL;
714
0
    }
715
716
5.77k
    if (type == TIMELIB_TZINFO_PHP) {
717
5.77k
      read_location(&tzf, tmp);
718
5.77k
    } else {
719
0
      set_default_location_and_comments(&tzf, tmp);
720
0
    }
721
266k
  } else {
722
266k
    *error_code = TIMELIB_ERROR_NO_SUCH_TIMEZONE;
723
266k
    tmp = NULL;
724
266k
  }
725
726
272k
  return tmp;
727
272k
}
728
729
void timelib_tzinfo_dtor(timelib_tzinfo *tz)
730
5.77k
{
731
5.77k
  TIMELIB_TIME_FREE(tz->name);
732
5.77k
  TIMELIB_TIME_FREE(tz->trans);
733
5.77k
  TIMELIB_TIME_FREE(tz->trans_idx);
734
5.77k
  TIMELIB_TIME_FREE(tz->type);
735
5.77k
  TIMELIB_TIME_FREE(tz->timezone_abbr);
736
5.77k
  TIMELIB_TIME_FREE(tz->leap_times);
737
5.77k
  TIMELIB_TIME_FREE(tz->location.comments);
738
5.77k
  TIMELIB_TIME_FREE(tz->posix_string);
739
5.77k
  if (tz->posix_info) {
740
5.77k
    timelib_posix_str_dtor(tz->posix_info);
741
5.77k
  }
742
5.77k
  TIMELIB_TIME_FREE(tz);
743
5.77k
  tz = NULL;
744
5.77k
}
745
746
timelib_tzinfo *timelib_tzinfo_clone(timelib_tzinfo *tz)
747
0
{
748
0
  timelib_tzinfo *tmp = timelib_tzinfo_ctor(tz->name);
749
0
  tmp->_bit32.ttisgmtcnt = tz->_bit32.ttisgmtcnt;
750
0
  tmp->_bit32.ttisstdcnt = tz->_bit32.ttisstdcnt;
751
0
  tmp->_bit32.leapcnt = tz->_bit32.leapcnt;
752
0
  tmp->_bit32.timecnt = tz->_bit32.timecnt;
753
0
  tmp->_bit32.typecnt = tz->_bit32.typecnt;
754
0
  tmp->_bit32.charcnt = tz->_bit32.charcnt;
755
0
  tmp->bit64.ttisgmtcnt = tz->bit64.ttisgmtcnt;
756
0
  tmp->bit64.ttisstdcnt = tz->bit64.ttisstdcnt;
757
0
  tmp->bit64.leapcnt = tz->bit64.leapcnt;
758
0
  tmp->bit64.timecnt = tz->bit64.timecnt;
759
0
  tmp->bit64.typecnt = tz->bit64.typecnt;
760
0
  tmp->bit64.charcnt = tz->bit64.charcnt;
761
762
0
  if (tz->bit64.timecnt) {
763
0
    tmp->trans = (int64_t *) timelib_malloc(tz->bit64.timecnt * sizeof(int64_t));
764
0
    tmp->trans_idx = (unsigned char*) timelib_malloc(tz->bit64.timecnt * sizeof(unsigned char));
765
0
    memcpy(tmp->trans, tz->trans, tz->bit64.timecnt * sizeof(int64_t));
766
0
    memcpy(tmp->trans_idx, tz->trans_idx, tz->bit64.timecnt * sizeof(unsigned char));
767
0
  }
768
769
0
  tmp->type = (ttinfo*) timelib_malloc(tz->bit64.typecnt * sizeof(ttinfo));
770
0
  memcpy(tmp->type, tz->type, tz->bit64.typecnt * sizeof(ttinfo));
771
772
0
  tmp->timezone_abbr = (char*) timelib_malloc(tz->bit64.charcnt);
773
0
  memcpy(tmp->timezone_abbr, tz->timezone_abbr, tz->bit64.charcnt);
774
775
0
  if (tz->bit64.leapcnt) {
776
0
    tmp->leap_times = (tlinfo*) timelib_malloc(tz->bit64.leapcnt * sizeof(tlinfo));
777
0
    memcpy(tmp->leap_times, tz->leap_times, tz->bit64.leapcnt * sizeof(tlinfo));
778
0
  }
779
780
0
  if (tz->posix_string) {
781
0
    tmp->posix_string = timelib_strdup(tz->posix_string);
782
0
  }
783
784
0
  return tmp;
785
0
}
786
787
/**
788
 * Algorithm From RFC 8536, Section 3.2
789
 * https://tools.ietf.org/html/rfc8536#section-3.2
790
 */
791
ttinfo* timelib_fetch_timezone_offset(timelib_tzinfo *tz, timelib_sll ts, timelib_sll *transition_time)
792
5.53k
{
793
5.53k
  uint32_t left, right;
794
795
  /* RFC 8536: If there are no transitions, local time for all timestamps is specified
796
   * by the TZ string in the footer if present and nonempty; otherwise, it is specified
797
   * by time type 0.
798
   *
799
   * timelib: If there is also no time type 0, return NULL.
800
   */
801
5.53k
  if (!tz->bit64.timecnt || !tz->trans) {
802
5.49k
    if (tz->posix_info) {
803
5.49k
      *transition_time = INT64_MIN;
804
5.49k
      return timelib_fetch_posix_timezone_offset(tz, ts, NULL);
805
5.49k
    }
806
807
0
    if (tz->bit64.typecnt == 1) {
808
0
      *transition_time = INT64_MIN;
809
0
      return &(tz->type[0]);
810
0
    }
811
0
    return NULL;
812
0
  }
813
814
  /* RFC 8536: Local time for timestamps before the first transition is specified by
815
   * the first time type (time type 0). */
816
40
  if (ts < tz->trans[0]) {
817
5
    *transition_time = INT64_MIN;
818
5
    return &(tz->type[0]);
819
5
  }
820
821
  /* RFC 8536: Local time for timestamps on or after the last transition is specified
822
   * by the TZ string in the footer (Section 3.3) if present and nonempty; otherwise,
823
   * it is unspecified.
824
   *
825
   * timelib: For 'unspecified', timelib assumes the last transition
826
   */
827
35
  if (ts >= tz->trans[tz->bit64.timecnt - 1]) {
828
35
    if (tz->posix_info) {
829
35
      return timelib_fetch_posix_timezone_offset(tz, ts, transition_time);
830
35
    }
831
832
0
    *transition_time = tz->trans[tz->bit64.timecnt - 1];
833
0
    return &(tz->type[tz->trans_idx[tz->bit64.timecnt - 1]]);
834
35
  }
835
836
  /* RFC 8536: The type corresponding to a transition time specifies local time for
837
   * timestamps starting at the given transition time and continuing up to, but not
838
   * including, the next transition time. */
839
0
  left = 0;
840
0
  right = tz->bit64.timecnt - 1;
841
842
0
  while (right - left > 1) {
843
0
    uint32_t mid = (left + right) >> 1;
844
845
0
    if (ts < tz->trans[mid]) {
846
0
      right = mid;
847
0
    } else {
848
0
      left = mid;
849
0
    }
850
0
  }
851
0
  *transition_time = tz->trans[left];
852
0
  return &(tz->type[tz->trans_idx[left]]);
853
35
}
854
855
static tlinfo* fetch_leaptime_offset(timelib_tzinfo *tz, timelib_sll ts)
856
4.66k
{
857
4.66k
  int i;
858
859
4.66k
  if (!tz->bit64.leapcnt || !tz->leap_times) {
860
4.66k
    return NULL;
861
4.66k
  }
862
863
0
  for (i = tz->bit64.leapcnt - 1; i > 0; i--) {
864
0
    if (ts > tz->leap_times[i].trans) {
865
0
      return &(tz->leap_times[i]);
866
0
    }
867
0
  }
868
0
  return NULL;
869
0
}
870
871
int timelib_timestamp_is_in_dst(timelib_sll ts, timelib_tzinfo *tz)
872
0
{
873
0
  ttinfo *to;
874
0
  timelib_sll dummy;
875
876
0
  if ((to = timelib_fetch_timezone_offset(tz, ts, &dummy))) {
877
0
    return to->isdst;
878
0
  }
879
0
  return -1;
880
0
}
881
882
timelib_time_offset *timelib_get_time_zone_info(timelib_sll ts, timelib_tzinfo *tz)
883
4.66k
{
884
4.66k
  ttinfo *to;
885
4.66k
  tlinfo *tl;
886
4.66k
  int32_t offset = 0, leap_secs = 0;
887
4.66k
  char *abbr;
888
4.66k
  timelib_time_offset *tmp = timelib_time_offset_ctor();
889
4.66k
  timelib_sll                transition_time;
890
891
4.66k
  if ((to = timelib_fetch_timezone_offset(tz, ts, &transition_time))) {
892
4.66k
    offset = to->offset;
893
4.66k
    abbr = &(tz->timezone_abbr[to->abbr_idx]);
894
4.66k
    tmp->is_dst = to->isdst;
895
4.66k
    tmp->transition_time = transition_time;
896
4.66k
  } else {
897
0
    offset = 0;
898
0
    abbr = tz->timezone_abbr;
899
0
    tmp->is_dst = 0;
900
0
    tmp->transition_time = 0;
901
0
  }
902
903
4.66k
  if ((tl = fetch_leaptime_offset(tz, ts))) {
904
0
    leap_secs = -tl->offset;
905
0
  }
906
907
4.66k
  tmp->offset = offset;
908
4.66k
  tmp->leap_secs = leap_secs;
909
4.66k
  tmp->abbr = abbr ? timelib_strdup(abbr) : timelib_strdup("GMT");
910
911
4.66k
  return tmp;
912
4.66k
}
913
914
int timelib_get_time_zone_offset_info(timelib_sll ts, timelib_tzinfo *tz, int32_t* offset, timelib_sll* transition_time, unsigned int* is_dst)
915
865
{
916
865
  ttinfo *to;
917
865
  timelib_sll tmp_transition_time;
918
919
865
  if (tz == NULL) {
920
0
    return 0;
921
0
  }
922
923
865
  if ((to = timelib_fetch_timezone_offset(tz, ts, &tmp_transition_time))) {
924
865
    if (offset) {
925
865
      *offset = to->offset;
926
865
    }
927
865
    if (is_dst) {
928
289
      *is_dst = to->isdst;
929
289
    }
930
865
    if (transition_time) {
931
583
      *transition_time = tmp_transition_time;
932
583
    }
933
865
    return 1;
934
865
  }
935
0
  return 0;
936
865
}
937
938
timelib_sll timelib_get_current_offset(timelib_time *t)
939
0
{
940
0
  switch (t->zone_type) {
941
0
    case TIMELIB_ZONETYPE_ABBR:
942
0
    case TIMELIB_ZONETYPE_OFFSET:
943
0
      return t->z + (t->dst * 3600);
944
945
0
    case TIMELIB_ZONETYPE_ID: {
946
0
      int32_t      offset = 0;
947
0
      timelib_get_time_zone_offset_info(t->sse, t->tz_info, &offset, NULL, NULL);
948
0
      return offset;
949
0
    }
950
951
0
    default:
952
0
      return 0;
953
0
  }
954
0
}
955
956
int timelib_same_timezone(timelib_time *one, timelib_time *two)
957
10
{
958
10
    if (one->zone_type != two->zone_type) {
959
0
        return 0;
960
0
    }
961
962
10
    if (one->zone_type == TIMELIB_ZONETYPE_ABBR || one->zone_type == TIMELIB_ZONETYPE_OFFSET) {
963
0
        if ((one->z + (one->dst * 3600)) == (two->z + (two->dst * 3600))) {
964
0
            return 1;
965
0
        }
966
0
        return 0;
967
0
    }
968
969
10
    if (one->zone_type == TIMELIB_ZONETYPE_ID && strcmp(one->tz_info->name, two->tz_info->name) == 0) {
970
10
        return 1;
971
10
    }
972
973
0
    return 0;
974
10
}