Annotation of embedaddon/libpdel/io/base64.c, revision 1.1.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>