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