diff --git a/skeletons/OBJECT_IDENTIFIER.c b/skeletons/OBJECT_IDENTIFIER.c index 0a27c8ca..c4176160 100644 --- a/skeletons/OBJECT_IDENTIFIER.c +++ b/skeletons/OBJECT_IDENTIFIER.c @@ -3,6 +3,7 @@ * Redistribution and modifications are permitted subject to BSD license. */ #include +#include /* for CHAR_BIT */ #include #include @@ -91,34 +92,100 @@ OBJECT_IDENTIFIER_constraint(asn1_TYPE_descriptor_t *td, const void *sptr, } int -OBJECT_IDENTIFIER_get_arc_l(uint8_t *arcbuf, int arclen, int add, unsigned long *rvalue) { - unsigned long accum; - uint8_t *arcend = arcbuf + arclen; +OBJECT_IDENTIFIER_get_single_arc(uint8_t *arcbuf, unsigned int arclen, signed int add, void *rvbuf, unsigned int rvsize) { + unsigned LE = 1; /* Little endian (x86) */ + uint8_t *arcend = arcbuf + arclen; /* End of arc */ + void *rvstart = rvbuf; /* Original start of the value buffer */ + unsigned int cache = 0; /* No more than 14 significant bits */ + int inc; /* Return value growth direction */ - if((size_t)arclen * 7 > 8 * sizeof(accum)) { - if((size_t)arclen * 7 <= 8 * (sizeof(accum) + 1)) { - if((*arcbuf & ~0x8f)) { + rvsize *= CHAR_BIT; /* bytes to bits */ + arclen *= 7; /* bytes to bits */ + + /* + * The arc has the number of bits + * cannot be represented using supplied return value type. + */ + if(arclen > rvsize) { + if(arclen > (rvsize + CHAR_BIT)) { + errno = ERANGE; /* Overflow */ + return -1; + } else { + /* + * Even if the number of bits in the arc representation + * is higher than the width of supplied * return value + * type, there is still possible to fit it when there + * are few unused high bits in the arc value + * representaion. + */ + uint8_t mask = (0xff << (7-(arclen - rvsize))) & 0x7f; + if((*arcbuf & mask)) { errno = ERANGE; /* Overflow */ return -1; } - } else { + /* Fool the routine computing unused bits */ + arclen -= 7; + cache = *arcbuf & 0x7f; + arcbuf++; + } + } + +#ifndef WORDS_BIGENDIAN + if(*(unsigned char *)&LE) { /* Little endian (x86) */ + /* "Convert" to big endian */ + rvbuf += rvsize / CHAR_BIT; + inc = -1; /* Descending */ + } else { + inc = +1; /* Ascending */ + } +#endif /* !WORDS_BIGENDIAN */ + + { /* Native big endian (Sparc, PPC) */ + unsigned int bits; /* typically no more than 3-4 bits */ + /* Clear the high unused bits */ + for(bits = rvsize - arclen; + bits > CHAR_BIT; + rvbuf += inc, bits -= CHAR_BIT) + *(unsigned char *)rvbuf = 0; + /* Fill the body of a value */ + for(; arcbuf < arcend; arcbuf++) { + cache = (cache << 7) | (*arcbuf & 0x7f); + bits += 7; + if(bits >= CHAR_BIT) { + bits -= CHAR_BIT; + *(unsigned char *)rvbuf = (cache >> bits); + rvbuf += inc; + } + } + if(bits) { + *(unsigned char *)rvbuf = cache; + rvbuf += inc; + } + } + + if(add) { + for(rvbuf -= inc; rvbuf != rvstart; rvbuf -= inc) { + int v = add + *(unsigned char *)rvbuf; + if(v & (-1 << CHAR_BIT)) { + *(unsigned char *)rvbuf + = v + (1 << CHAR_BIT); + add = -1; + } else { + *(unsigned char *)rvbuf = v; + break; + } + } + if(rvbuf == rvstart) { + /* No space to carry over */ errno = ERANGE; /* Overflow */ return -1; } } - /* Gather all bits into the accumulator */ - for(accum = 0; arcbuf < arcend; arcbuf++) - accum = (accum << 7) | (*arcbuf & ~0x80); - - assert(accum >= (unsigned long)-add); - accum += add; /* Actually, a negative value */ - - *rvalue = accum; - return 0; } + int OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen, int add, asn_app_consume_bytes_f *cb, void *app_key) { @@ -126,7 +193,8 @@ OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen, int add, unsigned long accum; /* Bits accumulator */ char *p; /* Position in the scratch buffer */ - if(OBJECT_IDENTIFIER_get_arc_l(arcbuf, arclen, add, &accum)) + if(OBJECT_IDENTIFIER_get_single_arc(arcbuf, arclen, add, + &accum, sizeof(accum))) return -1; /* Fill the scratch buffer in reverse. */ @@ -194,10 +262,10 @@ OBJECT_IDENTIFIER_print(asn1_TYPE_descriptor_t *td, const void *sptr, } int -OBJECT_IDENTIFIER_get_arcs_l(OBJECT_IDENTIFIER_t *oid, - unsigned long *arcs, int arcs_slots) { - unsigned long arc_value; - int cur_arc = 0; +OBJECT_IDENTIFIER_get_arcs(OBJECT_IDENTIFIER_t *oid, void *arcs, + unsigned int arc_type_size, unsigned int arc_slots) { + void *arcs_end = arcs + (arc_type_size * arc_slots); + int num_arcs = 0; int startn = 0; int add = 0; int i; @@ -212,56 +280,53 @@ OBJECT_IDENTIFIER_get_arcs_l(OBJECT_IDENTIFIER_t *oid, if((b & 0x80)) /* Continuation expected */ continue; - if(startn == 0) { + if(num_arcs == 0) { /* * First two arcs are encoded through the backdoor. */ - if(i) { - add = -80; - if(cur_arc < arcs_slots) arcs[cur_arc] = 2; - cur_arc++; - } else if(b <= 39) { - add = 0; - if(cur_arc < arcs_slots) arcs[cur_arc] = 0; - cur_arc++; - } else if(b < 79) { - add = -40; - if(cur_arc < arcs_slots) arcs[cur_arc] = 1; - cur_arc++; - } else { - add = -80; - if(cur_arc < arcs_slots) arcs[cur_arc] = 2; - cur_arc++; - } + unsigned LE = 1; /* Little endian */ + int first_arc; + num_arcs++; + if(!arc_slots) { num_arcs++; continue; } + + if(i) first_arc = 2; + else if(b <= 39) first_arc = 0; + else if(b < 79) first_arc = 1; + else first_arc = 2; + + add = -40 * first_arc; + memset(arcs, 0, arc_type_size); + *(unsigned char *)(arcs + + ((*(char *)&LE)?0:(arc_type_size - 1))) + = first_arc; + arcs += arc_type_size; } - /* Do not fill */ - if(cur_arc >= arcs_slots) { + /* Decode, if has space */ + if(arcs < arcs_end) { + if(OBJECT_IDENTIFIER_get_single_arc(&oid->buf[startn], + i - startn + 1, add, + arcs, arc_type_size)) + return -1; startn = i + 1; - continue; + arcs += arc_type_size; + add = 0; } - - if(OBJECT_IDENTIFIER_get_arc_l(&oid->buf[startn], - i - startn + 1, - add, &arc_value)) - return -1; - arcs[cur_arc++] = arc_value; - startn = i + 1; - add = 0; + num_arcs++; } - return cur_arc; + return num_arcs; } int -OBJECT_IDENTIFIER_set_arcs_l(OBJECT_IDENTIFIER_t *oid, unsigned long *arcs, int arcs_slots) { +OBJECT_IDENTIFIER_set_arcs_l(OBJECT_IDENTIFIER_t *oid, unsigned long *arcs, unsigned int arc_slots) { uint8_t *buf; uint8_t *bp; unsigned long long first_value; int size; int i; - if(oid == NULL || arcs == NULL || arcs_slots < 2) { + if(oid == NULL || arcs == NULL || arc_slots < 2) { errno = EINVAL; return -1; } @@ -283,7 +348,7 @@ OBJECT_IDENTIFIER_set_arcs_l(OBJECT_IDENTIFIER_t *oid, unsigned long *arcs, int /* * Roughly estimate the maximum size necessary to encode these arcs. */ - size = ((sizeof(arcs[0]) + 1) * 8 / 7) * arcs_slots; + size = ((sizeof(arcs[0]) + 1) * 8 / 7) * arc_slots; bp = buf = MALLOC(size + 1); if(!buf) { /* ENOMEM */ @@ -321,7 +386,7 @@ OBJECT_IDENTIFIER_set_arcs_l(OBJECT_IDENTIFIER_t *oid, unsigned long *arcs, int } } - for(i = 2; i < arcs_slots; i++) { + for(i = 2; i < arc_slots; i++) { unsigned long value = arcs[i]; uint8_t tbuf[sizeof(value) * 2]; /* Conservatively sized */ uint8_t *tp = tbuf; diff --git a/skeletons/OBJECT_IDENTIFIER.h b/skeletons/OBJECT_IDENTIFIER.h index 3e71f316..77b07def 100644 --- a/skeletons/OBJECT_IDENTIFIER.h +++ b/skeletons/OBJECT_IDENTIFIER.h @@ -29,27 +29,29 @@ int OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen, /* * This function fills an (_arcs) array with OBJECT IDENTIFIER arcs - * up to specified (_arcs_slots) elements. + * up to specified (_arc_slots) elements. * The function always returns the real number of arcs, even if there is no - * sufficient (_arcs_slots) provided. + * sufficient (_arc_slots) provided. * * EXAMPLE: * void print_arcs(OBJECT_IDENTIFIER_t *oid) { * unsigned long fixed_arcs[10]; // Try with fixed space first * unsigned long *arcs = fixed_arcs; - * int arcs_slots = sizeof(fixed_arcs)/sizeof(fixed_arcs[0]); // 10 + * int arc_type_size = sizeof(fixed_arcs[0]); // sizeof(long) + * int arc_slots = sizeof(fixed_arcs)/sizeof(fixed_arcs[0]); // 10 * int count; // Real number of arcs. * int i; * - * count = OBJECT_IDENTIFIER_get_arcs_l(oid, arcs, arcs_slots); + * count = OBJECT_IDENTIFIER_get_arcs(oid, arcs, + * arc_type_size, arc_slots); * // If necessary, reallocate arcs array and try again. - * if(count > arcs_slots) { - * arcs_slots = count; - * arcs = malloc(arcs_slots * sizeof(arcs[0])); + * if(count > arc_slots) { + * arc_slots = count; + * arcs = malloc(arc_type_size * arc_slots); * if(!arcs) return; - * count = OBJECT_IDENTIFIER_get_arcs_l(oid, - * arcs, arcs_slots); - * assert(count == arcs_slots); + * count = OBJECT_IDENTIFIER_get_arcs(oid, arcs, + * arc_type_size, arc_slots); + * assert(count == arc_slots); * } * * // Print the contents of the arcs array. @@ -65,13 +67,8 @@ int OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen, * -1/ERANGE: One or more arcs have value out of array cell type range. * >=0: Number of arcs contained in the OBJECT IDENTIFIER */ -int OBJECT_IDENTIFIER_get_arcs_l(OBJECT_IDENTIFIER_t *_oid, - unsigned long *_arcs, int _arcs_slots); -/* -int OBJECT_IDENTIFIER_get_arcs_im(OBJECT_IDENTIFIER_t *_oid, - uintmax_t *_arcs, int _arcs_slots); - */ - +int OBJECT_IDENTIFIER_get_arcs(OBJECT_IDENTIFIER_t *_oid, + void *_arcs, unsigned int _arc_type_size, unsigned int _arc_slots); /* * This functions initializes the OBJECT IDENTIFIER object with @@ -84,12 +81,14 @@ int OBJECT_IDENTIFIER_get_arcs_im(OBJECT_IDENTIFIER_t *_oid, * 0: The object was initialized with new arcs. */ int OBJECT_IDENTIFIER_set_arcs_l(OBJECT_IDENTIFIER_t *_oid, - unsigned long *arcs, int arcs_slots); + unsigned long *_arcs, unsigned int _arc_slots); /* * Internal functions. */ -int OBJECT_IDENTIFIER_get_arc_l(uint8_t *arcbuf, int arclen, - int add, unsigned long *value); +int OBJECT_IDENTIFIER_get_single_arc(uint8_t *arcbuf, unsigned int arclen, + signed int add, void *value, unsigned int value_size); +int OBJECT_IDENTIFIER_get_single_arc_l(uint8_t *arcbuf, unsigned int arclen, + signed int add, unsigned long *value); #endif /* _OBJECT_IDENTIFIER_H_ */ diff --git a/skeletons/RELATIVE-OID.c b/skeletons/RELATIVE-OID.c index 4fdad3d2..37f557d7 100644 --- a/skeletons/RELATIVE-OID.c +++ b/skeletons/RELATIVE-OID.c @@ -62,10 +62,10 @@ RELATIVE_OID_print(asn1_TYPE_descriptor_t *td, const void *sptr, int ilevel, int -RELATIVE_OID_get_arcs_l(RELATIVE_OID_t *roid, - unsigned long *arcs, int arcs_slots) { - unsigned long arc_value; - int cur_arc = 0; +RELATIVE_OID_get_arcs(RELATIVE_OID_t *roid, + void *arcs, unsigned int arc_type_size, unsigned int arc_slots) { + void *arcs_end = arcs + (arc_slots * arc_type_size); + int num_arcs = 0; int startn = 0; int i; @@ -79,17 +79,20 @@ RELATIVE_OID_get_arcs_l(RELATIVE_OID_t *roid, if((b & 0x80)) /* Continuation expected */ continue; - if(cur_arc < arcs_slots) { - if(OBJECT_IDENTIFIER_get_arc_l(&roid->buf[startn], - i - startn + 1, 0, &arc_value)) + if(arcs < arcs_end) { + if(OBJECT_IDENTIFIER_get_single_arc( + &roid->buf[startn], + i - startn + 1, 0, + arcs, arc_type_size)) return -1; - arcs[cur_arc++] = arc_value; + arcs += arc_type_size; + num_arcs++; } startn = i + 1; } - return cur_arc; + return num_arcs; } int diff --git a/skeletons/RELATIVE-OID.h b/skeletons/RELATIVE-OID.h index c0bc680e..926aca3a 100644 --- a/skeletons/RELATIVE-OID.h +++ b/skeletons/RELATIVE-OID.h @@ -23,8 +23,8 @@ asn_struct_print_f RELATIVE_OID_print; int RELATIVE_OID_set_arcs_l(RELATIVE_OID_t *_roid, unsigned long *arcs, int arcs_slots); -/* See OBJECT_IDENTIFIER_get_arcs_l() function in OBJECT_IDENTIFIER.h */ -int RELATIVE_OID_get_arcs_l(RELATIVE_OID_t *_roid, - unsigned long *arcs, int arcs_slots); +/* See OBJECT_IDENTIFIER_get_arcs() function in OBJECT_IDENTIFIER.h */ +int RELATIVE_OID_get_arcs(RELATIVE_OID_t *_roid, + void *arcs, unsigned int arc_type_size, unsigned int arc_slots); #endif /* _RELATIVE_OID_H_ */ diff --git a/skeletons/tests/check-OIDs.c b/skeletons/tests/check-OIDs.c index a97a910a..e7105f76 100644 --- a/skeletons/tests/check-OIDs.c +++ b/skeletons/tests/check-OIDs.c @@ -6,6 +6,7 @@ #include "../ber_tlv_tag.c" #include "../der_encoder.c" #include "../constraints.c" +#include static int _print(const void *buffer, size_t size, void *app_key) { @@ -40,8 +41,8 @@ check_OID(uint8_t *buf, size_t len, int *ck_buf, int ck_len) { OBJECT_IDENTIFIER_print(&asn1_DEF_OBJECT_IDENTIFIER, oid, 0, _print, 0); printf("\n"); - alen = OBJECT_IDENTIFIER_get_arcs_l(oid, - arcs, sizeof(arcs)/sizeof(arcs[0])); + alen = OBJECT_IDENTIFIER_get_arcs(oid, + arcs, sizeof(arcs[0]), sizeof(arcs)/sizeof(arcs[0])); assert(alen > 0); assert(alen == ck_len); @@ -83,8 +84,8 @@ check_ROID(uint8_t *buf, size_t len, int *ck_buf, int ck_len) { RELATIVE_OID_print(&asn1_DEF_RELATIVE_OID, oid, 0, _print, 0); printf("\n"); - alen = RELATIVE_OID_get_arcs_l(oid, - arcs, sizeof(arcs)/sizeof(arcs[0])); + alen = RELATIVE_OID_get_arcs(oid, + arcs, sizeof(arcs[0]), sizeof(arcs)/sizeof(arcs[0])); assert(alen > 0); assert(alen == ck_len); @@ -120,7 +121,8 @@ check_REGEN(int *arcs, int acount) { ret = RELATIVE_OID_set_arcs_l(&oid, (unsigned long *)arcs, acount); assert(ret == 0); - alen = RELATIVE_OID_get_arcs_l(&oid, tmp_arcs, tmp_alen); + alen = RELATIVE_OID_get_arcs(&oid, tmp_arcs, + sizeof(tmp_arcs[0]), tmp_alen); assert(alen >= 0); assert(alen < tmp_alen); @@ -154,7 +156,8 @@ check_REGEN_OID(int *arcs, int acount) { ret = OBJECT_IDENTIFIER_set_arcs_l(&oid, (unsigned long *)arcs, acount); assert(ret == 0); - alen = OBJECT_IDENTIFIER_get_arcs_l(&oid, tmp_arcs, tmp_alen); + alen = OBJECT_IDENTIFIER_get_arcs(&oid, + tmp_arcs, sizeof(tmp_arcs[0]), tmp_alen); assert(alen >= 0); assert(alen < tmp_alen); @@ -166,6 +169,48 @@ check_REGEN_OID(int *arcs, int acount) { printf(" }\n"); } +static int +check_speed() { + uint8_t buf[] = { 0x80 | 7, 0x80 | 2, 0x80 | 3, 0x80 | 4, 13 }; + int ret = 0; + int cycles = 100000000; + double a, b, c; + struct timeval tv; + unsigned long value; + int i; + + ret = OBJECT_IDENTIFIER_get_single_arc(buf, sizeof(buf), 0, + &value, sizeof(value)); + assert(ret == 0); + assert(value == 0x7040c20d); + + gettimeofday(&tv, 0); + a = tv.tv_sec + tv.tv_usec / 1000000.0; + for(i = 0; i < cycles; i++) { + ret = OBJECT_IDENTIFIER_get_single_arc(buf, sizeof(buf), 0, + &value, sizeof(value)); + } + assert(ret == 0); + assert(value == 0x7040c20d); + gettimeofday(&tv, 0); + b = tv.tv_sec + tv.tv_usec / 1000000.0; + for(i = 0; i < cycles; i++) { + ret = OBJECT_IDENTIFIER_get_single_arc(buf, sizeof(buf), 0, + &value, sizeof(value)); + } + assert(ret == 0); + assert(value == 0x7040c20d); + gettimeofday(&tv, 0); + c = tv.tv_sec + tv.tv_usec / 1000000.0; + + a = b - a; + b = c - b; + printf("Time for single_arc(): %f\n", a); + printf("Time for get_arc_l(): %f\n", b); + + return 0; +} + #define CHECK_OID(n) check_OID(buf ## n, sizeof(buf ## n), \ buf ## n ## _check, \ sizeof(buf ## n ## _check)/sizeof(buf ## n ## _check[0])) @@ -179,13 +224,13 @@ check_REGEN_OID(int *arcs, int acount) { int main(int ac, char **av) { - /* {joint-iso-itu-t 100 3} */ + /* {joint-iso-itu-t 230 3} */ uint8_t buf1[] = { 0x06, /* OBJECT IDENTIFIER */ 0x03, /* Length */ - 0x81, 0x34, 0x03 + 0x82, 0x36, 0x03 }; - int buf1_check[] = { 2, 100, 3 }; + int buf1_check[] = { 2, 230, 3 }; /* {8571 3 2} */ uint8_t buf2[] = { @@ -224,5 +269,7 @@ main(int ac, char **av) { CHECK_REGEN_OID(12); CHECK_REGEN_OID(13); + check_speed(); + return 0; }