# HG changeset patch # User Mike Becker # Date 1444744471 -7200 # Node ID ba8f1691c0ee06f7a5cbbc4160f7971f1ce9439d # Parent 7e0a8912ca25d3d89475a519733e664a68f69825 added parser for iso8601 dates diff -r 7e0a8912ca25 -r ba8f1691c0ee libidav/utils.c --- a/libidav/utils.c Tue Oct 13 14:23:15 2015 +0200 +++ b/libidav/utils.c Tue Oct 13 15:54:31 2015 +0200 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -56,15 +57,132 @@ #include "crypto.h" #include "webdav.h" +static int parse_iso8601(char *str, time_t *result) { + + // safety + if(!str || !result) { + return 1; + } + + struct tm tparts; + memset(&tparts, 0, sizeof(struct tm)); + *result = 0; + long val; + + // skip leading spaces + while(isspace(*str)) { + str++; + } + + // ensure we have numeric values (maybe with sign) + if(!isdigit(*str) && *str != '-' && *str != '+') { + return 1; + } + + // starting parsing the year + val = strtoul(str, &str, 10); + + if(*str == '-') { + // month (and day) seem to be dash separated + tparts.tm_year = val - 1900; + str++; + tparts.tm_mon = strtoul(str, &str, 10) - 1; + + if (*str++ != '-') { + return 1; + } + + tparts.tm_mday = strtoul(str, &str, 10); + } else { + // year, month, day was parsed as one big integer + tparts.tm_mday = val % 100; + tparts.tm_mon = (val % 10000) / 100 - 1; + tparts.tm_year = val / 10000 - 1900; + } + + // time separator + if(*str != 'T') { + return 1; + } + str++; + + // ensure we have numeric values (unsigned) + if(!isdigit(*str)) { + return 1; + } + + // start parsing the hour + val = strtoul(str, &str, 10); + if(*str == ':') { + // minutes (and seconds) are separated by colon + tparts.tm_hour = val; + str++; + tparts.tm_min = strtoul(str, &str, 10); + + if(*str++ != ':') { + return 1; + } + + tparts.tm_sec = strtoul(str, &str, 10); + } else { + // minutes (and seconds) are one big integer + tparts.tm_sec = val % 100; + tparts.tm_min = (val % 10000) / 100; + tparts.tm_hour = val / 10000; + } + + // parse fractional seconds, but skip them (we return a time_t) + if(*str == ',' || *str == '.') { + do { + str++; + } while(isdigit(*str)); + } + + // parse time zone (if any) + if(*str == 'Z') { + str++; + *result = mktime(&tparts) - timezone; + } else if (*str == '+' || *str == '-') { + int sign = (*str == '+') ? -1 : 1; + + val = strtoul(str + 1, &str, 10); + + if (*str == ':') { + val = 60 * val + strtoul(str + 1, &str, 10); + } else { + val = 60 * (val / 100) + (val % 100); + } + + *result = mktime(&tparts) - timezone + (time_t) (60 * val * sign); + } else { + // local time + tparts.tm_isdst = -1; + *result = mktime(&tparts); + } + + // skip trailing spaces + while(isspace(*str)) { + str++; + } + + // string must be zero terminated, no further characters may follow + return *str != '\0'; // return zero on success +} + time_t util_parse_creationdate(char *str) { - // parse a ISO-8601 date + // parse a ISO-8601 date (rfc-3339) // example: 2012-11-29T21:35:35Z if(!str) { return 0; } - // TODO: implement - return 0; + + time_t result; + if(!parse_iso8601(str, &result)) { + return result; + } else { + return 0; + } } time_t util_parse_lastmodified(char *str) {