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,
size = st->size;
do {
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;
ret = per_put_many_bits(po, buf, may_save * 8);
......@@ -182,7 +182,7 @@ ANY_encode_aper(const asn_TYPE_descriptor_t *td,
buf += may_save;
size -= may_save;
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 */
} while(size);
......
......@@ -291,13 +291,14 @@ INTEGER_encode_aper(const asn_TYPE_descriptor_t *td,
for(buf = st->buf, end = st->buf + st->size; buf < end;) {
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)
ASN__ENCODE_FAILED;
if(per_put_many_bits(po, buf, 8 * mayEncode))
ASN__ENCODE_FAILED;
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);
......
......@@ -342,9 +342,8 @@ OCTET_STRING_encode_aper(const asn_TYPE_descriptor_t *td,
st->size, sizeinunits - csiz->lower_bound,
csiz->effective_bits);
if (csiz->effective_bits > 0) {
ret = aper_put_length(po,
csiz->upper_bound - csiz->lower_bound + 1,
sizeinunits - csiz->lower_bound, 0);
ret = aper_put_length(po, csiz->lower_bound, csiz->upper_bound,
sizeinunits - csiz->lower_bound, NULL);
if(ret < 0) ASN__ENCODE_FAILED;
}
if (csiz->effective_bits > 0 || (st->size > 2)
......@@ -372,7 +371,7 @@ OCTET_STRING_encode_aper(const asn_TYPE_descriptor_t *td,
ASN_DEBUG("Encoding %lu bytes", st->size);
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__ENCODED_OK(er);
}
......@@ -380,7 +379,7 @@ OCTET_STRING_encode_aper(const asn_TYPE_descriptor_t *td,
buf = st->buf;
while(sizeinunits) {
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;
......@@ -404,7 +403,7 @@ OCTET_STRING_encode_aper(const asn_TYPE_descriptor_t *td,
buf += maySave >> 3;
sizeinunits -= maySave;
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 */
}
......
......@@ -101,12 +101,12 @@ aper_open_type_put(const asn_TYPE_descriptor_t *td,
for(bptr = buf, toGo = size; toGo;) {
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(per_put_many_bits(po, bptr, maySave * 8)) break;
bptr = (char *)bptr + 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);
return -1;
}
......
......@@ -128,38 +128,42 @@ int aper_put_align(asn_per_outp_t *po) {
}
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;
if(!need_eom) need_eom = &dummy;
*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 */
if (range <= 65536 && range >= 0)
return aper_put_nsnnwn(po, range, length) ? -1 : (ssize_t)length;
if (constrained && ub < 65536) {
int range = ub - lb + 1;
return aper_put_nsnnwn(po, range, n) ? -1 : (ssize_t)n;
}
if (aper_put_align(po) < 0)
return -1;
if(length <= 127) { /* #11.9.3.6 */
return per_put_few_bits(po, length, 8)
? -1 : (ssize_t)length;
if(n <= 127) { /* #11.9.3.6 */
return per_put_few_bits(po, n, 8)
? -1 : (ssize_t)n;
}
else if(length < 16384) /* #11.9.3.7 */
return per_put_few_bits(po, length|0x8000, 16)
? -1 : (ssize_t)length;
else if(n < 16384) /* #11.9.3.7 */
return per_put_few_bits(po, n|0x8000, 16)
? -1 : (ssize_t)n;
*need_eom = 0 == (length & 16383);
length >>= 14;
if(length > 4) {
*need_eom = 0 == (n & 16383);
n >>= 14;
if(n > 4) {
*need_eom = 0;
length = 4;
n = 4;
}
return per_put_few_bits(po, 0xC0 | length, 8)
? -1 : (ssize_t)(length << 14);
return per_put_few_bits(po, 0xC0 | n, 8)
? -1 : (ssize_t)(n << 14);
}
......@@ -171,7 +175,7 @@ aper_put_nslength(asn_per_outp_t *po, size_t length) {
if(length == 0) return -1;
return per_put_few_bits(po, length-1, 7) ? -1 : 0;
} 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 */
return -1;
}
......
......@@ -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"
* Put the length "whole_length" to the Aligned PER stream.
* If (opt_need_eom) is given, it will be set to 1 if final 0-length is needed.
* In that case, invoke aper_put_length(po, -1, 0, NULL) after encoding the last
* block.
* Put the length "n" to the Aligned PER stream.
* 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, -1, 0, NULL) after encoding the
* last block.
* This function returns the number of units which may be flushed
* 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);
/* Align the current bit position to octet bundary */
......
......@@ -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) {
/* 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;
}
......@@ -65,7 +65,7 @@ SEQUENCE_OF_encode_aper(const asn_TYPE_descriptor_t *td,
if(ct && ct->effective_bits >= 0) {
mayEncode = list->count;
} 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;
}
......@@ -79,7 +79,7 @@ SEQUENCE_OF_encode_aper(const asn_TYPE_descriptor_t *td,
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 */
}
......
......@@ -52,7 +52,7 @@ SET_OF_encode_aper(const asn_TYPE_descriptor_t *td,
ct->effective_bits))
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;
}
}
......@@ -70,7 +70,7 @@ SET_OF_encode_aper(const asn_TYPE_descriptor_t *td,
may_encode = list->count;
} else {
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;
}
......@@ -81,7 +81,7 @@ SET_OF_encode_aper(const asn_TYPE_descriptor_t *td,
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 */
}
......
#include <assert.h>
#include <aper_support.h>
static void put(asn_per_outp_t *po, int range, size_t length) {
fprintf(stderr, "put(%zd)\n", length);
static void put(asn_per_outp_t *po, ssize_t lb, ssize_t ub, size_t n) {
fprintf(stderr, "put(%zd)\n", n);
do {
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);
assert(may_write >= 0);
assert((size_t)may_write <= length);
assert((size_t)may_write <= n);
assert(need_eom != 123);
length -= may_write;
n -= may_write;
if(need_eom) {
assert(length == 0);
if(aper_put_length(po, -1, 0, 0)) {
assert(n == 0);
if(aper_put_length(po, -1, -1, 0, NULL)) {
assert(!"Unreachable");
}
fprintf(stderr, " put EOM 0\n");
}
} while(length);
} while(n);
fprintf(stderr, "put(...) in %zu bits\n", po->nboff);
assert(po->nboff != 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;
memset(&data, 0, sizeof(data));
data.buffer = po->tmpspace;
......@@ -36,7 +36,7 @@ static size_t get(asn_per_outp_t *po, int range) {
size_t length = 0;
int repeat = 0;
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);
assert(n >= 0);
length += n;
......@@ -47,18 +47,18 @@ static size_t get(asn_per_outp_t *po, int range) {
}
static void
check_round_trip(int range, size_t length) {
fprintf(stderr, "\nRound-trip for range=%d len=%zu\n", range, length);
check_round_trip(ssize_t lb, ssize_t ub, size_t n) {
fprintf(stderr, "\nRound-trip for range=(%zd..%zd) n=%zu\n", lb, ub, n);
asn_per_outp_t po;
memset(&po, 0, sizeof(po));
po.buffer = po.tmpspace;
po.nbits = 8 * sizeof(po.tmpspace);
put(&po, range, length);
size_t recovered = get(&po, range);
put(&po, lb, ub, n);
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) {
*/
static void
check_round_trips_range65536() {
check_round_trip(65536, 0);
check_round_trip(65536, 1);
check_round_trip(65536, 127);
check_round_trip(65536, 128);
check_round_trip(65536, 129);
check_round_trip(65536, 255);
check_round_trip(65536, 256);
check_round_trip(65536, 65534);
check_round_trip(65536, 65535);
check_round_trip(0, 65535, 0);
check_round_trip(0, 65535, 1);
check_round_trip(0, 65535, 127);
check_round_trip(0, 65535, 128);
check_round_trip(0, 65535, 129);
check_round_trip(0, 65535, 255);
check_round_trip(0, 65535, 256);
check_round_trip(0, 65535, 65534);
check_round_trip(0, 65535, 65535);
}
/*
......@@ -84,30 +84,32 @@ check_round_trips_range65536() {
static void
check_encode_number_greater_than_range() {
asn_per_outp_t po;
int range = 6500;
size_t length = 6503;
int lb = 0;
int ub = 6499;
size_t n = 6503;
ssize_t may_write;
memset(&po, 0, sizeof(po));
po.buffer = 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);
/* Also check value = range should fail: */
memset(&po, 0, sizeof(po));
po.buffer = po.tmpspace;
po.nbits = 8 * sizeof(po.tmpspace);
length = range;
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);
/* Again value = range, with edge case 65536: */
memset(&po, 0, sizeof(po));
po.buffer = po.tmpspace;
po.nbits = 8 * sizeof(po.tmpspace);
length = range = 65536;
may_write = aper_put_length(&po, range, length, NULL);
ub = 65535;
n = ub - lb + 1;
may_write = aper_put_length(&po, lb, ub, n, NULL);
assert(may_write < 0);
}
......@@ -118,17 +120,18 @@ check_encode_number_greater_than_range() {
static void
check_range65536_encoded_as_2octet() {
asn_per_outp_t po;
int range = 65536;
size_t length = 5;
int lb = 0;
int ub = 65535;
size_t n = 5;
memset(&po, 0, sizeof(po));
po.buffer = 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);
unsigned int bytes_needed = (po.buffer - po.tmpspace) + po.nboff/8;
fprintf(stderr, "\naper_put_length(range=%d, len=%zu) => bytes_needed=%u\n",
range, length, bytes_needed);
fprintf(stderr, "\naper_put_length(range=(%d..%d), len=%zu) => bytes_needed=%u\n",
lb, ub, n, bytes_needed);
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