From 523de9eba2d6963b2e0620bc93a3edc50e038c67 Mon Sep 17 00:00:00 2001 From: Lev Walkin <vlm@lionet.info> Date: Fri, 18 Aug 2006 01:34:18 +0000 Subject: [PATCH] per support --- skeletons/ANY.c | 2 +- skeletons/BIT_STRING.c | 1 + skeletons/BMPString.c | 2 +- skeletons/BOOLEAN.c | 16 ++++ skeletons/BOOLEAN.h | 1 + skeletons/ENUMERATED.c | 17 +++- skeletons/ENUMERATED.h | 1 + skeletons/GeneralString.c | 2 +- skeletons/GeneralizedTime.c | 2 +- skeletons/GraphicString.c | 2 +- skeletons/IA5String.c | 2 +- skeletons/INTEGER.c | 75 ++++++++++++++- skeletons/INTEGER.h | 1 + skeletons/ISO646String.c | 2 +- skeletons/NULL.c | 15 +++ skeletons/NULL.h | 1 + skeletons/NativeEnumerated.c | 83 ++++++++++++++++- skeletons/NativeEnumerated.h | 4 +- skeletons/NativeInteger.c | 25 ++++- skeletons/NativeInteger.h | 1 + skeletons/NativeReal.c | 2 +- skeletons/NumericString.c | 2 +- skeletons/OBJECT_IDENTIFIER.c | 25 ++--- skeletons/OCTET_STRING.c | 98 ++++++++++++++++++++ skeletons/OCTET_STRING.h | 1 + skeletons/ObjectDescriptor.c | 2 +- skeletons/PrintableString.c | 2 +- skeletons/REAL.c | 2 +- skeletons/RELATIVE-OID.c | 2 +- skeletons/T61String.c | 2 +- skeletons/TeletexString.c | 2 +- skeletons/UTCTime.c | 2 +- skeletons/UTF8String.c | 2 +- skeletons/UniversalString.c | 2 +- skeletons/VideotexString.c | 2 +- skeletons/VisibleString.c | 2 +- skeletons/constr_CHOICE.c | 82 ++++++++++++++++- skeletons/constr_CHOICE.h | 1 + skeletons/constr_SEQUENCE.c | 98 +++++++++++++++++++- skeletons/constr_SEQUENCE.h | 1 + skeletons/constr_SEQUENCE_OF.c | 69 +++++++++++++- skeletons/constr_SEQUENCE_OF.h | 1 + skeletons/constr_SET_OF.h | 1 + skeletons/constr_TYPE.h | 6 +- skeletons/der_encoder.c | 7 +- skeletons/der_encoder.h | 2 +- skeletons/file-dependencies | 1 + skeletons/per_encoder.c | 89 ++++++++++++++++++ skeletons/per_encoder.h | 49 ++++++++++ skeletons/per_support.c | 162 ++++++++++++++++++++++++++++++++- skeletons/per_support.h | 32 ++++++- skeletons/tests/check-PER.c | 100 +++++++++++++++++++- 52 files changed, 1043 insertions(+), 63 deletions(-) create mode 100644 skeletons/per_encoder.c create mode 100644 skeletons/per_encoder.h diff --git a/skeletons/ANY.c b/skeletons/ANY.c index a96aac0b..612238b6 100644 --- a/skeletons/ANY.c +++ b/skeletons/ANY.c @@ -21,7 +21,7 @@ asn_TYPE_descriptor_t asn_DEF_ANY = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_hex, ANY_encode_xer, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ 0, 0, 0, 0, 0, /* No PER visible constraints */ diff --git a/skeletons/BIT_STRING.c b/skeletons/BIT_STRING.c index 7434a2e1..6469d4fd 100644 --- a/skeletons/BIT_STRING.c +++ b/skeletons/BIT_STRING.c @@ -28,6 +28,7 @@ asn_TYPE_descriptor_t asn_DEF_BIT_STRING = { OCTET_STRING_decode_xer_binary, BIT_STRING_encode_xer, OCTET_STRING_decode_uper, /* Unaligned PER decoder */ + OCTET_STRING_encode_uper, /* Unaligned PER encoder */ 0, /* Use generic outmost tag fetcher */ asn_DEF_BIT_STRING_tags, sizeof(asn_DEF_BIT_STRING_tags) diff --git a/skeletons/BMPString.c b/skeletons/BMPString.c index 10fd05e0..1bfb174f 100644 --- a/skeletons/BMPString.c +++ b/skeletons/BMPString.c @@ -23,7 +23,7 @@ asn_TYPE_descriptor_t asn_DEF_BMPString = { OCTET_STRING_encode_der, BMPString_decode_xer, /* Convert from UTF-8 */ BMPString_encode_xer, /* Convert to UTF-8 */ - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_BMPString_tags, sizeof(asn_DEF_BMPString_tags) diff --git a/skeletons/BOOLEAN.c b/skeletons/BOOLEAN.c index 84e57858..bb4697c2 100644 --- a/skeletons/BOOLEAN.c +++ b/skeletons/BOOLEAN.c @@ -23,6 +23,7 @@ asn_TYPE_descriptor_t asn_DEF_BOOLEAN = { BOOLEAN_decode_xer, BOOLEAN_encode_xer, BOOLEAN_decode_uper, /* Unaligned PER decoder */ + BOOLEAN_encode_uper, /* Unaligned PER encoder */ 0, /* Use generic outmost tag fetcher */ asn_DEF_BOOLEAN_tags, sizeof(asn_DEF_BOOLEAN_tags) / sizeof(asn_DEF_BOOLEAN_tags[0]), @@ -266,3 +267,18 @@ BOOLEAN_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, return rv; } + +asn_enc_rval_t +BOOLEAN_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + const BOOLEAN_t *st = (const BOOLEAN_t *)sptr; + asn_enc_rval_t er; + + (void)constraints; + + if(!st) _ASN_ENCODE_FAILED; + + per_put_few_bits(po, *st ? 1 : 0, 1); + + _ASN_ENCODED_OK(er); +} diff --git a/skeletons/BOOLEAN.h b/skeletons/BOOLEAN.h index 1cf19803..217d0f16 100644 --- a/skeletons/BOOLEAN.h +++ b/skeletons/BOOLEAN.h @@ -27,6 +27,7 @@ der_type_encoder_f BOOLEAN_encode_der; xer_type_decoder_f BOOLEAN_decode_xer; xer_type_encoder_f BOOLEAN_encode_xer; per_type_decoder_f BOOLEAN_decode_uper; +per_type_encoder_f BOOLEAN_encode_uper; #ifdef __cplusplus } diff --git a/skeletons/ENUMERATED.c b/skeletons/ENUMERATED.c index 6a8b9c67..90761a2d 100644 --- a/skeletons/ENUMERATED.c +++ b/skeletons/ENUMERATED.c @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2003, 2005 Lev Walkin <vlm@lionet.info>. All rights reserved. + * Copyright (c) 2003, 2005, 2006 Lev Walkin <vlm@lionet.info>. + * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include <asn_internal.h> @@ -24,6 +25,7 @@ asn_TYPE_descriptor_t asn_DEF_ENUMERATED = { INTEGER_decode_xer, /* This is temporary! */ INTEGER_encode_xer, ENUMERATED_decode_uper, /* Unaligned PER decoder */ + ENUMERATED_encode_uper, /* Unaligned PER encoder */ 0, /* Use generic outmost tag fetcher */ asn_DEF_ENUMERATED_tags, sizeof(asn_DEF_ENUMERATED_tags) / sizeof(asn_DEF_ENUMERATED_tags[0]), @@ -54,3 +56,16 @@ ENUMERATED_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td rval.code = RC_FAIL; return rval; } + +asn_enc_rval_t +ENUMERATED_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + ENUMERATED_t *st = (ENUMERATED_t *)sptr; + long value; + + if(asn_INTEGER2long(st, &value)) + _ASN_ENCODE_FAILED; + + return NativeEnumerated_encode_uper(td, constraints, &value, po); +} + diff --git a/skeletons/ENUMERATED.h b/skeletons/ENUMERATED.h index e65a15af..542dcae9 100644 --- a/skeletons/ENUMERATED.h +++ b/skeletons/ENUMERATED.h @@ -16,6 +16,7 @@ typedef INTEGER_t ENUMERATED_t; /* Implemented via INTEGER */ extern asn_TYPE_descriptor_t asn_DEF_ENUMERATED; per_type_decoder_f ENUMERATED_decode_uper; +per_type_encoder_f ENUMERATED_encode_uper; #ifdef __cplusplus } diff --git a/skeletons/GeneralString.c b/skeletons/GeneralString.c index c1a8823e..55bb6643 100644 --- a/skeletons/GeneralString.c +++ b/skeletons/GeneralString.c @@ -22,7 +22,7 @@ asn_TYPE_descriptor_t asn_DEF_GeneralString = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_hex, OCTET_STRING_encode_xer, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_GeneralString_tags, sizeof(asn_DEF_GeneralString_tags) diff --git a/skeletons/GeneralizedTime.c b/skeletons/GeneralizedTime.c index 6236d2af..6d7855ee 100644 --- a/skeletons/GeneralizedTime.c +++ b/skeletons/GeneralizedTime.c @@ -152,7 +152,7 @@ asn_TYPE_descriptor_t asn_DEF_GeneralizedTime = { GeneralizedTime_encode_der, OCTET_STRING_decode_xer_utf8, GeneralizedTime_encode_xer, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_GeneralizedTime_tags, sizeof(asn_DEF_GeneralizedTime_tags) diff --git a/skeletons/GraphicString.c b/skeletons/GraphicString.c index 0c3ad47c..135cd733 100644 --- a/skeletons/GraphicString.c +++ b/skeletons/GraphicString.c @@ -22,7 +22,7 @@ asn_TYPE_descriptor_t asn_DEF_GraphicString = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_hex, OCTET_STRING_encode_xer, /* Can't expect it to be ASCII/UTF8 */ - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_GraphicString_tags, sizeof(asn_DEF_GraphicString_tags) diff --git a/skeletons/IA5String.c b/skeletons/IA5String.c index abc9ff38..5c000b03 100644 --- a/skeletons/IA5String.c +++ b/skeletons/IA5String.c @@ -22,7 +22,7 @@ asn_TYPE_descriptor_t asn_DEF_IA5String = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_utf8, OCTET_STRING_encode_xer_utf8, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_IA5String_tags, sizeof(asn_DEF_IA5String_tags) diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c index c43ac638..e9f61ac0 100644 --- a/skeletons/INTEGER.c +++ b/skeletons/INTEGER.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003, 2004, 2005 Lev Walkin <vlm@lionet.info>. + * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>. * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ @@ -25,6 +25,7 @@ asn_TYPE_descriptor_t asn_DEF_INTEGER = { INTEGER_decode_xer, INTEGER_encode_xer, INTEGER_decode_uper, /* Unaligned PER decoder */ + INTEGER_encode_uper, /* Unaligned PER encoder */ 0, /* Use generic outmost tag fetcher */ asn_DEF_INTEGER_tags, sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]), @@ -530,6 +531,78 @@ INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, return rval; } +asn_enc_rval_t +INTEGER_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_enc_rval_t er; + INTEGER_t *st = (INTEGER_t *)sptr; + const uint8_t *buf; + const uint8_t *end; + asn_per_constraint_t *ct; + long value = 0; + + if(!st || st->size == 0) _ASN_ENCODE_FAILED; + + if(!constraints) constraints = td->per_constraints; + ct = constraints ? &constraints->value : 0; + + er.encoded = 0; + + if(ct) { + int inext = 0; + if(asn_INTEGER2long(st, &value)) + _ASN_ENCODE_FAILED; + /* Check proper range */ + if(ct->flags & APC_SEMI_CONSTRAINED) { + if(value < ct->lower_bound) + inext = 1; + } else if(ct->range_bits >= 0) { + if(value < ct->lower_bound + || value > ct->upper_bound) + inext = 1; + } + ASN_DEBUG("Value %ld (%02x/%d) lb %ld ub %ld %s", + value, st->buf[0], st->size, + ct->lower_bound, ct->upper_bound, + inext ? "ext" : "fix"); + if(ct->flags & APC_EXTENSIBLE) { + if(per_put_few_bits(po, inext, 1)) + _ASN_ENCODE_FAILED; + if(inext) ct = 0; + } else if(inext) { + _ASN_ENCODE_FAILED; + } + } + + + /* X.691, #12.2.2 */ + if(ct && ct->range_bits >= 0) { + /* #10.5.6 */ + ASN_DEBUG("Encoding integer with range %d bits", + ct->range_bits); + if(per_put_few_bits(po, value - ct->lower_bound, + ct->range_bits)) + _ASN_ENCODE_FAILED; + _ASN_ENCODED_OK(er); + } + + if(ct && ct->lower_bound) { + ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound); + /* TODO: adjust lower bound */ + _ASN_ENCODE_FAILED; + } + + for(buf = st->buf, end = st->buf + st->size; buf < end;) { + ssize_t mayEncode = uper_put_length(po, end - buf); + if(mayEncode < 0) + _ASN_ENCODE_FAILED; + if(per_put_many_bits(po, buf, 8 * mayEncode)) + _ASN_ENCODE_FAILED; + } + + _ASN_ENCODED_OK(er); +} + int asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) { uint8_t *b, *end; diff --git a/skeletons/INTEGER.h b/skeletons/INTEGER.h index 410fbe90..62832b12 100644 --- a/skeletons/INTEGER.h +++ b/skeletons/INTEGER.h @@ -38,6 +38,7 @@ der_type_encoder_f INTEGER_encode_der; xer_type_decoder_f INTEGER_decode_xer; xer_type_encoder_f INTEGER_encode_xer; per_type_decoder_f INTEGER_decode_uper; +per_type_encoder_f INTEGER_encode_uper; /*********************************** * Some handy conversion routines. * diff --git a/skeletons/ISO646String.c b/skeletons/ISO646String.c index 829af328..d164aa7b 100644 --- a/skeletons/ISO646String.c +++ b/skeletons/ISO646String.c @@ -22,7 +22,7 @@ asn_TYPE_descriptor_t asn_DEF_ISO646String = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_utf8, OCTET_STRING_encode_xer_utf8, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_ISO646String_tags, sizeof(asn_DEF_ISO646String_tags) diff --git a/skeletons/NULL.c b/skeletons/NULL.c index 504be954..6d3316f1 100644 --- a/skeletons/NULL.c +++ b/skeletons/NULL.c @@ -24,6 +24,7 @@ asn_TYPE_descriptor_t asn_DEF_NULL = { NULL_decode_xer, NULL_encode_xer, NULL_decode_uper, /* Unaligned PER decoder */ + NULL_encode_uper, /* Unaligned PER encoder */ 0, /* Use generic outmost tag fetcher */ asn_DEF_NULL_tags, sizeof(asn_DEF_NULL_tags) / sizeof(asn_DEF_NULL_tags[0]), @@ -130,3 +131,17 @@ NULL_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, rv.consumed = 0; return rv; } + +asn_enc_rval_t +NULL_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, + void *sptr, asn_per_outp_t *po) { + asn_enc_rval_t er; + + (void)td; + (void)constraints; + (void)sptr; + (void)po; + + er.encoded = 0; + _ASN_ENCODED_OK(er); +} diff --git a/skeletons/NULL.h b/skeletons/NULL.h index 7126e1df..131e7759 100644 --- a/skeletons/NULL.h +++ b/skeletons/NULL.h @@ -24,6 +24,7 @@ der_type_encoder_f NULL_encode_der; xer_type_decoder_f NULL_decode_xer; xer_type_encoder_f NULL_encode_xer; per_type_decoder_f NULL_decode_uper; +per_type_encoder_f NULL_encode_uper; #ifdef __cplusplus } diff --git a/skeletons/NativeEnumerated.c b/skeletons/NativeEnumerated.c index 937accd1..fa16eb07 100644 --- a/skeletons/NativeEnumerated.c +++ b/skeletons/NativeEnumerated.c @@ -29,6 +29,7 @@ asn_TYPE_descriptor_t asn_DEF_NativeEnumerated = { NativeInteger_decode_xer, NativeEnumerated_encode_xer, NativeEnumerated_decode_uper, + NativeEnumerated_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_NativeEnumerated_tags, sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]), @@ -70,8 +71,9 @@ NativeEnumerated_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, } asn_dec_rval_t -NativeEnumerated_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, - asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { +NativeEnumerated_decode_uper(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, + void **sptr, asn_per_data_t *pd) { asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics; asn_dec_rval_t rval = { RC_OK, 0 }; long *native = (long *)*sptr; @@ -123,3 +125,80 @@ NativeEnumerated_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor return rval; } +static int +NativeEnumerated__compar_value2enum(const void *ap, const void *bp) { + const asn_INTEGER_enum_map_t *a = ap; + const asn_INTEGER_enum_map_t *b = bp; + if(a->nat_value == b->nat_value) + return 0; + if(a->nat_value < b->nat_value) + return -1; + return 1; +} + +asn_enc_rval_t +NativeEnumerated_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_INTEGER_specifics_t *specs = (asn_INTEGER_specifics_t *)td->specifics; + asn_enc_rval_t er; + long native, value; + asn_per_constraint_t *ct; + int inext = 0; + asn_INTEGER_enum_map_t key; + asn_INTEGER_enum_map_t *kf; + + if(!sptr) _ASN_ENCODE_FAILED; + if(!specs) _ASN_ENCODE_FAILED; + + if(constraints) ct = &constraints->value; + else if(td->per_constraints) ct = &td->per_constraints->value; + else _ASN_ENCODE_FAILED; /* Mandatory! */ + + ASN_DEBUG("Encoding %s as NativeEnumerated", td->name); + + er.encoded = 0; + + native = *(long *)sptr; + if(native < 0) _ASN_ENCODE_FAILED; + + key.nat_value = native; + kf = bsearch(&key, specs->value2enum, specs->map_count, + sizeof(key), NativeEnumerated__compar_value2enum); + if(!kf) { + ASN_DEBUG("No element corresponds to %ld", native); + _ASN_ENCODE_FAILED; + } + value = kf - specs->value2enum; + + if(ct->range_bits >= 0) { + int cmpWith = specs->extension + ? specs->extension - 1 : specs->map_count; + if(value >= cmpWith) + inext = 1; + } + if(ct->flags & APC_EXTENSIBLE) { + if(per_put_few_bits(po, inext, 0)) + _ASN_ENCODE_FAILED; + ct = 0; + } else if(inext) { + _ASN_ENCODE_FAILED; + } + + if(ct && ct->range_bits >= 0) { + if(per_put_few_bits(po, value, ct->range_bits)) + _ASN_ENCODE_FAILED; + _ASN_ENCODED_OK(er); + } + + if(!specs->extension) + _ASN_ENCODE_FAILED; + + /* + * X.691, #10.6: normally small non-negative whole number; + */ + if(uper_put_nsnnwn(po, value - (specs->extension - 1))) + _ASN_ENCODE_FAILED; + + _ASN_ENCODED_OK(er); +} + diff --git a/skeletons/NativeEnumerated.h b/skeletons/NativeEnumerated.h index 5792beed..c59bb1ba 100644 --- a/skeletons/NativeEnumerated.h +++ b/skeletons/NativeEnumerated.h @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2004, 2005 Lev Walkin <vlm@lionet.info>. All rights reserved. + * Copyright (c) 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>. + * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ /* @@ -22,6 +23,7 @@ extern asn_TYPE_descriptor_t asn_DEF_NativeEnumerated; xer_type_encoder_f NativeEnumerated_encode_xer; per_type_decoder_f NativeEnumerated_decode_uper; +per_type_encoder_f NativeEnumerated_encode_uper; #ifdef __cplusplus } diff --git a/skeletons/NativeInteger.c b/skeletons/NativeInteger.c index 3d1d6b47..34599f61 100644 --- a/skeletons/NativeInteger.c +++ b/skeletons/NativeInteger.c @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2004, 2005 Lev Walkin <vlm@lionet.info>. All rights reserved. + * Copyright (c) 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>. + * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ /* @@ -29,6 +30,7 @@ asn_TYPE_descriptor_t asn_DEF_NativeInteger = { NativeInteger_decode_xer, NativeInteger_encode_xer, NativeInteger_decode_uper, /* Unaligned PER decoder */ + NativeInteger_encode_uper, /* Unaligned PER encoder */ 0, /* Use generic outmost tag fetcher */ asn_DEF_NativeInteger_tags, sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]), @@ -253,6 +255,27 @@ NativeInteger_decode_uper(asn_codec_ctx_t *opt_codec_ctx, return rval; } +asn_enc_rval_t +NativeInteger_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_enc_rval_t er; + long native; + INTEGER_t tmpint; + + if(!sptr) _ASN_ENCODE_FAILED; + + native = *(long *)sptr; + + ASN_DEBUG("Encoding NativeInteger %s %ld (UPER)", td->name, native); + + memset(&tmpint, 0, sizeof(tmpint)); + if(asn_long2INTEGER(&tmpint, native)) + _ASN_ENCODE_FAILED; + er = INTEGER_encode_uper(td, constraints, &tmpint, po); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); + return er; +} + /* * INTEGER specific human-readable output. */ diff --git a/skeletons/NativeInteger.h b/skeletons/NativeInteger.h index e2ce22e9..4e63a835 100644 --- a/skeletons/NativeInteger.h +++ b/skeletons/NativeInteger.h @@ -28,6 +28,7 @@ der_type_encoder_f NativeInteger_encode_der; xer_type_decoder_f NativeInteger_decode_xer; xer_type_encoder_f NativeInteger_encode_xer; per_type_decoder_f NativeInteger_decode_uper; +per_type_encoder_f NativeInteger_encode_uper; #ifdef __cplusplus } diff --git a/skeletons/NativeReal.c b/skeletons/NativeReal.c index 1683f901..2b8ec166 100644 --- a/skeletons/NativeReal.c +++ b/skeletons/NativeReal.c @@ -29,7 +29,7 @@ asn_TYPE_descriptor_t asn_DEF_NativeReal = { NativeReal_encode_der, NativeReal_decode_xer, NativeReal_encode_xer, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_NativeReal_tags, sizeof(asn_DEF_NativeReal_tags) / sizeof(asn_DEF_NativeReal_tags[0]), diff --git a/skeletons/NumericString.c b/skeletons/NumericString.c index f980dcdc..cef64ea6 100644 --- a/skeletons/NumericString.c +++ b/skeletons/NumericString.c @@ -22,7 +22,7 @@ asn_TYPE_descriptor_t asn_DEF_NumericString = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_utf8, OCTET_STRING_encode_xer_utf8, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_NumericString_tags, sizeof(asn_DEF_NumericString_tags) diff --git a/skeletons/OBJECT_IDENTIFIER.c b/skeletons/OBJECT_IDENTIFIER.c index 53d5353e..b1666dc6 100644 --- a/skeletons/OBJECT_IDENTIFIER.c +++ b/skeletons/OBJECT_IDENTIFIER.c @@ -23,7 +23,7 @@ asn_TYPE_descriptor_t asn_DEF_OBJECT_IDENTIFIER = { der_encode_primitive, OBJECT_IDENTIFIER_decode_xer, OBJECT_IDENTIFIER_encode_xer, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_OBJECT_IDENTIFIER_tags, sizeof(asn_DEF_OBJECT_IDENTIFIER_tags) @@ -425,6 +425,7 @@ OBJECT_IDENTIFIER_set_single_arc(uint8_t *arcbuf, const void *arcval, unsigned i * The following conditions must hold: * assert(arcval); * assert(arcval_size > 0); + * assert(arcval_size <= 16); * assert(arcbuf); */ #ifdef WORDS_BIGENDIAN @@ -437,12 +438,7 @@ OBJECT_IDENTIFIER_set_single_arc(uint8_t *arcbuf, const void *arcval, unsigned i unsigned int cache; uint8_t *bp = arcbuf; int bits; -#ifdef __GNUC__ - uint8_t buffer[arcval_size]; -#else - uint8_t *buffer = alloca(arcval_size); - if(!buffer) { errno = ENOMEM; return -1; } -#endif + uint8_t buffer[16]; if(isLittleEndian && !prepared_order) { const uint8_t *a = (const unsigned char *)arcval + arcval_size - 1; @@ -502,7 +498,9 @@ OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *oid, const void *arcs, unsigned unsigned size; unsigned i; - if(!oid || !arcs || arc_type_size < 1 || arc_slots < 2) { + if(!oid || !arcs || arc_type_size < 1 + || arc_type_size > 16 + || arc_slots < 2) { errno = EINVAL; return -1; } @@ -586,17 +584,8 @@ OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *oid, const void *arcs, unsigned */ { uint8_t *tp; -#ifdef __GNUC__ - uint8_t first_value[1 + arc_type_size]; /* of two arcs */ - uint8_t *fv = first_value; -#else - uint8_t *first_value = alloca(1 + arc_type_size); + uint8_t first_value[1 + 16]; /* of two arcs */ uint8_t *fv = first_value; - if(!first_value) { - errno = ENOMEM; - return -1; - } -#endif /* * Simulate first_value = arc0 * 40 + arc1; diff --git a/skeletons/OCTET_STRING.c b/skeletons/OCTET_STRING.c index c5a4ed34..f2dd1c60 100644 --- a/skeletons/OCTET_STRING.c +++ b/skeletons/OCTET_STRING.c @@ -33,6 +33,7 @@ asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = { OCTET_STRING_decode_xer_hex, OCTET_STRING_encode_xer, OCTET_STRING_decode_uper, /* Unaligned PER decoder */ + OCTET_STRING_encode_uper, /* Unaligned PER encoder */ 0, /* Use generic outmost tag fetcher */ asn_DEF_OCTET_STRING_tags, sizeof(asn_DEF_OCTET_STRING_tags) @@ -1297,6 +1298,103 @@ OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx, return rval; } +asn_enc_rval_t +OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + + asn_OCTET_STRING_specifics_t *specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_DEF_OCTET_STRING_specs; + asn_per_constraint_t *ct = constraints ? &constraints->size + : (td->per_constraints + ? &td->per_constraints->size + : &asn_DEF_OCTET_STRING_constraint); + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + int unit_bits = (specs->subvariant != 1) * 7 + 1; + asn_enc_rval_t er; + int ct_extensible = ct->flags & APC_EXTENSIBLE; + int inext = 0; /* Lies not within extension root */ + int sizeinunits = st->size; + const uint8_t *buf; + int ret; + + if(!st || !st->buf) + _ASN_ENCODE_FAILED; + + if(unit_bits == 1) { + ASN_DEBUG("BIT STRING of %d bytes, %d bits unused", + sizeinunits, st->bits_unused); + sizeinunits = sizeinunits * 8 - (st->bits_unused & 0x07); + } + + ASN_DEBUG("Encoding %s into %d units", + td->name, sizeinunits); + + /* Figure out wheter size lies within PER visible consrtaint */ + + if(ct->effective_bits >= 0) { + if(sizeinunits < ct->lower_bound + || sizeinunits > ct->upper_bound) { + if(ct_extensible) { + ct = &asn_DEF_OCTET_STRING_constraint; + inext = 1; + } else + _ASN_ENCODE_FAILED; + } + } else { + inext = 0; + } + + if(ct_extensible) { + /* Declare whether length is [not] within extension root */ + if(per_put_few_bits(po, inext, 1)) + _ASN_ENCODE_FAILED; + } + + /* X.691, #16.5: zero-length encoding */ + /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ + /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ + if(ct->effective_bits >= 0) { + ASN_DEBUG("Encoding %d bytes (%ld), length in %d bits", + st->size, sizeinunits - ct->lower_bound, + ct->effective_bits); + ret = per_put_few_bits(po, sizeinunits - ct->lower_bound, + ct->effective_bits); + if(ret) _ASN_ENCODE_FAILED; + ret = per_put_many_bits(po, st->buf, sizeinunits); + if(ret) _ASN_ENCODE_FAILED; + _ASN_ENCODED_OK(er); + } + + ASN_DEBUG("Encoding %d bytes", st->size); + + if(sizeinunits == 0) { + if(uper_put_length(po, 0)) + _ASN_ENCODE_FAILED; + _ASN_ENCODED_OK(er); + } + + buf = st->buf; + while(sizeinunits) { + ssize_t maySave = uper_put_length(po, sizeinunits); + if(maySave < 0) _ASN_ENCODE_FAILED; + + ASN_DEBUG("Encoding %d of %d", maySave, sizeinunits); + + ret = per_put_many_bits(po, buf, maySave); + if(ret) _ASN_ENCODE_FAILED; + + if(unit_bits == 1) + buf += maySave >> 3; + else + buf += maySave; + sizeinunits -= maySave; + assert(!(maySave & 0x07) || !sizeinunits); + } + + _ASN_ENCODED_OK(er); +} + int OCTET_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { diff --git a/skeletons/OCTET_STRING.h b/skeletons/OCTET_STRING.h index e85d05c3..5150161a 100644 --- a/skeletons/OCTET_STRING.h +++ b/skeletons/OCTET_STRING.h @@ -31,6 +31,7 @@ xer_type_decoder_f OCTET_STRING_decode_xer_utf8; /* ASCII/UTF-8 */ xer_type_encoder_f OCTET_STRING_encode_xer; xer_type_encoder_f OCTET_STRING_encode_xer_utf8; per_type_decoder_f OCTET_STRING_decode_uper; +per_type_encoder_f OCTET_STRING_encode_uper; /****************************** * Handy conversion routines. * diff --git a/skeletons/ObjectDescriptor.c b/skeletons/ObjectDescriptor.c index 37f51e8c..44cb5f66 100644 --- a/skeletons/ObjectDescriptor.c +++ b/skeletons/ObjectDescriptor.c @@ -22,7 +22,7 @@ asn_TYPE_descriptor_t asn_DEF_ObjectDescriptor = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_utf8, OCTET_STRING_encode_xer_utf8, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_ObjectDescriptor_tags, sizeof(asn_DEF_ObjectDescriptor_tags) diff --git a/skeletons/PrintableString.c b/skeletons/PrintableString.c index 5533253f..f5880832 100644 --- a/skeletons/PrintableString.c +++ b/skeletons/PrintableString.c @@ -22,7 +22,7 @@ asn_TYPE_descriptor_t asn_DEF_PrintableString = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_utf8, OCTET_STRING_encode_xer_utf8, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_PrintableString_tags, sizeof(asn_DEF_PrintableString_tags) diff --git a/skeletons/REAL.c b/skeletons/REAL.c index 689b05ec..dfaedf7d 100644 --- a/skeletons/REAL.c +++ b/skeletons/REAL.c @@ -42,7 +42,7 @@ asn_TYPE_descriptor_t asn_DEF_REAL = { der_encode_primitive, REAL_decode_xer, REAL_encode_xer, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_REAL_tags, sizeof(asn_DEF_REAL_tags) / sizeof(asn_DEF_REAL_tags[0]), diff --git a/skeletons/RELATIVE-OID.c b/skeletons/RELATIVE-OID.c index 74511b7b..01814342 100644 --- a/skeletons/RELATIVE-OID.c +++ b/skeletons/RELATIVE-OID.c @@ -25,7 +25,7 @@ asn_TYPE_descriptor_t asn_DEF_RELATIVE_OID = { der_encode_primitive, RELATIVE_OID_decode_xer, RELATIVE_OID_encode_xer, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_RELATIVE_OID_tags, sizeof(asn_DEF_RELATIVE_OID_tags) diff --git a/skeletons/T61String.c b/skeletons/T61String.c index 4157a6b2..25d887ae 100644 --- a/skeletons/T61String.c +++ b/skeletons/T61String.c @@ -22,7 +22,7 @@ asn_TYPE_descriptor_t asn_DEF_T61String = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_hex, OCTET_STRING_encode_xer, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_T61String_tags, sizeof(asn_DEF_T61String_tags) diff --git a/skeletons/TeletexString.c b/skeletons/TeletexString.c index 11f57033..b96cb3bb 100644 --- a/skeletons/TeletexString.c +++ b/skeletons/TeletexString.c @@ -22,7 +22,7 @@ asn_TYPE_descriptor_t asn_DEF_TeletexString = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_hex, OCTET_STRING_encode_xer, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_TeletexString_tags, sizeof(asn_DEF_TeletexString_tags) diff --git a/skeletons/UTCTime.c b/skeletons/UTCTime.c index 5d7ba84e..3793a0e6 100644 --- a/skeletons/UTCTime.c +++ b/skeletons/UTCTime.c @@ -28,7 +28,7 @@ asn_TYPE_descriptor_t asn_DEF_UTCTime = { OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */ OCTET_STRING_decode_xer_utf8, UTCTime_encode_xer, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_UTCTime_tags, sizeof(asn_DEF_UTCTime_tags) diff --git a/skeletons/UTF8String.c b/skeletons/UTF8String.c index 85f2ccd8..3cd574d5 100644 --- a/skeletons/UTF8String.c +++ b/skeletons/UTF8String.c @@ -22,7 +22,7 @@ asn_TYPE_descriptor_t asn_DEF_UTF8String = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_utf8, OCTET_STRING_encode_xer_utf8, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_UTF8String_tags, sizeof(asn_DEF_UTF8String_tags) diff --git a/skeletons/UniversalString.c b/skeletons/UniversalString.c index 0fab915f..a39e5699 100644 --- a/skeletons/UniversalString.c +++ b/skeletons/UniversalString.c @@ -23,7 +23,7 @@ asn_TYPE_descriptor_t asn_DEF_UniversalString = { OCTET_STRING_encode_der, UniversalString_decode_xer, /* Convert from UTF-8 */ UniversalString_encode_xer, /* Convert into UTF-8 */ - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_UniversalString_tags, sizeof(asn_DEF_UniversalString_tags) diff --git a/skeletons/VideotexString.c b/skeletons/VideotexString.c index c51c31aa..5f5f33d6 100644 --- a/skeletons/VideotexString.c +++ b/skeletons/VideotexString.c @@ -22,7 +22,7 @@ asn_TYPE_descriptor_t asn_DEF_VideotexString = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_hex, OCTET_STRING_encode_xer, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_VideotexString_tags, sizeof(asn_DEF_VideotexString_tags) diff --git a/skeletons/VisibleString.c b/skeletons/VisibleString.c index 7c705013..8796582d 100644 --- a/skeletons/VisibleString.c +++ b/skeletons/VisibleString.c @@ -22,7 +22,7 @@ asn_TYPE_descriptor_t asn_DEF_VisibleString = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_utf8, OCTET_STRING_encode_xer_utf8, - 0, + 0, 0, 0, /* Use generic outmost tag fetcher */ asn_DEF_VisibleString_tags, sizeof(asn_DEF_VisibleString_tags) diff --git a/skeletons/constr_CHOICE.c b/skeletons/constr_CHOICE.c index 84a3b4e3..224e56a9 100644 --- a/skeletons/constr_CHOICE.c +++ b/skeletons/constr_CHOICE.c @@ -1,5 +1,5 @@ -/*- - * Copyright (c) 2003, 2004, 2005 Lev Walkin <vlm@lionet.info>. +/* + * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>. * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ @@ -363,6 +363,8 @@ CHOICE_encode_der(asn_TYPE_descriptor_t *td, void *sptr, size_t computed_size = 0; int present; + if(!sptr) _ASN_ENCODE_FAILED; + ASN_DEBUG("%s %s as CHOICE", cb?"Encoding":"Estimating", td->name); @@ -892,6 +894,82 @@ CHOICE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, return rv; } +asn_enc_rval_t +CHOICE_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + asn_TYPE_member_t *elm; /* CHOICE's element */ + asn_per_constraint_t *ct; + void *memb_ptr; + int present; + + if(!sptr) _ASN_ENCODE_FAILED; + + ASN_DEBUG("Encoding %s as CHOICE", td->name); + + if(constraints) ct = &constraints->value; + else if(td->per_constraints) ct = &td->per_constraints->value; + else ct = 0; + + present = _fetch_present_idx(sptr, + specs->pres_offset, specs->pres_size); + + /* + * If the structure was not initialized properly, it cannot be encoded: + * can't deduce what to encode in the choice type. + */ + if(present <= 0 || present > td->elements_count) + _ASN_ENCODE_FAILED; + else + present--; + + /* Adjust if canonical order is different from natural order */ + if(specs->canonical_order) + present = specs->canonical_order[present]; + + ASN_DEBUG("Encoding %s CHOICE element %d", td->name, present); + + if(ct && ct->range_bits >= 0) { + if(present < ct->lower_bound + || present > ct->upper_bound) { + if(ct->flags & APC_EXTENSIBLE) { + if(per_put_few_bits(po, 1, 1)) + _ASN_ENCODE_FAILED; + } else { + _ASN_ENCODE_FAILED; + } + ct = 0; + } + } + if(ct && ct->flags & APC_EXTENSIBLE) + if(per_put_few_bits(po, 0, 1)) + _ASN_ENCODE_FAILED; + + if(ct && ct->range_bits >= 0) { + if(per_put_few_bits(po, present, ct->range_bits)) + _ASN_ENCODE_FAILED; + } else { + if(specs->ext_start == -1) + _ASN_ENCODE_FAILED; + if(uper_put_nsnnwn(po, present - specs->ext_start)) + _ASN_ENCODE_FAILED; + ASN_DEBUG("NOT IMPLEMENTED YET"); + _ASN_ENCODE_FAILED; + } + + elm = &td->elements[present]; + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(!memb_ptr) _ASN_ENCODE_FAILED; + } else { + memb_ptr = (char *)sptr + elm->memb_offset; + } + + return elm->type->uper_encoder(elm->type, elm->per_constraints, + memb_ptr, po); +} + int CHOICE_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, diff --git a/skeletons/constr_CHOICE.h b/skeletons/constr_CHOICE.h index 6276d7e4..83404e6d 100644 --- a/skeletons/constr_CHOICE.h +++ b/skeletons/constr_CHOICE.h @@ -47,6 +47,7 @@ der_type_encoder_f CHOICE_encode_der; xer_type_decoder_f CHOICE_decode_xer; xer_type_encoder_f CHOICE_encode_xer; per_type_decoder_f CHOICE_decode_uper; +per_type_encoder_f CHOICE_encode_uper; asn_outmost_tag_f CHOICE_outmost_tag; #ifdef __cplusplus diff --git a/skeletons/constr_SEQUENCE.c b/skeletons/constr_SEQUENCE.c index d38afb5a..5b240070 100644 --- a/skeletons/constr_SEQUENCE.c +++ b/skeletons/constr_SEQUENCE.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003, 2004, 2005 Lev Walkin <vlm@lionet.info>. + * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>. * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ @@ -1097,7 +1097,7 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, /* This element is not present */ if(elm->default_value) { /* Fill-in DEFAULT */ - if(elm->default_value(memb_ptr2)) { + if(elm->default_value(1, memb_ptr2)) { FREEMEM(opres); _ASN_DECODE_FAILED; } @@ -1137,14 +1137,15 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, /* Fetch the pointer to this member */ if(elm->flags & ATF_POINTER) { - memb_ptr2 = (void **)((char *)st + elm->memb_offset); + memb_ptr2 = (void **)((char *)st + + elm->memb_offset); } else { memb_ptr = (char *)st + elm->memb_offset; memb_ptr2 = &memb_ptr; } /* Set default value */ - if(elm->default_value(memb_ptr2)) { + if(elm->default_value(1, memb_ptr2)) { FREEMEM(opres); _ASN_DECODE_FAILED; } @@ -1157,3 +1158,92 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, return rv; } +asn_enc_rval_t +SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_SEQUENCE_specifics_t *specs + = (asn_SEQUENCE_specifics_t *)td->specifics; + asn_enc_rval_t er; + int edx; + int i; + + (void)constraints; + + if(!sptr) + _ASN_ENCODE_FAILED; + + er.encoded = 0; + + ASN_DEBUG("Encoding %s as SEQUENCE (UPER)", td->name); + if(specs->ext_before >= 0) + _ASN_ENCODE_FAILED; /* We don't encode extensions yet */ + + /* Encode a presence bitmap */ + for(i = 0; i < specs->roms_count; i++) { + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + edx = specs->oms[i]; + asn_TYPE_member_t *elm = &td->elements[edx]; + int present; + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); + present = (*memb_ptr2 != 0); + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + memb_ptr2 = &memb_ptr; + present = 1; + } + + /* Eliminate default values */ + if(present && elm->default_value + && elm->default_value(0, memb_ptr2) == 1) + present = 0; + + ASN_DEBUG("Element %s %s %s->%s is %s", + elm->flags & ATF_POINTER ? "ptr" : "inline", + elm->default_value ? "def" : "wtv", + td->name, elm->name, present ? "present" : "absent"); + if(per_put_few_bits(po, present, 1)) + _ASN_ENCODE_FAILED; + } + + /* + * Get the sequence ROOT elements. + */ + for(edx = 0; edx < ((specs->ext_before < 0) + ? td->elements_count : specs->ext_before + 1); edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)sptr + elm->memb_offset); + if(!*memb_ptr2) { + ASN_DEBUG("Element %s %d not present", + elm->name, edx); + if(elm->optional) + continue; + /* Mandatory element is missing */ + _ASN_ENCODE_FAILED; + } + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + memb_ptr2 = &memb_ptr; + } + + /* Eliminate default values */ + if(elm->default_value && elm->default_value(0, memb_ptr2) == 1) + continue; + + er = elm->type->uper_encoder(elm->type, elm->per_constraints, + *memb_ptr2, po); + if(er.encoded == -1) + return er; + } + + _ASN_ENCODED_OK(er); +} + diff --git a/skeletons/constr_SEQUENCE.h b/skeletons/constr_SEQUENCE.h index b4ee47f9..5f589d5c 100644 --- a/skeletons/constr_SEQUENCE.h +++ b/skeletons/constr_SEQUENCE.h @@ -51,6 +51,7 @@ der_type_encoder_f SEQUENCE_encode_der; xer_type_decoder_f SEQUENCE_decode_xer; xer_type_encoder_f SEQUENCE_encode_xer; per_type_decoder_f SEQUENCE_decode_uper; +per_type_encoder_f SEQUENCE_encode_uper; #ifdef __cplusplus } diff --git a/skeletons/constr_SEQUENCE_OF.c b/skeletons/constr_SEQUENCE_OF.c index 3ddd5a39..aa101176 100644 --- a/skeletons/constr_SEQUENCE_OF.c +++ b/skeletons/constr_SEQUENCE_OF.c @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved. + * Copyright (c) 2003, 2004, 2006 Lev Walkin <vlm@lionet.info>. + * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include <asn_internal.h> @@ -139,3 +140,69 @@ cb_failed: _ASN_ENCODE_FAILED; } +asn_enc_rval_t +SEQUENCE_OF_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_anonymous_sequence_ *list; + asn_per_constraint_t *ct; + asn_enc_rval_t er; + asn_TYPE_member_t *elm = td->elements; + int seq; + + if(!sptr) _ASN_ENCODE_FAILED; + list = _A_SEQUENCE_FROM_VOID(sptr); + + er.encoded = 0; + + ASN_DEBUG("Encoding %s as SEQUENCE OF (%d)", td->name, list->count); + + if(constraints) ct = &constraints->size; + else if(td->per_constraints) ct = &td->per_constraints->size; + else ct = 0; + + /* If extensible constraint, check if size is in root */ + if(ct) { + int not_in_root = (list->count < ct->lower_bound + || list->count > ct->upper_bound); + ASN_DEBUG("lb %ld ub %ld %s", + ct->lower_bound, ct->upper_bound, + ct->flags & APC_EXTENSIBLE ? "ext" : "fix"); + if(ct->flags & APC_EXTENSIBLE) { + /* Declare whether size is in extension root */ + if(per_put_few_bits(po, not_in_root, 1)) + _ASN_ENCODE_FAILED; + if(not_in_root) ct = 0; + } else if(not_in_root && ct->effective_bits >= 0) + _ASN_ENCODE_FAILED; + } + + if(ct && ct->effective_bits >= 0) { + /* X.691, #19.5: No length determinant */ + if(per_put_few_bits(po, list->count - ct->lower_bound, + ct->effective_bits)) + _ASN_ENCODE_FAILED; + } + + for(seq = -1; seq < list->count;) { + ssize_t mayEncode; + if(seq < 0) seq = 0; + if(ct && ct->effective_bits >= 0) { + mayEncode = list->count; + } else { + mayEncode = uper_put_length(po, list->count - seq); + if(mayEncode < 0) _ASN_ENCODE_FAILED; + } + + while(mayEncode--) { + void *memb_ptr = list->array[seq++]; + if(!memb_ptr) _ASN_ENCODE_FAILED; + er = elm->type->uper_encoder(elm->type, + elm->per_constraints, memb_ptr, po); + if(er.encoded == -1) + _ASN_ENCODE_FAILED; + } + } + + _ASN_ENCODED_OK(er); +} + diff --git a/skeletons/constr_SEQUENCE_OF.h b/skeletons/constr_SEQUENCE_OF.h index 32078cb3..e2272f32 100644 --- a/skeletons/constr_SEQUENCE_OF.h +++ b/skeletons/constr_SEQUENCE_OF.h @@ -24,6 +24,7 @@ extern "C" { #define SEQUENCE_OF_decode_uper SET_OF_decode_uper der_type_encoder_f SEQUENCE_OF_encode_der; xer_type_encoder_f SEQUENCE_OF_encode_xer; +per_type_encoder_f SEQUENCE_OF_encode_uper; #ifdef __cplusplus } diff --git a/skeletons/constr_SET_OF.h b/skeletons/constr_SET_OF.h index 14209316..bcd09662 100644 --- a/skeletons/constr_SET_OF.h +++ b/skeletons/constr_SET_OF.h @@ -33,6 +33,7 @@ der_type_encoder_f SET_OF_encode_der; xer_type_decoder_f SET_OF_decode_xer; xer_type_encoder_f SET_OF_encode_xer; per_type_decoder_f SET_OF_decode_uper; +per_type_encoder_f SET_OF_encode_uper; #ifdef __cplusplus } diff --git a/skeletons/constr_TYPE.h b/skeletons/constr_TYPE.h index 70e78828..95507c80 100644 --- a/skeletons/constr_TYPE.h +++ b/skeletons/constr_TYPE.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003, 2004, 2005 Lev Walkin <vlm@lionet.info>. + * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin <vlm@lionet.info>. * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ @@ -40,6 +40,7 @@ typedef struct asn_struct_ctx_s { #include <xer_decoder.h> /* Decoder of XER (XML, text) */ #include <xer_encoder.h> /* Encoder into XER (XML, text) */ #include <per_decoder.h> /* Packet Encoding Rules decoder */ +#include <per_encoder.h> /* Packet Encoding Rules encoder */ #include <constraints.h> /* Subtype constraints support */ /* @@ -97,6 +98,7 @@ typedef struct asn_TYPE_descriptor_s { xer_type_decoder_f *xer_decoder; /* Generic XER decoder */ xer_type_encoder_f *xer_encoder; /* [Canonical] XER encoder */ per_type_decoder_f *uper_decoder; /* Unaligned PER decoder */ + per_type_encoder_f *uper_encoder; /* Unaligned PER encoder */ /*********************************************************************** * Internally useful members. Not to be used by applications directly. * @@ -144,7 +146,7 @@ typedef struct asn_TYPE_member_s { asn_TYPE_descriptor_t *type; /* Member type descriptor */ asn_constr_check_f *memb_constraints; /* Constraints validator */ asn_per_constraints_t *per_constraints; /* PER compiled constraints */ - int (*default_value)(void **sptr); /* DEFAULT <value> */ + int (*default_value)(int setval, void **sptr); /* DEFAULT <value> */ char *name; /* ASN.1 identifier of the element */ } asn_TYPE_member_t; diff --git a/skeletons/der_encoder.c b/skeletons/der_encoder.c index 68dd24e6..6c859e1b 100644 --- a/skeletons/der_encoder.c +++ b/skeletons/der_encoder.c @@ -52,20 +52,19 @@ static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) { */ asn_enc_rval_t der_encode_to_buffer(asn_TYPE_descriptor_t *type_descriptor, void *struct_ptr, - void *buffer, size_t *buffer_size) { + void *buffer, size_t buffer_size) { enc_to_buf_arg arg; asn_enc_rval_t ec; arg.buffer = buffer; - arg.left = *buffer_size; + arg.left = buffer_size; ec = type_descriptor->der_encoder(type_descriptor, struct_ptr, /* Pointer to the destination structure */ 0, 0, encode_to_buffer_cb, &arg); if(ec.encoded != -1) { - assert(ec.encoded == (ssize_t)(*buffer_size - arg.left)); + assert(ec.encoded == (ssize_t)(buffer_size - arg.left)); /* Return the encoded contents size */ - *buffer_size = ec.encoded; } return ec; } diff --git a/skeletons/der_encoder.h b/skeletons/der_encoder.h index 9e7867da..4e2fb06c 100644 --- a/skeletons/der_encoder.h +++ b/skeletons/der_encoder.h @@ -27,7 +27,7 @@ asn_enc_rval_t der_encode_to_buffer( struct asn_TYPE_descriptor_s *type_descriptor, void *struct_ptr, /* Structure to be encoded */ void *buffer, /* Pre-allocated buffer */ - size_t *buffer_size /* Initial buffer size (max) */ + size_t buffer_size /* Initial buffer size (maximum) */ ); /* diff --git a/skeletons/file-dependencies b/skeletons/file-dependencies index ca43363c..972eea47 100644 --- a/skeletons/file-dependencies +++ b/skeletons/file-dependencies @@ -60,6 +60,7 @@ xer_decoder.h xer_decoder.c # XER decoding support xer_encoder.h xer_encoder.c # XER encoding support per_support.h per_support.c # PER parsing per_decoder.h per_decoder.c # PER decoding support +per_encoder.h per_encoder.c # PER encoding support #asn-decoder-template.c # Template for quick decoder creation CODEC-PER: # THIS IS A SPECIAL SECTION diff --git a/skeletons/per_encoder.c b/skeletons/per_encoder.c new file mode 100644 index 00000000..6ba28e53 --- /dev/null +++ b/skeletons/per_encoder.c @@ -0,0 +1,89 @@ +#include <asn_application.h> +#include <asn_internal.h> +#include <per_encoder.h> + +/* Flush partially filled buffer */ +static int _uper_encode_flush_outp(asn_per_outp_t *po); + +asn_enc_rval_t +uper_encode(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { + asn_per_outp_t po; + asn_enc_rval_t er; + + /* + * Invoke type-specific encoder. + */ + if(!td || !td->uper_encoder) + _ASN_ENCODE_FAILED; /* PER is not compiled in */ + + po.buffer = po.tmpspace; + po.nboff = 0; + po.nbits = 8 * sizeof(po.tmpspace); + po.outper = cb; + po.op_key = app_key; + + er = td->uper_encoder(td, 0, sptr, &po); + if(er.encoded != -1 && _uper_encode_flush_outp(&po)) + _ASN_ENCODE_FAILED; + + return er; +} + +/* + * Argument type and callback necessary for uper_encode_to_buffer(). + */ +typedef struct enc_to_buf_arg { + void *buffer; + size_t left; +} enc_to_buf_arg; +static int encode_to_buffer_cb(const void *buffer, size_t size, void *key) { + enc_to_buf_arg *arg = (enc_to_buf_arg *)key; + + if(arg->left < size) + return -1; /* Data exceeds the available buffer size */ + + memcpy(arg->buffer, buffer, size); + arg->buffer = ((char *)arg->buffer) + size; + arg->left -= size; + + return 0; +} + +asn_enc_rval_t +uper_encode_to_buffer(asn_TYPE_descriptor_t *td, void *sptr, void *buffer, size_t buffer_size) { + enc_to_buf_arg key; + asn_enc_rval_t er; + + /* + * Invoke type-specific encoder. + */ + if(!td || !td->uper_encoder) + _ASN_ENCODE_FAILED; /* PER is not compiled in */ + + key.buffer = buffer; + key.left = buffer_size; + + ASN_DEBUG("Encoding \"%s\" using UNALIGNED PER", td->name); + + er = uper_encode(td, sptr, encode_to_buffer_cb, &key); + if(er.encoded != -1) + er.encoded = buffer_size - key.left; + return er; +} + +static int +_uper_encode_flush_outp(asn_per_outp_t *po) { + uint8_t *buf; + + if(po->nboff == 0 && po->buffer == po->tmpspace) + return 0; + + buf = po->buffer + (po->nboff >> 3); + /* Make sure we account for the last, partially filled */ + if(po->nboff & 0x07) { + buf[0] &= 0xff << (8 - (po->nboff & 0x07)); + buf++; + } + + return po->outper(po->tmpspace, buf - po->tmpspace, po->op_key); +} diff --git a/skeletons/per_encoder.h b/skeletons/per_encoder.h new file mode 100644 index 00000000..9ac130b7 --- /dev/null +++ b/skeletons/per_encoder.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2006 Lev Walkin <vlm@lionet.info>. All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _PER_ENCODER_H_ +#define _PER_ENCODER_H_ + +#include <asn_application.h> +#include <per_support.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +/* + * Unaligned PER encoder of any ASN.1 type. May be invoked by the application. + */ +asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + asn_app_consume_bytes_f *consume_bytes_cb, /* Data collector */ + void *app_key /* Arbitrary callback argument */ +); + +/* A variant of uper_encode() which encodes data into the existing buffer */ +asn_enc_rval_t uper_encode_to_buffer( + struct asn_TYPE_descriptor_s *type_descriptor, + void *struct_ptr, /* Structure to be encoded */ + void *buffer, /* Pre-allocated buffer */ + size_t buffer_size /* Initial buffer size (max) */ +); + + +/* + * Type of the generic PER encoder function. + */ +typedef asn_enc_rval_t (per_type_encoder_f)( + struct asn_TYPE_descriptor_s *type_descriptor, + asn_per_constraints_t *constraints, + void *struct_ptr, + asn_per_outp_t *per_output +); + +#ifdef __cplusplus +} +#endif + +#endif /* _PER_ENCODER_H_ */ diff --git a/skeletons/per_support.c b/skeletons/per_support.c index 63b39d08..0eb381c8 100644 --- a/skeletons/per_support.c +++ b/skeletons/per_support.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005 Lev Walkin <vlm@lionet.info>. All rights reserved. + * Copyright (c) 2005, 2006 Lev Walkin <vlm@lionet.info>. All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include <asn_system.h> @@ -80,7 +80,7 @@ per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int alright, int nbits) { } else { value = per_get_few_bits(pd, nbits); if(value < 0) return -1; - if(nbits & 7) { /* implies alright */ + if(nbits & 7) { /* implies left alignment */ value <<= 8 - (nbits & 7), nbits += 8 - (nbits & 7); if(nbits > 24) @@ -150,3 +150,161 @@ uper_get_nsnnwn(asn_per_data_t *pd) { return value; } + +/* + * Put the normally small non-negative whole number. + * X.691, #10.6 + */ +int +uper_put_nsnnwn(asn_per_outp_t *po, int n) { + int bytes; + + if(n <= 63) { + if(n < 0) return -1; + return per_put_few_bits(po, n, 7); + } + if(n < 256) + bytes = 1; + else if(n < 65536) + bytes = 2; + else if(n < 256 * 65536) + bytes = 3; + else + return -1; /* This is not a "normally small" value */ + if(per_put_few_bits(po, bytes, 8)) + return -1; + + return per_put_few_bits(po, n, 8 * bytes); +} + + +/* + * Put a small number of bits (<= 31). + */ +int +per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) { + size_t off; /* Next after last bit offset */ + size_t omsk; /* Existing last byte meaningful bits mask */ + uint8_t *buf; + + if(obits <= 0 || obits >= 32) return obits ? -1 : 0; + + /* + * Normalize position indicator. + */ + if(po->nboff >= 8) { + po->buffer += (po->nboff >> 3); + po->nbits -= (po->nboff & ~0x07); + po->nboff &= 0x07; + } + + /* + * Flush whole-bytes output, if necessary. + */ + if(po->nboff + obits > po->nbits) { + int complete_bytes = (po->buffer - po->tmpspace); + if(po->outper(po->buffer, complete_bytes, po->op_key) < 0) + return -1; + if(po->nboff) + po->tmpspace[0] = po->buffer[0]; + po->buffer = po->tmpspace; + po->nbits = 8 * sizeof(po->tmpspace); + } + + /* + * Now, due to sizeof(tmpspace), we are guaranteed large enough space. + */ + buf = po->buffer; + omsk = ~((1 << (8 - po->nboff)) - 1); + off = (po->nboff += obits); + + /* Clear data of debris before meaningful bits */ + bits &= (((uint32_t)1 << obits) - 1); + + ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits, bits, bits, + po->nboff - obits, off, buf[0], omsk&0xff, buf[0] & omsk); + + if(off <= 8) /* Completely within 1 byte */ + bits <<= (8 - off), + buf[0] = (buf[0] & omsk) | bits; + else if(off <= 16) + bits <<= (16 - off), + buf[0] = (buf[0] & omsk) | (bits >> 8), + buf[1] = bits; + else if(off <= 24) + bits <<= (24 - off), + buf[0] = (buf[0] & omsk) | (bits >> 16), + buf[1] = bits >> 8, + buf[2] = bits; + else if(off <= 31) + bits <<= (32 - off), + buf[0] = (buf[0] & omsk) | (bits >> 24), + buf[1] = bits >> 16, + buf[2] = bits >> 8, + buf[3] = bits; + else { + ASN_DEBUG("->[PER out split %d]", obits); + per_put_few_bits(po, bits >> 8, 24); + per_put_few_bits(po, bits, obits - 24); + ASN_DEBUG("<-[PER out split %d]", obits); + } + + ASN_DEBUG("[PER out %u/%x => %02x buf+%d]", + bits, bits, buf[0], po->buffer - po->tmpspace); + + return 0; +} + + +/* + * Output a large number of bits. + */ +int +per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int nbits) { + + while(nbits) { + uint32_t value; + + if(nbits >= 24) { + value = (src[0] << 16) | (src[1] << 8) | src[2]; + src += 3; + nbits -= 24; + if(per_put_few_bits(po, value, 24)) + return -1; + } else { + value = src[0]; + if(nbits > 8) + value = (value << 8) | src[1]; + if(nbits > 16) + value = (value << 8) | src[2]; + if(nbits & 0x07) + value >>= (8 - (nbits & 0x07)); + if(per_put_few_bits(po, value, nbits)) + return -1; + break; + } + } + + return 0; +} + +/* + * Put the length "n" (or part of it) into the stream. + */ +ssize_t +uper_put_length(asn_per_outp_t *po, size_t length) { + + if(length <= 127) /* #10.9.3.6 */ + return per_put_few_bits(po, length, 8) + ? -1 : (ssize_t)length; + else if(length < 16384) /* #10.9.3.7 */ + return per_put_few_bits(po, length|0x8000, 16) + ? -1 : (ssize_t)length; + + length >>= 14; + if(length > 4) length = 4; + + return per_put_few_bits(po, 0xC0 | length, 8) + ? -1 : (ssize_t)(length << 14); +} + diff --git a/skeletons/per_support.h b/skeletons/per_support.h index 44f0bb40..747abe27 100644 --- a/skeletons/per_support.h +++ b/skeletons/per_support.h @@ -12,7 +12,7 @@ extern "C" { #endif /* - * This structure describes a position inside a PER bit stream. + * This structure describes a position inside an incoming PER bit stream. */ typedef struct asn_per_data_s { const uint8_t *buffer; /* Pointer to the octet stream */ @@ -20,6 +20,18 @@ typedef struct asn_per_data_s { size_t nbits; /* Number of bits in the stream */ } asn_per_data_t; +/* + * This structure supports forming PER output. + */ +typedef struct asn_per_outp_s { + uint8_t *buffer; /* Pointer into the (tmpspace) */ + size_t nboff; /* Bit offset to the meaningful bit */ + size_t nbits; /* Number of bits left in (tmpspace) */ + uint8_t tmpspace[32]; /* Preliminary storage to hold data */ + int (*outper)(const void *data, size_t size, void *op_key); + void *op_key; +} asn_per_outp_t; + /* * Extract a small number of bits (<= 31) from the specified PER data pointer. * This function returns -1 if the specified number of bits could not be @@ -27,6 +39,9 @@ typedef struct asn_per_data_s { */ int32_t per_get_few_bits(asn_per_data_t *per_data, int get_nbits); +/* Output a small number of bits (<= 31) */ +int per_put_few_bits(asn_per_outp_t *per_data, uint32_t bits, int obits); + /* * Extract a large number of bits from the specified PER data pointer. * This function returns -1 if the specified number of bits could not be @@ -35,6 +50,9 @@ int32_t per_get_few_bits(asn_per_data_t *per_data, int get_nbits); int per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int right_align, int get_nbits); +/* Output a large number of bits */ +int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits); + /* * Get the length "n" from the Unaligned PER stream. */ @@ -42,11 +60,23 @@ ssize_t uper_get_length(asn_per_data_t *pd, int effective_bound_bits, int *repeat); +/* + * Put the length "n" to the Unaligned PER stream. + * This function returns the number of units which may be flushed + * in the next units saving iteration. + */ +ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length); + /* * Get the normally small non-negative whole number. */ ssize_t uper_get_nsnnwn(asn_per_data_t *pd); +/* + * Put the normally small non-negative whole number. + */ +int uper_put_nsnnwn(asn_per_outp_t *po, int n); + #ifdef __cplusplus } #endif diff --git a/skeletons/tests/check-PER.c b/skeletons/tests/check-PER.c index 5fcb1aee..6d355e83 100644 --- a/skeletons/tests/check-PER.c +++ b/skeletons/tests/check-PER.c @@ -1,8 +1,8 @@ #include <per_support.c> #include <assert.h> -int -main() { +static void +check_per_decoding() { uint8_t buf[] = { 0xB7, 0x19, 0x2F, 0xEE, 0xAD }; uint8_t tmpbuf[10]; int32_t z; @@ -119,6 +119,102 @@ main() { assert(tmpbuf[2] == buf[2]); assert(tmpbuf[3] == buf[3]); assert(tmpbuf[4] == buf[4]); +} + +static int Ignore(const void *data, size_t size, void *op_key) { + return 0; +} +static void +check_per_encoding() { + asn_per_outp_t po; + po.buffer = po.tmpspace; + po.nboff = 0; + po.nbits = 0; + po.outper = Ignore; + po.op_key = 0; + po.tmpspace[0] = 0xff; + int ret; + + ret = per_put_few_bits(&po, 0, 0); + assert(ret == 0); + assert(po.nboff == 0); + assert(po.buffer == po.tmpspace); + assert(po.tmpspace[0] == 0xff); + + ret = per_put_few_bits(&po, 0, 1); + assert(ret == 0); + assert(po.nboff == 1); + assert(po.nbits == 8 * sizeof(po.tmpspace)); + assert(po.buffer == po.tmpspace); + assert(po.tmpspace[0] == 0x00); + + ret = per_put_few_bits(&po, 1, 1); + assert(ret == 0); + assert(po.nboff == 2); + assert(po.nbits == 8 * sizeof(po.tmpspace)); + assert(po.buffer == po.tmpspace); + assert(po.tmpspace[0] == 0x40); + + ret = per_put_few_bits(&po, 1, 1); + assert(ret == 0); + assert(po.nboff == 3); + assert(po.nbits == 8 * sizeof(po.tmpspace)); + assert(po.buffer == po.tmpspace); + assert(po.tmpspace[0] == 0x60); + + ret = per_put_few_bits(&po, 15, 5); + assert(ret == 0); + assert(po.nboff == 8); + assert(po.nbits == 8 * sizeof(po.tmpspace)); + assert(po.buffer == po.tmpspace); + assert(po.tmpspace[0] == 0x6F); + + ret = per_put_few_bits(&po, 0xf0ff, 16); + assert(ret == 0); + assert(po.nboff == 16); + assert(po.nbits == 8 * sizeof(po.tmpspace) - 8); + assert(po.buffer == po.tmpspace + 1); + assert(po.tmpspace[0] == 0x6F); + assert(po.tmpspace[1] == 0xf0); + assert(po.tmpspace[2] == 0xff); + + po.nboff--; + + ret = per_put_few_bits(&po, 2, 1); + assert(ret == 0); + assert(po.nboff == 8); + assert(po.nbits == 8 * sizeof(po.tmpspace) - 16); + assert(po.buffer == po.tmpspace + 2); + assert(po.tmpspace[0] == 0x6F); + assert(po.tmpspace[1] == 0xf0); + assert(po.tmpspace[2] == 0xfe); + + ret = per_put_few_bits(&po, 2, 32); + assert(ret == -1); + + ret = per_put_few_bits(&po, 2, -1); + assert(ret == -1); + + ret = per_put_few_bits(&po, -1, 31); + assert(ret == 0); + assert(po.nboff == 31); + assert(po.nbits == 8 * sizeof(po.tmpspace) - 24); + assert(po.buffer == po.tmpspace + 3); + assert(po.tmpspace[0] == 0x6F); + assert(po.tmpspace[1] == 0xf0); + assert(po.tmpspace[2] == 0xfe); + assert(po.tmpspace[3] == 0xff); + assert(po.tmpspace[4] == 0xff); + assert(po.tmpspace[5] == 0xff); + assert(po.tmpspace[6] == 0xfe); + + +} + +int +main() { + check_per_decoding(); + check_per_encoding(); return 0; } -- GitLab