Coverage Report

Created: 2026-06-13 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mpv/stream/stream.c
Line
Count
Source
1
/*
2
 * This file is part of mpv.
3
 *
4
 * mpv is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2.1 of the License, or (at your option) any later version.
8
 *
9
 * mpv is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with mpv.  If not, see <http://www.gnu.org/licenses/>.
16
 */
17
18
#include <stdio.h>
19
#include <stdlib.h>
20
#include <limits.h>
21
22
#include <assert.h>
23
24
#include "osdep/io.h"
25
26
#include "mpv_talloc.h"
27
28
#include "config.h"
29
30
#include "common/common.h"
31
#include "common/global.h"
32
#include "demux/demux.h"
33
#include "misc/bstr.h"
34
#include "misc/thread_tools.h"
35
#include "common/msg.h"
36
#include "options/m_config.h"
37
#include "options/options.h"
38
#include "options/path.h"
39
#include "osdep/timer.h"
40
#include "stream.h"
41
42
#include "options/m_option.h"
43
#include "options/m_config.h"
44
45
extern const stream_info_t stream_info_mpv;
46
extern const stream_info_t stream_info_cdda;
47
extern const stream_info_t stream_info_dvb;
48
extern const stream_info_t stream_info_null;
49
extern const stream_info_t stream_info_memory;
50
extern const stream_info_t stream_info_mf;
51
extern const stream_info_t stream_info_ffmpeg;
52
extern const stream_info_t stream_info_ffmpeg_unsafe;
53
extern const stream_info_t stream_info_avdevice;
54
extern const stream_info_t stream_info_file;
55
extern const stream_info_t stream_info_slice;
56
extern const stream_info_t stream_info_fd;
57
extern const stream_info_t stream_info_ifo_dvdnav;
58
extern const stream_info_t stream_info_dvdnav;
59
extern const stream_info_t stream_info_bdmv_dir;
60
extern const stream_info_t stream_info_bluray;
61
extern const stream_info_t stream_info_edl;
62
extern const stream_info_t stream_info_libarchive;
63
extern const stream_info_t stream_info_cb;
64
extern const stream_info_t stream_info_curl;
65
66
static const stream_info_t *const stream_list[] = {
67
    &stream_info_mpv,
68
#if HAVE_CDDA
69
    &stream_info_cdda,
70
#endif
71
    &stream_info_avdevice,
72
#if HAVE_DVBIN
73
    &stream_info_dvb,
74
#endif
75
#if HAVE_DVDNAV
76
    &stream_info_ifo_dvdnav,
77
    &stream_info_dvdnav,
78
#endif
79
#if HAVE_LIBBLURAY
80
    &stream_info_bdmv_dir,
81
    &stream_info_bluray,
82
#endif
83
#if HAVE_LIBARCHIVE
84
    &stream_info_libarchive,
85
#endif
86
    &stream_info_memory,
87
    &stream_info_null,
88
    &stream_info_mf,
89
    &stream_info_edl,
90
    &stream_info_file,
91
    &stream_info_slice,
92
    &stream_info_fd,
93
    &stream_info_cb,
94
#if HAVE_LIBCURL
95
    &stream_info_curl,
96
#endif
97
    &stream_info_ffmpeg,
98
    &stream_info_ffmpeg_unsafe,
99
};
100
101
// Because of guarantees documented on STREAM_BUFFER_SIZE.
102
// Half the buffer is used as forward buffer, the other for seek-back.
103
#define STREAM_MIN_BUFFER_SIZE (STREAM_BUFFER_SIZE * 2)
104
// Sort of arbitrary; keep *2 of it comfortably within integer limits.
105
// Must be power of 2.
106
#define STREAM_MAX_BUFFER_SIZE (512 * 1024 * 1024)
107
108
struct stream_opts {
109
    int64_t buffer_size;
110
    bool load_unsafe_playlists;
111
};
112
113
#define OPT_BASE_STRUCT struct stream_opts
114
115
const struct m_sub_options stream_conf = {
116
    .opts = (const struct m_option[]){
117
        {"stream-buffer-size", OPT_BYTE_SIZE(buffer_size),
118
            M_RANGE(STREAM_MIN_BUFFER_SIZE, STREAM_MAX_BUFFER_SIZE)},
119
        {"load-unsafe-playlists", OPT_BOOL(load_unsafe_playlists)},
120
        {0}
121
    },
122
    .size = sizeof(struct stream_opts),
123
    .defaults = &(const struct stream_opts){
124
        .buffer_size = 128 * 1024,
125
    },
126
};
127
128
// return -1 if not hex char
129
static int hex2dec(char c)
130
136M
{
131
136M
    if (c >= '0' && c <= '9')
132
7.09M
        return c - '0';
133
129M
    if (c >= 'A' && c <= 'F')
134
16.5M
        return 10 + c - 'A';
135
113M
    if (c >= 'a' && c <= 'f')
136
3.49M
        return 10 + c - 'a';
137
109M
    return -1;
138
113M
}
139
140
// Replace escape sequences in an URL (or a part of an URL)
141
void mp_url_unescape_inplace(char *url)
142
4.33M
{
143
51.8G
    for (int len = strlen(url), i = 0, o = 0; i <= len;) {
144
51.8G
        if ((url[i] != '%') || (i > len - 3)) {  // %NN can't start after len-3
145
51.7G
            url[o++] = url[i++];
146
51.7G
            continue;
147
51.7G
        }
148
149
68.4M
        int msd = hex2dec(url[i + 1]),
150
68.4M
            lsd = hex2dec(url[i + 2]);
151
152
68.4M
        if (msd >= 0 && lsd >= 0) {
153
1.17M
            url[o++] = 16 * msd + lsd;
154
1.17M
            i += 3;
155
67.2M
        } else {
156
67.2M
            url[o++] = url[i++];
157
67.2M
            url[o++] = url[i++];
158
67.2M
            url[o++] = url[i++];
159
67.2M
        }
160
68.4M
    }
161
4.33M
}
162
163
char *mp_url_unescape(void *talloc_ctx, const char *url)
164
11.1k
{
165
11.1k
    char *unescaped = talloc_strdup(talloc_ctx, url);
166
11.1k
    mp_url_unescape_inplace(unescaped);
167
11.1k
    return unescaped;
168
11.1k
}
169
170
static const char hex_digits[] = "0123456789ABCDEF";
171
172
173
static const char url_default_ok[] = "abcdefghijklmnopqrstuvwxyz"
174
                                     "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
