diff options
Diffstat (limited to 'libasn1compiler')
-rw-r--r-- | libasn1compiler/asn1c_C.c | 23 | ||||
-rw-r--r-- | libasn1compiler/asn1c_constraint.c | 5 | ||||
-rw-r--r-- | libasn1compiler/asn1c_misc.c | 88 | ||||
-rw-r--r-- | libasn1compiler/asn1c_misc.h | 15 |
4 files changed, 115 insertions, 16 deletions
diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c index f91da76f..d39018ee 100644 --- a/libasn1compiler/asn1c_C.c +++ b/libasn1compiler/asn1c_C.c @@ -218,29 +218,26 @@ asn1c_lang_C_type_BIT_STRING(arg_t *arg) { asn1p_expr_t *expr = arg->expr; asn1p_expr_t *v; int el_count = expr_elements_count(arg, expr); - int eidx = 0; if(el_count) { + int eidx = 0; REDIR(OT_DEPS); OUT("typedef enum "); out_name_chain(arg, 1); OUT(" {\n"); TQ_FOR(v, &(expr->members), next) { - switch(v->expr_type) { - case A1TC_UNIVERVAL: - OUT("\t"); - out_name_chain(arg, 0); - OUT("_%s", MKID(v->Identifier)); - OUT("\t= %" PRIdASN "%s\n", - v->value->value.v_integer, - (eidx+1 < el_count) ? "," : ""); - eidx++; - break; - default: + eidx++; + if(v->expr_type != A1TC_UNIVERVAL) { OUT("/* Unexpected BIT STRING element: %s */\n", v->Identifier); - break; + continue; } + OUT("\t"); + out_name_chain(arg, 0); + OUT("_%s", MKID(v->Identifier)); + OUT("\t= %" PRIdASN "%s\n", + v->value->value.v_integer, + (eidx < el_count) ? "," : ""); } OUT("} "); out_name_chain(arg, 0); diff --git a/libasn1compiler/asn1c_constraint.c b/libasn1compiler/asn1c_constraint.c index d75313d2..372730fc 100644 --- a/libasn1compiler/asn1c_constraint.c +++ b/libasn1compiler/asn1c_constraint.c @@ -62,6 +62,9 @@ asn1c_emit_constraint_checking_code(arg_t *arg) { switch(etype) { case ASN_BASIC_INTEGER: case ASN_BASIC_ENUMERATED: + if(asn1c_type_fits_long(arg, arg->expr) == FL_NOTFIT) + produce_st = 1; + break; case ASN_BASIC_REAL: if(!(arg->flags & A1C_USE_NATIVE_TYPES)) produce_st = 1; @@ -556,7 +559,7 @@ emit_value_determination_code(arg_t *arg, asn1p_expr_type_e etype, asn1cnst_rang switch(etype) { case ASN_BASIC_INTEGER: case ASN_BASIC_ENUMERATED: - if(arg->flags & A1C_USE_NATIVE_TYPES) { + if(asn1c_type_fits_long(arg, arg->expr) != FL_NOTFIT) { OUT("value = *(const long *)sptr;\n"); } else { if(r_value->el_count == 0 diff --git a/libasn1compiler/asn1c_misc.c b/libasn1compiler/asn1c_misc.c index 8c5bb628..bcf062f3 100644 --- a/libasn1compiler/asn1c_misc.c +++ b/libasn1compiler/asn1c_misc.c @@ -1,7 +1,8 @@ #include "asn1c_internal.h" #include "asn1c_misc.h" -#include <asn1fix_export.h> +#include <asn1fix_crange.h> /* constraint groker from libasn1fix */ +#include <asn1fix_export.h> /* other exportable stuff from libasn1fix */ /* * Checks that the given string is not a reserved C/C++ keyword. @@ -189,7 +190,9 @@ asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) { case ASN_BASIC_INTEGER: case ASN_BASIC_ENUMERATED: case ASN_BASIC_REAL: - if((arg->flags & A1C_USE_NATIVE_TYPES)) { + if((expr->expr_type == ASN_BASIC_REAL + && (arg->flags & A1C_USE_NATIVE_TYPES)) + || asn1c_type_fits_long(arg, expr)) { switch(_format) { case TNF_CTYPE: case TNF_RSAFE: @@ -239,3 +242,84 @@ asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format) { return typename; } +/* + * Check whether the specified INTEGER or ENUMERATED type can be represented + * using the generic 'long' type. + */ +enum asn1c_fitslong_e +asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) { + asn1cnst_range_t *range = 0; + asn1cnst_edge_t left; + asn1cnst_edge_t right; + asn1p_expr_t *v; + +/* + * Since we don't know the sizeof(long) on the possible target platform + * which will be compiling the code generated by asn1c, let's play it + * simple: long's range is equal to or greater than int32_t. + */ +#define LEFTMIN INT32_MIN +#define RIGHTMAX INT32_MAX + + /* Descend to the terminal type */ + expr = asn1f_find_terminal_type_ex(arg->asn, expr); + if(expr == 0) return FL_NOTFIT; + + /* The "fits into long" operation is relevant only for integer types */ + switch(expr->expr_type) { + case ASN_BASIC_INTEGER: + case ASN_BASIC_ENUMERATED: + break; + default: + return FL_NOTFIT; + } + + /* + * First, evaluate the range of explicitly given identifiers. + */ + TQ_FOR(v, &(expr->members), next) { + if(v->expr_type != A1TC_UNIVERVAL) + continue; + if(v->value->value.v_integer < LEFTMIN + || v->value->value.v_integer > RIGHTMAX) + return FL_NOTFIT; + } + + /* + * Second, pull up the PER visible range of the INTEGER. + */ + if(expr->combined_constraints) + range = asn1constraint_compute_PER_range(expr->expr_type, + expr->combined_constraints, ACT_EL_RANGE, 0, 0, 0); + if(!range + || range->empty_constraint + || range->extensible + || range->incompatible + || range->not_PER_visible + ) { + asn1constraint_range_free(range); + return (arg->flags & A1C_USE_NATIVE_TYPES) + ? FL_FORCED : FL_NOTFIT; + } + + left = range->left; + right = range->right; + asn1constraint_range_free(range); + + /* If some fixed value is outside of target range, not fit */ + if(left.type == ARE_VALUE + && (left.value < LEFTMIN || left.value > RIGHTMAX)) + return FL_NOTFIT; + if(right.type == ARE_VALUE + && (right.value > RIGHTMAX || right.value < LEFTMIN)) + return FL_NOTFIT; + + /* If the range is open, fits only if -fnative-types is given */ + if(left.type != ARE_VALUE || right.type != ARE_VALUE) { + return (arg->flags & A1C_USE_NATIVE_TYPES) + ? FL_FORCED : FL_NOTFIT; + } + + return FL_FITSOK; +} + diff --git a/libasn1compiler/asn1c_misc.h b/libasn1compiler/asn1c_misc.h index eab75674..8da261df 100644 --- a/libasn1compiler/asn1c_misc.h +++ b/libasn1compiler/asn1c_misc.h @@ -24,4 +24,19 @@ enum tnfmt { }; char *asn1c_type_name(arg_t *arg, asn1p_expr_t *expr, enum tnfmt _format); +/* + * Check whether the specified INTEGER or ENUMERATED type can be represented + * using the generic 'long' type. + * Return values: + * FL_NOTFIT: No, it cannot be represented using long. + * FL_FITSOK: It can be represented using long. + * FL_FORCED: Probably can't, but -fnative-types is in force. + */ +enum asn1c_fitslong_e { + FL_NOTFIT, + FL_FITSOK, + FL_FORCED, +}; +enum asn1c_fitslong_e asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr); + #endif /* _ASN1_COMPILER_MISC_H_ */ |