unsigned integer of 32-bit widtth support for per
diff --git a/libasn1compiler/asn1c_C.c b/libasn1compiler/asn1c_C.c
index e2b4401..be7f059 100644
--- a/libasn1compiler/asn1c_C.c
+++ b/libasn1compiler/asn1c_C.c
@@ -222,9 +222,28 @@
OUT("0,\t/* Enumeration is not extensible */\n");
}
if(expr->expr_type == ASN_BASIC_ENUMERATED)
- OUT("1\t/* Strict enumeration */\n");
+ OUT("1,\t/* Strict enumeration */\n");
else
- OUT("0\n");
+ OUT("0,\n");
+ OUT("0,\t/* Native long size */\n");
+ OUT("0\n");
+ INDENT(-1);
+ OUT("};\n");
+ }
+
+ if(expr->expr_type == ASN_BASIC_INTEGER
+ && asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN) {
+ REDIR(OT_STAT_DEFS);
+ OUT("static asn_INTEGER_specifics_t asn_SPC_%s_specs_%d = {\n",
+ MKID(expr), expr->_type_unique_index);
+ INDENT(+1);
+ OUT("0,\t");
+ OUT("0,\t");
+ OUT("0,\t");
+ OUT("0,\t");
+ OUT("0,\n");
+ OUT("0,\t/* Native long size */\n");
+ OUT("1\t/* Unsigned representation */\n");
INDENT(-1);
OUT("};\n");
}
@@ -1112,7 +1131,10 @@
if((expr->expr_type == ASN_BASIC_ENUMERATED)
|| (0 /* -- prohibited by X.693:8.3.4 */
&& expr->expr_type == ASN_BASIC_INTEGER
- && expr_elements_count(arg, expr)))
+ && expr_elements_count(arg, expr))
+ || (expr->expr_type == ASN_BASIC_INTEGER
+ && asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN)
+ )
etd_spec = ETD_HAS_SPECIFICS;
else
etd_spec = ETD_NO_SPECIFICS;
@@ -2289,7 +2311,9 @@
|| expr->expr_type == ASN_BASIC_ENUMERATED
|| (0 /* -- prohibited by X.693:8.3.4 */
&& expr->expr_type == ASN_BASIC_INTEGER
- && expr_elements_count(arg, expr));
+ && expr_elements_count(arg, expr))
+ || (expr->expr_type == ASN_BASIC_INTEGER
+ && asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN);
if(C99_MODE) OUT(".type = ");
OUT("&asn_DEF_");
if(complex_contents) {
diff --git a/libasn1compiler/asn1c_constraint.c b/libasn1compiler/asn1c_constraint.c
index ea9df80..2b1420e 100644
--- a/libasn1compiler/asn1c_constraint.c
+++ b/libasn1compiler/asn1c_constraint.c
@@ -12,6 +12,7 @@
static int emit_size_determination_code(arg_t *arg, asn1p_expr_type_e etype);
static asn1p_expr_type_e _find_terminal_type(arg_t *arg);
static int emit_range_comparison_code(arg_t *arg, asn1cnst_range_t *range, const char *varname, asn1c_integer_t natural_start, asn1c_integer_t natural_stop);
+static int native_long_sign(asn1cnst_range_t *r); /* -1, 0, 1 */
int
asn1c_emit_constraint_checking_code(arg_t *arg) {
@@ -91,7 +92,11 @@
switch(etype) {
case ASN_BASIC_INTEGER:
case ASN_BASIC_ENUMERATED:
- OUT("long value;\n");
+ if(native_long_sign(r_value) >= 0) {
+ OUT("unsigned long value;\n");
+ } else {
+ OUT("long value;\n");
+ }
break;
case ASN_BASIC_REAL:
OUT("double value;\n");
@@ -133,6 +138,19 @@
INDENT(+1);
/*
+ * Optimization for unsigned longs.
+ */
+ if(!r_size && r_value
+ && (etype == ASN_BASIC_INTEGER
+ || etype == ASN_BASIC_ENUMERATED)
+ && native_long_sign(r_value) == 0) {
+ OUT("\n");
+ OUT("/* Constraint check succeeded */\n");
+ OUT("return 0;\n");
+ return 0;
+ }
+
+ /*
* Here is an if() {} else {} consrtaint checking code.
*/
OUT("\n");
@@ -578,9 +596,15 @@
switch(etype) {
case ASN_BASIC_INTEGER:
case ASN_BASIC_ENUMERATED:
- if(asn1c_type_fits_long(arg, arg->expr) != FL_NOTFIT) {
+ if(asn1c_type_fits_long(arg, arg->expr) == FL_FITS_UNSIGN) {
+ OUT("value = *(const unsigned long *)sptr;\n");
+ } else if(asn1c_type_fits_long(arg, arg->expr) != FL_NOTFIT) {
OUT("value = *(const long *)sptr;\n");
} else {
+ /*
+ * In some cases we can explore our knowledge of
+ * underlying INTEGER_t->buf format.
+ */
if(r_value->el_count == 0
&& (
/* Speed-up common case: (0..MAX) */
@@ -598,14 +622,26 @@
break;
}
- OUT("if(asn_INTEGER2long(st, &value)) {\n");
+ if(native_long_sign(r_value) >= 0) {
+ /* Special case for treating unsigned longs */
+ OUT("if(asn_INTEGER2ulong(st, &value)) {\n");
INDENT(+1);
OUT("_ASN_CTFAIL(app_key, td, sptr,\n");
OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
OUT("\ttd->name, __FILE__, __LINE__);\n");
OUT("return -1;\n");
INDENT(-1);
- OUT("}\n");
+ OUT("}\n");
+ } else {
+ OUT("if(asn_INTEGER2long(st, &value)) {\n");
+ INDENT(+1);
+ OUT("_ASN_CTFAIL(app_key, td, sptr,\n");
+ OUT("\t\"%%s: value too large (%%s:%%d)\",\n");
+ OUT("\ttd->name, __FILE__, __LINE__);\n");
+ OUT("return -1;\n");
+ INDENT(-1);
+ OUT("}\n");
+ }
}
break;
case ASN_BASIC_REAL:
@@ -652,3 +688,20 @@
return A1TC_INVALID;
}
+static int
+native_long_sign(asn1cnst_range_t *r) {
+ if(r->left.type == ARE_VALUE
+ && r->left.value >= 0
+ && r->right.type == ARE_VALUE
+ && r->right.value > 2147483647UL
+ && r->right.value <= 4294967295UL) {
+ if(r->el_count == 0
+ && r->left.value == 0
+ && r->right.value == 4294967295UL)
+ return 0;
+ else
+ return 1;
+ } else {
+ return -1;
+ }
+}
diff --git a/libasn1compiler/asn1c_misc.c b/libasn1compiler/asn1c_misc.c
index 543a165..f48ab08 100644
--- a/libasn1compiler/asn1c_misc.c
+++ b/libasn1compiler/asn1c_misc.c
@@ -215,6 +215,8 @@
case TNF_RSAFE:
if(expr->expr_type == ASN_BASIC_REAL)
return "double";
+ else if(asn1c_type_fits_long(arg, expr) == FL_FITS_UNSIGN)
+ return "unsigned long";
else
return "long";
default:
@@ -278,7 +280,7 @@
/*
* Check whether the specified INTEGER or ENUMERATED type can be represented
- * using the generic 'long' type.
+ * using the generic 'long' or 'unsigned long' type.
*/
enum asn1c_fitslong_e
asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr) {
@@ -339,7 +341,7 @@
right = range->right;
/* Use 4 instead of sizeof(long) is justified! */
if(right.type == ARE_VALUE && right.value <= 4)
- return FL_FITSOK;
+ return FL_FITS_SIGNED;
}
asn1constraint_range_free(range);
}
@@ -364,6 +366,15 @@
right = range->right;
asn1constraint_range_free(range);
+ /* Special case for unsigned */
+ if(left.type == ARE_VALUE
+ && left.value >= 0
+ && right.type == ARE_VALUE
+ && right.value > 2147483647
+ && right.value <= 4294967295UL)
+ return FL_FITS_UNSIGN;
+
+
/* If some fixed value is outside of target range, not fit */
if(left.type == ARE_VALUE
&& (left.value < LEFTMIN || left.value > RIGHTMAX))
@@ -378,6 +389,6 @@
? FL_FORCED : FL_NOTFIT;
}
- return FL_FITSOK;
+ return FL_FITS_SIGNED;
}
diff --git a/libasn1compiler/asn1c_misc.h b/libasn1compiler/asn1c_misc.h
index b14a155..6e2acb5 100644
--- a/libasn1compiler/asn1c_misc.h
+++ b/libasn1compiler/asn1c_misc.h
@@ -30,12 +30,14 @@
* 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_FITS_SIGNED: It can be represented using signed long.
+ * FL_FITS_UNSIGN: It can be represented using unsigned long.
* FL_FORCED: Probably can't, but -fnative-types is in force.
*/
enum asn1c_fitslong_e {
FL_NOTFIT,
- FL_FITSOK,
+ FL_FITS_SIGNED,
+ FL_FITS_UNSIGN,
FL_FORCED,
};
enum asn1c_fitslong_e asn1c_type_fits_long(arg_t *arg, asn1p_expr_t *expr);