diff --git a/skeletons/OBJECT_IDENTIFIER.c b/skeletons/OBJECT_IDENTIFIER.c index a08f18a9..535e4e26 100644 --- a/skeletons/OBJECT_IDENTIFIER.c +++ b/skeletons/OBJECT_IDENTIFIER.c @@ -22,7 +22,7 @@ asn_TYPE_descriptor_t asn_DEF_OBJECT_IDENTIFIER = { OBJECT_IDENTIFIER_constraint, ber_decode_primitive, der_encode_primitive, - 0, /* Not implemented yet */ + OBJECT_IDENTIFIER_decode_xer, OBJECT_IDENTIFIER_encode_xer, 0, /* Use generic outmost tag fetcher */ asn_DEF_OBJECT_IDENTIFIER_tags, @@ -263,6 +263,49 @@ OBJECT_IDENTIFIER__dump_body(const OBJECT_IDENTIFIER_t *st, asn_app_consume_byte return wrote_len; } +static ssize_t +OBJECT_IDENTIFIER__xer_body_decode(void *sptr, void *chunk_buf, size_t chunk_size) { + OBJECT_IDENTIFIER_t *st = (OBJECT_IDENTIFIER_t *)sptr; + char *endptr; + long s_arcs[10]; + long *arcs = s_arcs; + int arcs_count; + int ret; + + arcs_count = OBJECT_IDENTIFIER_parse_arcs( + (const char *)chunk_buf, chunk_size, arcs, 10, &endptr); + if(arcs_count <= 0) + return -1; /* Expecting more than zero arcs */ + if(arcs_count > 10) { + arcs = (long *)MALLOC(arcs_count * sizeof(long)); + if(!arcs) return -1; + ret = OBJECT_IDENTIFIER_parse_arcs( + (const char *)chunk_buf, chunk_size, + arcs, arcs_count, &endptr); + if(ret != arcs_count) + return -1; /* assert?.. */ + } + + /* + * Convert arcs into BER representation. + */ + ret = OBJECT_IDENTIFIER_set_arcs(st, arcs, sizeof(*arcs), arcs_count); + if(ret) return -1; + if(arcs != s_arcs) FREEMEM(arcs); + + return endptr - (char *)chunk_buf; +} + +asn_dec_rval_t +OBJECT_IDENTIFIER_decode_xer(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname, + void *buf_ptr, size_t size) { + + return xer_decode_primitive(opt_codec_ctx, td, + sptr, sizeof(OBJECT_IDENTIFIER_t), opt_mname, + buf_ptr, size, OBJECT_IDENTIFIER__xer_body_decode); +} + asn_enc_rval_t OBJECT_IDENTIFIER_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, int ilevel, enum xer_encoder_flags_e flags, @@ -596,3 +639,87 @@ OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *oid, void *arcs, unsigned int ar return 0; } + +int +OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length, + long *arcs, unsigned int arcs_slots, char **oid_text_end) { + unsigned int arcs_count = 0; + const char *oid_end; + long value = 0; + enum { + ST_SKIPSPACE, + ST_WAITDIGITS, /* Next character is expected to be a digit */ + ST_DIGITS, + } state = ST_SKIPSPACE; + + if(!oid_text || oid_txt_length < -1 || (arcs_slots && !arcs)) { + if(oid_text_end) (const char *)*oid_text_end = oid_text; + errno = EINVAL; + return -1; + } + + if(oid_txt_length == -1) + oid_txt_length = strlen(oid_text); + + for(oid_end = oid_text + oid_txt_length; oid_text=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. */ int OBJECT_IDENTIFIER_get_arcs(OBJECT_IDENTIFIER_t *_oid, void *_arcs, /* i.e., unsigned int arcs[N] */ @@ -92,6 +83,40 @@ int OBJECT_IDENTIFIER_set_arcs(OBJECT_IDENTIFIER_t *_oid, unsigned int _arc_type_size, /* i.e., sizeof(arcs[0]) */ unsigned int _arc_slots /* i.e., N */); +/* + * Print the specified OBJECT IDENTIFIER arc. + */ +int OBJECT_IDENTIFIER_print_arc(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(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). + * 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. + * + * If (oid_txt_length == -1), the strlen() will be invoked to determine the + * size of the (oid_text) string. + * + * After return, the optional (oid_text_end) is set to the character after + * the last parsed one. (oid_text_end) is never less than (oid_text). + * + * RETURN VALUES: + * -1: Parse error. + * >= 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. + */ +int OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length, + long arcs[], unsigned int arcs_slots, char **oid_text_end); + /* * Internal functions. * Used by RELATIVE-OID implementation in particular. diff --git a/skeletons/RELATIVE-OID.c b/skeletons/RELATIVE-OID.c index 13fa0e2b..d36d1f78 100644 --- a/skeletons/RELATIVE-OID.c +++ b/skeletons/RELATIVE-OID.c @@ -23,7 +23,7 @@ asn_TYPE_descriptor_t asn_DEF_RELATIVE_OID = { asn_generic_no_constraint, ber_decode_primitive, der_encode_primitive, - 0, /* Not implemented yet */ + RELATIVE_OID_decode_xer, RELATIVE_OID_encode_xer, 0, /* Use generic outmost tag fetcher */ asn_DEF_RELATIVE_OID_tags, @@ -86,6 +86,50 @@ RELATIVE_OID_print(asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, return (cb(" }", 2, app_key) < 0) ? -1 : 0; } +static ssize_t +RELATIVE_OID__xer_body_decode(void *sptr, void *chunk_buf, size_t chunk_size) { + RELATIVE_OID_t *st = (RELATIVE_OID_t *)sptr; + char *endptr; + long s_arcs[6]; + long *arcs = s_arcs; + int arcs_count; + int ret; + + arcs_count = OBJECT_IDENTIFIER_parse_arcs( + (const char *)chunk_buf, chunk_size, + arcs, 6, &endptr); + if(arcs_count < 0) + return -1; /* Expecting at least zero arcs */ + if(arcs_count > 6) { + arcs = (long *)MALLOC(arcs_count * sizeof(long)); + if(!arcs) return -1; + ret = OBJECT_IDENTIFIER_parse_arcs( + (const char *)chunk_buf, chunk_size, + arcs, arcs_count, &endptr); + if(ret != arcs_count) + return -1; /* assert?.. */ + } + + /* + * Convert arcs into BER representation. + */ + ret = RELATIVE_OID_set_arcs(st, arcs, sizeof(*arcs), arcs_count); + if(ret) return -1; + if(arcs != s_arcs) FREEMEM(arcs); + + return endptr - (char *)chunk_buf; +} + +asn_dec_rval_t +RELATIVE_OID_decode_xer(asn_codec_ctx_t *opt_codec_ctx, + asn_TYPE_descriptor_t *td, void **sptr, const char *opt_mname, + void *buf_ptr, size_t size) { + + return xer_decode_primitive(opt_codec_ctx, td, + sptr, sizeof(RELATIVE_OID_t), opt_mname, + buf_ptr, size, RELATIVE_OID__xer_body_decode); +} + asn_enc_rval_t RELATIVE_OID_encode_xer(asn_TYPE_descriptor_t *td, void *sptr, int ilevel, enum xer_encoder_flags_e flags, diff --git a/skeletons/RELATIVE-OID.h b/skeletons/RELATIVE-OID.h index 94351721..2b7f13d3 100644 --- a/skeletons/RELATIVE-OID.h +++ b/skeletons/RELATIVE-OID.h @@ -13,6 +13,7 @@ typedef OBJECT_IDENTIFIER_t RELATIVE_OID_t; extern asn_TYPE_descriptor_t asn_DEF_RELATIVE_OID; asn_struct_print_f RELATIVE_OID_print; +xer_type_decoder_f RELATIVE_OID_decode_xer; xer_type_encoder_f RELATIVE_OID_encode_xer; /********************************** diff --git a/skeletons/tests/check-OIDs.c b/skeletons/tests/check-OIDs.c index 8033d7cc..816eb559 100644 --- a/skeletons/tests/check-OIDs.c +++ b/skeletons/tests/check-OIDs.c @@ -223,6 +223,50 @@ check_speed() { return 0; } +static void check_parse(const char *oid_txt, int retval) { + int ret; + long l[2]; + char *p; + + ret = OBJECT_IDENTIFIER_parse_arcs(oid_txt, -1, l, 2, &p); + printf("[%s] => %d == %d\n", oid_txt, ret, retval); + assert(ret == retval); + assert(p >= oid_txt); +} + +static void check_xer(int expect_arcs, char *xer) { + 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.xer_decoder(0, + &asn_DEF_RELATIVE_OID, (void **)&st, "t", + xer, strlen(xer)); + if(expect_arcs == -1) { + if(rc.code != RC_OK) + 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(expect_arcs == -1) { + assert(ret == -1); + return; + } + for(i = 0; i < ret; i++) { + if(i) printf("."); + printf("%ld", arcs[i]); + assert(arcs[i] == i + 1); + } + printf(": %d == %d\n", ret, expect_arcs); + assert(ret == expect_arcs); +} + #define CHECK_OID(n) check_OID(buf ## n, sizeof(buf ## n), \ buf ## n ## _check, \ sizeof(buf ## n ## _check)/sizeof(buf ## n ## _check[0])) @@ -334,6 +378,42 @@ main() { CHECK_REGEN_OID(19); CHECK_REGEN_OID(20); + check_parse("", 0); + check_parse(" ", 0); + check_parse(" ", 0); + check_parse(".", -1); + check_parse(" .", -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("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.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 { + check_parse("1.2147483648.3", 3); + } + check_parse("1.900a0000000.3", -1); + check_parse("1.900a.3", -1); + + check_xer(0, ""); + check_xer(2, "1.2"); + check_xer(3, "1.2.3"); + check_xer(3, " 1.2.3 "); + check_xer(-1, "1.2.3 1"); + for(i = 0; i < 100000; i++) { int bufA_check[3] = { 2, i, rand() }; int bufB_check[2] = { rand(), i * 121 };