Commit 588bf0f7 authored by Lev Walkin's avatar Lev Walkin

OBJECT IDENTIFIER and RELATIVE-OID API simplified

parent 290e2c7f
......@@ -9,6 +9,7 @@
NOTABLE:
* converter-sample.c renamed into converter-example.c.
* OBJECT IDENTIFIER and RELATIVE-OID API simplified.
* Added random value generation (-R option to converter-example).
* Added LibFuzzer-based randomized tests for supported transfer syntaxes
(DER, OER, UPER, XER) into tests/tests-randomized. See the following
......
......@@ -434,7 +434,7 @@ print_TL(int fin, size_t offset, int level, int constr, ssize_t tlen,
static int
print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag,
ber_tlv_len_t tlv_len) {
asn1c_integer_t *arcs = 0; /* Object identifier arcs */
asn_oid_arc_t *arcs = 0; /* Object identifier arcs */
unsigned char *vbuf = 0;
asn1p_expr_type_e etype = 0;
asn1c_integer_t collector = 0;
......@@ -577,20 +577,19 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag,
break;
case ASN_BASIC_OBJECT_IDENTIFIER:
if(vbuf) {
OBJECT_IDENTIFIER_t oid;
int arcno;
OBJECT_IDENTIFIER_t oid = {0, 0};
ssize_t arcno;
oid.buf = vbuf;
oid.size = tlv_len;
arcno = OBJECT_IDENTIFIER_get_arcs(&oid, arcs, sizeof(*arcs),
tlv_len + 1);
arcno = OBJECT_IDENTIFIER_get_arcs(&oid, arcs, tlv_len + 1);
if(arcno >= 0) {
assert(arcno <= (tlv_len + 1));
printf(" F>");
for(i = 0; i < arcno; i++) {
if(i) printf(".");
printf("%s", asn1p_itoa(arcs[i]));
printf("%" PRIu32, arcs[i]);
}
FREEMEM(vbuf);
vbuf = 0;
......@@ -605,13 +604,13 @@ print_V(const char *fname, FILE *fp, ber_tlv_tag_t tlv_tag,
oid.buf = vbuf;
oid.size = tlv_len;
arcno = RELATIVE_OID_get_arcs(&oid, arcs, sizeof(*arcs), tlv_len);
arcno = RELATIVE_OID_get_arcs(&oid, arcs, tlv_len);
if(arcno >= 0) {
assert(arcno <= (tlv_len + 1));
assert(arcno <= tlv_len);
printf(" F>");
for(i = 0; i < arcno; i++) {
if(i) printf(".");
printf("%s", asn1p_itoa(arcs[i]));
printf("%" PRIu32, arcs[i]);
}
FREEMEM(vbuf);
vbuf = 0;
......
......@@ -1028,9 +1028,9 @@ asn_strtoimax_lim(const char *str, const char **end, intmax_t *intp) {
intmax_t value;
#define ASN1_INTMAX_MAX ((~(uintmax_t)0) >> 1)
const intmax_t upper_boundary = ASN1_INTMAX_MAX / 10;
intmax_t last_digit_max = ASN1_INTMAX_MAX % 10;
#undef ASN1_INTMAX_MAX
if(str >= *end) return ASN_STRTOX_ERROR_INVAL;
......@@ -1084,6 +1084,66 @@ asn_strtoimax_lim(const char *str, const char **end, intmax_t *intp) {
return ASN_STRTOX_OK;
}
/*
* 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 strtoul/strtoumax(3).
*/
enum asn_strtox_result_e
asn_strtoumax_lim(const char *str, const char **end, uintmax_t *uintp) {
uintmax_t value;
#define ASN1_UINTMAX_MAX ((~(uintmax_t)0))
const uintmax_t upper_boundary = ASN1_UINTMAX_MAX / 10;
uintmax_t last_digit_max = ASN1_UINTMAX_MAX % 10;
#undef ASN1_UINTMAX_MAX
if(str >= *end) return ASN_STRTOX_ERROR_INVAL;
switch(*str) {
case '-':
return ASN_STRTOX_ERROR_INVAL;
case '+':
str++;
if(str >= *end) {
*end = str;
return ASN_STRTOX_EXPECT_MORE;
}
}
for(value = 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: {
unsigned int d = *str - '0';
if(value < upper_boundary) {
value = value * 10 + d;
} else if(value == upper_boundary) {
if(d <= last_digit_max) {
value = value * 10 + d;
} else {
*end = str;
return ASN_STRTOX_ERROR_RANGE;
}
} else {
*end = str;
return ASN_STRTOX_ERROR_RANGE;
}
}
continue;
default:
*end = str;
*uintp = value;
return ASN_STRTOX_EXTRA_DATA;
}
}
*end = str;
*uintp = value;
return ASN_STRTOX_OK;
}
enum asn_strtox_result_e
asn_strtol_lim(const char *str, const char **end, long *lp) {
intmax_t value;
......@@ -1114,6 +1174,36 @@ asn_strtol_lim(const char *str, const char **end, long *lp) {
return ASN_STRTOX_ERROR_INVAL;
}
enum asn_strtox_result_e
asn_strtoul_lim(const char *str, const char **end, unsigned long *ulp) {
uintmax_t value;
switch(asn_strtoumax_lim(str, end, &value)) {
case ASN_STRTOX_ERROR_RANGE:
return ASN_STRTOX_ERROR_RANGE;
case ASN_STRTOX_ERROR_INVAL:
return ASN_STRTOX_ERROR_INVAL;
case ASN_STRTOX_EXPECT_MORE:
return ASN_STRTOX_EXPECT_MORE;
case ASN_STRTOX_OK:
if(value <= ULONG_MAX) {
*ulp = value;
return ASN_STRTOX_OK;
} else {
return ASN_STRTOX_ERROR_RANGE;
}
case ASN_STRTOX_EXTRA_DATA:
if(value <= ULONG_MAX) {
*ulp = value;
return ASN_STRTOX_EXTRA_DATA;
} else {
return ASN_STRTOX_ERROR_RANGE;
}
}
assert(!"Unreachable");
return ASN_STRTOX_ERROR_INVAL;
}
int
INTEGER_compare(const asn_TYPE_descriptor_t *td, const void *aptr,
const void *bptr) {
......
......@@ -83,8 +83,14 @@ enum asn_strtox_result_e {
ASN_STRTOX_OK = 0, /* Conversion succeded, number ends at (*end) */
ASN_STRTOX_EXTRA_DATA = 1 /* Conversion succeded, but the string has extra stuff */
};
enum asn_strtox_result_e asn_strtol_lim(const char *str, const char **end, long *l);
enum asn_strtox_result_e asn_strtoimax_lim(const char *str, const char **end, intmax_t *l);
enum asn_strtox_result_e asn_strtol_lim(const char *str, const char **end,
long *l);
enum asn_strtox_result_e asn_strtoul_lim(const char *str, const char **end,
unsigned long *l);
enum asn_strtox_result_e asn_strtoimax_lim(const char *str, const char **end,
intmax_t *l);
enum asn_strtox_result_e asn_strtoumax_lim(const char *str, const char **end,
uintmax_t *l);
/*
* Convert the integer value into the corresponding enumeration map entry.
......
......@@ -55,16 +55,6 @@ asn_TYPE_descriptor_t asn_DEF_OBJECT_IDENTIFIER = {
0 /* No specifics */
};
/*
* Endianness check. Will be optimized out by the compiler.
*/
static int
little_endian() {
int le_check = 1;
return *(char *)&le_check;
}
int
OBJECT_IDENTIFIER_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
asn_app_constraint_failed_f *ctfailcb, void *app_key) {
......@@ -88,209 +78,107 @@ OBJECT_IDENTIFIER_constraint(asn_TYPE_descriptor_t *td, const void *sptr,
return 0;
}
int
OBJECT_IDENTIFIER_get_single_arc(const uint8_t *arcbuf, unsigned int arclen, signed int add, void *rvbufp, unsigned int rvsize) {
const uint8_t *arcend = arcbuf + arclen; /* End of arc */
unsigned int cache = 0; /* No more than 14 significant bits */
unsigned char *rvbuf = (unsigned char *)rvbufp;
unsigned char *rvstart = rvbuf; /* Original start of the value buffer */
int inc; /* Return value growth direction */
static ssize_t
OBJECT_IDENTIFIER_get_first_arcs(const uint8_t *arcbuf, size_t arcbuf_len,
asn_oid_arc_t *arc0, asn_oid_arc_t *arc1) {
asn_oid_arc_t value;
ssize_t rd = OBJECT_IDENTIFIER_get_single_arc(arcbuf, arcbuf_len, &value);
if(rd <= 0) return rd;
if(value >= 80) {
*arc0 = 2;
*arc1 = value - 80;
} else if(value >= 40) {
*arc0 = 1;
*arc1 = value - 40;
} else {
*arc0 = 0;
*arc1 = value;
}
rvsize *= CHAR_BIT; /* bytes to bits */
arclen *= 7; /* bytes to bits */
return rd;
}
assert(add <= 0);
ssize_t
OBJECT_IDENTIFIER_get_single_arc(const uint8_t *arcbuf, size_t arcbuf_len,
asn_oid_arc_t *ret_value) {
const uint8_t *b = arcbuf;
const uint8_t *arcend = arcbuf + arcbuf_len; /* End of arc */
/*
* The arc has the number of bits
* cannot be represented using supplied return value type.
*/
if(arclen > rvsize) {
if(arclen > (rvsize + CHAR_BIT)) {
errno = ERANGE; /* Overflow */
return -1;
if(arcbuf == arcend) {
return 0;
} else {
/*
* Even if the number of bits in the arc representation
* is higher than the width of supplied * return value
* type, there is still possible to fit it when there
* are few unused high bits in the arc value
* representaion.
*
* Moreover, there is a possibility that the
* number could actually fit the arc space, given
* that add is negative, but we don't handle
* such "temporary lack of precision" situation here.
* May be considered as a bug.
*/
uint8_t mask = (0xff << (7-(arclen - rvsize))) & 0x7f;
if((*arcbuf & mask)) {
errno = ERANGE; /* Overflow */
return -1;
}
/* Fool the routine computing unused bits */
arclen -= 7;
cache = *arcbuf & 0x7f;
arcbuf++;
}
}
/* Faster path for common size */
if(rvsize == (CHAR_BIT * sizeof(unsigned long))
&& (arcend-arcbuf) <= (ssize_t)sizeof(unsigned long)) {
unsigned long accum;
asn_oid_arc_t accum;
/* Gather all bits into the accumulator */
for(accum = cache; arcbuf < arcend; arcbuf++)
accum = (accum << 7) | (*arcbuf & ~0x80);
if(accum < (unsigned)-add
|| accum > ULONG_MAX-(unsigned long)(-add)) {
for(accum = 0; b < arcend; b++) {
accum = (accum << 7) | (*b & ~0x80);
if((*b & 0x80) == 0) {
if(accum <= ASN_OID_ARC_MAX) {
*ret_value = accum;
return 1 + (b - arcbuf);
} else {
errno = ERANGE; /* Overflow */
return -1;
}
*(unsigned long *)(void *)rvbuf =
accum - (unsigned long)(-add); /* alignment OK! */
return 0;
}
if(little_endian()) { /* Little endian (x86) */
/* "Convert" to big endian */
rvbuf += rvsize / CHAR_BIT - 1;
rvstart--;
inc = -1; /* Descending */
} else {
inc = +1; /* Big endian */
}
{
int bits; /* typically no more than 3-4 bits */
/* Clear the high unused bits */
for(bits = rvsize - arclen;
bits > CHAR_BIT;
rvbuf += inc, bits -= CHAR_BIT)
*rvbuf = 0;
/* Fill the body of a value */
for(; arcbuf < arcend; arcbuf++) {
cache = (cache << 7) | (*arcbuf & 0x7f);
bits += 7;
if(bits >= CHAR_BIT) {
bits -= CHAR_BIT;
*rvbuf = (cache >> bits);
rvbuf += inc;
}
}
if(bits) {
*rvbuf = cache;
rvbuf += inc;
}
}
if(add) {
for(rvbuf -= inc; rvbuf != rvstart; rvbuf -= inc) {
int v = add + *rvbuf;
if(v & ((unsigned)~0 << CHAR_BIT)) {
*rvbuf = (unsigned char)(v + (1 << CHAR_BIT));
add = -1;
} else {
*rvbuf = v;
break;
}
}
if(rvbuf == rvstart) {
/* No space to carry over */
errno = ERANGE; /* Overflow */
errno = EINVAL;
return -1;
}
}
return 0;
}
ssize_t
OBJECT_IDENTIFIER__dump_arc(const uint8_t *arcbuf, int arclen, int add,
static ssize_t
OBJECT_IDENTIFIER__dump_body(const OBJECT_IDENTIFIER_t *st,
asn_app_consume_bytes_f *cb, void *app_key) {
char scratch[64]; /* Conservative estimate */
unsigned long accum; /* Bits accumulator */
char *p; /* Position in the scratch buffer */
char scratch[32];
asn_oid_arc_t arc0, arc1;
size_t produced = 0;
size_t off = 0;
ssize_t rd;
int ret;
if(OBJECT_IDENTIFIER_get_single_arc(arcbuf, arclen, add,
&accum, sizeof(accum)))
rd = OBJECT_IDENTIFIER_get_first_arcs(st->buf, st->size, &arc0, &arc1);
if(rd <= 0) {
return -1;
}
if(accum) {
ssize_t len;
/* Fill the scratch buffer in reverse. */
p = scratch + sizeof(scratch);
for(; accum; accum /= 10)
*(--p) = (char)(accum % 10) + 0x30; /* Put a digit */
len = sizeof(scratch) - (p - scratch);
if(cb(p, len, app_key) < 0)
ret = snprintf(scratch, sizeof(scratch), "%"PRIu32".%"PRIu32, arc0, arc1);
if(ret >= (ssize_t)sizeof(scratch)) {
return -1;
return len;
} else {
*scratch = 0x30;
if(cb(scratch, 1, app_key) < 0)
return -1;
return 1;
}
}
int
OBJECT_IDENTIFIER_print_arc(const uint8_t *arcbuf, int arclen, int add,
asn_app_consume_bytes_f *cb, void *app_key) {
if(OBJECT_IDENTIFIER__dump_arc(arcbuf, arclen, add, cb, app_key) < 0)
produced += ret;
if(cb(scratch, ret, app_key) < 0)
return -1;
return 0;
}
static ssize_t
OBJECT_IDENTIFIER__dump_body(const OBJECT_IDENTIFIER_t *st, asn_app_consume_bytes_f *cb, void *app_key) {
ssize_t wrote_len = 0;
size_t startn;
int add = 0;
size_t i;
for(i = 0, startn = 0; i < st->size; i++) {
uint8_t b = st->buf[i];
if((b & 0x80)) /* Continuation expected */
continue;
if(startn == 0) {
/*
* First two arcs are encoded through the backdoor.
*/
if(i) {
add = -80;
if(cb("2", 1, app_key) < 0) return -1;
} else if(b <= 39) {
add = 0;
if(cb("0", 1, app_key) < 0) return -1;
} else if(b < 79) {
add = -40;
if(cb("1", 1, app_key) < 0) return -1;
for(off = rd; ; ) {
asn_oid_arc_t arc;
rd = OBJECT_IDENTIFIER_get_single_arc(st->buf + off, st->size - off,
&arc);
if(rd < 0) {
return -1;
} else if(rd == 0) {
/* No more arcs. */
break;
} else {
add = -80;
if(cb("2", 1, app_key) < 0) return -1;
off += rd;
assert(off <= st->size);
ret = snprintf(scratch, sizeof(scratch), ".%" PRIu32, arc);
if(ret >= (ssize_t)sizeof(scratch)) {
return -1;
}
produced += ret;
if(cb(scratch, ret, app_key) < 0) return -1;
}
wrote_len += 1;
}
if(cb(".", 1, app_key) < 0) /* Separate arcs */
if(off != st->size) {
ASN_DEBUG("Could not scan to the end of Object Identifier");
return -1;
add = OBJECT_IDENTIFIER__dump_arc(&st->buf[startn],
i - startn + 1, add, cb, app_key);
if(add < 0) return -1;
wrote_len += 1 + add;
startn = i + 1;
add = 0;
}
return wrote_len;
return produced;
}
static enum xer_pbd_rval
......@@ -298,38 +186,37 @@ OBJECT_IDENTIFIER__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const
OBJECT_IDENTIFIER_t *st = (OBJECT_IDENTIFIER_t *)sptr;
const char *chunk_end = (const char *)chunk_buf + chunk_size;
const char *endptr;
long s_arcs[10];
long *arcs = s_arcs;
int arcs_count;
int ret;
asn_oid_arc_t s_arcs[10];
asn_oid_arc_t *arcs = s_arcs;
ssize_t num_arcs;
ssize_t ret;
(void)td;
arcs_count = OBJECT_IDENTIFIER_parse_arcs(
num_arcs = OBJECT_IDENTIFIER_parse_arcs(
(const char *)chunk_buf, chunk_size, arcs,
sizeof(s_arcs)/sizeof(s_arcs[0]), &endptr);
if(arcs_count < 0) {
sizeof(s_arcs) / sizeof(s_arcs[0]), &endptr);
if(num_arcs < 0) {
/* Expecting more than zero arcs */
return XPBD_BROKEN_ENCODING;
} else if(arcs_count == 0) {
} else if(num_arcs == 0) {
return XPBD_NOT_BODY_IGNORE;
}
assert(endptr == chunk_end);
if((size_t)arcs_count > sizeof(s_arcs)/sizeof(s_arcs[0])) {
arcs = (long *)MALLOC(arcs_count * sizeof(long));
if((size_t)num_arcs > sizeof(s_arcs)/sizeof(s_arcs[0])) {
arcs = (asn_oid_arc_t *)MALLOC(num_arcs * sizeof(asn_oid_arc_t));
if(!arcs) return XPBD_SYSTEM_FAILURE;
ret = OBJECT_IDENTIFIER_parse_arcs(
(const char *)chunk_buf, chunk_size,
arcs, arcs_count, &endptr);
if(ret != arcs_count)
ret = OBJECT_IDENTIFIER_parse_arcs((const char *)chunk_buf, chunk_size,
arcs, num_arcs, &endptr);
if(ret != num_arcs)
return XPBD_SYSTEM_FAILURE; /* assert?.. */
}
/*
* Convert arcs into BER representation.
*/
ret = OBJECT_IDENTIFIER_set_arcs(st, arcs, sizeof(*arcs), arcs_count);
ret = OBJECT_IDENTIFIER_set_arcs(st, arcs, num_arcs);
if(arcs != s_arcs) FREEMEM(arcs);
return ret ? XPBD_SYSTEM_FAILURE : XPBD_BODY_CONSUMED;
......@@ -355,8 +242,9 @@ OBJECT_IDENTIFIER_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
(void)ilevel;
(void)flags;
if(!st || !st->buf)
if(!st || !st->buf) {
ASN__ENCODE_FAILED;
}
er.encoded = OBJECT_IDENTIFIER__dump_body(st, cb, app_key);
if(er.encoded < 0) ASN__ENCODE_FAILED;
......@@ -379,65 +267,64 @@ OBJECT_IDENTIFIER_print(asn_TYPE_descriptor_t *td, const void *sptr,
if(cb("{ ", 2, app_key) < 0)
return -1;
if(OBJECT_IDENTIFIER__dump_body(st, cb, app_key) < 0)
if(OBJECT_IDENTIFIER__dump_body(st, cb, app_key) < 0) {
return -1;
}
return (cb(" }", 2, app_key) < 0) ? -1 : 0;
}
int
OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *oid, void *arcs,
unsigned int arc_type_size, unsigned int arc_slots) {
void *arcs_end = (char *)arcs + (arc_type_size * arc_slots);
int num_arcs = 0;
int startn = 0;
int add = 0;
size_t i;
if(!oid || !oid->buf || (arc_slots && arc_type_size <= 1)) {
ssize_t
OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *st, asn_oid_arc_t *arcs,
size_t arc_slots) {
asn_oid_arc_t arc0, arc1;
size_t num_arcs = 0;
size_t off;
ssize_t rd;
if(!st || !st->buf) {
errno = EINVAL;
return -1;
}
for(i = 0; i < oid->size; i++) {
uint8_t b = oid->buf[i];
if((b & 0x80)) /* Continuation expected */
continue;
if(num_arcs == 0) {
/*
* First two arcs are encoded through the backdoor.
*/
int first_arc;
num_arcs++;
if(!arc_slots) { num_arcs++; continue; }
if(i) first_arc = 2;
else if(b <= 39) first_arc = 0;
else if(b < 79) first_arc = 1;
else first_arc = 2;
add = -40 * first_arc;
memset(arcs, 0, arc_type_size);
*(unsigned char *)((char *)arcs
+ (little_endian()?0:(arc_type_size - 1)))
= first_arc;
arcs = ((char *)arcs) + arc_type_size;
}
/* Decode, if has space */
if(arcs < arcs_end) {
if(OBJECT_IDENTIFIER_get_single_arc(&oid->buf[startn],
i - startn + 1, add,
arcs, arc_type_size)) {
rd = OBJECT_IDENTIFIER_get_first_arcs(st->buf, st->size, &arc0, &arc1);
if(rd <= 0) {
return -1;
}
startn = i + 1;
arcs = ((char *)arcs) + arc_type_size;
add = 0;
num_arcs = 2;
switch(arc_slots) {
default:
case 2:
arcs[1] = arc1;
/* Fall through */
case 1:
arcs[0] = arc0;
/* Fall through */
case 0:
break;
}
for(off = rd; ; ) {
asn_oid_arc_t arc;
rd = OBJECT_IDENTIFIER_get_single_arc(st->buf + off, st->size - off,
&arc);
if(rd < 0) {
return -1;
} else if(rd == 0) {
/* No more arcs. */
break;
} else {
off += rd;
if(num_arcs < arc_slots) {
arcs[num_arcs] = arc;
}
num_arcs++;
}
}
if(off != st->size) {
return -1;
}
return num_arcs;
}
......@@ -446,137 +333,74 @@ OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *oid, void *arcs,
/*
* Save the single value as an object identifier arc.
*/
int
OBJECT_IDENTIFIER_set_single_arc(uint8_t *arcbuf, const void *arcval, unsigned int arcval_size, int prepared_order) {
ssize_t
OBJECT_IDENTIFIER_set_single_arc(uint8_t *arcbuf, size_t arcbuf_len,
asn_oid_arc_t value) {
/*
* The following conditions must hold:
* assert(arcval);
* assert(arcval_size > 0);
* assert(arcval_size <= 16);
* assert(arcbuf);
*/
const uint8_t *tend, *tp;
unsigned int cache;
uint8_t *bp = arcbuf;
int bits;
uint8_t buffer[16];
if(little_endian() && !prepared_order) {
const uint8_t *a = (const unsigned char *)arcval + arcval_size - 1;
const uint8_t *aend = (const uint8_t *)arcval;
uint8_t *msb = buffer + arcval_size - 1;
uint8_t *tb;
for(tb = buffer; a >= aend; tb++, a--)
if((*tb = *a) && (tb < msb))
msb = tb;
tend = &buffer[arcval_size];
tp = msb; /* Most significant non-zero byte */
} else {
/* Look for most significant non-zero byte */
tend = (const unsigned char *)arcval + arcval_size;
for(tp = (const uint8_t *)arcval; tp < tend - 1; tp++)
if(*tp) break;
}
/*
* Split the value in 7-bits chunks.
*/
bits = ((tend - tp) * CHAR_BIT) % 7;
if(bits) {
cache = *tp >> (CHAR_BIT - bits);
if(cache) {
*bp++ = cache | 0x80;
cache = *tp++;
bits = CHAR_BIT - bits;
} else {
bits = -bits;
}
} else {
cache = 0;
uint8_t scratch[((sizeof(value) * CHAR_BIT + 6) / 7)];
uint8_t *scratch_end = &scratch[sizeof(scratch)-1];
uint8_t *b;
size_t result_len;
uint8_t mask;
for(b = scratch_end, mask = 0; ; mask = 0x80, b--) {
*b = mask | (value & 0x7f);
value >>= 7;
if(!value) {
break;
}
for(; tp < tend; tp++) {
cache = (cache << CHAR_BIT) + *tp;
bits += CHAR_BIT;
while(bits >= 7) {
bits -= 7;
*bp++ = 0x80 | (cache >> bits);
}
result_len = (scratch_end - b) + 1;
if(result_len > arcbuf_len) {
return -1;
}
if(bits) *bp++ = cache;
bp[-1] &= 0x7f; /* Clear the last bit */
return bp - arcbuf;
memcpy(arcbuf, b, result_len);
return result_len;
}
int
OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *oid, const void *arcs, unsigned int arc_type_size, unsigned int arc_slots) {
OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *st, const asn_oid_arc_t *arcs,
size_t arc_slots) {
uint8_t *buf;
uint8_t *bp;
unsigned int arc0;
unsigned int arc1;
unsigned size;
unsigned i;
if(!oid || !arcs || arc_type_size < 1
|| arc_type_size > 16
|| arc_slots < 2) {
size_t wrote;
asn_oid_arc_t arc0;
asn_oid_arc_t arc1;
size_t size;
size_t i;
if(!st || !arcs || arc_slots < 2) {
errno = EINVAL;
return -1;
}
switch(arc_type_size) {
case sizeof(char):
arc0 = ((const unsigned char *)arcs)[0];
arc1 = ((const unsigned char *)arcs)[1];
break;
case sizeof(short):
arc0 = ((const unsigned short *)arcs)[0];
arc1 = ((const unsigned short *)arcs)[1];
break;
case sizeof(int):
arc0 = ((const unsigned int *)arcs)[0];
arc1 = ((const unsigned int *)arcs)[1];
break;
default:
arc1 = arc0 = 0;
if(little_endian()) { /* Little endian (x86) */
const unsigned char *ps, *pe;
/* If more significant bytes are present,
* make them > 255 quick */
for(ps = (const unsigned char *)arcs + 1, pe = ps+arc_type_size;
ps < pe; ps++)
arc0 |= *ps, arc1 |= *(ps + arc_type_size);
arc0 <<= CHAR_BIT, arc1 <<= CHAR_BIT;
arc0 = *((const unsigned char *)arcs + 0);
arc1 = *((const unsigned char *)arcs + arc_type_size);
} else {
const unsigned char *ps, *pe;
/* If more significant bytes are present,
* make them > 255 quick */
for(ps = (const unsigned char *)arcs, pe = ps+arc_type_size - 1; ps < pe; ps++)
arc0 |= *ps, arc1 |= *(ps + arc_type_size);
arc0 = *((const unsigned char *)arcs + arc_type_size - 1);
arc1 = *((const unsigned char *)arcs +(arc_type_size<< 1)-1);
}
}
arc0 = arcs[0];
arc1 = arcs[1];
/*
* The previous chapter left us with the first and the second arcs.
* The values are not precise (that is, they are valid only if
* they're less than 255), but OK for the purposes of making
* the sanity test below.
*/
if(arc0 <= 1) {
if(arc1 >= 39) {
if(arc1 >= 40) {
/* 8.19.4: At most 39 subsequent values (including 0) */
errno = ERANGE;
return -1;
}
} else if(arc0 == 2) {
if(arc1 > ASN_OID_ARC_MAX - 80) {
errno = ERANGE;
return -1;
}
} else if(arc0 > 2) {
/* 8.19.4: Only three values are allocated from the root node */
errno = ERANGE;
return -1;
}
/*
* After above tests it is known that the value of arc0 is completely
* trustworthy (0..2). However, the arc1's value is still meaningless.
......@@ -590,81 +414,53 @@ OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *oid, const void *arcs, unsigned
* * the first value may require more space (+1 byte)
* * the value of the first arc which is in range (0..2)
*/
size = ((arc_type_size * CHAR_BIT + 6) / 7) * arc_slots;
size = ((sizeof(asn_oid_arc_t) * CHAR_BIT + 6) / 7) * arc_slots;
bp = buf = (uint8_t *)MALLOC(size + 1);
if(!buf) {
/* ENOMEM */
return -1;
}
/*
* Encode the first two arcs.
* These require special treatment.
*/
{
uint8_t *tp;
uint8_t first_value[1 + 16]; /* of two arcs */
uint8_t *fv = first_value;
/*
* Simulate first_value = arc0 * 40 + arc1;
*/
/* Copy the second (1'st) arcs[1] into the first_value */
*fv++ = 0;
arcs = ((const char *)arcs) + arc_type_size;
if(little_endian()) {
const uint8_t *aend = (const unsigned char *)arcs - 1;
const uint8_t *a1 = (const unsigned char *)arcs + arc_type_size - 1;
for(; a1 > aend; fv++, a1--) *fv = *a1;
} else {
const uint8_t *a1 = (const uint8_t *)arcs;
const uint8_t *aend = a1 + arc_type_size;
for(; a1 < aend; fv++, a1++) *fv = *a1;
}
/* Increase the first_value by arc0 */
arc0 *= 40; /* (0..80) */
for(tp = first_value + arc_type_size; tp >= first_value; tp--) {
unsigned int v = *tp;
v += arc0;
*tp = v;
if(v >= (1 << CHAR_BIT)) arc0 = v >> CHAR_BIT;
else break;
wrote = OBJECT_IDENTIFIER_set_single_arc(bp, size, arc0 * 40 + arc1);
if(wrote <= 0) {
FREEMEM(buf);
return -1;
}
assert(wrote <= size);
bp += wrote;
size -= wrote;
assert(tp >= first_value);
bp += OBJECT_IDENTIFIER_set_single_arc(bp, first_value,
fv - first_value, 1);
for(i = 2; i < arc_slots; i++) {
wrote = OBJECT_IDENTIFIER_set_single_arc(bp, size, arcs[i]);
if(wrote <= 0) {
FREEMEM(buf);
return -1;
}
/*
* Save the rest of arcs.
*/
for(arcs = ((const char *)arcs) + arc_type_size, i = 2;
i < arc_slots;
i++, arcs = ((const char *)arcs) + arc_type_size) {
bp += OBJECT_IDENTIFIER_set_single_arc(bp,
arcs, arc_type_size, 0);
assert(wrote <= size);
bp += wrote;
size -= wrote;
assert(wrote <= size);
}
assert((unsigned)(bp - buf) <= size);
assert(size >= 0);
/*
* Replace buffer.
*/
oid->size = bp - buf;
bp = oid->buf;
oid->buf = buf;
st->size = bp - buf;
bp = st->buf;
st->buf = buf;
st->buf[st->size] = '\0';
if(bp) FREEMEM(bp);
return 0;
}
int
ssize_t
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;
asn_oid_arc_t *arcs, size_t arcs_count,
const char **opt_oid_text_end) {
size_t num_arcs = 0;
const char *oid_end;
enum {
ST_LEADSPACE,
......@@ -673,7 +469,7 @@ OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
ST_WAITDIGITS /* Next character is expected to be a digit */
} state = ST_LEADSPACE;
if(!oid_text || oid_txt_length < -1 || (arcs_slots && !arcs)) {
if(!oid_text || oid_txt_length < -1 || (arcs_count && !arcs)) {
if(opt_oid_text_end) *opt_oid_text_end = oid_text;
errno = EINVAL;
return -1;
......@@ -682,26 +478,27 @@ 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(oid_text, oid_end) do { \
#define _OID_CAPTURE_ARC(oid_text, oid_end) \
do { \
const char *endp = oid_end; \
long value; \
switch(asn_strtol_lim(oid_text, &endp, &value)) { \
unsigned long value; \
switch(asn_strtoul_lim(oid_text, &endp, &value)) { \
case ASN_STRTOX_EXTRA_DATA: \
case ASN_STRTOX_OK: \
if(arcs_count < arcs_slots) \
arcs[arcs_count] = value; \
arcs_count++; \
if(value <= ASN_OID_ARC_MAX) { \
if(num_arcs < arcs_count) arcs[num_arcs] = value; \
num_arcs++; \
oid_text = endp - 1; \
break; \
} \
/* Fall through */ \
case ASN_STRTOX_ERROR_RANGE: \
if(opt_oid_text_end) \
*opt_oid_text_end = oid_text; \
if(opt_oid_text_end) *opt_oid_text_end = oid_text; \
errno = ERANGE; \
return -1; \
case ASN_STRTOX_ERROR_INVAL: \
case ASN_STRTOX_EXPECT_MORE: \
if(opt_oid_text_end) \
*opt_oid_text_end = oid_text; \
if(opt_oid_text_end) *opt_oid_text_end = oid_text; \
errno = EINVAL; \
return -1; \
} \
......@@ -772,7 +569,7 @@ OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
return -1;
case ST_AFTERVALUE:
case ST_TAILSPACE:
return arcs_count;
return num_arcs;
}
errno = EINVAL; /* Broken OID */
......@@ -783,9 +580,9 @@ OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length,
* Generate values from the list of interesting values, or just a random
* value up to the upper limit.
*/
static uint32_t
OBJECT_IDENTIFIER__biased_random_arc(uint32_t upper_bound) {
static const uint16_t values[] = {0, 1, 127, 128, 129, 254, 255, 256};
static asn_oid_arc_t
OBJECT_IDENTIFIER__biased_random_arc(asn_oid_arc_t upper_bound) {
const asn_oid_arc_t values[] = {0, 1, 127, 128, 129, 254, 255, 256};
size_t idx;
switch(asn_random_between(0, 2)) {
......@@ -811,7 +608,7 @@ OBJECT_IDENTIFIER_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0};
asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
OBJECT_IDENTIFIER_t *st;
uint32_t arcs[5];
asn_oid_arc_t arcs[5];
size_t arcs_len = asn_random_between(2, 5);
size_t i;
......@@ -826,13 +623,13 @@ OBJECT_IDENTIFIER_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
}
arcs[0] = asn_random_between(0, 2);
arcs[1] =
OBJECT_IDENTIFIER__biased_random_arc(arcs[0] <= 1 ? 39 : UINT_MAX);
arcs[1] = OBJECT_IDENTIFIER__biased_random_arc(
arcs[0] <= 1 ? 39 : (ASN_OID_ARC_MAX - 80));
for(i = 2; i < arcs_len; i++) {
arcs[i] = OBJECT_IDENTIFIER__biased_random_arc(UINT_MAX);
arcs[i] = OBJECT_IDENTIFIER__biased_random_arc(ASN_OID_ARC_MAX);
}
if(OBJECT_IDENTIFIER_set_arcs(st, arcs, sizeof(arcs[0]), arcs_len)) {
if(OBJECT_IDENTIFIER_set_arcs(st, arcs, arcs_len)) {
if(st != *sptr) {
ASN_STRUCT_FREE(*td, st);
}
......@@ -841,5 +638,6 @@ OBJECT_IDENTIFIER_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
*sptr = st;
result_ok.length = st->size;
return result_ok;
}
......@@ -14,6 +14,9 @@
extern "C" {
#endif
typedef uint32_t asn_oid_arc_t;
#define ASN_OID_ARC_MAX (~((asn_oid_arc_t)0))
typedef ASN__PRIMITIVE_TYPE_t OBJECT_IDENTIFIER_t;
extern asn_TYPE_descriptor_t asn_DEF_OBJECT_IDENTIFIER;
......@@ -40,33 +43,30 @@ asn_random_fill_f OBJECT_IDENTIFIER_random_fill;
**********************************/
/*
* This function fills an (_arcs) array with OBJECT IDENTIFIER arcs
* up to specified (_arc_slots) elements.
* This function fills an (arcs) array with OBJECT IDENTIFIER arcs
* up to specified (arc_slots) elements.
*
* EXAMPLE:
* void print_arcs(OBJECT_IDENTIFIER_t *oid) {
* unsigned long fixed_arcs[10]; // Try with fixed space first
* unsigned long *arcs = fixed_arcs;
* int arc_type_size = sizeof(fixed_arcs[0]); // sizeof(long)
* int arc_slots = sizeof(fixed_arcs)/sizeof(fixed_arcs[0]); // 10
* int count; // Real number of arcs.
* asn_oid_arc_t fixed_arcs[10]; // Try with fixed space first
* asn_oid_arc_t *arcs = fixed_arcs;
* size_t arc_slots = sizeof(fixed_arcs)/sizeof(fixed_arcs[0]); // 10
* ssize_t count; // Real number of arcs.
* int i;
*
* count = OBJECT_IDENTIFIER_get_arcs(oid, arcs,
* arc_type_size, arc_slots);
* count = OBJECT_IDENTIFIER_get_arcs(oid, arcs, arc_slots);
* // If necessary, reallocate arcs array and try again.
* if(count > arc_slots) {
* arc_slots = count;
* arcs = malloc(arc_type_size * arc_slots);
* arcs = malloc(sizeof(asn_oid_arc_t) * arc_slots);
* if(!arcs) return;
* count = OBJECT_IDENTIFIER_get_arcs(oid, arcs,
* arc_type_size, arc_slots);
* count = OBJECT_IDENTIFIER_get_arcs(oid, arcs, arc_slots);
* assert(count == arc_slots);
* }
*
* // Print the contents of the arcs array.
* for(i = 0; i < count; i++)
* printf("%d\n", arcs[i]);
* printf("%"PRIu32"\n", arcs[i]);
*
* // Avoid memory leak.
* if(arcs != fixed_arcs) free(arcs);
......@@ -77,13 +77,11 @@ asn_random_fill_f OBJECT_IDENTIFIER_random_fill;
* -1/ERANGE: One or more arcs have value out of array cell type range.
* >=0: Number of arcs contained in the OBJECT IDENTIFIER
*
* WARNING: The function always returns the real number of arcs,
* even if there is no sufficient (_arc_slots) provided.
* WARNING: The function always returns the actual number of arcs,
* even if there is no sufficient (arc_slots) provided.
*/
int OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *_oid,
void *_arcs, /* e.g., unsigned int arcs[N] */
unsigned int _arc_type_size, /* e.g., sizeof(arcs[0]) */
unsigned int _arc_slots /* e.g., N */);
ssize_t OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *oid,
asn_oid_arc_t *arcs, size_t arc_slots);
/*
* This functions initializes the OBJECT IDENTIFIER object with
......@@ -95,25 +93,13 @@ int OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *_oid,
* -1/ENOMEM: Memory allocation failed
* 0: The object was initialized with new arcs.
*/
int OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *_oid,
const void *_arcs, /* e.g., unsigned int arcs[N] */
unsigned int _arc_type_size, /* e.g., sizeof(arcs[0]) */
unsigned int _arc_slots /* e.g., N */);
int OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *oid,
const asn_oid_arc_t *arcs, size_t arcs_count);
/*
* Print the specified OBJECT IDENTIFIER arc.
*/
int OBJECT_IDENTIFIER_print_arc(const uint8_t *arcbuf, int arclen,
int add, /* Arbitrary offset, required to process the first two arcs */
asn_app_consume_bytes_f *cb, void *app_key);
/* Same as above, but returns the number of written digits, instead of 0 */
ssize_t OBJECT_IDENTIFIER__dump_arc(const uint8_t *arcbuf, int arclen, int add,
asn_app_consume_bytes_f *cb, void *app_key);
/*
* Parse the OBJECT IDENTIFIER textual representation ("1.3.6.1.4.1.9363").
* No arc can exceed the (0..signed_long_max) range (typically, 0..2G if L32).
* No arc can exceed the (0..ASN_OID_ARC_MAX, which is the same as UINT32_MAX).
* This function is not specific to OBJECT IDENTIFIER, it may be used to parse
* the RELATIVE-OID data, or any other data consisting of dot-separated
* series of numeric values.
......@@ -129,20 +115,38 @@ ssize_t OBJECT_IDENTIFIER__dump_arc(const uint8_t *arcbuf, int arclen, int add,
* >= 0: Number of arcs contained in the OBJECT IDENTIFIER.
*
* WARNING: The function always returns the real number of arcs,
* even if there is no sufficient (_arc_slots) provided.
* This is useful for (_arc_slots) value estimation.
* even if there is no sufficient (arc_slots) provided.
* This is useful for (arc_slots) value estimation.
*/
int 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);
ssize_t OBJECT_IDENTIFIER_parse_arcs(const char *oid_text,
ssize_t oid_txt_length,
asn_oid_arc_t *arcs, size_t arcs_count,
const char **opt_oid_text_end);
/*
* Internal functions.
* Used by RELATIVE-OID implementation in particular.
*/
int OBJECT_IDENTIFIER_get_single_arc(const uint8_t *arcbuf, unsigned int arclen,
signed int add, void *value, unsigned int value_size);
int OBJECT_IDENTIFIER_set_single_arc(uint8_t *arcbuf,
const void *arcval, unsigned int arcval_size, int _prepared_order);
/*
* Retrieve a single arc of size from the (arcbuf) buffer.
* RETURN VALUES:
* -1: Failed to retrieve the value from the (arcbuf).
* >0: Number of bytes consumed from the (arcbuf), <= (arcbuf_len).
*/
ssize_t OBJECT_IDENTIFIER_get_single_arc(const uint8_t *arcbuf,
size_t arcbuf_len,
asn_oid_arc_t *ret_value);
/*
* Write the unterminated arc value into the (arcbuf) which has the size at
* least (arcbuf_len).
* RETURN VALUES:
* -1: (arcbuf_len) size is not sufficient to write the value.
* <n>: Number of bytes appended to the arcbuf (<= arcbuf_len).
*/
ssize_t OBJECT_IDENTIFIER_set_single_arc(uint8_t *arcbuf, size_t arcbuf_len,
asn_oid_arc_t arc_value);
#ifdef __cplusplus
}
......
......@@ -58,31 +58,38 @@ asn_TYPE_descriptor_t asn_DEF_RELATIVE_OID = {
static ssize_t
RELATIVE_OID__dump_body(const RELATIVE_OID_t *st, asn_app_consume_bytes_f *cb, void *app_key) {
ssize_t wrote = 0;
ssize_t ret;
size_t startn;
size_t i;
for(i = 0, startn = 0; i < st->size; i++) {
uint8_t b = st->buf[i];
if((b & 0x80)) /* Continuation expected */
continue;
if(startn) {
/* Separate arcs */
if(cb(".", 1, app_key) < 0)
char scratch[32];
size_t produced = 0;
size_t off = 0;
for(;;) {
asn_oid_arc_t arc;
ssize_t rd = OBJECT_IDENTIFIER_get_single_arc(st->buf + off,
st->size - off, &arc);
if(rd < 0) {
return -1;
} else if(rd == 0) {
/* No more arcs. */
break;
} else {
int ret = snprintf(scratch, sizeof(scratch), "%s%" PRIu32,
off ? "." : "", arc);
if(ret >= (ssize_t)sizeof(scratch)) {
return -1;
wrote++;
}
produced += ret;
off += rd;
assert(off <= st->size);
if(cb(scratch, ret, app_key) < 0) return -1;
}
}
ret = OBJECT_IDENTIFIER__dump_arc(&st->buf[startn],
i - startn + 1, 0, cb, app_key);
if(ret < 0) return -1;
wrote += ret;
startn = i + 1;
if(off != st->size) {
ASN_DEBUG("Could not scan to the end of Object Identifier");
return -1;
}
return wrote;
return produced;
}
int
......@@ -111,38 +118,38 @@ RELATIVE_OID__xer_body_decode(asn_TYPE_descriptor_t *td, void *sptr, const void
RELATIVE_OID_t *st = (RELATIVE_OID_t *)sptr;
const char *chunk_end = (const char *)chunk_buf + chunk_size;
const char *endptr;
long s_arcs[6];
long *arcs = s_arcs;
int arcs_count;
asn_oid_arc_t s_arcs[6];
asn_oid_arc_t *arcs = s_arcs;
ssize_t num_arcs;
int ret;
(void)td;
arcs_count = OBJECT_IDENTIFIER_parse_arcs(
(const char *)chunk_buf, chunk_size,
arcs, sizeof(s_arcs)/sizeof(s_arcs[0]), &endptr);
if(arcs_count < 0) {
num_arcs = OBJECT_IDENTIFIER_parse_arcs(
(const char *)chunk_buf, chunk_size, arcs,
sizeof(s_arcs) / sizeof(s_arcs[0]), &endptr);
if(num_arcs < 0) {
/* Expecting at least one arc arcs */
return XPBD_BROKEN_ENCODING;
} else if(arcs_count == 0) {
} else if(num_arcs == 0) {
return XPBD_NOT_BODY_IGNORE;
}
assert(endptr == chunk_end);
if((size_t)arcs_count > sizeof(s_arcs)/sizeof(s_arcs[0])) {
arcs = (long *)MALLOC(arcs_count * sizeof(long));
if((size_t)num_arcs > sizeof(s_arcs) / sizeof(s_arcs[0])) {
arcs = (asn_oid_arc_t *)MALLOC(num_arcs * sizeof(arcs[0]));
if(!arcs) return XPBD_SYSTEM_FAILURE;
ret = OBJECT_IDENTIFIER_parse_arcs(
(const char *)chunk_buf, chunk_size,
arcs, arcs_count, &endptr);
if(ret != arcs_count)
ret = OBJECT_IDENTIFIER_parse_arcs((const char *)chunk_buf, chunk_size,
arcs, num_arcs, &endptr);
if(ret != num_arcs) {
return XPBD_SYSTEM_FAILURE; /* assert?.. */
}
}
/*
* Convert arcs into BER representation.
*/
ret = RELATIVE_OID_set_arcs(st, arcs, sizeof(*arcs), arcs_count);
ret = RELATIVE_OID_set_arcs(st, arcs, num_arcs);
if(arcs != s_arcs) FREEMEM(arcs);
return ret ? XPBD_SYSTEM_FAILURE : XPBD_BODY_CONSUMED;
......@@ -177,48 +184,51 @@ RELATIVE_OID_encode_xer(asn_TYPE_descriptor_t *td, void *sptr,
ASN__ENCODED_OK(er);
}
int
RELATIVE_OID_get_arcs(const RELATIVE_OID_t *roid,
void *arcs, unsigned int arc_type_size, unsigned int arc_slots) {
void *arcs_end = (char *)arcs + (arc_slots * arc_type_size);
int num_arcs = 0;
size_t startn = 0;
size_t i;
ssize_t
RELATIVE_OID_get_arcs(const RELATIVE_OID_t *st, asn_oid_arc_t *arcs,
size_t arcs_count) {
size_t num_arcs = 0;
size_t off;
if(!roid || !roid->buf) {
if(!st || !st->buf) {
errno = EINVAL;
return -1;
}
for(i = 0; i < roid->size; i++) {
uint8_t b = roid->buf[i];
if((b & 0x80)) /* Continuation expected */
continue;
if(arcs < arcs_end) {
if(OBJECT_IDENTIFIER_get_single_arc(
&roid->buf[startn],
i - startn + 1, 0,
arcs, arc_type_size))
for(off = 0;;) {
asn_oid_arc_t arc;
ssize_t rd = OBJECT_IDENTIFIER_get_single_arc(st->buf + off,
st->size - off, &arc);
if(rd < 0) {
return -1;
arcs = ((char *)arcs) + arc_type_size;
} else if(rd == 0) {
/* No more arcs. */
break;
} else {
off += rd;
if(num_arcs < arcs_count) {
arcs[num_arcs] = arc;
}
num_arcs++;
}
}
startn = i + 1;
if(off != st->size) {
return -1;
}
return num_arcs;
}
int
RELATIVE_OID_set_arcs(RELATIVE_OID_t *roid, void *arcs, unsigned int arc_type_size, unsigned int arcs_slots) {
RELATIVE_OID_set_arcs(RELATIVE_OID_t *st, const asn_oid_arc_t *arcs,
size_t arcs_count) {
uint8_t *buf;
uint8_t *bp;
unsigned int size;
unsigned int i;
size_t size;
size_t i;
if(roid == NULL || arcs == NULL || arc_type_size < 1) {
if(!st || !arcs) {
errno = EINVAL;
return -1;
}
......@@ -226,7 +236,7 @@ RELATIVE_OID_set_arcs(RELATIVE_OID_t *roid, void *arcs, unsigned int arc_type_si
/*
* Roughly estimate the maximum size necessary to encode these arcs.
*/
size = ((arc_type_size * CHAR_BIT + 6) / 7) * arcs_slots;
size = ((sizeof(asn_oid_arc_t) * CHAR_BIT + 6) / 7) * arcs_count;
bp = buf = (uint8_t *)MALLOC(size + 1);
if(!buf) {
/* ENOMEM */
......@@ -236,19 +246,26 @@ RELATIVE_OID_set_arcs(RELATIVE_OID_t *roid, void *arcs, unsigned int arc_type_si
/*
* Encode the arcs.
*/
for(i = 0; i < arcs_slots; i++, arcs = ((char *)arcs) + arc_type_size) {
bp += OBJECT_IDENTIFIER_set_single_arc(bp,
arcs, arc_type_size, 0);
for(i = 0; i < arcs_count; i++) {
ssize_t wrote = OBJECT_IDENTIFIER_set_single_arc(bp, size, arcs[i]);
if(wrote <= 0) {
FREEMEM(buf);
return -1;
}
assert((size_t)wrote <= size);
bp += wrote;
size -= wrote;
}
assert((unsigned)(bp - buf) <= size);
assert(size >= 0);
/*
* Replace buffer.
*/
roid->size = (int)(bp - buf);
bp = roid->buf;
roid->buf = buf;
st->size = bp - buf;
bp = st->buf;
st->buf = buf;
st->buf[st->size] = '\0';
if(bp) FREEMEM(bp);
return 0;
......@@ -258,7 +275,7 @@ RELATIVE_OID_set_arcs(RELATIVE_OID_t *roid, void *arcs, unsigned int arc_type_si
/*
* Generate values from the list of interesting values, or just a random value.
*/
static uint32_t
static asn_oid_arc_t
RELATIVE_OID__biased_random_arc() {
static const uint16_t values[] = {0, 1, 127, 128, 129, 254, 255, 256};
......@@ -283,8 +300,9 @@ RELATIVE_OID_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0};
RELATIVE_OID_t *st;
const int min_arcs = 1; /* A minimum of 1 arc is required */
size_t arcs_len = asn_random_between(min_arcs, 3);
uint32_t arcs[3];
asn_oid_arc_t arcs[3];
size_t arcs_len =
asn_random_between(min_arcs, sizeof(arcs) / sizeof(arcs[0]));
size_t i;
(void)constraints;
......@@ -301,7 +319,7 @@ RELATIVE_OID_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
arcs[i] = RELATIVE_OID__biased_random_arc();
}
if(RELATIVE_OID_set_arcs(st, arcs, sizeof(arcs[0]), arcs_len)) {
if(RELATIVE_OID_set_arcs(st, arcs, arcs_len)) {
if(st != *sptr) {
ASN_STRUCT_FREE(*td, st);
}
......@@ -310,5 +328,6 @@ RELATIVE_OID_random_fill(const asn_TYPE_descriptor_t *td, void **sptr,
*sptr = st;
result_ok.length = st->size;
return result_ok;
}
......@@ -37,12 +37,12 @@ asn_random_fill_f RELATIVE_OID_random_fill;
**********************************/
/* See OBJECT_IDENTIFIER_get_arcs() function in OBJECT_IDENTIFIER.h */
int RELATIVE_OID_get_arcs(const RELATIVE_OID_t *_roid,
void *arcs, unsigned int arc_type_size, unsigned int arc_slots);
ssize_t RELATIVE_OID_get_arcs(const RELATIVE_OID_t *, asn_oid_arc_t *arcs,
size_t arcs_count);
/* See OBJECT_IDENTIFIER_set_arcs() function in OBJECT_IDENTIFIER.h */
int RELATIVE_OID_set_arcs(RELATIVE_OID_t *_roid,
void *arcs, unsigned int arc_type_size, unsigned int arcs_slots);
int RELATIVE_OID_set_arcs(RELATIVE_OID_t *, const asn_oid_arc_t *arcs,
size_t arcs_count);
#ifdef __cplusplus
}
......
......@@ -38,7 +38,7 @@ int get_asn1c_environment_version(void); /* Run-time version */
*/
#ifndef ASN_DEBUG /* If debugging code is not defined elsewhere... */
#if EMIT_ASN_DEBUG == 1 /* And it was asked to emit this code... */
#ifdef __GNUC__
#if __STDC_VERSION__ >= 199901L
#ifdef ASN_THREAD_SAFE
/* Thread safety requires sacrifice in output indentation:
* Retain empty definition of ASN_DEBUG_INDENT_ADD. */
......@@ -55,10 +55,10 @@ int asn_debug_indent;
fprintf(stderr, " (%s:%d)\n", \
__FILE__, __LINE__); \
} while(0)
#else /* !__GNUC__ */
#else /* !C99 */
void CC_PRINTFLIKE(1, 2) ASN_DEBUG_f(const char *fmt, ...);
#define ASN_DEBUG ASN_DEBUG_f
#endif /* __GNUC__ */
#endif /* C99 */
#else /* EMIT_ASN_DEBUG != 1 */
#if __STDC_VERSION__ >= 199901L
#define ASN_DEBUG(...) do{}while(0)
......
......@@ -17,7 +17,7 @@ static void
check_OID(int lineno, uint8_t *buf, size_t len, unsigned *ck_buf, int ck_len) {
OBJECT_IDENTIFIER_t *oid;
asn_dec_rval_t rval;
unsigned long arcs[10];
uint32_t arcs[10];
int alen;
int i;
......@@ -41,8 +41,8 @@ check_OID(int lineno, uint8_t *buf, size_t len, unsigned *ck_buf, int ck_len) {
printf("\n");
memset(arcs, 'A', sizeof(arcs));
alen = OBJECT_IDENTIFIER_get_arcs(oid,
arcs, sizeof(arcs[0]), sizeof(arcs)/sizeof(arcs[0]));
alen =
OBJECT_IDENTIFIER_get_arcs(oid, arcs, sizeof(arcs) / sizeof(arcs[0]));
assert(alen > 0);
printf("OBJECT_IDENTIFIER_get_arcs() => {");
......@@ -50,7 +50,7 @@ check_OID(int lineno, uint8_t *buf, size_t len, unsigned *ck_buf, int ck_len) {
* Make sure they are equivalent.
*/
for(i = 0; i < alen; i++) {
printf(" %lu", arcs[i]);
printf(" %" PRIu32, arcs[i]);
if(alen == ck_len) {
assert(arcs[i] == ck_buf[i]);
}
......@@ -62,15 +62,16 @@ check_OID(int lineno, uint8_t *buf, size_t len, unsigned *ck_buf, int ck_len) {
}
static void
check_ROID(int lineno, uint8_t *buf, size_t len, unsigned *ck_buf, int ck_len) {
check_ROID(int lineno, uint8_t *buf, size_t len, unsigned *ck_buf,
size_t ck_len) {
RELATIVE_OID_t *oid;
asn_dec_rval_t rval;
unsigned long arcs[10];
uint32_t arcs[10];
int alen;
int i;
size_t i;
printf("%03d: Checking {", lineno);
for(i = 0; i < (ssize_t)len; i++) { printf("%s%02x", i?" ":"", buf[i]); }
for(i = 0; i < len; i++) { printf("%s%02x", i?" ":"", buf[i]); }
printf("} against {");
for(i = 0; i < ck_len; i++) { printf("%s%u", i?" ":"", ck_buf[i]); }
printf("}\n");
......@@ -89,8 +90,7 @@ check_ROID(int lineno, uint8_t *buf, size_t len, unsigned *ck_buf, int ck_len) {
printf("\n");
memset(arcs, 'A', sizeof(arcs));
alen = RELATIVE_OID_get_arcs(oid,
arcs, sizeof(arcs[0]), sizeof(arcs)/sizeof(arcs[0]));
alen = RELATIVE_OID_get_arcs(oid, arcs, sizeof(arcs) / sizeof(arcs[0]));
assert(alen > 0);
assert(alen == ck_len);
......@@ -99,7 +99,7 @@ check_ROID(int lineno, uint8_t *buf, size_t len, unsigned *ck_buf, int ck_len) {
*/
printf("RELATIVE_OID_get_arcs() => {");
for(i = 0; i < alen; i++) {
printf(" %lu", arcs[i]);
printf(" %" PRIu32, arcs[i]);
assert(arcs[i] == ck_buf[i]);
}
printf(" }\n");
......@@ -113,26 +113,24 @@ check_speed() {
int cycles = 100000000;
double a, b, c;
struct timeval tv;
unsigned long value;
uint32_t value;
int i;
ret = OBJECT_IDENTIFIER_get_single_arc(buf, sizeof(buf), 0, &value, sizeof(value));
ret = OBJECT_IDENTIFIER_get_single_arc(buf, sizeof(buf), &value);
assert(ret == 0);
assert(value == 0x7040c20d);
gettimeofday(&tv, 0);
a = tv.tv_sec + tv.tv_usec / 1000000.0;
for(i = 0; i < cycles; i++) {
ret = OBJECT_IDENTIFIER_get_single_arc(buf, sizeof(buf), 0,
&value, sizeof(value));
ret = OBJECT_IDENTIFIER_get_single_arc(buf, sizeof(buf), &value);
}
assert(ret == 0);
assert(value == 0x7040c20d);
gettimeofday(&tv, 0);
b = tv.tv_sec + tv.tv_usec / 1000000.0;
for(i = 0; i < cycles; i++) {
ret = OBJECT_IDENTIFIER_get_single_arc(buf, sizeof(buf), 0,
&value, sizeof(value));
ret = OBJECT_IDENTIFIER_get_single_arc(buf, sizeof(buf), &value);
}
assert(ret == 0);
assert(value == 0x7040c20d);
......@@ -147,55 +145,66 @@ check_speed() {
return 0;
}
static void check_parse(const char *oid_txt, int retval) {
#define CHECK_PARSE(a, b) check_parse(__LINE__, a, b)
static void check_parse(int lineno, const char *oid_txt, int retval) {
int ret;
long l[2];
uint32_t arcs[2];
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);
ret = OBJECT_IDENTIFIER_parse_arcs(oid_txt, -1, arcs, 2, &p);
printf("%03d: [%s] => %d == %d\n", lineno, oid_txt, ret, retval);
assert(ret == retval);
assert(p >= oid_txt);
}
static void check_xer(int expect_arcs, char *xer) {
static void
check_xer(int lineno, asn_TYPE_descriptor_t *td, ssize_t expect_arcs, char *xer,
const asn_oid_arc_t *expected_arcs) {
asn_dec_rval_t rc;
RELATIVE_OID_t *st = 0;
long arcs[10];
int ret;
int i;
printf("[%s] => ", xer); fflush(stdout);
rc = asn_DEF_RELATIVE_OID.op->xer_decoder(0,
&asn_DEF_RELATIVE_OID, (void **)&st, "t",
xer, strlen(xer));
void *st = 0;
uint32_t arcs[10];
ssize_t got_arcs;
ssize_t i;
printf("%03d: [%s] => ", lineno, xer);
fflush(stdout);
rc = td->op->xer_decoder(0, td, (void **)&st, "t", xer, strlen(xer));
if(expect_arcs == -1) {
if(rc.code != RC_OK) {
printf("-1\n");
ASN_STRUCT_FREE(asn_DEF_RELATIVE_OID, st);
ASN_STRUCT_FREE(*td, st);
return;
}
}
assert(rc.code == RC_OK);
ret = RELATIVE_OID_get_arcs(st, arcs, sizeof(arcs[0]),
sizeof(arcs)/sizeof(arcs[0]));
assert(ret < 10);
if(td == &asn_DEF_OBJECT_IDENTIFIER) {
got_arcs = OBJECT_IDENTIFIER_get_arcs(st, arcs,
sizeof(arcs) / sizeof(arcs[0]));
} else if(td == &asn_DEF_RELATIVE_OID) {
got_arcs =
RELATIVE_OID_get_arcs(st, arcs, sizeof(arcs) / sizeof(arcs[0]));
} else {
assert(!"Unreachable");
}
assert(got_arcs < 10);
if(expect_arcs == -1) {
assert(ret == -1);
ASN_STRUCT_FREE(asn_DEF_RELATIVE_OID, st);
assert(got_arcs == -1);
ASN_STRUCT_FREE(*td, st);
return;
}
for(i = 0; i < ret; i++) {
for(i = 0; i < got_arcs; i++) {
if(i) printf(".");
printf("%ld", arcs[i]);
if(arcs[i] != i + 1) printf(" != %d\n", i + 1);
assert(arcs[i] == i + 1);
printf("%" PRIu32, arcs[i]);
if(arcs[i] != expected_arcs[i]) {
printf(" != %" PRIu32 "\n", expected_arcs[i]);
}
printf(": %d == %d\n", ret, expect_arcs);
assert(ret == expect_arcs);
ASN_STRUCT_FREE(asn_DEF_RELATIVE_OID, st);
assert(arcs[i] == expected_arcs[i]);
}
printf(": %zd == %zd\n", got_arcs, expect_arcs);
assert(got_arcs == expect_arcs);
ASN_STRUCT_FREE(*td, st);
}
#define CHECK_OID(n) \
......@@ -208,118 +217,176 @@ static void check_xer(int expect_arcs, char *xer) {
static void
check_binary_parsing() {
/* {0 0} */
uint8_t buf0[] = {
0x06, /* OBJECT IDENTIFIER */
0x01, /* Length */
0x00
};
uint32_t buf0_check[] = { 0, 0 };
/* {joint-iso-itu-t 230 3} */
uint8_t buf1[] = {
0x06, /* OBJECT IDENTIFIER */
0x03, /* Length */
0x82, 0x36, 0x03
};
unsigned buf1_check[] = { 2, 230, 3 };
/* {8571 3 2} */
uint8_t buf2[] = {
0x0D, /* RELATIVE-OID */
0x04, /* Length */
0xC2, 0x7B, 0x03, 0x02
};
unsigned buf2_check[] = { 8571, 3, 2 };
uint32_t buf1_check[] = { 2, 230, 3 };
/* {joint-iso-itu-t 42 } */
uint8_t buf3[] = {
uint8_t buf2[] = {
0x06, /* OBJECT IDENTIFIER */
0x01, /* Length */
0x7A
};
unsigned buf3_check[] = { 2, 42 };
uint32_t buf2_check[] = { 2, 42 };
/* {joint-iso-itu-t 25957 } */
uint8_t buf4[] = {
uint8_t buf3[] = {
0x06, /* OBJECT IDENTIFIER */
0x03, /* Length */
0x81, 0x80 + 0x4B, 0x35
};
unsigned buf4_check[] = { 2, 25957 };
uint32_t buf3_check[] = { 2, 25957 };
/* { jounsigned-iso-itu-t 2 1 1 } */
uint8_t buf5[] = {
uint8_t buf4[] = {
0x06, /* OBJECT IDENTIFIER */
0x03, /* Length */
0x52, 0x01, 0x01
};
unsigned buf5_check[] = { 2, 2, 1, 1 };
uint32_t buf4_check[] = { 2, 2, 1, 1 };
/* { jounsigned-iso-itu-t 2 1 0 1 } */
uint8_t buf6[] = {
uint8_t buf5[] = {
0x06, /* OBJECT IDENTIFIER */
0x04, /* Length */
0x52, 0x01, 0x00, 0x01
};
unsigned buf6_check[] = { 2, 2, 1, 0, 1 };
uint32_t buf5_check[] = { 2, 2, 1, 0, 1 };
/* {0 0} */
uint8_t buf10[] = {
0x0D, /* RELATIVE-OID */
0x01, /* Length */
0x00
};
uint32_t buf10_check[] = { 0 };
/* {0 0} */
uint8_t buf11[] = {
0x0D, /* RELATIVE-OID */
0x02, /* Length */
0x00, 0x00
};
uint32_t buf11_check[] = { 0, 0 };
/* {8571 3 2} */
uint8_t buf12[] = {
0x0D, /* RELATIVE-OID */
0x04, /* Length */
0xC2, 0x7B, 0x03, 0x02
};
uint32_t buf12_check[] = { 8571, 3, 2 };
CHECK_OID(0);
CHECK_OID(1);
CHECK_ROID(2);
CHECK_OID(2);
CHECK_OID(3);
CHECK_OID(4);
CHECK_OID(5);
CHECK_OID(6);
CHECK_ROID(10);
CHECK_ROID(11);
CHECK_ROID(12);
}
static void
check_text_parsing() {
check_parse("", 0);
check_parse(" ", 0);
check_parse(".", -1);
check_parse(" .", -1);
check_parse(".1", -1);
check_parse("1.", -1);
check_parse("1. ", -1);
check_parse(".1. ", -1);
check_parse(" .1. ", -1);
check_parse(" 1", 1);
check_parse(" 1.2", 2);
check_parse(" 1.", -1);
check_parse(" 1. ", -1);
check_parse("1. ", -1);
check_parse("1.2", 2);
check_parse("1.2 ", 2);
check_parse("1.2 ", 2);
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);
check_parse("10.30.234.234.", -1);
check_parse("1.2000000000.3", 3);
check_parse("1.2147483647.3", 3);
if(sizeof(long) == 4) {
check_parse("1.2147483648.3", -1); /* overflow on ILP32 */
check_parse("1.2147483649.3", -1); /* overflow on ILP32 */
check_parse("1.3000000000.3", -1);
check_parse("1.4000000000.3", -1);
check_parse("1.5000000000.3", -1);
check_parse("1.6000000000.3", -1);
check_parse("1.9000000000.3", -1);
} else if(sizeof(long) == 8) {
check_parse("1.2147483648.3", 3);
check_parse("1.9223372036854775807.3", 3);
check_parse("1.9223372036854775808.3", -1);
}
check_parse("1.900a0000000.3", -1);
check_parse("1.900a.3", -1);
CHECK_PARSE("", 0);
CHECK_PARSE(" ", 0);
CHECK_PARSE(".", -1);
CHECK_PARSE(" .", -1);
CHECK_PARSE(".1", -1);
CHECK_PARSE("1.", -1);
CHECK_PARSE("1. ", -1);
CHECK_PARSE(".1. ", -1);
CHECK_PARSE(" .1. ", -1);
CHECK_PARSE(" 1", 1);
CHECK_PARSE(" 1.2", 2);
CHECK_PARSE(" 1.", -1);
CHECK_PARSE(" 1. ", -1);
CHECK_PARSE("1. ", -1);
CHECK_PARSE("1.2", 2);
CHECK_PARSE("1.2 ", 2);
CHECK_PARSE("1.2 ", 2);
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("2.0", 2);
CHECK_PARSE("2.1", 2);
CHECK_PARSE("10.30.234.234", 4);
CHECK_PARSE("10.30.234.234 ", 4);
CHECK_PARSE("10.30.234. 234 ", -1);
CHECK_PARSE("10.30.234.234.", -1);
CHECK_PARSE("1.2000000000.3", 3);
CHECK_PARSE("1.2147483647.3", 3);
CHECK_PARSE("1.4294967295.3", 3);
CHECK_PARSE("1.4294967296.3", -1); /* overflow on ILP32 */
CHECK_PARSE("1.3000000000.3", 3);
CHECK_PARSE("1.4000000000.3", 3);
CHECK_PARSE("1.5000000000.3", -1);
CHECK_PARSE("1.6000000000.3", -1);
CHECK_PARSE("1.9000000000.3", -1);
CHECK_PARSE("1.900a0000000.3", -1);
CHECK_PARSE("1.900a.3", -1);
}
#define CHECK_XER(a, b, c, data) check_xer(__LINE__, &asn_DEF_##a, b, c, data)
static void
check_xer_parsing() {
check_xer(-1, "<t></t>");
check_xer(2, "<t>1.2</t>");
check_xer(3, "<t>1.2.3</t>");
check_xer(3, "<t> 1.2.3 </t>");
check_xer(-1, "<t>1.2.3 1</t>");
asn_oid_arc_t zero_zero[] = {0, 0};
asn_oid_arc_t zero_one[] = {0, 1};
asn_oid_arc_t one_zero[] = {1, 0};
asn_oid_arc_t one_one[] = {1, 1};
asn_oid_arc_t one_two[] = {1, 2};
asn_oid_arc_t two_one[] = {2, 1};
asn_oid_arc_t one_two_three[] = {1, 2,3};
CHECK_XER(RELATIVE_OID, -1, "<t></t>", 0);
CHECK_XER(RELATIVE_OID, -1, "<t>1.</t>", 0);
CHECK_XER(RELATIVE_OID, -1, "<t>2.1.</t>", 0);
CHECK_XER(RELATIVE_OID, 2, "<t>0.0</t>", zero_zero);
CHECK_XER(RELATIVE_OID, 2, "<t>0.1</t>", zero_one);
CHECK_XER(RELATIVE_OID, 2, "<t>1.0</t>", one_zero);
CHECK_XER(RELATIVE_OID, 2, "<t>1.2</t>", one_two);
CHECK_XER(RELATIVE_OID, -1, "<t>1.-2</t>", 0);
CHECK_XER(RELATIVE_OID, -1, "<t>1.+2</t>", 0);
CHECK_XER(RELATIVE_OID, 3, "<t>1.2.3</t>", one_two_three);
CHECK_XER(RELATIVE_OID, 3, "<t> 1.2.3 </t>", one_two_three);
CHECK_XER(RELATIVE_OID, -1, "<t>1.2.3 1</t>", 0);
CHECK_XER(RELATIVE_OID, 2, "<t>2.1</t>", two_one);
CHECK_XER(OBJECT_IDENTIFIER, -1, "<t></t>", 0);
CHECK_XER(OBJECT_IDENTIFIER, -1, "<t>1</t>", 0);
CHECK_XER(OBJECT_IDENTIFIER, -1, "<t>1.</t>", 0);
CHECK_XER(OBJECT_IDENTIFIER, -1, "<t>2.1.</t>", 0);
CHECK_XER(OBJECT_IDENTIFIER, 2, "<t>0.0</t>", zero_zero);
CHECK_XER(OBJECT_IDENTIFIER, 2, "<t>0.1</t>", zero_one);
CHECK_XER(OBJECT_IDENTIFIER, 2, "<t>1.0</t>", one_zero);
CHECK_XER(OBJECT_IDENTIFIER, 2, "<t>1.1</t>", one_one);
CHECK_XER(OBJECT_IDENTIFIER, 2, "<t>1.2</t>", one_two);
CHECK_XER(OBJECT_IDENTIFIER, -1, "<t>1.-2</t>", 0);
CHECK_XER(OBJECT_IDENTIFIER, -1, "<t>1.+2</t>", 0);
CHECK_XER(OBJECT_IDENTIFIER, 3, "<t>1.2.3</t>", one_two_three);
CHECK_XER(OBJECT_IDENTIFIER, 3, "<t> 1.2.3 </t>", one_two_three);
CHECK_XER(OBJECT_IDENTIFIER, -1, "<t>1.2.3 1</t>", 0);
CHECK_XER(OBJECT_IDENTIFIER, 2, "<t> 2.1 </t>", two_one);
}
int
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment