diff --git a/common/ChangeLog b/common/ChangeLog index f6380c64d..cebc0ece6 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,11 @@ +2011-02-27 Werner Koch + + * gettime.c (isotime2epoch): Factor check code out to .. + (isotime_p): .. new. + (isotime_human_p): New. + (string2isotime): New. + * t-gettime.c (test_string2isotime): New. + 2011-02-11 Andrey Jivsov * openpgp-oid.c (openpgp_oid_to_str): Use unsigned int for diff --git a/common/gettime.c b/common/gettime.c index 27dc8456e..e5462a7c6 100644 --- a/common/gettime.c +++ b/common/gettime.c @@ -1,5 +1,5 @@ /* gettime.c - Wrapper for time functions - * Copyright (C) 1998, 2002, 2007 Free Software Foundation, Inc. + * Copyright (C) 1998, 2002, 2007, 2011 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -179,29 +179,162 @@ scan_isodatestr( const char *string ) return stamp; } -/* Scan am ISO timestamp and return an Epoch based timestamp. The only + +int +isotime_p (const char *string) +{ + const char *s; + int i; + + if (!*string) + return 0; + for (s=string, i=0; i < 8; i++, s++) + if (!digitp (s)) + return 0; + if (*s != 'T') + return 0; + for (s++, i=9; i < 15; i++, s++) + if (!digitp (s)) + return 0; + if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ',')) + return 0; /* Wrong delimiter. */ + + return 1; +} + + +/* Scan a string and return true if the string represents the human + readable format of an ISO time. This format is: + yyyy-mm-dd[ hh[:mm[:ss]]] + Scanning stops at the second space or at a comma. */ +int +isotime_human_p (const char *string) +{ + const char *s; + int i; + + if (!*string) + return 0; + for (s=string, i=0; i < 4; i++, s++) + if (!digitp (s)) + return 0; + if (*s != '-') + return 0; + s++; + if (!digitp (s) || !digitp (s+1) || s[2] != '-') + return 0; + i = atoi_2 (s); + if (i < 1 || i > 12) + return 0; + s += 3; + if (!digitp (s) || !digitp (s+1)) + return 0; + i = atoi_2 (s); + if (i < 1 || i > 31) + return 0; + s += 2; + if (!*s || *s == ',') + return 1; /* Okay; only date given. */ + if (!spacep (s)) + return 0; + s++; + if (spacep (s)) + return 1; /* Okay, second space stops scanning. */ + if (!digitp (s) || !digitp (s+1)) + return 0; + i = atoi_2 (s); + if (i < 0 || i > 23) + return 0; + s += 2; + if (!*s || *s == ',') + return 1; /* Okay; only date and hour given. */ + if (*s != ':') + return 0; + s++; + if (!digitp (s) || !digitp (s+1)) + return 0; + i = atoi_2 (s); + if (i < 0 || i > 59) + return 0; + s += 2; + if (!*s || *s == ',') + return 1; /* Okay; only date, hour and minute given. */ + if (*s != ':') + return 0; + s++; + if (!digitp (s) || !digitp (s+1)) + return 0; + i = atoi_2 (s); + if (i < 0 || i > 60) + return 0; + s += 2; + if (!*s || *s == ',' || spacep (s)) + return 1; /* Okay; date, hour and minute and second given. */ + + return 0; /* Unexpected delimiter. */ +} + +/* Convert a standard isotime or a human readable variant into an + isotime structure. The allowed formats are those described by + isotime_p and isotime_human_p. The function returns 0 on failure + or the length of the scanned string on success. */ +size_t +string2isotime (gnupg_isotime_t atime, const char *string) +{ + gnupg_isotime_t dummyatime; + + if (!atime) + atime = dummyatime; + + atime[0] = 0; + if (isotime_p (string)) + { + memcpy (atime, string, 15); + atime[15] = 0; + return 15; + } + if (!isotime_human_p (string)) + return 0; + atime[0] = string[0]; + atime[1] = string[1]; + atime[2] = string[2]; + atime[3] = string[3]; + atime[4] = string[5]; + atime[5] = string[6]; + atime[6] = string[8]; + atime[7] = string[9]; + atime[8] = 'T'; + memset (atime+9, '0', 6); + atime[15] = 0; + if (!spacep (string+10)) + return 10; + if (spacep (string+11)) + return 11; /* As per def, second space stops scanning. */ + atime[9] = string[11]; + atime[10] = string[12]; + if (string[13] != ':') + return 13; + atime[11] = string[14]; + atime[12] = string[15]; + if (string[16] != ':') + return 16; + atime[13] = string[17]; + atime[14] = string[18]; + return 19; +} + + +/* Scan an ISO timestamp and return an Epoch based timestamp. The only supported format is "yyyymmddThhmmss" delimited by white space, nul, a colon or a comma. Returns (time_t)(-1) for an invalid string. */ time_t isotime2epoch (const char *string) { - const char *s; int year, month, day, hour, minu, sec; struct tm tmbuf; - int i; - if (!*string) + if (!isotime_p (string)) return (time_t)(-1); - for (s=string, i=0; i < 8; i++, s++) - if (!digitp (s)) - return (time_t)(-1); - if (*s != 'T') - return (time_t)(-1); - for (s++, i=9; i < 15; i++, s++) - if (!digitp (s)) - return (time_t)(-1); - if ( !(!*s || (isascii (*s) && isspace(*s)) || *s == ':' || *s == ',')) - return (time_t)(-1); /* Wrong delimiter. */ year = atoi_4 (string); month = atoi_2 (string + 4); diff --git a/common/gettime.h b/common/gettime.h index 731be569b..4199369e4 100644 --- a/common/gettime.h +++ b/common/gettime.h @@ -34,6 +34,9 @@ void gnupg_set_time (time_t newtime, int freeze); int gnupg_faked_time_p (void); u32 make_timestamp (void); u32 scan_isodatestr (const char *string); +int isotime_p (const char *string); +int isotime_human_p (const char *string); +size_t string2isotime (gnupg_isotime_t atime, const char *string); time_t isotime2epoch (const char *string); void epoch2isotime (gnupg_isotime_t timebuf, time_t atime); u32 add_days_to_timestamp (u32 stamp, u16 days); diff --git a/common/t-gettime.c b/common/t-gettime.c index 1cfde69c7..79c3d4335 100644 --- a/common/t-gettime.c +++ b/common/t-gettime.c @@ -1,5 +1,5 @@ /* t-gettime.c - Module test for gettime.c - * Copyright (C) 2007 Free Software Foundation, Inc. + * Copyright (C) 2007, 2011 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -89,6 +89,90 @@ test_isotime2epoch (void) +static void +test_string2isotime (void) +{ + struct { + const char *string; + size_t result; + const char *expected; + } array [] = { + { "19700101T000001", 15, "19700101T000001" }, + { "19700101T235959", 15, "19700101T235959" }, + { "19980815T143712", 15, "19980815T143712" }, + { "19700101T000000", 15, "19700101T000000" }, + { "19691231T235959", 15, "19691231T235959" }, + { "19000101T000000", 15, "19000101T000000" }, + { "", 0, "" }, + { "19000101T00000", 0, "" }, + { "20010101t123456", 0, "" }, + { "20010101T123456", 15, "20010101T123456" }, + { "20070629T160000", 15, "20070629T160000" }, + { "20070629T160000:", 15, "20070629T160000" }, + { "20070629T160000,", 15, "20070629T160000" }, + { "20070629T160000 ", 15, "20070629T160000" }, + { "20070629T160000\n", 15,"20070629T160000" }, + { "20070629T160000.", 0, "" }, + { "1066-03-20", 10, "10660320T000000" }, + { "1066-03-20,", 10, "10660320T000000" }, + { "1066-03-20:", 0, "" }, + { "1066-03-20 00", 13, "10660320T000000" }, + { "1066-03-20 01", 13, "10660320T010000" }, + { "1066-03-20 23", 13, "10660320T230000" }, + { "1066-03-20 24", 0, "" }, + { "1066-03-20 00:", 0, "" }, + { "1066-03-20 00:3", 0, "" }, + { "1066-03-20 00:31", 16, "10660320T003100" }, + { "1066-03-20 00:31:47", 19, "10660320T003147" }, + { "1066-03-20 00:31:47 ", 19, "10660320T003147" }, + { "1066-03-20 00:31:47,", 19, "10660320T003147" }, + { "1066-03-20 00:31:47:", 0, "" }, + { "1-03-20 00:31:47:", 0, "" }, + { "10-03-20 00:31:47:", 0, "" }, + { "106-03-20 00:31:47:", 0, "" }, + { "1066-23-20 00:31:47:", 0, "" }, + { "1066-00-20 00:31:47:", 0, "" }, + { "1066-0-20 00:31:47:", 0, "" }, + { "1066-01-2 00:31:47:", 0, "" }, + { "1066-01-2 00:31:47:", 0, "" }, + { "1066-01-32 00:31:47:", 0, "" }, + { "1066-01-00 00:31:47:", 0, "" }, + { "1066-03-20 00:31:47:",11, "10660320T000000" }, + { "1066-03-2000:31:47:", 0, "" }, + { "10666-03-20 00:31:47:", 0, "" }, + { NULL, 0 } + }; + int idx; + size_t result; + gnupg_isotime_t tbuf; + + for (idx=0; array[idx].string; idx++) + { + result = string2isotime (tbuf, array[idx].string); + if (result != array[idx].result) + { + fail (idx); + if (verbose) + fprintf (stderr, "string `%s' expected: %d, got: %d\n", + array[idx].string, (int)array[idx].result, (int)result); + } + else if (result && strlen (tbuf) != 15) + { + fail (idx); + if (verbose) + fprintf (stderr, "string `%s' invalid isotime returned\n", + array[idx].string); + } + else if (result && strcmp (array[idx].expected, tbuf)) + { + fail (idx); + if (verbose) + fprintf (stderr, "string `%s' bad isotime '%s' returned\n", + array[idx].string, tbuf); + } + } +} + int main (int argc, char **argv) @@ -97,6 +181,7 @@ main (int argc, char **argv) verbose = 1; test_isotime2epoch (); + test_string2isotime (); return !!errcount; } diff --git a/common/tlv.c b/common/tlv.c index 54ef6fca6..61f770e93 100644 --- a/common/tlv.c +++ b/common/tlv.c @@ -238,14 +238,14 @@ _parse_ber_header (unsigned char const **buffer, size_t *size, is the pointer to the S-expression and BUFLEN is a pointer to the length of this S-expression (used to validate the syntax). Both are updated to reflect the new position. The token itself is - returned as a pointer into the orginal buffer at TOK and TOKLEN. + returned as a pointer into the original buffer at TOK and TOKLEN. If a parentheses is the next token, TOK will be set to NULL. - TOKLEN is checked to be within the bounds. On error a error code - is returned and all pointers should are not guaranteed to point to - a meanigful value. DEPTH should be initialized to 0 and will + TOKLEN is checked to be within the bounds. On error an error code + is returned and no pointer is not guaranteed to point to + a meaningful value. DEPTH should be initialized to 0 and will reflect on return the actual depth of the tree. To detect the end of the S-expression it is advisable to check DEPTH after a - successful return: + successful return. depth = 0; while (!(err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)) diff --git a/common/tlv.h b/common/tlv.h index c7fafd547..fd57e1e90 100644 --- a/common/tlv.h +++ b/common/tlv.h @@ -90,15 +90,15 @@ gpg_error_t _parse_ber_header (unsigned char const **buffer, size_t *size, GPG_ERR_SOURCE_DEFAULT) -/* Return the next token of an canconical encoded S-expression. BUF +/* Return the next token of an canonical encoded S-expression. BUF is the pointer to the S-expression and BUFLEN is a pointer to the length of this S-expression (used to validate the syntax). Both are updated to reflect the new position. The token itself is - returned as a pointer into the orginal buffer at TOK and TOKLEN. + returned as a pointer into the original buffer at TOK and TOKLEN. If a parentheses is the next token, TOK will be set to NULL. - TOKLEN is checked to be within the bounds. On error a error code - is returned and all pointers should are not guaranteed to point to - a meanigful value. DEPTH should be initialized to 0 and will + TOKLEN is checked to be within the bounds. On error an error code + is returned and no pointer is not guaranteed to point to + a meaningful value. DEPTH should be initialized to 0 and will reflect on return the actual depth of the tree. To detect the end of the S-expression it is advisable to check DEPTH after a successful return. */