Coverage Report

Created: 2025-06-13 06:43

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