175
                                     "0123456789"
176
                                     "-._~";
177
178
// Escape according to http://tools.ietf.org/html/rfc3986#section-2.1
179
// Only unreserved characters are not escaped.
180
// The argument ok (if not NULL) is as follows:
181
//      ok[0] != '~': additional characters that are not escaped
182
//      ok[0] == '~': do not escape anything but these characters
183
//                    (can't override the unreserved characters, which are
184
//                     never escaped)
185
char *mp_url_escape(void *talloc_ctx, const char *url, const char *ok)
186
104
{
187
104
    char *rv = talloc_size(talloc_ctx, strlen(url) * 3 + 1);
188
104
    char *out = rv;
189
104
    bool negate = ok && ok[0] == '~';
190
191
36.4k
    for (char c; (c = *url); url++) {
192
36.3k
        bool as_is = negate ? !strchr(ok + 1, c)
193
36.3k
                            : (strchr(url_default_ok, c) || (ok && strchr(ok, c)));
194
36.3k
        if (as_is) {
195
15.2k
            *out++ = c;
196
21.1k
        } else {
197
21.1k
            unsigned char v = c;
198
21.1k
            *out++ = '%';
199
21.1k
            *out++ = hex_digits[v / 16];
200
21.1k
            *out++ = hex_digits[v % 16];
201
21.1k
        }
202
36.3k
    }
203
204
104
    *out = 0;
205
104
    return rv;
206
104
}
207
208
static const char *match_proto(const char *url, const char *proto)
209
2.13M
{
210
2.13M
    int l = strlen(proto);
211
2.13M
    if (l > 0) {
212
2.04M
        if (strncasecmp(url, proto, l) == 0 && strncmp("://", url + l, 3) == 0)
213
321k
            return url + l + 3;
214
2.04M
    } else if (!mp_is_url(bstr0(url))) {
215
7.72k
        return url; // pure filenames
216
7.72k
    }
217
1.80M
    return NULL;
218
2.13M
}
219
220
// src and new are both STREAM_ORIGIN_* values. This checks whether a stream
221
// with flags "new" can be opened from the "src". On success, return
222
// new origin, on incompatibility return 0.
223
static int check_origin(int src, int new)
224
145k
{
225
145k
    switch (src) {
226
107k
    case STREAM_ORIGIN_DIRECT:
227
108k
    case STREAM_ORIGIN_UNSAFE:
228
        // Allow anything, but constrain it to the new origin.
229
108k
        return new;
230
19.3k
    case STREAM_ORIGIN_FS:
231
        // From unix FS, allow all but unsafe.
232
19.3k
        if (new == STREAM_ORIGIN_FS || new == STREAM_ORIGIN_NET)
233
8.62k
            return new;
234
10.7k
        break;
235
18.2k
    case STREAM_ORIGIN_NET:
236
        // Allow only other network links.
237
18.2k
        if (new == STREAM_ORIGIN_NET)
238
8.98k
            return new;
239
9.22k
        break;
240
145k
    }
241
19.9k
    return 0;
242
145k
}
243
244
// Read len bytes from the start position, and wrap around as needed. Limit the
245
// actually read data to the size of the buffer. Return amount of copied bytes.
246
//  len: max bytes to copy to dst
247
//  pos: index into s->buffer[], e.g. s->buf_start is byte 0
248
//  returns: bytes copied to dst (limited by len and available buffered data)
249
static int ring_copy(struct stream *s, void *dst, int len, int pos)
250
5.41M
{
251
5.41M
    mp_assert(len >= 0);
252
253
5.41M
    if (pos < s->buf_start || pos > s->buf_end)
254
0
        return 0;
255
256
5.41M
    int copied = 0;
257
5.41M
    len = MPMIN(len, s->buf_end - pos);
258
259
5.41M
    if (len && pos <= s->buffer_mask) {
260
4.46M
        int copy = MPMIN(len, s->buffer_mask + 1 - pos);
261
4.46M
        memcpy(dst, &s->buffer[pos], copy);
262
4.46M
        copied += copy;
263
4.46M
        len -= copy;
264
4.46M
        pos += copy;
265
4.46M
    }
266
267
5.41M
    if (len) {
268
9.08k
        memcpy((char *)dst + copied, &s->buffer[pos & s->buffer_mask], len);
269
9.08k
        copied += len;
270
9.08k
    }
271
272
5.41M
    return copied;
273
5.41M
}
274
275
// Resize the current stream buffer. Uses a larger size if needed to keep data.
276
// Does nothing if the size is adequate. Calling this with 0 ensures it uses the
277
// default buffer size if possible.
278
// The caller must check whether enough data was really allocated.
279
//  keep: keep at least [buf_end-keep, buf_end] (used for mp_assert()s only)
280
//  new: new total size of buffer
281
//  returns: false if buffer allocation failed, true if reallocated or size ok
282
static bool stream_resize_buffer(struct stream *s, int keep, int new)
283
2.80M
{
284
2.80M
    mp_assert(keep >= s->buf_end - s->buf_cur);
285
2.80M
    mp_assert(keep <= new);
286
287
2.80M
    new = MPMAX(new, s->requested_buffer_size);
288
2.80M
    new = MPMIN(new, STREAM_MAX_BUFFER_SIZE);
289
2.80M
    new = mp_round_next_power_of_2(new);
290
291
2.80M
    mp_assert(keep <= new); // can't fail (if old buffer size was valid)
292
293
2.80M
    if (new == s->buffer_mask + 1)
294
2.49M
        return true;
295
296
316k
    int old_pos = s->buf_cur - s->buf_start;
297
316k
    int old_used_len = s->buf_end - s->buf_start;
298
316k
    int skip = old_used_len > new ? old_used_len - new : 0;
299
300
316k
    MP_DBG(s, "resize stream to %d bytes, drop %d bytes\n", new, skip);
301
302
316k
    void *nbuf = ta_alloc_size(s, new);
303
316k
    if (!nbuf)
304
0
        return false; // oom; tolerate it, caller needs to check if required
305
306
316k
    int new_len = 0;
307
316k
    if (s->buffer)
308
869
        new_len = ring_copy(s, nbuf, new, s->buf_start + skip);
309
316k
    mp_assert(new_len == old_used_len - skip);
310
316k
    mp_assert(old_pos >= skip); // "keep" too low
311
316k
    mp_assert(old_pos - skip <= new_len);
312
316k
    s->buf_start = 0;
313
316k
    s->buf_cur = old_pos - skip;
314
316k
    s->buf_end = new_len;
315
316
316k
    ta_free(s->buffer);
317
318
316k
    s->buffer = nbuf;
319
316k
    s->buffer_mask = new - 1;
320
321
316k
    return true;
322
316k
}
323
324
static int stream_create_instance(const stream_info_t *sinfo,
325
                                  struct stream_open_args *args,
326
                                  struct stream **ret)
