diff options
author | Lev Walkin <vlm@lionet.info> | 2004-10-28 13:22:54 +0000 |
---|---|---|
committer | Lev Walkin <vlm@lionet.info> | 2004-10-28 13:22:54 +0000 |
commit | 22b545579e88f3fb4545b4562d83595e413f27d9 (patch) | |
tree | 65abbe4f7e131462903baae9d6089afe5e607d66 | |
parent | 6379436cc3f0800d04224a700877a665b2c4eebb (diff) |
decoder template
-rw-r--r-- | skeletons/asn-decoder-template.c | 313 | ||||
-rw-r--r-- | skeletons/file-dependencies | 9 |
2 files changed, 318 insertions, 4 deletions
diff --git a/skeletons/asn-decoder-template.c b/skeletons/asn-decoder-template.c new file mode 100644 index 00000000..aa893fbb --- /dev/null +++ b/skeletons/asn-decoder-template.c @@ -0,0 +1,313 @@ +/* + * This is a generic BER decoder template for any ASN.1 type. + * + * To compile, please redefine the asn_DEF as shown: + * + * cc -Dasn_DEF=asn_DEF_MyCustomType -o myTypeDecoder.o -c decoder-template.c + */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <sys/types.h> +#include <unistd.h> /* for getopt */ +#include <string.h> /* for strerror(3) */ +#include <errno.h> /* for errno */ +#include <assert.h> /* for assert(3) */ +#include <sysexits.h> /* for EX_* exit codes */ + +#include <constr_TYPE.h> + +extern asn_TYPE_descriptor_t asn_DEF; /* ASN.1 type to be decoded */ + +/* + * Open file and parse its BER contens. + */ +static void *data_decode_from_file(const char *fname, ssize_t suggested_bufsize); + + int opt_debug; /* -d */ +static int opt_check; /* -c */ +static int opt_print; /* -p */ +static int opt_stack; /* -s */ +static int opt_toxml; /* -x */ + +#define DEBUG(fmt, args...) do { \ + if(!opt_debug) break; \ + fprintf(stderr, fmt, ##args); \ + fprintf(stderr, "\n"); \ +} while(0) + +int +main(int ac, char **av) { + ssize_t suggested_bufsize = 8192; /* close or equal to stdio buffer */ + int number_of_iterations = 1; + int num; + int ch; + + /* + * Pocess the command-line argments. + */ + while((ch = getopt(ac, av, "b:cdn:hps:x")) != -1) + switch(ch) { + case 'b': + suggested_bufsize = atoi(optarg); + if(suggested_bufsize < 1 + || suggested_bufsize > 16 * 1024 * 1024) { + fprintf(stderr, + "-b %s: Improper buffer size (1..16M)\n", + optarg); + exit(EX_UNAVAILABLE); + } + break; + case 'c': + opt_check = 1; + break; + case 'd': + opt_debug++; /* Double -dd means ASN.1 debug */ + break; + case 'n': + number_of_iterations = atoi(optarg); + if(number_of_iterations < 1) { + fprintf(stderr, + "-n %s: Improper iterations count\n", optarg); + exit(EX_UNAVAILABLE); + } + break; + case 'p': + opt_print++; + break; + case 's': + opt_stack = atoi(optarg); + if(opt_stack <= 0) { + fprintf(stderr, + "-s %s: Value greater than 0 expected\n", + optarg); + exit(EX_UNAVAILABLE); + } + break; + case 'x': + opt_toxml++; + break; + case 'h': + default: + fprintf(stderr, + "Usage: %s [options] <data.ber> ...\n" + "Where options are:\n" + " -b <size> Set the i/o buffer size (default is %ld)\n" + " -c Check ASN.1 constraints after decoding\n" + " -d Enable debugging (-dd is even better)\n" + " -n <num> Process files <num> times\n" + " -s <size> Set the stack usage limit\n" + " -p Print out the decoded contents\n" + " -x Print out as XML\n" + , av[0], (long)suggested_bufsize); + exit(EX_USAGE); + } + + ac -= optind; + av += optind; + + if(ac < 1) { + fprintf(stderr, "Error: missing filename\n"); + exit(EX_USAGE); + } + + setvbuf(stdout, 0, _IOLBF, 0); + + for(num = 0; num < number_of_iterations; num++) { + int ac_i; + /* + * Process all files in turn. + */ + for(ac_i = 0; ac_i < ac; ac_i++) { + char *fname = av[ac_i]; + void *structure; + + /* + * Decode the encoded structure from file. + */ + structure = data_decode_from_file(fname, suggested_bufsize); + if(!structure) { + /* Error message is already printed */ + exit(EX_DATAERR); + } + + fprintf(stderr, "%s: decoded successfully\n", fname); + + if(opt_print) asn_fprint(stdout, &asn_DEF, structure); + + if(opt_toxml + && xer_fprint(stdout, &asn_DEF, structure)) { + fprintf(stderr, "%s: Cannot convert into XML\n", fname); + exit(EX_UNAVAILABLE); + } + + /* Check ASN.1 constraints */ + if(opt_check) { + char errbuf[128]; + size_t errlen = sizeof(errbuf); + if(asn_check_constraints(&asn_DEF, structure, + errbuf, &errlen)) { + fprintf(stderr, "%s: ASN.1 constraint " + "check failed: %s\n", fname, errbuf); + exit(EX_DATAERR); + } + } + + asn_DEF.free_struct(&asn_DEF, structure, 0); + } + } + + return 0; +} + + +static char *buffer; +static size_t buf_offset; /* Offset from the start */ +static size_t buf_len; /* Length of meaningful contents */ +static size_t buf_size; /* Allocated memory */ +static off_t buf_shifted; /* Number of bytes ever shifted */ + +#define bufptr (buffer + buf_offset) +#define bufend (buffer + buf_offset + buf_len) + +/* + * Ensure that the buffer contains at least this amoount of free space. + */ +static void buf_extend(size_t bySize) { + + DEBUG("buf_extend(%ld) { o=%ld l=%ld s=%ld }", + (long)bySize, (long)buf_offset, (long)buf_len, (long)buf_size); + + if(buf_size >= (buf_offset + buf_len + bySize)) { + return; /* Nothing to do */ + } else if(bySize <= buf_offset) { + DEBUG("\tContents shifted by %ld", (long)buf_offset); + + /* Shift the buffer contents */ + memmove(buffer, buffer + buf_offset, buf_len); + buf_shifted += buf_offset; + buf_offset = 0; + } else { + size_t newsize = (buf_size << 2) + bySize; + void *p = realloc(buffer, newsize); + if(p) { + buffer = p; + buf_size = newsize; + + DEBUG("\tBuffer reallocated to %ld", (long)newsize); + } else { + perror("realloc()"); + exit(EX_OSERR); + } + } +} + +static void *data_decode_from_file(const char *fname, ssize_t suggested_bufsize) { + static char *fbuf; + static ssize_t fbuf_size; + static asn_codec_ctx_t s_codec_ctx; + asn_codec_ctx_t *opt_codec_ctx = 0; + void *structure = 0; + size_t rd; + FILE *fp; + + if(opt_stack) { + s_codec_ctx.max_stack_size = opt_stack; + opt_codec_ctx = &s_codec_ctx; + } + + DEBUG("Processing file %s", fname); + + fp = fopen(fname, "r"); + + if(!fp) { + fprintf(stderr, "%s: %s\n", fname, strerror(errno)); + return 0; + } + + /* prepare the file buffer */ + if(fbuf_size != suggested_bufsize) { + fbuf = realloc(fbuf, suggested_bufsize); + if(!fbuf) { + perror("realloc()"); + exit(EX_OSERR); + } + fbuf_size = suggested_bufsize; + } + + buf_shifted = 0; + buf_offset = 0; + buf_len = 0; + + while((rd = fread(fbuf, 1, fbuf_size, fp)) || !feof(fp)) { + asn_dec_rval_t rval; + int using_local_buf; + + /* + * Copy the data over, or use the original buffer. + */ + if(buf_len) { + /* Append the new data into the intermediate buffer */ + buf_extend(rd); + memcpy(bufend, fbuf, rd); + buf_len += rd; + + rval = ber_decode(opt_codec_ctx, &asn_DEF, + (void **)&structure, bufptr, buf_len); + DEBUG("ber_decode(%ld) consumed %ld, code %d", + (long)buf_len, (long)rval.consumed, rval.code); + + /* + * Adjust position inside the source buffer. + */ + assert(rval.consumed <= buf_len); + buf_offset += rval.consumed; + buf_len -= rval.consumed; + } else { + using_local_buf = 1; + + /* Feed the chunk of data into a BER decoder routine */ + rval = ber_decode(opt_codec_ctx, &asn_DEF, + (void **)&structure, fbuf, rd); + DEBUG("ber_decode(%ld) consumed %ld, code %d", + (long)rd, (long)rval.consumed, rval.code); + + /* + * Switch the remainder into the intermediate buffer. + */ + if(rval.code != RC_FAIL && rval.consumed < rd) { + buf_extend(rd - rval.consumed); + memcpy(bufend, + fbuf + rval.consumed, + rd - rval.consumed); + buf_len = rd - rval.consumed; + } + } + + switch(rval.code) { + case RC_OK: + DEBUG("RC_OK, finishing up"); + fclose(fp); + return structure; + case RC_WMORE: + DEBUG("RC_WMORE, continuing..."); + continue; + case RC_FAIL: + break; + } + break; + } + + fclose(fp); + + /* Clean up partially decoded structure */ + asn_DEF.free_struct(&asn_DEF, structure, 0); + + fprintf(stderr, "%s: " + "BER failure past %lld byte\n", + fname, (long long)(buf_shifted + buf_offset)); + + return 0; +} + diff --git a/skeletons/file-dependencies b/skeletons/file-dependencies index 3c8715fa..ce9c0010 100644 --- a/skeletons/file-dependencies +++ b/skeletons/file-dependencies @@ -41,11 +41,11 @@ constr_SEQUENCE_OF.h constr_SEQUENCE_OF.c asn_SEQUENCE_OF.h constr_SET_OF.h constr_SET.h constr_SET.c constr_SET_OF.h constr_SET_OF.c asn_SET_OF.h -COMMON-FILES: # This is a special section -asn_application.h -asn_internal.h -asn_codecs.h +COMMON-FILES: # THIS IS A SPECIAL SECTION +asn_application.h # Applications should include this file asn_system.h # Platform-dependent types +asn_codecs.h # Return types of encoders and decoders +asn_internal.h # Internal stuff OCTET_STRING.h OCTET_STRING.c # This one is used too widely BIT_STRING.h BIT_STRING.c # This one is necessary for the above one asn_codecs_prim.c asn_codecs_prim.h # enc/decoders for primitive types @@ -58,3 +58,4 @@ constraints.h constraints.c # Subtype constraints support xer_support.h xer_support.c # XML parsing xer_decoder.h xer_decoder.c # XER decoding support xer_encoder.h xer_encoder.c # XER encoding support +#asn-decoder-template.c # Template for quick decoder creation |