• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

libavutil/base64.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2006 Ryan Martell. (rdm4@martellventures.com)
00003  *
00004  * This file is part of FFmpeg.
00005  *
00006  * FFmpeg is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * FFmpeg is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with FFmpeg; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 
00027 #include "common.h"
00028 #include "base64.h"
00029 #include "intreadwrite.h"
00030 
00031 /* ---------------- private code */
00032 static const uint8_t map2[256] =
00033 {
00034     0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00035     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00036     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00037     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00038     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00039     0xff, 0xff, 0xff,
00040 
00041     0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36,
00042     0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff,
00043     0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x01,
00044     0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
00045     0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11,
00046     0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
00047     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1a, 0x1b,
00048     0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
00049     0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b,
00050     0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33,
00051 
00052                       0xff, 0xff, 0xff, 0xff, 0xff,
00053     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00054     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00055     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00056     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00057     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00058     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00059     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00060     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00061     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00062     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00063     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00064     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00065     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00066     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00067     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00068     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
00069 };
00070 
00071 #define BASE64_DEC_STEP(i) do { \
00072     bits = map2[in[i]]; \
00073     if (bits & 0x80) \
00074         goto out ## i; \
00075     v = i ? (v << 6) + bits : bits; \
00076 } while(0)
00077 
00078 int av_base64_decode(uint8_t *out, const char *in_str, int out_size)
00079 {
00080     uint8_t *dst = out;
00081     uint8_t *end = out + out_size;
00082     // no sign extension
00083     const uint8_t *in = in_str;
00084     unsigned bits = 0xff;
00085     unsigned v;
00086 
00087     while (end - dst > 3) {
00088         BASE64_DEC_STEP(0);
00089         BASE64_DEC_STEP(1);
00090         BASE64_DEC_STEP(2);
00091         BASE64_DEC_STEP(3);
00092         // Using AV_WB32 directly confuses compiler
00093         v = av_be2ne32(v << 8);
00094         AV_WN32(dst, v);
00095         dst += 3;
00096         in += 4;
00097     }
00098     if (end - dst) {
00099         BASE64_DEC_STEP(0);
00100         BASE64_DEC_STEP(1);
00101         BASE64_DEC_STEP(2);
00102         BASE64_DEC_STEP(3);
00103         *dst++ = v >> 16;
00104         if (end - dst)
00105             *dst++ = v >> 8;
00106         if (end - dst)
00107             *dst++ = v;
00108         in += 4;
00109     }
00110     while (1) {
00111         BASE64_DEC_STEP(0);
00112         in++;
00113         BASE64_DEC_STEP(0);
00114         in++;
00115         BASE64_DEC_STEP(0);
00116         in++;
00117         BASE64_DEC_STEP(0);
00118         in++;
00119     }
00120 
00121 out3:
00122     *dst++ = v >> 10;
00123     v <<= 2;
00124 out2:
00125     *dst++ = v >> 4;
00126 out1:
00127 out0:
00128     return bits & 1 ? -1 : dst - out;
00129 }
00130 
00131 /*****************************************************************************
00132 * b64_encode: Stolen from VLC's http.c.
00133 * Simplified by Michael.
00134 * Fixed edge cases and made it work from data (vs. strings) by Ryan.
00135 *****************************************************************************/
00136 
00137 char *av_base64_encode(char *out, int out_size, const uint8_t *in, int in_size)
00138 {
00139     static const char b64[] =
00140         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00141     char *ret, *dst;
00142     unsigned i_bits = 0;
00143     int i_shift = 0;
00144     int bytes_remaining = in_size;
00145 
00146     if (in_size >= UINT_MAX / 4 ||
00147         out_size < AV_BASE64_SIZE(in_size))
00148         return NULL;
00149     ret = dst = out;
00150     while (bytes_remaining > 3) {
00151         i_bits = AV_RB32(in);
00152         in += 3; bytes_remaining -= 3;
00153         *dst++ = b64[ i_bits>>26        ];
00154         *dst++ = b64[(i_bits>>20) & 0x3F];
00155         *dst++ = b64[(i_bits>>14) & 0x3F];
00156         *dst++ = b64[(i_bits>>8 ) & 0x3F];
00157     }
00158     i_bits = 0;
00159     while (bytes_remaining) {
00160         i_bits = (i_bits << 8) + *in++;
00161         bytes_remaining--;
00162         i_shift += 8;
00163     }
00164     while (i_shift > 0) {
00165         *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f];
00166         i_shift -= 6;
00167     }
00168     while ((dst - ret) & 3)
00169         *dst++ = '=';
00170     *dst = '\0';
00171 
00172     return ret;
00173 }
00174 
00175 #ifdef TEST
00176 // LCOV_EXCL_START
00177 
00178 #undef printf
00179 
00180 #define MAX_DATA_SIZE    1024
00181 #define MAX_ENCODED_SIZE 2048
00182 
00183 static int test_encode_decode(const uint8_t *data, unsigned int data_size,
00184                               const char *encoded_ref)
00185 {
00186     char  encoded[MAX_ENCODED_SIZE];
00187     uint8_t data2[MAX_DATA_SIZE];
00188     int data2_size, max_data2_size = MAX_DATA_SIZE;
00189 
00190     if (!av_base64_encode(encoded, MAX_ENCODED_SIZE, data, data_size)) {
00191         printf("Failed: cannot encode the input data\n");
00192         return 1;
00193     }
00194     if (encoded_ref && strcmp(encoded, encoded_ref)) {
00195         printf("Failed: encoded string differs from reference\n"
00196                "Encoded:\n%s\nReference:\n%s\n", encoded, encoded_ref);
00197         return 1;
00198     }
00199 
00200     if ((data2_size = av_base64_decode(data2, encoded, max_data2_size)) != data_size) {
00201         printf("Failed: cannot decode the encoded string\n"
00202                "Encoded:\n%s\n", encoded);
00203         return 1;
00204     }
00205     if ((data2_size = av_base64_decode(data2, encoded, data_size)) != data_size) {
00206         printf("Failed: cannot decode with minimal buffer\n"
00207                "Encoded:\n%s\n", encoded);
00208         return 1;
00209     }
00210     if (memcmp(data2, data, data_size)) {
00211         printf("Failed: encoded/decoded data differs from original data\n");
00212         return 1;
00213     }
00214     if (av_base64_decode(NULL, encoded, 0) != 0) {
00215         printf("Failed: decode to NULL buffer\n");
00216         return 1;
00217     }
00218     if (strlen(encoded)) {
00219         char *end = strchr(encoded, '=');
00220         if (!end)
00221             end = encoded + strlen(encoded) - 1;
00222         *end = '%';
00223         if (av_base64_decode(NULL, encoded, 0) >= 0) {
00224             printf("Failed: error detection\n");
00225             return 1;
00226         }
00227     }
00228 
00229     printf("Passed!\n");
00230     return 0;
00231 }
00232 
00233 int main(int argc, char ** argv)
00234 {
00235     int i, error_count = 0;
00236     struct test {
00237         const uint8_t *data;
00238         const char *encoded_ref;
00239     } tests[] = {
00240         { "",        ""},
00241         { "1",       "MQ=="},
00242         { "22",      "MjI="},
00243         { "333",     "MzMz"},
00244         { "4444",    "NDQ0NA=="},
00245         { "55555",   "NTU1NTU="},
00246         { "666666",  "NjY2NjY2"},
00247         { "abc:def", "YWJjOmRlZg=="},
00248     };
00249     char in[1024], out[2048];
00250 
00251     printf("Encoding/decoding tests\n");
00252     for (i = 0; i < FF_ARRAY_ELEMS(tests); i++)
00253         error_count += test_encode_decode(tests[i].data, strlen(tests[i].data), tests[i].encoded_ref);
00254 
00255     if (argc>1 && !strcmp(argv[1], "-t")) {
00256         memset(in, 123, sizeof(in));
00257         for(i=0; i<10000; i++){
00258             START_TIMER
00259             av_base64_encode(out, sizeof(out), in, sizeof(in));
00260             STOP_TIMER("encode")
00261         }
00262         for(i=0; i<10000; i++){
00263             START_TIMER
00264             av_base64_decode(in, out, sizeof(in));
00265             STOP_TIMER("decode")
00266         }
00267 
00268         for(i=0; i<10000; i++){
00269             START_TIMER
00270             av_base64_decode(NULL, out, 0);
00271             STOP_TIMER("syntax check")
00272         }
00273     }
00274 
00275     return error_count;
00276 }
00277 
00278 // LCOV_EXCL_STOP
00279 #endif
Generated on Fri Feb 1 2013 14:34:55 for FFmpeg by doxygen 1.7.1