Coverage Report

Created: 2026-05-16 07:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mpv/demux/ebml.c
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
}