From 558b86a5d03690b359f5a84ba1cd3222055e55fb Mon Sep 17 00:00:00 2001 From: Luca Barbato Date: Wed, 28 Feb 2007 03:40:23 +0000 Subject: [PATCH] Reverting stray commit part II, r8156 had the base64 export patch mixed with the nutdec patch Originally committed as revision 8158 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavformat/http.c | 348 +++++++++++++++++++++++++++++++++++++++++++++ libavutil/Makefile | 27 ++++ libavutil/avutil.h | 137 ++++++++++++++++++ libavutil/base64.c | 231 ++++++++++++++++++++++++++++++ libavutil/base64.h | 33 +++++ 5 files changed, 776 insertions(+) create mode 100644 libavformat/http.c create mode 100644 libavutil/Makefile create mode 100644 libavutil/avutil.h create mode 100644 libavutil/base64.c create mode 100644 libavutil/base64.h diff --git a/libavformat/http.c b/libavformat/http.c new file mode 100644 index 0000000000..1284c31de8 --- /dev/null +++ b/libavformat/http.c @@ -0,0 +1,348 @@ +/* + * HTTP protocol for ffmpeg client + * Copyright (c) 2000, 2001 Fabrice Bellard. + * + * 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 + */ +#include "avformat.h" +#include +#include "network.h" + +#include "base64.h" + +/* XXX: POST protocol is not completly implemented because ffmpeg use + only a subset of it */ + +//#define DEBUG + +/* used for protocol handling */ +#define BUFFER_SIZE 1024 +#define URL_SIZE 4096 +#define MAX_REDIRECTS 8 + +typedef struct { + URLContext *hd; + unsigned char buffer[BUFFER_SIZE], *buf_ptr, *buf_end; + int line_count; + int http_code; + offset_t off, filesize; + char location[URL_SIZE]; +} HTTPContext; + +static int http_connect(URLContext *h, const char *path, const char *hoststr, + const char *auth, int *new_location); +static int http_write(URLContext *h, uint8_t *buf, int size); + + +/* return non zero if error */ +static int http_open_cnx(URLContext *h) +{ + const char *path, *proxy_path; + char hostname[1024], hoststr[1024]; + char auth[1024]; + char path1[1024]; + char buf[1024]; + int port, use_proxy, err, location_changed = 0, redirects = 0; + HTTPContext *s = h->priv_data; + URLContext *hd = NULL; + + proxy_path = getenv("http_proxy"); + use_proxy = (proxy_path != NULL) && !getenv("no_proxy") && + strstart(proxy_path, "http://", NULL); + + /* fill the dest addr */ + redo: + /* needed in any case to build the host string */ + url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port, + path1, sizeof(path1), s->location); + if (port > 0) { + snprintf(hoststr, sizeof(hoststr), "%s:%d", hostname, port); + } else { + pstrcpy(hoststr, sizeof(hoststr), hostname); + } + + if (use_proxy) { + url_split(NULL, 0, auth, sizeof(auth), hostname, sizeof(hostname), &port, + NULL, 0, proxy_path); + path = s->location; + } else { + if (path1[0] == '\0') + path = "/"; + else + path = path1; + } + if (port < 0) + port = 80; + + snprintf(buf, sizeof(buf), "tcp://%s:%d", hostname, port); + err = url_open(&hd, buf, URL_RDWR); + if (err < 0) + goto fail; + + s->hd = hd; + if (http_connect(h, path, hoststr, auth, &location_changed) < 0) + goto fail; + if (s->http_code == 303 && location_changed == 1) { + /* url moved, get next */ + url_close(hd); + if (redirects++ >= MAX_REDIRECTS) + return AVERROR_IO; + location_changed = 0; + goto redo; + } + return 0; + fail: + if (hd) + url_close(hd); + return AVERROR_IO; +} + +static int http_open(URLContext *h, const char *uri, int flags) +{ + HTTPContext *s; + int ret; + + h->is_streamed = 1; + + s = av_malloc(sizeof(HTTPContext)); + if (!s) { + return AVERROR(ENOMEM); + } + h->priv_data = s; + s->filesize = -1; + s->off = 0; + pstrcpy (s->location, URL_SIZE, uri); + + ret = http_open_cnx(h); + if (ret != 0) + av_free (s); + return ret; +} +static int http_getc(HTTPContext *s) +{ + int len; + if (s->buf_ptr >= s->buf_end) { + len = url_read(s->hd, s->buffer, BUFFER_SIZE); + if (len < 0) { + return AVERROR_IO; + } else if (len == 0) { + return -1; + } else { + s->buf_ptr = s->buffer; + s->buf_end = s->buffer + len; + } + } + return *s->buf_ptr++; +} + +static int process_line(URLContext *h, char *line, int line_count, + int *new_location) +{ + HTTPContext *s = h->priv_data; + char *tag, *p; + + /* end of header */ + if (line[0] == '\0') + return 0; + + p = line; + if (line_count == 0) { + while (!isspace(*p) && *p != '\0') + p++; + while (isspace(*p)) + p++; + s->http_code = strtol(p, NULL, 10); +#ifdef DEBUG + printf("http_code=%d\n", s->http_code); +#endif + } else { + while (*p != '\0' && *p != ':') + p++; + if (*p != ':') + return 1; + + *p = '\0'; + tag = line; + p++; + while (isspace(*p)) + p++; + if (!strcmp(tag, "Location")) { + strcpy(s->location, p); + *new_location = 1; + } else if (!strcmp (tag, "Content-Length") && s->filesize == -1) { + s->filesize = atoll(p); + } else if (!strcmp (tag, "Content-Range")) { + /* "bytes $from-$to/$document_size" */ + const char *slash; + if (!strncmp (p, "bytes ", 6)) { + p += 6; + s->off = atoll(p); + if ((slash = strchr(p, '/')) && strlen(slash) > 0) + s->filesize = atoll(slash+1); + } + h->is_streamed = 0; /* we _can_ in fact seek */ + } + } + return 1; +} + +static int http_connect(URLContext *h, const char *path, const char *hoststr, + const char *auth, int *new_location) +{ + HTTPContext *s = h->priv_data; + int post, err, ch; + char line[1024], *q; + char *auth_b64; + offset_t off = s->off; + + + /* send http header */ + post = h->flags & URL_WRONLY; + + auth_b64 = av_base64_encode((uint8_t *)auth, strlen(auth)); + snprintf(s->buffer, sizeof(s->buffer), + "%s %s HTTP/1.1\r\n" + "User-Agent: %s\r\n" + "Accept: */*\r\n" + "Range: bytes=%"PRId64"-\r\n" + "Host: %s\r\n" + "Authorization: Basic %s\r\n" + "\r\n", + post ? "POST" : "GET", + path, + LIBAVFORMAT_IDENT, + s->off, + hoststr, + auth_b64); + + av_freep(&auth_b64); + if (http_write(h, s->buffer, strlen(s->buffer)) < 0) + return AVERROR_IO; + + /* init input buffer */ + s->buf_ptr = s->buffer; + s->buf_end = s->buffer; + s->line_count = 0; + s->off = 0; + if (post) { + sleep(1); + return 0; + } + + /* wait for header */ + q = line; + for(;;) { + ch = http_getc(s); + if (ch < 0) + return AVERROR_IO; + if (ch == '\n') { + /* process line */ + if (q > line && q[-1] == '\r') + q--; + *q = '\0'; +#ifdef DEBUG + printf("header='%s'\n", line); +#endif + err = process_line(h, line, s->line_count, new_location); + if (err < 0) + return err; + if (err == 0) + break; + s->line_count++; + q = line; + } else { + if ((q - line) < sizeof(line) - 1) + *q++ = ch; + } + } + + return (off == s->off) ? 0 : -1; +} + + +static int http_read(URLContext *h, uint8_t *buf, int size) +{ + HTTPContext *s = h->priv_data; + int len; + + /* read bytes from input buffer first */ + len = s->buf_end - s->buf_ptr; + if (len > 0) { + if (len > size) + len = size; + memcpy(buf, s->buf_ptr, len); + s->buf_ptr += len; + } else { + len = url_read(s->hd, buf, size); + } + if (len > 0) + s->off += len; + return len; +} + +/* used only when posting data */ +static int http_write(URLContext *h, uint8_t *buf, int size) +{ + HTTPContext *s = h->priv_data; + return url_write(s->hd, buf, size); +} + +static int http_close(URLContext *h) +{ + HTTPContext *s = h->priv_data; + url_close(s->hd); + av_free(s); + return 0; +} + +static offset_t http_seek(URLContext *h, offset_t off, int whence) +{ + HTTPContext *s = h->priv_data; + URLContext *old_hd = s->hd; + offset_t old_off = s->off; + + if (whence == AVSEEK_SIZE) + return s->filesize; + else if ((s->filesize == -1 && whence == SEEK_END) || h->is_streamed) + return -1; + + /* we save the old context in case the seek fails */ + s->hd = NULL; + if (whence == SEEK_CUR) + off += s->off; + else if (whence == SEEK_END) + off += s->filesize; + s->off = off; + + /* if it fails, continue on old connection */ + if (http_open_cnx(h) < 0) { + s->hd = old_hd; + s->off = old_off; + return -1; + } + url_close(old_hd); + return off; +} + +URLProtocol http_protocol = { + "http", + http_open, + http_read, + http_write, + http_seek, + http_close, +}; diff --git a/libavutil/Makefile b/libavutil/Makefile new file mode 100644 index 0000000000..67d4b0cb38 --- /dev/null +++ b/libavutil/Makefile @@ -0,0 +1,27 @@ +include ../config.mak + +OBJS= mathematics.o \ + rational.o \ + intfloat_readwrite.o \ + crc.o \ + md5.o \ + lls.o \ + adler32.o \ + log.o \ + mem.o \ + fifo.o \ + tree.o \ + lzo.o \ + random.o \ + aes.o \ + base64.o \ + +HEADERS = avutil.h common.h mathematics.h integer.h rational.h \ + intfloat_readwrite.h md5.h adler32.h log.h fifo.h lzo.h \ + random.h + +NAME=avutil +LIBVERSION=$(LAVUVERSION) +LIBMAJOR=$(LAVUMAJOR) + +include ../common.mak diff --git a/libavutil/avutil.h b/libavutil/avutil.h new file mode 100644 index 0000000000..d85755cd8b --- /dev/null +++ b/libavutil/avutil.h @@ -0,0 +1,137 @@ +/* + * copyright (c) 2006 Michael Niedermayer + * + * 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 + */ + +#ifndef AVUTIL_H +#define AVUTIL_H + +/** + * @file avutil.h + * external api header. + */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#define AV_STRINGIFY(s) AV_TOSTRING(s) +#define AV_TOSTRING(s) #s + +#define LIBAVUTIL_VERSION_INT ((49<<16)+(3<<8)+0) +#define LIBAVUTIL_VERSION 49.3.0 +#define LIBAVUTIL_BUILD LIBAVUTIL_VERSION_INT + +#define LIBAVUTIL_IDENT "Lavu" AV_STRINGIFY(LIBAVUTIL_VERSION) + + +#include "common.h" +#include "mathematics.h" +#include "rational.h" +#include "integer.h" +#include "intfloat_readwrite.h" +#include "log.h" + +/** + * Pixel format. Notes: + * + * PIX_FMT_RGB32 is handled in an endian-specific manner. A RGBA + * color is put together as: + * (A << 24) | (R << 16) | (G << 8) | B + * This is stored as BGRA on little endian CPU architectures and ARGB on + * big endian CPUs. + * + * When the pixel format is palettized RGB (PIX_FMT_PAL8), the palettized + * image data is stored in AVFrame.data[0]. The palette is transported in + * AVFrame.data[1] and, is 1024 bytes long (256 4-byte entries) and is + * formatted the same as in PIX_FMT_RGB32 described above (i.e., it is + * also endian-specific). Note also that the individual RGB palette + * components stored in AVFrame.data[1] should be in the range 0..255. + * This is important as many custom PAL8 video codecs that were designed + * to run on the IBM VGA graphics adapter use 6-bit palette components. + */ +enum PixelFormat { + PIX_FMT_NONE= -1, + PIX_FMT_YUV420P, ///< Planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples) + PIX_FMT_YUYV422, ///< Packed YUV 4:2:2, 16bpp, Y0 Cb Y1 Cr + PIX_FMT_RGB24, ///< Packed RGB 8:8:8, 24bpp, RGBRGB... + PIX_FMT_BGR24, ///< Packed RGB 8:8:8, 24bpp, BGRBGR... + PIX_FMT_YUV422P, ///< Planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples) + PIX_FMT_YUV444P, ///< Planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples) + PIX_FMT_RGB32, ///< Packed RGB 8:8:8, 32bpp, (msb)8A 8R 8G 8B(lsb), in cpu endianness + PIX_FMT_YUV410P, ///< Planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples) + PIX_FMT_YUV411P, ///< Planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) + PIX_FMT_RGB565, ///< Packed RGB 5:6:5, 16bpp, (msb) 5R 6G 5B(lsb), in cpu endianness + PIX_FMT_RGB555, ///< Packed RGB 5:5:5, 16bpp, (msb)1A 5R 5G 5B(lsb), in cpu endianness most significant bit to 0 + PIX_FMT_GRAY8, ///< Y , 8bpp + PIX_FMT_MONOWHITE, ///< Y , 1bpp, 1 is white + PIX_FMT_MONOBLACK, ///< Y , 1bpp, 0 is black + PIX_FMT_PAL8, ///< 8 bit with PIX_FMT_RGB32 palette + PIX_FMT_YUVJ420P, ///< Planar YUV 4:2:0, 12bpp, full scale (jpeg) + PIX_FMT_YUVJ422P, ///< Planar YUV 4:2:2, 16bpp, full scale (jpeg) + PIX_FMT_YUVJ444P, ///< Planar YUV 4:4:4, 24bpp, full scale (jpeg) + PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing(xvmc_render.h) + PIX_FMT_XVMC_MPEG2_IDCT, + PIX_FMT_UYVY422, ///< Packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 + PIX_FMT_UYYVYY411, ///< Packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3 + PIX_FMT_BGR32, ///< Packed RGB 8:8:8, 32bpp, (msb)8A 8B 8G 8R(lsb), in cpu endianness + PIX_FMT_BGR565, ///< Packed RGB 5:6:5, 16bpp, (msb) 5B 6G 5R(lsb), in cpu endianness + PIX_FMT_BGR555, ///< Packed RGB 5:5:5, 16bpp, (msb)1A 5B 5G 5R(lsb), in cpu endianness most significant bit to 1 + PIX_FMT_BGR8, ///< Packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb) + PIX_FMT_BGR4, ///< Packed RGB 1:2:1, 4bpp, (msb)1B 2G 1R(lsb) + PIX_FMT_BGR4_BYTE, ///< Packed RGB 1:2:1, 8bpp, (msb)1B 2G 1R(lsb) + PIX_FMT_RGB8, ///< Packed RGB 3:3:2, 8bpp, (msb)2R 3G 3B(lsb) + PIX_FMT_RGB4, ///< Packed RGB 1:2:1, 4bpp, (msb)2R 3G 3B(lsb) + PIX_FMT_RGB4_BYTE, ///< Packed RGB 1:2:1, 8bpp, (msb)2R 3G 3B(lsb) + PIX_FMT_NV12, ///< Planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 for UV + PIX_FMT_NV21, ///< as above, but U and V bytes are swapped + + PIX_FMT_RGB32_1, ///< Packed RGB 8:8:8, 32bpp, (msb)8R 8G 8B 8A(lsb), in cpu endianness + PIX_FMT_BGR32_1, ///< Packed RGB 8:8:8, 32bpp, (msb)8B 8G 8R 8A(lsb), in cpu endianness + + PIX_FMT_GRAY16BE, ///< Y , 16bpp, big-endian + PIX_FMT_GRAY16LE, ///< Y , 16bpp, little-endian + PIX_FMT_NB, ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions +}; + +#ifdef WORDS_BIGENDIAN +#define PIX_FMT_RGBA PIX_FMT_RGB32_1 +#define PIX_FMT_BGRA PIX_FMT_BGR32_1 +#define PIX_FMT_ARGB PIX_FMT_RGB32 +#define PIX_FMT_ABGR PIX_FMT_BGR32 +#define PIX_FMT_GRAY16 PIX_FMT_GRAY16BE +#else +#define PIX_FMT_RGBA PIX_FMT_BGR32 +#define PIX_FMT_BGRA PIX_FMT_RGB32 +#define PIX_FMT_ARGB PIX_FMT_BGR32_1 +#define PIX_FMT_ABGR PIX_FMT_RGB32_1 +#define PIX_FMT_GRAY16 PIX_FMT_GRAY16LE +#endif + +#if LIBAVUTIL_VERSION_INT < (50<<16) +#define PIX_FMT_UYVY411 PIX_FMT_UYYVYY411 +#define PIX_FMT_RGBA32 PIX_FMT_RGB32 +#define PIX_FMT_YUV422 PIX_FMT_YUYV422 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* AVUTIL_H */ diff --git a/libavutil/base64.c b/libavutil/base64.c new file mode 100644 index 0000000000..6279244d3b --- /dev/null +++ b/libavutil/base64.c @@ -0,0 +1,231 @@ +/* + * Base64.c + * 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 + */ + +/** +* @file base64.c + * @brief Base64 Encode/Decode + * @author Ryan Martell (with lots of Michael) + */ + +#include "common.h" +#include "base64.h" + +/* ---------------- private code */ +static uint8_t map2[] = +{ + 0x3e, 0xff, 0xff, 0xff, 0x3f, 0x34, 0x35, 0x36, + 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, + 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, + 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33 +}; + +int av_base64_decode(uint8_t * out, const char *in, int out_length) +{ + int i, v; + uint8_t *dst = out; + + v = 0; + for (i = 0; in[i] && in[i] != '='; i++) { + unsigned int index= in[i]-43; + if (index>=(sizeof(map2)/sizeof(map2[0])) || map2[index] == 0xff) + return -1; + v = (v << 6) + map2[index]; + if (i & 3) { + if (dst - out < out_length) { + *dst++ = v >> (6 - 2 * (i & 3)); + } + } + } + + return (dst - out); +} + +/***************************************************************************** +* b64_encode: stolen from VLC's http.c +* simplified by michael +* fixed edge cases and made it work from data (vs. strings) by ryan. +*****************************************************************************/ + +char *av_base64_encode(uint8_t * src, int len) +{ + static const char b64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + char *ret, *dst; + unsigned i_bits = 0; + int i_shift = 0; + int bytes_remaining = len; + + if (len < UINT_MAX / 4) { + ret = dst = av_malloc(len * 4 / 3 + 12); + } else + return NULL; + + if (len) { // special edge case, what should we really do here? + while (bytes_remaining) { + i_bits = (i_bits << 8) + *src++; + bytes_remaining--; + i_shift += 8; + + do { + *dst++ = b64[(i_bits << 6 >> i_shift) & 0x3f]; + i_shift -= 6; + } while (i_shift > 6 || (bytes_remaining == 0 && i_shift > 0)); + } + while ((dst - ret) & 3) + *dst++ = '='; + } + *dst = '\0'; + + return ret; +} + +// #define TEST_BASE64 + +#ifdef TEST_BASE64 +#include "avutil.h" + +int b64test() +{ + int numerr = 0; + int len; + int numtest = 1; + uint8_t decode[1000]; + struct test { + void *data; + int len; + const char *result; + } *t, tests[] = { + { + "", 0, ""}, { + "1", 1, "MQ=="}, { + "22", 2, "MjI="}, { + "333", 3, "MzMz"}, { + "4444", 4, "NDQ0NA=="}, { + "55555", 5, "NTU1NTU="}, { + "abc:def", 7, "YWJjOmRlZg=="}, { + NULL} + }; + for (t = tests; t->data; t++) { + char *str; + + av_log(NULL, AV_LOG_ERROR, "Encoding %s...\n", (char *) t->data); + str = av_base64_encode(t->data, t->len); + if (str) { + av_log(NULL, AV_LOG_ERROR, "Encoded to %s...\n", str); + if (strcmp(str, t->result) != 0) { + av_log(NULL, AV_LOG_ERROR, "failed test %d: %s != %s\n", + numtest, str, t->result); + numerr++; + } + av_free(str); + } + + av_log(NULL, AV_LOG_ERROR, "Done encoding, about to decode...\n"); + len = av_base64_decode(decode, t->result, sizeof(decode)); + if (len != t->len) { + av_log(NULL, AV_LOG_ERROR, "failed test %d: len %d != %d\n", + numtest, len, t->len); + numerr++; + } else if (memcmp(decode, t->data, t->len) != 0) { + av_log(NULL, AV_LOG_ERROR, "failed test %d: data\n", numtest); + numerr++; + } else { + av_log(NULL, AV_LOG_ERROR, "Decoded to %s\n", + (char *) t->data); + } + numtest++; + } + +#undef srand +#undef rand + + { + int test_count; + srand(123141); // time(NULL)); + for (test_count = 0; test_count < 100; test_count++) { + int size = rand() % 1024; + int ii; + uint8_t *data; + char *encoded_result; + + av_log(NULL, AV_LOG_ERROR, "Test %d: Size %d bytes...", + test_count, size); + data = (uint8_t *) av_malloc(size); + for (ii = 0; ii < size; ii++) { + data[ii] = rand() % 255; + } + + encoded_result = av_base64_encode(data, size); + if (encoded_result) { + int decode_buffer_size = size + 10; // try without 10 as well + uint8_t *decode_buffer = av_malloc(decode_buffer_size); + if (decode_buffer) { + int decoded_size = + av_base64_decode(decode_buffer, encoded_result, + decode_buffer_size); + + if (decoded_size != size) { + av_log(NULL, AV_LOG_ERROR, + "Decoded/Encoded size mismatch (%d != %d)\n", + decoded_size, size); + } else { + if (memcmp(decode_buffer, data, decoded_size) == 0) { + av_log(NULL, AV_LOG_ERROR, "Passed!\n"); + } else { + av_log(NULL, AV_LOG_ERROR, + "Failed (Data differs)!\n"); + } + } + av_free(decode_buffer); + } + + av_free(encoded_result); + } + } + } + + // these are invalid strings, that it currently decodes (which it probably shouldn't?) + { + uint8_t str[32]; + if (av_base64_decode(str, "M=M=", sizeof(str)) != -1) { + av_log(NULL, AV_LOG_ERROR, + "failed test %d: successful decode of `M=M='\n", + numtest++); + numerr++; + } + if (av_base64_decode(str, "MQ===", sizeof(str)) != -1) { + av_log(NULL, AV_LOG_ERROR, + "failed test %d: successful decode of `MQ==='\n", + numtest++); + numerr++; + } + } + + return numerr; +} +#endif + diff --git a/libavutil/base64.h b/libavutil/base64.h new file mode 100644 index 0000000000..5658ee837a --- /dev/null +++ b/libavutil/base64.h @@ -0,0 +1,33 @@ +/* + * Base64.c + * 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 + */ + +/** + * decodes base64 + * param order as strncpy() + */ +int av_base64_decode(uint8_t * out, const char *in, int out_length); + +/** + * encodes base64 + * @param src data, not a string + */ +char *av_base64_encode(uint8_t * src, int len); +