2  * Generic converter template for a selected ASN.1 type.
 
   3  * Copyright (c) 2005, 2006 Lev Walkin <vlm@lionet.info>. All rights reserved.
 
   5  * To compile with your own ASN.1 type, please redefine the PDU as shown:
 
   7  * cc -DPDU=MyCustomType -o myDecoder.o -c converter-sample.c
 
  13 #include <sys/types.h>
 
  14 #include <stdlib.h>     /* for atoi(3) */
 
  15 #include <unistd.h>     /* for getopt(3) */
 
  16 #include <string.h>     /* for strerror(3) */
 
  17 #include <sysexits.h>   /* for EX_* exit codes */
 
  18 #include <assert.h>     /* for assert(3) */
 
  19 #include <errno.h>      /* for errno */
 
  21 #include <asn_application.h>
 
  22 #include <asn_internal.h>       /* for _ASN_DEFAULT_STACK_MAX */
 
  24 /* Convert "Type" defined by -DPDU into "asn_DEF_Type" */
 
  25 #define ASN_DEF_PDU(t)  asn_DEF_ ## t
 
  26 #define DEF_PDU_Type(t) ASN_DEF_PDU(t)
 
  27 #define PDU_Type        DEF_PDU_Type(PDU)
 
  29 extern asn_TYPE_descriptor_t PDU_Type;  /* ASN.1 type to be decoded */
 
  30 #ifdef  ASN_PDU_COLLECTION              /* Generated by asn1c: -pdu=... */
 
  31 extern asn_TYPE_descriptor_t *asn_pdu_collection[];
 
  35  * Open file and parse its contens.
 
  37 static void *data_decode_from_file(asn_TYPE_descriptor_t *asnTypeOfPDU,
 
  38         FILE *file, const char *name, ssize_t suggested_bufsize, int first_pdu);
 
  39 static int write_out(const void *buffer, size_t size, void *key);
 
  40 static FILE *argument_to_file(char *av[], int idx);
 
  41 static char *argument_to_name(char *av[], int idx);
 
  43        int opt_debug;   /* -d (or -dd) */
 
  44 static int opt_check;   /* -c (constraints checking) */
 
  45 static int opt_stack;   /* -s (maximum stack size) */
 
  46 static int opt_ippad;   /* -per-padded (PER input is byte-padded) */
 
  47 static int opt_onepdu;  /* -1 (decode single PDU) */
 
  49 /* Input data format selector */
 
  50 static enum input_format {
 
  51         INP_BER,        /* -iber: BER input */
 
  52         INP_XER,        /* -ixer: XER input */
 
  53         INP_PER         /* -iper: Unaligned PER input */
 
  54 } iform;        /* -i<format> */
 
  56 /* Output data format selector */
 
  57 static enum output_format {
 
  58         OUT_XER,        /* -oxer: XER (XML) output */
 
  59         OUT_DER,        /* -oder: DER (BER) output */
 
  60         OUT_PER,        /* -oper: Unaligned PER output */
 
  61         OUT_TEXT,       /* -otext: semi-structured text */
 
  62         OUT_NULL        /* -onull: No pretty-printing */
 
  63 } oform;        /* -o<format> */
 
  65 /* Debug output function */
 
  67 DEBUG(const char *fmt, ...) {
 
  69         if(!opt_debug) return;
 
  70         fprintf(stderr, "AD: ");
 
  72         vfprintf(stderr, fmt, ap);
 
  74         fprintf(stderr, "\n");
 
  78 main(int ac, char *av[]) {
 
  79         static asn_TYPE_descriptor_t *pduType = &PDU_Type;
 
  80         ssize_t suggested_bufsize = 8192;  /* close or equal to stdio buffer */
 
  81         int number_of_iterations = 1;
 
  85         /* Figure out if Unaligned PER needs to be default */
 
  86         if(pduType->uper_decoder)
 
  90          * Pocess the command-line argments.
 
  92         while((ch = getopt(ac, av, "i:o:1b:cdn:p:hs:")) != -1)
 
  95                 if(optarg[0] == 'b') { iform = INP_BER; break; }
 
  96                 if(optarg[0] == 'x') { iform = INP_XER; break; }
 
  97                 if(pduType->uper_decoder
 
  98                 && optarg[0] == 'p') { iform = INP_PER; break; }
 
  99                 fprintf(stderr, "-i<format>: '%s': improper format selector\n",
 
 101                 exit(EX_UNAVAILABLE);
 
 103                 if(optarg[0] == 'd') { oform = OUT_DER; break; }
 
 104                 if(pduType->uper_encoder
 
 105                 && optarg[0] == 'p') { oform = OUT_PER; break; }
 
 106                 if(optarg[0] == 'x') { oform = OUT_XER; break; }
 
 107                 if(optarg[0] == 't') { oform = OUT_TEXT; break; }
 
 108                 if(optarg[0] == 'n') { oform = OUT_NULL; break; }
 
 109                 fprintf(stderr, "-o<format>: '%s': improper format selector\n",
 
 111                 exit(EX_UNAVAILABLE);
 
 116                 suggested_bufsize = atoi(optarg);
 
 117                 if(suggested_bufsize < 1
 
 118                         || suggested_bufsize > 16 * 1024 * 1024) {
 
 120                                 "-b %s: Improper buffer size (1..16M)\n",
 
 122                         exit(EX_UNAVAILABLE);
 
 129                 opt_debug++;    /* Double -dd means ASN.1 debug */
 
 132                 number_of_iterations = atoi(optarg);
 
 133                 if(number_of_iterations < 1) {
 
 135                                 "-n %s: Improper iterations count\n", optarg);
 
 136                         exit(EX_UNAVAILABLE);
 
 140                 if(strcmp(optarg, "er-padded") == 0) {
 
 144 #ifdef  ASN_PDU_COLLECTION
 
 145                 if(strcmp(optarg, "list") == 0) {
 
 146                         asn_TYPE_descriptor_t **pdu = asn_pdu_collection;
 
 147                         fprintf(stderr, "Available PDU types:\n");
 
 148                         for(; *pdu; pdu++) printf("%s\n", (*pdu)->name);
 
 150                 } else if(optarg[0] >= 'A' && optarg[0] <= 'Z') {
 
 151                         asn_TYPE_descriptor_t **pdu = asn_pdu_collection;
 
 152                         while(*pdu && strcmp((*pdu)->name, optarg)) pdu++;
 
 153                         if(*pdu) { pduType = *pdu; break; }
 
 154                         fprintf(stderr, "-p %s: Unrecognized PDU\n", optarg);
 
 156 #endif  /* ASN_PDU_COLLECTION */
 
 157                 fprintf(stderr, "-p %s: Unrecognized option\n", optarg);
 
 158                 exit(EX_UNAVAILABLE);
 
 160                 opt_stack = atoi(optarg);
 
 163                                 "-s %s: Non-negative value expected\n",
 
 165                         exit(EX_UNAVAILABLE);
 
 170                 fprintf(stderr, "Usage: %s [options] <data.ber> ...\n", av[0]);
 
 171                 fprintf(stderr, "Where options are:\n");
 
 172                 if(pduType->uper_decoder)
 
 174                 "  -iper        Input is in Unaligned PER (Packed Encoding Rules) (DEFAULT)\n");
 
 176                 "  -iber        Input is in BER (Basic Encoding Rules)%s\n",
 
 177                         iform == INP_PER ? "" : " (DEFAULT)");
 
 179                 "  -ixer        Input is in XER (XML Encoding Rules)\n");
 
 180                 if(pduType->uper_encoder)
 
 182                 "  -oper        Output in Unaligned PER (Packed Encoding Rules)\n");
 
 184                 "  -oder        Output in DER (Distinguished Encoding Rules)\n"
 
 185                 "  -oxer        Output in XER (XML Encoding Rules) (DEFAULT)\n"
 
 186                 "  -otext       Output in plain semi-structured text (dump)\n"
 
 187                 "  -onull       Verify (decode) input, but do not output\n");
 
 188                 if(pduType->uper_decoder)
 
 190                 "  -per-padded  Assume PER PDUs are byte-padded (-iper)\n");
 
 191 #ifdef  ASN_PDU_COLLECTION
 
 193                 "  -p <PDU>     Specify PDU type to decode\n"
 
 194                 "  -p list      List available PDUs\n");
 
 195 #endif  /* ASN_PDU_COLLECTION */
 
 197                 "  -1           Decode only the first PDU in file\n"
 
 198                 "  -b <size>    Set the i/o buffer size (default is %ld)\n"
 
 199                 "  -c           Check ASN.1 constraints after decoding\n"
 
 200                 "  -d           Enable debugging (-dd is even better)\n"
 
 201                 "  -n <num>     Process files <num> times\n"
 
 202                 "  -s <size>    Set the stack usage limit (default is %d)\n"
 
 203                 , (long)suggested_bufsize, _ASN_DEFAULT_STACK_MAX);
 
 211                 fprintf(stderr, "%s: No input files specified. "
 
 212                                 "Try '-h' for more information\n",
 
 217         setvbuf(stdout, 0, _IOLBF, 0);
 
 219         for(num = 0; num < number_of_iterations; num++) {
 
 222            * Process all files in turn.
 
 224           for(ac_i = 0; ac_i < ac; ac_i++) {
 
 226             void *structure;    /* Decoded structure */
 
 227             FILE *file = argument_to_file(av, ac_i);
 
 228             char *name = argument_to_name(av, ac_i);
 
 231             for(first_pdu = 1; first_pdu || !opt_onepdu; first_pdu = 0) {
 
 233                  * Decode the encoded structure from file.
 
 235                 structure = data_decode_from_file(pduType,
 
 236                                 file, name, suggested_bufsize, first_pdu);
 
 239                                 /* Error message is already printed */
 
 247                 /* Check ASN.1 constraints */
 
 250                         size_t errlen = sizeof(errbuf);
 
 251                         if(asn_check_constraints(pduType, structure,
 
 253                                 fprintf(stderr, "%s: ASN.1 constraint "
 
 254                                         "check failed: %s\n", name, errbuf);
 
 261                         fprintf(stderr, "%s: decoded successfully\n", name);
 
 263                 case OUT_TEXT:  /* -otext */
 
 264                         asn_fprint(stdout, pduType, structure);
 
 266                 case OUT_XER:   /* -oxer */
 
 267                         if(xer_fprint(stdout, pduType, structure)) {
 
 269                                         "%s: Cannot convert %s into XML\n",
 
 270                                         name, pduType->name);
 
 271                                 exit(EX_UNAVAILABLE);
 
 275                         erv = der_encode(pduType, structure, write_out, stdout);
 
 276                         if(erv.encoded < 0) {
 
 278                                         "%s: Cannot convert %s into DER\n",
 
 279                                         name, pduType->name);
 
 280                                 exit(EX_UNAVAILABLE);
 
 282                         DEBUG("Encoded in %ld bytes of DER", (long)erv.encoded);
 
 285                         erv = uper_encode(pduType, structure, write_out, stdout);
 
 286                         if(erv.encoded < 0) {
 
 288                                 "%s: Cannot convert %s into Unaligned PER\n",
 
 289                                         name, pduType->name);
 
 290                                 exit(EX_UNAVAILABLE);
 
 292                         DEBUG("Encoded in %ld bits of UPER", (long)erv.encoded);
 
 296                 ASN_STRUCT_FREE(*pduType, structure);
 
 299             if(file && file != stdin)
 
 307 static struct dynamic_buffer {
 
 308         uint8_t *data;          /* Pointer to the data bytes */
 
 309         size_t offset;          /* Offset from the start */
 
 310         size_t length;          /* Length of meaningful contents */
 
 311         size_t unbits;          /* Unused bits in the last byte */
 
 312         size_t allocated;       /* Allocated memory for data */
 
 313         int    nreallocs;       /* Number of data reallocations */
 
 314         off_t  bytes_shifted;   /* Number of bytes ever shifted */
 
 319         uint8_t *p = DynamicBuffer.data + DynamicBuffer.offset;
 
 320         uint8_t *e = p + DynamicBuffer.length - (DynamicBuffer.unbits ? 1 : 0);
 
 321         if(!opt_debug) return;
 
 322         DEBUG("Buffer: { d=%p, o=%ld, l=%ld, u=%ld, a=%ld, s=%ld }",
 
 324                 (long)DynamicBuffer.offset,
 
 325                 (long)DynamicBuffer.length,
 
 326                 (long)DynamicBuffer.unbits,
 
 327                 (long)DynamicBuffer.allocated,
 
 328                 (long)DynamicBuffer.bytes_shifted);
 
 330                 fprintf(stderr, " %c%c%c%c%c%c%c%c",
 
 331                         ((*p >> 7) & 1) ? '1' : '0',
 
 332                         ((*p >> 6) & 1) ? '1' : '0',
 
 333                         ((*p >> 5) & 1) ? '1' : '0',
 
 334                         ((*p >> 4) & 1) ? '1' : '0',
 
 335                         ((*p >> 3) & 1) ? '1' : '0',
 
 336                         ((*p >> 2) & 1) ? '1' : '0',
 
 337                         ((*p >> 1) & 1) ? '1' : '0',
 
 338                         ((*p >> 0) & 1) ? '1' : '0');
 
 340         if(DynamicBuffer.unbits) {
 
 342                 fprintf(stderr, " ");
 
 343                 for(shift = 7; shift >= DynamicBuffer.unbits; shift--)
 
 344                         fprintf(stderr, "%c", ((*p >> shift) & 1) ? '1' : '0');
 
 345                 fprintf(stderr, " %d:%d\n",
 
 346                         DynamicBuffer.length - 1, 8 - DynamicBuffer.unbits);
 
 348                 fprintf(stderr, " %d\n", DynamicBuffer.length);
 
 353  * Move the buffer content left N bits, possibly joining it with
 
 354  * preceeding content.
 
 357 buffer_shift_left(size_t offset, int bits) {
 
 358         uint8_t *ptr = DynamicBuffer.data + DynamicBuffer.offset + offset;
 
 359         uint8_t *end = DynamicBuffer.data + DynamicBuffer.offset
 
 360                         + DynamicBuffer.length - 1;
 
 364         DEBUG("Shifting left %d bits off %ld (o=%ld, u=%ld, l=%ld)",
 
 366                 (long)DynamicBuffer.offset,
 
 367                 (long)DynamicBuffer.unbits,
 
 368                 (long)DynamicBuffer.length);
 
 372                 right = ptr[0] >> (8 - bits);
 
 374                 DEBUG("oleft: %c%c%c%c%c%c%c%c",
 
 375                         ((ptr[-1] >> 7) & 1) ? '1' : '0',
 
 376                         ((ptr[-1] >> 6) & 1) ? '1' : '0',
 
 377                         ((ptr[-1] >> 5) & 1) ? '1' : '0',
 
 378                         ((ptr[-1] >> 4) & 1) ? '1' : '0',
 
 379                         ((ptr[-1] >> 3) & 1) ? '1' : '0',
 
 380                         ((ptr[-1] >> 2) & 1) ? '1' : '0',
 
 381                         ((ptr[-1] >> 1) & 1) ? '1' : '0',
 
 382                         ((ptr[-1] >> 0) & 1) ? '1' : '0');
 
 384                 DEBUG("oriht: %c%c%c%c%c%c%c%c",
 
 385                         ((ptr[0] >> 7) & 1) ? '1' : '0',
 
 386                         ((ptr[0] >> 6) & 1) ? '1' : '0',
 
 387                         ((ptr[0] >> 5) & 1) ? '1' : '0',
 
 388                         ((ptr[0] >> 4) & 1) ? '1' : '0',
 
 389                         ((ptr[0] >> 3) & 1) ? '1' : '0',
 
 390                         ((ptr[0] >> 2) & 1) ? '1' : '0',
 
 391                         ((ptr[0] >> 1) & 1) ? '1' : '0',
 
 392                         ((ptr[0] >> 0) & 1) ? '1' : '0');
 
 394                 DEBUG("mriht: %c%c%c%c%c%c%c%c",
 
 395                         ((right >> 7) & 1) ? '1' : '0',
 
 396                         ((right >> 6) & 1) ? '1' : '0',
 
 397                         ((right >> 5) & 1) ? '1' : '0',
 
 398                         ((right >> 4) & 1) ? '1' : '0',
 
 399                         ((right >> 3) & 1) ? '1' : '0',
 
 400                         ((right >> 2) & 1) ? '1' : '0',
 
 401                         ((right >> 1) & 1) ? '1' : '0',
 
 402                         ((right >> 0) & 1) ? '1' : '0');
 
 404                 ptr[-1] = (ptr[-1] & (0xff << bits)) | right;
 
 406                 DEBUG("after: %c%c%c%c%c%c%c%c",
 
 407                         ((ptr[-1] >> 7) & 1) ? '1' : '0',
 
 408                         ((ptr[-1] >> 6) & 1) ? '1' : '0',
 
 409                         ((ptr[-1] >> 5) & 1) ? '1' : '0',
 
 410                         ((ptr[-1] >> 4) & 1) ? '1' : '0',
 
 411                         ((ptr[-1] >> 3) & 1) ? '1' : '0',
 
 412                         ((ptr[-1] >> 2) & 1) ? '1' : '0',
 
 413                         ((ptr[-1] >> 1) & 1) ? '1' : '0',
 
 414                         ((ptr[-1] >> 0) & 1) ? '1' : '0');
 
 419         for(; ptr < end; ptr++) {
 
 420                 int right = ptr[1] >> (8 - bits);
 
 421                 *ptr = (*ptr << bits) | right;
 
 425         DEBUG("Unbits [%d=>", (int)DynamicBuffer.unbits);
 
 426         if(DynamicBuffer.unbits == 0) {
 
 427                 DynamicBuffer.unbits += bits;
 
 429                 DynamicBuffer.unbits += bits;
 
 430                 if(DynamicBuffer.unbits > 7) {
 
 431                         DynamicBuffer.unbits -= 8;
 
 432                         DynamicBuffer.length--;
 
 433                         DynamicBuffer.bytes_shifted++;
 
 436         DEBUG("Unbits =>%d]", (int)DynamicBuffer.unbits);
 
 440         DEBUG("Shifted. Now (o=%ld, u=%ld l=%ld)",
 
 441                 (long)DynamicBuffer.offset,
 
 442                 (long)DynamicBuffer.unbits,
 
 443                 (long)DynamicBuffer.length);
 
 449  * Ensure that the buffer contains at least this amount of free space.
 
 451 static void add_bytes_to_buffer(const void *data2add, size_t bytes) {
 
 453         if(bytes == 0) return;
 
 455         DEBUG("=> add_bytes(%ld) { o=%ld l=%ld u=%ld, s=%ld }",
 
 457                 (long)DynamicBuffer.offset,
 
 458                 (long)DynamicBuffer.length,
 
 459                 (long)DynamicBuffer.unbits,
 
 460                 (long)DynamicBuffer.allocated);
 
 462         if(DynamicBuffer.allocated
 
 463         >= (DynamicBuffer.offset + DynamicBuffer.length + bytes)) {
 
 464                 DEBUG("\tNo buffer reallocation is necessary");
 
 465         } else if(bytes <= DynamicBuffer.offset) {
 
 466                 DEBUG("\tContents shifted by %ld", DynamicBuffer.offset);
 
 468                 /* Shift the buffer contents */
 
 469                 memmove(DynamicBuffer.data,
 
 470                         DynamicBuffer.data + DynamicBuffer.offset,
 
 471                         DynamicBuffer.length);
 
 472                 DynamicBuffer.bytes_shifted += DynamicBuffer.offset;
 
 473                 DynamicBuffer.offset = 0;
 
 475                 size_t newsize = (DynamicBuffer.allocated << 2) + bytes;
 
 476                 void *p = MALLOC(newsize);
 
 482                         DynamicBuffer.data + DynamicBuffer.offset,
 
 483                         DynamicBuffer.length);
 
 484                 FREEMEM(DynamicBuffer.data);
 
 485                 DynamicBuffer.data = (char *)p;
 
 486                 DynamicBuffer.offset = 0;
 
 487                 DynamicBuffer.allocated = newsize;
 
 488                 DynamicBuffer.nreallocs++;
 
 489                 DEBUG("\tBuffer reallocated to %ld (%d time)",
 
 490                         newsize, DynamicBuffer.nreallocs);
 
 493         memcpy(DynamicBuffer.data
 
 494                 + DynamicBuffer.offset + DynamicBuffer.length,
 
 496         DynamicBuffer.length += bytes;
 
 497         if(DynamicBuffer.unbits) {
 
 498                 int bits = DynamicBuffer.unbits;
 
 499                 DynamicBuffer.unbits = 0;
 
 500                 buffer_shift_left(DynamicBuffer.length - bytes, bits);
 
 503         DEBUG("<= add_bytes(%ld) { o=%ld l=%ld u=%ld, s=%ld }",
 
 505                 (long)DynamicBuffer.offset,
 
 506                 (long)DynamicBuffer.length,
 
 507                 (long)DynamicBuffer.unbits,
 
 508                 (long)DynamicBuffer.allocated);
 
 512 data_decode_from_file(asn_TYPE_descriptor_t *pduType, FILE *file, const char *name, ssize_t suggested_bufsize, int on_first_pdu) {
 
 513         static uint8_t *fbuf;
 
 514         static ssize_t fbuf_size;
 
 515         static asn_codec_ctx_t s_codec_ctx;
 
 516         asn_codec_ctx_t *opt_codec_ctx = 0;
 
 525                 fprintf(stderr, "%s: %s\n", name, strerror(errno));
 
 531                 s_codec_ctx.max_stack_size = opt_stack;
 
 532                 opt_codec_ctx = &s_codec_ctx;
 
 535         DEBUG("Processing %s", name);
 
 537         /* prepare the file buffer */
 
 538         if(fbuf_size != suggested_bufsize) {
 
 539                 fbuf = (char *)REALLOC(fbuf, suggested_bufsize);
 
 544                 fbuf_size = suggested_bufsize;
 
 548                 DynamicBuffer.offset = 0;
 
 549                 DynamicBuffer.length = 0;
 
 550                 DynamicBuffer.unbits = 0;
 
 551                 DynamicBuffer.allocated = 0;
 
 552                 DynamicBuffer.bytes_shifted = 0;
 
 553                 DynamicBuffer.nreallocs = 0;
 
 556         old_offset = DynamicBuffer.bytes_shifted + DynamicBuffer.offset;
 
 558         /* Pretend immediate EOF */
 
 559         rval.code = RC_WMORE;
 
 562         for(tolerate_eof = 1;   /* Allow EOF first time buffer is non-empty */
 
 563             (rd = fread(fbuf, 1, fbuf_size, file))
 
 565                 || (tolerate_eof && DynamicBuffer.length)
 
 567                 int    ecbits = 0;      /* Extra consumed bits in case of PER */
 
 572                  * Copy the data over, or use the original buffer.
 
 574                 if(DynamicBuffer.allocated) {
 
 575                         /* Append new data into the existing dynamic buffer */
 
 576                         add_bytes_to_buffer(fbuf, rd);
 
 577                         i_bptr = DynamicBuffer.data + DynamicBuffer.offset;
 
 578                         i_size = DynamicBuffer.length;
 
 584                 DEBUG("Decoding %ld bytes", (long)i_size);
 
 588                         rval = ber_decode(opt_codec_ctx, pduType,
 
 589                                 (void **)&structure, i_bptr, i_size);
 
 592                         rval = xer_decode(opt_codec_ctx, pduType,
 
 593                                 (void **)&structure, i_bptr, i_size);
 
 596                         rval = uper_decode(opt_codec_ctx, pduType,
 
 597                                 (void **)&structure, i_bptr, i_size, 0,
 
 598                                 DynamicBuffer.unbits);
 
 599                         ecbits = rval.consumed % 8;     /* Extra bits */
 
 600                         rval.consumed /= 8; /* Convert to value in bytes! */
 
 601                         /* Check if input is byte-padded at the end */
 
 602                         if(opt_ippad && ecbits && rval.code == RC_OK) {
 
 608                 DEBUG("decode(%ld) consumed %ld+%db (%ld), code %d",
 
 609                         (long)DynamicBuffer.length,
 
 610                         (long)rval.consumed, ecbits, (long)i_size,
 
 613                 if(DynamicBuffer.allocated == 0) {
 
 615                          * Flush remainder into the intermediate buffer.
 
 617                         if(rval.code != RC_FAIL && rval.consumed < rd) {
 
 618                                 add_bytes_to_buffer(fbuf + rval.consumed,
 
 620                                 buffer_shift_left(0, ecbits);
 
 621                                 DynamicBuffer.bytes_shifted = rval.consumed;
 
 628                  * Adjust position inside the source buffer.
 
 630                 if(DynamicBuffer.allocated) {
 
 631                         DynamicBuffer.offset += rval.consumed;
 
 632                         DynamicBuffer.length -= rval.consumed;
 
 634                         DynamicBuffer.bytes_shifted += rval.consumed;
 
 639                         if(ecbits) buffer_shift_left(0, ecbits);
 
 640                         DEBUG("RC_OK, finishing up with %ld+%d",
 
 641                                 (long)rval.consumed, ecbits);
 
 644                         DEBUG("RC_WMORE, continuing read=%ld, cons=%ld "
 
 645                                 " with %ld..%ld-%ld..%ld",
 
 648                                 (long)DynamicBuffer.offset,
 
 649                                 (long)DynamicBuffer.length,
 
 650                                 (long)DynamicBuffer.unbits,
 
 651                                 (long)DynamicBuffer.allocated);
 
 652                         if(!rd) tolerate_eof--;
 
 660         /* Clean up partially decoded structure */
 
 661         ASN_STRUCT_FREE(*pduType, structure);
 
 663         new_offset = DynamicBuffer.bytes_shifted + DynamicBuffer.offset;
 
 666          * Print a message and return failure only if not EOF,
 
 667          * unless this is our first PDU (empty file).
 
 670         || DynamicBuffer.length
 
 671         || new_offset - old_offset > ((iform == INP_XER)?sizeof("\r\n")-1:0)
 
 673                 DEBUG("ofp %d, no=%ld, oo=%ld, dbl=%ld",
 
 674                         on_first_pdu, (long)new_offset, (long)old_offset,
 
 675                         (long)DynamicBuffer.length);
 
 676                 fprintf(stderr, "%s: "
 
 677                         "Decode failed past byte %ld: %s\n",
 
 678                         name, (long)new_offset,
 
 679                         (rval.code == RC_WMORE)
 
 680                                 ? "Unexpected end of input"
 
 681                                 : "Input processing error");
 
 683 #define ENOMSG EINVAL
 
 686 #define EBADMSG EINVAL
 
 688                 errno = (rval.code == RC_WMORE) ? ENOMSG : EBADMSG;
 
 690                 /* Got EOF after a few successful PDUs */
 
 697 /* Dump the buffer out to the specified FILE */
 
 698 static int write_out(const void *buffer, size_t size, void *key) {
 
 699         FILE *fp = (FILE *)key;
 
 700         return (fwrite(buffer, 1, size, fp) == size) ? 0 : -1;
 
 703 static int argument_is_stdin(char *av[], int idx) {
 
 704         if(strcmp(av[idx], "-")) {
 
 705                 return 0;       /* Certainly not <stdin> */
 
 707                 /* This might be <stdin>, unless `./program -- -` */
 
 708                 if(strcmp(av[-1], "--"))
 
 715 static FILE *argument_to_file(char *av[], int idx) {
 
 716         return argument_is_stdin(av, idx)
 
 718                 : fopen(av[idx], "r");
 
 721 static char *argument_to_name(char *av[], int idx) {
 
 722         return argument_is_stdin(av, idx)