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>