Commit 9f198236 authored by Pau Espin Pedrol's avatar Pau Espin Pedrol Committed by Mouse

aper: Rework aper_put_length to gain lb & ub information

This should help aper_put_length() to take proper decisions on the way
to encode the length, since the range alone is not enough.
A contraint of lb=1 ub=65536 would yield a range=65536, but according to
ITU-T X.691 11.9 it shouldn't be encoded using nsnnwn since that only
applies in case ub<65536.
As a result, it would end up encoding/decoding it using 2 bytes while it
should use only 1.

Related: https://github.com/mouse07410/asn1c/issues/94
parent 9310ffe0
...@@ -173,7 +173,7 @@ ANY_encode_aper(const asn_TYPE_descriptor_t *td, ...@@ -173,7 +173,7 @@ ANY_encode_aper(const asn_TYPE_descriptor_t *td,
size = st->size; size = st->size;
do { do {
int need_eom = 0; int need_eom = 0;
ssize_t may_save = aper_put_length(po, -1, size, &need_eom); ssize_t may_save = aper_put_length(po, -1, -1, size, &need_eom);
if(may_save < 0) ASN__ENCODE_FAILED; if(may_save < 0) ASN__ENCODE_FAILED;
ret = per_put_many_bits(po, buf, may_save * 8); ret = per_put_many_bits(po, buf, may_save * 8);
...@@ -182,7 +182,7 @@ ANY_encode_aper(const asn_TYPE_descriptor_t *td, ...@@ -182,7 +182,7 @@ ANY_encode_aper(const asn_TYPE_descriptor_t *td,
buf += may_save; buf += may_save;
size -= may_save; size -= may_save;
assert(!(may_save & 0x07) || !size); assert(!(may_save & 0x07) || !size);
if(need_eom && aper_put_length(po, -1, 0, 0)) if(need_eom && aper_put_length(po, -1, -1, 0, NULL))
ASN__ENCODE_FAILED; /* End of Message length */ ASN__ENCODE_FAILED; /* End of Message length */
} while(size); } while(size);
......
...@@ -291,13 +291,14 @@ INTEGER_encode_aper(const asn_TYPE_descriptor_t *td, ...@@ -291,13 +291,14 @@ INTEGER_encode_aper(const asn_TYPE_descriptor_t *td,
for(buf = st->buf, end = st->buf + st->size; buf < end;) { for(buf = st->buf, end = st->buf + st->size; buf < end;) {
int need_eom = 0; int need_eom = 0;
ssize_t mayEncode = aper_put_length(po, -1, end - buf, &need_eom); ssize_t mayEncode = aper_put_length(po, -1, -1, end - buf, &need_eom);
if(mayEncode < 0) if(mayEncode < 0)
ASN__ENCODE_FAILED; ASN__ENCODE_FAILED;
if(per_put_many_bits(po, buf, 8 * mayEncode)) if(per_put_many_bits(po, buf, 8 * mayEncode))
ASN__ENCODE_FAILED; ASN__ENCODE_FAILED;
buf += mayEncode; buf += mayEncode;
if(need_eom && (aper_put_length(po, -1, 0, 0) < 0)) ASN__ENCODE_FAILED; if(need_eom && (aper_put_length(po, -1, -1, 0, NULL) < 0))
ASN__ENCODE_FAILED;
} }
ASN__ENCODED_OK(er); ASN__ENCODED_OK(er);
......
...@@ -342,9 +342,8 @@ OCTET_STRING_encode_aper(const asn_TYPE_descriptor_t *td, ...@@ -342,9 +342,8 @@ OCTET_STRING_encode_aper(const asn_TYPE_descriptor_t *td,
st->size, sizeinunits - csiz->lower_bound, st->size, sizeinunits - csiz->lower_bound,
csiz->effective_bits); csiz->effective_bits);
if (csiz->effective_bits > 0) { if (csiz->effective_bits > 0) {
ret = aper_put_length(po, ret = aper_put_length(po, csiz->lower_bound, csiz->upper_bound,
csiz->upper_bound - csiz->lower_bound + 1, sizeinunits - csiz->lower_bound, NULL);
sizeinunits - csiz->lower_bound, 0);
if(ret < 0) ASN__ENCODE_FAILED; if(ret < 0) ASN__ENCODE_FAILED;
} }
if (csiz->effective_bits > 0 || (st->size > 2) if (csiz->effective_bits > 0 || (st->size > 2)
...@@ -372,7 +371,7 @@ OCTET_STRING_encode_aper(const asn_TYPE_descriptor_t *td, ...@@ -372,7 +371,7 @@ OCTET_STRING_encode_aper(const asn_TYPE_descriptor_t *td,
ASN_DEBUG("Encoding %lu bytes", st->size); ASN_DEBUG("Encoding %lu bytes", st->size);
if(sizeinunits == 0) { if(sizeinunits == 0) {
if(aper_put_length(po, -1, 0, 0) < 0) if(aper_put_length(po, -1, -1, 0, NULL) < 0)
ASN__ENCODE_FAILED; ASN__ENCODE_FAILED;
ASN__ENCODED_OK(er); ASN__ENCODED_OK(er);
} }
...@@ -380,7 +379,7 @@ OCTET_STRING_encode_aper(const asn_TYPE_descriptor_t *td, ...@@ -380,7 +379,7 @@ OCTET_STRING_encode_aper(const asn_TYPE_descriptor_t *td,
buf = st->buf; buf = st->buf;
while(sizeinunits) { while(sizeinunits) {
int need_eom = 0; int need_eom = 0;
ssize_t maySave = aper_put_length(po, -1, sizeinunits, &need_eom); ssize_t maySave = aper_put_length(po, -1, -1, sizeinunits, &need_eom);
if(maySave < 0) ASN__ENCODE_FAILED; if(maySave < 0) ASN__ENCODE_FAILED;
...@@ -404,7 +403,7 @@ OCTET_STRING_encode_aper(const asn_TYPE_descriptor_t *td, ...@@ -404,7 +403,7 @@ OCTET_STRING_encode_aper(const asn_TYPE_descriptor_t *td,
buf += maySave >> 3; buf += maySave >> 3;
sizeinunits -= maySave; sizeinunits -= maySave;
assert(!(maySave & 0x07) || !sizeinunits); assert(!(maySave & 0x07) || !sizeinunits);
if(need_eom && (aper_put_length(po, -1, 0, 0) < 0)) if(need_eom && (aper_put_length(po, -1, -1, 0, NULL) < 0))
ASN__ENCODE_FAILED; /* End of Message length */ ASN__ENCODE_FAILED; /* End of Message length */
} }
......
...@@ -101,12 +101,12 @@ aper_open_type_put(const asn_TYPE_descriptor_t *td, ...@@ -101,12 +101,12 @@ aper_open_type_put(const asn_TYPE_descriptor_t *td,
for(bptr = buf, toGo = size; toGo;) { for(bptr = buf, toGo = size; toGo;) {
int need_eom = 0; int need_eom = 0;
ssize_t maySave = aper_put_length(po, -1, toGo, &need_eom); ssize_t maySave = aper_put_length(po, -1, -1, toGo, &need_eom);
if(maySave < 0) break; if(maySave < 0) break;
if(per_put_many_bits(po, bptr, maySave * 8)) break; if(per_put_many_bits(po, bptr, maySave * 8)) break;
bptr = (char *)bptr + maySave; bptr = (char *)bptr + maySave;
toGo -= maySave; toGo -= maySave;
if(need_eom && (aper_put_length(po, -1, 0, 0) < 0)) { if(need_eom && (aper_put_length(po, -1, -1, 0, NULL) < 0)) {
FREEMEM(buf); FREEMEM(buf);
return -1; return -1;
} }
......
...@@ -128,38 +128,42 @@ int aper_put_align(asn_per_outp_t *po) { ...@@ -128,38 +128,42 @@ int aper_put_align(asn_per_outp_t *po) {
} }
ssize_t ssize_t
aper_put_length(asn_per_outp_t *po, int range, size_t length, int *need_eom) { aper_put_length(asn_per_outp_t *po, ssize_t lb, ssize_t ub, size_t n, int *need_eom) {
int constrained = (lb >= 0) && (ub >= 0);
int dummy = 0; int dummy = 0;
if(!need_eom) need_eom = &dummy; if(!need_eom) need_eom = &dummy;
*need_eom = 0; *need_eom = 0;
ASN_DEBUG("APER put length %zu with range %d", length, range);
ASN_DEBUG("APER put length %zu with range (%zd..%zd)", n, lb, ub);
/* 11.9 X.691 Note 2 */ /* 11.9 X.691 Note 2 */
if (range <= 65536 && range >= 0) if (constrained && ub < 65536) {
return aper_put_nsnnwn(po, range, length) ? -1 : (ssize_t)length; int range = ub - lb + 1;
return aper_put_nsnnwn(po, range, n) ? -1 : (ssize_t)n;
}
if (aper_put_align(po) < 0) if (aper_put_align(po) < 0)
return -1; return -1;
if(length <= 127) { /* #11.9.3.6 */ if(n <= 127) { /* #11.9.3.6 */
return per_put_few_bits(po, length, 8) return per_put_few_bits(po, n, 8)
? -1 : (ssize_t)length; ? -1 : (ssize_t)n;
} }
else if(length < 16384) /* #11.9.3.7 */ else if(n < 16384) /* #11.9.3.7 */
return per_put_few_bits(po, length|0x8000, 16) return per_put_few_bits(po, n|0x8000, 16)
? -1 : (ssize_t)length; ? -1 : (ssize_t)n;
*need_eom = 0 == (length & 16383); *need_eom = 0 == (n & 16383);
length >>= 14; n >>= 14;
if(length > 4) { if(n > 4) {
*need_eom = 0; *need_eom = 0;
length = 4; n = 4;
} }
return per_put_few_bits(po, 0xC0 | length, 8) return per_put_few_bits(po, 0xC0 | n, 8)
? -1 : (ssize_t)(length << 14); ? -1 : (ssize_t)(n << 14);
} }
...@@ -171,7 +175,7 @@ aper_put_nslength(asn_per_outp_t *po, size_t length) { ...@@ -171,7 +175,7 @@ aper_put_nslength(asn_per_outp_t *po, size_t length) {
if(length == 0) return -1; if(length == 0) return -1;
return per_put_few_bits(po, length-1, 7) ? -1 : 0; return per_put_few_bits(po, length-1, 7) ? -1 : 0;
} else { } else {
if(aper_put_length(po, -1, length, 0) != (ssize_t)length) { if(aper_put_length(po, -1, -1, length, NULL) != (ssize_t)length) {
/* This might happen in case of >16K extensions */ /* This might happen in case of >16K extensions */
return -1; return -1;
} }
......
...@@ -31,14 +31,14 @@ ssize_t aper_get_nsnnwn(asn_per_data_t *pd, int range); ...@@ -31,14 +31,14 @@ ssize_t aper_get_nsnnwn(asn_per_data_t *pd, int range);
/* /*
* X.691 (08/2015) #11.9 "General rules for encoding a length determinant" * X.691 (08/2015) #11.9 "General rules for encoding a length determinant"
* Put the length "whole_length" to the Aligned PER stream. * Put the length "n" to the Aligned PER stream.
* If (opt_need_eom) is given, it will be set to 1 if final 0-length is needed. * If (opt_need_eom) is given, it will be set to 1 if final 0-n is needed.
* In that case, invoke aper_put_length(po, -1, 0, NULL) after encoding the last * In that case, invoke aper_put_length(po, -1, -1, 0, NULL) after encoding the
* block. * last block.
* This function returns the number of units which may be flushed * This function returns the number of units which may be flushed
* in the next units saving iteration. * in the next units saving iteration.
*/ */
ssize_t aper_put_length(asn_per_outp_t *po, int range, size_t length, ssize_t aper_put_length(asn_per_outp_t *po, ssize_t lb, ssize_t ub, size_t n,
int *opt_need_eom); int *opt_need_eom);
/* Align the current bit position to octet bundary */ /* Align the current bit position to octet bundary */
......
...@@ -54,7 +54,7 @@ SEQUENCE_OF_encode_aper(const asn_TYPE_descriptor_t *td, ...@@ -54,7 +54,7 @@ SEQUENCE_OF_encode_aper(const asn_TYPE_descriptor_t *td,
*/ */
if (ct->lower_bound == ct->upper_bound && ct->upper_bound < 65536) { if (ct->lower_bound == ct->upper_bound && ct->upper_bound < 65536) {
/* No length determinant */ /* No length determinant */
} else if (aper_put_length(po, ct->upper_bound - ct->lower_bound + 1, list->count - ct->lower_bound, 0) < 0) } else if (aper_put_length(po, ct->lower_bound, ct->upper_bound, list->count - ct->lower_bound, 0) < 0)
ASN__ENCODE_FAILED; ASN__ENCODE_FAILED;
} }
...@@ -65,7 +65,7 @@ SEQUENCE_OF_encode_aper(const asn_TYPE_descriptor_t *td, ...@@ -65,7 +65,7 @@ SEQUENCE_OF_encode_aper(const asn_TYPE_descriptor_t *td,
if(ct && ct->effective_bits >= 0) { if(ct && ct->effective_bits >= 0) {
mayEncode = list->count; mayEncode = list->count;
} else { } else {
mayEncode = aper_put_length(po, -1, list->count - seq, &need_eom); mayEncode = aper_put_length(po, -1, -1, list->count - seq, &need_eom);
if(mayEncode < 0) ASN__ENCODE_FAILED; if(mayEncode < 0) ASN__ENCODE_FAILED;
} }
...@@ -79,7 +79,7 @@ SEQUENCE_OF_encode_aper(const asn_TYPE_descriptor_t *td, ...@@ -79,7 +79,7 @@ SEQUENCE_OF_encode_aper(const asn_TYPE_descriptor_t *td,
ASN__ENCODE_FAILED; ASN__ENCODE_FAILED;
} }
if(need_eom && (aper_put_length(po, -1, 0, 0) < 0)) if(need_eom && (aper_put_length(po, -1, -1, 0, NULL) < 0))
ASN__ENCODE_FAILED; /* End of Message length */ ASN__ENCODE_FAILED; /* End of Message length */
} }
......
...@@ -52,7 +52,7 @@ SET_OF_encode_aper(const asn_TYPE_descriptor_t *td, ...@@ -52,7 +52,7 @@ SET_OF_encode_aper(const asn_TYPE_descriptor_t *td,
ct->effective_bits)) ct->effective_bits))
ASN__ENCODE_FAILED;*/ ASN__ENCODE_FAILED;*/
if (aper_put_length(po, ct->upper_bound - ct->lower_bound + 1, list->count - ct->lower_bound, 0) < 0) { if (aper_put_length(po, ct->lower_bound, ct->upper_bound, list->count - ct->lower_bound, 0) < 0) {
ASN__ENCODE_FAILED; ASN__ENCODE_FAILED;
} }
} }
...@@ -70,7 +70,7 @@ SET_OF_encode_aper(const asn_TYPE_descriptor_t *td, ...@@ -70,7 +70,7 @@ SET_OF_encode_aper(const asn_TYPE_descriptor_t *td,
may_encode = list->count; may_encode = list->count;
} else { } else {
may_encode = may_encode =
aper_put_length(po, -1, list->count - seq, &need_eom); aper_put_length(po, -1, -1, list->count - seq, &need_eom);
if(may_encode < 0) ASN__ENCODE_FAILED; if(may_encode < 0) ASN__ENCODE_FAILED;
} }
...@@ -81,7 +81,7 @@ SET_OF_encode_aper(const asn_TYPE_descriptor_t *td, ...@@ -81,7 +81,7 @@ SET_OF_encode_aper(const asn_TYPE_descriptor_t *td,
break; break;
} }
} }
if(need_eom && (aper_put_length(po, -1, 0, 0) < 0)) if(need_eom && (aper_put_length(po, -1, -1, 0, NULL) < 0))
ASN__ENCODE_FAILED; /* End of Message length */ ASN__ENCODE_FAILED; /* End of Message length */
} }
......
#include <assert.h> #include <assert.h>
#include <aper_support.h> #include <aper_support.h>
static void put(asn_per_outp_t *po, int range, size_t length) { static void put(asn_per_outp_t *po, ssize_t lb, ssize_t ub, size_t n) {
fprintf(stderr, "put(%zd)\n", length); fprintf(stderr, "put(%zd)\n", n);
do { do {
int need_eom = 123; int need_eom = 123;
ssize_t may_write = aper_put_length(po, range, length, &need_eom); ssize_t may_write = aper_put_length(po, lb, ub, n, &need_eom);
fprintf(stderr, " put %zu\n", may_write); fprintf(stderr, " put %zu\n", may_write);
assert(may_write >= 0); assert(may_write >= 0);
assert((size_t)may_write <= length); assert((size_t)may_write <= n);
assert(need_eom != 123); assert(need_eom != 123);
length -= may_write; n -= may_write;
if(need_eom) { if(need_eom) {
assert(length == 0); assert(n == 0);
if(aper_put_length(po, -1, 0, 0)) { if(aper_put_length(po, -1, -1, 0, NULL)) {
assert(!"Unreachable"); assert(!"Unreachable");
} }
fprintf(stderr, " put EOM 0\n"); fprintf(stderr, " put EOM 0\n");
} }
} while(length); } while(n);
fprintf(stderr, "put(...) in %zu bits\n", po->nboff); fprintf(stderr, "put(...) in %zu bits\n", po->nboff);
assert(po->nboff != 0); assert(po->nboff != 0);
assert(po->flushed_bytes == 0); assert(po->flushed_bytes == 0);
} }
static size_t get(asn_per_outp_t *po, int range) { static size_t get(asn_per_outp_t *po, ssize_t lb, ssize_t ub) {
asn_bit_data_t data; asn_bit_data_t data;
memset(&data, 0, sizeof(data)); memset(&data, 0, sizeof(data));
data.buffer = po->tmpspace; data.buffer = po->tmpspace;
...@@ -36,7 +36,7 @@ static size_t get(asn_per_outp_t *po, int range) { ...@@ -36,7 +36,7 @@ static size_t get(asn_per_outp_t *po, int range) {
size_t length = 0; size_t length = 0;
int repeat = 0; int repeat = 0;
do { do {
ssize_t n = aper_get_length(&data, range, -1, &repeat); ssize_t n = aper_get_length(&data, ub - lb + 1, -1, &repeat);
fprintf(stderr, " get = %zu +%zd\n", length, n); fprintf(stderr, " get = %zu +%zd\n", length, n);
assert(n >= 0); assert(n >= 0);
length += n; length += n;
...@@ -47,18 +47,18 @@ static size_t get(asn_per_outp_t *po, int range) { ...@@ -47,18 +47,18 @@ static size_t get(asn_per_outp_t *po, int range) {
} }
static void static void
check_round_trip(int range, size_t length) { check_round_trip(ssize_t lb, ssize_t ub, size_t n) {
fprintf(stderr, "\nRound-trip for range=%d len=%zu\n", range, length); fprintf(stderr, "\nRound-trip for range=(%zd..%zd) n=%zu\n", lb, ub, n);
asn_per_outp_t po; asn_per_outp_t po;
memset(&po, 0, sizeof(po)); memset(&po, 0, sizeof(po));
po.buffer = po.tmpspace; po.buffer = po.tmpspace;
po.nbits = 8 * sizeof(po.tmpspace); po.nbits = 8 * sizeof(po.tmpspace);
put(&po, range, length); put(&po, lb, ub, n);
size_t recovered = get(&po, range); size_t recovered = get(&po, lb, ub);
assert(recovered == length); assert(recovered == n);
} }
/* /*
...@@ -67,15 +67,15 @@ check_round_trip(int range, size_t length) { ...@@ -67,15 +67,15 @@ check_round_trip(int range, size_t length) {
*/ */
static void static void
check_round_trips_range65536() { check_round_trips_range65536() {
check_round_trip(65536, 0); check_round_trip(0, 65535, 0);
check_round_trip(65536, 1); check_round_trip(0, 65535, 1);
check_round_trip(65536, 127); check_round_trip(0, 65535, 127);
check_round_trip(65536, 128); check_round_trip(0, 65535, 128);
check_round_trip(65536, 129); check_round_trip(0, 65535, 129);
check_round_trip(65536, 255); check_round_trip(0, 65535, 255);
check_round_trip(65536, 256); check_round_trip(0, 65535, 256);
check_round_trip(65536, 65534); check_round_trip(0, 65535, 65534);
check_round_trip(65536, 65535); check_round_trip(0, 65535, 65535);
} }
/* /*
...@@ -84,30 +84,32 @@ check_round_trips_range65536() { ...@@ -84,30 +84,32 @@ check_round_trips_range65536() {
static void static void
check_encode_number_greater_than_range() { check_encode_number_greater_than_range() {
asn_per_outp_t po; asn_per_outp_t po;
int range = 6500; int lb = 0;
size_t length = 6503; int ub = 6499;
size_t n = 6503;
ssize_t may_write; ssize_t may_write;
memset(&po, 0, sizeof(po)); memset(&po, 0, sizeof(po));
po.buffer = po.tmpspace; po.buffer = po.tmpspace;
po.nbits = 8 * sizeof(po.tmpspace); po.nbits = 8 * sizeof(po.tmpspace);
may_write = aper_put_length(&po, range, length, NULL); may_write = aper_put_length(&po, lb, ub, n, NULL);
assert(may_write < 0); assert(may_write < 0);
/* Also check value = range should fail: */ /* Also check value = range should fail: */
memset(&po, 0, sizeof(po)); memset(&po, 0, sizeof(po));
po.buffer = po.tmpspace; po.buffer = po.tmpspace;
po.nbits = 8 * sizeof(po.tmpspace); po.nbits = 8 * sizeof(po.tmpspace);
length = range; n = ub - lb + 1;
may_write = aper_put_length(&po, range, length, NULL); may_write = aper_put_length(&po, lb, ub, n, NULL);
assert(may_write < 0); assert(may_write < 0);
/* Again value = range, with edge case 65536: */ /* Again value = range, with edge case 65536: */
memset(&po, 0, sizeof(po)); memset(&po, 0, sizeof(po));
po.buffer = po.tmpspace; po.buffer = po.tmpspace;
po.nbits = 8 * sizeof(po.tmpspace); po.nbits = 8 * sizeof(po.tmpspace);
length = range = 65536; ub = 65535;
may_write = aper_put_length(&po, range, length, NULL); n = ub - lb + 1;
may_write = aper_put_length(&po, lb, ub, n, NULL);
assert(may_write < 0); assert(may_write < 0);
} }
...@@ -118,17 +120,18 @@ check_encode_number_greater_than_range() { ...@@ -118,17 +120,18 @@ check_encode_number_greater_than_range() {
static void static void
check_range65536_encoded_as_2octet() { check_range65536_encoded_as_2octet() {
asn_per_outp_t po; asn_per_outp_t po;
int range = 65536; int lb = 0;
size_t length = 5; int ub = 65535;
size_t n = 5;
memset(&po, 0, sizeof(po)); memset(&po, 0, sizeof(po));
po.buffer = po.tmpspace; po.buffer = po.tmpspace;
po.nbits = 8 * sizeof(po.tmpspace); po.nbits = 8 * sizeof(po.tmpspace);
ssize_t may_write = aper_put_length(&po, range, length, NULL); ssize_t may_write = aper_put_length(&po, lb, ub, n, NULL);
assert(may_write >= 0); assert(may_write >= 0);
unsigned int bytes_needed = (po.buffer - po.tmpspace) + po.nboff/8; unsigned int bytes_needed = (po.buffer - po.tmpspace) + po.nboff/8;
fprintf(stderr, "\naper_put_length(range=%d, len=%zu) => bytes_needed=%u\n", fprintf(stderr, "\naper_put_length(range=(%d..%d), len=%zu) => bytes_needed=%u\n",
range, length, bytes_needed); lb, ub, n, bytes_needed);
assert(bytes_needed == 2); assert(bytes_needed == 2);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment