aboutsummaryrefslogtreecommitdiffstats
path: root/skeletons
diff options
context:
space:
mode:
authorLev Walkin <vlm@lionet.info>2014-02-09 04:34:54 -0800
committerLev Walkin <vlm@lionet.info>2014-02-09 04:34:54 -0800
commit6c52784de169a792156a4d1da1312097ff93d551 (patch)
tree2abae447808b38c9130b22cdc2b9efdc0ba14882 /skeletons
parentbfc76e8f1e3c96cb7ada29b13825019201945bfd (diff)
PER-encoding of integers wider than 32 bits
Diffstat (limited to 'skeletons')
-rw-r--r--skeletons/INTEGER.c63
-rw-r--r--skeletons/per_support.c58
-rw-r--r--skeletons/per_support.h9
3 files changed, 93 insertions, 37 deletions
diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c
index 4dfe530a..9ce69604 100644
--- a/skeletons/INTEGER.c
+++ b/skeletons/INTEGER.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2003, 2004, 2005, 2006, 2007 Lev Walkin <vlm@lionet.info>.
+ * Copyright (c) 2003-2014 Lev Walkin <vlm@lionet.info>.
* All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
@@ -595,30 +595,35 @@ INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,
}
}
- /* X.691, #12.2.2 */
+ /* X.691-2008/11, #13.2.2, constrained whole number */
if(ct && ct->flags != APC_UNCONSTRAINED) {
- /* #10.5.6 */
+ /* #11.5.6 */
ASN_DEBUG("Integer with range %d bits", ct->range_bits);
if(ct->range_bits >= 0) {
- long value;
- if(ct->range_bits == 32) {
- long lhalf;
- value = per_get_few_bits(pd, 16);
- if(value < 0) _ASN_DECODE_STARVED;
- lhalf = per_get_few_bits(pd, 16);
- if(lhalf < 0) _ASN_DECODE_STARVED;
- value = (value << 16) | lhalf;
+ if((size_t)ct->range_bits > 8 * sizeof(unsigned long))
+ _ASN_DECODE_FAILED;
+
+ if(specs && specs->field_unsigned) {
+ unsigned long uvalue;
+ if(uper_get_constrained_whole_number(pd,
+ &uvalue, ct->range_bits))
+ _ASN_DECODE_STARVED;
+ ASN_DEBUG("Got value %lu + low %ld",
+ uvalue, ct->lower_bound);
+ uvalue += ct->lower_bound;
+ if(asn_ulong2INTEGER(st, uvalue))
+ _ASN_DECODE_FAILED;
} else {
- value = per_get_few_bits(pd, ct->range_bits);
- if(value < 0) _ASN_DECODE_STARVED;
+ unsigned long svalue;
+ if(uper_get_constrained_whole_number(pd,
+ &svalue, ct->range_bits))
+ _ASN_DECODE_STARVED;
+ ASN_DEBUG("Got value %ld + low %ld",
+ svalue, ct->lower_bound);
+ svalue += ct->lower_bound;
+ if(asn_long2INTEGER(st, svalue))
+ _ASN_DECODE_FAILED;
}
- ASN_DEBUG("Got value %ld + low %ld",
- value, ct->lower_bound);
- value += ct->lower_bound;
- if((specs && specs->field_unsigned)
- ? asn_ulong2INTEGER(st, value)
- : asn_long2INTEGER(st, value))
- _ASN_DECODE_FAILED;
return rval;
}
} else {
@@ -725,22 +730,14 @@ INTEGER_encode_uper(asn_TYPE_descriptor_t *td,
}
- /* X.691, #12.2.2 */
+ /* X.691-11/2008, #13.2.2, test if constrained whole number */
if(ct && ct->range_bits >= 0) {
- /* #10.5.6 */
+ /* #11.5.6 -> #11.3 */
ASN_DEBUG("Encoding integer with range %d bits",
ct->range_bits);
- if(ct->range_bits == 32) {
- /* TODO: extend to >32 bits */
- long v = value - ct->lower_bound;
- if(per_put_few_bits(po, v >> 1, 31)
- || per_put_few_bits(po, v, 1))
- _ASN_ENCODE_FAILED;
- } else {
- if(per_put_few_bits(po, value - ct->lower_bound,
- ct->range_bits))
- _ASN_ENCODE_FAILED;
- }
+ long v = value - ct->lower_bound;
+ if(uper_put_constrained_whole_number_s(po, v, ct->range_bits))
+ _ASN_ENCODE_FAILED;
_ASN_ENCODED_OK(er);
}
diff --git a/skeletons/per_support.c b/skeletons/per_support.c
index 2481fffb..0d089f49 100644
--- a/skeletons/per_support.c
+++ b/skeletons/per_support.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2006, 2007 Lev Walkin <vlm@lionet.info>.
+ * Copyright (c) 2005-2014 Lev Walkin <vlm@lionet.info>.
* All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
@@ -238,8 +238,8 @@ uper_get_nsnnwn(asn_per_data_t *pd) {
}
/*
- * Put the normally small non-negative whole number.
- * X.691, #10.6
+ * X.691-11/2008, #11.6
+ * Encoding of a normally small non-negative whole number
*/
int
uper_put_nsnnwn(asn_per_outp_t *po, int n) {
@@ -264,6 +264,58 @@ uper_put_nsnnwn(asn_per_outp_t *po, int n) {
}
+/* X.691-2008/11, #11.5.6 -> #11.3 */
+int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *out_value, int nbits) {
+ unsigned long lhalf; /* Lower half of the number*/
+ long half;
+
+ if(nbits <= 31) {
+ half = per_get_few_bits(pd, nbits);
+ if(half < 0) return -1;
+ *out_value = half;
+ return 0;
+ }
+
+ if((size_t)nbits > 8 * sizeof(*out_value))
+ return -1; /* RANGE */
+
+ half = per_get_few_bits(pd, 31);
+ if(half < 0) return -1;
+
+ if(uper_get_constrained_whole_number(pd, &lhalf, nbits - 31))
+ return -1;
+
+ *out_value = ((unsigned long)half << (nbits - 31)) | lhalf;
+ return 0;
+}
+
+
+/* X.691-2008/11, #11.5.6 -> #11.3 */
+int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits) {
+ /*
+ * Assume signed number can be safely coerced into
+ * unsigned of the same range.
+ * The following testing code will likely be optimized out
+ * by compiler if it is true.
+ */
+ unsigned long uvalue1 = ULONG_MAX;
+ long svalue = uvalue1;
+ unsigned long uvalue2 = svalue;
+ assert(uvalue1 == uvalue2);
+ return uper_put_constrained_whole_number_u(po, v, nbits);
+}
+
+int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits) {
+ if(nbits <= 31) {
+ return per_put_few_bits(po, v, nbits);
+ } else {
+ /* Put higher portion first, followed by lower 31-bit */
+ if(uper_put_constrained_whole_number_u(po, v >> 31, nbits - 31))
+ return -1;
+ return per_put_few_bits(po, v, 31);
+ }
+}
+
/*
* Put a small number of bits (<= 31).
*/
diff --git a/skeletons/per_support.h b/skeletons/per_support.h
index 7cb1a0ca..10c84ed0 100644
--- a/skeletons/per_support.h
+++ b/skeletons/per_support.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2006, 2007 Lev Walkin <vlm@lionet.info>.
+ * Copyright (c) 2005-2014 Lev Walkin <vlm@lionet.info>.
* All rights reserved.
* Redistribution and modifications are permitted subject to BSD license.
*/
@@ -81,6 +81,9 @@ ssize_t uper_get_nslength(asn_per_data_t *pd);
*/
ssize_t uper_get_nsnnwn(asn_per_data_t *pd);
+/* X.691-2008/11, #11.5.6 */
+int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *v, int nbits);
+
/* Non-thread-safe debugging function, don't use it */
char *per_data_string(asn_per_data_t *pd);
@@ -103,6 +106,10 @@ int per_put_few_bits(asn_per_outp_t *per_data, uint32_t bits, int obits);
/* Output a large number of bits */
int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits);
+/* X.691-2008/11, #11.5 */
+int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits);
+int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits);
+
/*
* Put the length "n" to the Unaligned PER stream.
* This function returns the number of units which may be flushed