327
1.44M
{
328
1.44M
    const char *url = args->url;
329
1.44M
    int flags = args->flags;
330
331
1.44M
    *ret = NULL;
332
333
1.44M
    const char *path = url;
334
335
1.44M
    if (flags & STREAM_LOCAL_FS_ONLY) {
336
0
        if (!sinfo->local_fs)
337
0
            return STREAM_NO_MATCH;
338
1.44M
    } else {
339
1.44M
        char **get_protocols = sinfo->get_protocols ? sinfo->get_protocols() : NULL;
340
1.44M
        char **protocols = get_protocols ? get_protocols : (char **)sinfo->protocols;
341
342
3.25M
        for (int n = 0; protocols && protocols[n]; n++) {
343
2.13M
            path = match_proto(url, protocols[n]);
344
2.13M
            if (path)
345
329k
                break;
346
2.13M
        }
347
348
1.44M
        talloc_free(get_protocols);
349
350
1.44M
        if (!path)
351
1.08M
            return STREAM_NO_MATCH;
352
1.44M
    }
353
354
365k
    stream_t *s = talloc_zero(NULL, stream_t);
355
365k
    s->global = args->global;
356
365k
    struct stream_opts *opts = mp_get_config_group(s, s->global, &stream_conf);
357
365k
    if (flags & STREAM_SILENT) {
358
172k
        s->log = mp_null_log;
359
193k
    } else {
360
193k
        s->log = mp_log_new(s, s->global->log, sinfo->name);
361
193k
    }
362
365k
    s->info = sinfo;
363
365k
    s->cancel = args->cancel;
364
365k
    s->url = talloc_strdup(s, url);
365
365k
    s->path = talloc_strdup(s, path);
366
365k
    s->mode = flags & (STREAM_READ | STREAM_WRITE);
367
365k
    s->requested_buffer_size = opts->buffer_size;
368
365k
    s->allow_partial_read = flags & STREAM_ALLOW_PARTIAL_READ;
369
370
365k
    if (flags & STREAM_LESS_NOISE)
371
0
        mp_msg_set_max_level(s->log, MSGL_WARN);
372
373
365k
    struct demux_opts *demux_opts = mp_get_config_group(s, s->global, &demux_conf);
374
365k
    s->access_references = demux_opts->access_references;
375
365k
    talloc_free(demux_opts);
376
377
365k
    MP_VERBOSE(s, "Opening %s\n", url);
378
379
365k
    if (strlen(url) > INT_MAX / 8) {
380
0
        MP_ERR(s, "URL too large.\n");
381
0
        talloc_free(s);
382
0
        return STREAM_ERROR;
383
0
    }
384
385
365k
    if ((s->mode & STREAM_WRITE) && !sinfo->can_write) {
386
0
        MP_DBG(s, "No write access implemented.\n");
387
0
        talloc_free(s);
388
0
        return STREAM_NO_MATCH;
389
0
    }
390
391
365k
    s->stream_origin = flags & STREAM_ORIGIN_MASK; // pass through by default
392
365k
    if (opts->load_unsafe_playlists) {
393
2
        s->stream_origin = STREAM_ORIGIN_DIRECT;
394
365k
    } else if (sinfo->stream_origin) {
395
145k
        s->stream_origin = check_origin(s->stream_origin, sinfo->stream_origin);
396
145k
    }
397
398
365k
    if (!s->stream_origin) {
399
19.9k
        talloc_free(s);
400
19.9k
        return STREAM_UNSAFE;
401
19.9k
    }
402
403
346k
    int r = STREAM_UNSUPPORTED;
404
346k
    if (sinfo->open2) {
405
271k
        r = sinfo->open2(s, args);
406
271k
    } else if (!args->special_arg) {
407
74.6k
        r = (sinfo->open)(s);
408
74.6k
    }
409
346k
    if (r != STREAM_OK) {
410
30.0k
        talloc_free(s);
411
30.0k
        return r;
412
30.0k
    }
413
414
315k
    if (!stream_resize_buffer(s, 0, 0)) {
415
0
        free_stream(s);
416
0
        return STREAM_ERROR;
417
0
    }
418
419
315k
    mp_assert(s->seekable == !!s->seek);
420
421
315k
    if (s->mime_type)
422
315k
        MP_VERBOSE(s, "Mime-type: '%s'\n", s->mime_type);
423
424
315k
    MP_DBG(s, "Stream opened successfully.\n");
425
426
315k
    *ret = s;
427
315k
    return STREAM_OK;
428
315k
}
429
430
int stream_create_with_args(struct stream_open_args *args, struct stream **ret)
431
340k
{
432
340k
    mp_assert(args->url);
433
434
340k
    int r = STREAM_NO_MATCH;
435
340k
    *ret = NULL;
436
437
    // Open stream proper
438
340k
    if (args->sinfo) {
439
172k
        r = stream_create_instance(args->sinfo, args, ret);
440
172k
    } else {
441
1.28M
        for (int i = 0; i < MP_ARRAY_SIZE(stream_list); i++) {
442
1.27M
            r = stream_create_instance(stream_list[i], args, ret);
443
1.27M
            if (r == STREAM_OK)
444
143k
                break;
445
1.13M
            if (r == STREAM_NO_MATCH || r == STREAM_UNSUPPORTED)
446
1.09M
                continue;
447
32.4k
            if (r == STREAM_UNSAFE)
448
19.9k
                continue;
449
12.4k
            break;
450
32.4k
        }
451
167k
    }
452
453
340k
    if (!*ret && !(args->flags & STREAM_SILENT) && !mp_cancel_test(args->cancel))
454
24.2k
    {
455
24.2k
        struct mp_log *log = mp_log_new(NULL, args->global->log, "!stream");
456
457
24.2k
        if (r == STREAM_UNSAFE) {
458
86
            mp_err(log, "\nRefusing to load potentially unsafe URL from a playlist.\n"
459
86
                   "Use the --load-unsafe-playlists option to load it anyway.\n\n");
460
24.1k
        } else if (r == STREAM_NO_MATCH || r == STREAM_UNSUPPORTED) {
461
11.6k
            mp_err(log, "No protocol handler found to open URL %s\n", args->url);
462
11.6k
            mp_err(log, "The protocol is either unsupported, or was disabled "
463
11.6k
                        "at compile-time.\n");
464
12.4k
        } else {
465
12.4k
            mp_err(log, "Failed to open %s.\n", args->url);
466
12.4k
        }
467
468
24.2k
        talloc_free(log);
469
24.2k
    }
470
471
340k
    return r;
472
340k
}
473
474
struct stream *stream_create(const char *url, int flags,
475
                             struct mp_cancel *c, struct mpv_global *global)
