make one-pass parsing for object identifier

aper
Lev Walkin 2013-03-16 07:00:58 -07:00
parent 86d8d7785e
commit cad560ae79
4 changed files with 86 additions and 34 deletions

View File

@ -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;
}

View File

@ -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);
/*

View File

@ -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;
}

View File

@ -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);