1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2007 The PHP Group |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 3.01 of the PHP license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.php.net/license/3_01.txt |
11 : | If you did not receive a copy of the PHP license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@php.net so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Authors: Derick Rethans <derick@derickrethans.nl> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: parse_tz.c,v 1.20.2.6.2.12 2007/01/25 14:38:45 tony2001 Exp $ */
20 :
21 : #include "timelib.h"
22 :
23 : #include <stdio.h>
24 :
25 : #ifdef HAVE_LOCALE_H
26 : #include <locale.h>
27 : #endif
28 :
29 : #ifdef HAVE_STRING_H
30 : #include <string.h>
31 : #else
32 : #include <strings.h>
33 : #endif
34 : #include "timezonedb.h"
35 :
36 : #ifdef WORDS_BIGENDIAN
37 : #define timelib_conv_int(l) (l)
38 : #else
39 : #define timelib_conv_int(l) ((l & 0x000000ff) << 24) + ((l & 0x0000ff00) << 8) + ((l & 0x00ff0000) >> 8) + ((l & 0xff000000) >> 24)
40 : #endif
41 :
42 : static void read_header(char **tzf, timelib_tzinfo *tz)
43 2 : {
44 : uint32_t buffer[6];
45 :
46 2 : memcpy(&buffer, *tzf, sizeof(buffer));
47 2 : tz->ttisgmtcnt = timelib_conv_int(buffer[0]);
48 2 : tz->ttisstdcnt = timelib_conv_int(buffer[1]);
49 2 : tz->leapcnt = timelib_conv_int(buffer[2]);
50 2 : tz->timecnt = timelib_conv_int(buffer[3]);
51 2 : tz->typecnt = timelib_conv_int(buffer[4]);
52 2 : tz->charcnt = timelib_conv_int(buffer[5]);
53 2 : *tzf += sizeof(buffer);
54 2 : }
55 :
56 : static void read_transistions(char **tzf, timelib_tzinfo *tz)
57 2 : {
58 2 : int32_t *buffer = NULL;
59 : uint32_t i;
60 2 : unsigned char *cbuffer = NULL;
61 :
62 2 : if (tz->timecnt) {
63 1 : buffer = (int32_t*) malloc(tz->timecnt * sizeof(int32_t));
64 1 : if (!buffer) {
65 0 : return;
66 : }
67 1 : memcpy(buffer, *tzf, sizeof(int32_t) * tz->timecnt);
68 1 : *tzf += (sizeof(int32_t) * tz->timecnt);
69 144 : for (i = 0; i < tz->timecnt; i++) {
70 143 : buffer[i] = timelib_conv_int(buffer[i]);
71 : }
72 :
73 1 : cbuffer = (unsigned char*) malloc(tz->timecnt * sizeof(unsigned char));
74 1 : if (!cbuffer) {
75 0 : return;
76 : }
77 1 : memcpy(cbuffer, *tzf, sizeof(unsigned char) * tz->timecnt);
78 1 : *tzf += sizeof(unsigned char) * tz->timecnt;
79 : }
80 :
81 2 : tz->trans = buffer;
82 2 : tz->trans_idx = cbuffer;
83 : }
84 :
85 : static void read_types(char **tzf, timelib_tzinfo *tz)
86 2 : {
87 : unsigned char *buffer;
88 : int32_t *leap_buffer;
89 : unsigned int i, j;
90 :
91 2 : buffer = (unsigned char*) malloc(tz->typecnt * sizeof(unsigned char) * 6);
92 2 : if (!buffer) {
93 0 : return;
94 : }
95 2 : memcpy(buffer, *tzf, sizeof(unsigned char) * 6 * tz->typecnt);
96 2 : *tzf += sizeof(unsigned char) * 6 * tz->typecnt;
97 :
98 2 : tz->type = (ttinfo*) malloc(tz->typecnt * sizeof(struct ttinfo));
99 2 : if (!tz->type) {
100 0 : return;
101 : }
102 :
103 11 : for (i = 0; i < tz->typecnt; i++) {
104 9 : j = i * 6;
105 9 : tz->type[i].offset = (buffer[j] * 16777216) + (buffer[j + 1] * 65536) + (buffer[j + 2] * 256) + buffer[j + 3];
106 9 : tz->type[i].isdst = buffer[j + 4];
107 9 : tz->type[i].abbr_idx = buffer[j + 5];
108 : }
109 2 : free(buffer);
110 :
111 2 : tz->timezone_abbr = (char*) malloc(tz->charcnt);
112 2 : if (!tz->timezone_abbr) {
113 0 : return;
114 : }
115 2 : memcpy(tz->timezone_abbr, *tzf, sizeof(char) * tz->charcnt);
116 2 : *tzf += sizeof(char) * tz->charcnt;
117 :
118 2 : leap_buffer = (int32_t *) malloc(tz->leapcnt * 2 * sizeof(int32_t));
119 2 : if (!leap_buffer) {
120 0 : return;
121 : }
122 2 : memcpy(leap_buffer, *tzf, sizeof(int32_t) * tz->leapcnt * 2);
123 2 : *tzf += sizeof(int32_t) * tz->leapcnt * 2;
124 :
125 2 : tz->leap_times = (tlinfo*) malloc(tz->leapcnt * sizeof(tlinfo));
126 2 : if (!tz->leap_times) {
127 0 : return;
128 : }
129 2 : for (i = 0; i < tz->leapcnt; i++) {
130 0 : tz->leap_times[i].trans = timelib_conv_int(leap_buffer[i * 2]);
131 0 : tz->leap_times[i].offset = timelib_conv_int(leap_buffer[i * 2 + 1]);
132 : }
133 2 : free(leap_buffer);
134 :
135 2 : buffer = (unsigned char*) malloc(tz->ttisstdcnt * sizeof(unsigned char));
136 2 : if (!buffer) {
137 0 : return;
138 : }
139 2 : memcpy(buffer, *tzf, sizeof(unsigned char) * tz->ttisstdcnt);
140 2 : *tzf += sizeof(unsigned char) * tz->ttisstdcnt;
141 :
142 11 : for (i = 0; i < tz->ttisstdcnt; i++) {
143 9 : tz->type[i].isstdcnt = buffer[i];
144 : }
145 2 : free(buffer);
146 :
147 2 : buffer = (unsigned char*) malloc(tz->ttisgmtcnt * sizeof(unsigned char));
148 2 : if (!buffer) {
149 0 : return;
150 : }
151 2 : memcpy(buffer, *tzf, sizeof(unsigned char) * tz->ttisgmtcnt);
152 2 : *tzf += sizeof(unsigned char) * tz->ttisgmtcnt;
153 :
154 11 : for (i = 0; i < tz->ttisgmtcnt; i++) {
155 9 : tz->type[i].isgmtcnt = buffer[i];
156 : }
157 2 : free(buffer);
158 : }
159 :
160 : void timelib_dump_tzinfo(timelib_tzinfo *tz)
161 0 : {
162 : uint32_t i;
163 :
164 0 : printf("UTC/Local count: %lu\n", (unsigned long) tz->ttisgmtcnt);
165 0 : printf("Std/Wall count: %lu\n", (unsigned long) tz->ttisstdcnt);
166 0 : printf("Leap.sec. count: %lu\n", (unsigned long) tz->leapcnt);
167 0 : printf("Trans. count: %lu\n", (unsigned long) tz->timecnt);
168 0 : printf("Local types count: %lu\n", (unsigned long) tz->typecnt);
169 0 : printf("Zone Abbr. count: %lu\n", (unsigned long) tz->charcnt);
170 :
171 0 : printf ("%8s (%12s) = %3d [%5ld %1d %3d '%s' (%d,%d)]\n",
172 : "", "", 0,
173 : (long int) tz->type[0].offset,
174 : tz->type[0].isdst,
175 : tz->type[0].abbr_idx,
176 : &tz->timezone_abbr[tz->type[0].abbr_idx],
177 : tz->type[0].isstdcnt,
178 : tz->type[0].isgmtcnt
179 : );
180 0 : for (i = 0; i < tz->timecnt; i++) {
181 0 : printf ("%08X (%12d) = %3d [%5ld %1d %3d '%s' (%d,%d)]\n",
182 : tz->trans[i], tz->trans[i], tz->trans_idx[i],
183 : (long int) tz->type[tz->trans_idx[i]].offset,
184 : tz->type[tz->trans_idx[i]].isdst,
185 : tz->type[tz->trans_idx[i]].abbr_idx,
186 : &tz->timezone_abbr[tz->type[tz->trans_idx[i]].abbr_idx],
187 : tz->type[tz->trans_idx[i]].isstdcnt,
188 : tz->type[tz->trans_idx[i]].isgmtcnt
189 : );
190 : }
191 0 : for (i = 0; i < tz->leapcnt; i++) {
192 0 : printf ("%08X (%12ld) = %d\n",
193 : tz->leap_times[i].trans,
194 : (long) tz->leap_times[i].trans,
195 : tz->leap_times[i].offset);
196 : }
197 0 : }
198 :
199 : static int seek_to_tz_position(const unsigned char **tzf, char *timezone, const timelib_tzdb *tzdb)
200 3 : {
201 3 : int left = 0, right = tzdb->index_size - 1;
202 : #ifdef HAVE_SETLOCALE
203 3 : char *cur_locale = NULL, *tmp;
204 :
205 3 : tmp = setlocale(LC_CTYPE, NULL);
206 3 : if (tmp) {
207 3 : cur_locale = strdup(tmp);
208 : }
209 3 : setlocale(LC_CTYPE, "C");
210 : #endif
211 :
212 : do {
213 28 : int mid = ((unsigned)left + right) >> 1;
214 28 : int cmp = strcasecmp(timezone, tzdb->index[mid].id);
215 :
216 28 : if (cmp < 0) {
217 10 : right = mid - 1;
218 18 : } else if (cmp > 0) {
219 15 : left = mid + 1;
220 : } else { /* (cmp == 0) */
221 3 : (*tzf) = &(tzdb->data[tzdb->index[mid].pos + 20]);
222 : #ifdef HAVE_SETLOCALE
223 3 : setlocale(LC_CTYPE, cur_locale);
224 3 : if (cur_locale) free(cur_locale);
225 : #endif
226 3 : return 1;
227 : }
228 :
229 25 : } while (left <= right);
230 :
231 : #ifdef HAVE_SETLOCALE
232 0 : setlocale(LC_CTYPE, cur_locale);
233 0 : if (cur_locale) free(cur_locale);
234 : #endif
235 0 : return 0;
236 : }
237 :
238 : const timelib_tzdb *timelib_builtin_db(void)
239 5 : {
240 5 : return &timezonedb_builtin;
241 : }
242 :
243 : const timelib_tzdb_index_entry *timelib_timezone_builtin_identifiers_list(int *count)
244 0 : {
245 0 : *count = sizeof(timezonedb_idx_builtin) / sizeof(*timezonedb_idx_builtin);
246 0 : return timezonedb_idx_builtin;
247 : }
248 :
249 : int timelib_timezone_id_is_valid(char *timezone, const timelib_tzdb *tzdb)
250 1 : {
251 : const unsigned char *tzf;
252 1 : return (seek_to_tz_position(&tzf, timezone, tzdb));
253 : }
254 :
255 : timelib_tzinfo *timelib_parse_tzfile(char *timezone, const timelib_tzdb *tzdb)
256 2 : {
257 : const unsigned char *tzf;
258 : timelib_tzinfo *tmp;
259 :
260 2 : if (seek_to_tz_position(&tzf, timezone, tzdb)) {
261 2 : tmp = timelib_tzinfo_ctor(timezone);
262 :
263 2 : read_header((char**) &tzf, tmp);
264 2 : read_transistions((char**) &tzf, tmp);
265 2 : read_types((char**) &tzf, tmp);
266 : } else {
267 0 : tmp = NULL;
268 : }
269 :
270 2 : return tmp;
271 : }
272 :
273 : static ttinfo* fetch_timezone_offset(timelib_tzinfo *tz, timelib_sll ts, timelib_sll *transition_time)
274 3 : {
275 : uint32_t i;
276 :
277 : /* If there is no transistion time, we pick the first one, if that doesn't
278 : * exist we return NULL */
279 3 : if (!tz->timecnt || !tz->trans) {
280 1 : *transition_time = 0;
281 1 : if (tz->typecnt == 1) {
282 1 : return &(tz->type[0]);
283 : }
284 0 : return NULL;
285 : }
286 :
287 : /* If the TS is lower than the first transistion time, then we scan over
288 : * all the transistion times to find the first non-DST one, or the first
289 : * one in case there are only DST entries. Not sure which smartass came up
290 : * with this idea in the first though :) */
291 2 : if (ts < tz->trans[0]) {
292 : uint32_t j;
293 :
294 0 : *transition_time = 0;
295 0 : j = 0;
296 0 : while (j < tz->timecnt && tz->type[j].isdst) {
297 0 : ++j;
298 : }
299 0 : if (j == tz->timecnt) {
300 0 : j = 0;
301 : }
302 0 : return &(tz->type[j]);
303 : }
304 :
305 : /* In all other cases we loop through the available transtion times to find
306 : * the correct entry */
307 166 : for (i = 0; i < tz->timecnt; i++) {
308 166 : if (ts < tz->trans[i]) {
309 2 : *transition_time = tz->trans[i - 1];
310 2 : return &(tz->type[tz->trans_idx[i - 1]]);
311 : }
312 : }
313 0 : *transition_time = tz->trans[tz->timecnt - 1];
314 0 : return &(tz->type[tz->trans_idx[tz->timecnt - 1]]);
315 : }
316 :
317 : static tlinfo* fetch_leaptime_offset(timelib_tzinfo *tz, timelib_sll ts)
318 3 : {
319 : int i;
320 :
321 3 : if (!tz->leapcnt || !tz->leap_times) {
322 3 : return NULL;
323 : }
324 :
325 0 : for (i = tz->leapcnt - 1; i > 0; i--) {
326 0 : if (ts > tz->leap_times[i].trans) {
327 0 : return &(tz->leap_times[i]);
328 : }
329 : }
330 0 : return NULL;
331 : }
332 :
333 : int timelib_timestamp_is_in_dst(timelib_sll ts, timelib_tzinfo *tz)
334 0 : {
335 : ttinfo *to;
336 : timelib_sll dummy;
337 :
338 0 : if ((to = fetch_timezone_offset(tz, ts, &dummy))) {
339 0 : return to->isdst;
340 : }
341 0 : return -1;
342 : }
343 :
344 : timelib_time_offset *timelib_get_time_zone_info(timelib_sll ts, timelib_tzinfo *tz)
345 3 : {
346 : ttinfo *to;
347 : tlinfo *tl;
348 3 : int32_t offset = 0, leap_secs = 0;
349 : char *abbr;
350 3 : timelib_time_offset *tmp = timelib_time_offset_ctor();
351 : timelib_sll transistion_time;
352 :
353 3 : if ((to = fetch_timezone_offset(tz, ts, &transistion_time))) {
354 3 : offset = to->offset;
355 3 : abbr = &(tz->timezone_abbr[to->abbr_idx]);
356 3 : tmp->is_dst = to->isdst;
357 3 : tmp->transistion_time = transistion_time;
358 : } else {
359 0 : offset = 0;
360 0 : abbr = tz->timezone_abbr;
361 0 : tmp->is_dst = 0;
362 0 : tmp->transistion_time = 0;
363 : }
364 :
365 3 : if ((tl = fetch_leaptime_offset(tz, ts))) {
366 0 : leap_secs = -tl->offset;
367 : }
368 :
369 3 : tmp->offset = offset;
370 3 : tmp->leap_secs = leap_secs;
371 3 : tmp->abbr = abbr ? strdup(abbr) : strdup("GMT");
372 :
373 3 : return tmp;
374 : }
375 :
376 : timelib_sll timelib_get_current_offset(timelib_time *t)
377 0 : {
378 : timelib_time_offset *gmt_offset;
379 : timelib_sll retval;
380 :
381 0 : switch (t->zone_type) {
382 : case TIMELIB_ZONETYPE_ABBR:
383 : case TIMELIB_ZONETYPE_OFFSET:
384 0 : return t->z * 60;
385 :
386 : case TIMELIB_ZONETYPE_ID:
387 0 : gmt_offset = timelib_get_time_zone_info(t->sse, t->tz_info);
388 0 : retval = gmt_offset->offset;
389 0 : timelib_time_offset_dtor(gmt_offset);
390 0 : return retval;
391 :
392 : default:
393 0 : return 0;
394 : }
395 : }
|