mirror of https://gerrit.osmocom.org/asn1c
make one-pass parsing for object identifier
parent
86d8d7785e
commit
cad560ae79
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
/*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue