libidav/utils.c

changeset 177
3c0734eeab33
parent 176
747f3796eddd
child 181
a8f8cdbf85df
equal deleted inserted replaced
176:747f3796eddd 177:3c0734eeab33
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

mercurial