diff options
author | Lev Walkin <vlm@lionet.info> | 2005-07-03 05:32:40 +0000 |
---|---|---|
committer | Lev Walkin <vlm@lionet.info> | 2005-07-03 05:32:40 +0000 |
commit | 535612a3f78980f6737bab9fdaf3983a991c1707 (patch) | |
tree | 2db18f7607f55539a55709fdaf3f48641ea26642 /skeletons | |
parent | 026661996e34894c8a8bc9101a4131a3d9412524 (diff) |
API extended to support fractions of seconds
Diffstat (limited to 'skeletons')
-rw-r--r-- | skeletons/GeneralizedTime.c | 166 | ||||
-rw-r--r-- | skeletons/GeneralizedTime.h | 13 | ||||
-rw-r--r-- | skeletons/tests/check-GeneralizedTime.c | 113 | ||||
-rw-r--r-- | skeletons/tests/check-UTCTime.c | 5 | ||||
-rw-r--r-- | skeletons/tests/check-UTF8String.c | 2 |
5 files changed, 204 insertions, 95 deletions
diff --git a/skeletons/GeneralizedTime.c b/skeletons/GeneralizedTime.c index 770a3043..45a082bd 100644 --- a/skeletons/GeneralizedTime.c +++ b/skeletons/GeneralizedTime.c @@ -108,7 +108,7 @@ static time_t timegm(struct tm *tm) { #endif /* _EMULATE_TIMEGM */ -#ifndef __NO_ASN_TABLE__ +#ifndef __ASN_INTERNAL_TEST_MODE__ /* * GeneralizedTime basic type description. @@ -139,7 +139,7 @@ asn_TYPE_descriptor_t asn_DEF_GeneralizedTime = { 0 /* No specifics */ }; -#endif /* __NO_ASN_TABLE__ */ +#endif /* __ASN_INTERNAL_TEST_MODE__ */ /* * Check that the time looks like the time. @@ -163,76 +163,70 @@ GeneralizedTime_constraint(asn_TYPE_descriptor_t *td, const void *sptr, } asn_enc_rval_t -GeneralizedTime_encode_der(asn_TYPE_descriptor_t *td, void *ptr, +GeneralizedTime_encode_der(asn_TYPE_descriptor_t *td, void *sptr, int tag_mode, ber_tlv_tag_t tag, asn_app_consume_bytes_f *cb, void *app_key) { - GeneralizedTime_t *st = (GeneralizedTime_t *)ptr; + GeneralizedTime_t *st = (GeneralizedTime_t *)sptr; asn_enc_rval_t erval; + long fv, fb; /* seconds fraction value and base */ + struct tm tm; + time_t tloc; - /* If not canonical DER, re-encode into canonical DER. */ - if(st->size && st->buf[st->size-1] != 0x5a) { - struct tm tm; - time_t tloc; + /* + * Encode as a canonical DER. + */ + errno = EPERM; + tloc = asn_GT2time_frac(st, &fv, &fb, &tm, 1); /* Recognize time */ + if(tloc == -1 && errno != EPERM) + /* Failed to recognize time. Fail completely. */ + _ASN_ENCODE_FAILED; - errno = EPERM; - tloc = asn_GT2time(st, &tm, 1); /* Recognize time */ - if(tloc == -1 && errno != EPERM) { - /* Failed to recognize time. Fail completely. */ - erval.encoded = -1; - erval.failed_type = td; - erval.structure_ptr = ptr; - return erval; - } - st = asn_time2GT(0, &tm, 1); /* Save time canonically */ - if(!st) { - /* Memory allocation failure. */ - erval.encoded = -1; - erval.failed_type = td; - erval.structure_ptr = ptr; - return erval; - } - } + st = asn_time2GT_frac(0, &tm, fv, fb, 1); /* Save time canonically */ + if(!st) _ASN_ENCODE_FAILED; /* Memory allocation failure. */ erval = OCTET_STRING_encode_der(td, st, tag_mode, tag, cb, app_key); - if(st != ptr) { - FREEMEM(st->buf); - FREEMEM(st); - } + FREEMEM(st->buf); + FREEMEM(st); return erval; } +#ifndef __ASN_INTERNAL_TEST_MODE__ + asn_enc_rval_t GeneralizedTime_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, int ilevel, enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb, void *app_key) { - OCTET_STRING_t st; if(flags & XER_F_CANONICAL) { - char buf[32]; + GeneralizedTime_t *gt; + asn_enc_rval_t rv; + long fv, fb; /* fractional parts */ struct tm tm; - ssize_t ret; errno = EPERM; - if(asn_GT2time((GeneralizedTime_t *)sptr, &tm, 1) == -1 + if(asn_GT2time_frac((GeneralizedTime_t *)sptr, + &fv, &fb, &tm, 1) == -1 && errno != EPERM) _ASN_ENCODE_FAILED; + + gt = asn_time2GT_frac(0, &tm, fv, fb, 1); + if(!gt) _ASN_ENCODE_FAILED; - ret = snprintf(buf, sizeof(buf), "%04d%02d%02d%02d%02d%02dZ", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - assert(ret > 0 && ret < (int)sizeof(buf)); - - st.buf = (uint8_t *)buf; - st.size = ret; - sptr = &st; + rv = OCTET_STRING_encode_xer_utf8(td, sptr, ilevel, flags, + cb, app_key); + asn_DEF_GeneralizedTime.free_struct(&asn_DEF_GeneralizedTime, + gt, 0); + return rv; + } else { + return OCTET_STRING_encode_xer_utf8(td, sptr, ilevel, flags, + cb, app_key); } - - return OCTET_STRING_encode_xer_utf8(td, sptr, ilevel, flags, - cb, app_key); } +#endif /* __ASN_INTERNAL_TEST_MODE__ */ + int GeneralizedTime_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { @@ -251,7 +245,7 @@ GeneralizedTime_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, return (cb("<bad-value>", 11, app_key) < 0) ? -1 : 0; ret = snprintf(buf, sizeof(buf), - "%04d-%02d-%02d %02d:%02d%02d (GMT)", + "%04d-%02d-%02d %02d:%02d:%02d (GMT)", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); assert(ret > 0 && ret < (int)sizeof(buf)); @@ -263,6 +257,11 @@ GeneralizedTime_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, time_t asn_GT2time(const GeneralizedTime_t *st, struct tm *ret_tm, int as_gmt) { + return asn_GT2time_frac(st, 0, 0, ret_tm, as_gmt); +} + +time_t +asn_GT2time_frac(const GeneralizedTime_t *st, long *frac_value, long *frac_base, struct tm *ret_tm, int as_gmt) { struct tm tm_s; uint8_t *buf; uint8_t *end; @@ -270,6 +269,8 @@ asn_GT2time(const GeneralizedTime_t *st, struct tm *ret_tm, int as_gmt) { int gmtoff_m = 0; int gmtoff = 0; /* h + m */ int offset_specified = 0; + long fvalue = 0; + long fbase = 1; time_t tloc; if(!st || !st->buf) { @@ -365,13 +366,21 @@ asn_GT2time(const GeneralizedTime_t *st, struct tm *ret_tm, int as_gmt) { * ^ ^ */ switch(*buf) { - case 0x2C: case 0x2E: /* (.|,) */ - /* Fractions of seconds are not supported - * by time_t or struct tm. Skip them */ + case 0x2C: case 0x2E: /* (.|,) */ + /* + * Process fractions of seconds. + */ for(buf++; buf < end; buf++) { - switch(*buf) { + int v = *buf; + switch(v) { case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: + if((fbase * 10 / fbase) != 10) { + /* Not enough precision, ignore */ + } else { + fbase *= 10; + fvalue = fvalue * 10 + (v - 0x30); + } continue; default: break; @@ -479,15 +488,29 @@ local_finish: } } + /* Fractions of seconds */ + if(frac_value) *frac_value = fvalue; + if(frac_base) *frac_base = fbase; + return tloc; } - GeneralizedTime_t * asn_time2GT(GeneralizedTime_t *opt_gt, const struct tm *tm, int force_gmt) { + return asn_time2GT_frac(opt_gt, tm, 0, 0, force_gmt); +} + +GeneralizedTime_t * +asn_time2GT_frac(GeneralizedTime_t *opt_gt, const struct tm *tm, long frac_value, long frac_base, int force_gmt) { struct tm tm_s; long gmtoff; - const unsigned int buf_size = 24; /* 4+2+2 +2+2+2 +4 + cushion */ + const unsigned int buf_size = + 4 + 2 + 2 /* yyyymmdd */ + + 2 + 2 + 2 /* hhmmss */ + + 1 + 6 /* .ffffff */ + + 1 + 4 /* +hhmm */ + + 1 /* '\0' */ + ; char *buf; char *p; int size; @@ -524,17 +547,48 @@ asn_time2GT(GeneralizedTime_t *opt_gt, const struct tm *tm, int force_gmt) { tm->tm_min, tm->tm_sec ); - assert(size == 14); + if(size != 14) { + /* Could be assert(size == 14); */ + FREEMEM(buf); + errno = EINVAL; + return 0; + } p = buf + size; + + /* + * Deal with fractions. + */ + if(frac_base >= 10 && frac_value > 0) { + char *end = p + 1 + 6; /* '.' + maximum 6 digits */ + char *z; + *p++ = '.'; + do { + int digit; + frac_base /= 10; + digit = frac_value / frac_base; + frac_value %= frac_base; + *p++ = digit + 0x30; + } while(frac_base >= 10 && frac_value > 0 && p < end); + for(z = p - 1; *z == 0x30; --z); /* Strip zeroes */ + p = z + (*z != '.'); + size = p - buf; + } + if(force_gmt) { *p++ = 0x5a; /* "Z" */ *p++ = 0; size++; } else { - int ret = snprintf(p, buf_size - size, "%+03ld%02ld", - gmtoff / 3600, gmtoff % 3600); - assert(ret >= 5 && ret <= 7); + int ret; + gmtoff %= 86400; + ret = snprintf(p, buf_size - size, "%+03ld%02ld", + gmtoff / 3600, labs(gmtoff % 3600)); + if(ret != 5) { + FREEMEM(buf); + errno = EINVAL; + return 0; + } size += ret; } diff --git a/skeletons/GeneralizedTime.h b/skeletons/GeneralizedTime.h index 21a680cb..90f7e089 100644 --- a/skeletons/GeneralizedTime.h +++ b/skeletons/GeneralizedTime.h @@ -32,14 +32,21 @@ struct tm; /* <time.h> */ time_t asn_GT2time(const GeneralizedTime_t *, struct tm *_optional_tm4fill, int as_gmt); +/* A version of the above function also returning the fractions of seconds */ +time_t asn_GT2time_frac(const GeneralizedTime_t *, + long *frac_value, long *frac_base, /* (value/base) */ + struct tm *_optional_tm4fill, int as_gmt); + /* * Convert a struct tm into GeneralizedTime. - * If __opt_gt is not given, this function will try to allocate one. + * If _optional_gt is not given, this function will try to allocate one. * If force_gmt is given, the resulting GeneralizedTime will be forced * into a GMT time zone (encoding ends with a "Z"). * On error, this function returns 0 and sets errno. */ -GeneralizedTime_t *asn_time2GT(GeneralizedTime_t *__opt_gt, const struct tm *, - int force_gmt); +GeneralizedTime_t *asn_time2GT(GeneralizedTime_t *_optional_gt, + const struct tm *, int force_gmt); +GeneralizedTime_t *asn_time2GT_frac(GeneralizedTime_t *_optional_gt, + const struct tm *, long frac_value, long frac_base, int force_gmt); #endif /* _GeneralizedTime_H_ */ diff --git a/skeletons/tests/check-GeneralizedTime.c b/skeletons/tests/check-GeneralizedTime.c index ff20772b..abd44b0f 100644 --- a/skeletons/tests/check-GeneralizedTime.c +++ b/skeletons/tests/check-GeneralizedTime.c @@ -1,31 +1,34 @@ -#define __NO_ASN_TABLE__ +#define __ASN_INTERNAL_TEST_MODE__ #include <GeneralizedTime.c> #include <constraints.c> static void -check(char *time_str, time_t expect, int as_gmt) { +recognize(char *time_str, time_t expect, int as_gmt) { GeneralizedTime_t gt; struct tm tm; time_t tloc; + long fv, fb; - gt.buf = time_str; + gt.buf = (uint8_t *)time_str; gt.size = strlen(time_str); - tloc = asn_GT2time(>, &tm, as_gmt); + tloc = asn_GT2time_frac(>, &fv, &fb, &tm, as_gmt); printf("%s: [%s] -> %ld == %ld\n", as_gmt?"GMT":"ofs", time_str, (long)tloc, (long)expect); if(tloc != -1) { - printf("\t%04d-%02d-%02dT%02d:%02d:%02d%+03ld%02ld\n", + printf("\t%04d-%02d-%02dT%02d:%02d:%02d(.%ld/%ld)%+03ld%02ld\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, + fv, fb, (GMTOFF(tm) / 3600), labs(GMTOFF(tm) % 3600) ); + assert(fb < 100 || (fb % 100) == 0); } assert(tloc == expect); @@ -33,11 +36,11 @@ check(char *time_str, time_t expect, int as_gmt) { assert(tloc == -1 || as_gmt == 0 || GMTOFF(tm) == 0); #endif - if(!as_gmt) check(time_str, expect, 1); + if(!as_gmt) recognize(time_str, expect, 1); } static void -rcheck(time_t tloc, const char *expect, int force_gmt) { +encode(time_t tloc, const char *expect, int force_gmt) { GeneralizedTime_t *gt; struct tm tm, *tmp; @@ -49,51 +52,97 @@ rcheck(time_t tloc, const char *expect, int force_gmt) { assert(expect); printf("[%s] vs [%s] (%d)\n", gt->buf, expect, force_gmt); - assert(gt->size == (int)strlen(gt->buf)); - assert(!strcmp(gt->buf, expect)); + assert(gt->size == (int)strlen((char *)gt->buf)); + assert(!strcmp((char *)gt->buf, expect)); } else { assert(!expect); } } + +static void +recode(char *time_str, const char *expect) { + long frac_value, frac_base; + GeneralizedTime_t gt; + struct tm tm; + time_t tloc; + + gt.buf = (uint8_t *)time_str; + gt.size = strlen(time_str); + + tloc = asn_GT2time_frac(>, &frac_value, &frac_base, &tm, 1); + assert(tloc != -1); + + gt.buf = 0; + asn_time2GT_frac(>, &tm, frac_value, frac_base, 1); + assert(gt.buf); + + printf("[%s] => [%s] == [%s]\n", time_str, gt.buf, expect); + + assert(strcmp((char *)gt.buf, expect) == 0); + FREEMEM(gt.buf); +} + int main(int ac, char **av) { (void)av; - check("200401250", -1, 0); - check("2004012509300", -1, 0); - check("20040125093000-", -1, 0); - check("20040125093007-0", -1, 0); - check("20040125093007-080", -1, 0); - check("200401250930.01Z", -1, 0); + recognize("200401250", -1, 0); + recognize("2004012509300", -1, 0); + recognize("20040125093000-", -1, 0); + recognize("20040125093007-0", -1, 0); + recognize("20040125093007-080", -1, 0); + recognize("200401250930.01Z", -1, 0); /* These six are from X.690:11.7.5 */ - check("19920520240000Z", -1, 0); /* midnight represented incorrectly */ - //check("19920622123421.0Z", -1, 0); /* spurious trailing zeros */ - //check("19920722132100.30Z", -1, 0); /* spurious trailing zeros */ - check("19920521000000Z", 706406400, 0); - check("19920622123421Z", 709216461, 0); - check("19920722132100.3Z", 711811260, 0); + recognize("19920520240000Z", -1, 0); /* midnight represented incorrectly */ + recognize("19920622123421.0Z", 709216461, 0); /* spurious trailing zeros */ + recognize("19920722132100.30Z", 711811260, 0); /* spurious trailing zeros */ + recognize("19920521000000Z", 706406400, 0); + recognize("19920622123421Z", 709216461, 0); + recognize("19920722132100.3Z", 711811260, 0); + + recognize("20040125093007Z", 1075023007, 0); + recognize("20040125093007+00", 1075023007, 0); + recognize("20040125093007.01+0000", 1075023007, 0); + recognize("20040125093007,1+0000", 1075023007, 0); + recognize("20040125093007-0800", 1075051807, 0); - check("20040125093007Z", 1075023007, 0); - check("20040125093007+00", 1075023007, 0); - check("20040125093007.01+0000", 1075023007, 0); - check("20040125093007,1+0000", 1075023007, 0); - check("20040125093007-0800", 1075051807, 0); + recognize("19920722132100.123000123Z", 711811260, 0); + recognize("19920722132100.1230000123Z", 711811260, 0); + recognize("19920722132100.12300000123Z", 711811260, 0); - rcheck(1075023007, "20040125093007Z", 1); + encode(1075023007, "20040125093007Z", 1); if(ac > 1) { /* These will be valid only inside PST time zone */ - check("20040125093007", 1075051807, 0); - check("200401250930", 1075051800, 0); - check("20040125093000,01", 1075051800, 0); - check("20040125093000,1234", 1075051800, 0); + recognize("20040125093007", 1075051807, 0); + recognize("200401250930", 1075051800, 0); + recognize("20040125093000,01", 1075051800, 0); + recognize("20040125093000,1234", 1075051800, 0); - rcheck(1075023007, "20040125013007-0800", 0); + encode(1075023007, "20040125013007-0800", 0); + recode("20050702123312", "20050702193312Z"); } + recode("20050702123312Z", "20050702123312Z"); + recode("20050702123312+01", "20050702113312Z"); + recode("20050702123312,0+01", "20050702113312Z"); + recode("20050702123312,1+01", "20050702113312.1Z"); + recode("20050702123312.01+01", "20050702113312.01Z"); + recode("20050702123312.00+01", "20050702113312Z"); + recode("20050702123312.30+01", "20050702113312.3Z"); + recode("20050702123312,30000+01", "20050702113312.3Z"); + recode("20050702123312,300000000+01", "20050702113312.3Z"); + recode("20050702123312.123456+01", "20050702113312.123456Z"); + recode("20050702123312.1234567+01", "20050702113312.123456Z"); + recode("20050702123312.12345678+01", "20050702113312.123456Z"); + recode("20050702123312.123456789+01", "20050702113312.123456Z"); + recode("20050702123312.000001+01", "20050702113312.000001Z"); + recode("20050702123312.0000001Z", "20050702123312Z"); + recode("20050702123312.0080010+1056", "20050702013712.008001Z"); + return 0; } diff --git a/skeletons/tests/check-UTCTime.c b/skeletons/tests/check-UTCTime.c index 4c76858b..96803ad6 100644 --- a/skeletons/tests/check-UTCTime.c +++ b/skeletons/tests/check-UTCTime.c @@ -1,6 +1,5 @@ -#define __NO_ASN_TABLE__ +#define __ASN_INTERNAL_TEST_MODE__ #include <GeneralizedTime.c> -#define __NO_ASN_TABLE__ #include <UTCTime.c> #include <constraints.c> @@ -10,7 +9,7 @@ check(char *time_str, time_t sample, int as_gmt) { struct tm tm; time_t tloc; - gt.buf = time_str; + gt.buf = (uint8_t *)time_str; gt.size = strlen(time_str); tloc = asn_UT2time(>, &tm, as_gmt); diff --git a/skeletons/tests/check-UTF8String.c b/skeletons/tests/check-UTF8String.c index ae368eab..10592a19 100644 --- a/skeletons/tests/check-UTF8String.c +++ b/skeletons/tests/check-UTF8String.c @@ -43,7 +43,7 @@ check_speed() { int ret; int i; - st.buf = long_test; + st.buf = (uint8_t *)long_test; st.size = sizeof(long_test) - 1; ret = UTF8String_length(&st); |