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