1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * Copyright (c) 2012 Nicolas George
3cabdff1aSopenharmony_ci *
4cabdff1aSopenharmony_ci * This file is part of FFmpeg.
5cabdff1aSopenharmony_ci *
6cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
7cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public License
8cabdff1aSopenharmony_ci * as published by the Free Software Foundation; either
9cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
10cabdff1aSopenharmony_ci *
11cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
12cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
13cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14cabdff1aSopenharmony_ci * GNU Lesser General Public License for more details.
15cabdff1aSopenharmony_ci *
16cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public License
17cabdff1aSopenharmony_ci * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
18cabdff1aSopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19cabdff1aSopenharmony_ci */
20cabdff1aSopenharmony_ci
21cabdff1aSopenharmony_ci#include <string.h>
22cabdff1aSopenharmony_ci#include "libavutil/avstring.h"
23cabdff1aSopenharmony_ci#include "libavutil/avutil.h"
24cabdff1aSopenharmony_ci#include "libavutil/base64.h"
25cabdff1aSopenharmony_ci#include "url.h"
26cabdff1aSopenharmony_ci
27cabdff1aSopenharmony_citypedef struct {
28cabdff1aSopenharmony_ci    const uint8_t *data;
29cabdff1aSopenharmony_ci    void *tofree;
30cabdff1aSopenharmony_ci    size_t size;
31cabdff1aSopenharmony_ci    size_t pos;
32cabdff1aSopenharmony_ci} DataContext;
33cabdff1aSopenharmony_ci
34cabdff1aSopenharmony_cistatic av_cold int data_open(URLContext *h, const char *uri, int flags)
35cabdff1aSopenharmony_ci{
36cabdff1aSopenharmony_ci    DataContext *dc = h->priv_data;
37cabdff1aSopenharmony_ci    const char *data, *opt, *next;
38cabdff1aSopenharmony_ci    char *ddata;
39cabdff1aSopenharmony_ci    int ret, base64 = 0;
40cabdff1aSopenharmony_ci    size_t in_size;
41cabdff1aSopenharmony_ci
42cabdff1aSopenharmony_ci    /* data:content/type[;base64],payload */
43cabdff1aSopenharmony_ci
44cabdff1aSopenharmony_ci    av_strstart(uri, "data:", &uri);
45cabdff1aSopenharmony_ci    data = strchr(uri, ',');
46cabdff1aSopenharmony_ci    if (!data) {
47cabdff1aSopenharmony_ci        av_log(h, AV_LOG_ERROR, "No ',' delimiter in URI\n");
48cabdff1aSopenharmony_ci        return AVERROR(EINVAL);
49cabdff1aSopenharmony_ci    }
50cabdff1aSopenharmony_ci    opt = uri;
51cabdff1aSopenharmony_ci    while (opt < data) {
52cabdff1aSopenharmony_ci        next = av_x_if_null(memchr(opt, ';', data - opt), data);
53cabdff1aSopenharmony_ci        if (opt == uri) {
54cabdff1aSopenharmony_ci            if (!memchr(opt, '/', next - opt)) { /* basic validity check */
55cabdff1aSopenharmony_ci                av_log(h, AV_LOG_ERROR, "Invalid content-type '%.*s'\n",
56cabdff1aSopenharmony_ci                       (int)(next - opt), opt);
57cabdff1aSopenharmony_ci                return AVERROR(EINVAL);
58cabdff1aSopenharmony_ci            }
59cabdff1aSopenharmony_ci            av_log(h, AV_LOG_VERBOSE, "Content-type: %.*s\n",
60cabdff1aSopenharmony_ci                   (int)(next - opt), opt);
61cabdff1aSopenharmony_ci        } else {
62cabdff1aSopenharmony_ci            if (!av_strncasecmp(opt, "base64", next - opt)) {
63cabdff1aSopenharmony_ci                base64 = 1;
64cabdff1aSopenharmony_ci            } else {
65cabdff1aSopenharmony_ci                av_log(h, AV_LOG_VERBOSE, "Ignoring option '%.*s'\n",
66cabdff1aSopenharmony_ci                       (int)(next - opt), opt);
67cabdff1aSopenharmony_ci            }
68cabdff1aSopenharmony_ci        }
69cabdff1aSopenharmony_ci        opt = next + 1;
70cabdff1aSopenharmony_ci    }
71cabdff1aSopenharmony_ci
72cabdff1aSopenharmony_ci    data++;
73cabdff1aSopenharmony_ci    in_size = strlen(data);
74cabdff1aSopenharmony_ci    if (base64) {
75cabdff1aSopenharmony_ci        size_t out_size = 3 * (in_size / 4) + 1;
76cabdff1aSopenharmony_ci
77cabdff1aSopenharmony_ci        if (out_size > INT_MAX || !(ddata = av_malloc(out_size)))
78cabdff1aSopenharmony_ci            return AVERROR(ENOMEM);
79cabdff1aSopenharmony_ci        if ((ret = av_base64_decode(ddata, data, out_size)) < 0) {
80cabdff1aSopenharmony_ci            av_free(ddata);
81cabdff1aSopenharmony_ci            av_log(h, AV_LOG_ERROR, "Invalid base64 in URI\n");
82cabdff1aSopenharmony_ci            return ret;
83cabdff1aSopenharmony_ci        }
84cabdff1aSopenharmony_ci        dc->data = dc->tofree = ddata;
85cabdff1aSopenharmony_ci        dc->size = ret;
86cabdff1aSopenharmony_ci    } else {
87cabdff1aSopenharmony_ci        dc->data = data;
88cabdff1aSopenharmony_ci        dc->size = in_size;
89cabdff1aSopenharmony_ci    }
90cabdff1aSopenharmony_ci    return 0;
91cabdff1aSopenharmony_ci}
92cabdff1aSopenharmony_ci
93cabdff1aSopenharmony_cistatic av_cold int data_close(URLContext *h)
94cabdff1aSopenharmony_ci{
95cabdff1aSopenharmony_ci    DataContext *dc = h->priv_data;
96cabdff1aSopenharmony_ci
97cabdff1aSopenharmony_ci    av_freep(&dc->tofree);
98cabdff1aSopenharmony_ci    return 0;
99cabdff1aSopenharmony_ci}
100cabdff1aSopenharmony_ci
101cabdff1aSopenharmony_cistatic int data_read(URLContext *h, unsigned char *buf, int size)
102cabdff1aSopenharmony_ci{
103cabdff1aSopenharmony_ci    DataContext *dc = h->priv_data;
104cabdff1aSopenharmony_ci
105cabdff1aSopenharmony_ci    if (dc->pos >= dc->size)
106cabdff1aSopenharmony_ci        return AVERROR_EOF;
107cabdff1aSopenharmony_ci    size = FFMIN(size, dc->size - dc->pos);
108cabdff1aSopenharmony_ci    memcpy(buf, dc->data + dc->pos, size);
109cabdff1aSopenharmony_ci    dc->pos += size;
110cabdff1aSopenharmony_ci    return size;
111cabdff1aSopenharmony_ci}
112cabdff1aSopenharmony_ci
113cabdff1aSopenharmony_ciconst URLProtocol ff_data_protocol = {
114cabdff1aSopenharmony_ci    .name           = "data",
115cabdff1aSopenharmony_ci    .url_open       = data_open,
116cabdff1aSopenharmony_ci    .url_close      = data_close,
117cabdff1aSopenharmony_ci    .url_read       = data_read,
118cabdff1aSopenharmony_ci    .priv_data_size = sizeof(DataContext),
119cabdff1aSopenharmony_ci};
120