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