From ec0e217b0647eb798576a7d3366b39c159c00624 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 20 Jul 2010 00:03:44 +0200 Subject: Update to asn1c official repository svn trunk r1409 --- include/asn1c/INTEGER.h | 4 + include/asn1c/Makefile.am | 2 +- include/asn1c/NativeReal.h | 4 +- include/asn1c/OCTET_STRING.h | 8 +- include/asn1c/REAL.h | 2 + include/asn1c/asn_internal.h | 20 +- include/asn1c/asn_system.h | 29 ++- include/asn1c/ber_decoder.h | 1 + include/asn1c/der_encoder.h | 1 + include/asn1c/per_decoder.h | 14 +- include/asn1c/per_encoder.h | 24 ++- include/asn1c/per_opentype.h | 22 +++ include/asn1c/per_support.h | 31 ++- src/ANY.c | 2 +- src/BIT_STRING.c | 9 +- src/BMPString.c | 19 +- src/BOOLEAN.c | 2 +- src/GeneralString.c | 3 +- src/GeneralizedTime.c | 23 ++- src/GraphicString.c | 3 +- src/IA5String.c | 14 +- src/INTEGER.c | 157 ++++++++++++--- src/ISO646String.c | 11 +- src/Makefile.am | 2 +- src/NativeEnumerated.c | 11 +- src/NativeInteger.c | 32 ++- src/NativeReal.c | 73 ++++++- src/NumericString.c | 36 +++- src/OBJECT_IDENTIFIER.c | 10 +- src/OCTET_STRING.c | 451 +++++++++++++++++++++++++++++++++---------- src/ObjectDescriptor.c | 3 +- src/PrintableString.c | 68 ++++--- src/REAL.c | 32 ++- src/RELATIVE-OID.c | 4 +- src/T61String.c | 3 +- src/TeletexString.c | 141 +++++++++++++- src/UTCTime.c | 12 +- src/UTF8String.c | 13 +- src/UniversalString.c | 17 +- src/VideotexString.c | 3 +- src/VisibleString.c | 16 +- src/constr_CHOICE.c | 53 ++--- src/constr_SEQUENCE.c | 244 +++++++++++++++++++---- src/constr_SET.c | 12 +- src/constr_SET_OF.c | 15 +- src/per_decoder.c | 38 ++++ src/per_encoder.c | 136 +++++++++---- src/per_opentype.c | 373 +++++++++++++++++++++++++++++++++++ src/per_support.c | 133 +++++++++++-- 49 files changed, 1962 insertions(+), 374 deletions(-) create mode 100644 include/asn1c/per_opentype.h create mode 100644 src/per_opentype.c diff --git a/include/asn1c/INTEGER.h b/include/asn1c/INTEGER.h index 62832b1..8411bfc 100644 --- a/include/asn1c/INTEGER.h +++ b/include/asn1c/INTEGER.h @@ -30,6 +30,8 @@ typedef struct asn_INTEGER_specifics_s { int map_count; /* Elements in either map */ int extension; /* This map is extensible */ int strict_enumeration; /* Enumeration set is fixed */ + int field_width; /* Size of native integer */ + int field_unsigned; /* Signed=0, unsigned=1 */ } asn_INTEGER_specifics_t; asn_struct_print_f INTEGER_print; @@ -51,7 +53,9 @@ per_type_encoder_f INTEGER_encode_uper; * -1/ENOMEM: Memory allocation failed (in asn_long2INTEGER()). */ int asn_INTEGER2long(const INTEGER_t *i, long *l); +int asn_INTEGER2ulong(const INTEGER_t *i, unsigned long *l); int asn_long2INTEGER(INTEGER_t *i, long l); +int asn_ulong2INTEGER(INTEGER_t *i, unsigned long l); /* * Convert the integer value into the corresponding enumeration map entry. diff --git a/include/asn1c/Makefile.am b/include/asn1c/Makefile.am index 81b654d..899ad78 100644 --- a/include/asn1c/Makefile.am +++ b/include/asn1c/Makefile.am @@ -1,3 +1,3 @@ asn1cdir = $(includedir)/asn1c -asn1c_HEADERS = ANY.h asn_application.h asn_codecs.h asn_codecs_prim.h asn_internal.h asn_SEQUENCE_OF.h asn_SET_OF.h asn_system.h ber_decoder.h ber_tlv_length.h ber_tlv_tag.h BIT_STRING.h BMPString.h BOOLEAN.h constraints.h constr_CHOICE.h constr_SEQUENCE.h constr_SEQUENCE_OF.h constr_SET.h constr_SET_OF.h constr_TYPE.h der_encoder.h ENUMERATED.h GeneralizedTime.h GeneralString.h GraphicString.h IA5String.h INTEGER.h ISO646String.h NativeEnumerated.h NativeInteger.h NativeReal.h NULL.h NumericString.h ObjectDescriptor.h OBJECT_IDENTIFIER.h OCTET_STRING.h per_decoder.h per_encoder.h per_support.h PrintableString.h REAL.h RELATIVE-OID.h T61String.h TeletexString.h UniversalString.h UTCTime.h UTF8String.h VideotexString.h VisibleString.h xer_decoder.h xer_encoder.h xer_support.h +asn1c_HEADERS = ANY.h asn_application.h asn_codecs.h asn_codecs_prim.h asn_internal.h asn_SEQUENCE_OF.h asn_SET_OF.h asn_system.h ber_decoder.h ber_tlv_length.h ber_tlv_tag.h BIT_STRING.h BMPString.h BOOLEAN.h constraints.h constr_CHOICE.h constr_SEQUENCE.h constr_SEQUENCE_OF.h constr_SET.h constr_SET_OF.h constr_TYPE.h der_encoder.h ENUMERATED.h GeneralizedTime.h GeneralString.h GraphicString.h IA5String.h INTEGER.h ISO646String.h NativeEnumerated.h NativeInteger.h NativeReal.h NULL.h NumericString.h ObjectDescriptor.h OBJECT_IDENTIFIER.h OCTET_STRING.h per_decoder.h per_encoder.h per_support.h PrintableString.h REAL.h RELATIVE-OID.h T61String.h TeletexString.h UniversalString.h UTCTime.h UTF8String.h VideotexString.h VisibleString.h xer_decoder.h xer_encoder.h xer_support.h per_opentype.h diff --git a/include/asn1c/NativeReal.h b/include/asn1c/NativeReal.h index 1f5266c..68a81d9 100644 --- a/include/asn1c/NativeReal.h +++ b/include/asn1c/NativeReal.h @@ -6,7 +6,7 @@ * This type differs from the standard REAL in that it is modelled using * the fixed machine type (double), so it can hold only values of * limited precision. There is no explicit type (i.e., NativeReal_t). - * Use of this type is normally enabled by -fnative-integers. + * Use of this type is normally enabled by -fnative-types. */ #ifndef ASN_TYPE_NativeReal_H #define ASN_TYPE_NativeReal_H @@ -25,6 +25,8 @@ ber_type_decoder_f NativeReal_decode_ber; der_type_encoder_f NativeReal_encode_der; 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; #ifdef __cplusplus } diff --git a/include/asn1c/OCTET_STRING.h b/include/asn1c/OCTET_STRING.h index 5150161..8df9a18 100644 --- a/include/asn1c/OCTET_STRING.h +++ b/include/asn1c/OCTET_STRING.h @@ -70,7 +70,13 @@ typedef struct asn_OCTET_STRING_specifics_s { int struct_size; /* Size of the structure */ int ctx_offset; /* Offset of the asn_struct_ctx_t member */ - int subvariant; /* {0,1,2} for O-S, BIT STRING or ANY */ + enum asn_OS_Subvariant { + ASN_OSUBV_ANY, /* The open type (ANY) */ + ASN_OSUBV_BIT, /* BIT STRING */ + ASN_OSUBV_STR, /* String types, not {BMP,Universal}String */ + ASN_OSUBV_U16, /* 16-bit character (BMPString) */ + ASN_OSUBV_U32 /* 32-bit character (UniversalString) */ + } subvariant; } asn_OCTET_STRING_specifics_t; #ifdef __cplusplus diff --git a/include/asn1c/REAL.h b/include/asn1c/REAL.h index 28ccf28..af3e84c 100644 --- a/include/asn1c/REAL.h +++ b/include/asn1c/REAL.h @@ -19,6 +19,8 @@ extern asn_TYPE_descriptor_t asn_DEF_REAL; asn_struct_print_f REAL_print; 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; /*********************************** * Some handy conversion routines. * diff --git a/include/asn1c/asn_internal.h b/include/asn1c/asn_internal.h index 67f055a..249d7ef 100644 --- a/include/asn1c/asn_internal.h +++ b/include/asn1c/asn_internal.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003, 2004, 2005 Lev Walkin . + * Copyright (c) 2003, 2004, 2005, 2007 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ @@ -20,7 +20,7 @@ extern "C" { #endif /* Environment version might be used to avoid running with the old library */ -#define ASN1C_ENVIRONMENT_VERSION 920 /* Compile-time version */ +#define ASN1C_ENVIRONMENT_VERSION 922 /* Compile-time version */ int get_asn1c_environment_version(void); /* Run-time version */ #define CALLOC(nmemb, size) calloc(nmemb, size) @@ -35,10 +35,17 @@ int get_asn1c_environment_version(void); /* Run-time version */ #ifndef ASN_DEBUG /* If debugging code is not defined elsewhere... */ #if EMIT_ASN_DEBUG == 1 /* And it was asked to emit this code... */ #ifdef __GNUC__ -#define ASN_DEBUG(fmt, args...) do { \ - fprintf(stderr, fmt, ##args); \ - fprintf(stderr, " (%s:%d)\n", \ - __FILE__, __LINE__); \ +#ifdef ASN_THREAD_SAFE +#define asn_debug_indent 0 +#else /* !ASN_THREAD_SAFE */ +int asn_debug_indent; +#endif /* ASN_THREAD_SAFE */ +#define ASN_DEBUG(fmt, args...) do { \ + int adi = asn_debug_indent; \ + while(adi--) fprintf(stderr, " "); \ + fprintf(stderr, fmt, ##args); \ + fprintf(stderr, " (%s:%d)\n", \ + __FILE__, __LINE__); \ } while(0) #else /* !__GNUC__ */ void ASN_DEBUG_f(const char *fmt, ...); @@ -70,6 +77,7 @@ static inline void ASN_DEBUG(const char *fmt, ...) { (void)fmt; } int __nl = ((nl) != 0); \ int __i; \ if(__nl) _ASN_CALLBACK("\n", 1); \ + if(__level < 0) __level = 0; \ for(__i = 0; __i < __level; __i++) \ _ASN_CALLBACK(" ", 4); \ er.encoded += __nl + 4 * __level; \ diff --git a/include/asn1c/asn_system.h b/include/asn1c/asn_system.h index d7ebdaa..0a9b092 100644 --- a/include/asn1c/asn_system.h +++ b/include/asn1c/asn_system.h @@ -1,5 +1,6 @@ /*- - * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Copyright (c) 2003, 2004, 2007 Lev Walkin . + * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ /* @@ -16,20 +17,27 @@ #include /* For *alloc(3) */ #include /* For memcpy(3) */ #include /* For size_t */ +#include /* For LONG_MAX */ #include /* For va_start */ #include /* for offsetof and ptrdiff_t */ #ifdef WIN32 #include -#include #define snprintf _snprintf #define vsnprintf _vsnprintf +/* 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)) + #ifdef _MSC_VER /* MSVS.Net */ #ifndef __cplusplus #define inline __inline #endif +#ifndef ASSUMESTDTYPES /* Standard types have been defined elsewhere */ #define ssize_t SSIZE_T typedef char int8_t; typedef short int16_t; @@ -37,6 +45,7 @@ typedef int int32_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; +#endif /* ASSUMESTDTYPES */ #define WIN32_LEAN_AND_MEAN #include #include @@ -44,6 +53,8 @@ typedef unsigned int uint32_t; #define finite _finite #define copysign _copysign #define ilogb _logb +#else /* !_MSC_VER */ +#include #endif /* _MSC_VER */ #else /* !WIN32 */ @@ -74,6 +85,9 @@ typedef unsigned int uint32_t; #endif /* defined(sun) */ #endif +#include /* for ntohl() */ +#define sys_ntohl(foo) ntohl(foo) + #endif /* defined(__vxworks) */ #endif /* WIN32 */ @@ -82,12 +96,23 @@ typedef unsigned int uint32_t; #ifndef GCC_PRINTFLIKE #define GCC_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) #endif +#ifndef GCC_NOTUSED +#define GCC_NOTUSED __attribute__((unused)) +#endif #else #ifndef GCC_PRINTFLIKE #define GCC_PRINTFLIKE(fmt,var) /* nothing */ #endif +#ifndef GCC_NOTUSED +#define GCC_NOTUSED +#endif #endif +/* Figure out if thread safety is requested */ +#if !defined(ASN_THREAD_SAFE) && (defined(THREAD_SAFE) || defined(_REENTRANT)) +#define ASN_THREAD_SAFE +#endif /* Thread safety */ + #ifndef offsetof /* If not defined by */ #define offsetof(s, m) ((ptrdiff_t)&(((s *)0)->m) - (ptrdiff_t)((s *)0)) #endif /* offsetof */ diff --git a/include/asn1c/ber_decoder.h b/include/asn1c/ber_decoder.h index 768133b..9fe2e89 100644 --- a/include/asn1c/ber_decoder.h +++ b/include/asn1c/ber_decoder.h @@ -17,6 +17,7 @@ struct asn_codec_ctx_s; /* Forward declaration */ /* * The BER decoder of any type. * This function may be invoked directly from the application. + * The der_encode() function (der_encoder.h) is an opposite to ber_decode(). */ asn_dec_rval_t ber_decode(struct asn_codec_ctx_s *opt_codec_ctx, struct asn_TYPE_descriptor_s *type_descriptor, diff --git a/include/asn1c/der_encoder.h b/include/asn1c/der_encoder.h index 4e2fb06..61431c6 100644 --- a/include/asn1c/der_encoder.h +++ b/include/asn1c/der_encoder.h @@ -15,6 +15,7 @@ struct asn_TYPE_descriptor_s; /* Forward declaration */ /* * The DER encoder of any type. May be invoked by the application. + * The ber_decode() function (ber_decoder.h) is an opposite of der_encode(). */ asn_enc_rval_t der_encode(struct asn_TYPE_descriptor_s *type_descriptor, void *struct_ptr, /* Structure to be encoded */ diff --git a/include/asn1c/per_decoder.h b/include/asn1c/per_decoder.h index 26aaf59..8397a54 100644 --- a/include/asn1c/per_decoder.h +++ b/include/asn1c/per_decoder.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2005 Lev Walkin . All rights reserved. + * Copyright (c) 2005, 2007 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _PER_DECODER_H_ @@ -14,8 +14,20 @@ extern "C" { struct asn_TYPE_descriptor_s; /* Forward declaration */ +/* + * Unaligned 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 uper_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 */ + ); + /* * Unaligned 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 uper_decode(struct asn_codec_ctx_s *opt_codec_ctx, struct asn_TYPE_descriptor_s *type_descriptor, /* Type to decode */ diff --git a/include/asn1c/per_encoder.h b/include/asn1c/per_encoder.h index 9ac130b..95a6506 100644 --- a/include/asn1c/per_encoder.h +++ b/include/asn1c/per_encoder.h @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2006 Lev Walkin . All rights reserved. + * Copyright (c) 2006, 2007 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _PER_ENCODER_H_ @@ -16,6 +16,9 @@ struct asn_TYPE_descriptor_s; /* Forward declaration */ /* * Unaligned PER encoder of any ASN.1 type. May be invoked by the application. + * WARNING: This function returns the number of encoded bits in the .encoded + * field of the return value. Use the following formula to convert to bytes: + * bytes = ((.encoded + 7) / 8) */ asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor, void *struct_ptr, /* Structure to be encoded */ @@ -23,7 +26,11 @@ asn_enc_rval_t uper_encode(struct asn_TYPE_descriptor_s *type_descriptor, void *app_key /* Arbitrary callback argument */ ); -/* A variant of uper_encode() which encodes data into the existing buffer */ +/* + * A variant of uper_encode() which encodes data into the existing buffer + * WARNING: This function returns the number of encoded bits in the .encoded + * field of the return value. + */ asn_enc_rval_t uper_encode_to_buffer( struct asn_TYPE_descriptor_s *type_descriptor, void *struct_ptr, /* Structure to be encoded */ @@ -31,6 +38,19 @@ asn_enc_rval_t uper_encode_to_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. + * WARNING: This function produces a "Production of the complete encoding", + * with length of at least one octet. Contrast this to precise bit-packing + * encoding of uper_encode() and uper_encode_to_buffer(). + */ +ssize_t uper_encode_to_new_buffer( + struct asn_TYPE_descriptor_s *type_descriptor, + asn_per_constraints_t *constraints, + void *struct_ptr, /* Structure to be encoded */ + void **buffer_r /* Buffer allocated and returned */ +); /* * Type of the generic PER encoder function. diff --git a/include/asn1c/per_opentype.h b/include/asn1c/per_opentype.h new file mode 100644 index 0000000..facfaa6 --- /dev/null +++ b/include/asn1c/per_opentype.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2007 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#ifndef _PER_OPENTYPE_H_ +#define _PER_OPENTYPE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +asn_dec_rval_t uper_open_type_get(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd); + +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); + +#ifdef __cplusplus +} +#endif + +#endif /* _PER_OPENTYPE_H_ */ diff --git a/include/asn1c/per_support.h b/include/asn1c/per_support.h index 420bb83..7cb1a0c 100644 --- a/include/asn1c/per_support.h +++ b/include/asn1c/per_support.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2005, 2006 Lev Walkin . All rights reserved. + * Copyright (c) 2005, 2006, 2007 Lev Walkin . + * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #ifndef _PER_SUPPORT_H_ @@ -29,15 +30,20 @@ typedef struct asn_per_constraint_s { typedef struct asn_per_constraints_s { asn_per_constraint_t value; asn_per_constraint_t size; + int (*value2code)(unsigned int value); + int (*code2value)(unsigned int code); } asn_per_constraints_t; /* * This structure describes a position inside an incoming PER bit stream. */ typedef struct asn_per_data_s { - const uint8_t *buffer; /* Pointer to the octet stream */ - size_t nboff; /* Bit offset to the meaningful bit */ - size_t nbits; /* Number of bits in the stream */ + 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 */ + int (*refill)(struct asn_per_data_s *); + void *refill_key; } asn_per_data_t; /* @@ -47,6 +53,9 @@ typedef struct asn_per_data_s { */ int32_t per_get_few_bits(asn_per_data_t *per_data, int get_nbits); +/* Undo the immediately preceeding "get_few_bits" operation */ +void per_get_undo(asn_per_data_t *per_data, int get_nbits); + /* * Extract a large number of bits from the specified PER data pointer. * This function returns -1 if the specified number of bits could not be @@ -62,11 +71,19 @@ ssize_t uper_get_length(asn_per_data_t *pd, int effective_bound_bits, int *repeat); +/* + * Get the normally small length "n". + */ +ssize_t uper_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); +/* Non-thread-safe debugging function, don't use it */ +char *per_data_string(asn_per_data_t *pd); + /* * This structure supports forming PER output. */ @@ -93,6 +110,12 @@ 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); +/* + * 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); + /* * Put the normally small non-negative whole number. */ diff --git a/src/ANY.c b/src/ANY.c index 612238b..0ad60d0 100644 --- a/src/ANY.c +++ b/src/ANY.c @@ -9,7 +9,7 @@ static asn_OCTET_STRING_specifics_t asn_DEF_ANY_specs = { sizeof(ANY_t), offsetof(ANY_t, _asn_ctx), - 2 /* Special indicator that this is an ANY type */ + ASN_OSUBV_ANY }; asn_TYPE_descriptor_t asn_DEF_ANY = { "ANY", diff --git a/src/BIT_STRING.c b/src/BIT_STRING.c index 6469d4f..9b98271 100644 --- a/src/BIT_STRING.c +++ b/src/BIT_STRING.c @@ -15,7 +15,7 @@ static ber_tlv_tag_t asn_DEF_BIT_STRING_tags[] = { static asn_OCTET_STRING_specifics_t asn_DEF_BIT_STRING_specs = { sizeof(BIT_STRING_t), offsetof(BIT_STRING_t, _asn_ctx), - 1, /* Special indicator that this is a BIT STRING type */ + ASN_OSUBV_BIT }; asn_TYPE_descriptor_t asn_DEF_BIT_STRING = { "BIT STRING", @@ -50,14 +50,15 @@ BIT_STRING_constraint(asn_TYPE_descriptor_t *td, const void *sptr, const BIT_STRING_t *st = (const BIT_STRING_t *)sptr; if(st && st->buf) { - if(st->size == 1 && st->bits_unused) { - _ASN_CTFAIL(app_key, td, + if((st->size == 0 && st->bits_unused) + || st->bits_unused < 0 || st->bits_unused > 7) { + _ASN_CTFAIL(app_key, td, sptr, "%s: invalid padding byte (%s:%d)", td->name, __FILE__, __LINE__); return -1; } } else { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: value not given (%s:%d)", td->name, __FILE__, __LINE__); return -1; diff --git a/src/BMPString.c b/src/BMPString.c index d6a9308..072bd07 100644 --- a/src/BMPString.c +++ b/src/BMPString.c @@ -13,6 +13,16 @@ static 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 */ }; +static asn_OCTET_STRING_specifics_t asn_DEF_BMPString_specs = { + sizeof(BMPString_t), + offsetof(BMPString_t, _asn_ctx), + ASN_OSUBV_U16 /* 16-bits character */ +}; +static asn_per_constraints_t asn_DEF_BMPString_constraints = { + { APC_CONSTRAINED, 16, 16, 0, 65535 }, + { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, + 0, 0 +}; asn_TYPE_descriptor_t asn_DEF_BMPString = { "BMPString", "BMPString", @@ -23,7 +33,8 @@ asn_TYPE_descriptor_t asn_DEF_BMPString = { OCTET_STRING_encode_der, BMPString_decode_xer, /* Convert from UTF-8 */ BMPString_encode_xer, /* Convert to UTF-8 */ - 0, 0, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_BMPString_tags, sizeof(asn_DEF_BMPString_tags) @@ -31,9 +42,9 @@ asn_TYPE_descriptor_t asn_DEF_BMPString = { asn_DEF_BMPString_tags, sizeof(asn_DEF_BMPString_tags) / sizeof(asn_DEF_BMPString_tags[0]), - 0, /* No PER visible constraints */ + &asn_DEF_BMPString_constraints, 0, 0, /* No members */ - 0 /* No specifics */ + &asn_DEF_BMPString_specs }; /* @@ -131,7 +142,7 @@ BMPString_decode_xer(asn_codec_ctx_t *opt_codec_ctx, rc.consumed = 0; return rc; } else { - dstwc[2 * wcs_len] = 0; + dstwc[wcs_len] = 0; /* nul-terminate */ wcs = (uint32_t *)dstwc; } } diff --git a/src/BOOLEAN.c b/src/BOOLEAN.c index bb4697c..2c2bbcf 100644 --- a/src/BOOLEAN.c +++ b/src/BOOLEAN.c @@ -257,7 +257,7 @@ BOOLEAN_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, switch(per_get_few_bits(pd, 1)) { case 1: *st = 1; break; case 0: *st = 0; break; - case -1: default: _ASN_DECODE_FAILED; + case -1: default: _ASN_DECODE_STARVED; } ASN_DEBUG("%s decoded as %s", td->name, *st ? "TRUE" : "FALSE"); diff --git a/src/GeneralString.c b/src/GeneralString.c index 55bb664..01b606b 100644 --- a/src/GeneralString.c +++ b/src/GeneralString.c @@ -22,7 +22,8 @@ asn_TYPE_descriptor_t asn_DEF_GeneralString = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_hex, OCTET_STRING_encode_xer, - 0, 0, + OCTET_STRING_decode_uper, /* Implemented in terms of OCTET STRING */ + OCTET_STRING_encode_uper, 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 f864d83..9d683ef 100644 --- a/src/GeneralizedTime.c +++ b/src/GeneralizedTime.c @@ -105,10 +105,13 @@ static long GMTOFF(struct tm a){ tzold = getenv("TZ"); \ if(tzold) { \ size_t tzlen = strlen(tzold); \ - if(tzlen < sizeof(tzoldbuf)) \ + if(tzlen < sizeof(tzoldbuf)) { \ tzold = memcpy(tzoldbuf, tzold, tzlen + 1); \ - else \ - tzold = strdup(tzold); /* Ignore error */ \ + } else { \ + char *dupptr = tzold; \ + tzold = MALLOC(tzlen + 1); \ + if(tzold) memcpy(tzold, dupptr, tzlen + 1); \ + } \ setenv("TZ", "UTC", 1); \ } \ tzset(); \ @@ -147,6 +150,11 @@ static ber_tlv_tag_t asn_DEF_GeneralizedTime_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (26 << 2)), /* [UNIVERSAL 26] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ }; +static asn_per_constraints_t asn_DEF_GeneralizedTime_constraints = { + { APC_CONSTRAINED, 7, 7, 0x20, 0x7e }, /* Value */ + { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, /* Size */ + 0, 0 +}; asn_TYPE_descriptor_t asn_DEF_GeneralizedTime = { "GeneralizedTime", "GeneralizedTime", @@ -157,7 +165,8 @@ asn_TYPE_descriptor_t asn_DEF_GeneralizedTime = { GeneralizedTime_encode_der, OCTET_STRING_decode_xer_utf8, GeneralizedTime_encode_xer, - 0, 0, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_GeneralizedTime_tags, sizeof(asn_DEF_GeneralizedTime_tags) @@ -165,7 +174,7 @@ asn_TYPE_descriptor_t asn_DEF_GeneralizedTime = { asn_DEF_GeneralizedTime_tags, sizeof(asn_DEF_GeneralizedTime_tags) / sizeof(asn_DEF_GeneralizedTime_tags[0]), - 0, /* No PER visible constraints */ + &asn_DEF_GeneralizedTime_constraints, 0, 0, /* No members */ 0 /* No specifics */ }; @@ -184,7 +193,7 @@ GeneralizedTime_constraint(asn_TYPE_descriptor_t *td, const void *sptr, errno = EPERM; /* Just an unlikely error code */ tloc = asn_GT2time(st, 0, 0); if(tloc == -1 && errno != EPERM) { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: Invalid time format: %s (%s:%d)", td->name, strerror(errno), __FILE__, __LINE__); return -1; @@ -657,7 +666,7 @@ asn_time2GT_frac(GeneralizedTime_t *opt_gt, const struct tm *tm, int frac_value, int ret; gmtoff %= 86400; ret = snprintf(p, buf_size - size, "%+03ld%02ld", - gmtoff / 3600, labs(gmtoff % 3600)); + gmtoff / 3600, labs(gmtoff % 3600) / 60); if(ret != 5) { FREEMEM(buf); errno = EINVAL; diff --git a/src/GraphicString.c b/src/GraphicString.c index 135cd73..7d59d52 100644 --- a/src/GraphicString.c +++ b/src/GraphicString.c @@ -22,7 +22,8 @@ asn_TYPE_descriptor_t asn_DEF_GraphicString = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_hex, OCTET_STRING_encode_xer, /* Can't expect it to be ASCII/UTF8 */ - 0, 0, + OCTET_STRING_decode_uper, /* Implemented in terms of OCTET STRING */ + OCTET_STRING_encode_uper, 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 5c000b0..02ecd3e 100644 --- a/src/IA5String.c +++ b/src/IA5String.c @@ -12,6 +12,11 @@ static 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 */ }; +static asn_per_constraints_t asn_DEF_IA5String_constraints = { + { APC_CONSTRAINED, 7, 7, 0, 0x7f }, /* Value */ + { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, /* Size */ + 0, 0 +}; asn_TYPE_descriptor_t asn_DEF_IA5String = { "IA5String", "IA5String", @@ -22,7 +27,8 @@ asn_TYPE_descriptor_t asn_DEF_IA5String = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_utf8, OCTET_STRING_encode_xer_utf8, - 0, 0, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_IA5String_tags, sizeof(asn_DEF_IA5String_tags) @@ -30,7 +36,7 @@ asn_TYPE_descriptor_t asn_DEF_IA5String = { asn_DEF_IA5String_tags, sizeof(asn_DEF_IA5String_tags) / sizeof(asn_DEF_IA5String_tags[0]), - 0, /* No PER visible constraints */ + &asn_DEF_IA5String_constraints, 0, 0, /* No members */ 0 /* No specifics */ }; @@ -49,7 +55,7 @@ IA5String_constraint(asn_TYPE_descriptor_t *td, const void *sptr, */ for(; buf < end; buf++) { if(*buf > 0x7F) { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: value byte %ld out of range: " "%d > 127 (%s:%d)", td->name, @@ -60,7 +66,7 @@ IA5String_constraint(asn_TYPE_descriptor_t *td, const void *sptr, } } } else { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: value not given (%s:%d)", td->name, __FILE__, __LINE__); return -1; diff --git a/src/INTEGER.c b/src/INTEGER.c index 9c8b9ed..f016131 100644 --- a/src/INTEGER.c +++ b/src/INTEGER.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . + * Copyright (c) 2003, 2004, 2005, 2006, 2007 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ @@ -158,7 +158,9 @@ INTEGER__dump(asn_TYPE_descriptor_t *td, const INTEGER_t *st, asn_app_consume_by } else { scrsize = sizeof(scratch); scr = scratch; - ret = snprintf(scr, scrsize, "%ld", accum); + ret = snprintf(scr, scrsize, + (specs && specs->field_unsigned) + ?"%lu":"%ld", accum); } assert(ret > 0 && (size_t)ret < scrsize); return (cb(scr, ret, app_key) < 0) ? -1 : ret; @@ -334,8 +336,8 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun } state = ST_SKIPSPACE; if(chunk_size) - ASN_DEBUG("INTEGER body %d 0x%2x..0x%2x", - chunk_size, *lstart, lstop[-1]); + ASN_DEBUG("INTEGER body %ld 0x%2x..0x%2x", + (long)chunk_size, *lstart, lstop[-1]); /* * We may have received a tag here. It will be processed inline. @@ -384,7 +386,7 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun case ST_HEXDIGIT2: value += (lv - 0x30); state = ST_HEXCOLON; - st->buf[st->size++] = value; + st->buf[st->size++] = (uint8_t)value; continue; case ST_HEXCOLON: return XPBD_BROKEN_ENCODING; @@ -467,7 +469,7 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun case ST_HEXDIGIT2: value += lv - ((lv < 0x61) ? 0x41 : 0x61); value += 10; - st->buf[st->size++] = value; + st->buf[st->size++] = (uint8_t)value; state = ST_HEXCOLON; continue; case ST_DIGITS: @@ -554,6 +556,7 @@ INTEGER_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, 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) { + 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; @@ -576,6 +579,8 @@ INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, } FREEMEM(st->buf); + st->buf = 0; + st->size = 0; if(ct) { if(ct->flags & APC_SEMI_CONSTRAINED) { st->buf = (uint8_t *)CALLOC(1, 2); @@ -586,11 +591,7 @@ INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, st->buf = (uint8_t *)MALLOC(1 + size + 1); if(!st->buf) _ASN_DECODE_FAILED; st->size = size; - } else { - st->size = 0; } - } else { - st->size = 0; } /* X.691, #12.2.2 */ @@ -598,12 +599,24 @@ INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, /* #10.5.6 */ ASN_DEBUG("Integer with range %d bits", ct->range_bits); if(ct->range_bits >= 0) { - long value = per_get_few_bits(pd, ct->range_bits); - if(value < 0) _ASN_DECODE_STARVED; + 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; + } else { + value = per_get_few_bits(pd, ct->range_bits); + if(value < 0) _ASN_DECODE_STARVED; + } ASN_DEBUG("Got value %ld + low %ld", value, ct->lower_bound); value += ct->lower_bound; - if(asn_long2INTEGER(st, value)) + if((specs && specs->field_unsigned) + ? asn_ulong2INTEGER(st, value) + : asn_long2INTEGER(st, value)) _ASN_DECODE_FAILED; return rval; } @@ -649,6 +662,7 @@ INTEGER_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_enc_rval_t INTEGER_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_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; @@ -665,21 +679,41 @@ INTEGER_encode_uper(asn_TYPE_descriptor_t *td, if(ct) { int inext = 0; - if(asn_INTEGER2long(st, &value)) - _ASN_ENCODE_FAILED; - /* Check proper range */ - if(ct->flags & APC_SEMI_CONSTRAINED) { - if(value < ct->lower_bound) - inext = 1; - } else if(ct->range_bits >= 0) { - if(value < ct->lower_bound - || value > ct->upper_bound) - inext = 1; + if(specs && specs->field_unsigned) { + unsigned long uval; + if(asn_INTEGER2ulong(st, &uval)) + _ASN_ENCODE_FAILED; + /* Check proper range */ + if(ct->flags & APC_SEMI_CONSTRAINED) { + if(uval < (unsigned long)ct->lower_bound) + inext = 1; + } else if(ct->range_bits >= 0) { + if(uval < (unsigned long)ct->lower_bound + || uval > (unsigned long)ct->upper_bound) + inext = 1; + } + ASN_DEBUG("Value %lu (%02x/%d) lb %lu ub %lu %s", + uval, st->buf[0], st->size, + ct->lower_bound, ct->upper_bound, + inext ? "ext" : "fix"); + value = uval; + } else { + if(asn_INTEGER2long(st, &value)) + _ASN_ENCODE_FAILED; + /* Check proper range */ + if(ct->flags & APC_SEMI_CONSTRAINED) { + if(value < ct->lower_bound) + inext = 1; + } else if(ct->range_bits >= 0) { + if(value < ct->lower_bound + || value > ct->upper_bound) + inext = 1; + } + ASN_DEBUG("Value %ld (%02x/%d) lb %ld ub %ld %s", + value, st->buf[0], st->size, + ct->lower_bound, ct->upper_bound, + inext ? "ext" : "fix"); } - ASN_DEBUG("Value %ld (%02x/%d) lb %ld ub %ld %s", - value, st->buf[0], st->size, - ct->lower_bound, ct->upper_bound, - inext ? "ext" : "fix"); if(ct->flags & APC_EXTENSIBLE) { if(per_put_few_bits(po, inext, 1)) _ASN_ENCODE_FAILED; @@ -695,9 +729,17 @@ INTEGER_encode_uper(asn_TYPE_descriptor_t *td, /* #10.5.6 */ ASN_DEBUG("Encoding integer with range %d bits", ct->range_bits); - if(per_put_few_bits(po, value - ct->lower_bound, + if(ct->range_bits == 32) { + /* TODO: extend to >32 bits */ + long v = value - ct->lower_bound; + if(per_put_few_bits(po, v >> 1, 31) + || per_put_few_bits(po, v, 1)) + _ASN_ENCODE_FAILED; + } else { + if(per_put_few_bits(po, value - ct->lower_bound, ct->range_bits)) - _ASN_ENCODE_FAILED; + _ASN_ENCODE_FAILED; + } _ASN_ENCODED_OK(er); } @@ -779,6 +821,63 @@ asn_INTEGER2long(const INTEGER_t *iptr, long *lptr) { return 0; } +int +asn_INTEGER2ulong(const INTEGER_t *iptr, unsigned long *lptr) { + uint8_t *b, *end; + unsigned long 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(unsigned long); 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; + uint8_t *end; + uint8_t *b; + int shr; + + if(value <= LONG_MAX) + return asn_long2INTEGER(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(long)-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_long2INTEGER(INTEGER_t *st, long value) { uint8_t *buf, *bp; diff --git a/src/ISO646String.c b/src/ISO646String.c index d164aa7..d6ded0e 100644 --- a/src/ISO646String.c +++ b/src/ISO646String.c @@ -12,6 +12,11 @@ static 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 */ }; +static asn_per_constraints_t asn_DEF_ISO646String_constraints = { + { APC_CONSTRAINED, 7, 7, 0x20, 0x7e }, /* Value */ + { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, /* Size */ + 0, 0 +}; asn_TYPE_descriptor_t asn_DEF_ISO646String = { "ISO646String", "ISO646String", @@ -22,7 +27,8 @@ asn_TYPE_descriptor_t asn_DEF_ISO646String = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_utf8, OCTET_STRING_encode_xer_utf8, - 0, 0, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_ISO646String_tags, sizeof(asn_DEF_ISO646String_tags) @@ -30,8 +36,7 @@ asn_TYPE_descriptor_t asn_DEF_ISO646String = { asn_DEF_ISO646String_tags, sizeof(asn_DEF_ISO646String_tags) / sizeof(asn_DEF_ISO646String_tags[0]), - 0, /* No PER visible constraints */ + &asn_DEF_ISO646String_constraints, 0, 0, /* No members */ 0 /* No specifics */ }; - diff --git a/src/Makefile.am b/src/Makefile.am index 4451f65..dcad645 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,5 +8,5 @@ AM_CFLAGS = -fPIC -Wall lib_LTLIBRARIES = libasn1c.la -libasn1c_la_SOURCES = ANY.c constraints.c GeneralizedTime.c NumericString.c T61String.c asn_codecs_prim.c constr_CHOICE.c GeneralString.c ObjectDescriptor.c TeletexString.c asn_SEQUENCE_OF.c constr_SEQUENCE.c GraphicString.c OBJECT_IDENTIFIER.c UniversalString.c asn_SET_OF.c constr_SEQUENCE_OF.c IA5String.c OCTET_STRING.c UTCTime.c ber_decoder.c constr_SET.c INTEGER.c per_decoder.c UTF8String.c ber_tlv_length.c constr_SET_OF.c ISO646String.c per_encoder.c VideotexString.c ber_tlv_tag.c constr_TYPE.c NativeEnumerated.c per_support.c VisibleString.c BIT_STRING.c NativeInteger.c PrintableString.c xer_decoder.c BMPString.c der_encoder.c NativeReal.c REAL.c xer_encoder.c BOOLEAN.c ENUMERATED.c NULL.c RELATIVE-OID.c xer_support.c +libasn1c_la_SOURCES = ANY.c constraints.c GeneralizedTime.c NumericString.c T61String.c asn_codecs_prim.c constr_CHOICE.c GeneralString.c ObjectDescriptor.c TeletexString.c asn_SEQUENCE_OF.c constr_SEQUENCE.c GraphicString.c OBJECT_IDENTIFIER.c UniversalString.c asn_SET_OF.c constr_SEQUENCE_OF.c IA5String.c OCTET_STRING.c UTCTime.c ber_decoder.c constr_SET.c INTEGER.c per_decoder.c UTF8String.c ber_tlv_length.c constr_SET_OF.c ISO646String.c per_encoder.c VideotexString.c ber_tlv_tag.c constr_TYPE.c NativeEnumerated.c per_support.c VisibleString.c BIT_STRING.c NativeInteger.c PrintableString.c xer_decoder.c BMPString.c der_encoder.c NativeReal.c REAL.c xer_encoder.c BOOLEAN.c ENUMERATED.c NULL.c RELATIVE-OID.c xer_support.c per_opentype.c diff --git a/src/NativeEnumerated.c b/src/NativeEnumerated.c index e3af1ca..1554220 100644 --- a/src/NativeEnumerated.c +++ b/src/NativeEnumerated.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2004 Lev Walkin . All rights reserved. + * Copyright (c) 2004, 2007 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ /* @@ -177,9 +177,9 @@ NativeEnumerated_encode_uper(asn_TYPE_descriptor_t *td, inext = 1; } if(ct->flags & APC_EXTENSIBLE) { - if(per_put_few_bits(po, inext, 0)) + if(per_put_few_bits(po, inext, 1)) _ASN_ENCODE_FAILED; - ct = 0; + if(inext) ct = 0; } else if(inext) { _ASN_ENCODE_FAILED; } @@ -196,7 +196,10 @@ NativeEnumerated_encode_uper(asn_TYPE_descriptor_t *td, /* * X.691, #10.6: normally small non-negative whole number; */ - if(uper_put_nsnnwn(po, value - (specs->extension - 1))) + ASN_DEBUG("value = %ld, ext = %d, inext = %d, res = %ld", + value, specs->extension, inext, + value - (inext ? (specs->extension - 1) : 0)); + if(uper_put_nsnnwn(po, value - (inext ? (specs->extension - 1) : 0))) _ASN_ENCODE_FAILED; _ASN_ENCODED_OK(er); diff --git a/src/NativeInteger.c b/src/NativeInteger.c index 34599f6..abdb71a 100644 --- a/src/NativeInteger.c +++ b/src/NativeInteger.c @@ -48,6 +48,7 @@ asn_dec_rval_t NativeInteger_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **nint_ptr, const void *buf_ptr, size_t size, int tag_mode) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; long *native = (long *)*nint_ptr; asn_dec_rval_t rval; ber_tlv_len_t length; @@ -105,7 +106,9 @@ NativeInteger_decode_ber(asn_codec_ctx_t *opt_codec_ctx, tmp.buf = (uint8_t *)unconst_buf.nonconstbuf; tmp.size = length; - if(asn_INTEGER2long(&tmp, &l)) { + if((specs&&specs->field_unsigned) + ? asn_INTEGER2ulong(&tmp, &l) + : asn_INTEGER2long(&tmp, &l)) { rval.code = RC_FAIL; rval.consumed = 0; return rval; @@ -145,7 +148,7 @@ NativeInteger_encode_der(asn_TYPE_descriptor_t *sd, void *ptr, /* Prepare a fake INTEGER */ for(p = buf + sizeof(buf) - 1; p >= buf; p--, native >>= 8) - *p = native; + *p = (uint8_t)native; tmp.buf = buf; tmp.size = sizeof(buf); @@ -167,6 +170,7 @@ asn_dec_rval_t NativeInteger_decode_xer(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname, const void *buf_ptr, size_t size) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; asn_dec_rval_t rval; INTEGER_t st; void *st_ptr = (void *)&st; @@ -182,7 +186,9 @@ NativeInteger_decode_xer(asn_codec_ctx_t *opt_codec_ctx, opt_mname, buf_ptr, size); if(rval.code == RC_OK) { long l; - if(asn_INTEGER2long(&st, &l)) { + if((specs&&specs->field_unsigned) + ? asn_INTEGER2ulong(&st, &l) + : asn_INTEGER2long(&st, &l)) { rval.code = RC_FAIL; rval.consumed = 0; } else { @@ -205,6 +211,7 @@ asn_enc_rval_t NativeInteger_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) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; char scratch[32]; /* Enough for 64-bit int */ asn_enc_rval_t er; const long *native = (const long *)sptr; @@ -214,7 +221,9 @@ NativeInteger_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, if(!native) _ASN_ENCODE_FAILED; - er.encoded = snprintf(scratch, sizeof(scratch), "%ld", *native); + er.encoded = snprintf(scratch, sizeof(scratch), + (specs && specs->field_unsigned) + ? "%lu" : "%ld", *native); if(er.encoded <= 0 || (size_t)er.encoded >= sizeof(scratch) || cb(scratch, er.encoded, app_key) < 0) _ASN_ENCODE_FAILED; @@ -227,6 +236,7 @@ NativeInteger_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; asn_dec_rval_t rval; long *native = (long *)*sptr; INTEGER_t tmpint; @@ -244,7 +254,9 @@ NativeInteger_decode_uper(asn_codec_ctx_t *opt_codec_ctx, rval = INTEGER_decode_uper(opt_codec_ctx, td, constraints, &tmpintptr, pd); if(rval.code == RC_OK) { - if(asn_INTEGER2long(&tmpint, native)) + if((specs&&specs->field_unsigned) + ? asn_INTEGER2ulong(&tmpint, native) + : asn_INTEGER2long(&tmpint, native)) rval.code = RC_FAIL; else ASN_DEBUG("NativeInteger %s got value %ld", @@ -258,6 +270,7 @@ NativeInteger_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_enc_rval_t NativeInteger_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; asn_enc_rval_t er; long native; INTEGER_t tmpint; @@ -269,7 +282,9 @@ NativeInteger_encode_uper(asn_TYPE_descriptor_t *td, ASN_DEBUG("Encoding NativeInteger %s %ld (UPER)", td->name, native); memset(&tmpint, 0, sizeof(tmpint)); - if(asn_long2INTEGER(&tmpint, native)) + if((specs&&specs->field_unsigned) + ? asn_ulong2INTEGER(&tmpint, native) + : asn_long2INTEGER(&tmpint, native)) _ASN_ENCODE_FAILED; er = INTEGER_encode_uper(td, constraints, &tmpint, po); ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_INTEGER, &tmpint); @@ -282,6 +297,7 @@ NativeInteger_encode_uper(asn_TYPE_descriptor_t *td, int NativeInteger_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { + asn_INTEGER_specifics_t *specs=(asn_INTEGER_specifics_t *)td->specifics; const long *native = (const long *)sptr; char scratch[32]; /* Enough for 64-bit int */ int ret; @@ -290,7 +306,9 @@ NativeInteger_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, (void)ilevel; /* Unused argument */ if(native) { - ret = snprintf(scratch, sizeof(scratch), "%ld", *native); + ret = snprintf(scratch, sizeof(scratch), + (specs && specs->field_unsigned) + ? "%lu" : "%ld", *native); assert(ret > 0 && (size_t)ret < sizeof(scratch)); return (cb(scratch, ret, app_key) < 0) ? -1 : 0; } else { diff --git a/src/NativeReal.c b/src/NativeReal.c index 2b8ec16..a1ff91e 100644 --- a/src/NativeReal.c +++ b/src/NativeReal.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2004 Lev Walkin . All rights reserved. + * Copyright (c) 2004, 2006 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ /* @@ -12,6 +12,7 @@ #include #include #include +#include /* * NativeReal basic type description. @@ -29,7 +30,8 @@ asn_TYPE_descriptor_t asn_DEF_NativeReal = { NativeReal_encode_der, NativeReal_decode_xer, NativeReal_encode_xer, - 0, 0, + NativeReal_decode_uper, + NativeReal_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_NativeReal_tags, sizeof(asn_DEF_NativeReal_tags) / sizeof(asn_DEF_NativeReal_tags[0]), @@ -157,7 +159,74 @@ NativeReal_encode_der(asn_TYPE_descriptor_t *td, void *ptr, return erval; } +/* + * Decode REAL type using PER. + */ +asn_dec_rval_t +NativeReal_decode_uper(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_uper(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. + */ +asn_enc_rval_t +NativeReal_encode_uper(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_uper(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 cef64ea..50fe449 100644 --- a/src/NumericString.c +++ b/src/NumericString.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003 Lev Walkin . All rights reserved. + * Copyright (c) 2003, 2006 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include @@ -12,6 +12,31 @@ static 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 */ }; +static int asn_DEF_NumericString_v2c(unsigned int value) { + switch(value) { + case 0x20: return 0; + case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: + case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: + return value - (0x30 - 1); + } + return -1; +} +static int asn_DEF_NumericString_c2v(unsigned int code) { + if(code > 0) { + if(code <= 10) + return code + (0x30 - 1); + else + return -1; + } else { + return 0x20; + } +} +static asn_per_constraints_t asn_DEF_NumericString_constraints = { + { APC_CONSTRAINED, 4, 4, 0x20, 0x39 }, /* Value */ + { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, /* Size */ + asn_DEF_NumericString_v2c, + asn_DEF_NumericString_c2v +}; asn_TYPE_descriptor_t asn_DEF_NumericString = { "NumericString", "NumericString", @@ -22,7 +47,8 @@ asn_TYPE_descriptor_t asn_DEF_NumericString = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_utf8, OCTET_STRING_encode_xer_utf8, - 0, 0, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_NumericString_tags, sizeof(asn_DEF_NumericString_tags) @@ -30,7 +56,7 @@ asn_TYPE_descriptor_t asn_DEF_NumericString = { asn_DEF_NumericString_tags, sizeof(asn_DEF_NumericString_tags) / sizeof(asn_DEF_NumericString_tags[0]), - 0, /* No PER visible constraints */ + &asn_DEF_NumericString_constraints, 0, 0, /* No members */ 0 /* No specifics */ }; @@ -55,7 +81,7 @@ NumericString_constraint(asn_TYPE_descriptor_t *td, const void *sptr, case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: continue; } - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: value byte %ld (%d) " "not in NumericString alphabet (%s:%d)", td->name, @@ -65,7 +91,7 @@ NumericString_constraint(asn_TYPE_descriptor_t *td, const void *sptr, return -1; } } else { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: value not given (%s:%d)", td->name, __FILE__, __LINE__); return -1; diff --git a/src/OBJECT_IDENTIFIER.c b/src/OBJECT_IDENTIFIER.c index b1666dc..0d7043e 100644 --- a/src/OBJECT_IDENTIFIER.c +++ b/src/OBJECT_IDENTIFIER.c @@ -4,6 +4,7 @@ */ #include #include +#include #include /* for CHAR_BIT */ #include @@ -23,7 +24,8 @@ asn_TYPE_descriptor_t asn_DEF_OBJECT_IDENTIFIER = { der_encode_primitive, OBJECT_IDENTIFIER_decode_xer, OBJECT_IDENTIFIER_encode_xer, - 0, 0, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_OBJECT_IDENTIFIER_tags, sizeof(asn_DEF_OBJECT_IDENTIFIER_tags) @@ -44,14 +46,14 @@ OBJECT_IDENTIFIER_constraint(asn_TYPE_descriptor_t *td, const void *sptr, if(st && st->buf) { if(st->size < 1) { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: at least one numerical value " "expected (%s:%d)", td->name, __FILE__, __LINE__); return -1; } } else { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: value not given (%s:%d)", td->name, __FILE__, __LINE__); return -1; @@ -63,7 +65,7 @@ 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) { - unsigned LE __attribute__ ((unused)) = 1; /* Little endian (x86) */ + unsigned LE GCC_NOTUSED = 1; /* Little endian (x86) */ uint8_t *arcend = arcbuf + arclen; /* End of arc */ unsigned int cache = 0; /* No more than 14 significant bits */ unsigned char *rvbuf = (unsigned char *)rvbufp; diff --git a/src/OCTET_STRING.c b/src/OCTET_STRING.c index 3a83bd9..584def8 100644 --- a/src/OCTET_STRING.c +++ b/src/OCTET_STRING.c @@ -17,10 +17,12 @@ static ber_tlv_tag_t asn_DEF_OCTET_STRING_tags[] = { static asn_OCTET_STRING_specifics_t asn_DEF_OCTET_STRING_specs = { sizeof(OCTET_STRING_t), offsetof(OCTET_STRING_t, _asn_ctx), - 0 + ASN_OSUBV_STR }; -static asn_per_constraint_t asn_DEF_OCTET_STRING_constraint = { - APC_SEMI_CONSTRAINED, -1, -1, 0, 0 +static asn_per_constraints_t asn_DEF_OCTET_STRING_constraints = { + { APC_CONSTRAINED, 8, 8, 0, 255 }, + { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, + 0, 0 }; asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = { "OCTET STRING", /* Canonical name */ @@ -102,15 +104,6 @@ asn_TYPE_descriptor_t asn_DEF_OCTET_STRING = { st->size = _es; \ } while(0) -/* - * Internal variant of the OCTET STRING. - */ -typedef enum OS_type { - _TT_GENERIC = 0, /* Just a random OCTET STRING */ - _TT_BIT_STRING = 1, /* BIT STRING type, a special case */ - _TT_ANY = 2 /* ANY type, a special case too */ -} OS_type_e; - /* * The main reason why ASN.1 is still alive is that too much time and effort * is necessary for learning it more or less adequately, thus creating a gut @@ -185,11 +178,11 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, struct _stack *stck; /* Expectations stack structure */ struct _stack_el *sel = 0; /* Stack element */ int tlv_constr; - OS_type_e type_variant = (OS_type_e)specs->subvariant; + enum asn_OS_Subvariant type_variant = specs->subvariant; ASN_DEBUG("Decoding %s as %s (frame %ld)", td->name, - (type_variant == _TT_GENERIC) ? + (type_variant == ASN_OSUBV_STR) ? "OCTET STRING" : "OS-SpecialCase", (long)size); @@ -230,7 +223,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, * Jump into stackless primitive decoding. */ _CH_PHASE(ctx, 3); - if(type_variant == _TT_ANY && tag_mode != 1) + if(type_variant == ASN_OSUBV_ANY && tag_mode != 1) APPEND(buf_ptr, rval.consumed); ADVANCE(rval.consumed); goto phase3; @@ -309,7 +302,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, ASN_DEBUG("Eat EOC; wn=%d--", sel->want_nulls); - if(type_variant == _TT_ANY + if(type_variant == ASN_OSUBV_ANY && (tag_mode != 1 || sel->cont_level)) APPEND("\0\0", 2); @@ -334,10 +327,10 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, * depending on ASN.1 type being decoded. */ switch(type_variant) { - case _TT_BIT_STRING: + case ASN_OSUBV_BIT: /* X.690: 8.6.4.1, NOTE 2 */ /* Fall through */ - case _TT_GENERIC: + case ASN_OSUBV_STR: default: if(sel) { int level = sel->cont_level; @@ -352,7 +345,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, /* else, Fall through */ } /* Fall through */ - case _TT_ANY: + case ASN_OSUBV_ANY: expected_tag = tlv_tag; break; } @@ -397,7 +390,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, } else { sel->left = tlv_len; } - if(type_variant == _TT_ANY + if(type_variant == ASN_OSUBV_ANY && (tag_mode != 1 || sel->cont_level)) APPEND(buf_ptr, tlvl); sel->got += tlvl; @@ -431,7 +424,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, len = ((ber_tlv_len_t)size < sel->left) ? (ber_tlv_len_t)size : sel->left; if(len > 0) { - if(type_variant == _TT_BIT_STRING + if(type_variant == ASN_OSUBV_BIT && sel->bits_chopped == 0) { /* Put the unused-bits-octet away */ st->bits_unused = *(const uint8_t *)buf_ptr; @@ -464,7 +457,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, if(size < (size_t)ctx->left) { if(!size) RETURN(RC_WMORE); - if(type_variant == _TT_BIT_STRING && !ctx->context) { + if(type_variant == ASN_OSUBV_BIT && !ctx->context) { st->bits_unused = *(const uint8_t *)buf_ptr; ctx->left--; ADVANCE(1); @@ -475,7 +468,7 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, ADVANCE(size); RETURN(RC_WMORE); } else { - if(type_variant == _TT_BIT_STRING + if(type_variant == ASN_OSUBV_BIT && !ctx->context && ctx->left) { st->bits_unused = *(const uint8_t *)buf_ptr; ctx->left--; @@ -502,14 +495,14 @@ OCTET_STRING_decode_ber(asn_codec_ctx_t *opt_codec_ctx, /* * BIT STRING-specific processing. */ - if(type_variant == _TT_BIT_STRING && st->size) { + if(type_variant == ASN_OSUBV_BIT && st->size) { /* Finalize BIT STRING: zero out unused bits. */ st->buf[st->size-1] &= 0xff << st->bits_unused; } ASN_DEBUG("Took %ld bytes to encode %s: [%s]:%ld", (long)consumed_myself, td->name, - (type_variant == _TT_GENERIC) ? (char *)st->buf : "", + (type_variant == ASN_OSUBV_STR) ? (char *)st->buf : "", (long)st->size); @@ -528,7 +521,7 @@ OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr, ? (asn_OCTET_STRING_specifics_t *)td->specifics : &asn_DEF_OCTET_STRING_specs; BIT_STRING_t *st = (BIT_STRING_t *)sptr; - OS_type_e type_variant = (OS_type_e)specs->subvariant; + enum asn_OS_Subvariant type_variant = specs->subvariant; int fix_last_byte = 0; ASN_DEBUG("%s %s as OCTET STRING", @@ -537,10 +530,11 @@ OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr, /* * Write tags. */ - if(type_variant != _TT_ANY || tag_mode == 1) { + if(type_variant != ASN_OSUBV_ANY || tag_mode == 1) { er.encoded = der_write_tags(td, - (type_variant == _TT_BIT_STRING) + st->size, - tag_mode, type_variant == _TT_ANY, tag, cb, app_key); + (type_variant == ASN_OSUBV_BIT) + st->size, + tag_mode, type_variant == ASN_OSUBV_ANY, tag, + cb, app_key); if(er.encoded == -1) { er.failed_type = td; er.structure_ptr = sptr; @@ -548,19 +542,19 @@ OCTET_STRING_encode_der(asn_TYPE_descriptor_t *td, void *sptr, } } else { /* Disallow: [] IMPLICIT ANY */ - assert(type_variant != _TT_ANY || tag_mode != -1); + assert(type_variant != ASN_OSUBV_ANY || tag_mode != -1); er.encoded = 0; } if(!cb) { - er.encoded += (type_variant == _TT_BIT_STRING) + st->size; + er.encoded += (type_variant == ASN_OSUBV_BIT) + st->size; _ASN_ENCODED_OK(er); } /* * Prepare to deal with the last octet of BIT STRING. */ - if(type_variant == _TT_BIT_STRING) { + if(type_variant == ASN_OSUBV_BIT) { uint8_t b = st->bits_unused & 0x07; if(b && st->size) fix_last_byte = 1; _ASN_CALLBACK(&b, 1); @@ -595,7 +589,7 @@ OCTET_STRING_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, uint8_t *end; size_t i; - if(!st || !st->buf) + if(!st || (!st->buf && st->size)) _ASN_ENCODE_FAILED; er.encoded = 0; @@ -751,7 +745,7 @@ OCTET_STRING_encode_xer_utf8(asn_TYPE_descriptor_t *td, void *sptr, (void)ilevel; /* Unused argument */ (void)flags; /* Unused argument */ - if(!st || !st->buf) + if(!st || (!st->buf && st->size)) _ASN_ENCODE_FAILED; buf = st->buf; @@ -1197,6 +1191,135 @@ OCTET_STRING_decode_xer_utf8(asn_codec_ctx_t *opt_codec_ctx, OCTET_STRING__convert_entrefs); } +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) { + uint8_t *end = buf + units * bpc; + + ASN_DEBUG("Expanding %d characters into (%ld..%ld):%d", + (int)units, lb, ub, unit_bits); + + /* X.691: 27.5.4 */ + if((unsigned long)ub <= ((unsigned long)2 << (unit_bits - 1))) { + /* Decode without translation */ + lb = 0; + } else if(pc && pc->code2value) { + if(unit_bits > 16) + return 1; /* FATAL: can't have constrained + * UniversalString with more than + * 16 million code points */ + for(; buf < end; buf += bpc) { + int value; + int code = per_get_few_bits(po, unit_bits); + if(code < 0) return -1; /* WMORE */ + value = pc->code2value(code); + if(value < 0) { + ASN_DEBUG("Code %d (0x%02x) is" + " not in map (%ld..%ld)", + code, code, lb, ub); + return 1; /* FATAL */ + } + switch(bpc) { + case 1: *buf = value; break; + case 2: buf[0] = value >> 8; buf[1] = value; break; + case 4: buf[0] = value >> 24; buf[1] = value >> 16; + buf[2] = value >> 8; buf[3] = value; break; + } + } + return 0; + } + + /* Shortcut the no-op copying to the aligned structure */ + if(lb == 0 && (unit_bits == 8 * bpc)) { + return per_get_many_bits(po, buf, 0, unit_bits * units); + } + + for(; buf < end; buf += bpc) { + int code = per_get_few_bits(po, unit_bits); + int ch = code + lb; + if(code < 0) return -1; /* WMORE */ + if(ch > ub) { + ASN_DEBUG("Code %d is out of range (%ld..%ld)", + ch, lb, ub); + return 1; /* FATAL */ + } + switch(bpc) { + case 1: *buf = ch; break; + case 2: buf[0] = ch >> 8; buf[1] = ch; break; + case 4: buf[0] = ch >> 24; buf[1] = ch >> 16; + buf[2] = ch >> 8; buf[3] = ch; break; + } + } + + return 0; +} + +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) { + const uint8_t *end = buf + units * bpc; + + ASN_DEBUG("Squeezing %d characters into (%ld..%ld):%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))) { + /* Encode as is */ + lb = 0; + } else if(pc && pc->value2code) { + for(; buf < end; buf += bpc) { + int code; + uint32_t value; + switch(bpc) { + case 1: value = *(const uint8_t *)buf; break; + case 2: value = (buf[0] << 8) | buf[1]; break; + case 4: value = (buf[0] << 24) | (buf[1] << 16) + | (buf[2] << 8) | buf[3]; break; + default: return -1; + } + code = pc->value2code(value); + if(code < 0) { + ASN_DEBUG("Character %d (0x%02x) is" + " not in map (%ld..%ld)", + *buf, *buf, lb, ub); + return -1; + } + if(per_put_few_bits(po, code, unit_bits)) + return -1; + } + } + + /* Shortcut the no-op copying to the aligned structure */ + if(lb == 0 && (unit_bits == 8 * bpc)) { + return per_put_many_bits(po, buf, unit_bits * units); + } + + for(ub -= lb; buf < end; buf += bpc) { + int ch; + uint32_t value; + switch(bpc) { + case 1: value = *(const uint8_t *)buf; break; + case 2: value = (buf[0] << 8) | buf[1]; break; + case 4: value = (buf[0] << 24) | (buf[1] << 16) + | (buf[2] << 8) | buf[3]; break; + default: return -1; + } + ch = value - lb; + if(ch < 0 || ch > ub) { + ASN_DEBUG("Character %d (0x%02x)" + " is out of range (%ld..%ld)", + *buf, *buf, lb, ub + lb); + return -1; + } + if(per_put_few_bits(po, ch, unit_bits)) + return -1; + } + + return 0; +} + asn_dec_rval_t OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, @@ -1205,18 +1328,62 @@ OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_OCTET_STRING_specifics_t *specs = td->specifics ? (asn_OCTET_STRING_specifics_t *)td->specifics : &asn_DEF_OCTET_STRING_specs; - asn_per_constraint_t *ct = constraints ? &constraints->size - : (td->per_constraints - ? &td->per_constraints->size - : &asn_DEF_OCTET_STRING_constraint); + 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; - int unit_bits = (specs->subvariant != 1) * 7 + 1; + 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_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. */ @@ -1225,24 +1392,26 @@ OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx, if(!st) RETURN(RC_FAIL); } - ASN_DEBUG("PER Decoding %s %ld .. %ld bits %d", - ct->flags & APC_EXTENSIBLE ? "extensible" : "fixed", - ct->lower_bound, ct->upper_bound, ct->effective_bits); + ASN_DEBUG("PER Decoding %s size %ld .. %ld bits %d", + csiz->flags & APC_EXTENSIBLE ? "extensible" : "non-extensible", + csiz->lower_bound, csiz->upper_bound, csiz->effective_bits); - if(ct->flags & APC_EXTENSIBLE) { + if(csiz->flags & APC_EXTENSIBLE) { int inext = per_get_few_bits(pd, 1); if(inext < 0) RETURN(RC_WMORE); - if(inext) ct = &asn_DEF_OCTET_STRING_constraint; - consumed_myself = 0; + if(inext) { + csiz = &asn_DEF_OCTET_STRING_constraints.size; + cval = &asn_DEF_OCTET_STRING_constraints.value; + unit_bits = canonical_unit_bits; + } } - if(ct->effective_bits >= 0 - && (!st->buf || st->size < ct->upper_bound)) { + if(csiz->effective_bits >= 0) { FREEMEM(st->buf); - if(unit_bits == 1) { - st->size = (ct->upper_bound + 7) >> 3; + if(bpc) { + st->size = csiz->upper_bound * bpc; } else { - st->size = ct->upper_bound; + st->size = (csiz->upper_bound + 7) >> 3; } st->buf = (uint8_t *)MALLOC(st->size + 1); if(!st->buf) { st->size = 0; RETURN(RC_FAIL); } @@ -1251,46 +1420,70 @@ OCTET_STRING_decode_uper(asn_codec_ctx_t *opt_codec_ctx, /* X.691, #16.5: zero-length encoding */ /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ - if(ct->effective_bits == 0) { - int ret = per_get_many_bits(pd, st->buf, 0, - unit_bits * ct->upper_bound); + if(csiz->effective_bits == 0) { + int ret; + if(bpc) { + ASN_DEBUG("Encoding OCTET STRING size %ld", + 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", + 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 * ct->upper_bound; + consumed_myself += unit_bits * csiz->upper_bound; st->buf[st->size] = 0; - if(unit_bits == 1 && (ct->upper_bound & 0x7)) - st->bits_unused = 8 - (ct->upper_bound & 0x7); + 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 */ - len_bits = uper_get_length(pd, ct->effective_bits, &repeat); - if(len_bits < 0) RETURN(RC_WMORE); - len_bits += ct->lower_bound; + raw_len = uper_get_length(pd, csiz->effective_bits, &repeat); + if(raw_len < 0) RETURN(RC_WMORE); + raw_len += csiz->lower_bound; ASN_DEBUG("Got PER length eb %ld, len %ld, %s (%s)", - (long)ct->effective_bits, (long)len_bits, + (long)csiz->effective_bits, (long)raw_len, repeat ? "repeat" : "once", td->name); - if(unit_bits == 1) { + 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 */ - } else { - len_bytes = len_bits; - len_bits = len_bytes << 3; } p = REALLOC(st->buf, st->size + len_bytes + 1); if(!p) RETURN(RC_FAIL); st->buf = (uint8_t *)p; - ret = per_get_many_bits(pd, &st->buf[st->size], 0, len_bits); + 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); @@ -1306,41 +1499,87 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, asn_OCTET_STRING_specifics_t *specs = td->specifics ? (asn_OCTET_STRING_specifics_t *)td->specifics : &asn_DEF_OCTET_STRING_specs; - asn_per_constraint_t *ct = constraints ? &constraints->size - : (td->per_constraints - ? &td->per_constraints->size - : &asn_DEF_OCTET_STRING_constraint); + 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; - int unit_bits = (specs->subvariant != 1) * 7 + 1; - asn_enc_rval_t er; - int ct_extensible = ct->flags & APC_EXTENSIBLE; + asn_enc_rval_t er = { 0, 0, 0 }; int inext = 0; /* Lies not within extension root */ - int sizeinunits = st->size; + unsigned int unit_bits; + unsigned int canonical_unit_bits; + unsigned int sizeinunits; const uint8_t *buf; int ret; - - if(!st || !st->buf) + 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(unit_bits == 1) { + 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, %d bits unused", sizeinunits, st->bits_unused); - sizeinunits = sizeinunits * 8 - (st->bits_unused & 0x07); + break; + case ASN_OSUBV_STR: + canonical_unit_bits = unit_bits = 8; + if(cval->flags & APC_CONSTRAINED) + unit_bits = cval->range_bits; + 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" - " (%d..%d, effective %d)%s", + " (%ld..%ld, effective %d)%s", td->name, sizeinunits, unit_bits, - ct->lower_bound, ct->upper_bound, - ct->effective_bits, ct_extensible ? " EXT" : ""); + csiz->lower_bound, csiz->upper_bound, + csiz->effective_bits, ct_extensible ? " EXT" : ""); - /* Figure out wheter size lies within PER visible consrtaint */ + /* Figure out wheter size lies within PER visible constraint */ - if(ct->effective_bits >= 0) { - if(sizeinunits < ct->lower_bound - || sizeinunits > ct->upper_bound) { + if(csiz->effective_bits >= 0) { + if((int)sizeinunits < csiz->lower_bound + || (int)sizeinunits > csiz->upper_bound) { if(ct_extensible) { - ct = &asn_DEF_OCTET_STRING_constraint; + 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; @@ -1358,14 +1597,21 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, /* X.691, #16.5: zero-length encoding */ /* X.691, #16.6: short fixed length encoding (up to 2 octets) */ /* X.691, #16.7: long fixed length encoding (up to 64K octets) */ - if(ct->effective_bits >= 0) { + if(csiz->effective_bits >= 0) { ASN_DEBUG("Encoding %d bytes (%ld), length in %d bits", - st->size, sizeinunits - ct->lower_bound, - ct->effective_bits); - ret = per_put_few_bits(po, sizeinunits - ct->lower_bound, - ct->effective_bits); + 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; - ret = per_put_many_bits(po, st->buf, sizeinunits * unit_bits); + 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); } @@ -1383,15 +1629,22 @@ OCTET_STRING_encode_uper(asn_TYPE_descriptor_t *td, ssize_t maySave = uper_put_length(po, sizeinunits); if(maySave < 0) _ASN_ENCODE_FAILED; - ASN_DEBUG("Encoding %d of %d", maySave, sizeinunits); + ASN_DEBUG("Encoding %ld of %ld", + (long)maySave, (long)sizeinunits); - ret = per_put_many_bits(po, buf, maySave * unit_bits); + 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(unit_bits == 1) - buf += maySave >> 3; + if(bpc) + buf += maySave * bpc; else - buf += maySave; + buf += maySave >> 3; sizeinunits -= maySave; assert(!(maySave & 0x07) || !sizeinunits); } @@ -1412,7 +1665,8 @@ OCTET_STRING_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, (void)td; /* Unused argument */ - if(!st || !st->buf) return (cb("", 8, app_key) < 0) ? -1 : 0; + if(!st || (!st->buf && st->size)) + return (cb("", 8, app_key) < 0) ? -1 : 0; /* * Dump the contents of the buffer in hexadecimal. @@ -1448,7 +1702,7 @@ OCTET_STRING_print_utf8(asn_TYPE_descriptor_t *td, const void *sptr, (void)td; /* Unused argument */ (void)ilevel; /* Unused argument */ - if(st && st->buf) { + if(st && (st->buf || !st->size)) { return (cb(st->buf, st->size, app_key) < 0) ? -1 : 0; } else { return (cb("", 8, app_key) < 0) ? -1 : 0; @@ -1472,6 +1726,7 @@ OCTET_STRING_free(asn_TYPE_descriptor_t *td, void *sptr, int contents_only) { if(st->buf) { FREEMEM(st->buf); + st->buf = 0; } /* diff --git a/src/ObjectDescriptor.c b/src/ObjectDescriptor.c index 44cb5f6..cd8e8a3 100644 --- a/src/ObjectDescriptor.c +++ b/src/ObjectDescriptor.c @@ -22,7 +22,8 @@ asn_TYPE_descriptor_t asn_DEF_ObjectDescriptor = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_utf8, OCTET_STRING_encode_xer_utf8, - 0, 0, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, 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 f588083..c8ee3ae 100644 --- a/src/PrintableString.c +++ b/src/PrintableString.c @@ -1,10 +1,31 @@ /*- - * Copyright (c) 2003, 2004 Lev Walkin . All rights reserved. + * Copyright (c) 2003, 2004, 2006 Lev Walkin . + * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include +/* + * ASN.1:1984 (X.409) + */ +static 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, /* . '() +,-./ */ +10,11,12,13,14,15,16,17,18,19,20, 0, 0,21, 0,22, /* 0123456789: = ? */ + 0,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37, /* ABCDEFGHIJKLMNO */ +38,39,40,41,42,43,44,45,46,47,48, 0, 0, 0, 0, 0, /* PQRSTUVWXYZ */ + 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] = { +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, +97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112, +113,114,115,116,117,118,119,120,121,122}; + /* * PrintableString basic type description. */ @@ -12,6 +33,20 @@ static 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 */ }; +static int asn_DEF_PrintableString_v2c(unsigned int value) { + return _PrintableString_alphabet[value > 255 ? 0 : value] - 1; +} +static int asn_DEF_PrintableString_c2v(unsigned int code) { + if(code < 74) + return _PrintableString_code2value[code]; + return -1; +} +static 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, + asn_DEF_PrintableString_c2v +}; asn_TYPE_descriptor_t asn_DEF_PrintableString = { "PrintableString", "PrintableString", @@ -22,7 +57,8 @@ asn_TYPE_descriptor_t asn_DEF_PrintableString = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_utf8, OCTET_STRING_encode_xer_utf8, - 0, 0, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_PrintableString_tags, sizeof(asn_DEF_PrintableString_tags) @@ -30,34 +66,12 @@ asn_TYPE_descriptor_t asn_DEF_PrintableString = { asn_DEF_PrintableString_tags, sizeof(asn_DEF_PrintableString_tags) / sizeof(asn_DEF_PrintableString_tags[0]), - 0, /* No PER visible constraints */ + &asn_DEF_PrintableString_constraints, 0, 0, /* No members */ 0 /* No specifics */ }; -/* - * ASN.1:1984 (X.409) - */ -static int _PrintableString_alphabet[256] = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, /* ' */ -0x41, 0x42, 0x00, 0x43, 0x44, 0x45, 0x46, 0x47, /* ( ) + , - . / */ -0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, /* 0 1 2 3 4 5 6 7 */ -0x3d, 0x3e, 0x48, 0x00, 0x00, 0x49, 0x00, 0x4a, /* 8 9 : = ? */ -0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* A B C D E F G */ -0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* H I J K L M N O */ -0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* P Q R S T U V W */ -0x18, 0x19, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, /* X Y Z */ -0x00, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, /* a b c d e f g */ -0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, /* h i j k l m n o */ -0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, /* p q r s t u v w */ -0x32, 0x33, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, /* x y z */ -}; - int PrintableString_constraint(asn_TYPE_descriptor_t *td, const void *sptr, asn_app_constraint_failed_f *ctfailcb, void *app_key) { @@ -73,7 +87,7 @@ PrintableString_constraint(asn_TYPE_descriptor_t *td, const void *sptr, */ for(; buf < end; buf++) { if(!_PrintableString_alphabet[*buf]) { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: value byte %ld (%d) " "not in PrintableString alphabet " "(%s:%d)", @@ -85,7 +99,7 @@ PrintableString_constraint(asn_TYPE_descriptor_t *td, const void *sptr, } } } else { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: value not given (%s:%d)", td->name, __FILE__, __LINE__); return -1; diff --git a/src/REAL.c b/src/REAL.c index 51098c0..5e93ac8 100644 --- a/src/REAL.c +++ b/src/REAL.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2004 Lev Walkin . All rights reserved. + * Copyright (c) 2004, 2006 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #if defined(__alpha) @@ -12,12 +12,13 @@ #include #include #include +#include #undef INT_MAX #define INT_MAX ((int)(((unsigned int)-1) >> 1)) #if !(defined(NAN) || defined(INFINITY)) -static volatile double real_zero __attribute__ ((unused)) = 0.0; +static volatile double real_zero GCC_NOTUSED = 0.0; #endif #ifndef NAN #define NAN (real_zero/real_zero) @@ -42,7 +43,8 @@ asn_TYPE_descriptor_t asn_DEF_REAL = { der_encode_primitive, REAL_decode_xer, REAL_encode_xer, - 0, 0, + REAL_decode_uper, + REAL_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_REAL_tags, sizeof(asn_DEF_REAL_tags) / sizeof(asn_DEF_REAL_tags[0]), @@ -341,6 +343,20 @@ REAL_decode_xer(asn_codec_ctx_t *opt_codec_ctx, buf_ptr, size, REAL__xer_body_decode); } +asn_dec_rval_t +REAL_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) { + (void)constraints; /* No PER visible constraints */ + return OCTET_STRING_decode_uper(opt_codec_ctx, td, 0, sptr, pd); +} + +asn_enc_rval_t +REAL_encode_uper(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_uper(td, 0, sptr, po); +} int asn_REAL2double(const REAL_t *st, double *dbl_value) { @@ -437,16 +453,16 @@ asn_REAL2double(const REAL_t *st, double *dbl_value) { return -1; } - if((octv & 0x03) == 0x11) { - /* 8.5.6.4, case d) */ + elen = (octv & 0x03); /* bits 2 to 1; 8.5.6.4 */ + if(elen == 0x03) { /* bits 2 to 1 = 11; 8.5.6.4, case d) */ elen = st->buf[1]; /* unsigned binary number */ if(elen == 0 || st->size <= (int)(2 + elen)) { errno = EINVAL; return -1; } + /* FIXME: verify constraints of case d) */ ptr = &st->buf[2]; } else { - elen = (octv & 0x03); ptr = &st->buf[1]; } @@ -505,8 +521,8 @@ asn_double2REAL(REAL_t *st, double dbl_value) { uint8_t buf[16]; /* More than enough for 8-byte dbl_value */ uint8_t dscr[sizeof(dbl_value)]; /* double value scratch pad */ /* Assertion guards: won't even compile, if unexpected double size */ - char assertion_buffer1[9 - sizeof(dbl_value)] __attribute__((unused)); - char assertion_buffer2[sizeof(dbl_value) - 7] __attribute__((unused)); + char assertion_buffer1[9 - sizeof(dbl_value)] GCC_NOTUSED; + char assertion_buffer2[sizeof(dbl_value) - 7] GCC_NOTUSED; uint8_t *ptr = buf; uint8_t *mstop; /* Last byte of mantissa */ unsigned int mval; /* Value of the last byte of mantissa */ diff --git a/src/RELATIVE-OID.c b/src/RELATIVE-OID.c index 0181434..983fc09 100644 --- a/src/RELATIVE-OID.c +++ b/src/RELATIVE-OID.c @@ -5,6 +5,7 @@ */ #include #include +#include #include /* Encoder and decoder of a primitive type */ #include /* for CHAR_BIT */ #include @@ -25,7 +26,8 @@ asn_TYPE_descriptor_t asn_DEF_RELATIVE_OID = { der_encode_primitive, RELATIVE_OID_decode_xer, RELATIVE_OID_encode_xer, - 0, 0, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_RELATIVE_OID_tags, sizeof(asn_DEF_RELATIVE_OID_tags) diff --git a/src/T61String.c b/src/T61String.c index 25d887a..98461bb 100644 --- a/src/T61String.c +++ b/src/T61String.c @@ -22,7 +22,8 @@ asn_TYPE_descriptor_t asn_DEF_T61String = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_hex, OCTET_STRING_encode_xer, - 0, 0, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, 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 b96cb3b..cc2acad 100644 --- a/src/TeletexString.c +++ b/src/TeletexString.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003 Lev Walkin . All rights reserved. + * Copyright (c) 2003, 2006 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include @@ -22,7 +22,8 @@ asn_TYPE_descriptor_t asn_DEF_TeletexString = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_hex, OCTET_STRING_encode_xer, - 0, 0, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_TeletexString_tags, sizeof(asn_DEF_TeletexString_tags) @@ -35,3 +36,139 @@ asn_TYPE_descriptor_t asn_DEF_TeletexString = { 0 /* No specifics */ }; +/* + * Here is a formal attempt at creating a mapping from TeletexString + * (T61String) of the latest ASN.1 standard (X.680:2002) into the Unicode + * character set. -- Lev Walkin + * + * The first thing to keep in mind is that TeletexString (T61String) + * is defined in ASN.1, and is not really a T.61 string. + * The T.61 standard is withdrawn by ITU-T and is no longer an authoritative + * reference. See http://www.itu.int/rec/T-REC-T.61 + * + * The X.680 specifies TeletexString (T61String) as a combination of the + * character sets specified by the registration numbers listed in + * ISO International Register of Coded Character Sets to be used with + * Escape Sequences (ISO-2375): + * 6, 87, 102, 103, 106, 107, 126, 144, 150, 153, 156, 164, 165, 168, + * plus SPACE and DELETE characters. + * In addition to that, the X.680 Table 6 NOTE 2 allows using register entries + * 6 and 156 instead of 102 and 103. + * + * The ISO Register itself is available at http://www.itscj.ipsj.or.jp/ISO-IR/ + * + * #6 is ASCII. http://www.itscj.ipsj.or.jp/ISO-IR/006.pdf + * Escapes into: + * G0: ESC 2/8 4/2 ("(B") + * G1: ESC 2/9 4/2 (")B") + * The range is [0x21 .. 0x7e]. Conversion into Unicode + * is simple, because it has one-to-one correspondence. + * #87 is a "Japanese Graphic Character Set for Information Interchange". + * Is a multiple-byte set of 6877 characters. + * The character set is JIS X 0208-1983 (originally JIS C 6226-1983). + * Escapes into: + * G0: ESC 2/4 4/2 ("$B") + * G1: ESC 2/4 2/9 4/2 ("$)B") + * G2: ESC 2/4 2/10 4/2 ("$*B") + * G3: ESC 2/4 2/11 4/2 ("$+B") + * #102 is "Teletex Primary Set of Graphic Characters" and is almost ASCII. + * Escapes into: + * G0: ESC 2/8 7/5 ("(u") + * G1: ESC 2/9 7/5 (")u") + * G2: ESC 2/10 7/5 ("*u") + * G3: ESC 2/11 7/5 ("+u") + * It is almost identical to ASCII, except for ASCII position for '$' + * (DOLLAR SIGN) is filled with 'ยค' (CURRENCY SIGN), which is U+00A4. + * Also, ASCII positions for '`', '\', '^', '{', '}', '~' are marked + * as "should not be used". + * #103 is a supplementary set of characters used in combination with #102. + * Escapes into: + * G0: ESC 2/8 7/6 ("(v") + * G1: ESC 2/9 7/6 (")v") + * G2: ESC 2/10 7/6 ("*v") + * G3: ESC 2/11 7/6 ("+v") + * Some characters in that character set are combining characters, + * which can only be restrictively used with certain basic Latin letters. + * It can be thought of as a subset of #156 with the exception of 4/12 + * which is UNDERLINE in #103 and absent in #156. + * #106 is a primary set of control functions, used in combination with #107. + * Escapes into: + * C0: ESC 2/1 4/5 ("!E") + * This set is so short I can list it here: + * 0x08 BS BACKSPACE -- same as Unicode + * 0x0a LF LINE FEED -- same as Unicode + * 0x0c FF FORM FEED -- same as Unicode + * 0x0d CR CARRIAGE RETURN -- same as Unicode + * 0x0e LS1 LOCKING SHIFT ONE + * 0x0f LS0 LOCKING SHIFT ZERO + * 0x19 SS2 SINGLE SHIFT TWO + * 0x1a SUB SUBSTITUTE CHARACTER + * 0x1b ESC ESCAPE -- same as Unicode + * 0x1d SS3 SINGLE SHIFT THREE + * The LS1 and LS0 are two magical functions which, respectively, invoke + * the currently designated G1 or G0 set into positions 2/1 to 7/14 + * The SS2 and SS3, respectively, invoke one character of the + * currently designated set G2 and G3. + * The SUB is wholly equivalent to U+001a (SUBSTITUTE) + * #107 is a supplementary set of control functions, used with #106. + * Escapes into: + * C1: ESC 2/2 4/8 ('"H') + * This set contains three special control codes: + * 0x8b PLD PARTIAL LINE DOWN -- similar to + * 0x8c PLU PARTIAL LINE UP -- sumilar to + * 0x9b CSI CONTROL SEQUENCE INTRODUCER + * This set is so out of world we can probably safely ignore it. + * #126 is a "Right-hand Part of the Latin/Greek Alphabet". + * Comprises of 90 characters, including accented letters. + * Escapes into: + * G1: ESC 2/13 4/6 ("-F") + * G2: ESC 2/14 4/6 (".F") + * G3: ESC 2/15 4/6 ("/F") + * Note: This Registration is a subset of ISO-IR 227. + * #144 is a "Cyrillic part of the Latin/Cyrillic Alphabet". + * Comprises of 95 characters. + * Escapes into: + * G1: ESC 2/13 4/12 ("-L") + * G2: ESC 2/14 4/12 (".L") + * G3: ESC 2/15 4/12 ("/L") + * #150 is a "Greek Primary Set of Graphic Characters". + * Comprises of 94 characters. + * Escapes into: + * G0: ESC 2/8 2/1 4/0 ("(!@") + * G1: ESC 2/9 2/1 4/0 (")!@") + * G2: ESC 2/10 2/1 4/0 ("*!@") + * G3: ESC 2/11 2/1 4/0 ("+!@") + * #153 is a "Basic Cyrillic Character Set for 8-bit codes". + * Comprises of 68 characters. + * Escapes into: + * G1: ESC 2/13 4/15 ("-O") + * G2: ESC 2/14 4/15 (".O") + * G3: ESC 2/15 4/15 ("/O") + * #156 is a "Supplementary Set of ISO/IEC 6937:1992" for use with #6 + * Comprises of 87 characters. + * Escapes into: + * G1: ESC 2/13 5/2 ("-R") + * G2: ESC 2/14 5/2 (".R") + * G3: ESC 2/15 5/2 ("/R") + * #164 is a "Hebrew Supplementary Set of Graphic Characters" + * Comprises of 27 characters. + * Escapes into: + * G1: ESC 2/13 5/3 ("-S") + * G2: ESC 2/14 5/3 (".S") + * G3: ESC 2/15 5/3 ("/S") + * #165 is a set of "Codes of the Chinese graphic character set" + * Is a multiple-byte set of 8446 characters. + * Escapes into: + * G0: ESC 2/4 2/8 4/5 ("$(E") + * G1: ESC 2/4 2/9 4/5 ("$)E") + * G2: ESC 2/4 2/10 4/5 ("$*E") + * G3: ESC 2/4 2/11 4/5 ("$+E") + * #168 is a "Japanese Graphic Character Set for Information Interchange" + * A multiple-byte set of 6879 characters updated from #87. + * Escapes into: + * G0: ESC 2/6 4/0 ESC 2/4 4/2 ("&@" "$B") + * G1: ESC 2/6 4/0 ESC 2/4 2/9 4/2 ("&@" "$)B") + * G2: ESC 2/6 4/0 ESC 2/4 2/10 4/2 ("&@" "$*B") + * G3: ESC 2/6 4/0 ESC 2/4 2/11 4/2 ("&@" "$+B") + */ + diff --git a/src/UTCTime.c b/src/UTCTime.c index 2a27718..0abe1db 100644 --- a/src/UTCTime.c +++ b/src/UTCTime.c @@ -23,6 +23,11 @@ static ber_tlv_tag_t asn_DEF_UTCTime_tags[] = { (ASN_TAG_CLASS_UNIVERSAL | (26 << 2)), /* [UNIVERSAL 26] IMPLICIT ...*/ (ASN_TAG_CLASS_UNIVERSAL | (4 << 2)) /* ... OCTET STRING */ }; +static asn_per_constraints_t asn_DEF_UTCTime_constraints = { + { APC_CONSTRAINED, 7, 7, 0x20, 0x7e }, /* Value */ + { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, /* Size */ + 0, 0 +}; asn_TYPE_descriptor_t asn_DEF_UTCTime = { "UTCTime", "UTCTime", @@ -33,7 +38,8 @@ asn_TYPE_descriptor_t asn_DEF_UTCTime = { OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */ OCTET_STRING_decode_xer_utf8, UTCTime_encode_xer, - 0, 0, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_UTCTime_tags, sizeof(asn_DEF_UTCTime_tags) @@ -41,7 +47,7 @@ asn_TYPE_descriptor_t asn_DEF_UTCTime = { asn_DEF_UTCTime_tags, sizeof(asn_DEF_UTCTime_tags) / sizeof(asn_DEF_UTCTime_tags[0]), - 0, /* No PER visible constraints */ + &asn_DEF_UTCTime_constraints, 0, 0, /* No members */ 0 /* No specifics */ }; @@ -60,7 +66,7 @@ UTCTime_constraint(asn_TYPE_descriptor_t *td, const void *sptr, errno = EPERM; /* Just an unlikely error code */ tloc = asn_UT2time(st, 0, 0); if(tloc == -1 && errno != EPERM) { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: Invalid time format: %s (%s:%d)", td->name, strerror(errno), __FILE__, __LINE__); return -1; diff --git a/src/UTF8String.c b/src/UTF8String.c index e3f7388..7e73d77 100644 --- a/src/UTF8String.c +++ b/src/UTF8String.c @@ -23,7 +23,8 @@ asn_TYPE_descriptor_t asn_DEF_UTF8String = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_utf8, OCTET_STRING_encode_xer_utf8, - 0, 0, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_UTF8String_tags, sizeof(asn_DEF_UTF8String_tags) @@ -72,26 +73,26 @@ UTF8String_constraint(asn_TYPE_descriptor_t *td, const void *sptr, ssize_t len = UTF8String_length((const UTF8String_t *)sptr); switch(len) { case U8E_EINVAL: - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: value not given", td->name); break; case U8E_TRUNC: - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: truncated UTF-8 sequence (%s:%d)", td->name, __FILE__, __LINE__); break; case U8E_ILLSTART: - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: UTF-8 illegal start of encoding (%s:%d)", td->name, __FILE__, __LINE__); break; case U8E_NOTCONT: - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: UTF-8 not continuation (%s:%d)", td->name, __FILE__, __LINE__); break; case U8E_NOTMIN: - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: UTF-8 not minimal sequence (%s:%d)", td->name, __FILE__, __LINE__); break; diff --git a/src/UniversalString.c b/src/UniversalString.c index a39e569..7d16781 100644 --- a/src/UniversalString.c +++ b/src/UniversalString.c @@ -13,6 +13,16 @@ static 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 */ }; +static asn_OCTET_STRING_specifics_t asn_DEF_UniversalString_specs = { + sizeof(UniversalString_t), + offsetof(UniversalString_t, _asn_ctx), + ASN_OSUBV_U32 /* 32-bits character */ +}; +static asn_per_constraints_t asn_DEF_UniversalString_constraints = { + { APC_CONSTRAINED, 32, 32, 0, 2147483647 }, + { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, + 0, 0 +}; asn_TYPE_descriptor_t asn_DEF_UniversalString = { "UniversalString", "UniversalString", @@ -23,7 +33,8 @@ asn_TYPE_descriptor_t asn_DEF_UniversalString = { OCTET_STRING_encode_der, UniversalString_decode_xer, /* Convert from UTF-8 */ UniversalString_encode_xer, /* Convert into UTF-8 */ - 0, 0, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_UniversalString_tags, sizeof(asn_DEF_UniversalString_tags) @@ -31,9 +42,9 @@ asn_TYPE_descriptor_t asn_DEF_UniversalString = { asn_DEF_UniversalString_tags, sizeof(asn_DEF_UniversalString_tags) / sizeof(asn_DEF_UniversalString_tags[0]), - 0, /* No PER visible constraints */ + &asn_DEF_UniversalString_constraints, 0, 0, /* No members */ - 0 /* No specifics */ + &asn_DEF_UniversalString_specs }; diff --git a/src/VideotexString.c b/src/VideotexString.c index 5f5f33d..df7233e 100644 --- a/src/VideotexString.c +++ b/src/VideotexString.c @@ -22,7 +22,8 @@ asn_TYPE_descriptor_t asn_DEF_VideotexString = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_hex, OCTET_STRING_encode_xer, - 0, 0, + OCTET_STRING_decode_uper, /* Implemented in terms of OCTET STRING */ + OCTET_STRING_encode_uper, 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 8796582..3487b6f 100644 --- a/src/VisibleString.c +++ b/src/VisibleString.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2003 Lev Walkin . All rights reserved. + * Copyright (c) 2003, 2006 Lev Walkin . All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include @@ -12,6 +12,11 @@ static 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 */ }; +static asn_per_constraints_t asn_DEF_VisibleString_constraints = { + { APC_CONSTRAINED, 7, 7, 0x20, 0x7e }, /* Value */ + { APC_SEMI_CONSTRAINED, -1, -1, 0, 0 }, /* Size */ + 0, 0 +}; asn_TYPE_descriptor_t asn_DEF_VisibleString = { "VisibleString", "VisibleString", @@ -22,7 +27,8 @@ asn_TYPE_descriptor_t asn_DEF_VisibleString = { OCTET_STRING_encode_der, OCTET_STRING_decode_xer_utf8, OCTET_STRING_encode_xer_utf8, - 0, 0, + OCTET_STRING_decode_uper, + OCTET_STRING_encode_uper, 0, /* Use generic outmost tag fetcher */ asn_DEF_VisibleString_tags, sizeof(asn_DEF_VisibleString_tags) @@ -30,7 +36,7 @@ asn_TYPE_descriptor_t asn_DEF_VisibleString = { asn_DEF_VisibleString_tags, sizeof(asn_DEF_VisibleString_tags) / sizeof(asn_DEF_VisibleString_tags[0]), - 0, /* No PER visible constraints */ + &asn_DEF_VisibleString_constraints, 0, 0, /* No members */ 0 /* No specifics */ }; @@ -52,7 +58,7 @@ VisibleString_constraint(asn_TYPE_descriptor_t *td, const void *sptr, */ for(; buf < end; buf++) { if(*buf < 0x20 || *buf > 0x7e) { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: value byte %ld (%d) " "not in VisibleString alphabet (%s:%d)", td->name, @@ -63,7 +69,7 @@ VisibleString_constraint(asn_TYPE_descriptor_t *td, const void *sptr, } } } else { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: value not given (%s:%d)", td->name, __FILE__, __LINE__); return -1; diff --git a/src/constr_CHOICE.c b/src/constr_CHOICE.c index b8d6fa9..a9eb719 100644 --- a/src/constr_CHOICE.c +++ b/src/constr_CHOICE.c @@ -1,10 +1,11 @@ /* - * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . + * Copyright (c) 2003, 2004, 2005, 2006, 2007 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include +#include /* * Number of bytes left for this structure. @@ -482,7 +483,7 @@ CHOICE_constraint(asn_TYPE_descriptor_t *td, const void *sptr, int present; if(!sptr) { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: value not given (%s:%d)", td->name, __FILE__, __LINE__); return -1; @@ -501,7 +502,7 @@ CHOICE_constraint(asn_TYPE_descriptor_t *td, const void *sptr, if(!memb_ptr) { if(elm->optional) return 0; - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: mandatory CHOICE element %s absent (%s:%d)", td->name, elm->name, __FILE__, __LINE__); return -1; @@ -524,7 +525,7 @@ CHOICE_constraint(asn_TYPE_descriptor_t *td, const void *sptr, return ret; } } else { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: no CHOICE element given (%s:%d)", td->name, __FILE__, __LINE__); return -1; @@ -871,8 +872,6 @@ CHOICE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, value += specs->ext_start; if(value >= td->elements_count) _ASN_DECODE_FAILED; - ASN_DEBUG("NOT IMPLEMENTED YET"); - _ASN_DECODE_FAILED; } /* Adjust if canonical order is different from natural order */ @@ -892,11 +891,17 @@ CHOICE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, } ASN_DEBUG("Discovered CHOICE %s encodes %s", td->name, elm->name); - rv = elm->type->uper_decoder(opt_codec_ctx, elm->type, + if(ct && ct->range_bits >= 0) { + rv = elm->type->uper_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)", - elm->name, td->name); + ASN_DEBUG("Failed to decode %s in %s (CHOICE) %d", + elm->name, td->name, rv.code); return rv; } @@ -951,18 +956,6 @@ CHOICE_encode_uper(asn_TYPE_descriptor_t *td, if(per_put_few_bits(po, 0, 1)) _ASN_ENCODE_FAILED; - if(ct && ct->range_bits >= 0) { - if(per_put_few_bits(po, present, ct->range_bits)) - _ASN_ENCODE_FAILED; - } else { - if(specs->ext_start == -1) - _ASN_ENCODE_FAILED; - if(uper_put_nsnnwn(po, present - specs->ext_start)) - _ASN_ENCODE_FAILED; - ASN_DEBUG("NOT IMPLEMENTED YET"); - _ASN_ENCODE_FAILED; - } - elm = &td->elements[present]; if(elm->flags & ATF_POINTER) { /* Member is a pointer to another structure */ @@ -972,8 +965,24 @@ CHOICE_encode_uper(asn_TYPE_descriptor_t *td, memb_ptr = (char *)sptr + elm->memb_offset; } - return elm->type->uper_encoder(elm->type, elm->per_constraints, + if(ct && ct->range_bits >= 0) { + if(per_put_few_bits(po, present, ct->range_bits)) + _ASN_ENCODE_FAILED; + + return elm->type->uper_encoder(elm->type, elm->per_constraints, memb_ptr, po); + } else { + asn_enc_rval_t rval; + if(specs->ext_start == -1) + _ASN_ENCODE_FAILED; + if(uper_put_nsnnwn(po, present - specs->ext_start)) + _ASN_ENCODE_FAILED; + if(uper_open_type_put(elm->type, elm->per_constraints, + memb_ptr, po)) + _ASN_ENCODE_FAILED; + rval.encoded = 0; + _ASN_ENCODED_OK(rval); + } } diff --git a/src/constr_SEQUENCE.c b/src/constr_SEQUENCE.c index b769434..db3c925 100644 --- a/src/constr_SEQUENCE.c +++ b/src/constr_SEQUENCE.c @@ -1,10 +1,11 @@ /*- - * Copyright (c) 2003, 2004, 2005, 2006 Lev Walkin . + * Copyright (c) 2003, 2004, 2005, 2006, 2007 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include +#include /* * Number of bytes left for this structure. @@ -346,7 +347,8 @@ SEQUENCE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, * or an extension (...), * or an end of the indefinite-length structure. */ - if(!IN_EXTENSION_GROUP(specs, edx)) { + if(!IN_EXTENSION_GROUP(specs, + edx + elements[edx].optional)) { ASN_DEBUG("Unexpected tag %s (at %d)", ber_tlv_tag_string(tlv_tag), edx); ASN_DEBUG("Expected tag %s (%s)%s", @@ -358,7 +360,10 @@ SEQUENCE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, } else { /* Skip this tag */ ssize_t skip; + edx += elements[edx].optional; + ASN_DEBUG("Skipping unexpected %s (at %d)", + ber_tlv_tag_string(tlv_tag), edx); skip = ber_skip_length(opt_codec_ctx, BER_TLV_CONSTRUCTED(ptr), (const char *)ptr + tag_len, @@ -976,7 +981,7 @@ SEQUENCE_constraint(asn_TYPE_descriptor_t *td, const void *sptr, int edx; if(!sptr) { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: value not given (%s:%d)", td->name, __FILE__, __LINE__); return -1; @@ -994,7 +999,7 @@ SEQUENCE_constraint(asn_TYPE_descriptor_t *td, const void *sptr, if(!memb_ptr) { if(elm->optional) continue; - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: mandatory element %s absent (%s:%d)", td->name, elm->name, __FILE__, __LINE__); return -1; @@ -1027,7 +1032,7 @@ SEQUENCE_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_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; void *st = *sptr; /* Target structure. */ - int extpresent = 0; /* Extension additions are present */ + int extpresent; /* Extension additions are present */ uint8_t *opres; /* Presence of optional root members */ asn_per_data_t opmd; asn_dec_rval_t rv; @@ -1049,9 +1054,12 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, 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; @@ -1061,24 +1069,24 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, _ASN_DECODE_STARVED; } opmd.buffer = opres; - opmd.nboff = 0; 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; - memset(&opmd, 0, sizeof opmd); } /* * Get the sequence ROOT elements. */ - for(edx = 0; edx < ((specs->ext_before < 0) - ? td->elements_count : specs->ext_before + 1); edx++) { + 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); @@ -1101,6 +1109,7 @@ SEQUENCE_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, FREEMEM(opres); _ASN_DECODE_FAILED; } + ASN_DEBUG("Filled-in default"); } /* The member is just not present */ continue; @@ -1120,50 +1129,176 @@ 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) { - ASN_DEBUG("Extensibility for %s: NOT IMPLEMENTED", td->name); - _ASN_DECODE_FAILED; - } else { - for(edx = specs->roms_count; edx < specs->roms_count - + specs->aoms_count; edx++) { - asn_TYPE_member_t *elm = &td->elements[edx]; - void *memb_ptr; /* Pointer to the member */ - void **memb_ptr2; /* Pointer to that pointer */ + ssize_t bmlength; + uint8_t *epres; /* Presence of extension members */ + asn_per_data_t epmd; - if(!elm->default_value) continue; + bmlength = uper_get_nslength(pd); + if(bmlength < 0) _ASN_DECODE_STARVED; - /* 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; - } + ASN_DEBUG("Extensions %d present in %s", bmlength, td->name); + + epres = (uint8_t *)MALLOC((bmlength + 15) >> 3); + if(!epres) _ASN_DECODE_STARVED; + + /* Get the extensions map */ + if(per_get_many_bits(pd, epres, 0, bmlength)) + _ASN_DECODE_STARVED; + + memset(&epmd, 0, sizeof(epmd)); + epmd.buffer = epres; + epmd.nbits = bmlength; + ASN_DEBUG("Read in extensions bitmap for %s of %d bits (%x..)", + td->name, bmlength, *epres); - /* Set default value */ - if(elm->default_value(1, memb_ptr2)) { - FREEMEM(opres); - _ASN_DECODE_FAILED; + /* 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; - FREEMEM(opres); return rv; } +static int +SEQUENCE_handle_extensions(asn_TYPE_descriptor_t *td, void *sptr, + asn_per_outp_t *po1, asn_per_outp_t *po2) { + asn_SEQUENCE_specifics_t *specs + = (asn_SEQUENCE_specifics_t *)td->specifics; + int exts_present = 0; + int exts_count = 0; + int edx; + + if(specs->ext_before < 0) + return 0; + + /* Find out which extensions are present */ + 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("%s (@%d) is not extension", elm->type->name, edx); + continue; + } + + /* 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; + } + + ASN_DEBUG("checking %s (@%d) present => %d", + elm->type->name, edx, present); + exts_count++; + exts_present += present; + + /* Encode as presence marker */ + 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, + elm->per_constraints, *memb_ptr2, po2)) + return -1; + + } + + return exts_present ? exts_count : 0; +} + asn_enc_rval_t SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td, asn_per_constraints_t *constraints, void *sptr, asn_per_outp_t *po) { asn_SEQUENCE_specifics_t *specs = (asn_SEQUENCE_specifics_t *)td->specifics; asn_enc_rval_t er; + int n_extensions; int edx; int i; @@ -1175,8 +1310,18 @@ SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td, er.encoded = 0; ASN_DEBUG("Encoding %s as SEQUENCE (UPER)", td->name); - if(specs->ext_before >= 0) - _ASN_ENCODE_FAILED; /* We don't encode extensions yet */ + + + /* + * 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++) { @@ -1212,14 +1357,21 @@ SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td, } /* - * Get the sequence ROOT elements. + * Encode the sequence ROOT elements. */ - for(edx = 0; edx < ((specs->ext_before < 0) - ? td->elements_count : specs->ext_before + 1); edx++) { + 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); @@ -1240,12 +1392,32 @@ SEQUENCE_encode_uper(asn_TYPE_descriptor_t *td, if(elm->default_value && elm->default_value(0, memb_ptr2) == 1) continue; + ASN_DEBUG("Encoding %s->%s", td->name, elm->name); er = elm->type->uper_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(uper_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_SET.c b/src/constr_SET.c index 9b6012f..ecf5661 100644 --- a/src/constr_SET.c +++ b/src/constr_SET.c @@ -6,12 +6,6 @@ #include #include -#ifndef WIN32 -#include /* for ntohl() */ -#else -#include /* for ntohl() */ -#endif - /* Check that all the mandatory members are present */ static int _SET_is_populated(asn_TYPE_descriptor_t *td, void *st); @@ -411,7 +405,7 @@ _SET_is_populated(asn_TYPE_descriptor_t *td, void *st) { midx = edx/(8 * sizeof(specs->_mandatory_elements[0])); pres = ((unsigned int *)((char *)st+specs->pres_offset))[midx]; - must = ntohl(specs->_mandatory_elements[midx]); + must = sys_ntohl(specs->_mandatory_elements[midx]); if((pres & must) == must) { /* @@ -945,7 +939,7 @@ SET_constraint(asn_TYPE_descriptor_t *td, const void *sptr, int edx; if(!sptr) { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: value not given (%s:%d)", td->name, __FILE__, __LINE__); return -1; @@ -963,7 +957,7 @@ SET_constraint(asn_TYPE_descriptor_t *td, const void *sptr, if(!memb_ptr) { if(elm->optional) continue; - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: mandatory element %s absent (%s:%d)", td->name, elm->name, __FILE__, __LINE__); return -1; diff --git a/src/constr_SET_OF.c b/src/constr_SET_OF.c index 09f27db..11eac57 100644 --- a/src/constr_SET_OF.c +++ b/src/constr_SET_OF.c @@ -227,6 +227,8 @@ SET_OF_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, } /* Fall through */ case RC_FAIL: /* Fatal error */ + ASN_STRUCT_FREE(*elm->type, ctx->ptr); + ctx->ptr = 0; RETURN(RC_FAIL); } /* switch(rval) */ @@ -787,8 +789,10 @@ SET_OF_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, void SET_OF_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { if(td && ptr) { + asn_SET_OF_specifics_t *specs; asn_TYPE_member_t *elm = td->elements; asn_anonymous_set_ *list = _A_SET_FROM_VOID(ptr); + asn_struct_ctx_t *ctx; /* Decoder context */ int i; /* @@ -804,6 +808,13 @@ SET_OF_free(asn_TYPE_descriptor_t *td, void *ptr, int contents_only) { asn_set_empty(list); /* Remove (list->array) */ + specs = (asn_SET_OF_specifics_t *)td->specifics; + ctx = (asn_struct_ctx_t *)((char *)ptr + specs->ctx_offset); + if(ctx->ptr) { + ASN_STRUCT_FREE(*elm->type, ctx->ptr); + ctx->ptr = 0; + } + if(!contents_only) { FREEMEM(ptr); } @@ -819,7 +830,7 @@ SET_OF_constraint(asn_TYPE_descriptor_t *td, const void *sptr, int i; if(!sptr) { - _ASN_CTFAIL(app_key, td, + _ASN_CTFAIL(app_key, td, sptr, "%s: value not given (%s:%d)", td->name, __FILE__, __LINE__); return -1; @@ -921,7 +932,7 @@ SET_OF_decode_uper(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, ASN_DEBUG("Failed to add element into %s", td->name); /* Fall through */ - rv.code == RC_FAIL; + rv.code = RC_FAIL; } else { ASN_DEBUG("Failed decoding %s of %s (SET OF)", elm->type->name, td->name); diff --git a/src/per_decoder.c b/src/per_decoder.c index 16dee36..2b3d2e2 100644 --- a/src/per_decoder.c +++ b/src/per_decoder.c @@ -2,6 +2,40 @@ #include #include +/* + * Decode a "Production of a complete encoding", X.691#10.1. + * The complete encoding contains at least one byte, and is an integral + * multiple of 8 bytes. + */ +asn_dec_rval_t +uper_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 = 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(((uint8_t *)buffer)[0] == 0) { + rval.consumed = 1; /* 1 byte */ + } else { + ASN_DEBUG("Expecting single zeroed byte"); + rval.code = RC_FAIL; + } + } else { + /* Must contain at least 8 bits. */ + rval.code = RC_WMORE; + } + } + + return rval; +} + asn_dec_rval_t uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sptr, const void *buffer, size_t size, int skip_bits, int unused_bits) { asn_codec_ctx_t s_codec_ctx; @@ -30,6 +64,7 @@ uper_decode(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, void **sp } /* 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 */ @@ -46,6 +81,9 @@ 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); + assert(rval.consumed == pd.moved); } else { /* PER codec is not a restartable */ rval.consumed = 0; diff --git a/src/per_encoder.c b/src/per_encoder.c index 614dd23..f4bace0 100644 --- a/src/per_encoder.c +++ b/src/per_encoder.c @@ -2,41 +2,11 @@ #include #include -/* Flush partially filled buffer */ -static int _uper_encode_flush_outp(asn_per_outp_t *po); +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); asn_enc_rval_t uper_encode(asn_TYPE_descriptor_t *td, void *sptr, asn_app_consume_bytes_f *cb, void *app_key) { - asn_per_outp_t po; - asn_enc_rval_t er; - - /* - * Invoke type-specific encoder. - */ - if(!td || !td->uper_encoder) - _ASN_ENCODE_FAILED; /* PER is not compiled in */ - - po.buffer = po.tmpspace; - po.nboff = 0; - po.nbits = 8 * sizeof(po.tmpspace); - po.outper = cb; - po.op_key = app_key; - po.flushed_bytes = 0; - - er = td->uper_encoder(td, 0, 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(_uper_encode_flush_outp(&po)) - _ASN_ENCODE_FAILED; - } - - return er; + return uper_encode_internal(td, 0, sptr, cb, app_key); } /* @@ -63,20 +33,71 @@ asn_enc_rval_t uper_encode_to_buffer(asn_TYPE_descriptor_t *td, void *sptr, void *buffer, size_t buffer_size) { enc_to_buf_arg key; - /* - * Invoke type-specific encoder. - */ - if(!td || !td->uper_encoder) - _ASN_ENCODE_FAILED; /* PER is not compiled in */ - key.buffer = buffer; key.left = buffer_size; - ASN_DEBUG("Encoding \"%s\" using UNALIGNED PER", td->name); + if(td) ASN_DEBUG("Encoding \"%s\" using UNALIGNED PER", td->name); - return uper_encode(td, sptr, encode_to_buffer_cb, &key); + return uper_encode_internal(td, 0, sptr, encode_to_buffer_cb, &key); } +typedef struct enc_dyn_arg { + void *buffer; + size_t length; + size_t allocated; +} enc_dyn_arg; +static int +encode_dyn_cb(const void *buffer, size_t size, void *key) { + enc_dyn_arg *arg = key; + if(arg->length + size >= arg->allocated) { + void *p; + arg->allocated = arg->allocated ? (arg->allocated << 2) : size; + p = REALLOC(arg->buffer, arg->allocated); + if(!p) { + FREEMEM(arg->buffer); + memset(arg, 0, sizeof(*arg)); + return -1; + } + arg->buffer = p; + } + memcpy(((char *)arg->buffer) + arg->length, buffer, size); + arg->length += size; + return 0; +} +ssize_t +uper_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 = uper_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. + */ + +/* Flush partially filled buffer */ static int _uper_encode_flush_outp(asn_per_outp_t *po) { uint8_t *buf; @@ -93,3 +114,38 @@ _uper_encode_flush_outp(asn_per_outp_t *po) { 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; + asn_enc_rval_t er; + + /* + * Invoke type-specific encoder. + */ + if(!td || !td->uper_encoder) + _ASN_ENCODE_FAILED; /* PER is not compiled in */ + + po.buffer = po.tmpspace; + po.nboff = 0; + po.nbits = 8 * sizeof(po.tmpspace); + po.outper = cb; + po.op_key = app_key; + po.flushed_bytes = 0; + + er = td->uper_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(_uper_encode_flush_outp(&po)) + _ASN_ENCODE_FAILED; + } + + return er; +} + diff --git a/src/per_opentype.c b/src/per_opentype.c new file mode 100644 index 0000000..c749c8c --- /dev/null +++ b/src/per_opentype.c @@ -0,0 +1,373 @@ +/* + * Copyright (c) 2007 Lev Walkin . All rights reserved. + * Redistribution and modifications are permitted subject to BSD license. + */ +#include +#include +#include +#include + +typedef struct uper_ugot_key { + asn_per_data_t oldpd; /* Old per data source */ + size_t unclaimed; + size_t ot_moved; /* Number of bits moved by OT processing */ + int repeat; +} uper_ugot_key; + +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 + */ +int +uper_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 = uper_encode_to_new_buffer(td, constraints, sptr, &buf); + if(size <= 0) return -1; + + for(bptr = buf, toGo = size; toGo;) { + ssize_t maySave = uper_put_length(po, toGo); + if(maySave < 0) break; + if(per_put_many_bits(po, bptr, maySave * 8)) break; + bptr = (char *)bptr + maySave; + toGo -= maySave; + } + + FREEMEM(buf); + if(toGo) return -1; + + ASN_DEBUG("Open type put %s of length %d + overhead (1byte?)", + td->name, size); + + return 0; +} + +static asn_dec_rval_t +uper_open_type_get_simple(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + asn_dec_rval_t rv; + ssize_t chunk_bytes; + int repeat; + uint8_t *buf = 0; + size_t bufLen = 0; + size_t bufSize = 0; + asn_per_data_t spd; + size_t padding; + + _ASN_STACK_OVERFLOW_CHECK(ctx); + + ASN_DEBUG("Getting open type %s...", td->name); + + do { + chunk_bytes = uper_get_length(pd, -1, &repeat); + if(chunk_bytes < 0) { + FREEMEM(buf); + _ASN_DECODE_STARVED; + } + if(bufLen + chunk_bytes > bufSize) { + void *ptr; + bufSize = chunk_bytes + (bufSize << 2); + ptr = REALLOC(buf, bufSize); + if(!ptr) { + FREEMEM(buf); + _ASN_DECODE_FAILED; + } + buf = ptr; + } + if(per_get_many_bits(pd, buf + bufLen, 0, chunk_bytes << 3)) { + FREEMEM(buf); + _ASN_DECODE_STARVED; + } + bufLen += chunk_bytes; + } while(repeat); + + ASN_DEBUG("Getting open type %s encoded in %d bytes", td->name, + bufLen); + + memset(&spd, 0, sizeof(spd)); + spd.buffer = buf; + spd.nbits = bufLen << 3; + + asn_debug_indent += 4; + rv = td->uper_decoder(ctx, td, constraints, sptr, &spd); + asn_debug_indent -= 4; + + if(rv.code == RC_OK) { + /* Check padding validity */ + padding = spd.nbits - spd.nboff; + if(padding < 8 && 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_DECODE_FAILED; + } else { + ASN_DEBUG("Non-zero padding"); + _ASN_DECODE_FAILED; + } + } else { + FREEMEM(buf); + /* rv.code could be RC_WMORE, nonsense in this context */ + rv.code = RC_FAIL; /* Noone would give us more */ + } + + return rv; +} + +static asn_dec_rval_t GCC_NOTUSED +uper_open_type_get_complex(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + uper_ugot_key arg; + asn_dec_rval_t rv; + ssize_t padding; + + _ASN_STACK_OVERFLOW_CHECK(ctx); + + ASN_DEBUG("Getting open type %s from %s", td->name, + per_data_string(pd)); + arg.oldpd = *pd; + arg.unclaimed = 0; + arg.ot_moved = 0; + arg.repeat = 1; + pd->refill = uper_ugot_refill; + pd->refill_key = &arg; + 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; + rv = td->uper_decoder(ctx, td, constraints, sptr, pd); + asn_debug_indent -= 4; + +#define UPDRESTOREPD do { \ + /* buffer and nboff are valid, preserve them. */ \ + pd->nbits = arg.oldpd.nbits - (pd->moved - arg.ot_moved); \ + pd->moved = arg.oldpd.moved + (pd->moved - arg.ot_moved); \ + pd->refill = arg.oldpd.refill; \ + pd->refill_key = arg.oldpd.refill_key; \ + } while(0) + + if(rv.code != RC_OK) { + UPDRESTOREPD; + return rv; + } + + 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); + + padding = pd->moved % 8; + if(padding) { + int32_t pvalue; + if(padding > 7) { + ASN_DEBUG("Too large padding %d in open type", + padding); + rv.code = RC_FAIL; + UPDRESTOREPD; + return rv; + } + padding = 8 - padding; + ASN_DEBUG("Getting padding of %d bits", padding); + pvalue = per_get_few_bits(pd, padding); + switch(pvalue) { + case -1: + ASN_DEBUG("Padding skip failed"); + UPDRESTOREPD; + _ASN_DECODE_STARVED; + case 0: break; + default: + ASN_DEBUG("Non-blank padding (%d bits 0x%02x)", + padding, (int)pvalue); + UPDRESTOREPD; + _ASN_DECODE_FAILED; + } + } + if(pd->nboff != pd->nbits) { + ASN_DEBUG("Open type %s overhead pd%s old%s", td->name, + per_data_string(pd), per_data_string(&arg.oldpd)); + if(1) { + UPDRESTOREPD; + _ASN_DECODE_FAILED; + } else { + arg.unclaimed += pd->nbits - pd->nboff; + } + } + + /* Adjust pd back so it points to original data */ + UPDRESTOREPD; + + /* Skip data not consumed by the decoder */ + if(arg.unclaimed) ASN_DEBUG("Getting unclaimed %d", arg.unclaimed); + if(arg.unclaimed) { + switch(per_skip_bits(pd, arg.unclaimed)) { + case -1: + ASN_DEBUG("Claim of %d failed", arg.unclaimed); + _ASN_DECODE_STARVED; + case 0: + ASN_DEBUG("Got claim of %d", arg.unclaimed); + break; + default: + /* Padding must be blank */ + ASN_DEBUG("Non-blank unconsumed padding"); + _ASN_DECODE_FAILED; + } + arg.unclaimed = 0; + } + + if(arg.repeat) { + ASN_DEBUG("Not consumed the whole thing"); + rv.code = RC_FAIL; + return rv; + } + + return rv; +} + + +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); + +} + +int +uper_open_type_skip(asn_codec_ctx_t *ctx, asn_per_data_t *pd) { + asn_TYPE_descriptor_t s_td; + asn_dec_rval_t rv; + + s_td.name = ""; + s_td.uper_decoder = uper_sot_suck; + + rv = uper_open_type_get(ctx, &s_td, 0, 0, pd); + if(rv.code != RC_OK) + return -1; + else + return 0; +} + +/* + * Internal functions. + */ + +static asn_dec_rval_t +uper_sot_suck(asn_codec_ctx_t *ctx, asn_TYPE_descriptor_t *td, + asn_per_constraints_t *constraints, void **sptr, asn_per_data_t *pd) { + asn_dec_rval_t rv; + + (void)ctx; + (void)td; + (void)constraints; + (void)sptr; + + while(per_get_few_bits(pd, 24) >= 0); + + rv.code = RC_OK; + rv.consumed = pd->moved; + + return rv; +} + +static int +uper_ugot_refill(asn_per_data_t *pd) { + uper_ugot_key *arg = pd->refill_key; + ssize_t next_chunk_bytes, next_chunk_bits; + ssize_t avail; + + asn_per_data_t *oldpd = &arg->oldpd; + + ASN_DEBUG("REFILLING pd->moved=%d, oldpd->moved=%d", + pd->moved, oldpd->moved); + + /* Advance our position to where pd is */ + oldpd->buffer = pd->buffer; + oldpd->nboff = pd->nboff; + oldpd->nbits -= pd->moved - arg->ot_moved; + oldpd->moved += pd->moved - arg->ot_moved; + arg->ot_moved = pd->moved; + + if(arg->unclaimed) { + /* Refill the container */ + if(per_get_few_bits(oldpd, 1)) + return -1; + if(oldpd->nboff == 0) { + assert(0); + return -1; + } + pd->buffer = oldpd->buffer; + pd->nboff = oldpd->nboff - 1; + pd->nbits = oldpd->nbits; + ASN_DEBUG("UNCLAIMED <- return from (pd->moved=%d)", pd->moved); + return 0; + } + + if(!arg->repeat) { + ASN_DEBUG("Want more but refill doesn't have it"); + return -1; + } + + 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); + if(next_chunk_bytes < 0) return -1; + if(next_chunk_bytes == 0) { + pd->refill = 0; /* No more refills, naturally */ + assert(!arg->repeat); /* Implementation guarantee */ + } + next_chunk_bits = next_chunk_bytes << 3; + avail = oldpd->nbits - oldpd->nboff; + 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); + } 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); + } + pd->buffer = oldpd->buffer; + pd->nboff = oldpd->nboff; + ASN_DEBUG("Refilled pd%s old%s", + per_data_string(pd), per_data_string(oldpd)); + return 0; +} + +static int +per_skip_bits(asn_per_data_t *pd, int skip_nbits) { + int hasNonZeroBits = 0; + while(skip_nbits > 0) { + int skip; + if(skip_nbits < skip) + skip = skip_nbits; + else + skip = 24; + skip_nbits -= skip; + + switch(per_get_few_bits(pd, skip)) { + case -1: return -1; /* Starving */ + case 0: continue; /* Skipped empty space */ + default: hasNonZeroBits = 1; continue; + } + } + return hasNonZeroBits; +} diff --git a/src/per_support.c b/src/per_support.c index c834419..e8299c7 100644 --- a/src/per_support.c +++ b/src/per_support.c @@ -1,25 +1,66 @@ /* - * Copyright (c) 2005, 2006 Lev Walkin . All rights reserved. + * Copyright (c) 2005, 2006, 2007 Lev Walkin . + * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include #include +char * +per_data_string(asn_per_data_t *pd) { + static char buf[2][32]; + 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); + return buf[n]; +} + +void +per_get_undo(asn_per_data_t *pd, int nbits) { + if((ssize_t)pd->nboff < nbits) { + assert((ssize_t)pd->nboff < nbits); + } else { + pd->nboff -= nbits; + pd->moved -= nbits; + } +} + /* * Extract a small number of bits (<= 31) from the specified PER data pointer. */ int32_t per_get_few_bits(asn_per_data_t *pd, int nbits) { size_t off; /* Next after last bit offset */ + ssize_t nleft; /* Number of bits left in this stream */ uint32_t accum; const uint8_t *buf; - if(nbits < 0 || pd->nboff + nbits > pd->nbits) + if(nbits < 0) return -1; - ASN_DEBUG("[PER get %d bits from %p+%d bits]", - nbits, pd->buffer, pd->nboff); + nleft = pd->nbits - pd->nboff; + if(nbits > nleft) { + 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); + tailv = per_get_few_bits(pd, nleft); + if(tailv < 0) return -1; + /* Refill (replace pd contents with new data) */ + if(pd->refill(pd)) + return -1; + nbits -= nleft; + vhead = per_get_few_bits(pd, nbits); + /* Combine the rest of previous pd with the head of new one */ + tailv = (tailv << nbits) | vhead; /* Could == -1 */ + return tailv; + } /* * Normalize position indicator. @@ -29,7 +70,9 @@ per_get_few_bits(asn_per_data_t *pd, int nbits) { pd->nbits -= (pd->nboff & ~0x07); pd->nboff &= 0x07; } - off = (pd->nboff += nbits); + pd->moved += nbits; + pd->nboff += nbits; + off = pd->nboff; buf = pd->buffer; /* @@ -47,15 +90,29 @@ per_get_few_bits(asn_per_data_t *pd, int nbits) { else if(nbits <= 31) { asn_per_data_t tpd = *pd; /* Here are we with our 31-bits limit plus 1..7 bits offset. */ - tpd.nboff -= nbits; + per_get_undo(&tpd, nbits); + /* The number of available bits in the stream allow + * for the following operations to take place without + * invoking the ->refill() function */ accum = per_get_few_bits(&tpd, nbits - 24) << 24; accum |= per_get_few_bits(&tpd, 24); } else { - pd->nboff -= nbits; /* Oops, revert back */ + per_get_undo(pd, nbits); return -1; } - return (accum & (((uint32_t)1 << nbits) - 1)); + 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, + pd->buffer[0], + pd->nbits - pd->nboff, + (int)accum); + + return accum; } /* @@ -129,6 +186,30 @@ uper_get_length(asn_per_data_t *pd, int ebits, int *repeat) { return (16384 * value); } +/* + * Get the normally small length "n". + * This procedure used to decode length of extensions bit-maps + * for SET and SEQUENCE types. + */ +ssize_t +uper_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 = uper_get_length(pd, -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 @@ -193,8 +274,8 @@ 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 to %p+%d bits]", - obits, po->buffer, po->nboff); + ASN_DEBUG("[PER put %d bits %x to %p+%d bits]", + obits, (int)bits, po->buffer, po->nboff); /* * Normalize position indicator. @@ -210,7 +291,9 @@ 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); - if(po->outper(po->buffer, complete_bytes, po->op_key) < 0) + ASN_DEBUG("[PER output %d complete + %d]", + complete_bytes, po->flushed_bytes); + if(po->outper(po->tmpspace, complete_bytes, po->op_key) < 0) return -1; if(po->nboff) po->tmpspace[0] = po->buffer[0]; @@ -229,7 +312,8 @@ per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) { /* Clear data of debris before meaningful bits */ bits &= (((uint32_t)1 << obits) - 1); - ASN_DEBUG("[PER out %d %u/%x (t=%d,o=%d) %x&%x=%x]", obits, bits, bits, + 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); if(off <= 8) /* Completely within 1 byte */ @@ -258,7 +342,7 @@ per_put_few_bits(asn_per_outp_t *po, uint32_t bits, int obits) { } ASN_DEBUG("[PER out %u/%x => %02x buf+%d]", - bits, bits, buf[0], po->buffer - po->tmpspace); + (int)bits, (int)bits, buf[0], po->buffer - po->tmpspace); return 0; } @@ -316,3 +400,26 @@ uper_put_length(asn_per_outp_t *po, size_t length) { ? -1 : (ssize_t)(length << 14); } + +/* + * Put the normally small length "n" into the stream. + * This procedure used to encode length of extensions bit-maps + * for SET and SEQUENCE types. + */ +int +uper_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(uper_put_length(po, length) != (ssize_t)length) { + /* This might happen in case of >16K extensions */ + return -1; + } + } + + return 0; +} + -- cgit v1.2.3