476
164k
{
477
164k
    struct stream_open_args args = {
478
164k
        .global = global,
479
164k
        .cancel = c,
480
164k
        .flags = flags,
481
164k
        .url = url,
482
164k
    };
483
164k
    struct stream *s;
484
164k
    stream_create_with_args(&args, &s);
485
164k
    return s;
486
164k
}
487
488
stream_t *open_output_stream(const char *filename, struct mpv_global *global)
489
0
{
490
0
    struct stream *s = stream_create(filename, STREAM_ORIGIN_DIRECT | STREAM_WRITE,
491
0
                                     NULL, global);
492
0
    if (s && s->is_directory) {
493
0
        free_stream(s);
494
0
        s = NULL;
495
0
    }
496
0
    return s;
497
0
}
498
499
// Read function bypassing the local stream buffer. This will not write into
500
// s->buffer, but into buf[0..len] instead.
501
// Returns 0 on error or EOF, and length of bytes read on success.
502
// Partial reads are possible, even if EOF is not reached.
503
static int stream_read_unbuffered(stream_t *s, void *buf, int len)
504
2.48M
{
505
2.48M
    mp_assert(len >= 0);
506
2.48M
    if (len <= 0)
507
0
        return 0;
508
509
2.48M
    int res = 0;
510
    // we will retry even if we already reached EOF previously.
511
2.48M
    if (s->fill_buffer && !mp_cancel_test(s->cancel))
512
2.48M
        res = s->fill_buffer(s, buf, len);
513
2.48M
    if (res <= 0) {
514
1.72M
        s->eof = 1;
515
1.72M
        return 0;
516
1.72M
    }
517
763k
    mp_assert(res <= len);
518
    // When reading succeeded we are obviously not at eof.
519
763k
    s->eof = 0;
520
763k
    s->pos += res;
521
763k
    s->total_unbuffered_read_bytes += res;
522
763k
    return res;
523
763k
}
524
525
// Ask for having at most "forward" bytes ready to read in the buffer.
526
// To read everything, you may have to call this in a loop.
527
//  forward: desired amount of bytes in buffer after s->cur_pos
528
//  returns: progress (false on EOF or on OOM or if enough data was available)
529
static bool stream_read_more(struct stream *s, int forward)
530
5.07M
{
531
5.07M
    mp_assert(forward >= 0);
532
533
5.07M
    int forward_avail = s->buf_end - s->buf_cur;
534
5.07M
    if (forward_avail >= forward)
535
2.88M
        return false;
536
537
    // Avoid that many small reads will lead to many low-level read calls.
538
2.19M
    forward = MPMAX(forward, s->requested_buffer_size / 2);
539
2.19M
    mp_assert(forward_avail < forward);
540
541
    // Keep guaranteed seek-back.
542
2.19M
    int buf_old = MPMIN(s->buf_cur - s->buf_start, s->requested_buffer_size / 2);
543
544
    // Never shrink the buffer here. That's stream_drop_buffers()'s job. Otherwise
545
    // data fetched by earlier larger reads (e.g. demuxer probing) would be
546
    // discarded, forcing redundant re-reads on backward seeks.
547
2.19M
    int new_size = MPMAX(buf_old + forward, s->buffer_mask + 1);
548
549
2.19M
    if (!stream_resize_buffer(s, buf_old + forward_avail, new_size))
550
0
        return false;
551
552
2.19M
    int buf_alloc = s->buffer_mask + 1;
553
554
2.19M
    mp_assert(s->buf_start <= s->buf_cur);
555
2.19M
    mp_assert(s->buf_cur <= s->buf_end);
556
2.19M
    mp_assert(s->buf_cur < buf_alloc * 2);
557
2.19M
    mp_assert(s->buf_end < buf_alloc * 2);
558
2.19M
    mp_assert(s->buf_start < buf_alloc);
559
560
    // Note: read as much as possible, even if forward is much smaller. Do
561
    // this because the stream buffer is supposed to set an approx. minimum
562
    // read size on it.
563
2.19M
    int read = buf_alloc - (buf_old + forward_avail); // free buffer past end
564
565
2.19M
    int pos = s->buf_end & s->buffer_mask;
566
2.19M
    read = MPMIN(read, buf_alloc - pos);
567
568
    // Note: if wrap-around happens, we need to make two calls. This may
569
    // affect latency (e.g. waiting for new data on a socket), so do only
570
    // 1 read call always.
571
2.19M
    read = stream_read_unbuffered(s, &s->buffer[pos], read);
572
573
2.19M
    s->buf_end += read;
574
575
    // May have overwritten old data.
576
2.19M
    if (s->buf_end - s->buf_start >= buf_alloc) {
577
9.16k
        mp_assert(s->buf_end >= buf_alloc);
578
579
9.16k
        s->buf_start = s->buf_end - buf_alloc;
580
581
9.16k
        mp_assert(s->buf_start <= s->buf_cur);
582
9.16k
        mp_assert(s->buf_cur <= s->buf_end);
583
584
9.16k
        if (s->buf_start >= buf_alloc) {
585
3
            s->buf_start -= buf_alloc;
586
3
            s->buf_cur -= buf_alloc;
587
3
            s->buf_end -= buf_alloc;
588
3
        }
589
9.16k
    }
590
591
    // Must not have overwritten guaranteed old data.
592
2.19M
    mp_assert(s->buf_cur - s->buf_start >= buf_old);
593
594
2.19M
    if (s->buf_cur < s->buf_end)
595
1.22M
        s->eof = 0;
596
597
2.19M
    return !!read;
598
2.19M
}
599
600
// Read between 1..buf_size bytes of data, return how much data has been read.
601
// Return 0 on EOF, error, or if buf_size was 0.
602
int stream_read_partial(stream_t *s, void *buf, int buf_size)
603
1.79M
{
604
1.79M
    mp_assert(s->buf_cur <= s->buf_end);
605
1.79M
    mp_assert(buf_size >= 0);
606
1.79M
    if (s->buf_cur == s->buf_end && buf_size > 0) {
607
1.16M
        if (buf_size > (s->buffer_mask + 1) / 2) {
608
            // Direct read if the buffer is too small anyway.
609
291k
            stream_drop_buffers(s);
610
291k
            return stream_read_unbuffered(s, buf, buf_size);
611
291k
        }
612
869k
        stream_read_more(s, 1);
613
869k
    }
614
1.50M
    int res = ring_copy(s, buf, buf_size, s->buf_cur);
615
1.50M
    s->buf_cur += res;
616
1.50M
    return res;
617
1.79M
}
618
619
// Slow version of stream_read_char(); called by it if the buffer is empty.
620
int stream_read_char_fallback(stream_t *s)
621
52.9k
{
622
52.9k
    uint8_t c;
623
52.9k
    return stream_read_partial(s, &c, 1) ? c : STREAM_EOF;
624
52.9k
}
625
626
int stream_read(stream_t *s, void *mem, int total)
627
988k
{
628
988k
    int len = total;
629
2.04M
    while (len > 0) {
630
1.08M
        int read = stream_read_partial(s, mem, len);
631
1.08M
        if (read <= 0)
632
26.9k
            break; // EOF
633
1.05M
        mem = (char *)mem + read;
634
1.05M
        len -= read;
635
1.05M
    }
636
988k
    total -= len;
637
988k
    return total;
638
988k
}
639
640
// Read ahead so that at least forward_size bytes are readable ahead. Returns
641
// the actual forward amount available (restricted by EOF or buffer limits).
642
int stream_peek(stream_t *s, int forward_size)
643
3.91M
{
644
4.18M
    while (stream_read_more(s, forward_size)) {}
645
3.91M
    return s->buf_end - s->buf_cur;
646
3.91M
}
647
648
// Like stream_read(), but do not advance the current position. This may resize
649
// the buffer to satisfy the read request.
650
int stream_read_peek(stream_t *s, void *buf, int buf_size)
651
3.91M
{
652
3.91M
    stream_peek(s, buf_size);
653
3.91M
    return ring_copy(s, buf, buf_size, s->buf_cur);
654
3.91M
}
655
656
int stream_write_buffer(stream_t *s, void *buf, int len)
657
0
{
658
0
    if (!s->write_buffer)
659
0
        return -1;
660
0
    int orig_len = len;
661
0
    while (len) {
662
0
        int w = s->write_buffer(s, buf, len);
663
0
        if (w <= 0)
664
0
            return -1;
665
0
        s->pos += w;
666
0
        buf = (char *)buf + w;
667
0
        len -= w;
668
0
    }
669
0
    return orig_len;
670
0
}
671
672
// Drop len bytes form input, possibly reading more until all is skipped. If
673
// EOF or an error was encountered before all could be skipped, return false,
674
// otherwise return true.
675
static bool stream_skip_read(struct stream *s, int64_t len)
676
27.4k
{
677
49.6k
    while (len > 0) {
678
49.6k
        unsigned int left = s->buf_end - s->buf_cur;
679
49.6k
        if (!left) {
680
27.5k
            if (!stream_read_more(s, 1))
681
27.4k
                return false;
682
62
            continue;
683
27.5k
        }
684
22.1k
        unsigned skip = MPMIN(len, left);
685
22.1k
        s->buf_cur += skip;
686
22.1k
        len -= skip;
687
22.1k
    }
688
41
    return true;
689
27.4k
}
690
691
// Drop the internal buffer. Note that this will advance the stream position
692
// (as seen by stream_tell()), because the real stream position is ahead of the
693
// logical stream position by the amount of buffered but not yet read data.
694
void stream_drop_buffers(stream_t *s)
695
297k
{
696
297k
    s->pos = stream_tell(s);
697
297k
    s->buf_start = s->buf_cur = s->buf_end = 0;
698
297k
    s->eof = 0;
699
297k
    stream_resize_buffer(s, 0, 0);
700
297k
}
701
702
// Seek function bypassing the local stream buffer.
703
static bool stream_seek_unbuffered(stream_t *s, int64_t newpos)
704
850k
{
705
850k
    if (newpos != s->pos) {
706
850k
        MP_VERBOSE(s, "stream level seek from %" PRId64 " to %" PRId64 "\n",
707
850k
                   s->pos, newpos);
708
709
850k
        s->total_stream_seeks++;
710
711
850k
        if (newpos > s->pos && !s->seekable) {
712
0
            MP_ERR(s, "Cannot seek forward in this stream\n");
713
0
            return false;
714
0
        }
715
850k
        if (newpos < s->pos && !s->seekable) {
716
0
            MP_ERR(s, "Cannot seek backward in linear streams!\n");
717
0
            return false;
718
0
        }
719
850k
        if (s->seek(s, newpos) <= 0) {
720
845k
            int level = mp_cancel_test(s->cancel) ? MSGL_V : MSGL_ERR;
721
845k
            MP_MSG(s, level, "Seek failed (to %lld, size %lld)\n",
722
845k
                   (long long)newpos, (long long)stream_get_size(s));
723
845k
            return false;
724
845k
        }
725
5.53k
        stream_drop_buffers(s);
726
5.53k
        s->pos = newpos;
727
5.53k
    }
728
5.53k
    return true;
729
850k
}
730
731
bool stream_seek(stream_t *s, int64_t pos)
732
5.21M
{
733
5.21M
    MP_TRACE(s, "seek request from %" PRId64 " to %" PRId64 "\n",
734
5.21M
             stream_tell(s), pos);
735
736
5.21M
    s->eof = 0; // eof should be set only on read; seeking always clears it
737
738
5.21M
    if (pos < 0) {
739
12
        MP_ERR(s, "Invalid seek to negative position %lld!\n", (long long)pos);
740
12
        pos = 0;
741
12
    }
742
743
5.21M
    if (pos <= s->pos) {
744
4.33M
        int64_t x = pos - (s->pos - (int)s->buf_end);
745
4.33M
        if (x >= (int)s->buf_start) {
746
4.33M
            s->buf_cur = x;
747
4.33M
            mp_assert(s->buf_cur >= s->buf_start);
748
4.33M
            mp_assert(s->buf_cur <= s->buf_end);
749
4.33M
            return true;
750
4.33M
        }
751
4.33M
    }
752
753
878k
    if (s->mode == STREAM_WRITE)
754
0
        return s->seekable && s->seek(s, pos);
755
756
    // Skip data instead of performing a seek in some cases.
757
878k
    if (pos >= s->pos &&
758
875k
        ((!s->seekable && s->fast_skip) ||
759
875k
         pos - s->pos <= s->requested_buffer_size))
760
27.4k
    {
761
27.4k
        return stream_skip_read(s, pos - stream_tell(s));
762
27.4k
    }
763
764
850k
    return stream_seek_unbuffered(s, pos);
765
878k
}
766
767
// Like stream_seek(), but strictly prefer skipping data instead of failing, if
768
// it's a forward-seek.
769
bool stream_seek_skip(stream_t *s, int64_t pos)
770
2.21M
{
771
2.21M
    uint64_t cur_pos = stream_tell(s);
772
773
2.21M
    if (cur_pos == pos)
774
436k
        return true;
775
776
1.78M
    return !s->seekable && pos > cur_pos
777
1.78M
        ? stream_skip_read(s, pos - cur_pos)
778
1.78M
        : stream_seek(s, pos);
779
2.21M
}
780
781
int stream_control(stream_t *s, int cmd, void *arg)
782
6.51M
{
783
6.51M
    return s->control ? s->control(s, cmd, arg) : STREAM_UNSUPPORTED;
784
6.51M
}
785
786
// Return the current size of the stream, or a negative value if unknown.
787
int64_t stream_get_size(stream_t *s)
788
1.17M
{
789
1.17M
    return s->get_size ? s->get_size(s) : -1;
790
1.17M
}
791
792
void free_stream(stream_t *s)
793
1.36M
{
794
1.36M
    if (!s)
795
1.05M
        return;
796
797
315k
    if (s->close)
798
68.0k
        s->close(s);
799
315k
    talloc_free(s);
800
315k
}
801
802
static const char *const bom[3] = {"\xEF\xBB\xBF", "\xFF\xFE", "\xFE\xFF"};
803
804
// Return utf16 argument for stream_read_line
805
int stream_skip_bom(struct stream *s)
806
179k
{
807
179k
    char buf[4];
808
179k
    int len = stream_read_peek(s, buf, sizeof(buf));
809
179k
    bstr data = {buf, len};
810
715k
    for (int n = 0; n < 3; n++) {
811
538k
        if (bstr_startswith0(data, bom[n])) {
812
2.77k
            stream_seek_skip(s, stream_tell(s) + strlen(bom[n]));
813
2.77k
            return n;
814
2.77k
        }
815
538k
    }
816
177k
    return -1; // default to 8 bit codepages
817
179k
}
818
819
// Read the rest of the stream into memory (current pos to EOF), and return it.
820
//  talloc_ctx: used as talloc parent for the returned allocation
821
//  max_size: must be set to >=0. If the file is larger than that, it is treated
822
//            as error. This is a minor robustness measure. If the stream is
823
//            created with STREAM_ALLOW_PARTIAL_READ flag, partial result up to
824
//            max_size is returned instead.
825
//  returns: stream contents, or .start/.len set to NULL on error
826
// If the file was empty, but no error happened, .start will be non-NULL and
827
// .len will be 0.
828
// For convenience, the returned buffer is padded with a 0 byte. The padding
829
// is not included in the returned length.
830
struct bstr stream_read_complete(struct stream *s, void *talloc_ctx,
831
                                 int max_size)
