source: src/router/php7/ext/date/lib/parse_tz.c @ 31877

Last change on this file since 31877 was 31877, checked in by brainslayer, 2 months ago

update php

File size: 14.3 KB
Line 
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
27#include <stdio.h>
28
29#ifdef HAVE_LOCALE_H
30#include <locale.h>
31#endif
32
33#ifdef HAVE_STRING_H
34#include <string.h>
35#else
36#include <strings.h>
37#endif
38
39#define TIMELIB_SUPPORTS_V2DATA
40#include "timezonedb.h"
41
42#if (defined(__APPLE__) || defined(__APPLE_CC__)) && (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__))
43# if defined(__LITTLE_ENDIAN__)
44#  undef WORDS_BIGENDIAN
45# else
46#  if defined(__BIG_ENDIAN__)
47#   define WORDS_BIGENDIAN
48#  endif
49# endif
50#endif
51
52#ifdef WORDS_BIGENDIAN
53#define timelib_conv_int(l) (l)
54#else
55#define timelib_conv_int(l) ((l & 0x000000ff) << 24) + ((l & 0x0000ff00) << 8) + ((l & 0x00ff0000) >> 8) + ((l & 0xff000000) >> 24)
56#endif
57
58static int read_preamble(const unsigned char **tzf, timelib_tzinfo *tz)
59{
60        uint32_t version;
61
62        /* read ID */
63        version = (*tzf)[3] - '0';
64        *tzf += 4;
65
66        /* read BC flag */
67        tz->bc = (**tzf == '\1');
68        *tzf += 1;
69
70        /* read country code */
71        memcpy(tz->location.country_code, *tzf, 2);
72        tz->location.country_code[2] = '\0';
73        *tzf += 2;
74
75        /* skip rest of preamble */
76        *tzf += 13;
77
78        return version;
79}
80
81static void read_header(const unsigned char **tzf, timelib_tzinfo *tz)
82{
83        uint32_t buffer[6];
84
85        memcpy(&buffer, *tzf, sizeof(buffer));
86        tz->bit32.ttisgmtcnt = timelib_conv_int(buffer[0]);
87        tz->bit32.ttisstdcnt = timelib_conv_int(buffer[1]);
88        tz->bit32.leapcnt    = timelib_conv_int(buffer[2]);
89        tz->bit32.timecnt    = timelib_conv_int(buffer[3]);
90        tz->bit32.typecnt    = timelib_conv_int(buffer[4]);
91        tz->bit32.charcnt    = timelib_conv_int(buffer[5]);
92        *tzf += sizeof(buffer);
93}
94
95static void skip_64bit_transistions(const unsigned char **tzf, timelib_tzinfo *tz)
96{
97        if (tz->bit64.timecnt) {
98                *tzf += (sizeof(int64_t) * tz->bit64.timecnt);
99                *tzf += (sizeof(unsigned char) * tz->bit64.timecnt);
100        }
101}
102
103static void read_transistions(const unsigned char **tzf, timelib_tzinfo *tz)
104{
105        int32_t *buffer = NULL;
106        uint32_t i;
107        unsigned char *cbuffer = NULL;
108
109        if (tz->bit32.timecnt) {
110                buffer = (int32_t*) timelib_malloc(tz->bit32.timecnt * sizeof(int32_t));
111                if (!buffer) {
112                        return;
113                }
114                memcpy(buffer, *tzf, sizeof(int32_t) * tz->bit32.timecnt);
115                *tzf += (sizeof(int32_t) * tz->bit32.timecnt);
116                for (i = 0; i < tz->bit32.timecnt; i++) {
117                        buffer[i] = timelib_conv_int(buffer[i]);
118                }
119
120                cbuffer = (unsigned char*) timelib_malloc(tz->bit32.timecnt * sizeof(unsigned char));
121                if (!cbuffer) {
122                        timelib_free(buffer);
123                        return;
124                }
125                memcpy(cbuffer, *tzf, sizeof(unsigned char) * tz->bit32.timecnt);
126                *tzf += sizeof(unsigned char) * tz->bit32.timecnt;
127        }
128
129        tz->trans = buffer;
130        tz->trans_idx = cbuffer;
131}
132
133static void skip_64bit_types(const unsigned char **tzf, timelib_tzinfo *tz)
134{
135        *tzf += sizeof(unsigned char) * 6 * tz->bit64.typecnt;
136        *tzf += sizeof(char) * tz->bit64.charcnt;
137        if (tz->bit64.leapcnt) {
138                *tzf += sizeof(int64_t) * tz->bit64.leapcnt * 2;
139        }
140        if (tz->bit64.ttisstdcnt) {
141                *tzf += sizeof(unsigned char) * tz->bit64.ttisstdcnt;
142        }
143        if (tz->bit64.ttisgmtcnt) {
144                *tzf += sizeof(unsigned char) * tz->bit64.ttisgmtcnt;
145        }
146}
147
148static void read_types(const unsigned char **tzf, timelib_tzinfo *tz)
149{
150        unsigned char *buffer;
151        int32_t *leap_buffer;
152        unsigned int i, j;
153
154        buffer = (unsigned char*) timelib_malloc(tz->bit32.typecnt * sizeof(unsigned char) * 6);
155        if (!buffer) {
156                return;
157        }
158        memcpy(buffer, *tzf, sizeof(unsigned char) * 6 * tz->bit32.typecnt);
159        *tzf += sizeof(unsigned char) * 6 * tz->bit32.typecnt;
160
161        tz->type = (ttinfo*) timelib_malloc(tz->bit32.typecnt * sizeof(struct ttinfo));
162        if (!tz->type) {
163                timelib_free(buffer);
164                return;
165        }
166
167        for (i = 0; i < tz->bit32.typecnt; i++) {
168                j = i * 6;
169                tz->type[i].offset = (buffer[j] * 16777216) + (buffer[j + 1] * 65536) + (buffer[j + 2] * 256) + buffer[j + 3];
170                tz->type[i].isdst = buffer[j + 4];
171                tz->type[i].abbr_idx = buffer[j + 5];
172        }
173        timelib_free(buffer);
174
175        tz->timezone_abbr = (char*) timelib_malloc(tz->bit32.charcnt);
176        if (!tz->timezone_abbr) {
177                return;
178        }
179        memcpy(tz->timezone_abbr, *tzf, sizeof(char) * tz->bit32.charcnt);
180        *tzf += sizeof(char) * tz->bit32.charcnt;
181
182        if (tz->bit32.leapcnt) {
183                leap_buffer = (int32_t *) timelib_malloc(tz->bit32.leapcnt * 2 * sizeof(int32_t));
184                if (!leap_buffer) {
185                        return;
186                }
187                memcpy(leap_buffer, *tzf, sizeof(int32_t) * tz->bit32.leapcnt * 2);
188                *tzf += sizeof(int32_t) * tz->bit32.leapcnt * 2;
189
190                tz->leap_times = (tlinfo*) timelib_malloc(tz->bit32.leapcnt * sizeof(tlinfo));
191                if (!tz->leap_times) {
192                        timelib_free(leap_buffer);
193                        return;
194                }
195                for (i = 0; i < tz->bit32.leapcnt; i++) {
196                        tz->leap_times[i].trans = timelib_conv_int(leap_buffer[i * 2]);
197                        tz->leap_times[i].offset = timelib_conv_int(leap_buffer[i * 2 + 1]);
198                }
199                timelib_free(leap_buffer);
200        }
201
202        if (tz->bit32.ttisstdcnt) {
203                buffer = (unsigned char*) timelib_malloc(tz->bit32.ttisstdcnt * sizeof(unsigned char));
204                if (!buffer) {
205                        return;
206                }
207                memcpy(buffer, *tzf, sizeof(unsigned char) * tz->bit32.ttisstdcnt);
208                *tzf += sizeof(unsigned char) * tz->bit32.ttisstdcnt;
209
210                for (i = 0; i < tz->bit32.ttisstdcnt; i++) {
211                        tz->type[i].isstdcnt = buffer[i];
212                }
213                timelib_free(buffer);
214        }
215
216        if (tz->bit32.ttisgmtcnt) {
217                buffer = (unsigned char*) timelib_malloc(tz->bit32.ttisgmtcnt * sizeof(unsigned char));
218                if (!buffer) {
219                        return;
220                }
221                memcpy(buffer, *tzf, sizeof(unsigned char) * tz->bit32.ttisgmtcnt);
222                *tzf += sizeof(unsigned char) * tz->bit32.ttisgmtcnt;
223
224                for (i = 0; i < tz->bit32.ttisgmtcnt; i++) {
225                        tz->type[i].isgmtcnt = buffer[i];
226                }
227                timelib_free(buffer);
228        }
229}
230
231static void skip_posix_string(const unsigned char **tzf, timelib_tzinfo *tz)
232{
233        int n_count = 0;
234
235        do {
236                if (*tzf[0] == '\n') {
237                        n_count++;
238                }
239                (*tzf)++;
240        } while (n_count < 2);
241}
242
243static void read_location(const unsigned char **tzf, timelib_tzinfo *tz)
244{
245        uint32_t buffer[3];
246        uint32_t comments_len;
247
248        memcpy(&buffer, *tzf, sizeof(buffer));
249        tz->location.latitude = timelib_conv_int(buffer[0]);
250        tz->location.latitude = (tz->location.latitude / 100000) - 90;
251        tz->location.longitude = timelib_conv_int(buffer[1]);
252        tz->location.longitude = (tz->location.longitude / 100000) - 180;
253        comments_len = timelib_conv_int(buffer[2]);
254        *tzf += sizeof(buffer);
255
256        tz->location.comments = timelib_malloc(comments_len + 1);
257        memcpy(tz->location.comments, *tzf, comments_len);
258        tz->location.comments[comments_len] = '\0';
259        *tzf += comments_len;
260}
261
262void timelib_dump_tzinfo(timelib_tzinfo *tz)
263{
264        uint32_t i;
265
266        printf("Country Code:      %s\n", tz->location.country_code);
267        printf("Geo Location:      %f,%f\n", tz->location.latitude, tz->location.longitude);
268        printf("Comments:\n%s\n",          tz->location.comments);
269        printf("BC:                %s\n",  tz->bc ? "" : "yes");
270        printf("UTC/Local count:   " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit32.ttisgmtcnt);
271        printf("Std/Wall count:    " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit32.ttisstdcnt);
272        printf("Leap.sec. count:   " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit32.leapcnt);
273        printf("Trans. count:      " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit32.timecnt);
274        printf("Local types count: " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit32.typecnt);
275        printf("Zone Abbr. count:  " TIMELIB_ULONG_FMT "\n", (timelib_ulong) tz->bit32.charcnt);
276
277        printf ("%8s (%12s) = %3d [%5ld %1d %3d '%s' (%d,%d)]\n",
278                "", "", 0,
279                (long int) tz->type[0].offset,
280                tz->type[0].isdst,
281                tz->type[0].abbr_idx,
282                &tz->timezone_abbr[tz->type[0].abbr_idx],
283                tz->type[0].isstdcnt,
284                tz->type[0].isgmtcnt
285                );
286        for (i = 0; i < tz->bit32.timecnt; i++) {
287                printf ("%08X (%12d) = %3d [%5ld %1d %3d '%s' (%d,%d)]\n",
288                        tz->trans[i], tz->trans[i], tz->trans_idx[i],
289                        (long int) tz->type[tz->trans_idx[i]].offset,
290                        tz->type[tz->trans_idx[i]].isdst,
291                        tz->type[tz->trans_idx[i]].abbr_idx,
292                        &tz->timezone_abbr[tz->type[tz->trans_idx[i]].abbr_idx],
293                        tz->type[tz->trans_idx[i]].isstdcnt,
294                        tz->type[tz->trans_idx[i]].isgmtcnt
295                        );
296        }
297        for (i = 0; i < tz->bit32.leapcnt; i++) {
298                printf ("%08X (%12ld) = %d\n",
299                        tz->leap_times[i].trans,
300                        (long) tz->leap_times[i].trans,
301                        tz->leap_times[i].offset);
302        }
303}
304
305static int seek_to_tz_position(const unsigned char **tzf, char *timezone, const timelib_tzdb *tzdb)
306{
307        int left = 0, right = tzdb->index_size - 1;
308#ifdef HAVE_SETLOCALE
309        char *cur_locale = NULL, *tmp;
310
311        tmp = setlocale(LC_CTYPE, NULL);
312        if (tmp) {
313                cur_locale = timelib_strdup(tmp);
314        }
315        setlocale(LC_CTYPE, "C");
316#endif
317
318        do {
319                int mid = ((unsigned)left + right) >> 1;
320                int cmp = strcasecmp(timezone, tzdb->index[mid].id);
321
322                if (cmp < 0) {
323                        right = mid - 1;
324                } else if (cmp > 0) {
325                        left = mid + 1;
326                } else { /* (cmp == 0) */
327                        (*tzf) = &(tzdb->data[tzdb->index[mid].pos]);
328#ifdef HAVE_SETLOCALE
329                        setlocale(LC_CTYPE, cur_locale);
330                        if (cur_locale) timelib_free(cur_locale);
331#endif
332                        return 1;
333                }
334
335        } while (left <= right);
336
337#ifdef HAVE_SETLOCALE
338        setlocale(LC_CTYPE, cur_locale);
339        if (cur_locale) timelib_free(cur_locale);
340#endif
341        return 0;
342}
343
344const timelib_tzdb *timelib_builtin_db(void)
345{
346        return &timezonedb_builtin;
347}
348
349const timelib_tzdb_index_entry *timelib_timezone_builtin_identifiers_list(int *count)
350{
351        *count = sizeof(timezonedb_idx_builtin) / sizeof(*timezonedb_idx_builtin);
352        return timezonedb_idx_builtin;
353}
354
355int timelib_timezone_id_is_valid(char *timezone, const timelib_tzdb *tzdb)
356{
357        const unsigned char *tzf;
358        return (seek_to_tz_position(&tzf, timezone, tzdb));
359}
360
361static void skip_64bit_preamble(const unsigned char **tzf, timelib_tzinfo *tz)
362{
363        *tzf += 20;
364}
365
366static void read_64bit_header(const unsigned char **tzf, timelib_tzinfo *tz)
367{
368        uint32_t buffer[6];
369
370        memcpy(&buffer, *tzf, sizeof(buffer));
371        tz->bit64.ttisgmtcnt = timelib_conv_int(buffer[0]);
372        tz->bit64.ttisstdcnt = timelib_conv_int(buffer[1]);
373        tz->bit64.leapcnt    = timelib_conv_int(buffer[2]);
374        tz->bit64.timecnt    = timelib_conv_int(buffer[3]);
375        tz->bit64.typecnt    = timelib_conv_int(buffer[4]);
376        tz->bit64.charcnt    = timelib_conv_int(buffer[5]);
377        *tzf += sizeof(buffer);
378}
379
380timelib_tzinfo *timelib_parse_tzfile(char *timezone, const timelib_tzdb *tzdb)
381{
382        const unsigned char *tzf;
383        timelib_tzinfo *tmp;
384        int version;
385
386        if (seek_to_tz_position(&tzf, timezone, tzdb)) {
387                tmp = timelib_tzinfo_ctor(timezone);
388
389                version = read_preamble(&tzf, tmp);
390                read_header(&tzf, tmp);
391                read_transistions(&tzf, tmp);
392                read_types(&tzf, tmp);
393                if (version == 2) {
394                        skip_64bit_preamble(&tzf, tmp);
395                        read_64bit_header(&tzf, tmp);
396                        skip_64bit_transistions(&tzf, tmp);
397                        skip_64bit_types(&tzf, tmp);
398                        skip_posix_string(&tzf, tmp);
399                }
400                read_location(&tzf, tmp);
401        } else {
402                tmp = NULL;
403        }
404
405        return tmp;
406}
407
408static ttinfo* fetch_timezone_offset(timelib_tzinfo *tz, timelib_sll ts, timelib_sll *transition_time)
409{
410        uint32_t i;
411
412        /* If there is no transition time, we pick the first one, if that doesn't
413         * exist we return NULL */
414        if (!tz->bit32.timecnt || !tz->trans) {
415                *transition_time = 0;
416                if (tz->bit32.typecnt == 1) {
417                        return &(tz->type[0]);
418                }
419                return NULL;
420        }
421
422        /* If the TS is lower than the first transition time, then we scan over
423         * all the transition times to find the first non-DST one, or the first
424         * one in case there are only DST entries. Not sure which smartass came up
425         * with this idea in the first though :) */
426        if (ts < tz->trans[0]) {
427                uint32_t j;
428
429                *transition_time = 0;
430                j = 0;
431                while (j < tz->bit32.timecnt && tz->type[tz->trans_idx[j]].isdst) {
432                        ++j;
433                }
434                if (j == tz->bit32.timecnt) {
435                        j = 0;
436                }
437                return &(tz->type[tz->trans_idx[j]]);
438        }
439
440        /* In all other cases we loop through the available transtion times to find
441         * the correct entry */
442        for (i = 0; i < tz->bit32.timecnt; i++) {
443                if (ts < tz->trans[i]) {
444                        *transition_time = tz->trans[i - 1];
445                        return &(tz->type[tz->trans_idx[i - 1]]);
446                }
447        }
448        *transition_time = tz->trans[tz->bit32.timecnt - 1];
449        return &(tz->type[tz->trans_idx[tz->bit32.timecnt - 1]]);
450}
451
452static tlinfo* fetch_leaptime_offset(timelib_tzinfo *tz, timelib_sll ts)
453{
454        int i;
455
456        if (!tz->bit32.leapcnt || !tz->leap_times) {
457                return NULL;
458        }
459
460        for (i = tz->bit32.leapcnt - 1; i > 0; i--) {
461                if (ts > tz->leap_times[i].trans) {
462                        return &(tz->leap_times[i]);
463                }
464        }
465        return NULL;
466}
467
468int timelib_timestamp_is_in_dst(timelib_sll ts, timelib_tzinfo *tz)
469{
470        ttinfo *to;
471        timelib_sll dummy;
472
473        if ((to = fetch_timezone_offset(tz, ts, &dummy))) {
474                return to->isdst;
475        }
476        return -1;
477}
478
479timelib_time_offset *timelib_get_time_zone_info(timelib_sll ts, timelib_tzinfo *tz)
480{
481        ttinfo *to;
482        tlinfo *tl;
483        int32_t offset = 0, leap_secs = 0;
484        char *abbr;
485        timelib_time_offset *tmp = timelib_time_offset_ctor();
486        timelib_sll                transistion_time;
487
488        if ((to = fetch_timezone_offset(tz, ts, &transistion_time))) {
489                offset = to->offset;
490                abbr = &(tz->timezone_abbr[to->abbr_idx]);
491                tmp->is_dst = to->isdst;
492                tmp->transistion_time = transistion_time;
493        } else {
494                offset = 0;
495                abbr = tz->timezone_abbr;
496                tmp->is_dst = 0;
497                tmp->transistion_time = 0;
498        }
499
500        if ((tl = fetch_leaptime_offset(tz, ts))) {
501                leap_secs = -tl->offset;
502        }
503
504        tmp->offset = offset;
505        tmp->leap_secs = leap_secs;
506        tmp->abbr = abbr ? timelib_strdup(abbr) : timelib_strdup("GMT");
507
508        return tmp;
509}
510
511timelib_sll timelib_get_current_offset(timelib_time *t)
512{
513        timelib_time_offset *gmt_offset;
514        timelib_sll retval;
515
516        switch (t->zone_type) {
517                case TIMELIB_ZONETYPE_ABBR:
518                case TIMELIB_ZONETYPE_OFFSET:
519                        return (t->z + t->dst) * -60;
520
521                case TIMELIB_ZONETYPE_ID:
522                        gmt_offset = timelib_get_time_zone_info(t->sse, t->tz_info);
523                        retval = gmt_offset->offset;
524                        timelib_time_offset_dtor(gmt_offset);
525                        return retval;
526
527                default:
528                        return 0;
529        }
530}
Note: See TracBrowser for help on using the repository browser.