diff --git a/skeletons/per_support.c b/skeletons/per_support.c index 506ca780..9b048f0f 100644 --- a/skeletons/per_support.c +++ b/skeletons/per_support.c @@ -6,7 +6,7 @@ #include /* - * Extract a small number of bits (<= 24) from the specified PER data pointer. + * Extract a small number of bits (<= 31) from the specified PER data pointer. */ int32_t per_get_few_bits(asn_per_data_t *pd, int nbits) { @@ -16,8 +16,6 @@ per_get_few_bits(asn_per_data_t *pd, int nbits) { if(nbits < 0 || pd->nboff + nbits > pd->nbits) return -1; - if(nbits == 0) - return 0; /* * Normalize position indicator. @@ -34,7 +32,7 @@ per_get_few_bits(asn_per_data_t *pd, int nbits) { * Extract specified number of bits. */ if(off <= 8) - accum = (buf[0]) >> (8 - off); + accum = nbits ? (buf[0]) >> (8 - off) : 0; else if(off <= 16) accum = ((buf[0] << 8) + buf[1]) >> (16 - off); else if(off <= 24) @@ -42,12 +40,18 @@ per_get_few_bits(asn_per_data_t *pd, int nbits) { else if(off <= 31) accum = ((buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + (buf[3])) >> (32 - off); - else { + else if(nbits <= 31) { + asn_per_data_t tpd = *pd; + /* Here are we with our 31-bits limit plus 1..7 bits offset. */ + tpd.nboff -= nbits; + accum = per_get_few_bits(&tpd, nbits - 24) << 24; + accum |= per_get_few_bits(&tpd, 24); + } else { pd->nboff -= nbits; /* Oops, revert back */ return -1; } - return (accum & ((1 << nbits) - 1)); + return (accum & (((uint32_t)1 << nbits) - 1)); } /* diff --git a/skeletons/per_support.h b/skeletons/per_support.h index 25c92566..a8f15fbe 100644 --- a/skeletons/per_support.h +++ b/skeletons/per_support.h @@ -21,7 +21,7 @@ typedef struct asn_per_data_s { } asn_per_data_t; /* - * Extract a small number of bits (<= 24) from the specified PER data pointer. + * Extract a small number of bits (<= 31) from the specified PER data pointer. * This function returns -1 if the specified number of bits could not be * extracted due to EOD or other conditions. */ diff --git a/skeletons/tests/check-PER.c b/skeletons/tests/check-PER.c index 94f5fe42..5fcb1aee 100644 --- a/skeletons/tests/check-PER.c +++ b/skeletons/tests/check-PER.c @@ -14,22 +14,27 @@ main() { z = per_get_few_bits(&pos, 32); assert(z == -1); + assert(pos.nbits == sizeof(buf) * 8); z = per_get_few_bits(&pos, 0); assert(z == 0); assert(pos.nboff == 0); + assert(pos.nbits == sizeof(buf) * 8); z = per_get_few_bits(&pos, 1); assert(z == 1); assert(pos.nboff == 1); + assert(pos.nbits == sizeof(buf) * 8); z = per_get_few_bits(&pos, 2); assert(z == 1); assert(pos.nboff == 3); + assert(pos.nbits == sizeof(buf) * 8); z = per_get_few_bits(&pos, 2); assert(z == 2); assert(pos.nboff == 5); + assert(pos.nbits == sizeof(buf) * 8); z = per_get_few_bits(&pos, 3); assert(z == 7); @@ -61,6 +66,20 @@ main() { z = per_get_few_bits(&pos, 24); assert(z == 14443711); + /* Get full 31-bit range */ + pos.buffer = buf; + pos.nboff = 7; + pos.nbits = sizeof(buf) * 8; + z = per_get_few_bits(&pos, 31); + assert(z == 1179384747); + + /* Get a bit shifted range */ + pos.buffer = buf; + pos.nboff = 6; + pos.nbits = sizeof(buf) * 8; + z = per_get_few_bits(&pos, 31); + assert(z == 1663434197); + pos.buffer = buf; pos.nboff = 0; pos.nbits = sizeof(buf) * 8;