File Coverage

src/panda/time/tzparse_format.icc
Criterion Covered Total %
statement 119 134 88.8
branch 53 128 41.4
condition n/a
subroutine n/a
pod n/a
total 172 262 65.6


line stmt bran cond sub pod time code
1             #undef PTIME_TZPARSE_HEADERFUNC
2             #undef PTIME_TZPARSE_BODYFUNC
3             #undef PTIME_TZPARSE_TRANSTIME_TYPE
4             #undef PTIME_TZPARSE_LEAPSEC_TYPE
5             #undef PTIME_TZPARSE_LEAPSEC_SIZE
6             #undef PTIME_TZPARSE_NTOH_DYN
7              
8             #ifdef PTIME_TZPARSE_V2
9             # define PTIME_TZPARSE_HEADERFUNC tzparse_headerV2
10             # define PTIME_TZPARSE_BODYFUNC tzparse_bodyV2
11             # define PTIME_TZPARSE_TRANSTIME_TYPE ftz_transtimeV2
12             # define PTIME_TZPARSE_LEAPSEC_TYPE ftz_leapsecV2
13             # define PTIME_TZPARSE_NTOH_DYN(val) ((int64_t)panda::lib::be2h64(val))
14             #else
15             # define PTIME_TZPARSE_HEADERFUNC tzparse_headerV1
16             # define PTIME_TZPARSE_BODYFUNC tzparse_bodyV1
17             # define PTIME_TZPARSE_TRANSTIME_TYPE ftz_transtimeV1
18             # define PTIME_TZPARSE_LEAPSEC_TYPE ftz_leapsecV1
19             # define PTIME_TZPARSE_NTOH_DYN(val) ((int32_t)panda::lib::be2h32(val))
20             #endif
21              
22             #ifndef PTIME_TZPARSE_TRANSCMP
23             # define PTIME_TZPARSE_TRANSCMP
24 368873           static int trans_cmp (const void* _a, const void* _b) {
25 368873           Timezone::Transition* a = (Timezone::Transition*) _a;
26 368873           Timezone::Transition* b = (Timezone::Transition*) _b;
27 368873 100         if (a->start < b->start) return -1;
28 25767 50         else if (a->start == b->start) return 0;
29 25767           else return 1;
30             }
31             #endif
32              
33             #define PTIME_TZPARSE_BODY_BASE_SIZE(head) ( \
34             head.tzh_timecnt*sizeof(PTIME_TZPARSE_TRANSTIME_TYPE) + /* transition times */ \
35             head.tzh_timecnt*sizeof(ftz_ilocaltype) + /* types of local time starting at above */ \
36             head.tzh_typecnt*sizeof(ftz_localtype) + /* local times */ \
37             head.tzh_charcnt + /* abbrevs */ \
38             head.tzh_leapcnt*sizeof(PTIME_TZPARSE_LEAPSEC_TYPE) + /* leap seconds */ \
39             head.tzh_ttisstdcnt*sizeof(ftz_isstd) + \
40             head.tzh_ttisgmtcnt*sizeof(ftz_isgmt) \
41             )
42              
43 2480           static inline int PTIME_TZPARSE_HEADERFUNC (const char*& ptr, const char*const end, ftz_head& head, int* version) {
44 2480 50         if (ptr + sizeof(head) > end) return -1;
    50          
45 2480           head = *((ftz_head*)ptr);
46 2480           ptr += sizeof(head);
47            
48 2480 50         if (strncmp(head.tzh_magic, FTZ_MAGIC, sizeof(head.tzh_magic)) != 0) {
    50          
49             //fprintf(stderr, "ptime: BAD FILE MAGIC\n", head.tzh_magic);
50 0           return -1;
51             }
52            
53 2480 50         *version = head.tzh_version[0] ? (head.tzh_version[0] - '0') : 1;
    50          
54            
55 2480           head.tzh_ttisgmtcnt = panda::lib::be2h32(head.tzh_ttisgmtcnt);
56 2480           head.tzh_ttisstdcnt = panda::lib::be2h32(head.tzh_ttisstdcnt);
57 2480           head.tzh_leapcnt = panda::lib::be2h32(head.tzh_leapcnt);
58 2480           head.tzh_timecnt = panda::lib::be2h32(head.tzh_timecnt);
59 2480           head.tzh_typecnt = panda::lib::be2h32(head.tzh_typecnt);
60 2480           head.tzh_charcnt = panda::lib::be2h32(head.tzh_charcnt);
61            
62 2480           if (head.tzh_timecnt > FTZ_MAX_TIMES) {
63             //fprintf(stderr, "ptime: tzh_timecnt %d is greater than max supported %d\n", head.tzh_timecnt, FTZ_MAX_TIMES);
64 0           return -1;
65             }
66            
67 2480 50         if (head.tzh_typecnt > FTZ_MAX_TYPES) {
    50          
68             //fprintf(stderr, "ptime: tzh_typecnt %d is greater than max supported %d\n", head.tzh_typecnt, FTZ_MAX_TYPES);
69 0           return -1;
70             }
71            
72 2480 50         if (head.tzh_charcnt > FTZ_MAX_CHARS) {
    50          
73             //fprintf(stderr, "ptime: tzh_charcnt %d is greater than max supported %d\n", head.tzh_charcnt, FTZ_MAX_CHARS);
74 0           return -1;
75             }
76            
77 2480 50         if (head.tzh_leapcnt > FTZ_MAX_LEAPS) {
    50          
78             //fprintf(stderr, "ptime: tzh_leapcnt %d is greater than max supported %d\n", head.tzh_leapcnt, FTZ_MAX_LEAPS);
79 0           return -1;
80             }
81              
82 2480           return PTIME_TZPARSE_BODY_BASE_SIZE(head);
83             }
84              
85 1240           static inline bool PTIME_TZPARSE_BODYFUNC (const char*& ptr, const char*const end, ftz_head& head, Timezone* zone) {
86 1240 50         if (ptr + PTIME_TZPARSE_BODY_BASE_SIZE(head) > end) return false;
    0          
87            
88 1240           PTIME_TZPARSE_TRANSTIME_TYPE* transitions = (PTIME_TZPARSE_TRANSTIME_TYPE*)ptr;
89 1240           ptr += head.tzh_timecnt * sizeof(PTIME_TZPARSE_TRANSTIME_TYPE);
90              
91 1240           ftz_ilocaltype* ilocaltypes = (ftz_ilocaltype*)ptr;
92 1240           ptr += head.tzh_timecnt * sizeof(ftz_ilocaltype);
93              
94             ftz_localtype localtypes[FTZ_MAX_TYPES];
95 8037 100         for (uint32_t i = 0; i < head.tzh_typecnt; i++) {
    0          
96 6797           localtypes[i] = *((ftz_localtype*)ptr);
97 6797           localtypes[i].offset = panda::lib::be2h32(localtypes[i].offset);
98 6797           ptr += sizeof(ftz_localtype);
99             }
100              
101 1240           const char* abbrevs = ptr;
102 1240           ptr += head.tzh_charcnt * sizeof(char);
103              
104 1240           zone->leaps_cnt = head.tzh_leapcnt;
105 1240 100         zone->leaps = zone->leaps_cnt > 0 ? new Timezone::Leap[zone->leaps_cnt] : NULL;
    50          
    50          
    0          
    0          
    0          
106 17683 100         for (uint32_t i = 0; i < head.tzh_leapcnt; i++) {
    0          
107 16443           PTIME_TZPARSE_LEAPSEC_TYPE leapsec = *((PTIME_TZPARSE_LEAPSEC_TYPE*)ptr);
108 16443           zone->leaps[i].time = (ptime_t)PTIME_TZPARSE_NTOH_DYN(leapsec.time);
109 16443           zone->leaps[i].correction = panda::lib::be2h32(leapsec.correction);
110 16443           ptr += sizeof(leapsec);
111             }
112              
113             //ftz_isstd* isstds = (ftz_isstd*)ptr;
114 1240           ptr += head.tzh_ttisstdcnt * sizeof(ftz_isstd);
115              
116             //ftz_isgmt* isgmts = (ftz_isgmt*)ptr;
117 1240           ptr += head.tzh_ttisgmtcnt * sizeof(ftz_isgmt);
118            
119             // find past localtype - first localtype if it's not used in transitions, otherwise it's first std time localtype
120 1240           int past_lt_index = 0;
121 1554 100         for (uint32_t i = 0; i < head.tzh_timecnt; ++i) {
    0          
122 1552 100         if (ilocaltypes[i] != 0) continue;
    0          
123 1238           past_lt_index = -1;
124 1238           break;
125             }
126 2494 100         if (past_lt_index < 0) for (uint32_t i = 0; i < head.tzh_typecnt; ++i) {
    50          
    0          
    0          
127 1254 100         if (localtypes[i].isdst) continue;
    0          
128 1238           past_lt_index = i;
129 1238           break;
130             }
131 1240 50         if (past_lt_index < 0) past_lt_index = 0;
    0          
132            
133 1240           zone->trans_cnt = head.tzh_timecnt + 1 + zone->leaps_cnt; // +1 for 'past'
134 1240 50         zone->trans = new Timezone::Transition[zone->trans_cnt];
    50          
    0          
    0          
135 1240           std::memset(zone->trans, 0, zone->trans_cnt * sizeof(*zone->trans));
136            
137 1240           zone->trans[0].start = EPOCH_NEGINF;
138 1240           zone->trans[0].local_start = EPOCH_NEGINF;
139 1240           zone->trans[0].local_lower = EPOCH_NEGINF;
140 1240           zone->trans[0].local_upper = EPOCH_NEGINF;
141 1240           zone->trans[0].offset = localtypes[past_lt_index].offset;
142 1240           zone->trans[0].gmt_offset = localtypes[past_lt_index].offset;
143 1240           zone->trans[0].delta = 0;
144 1240           zone->trans[0].isdst = localtypes[past_lt_index].isdst;
145 1240           zone->trans[0].leap_corr = 0;
146 1240           zone->trans[0].leap_delta = 0;
147 1240           zone->trans[0].leap_end = EPOCH_NEGINF;
148 1240           zone->trans[0].leap_lend = EPOCH_NEGINF;
149 1240           const char* past_abbrev = abbrevs + localtypes[past_lt_index].abbrev_offset;
150 1240 50         if (strlen(past_abbrev) > ZONE_ABBR_MAX) {
    0          
151             //fprintf(stderr, "ptime: past abbrev is too long (%d), max is %d\n", strlen(past_abbrev), ZONE_ABBR_MAX);
152 0           zone->clear();
153 0           return false;
154             }
155 1240           strcpy(zone->trans[0].abbrev, past_abbrev);
156              
157 87818 100         for (uint32_t i = 0; i < head.tzh_timecnt; ++i) {
    0          
158 86578           ftz_localtype localtype = localtypes[ilocaltypes[i]];
159 86578           auto this_trans = &zone->trans[i+1];
160 86578           this_trans->start = (ptime_t)PTIME_TZPARSE_NTOH_DYN(transitions[i]);
161 86578           this_trans->gmt_offset = localtype.offset;
162 86578           this_trans->isdst = localtype.isdst;
163 86578           const char* abbrev = abbrevs + localtype.abbrev_offset;
164 86578           if (strlen(abbrev) > ZONE_ABBR_MAX) {
165             //fprintf(stderr, "ptime: locatype's #%d abbrev is too long (%d), max is %d\n", ilocaltypes[i], strlen(abbrev), ZONE_ABBR_MAX);
166 0           zone->clear();
167 0           return false;
168             }
169 86578           strcpy(this_trans->abbrev, abbrev);
170             }
171            
172 17683 100         for (uint32_t i = 0; i < zone->leaps_cnt; i++) {
    0          
173 16443           auto this_trans = &zone->trans[head.tzh_timecnt+i+1];
174 16443           this_trans->start = zone->leaps[i].time;
175 16443           this_trans->leap_corr = zone->leaps[i].correction;
176             }
177            
178 1240 50         qsort(zone->trans, zone->trans_cnt, sizeof(*zone->trans), trans_cmp);
    0          
179            
180 104261 100         for (uint32_t i = 1; i < zone->trans_cnt; ++i) {
    0          
181 103021           auto this_trans = &zone->trans[i];
182 103021           auto prev_trans = &zone->trans[i-1];
183            
184 103021 100         if (this_trans->leap_corr != 0) {
    0          
185 16443           this_trans->leap_delta = this_trans->leap_corr - prev_trans->leap_corr;
186 16443           this_trans->gmt_offset = prev_trans->gmt_offset;
187 16443           this_trans->isdst = prev_trans->isdst;
188 16443           strcpy(this_trans->abbrev, prev_trans->abbrev);
189             } else {
190 86578           this_trans->leap_delta = 0;
191 86578           this_trans->leap_corr = prev_trans->leap_corr;
192             }
193            
194 103021           this_trans->offset = this_trans->gmt_offset - this_trans->leap_corr;
195 103021           this_trans->delta = this_trans->offset - prev_trans->offset;
196 103021           this_trans->local_start = this_trans->start + this_trans->offset;
197 103021           prev_trans->local_end = this_trans->start + prev_trans->offset;
198 103021           this_trans->local_lower = this_trans->local_start;
199 103021           this_trans->local_upper = std::max(this_trans->local_start, prev_trans->local_end);
200 103021           this_trans->leap_end = this_trans->start + this_trans->leap_delta;
201 103021           this_trans->leap_lend = this_trans->local_start + 2*this_trans->leap_delta;
202             }
203              
204            
205 1240           const char* posixstr = ptr;
206 1240           const char* posixend = ptr;
207            
208             #ifdef PTIME_TZPARSE_V2
209 1240           posixstr++; // because POSIX rule begins and ends with '\n'
210 1240 50         if (posixstr >= end) { zone->clear(); return false; }
211 1240           posixend = (const char*)std::memchr(posixstr, '\n', end - posixstr);
212 1240 50         if (posixend == NULL) { zone->clear(); return false; }
213             #endif
214              
215 1240           zone->ltrans = zone->trans[zone->trans_cnt-1];
216              
217 1240 50         if (posixend == posixstr) { // no posix string, using last transition
    0          
218 0           zone->future.hasdst = 0;
219 0           zone->future.outer.gmt_offset = zone->ltrans.gmt_offset;
220 0           zone->future.outer.isdst = zone->ltrans.isdst;
221 0           strcpy(zone->future.outer.abbrev, zone->ltrans.abbrev);
222             }
223 1240 50         else if (!tzparse_rule(string_view(posixstr, posixend-posixstr), &zone->future)) {
    50          
    0          
    0          
224             //fprintf(stderr, "ptime: tzparse_rule failed\n");
225 0           zone->clear();
226 0           return false;
227             }
228              
229 1240           zone->future.outer.offset = zone->future.outer.gmt_offset - zone->ltrans.leap_corr;
230 1240 100         if (zone->future.hasdst) {
    0          
231 452           zone->future.inner.offset = zone->future.inner.gmt_offset - zone->ltrans.leap_corr;
232 452           zone->future.delta = zone->future.inner.offset - zone->future.outer.offset;
233 452           zone->future.max_offset = std::max(zone->future.outer.offset, zone->future.inner.offset);
234             }
235            
236 1240           return true;
237             }