xref: /PHP-7.2/ext/date/lib/parse_tz.c (revision 5feb5396)
1 /*
2  * The MIT License (MIT)
3  *
4  * Copyright (c) 2015 Derick Rethans
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 
25 #include "timelib.h"
26 #include "timelib_private.h"
27 
28 #define TIMELIB_SUPPORTS_V2DATA
29 #include "timezonedb.h"
30 
31 #if (defined(__APPLE__) || defined(__APPLE_CC__)) && (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__))
32 # if defined(__LITTLE_ENDIAN__)
33 #  undef WORDS_BIGENDIAN
34 # else
35 #  if defined(__BIG_ENDIAN__)
36 #   define WORDS_BIGENDIAN
37 #  endif
38 # endif
39 #endif
40 
41 #if defined(__s390__)
42 # if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
43 #  define WORDS_BIGENDIAN
44 # else
45 #  undef WORDS_BIGENDIAN
46 # endif
47 #endif
48 
49 #ifdef WORDS_BIGENDIAN
timelib_conv_int_unsigned(uint32_t value)50 static inline uint32_t timelib_conv_int_unsigned(uint32_t value)
51 {
52 	return value;
53 }
54 #else
timelib_conv_int_unsigned(uint32_t value)55 static inline uint32_t timelib_conv_int_unsigned(uint32_t value)
56 {
57 	return ((value & 0x000000ff) << 24) +
58 		((value & 0x0000ff00) << 8) +
59 		((value & 0x00ff0000) >> 8) +
60 		((value & 0xff000000) >> 24);
61 }
62 #endif
63 
64 #define timelib_conv_int_signed(value) ((int32_t) timelib_conv_int_unsigned((int32_t) value))
65 
read_php_preamble(const unsigned char ** tzf,timelib_tzinfo * tz)66 static int read_php_preamble(const unsigned char **tzf, timelib_tzinfo *tz)
67 {
68 	uint32_t version;
69 
70 	/* read ID */
71 	version = (*tzf)[3] - '0';
72 	*tzf += 4;
73 
74 	/* read BC flag */
75 	tz->bc = (**tzf == '\1');
76 	*tzf += 1;
77 
78 	/* read country code */
79 	memcpy(tz->location.country_code, *tzf, 2);
80 	tz->location.country_code[2] = '\0';
81 	*tzf += 2;
82 
83 	/* skip rest of preamble */
84 	*tzf += 13;
85 
86 	return version;
87 }
88 
read_tzif_preamble(const unsigned char ** tzf,timelib_tzinfo * tz)89 static int read_tzif_preamble(const unsigned char **tzf, timelib_tzinfo *tz)
90 {
91 	uint32_t version;
92 
93 	/* read ID */
94 	switch ((*tzf)[4]) {
95 		case '\0':
96 			version = 0;
97 			break;
98 		case '2':
99 			version = 2;
100 			break;
101 		case '3':
102 			version = 3;
103 			break;
104 		default:
105 			return -1;
106 	}
107 	*tzf += 5;
108 
109 	/* set BC flag and country code to default */
110 	tz->bc = 0;
111 	tz->location.country_code[0] = '?';
112 	tz->location.country_code[1] = '?';
113 	tz->location.country_code[2] = '\0';
114 
115 	/* skip rest of preamble */
116 	*tzf += 15;
117 
118 	return version;
119 }
120 
read_preamble(const unsigned char ** tzf,timelib_tzinfo * tz,unsigned int * type)121 static int read_preamble(const unsigned char **tzf, timelib_tzinfo *tz, unsigned int *type)
122 {
123 	/* read marker (TZif) or (PHP) */
124 	if (memcmp(*tzf, "PHP", 3) == 0) {
125 		*type = TIMELIB_TZINFO_PHP;
126 		return read_php_preamble(tzf, tz);
127 	} else if (memcmp(*tzf, "TZif", 4) == 0) {
128 		*type = TIMELIB_TZINFO_ZONEINFO;
129 		return read_tzif_preamble(tzf, tz);
130 	} else {
131 		return -1;
132 	}
133 }
134 
read_header(const unsigned char ** tzf,timelib_tzinfo * tz)135 static void read_header(const unsigned char **tzf, timelib_tzinfo *tz)
136 {
137 	uint32_t buffer[6];
138 
139 	memcpy(&buffer, *tzf, sizeof(buffer));
140 	tz->bit32.ttisgmtcnt = timelib_conv_int_unsigned(buffer[0]);
141 	tz->bit32.ttisstdcnt = timelib_conv_int_unsigned(buffer[1]);
142 	tz->bit32.leapcnt    = timelib_conv_int_unsigned(buffer[2]);
143 	tz->bit32.timecnt    = timelib_conv_int_unsigned(buffer[3]);
144 	tz->bit32.typecnt    = timelib_conv_int_unsigned(buffer[4]);
145 	tz->bit32.charcnt    = timelib_conv_int_unsigned(buffer[5]);
146 	*tzf += sizeof(buffer);
147 }
148 
skip_64bit_transitions(const unsigned char ** tzf,timelib_tzinfo * tz)149 static void skip_64bit_transitions(const unsigned char **tzf, timelib_tzinfo *tz)
150 {
151 	if (tz->bit64.timecnt) {
152 		*tzf += (sizeof(int64_t) * tz->bit64.timecnt);
153 		*tzf += (sizeof(unsigned char) * tz->bit64.timecnt);
154 	}
155 }
156 
read_transitions(const unsigned char ** tzf,timelib_tzinfo * tz)157 static int read_transitions(const unsigned char **tzf, timelib_tzinfo *tz)
158 {
159 	int32_t *buffer = NULL;
160 	uint32_t i;
161 	unsigned char *cbuffer = NULL;
162 
163 	if (tz->bit32.timecnt) {
164 		buffer = (int32_t*) timelib_malloc(tz->bit32.timecnt * sizeof(int32_t));
165 		if (!buffer) {
166 			return TIMELIB_ERROR_CANNOT_ALLOCATE;
167 		}
168 		memcpy(buffer, *tzf, sizeof(int32_t) * tz->bit32.timecnt);
169 		*tzf += (sizeof(int32_t) * tz->bit32.timecnt);
170 		for (i = 0; i < tz->bit32.timecnt; i++) {
171 			buffer[i] = timelib_conv_int_signed(buffer[i]);
172 			/* Sanity check to see whether TS is just increasing */
173 			if (i > 0 && !(buffer[i] > buffer[i - 1])) {
174 				return TIMELIB_ERROR_CORRUPT_TRANSITIONS_DONT_INCREASE;
175 			}
176 		}
177 
178 		cbuffer = (unsigned char*) timelib_malloc(tz->bit32.timecnt * sizeof(unsigned char));
179 		if (!cbuffer) {
180 			timelib_free(buffer);
181 			return TIMELIB_ERROR_CANNOT_ALLOCATE;
182 		}
183 		memcpy(cbuffer, *tzf, sizeof(unsigned char) * tz->bit32.timecnt);
184 		*tzf += sizeof(unsigned char) * tz->bit32.timecnt;
185 	}
186 
187 	tz->trans = buffer;
188 	tz->trans_idx = cbuffer;
189 
190 	return 0;
191 }
192 
skip_64bit_types(const unsigned char ** tzf,timelib_tzinfo * tz)193 static void skip_64bit_types(const unsigned char **tzf, timelib_tzinfo *tz)
194 {
195 	*tzf += sizeof(unsigned char) * 6 * tz->bit64.typecnt;
196 	*tzf += sizeof(char) * tz->bit64.charcnt;
197 	if (tz->bit64.leapcnt) {
198 		*tzf += sizeof(int64_t) * tz->bit64.leapcnt * 2;
199 	}
200 	if (tz->bit64.ttisstdcnt) {
201 		*tzf += sizeof(unsigned char) * tz->bit64.ttisstdcnt;
202 	}
203 	if (tz->bit64.ttisgmtcnt) {
204 		*tzf += sizeof(unsigned char) * tz->bit64.ttisgmtcnt;
205 	}
206 }
207 
read_types(const unsigned char ** tzf,timelib_tzinfo * tz)208 static int read_types(const unsigned char **tzf, timelib_tzinfo *tz)
209 {
210 	unsigned char *buffer;
211 	int32_t *leap_buffer;
212 	unsigned int i, j;
213 
214 	buffer = (unsigned char*) timelib_malloc(tz->bit32.typecnt * sizeof(unsigned char) * 6);
215 	if (!buffer) {
216 		return TIMELIB_ERROR_CANNOT_ALLOCATE;
217 	}
218 	memcpy(buffer, *tzf, sizeof(unsigned char) * 6 * tz->bit32.typecnt);
219 	*tzf += sizeof(unsigned char) * 6 * tz->bit32.typecnt;
220 
221 	tz->type = (ttinfo*) timelib_malloc(tz->bit32.typecnt * sizeof(ttinfo));
222 	if (!tz->type) {
223 		timelib_free(buffer);
224 		return TIMELIB_ERROR_CANNOT_ALLOCATE;
225 	}
226 
227 	for (i = 0; i < tz->bit32.typecnt; i++) {
228 		j = i * 6;
229 		tz->type[i].offset = 0;
230 		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];
231 		tz->type[i].isdst = buffer[j + 4];
232 		tz->type[i].abbr_idx = buffer[j + 5];
233 	}
234 	timelib_free(buffer);
235 
236 	tz->timezone_abbr = (char*) timelib_malloc(tz->bit32.charcnt);
237 	if (!tz->timezone_abbr) {
238 		return TIMELIB_ERROR_CORRUPT_NO_ABBREVIATION;
239 	}
240 	memcpy(tz->timezone_abbr, *tzf, sizeof(char) * tz->bit32.charcnt);
241 	*tzf += sizeof(char) * tz->bit32.charcnt;
242 
243 	if (tz->bit32.leapcnt) {
244 		leap_buffer = (int32_t *) timelib_malloc(tz->bit32.leapcnt * 2 * sizeof(int32_t));
245 		if (!leap_buffer) {
246 			return TIMELIB_ERROR_CANNOT_ALLOCATE;
247 		}
248 		memcpy(leap_buffer, *tzf, sizeof(int32_t) * tz->bit32.leapcnt * 2);
249 		*tzf += sizeof(int32_t) * tz->bit32.leapcnt * 2;
250 
251 		tz->leap_times = (tlinfo*) timelib_malloc(tz->bit32.leapcnt * sizeof(tlinfo));
252 		if (!tz->leap_times) {
253 			timelib_free(leap_buffer);
254 			return TIMELIB_ERROR_CANNOT_ALLOCATE;
255 		}
256 		for (i = 0; i < tz->bit32.leapcnt; i++) {
257 			tz->leap_times[i].trans = timelib_conv_int_signed(leap_buffer[i * 2]);
258 			tz->leap_times[i].offset = timelib_conv_int_signed(leap_buffer[i * 2 + 1]);
259 		}
260 		timelib_free(leap_buffer);
261 	}
262 
263 	if (tz->bit32.ttisstdcnt) {
264 		buffer = (unsigned char*) timelib_malloc(tz->bit32.ttisstdcnt * sizeof(unsigned char));
265 		if (!buffer) {
266 			return TIMELIB_ERROR_CANNOT_ALLOCATE;
267 		}
268 		memcpy(buffer, *tzf, sizeof(unsigned char) * tz->bit32.ttisstdcnt);
269 		*tzf += sizeof(unsigned char) * tz->bit32.ttisstdcnt;
270 
271 		for (i = 0; i < tz->bit32.ttisstdcnt; i++) {
272 			tz->type[i].isstdcnt = buffer[i];
273 		}
274 		timelib_free(buffer);
275 	}
276 
277 	if (tz->bit32.ttisgmtcnt) {
278 		buffer = (unsigned char*) timelib_malloc(tz->bit32.ttisgmtcnt * sizeof(unsigned char));
279 		if (!buffer) {
280 			return TIMELIB_ERROR_CANNOT_ALLOCATE;
281 		}
282 		memcpy(buffer, *tzf, sizeof(unsigned char) * tz->bit32.ttisgmtcnt);
283 		*tzf += sizeof(unsigned char) * tz->bit32.ttisgmtcnt;
284 
285 		for (i = 0; i < tz->bit32.ttisgmtcnt; i++) {
286 			tz->type[i].isgmtcnt = buffer[i];
287 		}
288 		timelib_free(buffer);
289 	}
290 
291 	return 0;
292 }
293 
skip_posix_string(const unsigned char ** tzf,timelib_tzinfo * tz)294 static void skip_posix_string(const unsigned char **tzf, timelib_tzinfo *tz)
295 {
296 	int n_count = 0;
297 
298 	do {
299 		if (*tzf[0] == '\n') {
300 			n_count++;
301 		}
302 		(*tzf)++;
303 	} while (n_count < 2);
304 }
305 
read_location(const unsigned char ** tzf,timelib_tzinfo * tz)306 static void read_location(const unsigned char **tzf, timelib_tzinfo *tz)
307 {
308 	uint32_t buffer[3];
309 	uint32_t comments_len;
310 
311 	memcpy(&buffer, *tzf, sizeof(buffer));
312 	tz->location.latitude = timelib_conv_int_unsigned(buffer[0]);
313 	tz->location.latitude = (tz->location.latitude / 100000) - 90;
314 	tz->location.longitude = timelib_conv_int_unsigned(buffer[1]);
315 	tz->location.longitude = (tz->location.longitude / 100000) - 180;
316 	comments_len = timelib_conv_int_unsigned(buffer[2]);
317 	*tzf += sizeof(buffer);
318 
319 	tz->location.comments = timelib_malloc(comments_len + 1);
320 	memcpy(tz->location.comments, *tzf, comments_len);
321 	tz->location.comments[comments_len] = '\0';
322 	*tzf += comments_len;
323 }
324 
set_default_location_and_comments(const unsigned char ** tzf,timelib_tzinfo * tz)325 static void set_default_location_and_comments(const unsigned char **tzf, timelib_tzinfo *tz)
326 {
327 	tz->location.latitude = 0;
328 	tz->location.longitude = 0;
329 	tz->location.comments = timelib_malloc(2);
330 	tz->location.comments[0] = '?';
331 	tz->location.comments[1] = '\0';
332 }
333 
timelib_dump_tzinfo(timelib_tzinfo * tz)334 void timelib_dump_tzinfo(timelib_tzinfo *tz)
335 {
336 	uint32_t i;
337 
338 	printf("Country Code:      %s\n", tz->location.country_code);
339 	printf("Geo Location:      %f,%f\n", tz->location.latitude, tz->location.longitude);
340 	printf("Comments:\n%s\n",          tz->location.comments);
341 	printf("BC:                %s\n",  tz->bc ? "" : "yes");
342 	printf("UTC/Local count:   " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit32.ttisgmtcnt);
343 	printf("Std/Wall count:    " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit32.ttisstdcnt);
344 	printf("Leap.sec. count:   " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit32.leapcnt);
345 	printf("Trans. count:      " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit32.timecnt);
346 	printf("Local types count: " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit32.typecnt);
347 	printf("Zone Abbr. count:  " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit32.charcnt);
348 
349 	printf ("%8s (%12s) = %3d [%5ld %1d %3d '%s' (%d,%d)]\n",
350 		"", "", 0,
351 		(long int) tz->type[0].offset,
352 		tz->type[0].isdst,
353 		tz->type[0].abbr_idx,
354 		&tz->timezone_abbr[tz->type[0].abbr_idx],
355 		tz->type[0].isstdcnt,
356 		tz->type[0].isgmtcnt
357 		);
358 	for (i = 0; i < tz->bit32.timecnt; i++) {
359 		printf ("%08X (%12d) = %3d [%5ld %1d %3d '%s' (%d,%d)]\n",
360 			tz->trans[i], tz->trans[i], tz->trans_idx[i],
361 			(long int) tz->type[tz->trans_idx[i]].offset,
362 			tz->type[tz->trans_idx[i]].isdst,
363 			tz->type[tz->trans_idx[i]].abbr_idx,
364 			&tz->timezone_abbr[tz->type[tz->trans_idx[i]].abbr_idx],
365 			tz->type[tz->trans_idx[i]].isstdcnt,
366 			tz->type[tz->trans_idx[i]].isgmtcnt
367 			);
368 	}
369 	for (i = 0; i < tz->bit32.leapcnt; i++) {
370 		printf ("%08X (%12ld) = %d\n",
371 			tz->leap_times[i].trans,
372 			(long) tz->leap_times[i].trans,
373 			tz->leap_times[i].offset);
374 	}
375 }
376 
seek_to_tz_position(const unsigned char ** tzf,char * timezone,const timelib_tzdb * tzdb)377 static int seek_to_tz_position(const unsigned char **tzf, char *timezone, const timelib_tzdb *tzdb)
378 {
379 	int left = 0, right = tzdb->index_size - 1;
380 
381 	if (tzdb->index_size == 0) {
382 		return 0;
383 	}
384 
385 	do {
386 		int mid = ((unsigned)left + right) >> 1;
387 		int cmp = timelib_strcasecmp(timezone, tzdb->index[mid].id);
388 
389 		if (cmp < 0) {
390 			right = mid - 1;
391 		} else if (cmp > 0) {
392 			left = mid + 1;
393 		} else { /* (cmp == 0) */
394 			(*tzf) = &(tzdb->data[tzdb->index[mid].pos]);
395 			return 1;
396 		}
397 
398 	} while (left <= right);
399 
400 	return 0;
401 }
402 
timelib_builtin_db(void)403 const timelib_tzdb *timelib_builtin_db(void)
404 {
405 	return &timezonedb_builtin;
406 }
407 
timelib_timezone_identifiers_list(const timelib_tzdb * tzdb,int * count)408 const timelib_tzdb_index_entry *timelib_timezone_identifiers_list(const timelib_tzdb *tzdb, int *count)
409 {
410 	*count = tzdb->index_size;
411 	return tzdb->index;
412 }
413 
timelib_timezone_id_is_valid(char * timezone,const timelib_tzdb * tzdb)414 int timelib_timezone_id_is_valid(char *timezone, const timelib_tzdb *tzdb)
415 {
416 	const unsigned char *tzf;
417 	return (seek_to_tz_position(&tzf, timezone, tzdb));
418 }
419 
skip_64bit_preamble(const unsigned char ** tzf,timelib_tzinfo * tz)420 static int skip_64bit_preamble(const unsigned char **tzf, timelib_tzinfo *tz)
421 {
422 	if (memcmp(*tzf, "TZif2", 5) == 0) {
423 		*tzf += 20;
424 		return 1;
425 	} else if (memcmp(*tzf, "TZif3", 5) == 0) {
426 		*tzf += 20;
427 		return 1;
428 	} else {
429 		return 0;
430 	}
431 }
432 
read_64bit_header(const unsigned char ** tzf,timelib_tzinfo * tz)433 static void read_64bit_header(const unsigned char **tzf, timelib_tzinfo *tz)
434 {
435 	uint32_t buffer[6];
436 
437 	memcpy(&buffer, *tzf, sizeof(buffer));
438 	tz->bit64.ttisgmtcnt = timelib_conv_int_unsigned(buffer[0]);
439 	tz->bit64.ttisstdcnt = timelib_conv_int_unsigned(buffer[1]);
440 	tz->bit64.leapcnt    = timelib_conv_int_unsigned(buffer[2]);
441 	tz->bit64.timecnt    = timelib_conv_int_unsigned(buffer[3]);
442 	tz->bit64.typecnt    = timelib_conv_int_unsigned(buffer[4]);
443 	tz->bit64.charcnt    = timelib_conv_int_unsigned(buffer[5]);
444 	*tzf += sizeof(buffer);
445 }
446 
timelib_tzinfo_ctor(char * name)447 static timelib_tzinfo* timelib_tzinfo_ctor(char *name)
448 {
449 	timelib_tzinfo *t;
450 	t = timelib_calloc(1, sizeof(timelib_tzinfo));
451 	t->name = timelib_strdup(name);
452 
453 	return t;
454 }
455 
timelib_parse_tzfile(char * timezone,const timelib_tzdb * tzdb,int * error_code)456 timelib_tzinfo *timelib_parse_tzfile(char *timezone, const timelib_tzdb *tzdb, int *error_code)
457 {
458 	const unsigned char *tzf;
459 	timelib_tzinfo *tmp;
460 	int version;
461 	int transitions_result, types_result;
462 	unsigned int type; /* TIMELIB_TZINFO_PHP or TIMELIB_TZINFO_ZONEINFO */
463 
464 	if (seek_to_tz_position(&tzf, timezone, tzdb)) {
465 		tmp = timelib_tzinfo_ctor(timezone);
466 
467 		version = read_preamble(&tzf, tmp, &type);
468 		if (version == -1) {
469 			*error_code = TIMELIB_ERROR_UNSUPPORTED_VERSION;
470 			timelib_tzinfo_dtor(tmp);
471 			return NULL;
472 		}
473 //printf("- timezone: %s, version: %0d\n", timezone, version);
474 
475 		read_header(&tzf, tmp);
476 		if ((transitions_result = read_transitions(&tzf, tmp)) != 0) {
477 			/* Corrupt file as transitions do not increase */
478 			*error_code = transitions_result;
479 			timelib_tzinfo_dtor(tmp);
480 			return NULL;
481 		}
482 		if ((types_result = read_types(&tzf, tmp)) != 0) {
483 			*error_code = types_result;
484 			timelib_tzinfo_dtor(tmp);
485 			return NULL;
486 		}
487 		if (version == 2 || version == 3) {
488 			if (!skip_64bit_preamble(&tzf, tmp)) {
489 				/* 64 bit preamble is not in place */
490 				*error_code = TIMELIB_ERROR_CORRUPT_NO_64BIT_PREAMBLE;
491 				return NULL;
492 			}
493 			read_64bit_header(&tzf, tmp);
494 			skip_64bit_transitions(&tzf, tmp);
495 			skip_64bit_types(&tzf, tmp);
496 			skip_posix_string(&tzf, tmp);
497 		}
498 
499 		if (type == TIMELIB_TZINFO_PHP) {
500 			read_location(&tzf, tmp);
501 		} else {
502 			set_default_location_and_comments(&tzf, tmp);
503 		}
504 	} else {
505 		*error_code = TIMELIB_ERROR_NO_SUCH_TIMEZONE;
506 		tmp = NULL;
507 	}
508 
509 	return tmp;
510 }
511 
timelib_tzinfo_dtor(timelib_tzinfo * tz)512 void timelib_tzinfo_dtor(timelib_tzinfo *tz)
513 {
514 	TIMELIB_TIME_FREE(tz->name);
515 	TIMELIB_TIME_FREE(tz->trans);
516 	TIMELIB_TIME_FREE(tz->trans_idx);
517 	TIMELIB_TIME_FREE(tz->type);
518 	TIMELIB_TIME_FREE(tz->timezone_abbr);
519 	TIMELIB_TIME_FREE(tz->leap_times);
520 	TIMELIB_TIME_FREE(tz->location.comments);
521 	TIMELIB_TIME_FREE(tz);
522 	tz = NULL;
523 }
524 
timelib_tzinfo_clone(timelib_tzinfo * tz)525 timelib_tzinfo *timelib_tzinfo_clone(timelib_tzinfo *tz)
526 {
527 	timelib_tzinfo *tmp = timelib_tzinfo_ctor(tz->name);
528 	tmp->bit32.ttisgmtcnt = tz->bit32.ttisgmtcnt;
529 	tmp->bit32.ttisstdcnt = tz->bit32.ttisstdcnt;
530 	tmp->bit32.leapcnt = tz->bit32.leapcnt;
531 	tmp->bit32.timecnt = tz->bit32.timecnt;
532 	tmp->bit32.typecnt = tz->bit32.typecnt;
533 	tmp->bit32.charcnt = tz->bit32.charcnt;
534 
535 	if (tz->bit32.timecnt) {
536 		tmp->trans = (int32_t *) timelib_malloc(tz->bit32.timecnt * sizeof(int32_t));
537 		tmp->trans_idx = (unsigned char*) timelib_malloc(tz->bit32.timecnt * sizeof(unsigned char));
538 		memcpy(tmp->trans, tz->trans, tz->bit32.timecnt * sizeof(int32_t));
539 		memcpy(tmp->trans_idx, tz->trans_idx, tz->bit32.timecnt * sizeof(unsigned char));
540 	}
541 
542 	tmp->type = (ttinfo*) timelib_malloc(tz->bit32.typecnt * sizeof(ttinfo));
543 	memcpy(tmp->type, tz->type, tz->bit32.typecnt * sizeof(ttinfo));
544 
545 	tmp->timezone_abbr = (char*) timelib_malloc(tz->bit32.charcnt);
546 	memcpy(tmp->timezone_abbr, tz->timezone_abbr, tz->bit32.charcnt);
547 
548 	if (tz->bit32.leapcnt) {
549 		tmp->leap_times = (tlinfo*) timelib_malloc(tz->bit32.leapcnt * sizeof(tlinfo));
550 		memcpy(tmp->leap_times, tz->leap_times, tz->bit32.leapcnt * sizeof(tlinfo));
551 	}
552 
553 	return tmp;
554 }
555 
fetch_timezone_offset(timelib_tzinfo * tz,timelib_sll ts,timelib_sll * transition_time)556 static ttinfo* fetch_timezone_offset(timelib_tzinfo *tz, timelib_sll ts, timelib_sll *transition_time)
557 {
558 	uint32_t i;
559 
560 	/* If there is no transition time, we pick the first one, if that doesn't
561 	 * exist we return NULL */
562 	if (!tz->bit32.timecnt || !tz->trans) {
563 		*transition_time = 0;
564 		if (tz->bit32.typecnt == 1) {
565 			return &(tz->type[0]);
566 		}
567 		return NULL;
568 	}
569 
570 	/* If the TS is lower than the first transition time, then we scan over
571 	 * all the transition times to find the first non-DST one, or the first
572 	 * one in case there are only DST entries. Not sure which smartass came up
573 	 * with this idea in the first though :) */
574 	if (ts < tz->trans[0]) {
575 		uint32_t j;
576 
577 		*transition_time = 0;
578 		j = 0;
579 		while (j < tz->bit32.timecnt && tz->type[tz->trans_idx[j]].isdst) {
580 			++j;
581 		}
582 		if (j == tz->bit32.timecnt) {
583 			j = 0;
584 		}
585 		return &(tz->type[tz->trans_idx[j]]);
586 	}
587 
588 	/* In all other cases we loop through the available transtion times to find
589 	 * the correct entry */
590 	for (i = 0; i < tz->bit32.timecnt; i++) {
591 		if (ts < tz->trans[i]) {
592 			*transition_time = tz->trans[i - 1];
593 			return &(tz->type[tz->trans_idx[i - 1]]);
594 		}
595 	}
596 	*transition_time = tz->trans[tz->bit32.timecnt - 1];
597 	return &(tz->type[tz->trans_idx[tz->bit32.timecnt - 1]]);
598 }
599 
fetch_leaptime_offset(timelib_tzinfo * tz,timelib_sll ts)600 static tlinfo* fetch_leaptime_offset(timelib_tzinfo *tz, timelib_sll ts)
601 {
602 	int i;
603 
604 	if (!tz->bit32.leapcnt || !tz->leap_times) {
605 		return NULL;
606 	}
607 
608 	for (i = tz->bit32.leapcnt - 1; i > 0; i--) {
609 		if (ts > tz->leap_times[i].trans) {
610 			return &(tz->leap_times[i]);
611 		}
612 	}
613 	return NULL;
614 }
615 
timelib_timestamp_is_in_dst(timelib_sll ts,timelib_tzinfo * tz)616 int timelib_timestamp_is_in_dst(timelib_sll ts, timelib_tzinfo *tz)
617 {
618 	ttinfo *to;
619 	timelib_sll dummy;
620 
621 	if ((to = fetch_timezone_offset(tz, ts, &dummy))) {
622 		return to->isdst;
623 	}
624 	return -1;
625 }
626 
timelib_get_time_zone_info(timelib_sll ts,timelib_tzinfo * tz)627 timelib_time_offset *timelib_get_time_zone_info(timelib_sll ts, timelib_tzinfo *tz)
628 {
629 	ttinfo *to;
630 	tlinfo *tl;
631 	int32_t offset = 0, leap_secs = 0;
632 	char *abbr;
633 	timelib_time_offset *tmp = timelib_time_offset_ctor();
634 	timelib_sll                transition_time;
635 
636 	if ((to = fetch_timezone_offset(tz, ts, &transition_time))) {
637 		offset = to->offset;
638 		abbr = &(tz->timezone_abbr[to->abbr_idx]);
639 		tmp->is_dst = to->isdst;
640 		tmp->transition_time = transition_time;
641 	} else {
642 		offset = 0;
643 		abbr = tz->timezone_abbr;
644 		tmp->is_dst = 0;
645 		tmp->transition_time = 0;
646 	}
647 
648 	if ((tl = fetch_leaptime_offset(tz, ts))) {
649 		leap_secs = -tl->offset;
650 	}
651 
652 	tmp->offset = offset;
653 	tmp->leap_secs = leap_secs;
654 	tmp->abbr = abbr ? timelib_strdup(abbr) : timelib_strdup("GMT");
655 
656 	return tmp;
657 }
658 
timelib_get_current_offset(timelib_time * t)659 timelib_sll timelib_get_current_offset(timelib_time *t)
660 {
661 	timelib_time_offset *gmt_offset;
662 	timelib_sll retval;
663 
664 	switch (t->zone_type) {
665 		case TIMELIB_ZONETYPE_ABBR:
666 		case TIMELIB_ZONETYPE_OFFSET:
667 			return t->z + (t->dst * 3600);
668 
669 		case TIMELIB_ZONETYPE_ID:
670 			gmt_offset = timelib_get_time_zone_info(t->sse, t->tz_info);
671 			retval = gmt_offset->offset;
672 			timelib_time_offset_dtor(gmt_offset);
673 			return retval;
674 
675 		default:
676 			return 0;
677 	}
678 }
679