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 | } |