832
20.7k
{
833
20.7k
    if (max_size < 0 || max_size > STREAM_MAX_READ_SIZE)
834
0
        abort();
835
20.7k
    if (s->is_directory)
836
0
        return (struct bstr){NULL, 0};
837
838
20.7k
    int bufsize;
839
20.7k
    int total_read = 0;
840
20.7k
    int padding = 1;
841
20.7k
    char *buf = NULL;
842
20.7k
    int64_t size = stream_get_size(s) - stream_tell(s);
843
20.7k
    if (size > max_size && !s->allow_partial_read)
844
94
        return (struct bstr){NULL, 0};
845
20.6k
    if (size > 0)
846
16.0k
        bufsize = size + padding;
847
4.53k
    else
848
4.53k
        bufsize = 1000;
849
20.6k
    if (s->allow_partial_read)
850
0
        bufsize = MPMIN(bufsize, max_size + padding);
851
25.5k
    while (1) {
852
25.5k
        buf = talloc_realloc_size(talloc_ctx, buf, bufsize);
853
25.5k
        int readsize = stream_read(s, buf + total_read, bufsize - total_read);
854
25.5k
        total_read += readsize;
855
25.5k
        if (total_read >= max_size && s->allow_partial_read) {
856
0
            total_read = max_size;
857
0
            break;
858
0
        }
859
25.5k
        if (total_read < bufsize)
860
20.6k
            break;
861
4.98k
        if (bufsize > max_size) {
862
24
            talloc_free(buf);
863
24
            return (struct bstr){NULL, 0};
864
24
        }
865
4.96k
        bufsize = MPMIN(bufsize + (bufsize >> 1), max_size + padding);
866
4.96k
    }
867
20.6k
    buf = talloc_realloc_size(talloc_ctx, buf, total_read + padding);
868
20.6k
    memset(&buf[total_read], 0, padding);
869
20.6k
    return (struct bstr){buf, total_read};
870
20.6k
}
871
872
struct bstr stream_read_file(const char *filename, void *talloc_ctx,
873
                             struct mpv_global *global, int max_size)
