From 41b85d5597119fa8105dc0641ffe5cd1bbae39b2 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 31 Aug 2015 08:56:53 +0200 Subject: update to asn1c aper branch commit 6e00cbce7304a6972e82a12bb5fa82e41fa541be which is closes to Lev Walkins master 62913d8b8e1eb96d74315ff748475ca818b69752 --- asn1c-talloc.patch | 16 +- configure.ac | 2 +- include/asn1c/ANY.h | 3 + include/asn1c/BOOLEAN.h | 2 + include/asn1c/ENUMERATED.h | 2 + include/asn1c/INTEGER.h | 27 +- include/asn1c/NULL.h | 2 + include/asn1c/NativeEnumerated.h | 2 + include/asn1c/NativeInteger.h | 2 + include/asn1c/NativeReal.h | 2 + include/asn1c/OBJECT_IDENTIFIER.h | 8 +- include/asn1c/OCTET_STRING.h | 4 +- include/asn1c/REAL.h | 2 + include/asn1c/RELATIVE-OID.h | 2 +- include/asn1c/asn_codecs.h | 4 +- include/asn1c/asn_internal.h | 19 +- include/asn1c/asn_system.h | 12 +- include/asn1c/constr_CHOICE.h | 6 +- include/asn1c/constr_SEQUENCE.h | 8 +- include/asn1c/constr_SEQUENCE_OF.h | 2 + include/asn1c/constr_SET.h | 10 +- include/asn1c/constr_SET_OF.h | 4 +- include/asn1c/constr_TYPE.h | 20 +- include/asn1c/per_decoder.h | 22 + include/asn1c/per_encoder.h | 11 + include/asn1c/per_opentype.h | 2 + include/asn1c/per_support.h | 44 +- include/asn1c/xer_decoder.h | 7 +- src/ANY.c | 87 +++- src/BIT_STRING.c | 6 +- src/BMPString.c | 6 +- src/BOOLEAN.c | 58 ++- src/ENUMERATED.c | 36 +- src/GeneralString.c | 4 +- src/GeneralizedTime.c | 37 +- src/GraphicString.c | 4 +- src/IA5String.c | 4 +- src/INTEGER.c | 815 ++++++++++++++++++++++++++++++------- src/ISO646String.c | 4 +- src/Makefile.am | 2 +- src/NULL.c | 56 ++- src/NativeEnumerated.c | 130 +++++- src/NativeInteger.c | 72 +++- src/NativeReal.c | 104 ++++- src/NumericString.c | 4 +- src/OBJECT_IDENTIFIER.c | 131 +++--- src/OCTET_STRING.c | 405 ++++++++++++++++-- src/ObjectDescriptor.c | 4 +- src/PrintableString.c | 10 +- src/REAL.c | 125 ++++-- src/RELATIVE-OID.c | 16 +- src/T61String.c | 4 +- src/TeletexString.c | 4 +- src/UTCTime.c | 4 +- src/UTF8String.c | 8 +- src/UniversalString.c | 4 +- src/VideotexString.c | 4 +- src/VisibleString.c | 4 +- src/asn_codecs_prim.c | 45 +- src/ber_decoder.c | 2 +- src/constr_CHOICE.c | 194 ++++++++- src/constr_SEQUENCE.c | 355 +++++++++++++++- src/constr_SEQUENCE_OF.c | 69 +++- src/constr_SET.c | 218 +++++++++- src/constr_SET_OF.c | 94 ++++- src/constr_TYPE.c | 2 +- src/der_encoder.c | 14 +- src/per_decoder.c | 87 +++- src/per_encoder.c | 95 ++++- src/per_opentype.c | 102 +++-- src/per_support.c | 307 ++++++++++++-- src/xer_decoder.c | 14 +- src/xer_support.c | 16 +- 73 files changed, 3489 insertions(+), 524 deletions(-) diff --git a/asn1c-talloc.patch b/asn1c-talloc.patch index 909772f..87bb44b 100644 --- a/asn1c-talloc.patch +++ b/asn1c-talloc.patch @@ -1,18 +1,16 @@ -diff --git a/include/asn1c/asn_internal.h b/include/asn1c/asn_internal.h -index 67f055a..45b1adb 100644 ---- a/include/asn1c/asn_internal.h -+++ b/include/asn1c/asn_internal.h +--- ../asn1c/skeletons/asn_internal.h 2015-08-31 09:29:45.590924282 +0200 ++++ include/asn1c/asn_internal.h 2015-08-31 09:26:17.461872713 +0200 @@ -15,6 +15,8 @@ #include /* for assert() macro */ #endif -+#include ++#include + #ifdef __cplusplus extern "C" { #endif -@@ -23,10 +25,12 @@ extern "C" { - #define ASN1C_ENVIRONMENT_VERSION 920 /* Compile-time version */ +@@ -23,10 +25,12 @@ + #define ASN1C_ENVIRONMENT_VERSION 924 /* Compile-time version */ int get_asn1c_environment_version(void); /* Run-time version */ -#define CALLOC(nmemb, size) calloc(nmemb, size) @@ -26,5 +24,5 @@ index 67f055a..45b1adb 100644 +#define REALLOC(oldptr, size) talloc_realloc_size(talloc_asn1_ctx, oldptr, size) +#define FREEMEM(ptr) talloc_free(ptr) - /* - * A macro for debugging the ASN.1 internals. + #define asn_debug_indent 0 + #define ASN_DEBUG_INDENT_ADD(i) do{}while(0) diff --git a/configure.ac b/configure.ac index ce5140a..b8b5743 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT([libasn1c], [0.9.21], +AC_INIT([libasn1c], [0.9.28], [openbsc-devel@lists.openbsc.org]) AM_INIT_AUTOMAKE([dist-bzip2]) diff --git a/include/asn1c/ANY.h b/include/asn1c/ANY.h index b7d92fa..a68441d 100644 --- a/include/asn1c/ANY.h +++ b/include/asn1c/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/include/asn1c/BOOLEAN.h b/include/asn1c/BOOLEAN.h index 217d0f1..8ea2892 100644 --- a/include/asn1c/BOOLEAN.h +++ b/include/asn1c/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/include/asn1c/ENUMERATED.h b/include/asn1c/ENUMERATED.h index 542dcae..5c4a2ed 100644 --- a/include/asn1c/ENUMERATED.h +++ b/include/asn1c/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/include/asn1c/INTEGER.h b/include/asn1c/INTEGER.h index 8411bfc..e8b36c7 100644 --- a/include/asn1c/INTEGER.h +++ b/include/asn1c/INTEGER.h @@ -18,15 +18,15 @@ 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; /* This type describes an enumeration for INTEGER and ENUMERATED types */ -typedef struct asn_INTEGER_specifics_s { - asn_INTEGER_enum_map_t *value2enum; /* N -> "tag"; sorted by N */ - unsigned int *enum2value; /* "tag" => N; sorted by tag */ +typedef const struct asn_INTEGER_specifics_s { + const asn_INTEGER_enum_map_t *value2enum; /* N -> "tag"; sorted by N */ + const unsigned int *enum2value; /* "tag" => N; sorted by tag */ int map_count; /* Elements in either map */ int extension; /* This map is extensible */ int strict_enumeration; /* Enumeration set is fixed */ @@ -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,11 +54,28 @@ 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); +/* A a reified version of strtol(3) with nicer error reporting. */ +enum asn_strtol_result_e { + ASN_STRTOL_ERROR_RANGE = -3, /* Input outside of numeric range for long type */ + ASN_STRTOL_ERROR_INVAL = -2, /* Invalid data encountered (e.g., "+-") */ + ASN_STRTOL_EXPECT_MORE = -1, /* More data expected (e.g. "+") */ + ASN_STRTOL_OK = 0, /* Conversion succeded, number ends at (*end) */ + ASN_STRTOL_EXTRA_DATA = 1, /* Conversion succeded, but the string has extra stuff */ +}; +enum asn_strtol_result_e asn_strtol_lim(const char *str, const char **end, long *l); + +/* The asn_strtol is going to be DEPRECATED soon */ +enum asn_strtol_result_e asn_strtol(const char *str, const char *end, long *l); + /* * Convert the integer value into the corresponding enumeration map entry. */ diff --git a/include/asn1c/NULL.h b/include/asn1c/NULL.h index 131e775..90784d8 100644 --- a/include/asn1c/NULL.h +++ b/include/asn1c/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/include/asn1c/NativeEnumerated.h b/include/asn1c/NativeEnumerated.h index b5acc71..9db2611 100644 --- a/include/asn1c/NativeEnumerated.h +++ b/include/asn1c/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; asn_struct_print_f NativeEnumerated_print; #ifdef __cplusplus diff --git a/include/asn1c/NativeInteger.h b/include/asn1c/NativeInteger.h index 4e63a83..14aa1a4 100644 --- a/include/asn1c/NativeInteger.h +++ b/include/asn1c/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/include/asn1c/NativeReal.h b/include/asn1c/NativeReal.h index 68a81d9..94ed9de 100644 --- a/include/asn1c/NativeReal.h +++ b/include/asn1c/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/include/asn1c/OBJECT_IDENTIFIER.h b/include/asn1c/OBJECT_IDENTIFIER.h index 2bb5d03..c2c6373 100644 --- a/include/asn1c/OBJECT_IDENTIFIER.h +++ b/include/asn1c/OBJECT_IDENTIFIER.h @@ -68,7 +68,7 @@ xer_type_encoder_f OBJECT_IDENTIFIER_encode_xer; * WARNING: The function always returns the real number of arcs, * even if there is no sufficient (_arc_slots) provided. */ -int OBJECT_IDENTIFIER_get_arcs(OBJECT_IDENTIFIER_t *_oid, +int OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *_oid, void *_arcs, /* e.g., unsigned int arcs[N] */ unsigned int _arc_type_size, /* e.g., sizeof(arcs[0]) */ unsigned int _arc_slots /* e.g., N */); @@ -91,12 +91,12 @@ int OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *_oid, /* * Print the specified OBJECT IDENTIFIER arc. */ -int OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen, +int OBJECT_IDENTIFIER_print_arc(const uint8_t *arcbuf, int arclen, int add, /* Arbitrary offset, required to process the first two arcs */ asn_app_consume_bytes_f *cb, void *app_key); /* Same as above, but returns the number of written digits, instead of 0 */ -ssize_t OBJECT_IDENTIFIER__dump_arc(uint8_t *arcbuf, int arclen, int add, +ssize_t OBJECT_IDENTIFIER__dump_arc(const uint8_t *arcbuf, int arclen, int add, asn_app_consume_bytes_f *cb, void *app_key); /* @@ -127,7 +127,7 @@ int OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length, * Internal functions. * Used by RELATIVE-OID implementation in particular. */ -int OBJECT_IDENTIFIER_get_single_arc(uint8_t *arcbuf, unsigned int arclen, +int OBJECT_IDENTIFIER_get_single_arc(const uint8_t *arcbuf, unsigned int arclen, signed int add, void *value, unsigned int value_size); int OBJECT_IDENTIFIER_set_single_arc(uint8_t *arcbuf, const void *arcval, unsigned int arcval_size, int _prepared_order); diff --git a/include/asn1c/OCTET_STRING.h b/include/asn1c/OCTET_STRING.h index 8df9a18..bc25666 100644 --- a/include/asn1c/OCTET_STRING.h +++ b/include/asn1c/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. * @@ -63,7 +65,7 @@ OCTET_STRING_t *OCTET_STRING_new_fromBuf(asn_TYPE_descriptor_t *td, * Internally useful stuff. * ****************************/ -typedef struct asn_OCTET_STRING_specifics_s { +typedef const struct asn_OCTET_STRING_specifics_s { /* * Target structure description. */ diff --git a/include/asn1c/REAL.h b/include/asn1c/REAL.h index af3e84c..503e254 100644 --- a/include/asn1c/REAL.h +++ b/include/asn1c/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/include/asn1c/RELATIVE-OID.h b/include/asn1c/RELATIVE-OID.h index 2235cfd..65acaab 100644 --- a/include/asn1c/RELATIVE-OID.h +++ b/include/asn1c/RELATIVE-OID.h @@ -25,7 +25,7 @@ xer_type_encoder_f RELATIVE_OID_encode_xer; **********************************/ /* See OBJECT_IDENTIFIER_get_arcs() function in OBJECT_IDENTIFIER.h */ -int RELATIVE_OID_get_arcs(RELATIVE_OID_t *_roid, +int RELATIVE_OID_get_arcs(const RELATIVE_OID_t *_roid, void *arcs, unsigned int arc_type_size, unsigned int arc_slots); /* See OBJECT_IDENTIFIER_set_arcs() function in OBJECT_IDENTIFIER.h */ diff --git a/include/asn1c/asn_codecs.h b/include/asn1c/asn_codecs.h index 4a251d9..e560014 100644 --- a/include/asn1c/asn_codecs.h +++ b/include/asn1c/asn_codecs.h @@ -62,7 +62,7 @@ typedef struct asn_enc_rval_s { tmp_error.encoded = -1; \ tmp_error.failed_type = td; \ tmp_error.structure_ptr = sptr; \ - ASN_DEBUG("Failed to encode element %s", td->name); \ + ASN_DEBUG("Failed to encode element %s", td ? td->name : ""); \ return tmp_error; \ } while(0) #define _ASN_ENCODED_OK(rval) do { \ @@ -92,7 +92,7 @@ typedef struct asn_dec_rval_s { asn_dec_rval_t tmp_error; \ tmp_error.code = RC_FAIL; \ tmp_error.consumed = 0; \ - ASN_DEBUG("Failed to decode element %s", td->name); \ + ASN_DEBUG("Failed to decode element %s", td ? td->name : ""); \ return tmp_error; \ } while(0) #define _ASN_DECODE_STARVED do { \ diff --git a/include/asn1c/asn_internal.h b/include/asn1c/asn_internal.h index e6da3fe..58b4583 100644 --- a/include/asn1c/asn_internal.h +++ b/include/asn1c/asn_internal.h @@ -22,7 +22,7 @@ extern "C" { #endif /* Environment version might be used to avoid running with the old library */ -#define ASN1C_ENVIRONMENT_VERSION 922 /* Compile-time version */ +#define ASN1C_ENVIRONMENT_VERSION 924 /* Compile-time version */ int get_asn1c_environment_version(void); /* Run-time version */ extern void *talloc_asn1_ctx; @@ -32,6 +32,9 @@ extern void *talloc_asn1_ctx; #define REALLOC(oldptr, size) talloc_realloc_size(talloc_asn1_ctx, oldptr, size) #define FREEMEM(ptr) talloc_free(ptr) +#define asn_debug_indent 0 +#define ASN_DEBUG_INDENT_ADD(i) do{}while(0) + /* * A macro for debugging the ASN.1 internals. * You may enable or override it. @@ -40,17 +43,25 @@ extern void *talloc_asn1_ctx; #if EMIT_ASN_DEBUG == 1 /* And it was asked to emit this code... */ #ifdef __GNUC__ #ifdef ASN_THREAD_SAFE -#define asn_debug_indent 0 +/* Thread safety requires sacrifice in output indentation: + * Retain empty definition of ASN_DEBUG_INDENT_ADD. */ #else /* !ASN_THREAD_SAFE */ +#undef ASN_DEBUG_INDENT_ADD +#undef asn_debug_indent 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/include/asn1c/asn_system.h b/include/asn1c/asn_system.h index 0a9b092..e420ad2 100644 --- a/include/asn1c/asn_system.h +++ b/include/asn1c/asn_system.h @@ -21,7 +21,7 @@ #include /* For va_start */ #include /* for offsetof and ptrdiff_t */ -#ifdef WIN32 +#ifdef _WIN32 #include #define snprintf _snprintf @@ -29,9 +29,9 @@ /* To avoid linking with ws2_32.lib, here's the definition of ntohl() */ #define sys_ntohl(l) ((((l) << 24) & 0xff000000) \ - | (((l) << 16) & 0xff0000) \ - | (((l) << 8) & 0xff00) \ - | ((l) & 0xff)) + | (((l) << 8) & 0xff0000) \ + | (((l) >> 8) & 0xff00) \ + | ((l >> 24) & 0xff)) #ifdef _MSC_VER /* MSVS.Net */ #ifndef __cplusplus @@ -57,7 +57,7 @@ typedef unsigned int uint32_t; #include #endif /* _MSC_VER */ -#else /* !WIN32 */ +#else /* !_WIN32 */ #if defined(__vxworks) #include @@ -90,7 +90,7 @@ typedef unsigned int uint32_t; #endif /* defined(__vxworks) */ -#endif /* WIN32 */ +#endif /* _WIN32 */ #if __GNUC__ >= 3 #ifndef GCC_PRINTFLIKE diff --git a/include/asn1c/constr_CHOICE.h b/include/asn1c/constr_CHOICE.h index 83404e6..ddcbb39 100644 --- a/include/asn1c/constr_CHOICE.h +++ b/include/asn1c/constr_CHOICE.h @@ -12,7 +12,7 @@ extern "C" { #endif -typedef struct asn_CHOICE_specifics_s { +typedef const struct asn_CHOICE_specifics_s { /* * Target structure description. */ @@ -24,7 +24,7 @@ typedef struct asn_CHOICE_specifics_s { /* * Tags to members mapping table. */ - asn_TYPE_tag2member_t *tag2el; + const asn_TYPE_tag2member_t *tag2el; int tag2el_count; /* Canonical ordering of CHOICE elements, for PER */ @@ -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/include/asn1c/constr_SEQUENCE.h b/include/asn1c/constr_SEQUENCE.h index 5f589d5..d181848 100644 --- a/include/asn1c/constr_SEQUENCE.h +++ b/include/asn1c/constr_SEQUENCE.h @@ -11,7 +11,7 @@ extern "C" { #endif -typedef struct asn_SEQUENCE_specifics_s { +typedef const struct asn_SEQUENCE_specifics_s { /* * Target structure description. */ @@ -21,14 +21,14 @@ typedef struct asn_SEQUENCE_specifics_s { /* * Tags to members mapping table (sorted). */ - asn_TYPE_tag2member_t *tag2el; + const asn_TYPE_tag2member_t *tag2el; int tag2el_count; /* * Optional members of the extensions root (roms) or additions (aoms). * Meaningful for PER. */ - int *oms; /* Optional MemberS */ + const int *oms; /* Optional MemberS */ int roms_count; /* Root optional members count */ int aoms_count; /* Additions optional members count */ @@ -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/include/asn1c/constr_SEQUENCE_OF.h b/include/asn1c/constr_SEQUENCE_OF.h index e2272f3..94a7cd5 100644 --- a/include/asn1c/constr_SEQUENCE_OF.h +++ b/include/asn1c/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/include/asn1c/constr_SET.h b/include/asn1c/constr_SET.h index 0c78ed5..11b7153 100644 --- a/include/asn1c/constr_SET.h +++ b/include/asn1c/constr_SET.h @@ -12,7 +12,7 @@ extern "C" { #endif -typedef struct asn_SET_specifics_s { +typedef const struct asn_SET_specifics_s { /* * Target structure description. */ @@ -25,21 +25,21 @@ typedef struct asn_SET_specifics_s { * Sometimes suitable for DER encoding (untagged CHOICE is present); * if so, tag2el_count will be greater than td->elements_count. */ - asn_TYPE_tag2member_t *tag2el; + const asn_TYPE_tag2member_t *tag2el; int tag2el_count; /* * Tags to members mapping table, second edition. * Suitable for CANONICAL-XER encoding. */ - asn_TYPE_tag2member_t *tag2el_cxer; + const asn_TYPE_tag2member_t *tag2el_cxer; int tag2el_cxer_count; /* * Extensions-related stuff. */ int extensible; /* Whether SET is extensible */ - unsigned int *_mandatory_elements; /* Bitmask of mandatory ones */ + const unsigned int *_mandatory_elements; /* Bitmask of mandatory ones */ } asn_SET_specifics_t; /* @@ -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/include/asn1c/constr_SET_OF.h b/include/asn1c/constr_SET_OF.h index bcd0966..8ddd0e3 100644 --- a/include/asn1c/constr_SET_OF.h +++ b/include/asn1c/constr_SET_OF.h @@ -11,7 +11,7 @@ extern "C" { #endif -typedef struct asn_SET_OF_specifics_s { +typedef const struct asn_SET_OF_specifics_s { /* * Target structure description. */ @@ -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/include/asn1c/constr_TYPE.h b/include/asn1c/constr_TYPE.h index 95507c8..13c60f3 100644 --- a/include/asn1c/constr_TYPE.h +++ b/include/asn1c/constr_TYPE.h @@ -73,7 +73,7 @@ typedef int (asn_struct_print_f)( * Do not use it in your application. */ typedef ber_tlv_tag_t (asn_outmost_tag_f)( - struct asn_TYPE_descriptor_s *type_descriptor, + const struct asn_TYPE_descriptor_s *type_descriptor, const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag); /* The instance of the above function type; used internally. */ asn_outmost_tag_f asn_TYPE_outmost_tag; @@ -83,8 +83,8 @@ asn_outmost_tag_f asn_TYPE_outmost_tag; * The definitive description of the destination language's structure. */ typedef struct asn_TYPE_descriptor_s { - char *name; /* A name of the ASN.1 type. "" in some cases. */ - char *xml_tag; /* Name used in XML tag */ + const char *name; /* A name of the ASN.1 type. "" in some cases. */ + const char *xml_tag; /* Name used in XML tag */ /* * Generalized functions for dealing with the specific type. @@ -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. * @@ -108,10 +110,10 @@ typedef struct asn_TYPE_descriptor_s { * Tags that are expected to occur. */ asn_outmost_tag_f *outmost_tag; /* */ - ber_tlv_tag_t *tags; /* Effective tags sequence for this type */ - int tags_count; /* Number of tags which are expected */ - ber_tlv_tag_t *all_tags;/* Every tag for BER/containment */ - int all_tags_count; /* Number of tags */ + const ber_tlv_tag_t *tags; /* Effective tags sequence for this type */ + int tags_count; /* Number of tags which are expected */ + const ber_tlv_tag_t *all_tags; /* Every tag for BER/containment */ + int all_tags_count; /* Number of tags */ asn_per_constraints_t *per_constraints; /* PER compiled constraints */ @@ -125,7 +127,7 @@ typedef struct asn_TYPE_descriptor_s { * Additional information describing the type, used by appropriate * functions above. */ - void *specifics; + const void *specifics; } asn_TYPE_descriptor_t; /* @@ -147,7 +149,7 @@ typedef struct asn_TYPE_member_s { asn_constr_check_f *memb_constraints; /* Constraints validator */ asn_per_constraints_t *per_constraints; /* PER compiled constraints */ int (*default_value)(int setval, void **sptr); /* DEFAULT */ - char *name; /* ASN.1 identifier of the element */ + const char *name; /* ASN.1 identifier of the element */ } asn_TYPE_member_t; /* diff --git a/include/asn1c/per_decoder.h b/include/asn1c/per_decoder.h index 8397a54..5541bae 100644 --- a/include/asn1c/per_decoder.h +++ b/include/asn1c/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/include/asn1c/per_encoder.h b/include/asn1c/per_encoder.h index 95a6506..e3b9190 100644 --- a/include/asn1c/per_encoder.h +++ b/include/asn1c/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/include/asn1c/per_opentype.h b/include/asn1c/per_opentype.h index facfaa6..2117efe 100644 --- a/include/asn1c/per_opentype.h +++ b/include/asn1c/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/include/asn1c/per_support.h b/include/asn1c/per_support.h index 7cb1a0c..181fe24 100644 --- a/include/asn1c/per_support.h +++ b/include/asn1c/per_support.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, 2007 Lev Walkin . + * Copyright (c) 2005-2014 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ @@ -15,7 +15,7 @@ extern "C" { /* * Pre-computed PER constraints. */ -typedef struct asn_per_constraint_s { +typedef const struct asn_per_constraint_s { enum asn_per_constraint_flags { APC_UNCONSTRAINED = 0x0, /* No PER visible constraints */ APC_SEMI_CONSTRAINED = 0x1, /* Constrained at "lb" */ @@ -24,12 +24,12 @@ typedef 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 struct asn_per_constraints_s { - asn_per_constraint_t value; - asn_per_constraint_t size; +typedef const struct asn_per_constraints_s { + struct asn_per_constraint_s value; + struct asn_per_constraint_s size; int (*value2code)(unsigned int value); int (*code2value)(unsigned int code); } asn_per_constraints_t; @@ -39,9 +39,9 @@ typedef 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,25 @@ 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); /* Non-thread-safe debugging function, don't use it */ char *per_data_string(asn_per_data_t *pd); @@ -103,6 +113,14 @@ int per_put_few_bits(asn_per_outp_t *per_data, uint32_t bits, int obits); /* Output a large number of bits */ int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits); +/* X.691-2008/11, #11.5 */ +int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits); +int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits); + +/* 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 @@ -110,17 +128,23 @@ int per_put_many_bits(asn_per_outp_t *po, const uint8_t *src, int put_nbits); */ 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 diff --git a/include/asn1c/xer_decoder.h b/include/asn1c/xer_decoder.h index cf0d846..6988648 100644 --- a/include/asn1c/xer_decoder.h +++ b/include/asn1c/xer_decoder.h @@ -87,12 +87,11 @@ xer_check_tag_e xer_check_tag(const void *buf_ptr, int size, const char *need_tag); /* - * Check whether this buffer consists of entirely XER whitespace characters. + * Get the number of bytes consisting entirely of XER whitespace characters. * RETURN VALUES: - * 1: Whitespace or empty string - * 0: Non-whitespace + * >=0: Number of whitespace characters in the string. */ -int xer_is_whitespace(const void *chunk_buf, size_t chunk_size); +size_t xer_whitespace_span(const void *chunk_buf, size_t chunk_size); /* * Skip the series of anticipated extensions. diff --git a/src/ANY.c b/src/ANY.c index 0ad60d0..0fe63ae 100644 --- a/src/ANY.c +++ b/src/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/src/BIT_STRING.c b/src/BIT_STRING.c index 9b98271..ad2ca60 100644 --- a/src/BIT_STRING.c +++ b/src/BIT_STRING.c @@ -9,7 +9,7 @@ /* * BIT STRING basic type description. */ -static ber_tlv_tag_t asn_DEF_BIT_STRING_tags[] = { +static const ber_tlv_tag_t asn_DEF_BIT_STRING_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (3 << 2)) }; static asn_OCTET_STRING_specifics_t asn_DEF_BIT_STRING_specs = { @@ -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) @@ -140,7 +142,7 @@ cb_failed: int BIT_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { - static const char *h2c = "0123456789ABCDEF"; + const char * const h2c = "0123456789ABCDEF"; char scratch[64]; const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; uint8_t *buf; diff --git a/src/BMPString.c b/src/BMPString.c index 072bd07..94471f6 100644 --- a/src/BMPString.c +++ b/src/BMPString.c @@ -9,7 +9,7 @@ /* * BMPString basic type description. */ -static ber_tlv_tag_t asn_DEF_BMPString_tags[] = { +static const ber_tlv_tag_t asn_DEF_BMPString_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (30 << 2)), /* [UNIVERSAL 30] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ }; @@ -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) @@ -143,7 +145,7 @@ BMPString_decode_xer(asn_codec_ctx_t *opt_codec_ctx, return rc; } else { dstwc[wcs_len] = 0; /* nul-terminate */ - wcs = (uint32_t *)dstwc; + wcs = (uint32_t *)(void *)dstwc; /* Alignment OK */ } } diff --git a/src/BOOLEAN.c b/src/BOOLEAN.c index 2c2bbcf..42374b8 100644 --- a/src/BOOLEAN.c +++ b/src/BOOLEAN.c @@ -9,7 +9,7 @@ /* * BOOLEAN basic type description. */ -static ber_tlv_tag_t asn_DEF_BOOLEAN_tags[] = { +static const ber_tlv_tag_t asn_DEF_BOOLEAN_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (1 << 2)) }; asn_TYPE_descriptor_t asn_DEF_BOOLEAN = { @@ -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]), @@ -161,10 +163,7 @@ BOOLEAN__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun } return XPBD_BODY_CONSUMED; } else { - if(xer_is_whitespace(chunk_buf, chunk_size)) - return XPBD_NOT_BODY_IGNORE; - else - return XPBD_BROKEN_ENCODING; + return XPBD_BROKEN_ENCODING; } } @@ -267,18 +266,63 @@ 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, 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; + asn_enc_rval_t er = { 0, 0, 0 }; (void)constraints; if(!st) _ASN_ENCODE_FAILED; - per_put_few_bits(po, *st ? 1 : 0, 1); + if(per_put_few_bits(po, *st ? 1 : 0, 1)) + _ASN_ENCODE_FAILED; _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/src/ENUMERATED.c b/src/ENUMERATED.c index 90761a2..f313f96 100644 --- a/src/ENUMERATED.c +++ b/src/ENUMERATED.c @@ -11,7 +11,7 @@ /* * ENUMERATED basic type description. */ -static ber_tlv_tag_t asn_DEF_ENUMERATED_tags[] = { +static const ber_tlv_tag_t asn_DEF_ENUMERATED_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (10 << 2)) }; asn_TYPE_descriptor_t asn_DEF_ENUMERATED = { @@ -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/src/GeneralString.c b/src/GeneralString.c index 01b606b..934b8a2 100644 --- a/src/GeneralString.c +++ b/src/GeneralString.c @@ -8,7 +8,7 @@ /* * GeneralString basic type description. */ -static ber_tlv_tag_t asn_DEF_GeneralString_tags[] = { +static const ber_tlv_tag_t asn_DEF_GeneralString_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (27 << 2)), /* [UNIVERSAL 27] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ }; @@ -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/src/GeneralizedTime.c b/src/GeneralizedTime.c index 9d683ef..29dcc6c 100644 --- a/src/GeneralizedTime.c +++ b/src/GeneralizedTime.c @@ -14,7 +14,7 @@ #include #endif /* __CYGWIN__ */ -#if defined(WIN32) +#if defined(_WIN32) #pragma message( "PLEASE STOP AND READ!") #pragma message( " localtime_r is implemented via localtime(), which may be not thread-safe.") #pragma message( " gmtime_r is implemented via gmtime(), which may be not thread-safe.") @@ -41,7 +41,7 @@ static struct tm *gmtime_r(const time_t *tloc, struct tm *result) { #define putenv(c) _putenv(c) #define _EMULATE_TIMEGM -#endif /* WIN32 */ +#endif /* _WIN32 */ #if defined(sun) || defined(_sun_) || defined(__solaris__) #define _EMULATE_TIMEGM @@ -67,6 +67,14 @@ static struct tm *gmtime_r(const time_t *tloc, struct tm *result) { #define GMTOFF(tm) (-timezone) #endif /* HAVE_TM_GMTOFF */ +#if defined(_WIN32) +#pragma message( "PLEASE STOP AND READ!") +#pragma message( " timegm() is implemented via getenv(\"TZ\")/setenv(\"TZ\"), which may be not thread-safe.") +#pragma message( " ") +#pragma message( " You must fix the code by inserting appropriate locking") +#pragma message( " if you want to use asn_GT2time() or asn_UT2time().") +#pragma message( "PLEASE STOP AND READ!") +#else #if (defined(_EMULATE_TIMEGM) || !defined(HAVE_TM_GMTOFF)) #warning "PLEASE STOP AND READ!" #warning " timegm() is implemented via getenv(\"TZ\")/setenv(\"TZ\"), which may be not thread-safe." @@ -75,6 +83,7 @@ static struct tm *gmtime_r(const time_t *tloc, struct tm *result) { #warning " if you want to use asn_GT2time() or asn_UT2time()." #warning "PLEASE STOP AND READ!" #endif /* _EMULATE_TIMEGM */ +#endif /* * Override our GMTOFF decision for other known platforms. @@ -128,6 +137,7 @@ static long GMTOFF(struct tm a){ tzset(); \ } while(0); } while(0); +#ifndef HAVE_TIMEGM #ifdef _EMULATE_TIMEGM static time_t timegm(struct tm *tm) { time_t tloc; @@ -138,6 +148,7 @@ static time_t timegm(struct tm *tm) { return tloc; } #endif /* _EMULATE_TIMEGM */ +#endif #ifndef __ASN_INTERNAL_TEST_MODE__ @@ -145,7 +156,7 @@ static time_t timegm(struct tm *tm) { /* * GeneralizedTime basic type description. */ -static ber_tlv_tag_t asn_DEF_GeneralizedTime_tags[] = { +static const ber_tlv_tag_t asn_DEF_GeneralizedTime_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (24 << 2)), /* [UNIVERSAL 24] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (26 << 2)), /* [UNIVERSAL 26] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ @@ -167,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) @@ -314,13 +327,14 @@ asn_GT2time_prec(const GeneralizedTime_t *st, int *frac_value, int frac_digits, while(fd > frac_digits) fv /= 10, fd--; while(fd < frac_digits) { - int new_fv = fv * 10; - if(new_fv / 10 != fv) { + if(fv < INT_MAX / 10) { + fv *= 10; + fd++; + } else { /* Too long precision request */ fv = 0; break; } - fv = new_fv, fd++; } *frac_value = fv; @@ -441,16 +455,15 @@ asn_GT2time_frac(const GeneralizedTime_t *st, int *frac_value, int *frac_digits, */ for(buf++; buf < end; buf++) { int v = *buf; - int new_fvalue; + /* GCC 4.x is being too smart without volatile */ switch(v) { case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: - new_fvalue = fvalue * 10 + (v - 0x30); - if(new_fvalue / 10 != fvalue) { - /* Not enough precision, ignore */ - } else { - fvalue = new_fvalue; + if(fvalue < INT_MAX/10) { + fvalue = fvalue * 10 + (v - 0x30); fdigits++; + } else { + /* Not enough precision, ignore */ } continue; default: diff --git a/src/GraphicString.c b/src/GraphicString.c index 7d59d52..5f62486 100644 --- a/src/GraphicString.c +++ b/src/GraphicString.c @@ -8,7 +8,7 @@ /* * GraphicString basic type description. */ -static ber_tlv_tag_t asn_DEF_GraphicString_tags[] = { +static const ber_tlv_tag_t asn_DEF_GraphicString_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (25 << 2)), /* [UNIVERSAL 25] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ }; @@ -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/src/IA5String.c b/src/IA5String.c index 02ecd3e..cec61c3 100644 --- a/src/IA5String.c +++ b/src/IA5String.c @@ -8,7 +8,7 @@ /* * IA5String basic type description. */ -static ber_tlv_tag_t asn_DEF_IA5String_tags[] = { +static const ber_tlv_tag_t asn_DEF_IA5String_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (22 << 2)), /* [UNIVERSAL 22] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ }; @@ -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/src/INTEGER.c b/src/INTEGER.c index f016131..c74c5b4 100644 --- a/src/INTEGER.c +++ b/src/INTEGER.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003, 2004, 2005, 2006, 2007 Lev Walkin . + * Copyright (c) 2003-2014 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ @@ -11,7 +11,7 @@ /* * INTEGER basic type description. */ -static ber_tlv_tag_t asn_DEF_INTEGER_tags[] = { +static const ber_tlv_tag_t asn_DEF_INTEGER_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) }; asn_TYPE_descriptor_t asn_DEF_INTEGER = { @@ -24,8 +24,17 @@ asn_TYPE_descriptor_t asn_DEF_INTEGER = { INTEGER_encode_der, INTEGER_decode_xer, INTEGER_encode_xer, +#ifdef ASN_DISABLE_PER_SUPPORT + 0, + 0, + 0, + 0, +#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, sizeof(asn_DEF_INTEGER_tags) / sizeof(asn_DEF_INTEGER_tags[0]), @@ -101,52 +110,35 @@ static const asn_INTEGER_enum_map_t *INTEGER_map_enum2value(asn_INTEGER_specific * INTEGER specific human-readable output. */ static ssize_t -INTEGER__dump(asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key, int plainOrXER) { +INTEGER__dump(const asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_bytes_f *cb, void *app_key, int plainOrXER) { asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; char scratch[32]; /* Enough for 64-bit integer */ uint8_t *buf = st->buf; uint8_t *buf_end = st->buf + st->size; - signed long accum; + signed long value; ssize_t wrote = 0; char *p; int ret; - /* - * Advance buf pointer until the start of the value's body. - * This will make us able to process large integers using simple case, - * when the actual value is small - * (0x0000000000abcdef would yield a fine 0x00abcdef) - */ - /* Skip the insignificant leading bytes */ - for(; buf < buf_end-1; buf++) { - switch(*buf) { - case 0x00: if((buf[1] & 0x80) == 0) continue; break; - case 0xff: if((buf[1] & 0x80) != 0) continue; break; - } - break; - } + if(specs && specs->field_unsigned) + ret = asn_INTEGER2ulong(st, (unsigned long *)&value); + else + ret = asn_INTEGER2long(st, &value); /* Simple case: the integer size is small */ - if((size_t)(buf_end - buf) <= sizeof(accum)) { + if(ret == 0) { const asn_INTEGER_enum_map_t *el; size_t scrsize; char *scr; - if(buf == buf_end) { - accum = 0; - } else { - accum = (*buf & 0x80) ? -1 : 0; - for(; buf < buf_end; buf++) - accum = (accum << 8) | *buf; - } - - el = INTEGER_map_value2enum(specs, accum); + el = (value >= 0 || !specs || !specs->field_unsigned) + ? INTEGER_map_value2enum(specs, value) : 0; if(el) { scrsize = el->enum_len + 32; scr = (char *)alloca(scrsize); if(plainOrXER == 0) ret = snprintf(scr, scrsize, - "%ld (%s)", accum, el->enum_name); + "%ld (%s)", value, el->enum_name); else ret = snprintf(scr, scrsize, "<%s/>", el->enum_name); @@ -160,7 +152,7 @@ INTEGER__dump(asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_by scr = scratch; ret = snprintf(scr, scrsize, (specs && specs->field_unsigned) - ?"%lu":"%ld", accum); + ?"%lu":"%ld", value); } assert(ret > 0 && (size_t)ret < scrsize); return (cb(scr, ret, app_key) < 0) ? -1 : ret; @@ -178,7 +170,7 @@ INTEGER__dump(asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_by /* Output in the long xx:yy:zz... format */ /* TODO: replace with generic algorithm (Knuth TAOCP Vol 2, 4.3.1) */ for(p = scratch; buf < buf_end; buf++) { - static const char *h2c = "0123456789ABCDEF"; + const char * const h2c = "0123456789ABCDEF"; if((p - scratch) >= (ssize_t)(sizeof(scratch) - 4)) { /* Flush buffer */ if(cb(scratch, p - scratch, app_key) < 0) @@ -220,8 +212,8 @@ INTEGER_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, struct e2v_key { const char *start; const char *stop; - asn_INTEGER_enum_map_t *vemap; - unsigned int *evmap; + const asn_INTEGER_enum_map_t *vemap; + const unsigned int *evmap; }; static int INTEGER__compar_enum2value(const void *kp, const void *am) { @@ -244,7 +236,7 @@ INTEGER__compar_enum2value(const void *kp, const void *am) { static const asn_INTEGER_enum_map_t * INTEGER_map_enum2value(asn_INTEGER_specifics_t *specs, const char *lstart, const char *lstop) { - asn_INTEGER_enum_map_t *el_found; + const asn_INTEGER_enum_map_t *el_found; int count = specs ? specs->map_count : 0; struct e2v_key key; const char *lp; @@ -319,57 +311,71 @@ INTEGER_st_prealloc(INTEGER_t *st, int min_size) { static enum xer_pbd_rval INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) { INTEGER_t *st = (INTEGER_t *)sptr; - long sign = 1; - long value; + long dec_value; + long hex_value = 0; const char *lp; const char *lstart = (const char *)chunk_buf; const char *lstop = lstart + chunk_size; enum { - ST_SKIPSPACE, + ST_LEADSPACE, ST_SKIPSPHEX, ST_WAITDIGITS, ST_DIGITS, + ST_DIGITS_TRAILSPACE, ST_HEXDIGIT1, ST_HEXDIGIT2, + ST_HEXDIGITS_TRAILSPACE, ST_HEXCOLON, - ST_EXTRASTUFF - } state = ST_SKIPSPACE; + ST_END_ENUM, + ST_UNEXPECTED + } state = ST_LEADSPACE; + const char *dec_value_start = 0; /* INVARIANT: always !0 in ST_DIGITS */ + const char *dec_value_end = 0; if(chunk_size) ASN_DEBUG("INTEGER body %ld 0x%2x..0x%2x", (long)chunk_size, *lstart, lstop[-1]); + if(INTEGER_st_prealloc(st, (chunk_size/3) + 1)) + return XPBD_SYSTEM_FAILURE; + /* * We may have received a tag here. It will be processed inline. * Use strtoul()-like code and serialize the result. */ - for(value = 0, lp = lstart; lp < lstop; lp++) { + for(lp = lstart; lp < lstop; lp++) { int lv = *lp; switch(lv) { case 0x09: case 0x0a: case 0x0d: case 0x20: switch(state) { - case ST_SKIPSPACE: + case ST_LEADSPACE: + case ST_DIGITS_TRAILSPACE: + case ST_HEXDIGITS_TRAILSPACE: case ST_SKIPSPHEX: continue; + case ST_DIGITS: + dec_value_end = lp; + state = ST_DIGITS_TRAILSPACE; + continue; case ST_HEXCOLON: - if(xer_is_whitespace(lp, lstop - lp)) { - lp = lstop - 1; - continue; - } - break; + state = ST_HEXDIGITS_TRAILSPACE; + continue; default: break; } break; case 0x2d: /* '-' */ - if(state == ST_SKIPSPACE) { - sign = -1; + if(state == ST_LEADSPACE) { + dec_value = 0; + dec_value_start = lp; state = ST_WAITDIGITS; continue; } break; case 0x2b: /* '+' */ - if(state == ST_SKIPSPACE) { + if(state == ST_LEADSPACE) { + dec_value = 0; + dec_value_start = lp; state = ST_WAITDIGITS; continue; } @@ -377,57 +383,41 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: switch(state) { - case ST_DIGITS: break; + case ST_DIGITS: continue; case ST_SKIPSPHEX: /* Fall through */ case ST_HEXDIGIT1: - value = (lv - 0x30) << 4; + hex_value = (lv - 0x30) << 4; state = ST_HEXDIGIT2; continue; case ST_HEXDIGIT2: - value += (lv - 0x30); + hex_value += (lv - 0x30); state = ST_HEXCOLON; - st->buf[st->size++] = (uint8_t)value; + st->buf[st->size++] = (uint8_t)hex_value; continue; case ST_HEXCOLON: return XPBD_BROKEN_ENCODING; - default: + case ST_LEADSPACE: + dec_value = 0; + dec_value_start = lp; + /* FALL THROUGH */ + case ST_WAITDIGITS: state = ST_DIGITS; + continue; + default: break; } - - { - long new_value = value * 10; - - if(new_value / 10 != value) - /* Overflow */ - return XPBD_DECODER_LIMIT; - - value = new_value + (lv - 0x30); - /* Check for two's complement overflow */ - if(value < 0) { - /* Check whether it is a LONG_MIN */ - if(sign == -1 - && (unsigned long)value - == ~((unsigned long)-1 >> 1)) { - sign = 1; - } else { - /* Overflow */ - return XPBD_DECODER_LIMIT; - } - } - } - continue; - case 0x3c: /* '<' */ - if(state == ST_SKIPSPACE) { + break; + case 0x3c: /* '<', start of XML encoded enumeration */ + if(state == ST_LEADSPACE) { const asn_INTEGER_enum_map_t *el; el = INTEGER_map_enum2value( (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); - state = ST_DIGITS; - value = el->nat_value; + dec_value = el->nat_value; + state = ST_END_ENUM; lp = lstop - 1; continue; } @@ -445,13 +435,12 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun * places as a decimal value. * Switch decoding mode. */ ASN_DEBUG("INTEGER re-evaluate as hex form"); - if(INTEGER_st_prealloc(st, (chunk_size/3) + 1)) - return XPBD_SYSTEM_FAILURE; state = ST_SKIPSPHEX; + dec_value_start = 0; lp = lstart - 1; continue; } else { - ASN_DEBUG("state %d at %d", state, lp - lstart); + ASN_DEBUG("state %d at %ld", state, (long)(lp - lstart)); break; } /* [A-Fa-f] */ @@ -459,24 +448,23 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66: switch(state) { case ST_SKIPSPHEX: - case ST_SKIPSPACE: /* Fall through */ + case ST_LEADSPACE: /* Fall through */ case ST_HEXDIGIT1: - value = lv - ((lv < 0x61) ? 0x41 : 0x61); - value += 10; - value <<= 4; + hex_value = lv - ((lv < 0x61) ? 0x41 : 0x61); + hex_value += 10; + hex_value <<= 4; state = ST_HEXDIGIT2; continue; case ST_HEXDIGIT2: - value += lv - ((lv < 0x61) ? 0x41 : 0x61); - value += 10; - st->buf[st->size++] = (uint8_t)value; + hex_value += lv - ((lv < 0x61) ? 0x41 : 0x61); + hex_value += 10; + st->buf[st->size++] = (uint8_t)hex_value; state = ST_HEXCOLON; continue; case ST_DIGITS: ASN_DEBUG("INTEGER re-evaluate as hex form"); - if(INTEGER_st_prealloc(st, (chunk_size/3) + 1)) - return XPBD_SYSTEM_FAILURE; state = ST_SKIPSPHEX; + dec_value_start = 0; lp = lstart - 1; continue; default: @@ -486,39 +474,54 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun } /* Found extra non-numeric stuff */ - ASN_DEBUG("Found non-numeric 0x%2x at %d", - lv, lp - lstart); - state = ST_EXTRASTUFF; + ASN_DEBUG("INTEGER :: Found non-numeric 0x%2x at %ld", + lv, (long)(lp - lstart)); + state = ST_UNEXPECTED; break; } switch(state) { + case ST_END_ENUM: + /* Got a complete and valid enumeration encoded as a tag. */ + break; case ST_DIGITS: - /* Everything is cool */ + dec_value_end = lstop; + /* FALL THROUGH */ + case ST_DIGITS_TRAILSPACE: + /* The last symbol encountered was a digit. */ + switch(asn_strtol_lim(dec_value_start, &dec_value_end, &dec_value)) { + case ASN_STRTOL_OK: + break; + case ASN_STRTOL_ERROR_RANGE: + return XPBD_DECODER_LIMIT; + case ASN_STRTOL_ERROR_INVAL: + case ASN_STRTOL_EXPECT_MORE: + case ASN_STRTOL_EXTRA_DATA: + return XPBD_BROKEN_ENCODING; + } break; case ST_HEXCOLON: + case ST_HEXDIGITS_TRAILSPACE: st->buf[st->size] = 0; /* Just in case termination */ return XPBD_BODY_CONSUMED; case ST_HEXDIGIT1: case ST_HEXDIGIT2: case ST_SKIPSPHEX: return XPBD_BROKEN_ENCODING; - default: - if(xer_is_whitespace(lp, lstop - lp)) { - if(state != ST_EXTRASTUFF) - return XPBD_NOT_BODY_IGNORE; - break; - } else { - ASN_DEBUG("INTEGER: No useful digits (state %d)", - state); - return XPBD_BROKEN_ENCODING; /* No digits */ - } - break; + case ST_LEADSPACE: + /* Content not found */ + return XPBD_NOT_BODY_IGNORE; + case ST_WAITDIGITS: + case ST_UNEXPECTED: + ASN_DEBUG("INTEGER: No useful digits (state %d)", state); + return XPBD_BROKEN_ENCODING; /* No digits */ } - value *= sign; /* Change sign, if needed */ - - if(asn_long2INTEGER(st, value)) + /* + * Convert the result of parsing of enumeration or a straight + * decimal value into a BER representation. + */ + if(asn_long2INTEGER(st, dec_value)) return XPBD_SYSTEM_FAILURE; return XPBD_BODY_CONSUMED; @@ -553,6 +556,8 @@ INTEGER_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, _ASN_ENCODED_OK(er); } +#ifndef ASN_DISABLE_PER_SUPPORT + asn_dec_rval_t INTEGER_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) { @@ -594,31 +599,179 @@ INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, } } + /* X.691-2008/11, #13.2.2, constrained whole number */ + if(ct && ct->flags != APC_UNCONSTRAINED) { + /* #11.5.6 */ + ASN_DEBUG("Integer with range %d bits", ct->range_bits); + if(ct->range_bits >= 0) { + if((size_t)ct->range_bits > 8 * sizeof(unsigned long)) + _ASN_DECODE_FAILED; + + if(specs && specs->field_unsigned) { + unsigned long uvalue; + if(uper_get_constrained_whole_number(pd, + &uvalue, ct->range_bits)) + _ASN_DECODE_STARVED; + ASN_DEBUG("Got value %lu + low %lld", + uvalue, ct->lower_bound); + uvalue += ct->lower_bound; + if(asn_ulong2INTEGER(st, uvalue)) + _ASN_DECODE_FAILED; + } else { + unsigned long svalue; + if(uper_get_constrained_whole_number(pd, + &svalue, ct->range_bits)) + _ASN_DECODE_STARVED; + ASN_DEBUG("Got value %ld + low %ld", + svalue, ct->lower_bound); + svalue += ct->lower_bound; + if(asn_long2INTEGER(st, svalue)) + _ASN_DECODE_FAILED; + } + return rval; + } + } 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 = uper_get_length(pd, -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_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) { - long value; - if(ct->range_bits == 32) { - long lhalf; - value = per_get_few_bits(pd, 16); - if(value < 0) _ASN_DECODE_STARVED; - lhalf = per_get_few_bits(pd, 16); - if(lhalf < 0) _ASN_DECODE_STARVED; - value = (value << 16) | lhalf; + if (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 { - value = per_get_few_bits(pd, ct->range_bits); - if(value < 0) _ASN_DECODE_STARVED; + 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; } - ASN_DEBUG("Got value %ld + low %ld", - value, ct->lower_bound); - value += ct->lower_bound; - if((specs && specs->field_unsigned) - ? asn_ulong2INTEGER(st, value) - : asn_long2INTEGER(st, value)) - _ASN_DECODE_FAILED; return rval; + } else { + _ASN_DECODE_FAILED; } } else { ASN_DEBUG("Decoding unconstrained integer %s", td->name); @@ -631,7 +784,7 @@ INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, int ret; /* Get the PER length */ - len = uper_get_length(pd, -1, &repeat); + len = aper_get_length(pd, -1, -1, &repeat); if(len < 0) _ASN_DECODE_STARVED; p = REALLOC(st->buf, st->size + len + 1); @@ -692,7 +845,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"); @@ -709,7 +862,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"); @@ -724,33 +877,148 @@ INTEGER_encode_uper(asn_TYPE_descriptor_t *td, } + /* X.691-11/2008, #13.2.2, test if constrained whole number */ + if(ct && ct->range_bits >= 0) { + /* #11.5.6 -> #11.3 */ + ASN_DEBUG("Encoding integer %ld (%lu) with range %d bits", + value, value - ct->lower_bound, ct->range_bits); + unsigned long v = value - ct->lower_bound; + if(uper_put_constrained_whole_number_u(po, v, ct->range_bits)) + _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 = uper_put_length(po, 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); +} + +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); - if(ct->range_bits == 32) { - /* TODO: extend to >32 bits */ - long v = value - ct->lower_bound; - if(per_put_few_bits(po, v >> 1, 31) - || per_put_few_bits(po, v, 1)) + 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 { - if(per_put_few_bits(po, value - ct->lower_bound, - ct->range_bits)) + /* 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 %ld", 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 = uper_put_length(po, end - buf); + 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)) @@ -761,6 +1029,8 @@ INTEGER_encode_uper(asn_TYPE_descriptor_t *td, _ASN_ENCODED_OK(er); } +#endif /* ASN_DISABLE_PER_SUPPORT */ + int asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) { uint8_t *b, *end; @@ -821,6 +1091,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 +1183,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 +1240,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; @@ -932,3 +1374,92 @@ asn_long2INTEGER(INTEGER_t *st, long value) { return 0; } + +/* + * This function is going to be DEPRECATED soon. + */ +enum asn_strtol_result_e +asn_strtol(const char *str, const char *end, long *lp) { + const char *endp = end; + + switch(asn_strtol_lim(str, &endp, lp)) { + case ASN_STRTOL_ERROR_RANGE: + return ASN_STRTOL_ERROR_RANGE; + case ASN_STRTOL_ERROR_INVAL: + return ASN_STRTOL_ERROR_INVAL; + case ASN_STRTOL_EXPECT_MORE: + return ASN_STRTOL_ERROR_INVAL; /* Retain old behavior */ + case ASN_STRTOL_OK: + return ASN_STRTOL_OK; + case ASN_STRTOL_EXTRA_DATA: + return ASN_STRTOL_ERROR_INVAL; /* Retain old behavior */ + } + + return ASN_STRTOL_ERROR_INVAL; /* Retain old behavior */ +} + +/* + * Parse the number in the given string until the given *end position, + * returning the position after the last parsed character back using the + * same (*end) pointer. + * WARNING: This behavior is different from the standard strtol(3). + */ +enum asn_strtol_result_e +asn_strtol_lim(const char *str, const char **end, long *lp) { + int sign = 1; + long l; + + const long upper_boundary = LONG_MAX / 10; + long last_digit_max = LONG_MAX % 10; + + if(str >= *end) return ASN_STRTOL_ERROR_INVAL; + + switch(*str) { + case '-': + last_digit_max++; + sign = -1; + case '+': + str++; + if(str >= *end) { + *end = str; + return ASN_STRTOL_EXPECT_MORE; + } + } + + for(l = 0; str < (*end); str++) { + switch(*str) { + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: { + int d = *str - '0'; + if(l < upper_boundary) { + l = l * 10 + d; + } else if(l == upper_boundary) { + if(d <= last_digit_max) { + if(sign > 0) { + l = l * 10 + d; + } else { + sign = 1; + l = -l * 10 - d; + } + } else { + *end = str; + return ASN_STRTOL_ERROR_RANGE; + } + } else { + *end = str; + return ASN_STRTOL_ERROR_RANGE; + } + } + continue; + default: + *end = str; + *lp = sign * l; + return ASN_STRTOL_EXTRA_DATA; + } + } + + *end = str; + *lp = sign * l; + return ASN_STRTOL_OK; +} + diff --git a/src/ISO646String.c b/src/ISO646String.c index d6ded0e..a6cc761 100644 --- a/src/ISO646String.c +++ b/src/ISO646String.c @@ -8,7 +8,7 @@ /* * ISO646String basic type description. */ -static ber_tlv_tag_t asn_DEF_ISO646String_tags[] = { +static const ber_tlv_tag_t asn_DEF_ISO646String_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (26 << 2)), /* [UNIVERSAL 26] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ }; @@ -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/src/Makefile.am b/src/Makefile.am index 1bbcfc5..633cc04 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ # This is _NOT_ the library release version, it's an API version. # Please read Chapter 6 "Library interface versions" of the libtool # documentation before making any modification -LIBVERSION=0:0:0 +LIBVERSION=1:0:0 AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include/asn1c AM_CFLAGS = -fPIC -Wall $(LIBOSMOCORE_CFLAGS) diff --git a/src/NULL.c b/src/NULL.c index 6d3316f..f514ca2 100644 --- a/src/NULL.c +++ b/src/NULL.c @@ -10,7 +10,7 @@ /* * NULL basic type description. */ -static ber_tlv_tag_t asn_DEF_NULL_tags[] = { +static const ber_tlv_tag_t asn_DEF_NULL_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (5 << 2)) }; asn_TYPE_descriptor_t asn_DEF_NULL = { @@ -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]), @@ -73,11 +75,15 @@ static enum xer_pbd_rval NULL__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chunk_buf, size_t chunk_size) { (void)td; (void)sptr; + (void)chunk_buf; /* Going to be empty according to the rules below. */ - if(xer_is_whitespace(chunk_buf, chunk_size)) - return XPBD_BODY_CONSUMED; - else + /* + * There must be no content in self-terminating tag. + */ + if(chunk_size) return XPBD_BROKEN_ENCODING; + else + return XPBD_BODY_CONSUMED; } asn_dec_rval_t @@ -132,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) { @@ -145,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/src/NativeEnumerated.c b/src/NativeEnumerated.c index 3184644..124e7f0 100644 --- a/src/NativeEnumerated.c +++ b/src/NativeEnumerated.c @@ -15,7 +15,7 @@ /* * NativeEnumerated basic type description. */ -static ber_tlv_tag_t asn_DEF_NativeEnumerated_tags[] = { +static const ber_tlv_tag_t asn_DEF_NativeEnumerated_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (10 << 2)) }; asn_TYPE_descriptor_t asn_DEF_NativeEnumerated = { @@ -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; @@ -145,7 +202,7 @@ NativeEnumerated_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraint_t *ct; int inext = 0; asn_INTEGER_enum_map_t key; - asn_INTEGER_enum_map_t *kf; + const asn_INTEGER_enum_map_t *kf; if(!sptr) _ASN_ENCODE_FAILED; if(!specs) _ASN_ENCODE_FAILED; @@ -205,6 +262,75 @@ 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); +} + int NativeEnumerated_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { diff --git a/src/NativeInteger.c b/src/NativeInteger.c index abdb71a..ef17bee 100644 --- a/src/NativeInteger.c +++ b/src/NativeInteger.c @@ -16,7 +16,7 @@ /* * NativeInteger basic type description. */ -static ber_tlv_tag_t asn_DEF_NativeInteger_tags[] = { +static const ber_tlv_tag_t asn_DEF_NativeInteger_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)) }; asn_TYPE_descriptor_t asn_DEF_NativeInteger = { @@ -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]), @@ -107,7 +109,7 @@ NativeInteger_decode_ber(asn_codec_ctx_t *opt_codec_ctx, tmp.size = length; if((specs&&specs->field_unsigned) - ? asn_INTEGER2ulong(&tmp, &l) + ? asn_INTEGER2ulong(&tmp, (unsigned long *)&l) /* sic */ : asn_INTEGER2long(&tmp, &l)) { rval.code = RC_FAIL; rval.consumed = 0; @@ -187,7 +189,7 @@ NativeInteger_decode_xer(asn_codec_ctx_t *opt_codec_ctx, if(rval.code == RC_OK) { long l; if((specs&&specs->field_unsigned) - ? asn_INTEGER2ulong(&st, &l) + ? asn_INTEGER2ulong(&st, (unsigned long *)&l) /* sic */ : asn_INTEGER2long(&st, &l)) { rval.code = RC_FAIL; rval.consumed = 0; @@ -255,7 +257,43 @@ NativeInteger_decode_uper(asn_codec_ctx_t *opt_codec_ctx, &tmpintptr, pd); if(rval.code == RC_OK) { if((specs&&specs->field_unsigned) - ? asn_INTEGER2ulong(&tmpint, native) + ? 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_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 @@ -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/src/NativeReal.c b/src/NativeReal.c index a1ff91e..3bd5a28 100644 --- a/src/NativeReal.c +++ b/src/NativeReal.c @@ -17,7 +17,7 @@ /* * NativeReal basic type description. */ -static ber_tlv_tag_t asn_DEF_NativeReal_tags[] = { +static const ber_tlv_tag_t asn_DEF_NativeReal_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (9 << 2)) }; asn_TYPE_descriptor_t asn_DEF_NativeReal = { @@ -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]), @@ -107,10 +109,39 @@ NativeReal_decode_ber(asn_codec_ctx_t *opt_codec_ctx, tmp.buf = (uint8_t *)unconst_buf.nonconstbuf; tmp.size = length; - if(asn_REAL2double(&tmp, &d)) { - rval.code = RC_FAIL; - rval.consumed = 0; - return rval; + if(length < (ber_tlv_len_t)size) { + int ret; + uint8_t saved_byte = tmp.buf[tmp.size]; + tmp.buf[tmp.size] = '\0'; + ret = asn_REAL2double(&tmp, &d); + tmp.buf[tmp.size] = saved_byte; + if(ret) { + rval.code = RC_FAIL; + rval.consumed = 0; + return rval; + } + } else if(length < 48 /* Enough for longish %f value. */) { + tmp.buf = alloca(length + 1); + tmp.size = length; + memcpy(tmp.buf, buf_ptr, length); + tmp.buf[tmp.size] = '\0'; + if(asn_REAL2double(&tmp, &d)) { + rval.code = RC_FAIL; + rval.consumed = 0; + return rval; + } + } else { + /* This should probably never happen: impractically long value */ + tmp.buf = CALLOC(1, length + 1); + tmp.size = length; + if(tmp.buf) memcpy(tmp.buf, buf_ptr, length); + if(!tmp.buf || asn_REAL2double(&tmp, &d)) { + FREEMEM(tmp.buf); + rval.code = RC_FAIL; + rval.consumed = 0; + return rval; + } + FREEMEM(tmp.buf); } *Dbl = d; @@ -199,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. */ @@ -228,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/src/NumericString.c b/src/NumericString.c index 50fe449..81b880a 100644 --- a/src/NumericString.c +++ b/src/NumericString.c @@ -8,7 +8,7 @@ /* * NumericString basic type description. */ -static ber_tlv_tag_t asn_DEF_NumericString_tags[] = { +static const ber_tlv_tag_t asn_DEF_NumericString_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (18 << 2)), /* [UNIVERSAL 18] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ }; @@ -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/src/OBJECT_IDENTIFIER.c b/src/OBJECT_IDENTIFIER.c index 0d7043e..24f4e0e 100644 --- a/src/OBJECT_IDENTIFIER.c +++ b/src/OBJECT_IDENTIFIER.c @@ -3,6 +3,7 @@ * Redistribution and modifications are permitted subject to BSD license. */ #include +#include #include #include #include /* for CHAR_BIT */ @@ -11,7 +12,7 @@ /* * OBJECT IDENTIFIER basic type description. */ -static ber_tlv_tag_t asn_DEF_OBJECT_IDENTIFIER_tags[] = { +static const ber_tlv_tag_t asn_DEF_OBJECT_IDENTIFIER_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (6 << 2)) }; asn_TYPE_descriptor_t asn_DEF_OBJECT_IDENTIFIER = { @@ -26,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) @@ -64,9 +67,9 @@ OBJECT_IDENTIFIER_constraint(asn_TYPE_descriptor_t *td, const void *sptr, int -OBJECT_IDENTIFIER_get_single_arc(uint8_t *arcbuf, unsigned int arclen, signed int add, void *rvbufp, unsigned int rvsize) { +OBJECT_IDENTIFIER_get_single_arc(const uint8_t *arcbuf, unsigned int arclen, signed int add, void *rvbufp, unsigned int rvsize) { unsigned LE GCC_NOTUSED = 1; /* Little endian (x86) */ - uint8_t *arcend = arcbuf + arclen; /* End of arc */ + const uint8_t *arcend = arcbuf + arclen; /* End of arc */ unsigned int cache = 0; /* No more than 14 significant bits */ unsigned char *rvbuf = (unsigned char *)rvbufp; unsigned char *rvstart = rvbuf; /* Original start of the value buffer */ @@ -119,7 +122,7 @@ OBJECT_IDENTIFIER_get_single_arc(uint8_t *arcbuf, unsigned int arclen, signed in errno = ERANGE; /* Overflow */ return -1; } - *(unsigned long *)rvbuf = accum + add; /* alignment OK! */ + *(unsigned long *)(void *)rvbuf = accum + add; /* alignment OK! */ return 0; } @@ -180,7 +183,7 @@ OBJECT_IDENTIFIER_get_single_arc(uint8_t *arcbuf, unsigned int arclen, signed in } ssize_t -OBJECT_IDENTIFIER__dump_arc(uint8_t *arcbuf, int arclen, int add, +OBJECT_IDENTIFIER__dump_arc(const uint8_t *arcbuf, int arclen, int add, asn_app_consume_bytes_f *cb, void *app_key) { char scratch[64]; /* Conservative estimate */ unsigned long accum; /* Bits accumulator */ @@ -211,7 +214,7 @@ OBJECT_IDENTIFIER__dump_arc(uint8_t *arcbuf, int arclen, int add, } int -OBJECT_IDENTIFIER_print_arc(uint8_t *arcbuf, int arclen, int add, +OBJECT_IDENTIFIER_print_arc(const uint8_t *arcbuf, int arclen, int add, asn_app_consume_bytes_f *cb, void *app_key) { if(OBJECT_IDENTIFIER__dump_arc(arcbuf, arclen, add, cb, app_key) < 0) @@ -281,15 +284,13 @@ OBJECT_IDENTIFIER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const arcs_count = OBJECT_IDENTIFIER_parse_arcs( (const char *)chunk_buf, chunk_size, arcs, sizeof(s_arcs)/sizeof(s_arcs[0]), &endptr); - if(arcs_count <= 0) { + if(arcs_count < 0) { /* Expecting more than zero arcs */ return XPBD_BROKEN_ENCODING; + } else if(arcs_count == 0) { + return XPBD_NOT_BODY_IGNORE; } - if(endptr < chunk_end) { - /* We have a tail of unrecognized data. Check its safety. */ - if(!xer_is_whitespace(endptr, chunk_end - endptr)) - return XPBD_BROKEN_ENCODING; - } + assert(endptr == chunk_end); if((size_t)arcs_count > sizeof(s_arcs)/sizeof(s_arcs[0])) { arcs = (long *)MALLOC(arcs_count * sizeof(long)); @@ -361,7 +362,7 @@ OBJECT_IDENTIFIER_print(asn_TYPE_descriptor_t *td, const void *sptr, } int -OBJECT_IDENTIFIER_get_arcs(OBJECT_IDENTIFIER_t *oid, void *arcs, +OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *oid, void *arcs, unsigned int arc_type_size, unsigned int arc_slots) { void *arcs_end = (char *)arcs + (arc_type_size * arc_slots); int num_arcs = 0; @@ -649,12 +650,12 @@ OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length, long *arcs, unsigned int arcs_slots, const char **opt_oid_text_end) { unsigned int arcs_count = 0; const char *oid_end; - long value = 0; enum { - ST_SKIPSPACE, + ST_LEADSPACE, + ST_TAILSPACE, + ST_AFTERVALUE, /* Next character ought to be '.' or a space */ ST_WAITDIGITS, /* Next character is expected to be a digit */ - ST_DIGITS - } state = ST_SKIPSPACE; + } state = ST_LEADSPACE; if(!oid_text || oid_txt_length < -1 || (arcs_slots && !arcs)) { if(opt_oid_text_end) *opt_oid_text_end = oid_text; @@ -665,41 +666,76 @@ OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length, if(oid_txt_length == -1) oid_txt_length = strlen(oid_text); +#define _OID_CAPTURE_ARC(oid_text, oid_end) do { \ + const char *endp = oid_end; \ + long value; \ + switch(asn_strtol_lim(oid_text, &endp, &value)) { \ + case ASN_STRTOL_EXTRA_DATA: \ + case ASN_STRTOL_OK: \ + if(arcs_count < arcs_slots) \ + arcs[arcs_count] = value; \ + arcs_count++; \ + oid_text = endp - 1; \ + break; \ + case ASN_STRTOL_ERROR_RANGE: \ + if(opt_oid_text_end) \ + *opt_oid_text_end = oid_text; \ + errno = ERANGE; \ + return -1; \ + case ASN_STRTOL_ERROR_INVAL: \ + case ASN_STRTOL_EXPECT_MORE: \ + if(opt_oid_text_end) \ + *opt_oid_text_end = oid_text; \ + errno = EINVAL; \ + return -1; \ + } \ + } while(0) + for(oid_end = oid_text + oid_txt_length; oid_text broken OID */ + return -1; + case ST_LEADSPACE: + case ST_WAITDIGITS: + _OID_CAPTURE_ARC(oid_text, oid_end); + state = ST_AFTERVALUE; continue; } + break; default: /* Unexpected symbols */ state = ST_WAITDIGITS; @@ -713,17 +749,18 @@ OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length, /* Finalize last arc */ switch(state) { + case ST_LEADSPACE: + return 0; /* No OID found in input data */ case ST_WAITDIGITS: - errno = EINVAL; + errno = EINVAL; /* Broken OID */ return -1; - case ST_DIGITS: - if(arcs_count < arcs_slots) - arcs[arcs_count] = value; - arcs_count++; - /* Fall through */ - default: + case ST_AFTERVALUE: + case ST_TAILSPACE: return arcs_count; } + + errno = EINVAL; /* Broken OID */ + return -1; } diff --git a/src/OCTET_STRING.c b/src/OCTET_STRING.c index 584def8..3e424e7 100644 --- a/src/OCTET_STRING.c +++ b/src/OCTET_STRING.c @@ -11,15 +11,15 @@ /* * OCTET STRING basic type description. */ -static ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = { +static const ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) }; -static asn_OCTET_STRING_specifics_t asn_DEF_OCTET_STRING_specs = { +static const asn_OCTET_STRING_specifics_t asn_DEF_OCTET_STRING_specs = { sizeof(OCTET_STRING_t), offsetof(OCTET_STRING_t, _asn_ctx), ASN_OSUBV_STR }; -static asn_per_constraints_t asn_DEF_OCTET_STRING_constraints = { +static const asn_per_constraints_t asn_DEF_OCTET_STRING_constraints = { { APC_CONSTRAINED, 8, 8, 0, 255 }, { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, 0, 0 @@ -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) @@ -580,7 +582,7 @@ asn_enc_rval_t OCTET_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, int ilevel, enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb, void *app_key) { - static const char *h2c = "0123456789ABCDEF"; + const char * const h2c = "0123456789ABCDEF"; const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; asn_enc_rval_t er; char scratch[16 * 3 + 4]; @@ -639,8 +641,8 @@ cb_failed: _ASN_ENCODE_FAILED; } -static struct OCTET_STRING__xer_escape_table_s { - char *string; +static const struct OCTET_STRING__xer_escape_table_s { + const char *string; int size; } OCTET_STRING__xer_escape_table[] = { #define OSXET(s) { s, sizeof(s) - 1 } @@ -702,7 +704,7 @@ OS__check_escaped_control_char(const void *buf, int size) { * nested table lookups). */ for(i = 0; i < 32 /* Don't spend time on the bottom half */; i++) { - struct OCTET_STRING__xer_escape_table_s *el; + const struct OCTET_STRING__xer_escape_table_s *el; el = &OCTET_STRING__xer_escape_table[i]; if(el->size == size && memcmp(buf, el->string, size) == 0) return i; @@ -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,12 +1756,12 @@ 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" : ""); - /* Figure out wheter size lies within PER visible constraint */ + /* Figure out whether size lies within PER visible constraint */ if(csiz->effective_bits >= 0) { if((int)sizeinunits < csiz->lower_bound @@ -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,10 +1842,177 @@ 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) { - static const char *h2c = "0123456789ABCDEF"; + const char * const h2c = "0123456789ABCDEF"; const OCTET_STRING_t *st = (const OCTET_STRING_t *)sptr; char scratch[16 * 3 + 4]; char *p = scratch; diff --git a/src/ObjectDescriptor.c b/src/ObjectDescriptor.c index cd8e8a3..f049c1c 100644 --- a/src/ObjectDescriptor.c +++ b/src/ObjectDescriptor.c @@ -8,7 +8,7 @@ /* * ObjectDescriptor basic type description. */ -static ber_tlv_tag_t asn_DEF_ObjectDescriptor_tags[] = { +static const ber_tlv_tag_t asn_DEF_ObjectDescriptor_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (7 << 2)), /* [UNIVERSAL 7] IMPLICIT ... */ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ }; @@ -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/src/PrintableString.c b/src/PrintableString.c index c8ee3ae..3058d09 100644 --- a/src/PrintableString.c +++ b/src/PrintableString.c @@ -9,7 +9,7 @@ /* * ASN.1:1984 (X.409) */ -static int _PrintableString_alphabet[256] = { +static const int _PrintableString_alphabet[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* */ 1, 0, 0, 0, 0, 0, 0, 2, 3, 4, 0, 5, 6, 7, 8, 9, /* . '() +,-./ */ @@ -19,7 +19,7 @@ static int _PrintableString_alphabet[256] = { 0,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, /* abcdefghijklmno */ 64,65,66,67,68,69,70,71,72,73,74, 0, 0, 0, 0, 0, /* pqrstuvwxyz */ }; -static int _PrintableString_code2value[74] = { +static const int _PrintableString_code2value[74] = { 32,39,40,41,43,44,45,46,47,48,49,50,51,52,53,54, 55,56,57,58,61,63,65,66,67,68,69,70,71,72,73,74, 75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90, @@ -29,7 +29,7 @@ static int _PrintableString_code2value[74] = { /* * PrintableString basic type description. */ -static ber_tlv_tag_t asn_DEF_PrintableString_tags[] = { +static const ber_tlv_tag_t asn_DEF_PrintableString_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (19 << 2)), /* [UNIVERSAL 19] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ }; @@ -41,7 +41,7 @@ static int asn_DEF_PrintableString_c2v(unsigned int code) { return _PrintableString_code2value[code]; return -1; } -static asn_per_constraints_t asn_DEF_PrintableString_constraints = { +static const asn_per_constraints_t asn_DEF_PrintableString_constraints = { { APC_CONSTRAINED, 4, 4, 0x20, 0x39 }, /* Value */ { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, /* Size */ asn_DEF_PrintableString_v2c, @@ -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/src/REAL.c b/src/REAL.c index 5e93ac8..e179152 100644 --- a/src/REAL.c +++ b/src/REAL.c @@ -1,10 +1,10 @@ /*- - * Copyright (c) 2004, 2006 Lev Walkin . All rights reserved. + * Copyright (c) 2004-2013 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ -#if defined(__alpha) -#define _ISOC99_SOURCE /* For quiet NAN, through bits/nan.h */ +#define _ISOC99_SOURCE /* For ilogb() and quiet NAN */ #define _BSD_SOURCE /* To reintroduce finite(3) */ +#if defined(__alpha) #include /* For INFINITY */ #endif #include @@ -27,10 +27,16 @@ static volatile double real_zero GCC_NOTUSED = 0.0; #define INFINITY (1.0/real_zero) #endif +#ifdef isfinite +#define _asn_isfinite(d) isfinite(d) /* ISO C99 */ +#else +#define _asn_isfinite(d) finite(d) /* Deprecated on Mac OS X 10.9 */ +#endif + /* * REAL basic type description. */ -static ber_tlv_tag_t asn_DEF_REAL_tags[] = { +static const ber_tlv_tag_t asn_DEF_REAL_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (9 << 2)) }; asn_TYPE_descriptor_t asn_DEF_REAL = { @@ -45,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]), @@ -88,7 +96,7 @@ REAL__dump(double d, int canonical, asn_app_consume_bytes_f *cb, void *app_key) buf = specialRealValue[SRV__NOT_A_NUMBER].string; buflen = specialRealValue[SRV__NOT_A_NUMBER].length; return (cb(buf, buflen, app_key) < 0) ? -1 : buflen; - } else if(!finite(d)) { + } else if(!_asn_isfinite(d)) { if(copysign(1.0, d) < 0.0) { buf = specialRealValue[SRV__MINUS_INFINITY].string; buflen = specialRealValue[SRV__MINUS_INFINITY].length; @@ -137,6 +145,7 @@ REAL__dump(double d, int canonical, asn_app_consume_bytes_f *cb, void *app_key) dot = (buf[0] == 0x2d /* '-' */) ? (buf + 2) : (buf + 1); if(*dot >= 0x30) { + if(buf != local_buf) FREEMEM(buf); errno = EINVAL; return -1; /* Not a dot, really */ } @@ -157,6 +166,7 @@ REAL__dump(double d, int canonical, asn_app_consume_bytes_f *cb, void *app_key) } expptr++; if(expptr > end) { + if(buf != local_buf) FREEMEM(buf); errno = EINVAL; return -1; } @@ -182,6 +192,7 @@ REAL__dump(double d, int canonical, asn_app_consume_bytes_f *cb, void *app_key) } } if(E == end) { + if(buf != local_buf) FREEMEM(buf); errno = EINVAL; return -1; /* No promised E */ } @@ -358,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; @@ -375,10 +401,11 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) { octv = st->buf[0]; /* unsigned byte */ switch(octv & 0xC0) { - case 0x40: /* X.690: 8.5.8 */ + case 0x40: /* X.690: 8.5.6 a) => 8.5.9 */ /* "SpecialRealValue" */ /* Be liberal in what you accept... + * http://en.wikipedia.org/wiki/Robustness_principle if(st->size != 1) ... */ @@ -389,10 +416,6 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) { case 0x41: /* 01000001: MINUS-INFINITY */ *dbl_value = - INFINITY; return 0; - /* - * The following cases are defined by - * X.690 Amendment 1 (10/03) - */ case 0x42: /* 01000010: NOT-A-NUMBER */ *dbl_value = NAN; return 0; @@ -403,21 +426,67 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) { errno = EINVAL; return -1; - case 0x00: { /* X.690: 8.5.6 */ + case 0x00: { /* X.690: 8.5.7 */ /* - * Decimal. NR{1,2,3} format. + * Decimal. NR{1,2,3} format from ISO 6093. + * NR1: [ ]*[+-]?[0-9]+ + * NR2: [ ]*[+-]?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+) + * NR3: [ ]*[+-]?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)[Ee][+-]?[0-9]+ */ double d; + char *buf; + char *endptr; + int used_malloc = 0; + + if(octv == 0 || (octv & 0x3C)) { + /* Remaining values of bits 6 to 1 are Reserved. */ + errno = EINVAL; + return -1; + } - assert(st->buf[st->size - 1] == 0); /* Security, vashu mat' */ - d = strtod((char *)st->buf, 0); - if(finite(d)) { + /* 1. By contract, an input buffer should be null-terminated. + * OCTET STRING decoder ensures that, as is asn_double2REAL(). + * 2. ISO 6093 specifies COMMA as a possible decimal separator. + * However, strtod() can't always deal with COMMA. + * So her we fix both by reallocating, copying and fixing. + */ + if(st->buf[st->size] || memchr(st->buf, ',', st->size)) { + uint8_t *p, *end; + char *b; + if(st->size > 100) { + /* Avoid malicious stack overflow in alloca() */ + buf = (char *)MALLOC(st->size); + if(!buf) return -1; + used_malloc = 1; + } else { + buf = alloca(st->size); + } + b = buf; + /* Copy without the first byte and with 0-termination */ + for(p = st->buf + 1, end = st->buf + st->size; + p < end; b++, p++) + *b = (*p == ',') ? '.' : *p; + *b = '\0'; + } else { + buf = (char *)&st->buf[1]; + } + + endptr = buf; + d = strtod(buf, &endptr); + if(*endptr != '\0') { + /* Format is not consistent with ISO 6093 */ + if(used_malloc) FREEMEM(buf); + errno = EINVAL; + return -1; + } + if(used_malloc) FREEMEM(buf); + if(_asn_isfinite(d)) { *dbl_value = d; return 0; } else { errno = ERANGE; - return 0; + return -1; } } } @@ -476,13 +545,11 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) { /* Okay, the exponent is here. Now, what about mantissa? */ end = st->buf + st->size; - if(ptr < end) { - for(; ptr < end; ptr++) - m = ldexp(m, 8) + *ptr; - } + for(; ptr < end; ptr++) + m = ldexp(m, 8) + *ptr; if(0) - ASN_DEBUG("m=%.10f, scF=%d, bF=%d, expval=%d, ldexp()=%f, ldexp()=%f", + ASN_DEBUG("m=%.10f, scF=%d, bF=%d, expval=%d, ldexp()=%f, ldexp()=%f\n", m, scaleF, baseF, expval, ldexp(m, expval * baseF + scaleF), ldexp(m, scaleF) * pow(pow(2, baseF), expval) @@ -494,7 +561,7 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) { m = ldexp(m, scaleF) * pow(pow(2, base), expval); */ m = ldexp(m, expval * baseF + scaleF); - if(finite(m)) { + if(_asn_isfinite(m)) { *dbl_value = sign ? -m : m; } else { errno = ERANGE; @@ -555,7 +622,7 @@ asn_double2REAL(REAL_t *st, double dbl_value) { st->buf[0] = 0x42; /* NaN */ st->buf[1] = 0; st->size = 1; - } else if(!finite(dbl_value)) { + } else if(!_asn_isfinite(dbl_value)) { if(copysign(1.0, dbl_value) < 0.0) { st->buf[0] = 0x41; /* MINUS-INFINITY */ } else { @@ -564,14 +631,14 @@ asn_double2REAL(REAL_t *st, double dbl_value) { st->buf[1] = 0; st->size = 1; } else { - if(copysign(1.0, dbl_value) < 0.0) { - st->buf[0] = 0x80 | 0x40; - st->buf[1] = 0; - st->size = 2; - } else { + if(copysign(1.0, dbl_value) >= 0.0) { /* no content octets: positive zero */ st->buf[0] = 0; /* JIC */ st->size = 0; + } else { + /* Negative zero. #8.5.3, 8.5.9 */ + st->buf[0] = 0x43; + st->size = 1; } } return 0; @@ -630,7 +697,7 @@ asn_double2REAL(REAL_t *st, double dbl_value) { accum = mval << ishift; } - /* Adjust mantissa appropriately. */ + /* Adjust exponent appropriately. */ expval += shift_count; } diff --git a/src/RELATIVE-OID.c b/src/RELATIVE-OID.c index 983fc09..8e3e97f 100644 --- a/src/RELATIVE-OID.c +++ b/src/RELATIVE-OID.c @@ -13,7 +13,7 @@ /* * RELATIVE-OID basic type description. */ -static ber_tlv_tag_t asn_DEF_RELATIVE_OID_tags[] = { +static const ber_tlv_tag_t asn_DEF_RELATIVE_OID_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (13 << 2)) }; asn_TYPE_descriptor_t asn_DEF_RELATIVE_OID = { @@ -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) @@ -106,14 +108,12 @@ RELATIVE_OID__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void (const char *)chunk_buf, chunk_size, arcs, sizeof(s_arcs)/sizeof(s_arcs[0]), &endptr); if(arcs_count < 0) { - /* Expecting at least zero arcs */ + /* Expecting at least one arc arcs */ return XPBD_BROKEN_ENCODING; + } else if(arcs_count == 0) { + return XPBD_NOT_BODY_IGNORE; } - if(endptr < chunk_end) { - /* We have a tail of unrecognized data. Check its safety. */ - if(!xer_is_whitespace(endptr, chunk_end - endptr)) - return XPBD_BROKEN_ENCODING; - } + assert(endptr == chunk_end); if((size_t)arcs_count > sizeof(s_arcs)/sizeof(s_arcs[0])) { arcs = (long *)MALLOC(arcs_count * sizeof(long)); @@ -164,7 +164,7 @@ RELATIVE_OID_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, } int -RELATIVE_OID_get_arcs(RELATIVE_OID_t *roid, +RELATIVE_OID_get_arcs(const RELATIVE_OID_t *roid, void *arcs, unsigned int arc_type_size, unsigned int arc_slots) { void *arcs_end = (char *)arcs + (arc_slots * arc_type_size); int num_arcs = 0; diff --git a/src/T61String.c b/src/T61String.c index 98461bb..4a6ad47 100644 --- a/src/T61String.c +++ b/src/T61String.c @@ -8,7 +8,7 @@ /* * T61String basic type description. */ -static ber_tlv_tag_t asn_DEF_T61String_tags[] = { +static const ber_tlv_tag_t asn_DEF_T61String_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (20 << 2)), /* [UNIVERSAL 20] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ }; @@ -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/src/TeletexString.c b/src/TeletexString.c index cc2acad..40b5c4e 100644 --- a/src/TeletexString.c +++ b/src/TeletexString.c @@ -8,7 +8,7 @@ /* * TeletexString basic type description. */ -static ber_tlv_tag_t asn_DEF_TeletexString_tags[] = { +static const ber_tlv_tag_t asn_DEF_TeletexString_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (20 << 2)), /* [UNIVERSAL 20] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)), /* ... OCTET STRING */ }; @@ -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/src/UTCTime.c b/src/UTCTime.c index 0abe1db..98a4c15 100644 --- a/src/UTCTime.c +++ b/src/UTCTime.c @@ -18,7 +18,7 @@ /* * UTCTime basic type description. */ -static ber_tlv_tag_t asn_DEF_UTCTime_tags[] = { +static const ber_tlv_tag_t asn_DEF_UTCTime_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (23 << 2)), /* [UNIVERSAL 23] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (26 << 2)), /* [UNIVERSAL 26] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ @@ -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/src/UTF8String.c b/src/UTF8String.c index 7e73d77..4103af3 100644 --- a/src/UTF8String.c +++ b/src/UTF8String.c @@ -9,7 +9,7 @@ /* * UTF8String basic type description. */ -static ber_tlv_tag_t asn_DEF_UTF8String_tags[] = { +static const ber_tlv_tag_t asn_DEF_UTF8String_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (12 << 2)), /* [UNIVERSAL 12] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)), /* ... OCTET STRING */ }; @@ -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) @@ -41,7 +43,7 @@ asn_TYPE_descriptor_t asn_DEF_UTF8String = { * This is the table of length expectations. * The second half of this table is only applicable to the long sequences. */ -static int UTF8String_ht[2][16] = { +static const int UTF8String_ht[2][16] = { { /* 0x0 ... 0x7 */ /* 0000..0111 */ 1, 1, 1, 1, 1, 1, 1, 1, @@ -52,7 +54,7 @@ static int UTF8String_ht[2][16] = { 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, -1, -1 } }; -static int32_t UTF8String_mv[7] = { 0, 0, +static const int32_t UTF8String_mv[7] = { 0, 0, 0x00000080, 0x00000800, 0x00010000, diff --git a/src/UniversalString.c b/src/UniversalString.c index 7d16781..0cffce5 100644 --- a/src/UniversalString.c +++ b/src/UniversalString.c @@ -9,7 +9,7 @@ /* * UniversalString basic type description. */ -static ber_tlv_tag_t asn_DEF_UniversalString_tags[] = { +static const ber_tlv_tag_t asn_DEF_UniversalString_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (28 << 2)), /* [UNIVERSAL 28] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ }; @@ -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/src/VideotexString.c b/src/VideotexString.c index df7233e..e6fc423 100644 --- a/src/VideotexString.c +++ b/src/VideotexString.c @@ -8,7 +8,7 @@ /* * VideotexString basic type description. */ -static ber_tlv_tag_t asn_DEF_VideotexString_tags[] = { +static const ber_tlv_tag_t asn_DEF_VideotexString_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (21 << 2)), /* [UNIVERSAL 21] IMPLICIT */ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ }; @@ -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/src/VisibleString.c b/src/VisibleString.c index 3487b6f..20d1b21 100644 --- a/src/VisibleString.c +++ b/src/VisibleString.c @@ -8,7 +8,7 @@ /* * VisibleString basic type description. */ -static ber_tlv_tag_t asn_DEF_VisibleString_tags[] = { +static const ber_tlv_tag_t asn_DEF_VisibleString_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (26 << 2)), /* [UNIVERSAL 26] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ }; @@ -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/src/asn_codecs_prim.c b/src/asn_codecs_prim.c index a9bc10d..8e604a4 100644 --- a/src/asn_codecs_prim.c +++ b/src/asn_codecs_prim.c @@ -6,8 +6,6 @@ #include #include -void *talloc_asn1_ctx; - /* * Decode an always-primitive type. */ @@ -17,7 +15,7 @@ ber_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, void **sptr, const void *buf_ptr, size_t size, int tag_mode) { ASN__PRIMITIVE_TYPE_t *st = (ASN__PRIMITIVE_TYPE_t *)*sptr; asn_dec_rval_t rval; - ber_tlv_len_t length; + ber_tlv_len_t length = 0; // =0 to avoid [incorrect] warning. /* * If the structure is not there, allocate it. @@ -145,20 +143,26 @@ struct xdp_arg_s { int want_more; }; - +/* + * Since some kinds of primitive values can be encoded using value-specific + * tags (, , etc), the primitive decoder must + * be supplied with such tags to parse them as needed. + */ static int xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) { struct xdp_arg_s *arg = (struct xdp_arg_s *)key; enum xer_pbd_rval bret; - if(arg->decoded_something) { - if(xer_is_whitespace(chunk_buf, chunk_size)) - return 0; /* Skip it. */ - /* - * Decoding was done once already. Prohibit doing it again. - */ + /* + * The chunk_buf is guaranteed to start at '<'. + */ + assert(chunk_size && ((const char *)chunk_buf)[0] == 0x3c); + + /* + * Decoding was performed once already. Prohibit doing it again. + */ + if(arg->decoded_something) return -1; - } bret = arg->prim_body_decoder(arg->type_descriptor, arg->struct_key, chunk_buf, chunk_size); @@ -179,13 +183,20 @@ xer_decode__unexpected_tag(void *key, const void *chunk_buf, size_t chunk_size) } static ssize_t -xer_decode__body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) { +xer_decode__primitive_body(void *key, const void *chunk_buf, size_t chunk_size, int have_more) { struct xdp_arg_s *arg = (struct xdp_arg_s *)key; enum xer_pbd_rval bret; + size_t lead_wsp_size; if(arg->decoded_something) { - if(xer_is_whitespace(chunk_buf, chunk_size)) + if(xer_whitespace_span(chunk_buf, chunk_size) == chunk_size) { + /* + * Example: + * "123 " + * ^- chunk_buf position. + */ return chunk_size; + } /* * Decoding was done once already. Prohibit doing it again. */ @@ -205,6 +216,10 @@ xer_decode__body(void *key, const void *chunk_buf, size_t chunk_size, int have_m return -1; } + lead_wsp_size = xer_whitespace_span(chunk_buf, chunk_size); + chunk_buf = (const char *)chunk_buf + lead_wsp_size; + chunk_size -= lead_wsp_size; + bret = arg->prim_body_decoder(arg->type_descriptor, arg->struct_key, chunk_buf, chunk_size); switch(bret) { @@ -217,7 +232,7 @@ xer_decode__body(void *key, const void *chunk_buf, size_t chunk_size, int have_m arg->decoded_something = 1; /* Fall through */ case XPBD_NOT_BODY_IGNORE: /* Safe to proceed further */ - return chunk_size; + return lead_wsp_size + chunk_size; } return -1; @@ -255,7 +270,7 @@ xer_decode_primitive(asn_codec_ctx_t *opt_codec_ctx, rc = xer_decode_general(opt_codec_ctx, &s_ctx, &s_arg, xml_tag, buf_ptr, size, - xer_decode__unexpected_tag, xer_decode__body); + xer_decode__unexpected_tag, xer_decode__primitive_body); switch(rc.code) { case RC_OK: if(!s_arg.decoded_something) { diff --git a/src/ber_decoder.c b/src/ber_decoder.c index 601f66c..0f99400 100644 --- a/src/ber_decoder.c +++ b/src/ber_decoder.c @@ -206,7 +206,7 @@ ber_check_tags(asn_codec_ctx_t *opt_codec_ctx, */ len_len = ber_fetch_length(tlv_constr, (const char *)ptr + tag_len, size - tag_len, &tlv_len); - ASN_DEBUG("Fetchinig len = %ld", (long)len_len); + ASN_DEBUG("Fetching len = %ld", (long)len_len); switch(len_len) { case -1: RETURN(RC_FAIL); case 0: RETURN(RC_WMORE); diff --git a/src/constr_CHOICE.c b/src/constr_CHOICE.c index 4f0d992..18c24cd 100644 --- a/src/constr_CHOICE.c +++ b/src/constr_CHOICE.c @@ -183,11 +183,11 @@ CHOICE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, } do { - asn_TYPE_tag2member_t *t2m; + const asn_TYPE_tag2member_t *t2m; asn_TYPE_tag2member_t key; key.el_tag = tlv_tag; - t2m = (asn_TYPE_tag2member_t *)bsearch(&key, + t2m = (const asn_TYPE_tag2member_t *)bsearch(&key, specs->tag2el, specs->tag2el_count, sizeof(specs->tag2el[0]), _search4tag); if(t2m) { @@ -445,7 +445,7 @@ CHOICE_encode_der(asn_TYPE_descriptor_t *td, void *sptr, } ber_tlv_tag_t -CHOICE_outmost_tag(asn_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ber_tlv_tag_t tag) { +CHOICE_outmost_tag(const asn_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ber_tlv_tag_t tag) { asn_CHOICE_specifics_t *specs = (asn_CHOICE_specifics_t *)td->specifics; int present; @@ -458,7 +458,7 @@ CHOICE_outmost_tag(asn_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ber present = _fetch_present_idx(ptr, specs->pres_offset, specs->pres_size); if(present > 0 || present <= td->elements_count) { - asn_TYPE_member_t *elm = &td->elements[present-1]; + const asn_TYPE_member_t *elm = &td->elements[present-1]; const void *memb_ptr; if(elm->flags & ATF_POINTER) { @@ -535,7 +535,7 @@ CHOICE_constraint(asn_TYPE_descriptor_t *td, const void *sptr, #undef XER_ADVANCE #define XER_ADVANCE(num_bytes) do { \ size_t num = num_bytes; \ - buf_ptr = ((const char *)buf_ptr) + num;\ + buf_ptr = (const void *)(((const char *)buf_ptr) + num); \ size -= num; \ consumed_myself += num; \ } while(0) @@ -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) { @@ -913,10 +994,11 @@ CHOICE_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraint_t *ct; void *memb_ptr; int present; + int present_enc; 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; @@ -934,15 +1016,17 @@ CHOICE_encode_uper(asn_TYPE_descriptor_t *td, else present--; + ASN_DEBUG("Encoding %s CHOICE element %d", td->name, 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); + present_enc = specs->canonical_order[present]; + else + present_enc = present; if(ct && ct->range_bits >= 0) { - if(present < ct->lower_bound - || present > ct->upper_bound) { + if(present_enc < ct->lower_bound + || present_enc > ct->upper_bound) { if(ct->flags & APC_EXTENSIBLE) { if(per_put_few_bits(po, 1, 1)) _ASN_ENCODE_FAILED; @@ -966,7 +1050,7 @@ CHOICE_encode_uper(asn_TYPE_descriptor_t *td, } if(ct && ct->range_bits >= 0) { - if(per_put_few_bits(po, present, ct->range_bits)) + if(per_put_few_bits(po, present_enc, ct->range_bits)) _ASN_ENCODE_FAILED; return elm->type->uper_encoder(elm->type, elm->per_constraints, @@ -975,7 +1059,7 @@ CHOICE_encode_uper(asn_TYPE_descriptor_t *td, asn_enc_rval_t rval; if(specs->ext_start == -1) _ASN_ENCODE_FAILED; - if(uper_put_nsnnwn(po, present - specs->ext_start)) + if(uper_put_nsnnwn(po, present_enc - specs->ext_start)) _ASN_ENCODE_FAILED; if(uper_open_type_put(elm->type, elm->per_constraints, memb_ptr, po)) @@ -984,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/src/constr_SEQUENCE.c b/src/constr_SEQUENCE.c index db3c925..21e5190 100644 --- a/src/constr_SEQUENCE.c +++ b/src/constr_SEQUENCE.c @@ -34,7 +34,7 @@ #undef ADVANCE #define ADVANCE(num_bytes) do { \ size_t num = num_bytes; \ - ptr = ((const char *)ptr) + num;\ + ptr = ((const char *)ptr) + num; \ size -= num; \ if(ctx->left >= 0) \ ctx->left -= num; \ @@ -310,16 +310,16 @@ SEQUENCE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, * Resort to a binary search over * sorted array of tags. */ - asn_TYPE_tag2member_t *t2m; + const asn_TYPE_tag2member_t *t2m; asn_TYPE_tag2member_t key; key.el_tag = tlv_tag; key.el_no = edx; - t2m = (asn_TYPE_tag2member_t *)bsearch(&key, + t2m = (const asn_TYPE_tag2member_t *)bsearch(&key, specs->tag2el, specs->tag2el_count, sizeof(specs->tag2el[0]), _t2e_cmp); if(t2m) { - asn_TYPE_tag2member_t *best = 0; - asn_TYPE_tag2member_t *t2m_f, *t2m_l; + const asn_TYPE_tag2member_t *best = 0; + const asn_TYPE_tag2member_t *t2m_f, *t2m_l; int edx_max = edx + elements[edx].optional; /* * Rewind to the first element with that tag, @@ -667,8 +667,7 @@ SEQUENCE_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, if(elm->flags & ATF_POINTER) { /* Member is a pointer to another structure */ - memb_ptr2 = (void **)((char *)st - + elm->memb_offset); + memb_ptr2 = (void **)((char *)st + elm->memb_offset); } else { memb_ptr = (char *)st + elm->memb_offset; memb_ptr2 = &memb_ptr; @@ -1132,6 +1131,219 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, /* 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 %ld present in %s", (long)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 %ld bits (%x..)", + td->name, (long)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; +} + +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. */ @@ -1283,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; @@ -1421,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/src/constr_SEQUENCE_OF.c b/src/constr_SEQUENCE_OF.c index aa10117..6981c8b 100644 --- a/src/constr_SEQUENCE_OF.c +++ b/src/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/src/constr_SET.c b/src/constr_SET.c index ecf5661..8a124c0 100644 --- a/src/constr_SET.c +++ b/src/constr_SET.c @@ -175,7 +175,7 @@ SET_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, * for optimization. */ for(;; ctx->step = 0) { - asn_TYPE_tag2member_t *t2m; + const asn_TYPE_tag2member_t *t2m; asn_TYPE_tag2member_t key; void *memb_ptr; /* Pointer to the member */ void **memb_ptr2; /* Pointer to that pointer */ @@ -225,7 +225,7 @@ SET_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, } key.el_tag = tlv_tag; - t2m = (asn_TYPE_tag2member_t *)bsearch(&key, + t2m = (const asn_TYPE_tag2member_t *)bsearch(&key, specs->tag2el, specs->tag2el_count, sizeof(specs->tag2el[0]), _t2e_cmp); if(t2m) { @@ -404,7 +404,7 @@ _SET_is_populated(asn_TYPE_descriptor_t *td, void *st) { unsigned int midx, pres, must; midx = edx/(8 * sizeof(specs->_mandatory_elements[0])); - pres = ((unsigned int *)((char *)st+specs->pres_offset))[midx]; + pres = ((unsigned int *)((char *)st + specs->pres_offset))[midx]; must = sys_ntohl(specs->_mandatory_elements[midx]); if((pres & must) == must) { @@ -439,7 +439,8 @@ SET_encode_der(asn_TYPE_descriptor_t *td, size_t computed_size = 0; asn_enc_rval_t er; int t2m_build_own = (specs->tag2el_count != td->elements_count); - asn_TYPE_tag2member_t *t2m; + const asn_TYPE_tag2member_t *t2m; + asn_TYPE_tag2member_t *t2m_build; int t2m_count; ssize_t ret; int edx; @@ -448,17 +449,16 @@ SET_encode_der(asn_TYPE_descriptor_t *td, * 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_build = (asn_TYPE_tag2member_t *)alloca( + td->elements_count * sizeof(t2m_build[0])); + if(!t2m_build) _ASN_ENCODE_FAILED; /* There are such platforms */ t2m_count = 0; } else { + t2m_build = NULL; /* * There is no untagged CHOICE in this SET. * Employ existing table. */ - t2m = specs->tag2el; - t2m_count = specs->tag2el_count; } /* @@ -479,8 +479,8 @@ SET_encode_der(asn_TYPE_descriptor_t *td, /* Mandatory elements missing */ _ASN_ENCODE_FAILED; if(t2m_build_own) { - t2m[t2m_count].el_no = edx; - t2m[t2m_count].el_tag = 0; + t2m_build[t2m_count].el_no = edx; + t2m_build[t2m_count].el_tag = 0; t2m_count++; } continue; @@ -499,8 +499,8 @@ SET_encode_der(asn_TYPE_descriptor_t *td, * 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( + t2m_build[t2m_count].el_no = edx; + t2m_build[t2m_count].el_tag = asn_TYPE_outmost_tag( elm->type, memb_ptr, elm->tag_mode, elm->tag); t2m_count++; } else { @@ -513,18 +513,21 @@ SET_encode_der(asn_TYPE_descriptor_t *td, /* * 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); + qsort(t2m_build, t2m_count, sizeof(specs->tag2el[0]), _t2e_cmp); + t2m = t2m_build; } else { /* * Tags are already sorted by the compiler. */ + t2m = specs->tag2el; + t2m_count = specs->tag2el_count; } + assert(t2m_count == td->elements_count); /* * Encode the TLV for the sequence itself. @@ -570,6 +573,186 @@ 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_ENCODE_FAILED; +} + +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_DECODE_FAILED; +} + +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; + int t2m_build_own = (specs->tag2el_count != td->elements_count); + const asn_TYPE_tag2member_t *t2m; + asn_TYPE_tag2member_t *t2m_build; + 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_build = (asn_TYPE_tag2member_t *)alloca( + td->elements_count * sizeof(t2m[0])); + if(!t2m_build) _ASN_ENCODE_FAILED; /* There are such platforms */ + t2m_count = 0; + } else { + t2m_build = NULL; + /* + * There is no untagged CHOICE in this SET. + * Employ existing table. + */ + } + + /* + * Gather the length of the underlying members sequence. + */ + for(edx = 0; edx < td->elements_count; edx++) { + asn_TYPE_member_t *elm = &td->elements[edx]; + 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_build[t2m_count].el_no = edx; + t2m_build[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_build[t2m_count].el_no = edx; + t2m_build[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_build, t2m_count, sizeof(specs->tag2el[0]), _t2e_cmp); + t2m = t2m_build; + } else { + /* + * Tags are already sorted by the compiler. + */ + t2m = specs->tag2el; + t2m_count = specs->tag2el_count; + } + assert(t2m_count == td->elements_count); + + 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; \ @@ -648,8 +831,7 @@ SET_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, if(elm->flags & ATF_POINTER) { /* Member is a pointer to another structure */ - memb_ptr2 = (void **)((char *)st - + elm->memb_offset); + memb_ptr2 = (void **)((char *)st + elm->memb_offset); } else { memb_ptr = (char *)st + elm->memb_offset; memb_ptr2 = &memb_ptr; @@ -804,7 +986,7 @@ SET_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, asn_SET_specifics_t *specs = (asn_SET_specifics_t *)td->specifics; asn_enc_rval_t er; int xcan = (flags & XER_F_CANONICAL); - asn_TYPE_tag2member_t *t2m = specs->tag2el_cxer; + const asn_TYPE_tag2member_t *t2m = specs->tag2el_cxer; int t2m_count = specs->tag2el_cxer_count; int edx; diff --git a/src/constr_SET_OF.c b/src/constr_SET_OF.c index 11eac57..2fd530e 100644 --- a/src/constr_SET_OF.c +++ b/src/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; @@ -915,7 +915,7 @@ SET_OF_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, nelems = uper_get_length(pd, ct ? ct->effective_bits : -1, &repeat); ASN_DEBUG("Got to decode %d elements (eff %d)", - (int)nelems, (int)ct ? ct->effective_bits : -1); + (int)nelems, (int)(ct ? ct->effective_bits : -1)); if(nelems < 0) _ASN_DECODE_STARVED; } @@ -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/src/constr_TYPE.c b/src/constr_TYPE.c index 4bc88d4..322f68c 100644 --- a/src/constr_TYPE.c +++ b/src/constr_TYPE.c @@ -17,7 +17,7 @@ static asn_app_consume_bytes_f _print2fp; * Return the outmost tag of the type. */ ber_tlv_tag_t -asn_TYPE_outmost_tag(asn_TYPE_descriptor_t *type_descriptor, +asn_TYPE_outmost_tag(const asn_TYPE_descriptor_t *type_descriptor, const void *struct_ptr, int tag_mode, ber_tlv_tag_t tag) { if(tag_mode) diff --git a/src/der_encoder.c b/src/der_encoder.c index 6c859e1..1c01480 100644 --- a/src/der_encoder.c +++ b/src/der_encoder.c @@ -80,8 +80,8 @@ der_write_tags(asn_TYPE_descriptor_t *sd, ber_tlv_tag_t tag, /* EXPLICIT or IMPLICIT tag */ asn_app_consume_bytes_f *cb, void *app_key) { - ber_tlv_tag_t *tags; /* Copy of tags stream */ - int tags_count; /* Number of tags */ + const ber_tlv_tag_t *tags; /* Copy of tags stream */ + int tags_count; /* Number of tags */ size_t overall_length; ssize_t *lens; int i; @@ -102,8 +102,9 @@ der_write_tags(asn_TYPE_descriptor_t *sd, * and initialize it appropriately. */ int stag_offset; - tags = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t)); - if(!tags) { /* Can fail on !x86 */ + ber_tlv_tag_t *tags_buf; + tags_buf = (ber_tlv_tag_t *)alloca((sd->tags_count + 1) * sizeof(ber_tlv_tag_t)); + if(!tags_buf) { /* Can fail on !x86 */ errno = ENOMEM; return -1; } @@ -111,10 +112,11 @@ der_write_tags(asn_TYPE_descriptor_t *sd, + 1 /* EXPLICIT or IMPLICIT tag is given */ - ((tag_mode == -1) && sd->tags_count); /* Copy tags over */ - tags[0] = tag; + tags_buf[0] = tag; stag_offset = -1 + ((tag_mode == -1) && sd->tags_count); for(i = 1; i < tags_count; i++) - tags[i] = sd->tags[i + stag_offset]; + tags_buf[i] = sd->tags[i + stag_offset]; + tags = tags_buf; } else { tags = sd->tags; tags_count = sd->tags_count; diff --git a/src/per_decoder.c b/src/per_decoder.c index 2b3d2e2..20fe1a1 100644 --- a/src/per_decoder.c +++ b/src/per_decoder.c @@ -12,6 +12,35 @@ uper_decode_complete(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_dec_rval_t rval; rval = uper_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(((const 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 +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, @@ -81,8 +110,8 @@ uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sp /* 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); + ASN_DEBUG("PER decoding consumed %ld, counted %ld", + (long)rval.consumed, (long)pd.moved); assert(rval.consumed == pd.moved); } else { /* PER codec is not a restartable */ @@ -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/src/per_encoder.c b/src/per_encoder.c index f4bace0..02dc3a2 100644 --- a/src/per_encoder.c +++ b/src/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; @@ -88,11 +101,40 @@ uper_encode_to_new_buffer(asn_TYPE_descriptor_t *td, asn_per_constraints_t *cons } default: *buffer_r = key.buffer; - ASN_DEBUG("Complete encoded in %d bits", er.encoded); + ASN_DEBUG("Complete encoded in %ld bits", (long)er.encoded); return ((er.encoded + 7) >> 3); } } +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/src/per_opentype.c b/src/per_opentype.c index c749c8c..984a96d 100644 --- a/src/per_opentype.c +++ b/src/per_opentype.c @@ -18,8 +18,6 @@ static int uper_ugot_refill(asn_per_data_t *pd); static int per_skip_bits(asn_per_data_t *pd, int skip_nbits); static asn_dec_rval_t uper_sot_suck(asn_codec_ctx_t *, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd); -int asn_debug_indent; - /* * Encode an "open type field". * #10.1, #10.2 @@ -38,6 +36,37 @@ uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints for(bptr = buf, toGo = size; toGo;) { ssize_t maySave = uper_put_length(po, toGo); + ASN_DEBUG("Prepending length %d to %s and allowing to save %d", + (int)size, td->name, (int)maySave); + 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 %ld + overhead (1byte?)", + td->name, (long)size); + + 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; @@ -48,7 +77,7 @@ uper_open_type_put(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints if(toGo) return -1; ASN_DEBUG("Open type put %s of length %d + overhead (1byte?)", - td->name, size); + td->name, size); return 0; } @@ -92,28 +121,31 @@ uper_open_type_get_simple(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, bufLen += chunk_bytes; } while(repeat); - ASN_DEBUG("Getting open type %s encoded in %d bytes", td->name, - bufLen); + ASN_DEBUG("Getting open type %s encoded in %ld bytes", td->name, + (long)bufLen); memset(&spd, 0, sizeof(spd)); spd.buffer = buf; spd.nbits = bufLen << 3; - asn_debug_indent += 4; + ASN_DEBUG_INDENT_ADD(+4); rv = td->uper_decoder(ctx, td, constraints, sptr, &spd); - asn_debug_indent -= 4; + ASN_DEBUG_INDENT_ADD(-4); if(rv.code == RC_OK) { /* Check padding validity */ padding = spd.nbits - spd.nboff; - if(padding < 8 && per_get_few_bits(&spd, padding) == 0) { + if ((padding < 8 || + /* X.691#10.1.3 */ + (spd.nboff == 0 && spd.nbits == 8 && spd.buffer == buf)) && + per_get_few_bits(&spd, padding) == 0) { /* Everything is cool */ FREEMEM(buf); return rv; } FREEMEM(buf); if(padding >= 8) { - ASN_DEBUG("Too large padding %d in open type", padding); + ASN_DEBUG("Too large padding %d in open type", (int)padding); _ASN_DECODE_FAILED; } else { ASN_DEBUG("Non-zero padding"); @@ -148,9 +180,9 @@ uper_open_type_get_complex(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, pd->nbits = pd->nboff; /* 0 good bits at this point, will refill */ pd->moved = 0; /* This now counts the open type size in bits */ - asn_debug_indent += 4; + ASN_DEBUG_INDENT_ADD(+4); rv = td->uper_decoder(ctx, td, constraints, sptr, pd); - asn_debug_indent -= 4; + ASN_DEBUG_INDENT_ADD(-4); #define UPDRESTOREPD do { \ /* buffer and nboff are valid, preserve them. */ \ @@ -165,24 +197,23 @@ uper_open_type_get_complex(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, return rv; } - ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d" - , td->name, + ASN_DEBUG("OpenType %s pd%s old%s unclaimed=%d, repeat=%d", td->name, per_data_string(pd), per_data_string(&arg.oldpd), - arg.unclaimed, arg.repeat); + (int)arg.unclaimed, (int)arg.repeat); padding = pd->moved % 8; if(padding) { int32_t pvalue; if(padding > 7) { ASN_DEBUG("Too large padding %d in open type", - padding); + (int)padding); rv.code = RC_FAIL; UPDRESTOREPD; return rv; } padding = 8 - padding; - ASN_DEBUG("Getting padding of %d bits", padding); + ASN_DEBUG("Getting padding of %d bits", (int)padding); pvalue = per_get_few_bits(pd, padding); switch(pvalue) { case -1: @@ -192,7 +223,7 @@ uper_open_type_get_complex(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, case 0: break; default: ASN_DEBUG("Non-blank padding (%d bits 0x%02x)", - padding, (int)pvalue); + (int)padding, (int)pvalue); UPDRESTOREPD; _ASN_DECODE_FAILED; } @@ -212,14 +243,14 @@ uper_open_type_get_complex(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, UPDRESTOREPD; /* Skip data not consumed by the decoder */ - if(arg.unclaimed) ASN_DEBUG("Getting unclaimed %d", arg.unclaimed); if(arg.unclaimed) { + ASN_DEBUG("Getting unclaimed %d", (int)arg.unclaimed); switch(per_skip_bits(pd, arg.unclaimed)) { case -1: - ASN_DEBUG("Claim of %d failed", arg.unclaimed); + ASN_DEBUG("Claim of %d failed", (int)arg.unclaimed); _ASN_DECODE_STARVED; case 0: - ASN_DEBUG("Got claim of %d", arg.unclaimed); + ASN_DEBUG("Got claim of %d", (int)arg.unclaimed); break; default: /* Padding must be blank */ @@ -243,9 +274,7 @@ asn_dec_rval_t uper_open_type_get(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { - return uper_open_type_get_simple(ctx, td, constraints, - sptr, pd); - + return uper_open_type_get_simple(ctx, td, constraints, sptr, pd); } int @@ -293,8 +322,8 @@ uper_ugot_refill(asn_per_data_t *pd) { asn_per_data_t *oldpd = &arg->oldpd; - ASN_DEBUG("REFILLING pd->moved=%d, oldpd->moved=%d", - pd->moved, oldpd->moved); + ASN_DEBUG("REFILLING pd->moved=%ld, oldpd->moved=%ld", + (long)pd->moved, (long)oldpd->moved); /* Advance our position to where pd is */ oldpd->buffer = pd->buffer; @@ -314,7 +343,8 @@ uper_ugot_refill(asn_per_data_t *pd) { pd->buffer = oldpd->buffer; pd->nboff = oldpd->nboff - 1; pd->nbits = oldpd->nbits; - ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%d)", pd->moved); + ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%ld)", + (long)pd->moved); return 0; } @@ -324,8 +354,8 @@ uper_ugot_refill(asn_per_data_t *pd) { } next_chunk_bytes = uper_get_length(oldpd, -1, &arg->repeat); - ASN_DEBUG("Open type LENGTH %d bytes at off %d, repeat %d", - next_chunk_bytes, oldpd->moved, arg->repeat); + ASN_DEBUG("Open type LENGTH %ld bytes at off %ld, repeat %ld", + (long)next_chunk_bytes, (long)oldpd->moved, (long)arg->repeat); if(next_chunk_bytes < 0) return -1; if(next_chunk_bytes == 0) { pd->refill = 0; /* No more refills, naturally */ @@ -336,14 +366,16 @@ uper_ugot_refill(asn_per_data_t *pd) { if(avail >= next_chunk_bits) { pd->nbits = oldpd->nboff + next_chunk_bits; arg->unclaimed = 0; - ASN_DEBUG("!+Parent frame %d bits, alloting %d [%d..%d] (%d)", - next_chunk_bits, oldpd->moved, - oldpd->nboff, oldpd->nbits, - oldpd->nbits - oldpd->nboff); + ASN_DEBUG("!+Parent frame %ld bits, alloting %ld [%ld..%ld] (%ld)", + (long)next_chunk_bits, (long)oldpd->moved, + (long)oldpd->nboff, (long)oldpd->nbits, + (long)(oldpd->nbits - oldpd->nboff)); } else { pd->nbits = oldpd->nbits; arg->unclaimed = next_chunk_bits - avail; - ASN_DEBUG("!-Parent frame %d, require %d, will claim %d", avail, next_chunk_bits, arg->unclaimed); + ASN_DEBUG("!-Parent frame %ld, require %ld, will claim %ld", + (long)avail, (long)next_chunk_bits, + (long)arg->unclaimed); } pd->buffer = oldpd->buffer; pd->nboff = oldpd->nboff; @@ -357,7 +389,9 @@ per_skip_bits(asn_per_data_t *pd, int skip_nbits) { int hasNonZeroBits = 0; while(skip_nbits > 0) { int skip; - if(skip_nbits < skip) + + /* per_get_few_bits() is more efficient when nbits <= 24 */ + if(skip_nbits < 24) skip = skip_nbits; else skip = 24; diff --git a/src/per_support.c b/src/per_support.c index 173e696..d536bc0 100644 --- a/src/per_support.c +++ b/src/per_support.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, 2007 Lev Walkin . + * Copyright (c) 2005-2014 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ @@ -13,11 +13,11 @@ per_data_string(asn_per_data_t *pd) { static int n; n = (n+1) % 2; snprintf(buf[n], sizeof(buf), - "{m=%d span %+d[%d..%d] (%d)}", - pd->moved, - (((int)pd->buffer) & 0xf), - pd->nboff, pd->nbits, - pd->nbits - pd->nboff); + "{m=%ld span %+ld[%d..%d] (%d)}", + (long)pd->moved, + (((long)pd->buffer) & 0xf), + (int)pd->nboff, (int)pd->nbits, + (int)(pd->nbits - pd->nboff)); return buf[n]; } @@ -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. */ @@ -49,7 +59,8 @@ per_get_few_bits(asn_per_data_t *pd, int nbits) { int32_t tailv, vhead; if(!pd->refill || nbits > 31) return -1; /* Accumulate unused bytes before refill */ - ASN_DEBUG("Obtain the rest %d bits (want %d)", nleft, nbits); + ASN_DEBUG("Obtain the rest %d bits (want %d)", + (int)nleft, (int)nbits); tailv = per_get_few_bits(pd, nleft); if(tailv < 0) return -1; /* Refill (replace pd contents with new data) */ @@ -103,13 +114,13 @@ 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 %+d[%d..%d]:%02x (%d) => 0x%x]", - nbits, nleft, - pd->moved, - (((int)pd->buffer) & 0xf), - pd->nboff, pd->nbits, + 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), + (int)pd->nboff, (int)pd->nbits, pd->buffer[0], - pd->nbits - pd->nboff, + (int)(pd->nbits - pd->nboff), (int)accum); return accum; @@ -122,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); @@ -186,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 @@ -200,7 +243,7 @@ uper_get_nslength(asn_per_data_t *pd) { 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); + ASN_DEBUG("l=%d", (int)length); return length; } else { int repeat; @@ -210,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 @@ -236,14 +298,49 @@ 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; +} + /* - * Put the normally small non-negative whole number. - * X.691, #10.6 + * X.691-11/2008, #11.6 + * Encoding of a normally small non-negative whole number */ int uper_put_nsnnwn(asn_per_outp_t *po, int n) { 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); @@ -263,6 +360,58 @@ uper_put_nsnnwn(asn_per_outp_t *po, int n) { } +/* X.691-2008/11, #11.5.6 -> #11.3 */ +int uper_get_constrained_whole_number(asn_per_data_t *pd, unsigned long *out_value, int nbits) { + unsigned long lhalf; /* Lower half of the number*/ + long half; + + if(nbits <= 31) { + half = per_get_few_bits(pd, nbits); + if(half < 0) return -1; + *out_value = half; + return 0; + } + + if((size_t)nbits > 8 * sizeof(*out_value)) + return -1; /* RANGE */ + + half = per_get_few_bits(pd, 31); + if(half < 0) return -1; + + if(uper_get_constrained_whole_number(pd, &lhalf, nbits - 31)) + return -1; + + *out_value = ((unsigned long)half << (nbits - 31)) | lhalf; + return 0; +} + + +/* X.691-2008/11, #11.5.6 -> #11.3 */ +int uper_put_constrained_whole_number_s(asn_per_outp_t *po, long v, int nbits) { + /* + * Assume signed number can be safely coerced into + * unsigned of the same range. + * The following testing code will likely be optimized out + * by compiler if it is true. + */ + unsigned long uvalue1 = ULONG_MAX; + long svalue = uvalue1; + unsigned long uvalue2 = svalue; + assert(uvalue1 == uvalue2); + return uper_put_constrained_whole_number_u(po, v, nbits); +} + +int uper_put_constrained_whole_number_u(asn_per_outp_t *po, unsigned long v, int nbits) { + if(nbits <= 31) { + return per_put_few_bits(po, v, nbits); + } else { + /* Put higher portion first, followed by lower 31-bit */ + if(uper_put_constrained_whole_number_u(po, v >> 31, nbits - 31)) + return -1; + return per_put_few_bits(po, v, 31); + } +} + /* * Put a small number of bits (<= 31). */ @@ -275,7 +424,7 @@ per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) { if(obits <= 0 || obits >= 32) return obits ? -1 : 0; ASN_DEBUG("[PER put %d bits %x to %p+%d bits]", - obits, (int)bits, po->buffer, po->nboff); + obits, (int)bits, po->buffer, (int)po->nboff); /* * Normalize position indicator. @@ -291,8 +440,8 @@ per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) { */ if(po->nboff + obits > po->nbits) { int complete_bytes = (po->buffer - po->tmpspace); - ASN_DEBUG("[PER output %d complete + %d]", - complete_bytes, po->flushed_bytes); + ASN_DEBUG("[PER output %ld complete + %ld]", + (long)complete_bytes, (long)po->flushed_bytes); if(po->outper(po->tmpspace, complete_bytes, po->op_key) < 0) return -1; if(po->nboff) @@ -307,47 +456,106 @@ per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) { */ buf = po->buffer; omsk = ~((1 << (8 - po->nboff)) - 1); - off = (po->nboff += obits); + off = (po->nboff + obits); /* Clear data of debris before meaningful bits */ bits &= (((uint32_t)1 << obits) - 1); ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits, (int)bits, (int)bits, - po->nboff - obits, off, buf[0], omsk&0xff, buf[0] & omsk); + (int)po->nboff, (int)off, + buf[0], (int)(omsk&0xff), + (int)(buf[0] & omsk)); if(off <= 8) /* Completely within 1 byte */ + po->nboff = off, bits <<= (8 - off), buf[0] = (buf[0] & omsk) | bits; else if(off <= 16) + po->nboff = off, bits <<= (16 - off), buf[0] = (buf[0] & omsk) | (bits >> 8), buf[1] = bits; else if(off <= 24) + po->nboff = off, bits <<= (24 - off), buf[0] = (buf[0] & omsk) | (bits >> 16), buf[1] = bits >> 8, buf[2] = bits; else if(off <= 31) + po->nboff = off, bits <<= (32 - off), buf[0] = (buf[0] & omsk) | (bits >> 24), buf[1] = bits >> 16, buf[2] = bits >> 8, buf[3] = bits; else { - ASN_DEBUG("->[PER out split %d]", obits); - po->nboff -= obits; /* undo incrementation from a few lines above */ - per_put_few_bits(po, bits >> (obits - 24), 24); /* shift according to the rest of the bits */ + per_put_few_bits(po, bits >> (obits - 24), 24); per_put_few_bits(po, bits, obits - 24); - ASN_DEBUG("<-[PER out split %d]", obits); } - ASN_DEBUG("[PER out %u/%x => %02x buf+%d]", - (int)bits, (int)bits, buf[0], po->buffer - po->tmpspace); + ASN_DEBUG("[PER out %u/%x => %02x buf+%ld]", + (int)bits, (int)bits, buf[0], + (long)(po->buffer - po->tmpspace)); 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. @@ -387,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; @@ -401,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. @@ -424,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/src/xer_decoder.c b/src/xer_decoder.c index 161dc78..cb4b5f8 100644 --- a/src/xer_decoder.c +++ b/src/xer_decoder.c @@ -109,7 +109,8 @@ xer_check_tag(const void *buf_ptr, int size, const char *need_tag) { if(size < 2 || buf[0] != LANGLE || buf[size-1] != RANGLE) { if(size >= 2) - ASN_DEBUG("Broken XML tag: \"%c...%c\"", buf[0], buf[size - 1]); + ASN_DEBUG("Broken XML tag: \"%c...%c\"", + buf[0], buf[size - 1]); return XCT_BROKEN; } @@ -315,8 +316,8 @@ xer_decode_general(asn_codec_ctx_t *opt_codec_ctx, } -int -xer_is_whitespace(const void *chunk_buf, size_t chunk_size) { +size_t +xer_whitespace_span(const void *chunk_buf, size_t chunk_size) { const char *p = (const char *)chunk_buf; const char *pend = p + chunk_size; @@ -329,12 +330,13 @@ xer_is_whitespace(const void *chunk_buf, size_t chunk_size) { * SPACE (32) */ case 0x09: case 0x0a: case 0x0d: case 0x20: - break; + continue; default: - return 0; + break; } + break; } - return 1; /* All whitespace */ + return (p - (const char *)chunk_buf); } /* diff --git a/src/xer_support.c b/src/xer_support.c index 9e34e69..36b4bfb 100644 --- a/src/xer_support.c +++ b/src/xer_support.c @@ -22,16 +22,7 @@ typedef enum { ST_COMMENT_CLO_RT /* "-->"[1] */ } pstate_e; -static pxml_chunk_type_e final_chunk_type[] = { - PXML_TEXT, - PXML_TAG_END, - PXML_COMMENT_END, - PXML_TAG_END, - PXML_COMMENT_END, -}; - - -static int +static const int _charclass[256] = { 0,0,0,0,0,0,0,0, 0,1,1,0,1,1,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, @@ -79,8 +70,11 @@ _charclass[256] = { #define TOKEN_CB(_type, _ns, _current_too) \ TOKEN_CB_CALL(_type, _ns, _current_too, 0) +#define PXML_TAG_FINAL_CHUNK_TYPE PXML_TAG_END +#define PXML_COMMENT_FINAL_CHUNK_TYPE PXML_COMMENT_END + #define TOKEN_CB_FINAL(_type, _ns, _current_too) \ - TOKEN_CB_CALL(final_chunk_type[_type], _ns, _current_too, 1) + TOKEN_CB_CALL( _type ## _FINAL_CHUNK_TYPE , _ns, _current_too, 1) /* * Parser itself -- cgit v1.2.3