15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* vi: set expandtab shiftwidth=4 tabstop=4: */
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * \file
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * <PRE>
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * MODP_B64 - High performance base64 encoder/decoder
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Version 1.3 -- 17-Mar-2006
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * http://modp.com/release/base64
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Copyright &copy; 2005, 2006  Nick Galbreath -- nickg [at] modp [dot] com
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * All rights reserved.
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Redistribution and use in source and binary forms, with or without
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * modification, are permitted provided that the following conditions are
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * met:
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *   Redistributions of source code must retain the above copyright
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *   notice, this list of conditions and the following disclaimer.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *   Redistributions in binary form must reproduce the above copyright
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *   notice, this list of conditions and the following disclaimer in the
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *   documentation and/or other materials provided with the distribution.
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *   Neither the name of the modp.com nor the names of its
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *   contributors may be used to endorse or promote products derived from
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *   this software without specific prior written permission.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This is the standard "new" BSD license:
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * http://www.opensource.org/licenses/bsd-license.php
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * </PRE>
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* public header */
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "modp_b64.h"
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * If you are ripping this out of the library, comment out the next
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * line and uncomment the next lines as approrpiate
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//#include "config.h"
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* if on motoral, sun, ibm; uncomment this */
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* #define WORDS_BIGENDIAN 1 */
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* else for Intel, Amd; uncomment this */
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/* #undef WORDS_BIGENDIAN */
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "modp_b64_data.h"
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define BADCHAR 0x01FFFFFF
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * you can control if we use padding by commenting out this
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * next line.  However, I highly recommend you use padding and not
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * using it should only be for compatability with a 3rd party.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * Also, 'no padding' is not tested!
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define DOPAD 1
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/*
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * if we aren't doing padding
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * set the pad character to NULL
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef DOPAD
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#undef CHARPAD
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CHARPAD '\0'
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)size_t modp_b64_encode(char* dest, const char* str, size_t len)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    size_t i = 0;
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint8_t* p = (uint8_t*) dest;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* unsigned here is important! */
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint8_t t1, t2, t3;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (len > 2) {
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        for (; i < len - 2; i += 3) {
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            t1 = str[i]; t2 = str[i+1]; t3 = str[i+2];
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            *p++ = e0[t1];
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            *p++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)];
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            *p++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)];
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            *p++ = e2[t3];
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (len - i) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 0:
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 1:
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        t1 = str[i];
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p++ = e0[t1];
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p++ = e1[(t1 & 0x03) << 4];
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p++ = CHARPAD;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p++ = CHARPAD;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default: /* case 2 */
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        t1 = str[i]; t2 = str[i+1];
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p++ = e0[t1];
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)];
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p++ = e2[(t2 & 0x0F) << 2];
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p++ = CHARPAD;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *p = '\0';
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return p - (uint8_t*)dest;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef WORDS_BIGENDIAN   /* BIG ENDIAN -- SUN / IBM / MOTOROLA */
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int modp_b64_decode(char* dest, const char* src, int len)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (len == 0) return 0;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef DOPAD
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* if padding is used, then the message must be at least
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       4 chars and be a multiple of 4.
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       there can be at most 2 pad chars at the end */
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (len < 4 || (len % 4 != 0)) return MODP_B64_ERROR;
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (src[len-1] == CHARPAD) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        len--;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (src[len -1] == CHARPAD) {
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            len--;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  /* DOPAD */
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    size_t i;
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int leftover = len % 4;
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    size_t chunks = (leftover == 0) ? len / 4 - 1 : len /4;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint8_t* p = (uint8_t*) dest;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t x = 0;
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t* destInt = (uint32_t*) p;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t* srcInt = (uint32_t*) src;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t y = *srcInt++;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (i = 0; i < chunks; ++i) {
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        x = d0[y >> 24 & 0xff] | d1[y >> 16 & 0xff] |
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            d2[y >> 8 & 0xff] | d3[y & 0xff];
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (x >= BADCHAR)  return MODP_B64_ERROR;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *destInt = x << 8;
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p += 3;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        destInt = (uint32_t*)p;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        y = *srcInt++;
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (leftover) {
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 0:
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        x = d0[y >> 24 & 0xff] | d1[y >> 16 & 0xff] |
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            d2[y >>  8 & 0xff] | d3[y & 0xff];
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (x >= BADCHAR)  return MODP_B64_ERROR;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p++ = ((uint8_t*)&x)[1];
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p++ = ((uint8_t*)&x)[2];
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p = ((uint8_t*)&x)[3];
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return (chunks+1)*3;
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 1:
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        x = d3[y >> 24];
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p =  (uint8_t)x;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 2:
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        x = d3[y >> 24] *64 + d3[(y >> 16) & 0xff];
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p =  (uint8_t)(x >> 4);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default:  /* case 3 */
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        x = (d3[y >> 24] *64 + d3[(y >> 16) & 0xff])*64 +
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            d3[(y >> 8) & 0xff];
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p++ = (uint8_t) (x >> 10);
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p = (uint8_t) (x >> 2);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (x >= BADCHAR) return MODP_B64_ERROR;
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 3*chunks + (6*leftover)/8;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else /* LITTLE  ENDIAN -- INTEL AND FRIENDS */
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)size_t modp_b64_decode(char* dest, const char* src, size_t len)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles){
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (len == 0) return 0;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef DOPAD
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /*
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * if padding is used, then the message must be at least
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * 4 chars and be a multiple of 4
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (len < 4 || (len % 4 != 0)) return MODP_B64_ERROR; /* error */
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /* there can be at most 2 pad chars at the end */
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (src[len-1] == CHARPAD) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        len--;
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (src[len -1] == CHARPAD) {
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            len--;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    size_t i;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int leftover = len % 4;
2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    size_t chunks = (leftover == 0) ? len / 4 - 1 : len /4;
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint8_t* p = (uint8_t*)dest;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t x = 0;
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t* destInt = (uint32_t*) p;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t* srcInt = (uint32_t*) src;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    uint32_t y = *srcInt++;
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (i = 0; i < chunks; ++i) {
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        x = d0[y & 0xff] |
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            d1[(y >> 8) & 0xff] |
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            d2[(y >> 16) & 0xff] |
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            d3[(y >> 24) & 0xff];
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (x >= BADCHAR) return MODP_B64_ERROR;
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *destInt = x ;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        p += 3;
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        destInt = (uint32_t*)p;
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        y = *srcInt++;}
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (leftover) {
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 0:
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        x = d0[y & 0xff] |
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            d1[(y >> 8) & 0xff] |
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            d2[(y >> 16) & 0xff] |
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            d3[(y >> 24) & 0xff];
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (x >= BADCHAR) return MODP_B64_ERROR;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p++ =  ((uint8_t*)(&x))[0];
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p++ =  ((uint8_t*)(&x))[1];
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p =    ((uint8_t*)(&x))[2];
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return (chunks+1)*3;
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 1:  /* with padding this is an impossible case */
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        x = d0[y & 0xff];
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p = *((uint8_t*)(&x)); // i.e. first char/byte in int
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    case 2: // * case 2, 1  output byte */
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        x = d0[y & 0xff] | d1[y >> 8 & 0xff];
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p = *((uint8_t*)(&x)); // i.e. first char
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    default: /* case 3, 2 output bytes */
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        x = d0[y & 0xff] |
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            d1[y >> 8 & 0xff ] |
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            d2[y >> 16 & 0xff];  /* 0x3c */
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p++ =  ((uint8_t*)(&x))[0];
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        *p =  ((uint8_t*)(&x))[1];
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (x >= BADCHAR) return MODP_B64_ERROR;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 3*chunks + (6*leftover)/8;
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  /* if bigendian / else / endif */
266