aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLev Walkin <vlm@lionet.info>2013-03-16 07:00:58 -0700
committerLev Walkin <vlm@lionet.info>2013-03-16 07:00:58 -0700
commitcad560ae7962310a4073e9e8537dc82c7ad3ed79 (patch)
tree6bd6d438cc3da224ee2a9a5c08b7245895fdd54f
parent86d8d7785e52b8fb2b681fecd4508013bbf26e7f (diff)
make one-pass parsing for object identifier
-rw-r--r--skeletons/INTEGER.c51
-rw-r--r--skeletons/INTEGER.h11
-rw-r--r--skeletons/OBJECT_IDENTIFIER.c45
-rw-r--r--skeletons/tests/check-OIDs.c13
4 files changed, 86 insertions, 34 deletions
diff --git a/skeletons/INTEGER.c b/skeletons/INTEGER.c
index 8203ffd1..56d02b49 100644
--- a/skeletons/INTEGER.c
+++ b/skeletons/INTEGER.c
@@ -499,14 +499,17 @@ INTEGER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void *chun
break;
case ST_DIGITS:
dec_value_end = lstop;
+ /* FALL THROUGH */
case ST_DIGITS_TRAILSPACE:
/* The last symbol encountered was a digit. */
- switch(asn_strtol(dec_value_start, dec_value_end, &dec_value)) {
+ switch(asn_strtol_lim(dec_value_start, &dec_value_end, &dec_value)) {
case ASN_STRTOL_OK:
break;
case ASN_STRTOL_ERROR_RANGE:
return XPBD_DECODER_LIMIT;
case ASN_STRTOL_ERROR_INVAL:
+ case ASN_STRTOL_EXPECT_MORE:
+ case ASN_STRTOL_EXTRA_DATA:
return XPBD_BROKEN_ENCODING;
}
break;
@@ -950,15 +953,44 @@ asn_long2INTEGER(INTEGER_t *st, long value) {
return 0;
}
+/*
+ * This function is going to be DEPRECATED soon.
+ */
enum asn_strtol_result_e
asn_strtol(const char *str, const char *end, long *lp) {
+ const char *endp = end;
+
+ switch(asn_strtol_lim(str, &endp, lp)) {
+ case ASN_STRTOL_ERROR_RANGE:
+ return ASN_STRTOL_ERROR_RANGE;
+ case ASN_STRTOL_ERROR_INVAL:
+ return ASN_STRTOL_ERROR_INVAL;
+ case ASN_STRTOL_EXPECT_MORE:
+ return ASN_STRTOL_ERROR_INVAL; /* Retain old behavior */
+ case ASN_STRTOL_OK:
+ return ASN_STRTOL_OK;
+ case ASN_STRTOL_EXTRA_DATA:
+ return ASN_STRTOL_ERROR_INVAL; /* Retain old behavior */
+ }
+
+ return ASN_STRTOL_ERROR_INVAL; /* Retain old behavior */
+}
+
+/*
+ * Parse the number in the given string until the given *end position,
+ * returning the position after the last parsed character back using the
+ * same (*end) pointer.
+ * WARNING: This behavior is different from the standard strtol(3).
+ */
+enum asn_strtol_result_e
+asn_strtol_lim(const char *str, const char **end, long *lp) {
int sign = 1;
long l;
const long upper_boundary = LONG_MAX / 10;
long last_digit_max = LONG_MAX % 10;
- if(str >= end) return ASN_STRTOL_ERROR_INVAL;
+ if(str >= *end) return ASN_STRTOL_ERROR_INVAL;
switch(*str) {
case '-':
@@ -966,11 +998,13 @@ asn_strtol(const char *str, const char *end, long *lp) {
sign = -1;
case '+':
str++;
+ if(str >= *end) {
+ *end = str;
+ return ASN_STRTOL_EXPECT_MORE;
+ }
}
- if(str >= end) return ASN_STRTOL_ERROR_INVAL;
-
- for(l = 0; str < end; str++) {
+ for(l = 0; str < (*end); str++) {
switch(*str) {
case 0x30: case 0x31: case 0x32: case 0x33: case 0x34:
case 0x35: case 0x36: case 0x37: case 0x38: case 0x39: {
@@ -986,18 +1020,23 @@ asn_strtol(const char *str, const char *end, long *lp) {
l = -l * 10 - d;
}
} else {
+ *end = str;
return ASN_STRTOL_ERROR_RANGE;
}
} else {
+ *end = str;
return ASN_STRTOL_ERROR_RANGE;
}
}
continue;
default:
- return ASN_STRTOL_ERROR_INVAL;
+ *end = str;
+ *lp = sign * l;
+ return ASN_STRTOL_EXTRA_DATA;
}
}
+ *end = str;
*lp = sign * l;
return ASN_STRTOL_OK;
}
diff --git a/skeletons/INTEGER.h b/skeletons/INTEGER.h
index 8164e9e7..fe08b038 100644
--- a/skeletons/INTEGER.h
+++ b/skeletons/INTEGER.h
@@ -59,10 +59,15 @@ int asn_ulong2INTEGER(INTEGER_t *i, unsigned long l);
/* A a reified version of strtol(3) with nicer error reporting. */
enum asn_strtol_result_e {
- ASN_STRTOL_ERROR_INVAL = -1, /* Invalid input */
- ASN_STRTOL_OK = 0, /* Conversion succeded */
- ASN_STRTOL_ERROR_RANGE = 1, /* Input out of range */
+ ASN_STRTOL_ERROR_RANGE = -3, /* Input outside of numeric range for long type */
+ ASN_STRTOL_ERROR_INVAL = -2, /* Invalid data encountered (e.g., "+-") */
+ ASN_STRTOL_EXPECT_MORE = -1, /* More data expected (e.g. "+") */
+ ASN_STRTOL_OK = 0, /* Conversion succeded, number ends at (*end) */
+ ASN_STRTOL_EXTRA_DATA = 1, /* Conversion succeded, but the string has extra stuff */
};
+enum asn_strtol_result_e asn_strtol_lim(const char *str, const char **end, long *l);
+
+/* The asn_strtol is going to be DEPRECATED soon */
enum asn_strtol_result_e asn_strtol(const char *str, const char *end, long *l);
/*
diff --git a/skeletons/OBJECT_IDENTIFIER.c b/skeletons/OBJECT_IDENTIFIER.c
index 2939f25a..066d5625 100644
--- a/skeletons/OBJECT_IDENTIFIER.c
+++ b/skeletons/OBJECT_IDENTIFIER.c
@@ -648,12 +648,11 @@ OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
long *arcs, unsigned int arcs_slots, const char **opt_oid_text_end) {
unsigned int arcs_count = 0;
const char *oid_end;
- const char *value_start;
enum {
ST_LEADSPACE,
ST_TAILSPACE,
+ ST_AFTERVALUE, /* Next character ought to be '.' or a space */
ST_WAITDIGITS, /* Next character is expected to be a digit */
- ST_DIGITS /* INVARIANT: value_start != 0 in this state */
} state = ST_LEADSPACE;
if(!oid_text || oid_txt_length < -1 || (arcs_slots && !arcs)) {
@@ -665,13 +664,16 @@ OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
if(oid_txt_length == -1)
oid_txt_length = strlen(oid_text);
-#define _OID_CAPTURE_ARC(value_start, oid_text) do { \
+#define _OID_CAPTURE_ARC(oid_text, oid_end) do { \
+ const char *endp = oid_end; \
long value; \
- switch(asn_strtol(value_start, oid_text, &value)) { \
+ switch(asn_strtol_lim(oid_text, &endp, &value)) { \
+ case ASN_STRTOL_EXTRA_DATA: \
case ASN_STRTOL_OK: \
if(arcs_count < arcs_slots) \
arcs[arcs_count] = value; \
arcs_count++; \
+ oid_text = endp - 1; \
break; \
case ASN_STRTOL_ERROR_RANGE: \
if(opt_oid_text_end) \
@@ -679,6 +681,7 @@ OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
errno = ERANGE; \
return -1; \
case ASN_STRTOL_ERROR_INVAL: \
+ case ASN_STRTOL_EXPECT_MORE: \
if(opt_oid_text_end) \
*opt_oid_text_end = oid_text; \
errno = EINVAL; \
@@ -693,23 +696,24 @@ OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
case ST_LEADSPACE:
case ST_TAILSPACE:
continue;
- case ST_DIGITS:
- _OID_CAPTURE_ARC(value_start, oid_text);
+ case ST_AFTERVALUE:
state = ST_TAILSPACE;
continue;
case ST_WAITDIGITS:
- break;
+ break; /* Digits expected after ".", got whitespace */
}
+ break;
case 0x2e: /* '.' */
switch(state) {
case ST_LEADSPACE:
- case ST_WAITDIGITS:
- break;
case ST_TAILSPACE:
- state = ST_WAITDIGITS;
+ case ST_WAITDIGITS:
+ if(opt_oid_text_end)
+ *opt_oid_text_end = oid_text;
+ errno = EINVAL; /* Broken OID */
+ return -1;
break;
- case ST_DIGITS:
- _OID_CAPTURE_ARC(value_start, oid_text);
+ case ST_AFTERVALUE:
state = ST_WAITDIGITS;
continue;
}
@@ -718,14 +722,15 @@ OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
case 0x35: case 0x36: case 0x37: case 0x38: case 0x39:
switch(state) {
case ST_TAILSPACE:
- state = ST_WAITDIGITS;
- break;
+ case ST_AFTERVALUE:
+ if(opt_oid_text_end)
+ *opt_oid_text_end = oid_text;
+ errno = EINVAL; /* "1. 1" => broken OID */
+ return -1;
case ST_LEADSPACE:
case ST_WAITDIGITS:
- state = ST_DIGITS;
- value_start = oid_text;
- continue;
- case ST_DIGITS:
+ _OID_CAPTURE_ARC(oid_text, oid_end);
+ state = ST_AFTERVALUE;
continue;
}
break;
@@ -744,12 +749,10 @@ OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
switch(state) {
case ST_LEADSPACE:
return 0; /* No OID found in input data */
- case ST_DIGITS:
- _OID_CAPTURE_ARC(value_start, oid_text);
- return arcs_count;
case ST_WAITDIGITS:
errno = EINVAL; /* Broken OID */
return -1;
+ case ST_AFTERVALUE:
case ST_TAILSPACE:
return arcs_count;
}
diff --git a/skeletons/tests/check-OIDs.c b/skeletons/tests/check-OIDs.c
index ce62bdae..05b49932 100644
--- a/skeletons/tests/check-OIDs.c
+++ b/skeletons/tests/check-OIDs.c
@@ -228,7 +228,8 @@ check_speed() {
static void check_parse(const char *oid_txt, int retval) {
int ret;
long l[2];
- const char *p;
+ const char *p = oid_txt - 13;
+ assert(p < oid_txt);
ret = OBJECT_IDENTIFIER_parse_arcs(oid_txt, -1, l, 2, &p);
printf("[%s] => %d == %d\n", oid_txt, ret, retval);
@@ -266,6 +267,7 @@ static void check_xer(int expect_arcs, char *xer) {
for(i = 0; i < ret; i++) {
if(i) printf(".");
printf("%ld", arcs[i]);
+ if(arcs[i] != i + 1) printf(" != %d\n", i + 1);
assert(arcs[i] == i + 1);
}
printf(": %d == %d\n", ret, expect_arcs);
@@ -383,9 +385,8 @@ main() {
CHECK_REGEN_OID(19);
CHECK_REGEN_OID(20);
- check_parse("", -1);
- check_parse(" ", -1);
- check_parse(" ", -1);
+ check_parse("", 0);
+ check_parse(" ", 0);
check_parse(".", -1);
check_parse(" .", -1);
check_parse(".1", -1);
@@ -404,6 +405,10 @@ main() {
check_parse(" 1.2 ", 2);
check_parse("1. 2", -1);
check_parse("1 .2", -1);
+ check_parse(" 1 .2", -1);
+ check_parse(" 1 .2 ", -1);
+ check_parse("1 .2 ", -1);
+ check_parse("1.+1", -1);
check_parse("10.30.234.234", 4);
check_parse("10.30.234.234 ", 4);
check_parse("10.30.234. 234 ", -1);