From 498c97170c4d20f25734cb91e1d646d86461a3cb Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 30 Aug 2015 16:33:07 +0200 Subject: port/merge Eurecom APER support from OPENAIRMME Eurecom has developed APER support for asn1c as part of the OPENAIRMME softare (a LTE MME). This is too important to let it bit-rout out of asn1c. Let's forward-port and merge it. --- asn1c/unber.c | 4 + libasn1compiler/asn1c_C.c | 46 ++++- libasn1compiler/asn1c_misc.c | 2 +- libasn1compiler/asn1c_out.h | 20 +- skeletons/ANY.c | 87 +++++++- skeletons/ANY.h | 3 + skeletons/BIT_STRING.c | 2 + skeletons/BMPString.c | 2 + skeletons/BOOLEAN.c | 46 +++++ skeletons/BOOLEAN.h | 2 + skeletons/ENUMERATED.c | 34 ++++ skeletons/ENUMERATED.h | 2 + skeletons/GeneralString.c | 2 + skeletons/GeneralizedTime.c | 2 + skeletons/GraphicString.c | 2 + skeletons/IA5String.c | 2 + skeletons/INTEGER.c | 450 ++++++++++++++++++++++++++++++++++++++++- skeletons/INTEGER.h | 8 +- skeletons/ISO646String.c | 2 + skeletons/NULL.c | 44 ++++ skeletons/NULL.h | 2 + skeletons/NativeEnumerated.c | 126 ++++++++++++ skeletons/NativeEnumerated.h | 2 + skeletons/NativeInteger.c | 64 ++++++ skeletons/NativeInteger.h | 2 + skeletons/NativeReal.c | 65 ++++++ skeletons/NativeReal.h | 2 + skeletons/NumericString.c | 2 + skeletons/OBJECT_IDENTIFIER.c | 2 + skeletons/OCTET_STRING.c | 387 +++++++++++++++++++++++++++++++++-- skeletons/OCTET_STRING.h | 2 + skeletons/ObjectDescriptor.c | 2 + skeletons/PrintableString.c | 2 + skeletons/REAL.c | 17 ++ skeletons/REAL.h | 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/asn_internal.h | 10 +- skeletons/constr_CHOICE.c | 167 ++++++++++++++- skeletons/constr_CHOICE.h | 2 + skeletons/constr_SEQUENCE.c | 342 ++++++++++++++++++++++++++++++- skeletons/constr_SEQUENCE.h | 2 + skeletons/constr_SEQUENCE_OF.c | 69 ++++++- skeletons/constr_SEQUENCE_OF.h | 2 + skeletons/constr_SET.c | 175 ++++++++++++++++ skeletons/constr_SET.h | 2 + skeletons/constr_SET_OF.c | 92 ++++++++- skeletons/constr_SET_OF.h | 2 + skeletons/constr_TYPE.h | 2 + skeletons/per_decoder.c | 83 ++++++++ skeletons/per_decoder.h | 22 ++ skeletons/per_encoder.c | 93 +++++++++ skeletons/per_encoder.h | 11 + skeletons/per_opentype.c | 29 +++ skeletons/per_opentype.h | 2 + skeletons/per_support.c | 198 +++++++++++++++++- skeletons/per_support.h | 27 ++- 63 files changed, 2741 insertions(+), 48 deletions(-) diff --git a/asn1c/unber.c b/asn1c/unber.c index 088491f7..f5fc0226 100644 --- a/asn1c/unber.c +++ b/asn1c/unber.c @@ -775,4 +775,8 @@ asn_dec_rval_t OCTET_STRING_decode_uper(asn_codec_ctx_t *ctx, asn_TYPE_descripto asn_enc_rval_t OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *cts, void *sptr, asn_per_outp_t *po) { asn_enc_rval_t er = { 0, 0, 0 }; (void)td; (void)cts; (void)sptr; (void)po; return er; } +asn_dec_rval_t OCTET_STRING_decode_aper(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *cts, void **sptr, asn_per_data_t *pd) { asn_dec_rval_t rv = { 0, 0 }; (void)ctx; (void)td; (void)cts; (void)sptr; (void)pd; return rv; } + +asn_enc_rval_t OCTET_STRING_encode_aper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *cts, void *sptr, asn_per_outp_t *po) { asn_enc_rval_t er = { 0, 0, 0 }; (void)td; (void)cts; (void)sptr; (void)po; return er; } + size_t xer_whitespace_span(const void *chunk_buf, size_t chunk_size) { (void)chunk_buf; (void)chunk_size; return 0; } diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c index d49fd3fe..96e3ef69 100644 --- a/libasn1compiler/asn1c_C.c +++ b/libasn1compiler/asn1c_C.c @@ -1243,6 +1243,8 @@ asn1c_lang_C_type_SIMPLE_TYPE(arg_t *arg) { OUT("td->xer_encoder = asn_DEF_%s.xer_encoder;\n", type_name); OUT("td->uper_decoder = asn_DEF_%s.uper_decoder;\n", type_name); OUT("td->uper_encoder = asn_DEF_%s.uper_encoder;\n", type_name); + OUT("td->aper_decoder = asn_DEF_%s.aper_decoder;\n", type_name); + OUT("td->aper_encoder = asn_DEF_%s.aper_encoder;\n", type_name); if(!terminal && !tags_count) { OUT("/* The next four lines are here because of -fknown-extern-type */\n"); OUT("td->tags = asn_DEF_%s.tags;\n", type_name); @@ -1395,7 +1397,39 @@ asn1c_lang_C_type_SIMPLE_TYPE(arg_t *arg) { ); OUT("}\n"); OUT("\n"); - } + + p = MKID(expr); + if(HIDE_INNER_DEFS) OUT("static "); + OUT("asn_enc_rval_t\n"); + OUT("%s", p); + if(HIDE_INNER_DEFS) OUT("_%d", expr->_type_unique_index); + OUT("_encode_aper(asn_TYPE_descriptor_t *td,\n"); + INDENTED( + OUT("\tasn_per_constraints_t *constraints,\n"); + OUT("\tvoid *structure, asn_per_outp_t *per_out) {\n"); + OUT("%s_%d_inherit_TYPE_descriptor(td);\n", + p, expr->_type_unique_index); + OUT("return td->aper_encoder(td, constraints, structure, per_out);\n"); + ); + OUT("}\n"); + OUT("\n"); + + p = MKID(expr); + + if(HIDE_INNER_DEFS) OUT("static "); + OUT("asn_dec_rval_t\n"); + OUT("%s", p); + if(HIDE_INNER_DEFS) OUT("_%d", expr->_type_unique_index); + OUT("_decode_aper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td,\n"); + INDENTED( + OUT("\tasn_per_constraints_t *constraints, void **structure, asn_per_data_t *per_data) {\n"); + OUT("%s_%d_inherit_TYPE_descriptor(td);\n", + p, expr->_type_unique_index); + OUT("return td->aper_decoder(opt_codec_ctx, td, constraints, structure, per_data);\n"); + ); + OUT("}\n"); + OUT("\n"); + } REDIR(OT_FUNC_DECLS); @@ -1416,6 +1450,8 @@ asn1c_lang_C_type_SIMPLE_TYPE(arg_t *arg) { if(arg->flags & A1C_GEN_PER) { OUT("per_type_decoder_f %s_decode_uper;\n", p); OUT("per_type_encoder_f %s_encode_uper;\n", p); + OUT("per_type_decoder_f %s_decode_aper;\n", p); + OUT("per_type_encoder_f %s_encode_aper;\n", p); } } @@ -2003,7 +2039,7 @@ emit_member_PER_constraints(arg_t *arg, asn1p_expr_t *expr, const char *pfx) { break; case ASN_STRING_UniversalString: OUT("{ APC_CONSTRAINED,\t32, 32," - " 0, 2147483647 }" + " 0, 2147483647L }" " /* special case 1 */\n"); goto avoid; default: @@ -2456,8 +2492,12 @@ emit_type_DEF(arg_t *arg, asn1p_expr_t *expr, enum tvm_compat tv_mode, int tags_ if(arg->flags & A1C_GEN_PER) { FUNCREF(decode_uper); FUNCREF(encode_uper); + FUNCREF(decode_aper); + FUNCREF(encode_aper); } else { - OUT("0, 0,\t/* No PER support, " + OUT("0, 0,\t/* No UPER support, " + "use \"-gen-PER\" to enable */\n"); + OUT("0, 0,\t/* No APER support, " "use \"-gen-PER\" to enable */\n"); } diff --git a/libasn1compiler/asn1c_misc.c b/libasn1compiler/asn1c_misc.c index fae9b52f..a083399d 100644 --- a/libasn1compiler/asn1c_misc.c +++ b/libasn1compiler/asn1c_misc.c @@ -383,7 +383,7 @@ asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) { if(left.type == ARE_VALUE && left.value >= 0 && right.type == ARE_VALUE - && right.value > 2147483647 + && right.value > 2147483647L && right.value <= 4294967295UL) return FL_FITS_UNSIGN; diff --git a/libasn1compiler/asn1c_out.h b/libasn1compiler/asn1c_out.h index d68f3a85..80026cec 100644 --- a/libasn1compiler/asn1c_out.h +++ b/libasn1compiler/asn1c_out.h @@ -117,17 +117,25 @@ int asn1c_compiled_output(arg_t *arg, const char *fmt, ...); * Format LONG_MIN according to C90 rules. */ #define OINT(iv) do { \ - if(iv == (-2147483647L - 1)) \ + if(iv == (-2147483647L - 1)) \ OUT("(-2147483647L - 1)"); \ - else \ - OUT("%" PRIdASN, iv); \ + else if (iv > 4294967296UL) \ + OUT("%" PRIdASN "ull", iv); \ + else if (iv > 2147483647L) \ + OUT("%" PRIdASN "ul", iv); \ + else \ + OUT("%" PRIdASN "l", iv); \ } while(0) #define OINTS(iv) do { \ - if(iv == (-2147483647L - 1)) \ + if(iv == (-2147483647L - 1)) \ OUT("(-2147483647L - 1)"); \ - else \ - OUT("% " PRIdASN, iv); \ + else if (iv > 4294967296UL) \ + OUT("%" PRIdASN "ull", iv); \ + else if (iv > 2147483647L) \ + OUT("%" PRIdASN "ul", iv); \ + else \ + OUT("% " PRIdASN "l", iv); \ } while(0) #endif /* _ASN1_COMPILED_OUTPUT_H_ */ diff --git a/skeletons/ANY.c b/skeletons/ANY.c index 0ad60d0a..0fe63ae9 100644 --- a/skeletons/ANY.c +++ b/skeletons/ANY.c @@ -21,7 +21,10 @@ asn_TYPE_descriptor_t asn_DEF_ANY = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_hex, ANY_encode_xer, - 0, 0, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 0, /* Use generic outmost tag fetcher */ 0, 0, 0, 0, 0, /* No PER visible constraints */ @@ -87,6 +90,37 @@ ANY_fromType(ANY_t *st, asn_TYPE_descriptor_t *td, void *sptr) { return 0; } +int +ANY_fromType_aper(ANY_t *st, asn_TYPE_descriptor_t *td, void *sptr) { + uint8_t *buffer = NULL; + ssize_t erval; + + if(!st || !td) { + errno = EINVAL; + return -1; + } + + if(!sptr) { + if(st->buf) FREEMEM(st->buf); + st->size = 0; + return 0; + } + + erval = aper_encode_to_new_buffer(td, td->per_constraints, sptr, (void**)&buffer); + + if(erval == -1) { + if(buffer) FREEMEM(buffer); + return -1; + } + assert((size_t)erval > 0); + + if(st->buf) FREEMEM(st->buf); + st->buf = buffer; + st->size = erval; + + return 0; +} + ANY_t * ANY_new_fromType(asn_TYPE_descriptor_t *td, void *sptr) { ANY_t tmp; @@ -111,6 +145,30 @@ ANY_new_fromType(asn_TYPE_descriptor_t *td, void *sptr) { } } +ANY_t * +ANY_new_fromType_aper(asn_TYPE_descriptor_t *td, void *sptr) { + ANY_t tmp; + ANY_t *st; + + if(!td || !sptr) { + errno = EINVAL; + return 0; + } + + memset(&tmp, 0, sizeof(tmp)); + + if(ANY_fromType_aper(&tmp, td, sptr)) return 0; + + st = (ANY_t *)CALLOC(1, sizeof(ANY_t)); + if(st) { + *st = tmp; + return st; + } else { + FREEMEM(tmp.buf); + return 0; + } +} + int ANY_to_type(ANY_t *st, asn_TYPE_descriptor_t *td, void **struct_ptr) { asn_dec_rval_t rval; @@ -138,6 +196,33 @@ ANY_to_type(ANY_t *st, asn_TYPE_descriptor_t *td, void **struct_ptr) { } } +int +ANY_to_type_aper(ANY_t *st, asn_TYPE_descriptor_t *td, void **struct_ptr) { + asn_dec_rval_t rval; + void *newst = 0; + + if(!st || !td || !struct_ptr) { + errno = EINVAL; + return -1; + } + + if(st->buf == 0) { + /* Nothing to convert, make it empty. */ + *struct_ptr = (void *)0; + return 0; + } + + rval = aper_decode(0, td, (void **)&newst, st->buf, st->size, 0, 0); + if(rval.code == RC_OK) { + *struct_ptr = newst; + return 0; + } else { + /* Remove possibly partially decoded data. */ + ASN_STRUCT_FREE(*td, newst); + return -1; + } +} + static int ANY__consume_bytes(const void *buffer, size_t size, void *key) { struct _callback_arg *arg = (struct _callback_arg *)key; diff --git a/skeletons/ANY.h b/skeletons/ANY.h index b7d92fa9..a68441df 100644 --- a/skeletons/ANY.h +++ b/skeletons/ANY.h @@ -32,10 +32,13 @@ xer_type_encoder_f ANY_encode_xer; /* Convert another ASN.1 type into the ANY. This implies DER encoding. */ int ANY_fromType(ANY_t *, asn_TYPE_descriptor_t *td, void *struct_ptr); +int ANY_fromType_aper(ANY_t *st, asn_TYPE_descriptor_t *td, void *sptr); ANY_t *ANY_new_fromType(asn_TYPE_descriptor_t *td, void *struct_ptr); +ANY_t *ANY_new_fromType_aper(asn_TYPE_descriptor_t *td, void *sptr); /* Convert the contents of the ANY type into the specified type. */ int ANY_to_type(ANY_t *, asn_TYPE_descriptor_t *td, void **struct_ptr); +int ANY_to_type_aper(ANY_t *, asn_TYPE_descriptor_t *td, void **struct_ptr); #define ANY_fromBuf(s, buf, size) OCTET_STRING_fromBuf((s), (buf), (size)) #define ANY_new_fromBuf(buf, size) OCTET_STRING_new_fromBuf( \ diff --git a/skeletons/BIT_STRING.c b/skeletons/BIT_STRING.c index 9e0e50c6..ad2ca604 100644 --- a/skeletons/BIT_STRING.c +++ b/skeletons/BIT_STRING.c @@ -29,6 +29,8 @@ asn_TYPE_descriptor_t asn_DEF_BIT_STRING = { BIT_STRING_encode_xer, OCTET_STRING_decode_uper, /* Unaligned PER decoder */ OCTET_STRING_encode_uper, /* Unaligned PER encoder */ + OCTET_STRING_decode_aper, /* Aligned PER decoder */ + OCTET_STRING_encode_aper, /* Aligned 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 458622cd..94471f68 100644 --- a/skeletons/BMPString.c +++ b/skeletons/BMPString.c @@ -35,6 +35,8 @@ asn_TYPE_descriptor_t asn_DEF_BMPString = { BMPString_encode_xer, /* Convert to UTF-8 */ OCTET_STRING_decode_uper, OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, /* Aligned PER decoder */ + OCTET_STRING_encode_aper, /* Aligned PER encoder */ 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 2ba07840..42374b81 100644 --- a/skeletons/BOOLEAN.c +++ b/skeletons/BOOLEAN.c @@ -24,6 +24,8 @@ asn_TYPE_descriptor_t asn_DEF_BOOLEAN = { BOOLEAN_encode_xer, BOOLEAN_decode_uper, /* Unaligned PER decoder */ BOOLEAN_encode_uper, /* Unaligned PER encoder */ + BOOLEAN_decode_aper, /* Aligned PER decoder */ + BOOLEAN_encode_aper, /* Aligned PER encoder */ 0, /* Use generic outmost tag fetcher */ asn_DEF_BOOLEAN_tags, sizeof(asn_DEF_BOOLEAN_tags) / sizeof(asn_DEF_BOOLEAN_tags[0]), @@ -264,6 +266,35 @@ BOOLEAN_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, return rv; } +asn_dec_rval_t +BOOLEAN_decode_aper(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_dec_rval_t rv; + BOOLEAN_t *st = (BOOLEAN_t *)*sptr; + + (void)opt_codec_ctx; + (void)constraints; + + if(!st) { + st = (BOOLEAN_t *)(*sptr = MALLOC(sizeof(*st))); + if(!st) _ASN_DECODE_FAILED; + } + + /* + * Extract a single bit + */ + switch(per_get_few_bits(pd, 1)) { + case 1: *st = 1; break; + case 0: *st = 0; break; + case -1: default: _ASN_DECODE_STARVED; + } + + ASN_DEBUG("%s decoded as %s", td->name, *st ? "TRUE" : "FALSE"); + + rv.code = RC_OK; + rv.consumed = 1; + return rv; +} asn_enc_rval_t BOOLEAN_encode_uper(asn_TYPE_descriptor_t *td, @@ -280,3 +311,18 @@ BOOLEAN_encode_uper(asn_TYPE_descriptor_t *td, _ASN_ENCODED_OK(er); } + +asn_enc_rval_t +BOOLEAN_encode_aper(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 217d0f16..8ea28928 100644 --- a/skeletons/BOOLEAN.h +++ b/skeletons/BOOLEAN.h @@ -28,6 +28,8 @@ 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; +per_type_decoder_f BOOLEAN_decode_aper; +per_type_encoder_f BOOLEAN_encode_aper; #ifdef __cplusplus } diff --git a/skeletons/ENUMERATED.c b/skeletons/ENUMERATED.c index 045554bb..f313f96f 100644 --- a/skeletons/ENUMERATED.c +++ b/skeletons/ENUMERATED.c @@ -26,6 +26,8 @@ asn_TYPE_descriptor_t asn_DEF_ENUMERATED = { INTEGER_encode_xer, ENUMERATED_decode_uper, /* Unaligned PER decoder */ ENUMERATED_encode_uper, /* Unaligned PER encoder */ + ENUMERATED_decode_aper, /* Aligned PER decoder */ + ENUMERATED_encode_aper, /* Aligned PER encoder */ 0, /* Use generic outmost tag fetcher */ asn_DEF_ENUMERATED_tags, sizeof(asn_DEF_ENUMERATED_tags) / sizeof(asn_DEF_ENUMERATED_tags[0]), @@ -57,6 +59,27 @@ ENUMERATED_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td return rval; } +asn_dec_rval_t +ENUMERATED_decode_aper(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_dec_rval_t rval; + ENUMERATED_t *st = (ENUMERATED_t *)*sptr; + long value; + void *vptr = &value; + + if(!st) { + st = (ENUMERATED_t *)(*sptr = CALLOC(1, sizeof(*st))); + if(!st) _ASN_DECODE_FAILED; + } + + rval = NativeEnumerated_decode_aper(opt_codec_ctx, td, constraints, + (void **)&vptr, pd); + if(rval.code == RC_OK) + if(asn_long2INTEGER(st, value)) + 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) { @@ -69,3 +92,14 @@ ENUMERATED_encode_uper(asn_TYPE_descriptor_t *td, return NativeEnumerated_encode_uper(td, constraints, &value, po); } +asn_enc_rval_t +ENUMERATED_encode_aper(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_aper(td, constraints, &value, po); +} diff --git a/skeletons/ENUMERATED.h b/skeletons/ENUMERATED.h index 542dcae9..5c4a2eda 100644 --- a/skeletons/ENUMERATED.h +++ b/skeletons/ENUMERATED.h @@ -17,6 +17,8 @@ extern asn_TYPE_descriptor_t asn_DEF_ENUMERATED; per_type_decoder_f ENUMERATED_decode_uper; per_type_encoder_f ENUMERATED_encode_uper; +per_type_decoder_f ENUMERATED_decode_aper; +per_type_encoder_f ENUMERATED_encode_aper; #ifdef __cplusplus } diff --git a/skeletons/GeneralString.c b/skeletons/GeneralString.c index c398d2b3..934b8a2b 100644 --- a/skeletons/GeneralString.c +++ b/skeletons/GeneralString.c @@ -24,6 +24,8 @@ asn_TYPE_descriptor_t asn_DEF_GeneralString = { OCTET_STRING_encode_xer, OCTET_STRING_decode_uper, /* Implemented in terms of OCTET STRING */ OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 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 cd36f034..29dcc6c7 100644 --- a/skeletons/GeneralizedTime.c +++ b/skeletons/GeneralizedTime.c @@ -178,6 +178,8 @@ asn_TYPE_descriptor_t asn_DEF_GeneralizedTime = { GeneralizedTime_encode_xer, OCTET_STRING_decode_uper, OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 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 e572ccdf..5f624863 100644 --- a/skeletons/GraphicString.c +++ b/skeletons/GraphicString.c @@ -24,6 +24,8 @@ asn_TYPE_descriptor_t asn_DEF_GraphicString = { OCTET_STRING_encode_xer, /* Can't expect it to be ASCII/UTF8 */ OCTET_STRING_decode_uper, /* Implemented in terms of OCTET STRING */ OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 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 0fdc0748..cec61c34 100644 --- a/skeletons/IA5String.c +++ b/skeletons/IA5String.c @@ -29,6 +29,8 @@ asn_TYPE_descriptor_t asn_DEF_IA5String = { OCTET_STRING_encode_xer_utf8, OCTET_STRING_decode_uper, OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 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 8ead23d5..7b3d10a2 100644 --- a/skeletons/INTEGER.c +++ b/skeletons/INTEGER.c @@ -30,6 +30,8 @@ asn_TYPE_descriptor_t asn_DEF_INTEGER = { #else INTEGER_decode_uper, /* Unaligned PER decoder */ INTEGER_encode_uper, /* Unaligned PER encoder */ + INTEGER_decode_aper, + INTEGER_encode_aper, #endif /* ASN_DISABLE_PER_SUPPORT */ 0, /* Use generic outmost tag fetcher */ asn_DEF_INTEGER_tags, @@ -410,7 +412,7 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun (asn_INTEGER_specifics_t *) td->specifics, lstart, lstop); if(el) { - ASN_DEBUG("Found \"%s\" => %ld", + ASN_DEBUG("Found \"%s\" => %lld", el->enum_name, el->nat_value); dec_value = el->nat_value; state = ST_END_ENUM; @@ -608,7 +610,7 @@ INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, if(uper_get_constrained_whole_number(pd, &uvalue, ct->range_bits)) _ASN_DECODE_STARVED; - ASN_DEBUG("Got value %lu + low %ld", + ASN_DEBUG("Got value %lu + low %lld", uvalue, ct->lower_bound); uvalue += ct->lower_bound; if(asn_ulong2INTEGER(st, uvalue)) @@ -665,6 +667,149 @@ INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, return rval; } +asn_dec_rval_t +INTEGER_decode_aper(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 }; + INTEGER_t *st = (INTEGER_t *)*sptr; + asn_per_constraint_t *ct; + int repeat; + + (void)opt_codec_ctx; + + if(!st) { + st = (INTEGER_t *)(*sptr = CALLOC(1, sizeof(*st))); + if(!st) _ASN_DECODE_FAILED; + } + + if(!constraints) constraints = td->per_constraints; + ct = constraints ? &constraints->value : 0; + + if(ct && ct->flags & APC_EXTENSIBLE) { + int inext = per_get_few_bits(pd, 1); + if(inext < 0) _ASN_DECODE_STARVED; + if(inext) ct = 0; + } + + FREEMEM(st->buf); + st->buf = 0; + st->size = 0; + if(ct) { + if(ct->flags & APC_SEMI_CONSTRAINED) { + st->buf = (uint8_t *)CALLOC(1, 2); + if(!st->buf) _ASN_DECODE_FAILED; + st->size = 1; + } else if(ct->flags & APC_CONSTRAINED && ct->range_bits >= 0) { + size_t size = (ct->range_bits + 7) >> 3; + st->buf = (uint8_t *)MALLOC(1 + size + 1); + if(!st->buf) _ASN_DECODE_FAILED; + st->size = size; + } + } + + /* X.691, #12.2.2 */ + if(ct && ct->flags != APC_UNCONSTRAINED) { + /* #10.5.6 */ + ASN_DEBUG("Integer with range %d bits", ct->range_bits); + if(ct->range_bits >= 0) { + if (ct->range_bits > 16) { + int max_range_bytes = (ct->range_bits >> 3) + 1; + int length, i; + int64_t value = 0; + + for (i = 0; i < max_range_bytes; i++) { + int upper = 1 << (i + 1); + if (upper > max_range_bytes) + break; + } + if ((length = per_get_few_bits(pd, i + 1)) < 0) + _ASN_DECODE_STARVED; + if (aper_get_align(pd) != 0) + _ASN_DECODE_STARVED; + ASN_DEBUG("Got length %d", length + 1); + for (i = 0; i < length + 1; i++) { + int buf = per_get_few_bits(pd, 8); + if (buf < 0) + _ASN_DECODE_STARVED; + value += (((int64_t)buf) << (8 * i)); + } + + if((specs && specs->field_unsigned) + ? asn_uint642INTEGER(st, value) + : asn_int642INTEGER(st, value)) + _ASN_DECODE_FAILED; + ASN_DEBUG("Got value %lld + low %lld", + value, ct->lower_bound); + value += ct->lower_bound; + } else { + long value = 0; + if (ct->range_bits < 8) { + value = per_get_few_bits(pd, ct->range_bits); + if(value < 0) _ASN_DECODE_STARVED; + } else if (ct->range_bits == 8) { + if (aper_get_align(pd) < 0) + _ASN_DECODE_FAILED; + value = per_get_few_bits(pd, ct->range_bits); + if(value < 0) _ASN_DECODE_STARVED; + } else { + /* Align */ + if (aper_get_align(pd) < 0) + _ASN_DECODE_FAILED; + value = per_get_few_bits(pd, 16); + if(value < 0) _ASN_DECODE_STARVED; + } + if((specs && specs->field_unsigned) + ? asn_ulong2INTEGER(st, value) + : asn_long2INTEGER(st, value)) + _ASN_DECODE_FAILED; + ASN_DEBUG("Got value %ld + low %lld", + value, ct->lower_bound); + value += ct->lower_bound; + } + return rval; + } else { + _ASN_DECODE_FAILED; + } + } else { + ASN_DEBUG("Decoding unconstrained integer %s", td->name); + } + + /* X.691, #12.2.3, #12.2.4 */ + do { + ssize_t len; + void *p; + int ret; + + /* Get the PER length */ + len = aper_get_length(pd, -1, -1, &repeat); + if(len < 0) _ASN_DECODE_STARVED; + + p = REALLOC(st->buf, st->size + len + 1); + if(!p) _ASN_DECODE_FAILED; + st->buf = (uint8_t *)p; + + ret = per_get_many_bits(pd, &st->buf[st->size], 0, 8 * len); + if(ret < 0) _ASN_DECODE_STARVED; + st->size += len; + } while(repeat); + st->buf[st->size] = 0; /* JIC */ + + /* #12.2.3 */ + if(ct && ct->lower_bound) { + /* + * TODO: replace by in-place arithmetics. + */ + long value; + if(asn_INTEGER2long(st, &value)) + _ASN_DECODE_FAILED; + if(asn_long2INTEGER(st, value + ct->lower_bound)) + _ASN_DECODE_FAILED; + } + + 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) { @@ -698,7 +843,7 @@ INTEGER_encode_uper(asn_TYPE_descriptor_t *td, || uval > (unsigned long)ct->upper_bound) inext = 1; } - ASN_DEBUG("Value %lu (%02x/%d) lb %lu ub %lu %s", + ASN_DEBUG("Value %lu (%02x/%d) lb %llu ub %llu %s", uval, st->buf[0], st->size, ct->lower_bound, ct->upper_bound, inext ? "ext" : "fix"); @@ -715,7 +860,7 @@ INTEGER_encode_uper(asn_TYPE_descriptor_t *td, || value > ct->upper_bound) inext = 1; } - ASN_DEBUG("Value %ld (%02x/%d) lb %ld ub %ld %s", + ASN_DEBUG("Value %ld (%02x/%d) lb %lld ub %lld %s", value, st->buf[0], st->size, ct->lower_bound, ct->upper_bound, inext ? "ext" : "fix"); @@ -742,7 +887,7 @@ INTEGER_encode_uper(asn_TYPE_descriptor_t *td, } if(ct && ct->lower_bound) { - ASN_DEBUG("Adjust lower bound to %ld", ct->lower_bound); + ASN_DEBUG("Adjust lower bound to %lld", ct->lower_bound); /* TODO: adjust lower bound */ _ASN_ENCODE_FAILED; } @@ -761,6 +906,129 @@ INTEGER_encode_uper(asn_TYPE_descriptor_t *td, #endif /* ASN_DISABLE_PER_SUPPORT */ +asn_enc_rval_t +INTEGER_encode_aper(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; + INTEGER_t *st = (INTEGER_t *)sptr; + const uint8_t *buf; + const uint8_t *end; + asn_per_constraint_t *ct; + int64_t 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(specs && specs->field_unsigned) { + uint64_t uval; + if(asn_INTEGER2uint64(st, &uval)) + _ASN_ENCODE_FAILED; + /* Check proper range */ + if(ct->flags & APC_SEMI_CONSTRAINED) { + if(uval < (unsigned long long)ct->lower_bound) + inext = 1; + } else if(ct->range_bits >= 0) { + if(uval < (unsigned long long)ct->lower_bound + || uval > (unsigned long long)ct->upper_bound) + inext = 1; + } + ASN_DEBUG("Value %llu (%02x/%d) lb %llu ub %llu %s", + uval, st->buf[0], st->size, + ct->lower_bound, ct->upper_bound, + inext ? "ext" : "fix"); + value = uval; + } else { + if(asn_INTEGER2int64(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 %lld (%02x/%d) lb %lld ub %lld %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); + + /* #12 <= 8 -> alignment ? */ + if (ct->range_bits < 8) { + if(per_put_few_bits(po, 0x00 | value, ct->range_bits)) + _ASN_ENCODE_FAILED; + } else if (ct->range_bits == 8) { + if(aper_put_align(po) < 0) + _ASN_ENCODE_FAILED; + if(per_put_few_bits(po, 0x00 | value, ct->range_bits)) + _ASN_ENCODE_FAILED; + } else if (ct->range_bits <= 16) { + // Consume the bytes to align on octet + if(aper_put_align(po) < 0) + _ASN_ENCODE_FAILED; + if(per_put_few_bits(po, 0x0000 | value, + 16)) + _ASN_ENCODE_FAILED; + } else { + /* TODO: extend to >64 bits */ + int64_t v = value; + int i; + + /* Putting length - 1 in the minimum number of bits ex: 5 = 3bits */ + if (per_put_few_bits(po, st->size - 1, (ct->range_bits >> 3)-1)) + _ASN_ENCODE_FAILED; + + // Consume the bits to align on octet + if (aper_put_align(po) < 0) + _ASN_ENCODE_FAILED; + /* Put the value */ + for (i = 0; i < st->size; i++) { + if(per_put_few_bits(po, (v >> (8 * (st->size - i - 1))) & 0xff, 8)) _ASN_ENCODE_FAILED; + } + } + _ASN_ENCODED_OK(er); + } + + if(ct && ct->lower_bound) { + ASN_DEBUG("Adjust lower bound to %lld", ct->lower_bound); + /* TODO: adjust lower bound */ + _ASN_ENCODE_FAILED; + } + + for(buf = st->buf, end = st->buf + st->size; buf < end;) { + ssize_t mayEncode = aper_put_length(po, -1, end - buf); + if(mayEncode < 0) + _ASN_ENCODE_FAILED; + if(per_put_many_bits(po, buf, 8 * mayEncode)) + _ASN_ENCODE_FAILED; + buf += mayEncode; + } + + _ASN_ENCODED_OK(er); +} + int asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) { uint8_t *b, *end; @@ -821,6 +1089,66 @@ asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) { return 0; } +int +asn_INTEGER2int64(const INTEGER_t *iptr, int64_t *lptr) { + uint8_t *b, *end; + size_t size; + int64_t l; + + /* Sanity checking */ + if(!iptr || !iptr->buf || !lptr) { + errno = EINVAL; + return -1; + } + + /* Cache the begin/end of the buffer */ + b = iptr->buf; /* Start of the INTEGER buffer */ + size = iptr->size; + end = b + size; /* Where to stop */ + + if(size > sizeof(int64_t)) { + uint8_t *end1 = end - 1; + /* + * Slightly more advanced processing, + * able to >sizeof(int64_t) bytes, + * when the actual value is small + * (0x0000000000abcdef would yield a fine 0x00abcdef) + */ + /* Skip out the insignificant leading bytes */ + for(; b < end1; b++) { + switch(*b) { + case 0x00: if((b[1] & 0x80) == 0) continue; break; + case 0xff: if((b[1] & 0x80) != 0) continue; break; + } + break; + } + + size = end - b; + if(size > sizeof(int64_t)) { + /* Still cannot fit the int64_t */ + errno = ERANGE; + return -1; + } + } + + /* Shortcut processing of a corner case */ + if(end == b) { + *lptr = 0; + return 0; + } + + /* Perform the sign initialization */ + /* Actually l = -(*b >> 7); gains nothing, yet unreadable! */ + if((*b >> 7)) l = -1; else l = 0; + + /* Conversion engine */ + for(; b < end; b++) + l = (l << 8) | *b; + + *lptr = l; + return 0; +} + int asn_INTEGER2ulong(const INTEGER_t *iptr, unsigned long *lptr) { uint8_t *b, *end; @@ -853,6 +1181,38 @@ asn_INTEGER2ulong(const INTEGER_t *iptr, unsigned long *lptr) { return 0; } +int +asn_INTEGER2uint64(const INTEGER_t *iptr, uint64_t *lptr) { + uint8_t *b, *end; + uint64_t l; + size_t size; + + if(!iptr || !iptr->buf || !lptr) { + errno = EINVAL; + return -1; + } + + b = iptr->buf; + size = iptr->size; + end = b + size; + + /* If all extra leading bytes are zeroes, ignore them */ + for(; size > sizeof(uint64_t); b++, size--) { + if(*b) { + /* Value won't fit unsigned long */ + errno = ERANGE; + return -1; + } + } + + /* Conversion engine */ + for(l = 0; b < end; b++) + l = (l << 8) | *b; + + *lptr = l; + return 0; +} + int asn_ulong2INTEGER(INTEGER_t *st, unsigned long value) { uint8_t *buf; @@ -878,6 +1238,86 @@ asn_ulong2INTEGER(INTEGER_t *st, unsigned long value) { return 0; } +int +asn_uint642INTEGER(INTEGER_t *st, uint64_t value) { + uint8_t *buf; + uint8_t *end; + uint8_t *b; + int shr; + + if(value <= INT64_MAX) + return asn_int642INTEGER(st, value); + + buf = (uint8_t *)MALLOC(1 + sizeof(value)); + if(!buf) return -1; + + end = buf + (sizeof(value) + 1); + buf[0] = 0; + for(b = buf + 1, shr = (sizeof(value)-1)*8; b < end; shr -= 8, b++) + *b = (uint8_t)(value >> shr); + + if(st->buf) FREEMEM(st->buf); + st->buf = buf; + st->size = 1 + sizeof(value); + + return 0; +} + +int +asn_int642INTEGER(INTEGER_t *st, int64_t value) { + uint8_t *buf, *bp; + uint8_t *p; + uint8_t *pstart; + uint8_t *pend1; + int littleEndian = 1; /* Run-time detection */ + int add; + + if(!st) { + errno = EINVAL; + return -1; + } + + buf = (uint8_t *)MALLOC(sizeof(value)); + if(!buf) return -1; + + if(*(char *)&littleEndian) { + pstart = (uint8_t *)&value + sizeof(value) - 1; + pend1 = (uint8_t *)&value; + add = -1; + } else { + pstart = (uint8_t *)&value; + pend1 = pstart + sizeof(value) - 1; + add = 1; + } + + /* + * If the contents octet consists of more than one octet, + * then bits of the first octet and bit 8 of the second octet: + * a) shall not all be ones; and + * b) shall not all be zero. + */ + for(p = pstart; p != pend1; p += add) { + switch(*p) { + case 0x00: if((*(p+add) & 0x80) == 0) + continue; + break; + case 0xff: if((*(p+add) & 0x80)) + continue; + break; + } + break; + } + /* Copy the integer body */ + for(pstart = p, bp = buf, pend1 += add; p != pend1; p += add) + *bp++ = *p; + + if(st->buf) FREEMEM(st->buf); + st->buf = buf; + st->size = bp - buf; + + return 0; +} + int asn_long2INTEGER(INTEGER_t *st, long value) { uint8_t *buf, *bp; diff --git a/skeletons/INTEGER.h b/skeletons/INTEGER.h index 2813f0cb..e8b36c79 100644 --- a/skeletons/INTEGER.h +++ b/skeletons/INTEGER.h @@ -18,7 +18,7 @@ extern asn_TYPE_descriptor_t asn_DEF_INTEGER; /* Map with to integer value association */ typedef struct asn_INTEGER_enum_map_s { - long nat_value; /* associated native integer value */ + int64_t nat_value; /* associated native integer value */ size_t enum_len; /* strlen("tag") */ const char *enum_name; /* "tag" */ } asn_INTEGER_enum_map_t; @@ -41,6 +41,8 @@ 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; +per_type_decoder_f INTEGER_decode_aper; +per_type_encoder_f INTEGER_encode_aper; /*********************************** * Some handy conversion routines. * @@ -52,8 +54,12 @@ per_type_encoder_f INTEGER_encode_uper; * -1/ERANGE: Value encoded is out of range for long representation * -1/ENOMEM: Memory allocation failed (in asn_long2INTEGER()). */ +int asn_INTEGER2int64(const INTEGER_t *i, int64_t *l); +int asn_INTEGER2uint64(const INTEGER_t *i, uint64_t *l); int asn_INTEGER2long(const INTEGER_t *i, long *l); int asn_INTEGER2ulong(const INTEGER_t *i, unsigned long *l); +int asn_int642INTEGER(INTEGER_t *i, int64_t l); +int asn_uint642INTEGER(INTEGER_t *i, uint64_t l); int asn_long2INTEGER(INTEGER_t *i, long l); int asn_ulong2INTEGER(INTEGER_t *i, unsigned long l); diff --git a/skeletons/ISO646String.c b/skeletons/ISO646String.c index 8d681c82..a6cc7619 100644 --- a/skeletons/ISO646String.c +++ b/skeletons/ISO646String.c @@ -29,6 +29,8 @@ asn_TYPE_descriptor_t asn_DEF_ISO646String = { OCTET_STRING_encode_xer_utf8, OCTET_STRING_decode_uper, OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 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 8dcb6aa9..f514ca29 100644 --- a/skeletons/NULL.c +++ b/skeletons/NULL.c @@ -25,6 +25,8 @@ asn_TYPE_descriptor_t asn_DEF_NULL = { NULL_encode_xer, NULL_decode_uper, /* Unaligned PER decoder */ NULL_encode_uper, /* Unaligned PER encoder */ + NULL_decode_aper, /* Aligned PER decoder */ + NULL_encode_aper, /* Aligned PER encoder */ 0, /* Use generic outmost tag fetcher */ asn_DEF_NULL_tags, sizeof(asn_DEF_NULL_tags) / sizeof(asn_DEF_NULL_tags[0]), @@ -136,6 +138,34 @@ NULL_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, return rv; } +asn_dec_rval_t +NULL_decode_aper(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_dec_rval_t rv; + + (void)opt_codec_ctx; + (void)td; + (void)constraints; + (void)pd; + + if(!*sptr) { + *sptr = MALLOC(sizeof(NULL_t)); + if(*sptr) { + *(NULL_t *)*sptr = 0; + } else { + _ASN_DECODE_FAILED; + } + } + + /* + * NULL type does not have content octets. + */ + + rv.code = RC_OK; + 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) { @@ -149,3 +179,17 @@ NULL_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, er.encoded = 0; _ASN_ENCODED_OK(er); } + +asn_enc_rval_t +NULL_encode_aper(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 131e7759..90784d81 100644 --- a/skeletons/NULL.h +++ b/skeletons/NULL.h @@ -25,6 +25,8 @@ 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; +per_type_decoder_f NULL_decode_aper; +per_type_encoder_f NULL_encode_aper; #ifdef __cplusplus } diff --git a/skeletons/NativeEnumerated.c b/skeletons/NativeEnumerated.c index ecf66d1b..4df925e4 100644 --- a/skeletons/NativeEnumerated.c +++ b/skeletons/NativeEnumerated.c @@ -30,6 +30,8 @@ asn_TYPE_descriptor_t asn_DEF_NativeEnumerated = { NativeEnumerated_encode_xer, NativeEnumerated_decode_uper, NativeEnumerated_encode_uper, + NativeEnumerated_decode_aper, + NativeEnumerated_encode_aper, 0, /* Use generic outmost tag fetcher */ asn_DEF_NativeEnumerated_tags, sizeof(asn_DEF_NativeEnumerated_tags) / sizeof(asn_DEF_NativeEnumerated_tags[0]), @@ -125,6 +127,61 @@ NativeEnumerated_decode_uper(asn_codec_ctx_t *opt_codec_ctx, return rval; } +asn_dec_rval_t +NativeEnumerated_decode_aper(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; + asn_per_constraint_t *ct; + long value; + + (void)opt_codec_ctx; + + if(constraints) ct = &constraints->value; + else if(td->per_constraints) ct = &td->per_constraints->value; + else _ASN_DECODE_FAILED; /* Mandatory! */ + if(!specs) _ASN_DECODE_FAILED; + + if(!native) { + native = (long *)(*sptr = CALLOC(1, sizeof(*native))); + if(!native) _ASN_DECODE_FAILED; + } + + ASN_DEBUG("Decoding %s as NativeEnumerated", td->name); + + if(ct->flags & APC_EXTENSIBLE) { + int inext = per_get_few_bits(pd, 1); + if(inext < 0) _ASN_DECODE_STARVED; + if(inext) ct = 0; + } + + if(ct && ct->range_bits >= 0) { + value = per_get_few_bits(pd, ct->range_bits); + if(value < 0) _ASN_DECODE_STARVED; + if(value >= (specs->extension + ? specs->extension - 1 : specs->map_count)) + _ASN_DECODE_FAILED; + } else { + if(!specs->extension) + _ASN_DECODE_FAILED; + /* + * X.691, #10.6: normally small non-negative whole number; + */ + value = uper_get_nsnnwn(pd); + if(value < 0) _ASN_DECODE_STARVED; + value += specs->extension - 1; + if(value >= specs->map_count) + _ASN_DECODE_FAILED; + } + + *native = specs->value2enum[value].nat_value; + ASN_DEBUG("Decoded %s = %ld", td->name, *native); + + return rval; +} + static int NativeEnumerated__compar_value2enum(const void *ap, const void *bp) { const asn_INTEGER_enum_map_t *a = ap; @@ -205,3 +262,72 @@ NativeEnumerated_encode_uper(asn_TYPE_descriptor_t *td, _ASN_ENCODED_OK(er); } +asn_enc_rval_t +NativeEnumerated_encode_aper(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, 1)) + _ASN_ENCODE_FAILED; + if(inext) 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; + */ + ASN_DEBUG("value = %ld, ext = %d, inext = %d, res = %ld", + value, specs->extension, inext, + value - (inext ? (specs->extension - 1) : 0)); + if(uper_put_nsnnwn(po, value - (inext ? (specs->extension - 1) : 0))) + _ASN_ENCODE_FAILED; + + _ASN_ENCODED_OK(er); +} + diff --git a/skeletons/NativeEnumerated.h b/skeletons/NativeEnumerated.h index c59bb1ba..95f05312 100644 --- a/skeletons/NativeEnumerated.h +++ b/skeletons/NativeEnumerated.h @@ -24,6 +24,8 @@ 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; +per_type_decoder_f NativeEnumerated_decode_aper; +per_type_encoder_f NativeEnumerated_encode_aper; #ifdef __cplusplus } diff --git a/skeletons/NativeInteger.c b/skeletons/NativeInteger.c index 7f8e9276..ef17bee3 100644 --- a/skeletons/NativeInteger.c +++ b/skeletons/NativeInteger.c @@ -31,6 +31,8 @@ asn_TYPE_descriptor_t asn_DEF_NativeInteger = { NativeInteger_encode_xer, NativeInteger_decode_uper, /* Unaligned PER decoder */ NativeInteger_encode_uper, /* Unaligned PER encoder */ + NativeInteger_decode_aper, /* Aligned PER decoder */ + NativeInteger_encode_aper, /* Aligned PER encoder */ 0, /* Use generic outmost tag fetcher */ asn_DEF_NativeInteger_tags, sizeof(asn_DEF_NativeInteger_tags) / sizeof(asn_DEF_NativeInteger_tags[0]), @@ -267,6 +269,42 @@ NativeInteger_decode_uper(asn_codec_ctx_t *opt_codec_ctx, return rval; } +asn_dec_rval_t +NativeInteger_decode_aper(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; + long *native = (long *)*sptr; + INTEGER_t tmpint; + void *tmpintptr = &tmpint; + + (void)opt_codec_ctx; + ASN_DEBUG("Decoding NativeInteger %s (APER)", td->name); + + if(!native) { + native = (long *)(*sptr = CALLOC(1, sizeof(*native))); + if(!native) _ASN_DECODE_FAILED; + } + + memset(&tmpint, 0, sizeof tmpint); + rval = INTEGER_decode_aper(opt_codec_ctx, td, constraints, + &tmpintptr, pd); + if(rval.code == RC_OK) { + if((specs&&specs->field_unsigned) + ? asn_INTEGER2ulong(&tmpint, (unsigned long *)native) + : asn_INTEGER2long(&tmpint, native)) + rval.code = RC_FAIL; + else + ASN_DEBUG("NativeInteger %s got value %ld", + td->name, *native); + } + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); + + 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) { @@ -291,6 +329,32 @@ NativeInteger_encode_uper(asn_TYPE_descriptor_t *td, return er; } +asn_enc_rval_t +NativeInteger_encode_aper( + 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; + INTEGER_t tmpint; + + if(!sptr) _ASN_ENCODE_FAILED; + + native = *(long *)sptr; + + ASN_DEBUG("Encoding NativeInteger %s %ld (APER)", td->name, native); + + memset(&tmpint, 0, sizeof(tmpint)); + if((specs&&specs->field_unsigned) + ? asn_ulong2INTEGER(&tmpint, native) + : asn_long2INTEGER(&tmpint, native)) + _ASN_ENCODE_FAILED; + er = INTEGER_encode_aper(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 4e63a835..14aa1a49 100644 --- a/skeletons/NativeInteger.h +++ b/skeletons/NativeInteger.h @@ -29,6 +29,8 @@ 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; +per_type_decoder_f NativeInteger_decode_aper; +per_type_encoder_f NativeInteger_encode_aper; #ifdef __cplusplus } diff --git a/skeletons/NativeReal.c b/skeletons/NativeReal.c index 3fd51a4c..3bd5a28a 100644 --- a/skeletons/NativeReal.c +++ b/skeletons/NativeReal.c @@ -32,6 +32,8 @@ asn_TYPE_descriptor_t asn_DEF_NativeReal = { NativeReal_encode_xer, NativeReal_decode_uper, NativeReal_encode_uper, + NativeReal_decode_aper, + NativeReal_encode_aper, 0, /* Use generic outmost tag fetcher */ asn_DEF_NativeReal_tags, sizeof(asn_DEF_NativeReal_tags) / sizeof(asn_DEF_NativeReal_tags[0]), @@ -228,6 +230,43 @@ NativeReal_decode_uper(asn_codec_ctx_t *opt_codec_ctx, return rval; } +asn_dec_rval_t +NativeReal_decode_aper(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, + void **dbl_ptr, asn_per_data_t *pd) { + double *Dbl = (double *)*dbl_ptr; + asn_dec_rval_t rval; + REAL_t tmp; + void *ptmp = &tmp; + int ret; + + (void)constraints; + + /* + * If the structure is not there, allocate it. + */ + if(Dbl == NULL) { + *dbl_ptr = CALLOC(1, sizeof(*Dbl)); + Dbl = (double *)*dbl_ptr; + if(Dbl == NULL) + _ASN_DECODE_FAILED; + } + + memset(&tmp, 0, sizeof(tmp)); + rval = OCTET_STRING_decode_aper(opt_codec_ctx, td, NULL, + &ptmp, pd); + if(rval.code != RC_OK) { + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp); + return rval; + } + + ret = asn_REAL2double(&tmp, Dbl); + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp); + if(ret) _ASN_DECODE_FAILED; + + return rval; +} + /* * Encode the NativeReal using the OCTET STRING PER encoder. */ @@ -257,6 +296,32 @@ NativeReal_encode_uper(asn_TYPE_descriptor_t *td, return erval; } +asn_enc_rval_t +NativeReal_encode_aper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + double Dbl = *(const double *)sptr; + asn_enc_rval_t erval; + REAL_t tmp; + + (void)constraints; + + /* Prepare a temporary clean structure */ + memset(&tmp, 0, sizeof(tmp)); + + if(asn_double2REAL(&tmp, Dbl)) + _ASN_ENCODE_FAILED; + + /* Encode a DER REAL */ + erval = OCTET_STRING_encode_aper(td, NULL, &tmp, po); + if(erval.encoded == -1) + erval.structure_ptr = sptr; + + /* Free possibly allocated members of the temporary structure */ + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_REAL, &tmp); + + return erval; +} + /* * Decode the chunk of XML text encoding REAL. */ diff --git a/skeletons/NativeReal.h b/skeletons/NativeReal.h index 68a81d9b..94ed9ded 100644 --- a/skeletons/NativeReal.h +++ b/skeletons/NativeReal.h @@ -27,6 +27,8 @@ xer_type_decoder_f NativeReal_decode_xer; xer_type_encoder_f NativeReal_encode_xer; per_type_decoder_f NativeReal_decode_uper; per_type_encoder_f NativeReal_encode_uper; +per_type_decoder_f NativeReal_decode_aper; +per_type_encoder_f NativeReal_encode_aper; #ifdef __cplusplus } diff --git a/skeletons/NumericString.c b/skeletons/NumericString.c index b669f571..81b880ac 100644 --- a/skeletons/NumericString.c +++ b/skeletons/NumericString.c @@ -49,6 +49,8 @@ asn_TYPE_descriptor_t asn_DEF_NumericString = { OCTET_STRING_encode_xer_utf8, OCTET_STRING_decode_uper, OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 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 03bfc033..24f4e0e8 100644 --- a/skeletons/OBJECT_IDENTIFIER.c +++ b/skeletons/OBJECT_IDENTIFIER.c @@ -27,6 +27,8 @@ asn_TYPE_descriptor_t asn_DEF_OBJECT_IDENTIFIER = { OBJECT_IDENTIFIER_encode_xer, OCTET_STRING_decode_uper, OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 0, /* Use generic outmost tag fetcher */ asn_DEF_OBJECT_IDENTIFIER_tags, sizeof(asn_DEF_OBJECT_IDENTIFIER_tags) diff --git a/skeletons/OCTET_STRING.c b/skeletons/OCTET_STRING.c index ece27a28..3e424e7f 100644 --- a/skeletons/OCTET_STRING.c +++ b/skeletons/OCTET_STRING.c @@ -36,6 +36,8 @@ asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = { OCTET_STRING_encode_xer, OCTET_STRING_decode_uper, /* Unaligned PER decoder */ OCTET_STRING_encode_uper, /* Unaligned PER encoder */ + OCTET_STRING_decode_aper, /* Aligned PER decoder */ + OCTET_STRING_encode_aper, /* Aligned PER encoder */ 0, /* Use generic outmost tag fetcher */ asn_DEF_OCTET_STRING_tags, sizeof(asn_DEF_OCTET_STRING_tags) @@ -1194,14 +1196,14 @@ OCTET_STRING_decode_xer_utf8(asn_codec_ctx_t *opt_codec_ctx, static int OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf, size_t units, unsigned int bpc, unsigned int unit_bits, - long lb, long ub, asn_per_constraints_t *pc) { + int64_t lb, int64_t ub, asn_per_constraints_t *pc) { uint8_t *end = buf + units * bpc; - ASN_DEBUG("Expanding %d characters into (%ld..%ld):%d", + ASN_DEBUG("Expanding %d characters into (%lld..%lld):%d", (int)units, lb, ub, unit_bits); /* X.691: 27.5.4 */ - if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) { + if((uint64_t)ub <= ((uint64_t)2 << (unit_bits - 1))) { /* Decode without translation */ lb = 0; } else if(pc && pc->code2value) { @@ -1216,7 +1218,7 @@ OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf, value = pc->code2value(code); if(value < 0) { ASN_DEBUG("Code %d (0x%02x) is" - " not in map (%ld..%ld)", + " not in map (%lld..%lld)", code, code, lb, ub); return 1; /* FATAL */ } @@ -1240,7 +1242,7 @@ OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf, int ch = code + lb; if(code < 0) return -1; /* WMORE */ if(ch > ub) { - ASN_DEBUG("Code %d is out of range (%ld..%ld)", + ASN_DEBUG("Code %d is out of range (%lld..%lld)", ch, lb, ub); return 1; /* FATAL */ } @@ -1258,14 +1260,14 @@ OCTET_STRING_per_get_characters(asn_per_data_t *po, uint8_t *buf, static int OCTET_STRING_per_put_characters(asn_per_outp_t *po, const uint8_t *buf, size_t units, unsigned int bpc, unsigned int unit_bits, - long lb, long ub, asn_per_constraints_t *pc) { + int64_t lb, int64_t ub, asn_per_constraints_t *pc) { const uint8_t *end = buf + units * bpc; - ASN_DEBUG("Squeezing %d characters into (%ld..%ld):%d (%d bpc)", + ASN_DEBUG("Squeezing %d characters into (%lld..%lld):%d (%d bpc)", (int)units, lb, ub, unit_bits, bpc); /* X.691: 27.5.4 */ - if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) { + if((uint64_t)ub <= ((uint64_t)2 << (unit_bits - 1))) { /* Encode as is */ lb = 0; } else if(pc && pc->value2code) { @@ -1282,7 +1284,7 @@ OCTET_STRING_per_put_characters(asn_per_outp_t *po, const uint8_t *buf, code = pc->value2code(value); if(code < 0) { ASN_DEBUG("Character %d (0x%02x) is" - " not in map (%ld..%ld)", + " not in map (%lld..%lld)", *buf, *buf, lb, ub); return -1; } @@ -1309,7 +1311,7 @@ OCTET_STRING_per_put_characters(asn_per_outp_t *po, const uint8_t *buf, ch = value - lb; if(ch < 0 || ch > ub) { ASN_DEBUG("Character %d (0x%02x)" - " is out of range (%ld..%ld)", + " is out of range (%lld..%lld)", *buf, *buf, lb, ub + lb); return -1; } @@ -1392,7 +1394,7 @@ OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx, if(!st) RETURN(RC_FAIL); } - ASN_DEBUG("PER Decoding %s size %ld .. %ld bits %d", + ASN_DEBUG("PER Decoding %s size %lld .. %lld bits %d", csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible", csiz->lower_bound, csiz->upper_bound, csiz->effective_bits); @@ -1423,14 +1425,14 @@ OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx, if(csiz->effective_bits == 0) { int ret; if(bpc) { - ASN_DEBUG("Encoding OCTET STRING size %ld", + ASN_DEBUG("Encoding OCTET STRING size %lld", csiz->upper_bound); ret = OCTET_STRING_per_get_characters(pd, st->buf, csiz->upper_bound, bpc, unit_bits, cval->lower_bound, cval->upper_bound, pc); if(ret > 0) RETURN(RC_FAIL); } else { - ASN_DEBUG("Encoding BIT STRING size %ld", + ASN_DEBUG("Encoding BIT STRING size %lld", csiz->upper_bound); ret = per_get_many_bits(pd, st->buf, 0, unit_bits * csiz->upper_bound); @@ -1492,6 +1494,194 @@ OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx, return rval; } +asn_dec_rval_t +OCTET_STRING_decode_aper(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_OCTET_STRING_specifics_t *specs = td->specifics + ? (asn_OCTET_STRING_specifics_t *)td->specifics + : &asn_DEF_OCTET_STRING_specs; + asn_per_constraints_t *pc = constraints ? constraints + : td->per_constraints; + asn_per_constraint_t *cval; + asn_per_constraint_t *csiz; + asn_dec_rval_t rval = { RC_OK, 0 }; + BIT_STRING_t *st = (BIT_STRING_t *)*sptr; + ssize_t consumed_myself = 0; + int repeat; + enum { + OS__BPC_BIT = 0, + OS__BPC_CHAR = 1, + OS__BPC_U16 = 2, + OS__BPC_U32 = 4 + } bpc; /* Bytes per character */ + unsigned int unit_bits; + unsigned int canonical_unit_bits; + + (void)opt_codec_ctx; + + if(pc) { + cval = &pc->value; + csiz = &pc->size; + } else { + cval = &asn_DEF_OCTET_STRING_constraints.value; + csiz = &asn_DEF_OCTET_STRING_constraints.size; + } + + switch(specs->subvariant) { + default: +// case ASN_OSUBV_ANY: +// ASN_DEBUG("Unrecognized subvariant %d", specs->subvariant); +// RETURN(RC_FAIL); + case ASN_OSUBV_BIT: + canonical_unit_bits = unit_bits = 1; + bpc = OS__BPC_BIT; + break; + case ASN_OSUBV_ANY: + case ASN_OSUBV_STR: + canonical_unit_bits = unit_bits = 8; +// if(cval->flags & APC_CONSTRAINED) +// unit_bits = cval->range_bits; + bpc = OS__BPC_CHAR; + break; + case ASN_OSUBV_U16: + canonical_unit_bits = unit_bits = 16; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_U16; + break; + case ASN_OSUBV_U32: + canonical_unit_bits = unit_bits = 32; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_U32; + break; + } + + /* + * Allocate the string. + */ + if(!st) { + st = (BIT_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); + if(!st) RETURN(RC_FAIL); + } + + ASN_DEBUG("PER Decoding %s size %lld .. %lld bits %d", + csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible", + csiz->lower_bound, csiz->upper_bound, csiz->effective_bits); + + if(csiz->flags & APC_EXTENSIBLE) { + int inext = per_get_few_bits(pd, 1); + if(inext < 0) RETURN(RC_WMORE); + if(inext) { + csiz = &asn_DEF_OCTET_STRING_constraints.size; + cval = &asn_DEF_OCTET_STRING_constraints.value; + unit_bits = canonical_unit_bits; + } + } + + if(csiz->effective_bits >= 0) { + FREEMEM(st->buf); + if(bpc) { + st->size = csiz->upper_bound * bpc; + } else { + st->size = (csiz->upper_bound + 7) >> 3; + } + st->buf = (uint8_t *)MALLOC(st->size + 1); + if(!st->buf) { st->size = 0; RETURN(RC_FAIL); } + } + + /* 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(csiz->effective_bits == 0) { + int ret; + if (st->size > 2) { /* X.691 #16 NOTE 1 */ + if (aper_get_align(pd) < 0) + RETURN(RC_FAIL); + } + if(bpc) { + ASN_DEBUG("Decoding OCTET STRING size %lld", + csiz->upper_bound); + ret = OCTET_STRING_per_get_characters(pd, st->buf, + csiz->upper_bound, bpc, unit_bits, + cval->lower_bound, cval->upper_bound, pc); + if(ret > 0) RETURN(RC_FAIL); + } else { + ASN_DEBUG("Decoding BIT STRING size %lld", + csiz->upper_bound); + ret = per_get_many_bits(pd, st->buf, 0, + unit_bits * csiz->upper_bound); + } + if(ret < 0) RETURN(RC_WMORE); + consumed_myself += unit_bits * csiz->upper_bound; + st->buf[st->size] = 0; + if(bpc == 0) { + int ubs = (csiz->upper_bound & 0x7); + st->bits_unused = ubs ? 8 - ubs : 0; + } + RETURN(RC_OK); + } + + st->size = 0; + do { + ssize_t raw_len; + ssize_t len_bytes; + ssize_t len_bits; + void *p; + int ret; + + /* Get the PER length */ + if (csiz->upper_bound - csiz->lower_bound == 0) + // Indefinite length case + raw_len = aper_get_length(pd, -1, csiz->effective_bits, &repeat); + else + raw_len = aper_get_length(pd, csiz->upper_bound - csiz->lower_bound + 1, csiz->effective_bits, &repeat); + repeat = 0; + if(raw_len < 0) RETURN(RC_WMORE); + raw_len += csiz->lower_bound; + + ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)", + (long)csiz->effective_bits, (long)raw_len, + repeat ? "repeat" : "once", td->name); + + if (raw_len > 2) { /* X.691 #16 NOTE 1 */ + if (aper_get_align(pd) < 0) + RETURN(RC_FAIL); + } + + if(bpc) { + len_bytes = raw_len * bpc; + len_bits = len_bytes * unit_bits; + } else { + len_bits = raw_len; + len_bytes = (len_bits + 7) >> 3; + if(len_bits & 0x7) + st->bits_unused = 8 - (len_bits & 0x7); + /* len_bits be multiple of 16K if repeat is set */ + } + p = REALLOC(st->buf, st->size + len_bytes + 1); + if(!p) RETURN(RC_FAIL); + st->buf = (uint8_t *)p; + + if(bpc) { + ret = OCTET_STRING_per_get_characters(pd, + &st->buf[st->size], raw_len, bpc, unit_bits, + cval->lower_bound, cval->upper_bound, pc); + if(ret > 0) RETURN(RC_FAIL); + } else { + ret = per_get_many_bits(pd, &st->buf[st->size], + 0, len_bits); + } + if(ret < 0) RETURN(RC_WMORE); + st->size += len_bytes; + } while(repeat); + st->buf[st->size] = 0; /* nul-terminate */ + + 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) { @@ -1566,7 +1756,7 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, } ASN_DEBUG("Encoding %s into %d units of %d bits" - " (%ld..%ld, effective %d)%s", + " (%lld..%lld, effective %d)%s", td->name, sizeinunits, unit_bits, csiz->lower_bound, csiz->upper_bound, csiz->effective_bits, ct_extensible ? " EXT" : ""); @@ -1598,7 +1788,7 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, /* 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(csiz->effective_bits >= 0) { - ASN_DEBUG("Encoding %d bytes (%ld), length in %d bits", + ASN_DEBUG("Encoding %d bytes (%lld), length in %d bits", st->size, sizeinunits - csiz->lower_bound, csiz->effective_bits); ret = per_put_few_bits(po, sizeinunits - csiz->lower_bound, @@ -1652,6 +1842,173 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, _ASN_ENCODED_OK(er); } +asn_enc_rval_t +OCTET_STRING_encode_aper(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_constraints_t *pc = constraints ? constraints + : td->per_constraints; + asn_per_constraint_t *cval; + asn_per_constraint_t *csiz; + const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; + asn_enc_rval_t er = { 0, 0, 0 }; + int inext = 0; /* Lies not within extension root */ + unsigned int unit_bits; + unsigned int canonical_unit_bits; + unsigned int sizeinunits; + const uint8_t *buf; + int ret; + enum { + OS__BPC_BIT = 0, + OS__BPC_CHAR = 1, + OS__BPC_U16 = 2, + OS__BPC_U32 = 4 + } bpc; /* Bytes per character */ + int ct_extensible; + + if(!st || (!st->buf && st->size)) + _ASN_ENCODE_FAILED; + + if(pc) { + cval = &pc->value; + csiz = &pc->size; + } else { + cval = &asn_DEF_OCTET_STRING_constraints.value; + csiz = &asn_DEF_OCTET_STRING_constraints.size; + } + ct_extensible = csiz->flags & APC_EXTENSIBLE; + + switch(specs->subvariant) { + default: +// case ASN_OSUBV_ANY: +// _ASN_ENCODE_FAILED; + case ASN_OSUBV_BIT: + canonical_unit_bits = unit_bits = 1; + bpc = OS__BPC_BIT; + sizeinunits = st->size * 8 - (st->bits_unused & 0x07); + ASN_DEBUG("BIT STRING of %d bytes", + sizeinunits); + break; + case ASN_OSUBV_ANY: + case ASN_OSUBV_STR: + canonical_unit_bits = unit_bits = 8; +// if(cval->flags & APC_CONSTRAINED) +// unit_bits = 8; + bpc = OS__BPC_CHAR; + sizeinunits = st->size; + break; + case ASN_OSUBV_U16: + canonical_unit_bits = unit_bits = 16; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_U16; + sizeinunits = st->size / 2; + break; + case ASN_OSUBV_U32: + canonical_unit_bits = unit_bits = 32; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + bpc = OS__BPC_U32; + sizeinunits = st->size / 4; + break; + } + + ASN_DEBUG("Encoding %s into %d units of %d bits" + " (%lld..%lld, effective %d)%s", + td->name, sizeinunits, unit_bits, + csiz->lower_bound, csiz->upper_bound, + csiz->effective_bits, ct_extensible ? " EXT" : ""); + + /* Figure out wheter size lies within PER visible constraint */ + + if(csiz->effective_bits >= 0) { + if((int)sizeinunits < csiz->lower_bound + || (int)sizeinunits > csiz->upper_bound) { + if(ct_extensible) { + cval = &asn_DEF_OCTET_STRING_constraints.value; + csiz = &asn_DEF_OCTET_STRING_constraints.size; + unit_bits = canonical_unit_bits; + 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(csiz->effective_bits >= 0) { + ASN_DEBUG("Encoding %d bytes (%lld), length in %d bits", + st->size, sizeinunits - csiz->lower_bound, + csiz->effective_bits); + ret = per_put_few_bits(po, sizeinunits - csiz->lower_bound, + csiz->effective_bits); + if(ret) _ASN_ENCODE_FAILED; + if (st->size > 2) { /* X.691 #16 NOTE 1 */ + if (aper_put_align(po) < 0) + _ASN_ENCODE_FAILED; + } + if(bpc) { + ret = OCTET_STRING_per_put_characters(po, st->buf, + sizeinunits, bpc, unit_bits, + cval->lower_bound, cval->upper_bound, pc); + } else { + ret = per_put_many_bits(po, st->buf, + sizeinunits * unit_bits); + } + if(ret) _ASN_ENCODE_FAILED; + _ASN_ENCODED_OK(er); + } + + ASN_DEBUG("Encoding %d bytes", st->size); + + if(sizeinunits == 0) { + if(aper_put_length(po, -1, 0)) + _ASN_ENCODE_FAILED; + _ASN_ENCODED_OK(er); + } + + buf = st->buf; + while(sizeinunits) { + ssize_t maySave = aper_put_length(po, -1, sizeinunits); + + if(maySave < 0) _ASN_ENCODE_FAILED; + + ASN_DEBUG("Encoding %ld of %ld", + (long)maySave, (long)sizeinunits); + + if(bpc) { + ret = OCTET_STRING_per_put_characters(po, buf, + maySave, bpc, unit_bits, + cval->lower_bound, cval->upper_bound, pc); + } else { + ret = per_put_many_bits(po, buf, maySave * unit_bits); + } + if(ret) _ASN_ENCODE_FAILED; + + if(bpc) + buf += maySave * bpc; + else + buf += maySave >> 3; + 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 013c7b13..bc256668 100644 --- a/skeletons/OCTET_STRING.h +++ b/skeletons/OCTET_STRING.h @@ -32,6 +32,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; +per_type_decoder_f OCTET_STRING_decode_aper; +per_type_encoder_f OCTET_STRING_encode_aper; /****************************** * Handy conversion routines. * diff --git a/skeletons/ObjectDescriptor.c b/skeletons/ObjectDescriptor.c index 31bc1b2c..f049c1cc 100644 --- a/skeletons/ObjectDescriptor.c +++ b/skeletons/ObjectDescriptor.c @@ -24,6 +24,8 @@ asn_TYPE_descriptor_t asn_DEF_ObjectDescriptor = { OCTET_STRING_encode_xer_utf8, OCTET_STRING_decode_uper, OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 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 5a3525ea..3058d095 100644 --- a/skeletons/PrintableString.c +++ b/skeletons/PrintableString.c @@ -59,6 +59,8 @@ asn_TYPE_descriptor_t asn_DEF_PrintableString = { OCTET_STRING_encode_xer_utf8, OCTET_STRING_decode_uper, OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 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 1212050c..e1791527 100644 --- a/skeletons/REAL.c +++ b/skeletons/REAL.c @@ -51,6 +51,8 @@ asn_TYPE_descriptor_t asn_DEF_REAL = { REAL_encode_xer, REAL_decode_uper, REAL_encode_uper, + REAL_decode_aper, + REAL_encode_aper, 0, /* Use generic outmost tag fetcher */ asn_DEF_REAL_tags, sizeof(asn_DEF_REAL_tags) / sizeof(asn_DEF_REAL_tags[0]), @@ -367,6 +369,21 @@ REAL_encode_uper(asn_TYPE_descriptor_t *td, return OCTET_STRING_encode_uper(td, 0, sptr, po); } +asn_dec_rval_t +REAL_decode_aper(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, + void **sptr, asn_per_data_t *pd) { + (void)constraints; /* No PER visible constraints */ + return OCTET_STRING_decode_aper(opt_codec_ctx, td, 0, sptr, pd); +} + +asn_enc_rval_t +REAL_encode_aper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + (void)constraints; /* No PER visible constraints */ + return OCTET_STRING_encode_aper(td, 0, sptr, po); +} + int asn_REAL2double(const REAL_t *st, double *dbl_value) { unsigned int octv; diff --git a/skeletons/REAL.h b/skeletons/REAL.h index af3e84cc..503e2546 100644 --- a/skeletons/REAL.h +++ b/skeletons/REAL.h @@ -21,6 +21,8 @@ xer_type_decoder_f REAL_decode_xer; xer_type_encoder_f REAL_encode_xer; per_type_decoder_f REAL_decode_uper; per_type_encoder_f REAL_encode_uper; +per_type_decoder_f REAL_decode_aper; +per_type_encoder_f REAL_encode_aper; /*********************************** * Some handy conversion routines. * diff --git a/skeletons/RELATIVE-OID.c b/skeletons/RELATIVE-OID.c index 44f27587..8e3e97f4 100644 --- a/skeletons/RELATIVE-OID.c +++ b/skeletons/RELATIVE-OID.c @@ -28,6 +28,8 @@ asn_TYPE_descriptor_t asn_DEF_RELATIVE_OID = { RELATIVE_OID_encode_xer, OCTET_STRING_decode_uper, OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 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 115d7d43..4a6ad475 100644 --- a/skeletons/T61String.c +++ b/skeletons/T61String.c @@ -24,6 +24,8 @@ asn_TYPE_descriptor_t asn_DEF_T61String = { OCTET_STRING_encode_xer, OCTET_STRING_decode_uper, OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 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 faad6973..40b5c4e6 100644 --- a/skeletons/TeletexString.c +++ b/skeletons/TeletexString.c @@ -24,6 +24,8 @@ asn_TYPE_descriptor_t asn_DEF_TeletexString = { OCTET_STRING_encode_xer, OCTET_STRING_decode_uper, OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 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 edcbaf19..98a4c15b 100644 --- a/skeletons/UTCTime.c +++ b/skeletons/UTCTime.c @@ -40,6 +40,8 @@ asn_TYPE_descriptor_t asn_DEF_UTCTime = { UTCTime_encode_xer, OCTET_STRING_decode_uper, OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 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 5e4f2506..4103af3e 100644 --- a/skeletons/UTF8String.c +++ b/skeletons/UTF8String.c @@ -25,6 +25,8 @@ asn_TYPE_descriptor_t asn_DEF_UTF8String = { OCTET_STRING_encode_xer_utf8, OCTET_STRING_decode_uper, OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 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 b758be02..0cffce57 100644 --- a/skeletons/UniversalString.c +++ b/skeletons/UniversalString.c @@ -35,6 +35,8 @@ asn_TYPE_descriptor_t asn_DEF_UniversalString = { UniversalString_encode_xer, /* Convert into UTF-8 */ OCTET_STRING_decode_uper, OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 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 09967db1..e6fc4238 100644 --- a/skeletons/VideotexString.c +++ b/skeletons/VideotexString.c @@ -24,6 +24,8 @@ asn_TYPE_descriptor_t asn_DEF_VideotexString = { OCTET_STRING_encode_xer, OCTET_STRING_decode_uper, /* Implemented in terms of OCTET STRING */ OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 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 baf8d0c9..20d1b217 100644 --- a/skeletons/VisibleString.c +++ b/skeletons/VisibleString.c @@ -29,6 +29,8 @@ asn_TYPE_descriptor_t asn_DEF_VisibleString = { OCTET_STRING_encode_xer_utf8, OCTET_STRING_decode_uper, OCTET_STRING_encode_uper, + OCTET_STRING_decode_aper, + OCTET_STRING_encode_aper, 0, /* Use generic outmost tag fetcher */ asn_DEF_VisibleString_tags, sizeof(asn_DEF_VisibleString_tags) diff --git a/skeletons/asn_internal.h b/skeletons/asn_internal.h index 7e0f71be..561dcf67 100644 --- a/skeletons/asn_internal.h +++ b/skeletons/asn_internal.h @@ -20,7 +20,7 @@ extern "C" { #endif /* Environment version might be used to avoid running with the old library */ -#define ASN1C_ENVIRONMENT_VERSION 923 /* Compile-time version */ +#define ASN1C_ENVIRONMENT_VERSION 924 /* Compile-time version */ int get_asn1c_environment_version(void); /* Run-time version */ #define CALLOC(nmemb, size) calloc(nmemb, size) @@ -47,13 +47,17 @@ int get_asn1c_environment_version(void); /* Run-time version */ int asn_debug_indent; #define ASN_DEBUG_INDENT_ADD(i) do { asn_debug_indent += i; } while(0) #endif /* ASN_THREAD_SAFE */ -#define ASN_DEBUG(fmt, args...) do { \ +extern int asn_debug; /* Allow option on execution */ +#define ASN_DEBUG(fmt, args...) \ +if (asn_debug) { \ + do { \ int adi = asn_debug_indent; \ while(adi--) fprintf(stderr, " "); \ fprintf(stderr, fmt, ##args); \ fprintf(stderr, " (%s:%d)\n", \ __FILE__, __LINE__); \ - } while(0) + } while(0); \ +} #else /* !__GNUC__ */ void ASN_DEBUG_f(const char *fmt, ...); #define ASN_DEBUG ASN_DEBUG_f diff --git a/skeletons/constr_CHOICE.c b/skeletons/constr_CHOICE.c index f366f754..00863a44 100644 --- a/skeletons/constr_CHOICE.c +++ b/skeletons/constr_CHOICE.c @@ -904,7 +904,88 @@ CHOICE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, elm->name, td->name, rv.code); return rv; } - + +asn_dec_rval_t +CHOICE_decode_aper(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_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; + asn_dec_rval_t rv; + asn_per_constraint_t *ct; + asn_TYPE_member_t *elm; /* CHOICE's element */ + void *memb_ptr; + void **memb_ptr2; + void *st = *sptr; + int value; + + if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) + _ASN_DECODE_FAILED; + + /* + * Create the target structure if it is not present already. + */ + if(!st) { + st = *sptr = CALLOC(1, specs->struct_size); + if(!st) _ASN_DECODE_FAILED; + } + + if(constraints) ct = &constraints->value; + else if(td->per_constraints) ct = &td->per_constraints->value; + else ct = 0; + + if(ct && ct->flags & APC_EXTENSIBLE) { + value = per_get_few_bits(pd, 1); + if(value < 0) _ASN_DECODE_STARVED; + if(value) ct = 0; /* Not restricted */ + } + + if(ct && ct->range_bits >= 0) { + value = per_get_few_bits(pd, ct->range_bits); + if(value < 0) _ASN_DECODE_STARVED; + ASN_DEBUG("CHOICE %s got index %d in range %d", + td->name, value, ct->range_bits); + if(value > ct->upper_bound) + _ASN_DECODE_FAILED; + } else { + if(specs->ext_start == -1) + _ASN_DECODE_FAILED; + value = uper_get_nsnnwn(pd); + if(value < 0) _ASN_DECODE_STARVED; + value += specs->ext_start; + if(value >= td->elements_count) + _ASN_DECODE_FAILED; + } + + /* Adjust if canonical order is different from natural order */ + if(specs->canonical_order) + value = specs->canonical_order[value]; + + /* Set presence to be able to free it later */ + _set_present_idx(st, specs->pres_offset, specs->pres_size, value + 1); + + elm = &td->elements[value]; + if(elm->flags & ATF_POINTER) { + /* Member is a pointer to another structure */ + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + ASN_DEBUG("Discovered CHOICE %s encodes %s", td->name, elm->name); + + if(ct && ct->range_bits >= 0) { + rv = elm->type->aper_decoder(opt_codec_ctx, elm->type, + elm->per_constraints, memb_ptr2, pd); + } else { + rv = uper_open_type_get(opt_codec_ctx, elm->type, + elm->per_constraints, memb_ptr2, pd); + } + + if(rv.code != RC_OK) + ASN_DEBUG("Failed to decode %s in %s (CHOICE) %d", + elm->name, td->name, rv.code); + 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) { @@ -917,7 +998,7 @@ CHOICE_encode_uper(asn_TYPE_descriptor_t *td, if(!sptr) _ASN_ENCODE_FAILED; - ASN_DEBUG("Encoding %s as CHOICE", td->name); + ASN_DEBUG("Encoding %s as CHOICE using UPER", td->name); if(constraints) ct = &constraints->value; else if(td->per_constraints) ct = &td->per_constraints->value; @@ -987,7 +1068,87 @@ CHOICE_encode_uper(asn_TYPE_descriptor_t *td, _ASN_ENCODED_OK(rval); } } - + +asn_enc_rval_t +CHOICE_encode_aper(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 using ALIGNED PER", 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; + } + + 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; + } + + if(ct && ct->range_bits >= 0) { + if(per_put_few_bits(po, present, ct->range_bits)) + _ASN_ENCODE_FAILED; + + return elm->type->aper_encoder(elm->type, elm->per_constraints, + memb_ptr, po); + } else { + asn_enc_rval_t rval; + if(specs->ext_start == -1) + _ASN_ENCODE_FAILED; + if(aper_put_nsnnwn(po, ct->range_bits, present - specs->ext_start)) + _ASN_ENCODE_FAILED; + if(aper_open_type_put(elm->type, elm->per_constraints, + memb_ptr, po)) + _ASN_ENCODE_FAILED; + rval.encoded = 0; + _ASN_ENCODED_OK(rval); + } +} 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 e824a220..ddcbb393 100644 --- a/skeletons/constr_CHOICE.h +++ b/skeletons/constr_CHOICE.h @@ -48,6 +48,8 @@ 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; +per_type_decoder_f CHOICE_decode_aper; +per_type_encoder_f CHOICE_encode_aper; asn_outmost_tag_f CHOICE_outmost_tag; #ifdef __cplusplus diff --git a/skeletons/constr_SEQUENCE.c b/skeletons/constr_SEQUENCE.c index 07dcedfb..21e51901 100644 --- a/skeletons/constr_SEQUENCE.c +++ b/skeletons/constr_SEQUENCE.c @@ -1239,6 +1239,219 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, return rv; } +asn_dec_rval_t +SEQUENCE_decode_aper(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_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; + void *st = *sptr; /* Target structure. */ + int extpresent; /* Extension additions are present */ + uint8_t *opres; /* Presence of optional root members */ + asn_per_data_t opmd; + asn_dec_rval_t rv; + int edx; + + (void)constraints; + + if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) + _ASN_DECODE_FAILED; + + if(!st) { + st = *sptr = CALLOC(1, specs->struct_size); + if(!st) _ASN_DECODE_FAILED; + } + + ASN_DEBUG("Decoding %s as SEQUENCE (APER)", td->name); + + /* Handle extensions */ + if(specs->ext_before >= 0) { + extpresent = per_get_few_bits(pd, 1); + if(extpresent < 0) _ASN_DECODE_STARVED; + } else { + extpresent = 0; + } + + /* Prepare a place and read-in the presence bitmap */ + memset(&opmd, 0, sizeof(opmd)); + if(specs->roms_count) { + opres = (uint8_t *)MALLOC(((specs->roms_count + 7) >> 3) + 1); + if(!opres) _ASN_DECODE_FAILED; + /* Get the presence map */ + if(per_get_many_bits(pd, opres, 0, specs->roms_count)) { + FREEMEM(opres); + _ASN_DECODE_STARVED; + } + opmd.buffer = opres; + opmd.nbits = specs->roms_count; + ASN_DEBUG("Read in presence bitmap for %s of %d bits (%x..)", + td->name, specs->roms_count, *opres); + } else { + opres = 0; + } + + /* + * Get the sequence ROOT elements. + */ + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + if(IN_EXTENSION_GROUP(specs, edx)) + continue; + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + memb_ptr = (char *)st + elm->memb_offset; + memb_ptr2 = &memb_ptr; + } + + /* Deal with optionality */ + if(elm->optional) { + int present = per_get_few_bits(&opmd, 1); + ASN_DEBUG("Member %s->%s is optional, p=%d (%d->%d)", + td->name, elm->name, present, + (int)opmd.nboff, (int)opmd.nbits); + if(present == 0) { + /* This element is not present */ + if(elm->default_value) { + /* Fill-in DEFAULT */ + if(elm->default_value(1, memb_ptr2)) { + FREEMEM(opres); + _ASN_DECODE_FAILED; + } + ASN_DEBUG("Filled-in default"); + } + /* The member is just not present */ + continue; + } + /* Fall through */ + } + + /* Fetch the member from the stream */ + ASN_DEBUG("Decoding member %s in %s", elm->name, td->name); + rv = elm->type->aper_decoder(opt_codec_ctx, elm->type, + elm->per_constraints, memb_ptr2, pd); + if(rv.code != RC_OK) { + ASN_DEBUG("Failed decode %s in %s", + elm->name, td->name); + FREEMEM(opres); + return rv; + } + } + + /* Optionality map is not needed anymore */ + FREEMEM(opres); + + /* + * Deal with extensions. + */ + if(extpresent) { + ssize_t bmlength; + uint8_t *epres; /* Presence of extension members */ + asn_per_data_t epmd; + + bmlength = uper_get_nslength(pd); + if(bmlength < 0) _ASN_DECODE_STARVED; + + ASN_DEBUG("Extensions %d present in %s", bmlength, td->name); + + epres = (uint8_t *)MALLOC((bmlength + 15) >> 3); + if(!epres) _ASN_DECODE_STARVED; + + /* Get the extensions map */ + if(per_get_many_bits(pd, epres, 0, bmlength)) + _ASN_DECODE_STARVED; + + memset(&epmd, 0, sizeof(epmd)); + epmd.buffer = epres; + epmd.nbits = bmlength; + ASN_DEBUG("Read in extensions bitmap for %s of %d bits (%x..)", + td->name, bmlength, *epres); + + /* Go over extensions and read them in */ + for(edx = specs->ext_after + 1; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + int present; + + if(!IN_EXTENSION_GROUP(specs, edx)) { + ASN_DEBUG("%d is not extension", edx); + continue; + } + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)st + elm->memb_offset); + } else { + memb_ptr = (void *)((char *)st + elm->memb_offset); + memb_ptr2 = &memb_ptr; + } + + present = per_get_few_bits(&epmd, 1); + if(present <= 0) { + if(present < 0) break; /* No more extensions */ + continue; + } + + ASN_DEBUG("Decoding member %s in %s %p", elm->name, td->name, *memb_ptr2); + rv = uper_open_type_get(opt_codec_ctx, elm->type, + elm->per_constraints, memb_ptr2, pd); + if(rv.code != RC_OK) { + FREEMEM(epres); + return rv; + } + } + + /* Skip over overflow extensions which aren't present + * in this system's version of the protocol */ + for(;;) { + ASN_DEBUG("Getting overflow extensions"); + switch(per_get_few_bits(&epmd, 1)) { + case -1: break; + case 0: continue; + default: + if(uper_open_type_skip(opt_codec_ctx, pd)) { + FREEMEM(epres); + _ASN_DECODE_STARVED; + } + } + break; + } + + FREEMEM(epres); + } + + /* Fill DEFAULT members in extensions */ + for(edx = specs->roms_count; edx < specs->roms_count + + specs->aoms_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + void **memb_ptr2; /* Pointer to member pointer */ + + if(!elm->default_value) continue; + + /* Fetch the pointer to this member */ + if(elm->flags & ATF_POINTER) { + memb_ptr2 = (void **)((char *)st + + elm->memb_offset); + if(*memb_ptr2) continue; + } else { + continue; /* Extensions are all optionals */ + } + + /* Set default value */ + if(elm->default_value(1, memb_ptr2)) { + _ASN_DECODE_FAILED; + } + } + + rv.consumed = 0; + rv.code = RC_OK; + return rv; +} + static int SEQUENCE_handle_extensions(asn_TYPE_descriptor_t *td, void *sptr, asn_per_outp_t *po1, asn_per_outp_t *po2) { @@ -1282,7 +1495,7 @@ SEQUENCE_handle_extensions(asn_TYPE_descriptor_t *td, void *sptr, if(po1 && per_put_few_bits(po1, present, 1)) return -1; /* Encode as open type field */ - if(po2 && present && uper_open_type_put(elm->type, + if(po2 && present && aper_open_type_put(elm->type, elm->per_constraints, *memb_ptr2, po2)) return -1; @@ -1420,3 +1633,130 @@ SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td, _ASN_ENCODED_OK(er); } +asn_enc_rval_t +SEQUENCE_encode_aper(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 n_extensions; + int edx; + int i; + + (void)constraints; + + if(!sptr) + _ASN_ENCODE_FAILED; + + er.encoded = 0; + + ASN_DEBUG("Encoding %s as SEQUENCE (APER)", td->name); + + /* + * X.691#18.1 Whether structure is extensible + * and whether to encode extensions + */ + if(specs->ext_before >= 0) { + n_extensions = SEQUENCE_handle_extensions(td, sptr, 0, 0); + per_put_few_bits(po, n_extensions ? 1 : 0, 1); + } else { + n_extensions = 0; /* There are no extensions to encode */ + } + + /* Encode a presence bitmap */ + for(i = 0; i < specs->roms_count; i++) { + asn_TYPE_member_t *elm; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + int present; + + edx = specs->oms[i]; + elm = &td->elements[edx]; + + /* 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; + } + + /* + * Encode the sequence ROOT elements. + */ + ASN_DEBUG("ext_after = %d, ec = %d, eb = %d", specs->ext_after, td->elements_count, specs->ext_before); + for(edx = 0; edx < ((specs->ext_after < 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 */ + + if(IN_EXTENSION_GROUP(specs, edx)) + continue; + + ASN_DEBUG("About to encode %s", elm->type->name); + + /* 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; + + ASN_DEBUG("Encoding %s->%s", td->name, elm->name); + er = elm->type->aper_encoder(elm->type, elm->per_constraints, + *memb_ptr2, po); + if(er.encoded == -1) + return er; + } + + /* No extensions to encode */ + if(!n_extensions) _ASN_ENCODED_OK(er); + + ASN_DEBUG("Length of %d bit-map", n_extensions); + /* #18.8. Write down the presence bit-map length. */ + if(aper_put_nslength(po, n_extensions)) + _ASN_ENCODE_FAILED; + + ASN_DEBUG("Bit-map of %d elements", n_extensions); + /* #18.7. Encoding the extensions presence bit-map. */ + /* TODO: act upon NOTE in #18.7 for canonical PER */ + if(SEQUENCE_handle_extensions(td, sptr, po, 0) != n_extensions) + _ASN_ENCODE_FAILED; + + ASN_DEBUG("Writing %d extensions", n_extensions); + /* #18.9. Encode extensions as open type fields. */ + if(SEQUENCE_handle_extensions(td, sptr, 0, po) != n_extensions) + _ASN_ENCODE_FAILED; + + _ASN_ENCODED_OK(er); +} diff --git a/skeletons/constr_SEQUENCE.h b/skeletons/constr_SEQUENCE.h index c2aeb667..d1818484 100644 --- a/skeletons/constr_SEQUENCE.h +++ b/skeletons/constr_SEQUENCE.h @@ -52,6 +52,8 @@ 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; +per_type_decoder_f SEQUENCE_decode_aper; +per_type_encoder_f SEQUENCE_encode_aper; #ifdef __cplusplus } diff --git a/skeletons/constr_SEQUENCE_OF.c b/skeletons/constr_SEQUENCE_OF.c index aa101176..6981c8bf 100644 --- a/skeletons/constr_SEQUENCE_OF.c +++ b/skeletons/constr_SEQUENCE_OF.c @@ -164,7 +164,7 @@ SEQUENCE_OF_encode_uper(asn_TYPE_descriptor_t *td, if(ct) { int not_in_root = (list->count < ct->lower_bound || list->count > ct->upper_bound); - ASN_DEBUG("lb %ld ub %ld %s", + ASN_DEBUG("lb %lld ub %lld %s", ct->lower_bound, ct->upper_bound, ct->flags & APC_EXTENSIBLE ? "ext" : "fix"); if(ct->flags & APC_EXTENSIBLE) { @@ -206,3 +206,70 @@ SEQUENCE_OF_encode_uper(asn_TYPE_descriptor_t *td, _ASN_ENCODED_OK(er); } +asn_enc_rval_t +SEQUENCE_OF_encode_aper(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 size (%d) using ALIGNED PER", 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 %lld ub %lld %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; + if (aper_put_length(po, ct->upper_bound - ct->lower_bound + 1, list->count - ct->lower_bound) < 0) + _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 = aper_put_length(po, -1, 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->aper_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 e2272f32..94a7cd54 100644 --- a/skeletons/constr_SEQUENCE_OF.h +++ b/skeletons/constr_SEQUENCE_OF.h @@ -22,9 +22,11 @@ extern "C" { #define SEQUENCE_OF_decode_ber SET_OF_decode_ber #define SEQUENCE_OF_decode_xer SET_OF_decode_xer #define SEQUENCE_OF_decode_uper SET_OF_decode_uper +#define SEQUENCE_OF_decode_aper SET_OF_decode_aper der_type_encoder_f SEQUENCE_OF_encode_der; xer_type_encoder_f SEQUENCE_OF_encode_xer; per_type_encoder_f SEQUENCE_OF_encode_uper; +per_type_encoder_f SEQUENCE_OF_encode_aper; #ifdef __cplusplus } diff --git a/skeletons/constr_SET.c b/skeletons/constr_SET.c index 1fcbc2e4..f29e4201 100644 --- a/skeletons/constr_SET.c +++ b/skeletons/constr_SET.c @@ -573,6 +573,181 @@ SET_encode_der(asn_TYPE_descriptor_t *td, _ASN_ENCODED_OK(er); } +asn_enc_rval_t +SET_encode_uper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, + void *sptr, + asn_per_outp_t *po) { +} + +asn_dec_rval_t +SET_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_enc_rval_t +SET_encode_aper(asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, + void *sptr, + asn_per_outp_t *po) { + asn_SET_specifics_t *specs = (asn_SET_specifics_t *)td->specifics; + asn_enc_rval_t er; + int edx, i; + int t2m_build_own = (specs->tag2el_count != td->elements_count); + asn_TYPE_tag2member_t *t2m; + int t2m_count; + + (void)constraints; + + if(!sptr) + _ASN_ENCODE_FAILED; + + er.encoded = 0; + + ASN_DEBUG("Encoding %s as SET (APER) map %d", td->name, specs->_mandatory_elements[0]); + + /* + * Use existing, or build our own tags map. + */ + if(t2m_build_own) { + t2m = (asn_TYPE_tag2member_t *)alloca( + td->elements_count * sizeof(t2m[0])); + if(!t2m) _ASN_ENCODE_FAILED; /* There are such platforms */ + t2m_count = 0; + } else { + /* + * There is no untagged CHOICE in this SET. + * Employ existing table. + */ + t2m = specs->tag2el; + t2m_count = specs->tag2el_count; + } + + /* + * Gather the length of the underlying members sequence. + */ + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + asn_enc_rval_t tmper; + void *memb_ptr; + + /* + * Compute the length of the encoding of this member. + */ + if(elm->flags & ATF_POINTER) { + memb_ptr = *(void **)((char *)sptr + elm->memb_offset); + if(!memb_ptr) { + if(!elm->optional) + /* Mandatory elements missing */ + _ASN_ENCODE_FAILED; + if(t2m_build_own) { + t2m[t2m_count].el_no = edx; + t2m[t2m_count].el_tag = 0; + t2m_count++; + } + continue; + } + } else { + memb_ptr = (void *)((char *)sptr + elm->memb_offset); + } + + /* + * Remember the outmost tag of this member. + */ + if(t2m_build_own) { + t2m[t2m_count].el_no = edx; + t2m[t2m_count].el_tag = asn_TYPE_outmost_tag( + elm->type, memb_ptr, elm->tag_mode, elm->tag); + t2m_count++; + } else { + /* + * No dynamic sorting is necessary. + */ + } + } + + /* + * Finalize order of the components. + */ + assert(t2m_count == td->elements_count); + if(t2m_build_own) { + /* + * Sort the underlying members according to their + * canonical tags order. DER encoding mandates it. + */ + qsort(t2m, t2m_count, sizeof(specs->tag2el[0]), _t2e_cmp); + } else { + /* + * Tags are already sorted by the compiler. + */ + } + + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[t2m[edx].el_no]; + asn_enc_rval_t tmper; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + 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; + continue; + } + +// /* 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 << 7, 8)) + _ASN_ENCODE_FAILED; + } + + /* + * Encode all members. + */ + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + asn_enc_rval_t tmper; + void *memb_ptr; /* Pointer to the member */ + void **memb_ptr2; /* Pointer to that pointer */ + + /* Encode according to the tag order */ +// elm = &td->elements[t2m[edx].el_no]; + + 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; + } + tmper = elm->type->aper_encoder(elm->type, elm->per_constraints, + *memb_ptr2, po); + if(tmper.encoded == -1) + return tmper; + } + + _ASN_ENCODED_OK(er); +} + #undef XER_ADVANCE #define XER_ADVANCE(num_bytes) do { \ size_t num = num_bytes; \ diff --git a/skeletons/constr_SET.h b/skeletons/constr_SET.h index 6a3a1aa9..11b7153e 100644 --- a/skeletons/constr_SET.h +++ b/skeletons/constr_SET.h @@ -53,7 +53,9 @@ der_type_encoder_f SET_encode_der; xer_type_decoder_f SET_decode_xer; xer_type_encoder_f SET_encode_xer; per_type_decoder_f SET_decode_uper; +per_type_decoder_f SET_decode_aper; per_type_encoder_f SET_encode_uper; +per_type_encoder_f SET_encode_aper; /*********************** * Some handy helpers. * diff --git a/skeletons/constr_SET_OF.c b/skeletons/constr_SET_OF.c index b68d7ca1..bc294554 100644 --- a/skeletons/constr_SET_OF.c +++ b/skeletons/constr_SET_OF.c @@ -884,7 +884,7 @@ SET_OF_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, if(!st) { st = *sptr = CALLOC(1, specs->struct_size); if(!st) _ASN_DECODE_FAILED; - } + } list = _A_SET_FROM_VOID(st); /* Figure out which constraints to use */ @@ -901,7 +901,7 @@ SET_OF_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, if(ct && ct->effective_bits >= 0) { /* X.691, #19.5: No length determinant */ nelems = per_get_few_bits(pd, ct->effective_bits); - ASN_DEBUG("Preparing to fetch %ld+%ld elements from %s", + ASN_DEBUG("Preparing to fetch %ld+%lld elements from %s", (long)nelems, ct->lower_bound, td->name); if(nelems < 0) _ASN_DECODE_STARVED; nelems += ct->lower_bound; @@ -951,3 +951,91 @@ SET_OF_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, return rv; } +asn_dec_rval_t +SET_OF_decode_aper(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_dec_rval_t rv; + asn_SET_OF_specifics_t *specs = (asn_SET_OF_specifics_t *)td->specifics; + asn_TYPE_member_t *elm = td->elements; /* Single one */ + void *st = *sptr; + asn_anonymous_set_ *list; + asn_per_constraint_t *ct; + int repeat = 0; + ssize_t nelems; + + if(_ASN_STACK_OVERFLOW_CHECK(opt_codec_ctx)) + _ASN_DECODE_FAILED; + + /* + * Create the target structure if it is not present already. + */ + if(!st) { + st = *sptr = CALLOC(1, specs->struct_size); + if(!st) _ASN_DECODE_FAILED; + } + list = _A_SET_FROM_VOID(st); + + /* Figure out which constraints to use */ + if(constraints) ct = &constraints->size; + else if(td->per_constraints) ct = &td->per_constraints->size; + else ct = 0; + + if(ct && ct->flags & APC_EXTENSIBLE) { + int value = per_get_few_bits(pd, 1); + if(value < 0) _ASN_DECODE_STARVED; + if(value) ct = 0; /* Not restricted! */ + } + + if(ct && ct->effective_bits >= 0) { + /* X.691, #19.5: No length determinant */ +// nelems = per_get_few_bits(pd, ct->effective_bits); + nelems = aper_get_nsnnwn(pd, ct->upper_bound - ct->lower_bound); + ASN_DEBUG("Preparing to fetch %ld+%lld elements from %s", + (long)nelems, ct->lower_bound, td->name); + if(nelems < 0) _ASN_DECODE_STARVED; + nelems += ct->lower_bound; + } else { + nelems = -1; + } + + do { + int i; + if(nelems < 0) { + nelems = aper_get_length(pd, ct ? ct->upper_bound - ct->lower_bound + 1 : -1, + ct ? ct->effective_bits : -1, &repeat); + ASN_DEBUG("Got to decode %d elements (eff %d)", + (int)nelems, (int)ct ? ct->effective_bits : -1); + if(nelems < 0) _ASN_DECODE_STARVED; + } + + for(i = 0; i < nelems; i++) { + void *ptr = 0; + ASN_DEBUG("SET OF %s decoding", elm->type->name); + rv = elm->type->aper_decoder(opt_codec_ctx, elm->type, + elm->per_constraints, &ptr, pd); + ASN_DEBUG("%s SET OF %s decoded %d, %p", + td->name, elm->type->name, rv.code, ptr); + if(rv.code == RC_OK) { + if(ASN_SET_ADD(list, ptr) == 0) + continue; + ASN_DEBUG("Failed to add element into %s", + td->name); + /* Fall through */ + rv.code = RC_FAIL; + } else { + ASN_DEBUG("Failed decoding %s of %s (SET OF)", + elm->type->name, td->name); + } + if(ptr) ASN_STRUCT_FREE(*elm->type, ptr); + return rv; + } + + nelems = -1; /* Allow uper_get_length() */ + } while(repeat); + + ASN_DEBUG("Decoded %s as SET OF", td->name); + + rv.code = RC_OK; + rv.consumed = 0; + return rv; +} diff --git a/skeletons/constr_SET_OF.h b/skeletons/constr_SET_OF.h index 75e18cfa..8ddd0e3b 100644 --- a/skeletons/constr_SET_OF.h +++ b/skeletons/constr_SET_OF.h @@ -34,6 +34,8 @@ 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; +per_type_decoder_f SET_OF_decode_aper; +per_type_encoder_f SET_OF_encode_aper; #ifdef __cplusplus } diff --git a/skeletons/constr_TYPE.h b/skeletons/constr_TYPE.h index a9cd86dc..13c60f33 100644 --- a/skeletons/constr_TYPE.h +++ b/skeletons/constr_TYPE.h @@ -99,6 +99,8 @@ typedef struct asn_TYPE_descriptor_s { 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 */ + per_type_decoder_f *aper_decoder; /* Aligned PER decoder */ + per_type_encoder_f *aper_encoder; /* Aligned PER encoder */ /*********************************************************************** * Internally useful members. Not to be used by applications directly. * diff --git a/skeletons/per_decoder.c b/skeletons/per_decoder.c index 220d7f9f..20fe1a1d 100644 --- a/skeletons/per_decoder.c +++ b/skeletons/per_decoder.c @@ -36,6 +36,35 @@ uper_decode_complete(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, return rval; } +asn_dec_rval_t +aper_decode_complete(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size) { + asn_dec_rval_t rval; + + rval = aper_decode(opt_codec_ctx, td, sptr, buffer, size, 0, 0); + if(rval.consumed) { + /* + * We've always given 8-aligned data, + * so convert bits to integral bytes. + */ + rval.consumed += 7; + rval.consumed >>= 3; + } else if(rval.code == RC_OK) { + if(size) { + if(((uint8_t *)buffer)[0] == 0) { + rval.consumed = 1; /* 1 byte */ + } else { + ASN_DEBUG("Expecting single zeroed byte"); + rval.code = RC_FAIL; + } + } else { + /* Must contain at least 8 bits. */ + rval.code = RC_WMORE; + } + } + + return rval; +} + asn_dec_rval_t uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size, int skip_bits, int unused_bits) { asn_codec_ctx_t s_codec_ctx; @@ -91,3 +120,57 @@ uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sp return rval; } +asn_dec_rval_t +aper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size, int skip_bits, int unused_bits) { + asn_codec_ctx_t s_codec_ctx; + asn_dec_rval_t rval; + asn_per_data_t pd; + + if(skip_bits < 0 || skip_bits > 7 + || unused_bits < 0 || unused_bits > 7 + || (unused_bits > 0 && !size)) + _ASN_DECODE_FAILED; + + /* + * Stack checker requires that the codec context + * must be allocated on the stack. + */ + if(opt_codec_ctx) { + if(opt_codec_ctx->max_stack_size) { + s_codec_ctx = *opt_codec_ctx; + opt_codec_ctx = &s_codec_ctx; + } + } else { + /* If context is not given, be security-conscious anyway */ + memset(&s_codec_ctx, 0, sizeof(s_codec_ctx)); + s_codec_ctx.max_stack_size = _ASN_DEFAULT_STACK_MAX; + opt_codec_ctx = &s_codec_ctx; + } + + /* Fill in the position indicator */ + memset(&pd, 0, sizeof(pd)); + pd.buffer = (const uint8_t *)buffer; + pd.nboff = skip_bits; + pd.nbits = 8 * size - unused_bits; /* 8 is CHAR_BIT from */ + if(pd.nboff > pd.nbits) + _ASN_DECODE_FAILED; + + /* + * Invoke type-specific decoder. + */ + if(!td->aper_decoder) + _ASN_DECODE_FAILED; /* PER is not compiled in */ + rval = td->aper_decoder(opt_codec_ctx, td, 0, sptr, &pd); + if(rval.code == RC_OK) { + /* Return the number of consumed bits */ + rval.consumed = ((pd.buffer - (const uint8_t *)buffer) << 3) + + pd.nboff - skip_bits; + ASN_DEBUG("PER decoding consumed %d, counted %d", + rval.consumed, pd.moved); + assert(rval.consumed == pd.moved); + } else { + /* PER codec is not a restartable */ + rval.consumed = 0; + } + return rval; +} diff --git a/skeletons/per_decoder.h b/skeletons/per_decoder.h index 8397a545..5541bae8 100644 --- a/skeletons/per_decoder.h +++ b/skeletons/per_decoder.h @@ -38,7 +38,29 @@ asn_dec_rval_t uper_decode(struct asn_codec_ctx_s *opt_codec_ctx, int unused_bits /* Number of unused tailing bits, 0..7 */ ); +/* + * Aligned PER decoder of a "complete encoding" as per X.691#10.1. + * On success, this call always returns (.consumed >= 1), as per X.691#10.1.3. + */ +asn_dec_rval_t aper_decode_complete(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size /* Size of data buffer */ + ); +/* + * Aligned PER decoder of any ASN.1 type. May be invoked by the application. + * WARNING: This call returns the number of BITS read from the stream. Beware. + */ +asn_dec_rval_t aper_decode(struct asn_codec_ctx_s *opt_codec_ctx, + struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ + void **struct_ptr, /* Pointer to a target structure's pointer */ + const void *buffer, /* Data to be decoded */ + size_t size, /* Size of data buffer */ + int skip_bits, /* Number of unused leading bits, 0..7 */ + int unused_bits /* Number of unused tailing bits, 0..7 */ + ); /* * Type of the type-specific PER decoder function. */ diff --git a/skeletons/per_encoder.c b/skeletons/per_encoder.c index e76ef74a..02dc3a22 100644 --- a/skeletons/per_encoder.c +++ b/skeletons/per_encoder.c @@ -4,6 +4,7 @@ static asn_enc_rval_t uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *, void *sptr, asn_app_consume_bytes_f *cb, void *app_key); +static asn_enc_rval_t aper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *, void *sptr, asn_app_consume_bytes_f *cb, void *app_key); asn_enc_rval_t uper_encode(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { return uper_encode_internal(td, 0, sptr, cb, app_key); @@ -41,6 +42,18 @@ uper_encode_to_buffer(asn_TYPE_descriptor_t *td, void *sptr, void *buffer, size_ return uper_encode_internal(td, 0, sptr, encode_to_buffer_cb, &key); } +asn_enc_rval_t +aper_encode_to_buffer(asn_TYPE_descriptor_t *td, void *sptr, void *buffer, size_t buffer_size) { + enc_to_buf_arg key; + + key.buffer = buffer; + key.left = buffer_size; + + if(td) ASN_DEBUG("Encoding \"%s\" using ALIGNED PER", td->name); + + return aper_encode_internal(td, 0, sptr, encode_to_buffer_cb, &key); +} + typedef struct enc_dyn_arg { void *buffer; size_t length; @@ -93,6 +106,35 @@ uper_encode_to_new_buffer(asn_TYPE_descriptor_t *td, asn_per_constraints_t *cons } } +ssize_t +aper_encode_to_new_buffer(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, void **buffer_r) { + asn_enc_rval_t er; + enc_dyn_arg key; + + memset(&key, 0, sizeof(key)); + + er = aper_encode_internal(td, constraints, sptr, encode_dyn_cb, &key); + switch(er.encoded) { + case -1: + FREEMEM(key.buffer); + return -1; + case 0: + FREEMEM(key.buffer); + key.buffer = MALLOC(1); + if(key.buffer) { + *(char *)key.buffer = '\0'; + *buffer_r = key.buffer; + return 1; + } else { + return -1; + } + default: + *buffer_r = key.buffer; + ASN_DEBUG("Complete encoded in %d bits", er.encoded); + return ((er.encoded + 7) >> 3); + } +} + /* * Internally useful functions. */ @@ -115,6 +157,23 @@ _uper_encode_flush_outp(asn_per_outp_t *po) { return po->outper(po->tmpspace, buf - po->tmpspace, po->op_key); } +static int +_aper_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); +} + static asn_enc_rval_t uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { asn_per_outp_t po; @@ -149,3 +208,37 @@ uper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constrain return er; } +static asn_enc_rval_t +aper_encode_internal(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, 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->aper_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; + po.flushed_bytes = 0; + + er = td->aper_encoder(td, constraints, sptr, &po); + if(er.encoded != -1) { + size_t bits_to_flush; + + bits_to_flush = ((po.buffer - po.tmpspace) << 3) + po.nboff; + + /* Set number of bits encoded to a firm value */ + er.encoded = (po.flushed_bytes << 3) + bits_to_flush; + + if(_aper_encode_flush_outp(&po)) + _ASN_ENCODE_FAILED; + } + + return er; +} + diff --git a/skeletons/per_encoder.h b/skeletons/per_encoder.h index 95a6506e..e3b9190b 100644 --- a/skeletons/per_encoder.h +++ b/skeletons/per_encoder.h @@ -38,6 +38,12 @@ asn_enc_rval_t uper_encode_to_buffer( size_t buffer_size /* Initial buffer size (max) */ ); +asn_enc_rval_t aper_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) */ +); /* * A variant of uper_encode_to_buffer() which allocates buffer itself. * Returns the number of bytes in the buffer or -1 in case of failure. @@ -52,6 +58,11 @@ ssize_t uper_encode_to_new_buffer( void **buffer_r /* Buffer allocated and returned */ ); +ssize_t +aper_encode_to_new_buffer(struct asn_TYPE_descriptor_s *td, + asn_per_constraints_t *constraints, + void *sptr, + void **buffer_r); /* * Type of the generic PER encoder function. */ diff --git a/skeletons/per_opentype.c b/skeletons/per_opentype.c index ec404cf9..984a96dd 100644 --- a/skeletons/per_opentype.c +++ b/skeletons/per_opentype.c @@ -53,6 +53,35 @@ uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints return 0; } +int +aper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + void *buf; + void *bptr; + ssize_t size; + size_t toGo; + + ASN_DEBUG("Open type put %s ...", td->name); + + size = aper_encode_to_new_buffer(td, constraints, sptr, &buf); + if(size <= 0) return -1; + + for(bptr = buf, toGo = size; toGo;) { + ssize_t maySave = aper_put_length(po, -1, toGo); + if(maySave < 0) break; + if(per_put_many_bits(po, bptr, maySave * 8)) break; + bptr = (char *)bptr + maySave; + toGo -= maySave; + } + + FREEMEM(buf); + if(toGo) return -1; + + ASN_DEBUG("Open type put %s of length %d + overhead (1byte?)", + td->name, size); + + return 0; +} + static asn_dec_rval_t uper_open_type_get_simple(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { diff --git a/skeletons/per_opentype.h b/skeletons/per_opentype.h index facfaa63..2117efe6 100644 --- a/skeletons/per_opentype.h +++ b/skeletons/per_opentype.h @@ -15,6 +15,8 @@ int uper_open_type_skip(asn_codec_ctx_t *opt_codec_ctx, asn_per_data_t *pd); int uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po); +int aper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po); + #ifdef __cplusplus } #endif diff --git a/skeletons/per_support.c b/skeletons/per_support.c index 0d089f49..d536bc0d 100644 --- a/skeletons/per_support.c +++ b/skeletons/per_support.c @@ -31,6 +31,16 @@ per_get_undo(asn_per_data_t *pd, int nbits) { } } +int32_t +aper_get_align(asn_per_data_t *pd) { + + if(pd->nboff & 0x7) { + ASN_DEBUG("Aligning %d bits", 8 - (pd->nboff & 0x7)); + return per_get_few_bits(pd, 8 - (pd->nboff & 0x7)); + } + return 0; +} + /* * Extract a small number of bits (<= 31) from the specified PER data pointer. */ @@ -104,7 +114,7 @@ per_get_few_bits(asn_per_data_t *pd, int nbits) { accum &= (((uint32_t)1 << nbits) - 1); - ASN_DEBUG(" [PER got %2d<=%2d bits => span %d %+ld[%d..%d]:%02x (%d) => 0x%x]", + ASN_DEBUG(" [PER got %2d<=%2d bits => span %d %+ld[%d..%d]:%02x (%d) => 0x%02x]", (int)nbits, (int)nleft, (int)pd->moved, (((long)pd->buffer) & 0xf), @@ -123,6 +133,8 @@ int per_get_many_bits(asn_per_data_t *pd, uint8_t *dst, int alright, int nbits) { int32_t value; + ASN_DEBUG("align: %s, nbits %d", alright ? "YES":"NO", nbits); + if(alright && (nbits & 7)) { /* Perform right alignment of a first few bits */ value = per_get_few_bits(pd, nbits & 0x07); @@ -187,6 +199,36 @@ uper_get_length(asn_per_data_t *pd, int ebits, int *repeat) { return (16384 * value); } +ssize_t +aper_get_length(asn_per_data_t *pd, int range, int ebits, int *repeat) { + ssize_t value; + + *repeat = 0; + + if (range <= 65536 && range >= 0) + return aper_get_nsnnwn(pd, range); + + if (aper_get_align(pd) < 0) + return -1; + + if(ebits >= 0) return per_get_few_bits(pd, ebits); + + value = per_get_few_bits(pd, 8); + if(value < 0) return -1; + if((value & 128) == 0) /* #10.9.3.6 */ + return (value & 0x7F); + if((value & 64) == 0) { /* #10.9.3.7 */ + value = ((value & 63) << 8) | per_get_few_bits(pd, 8); + if(value < 0) return -1; + return value; + } + value &= 63; /* this is "m" from X.691, #10.9.3.8 */ + if(value < 1 || value > 4) + return -1; + *repeat = 1; + return (16384 * value); +} + /* * Get the normally small length "n". * This procedure used to decode length of extensions bit-maps @@ -211,6 +253,25 @@ uper_get_nslength(asn_per_data_t *pd) { } } +ssize_t +aper_get_nslength(asn_per_data_t *pd) { + ssize_t length; + + ASN_DEBUG("Getting normally small length"); + + if(per_get_few_bits(pd, 1) == 0) { + length = per_get_few_bits(pd, 6) + 1; + if(length <= 0) return -1; + ASN_DEBUG("l=%d", length); + return length; + } else { + int repeat; + length = aper_get_length(pd, -1, -1, &repeat); + if(length >= 0 && !repeat) return length; + return -1; /* Error, or do not support >16K extensions */ + } +} + /* * Get the normally small non-negative whole number. * X.691, #10.6 @@ -237,6 +298,40 @@ uper_get_nsnnwn(asn_per_data_t *pd) { return value; } +ssize_t +aper_get_nsnnwn(asn_per_data_t *pd, int range) { + ssize_t value; + int bytes = 0; + + ASN_DEBUG("getting nsnnwn with range %d", range); + + if(range <= 255) { + if (range < 0) return -1; + /* 1 -> 8 bits */ + int i; + for (i = 1; i <= 8; i++) { + int upper = 1 << i; + if (upper >= range) + break; + } + value = per_get_few_bits(pd, i); + return value; + } else if (range == 256){ + /* 1 byte */ + bytes = 1; + return -1; + } else if (range <= 65536) { + /* 2 bytes */ + bytes = 2; + } else { + return -1; + } + if (aper_get_align(pd) < 0) + return -1; + value = per_get_few_bits(pd, 8 * bytes); + return value; +} + /* * X.691-11/2008, #11.6 * Encoding of a normally small non-negative whole number @@ -245,6 +340,7 @@ int uper_put_nsnnwn(asn_per_outp_t *po, int n) { int bytes; + ASN_DEBUG("uper put nsnnwn n %d", n); if(n <= 63) { if(n < 0) return -1; return per_put_few_bits(po, n, 7); @@ -405,6 +501,61 @@ per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) { return 0; } +int +aper_put_nsnnwn(asn_per_outp_t *po, int range, int number) { + int bytes; + + ASN_DEBUG("aper put nsnnwn %d with range %d", number, range); + /* 10.5.7.1 X.691 */ + if(range < 0) { + int i; + for (i = 1; ; i++) { + int bits = 1 << (8 * i); + if (number <= bits) + break; + } + bytes = i; + assert(i <= 4); + } + if(range <= 255) { + int i; + for (i = 1; i <= 8; i++) { + int bits = 1 << i; + if (range <= bits) + break; + } + return per_put_few_bits(po, number, i); + } else if(range == 256) { + bytes = 1; + } else if(range <= 65536) { + bytes = 2; + } else { /* Ranges > 64K */ + int i; + for (i = 1; ; i++) { + int bits = 1 << (8 * i); + if (range <= bits) + break; + } + assert(i <= 4); + bytes = i; + } + if(aper_put_align(po) < 0) /* Aligning on octet */ + return -1; +// if(per_put_few_bits(po, bytes, 8)) +// return -1; + + return per_put_few_bits(po, number, 8 * bytes); +} + +int aper_put_align(asn_per_outp_t *po) { + + if(po->nboff & 0x7) { + ASN_DEBUG("Aligning %d bits", 8 - (po->nboff & 0x7)); + if(per_put_few_bits(po, 0x00, (8 - (po->nboff & 0x7)))) + return -1; + } + return 0; +} /* * Output a large number of bits. @@ -444,6 +595,8 @@ per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int nbits) { ssize_t uper_put_length(asn_per_outp_t *po, size_t length) { + ASN_DEBUG("UPER put length %d", length); + if(length <= 127) /* #10.9.3.6 */ return per_put_few_bits(po, length, 8) ? -1 : (ssize_t)length; @@ -458,6 +611,33 @@ uper_put_length(asn_per_outp_t *po, size_t length) { ? -1 : (ssize_t)(length << 14); } +ssize_t +aper_put_length(asn_per_outp_t *po, int range, size_t length) { + + ASN_DEBUG("APER put length %d with range %d", length, range); + + /* 10.9 X.691 Note 2 */ + if (range <= 65536 && range >= 0) + return aper_put_nsnnwn(po, range, length); + + if (aper_put_align(po) < 0) + return -1; + + 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); +} + /* * Put the normally small length "n" into the stream. @@ -481,3 +661,19 @@ uper_put_nslength(asn_per_outp_t *po, size_t length) { return 0; } +int +aper_put_nslength(asn_per_outp_t *po, size_t length) { + + if(length <= 64) { + /* #10.9.3.4 */ + if(length == 0) return -1; + return per_put_few_bits(po, length-1, 7) ? -1 : 0; + } else { + if(aper_put_length(po, -1, length) != (ssize_t)length) { + /* This might happen in case of >16K extensions */ + return -1; + } + } + + return 0; +} diff --git a/skeletons/per_support.h b/skeletons/per_support.h index a75ac94f..181fe248 100644 --- a/skeletons/per_support.h +++ b/skeletons/per_support.h @@ -24,8 +24,8 @@ typedef const struct asn_per_constraint_s { } flags; int range_bits; /* Full number of bits in the range */ int effective_bits; /* Effective bits */ - long lower_bound; /* "lb" value */ - long upper_bound; /* "ub" value */ + int64_t lower_bound; /* "lb" value */ + int64_t upper_bound; /* "ub" value */ } asn_per_constraint_t; typedef const struct asn_per_constraints_s { struct asn_per_constraint_s value; @@ -39,9 +39,9 @@ typedef const struct asn_per_constraints_s { */ typedef struct asn_per_data_s { const uint8_t *buffer; /* Pointer to the octet stream */ - size_t nboff; /* Bit offset to the meaningful bit */ - size_t nbits; /* Number of bits in the stream */ - size_t moved; /* Number of bits moved through this bit stream */ + size_t nboff; /* Bit offset to the meaningful bit */ + size_t nbits; /* Number of bits in the stream */ + size_t moved; /* Number of bits moved through this bit stream */ int (*refill)(struct asn_per_data_s *); void *refill_key; } asn_per_data_t; @@ -71,15 +71,22 @@ ssize_t uper_get_length(asn_per_data_t *pd, int effective_bound_bits, int *repeat); +ssize_t aper_get_length(asn_per_data_t *pd, + int range, + int effective_bound_bits, + int *repeat); + /* * Get the normally small length "n". */ ssize_t uper_get_nslength(asn_per_data_t *pd); +ssize_t aper_get_nslength(asn_per_data_t *pd); /* * Get the normally small non-negative whole number. */ ssize_t uper_get_nsnnwn(asn_per_data_t *pd); +ssize_t aper_get_nsnnwn(asn_per_data_t *pd, int range); /* X.691-2008/11, #11.5.6 */ int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *v, int nbits); @@ -110,6 +117,10 @@ int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits); 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); +/* Align the current bit position to octet bundary */ +int aper_put_align(asn_per_outp_t *po); +int32_t aper_get_align(asn_per_data_t *pd); + /* * Put the length "n" to the Unaligned PER stream. * This function returns the number of units which may be flushed @@ -117,17 +128,23 @@ int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int */ ssize_t uper_put_length(asn_per_outp_t *po, size_t whole_length); +ssize_t aper_put_length(asn_per_outp_t *po, int range, size_t length); + /* * Put the normally small length "n" to the Unaligned PER stream. * Returns 0 or -1. */ int uper_put_nslength(asn_per_outp_t *po, size_t length); +int aper_put_nslength(asn_per_outp_t *po, size_t length); + /* * Put the normally small non-negative whole number. */ int uper_put_nsnnwn(asn_per_outp_t *po, int n); +int aper_put_nsnnwn(asn_per_outp_t *po, int range, int number); + #ifdef __cplusplus } #endif -- cgit v1.2.3