874
0
{
875
0
    return stream_read_file2(filename, talloc_ctx, STREAM_READ_FILE_FLAGS_DEFAULT,
876
0
                             global, max_size);
877
0
}
878
879
struct bstr stream_read_file2(const char *filename, void *talloc_ctx,
880
                              int flags, struct mpv_global *global, int max_size)
881
11.6k
{
882
11.6k
    struct bstr res = {0};
883
11.6k
    stream_t *s = stream_create(filename, flags, NULL, global);
884
11.6k
    if (s) {
885
8.76k
        if (s->is_directory)
886
0
            mp_err(s->log, "Failed to open %s (not a file).\n", filename);
887
8.76k
        else
888
8.76k
            res = stream_read_complete(s, talloc_ctx, max_size);
889
8.76k
    }
890
11.6k
    free_stream(s);
891
11.6k
    return res;
892
11.6k
}
893
894
char **stream_get_proto_list(bool safe_only)
895
1.93k
{
896
1.93k
    char **list = NULL;
897
1.93k
    int num = 0;
898
27.1k
    for (int i = 0; i < MP_ARRAY_SIZE(stream_list); i++) {
899
25.1k
        const stream_info_t *stream_info = stream_list[i];
900
25.1k
        if (safe_only && (stream_info->stream_origin & STREAM_ORIGIN_UNSAFE))
901
0
            continue;
902
903
25.1k
        char **get_protocols = stream_info->get_protocols ? stream_info->get_protocols() : NULL;
904
25.1k
        char **protocols = get_protocols ? get_protocols : (char **)stream_info->protocols;
905
906
79.4k
        for (int j = 0; protocols && protocols[j]; j++) {
907
54.2k
            if (*protocols[j] == '\0')
908
1.93k
                continue;
909
910
52.2k
            MP_TARRAY_APPEND(NULL, list, num, talloc_strdup(list, protocols[j]));
911
52.2k
        }
912
913
25.1k
        talloc_free(get_protocols);
914
25.1k
    }
915
1.93k
    MP_TARRAY_APPEND(NULL, list, num, NULL);
916
1.93k
    return list;
917
1.93k
}
918
919
void stream_print_proto_list(struct mp_log *log)
920
1.78k
{
921
1.78k
    int count = 0;
922
923
1.78k
    mp_info(log, "Protocols:\n\n");
924
1.78k
    char **list = stream_get_proto_list(false);
925
49.9k
    for (int i = 0; list[i]; i++) {
926
48.1k
        mp_info(log, " %s://\n", list[i]);
927
48.1k
        count++;
928
48.1k
    }
929
1.78k
    talloc_free(list);
930
1.78k
    mp_info(log, "\nTotal: %d protocols\n", count);
931
1.78k
}
932
933
bool stream_has_proto(const char *proto)
934
0
{
935
0
    for (int i = 0; i < MP_ARRAY_SIZE(stream_list); i++) {
936
0
        const stream_info_t *stream_info = stream_list[i];
937
938
0
        bool match = false;
939
0
        char **get_protocols = stream_info->get_protocols ? stream_info->get_protocols() : NULL;
940
0
        char **protocols = get_protocols ? get_protocols : (char **)stream_info->protocols;
941
942
0
        for (int j = 0; protocols && protocols[j]; j++) {
943
0
            if (strcmp(protocols[j], proto) == 0) {
944
0
                match = true;
945
0
                break;
946
0
            }
947
0
        }
948
949
0
        talloc_free(get_protocols);
950
0
        if (match)
951
0
            return match;
952
0
    }
953
954
0
    return false;
955
0
}