Shaka Packager SDK
Loading...
Searching...
No Matches
webm_parser.cc
1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// This file contains code to parse WebM file elements. It was created
6// from information in the Matroska spec.
7// http://www.matroska.org/technical/specs/index.html
8//
9// This file contains code for encrypted WebM. Current WebM
10// encrypted request for comments specification is here
11// http://wiki.webmproject.org/encryption/webm-encryption-rfc
12
13#include <packager/media/formats/webm/webm_parser.h>
14
15#include <cstddef>
16#include <cstdint>
17#include <cstring>
18#include <ios>
19#include <iterator>
20#include <limits>
21#include <string>
22
23#include <absl/log/check.h>
24#include <absl/log/log.h>
25
26#include <packager/macros/logging.h>
27#include <packager/media/formats/webm/webm_constants.h>
28
29namespace shaka {
30namespace media {
31
32enum ElementType {
33 UNKNOWN,
34 LIST, // Referred to as Master Element in the Matroska spec.
35 UINT,
36 FLOAT,
37 BINARY,
38 STRING,
39 SKIP,
40};
41
42struct ElementIdInfo {
43 ElementType type_;
44 int id_;
45};
46
47struct ListElementInfo {
48 int id_;
49 int level_;
50 const ElementIdInfo* id_info_;
51 int id_info_count_;
52};
53
54// The following are tables indicating what IDs are valid sub-elements
55// of particular elements. If an element is encountered that doesn't
56// appear in the list, a parsing error is signalled. Some elements are
57// marked as SKIP because they are valid, but we don't care about them
58// right now.
59static const ElementIdInfo kEBMLHeaderIds[] = {
60 {UINT, kWebMIdEBMLVersion}, {UINT, kWebMIdEBMLReadVersion},
61 {UINT, kWebMIdEBMLMaxIDLength}, {UINT, kWebMIdEBMLMaxSizeLength},
62 {STRING, kWebMIdDocType}, {UINT, kWebMIdDocTypeVersion},
63 {UINT, kWebMIdDocTypeReadVersion},
64};
65
66static const ElementIdInfo kSegmentIds[] = {
67 {LIST, kWebMIdSeekHead}, {LIST, kWebMIdInfo}, {LIST, kWebMIdCluster},
68 {LIST, kWebMIdTracks}, {LIST, kWebMIdCues}, {LIST, kWebMIdAttachments},
69 {LIST, kWebMIdChapters}, {LIST, kWebMIdTags},
70};
71
72static const ElementIdInfo kSeekHeadIds[] = {
73 {LIST, kWebMIdSeek},
74};
75
76static const ElementIdInfo kSeekIds[] = {
77 {BINARY, kWebMIdSeekID},
78 {UINT, kWebMIdSeekPosition},
79};
80
81static const ElementIdInfo kInfoIds[] = {
82 {BINARY, kWebMIdSegmentUID}, {STRING, kWebMIdSegmentFilename},
83 {BINARY, kWebMIdPrevUID}, {STRING, kWebMIdPrevFilename},
84 {BINARY, kWebMIdNextUID}, {STRING, kWebMIdNextFilename},
85 {BINARY, kWebMIdSegmentFamily}, {LIST, kWebMIdChapterTranslate},
86 {UINT, kWebMIdTimecodeScale}, {FLOAT, kWebMIdDuration},
87 {BINARY, kWebMIdDateUTC}, {STRING, kWebMIdTitle},
88 {STRING, kWebMIdMuxingApp}, {STRING, kWebMIdWritingApp},
89};
90
91static const ElementIdInfo kChapterTranslateIds[] = {
92 {UINT, kWebMIdChapterTranslateEditionUID},
93 {UINT, kWebMIdChapterTranslateCodec},
94 {BINARY, kWebMIdChapterTranslateID},
95};
96
97static const ElementIdInfo kClusterIds[] = {
98 {BINARY, kWebMIdSimpleBlock}, {UINT, kWebMIdTimecode},
99 {LIST, kWebMIdSilentTracks}, {UINT, kWebMIdPosition},
100 {UINT, kWebMIdPrevSize}, {LIST, kWebMIdBlockGroup},
101};
102
103static const ElementIdInfo kSilentTracksIds[] = {
104 {UINT, kWebMIdSilentTrackNumber},
105};
106
107static const ElementIdInfo kBlockGroupIds[] = {
108 {BINARY, kWebMIdBlock}, {LIST, kWebMIdBlockAdditions},
109 {UINT, kWebMIdBlockDuration}, {UINT, kWebMIdReferencePriority},
110 {BINARY, kWebMIdReferenceBlock}, {BINARY, kWebMIdCodecState},
111 {BINARY, kWebMIdDiscardPadding}, {LIST, kWebMIdSlices},
112};
113
114static const ElementIdInfo kBlockAdditionsIds[] = {
115 {LIST, kWebMIdBlockMore},
116};
117
118static const ElementIdInfo kBlockMoreIds[] = {
119 {UINT, kWebMIdBlockAddID},
120 {BINARY, kWebMIdBlockAdditional},
121};
122
123static const ElementIdInfo kSlicesIds[] = {
124 {LIST, kWebMIdTimeSlice},
125};
126
127static const ElementIdInfo kTimeSliceIds[] = {
128 {UINT, kWebMIdLaceNumber},
129};
130
131static const ElementIdInfo kTracksIds[] = {
132 {LIST, kWebMIdTrackEntry},
133};
134
135static const ElementIdInfo kTrackEntryIds[] = {
136 {UINT, kWebMIdTrackNumber},
137 {BINARY, kWebMIdTrackUID},
138 {UINT, kWebMIdTrackType},
139 {UINT, kWebMIdFlagEnabled},
140 {UINT, kWebMIdFlagDefault},
141 {UINT, kWebMIdFlagForced},
142 {UINT, kWebMIdFlagLacing},
143 {UINT, kWebMIdMinCache},
144 {UINT, kWebMIdMaxCache},
145 {UINT, kWebMIdDefaultDuration},
146 {FLOAT, kWebMIdTrackTimecodeScale},
147 {UINT, kWebMIdMaxBlockAdditionId},
148 {STRING, kWebMIdName},
149 {STRING, kWebMIdLanguage},
150 {STRING, kWebMIdCodecID},
151 {BINARY, kWebMIdCodecPrivate},
152 {STRING, kWebMIdCodecName},
153 {UINT, kWebMIdAttachmentLink},
154 {UINT, kWebMIdCodecDecodeAll},
155 {UINT, kWebMIdTrackOverlay},
156 {UINT, kWebMIdCodecDelay},
157 {UINT, kWebMIdSeekPreRoll},
158 {LIST, kWebMIdTrackTranslate},
159 {LIST, kWebMIdVideo},
160 {LIST, kWebMIdAudio},
161 {LIST, kWebMIdTrackOperation},
162 {LIST, kWebMIdContentEncodings},
163};
164
165static const ElementIdInfo kTrackTranslateIds[] = {
166 {UINT, kWebMIdTrackTranslateEditionUID},
167 {UINT, kWebMIdTrackTranslateCodec},
168 {BINARY, kWebMIdTrackTranslateTrackID},
169};
170
171static const ElementIdInfo kVideoIds[] = {
172 {UINT, kWebMIdFlagInterlaced}, {UINT, kWebMIdStereoMode},
173 {UINT, kWebMIdAlphaMode}, {UINT, kWebMIdPixelWidth},
174 {UINT, kWebMIdPixelHeight}, {UINT, kWebMIdPixelCropBottom},
175 {UINT, kWebMIdPixelCropTop}, {UINT, kWebMIdPixelCropLeft},
176 {UINT, kWebMIdPixelCropRight}, {UINT, kWebMIdDisplayWidth},
177 {UINT, kWebMIdDisplayHeight}, {UINT, kWebMIdDisplayUnit},
178 {UINT, kWebMIdAspectRatioType}, {BINARY, kWebMIdColorSpace},
179 {FLOAT, kWebMIdFrameRate}, {LIST, kWebMIdColor},
180 {LIST, kWebMIdProjection},
181};
182
183static const ElementIdInfo kColorIds[] = {
184 {UINT, kWebMIdColorMatrixCoefficients},
185 {UINT, kWebMIdColorBitsPerChannel},
186 {UINT, kWebMIdColorChromaSubsamplingHorz},
187 {UINT, kWebMIdColorChromaSubsamplingVert},
188 {UINT, kWebMIdColorCbSamplingHorz},
189 {UINT, kWebMIdColorCbSamplingVert},
190 {UINT, kWebMIdColorChromaSitingHorz},
191 {UINT, kWebMIdColorChromaSitingVert},
192 {UINT, kWebMIdColorRange},
193 {UINT, kWebMIdColorTransferCharacteristics},
194 {UINT, kWebMIdColorPrimaries},
195 {UINT, kWebMIdColorMaxCLL},
196 {UINT, kWebMIdColorMaxFALL},
197 {LIST, kWebMIdColorMasteringMetadata},
198};
199
200static const ElementIdInfo kProjectionIds[] = {
201 {UINT, kWebMIdProjectionType},
202};
203
204static const ElementIdInfo kAudioIds[] = {
205 {FLOAT, kWebMIdSamplingFrequency},
206 {FLOAT, kWebMIdOutputSamplingFrequency},
207 {UINT, kWebMIdChannels},
208 {UINT, kWebMIdBitDepth},
209};
210
211static const ElementIdInfo kTrackOperationIds[] = {
212 {LIST, kWebMIdTrackCombinePlanes},
213 {LIST, kWebMIdJoinBlocks},
214};
215
216static const ElementIdInfo kTrackCombinePlanesIds[] = {
217 {LIST, kWebMIdTrackPlane},
218};
219
220static const ElementIdInfo kTrackPlaneIds[] = {
221 {UINT, kWebMIdTrackPlaneUID},
222 {UINT, kWebMIdTrackPlaneType},
223};
224
225static const ElementIdInfo kJoinBlocksIds[] = {
226 {UINT, kWebMIdTrackJoinUID},
227};
228
229static const ElementIdInfo kContentEncodingsIds[] = {
230 {LIST, kWebMIdContentEncoding},
231};
232
233static const ElementIdInfo kContentEncodingIds[] = {
234 {UINT, kWebMIdContentEncodingOrder}, {UINT, kWebMIdContentEncodingScope},
235 {UINT, kWebMIdContentEncodingType}, {LIST, kWebMIdContentCompression},
236 {LIST, kWebMIdContentEncryption},
237};
238
239static const ElementIdInfo kContentCompressionIds[] = {
240 {UINT, kWebMIdContentCompAlgo},
241 {BINARY, kWebMIdContentCompSettings},
242};
243
244static const ElementIdInfo kContentEncryptionIds[] = {
245 {LIST, kWebMIdContentEncAESSettings}, {UINT, kWebMIdContentEncAlgo},
246 {BINARY, kWebMIdContentEncKeyID}, {BINARY, kWebMIdContentSignature},
247 {BINARY, kWebMIdContentSigKeyID}, {UINT, kWebMIdContentSigAlgo},
248 {UINT, kWebMIdContentSigHashAlgo},
249};
250
251static const ElementIdInfo kContentEncAESSettingsIds[] = {
252 {UINT, kWebMIdAESSettingsCipherMode},
253};
254
255static const ElementIdInfo kCuesIds[] = {
256 {LIST, kWebMIdCuePoint},
257};
258
259static const ElementIdInfo kCuePointIds[] = {
260 {UINT, kWebMIdCueTime},
261 {LIST, kWebMIdCueTrackPositions},
262};
263
264static const ElementIdInfo kCueTrackPositionsIds[] = {
265 {UINT, kWebMIdCueTrack}, {UINT, kWebMIdCueClusterPosition},
266 {UINT, kWebMIdCueBlockNumber}, {UINT, kWebMIdCueCodecState},
267 {LIST, kWebMIdCueReference},
268};
269
270static const ElementIdInfo kCueReferenceIds[] = {
271 {UINT, kWebMIdCueRefTime},
272};
273
274static const ElementIdInfo kAttachmentsIds[] = {
275 {LIST, kWebMIdAttachedFile},
276};
277
278static const ElementIdInfo kAttachedFileIds[] = {
279 {STRING, kWebMIdFileDescription}, {STRING, kWebMIdFileName},
280 {STRING, kWebMIdFileMimeType}, {BINARY, kWebMIdFileData},
281 {UINT, kWebMIdFileUID},
282};
283
284static const ElementIdInfo kChaptersIds[] = {
285 {LIST, kWebMIdEditionEntry},
286};
287
288static const ElementIdInfo kEditionEntryIds[] = {
289 {UINT, kWebMIdEditionUID}, {UINT, kWebMIdEditionFlagHidden},
290 {UINT, kWebMIdEditionFlagDefault}, {UINT, kWebMIdEditionFlagOrdered},
291 {LIST, kWebMIdChapterAtom},
292};
293
294static const ElementIdInfo kChapterAtomIds[] = {
295 {UINT, kWebMIdChapterUID},
296 {UINT, kWebMIdChapterTimeStart},
297 {UINT, kWebMIdChapterTimeEnd},
298 {UINT, kWebMIdChapterFlagHidden},
299 {UINT, kWebMIdChapterFlagEnabled},
300 {BINARY, kWebMIdChapterSegmentUID},
301 {UINT, kWebMIdChapterSegmentEditionUID},
302 {UINT, kWebMIdChapterPhysicalEquiv},
303 {LIST, kWebMIdChapterTrack},
304 {LIST, kWebMIdChapterDisplay},
305 {LIST, kWebMIdChapProcess},
306};
307
308static const ElementIdInfo kChapterTrackIds[] = {
309 {UINT, kWebMIdChapterTrackNumber},
310};
311
312static const ElementIdInfo kChapterDisplayIds[] = {
313 {STRING, kWebMIdChapString},
314 {STRING, kWebMIdChapLanguage},
315 {STRING, kWebMIdChapCountry},
316};
317
318static const ElementIdInfo kChapProcessIds[] = {
319 {UINT, kWebMIdChapProcessCodecID},
320 {BINARY, kWebMIdChapProcessPrivate},
321 {LIST, kWebMIdChapProcessCommand},
322};
323
324static const ElementIdInfo kChapProcessCommandIds[] = {
325 {UINT, kWebMIdChapProcessTime},
326 {BINARY, kWebMIdChapProcessData},
327};
328
329static const ElementIdInfo kTagsIds[] = {
330 {LIST, kWebMIdTag},
331};
332
333static const ElementIdInfo kTagIds[] = {
334 {LIST, kWebMIdTargets},
335 {LIST, kWebMIdSimpleTag},
336};
337
338static const ElementIdInfo kTargetsIds[] = {
339 {UINT, kWebMIdTargetTypeValue}, {STRING, kWebMIdTargetType},
340 {UINT, kWebMIdTagTrackUID}, {UINT, kWebMIdTagEditionUID},
341 {UINT, kWebMIdTagChapterUID}, {UINT, kWebMIdTagAttachmentUID},
342};
343
344static const ElementIdInfo kSimpleTagIds[] = {
345 {STRING, kWebMIdTagName}, {STRING, kWebMIdTagLanguage},
346 {UINT, kWebMIdTagDefault}, {STRING, kWebMIdTagString},
347 {BINARY, kWebMIdTagBinary},
348};
349
350#define LIST_ELEMENT_INFO(id, level, id_info) \
351 {(id), (level), (id_info), std::size(id_info)}
352
353static const ListElementInfo kListElementInfo[] = {
354 LIST_ELEMENT_INFO(kWebMIdCluster, 1, kClusterIds),
355 LIST_ELEMENT_INFO(kWebMIdEBMLHeader, 0, kEBMLHeaderIds),
356 LIST_ELEMENT_INFO(kWebMIdSegment, 0, kSegmentIds),
357 LIST_ELEMENT_INFO(kWebMIdSeekHead, 1, kSeekHeadIds),
358 LIST_ELEMENT_INFO(kWebMIdSeek, 2, kSeekIds),
359 LIST_ELEMENT_INFO(kWebMIdInfo, 1, kInfoIds),
360 LIST_ELEMENT_INFO(kWebMIdChapterTranslate, 2, kChapterTranslateIds),
361 LIST_ELEMENT_INFO(kWebMIdSilentTracks, 2, kSilentTracksIds),
362 LIST_ELEMENT_INFO(kWebMIdBlockGroup, 2, kBlockGroupIds),
363 LIST_ELEMENT_INFO(kWebMIdBlockAdditions, 3, kBlockAdditionsIds),
364 LIST_ELEMENT_INFO(kWebMIdBlockMore, 4, kBlockMoreIds),
365 LIST_ELEMENT_INFO(kWebMIdSlices, 3, kSlicesIds),
366 LIST_ELEMENT_INFO(kWebMIdTimeSlice, 4, kTimeSliceIds),
367 LIST_ELEMENT_INFO(kWebMIdTracks, 1, kTracksIds),
368 LIST_ELEMENT_INFO(kWebMIdTrackEntry, 2, kTrackEntryIds),
369 LIST_ELEMENT_INFO(kWebMIdTrackTranslate, 3, kTrackTranslateIds),
370 LIST_ELEMENT_INFO(kWebMIdVideo, 3, kVideoIds),
371 LIST_ELEMENT_INFO(kWebMIdColor, 4, kColorIds),
372 LIST_ELEMENT_INFO(kWebMIdProjection, 4, kProjectionIds),
373 LIST_ELEMENT_INFO(kWebMIdAudio, 3, kAudioIds),
374 LIST_ELEMENT_INFO(kWebMIdTrackOperation, 3, kTrackOperationIds),
375 LIST_ELEMENT_INFO(kWebMIdTrackCombinePlanes, 4, kTrackCombinePlanesIds),
376 LIST_ELEMENT_INFO(kWebMIdTrackPlane, 5, kTrackPlaneIds),
377 LIST_ELEMENT_INFO(kWebMIdJoinBlocks, 4, kJoinBlocksIds),
378 LIST_ELEMENT_INFO(kWebMIdContentEncodings, 3, kContentEncodingsIds),
379 LIST_ELEMENT_INFO(kWebMIdContentEncoding, 4, kContentEncodingIds),
380 LIST_ELEMENT_INFO(kWebMIdContentCompression, 5, kContentCompressionIds),
381 LIST_ELEMENT_INFO(kWebMIdContentEncryption, 5, kContentEncryptionIds),
382 LIST_ELEMENT_INFO(kWebMIdContentEncAESSettings,
383 6,
384 kContentEncAESSettingsIds),
385 LIST_ELEMENT_INFO(kWebMIdCues, 1, kCuesIds),
386 LIST_ELEMENT_INFO(kWebMIdCuePoint, 2, kCuePointIds),
387 LIST_ELEMENT_INFO(kWebMIdCueTrackPositions, 3, kCueTrackPositionsIds),
388 LIST_ELEMENT_INFO(kWebMIdCueReference, 4, kCueReferenceIds),
389 LIST_ELEMENT_INFO(kWebMIdAttachments, 1, kAttachmentsIds),
390 LIST_ELEMENT_INFO(kWebMIdAttachedFile, 2, kAttachedFileIds),
391 LIST_ELEMENT_INFO(kWebMIdChapters, 1, kChaptersIds),
392 LIST_ELEMENT_INFO(kWebMIdEditionEntry, 2, kEditionEntryIds),
393 LIST_ELEMENT_INFO(kWebMIdChapterAtom, 3, kChapterAtomIds),
394 LIST_ELEMENT_INFO(kWebMIdChapterTrack, 4, kChapterTrackIds),
395 LIST_ELEMENT_INFO(kWebMIdChapterDisplay, 4, kChapterDisplayIds),
396 LIST_ELEMENT_INFO(kWebMIdChapProcess, 4, kChapProcessIds),
397 LIST_ELEMENT_INFO(kWebMIdChapProcessCommand, 5, kChapProcessCommandIds),
398 LIST_ELEMENT_INFO(kWebMIdTags, 1, kTagsIds),
399 LIST_ELEMENT_INFO(kWebMIdTag, 2, kTagIds),
400 LIST_ELEMENT_INFO(kWebMIdTargets, 3, kTargetsIds),
401 LIST_ELEMENT_INFO(kWebMIdSimpleTag, 3, kSimpleTagIds),
402};
403
404// Parses an element header id or size field. These fields are variable length
405// encoded. The first byte indicates how many bytes the field occupies.
406// |buf| - The buffer to parse.
407// |size| - The number of bytes in |buf|
408// |max_bytes| - The maximum number of bytes the field can be. ID fields
409// set this to 4 & element size fields set this to 8. If the
410// first byte indicates a larger field size than this it is a
411// parser error.
412// |mask_first_byte| - For element size fields the field length encoding bits
413// need to be masked off. This parameter is true for
414// element size fields and is false for ID field values.
415//
416// Returns: The number of bytes parsed on success. -1 on error.
417static int ParseWebMElementHeaderField(const uint8_t* buf,
418 int size,
419 int max_bytes,
420 bool mask_first_byte,
421 int64_t* num) {
422 DCHECK(buf);
423 DCHECK(num);
424
425 if (size < 0)
426 return -1;
427
428 if (size == 0)
429 return 0;
430
431 int mask = 0x80;
432 uint8_t ch = buf[0];
433 int extra_bytes = -1;
434 bool all_ones = false;
435 for (int i = 0; i < max_bytes; ++i) {
436 if ((ch & mask) != 0) {
437 mask = ~mask & 0xff;
438 *num = mask_first_byte ? ch & mask : ch;
439 all_ones = (ch & mask) == mask;
440 extra_bytes = i;
441 break;
442 }
443 mask = 0x80 | mask >> 1;
444 }
445
446 if (extra_bytes == -1)
447 return -1;
448
449 // Return 0 if we need more data.
450 if ((1 + extra_bytes) > size)
451 return 0;
452
453 int bytes_used = 1;
454
455 for (int i = 0; i < extra_bytes; ++i) {
456 ch = buf[bytes_used++];
457 all_ones &= (ch == 0xff);
458 *num = (*num << 8) | ch;
459 }
460
461 if (all_ones)
462 *num = std::numeric_limits<int64_t>::max();
463
464 return bytes_used;
465}
466
467int WebMParseElementHeader(const uint8_t* buf,
468 int size,
469 int* id,
470 int64_t* element_size) {
471 DCHECK(buf);
472 DCHECK_GE(size, 0);
473 DCHECK(id);
474 DCHECK(element_size);
475
476 if (size == 0)
477 return 0;
478
479 int64_t tmp = 0;
480 int num_id_bytes = ParseWebMElementHeaderField(buf, size, 4, false, &tmp);
481
482 if (num_id_bytes <= 0)
483 return num_id_bytes;
484
485 if (tmp == std::numeric_limits<int64_t>::max())
486 tmp = kWebMReservedId;
487
488 *id = static_cast<int>(tmp);
489
490 int num_size_bytes = ParseWebMElementHeaderField(
491 buf + num_id_bytes, size - num_id_bytes, 8, true, &tmp);
492
493 if (num_size_bytes <= 0)
494 return num_size_bytes;
495
496 if (tmp == std::numeric_limits<int64_t>::max())
497 tmp = kWebMUnknownSize;
498
499 *element_size = tmp;
500 DVLOG(3) << "WebMParseElementHeader() : id " << std::hex << *id << std::dec
501 << " size " << *element_size;
502 return num_id_bytes + num_size_bytes;
503}
504
505// Finds ElementType for a specific ID.
506static ElementType FindIdType(int id,
507 const ElementIdInfo* id_info,
508 int id_info_count) {
509 // Check for global element IDs that can be anywhere.
510 if (id == kWebMIdVoid || id == kWebMIdCRC32)
511 return SKIP;
512
513 for (int i = 0; i < id_info_count; ++i) {
514 if (id == id_info[i].id_)
515 return id_info[i].type_;
516 }
517
518 return UNKNOWN;
519}
520
521// Finds ListElementInfo for a specific ID.
522static const ListElementInfo* FindListInfo(int id) {
523 for (size_t i = 0; i < std::size(kListElementInfo); ++i) {
524 if (id == kListElementInfo[i].id_)
525 return &kListElementInfo[i];
526 }
527
528 return NULL;
529}
530
531static int FindListLevel(int id) {
532 const ListElementInfo* list_info = FindListInfo(id);
533 if (list_info)
534 return list_info->level_;
535
536 return -1;
537}
538
539static int ParseUInt(const uint8_t* buf,
540 int size,
541 int id,
542 WebMParserClient* client) {
543 if ((size <= 0) || (size > 8))
544 return -1;
545
546 // Read in the big-endian integer.
547 uint64_t value = 0;
548 for (int i = 0; i < size; ++i)
549 value = (value << 8) | buf[i];
550
551 // We use int64_t in place of uint64_t everywhere for convenience. See this
552 // bug
553 // for more details: http://crbug.com/366750#c3
554 if (value > static_cast<uint64_t>(std::numeric_limits<int64_t>::max()))
555 return -1;
556
557 if (!client->OnUInt(id, value))
558 return -1;
559
560 return size;
561}
562
563static int ParseFloat(const uint8_t* buf,
564 int size,
565 int id,
566 WebMParserClient* client) {
567 if ((size != 4) && (size != 8))
568 return -1;
569
570 double value = -1;
571
572 // Read the bytes from big-endian form into a native endian integer.
573 int64_t tmp = 0;
574 for (int i = 0; i < size; ++i)
575 tmp = (tmp << 8) | buf[i];
576
577 // Use a union to convert the integer bit pattern into a floating point
578 // number.
579 if (size == 4) {
580 union {
581 int32_t src;
582 float dst;
583 } tmp2;
584 tmp2.src = static_cast<int32_t>(tmp);
585 value = tmp2.dst;
586 } else if (size == 8) {
587 union {
588 int64_t src;
589 double dst;
590 } tmp2;
591 tmp2.src = tmp;
592 value = tmp2.dst;
593 } else {
594 return -1;
595 }
596
597 if (!client->OnFloat(id, value))
598 return -1;
599
600 return size;
601}
602
603static int ParseBinary(const uint8_t* buf,
604 int size,
605 int id,
606 WebMParserClient* client) {
607 return client->OnBinary(id, buf, size) ? size : -1;
608}
609
610static int ParseString(const uint8_t* buf,
611 int size,
612 int id,
613 WebMParserClient* client) {
614 const uint8_t* end = static_cast<const uint8_t*>(memchr(buf, '\0', size));
615 int length = (end != NULL) ? static_cast<int>(end - buf) : size;
616 std::string str(reinterpret_cast<const char*>(buf), length);
617 return client->OnString(id, str) ? size : -1;
618}
619
620static int ParseNonListElement(ElementType type,
621 int id,
622 int64_t element_size,
623 const uint8_t* buf,
624 int size,
625 WebMParserClient* client) {
626 DCHECK_GE(size, element_size);
627
628 int result = -1;
629 switch (type) {
630 case LIST:
631 NOTIMPLEMENTED();
632 result = -1;
633 break;
634 case UINT:
635 result = ParseUInt(buf, element_size, id, client);
636 break;
637 case FLOAT:
638 result = ParseFloat(buf, element_size, id, client);
639 break;
640 case BINARY:
641 result = ParseBinary(buf, element_size, id, client);
642 break;
643 case STRING:
644 result = ParseString(buf, element_size, id, client);
645 break;
646 case SKIP:
647 result = element_size;
648 break;
649 default:
650 DVLOG(1) << "Unhandled ID type " << type;
651 return -1;
652 };
653
654 DCHECK_LE(result, size);
655 return result;
656}
657
658WebMParserClient::WebMParserClient() {}
659WebMParserClient::~WebMParserClient() {}
660
661WebMParserClient* WebMParserClient::OnListStart(int id) {
662 DVLOG(1) << "Unexpected list element start with ID " << std::hex << id;
663 return NULL;
664}
665
666bool WebMParserClient::OnListEnd(int id) {
667 DVLOG(1) << "Unexpected list element end with ID " << std::hex << id;
668 return false;
669}
670
671bool WebMParserClient::OnUInt(int id, int64_t /*val*/) {
672 DVLOG(1) << "Unexpected unsigned integer element with ID " << std::hex << id;
673 return false;
674}
675
676bool WebMParserClient::OnFloat(int id, double /*val*/) {
677 DVLOG(1) << "Unexpected float element with ID " << std::hex << id;
678 return false;
679}
680
681bool WebMParserClient::OnBinary(int id, const uint8_t* /*data*/, int /*size*/) {
682 DVLOG(1) << "Unexpected binary element with ID " << std::hex << id;
683 return false;
684}
685
686bool WebMParserClient::OnString(int id, const std::string& /*str*/) {
687 DVLOG(1) << "Unexpected string element with ID " << std::hex << id;
688 return false;
689}
690
692 : state_(NEED_LIST_HEADER),
693 root_id_(id),
694 root_level_(FindListLevel(id)),
695 root_client_(client) {
696 DCHECK_GE(root_level_, 0);
697 DCHECK(client);
698}
699
700WebMListParser::~WebMListParser() {}
701
703 ChangeState(NEED_LIST_HEADER);
704 list_state_stack_.clear();
705}
706
707int WebMListParser::Parse(const uint8_t* buf, int size) {
708 DCHECK(buf);
709
710 if (size < 0 || state_ == PARSE_ERROR || state_ == DONE_PARSING_LIST)
711 return -1;
712
713 if (size == 0)
714 return 0;
715
716 const uint8_t* cur = buf;
717 int cur_size = size;
718 int bytes_parsed = 0;
719
720 while (cur_size > 0 && state_ != PARSE_ERROR && state_ != DONE_PARSING_LIST) {
721 int element_id = 0;
722 int64_t element_size = 0;
723 int result =
724 WebMParseElementHeader(cur, cur_size, &element_id, &element_size);
725
726 if (result < 0)
727 return result;
728
729 if (result == 0)
730 return bytes_parsed;
731
732 switch (state_) {
733 case NEED_LIST_HEADER: {
734 if (element_id != root_id_) {
735 ChangeState(PARSE_ERROR);
736 return -1;
737 }
738
739 // Only allow Segment & Cluster to have an unknown size.
740 if (element_size == kWebMUnknownSize &&
741 (element_id != kWebMIdSegment) && (element_id != kWebMIdCluster)) {
742 ChangeState(PARSE_ERROR);
743 return -1;
744 }
745
746 ChangeState(INSIDE_LIST);
747 if (!OnListStart(root_id_, element_size))
748 return -1;
749
750 break;
751 }
752
753 case INSIDE_LIST: {
754 int header_size = result;
755 const uint8_t* element_data = cur + header_size;
756 int element_data_size = cur_size - header_size;
757
758 if (element_size < element_data_size)
759 element_data_size = element_size;
760
761 result = ParseListElement(header_size, element_id, element_size,
762 element_data, element_data_size);
763
764 DCHECK_LE(result, header_size + element_data_size);
765 if (result < 0) {
766 ChangeState(PARSE_ERROR);
767 return -1;
768 }
769
770 if (result == 0)
771 return bytes_parsed;
772
773 break;
774 }
775 case DONE_PARSING_LIST:
776 case PARSE_ERROR:
777 // Shouldn't be able to get here.
778 NOTIMPLEMENTED();
779 break;
780 }
781
782 cur += result;
783 cur_size -= result;
784 bytes_parsed += result;
785 }
786
787 return (state_ == PARSE_ERROR) ? -1 : bytes_parsed;
788}
789
791 return state_ == DONE_PARSING_LIST;
792}
793
794void WebMListParser::ChangeState(State new_state) {
795 state_ = new_state;
796}
797
798int WebMListParser::ParseListElement(int header_size,
799 int id,
800 int64_t element_size,
801 const uint8_t* data,
802 int size) {
803 DCHECK_GT(list_state_stack_.size(), 0u);
804
805 ListState& list_state = list_state_stack_.back();
806 DCHECK(list_state.element_info_);
807
808 const ListElementInfo* element_info = list_state.element_info_;
809 ElementType id_type =
810 FindIdType(id, element_info->id_info_, element_info->id_info_count_);
811
812 // Unexpected ID.
813 if (id_type == UNKNOWN) {
814 if (list_state.size_ != kWebMUnknownSize ||
815 !IsSiblingOrAncestor(list_state.id_, id)) {
816 DVLOG(1) << "No ElementType info for ID 0x" << std::hex << id;
817 return -1;
818 }
819
820 // We've reached the end of a list of unknown size. Update the size now that
821 // we know it and dispatch the end of list calls.
822 list_state.size_ = list_state.bytes_parsed_;
823
824 if (!OnListEnd())
825 return -1;
826
827 // Check to see if all open lists have ended.
828 if (list_state_stack_.size() == 0)
829 return 0;
830
831 list_state = list_state_stack_.back();
832 }
833
834 // Make sure the whole element can fit inside the current list.
835 int64_t total_element_size = header_size + element_size;
836 if (list_state.size_ != kWebMUnknownSize &&
837 list_state.size_ < list_state.bytes_parsed_ + total_element_size) {
838 return -1;
839 }
840
841 if (id_type == LIST) {
842 list_state.bytes_parsed_ += header_size;
843
844 if (!OnListStart(id, element_size))
845 return -1;
846 return header_size;
847 }
848
849 // Make sure we have the entire element before trying to parse a non-list
850 // element.
851 if (size < element_size)
852 return 0;
853
854 int bytes_parsed = ParseNonListElement(id_type, id, element_size, data, size,
855 list_state.client_);
856 DCHECK_LE(bytes_parsed, size);
857
858 // Return if an error occurred or we need more data.
859 // Note: bytes_parsed is 0 for a successful parse of a size 0 element. We
860 // need to check the element_size to disambiguate the "need more data" case
861 // from a successful parse.
862 if (bytes_parsed < 0 || (bytes_parsed == 0 && element_size != 0))
863 return bytes_parsed;
864
865 int result = header_size + bytes_parsed;
866 list_state.bytes_parsed_ += result;
867
868 // See if we have reached the end of the current list.
869 if (list_state.bytes_parsed_ == list_state.size_) {
870 if (!OnListEnd())
871 return -1;
872 }
873
874 return result;
875}
876
877bool WebMListParser::OnListStart(int id, int64_t size) {
878 const ListElementInfo* element_info = FindListInfo(id);
879 if (!element_info)
880 return false;
881
882 int current_level =
883 root_level_ + static_cast<int>(list_state_stack_.size()) - 1;
884 if (current_level + 1 != element_info->level_)
885 return false;
886
887 WebMParserClient* current_list_client = NULL;
888 if (!list_state_stack_.empty()) {
889 // Make sure the new list doesn't go past the end of the current list.
890 ListState current_list_state = list_state_stack_.back();
891 if (current_list_state.size_ != kWebMUnknownSize &&
892 current_list_state.size_ < current_list_state.bytes_parsed_ + size)
893 return false;
894 current_list_client = current_list_state.client_;
895 } else {
896 current_list_client = root_client_;
897 }
898
899 WebMParserClient* new_list_client = current_list_client->OnListStart(id);
900 if (!new_list_client)
901 return false;
902
903 ListState new_list_state = {id, size, 0, element_info, new_list_client};
904 list_state_stack_.push_back(new_list_state);
905
906 if (size == 0)
907 return OnListEnd();
908
909 return true;
910}
911
912bool WebMListParser::OnListEnd() {
913 int lists_ended = 0;
914 for (; !list_state_stack_.empty(); ++lists_ended) {
915 const ListState& list_state = list_state_stack_.back();
916 int64_t bytes_parsed = list_state.bytes_parsed_;
917 int id = list_state.id_;
918
919 if (bytes_parsed != list_state.size_)
920 break;
921
922 list_state_stack_.pop_back();
923
924 WebMParserClient* client = NULL;
925 if (!list_state_stack_.empty()) {
926 // Update the bytes_parsed_ for the parent element.
927 list_state_stack_.back().bytes_parsed_ += bytes_parsed;
928 client = list_state_stack_.back().client_;
929 } else {
930 client = root_client_;
931 }
932
933 if (!client->OnListEnd(id))
934 return false;
935 }
936
937 DCHECK_GE(lists_ended, 1);
938
939 if (list_state_stack_.empty())
940 ChangeState(DONE_PARSING_LIST);
941
942 return true;
943}
944
945bool WebMListParser::IsSiblingOrAncestor(int id_a, int id_b) const {
946 DCHECK((id_a == kWebMIdSegment) || (id_a == kWebMIdCluster));
947
948 if (id_a == kWebMIdCluster) {
949 // kWebMIdCluster siblings.
950 for (size_t i = 0; i < std::size(kSegmentIds); i++) {
951 if (kSegmentIds[i].id_ == id_b)
952 return true;
953 }
954 }
955
956 // kWebMIdSegment siblings.
957 return ((id_b == kWebMIdSegment) || (id_b == kWebMIdEBMLHeader));
958}
959
960} // namespace media
961} // namespace shaka
void Reset()
Resets the state of the parser so it can start parsing a new list.
WebMListParser(int id, WebMParserClient *client)
int Parse(const uint8_t *buf, int size)
All the methods that are virtual are virtual for mocking.