libavutil/base64.c
558b86a5
 /*
  * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com)
  *
  * This file is part of FFmpeg.
  *
  * FFmpeg is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * License as published by the Free Software Foundation; either
  * version 2.1 of the License, or (at your option) any later version.
  *
  * FFmpeg is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with FFmpeg; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 /**
ba87f080
  * @file
bfe3676f
  * @brief Base64 encode/decode
558b86a5
  * @author Ryan Martell <rdm4@martellventures.com> (with lots of Michael)
  */
 
 #include "common.h"
 #include "base64.h"
112bca91
 #include "intreadwrite.h"
965fa6b0
 #include "timer.h"
558b86a5
 
 /* ---------------- private code */
523f676b
 static const uint8_t map2[256] =
558b86a5
 {
523f676b
     0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff,
 
558b86a5
     0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36,
     0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff,
523f676b
     0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x01,
558b86a5
     0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
     0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
     0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b,
     0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
     0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
523f676b
     0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33,
 
                       0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
558b86a5
 };
 
420719e1
 #define BASE64_DEC_STEP(i) do { \
def19c90
     bits = map2[in[i]]; \
     if (bits & 0x80) \
daa47fdd
         goto out ## i; \
     v = i ? (v << 6) + bits : bits; \
420719e1
 } while(0)
def19c90
 
523f676b
 int av_base64_decode(uint8_t *out, const char *in_str, int out_size)
558b86a5
 {
     uint8_t *dst = out;
6af4c981
     uint8_t *end = out + out_size;
523f676b
     // no sign extension
     const uint8_t *in = in_str;
def19c90
     unsigned bits = 0xff;
daa47fdd
     unsigned v;
558b86a5
 
daa47fdd
     while (end - dst > 3) {
420719e1
         BASE64_DEC_STEP(0);
         BASE64_DEC_STEP(1);
         BASE64_DEC_STEP(2);
         BASE64_DEC_STEP(3);
daa47fdd
         // Using AV_WB32 directly confuses compiler
2bb7396b
         v = av_be2ne32(v << 8);
daa47fdd
         AV_WN32(dst, v);
         dst += 3;
def19c90
         in += 4;
     }
     if (end - dst) {
420719e1
         BASE64_DEC_STEP(0);
         BASE64_DEC_STEP(1);
daa47fdd
         BASE64_DEC_STEP(2);
         BASE64_DEC_STEP(3);
         *dst++ = v >> 16;
         if (end - dst)
             *dst++ = v >> 8;
         if (end - dst)
             *dst++ = v;
         in += 4;
def19c90
     }
     while (1) {
420719e1
         BASE64_DEC_STEP(0);
def19c90
         in++;
420719e1
         BASE64_DEC_STEP(0);
def19c90
         in++;
420719e1
         BASE64_DEC_STEP(0);
def19c90
         in++;
420719e1
         BASE64_DEC_STEP(0);
def19c90
         in++;
558b86a5
     }
 
daa47fdd
 out3:
     *dst++ = v >> 10;
     v <<= 2;
 out2:
     *dst++ = v >> 4;
 out1:
 out0:
305180f5
     return bits & 1 ? AVERROR_INVALIDDATA : dst - out;
558b86a5
 }
 
 /*****************************************************************************
bfe3676f
 * b64_encode: Stolen from VLC's http.c.
 * Simplified by Michael.
 * Fixed edge cases and made it work from data (vs. strings) by Ryan.
558b86a5
 *****************************************************************************/
 
5118bd44
 char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size)
558b86a5
 {
     static const char b64[] =
         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
     char *ret, *dst;
     unsigned i_bits = 0;
     int i_shift = 0;
5118bd44
     int bytes_remaining = in_size;
558b86a5
 
5118bd44
     if (in_size >= UINT_MAX / 4 ||
784824a6
         out_size < AV_BASE64_SIZE(in_size))
558b86a5
         return NULL;
52ef50a0
     ret = dst = out;
112bca91
     while (bytes_remaining > 3) {
         i_bits = AV_RB32(in);
         in += 3; bytes_remaining -= 3;
         *dst++ = b64[ i_bits>>26        ];
         *dst++ = b64[(i_bits>>20) & 0x3F];
         *dst++ = b64[(i_bits>>14) & 0x3F];
         *dst++ = b64[(i_bits>>8 ) & 0x3F];
     }
     i_bits = 0;
353fa898
     while (bytes_remaining) {
52ef50a0
         i_bits = (i_bits << 8) + *in++;
353fa898
         bytes_remaining--;
         i_shift += 8;
     }
ea4da948
     while (i_shift > 0) {
d60d718c
         *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f];
ea4da948
         i_shift -= 6;
     }
353fa898
     while ((dst - ret) & 3)
         *dst++ = '=';
558b86a5
     *dst = '\0';
 
     return ret;
 }