Line | Count | Source |
1 | | /* |
2 | | * native ebml reader for the Matroska demuxer |
3 | | * new parser copyright (c) 2010 Uoti Urpala |
4 | | * copyright (c) 2004 Aurelien Jacobs <aurel@gnuage.org> |
5 | | * based on the one written by Ronald Bultje for gstreamer |
6 | | * |
7 | | * This file is part of mpv. |
8 | | * |
9 | | * mpv is free software; you can redistribute it and/or |
10 | | * modify it under the terms of the GNU Lesser General Public |
11 | | * License as published by the Free Software Foundation; either |
12 | | * version 2.1 of the License, or (at your option) any later version. |
13 | | * |
14 | | * mpv is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | | * GNU Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public |
20 | | * License along with mpv. If not, see <http://www.gnu.org/licenses/>. |
21 | | */ |
22 | | |
23 | | #include <stdlib.h> |
24 | | #include <stdbool.h> |
25 | | #include <inttypes.h> |
26 | | #include <stddef.h> |
27 | | #include <assert.h> |
28 | | |
29 | | #include <libavutil/intfloat.h> |
30 | | #include <libavutil/common.h> |
31 | | #include "mpv_talloc.h" |
32 | | #include "ebml.h" |
33 | | #include "stream/stream.h" |
34 | | #include "common/common.h" |
35 | | #include "common/msg.h" |
36 | | |
37 | | // Whether the id is a known Matroska level 1 element (allowed as element on |
38 | | // global file level, after the level 0 MATROSKA_ID_SEGMENT). |
39 | | // This (intentionally) doesn't include "global" elements. |
40 | | bool ebml_is_mkv_level1_id(uint32_t id) |
41 | 242k | { |
42 | 242k | switch (id) { |
43 | 14.9k | case MATROSKA_ID_SEEKHEAD: |
44 | 38.8k | case MATROSKA_ID_INFO: |
45 | 55.0k | case MATROSKA_ID_CLUSTER: |
46 | 78.8k | case MATROSKA_ID_TRACKS: |
47 | 84.9k | case MATROSKA_ID_CUES: |
48 | 85.7k | case MATROSKA_ID_ATTACHMENTS: |
49 | 87.4k | case MATROSKA_ID_CHAPTERS: |
50 | 96.1k | case MATROSKA_ID_TAGS: |
51 | 96.1k | return true; |
52 | 146k | default: |
53 | 146k | return false; |
54 | 242k | } |
55 | 242k | } |
56 | | |
57 | | /* |
58 | | * Read: the element content data ID. |
59 | | * Return: the ID. |
60 | | */ |
61 | | uint32_t ebml_read_id(stream_t *s) |
62 | 5.24M | { |
63 | 5.24M | int i, len_mask = 0x80; |
64 | 5.24M | uint32_t id; |
65 | | |
66 | 23.2M | for (i = 0, id = stream_read_char(s); i < 4 && !(id & len_mask); i++) |
67 | 17.9M | len_mask >>= 1; |
68 | 5.24M | if (i >= 4) |
69 | 4.27M | return EBML_ID_INVALID; |
70 | 1.84M | while (i--) |
71 | 872k | id = (id << 8) | stream_read_char(s); |
72 | 969k | return id; |
73 | 5.24M | } |
74 | | |
75 | | /* |
76 | | * Read: element content length. |
77 | | */ |
78 | | uint64_t ebml_read_length(stream_t *s) |
79 | 1.18M | { |
80 | 1.18M | int byte = stream_read_char(s); |
81 | 1.18M | if (byte == STREAM_EOF || byte < 1) |
82 | 25.9k | return EBML_UINT_INVALID; |
83 | | |
84 | 1.15M | uint8_t leading_zeros = 7 - mp_log2((uint8_t)byte); |
85 | 1.15M | uint64_t len = (uint8_t)byte & ((1 << (8 - leading_zeros - 1)) - 1); |
86 | 2.13M | for (uint8_t i = 0; i < leading_zeros; ++i) { |
87 | 973k | byte = stream_read_char(s); |
88 | 973k | if (byte == STREAM_EOF) |
89 | 268 | return EBML_UINT_INVALID; |
90 | 973k | len = (len << 8) | (uint8_t)byte; |
91 | 973k | } |
92 | | |
93 | 1.15M | return len; |
94 | 1.15M | } |
95 | | |
96 | | /* |
97 | | * Read a variable length signed int. |
98 | | */ |
99 | | int64_t ebml_read_signed_length(stream_t *s) |
100 | 80.6k | { |
101 | 80.6k | uint64_t unum; |
102 | 80.6k | int l; |
103 | | |
104 | | /* read as unsigned number first */ |
105 | 80.6k | uint64_t offset = stream_tell(s); |
106 | 80.6k | unum = ebml_read_length(s); |
107 | 80.6k | if (unum == EBML_UINT_INVALID) |
108 | 4.33k | return EBML_INT_INVALID; |
109 | 76.3k | l = stream_tell(s) - offset; |
110 | | |
111 | 76.3k | return unum - ((1LL << ((7 * l) - 1)) - 1); |
112 | 80.6k | } |
113 | | |
114 | | /* |
115 | | * Read the next element as an unsigned int. |
116 | | */ |
117 | | uint64_t ebml_read_uint(stream_t *s) |
118 | 39.6k | { |
119 | 39.6k | uint64_t len, value = 0; |
120 | | |
121 | 39.6k | len = ebml_read_length(s); |
122 | 39.6k | if (len == EBML_UINT_INVALID || len > 8) |
123 | 2.66k | return EBML_UINT_INVALID; |
124 | | |
125 | 81.1k | while (len--) |
126 | 44.1k | value = (value << 8) | stream_read_char(s); |
127 | | |
128 | 36.9k | return value; |
129 | 39.6k | } |
130 | | |
131 | | /* |
132 | | * Read the next element as a signed int. |
133 | | */ |
134 | | int64_t ebml_read_int(stream_t *s) |
135 | 27.2k | { |
136 | 27.2k | uint64_t value = 0; |
137 | 27.2k | uint64_t len; |
138 | 27.2k | int l; |
139 | | |
140 | 27.2k | len = ebml_read_length(s); |
141 | 27.2k | if (len == EBML_UINT_INVALID || len > 8) |
142 | 833 | return EBML_INT_INVALID; |
143 | 26.4k | if (!len) |
144 | 452 | return 0; |
145 | | |
146 | 25.9k | len--; |
147 | 25.9k | l = stream_read_char(s); |
148 | 25.9k | if (l & 0x80) |
149 | 22.4k | value = -1; |
150 | 25.9k | value = (value << 8) | l; |
151 | 39.2k | while (len--) |
152 | 13.2k | value = (value << 8) | stream_read_char(s); |
153 | | |
154 | 25.9k | return (int64_t)value; // assume complement of 2 |
155 | 26.4k | } |
156 | | |
157 | | /* |
158 | | * Skip the current element. |
159 | | * end: the end of the parent element or -1 (for robust error handling) |
160 | | */ |
161 | | int ebml_read_skip(struct mp_log *log, int64_t end, stream_t *s) |
162 | 247k | { |
163 | 247k | uint64_t len; |
164 | | |
165 | 247k | int64_t pos = stream_tell(s); |
166 | | |
167 | 247k | len = ebml_read_length(s); |
168 | 247k | if (len == EBML_UINT_INVALID) |
169 | 9.61k | goto invalid; |
170 | | |
171 | 237k | int64_t pos2 = stream_tell(s); |
172 | 237k | if (len >= INT64_MAX - pos2 || (end > 0 && pos2 + len > end)) |
173 | 21.6k | goto invalid; |
174 | | |
175 | 215k | if (!stream_seek_skip(s, pos2 + len)) |
176 | 23.0k | goto invalid; |
177 | | |
178 | 192k | return 0; |
179 | | |
180 | 54.3k | invalid: |
181 | 54.3k | mp_err(log, "Invalid EBML length at position %"PRId64"\n", pos); |
182 | 54.3k | stream_seek_skip(s, pos); |
183 | 54.3k | return 1; |
184 | 215k | } |
185 | | |
186 | | /* |
187 | | * Skip to (probable) next cluster (MATROSKA_ID_CLUSTER) element start position. |
188 | | */ |
189 | | int ebml_resync_cluster(struct mp_log *log, stream_t *s) |
190 | 77.5k | { |
191 | 77.5k | int64_t pos = stream_tell(s); |
192 | 77.5k | uint32_t last_4_bytes = 0; |
193 | 77.5k | stream_read_peek(s, &(char){0}, 1); |
194 | 77.5k | if (!s->eof) { |
195 | 77.5k | mp_err(log, "Corrupt file detected. " |
196 | 77.5k | "Trying to resync starting from position %"PRId64"...\n", pos); |
197 | 77.5k | } |
198 | 76.8M | while (!s->eof) { |
199 | | // Assumes MATROSKA_ID_CLUSTER is 4 bytes, with no 0 bytes. |
200 | 76.8M | if (last_4_bytes == MATROSKA_ID_CLUSTER) { |
201 | 66.8k | mp_err(log, "Cluster found at %"PRId64".\n", pos - 4); |
202 | 66.8k | stream_seek(s, pos - 4); |
203 | 66.8k | return 0; |
204 | 66.8k | } |
205 | 76.7M | last_4_bytes = (last_4_bytes << 8) | stream_read_char(s); |
206 | 76.7M | pos++; |
207 | 76.7M | } |
208 | 10.7k | return -1; |
209 | 77.5k | } |
210 | | |
211 | | |
212 | | |
213 | | #define EVALARGS(F, ...) F(__VA_ARGS__) |
214 | | #define E(str, N, type) const struct ebml_elem_desc ebml_ ## N ## _desc = { str, type }; |
215 | | #define E_SN(str, count, N) const struct ebml_elem_desc ebml_ ## N ## _desc = { str, EBML_TYPE_SUBELEMENTS, sizeof(struct ebml_ ## N), count, (const struct ebml_field_desc[]){ |
216 | | #define E_S(str, count) EVALARGS(E_SN, str, count, N) |
217 | | #define FN(id, name, multiple, N) { id, multiple, offsetof(struct ebml_ ## N, name), offsetof(struct ebml_ ## N, n_ ## name), &ebml_##name##_desc}, |
218 | | #define F(id, name, multiple) EVALARGS(FN, id, name, multiple, N) |
219 | | #include "ebml_defs.inc" |
220 | | #undef EVALARGS |
221 | | #undef SN |
222 | | #undef S |
223 | | #undef FN |
224 | | #undef F |
225 | | |
226 | | // Used to read/write pointers to different struct types |
227 | | struct generic; |
228 | | #define generic_struct struct generic |
229 | | |
230 | | static uint32_t ebml_parse_id(uint8_t *data, size_t data_len, int *length) |
231 | 2.82M | { |
232 | 2.82M | *length = -1; |
233 | 2.82M | uint8_t *end = data + data_len; |
234 | 2.82M | if (data == end) |
235 | 12 | return EBML_ID_INVALID; |
236 | 2.82M | int len = 1; |
237 | 2.82M | uint32_t id = *data++; |
238 | 4.35M | for (int len_mask = 0x80; !(id & len_mask); len_mask >>= 1) { |
239 | 1.53M | len++; |
240 | 1.53M | if (len > 4) |
241 | 6.60k | return EBML_ID_INVALID; |
242 | 1.53M | } |
243 | 2.81M | *length = len; |
244 | 4.32M | while (--len && data < end) |
245 | 1.50M | id = (id << 8) | *data++; |
246 | 2.81M | return id; |
247 | 2.82M | } |
248 | | |
249 | | static uint64_t ebml_parse_length(uint8_t *data, size_t data_len, int *length) |
250 | 2.76M | { |
251 | 2.76M | *length = -1; |
252 | 2.76M | uint8_t *end = data + data_len; |
253 | 2.76M | if (data == end) |
254 | 518 | return -1; |
255 | 2.76M | uint64_t r = *data++; |
256 | 2.76M | int len = 1; |
257 | 2.76M | int len_mask; |
258 | 3.45M | for (len_mask = 0x80; !(r & len_mask); len_mask >>= 1) { |
259 | 691k | len++; |
260 | 691k | if (len > 8) |
261 | 3.66k | return -1; |
262 | 691k | } |
263 | 2.76M | r &= len_mask - 1; |
264 | | |
265 | 2.76M | int num_allones = 0; |
266 | 2.76M | if (r == len_mask - 1) |
267 | 86.1k | num_allones++; |
268 | 3.42M | for (int i = 1; i < len; i++) { |
269 | 660k | if (data == end) |
270 | 1.58k | return -1; |
271 | 659k | if (*data == 255) |
272 | 9.11k | num_allones++; |
273 | 659k | r = (r << 8) | *data++; |
274 | 659k | } |
275 | | // According to Matroska specs this means "unknown length" |
276 | | // Could be supported if there are any actual files using it |
277 | 2.76M | if (num_allones == len) |
278 | 3.37k | return -1; |
279 | 2.75M | *length = len; |
280 | 2.75M | return r; |
281 | 2.76M | } |
282 | | |
283 | | static uint64_t ebml_parse_uint(uint8_t *data, int length) |
284 | 681k | { |
285 | 681k | mp_assert(length >= 0 && length <= 8); |
286 | 681k | uint64_t r = 0; |
287 | 2.12M | while (length--) |
288 | 1.43M | r = (r << 8) + *data++; |
289 | 681k | return r; |
290 | 681k | } |
291 | | |
292 | | static int64_t ebml_parse_sint(uint8_t *data, int length) |
293 | 7.67k | { |
294 | 7.67k | mp_assert(length >= 0 && length <= 8); |
295 | 7.67k | if (!length) |
296 | 1 | return 0; |
297 | 7.67k | uint64_t r = 0; |
298 | 7.67k | if (*data & 0x80) |
299 | 3 | r = -1; |
300 | 69.0k | while (length--) |
301 | 61.3k | r = (r << 8) | *data++; |
302 | 7.67k | return (int64_t)r; // assume complement of 2 |
303 | 7.67k | } |
304 | | |
305 | | static double ebml_parse_float(uint8_t *data, int length) |
306 | 29.1k | { |
307 | 29.1k | mp_assert(length == 0 || length == 4 || length == 8); |
308 | 29.1k | uint64_t i = ebml_parse_uint(data, length); |
309 | 29.1k | if (length == 4) |
310 | 22.9k | return av_int2float(i); |
311 | 6.11k | else |
312 | 6.11k | return av_int2double(i); |
313 | 29.1k | } |
314 | | |
315 | | |
316 | | // target must be initialized to zero |
317 | | static void ebml_parse_element(struct ebml_parse_ctx *ctx, void *target, |
318 | | uint8_t *data, int size, |
319 | | const struct ebml_elem_desc *type, int level) |
320 | 395k | { |
321 | 395k | mp_assert(type->type == EBML_TYPE_SUBELEMENTS); |
322 | 395k | mp_assert(level < 8); |
323 | 395k | MP_TRACE(ctx, "%.*sParsing element %s\n", level, " ", type->name); |
324 | | |
325 | 395k | char *s = target; |
326 | 395k | uint8_t *end = data + size; |
327 | 395k | uint8_t *p = data; |
328 | 395k | int num_elems[MAX_EBML_SUBELEMENTS] = {0}; |
329 | 1.77M | while (p < end) { |
330 | 1.39M | uint8_t *startp = p; |
331 | 1.39M | int len; |
332 | 1.39M | uint32_t id = ebml_parse_id(p, end - p, &len); |
333 | 1.39M | if (len > end - p) |
334 | 734 | goto past_end_error; |
335 | 1.39M | if (len < 0) { |
336 | 6.53k | MP_ERR(ctx, "Error parsing subelement id\n"); |
337 | 6.53k | goto other_error; |
338 | 6.53k | } |
339 | 1.39M | p += len; |
340 | 1.39M | uint64_t length = ebml_parse_length(p, end - p, &len); |
341 | 1.39M | if (len > end - p) |
342 | 0 | goto past_end_error; |
343 | 1.39M | if (len < 0) { |
344 | 9.13k | MP_ERR(ctx, "Error parsing subelement length\n"); |
345 | 9.13k | goto other_error; |
346 | 9.13k | } |
347 | 1.38M | p += len; |
348 | | |
349 | 1.38M | int field_idx = -1; |
350 | 6.32M | for (int i = 0; i < type->field_count; i++) |
351 | 6.17M | if (type->fields[i].id == id) { |
352 | 1.22M | field_idx = i; |
353 | 1.22M | num_elems[i]++; |
354 | 1.22M | if (num_elems[i] >= 0x70000000) { |
355 | 0 | MP_ERR(ctx, "Too many EBML subelements.\n"); |
356 | 0 | goto other_error; |
357 | 0 | } |
358 | 1.22M | break; |
359 | 1.22M | } |
360 | | |
361 | 1.38M | if (length > end - p) { |
362 | 32.3k | if (field_idx >= 0 && type->fields[field_idx].desc->type |
363 | 13.2k | != EBML_TYPE_SUBELEMENTS) { |
364 | 5.01k | MP_ERR(ctx, "Subelement content goes " |
365 | 5.01k | "past end of containing element\n"); |
366 | 5.01k | goto other_error; |
367 | 5.01k | } |
368 | | // Try to parse what is possible from inside this partial element |
369 | 27.2k | ctx->has_errors = true; |
370 | 27.2k | length = end - p; |
371 | 27.2k | } |
372 | 1.37M | p += length; |
373 | | |
374 | 1.37M | continue; |
375 | | |
376 | 734 | past_end_error: |
377 | 734 | MP_ERR(ctx, "Subelement headers go past end of containing element\n"); |
378 | 21.4k | other_error: |
379 | 21.4k | ctx->has_errors = true; |
380 | 21.4k | end = startp; |
381 | 21.4k | break; |
382 | 734 | } |
383 | | |
384 | 2.59M | for (int i = 0; i < type->field_count; i++) { |
385 | 2.19M | if (num_elems[i] && type->fields[i].multiple) { |
386 | 141k | char *ptr = s + type->fields[i].offset; |
387 | 141k | switch (type->fields[i].desc->type) { |
388 | 138k | case EBML_TYPE_SUBELEMENTS: { |
389 | 138k | size_t max = 1000000000 / type->fields[i].desc->size; |
390 | 138k | if (num_elems[i] > max) { |
391 | 0 | MP_ERR(ctx, "Too many subelements.\n"); |
392 | 0 | num_elems[i] = max; |
393 | 0 | } |
394 | 138k | int sz = num_elems[i] * type->fields[i].desc->size; |
395 | 138k | *(generic_struct **) ptr = talloc_zero_size(ctx->talloc_ctx, sz); |
396 | 138k | break; |
397 | 0 | } |
398 | 0 | case EBML_TYPE_UINT: |
399 | 0 | *(uint64_t **) ptr = talloc_zero_array(ctx->talloc_ctx, |
400 | 0 | uint64_t, num_elems[i]); |
401 | 0 | break; |
402 | 0 | case EBML_TYPE_SINT: |
403 | 0 | *(int64_t **) ptr = talloc_zero_array(ctx->talloc_ctx, |
404 | 0 | int64_t, num_elems[i]); |
405 | 0 | break; |
406 | 0 | case EBML_TYPE_FLOAT: |
407 | 0 | *(double **) ptr = talloc_zero_array(ctx->talloc_ctx, |
408 | 0 | double, num_elems[i]); |
409 | 0 | break; |
410 | 3.87k | case EBML_TYPE_STR: |
411 | 3.87k | *(char ***) ptr = talloc_zero_array(ctx->talloc_ctx, |
412 | 3.87k | char *, num_elems[i]); |
413 | 3.87k | break; |
414 | 0 | case EBML_TYPE_BINARY: |
415 | 0 | *(struct bstr **) ptr = talloc_zero_array(ctx->talloc_ctx, |
416 | 0 | struct bstr, |
417 | 0 | num_elems[i]); |
418 | 0 | break; |
419 | 0 | case EBML_TYPE_EBML_ID: |
420 | 0 | *(int32_t **) ptr = talloc_zero_array(ctx->talloc_ctx, |
421 | 0 | uint32_t, num_elems[i]); |
422 | 0 | break; |
423 | 0 | default: |
424 | 0 | MP_ASSERT_UNREACHABLE(); |
425 | 141k | } |
426 | 141k | } |
427 | 2.19M | } |
428 | | |
429 | 1.77M | while (data < end) { |
430 | 1.37M | int len; |
431 | 1.37M | uint32_t id = ebml_parse_id(data, end - data, &len); |
432 | 1.37M | if (len < 0 || len > end - data) { |
433 | 0 | MP_ERR(ctx, "Error parsing subelement\n"); |
434 | 0 | break; |
435 | 0 | } |
436 | 1.37M | data += len; |
437 | 1.37M | uint64_t length = ebml_parse_length(data, end - data, &len); |
438 | 1.37M | if (len < 0 || len > end - data) { |
439 | 0 | MP_ERR(ctx, "Error parsing subelement length\n"); |
440 | 0 | break; |
441 | 0 | } |
442 | 1.37M | data += len; |
443 | 1.37M | if (length > end - data) { |
444 | | // Try to parse what is possible from inside this partial element |
445 | 27.2k | length = end - data; |
446 | 27.2k | MP_ERR(ctx, "Next subelement content goes " |
447 | 27.2k | "past end of containing element, will be truncated\n"); |
448 | 27.2k | } |
449 | 1.37M | int field_idx = -1; |
450 | 6.28M | for (int i = 0; i < type->field_count; i++) |
451 | 6.13M | if (type->fields[i].id == id) { |
452 | 1.22M | field_idx = i; |
453 | 1.22M | break; |
454 | 1.22M | } |
455 | 1.37M | if (field_idx < 0) { |
456 | 153k | if (id == 0xec) { |
457 | 1.35k | MP_TRACE(ctx, "%.*sIgnoring Void element " |
458 | 1.35k | "size: %"PRIu64"\n", level+1, " ", length); |
459 | 151k | } else if (id == 0xbf) { |
460 | 19.2k | MP_TRACE(ctx, "%.*sIgnoring CRC-32 " |
461 | 19.2k | "element size: %"PRIu64"\n", level+1, " ", |
462 | 19.2k | length); |
463 | 132k | } else { |
464 | 132k | MP_DBG(ctx, "Ignoring unrecognized " |
465 | 132k | "subelement. ID: %x size: %"PRIu64"\n", id, length); |
466 | 132k | } |
467 | 153k | data += length; |
468 | 153k | continue; |
469 | 153k | } |
470 | 1.22M | const struct ebml_field_desc *fd = &type->fields[field_idx]; |
471 | 1.22M | const struct ebml_elem_desc *ed = fd->desc; |
472 | 1.22M | bool multiple = fd->multiple; |
473 | 1.22M | int *countptr = (int *) (s + fd->count_offset); |
474 | 1.22M | if (*countptr >= num_elems[field_idx]) { |
475 | | // Shouldn't happen on any sane file without bugs |
476 | 0 | MP_ERR(ctx, "Too many subelements.\n"); |
477 | 0 | ctx->has_errors = true; |
478 | 0 | data += length; |
479 | 0 | continue; |
480 | 0 | } |
481 | 1.22M | if (*countptr > 0 && !multiple) { |
482 | 533 | MP_WARN(ctx, "Another subelement of type " |
483 | 533 | "%x %s (size: %"PRIu64"). Only one allowed. Ignoring.\n", |
484 | 533 | id, ed->name, length); |
485 | 533 | ctx->has_errors = true; |
486 | 533 | data += length; |
487 | 533 | continue; |
488 | 533 | } |
489 | 1.22M | MP_TRACE(ctx, "%.*sParsing %x %s size: %"PRIu64 |
490 | 1.22M | " value: ", level+1, " ", id, ed->name, length); |
491 | | |
492 | 1.22M | char *fieldptr = s + fd->offset; |
493 | 1.22M | switch (ed->type) { |
494 | 325k | case EBML_TYPE_SUBELEMENTS: |
495 | 325k | MP_TRACE(ctx, "subelements\n"); |
496 | 325k | char *subelptr; |
497 | 325k | if (multiple) { |
498 | 293k | char *array_start = (char *) *(generic_struct **) fieldptr; |
499 | 293k | subelptr = array_start + *countptr * ed->size; |
500 | 293k | } else |
501 | 31.7k | subelptr = fieldptr; |
502 | 325k | ebml_parse_element(ctx, subelptr, data, length, ed, level + 1); |
503 | 325k | break; |
504 | | |
505 | 657k | case EBML_TYPE_UINT:; |
506 | 657k | uint64_t *uintptr; |
507 | 657k | #define GETPTR(subelptr, fieldtype) \ |
508 | 897k | if (multiple) \ |
509 | 897k | subelptr = *(fieldtype **) fieldptr + *countptr; \ |
510 | 897k | else \ |
511 | 897k | subelptr = (fieldtype *) fieldptr |
512 | 657k | GETPTR(uintptr, uint64_t); |
513 | 657k | if (length < 1 || length > 8) { |
514 | 5.44k | MP_ERR(ctx, "uint invalid length %"PRIu64"\n", length); |
515 | 5.44k | goto error; |
516 | 5.44k | } |
517 | 652k | *uintptr = ebml_parse_uint(data, length); |
518 | 652k | MP_TRACE(ctx, "uint %"PRIu64"\n", *uintptr); |
519 | 652k | break; |
520 | | |
521 | 7.68k | case EBML_TYPE_SINT:; |
522 | 7.68k | int64_t *sintptr; |
523 | 7.68k | GETPTR(sintptr, int64_t); |
524 | 7.68k | if (length > 8) { |
525 | 10 | MP_ERR(ctx, "sint invalid length %"PRIu64"\n", length); |
526 | 10 | goto error; |
527 | 10 | } |
528 | 7.67k | *sintptr = ebml_parse_sint(data, length); |
529 | 7.67k | MP_TRACE(ctx, "sint %"PRId64"\n", *sintptr); |
530 | 7.67k | break; |
531 | | |
532 | 29.1k | case EBML_TYPE_FLOAT:; |
533 | 29.1k | double *floatptr; |
534 | 29.1k | GETPTR(floatptr, double); |
535 | 29.1k | if (length != 0 && length != 4 && length != 8) { |
536 | 66 | MP_ERR(ctx, "float invalid length %"PRIu64"\n", length); |
537 | 66 | goto error; |
538 | 66 | } |
539 | 29.1k | *floatptr = ebml_parse_float(data, length); |
540 | 29.1k | MP_DBG(ctx, "float %f\n", *floatptr); |
541 | 29.1k | break; |
542 | | |
543 | 120k | case EBML_TYPE_STR: |
544 | 120k | if (length > 1024 * 1024) { |
545 | 0 | MP_ERR(ctx, "Not reading overly long string element.\n"); |
546 | 0 | break; |
547 | 0 | } |
548 | 120k | char **strptr; |
549 | 120k | GETPTR(strptr, char *); |
550 | 120k | *strptr = talloc_strndup(ctx->talloc_ctx, data, length); |
551 | 120k | MP_TRACE(ctx, "string \"%s\"\n", *strptr); |
552 | 120k | break; |
553 | | |
554 | 31.7k | case EBML_TYPE_BINARY:; |
555 | 31.7k | if (length > 0x80000000) { |
556 | 0 | MP_ERR(ctx, "Not reading overly long EBML element.\n"); |
557 | 0 | break; |
558 | 0 | } |
559 | 31.7k | struct bstr *binptr; |
560 | 31.7k | GETPTR(binptr, struct bstr); |
561 | 31.7k | binptr->start = data; |
562 | 31.7k | binptr->len = length; |
563 | 31.7k | MP_TRACE(ctx, "binary %zd bytes\n", binptr->len); |
564 | 31.7k | break; |
565 | | |
566 | 50.3k | case EBML_TYPE_EBML_ID:; |
567 | 50.3k | uint32_t *idptr; |
568 | 50.3k | GETPTR(idptr, uint32_t); |
569 | 50.3k | *idptr = ebml_parse_id(data, end - data, &len); |
570 | 50.3k | if (len != length) { |
571 | 392 | MP_ERR(ctx, "ebml_id broken value\n"); |
572 | 392 | goto error; |
573 | 392 | } |
574 | 49.9k | MP_TRACE(ctx, "ebml_id %x\n", (unsigned)*idptr); |
575 | 49.9k | break; |
576 | 0 | default: |
577 | 0 | MP_ASSERT_UNREACHABLE(); |
578 | 1.22M | } |
579 | 1.21M | *countptr += 1; |
580 | 1.22M | error: |
581 | 1.22M | data += length; |
582 | 1.22M | } |
583 | 395k | } |
584 | | |
585 | | // target must be initialized to zero |
586 | | int ebml_read_element(struct stream *s, struct ebml_parse_ctx *ctx, |
587 | | void *target, const struct ebml_elem_desc *desc) |
588 | 69.9k | { |
589 | 69.9k | ctx->has_errors = false; |
590 | 69.9k | int msglevel = ctx->no_error_messages ? MSGL_DEBUG : MSGL_WARN; |
591 | 69.9k | uint64_t length = ebml_read_length(s); |
592 | 69.9k | if (s->eof) { |
593 | 45 | MP_MSG(ctx, msglevel, "Unexpected end of file " |
594 | 45 | "- partial or corrupt file?\n"); |
595 | 45 | return -1; |
596 | 45 | } |
597 | 69.8k | if (length == EBML_UINT_INVALID) { |
598 | 40 | MP_MSG(ctx, msglevel, "EBML element with unknown length - unsupported\n"); |
599 | 40 | return -1; |
600 | 40 | } |
601 | | #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
602 | | if (length > (512 << 20)) { |
603 | | #else |
604 | 69.8k | if (length > (64 << 20)) { |
605 | 178 | #endif |
606 | 178 | MP_MSG(ctx, msglevel, "Element too big (%" PRIu64 " MiB) - skipping\n", length >> 20); |
607 | 178 | return -1; |
608 | 178 | } |
609 | 69.6k | ctx->talloc_ctx = talloc_size(NULL, length); |
610 | 69.6k | int read_len = stream_read(s, ctx->talloc_ctx, length); |
611 | 69.6k | if (read_len < length) |
612 | 2.68k | MP_MSG(ctx, msglevel, "Unexpected end of file - partial or corrupt file?\n"); |
613 | 69.6k | ebml_parse_element(ctx, target, ctx->talloc_ctx, read_len, desc, 0); |
614 | 69.6k | if (ctx->has_errors) |
615 | 32.4k | MP_MSG(ctx, msglevel, "Error parsing element %s\n", desc->name); |
616 | 69.6k | return 0; |
617 | 69.8k | } |