55 |
55 |
56 #include "utils.h" |
56 #include "utils.h" |
57 #include "crypto.h" |
57 #include "crypto.h" |
58 #include "webdav.h" |
58 #include "webdav.h" |
59 |
59 |
60 static int parse_iso8601(char *str, time_t *result) { |
60 static size_t extractval(sstr_t str, char *result, char delim) { |
|
61 size_t n = 0; |
|
62 for(size_t i = 0; i < str.length ; i++) { |
|
63 if(isdigit(str.ptr[i])) { |
|
64 result[n++] = str.ptr[i]; |
|
65 } else if(str.ptr[i] != delim) { |
|
66 return 0; |
|
67 } |
|
68 } |
|
69 result[n] = '\0'; |
|
70 return n; |
|
71 } |
|
72 |
|
73 static int parse_iso8601(char *iso8601str) { |
61 |
74 |
62 // safety |
75 // safety |
63 if(!str || !result) { |
76 if(!iso8601str) { |
64 return 1; |
77 return 0; |
65 } |
78 } |
66 |
79 |
|
80 // local vars |
67 struct tm tparts; |
81 struct tm tparts; |
68 memset(&tparts, 0, sizeof(struct tm)); |
82 memset(&tparts, 0, sizeof(struct tm)); |
69 *result = 0; |
|
70 long val; |
83 long val; |
71 |
84 char conv[16]; |
72 // skip leading spaces |
85 |
73 while(isspace(*str)) { |
86 // work on the trimmed string |
74 str++; |
87 sstr_t date = sstrtrim(sstr(iso8601str)); |
75 } |
88 |
76 |
89 sstr_t time = sstrchr(date, 'T'); |
77 // ensure we have numeric values |
90 if(time.length == 0) { |
78 if(!isdigit(*str)) { |
91 return 0; |
79 return 1; |
92 } |
80 } |
93 date.length = time.ptr - date.ptr; |
81 |
94 time.ptr++; time.length--; |
82 // starting parsing the year |
95 |
83 val = strtoul(str, &str, 10); |
96 sstr_t tzinfo; |
84 |
97 if((tzinfo = sstrchr(time, 'Z')).length > 0 || |
85 if(*str == '-') { |
98 (tzinfo = sstrchr(time, '+')).length > 0 || |
86 // month (and day) seem to be dash separated |
99 (tzinfo = sstrchr(time, '-')).length > 0) { |
87 tparts.tm_year = val - 1900; |
100 |
88 str++; |
101 time.length = tzinfo.ptr - time.ptr; |
89 tparts.tm_mon = strtoul(str, &str, 10) - 1; |
102 } |
90 |
103 |
91 if(*str++ != '-') { |
104 // parse date |
92 return 1; |
105 if((date.length != 8 && date.length != 10) |
93 } |
106 || extractval(date, conv , '-') != 8) { |
94 |
107 return 0; |
95 tparts.tm_mday = strtoul(str, &str, 10); |
108 } |
96 } else { |
109 val = atol(conv); |
97 // year, month, day was parsed as one big integer |
110 if(val < 19000000L) { |
98 tparts.tm_mday = val % 100; |
111 return 0; |
99 tparts.tm_mon = (val % 10000) / 100 - 1; |
112 } |
100 tparts.tm_year = val / 10000 - 1900; |
113 tparts.tm_mday = val % 100; |
101 } |
114 tparts.tm_mon = (val % 10000) / 100 - 1; |
102 |
115 tparts.tm_year = val / 10000 - 1900; |
103 // time separator |
116 |
104 if(*str != 'T') { |
117 // parse time and skip possible fractional seconds |
105 return 1; |
118 sstr_t frac; |
106 } |
119 if((frac = sstrchr(time, '.')).length > 0 || |
107 str++; |
120 (frac = sstrchr(time, ',')).length > 0) { |
108 |
121 time.length = frac.ptr - time.ptr; |
109 // ensure we have numeric values (unsigned) |
122 } |
110 if(!isdigit(*str)) { |
123 if((time.length != 6 && time.length != 8) |
111 return 1; |
124 || extractval(time, conv , ':') != 6) { |
112 } |
125 return 0; |
113 |
126 } |
114 // start parsing the hour |
127 val = atol(conv); |
115 val = strtoul(str, &str, 10); |
128 tparts.tm_sec = val % 100; |
116 if(*str == ':') { |
129 tparts.tm_min = (val % 10000) / 100; |
117 // minutes (and seconds) are separated by colon |
130 tparts.tm_hour = val / 10000; |
118 tparts.tm_hour = val; |
131 |
119 str++; |
|
120 tparts.tm_min = strtoul(str, &str, 10); |
|
121 |
|
122 if(*str++ != ':') { |
|
123 return 1; |
|
124 } |
|
125 |
|
126 tparts.tm_sec = strtoul(str, &str, 10); |
|
127 } else { |
|
128 // minutes (and seconds) are one big integer |
|
129 tparts.tm_sec = val % 100; |
|
130 tparts.tm_min = (val % 10000) / 100; |
|
131 tparts.tm_hour = val / 10000; |
|
132 } |
|
133 |
|
134 // parse fractional seconds, but skip them (we return a time_t) |
|
135 if(*str == ',' || *str == '.') { |
|
136 do { |
|
137 str++; |
|
138 } while(isdigit(*str)); |
|
139 } |
|
140 |
132 |
141 // parse time zone (if any) |
133 // parse time zone (if any) |
142 if(*str == 'Z') { |
134 if(tzinfo.length == 0) { |
143 str++; |
|
144 *result = mktime(&tparts) - timezone; |
|
145 } else if (*str == '+' || *str == '-') { |
|
146 int sign = (*str == '+') ? -1 : 1; |
|
147 |
|
148 val = strtoul(str + 1, &str, 10); |
|
149 |
|
150 if (*str == ':') { |
|
151 val = 60 * val + strtoul(str + 1, &str, 10); |
|
152 } else { |
|
153 val = 60 * (val / 100) + (val % 100); |
|
154 } |
|
155 |
|
156 *result = mktime(&tparts) - timezone + (time_t) (60 * val * sign); |
|
157 } else { |
|
158 // local time |
135 // local time |
159 tparts.tm_isdst = -1; |
136 tparts.tm_isdst = -1; |
160 *result = mktime(&tparts); |
137 return mktime(&tparts); |
161 } |
138 } else if(!sstrcmp(tzinfo, S("Z"))) { |
162 |
139 return mktime(&tparts) - timezone; |
163 // skip trailing spaces |
140 } else if(tzinfo.ptr[0] == '+' || tzinfo.ptr[0] == '-') { |
164 while(isspace(*str)) { |
141 int sign = (tzinfo.ptr[0] == '+') ? -1 : 1; |
165 str++; |
142 |
166 } |
143 if(tzinfo.length > 6) { |
167 |
144 return 0; |
168 // string must be zero terminated, no further characters may follow |
145 } else { |
169 return *str != '\0'; // return zero on success |
146 tzinfo.ptr++; tzinfo.length--; |
|
147 extractval(tzinfo, conv, ':'); |
|
148 val = atol(conv); |
|
149 val = 60 * (val / 100) + (val % 100); |
|
150 |
|
151 return mktime(&tparts) - timezone + (time_t) (60 * val * sign); |
|
152 } |
|
153 } else { |
|
154 return 0; |
|
155 } |
170 } |
156 } |
171 |
157 |
172 |
158 |
173 time_t util_parse_creationdate(char *str) { |
159 time_t util_parse_creationdate(char *str) { |
174 // parse a ISO-8601 date (rfc-3339) |
160 // parse a ISO-8601 date (rfc-3339) |
175 // example: 2012-11-29T21:35:35Z |
161 // example: 2012-11-29T21:35:35Z |
176 if(!str) { |
162 if(!str) { |
177 return 0; |
163 return 0; |
178 } |
164 } |
179 |
165 |
180 time_t result; |
166 return parse_iso8601(str); |
181 if(!parse_iso8601(str, &result)) { |
|
182 return result; |
|
183 } else { |
|
184 return 0; |
|
185 } |
|
186 } |
167 } |
187 |
168 |
188 time_t util_parse_lastmodified(char *str) { |
169 time_t util_parse_lastmodified(char *str) { |
189 // parse a rfc-1123 date |
170 // parse a rfc-1123 date |
190 // example: Thu, 29 Nov 2012 21:35:35 GMT |
171 // example: Thu, 29 Nov 2012 21:35:35 GMT |