diff options
author | Lev Walkin <vlm@lionet.info> | 2005-07-04 12:21:51 +0000 |
---|---|---|
committer | Lev Walkin <vlm@lionet.info> | 2005-07-04 12:21:51 +0000 |
commit | 3a52278ac5d01209159cd3b30074646b6133b6e9 (patch) | |
tree | 2576f882e1eb9ce7d50ff72742b01de99214b3ff | |
parent | ca5876ae8cb59f670b2773adbbc0eb43b517378f (diff) |
new decimal point paradigm
-rw-r--r-- | skeletons/GeneralizedTime.c | 87 | ||||
-rw-r--r-- | skeletons/GeneralizedTime.h | 13 | ||||
-rw-r--r-- | skeletons/tests/check-GeneralizedTime.c | 96 |
3 files changed, 131 insertions, 65 deletions
diff --git a/skeletons/GeneralizedTime.c b/skeletons/GeneralizedTime.c index 51070406..9103455d 100644 --- a/skeletons/GeneralizedTime.c +++ b/skeletons/GeneralizedTime.c @@ -168,7 +168,7 @@ GeneralizedTime_encode_der(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { GeneralizedTime_t *st = (GeneralizedTime_t *)sptr; asn_enc_rval_t erval; - long fv, fb; /* seconds fraction value and base */ + int fv, fd; /* seconds fraction value and number of digits */ struct tm tm; time_t tloc; @@ -176,12 +176,12 @@ GeneralizedTime_encode_der(asn_TYPE_descriptor_t *td, void *sptr, * Encode as a canonical DER. */ errno = EPERM; - tloc = asn_GT2time_frac(st, &fv, &fb, &tm, 1); /* Recognize time */ + tloc = asn_GT2time_frac(st, &fv, &fd, &tm, 1); /* Recognize time */ if(tloc == -1 && errno != EPERM) /* Failed to recognize time. Fail completely. */ _ASN_ENCODE_FAILED; - st = asn_time2GT_frac(0, &tm, fv, fb, 1); /* Save time canonically */ + st = asn_time2GT_frac(0, &tm, fv, fd, 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); @@ -202,16 +202,16 @@ GeneralizedTime_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, if(flags & XER_F_CANONICAL) { GeneralizedTime_t *gt; asn_enc_rval_t rv; - long fv, fb; /* fractional parts */ + int fv, fd; /* fractional parts */ struct tm tm; errno = EPERM; if(asn_GT2time_frac((GeneralizedTime_t *)sptr, - &fv, &fb, &tm, 1) == -1 + &fv, &fd, &tm, 1) == -1 && errno != EPERM) _ASN_ENCODE_FAILED; - gt = asn_time2GT_frac(0, &tm, fv, fb, 1); + gt = asn_time2GT_frac(0, &tm, fv, fd, 1); if(!gt) _ASN_ENCODE_FAILED; rv = OCTET_STRING_encode_xer_utf8(td, sptr, ilevel, flags, @@ -261,7 +261,37 @@ asn_GT2time(const GeneralizedTime_t *st, struct tm *ret_tm, int as_gmt) { } time_t -asn_GT2time_frac(const GeneralizedTime_t *st, long *frac_value, long *frac_base, struct tm *ret_tm, int as_gmt) { +asn_GT2time_prec(const GeneralizedTime_t *st, int *frac_value, int frac_digits, struct tm *ret_tm, int as_gmt) { + time_t tloc; + int fv, fd = 0; + + if(frac_value) + tloc = asn_GT2time_frac(st, &fv, &fd, ret_tm, as_gmt); + else + return asn_GT2time_frac(st, 0, 0, ret_tm, as_gmt); + if(fd == 0 || frac_digits <= 0) { + *frac_value = 0; + } else { + while(fd > frac_digits) + fv /= 10, fd--; + while(fd < frac_digits) { + int new_fv = fv * 10; + if(new_fv / 10 != fv) { + /* Too long precision request */ + fv = 0; + break; + } + fv = new_fv, fd++; + } + + *frac_value = fv; + } + + return tloc; +} + +time_t +asn_GT2time_frac(const GeneralizedTime_t *st, int *frac_value, int *frac_digits, struct tm *ret_tm, int as_gmt) { struct tm tm_s; uint8_t *buf; uint8_t *end; @@ -269,8 +299,8 @@ asn_GT2time_frac(const GeneralizedTime_t *st, long *frac_value, long *frac_base, int gmtoff_m = 0; int gmtoff = 0; /* h + m */ int offset_specified = 0; - long fvalue = 0; - long fbase = 1; + int fvalue = 0; + int fdigits = 0; time_t tloc; if(!st || !st->buf) { @@ -372,14 +402,16 @@ asn_GT2time_frac(const GeneralizedTime_t *st, long *frac_value, long *frac_base, */ for(buf++; buf < end; buf++) { int v = *buf; + int new_fvalue; 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) { + new_fvalue = fvalue * 10 + (v - 0x30); + if(new_fvalue / 10 != fvalue) { /* Not enough precision, ignore */ } else { - fbase *= 10; - fvalue = fvalue * 10 + (v - 0x30); + fvalue = new_fvalue; + fdigits++; } continue; default: @@ -490,7 +522,7 @@ local_finish: /* Fractions of seconds */ if(frac_value) *frac_value = fvalue; - if(frac_base) *frac_base = fbase; + if(frac_digits) *frac_digits = fdigits; return tloc; } @@ -501,7 +533,7 @@ asn_time2GT(GeneralizedTime_t *opt_gt, const struct tm *tm, int force_gmt) { } GeneralizedTime_t * -asn_time2GT_frac(GeneralizedTime_t *opt_gt, const struct tm *tm, long frac_value, long frac_base, int force_gmt) { +asn_time2GT_frac(GeneralizedTime_t *opt_gt, const struct tm *tm, int frac_value, int frac_digits, int force_gmt) { struct tm tm_s; long gmtoff; const unsigned int buf_size = @@ -559,23 +591,28 @@ asn_time2GT_frac(GeneralizedTime_t *opt_gt, const struct tm *tm, long frac_value /* * Deal with fractions. */ - if(frac_base >= 10 - && frac_value > 0 - && (frac_value/frac_base) == 0 - ) { + if(frac_value > 0 && frac_digits > 0) { char *end = p + 1 + 6; /* '.' + maximum 6 digits */ char *z = p; + long fbase; *z++ = '.'; - frac_value %= frac_base; + + /* Place bounds on precision */ + while(frac_digits-- > 6) + frac_value /= 10; + + /* emulate fbase = pow(10, frac_digits) */ + for(fbase = 1; frac_digits--;) + fbase *= 10; + do { - int digit; - frac_base /= 10; - digit = frac_value / frac_base; + int digit = frac_value / fbase; if(digit > 9) { z = 0; break; } - frac_value %= frac_base; *z++ = digit + 0x30; - } while(frac_base >= 10 && frac_value > 0 && z < end); - if(z && (frac_base == 1 || frac_base >= 10)) { + frac_value %= fbase; + fbase /= 10; + } while(fbase > 0 && frac_value > 0 && z < end); + if(z) { for(--z; *z == 0x30; --z); /* Strip zeroes */ p = z + (*z != '.'); size = p - buf; diff --git a/skeletons/GeneralizedTime.h b/skeletons/GeneralizedTime.h index 90f7e089..6b4c1ecc 100644 --- a/skeletons/GeneralizedTime.h +++ b/skeletons/GeneralizedTime.h @@ -34,7 +34,16 @@ time_t asn_GT2time(const GeneralizedTime_t *, struct tm *_optional_tm4fill, /* 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) */ + int *frac_value, int *frac_digits, /* (value / (10 ^ digits)) */ + struct tm *_optional_tm4fill, int as_gmt); + +/* + * Another version returning fractions with defined precision + * For example, parsing of the time ending with ".1" seconds + * with frac_digits=3 (msec) would yield frac_value = 100. + */ +time_t asn_GT2time_prec(const GeneralizedTime_t *, + int *frac_value, int frac_digits, struct tm *_optional_tm4fill, int as_gmt); /* @@ -47,6 +56,6 @@ time_t asn_GT2time_frac(const GeneralizedTime_t *, 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); + const struct tm *, int frac_value, int frac_digits, int force_gmt); #endif /* _GeneralizedTime_H_ */ diff --git a/skeletons/tests/check-GeneralizedTime.c b/skeletons/tests/check-GeneralizedTime.c index 4b9f2661..245e9408 100644 --- a/skeletons/tests/check-GeneralizedTime.c +++ b/skeletons/tests/check-GeneralizedTime.c @@ -1,34 +1,34 @@ #define __ASN_INTERNAL_TEST_MODE__ #include <GeneralizedTime.c> #include <constraints.c> +#include <math.h> /* for pow(3) */ static void recognize(char *time_str, time_t expect, int as_gmt) { GeneralizedTime_t gt; struct tm tm; time_t tloc; - long fv, fb; + int fv, fp; gt.buf = (uint8_t *)time_str; gt.size = strlen(time_str); - tloc = asn_GT2time_frac(>, &fv, &fb, &tm, as_gmt); + tloc = asn_GT2time_frac(>, &fv, &fp, &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(.%ld/%ld)%+03ld%02ld\n", + printf("\t%04d-%02d-%02dT%02d:%02d:%02d.%f(%d/%d)%+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, + (double)fv * pow(0.1, fp), fv, fp, (GMTOFF(tm) / 3600), labs(GMTOFF(tm) % 3600) ); - assert(fb < 100 || (fb % 100) == 0); } assert(tloc == expect); @@ -62,7 +62,7 @@ encode(time_t tloc, const char *expect, int force_gmt) { static void recode(char *time_str, const char *expect) { - long frac_value, frac_base; + int frac_value, frac_digits; GeneralizedTime_t gt; struct tm tm; time_t tloc; @@ -70,14 +70,15 @@ recode(char *time_str, const char *expect) { gt.buf = (uint8_t *)time_str; gt.size = strlen(time_str); - tloc = asn_GT2time_frac(>, &frac_value, &frac_base, &tm, 1); + tloc = asn_GT2time_frac(>, &frac_value, &frac_digits, &tm, 1); assert(tloc != -1); gt.buf = 0; - asn_time2GT_frac(>, &tm, frac_value, frac_base, 1); + asn_time2GT_frac(>, &tm, frac_value, frac_digits, 1); assert(gt.buf); - printf("[%s] => [%s] == [%s]\n", time_str, gt.buf, expect); + printf("[%s] => [%s] == [%s] (%d, %d)\n", + time_str, gt.buf, expect, frac_value, frac_digits); assert(strcmp((char *)gt.buf, expect) == 0); FREEMEM(gt.buf); @@ -87,6 +88,8 @@ static void check_fractions() { GeneralizedTime_t *gt = 0; struct tm tm; + int fv, fd; + time_t tloc; memset(&tm, 0, sizeof tm); tm.tm_year = 70; @@ -117,51 +120,61 @@ check_fractions() { printf("[%s]\n", gt->buf); assert(strcmp((char *)gt->buf, "19700101000000Z") == 0); - /* Normalization should happen prior calling the _frac() */ - gt = asn_time2GT_frac(gt, &tm, 55, 10, 1); - assert(gt); - printf("[%s]\n", gt->buf); - assert(strcmp((char *)gt->buf, "19700101000000Z") == 0); - - gt = asn_time2GT_frac(gt, &tm, 10, 20, 1); + /* Normalization should happen prior to calling the _frac() */ + gt = asn_time2GT_frac(gt, &tm, 55, 2, 1); assert(gt); printf("[%s]\n", gt->buf); - assert(strcmp((char *)gt->buf, "19700101000000Z") == 0); + assert(strcmp((char *)gt->buf, "19700101000000.55Z") == 0); - gt = asn_time2GT_frac(gt, &tm, 10000000, 20000000, 1); + gt = asn_time2GT_frac(gt, &tm, 5, 2, 1); assert(gt); printf("[%s]\n", gt->buf); - assert(strcmp((char *)gt->buf, "19700101000000.5Z") == 0); + assert(strcmp((char *)gt->buf, "19700101000000.05Z") == 0); - gt = asn_time2GT_frac(gt, &tm, -10, 20, 1); + /* Normalization should happen prior calling the _frac() */ + gt = asn_time2GT_frac(gt, &tm, 900, 2, 1); assert(gt); printf("[%s]\n", gt->buf); assert(strcmp((char *)gt->buf, "19700101000000Z") == 0); - gt = asn_time2GT_frac(gt, &tm, 98, 99, 1); + gt = asn_time2GT_frac(gt, &tm, 90, 2, 1); assert(gt); printf("[%s]\n", gt->buf); - assert(strcmp((char *)gt->buf, "19700101000000Z") == 0); + assert(strcmp((char *)gt->buf, "19700101000000.9Z") == 0); - gt = asn_time2GT_frac(gt, &tm, 988, 999, 1); - assert(gt); - printf("[%s]\n", gt->buf); - assert(strcmp((char *)gt->buf, "19700101000000Z") == 0); + tloc = asn_GT2time_prec(gt, &fv, 0, 0, 1); + assert(tloc == 0); + assert(fv == 0); - gt = asn_time2GT_frac(gt, &tm, 90, 91, 1); - assert(gt); - printf("[%s]\n", gt->buf); - assert(strcmp((char *)gt->buf, "19700101000000Z") == 0); + tloc = asn_GT2time_prec(gt, &fv, 1, 0, 1); + assert(tloc == 0); + assert(fv == 9); - gt = asn_time2GT_frac(gt, &tm, 89, 91, 1); - assert(gt); - printf("[%s]\n", gt->buf); - assert(strcmp((char *)gt->buf, "19700101000000Z") == 0); + tloc = asn_GT2time_prec(gt, &fv, 2, 0, 1); + assert(tloc == 0); + assert(fv == 90); - gt = asn_time2GT_frac(gt, &tm, 89000000, 91000000, 1); - assert(gt); - printf("[%s]\n", gt->buf); - assert(strcmp((char *)gt->buf, "19700101000000.978021Z") == 0); + tloc = asn_GT2time_frac(gt, &fv, &fd, 0, 1); + assert(tloc == 0); + assert(fv == 9); + assert(fd == 1); + + gt->buf[gt->size-1] = '0'; + gt->buf[gt->size++] = 'Z'; + gt->buf[gt->size] = '\0'; + + tloc = asn_GT2time_frac(gt, &fv, &fd, 0, 1); + assert(tloc == 0); + assert(fd == 2); + assert(fv == 90); + + tloc = asn_GT2time_prec(gt, &fv, 1, 0, 1); + assert(tloc == 0); + assert(fv == 9); + + tloc = asn_GT2time_prec(gt, &fv, 100, 0, 1); + assert(tloc == 0); + assert(fv == 0); FREEMEM(gt->buf); FREEMEM(gt); @@ -225,6 +238,13 @@ main(int ac, char **av) { recode("20050702123312.1234567+01", "20050702113312.123456Z"); recode("20050702123312.12345678+01", "20050702113312.123456Z"); recode("20050702123312.123456789+01", "20050702113312.123456Z"); + recode("20050702123312.2000000000+01", "20050702113312.2Z"); + recode("20050702123312.3000000000+01", "20050702113312.3Z"); + recode("20050702123312.4000000000+01", "20050702113312.4Z"); + recode("20050702123312.5000000000+01", "20050702113312.5Z"); + recode("20050702123312.5000000001+01", "20050702113312.5Z"); + recode("20050702123312.5000010001+01", "20050702113312.500001Z"); + recode("20050702123312.5000001001+01", "20050702113312.5Z"); recode("20050702123312.000001+01", "20050702113312.000001Z"); recode("20050702123312.0000001Z", "20050702123312Z"); recode("20050702123312.0080010+1056", "20050702013712.008001Z"); |