PageRenderTime 47ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/date/lib/parse_tz.c

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