add some INTEGER OER encoding code
diff --git a/skeletons/INTEGER_oer.c b/skeletons/INTEGER_oer.c
index a606bf9..73c7e7f 100644
--- a/skeletons/INTEGER_oer.c
+++ b/skeletons/INTEGER_oer.c
@@ -87,23 +87,23 @@
rval.consumed += req_bytes;
return rval;
- } else if(ct && (ct->flags & AOC_HAS_LOWER_BOUND)) {
+ } else if(ct
+ && ((ct->flags
+ & (AOC_HAS_LOWER_BOUND | AOC_HAS_UPPER_BOUND))
+ == (AOC_HAS_LOWER_BOUND | AOC_HAS_UPPER_BOUND))) {
/* X.969 08/2015 10.2(b) - no lower bound or negative lower bound */
intmax_t lb = ct->lower_bound;
intmax_t ub = ct->upper_bound;
- if(ct->flags & AOC_HAS_UPPER_BOUND) {
- if(lb >= -128 && ub <= 127) {
- req_bytes = 1;
- } else if(lb >= -32768 && ub <= 32767) {
- req_bytes = 2;
- } else if(lb >= -2147483648L && ub <= 2147483647L) {
- req_bytes = 4;
- } else if(lb >= -9223372036854775808LL
- && ub <= 9223372036854775807LL) {
- req_bytes = 8;
- }
+ if(lb >= -128 && ub <= 127) {
+ req_bytes = 1;
+ } else if(lb >= -32768 && ub <= 32767) {
+ req_bytes = 2;
+ } else if(lb >= -2147483648L && ub <= 2147483647L) {
+ req_bytes = 4;
+ } else if(lb >= -9223372036854775808LL && ub <= 9223372036854775807LL) {
+ req_bytes = 8;
}
}
@@ -138,4 +138,110 @@
return rval;
}
+/*
+ * Encode as Canonical OER.
+ */
+asn_enc_rval_t
+INTEGER_encode_oer(asn_TYPE_descriptor_t *td,
+ asn_oer_constraints_t *constraints, void *sptr,
+ asn_app_consume_bytes_f *cb, void *app_key) {
+ const INTEGER_t *st = *(const INTEGER_t **)sptr;
+ asn_enc_rval_t er;
+ asn_oer_constraint_t *ct;
+ const uint8_t *buf;
+ const uint8_t *end;
+ size_t useful_bytes;
+ size_t req_bytes = 0;
+ int encode_as_unsigned;
+ int sign = 0;
+
+ if(!st || st->size == 0) ASN__ENCODE_FAILED;
+
+ if(!constraints) constraints = td->oer_constraints;
+ ct = constraints ? &constraints->value : 0;
+
+ er.encoded = 0;
+
+ buf = st->buf;
+ end = buf + st->size;
+
+ encode_as_unsigned =
+ ct && (ct->flags & AOC_HAS_LOWER_BOUND) && ct->lower_bound >= 0;
+
+ sign = (buf && buf < end) ? buf[0] & 0x80 : 0;
+
+ if(encode_as_unsigned && sign) {
+ /* The value given is a signed value. Can't proceed. */
+ ASN__ENCODE_FAILED;
+ }
+
+ /* Ignore 9 leading zeroes or ones */
+ for(; buf + 1 < end; buf++) {
+ if(buf[0] == 0x0 && ((buf[1] & 0x80) == 0 || encode_as_unsigned)) {
+ continue;
+ } else if(buf[0] == 0xff && (buf[1] & 0x80) != 0) {
+ continue;
+ }
+ break;
+ }
+
+ useful_bytes = end - buf;
+ if(encode_as_unsigned) {
+ intmax_t ub = ct->upper_bound;
+
+ if(ub <= 255) {
+ req_bytes = 1;
+ } else if(ub <= 65535) {
+ req_bytes = 2;
+ } else if(ub <= 4294967295UL) {
+ req_bytes = 4;
+ } else if(ub <= 18446744073709551615ULL) {
+ req_bytes = 8;
+ }
+ } else if(ct
+ && ((ct->flags
+ & (AOC_HAS_LOWER_BOUND | AOC_HAS_UPPER_BOUND))
+ == (AOC_HAS_LOWER_BOUND | AOC_HAS_UPPER_BOUND))) {
+ /* X.969 08/2015 10.2(b) - no lower bound or negative lower bound */
+
+ intmax_t lb = ct->lower_bound;
+ intmax_t ub = ct->upper_bound;
+
+ if(lb >= -128 && ub <= 127) {
+ req_bytes = 1;
+ } else if(lb >= -32768 && ub <= 32767) {
+ req_bytes = 2;
+ } else if(lb >= -2147483648L && ub <= 2147483647L) {
+ req_bytes = 4;
+ } else if(lb >= -9223372036854775808LL && ub <= 9223372036854775807LL) {
+ req_bytes = 8;
+ }
+ }
+
+ if(req_bytes == 0) {
+ ssize_t r = oer_serialize_length(useful_bytes, cb, app_key);
+ if(r < 0) {
+ ASN__ENCODE_FAILED;
+ }
+ er.encoded += r;
+ req_bytes = useful_bytes;
+ } else if(req_bytes < useful_bytes) {
+ ASN__ENCODE_FAILED;
+ }
+
+ er.encoded += req_bytes;
+
+ for(; req_bytes > useful_bytes; req_bytes--) {
+ if(cb(sign?"\xff":"\0", 1, app_key) < 0) {
+ ASN__ENCODE_FAILED;
+ }
+ }
+
+ if(cb(buf, useful_bytes, app_key) < 0) {
+ ASN__ENCODE_FAILED;
+ }
+
+ ASN__ENCODED_OK(er);
+}
+
#endif /* ASN_DISABLE_OER_SUPPORT */
diff --git a/skeletons/oer_support.c b/skeletons/oer_support.c
index 62d2f6d..096652c 100644
--- a/skeletons/oer_support.c
+++ b/skeletons/oer_support.c
@@ -63,3 +63,54 @@
}
+/*
+ * Serialize OER length. Returns the number of bytes serialized
+ * or -1 if a given callback returned with negative result.
+ */
+ssize_t
+oer_serialize_length(size_t length, asn_app_consume_bytes_f *cb,
+ void *app_key) {
+ uint8_t scratch[1 + sizeof(length)];
+ uint8_t *sp = scratch;
+ int littleEndian = 1; /* Run-time detection */
+ const uint8_t *pstart;
+ const uint8_t *pend;
+ const uint8_t *p;
+ int add;
+
+ if(length <= 127) {
+ uint8_t b = length;
+ if(cb(&b, 1, app_key) < 0) {
+ return -1;
+ }
+ return 1;
+ }
+
+ if(*(char *)&littleEndian) {
+ pstart = (const uint8_t *)&length + sizeof(length);
+ pend = (const uint8_t *)&length;
+ add = -1;
+ } else {
+ pstart = (const uint8_t *)&length;
+ pend = pstart + sizeof(length);
+ add = 1;
+ }
+
+ for(p = pstart; p != pend; p += add) {
+ /* Skip leading zeros. */
+ if(*p) break;
+ }
+
+ for(sp = scratch + 1; p != pend; p += add, sp++) {
+ *sp = *p;
+ }
+ assert((sp - scratch) - 1 <= 0x7f);
+ scratch[0] = 0x80 + ((sp - scratch) - 1);
+
+ if(cb(scratch, sp - scratch, app_key) < 0) {
+ return -1;
+ }
+
+ return sp - scratch;
+}
+
diff --git a/skeletons/oer_support.h b/skeletons/oer_support.h
index 3fba47e..727d7db 100644
--- a/skeletons/oer_support.h
+++ b/skeletons/oer_support.h
@@ -38,6 +38,12 @@
*/
ssize_t oer_fetch_length(const void *bufptr, size_t size, size_t *len_r);
+/*
+ * Serialize OER length. Returns the number of bytes serialized
+ * or -1 if a given callback returned with negative result.
+ */
+ssize_t oer_serialize_length(size_t length, asn_app_consume_bytes_f *cb, void *app_key);
+
#ifdef __cplusplus
}