Annotation of embedaddon/libpdel/io/base64.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * Copyright (c) 2001-2002 Packet Design, LLC.
! 4: * All rights reserved.
! 5: *
! 6: * Subject to the following obligations and disclaimer of warranty,
! 7: * use and redistribution of this software, in source or object code
! 8: * forms, with or without modifications are expressly permitted by
! 9: * Packet Design; provided, however, that:
! 10: *
! 11: * (i) Any and all reproductions of the source or object code
! 12: * must include the copyright notice above and the following
! 13: * disclaimer of warranties; and
! 14: * (ii) No rights are granted, in any manner or form, to use
! 15: * Packet Design trademarks, including the mark "PACKET DESIGN"
! 16: * on advertising, endorsements, or otherwise except as such
! 17: * appears in the above copyright notice or in the software.
! 18: *
! 19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
! 20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
! 21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
! 22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
! 23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
! 24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
! 25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
! 26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
! 27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
! 28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
! 29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
! 30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
! 31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
! 32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
! 33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
! 35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
! 36: * THE POSSIBILITY OF SUCH DAMAGE.
! 37: *
! 38: * Author: Archie Cobbs <archie@freebsd.org>
! 39: */
! 40:
! 41: #include <sys/types.h>
! 42: #include <sys/param.h>
! 43:
! 44: #include <assert.h>
! 45: #include <stdio.h>
! 46: #include <stdarg.h>
! 47: #include <string.h>
! 48: #include <errno.h>
! 49: #include <stdlib.h>
! 50: #include <pthread.h>
! 51:
! 52: #include "structs/structs.h"
! 53: #include "structs/type/array.h"
! 54:
! 55: #include "io/base64.h"
! 56: #include "io/filter.h"
! 57: #include "util/typed_mem.h"
! 58:
! 59: /************************************************************************
! 60: BASE 64 ENCODER
! 61: ************************************************************************/
! 62:
! 63: #define ENCODER_MEM_TYPE "base64_encoder"
! 64:
! 65: /* Encoder state */
! 66: struct b64_encoder {
! 67: struct filter filter;
! 68: pthread_mutex_t mutex;
! 69: char *cmap;
! 70: u_char dbuf[3];
! 71: int doff;
! 72: char *obuf;
! 73: int olen;
! 74: int osize;
! 75: u_char done;
! 76: };
! 77:
! 78: /* Internal functions */
! 79: static filter_read_t b64_encoder_read;
! 80: static filter_write_t b64_encoder_write;
! 81: static filter_end_t b64_encoder_end;
! 82: static filter_convert_t b64_encoder_convert;
! 83: static filter_destroy_t b64_encoder_destroy;
! 84:
! 85: static void b64_encoder_encode(struct b64_encoder *enc, char *buf);
! 86: static int b64_encoder_output(struct b64_encoder *enc, const char *buf);
! 87: static int b64_cmap_check(const char *cmap);
! 88:
! 89: /* Public variables */
! 90: const char b64_rfc2045_charset[] =
! 91: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
! 92:
! 93: /*
! 94: * Create a new base-64 encoder with optional custom character set.
! 95: */
! 96: struct filter *
! 97: b64_encoder_create(const char *cmap)
! 98: {
! 99: struct b64_encoder *enc;
! 100:
! 101: /* Default to HTTP charset */
! 102: if (cmap == NULL)
! 103: cmap = b64_rfc2045_charset;
! 104: else if (b64_cmap_check(cmap) == -1)
! 105: return (NULL);
! 106:
! 107: /* Create object */
! 108: if ((enc = MALLOC(ENCODER_MEM_TYPE, sizeof(*enc))) == NULL)
! 109: return (NULL);
! 110: memset(enc, 0, sizeof(*enc));
! 111:
! 112: /* Copy character map */
! 113: if ((enc->cmap = STRDUP(ENCODER_MEM_TYPE, cmap)) == NULL) {
! 114: FREE(ENCODER_MEM_TYPE, enc);
! 115: return (NULL);
! 116: }
! 117:
! 118: /* Create mutex */
! 119: if ((errno = pthread_mutex_init(&enc->mutex, NULL)) != 0) {
! 120: FREE(ENCODER_MEM_TYPE, enc->cmap);
! 121: FREE(ENCODER_MEM_TYPE, enc);
! 122: return (NULL);
! 123: }
! 124:
! 125: /* Set up methods */
! 126: enc->filter.read = b64_encoder_read;
! 127: enc->filter.write = b64_encoder_write;
! 128: enc->filter.end = b64_encoder_end;
! 129: enc->filter.convert = b64_encoder_convert;
! 130: enc->filter.destroy = b64_encoder_destroy;
! 131:
! 132: /* Done */
! 133: return (&enc->filter);
! 134: }
! 135:
! 136: /*
! 137: * Destroy a base 64 encoder.
! 138: */
! 139: void
! 140: b64_encoder_destroy(struct filter **filterp)
! 141: {
! 142: struct b64_encoder **const encp = (struct b64_encoder **)filterp;
! 143: struct b64_encoder *const enc = *encp;
! 144:
! 145: if (enc != NULL) {
! 146: pthread_mutex_destroy(&enc->mutex);
! 147: FREE(ENCODER_MEM_TYPE, enc->cmap);
! 148: FREE(ENCODER_MEM_TYPE, enc->obuf);
! 149: FREE(ENCODER_MEM_TYPE, enc);
! 150: *encp = NULL;
! 151: }
! 152: }
! 153:
! 154: /*
! 155: * Write raw bytes into the encoder.
! 156: */
! 157: int
! 158: b64_encoder_write(struct filter *filter, const void *data, int len)
! 159: {
! 160: struct b64_encoder *const enc = (struct b64_encoder *)filter;
! 161: char buf[4];
! 162: int total;
! 163: int chunk;
! 164: int r;
! 165:
! 166: /* Lock encoder */
! 167: r = pthread_mutex_lock(&enc->mutex);
! 168: assert(r == 0);
! 169:
! 170: /* Check if closed */
! 171: if (enc->done) {
! 172: r = pthread_mutex_unlock(&enc->mutex);
! 173: assert(r == 0);
! 174: errno = EPIPE;
! 175: return (-1);
! 176: }
! 177:
! 178: /* Process bytes */
! 179: for (total = 0; len > 0; total += chunk) {
! 180:
! 181: /* Read in next chunk of raw data */
! 182: chunk = MIN(len, 3 - enc->doff);
! 183: memcpy(enc->dbuf + enc->doff, data, chunk);
! 184: data = (char *)data + chunk;
! 185: len -= chunk;
! 186:
! 187: /* Process data if data buffer full */
! 188: if ((enc->doff += chunk) == 3) {
! 189: b64_encoder_encode(enc, buf);
! 190: if (b64_encoder_output(enc, buf) == -1) {
! 191: total = (total == 0) ? -1 : total;
! 192: break;
! 193: }
! 194: enc->doff = 0;
! 195: }
! 196:
! 197: /* Unlock encoder in case there is a reader */
! 198: r = pthread_mutex_unlock(&enc->mutex);
! 199: assert(r == 0);
! 200: r = pthread_mutex_lock(&enc->mutex);
! 201: assert(r == 0);
! 202: }
! 203:
! 204: /* Done */
! 205: r = pthread_mutex_unlock(&enc->mutex);
! 206: assert(r == 0);
! 207: return (total);
! 208: }
! 209:
! 210: /*
! 211: * Read out encoded data.
! 212: */
! 213: int
! 214: b64_encoder_read(struct filter *filter, void *data, int len)
! 215: {
! 216: struct b64_encoder *const enc = (struct b64_encoder *)filter;
! 217: int r;
! 218:
! 219: r = pthread_mutex_lock(&enc->mutex);
! 220: assert(r == 0);
! 221: len = MIN(len, enc->olen);
! 222: memcpy(data, enc->obuf, len);
! 223: memmove(enc->obuf, enc->obuf + len, enc->olen - len);
! 224: enc->olen -= len;
! 225: r = pthread_mutex_unlock(&enc->mutex);
! 226: assert(r == 0);
! 227: return (len);
! 228: }
! 229:
! 230: /*
! 231: * Mark end of written data.
! 232: */
! 233: int
! 234: b64_encoder_end(struct filter *filter)
! 235: {
! 236: struct b64_encoder *const enc = (struct b64_encoder *)filter;
! 237: char buf[4];
! 238: int r;
! 239:
! 240: /* Lock encoder */
! 241: r = pthread_mutex_lock(&enc->mutex);
! 242: assert(r == 0);
! 243:
! 244: /* Only do this once */
! 245: if (enc->done)
! 246: goto done;
! 247:
! 248: /* Pad with termination character(s) */
! 249: if (enc->doff > 0) {
! 250: memset(enc->dbuf + enc->doff, 0, 3 - enc->doff);
! 251: b64_encoder_encode(enc, buf);
! 252: switch (enc->doff) {
! 253: case 1:
! 254: buf[2] = enc->cmap[64];
! 255: /* fall through */
! 256: case 2:
! 257: buf[3] = enc->cmap[64];
! 258: break;
! 259: }
! 260: if (b64_encoder_output(enc, buf) == -1) {
! 261: r = pthread_mutex_unlock(&enc->mutex);
! 262: assert(r == 0);
! 263: return (-1);
! 264: }
! 265: }
! 266:
! 267: done:
! 268: /* Done */
! 269: enc->done = 1;
! 270: r = pthread_mutex_unlock(&enc->mutex);
! 271: assert(r == 0);
! 272: return (0);
! 273: }
! 274:
! 275: /*
! 276: * Convert byte count to read before and after filter.
! 277: */
! 278: static int
! 279: b64_encoder_convert(struct filter *filter, int num, int forward)
! 280: {
! 281: if (forward)
! 282: return (((num * 4) + 2) / 3);
! 283: else
! 284: return (((num * 3) + 3) / 4);
! 285: }
! 286:
! 287: /*
! 288: * Encode one chunk of data (3 bytes -> 4 characters).
! 289: *
! 290: * This assumes the encoder is locked.
! 291: */
! 292: static void
! 293: b64_encoder_encode(struct b64_encoder *enc, char *buf)
! 294: {
! 295: buf[0] = (enc->dbuf[0] >> 2) & 0x3f;
! 296: buf[0] = enc->cmap[(u_char)buf[0]];
! 297: buf[1] = ((enc->dbuf[0] << 4) & 0x30) | ((enc->dbuf[1] >> 4) & 0x0f);
! 298: buf[1] = enc->cmap[(u_char)buf[1]];
! 299: buf[2] = ((enc->dbuf[1] << 2) & 0x3c) | ((enc->dbuf[2] >> 6) & 0x03);
! 300: buf[2] = enc->cmap[(u_char)buf[2]];
! 301: buf[3] = enc->dbuf[2] & 0x3f;
! 302: buf[3] = enc->cmap[(u_char)buf[3]];
! 303: }
! 304:
! 305: /*
! 306: * Append encoded characters to the output buffer.
! 307: *
! 308: * This assumes the encoder is locked.
! 309: */
! 310: static int
! 311: b64_encoder_output(struct b64_encoder *enc, const char *buf)
! 312: {
! 313: if (enc->olen + 4 > enc->osize) {
! 314: const int new_osize = (enc->olen * 2) + 31;
! 315: char *new_obuf;
! 316:
! 317: if ((new_obuf = REALLOC(ENCODER_MEM_TYPE,
! 318: enc->obuf, new_osize)) == NULL)
! 319: return (-1);
! 320: enc->obuf = new_obuf;
! 321: enc->osize = new_osize;
! 322: }
! 323: memcpy(enc->obuf + enc->olen, buf, 4);
! 324: enc->olen += 4;
! 325: return (0);
! 326: }
! 327:
! 328: /*
! 329: * Sanity check character map.
! 330: */
! 331: static int
! 332: b64_cmap_check(const char *cmap)
! 333: {
! 334: int i;
! 335: int j;
! 336:
! 337: if (strlen(cmap) != 65)
! 338: goto bogus;
! 339: for (i = 0; i < 64; i++) {
! 340: for (j = i + 1; j < 65; j++) {
! 341: if (cmap[i] == cmap[j]) {
! 342: bogus: errno = EINVAL;
! 343: return (-1);
! 344: }
! 345: }
! 346: }
! 347: return (0);
! 348: }
! 349:
! 350: /************************************************************************
! 351: BASE 64 DECODER
! 352: ************************************************************************/
! 353:
! 354: #define DECODER_MEM_TYPE "base64_decoder"
! 355:
! 356: /* Encoder state */
! 357: struct b64_decoder {
! 358: struct filter filter;
! 359: pthread_mutex_t mutex;
! 360: u_char cmap[256];
! 361: u_char cbuf[4];
! 362: int coff;
! 363: u_char *obuf;
! 364: int olen;
! 365: int osize;
! 366: char pad;
! 367: u_char done;
! 368: u_char strict;
! 369: };
! 370:
! 371: /* Internal functions */
! 372: static filter_read_t b64_decoder_read;
! 373: static filter_write_t b64_decoder_write;
! 374: static filter_end_t b64_decoder_end;
! 375: static filter_convert_t b64_decoder_convert;
! 376: static filter_destroy_t b64_decoder_destroy;
! 377:
! 378: static void b64_decoder_decode(struct b64_decoder *dec, u_char *buf);
! 379: static int b64_decoder_output(struct b64_decoder *dec,
! 380: u_char *buf, int len);
! 381:
! 382: /*
! 383: * Create a new base-64 decoder with optional custom character set.
! 384: */
! 385: struct filter *
! 386: b64_decoder_create(const char *cmap, int strict)
! 387: {
! 388: struct b64_decoder *dec;
! 389: const char *s;
! 390: u_char byte;
! 391: int i;
! 392:
! 393: /* Default to HTTP charset */
! 394: if (cmap == NULL)
! 395: cmap = b64_rfc2045_charset;
! 396: else if (b64_cmap_check(cmap) == -1)
! 397: return (NULL);
! 398:
! 399: /* Create object */
! 400: if ((dec = MALLOC(DECODER_MEM_TYPE, sizeof(*dec))) == NULL)
! 401: return (NULL);
! 402: memset(dec, 0, sizeof(*dec));
! 403: dec->strict = !!strict;
! 404: dec->pad = cmap[64];
! 405:
! 406: /* Create mutex */
! 407: if ((errno = pthread_mutex_init(&dec->mutex, NULL)) != 0) {
! 408: FREE(DECODER_MEM_TYPE, dec);
! 409: return (NULL);
! 410: }
! 411:
! 412: /* Create inverse character map */
! 413: memset(dec->cmap, 0xff, sizeof(dec->cmap));
! 414: for (i = 1; i < sizeof(dec->cmap); i++) {
! 415: if ((s = strchr(cmap, (char)i)) != NULL) {
! 416: byte = (u_char)(s - cmap);
! 417: dec->cmap[i] = (byte == 64) ? 0xfe : byte;
! 418: }
! 419: }
! 420:
! 421: /* Set up methods */
! 422: dec->filter.read = b64_decoder_read;
! 423: dec->filter.write = b64_decoder_write;
! 424: dec->filter.end = b64_decoder_end;
! 425: dec->filter.convert = b64_decoder_convert;
! 426: dec->filter.destroy = b64_decoder_destroy;
! 427:
! 428: /* Done */
! 429: return (&dec->filter);
! 430: }
! 431:
! 432: /*
! 433: * Destroy a base 64 decoder.
! 434: */
! 435: void
! 436: b64_decoder_destroy(struct filter **filterp)
! 437: {
! 438: struct b64_decoder **const decp = (struct b64_decoder **)filterp;
! 439: struct b64_decoder *const dec = *decp;
! 440:
! 441: if (dec != NULL) {
! 442: pthread_mutex_destroy(&dec->mutex);
! 443: FREE(DECODER_MEM_TYPE, dec->obuf);
! 444: FREE(DECODER_MEM_TYPE, dec);
! 445: *decp = NULL;
! 446: }
! 447: }
! 448:
! 449: /*
! 450: * Write encoded characters into the decoder.
! 451: */
! 452: int
! 453: b64_decoder_write(struct filter *filter, const void *data, int len)
! 454: {
! 455: struct b64_decoder *const dec = (struct b64_decoder *)filter;
! 456: u_char buf[3];
! 457: int total = 0;
! 458: int r;
! 459:
! 460: /* Lock decoder */
! 461: r = pthread_mutex_lock(&dec->mutex);
! 462: assert(r == 0);
! 463:
! 464: /* Check if closed */
! 465: if (dec->done) {
! 466: r = pthread_mutex_unlock(&dec->mutex);
! 467: assert(r == 0);
! 468: errno = EPIPE;
! 469: return (-1);
! 470: }
! 471:
! 472: /* Process bytes */
! 473: while (total < len) {
! 474:
! 475: /* Fill up input buffer */
! 476: for ( ; dec->coff < 4 && total < len; total++) {
! 477: const u_char val = dec->cmap[((u_char *)data)[total]];
! 478:
! 479: if (val == 0xff) {
! 480: if (dec->strict) {
! 481: errno = EINVAL;
! 482: total = (total == 0) ? -1 : total;
! 483: goto done;
! 484: }
! 485: continue;
! 486: }
! 487: if (val == 0xfe) /* pad char */
! 488: continue;
! 489: assert(val < 64);
! 490: dec->cbuf[dec->coff++] = val;
! 491: }
! 492:
! 493: /* Process characters if character buffer is full */
! 494: if (dec->coff == 4) {
! 495: b64_decoder_decode(dec, buf);
! 496: if (b64_decoder_output(dec, buf, 3) == -1) {
! 497: total = (total == 0) ? -1 : total;
! 498: goto done;
! 499: }
! 500: dec->coff = 0;
! 501: }
! 502:
! 503: /* Take a breather */
! 504: r = pthread_mutex_unlock(&dec->mutex);
! 505: assert(r == 0);
! 506: r = pthread_mutex_lock(&dec->mutex);
! 507: assert(r == 0);
! 508: }
! 509:
! 510: done:
! 511: /* Done */
! 512: r = pthread_mutex_unlock(&dec->mutex);
! 513: assert(r == 0);
! 514: return (total);
! 515: }
! 516:
! 517: /*
! 518: * Read out decoded data.
! 519: */
! 520: int
! 521: b64_decoder_read(struct filter *filter, void *buf, int len)
! 522: {
! 523: struct b64_decoder *const dec = (struct b64_decoder *)filter;
! 524: int r;
! 525:
! 526: r = pthread_mutex_lock(&dec->mutex);
! 527: assert(r == 0);
! 528: len = MIN(len, dec->olen);
! 529: memcpy(buf, dec->obuf, len);
! 530: memmove(dec->obuf, dec->obuf + len, dec->olen - len);
! 531: dec->olen -= len;
! 532: r = pthread_mutex_unlock(&dec->mutex);
! 533: assert(r == 0);
! 534: return (len);
! 535: }
! 536:
! 537: /*
! 538: * Mark end of written data.
! 539: */
! 540: int
! 541: b64_decoder_end(struct filter *filter)
! 542: {
! 543: struct b64_decoder *const dec = (struct b64_decoder *)filter;
! 544: u_char buf[3];
! 545: int len;
! 546: int r;
! 547:
! 548: /* Lock decoder */
! 549: r = pthread_mutex_lock(&dec->mutex);
! 550: assert(r == 0);
! 551:
! 552: /* Only do this once */
! 553: if (dec->done)
! 554: goto done;
! 555:
! 556: /* Spit out any trailing characters */
! 557: if (dec->coff > 0) {
! 558: switch (dec->coff) {
! 559: case 1: /* really not valid */
! 560: case 2:
! 561: len = 1;
! 562: break;
! 563: case 3:
! 564: len = 2;
! 565: break;
! 566: default:
! 567: assert(0);
! 568: len = 0; /* silence gcc warning */
! 569: }
! 570: memset(dec->cbuf + dec->coff, 0, 4 - dec->coff);
! 571: b64_decoder_decode(dec, buf);
! 572: if (b64_decoder_output(dec, buf, len) == -1) {
! 573: r = pthread_mutex_unlock(&dec->mutex);
! 574: assert(r == 0);
! 575: return (-1);
! 576: }
! 577: dec->coff = 0;
! 578: }
! 579:
! 580: done:
! 581: /* Done */
! 582: dec->done = 1;
! 583: r = pthread_mutex_unlock(&dec->mutex);
! 584: assert(r == 0);
! 585: return (0);
! 586: }
! 587:
! 588: /*
! 589: * Convert byte count to read before and after filter.
! 590: */
! 591: static int
! 592: b64_decoder_convert(struct filter *filter, int num, int forward)
! 593: {
! 594: if (forward)
! 595: return (((num * 3) + 3) / 4);
! 596: else
! 597: return (((num * 4) + 2) / 3);
! 598: }
! 599:
! 600: /*
! 601: * Decode one chunk of characters (4 characters -> 3 bytes).
! 602: *
! 603: * This assumes the decoder is locked.
! 604: */
! 605: static void
! 606: b64_decoder_decode(struct b64_decoder *dec, u_char *buf)
! 607: {
! 608: buf[0] = (dec->cbuf[0] << 2) | (dec->cbuf[1] >> 4);
! 609: buf[1] = (dec->cbuf[1] << 4) | (dec->cbuf[2] >> 2);
! 610: buf[2] = (dec->cbuf[2] << 6) | dec->cbuf[3];
! 611: }
! 612:
! 613: /*
! 614: * Append decoded characters to the output buffer.
! 615: *
! 616: * This assumes the decoder is locked.
! 617: */
! 618: static int
! 619: b64_decoder_output(struct b64_decoder *dec, u_char *buf, int len)
! 620: {
! 621: if (dec->olen + len > dec->osize) {
! 622: const int new_osize = (dec->olen * 2) + 31;
! 623: u_char *new_obuf;
! 624:
! 625: if ((new_obuf = REALLOC(DECODER_MEM_TYPE,
! 626: dec->obuf, new_osize)) == NULL)
! 627: return (-1);
! 628: dec->obuf = new_obuf;
! 629: dec->osize = new_osize;
! 630: }
! 631: memcpy(dec->obuf + dec->olen, buf, len);
! 632: dec->olen += len;
! 633: return (0);
! 634: }
! 635:
! 636: #ifdef BASE64_TEST
! 637:
! 638: #include <err.h>
! 639: #include <unistd.h>
! 640:
! 641: int
! 642: main(int ac, char **av)
! 643: {
! 644: struct filter *filter;
! 645: int do_encode = 1; /* default encode */
! 646: int do_input = 1; /* default test input stream */
! 647: int strict = 0;
! 648: char buf[123];
! 649: FILE *input;
! 650: FILE *output;
! 651: int len;
! 652: int ch;
! 653:
! 654: /* Process command line */
! 655: while ((ch = getopt(ac, av, "deiso")) != -1) {
! 656: switch (ch) {
! 657: case 'd': /* decode */
! 658: do_encode = 0;
! 659: break;
! 660: case 'e': /* encode */
! 661: do_encode = 1;
! 662: break;
! 663: case 'i': /* test input stream */
! 664: do_input = 1;
! 665: break;
! 666: case 'o': /* test output stream */
! 667: do_input = 0;
! 668: break;
! 669: case 's': /* enforce strict decoding */
! 670: strict = 1;
! 671: break;
! 672: default:
! 673: usage:
! 674: errx(1, "usage: base64 <-e|-d> <-i|-o> [-s]");
! 675: }
! 676: }
! 677: ac -= optind;
! 678: av += optind;
! 679:
! 680: /* Sanity */
! 681: if (do_input == -1 || do_encode == -1)
! 682: goto usage;
! 683:
! 684: /* Get filter */
! 685: if (do_encode) {
! 686: if ((filter = b64_encoder_create(NULL)) == NULL)
! 687: err(1, "b64_encoder_create");
! 688: } else {
! 689: if ((filter = b64_decoder_create(NULL, strict)) == NULL)
! 690: err(1, "b64_decoder_create");
! 691: }
! 692:
! 693: /* Get filter stream */
! 694: if (do_input) {
! 695: if ((output = filter_fopen(filter, 0, stdout, "w")) == NULL)
! 696: err(1, "filter_fopen");
! 697: input = stdin;
! 698: } else {
! 699: if ((input = filter_fopen(filter, 0, stdin, "r")) == NULL)
! 700: err(1, "filter_fopen");
! 701: output = stdout;
! 702: }
! 703:
! 704: /* Convert */
! 705: while ((len = fread(buf, 1, sizeof(buf), input)) != 0)
! 706: fwrite(buf, 1, len, output);
! 707:
! 708: /* Done */
! 709: fclose(output);
! 710: return (0);
! 711: }
! 712:
! 713: #endif /* BASE64_TEST */
! 714:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>