Commit 6c52784d authored by Lev Walkin's avatar Lev Walkin

PER-encoding of integers wider than 32 bits

parent bfc76e8f
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
* Default constraint checking fix. * Default constraint checking fix.
Thanks to Bartosz Marcinkiewicz <bma@megawatt.com.pl> Thanks to Bartosz Marcinkiewicz <bma@megawatt.com.pl>
* Get rid of non-standard pointer arithmetics on void* pointer. * Get rid of non-standard pointer arithmetics on void* pointer.
* PER-encoding of integers wider than 32 bits.
0.9.24: 2013-Mar-16 0.9.24: 2013-Mar-16
......
/*
* Verify INTEGER values with greater than 32 bits range.
*/
#undef NDEBUG
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <T.h>
#ifndef _LP64
int main() {
assert(sizeof(void *) < 8);
return;
}
#else /* 64-bit platform */
static unsigned long i2ul(const INTEGER_t *i) {
unsigned long l;
int ret = asn_INTEGER2ulong(i, &l);
assert(ret == 0);
return l;
}
static void ul2i(INTEGER_t *i, unsigned long l) {
int ret = asn_ulong2INTEGER(i, l);
assert(ret == 0);
}
static void
verify(int testNo, T_t *ti) {
asn_enc_rval_t er;
asn_dec_rval_t rv;
unsigned char buf[16];
T_t *to = 0;
fprintf(stderr, "%d IN: { %lu, %lu }\n", testNo,
i2ul(&ti->unsigned33), i2ul(&ti->unsigned42));
er = uper_encode_to_buffer(&asn_DEF_T, ti, buf, sizeof buf);
assert(er.encoded == 33 + 42);
rv = uper_decode(0, &asn_DEF_T, (void *)&to, buf, sizeof buf, 0, 0);
assert(rv.code == RC_OK);
fprintf(stderr, "%d ENC: %2x%2x%2x%2x %2x%2x%2x%2x\n", testNo,
buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5], buf[6], buf[7]);
fprintf(stderr, "%d OUT: { %lu, %lu } vs { %lu, %lu }\n",
testNo,
i2ul(&ti->unsigned33), i2ul(&ti->unsigned42),
i2ul(&to->unsigned33), i2ul(&to->unsigned42));
assert(i2ul(&ti->unsigned33) == i2ul(&to->unsigned33));
assert(i2ul(&ti->unsigned42) == i2ul(&to->unsigned42));
xer_fprint(stderr, &asn_DEF_T, ti);
xer_fprint(stderr, &asn_DEF_T, to);
}
static void
NO_encode(int testNo, T_t *ti) {
asn_enc_rval_t er;
unsigned char buf[16];
fprintf(stderr, "%d IN: { %lu, %lu }\n", testNo,
i2ul(&ti->unsigned33), i2ul(&ti->unsigned42));
er = uper_encode_to_buffer(&asn_DEF_T, ti, buf, sizeof buf);
assert(er.encoded == -1);
}
int main() {
T_t ti;
memset(&ti, 0, sizeof(ti));
ul2i(&ti.unsigned33, 0);
ul2i(&ti.unsigned42, 0);
verify(1, &ti);
ul2i(&ti.unsigned33, 1);
ul2i(&ti.unsigned42, 1);
verify(2, &ti);
ul2i(&ti.unsigned33, 5000000000);
ul2i(&ti.unsigned42, 3153600000000);
verify(3, &ti);
ul2i(&ti.unsigned33, -1);
ul2i(&ti.unsigned42, 0);
NO_encode(4, &ti);
ul2i(&ti.unsigned33, 0);
ul2i(&ti.unsigned42, -1);
NO_encode(5, &ti);
ul2i(&ti.unsigned33, 5000000000 + 1);
ul2i(&ti.unsigned42, 0);
NO_encode(6, &ti);
ul2i(&ti.unsigned33, 0);
ul2i(&ti.unsigned42, 3153600000000 + 1);
NO_encode(7, &ti);
ul2i(&ti.unsigned33, 5000000000 - 1);
ul2i(&ti.unsigned42, 3153600000000 - 1);
verify(8, &ti);
return 0;
}
#endif /* 64-bit platform */
/*- /*-
* Copyright (c) 2003, 2004, 2005, 2006, 2007 Lev Walkin <vlm@lionet.info>. * Copyright (c) 2003-2014 Lev Walkin <vlm@lionet.info>.
* All rights reserved. * All rights reserved.
* Redistribution and modifications are permitted subject to BSD license. * 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, ...@@ -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) { if(ct && ct->flags != APC_UNCONSTRAINED) {
/* #10.5.6 */ /* #11.5.6 */
ASN_DEBUG("Integer with range %d bits", ct->range_bits); ASN_DEBUG("Integer with range %d bits", ct->range_bits);
if(ct->range_bits >= 0) { if(ct->range_bits >= 0) {
long value; if((size_t)ct->range_bits > 8 * sizeof(unsigned long))
if(ct->range_bits == 32) { _ASN_DECODE_FAILED;
long lhalf;
value = per_get_few_bits(pd, 16); if(specs && specs->field_unsigned) {
if(value < 0) _ASN_DECODE_STARVED; unsigned long uvalue;
lhalf = per_get_few_bits(pd, 16); if(uper_get_constrained_whole_number(pd,
if(lhalf < 0) _ASN_DECODE_STARVED; &uvalue, ct->range_bits))
value = (value << 16) | lhalf; _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 { } else {
value = per_get_few_bits(pd, ct->range_bits); unsigned long svalue;
if(value < 0) _ASN_DECODE_STARVED; 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; return rval;
} }
} else { } else {
...@@ -725,22 +730,14 @@ INTEGER_encode_uper(asn_TYPE_descriptor_t *td, ...@@ -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) { if(ct && ct->range_bits >= 0) {
/* #10.5.6 */ /* #11.5.6 -> #11.3 */
ASN_DEBUG("Encoding integer with range %d bits", ASN_DEBUG("Encoding integer with range %d bits",
ct->range_bits); ct->range_bits);
if(ct->range_bits == 32) { long v = value - ct->lower_bound;
/* TODO: extend to >32 bits */ if(uper_put_constrained_whole_number_s(po, v, ct->range_bits))
long v = value - ct->lower_bound; _ASN_ENCODE_FAILED;
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;
}
_ASN_ENCODED_OK(er); _ASN_ENCODED_OK(er);
} }
......
/* /*
* Copyright (c) 2005, 2006, 2007 Lev Walkin <vlm@lionet.info>. * Copyright (c) 2005-2014 Lev Walkin <vlm@lionet.info>.
* All rights reserved. * All rights reserved.
* Redistribution and modifications are permitted subject to BSD license. * Redistribution and modifications are permitted subject to BSD license.
*/ */
...@@ -238,8 +238,8 @@ uper_get_nsnnwn(asn_per_data_t *pd) { ...@@ -238,8 +238,8 @@ uper_get_nsnnwn(asn_per_data_t *pd) {
} }
/* /*
* Put the normally small non-negative whole number. * X.691-11/2008, #11.6
* X.691, #10.6 * Encoding of a normally small non-negative whole number
*/ */
int int
uper_put_nsnnwn(asn_per_outp_t *po, int n) { uper_put_nsnnwn(asn_per_outp_t *po, int n) {
...@@ -264,6 +264,58 @@ 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). * Put a small number of bits (<= 31).
*/ */
......
/* /*
* Copyright (c) 2005, 2006, 2007 Lev Walkin <vlm@lionet.info>. * Copyright (c) 2005-2014 Lev Walkin <vlm@lionet.info>.
* All rights reserved. * All rights reserved.
* Redistribution and modifications are permitted subject to BSD license. * Redistribution and modifications are permitted subject to BSD license.
*/ */
...@@ -81,6 +81,9 @@ ssize_t uper_get_nslength(asn_per_data_t *pd); ...@@ -81,6 +81,9 @@ ssize_t uper_get_nslength(asn_per_data_t *pd);
*/ */
ssize_t uper_get_nsnnwn(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 */ /* Non-thread-safe debugging function, don't use it */
char *per_data_string(asn_per_data_t *pd); 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); ...@@ -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 */ /* Output a large number of bits */
int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits); 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. * Put the length "n" to the Unaligned PER stream.
* This function returns the number of units which may be flushed * This function returns the number of units which may be flushed
......
-- OK: Everything is fine -- OK: Everything is fine
-- Also see .134 for wider integer types.
-- iso.org.dod.internet.private.enterprise (1.3.6.1.4.1) -- iso.org.dod.internet.private.enterprise (1.3.6.1.4.1)
-- .spelio.software.asn1c.test (9363.1.5.1) -- .spelio.software.asn1c.test (9363.1.5.1)
...@@ -12,6 +13,7 @@ ModulePERLong ...@@ -12,6 +13,7 @@ ModulePERLong
BEGIN BEGIN
T ::= SEQUENCE { T ::= SEQUENCE {
-- Should be supported on all 32-bit platforms and above.
small32range INTEGER (-2000000000..2000000000), small32range INTEGER (-2000000000..2000000000),
full32range INTEGER (-2147483648..2147483647), full32range INTEGER (-2147483648..2147483647),
unsigned32 INTEGER (0..4294967295), unsigned32 INTEGER (0..4294967295),
......
-- OK: Everything is fine
-- Also see .127 for narrower integer types.
-- iso.org.dod.internet.private.enterprise (1.3.6.1.4.1)
-- .spelio.software.asn1c.test (9363.1.5.1)
-- .134
ModulePERLong
{ iso org(3) dod(6) internet (1) private(4) enterprise(1)
spelio(9363) software(1) asn1c(5) test(1) 134 }
DEFINITIONS AUTOMATIC TAGS ::=
BEGIN
-- Supported only on 64-bit platforms.
T ::= SEQUENCE {
unsigned33 INTEGER (0..5000000000), -- range 33 bits
unsigned42 INTEGER (0..3153600000000) -- range 42 bits
}
END
/*** <<< INCLUDES [T] >>> ***/
#include <INTEGER.h>
#include <constr_SEQUENCE.h>
/*** <<< TYPE-DECLS [T] >>> ***/
typedef struct T {
INTEGER_t unsigned33;
INTEGER_t unsigned42;
/* Context for parsing across buffer boundaries */
asn_struct_ctx_t _asn_ctx;
} T_t;
/*** <<< FUNC-DECLS [T] >>> ***/
extern asn_TYPE_descriptor_t asn_DEF_T;
/*** <<< CODE [T] >>> ***/
static int
memb_unsigned33_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr,
asn_app_constraint_failed_f *ctfailcb, void *app_key) {
const INTEGER_t *st = (const INTEGER_t *)sptr;
long value;
if(!sptr) {
_ASN_CTFAIL(app_key, td, sptr,
"%s: value not given (%s:%d)",
td->name, __FILE__, __LINE__);
return -1;
}
if(asn_INTEGER2long(st, &value)) {
_ASN_CTFAIL(app_key, td, sptr,
"%s: value too large (%s:%d)",
td->name, __FILE__, __LINE__);
return -1;
}
if((value >= 0 && value <= 5000000000)) {
/* Constraint check succeeded */
return 0;
} else {
_ASN_CTFAIL(app_key, td, sptr,
"%s: constraint failed (%s:%d)",
td->name, __FILE__, __LINE__);
return -1;
}
}
static int
memb_unsigned42_constraint_1(asn_TYPE_descriptor_t *td, const void *sptr,
asn_app_constraint_failed_f *ctfailcb, void *app_key) {
const INTEGER_t *st = (const INTEGER_t *)sptr;
long value;
if(!sptr) {
_ASN_CTFAIL(app_key, td, sptr,
"%s: value not given (%s:%d)",
td->name, __FILE__, __LINE__);
return -1;
}
if(asn_INTEGER2long(st, &value)) {
_ASN_CTFAIL(app_key, td, sptr,
"%s: value too large (%s:%d)",
td->name, __FILE__, __LINE__);
return -1;
}
if((value >= 0 && value <= 3153600000000)) {
/* Constraint check succeeded */
return 0;
} else {
_ASN_CTFAIL(app_key, td, sptr,
"%s: constraint failed (%s:%d)",
td->name, __FILE__, __LINE__);
return -1;
}
}
/*** <<< CTDEFS [T] >>> ***/
static asn_per_constraints_t asn_PER_memb_unsigned33_constr_2 GCC_NOTUSED = {
{ APC_CONSTRAINED, 33, -1, 0, 5000000000 } /* (0..5000000000) */,
{ APC_UNCONSTRAINED, -1, -1, 0, 0 },
0, 0 /* No PER value map */
};
static asn_per_constraints_t asn_PER_memb_unsigned42_constr_3 GCC_NOTUSED = {
{ APC_CONSTRAINED, 42, -1, 0, 3153600000000 } /* (0..3153600000000) */,
{ APC_UNCONSTRAINED, -1, -1, 0, 0 },
0, 0 /* No PER value map */
};
/*** <<< STAT-DEFS [T] >>> ***/
static asn_TYPE_member_t asn_MBR_T_1[] = {
{ ATF_NOFLAGS, 0, offsetof(struct T, unsigned33),
.tag = (ASN_TAG_CLASS_CONTEXT | (0 << 2)),
.tag_mode = -1, /* IMPLICIT tag at current level */
.type = &asn_DEF_INTEGER,
.memb_constraints = memb_unsigned33_constraint_1,
.per_constraints = &asn_PER_memb_unsigned33_constr_2,
.default_value = 0,
.name = "unsigned33"
},
{ ATF_NOFLAGS, 0, offsetof(struct T, unsigned42),
.tag = (ASN_TAG_CLASS_CONTEXT | (1 << 2)),
.tag_mode = -1, /* IMPLICIT tag at current level */
.type = &asn_DEF_INTEGER,
.memb_constraints = memb_unsigned42_constraint_1,
.per_constraints = &asn_PER_memb_unsigned42_constr_3,
.default_value = 0,
.name = "unsigned42"
},
};
static ber_tlv_tag_t asn_DEF_T_tags_1[] = {
(ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
};
static asn_TYPE_tag2member_t asn_MAP_T_tag2el_1[] = {
{ (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 }, /* unsigned33 */
{ (ASN_TAG_CLASS_CONTEXT | (1 << 2)), 1, 0, 0 } /* unsigned42 */
};
static asn_SEQUENCE_specifics_t asn_SPC_T_specs_1 = {
sizeof(struct T),
offsetof(struct T, _asn_ctx),
asn_MAP_T_tag2el_1,
2, /* Count of tags in the map */
0, 0, 0, /* Optional elements (not needed) */
-1, /* Start extensions */
-1 /* Stop extensions */
};
asn_TYPE_descriptor_t asn_DEF_T = {
"T",
"T",
SEQUENCE_free,
SEQUENCE_print,
SEQUENCE_constraint,
SEQUENCE_decode_ber,
SEQUENCE_encode_der,
SEQUENCE_decode_xer,
SEQUENCE_encode_xer,
SEQUENCE_decode_uper,
SEQUENCE_encode_uper,
0, /* Use generic outmost tag fetcher */
asn_DEF_T_tags_1,
sizeof(asn_DEF_T_tags_1)
/sizeof(asn_DEF_T_tags_1[0]), /* 1 */
asn_DEF_T_tags_1, /* Same as above */
sizeof(asn_DEF_T_tags_1)
/sizeof(asn_DEF_T_tags_1[0]), /* 1 */
0, /* No PER visible constraints */
asn_MBR_T_1,
2, /* Elements count */
&asn_SPC_T_specs_1 /* Additional specs */
};
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