1 // Copyright (c) 2012 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.
5 #include "media/webm/webm_parser.h"
7 // This file contains code to parse WebM file elements. It was created
8 // from information in the Matroska spec.
9 // http://www.matroska.org/technical/specs/index.html
10 // This file contains code for encrypted WebM. Current WebM
11 // encrypted request for comments specification is here
12 // http://wiki.webmproject.org/encryption/webm-encryption-rfc
16 #include "base/logging.h"
17 #include "media/webm/webm_constants.h"
23 LIST, // Referred to as Master Element in the Matroska spec.
31 struct ElementIdInfo {
36 struct ListElementInfo {
39 const ElementIdInfo* id_info_;
43 // The following are tables indicating what IDs are valid sub-elements
44 // of particular elements. If an element is encountered that doesn't
45 // appear in the list, a parsing error is signalled. Some elements are
46 // marked as SKIP because they are valid, but we don't care about them
48 static const ElementIdInfo kEBMLHeaderIds[] = {
49 {UINT, kWebMIdEBMLVersion},
50 {UINT, kWebMIdEBMLReadVersion},
51 {UINT, kWebMIdEBMLMaxIDLength},
52 {UINT, kWebMIdEBMLMaxSizeLength},
53 {STRING, kWebMIdDocType},
54 {UINT, kWebMIdDocTypeVersion},
55 {UINT, kWebMIdDocTypeReadVersion},
58 static const ElementIdInfo kSegmentIds[] = {
59 {LIST, kWebMIdSeekHead},
61 {LIST, kWebMIdCluster},
62 {LIST, kWebMIdTracks},
64 {LIST, kWebMIdAttachments},
65 {LIST, kWebMIdChapters},
69 static const ElementIdInfo kSeekHeadIds[] = {
73 static const ElementIdInfo kSeekIds[] = {
74 {BINARY, kWebMIdSeekID},
75 {UINT, kWebMIdSeekPosition},
78 static const ElementIdInfo kInfoIds[] = {
79 {BINARY, kWebMIdSegmentUID},
80 {STRING, kWebMIdSegmentFilename},
81 {BINARY, kWebMIdPrevUID},
82 {STRING, kWebMIdPrevFilename},
83 {BINARY, kWebMIdNextUID},
84 {STRING, kWebMIdNextFilename},
85 {BINARY, kWebMIdSegmentFamily},
86 {LIST, kWebMIdChapterTranslate},
87 {UINT, kWebMIdTimecodeScale},
88 {FLOAT, kWebMIdDuration},
89 {BINARY, kWebMIdDateUTC},
90 {STRING, kWebMIdTitle},
91 {STRING, kWebMIdMuxingApp},
92 {STRING, kWebMIdWritingApp},
95 static const ElementIdInfo kChapterTranslateIds[] = {
96 {UINT, kWebMIdChapterTranslateEditionUID},
97 {UINT, kWebMIdChapterTranslateCodec},
98 {BINARY, kWebMIdChapterTranslateID},
101 static const ElementIdInfo kClusterIds[] = {
102 {BINARY, kWebMIdSimpleBlock},
103 {UINT, kWebMIdTimecode},
104 {LIST, kWebMIdSilentTracks},
105 {UINT, kWebMIdPosition},
106 {UINT, kWebMIdPrevSize},
107 {LIST, kWebMIdBlockGroup},
110 static const ElementIdInfo kSilentTracksIds[] = {
111 {UINT, kWebMIdSilentTrackNumber},
114 static const ElementIdInfo kBlockGroupIds[] = {
115 {BINARY, kWebMIdBlock},
116 {LIST, kWebMIdBlockAdditions},
117 {UINT, kWebMIdBlockDuration},
118 {UINT, kWebMIdReferencePriority},
119 {BINARY, kWebMIdReferenceBlock},
120 {BINARY, kWebMIdCodecState},
121 {UINT, kWebMIdDiscardPadding},
122 {LIST, kWebMIdSlices},
125 static const ElementIdInfo kBlockAdditionsIds[] = {
126 {LIST, kWebMIdBlockMore},
129 static const ElementIdInfo kBlockMoreIds[] = {
130 {UINT, kWebMIdBlockAddID},
131 {BINARY, kWebMIdBlockAdditional},
134 static const ElementIdInfo kSlicesIds[] = {
135 {LIST, kWebMIdTimeSlice},
138 static const ElementIdInfo kTimeSliceIds[] = {
139 {UINT, kWebMIdLaceNumber},
142 static const ElementIdInfo kTracksIds[] = {
143 {LIST, kWebMIdTrackEntry},
146 static const ElementIdInfo kTrackEntryIds[] = {
147 {UINT, kWebMIdTrackNumber},
148 {UINT, kWebMIdTrackUID},
149 {UINT, kWebMIdTrackType},
150 {UINT, kWebMIdFlagEnabled},
151 {UINT, kWebMIdFlagDefault},
152 {UINT, kWebMIdFlagForced},
153 {UINT, kWebMIdFlagLacing},
154 {UINT, kWebMIdMinCache},
155 {UINT, kWebMIdMaxCache},
156 {UINT, kWebMIdDefaultDuration},
157 {FLOAT, kWebMIdTrackTimecodeScale},
158 {UINT, kWebMIdMaxBlockAdditionId},
159 {STRING, kWebMIdName},
160 {STRING, kWebMIdLanguage},
161 {STRING, kWebMIdCodecID},
162 {BINARY, kWebMIdCodecPrivate},
163 {STRING, kWebMIdCodecName},
164 {UINT, kWebMIdAttachmentLink},
165 {UINT, kWebMIdCodecDecodeAll},
166 {UINT, kWebMIdTrackOverlay},
167 {UINT, kWebMIdCodecDelay},
168 {UINT, kWebMIdSeekPreRoll},
169 {LIST, kWebMIdTrackTranslate},
170 {LIST, kWebMIdVideo},
171 {LIST, kWebMIdAudio},
172 {LIST, kWebMIdTrackOperation},
173 {LIST, kWebMIdContentEncodings},
176 static const ElementIdInfo kTrackTranslateIds[] = {
177 {UINT, kWebMIdTrackTranslateEditionUID},
178 {UINT, kWebMIdTrackTranslateCodec},
179 {BINARY, kWebMIdTrackTranslateTrackID},
182 static const ElementIdInfo kVideoIds[] = {
183 {UINT, kWebMIdFlagInterlaced},
184 {UINT, kWebMIdStereoMode},
185 {UINT, kWebMIdAlphaMode},
186 {UINT, kWebMIdPixelWidth},
187 {UINT, kWebMIdPixelHeight},
188 {UINT, kWebMIdPixelCropBottom},
189 {UINT, kWebMIdPixelCropTop},
190 {UINT, kWebMIdPixelCropLeft},
191 {UINT, kWebMIdPixelCropRight},
192 {UINT, kWebMIdDisplayWidth},
193 {UINT, kWebMIdDisplayHeight},
194 {UINT, kWebMIdDisplayUnit},
195 {UINT, kWebMIdAspectRatioType},
196 {BINARY, kWebMIdColorSpace},
197 {FLOAT, kWebMIdFrameRate},
200 static const ElementIdInfo kAudioIds[] = {
201 {FLOAT, kWebMIdSamplingFrequency},
202 {FLOAT, kWebMIdOutputSamplingFrequency},
203 {UINT, kWebMIdChannels},
204 {UINT, kWebMIdBitDepth},
207 static const ElementIdInfo kTrackOperationIds[] = {
208 {LIST, kWebMIdTrackCombinePlanes},
209 {LIST, kWebMIdJoinBlocks},
212 static const ElementIdInfo kTrackCombinePlanesIds[] = {
213 {LIST, kWebMIdTrackPlane},
216 static const ElementIdInfo kTrackPlaneIds[] = {
217 {UINT, kWebMIdTrackPlaneUID},
218 {UINT, kWebMIdTrackPlaneType},
221 static const ElementIdInfo kJoinBlocksIds[] = {
222 {UINT, kWebMIdTrackJoinUID},
225 static const ElementIdInfo kContentEncodingsIds[] = {
226 {LIST, kWebMIdContentEncoding},
229 static const ElementIdInfo kContentEncodingIds[] = {
230 {UINT, kWebMIdContentEncodingOrder},
231 {UINT, kWebMIdContentEncodingScope},
232 {UINT, kWebMIdContentEncodingType},
233 {LIST, kWebMIdContentCompression},
234 {LIST, kWebMIdContentEncryption},
237 static const ElementIdInfo kContentCompressionIds[] = {
238 {UINT, kWebMIdContentCompAlgo},
239 {BINARY, kWebMIdContentCompSettings},
242 static const ElementIdInfo kContentEncryptionIds[] = {
243 {LIST, kWebMIdContentEncAESSettings},
244 {UINT, kWebMIdContentEncAlgo},
245 {BINARY, kWebMIdContentEncKeyID},
246 {BINARY, kWebMIdContentSignature},
247 {BINARY, kWebMIdContentSigKeyID},
248 {UINT, kWebMIdContentSigAlgo},
249 {UINT, kWebMIdContentSigHashAlgo},
252 static const ElementIdInfo kContentEncAESSettingsIds[] = {
253 {UINT, kWebMIdAESSettingsCipherMode},
256 static const ElementIdInfo kCuesIds[] = {
257 {LIST, kWebMIdCuePoint},
260 static const ElementIdInfo kCuePointIds[] = {
261 {UINT, kWebMIdCueTime},
262 {LIST, kWebMIdCueTrackPositions},
265 static const ElementIdInfo kCueTrackPositionsIds[] = {
266 {UINT, kWebMIdCueTrack},
267 {UINT, kWebMIdCueClusterPosition},
268 {UINT, kWebMIdCueBlockNumber},
269 {UINT, kWebMIdCueCodecState},
270 {LIST, kWebMIdCueReference},
273 static const ElementIdInfo kCueReferenceIds[] = {
274 {UINT, kWebMIdCueRefTime},
277 static const ElementIdInfo kAttachmentsIds[] = {
278 {LIST, kWebMIdAttachedFile},
281 static const ElementIdInfo kAttachedFileIds[] = {
282 {STRING, kWebMIdFileDescription},
283 {STRING, kWebMIdFileName},
284 {STRING, kWebMIdFileMimeType},
285 {BINARY, kWebMIdFileData},
286 {UINT, kWebMIdFileUID},
289 static const ElementIdInfo kChaptersIds[] = {
290 {LIST, kWebMIdEditionEntry},
293 static const ElementIdInfo kEditionEntryIds[] = {
294 {UINT, kWebMIdEditionUID},
295 {UINT, kWebMIdEditionFlagHidden},
296 {UINT, kWebMIdEditionFlagDefault},
297 {UINT, kWebMIdEditionFlagOrdered},
298 {LIST, kWebMIdChapterAtom},
301 static const ElementIdInfo kChapterAtomIds[] = {
302 {UINT, kWebMIdChapterUID},
303 {UINT, kWebMIdChapterTimeStart},
304 {UINT, kWebMIdChapterTimeEnd},
305 {UINT, kWebMIdChapterFlagHidden},
306 {UINT, kWebMIdChapterFlagEnabled},
307 {BINARY, kWebMIdChapterSegmentUID},
308 {UINT, kWebMIdChapterSegmentEditionUID},
309 {UINT, kWebMIdChapterPhysicalEquiv},
310 {LIST, kWebMIdChapterTrack},
311 {LIST, kWebMIdChapterDisplay},
312 {LIST, kWebMIdChapProcess},
315 static const ElementIdInfo kChapterTrackIds[] = {
316 {UINT, kWebMIdChapterTrackNumber},
319 static const ElementIdInfo kChapterDisplayIds[] = {
320 {STRING, kWebMIdChapString},
321 {STRING, kWebMIdChapLanguage},
322 {STRING, kWebMIdChapCountry},
325 static const ElementIdInfo kChapProcessIds[] = {
326 {UINT, kWebMIdChapProcessCodecID},
327 {BINARY, kWebMIdChapProcessPrivate},
328 {LIST, kWebMIdChapProcessCommand},
331 static const ElementIdInfo kChapProcessCommandIds[] = {
332 {UINT, kWebMIdChapProcessTime},
333 {BINARY, kWebMIdChapProcessData},
336 static const ElementIdInfo kTagsIds[] = {
340 static const ElementIdInfo kTagIds[] = {
341 {LIST, kWebMIdTargets},
342 {LIST, kWebMIdSimpleTag},
345 static const ElementIdInfo kTargetsIds[] = {
346 {UINT, kWebMIdTargetTypeValue},
347 {STRING, kWebMIdTargetType},
348 {UINT, kWebMIdTagTrackUID},
349 {UINT, kWebMIdTagEditionUID},
350 {UINT, kWebMIdTagChapterUID},
351 {UINT, kWebMIdTagAttachmentUID},
354 static const ElementIdInfo kSimpleTagIds[] = {
355 {STRING, kWebMIdTagName},
356 {STRING, kWebMIdTagLanguage},
357 {UINT, kWebMIdTagDefault},
358 {STRING, kWebMIdTagString},
359 {BINARY, kWebMIdTagBinary},
362 #define LIST_ELEMENT_INFO(id, level, id_info) \
363 { (id), (level), (id_info), arraysize(id_info) }
365 static const ListElementInfo kListElementInfo[] = {
366 LIST_ELEMENT_INFO(kWebMIdCluster, 1, kClusterIds),
367 LIST_ELEMENT_INFO(kWebMIdEBMLHeader, 0, kEBMLHeaderIds),
368 LIST_ELEMENT_INFO(kWebMIdSegment, 0, kSegmentIds),
369 LIST_ELEMENT_INFO(kWebMIdSeekHead, 1, kSeekHeadIds),
370 LIST_ELEMENT_INFO(kWebMIdSeek, 2, kSeekIds),
371 LIST_ELEMENT_INFO(kWebMIdInfo, 1, kInfoIds),
372 LIST_ELEMENT_INFO(kWebMIdChapterTranslate, 2, kChapterTranslateIds),
373 LIST_ELEMENT_INFO(kWebMIdSilentTracks, 2, kSilentTracksIds),
374 LIST_ELEMENT_INFO(kWebMIdBlockGroup, 2, kBlockGroupIds),
375 LIST_ELEMENT_INFO(kWebMIdBlockAdditions, 3, kBlockAdditionsIds),
376 LIST_ELEMENT_INFO(kWebMIdBlockMore, 4, kBlockMoreIds),
377 LIST_ELEMENT_INFO(kWebMIdSlices, 3, kSlicesIds),
378 LIST_ELEMENT_INFO(kWebMIdTimeSlice, 4, kTimeSliceIds),
379 LIST_ELEMENT_INFO(kWebMIdTracks, 1, kTracksIds),
380 LIST_ELEMENT_INFO(kWebMIdTrackEntry, 2, kTrackEntryIds),
381 LIST_ELEMENT_INFO(kWebMIdTrackTranslate, 3, kTrackTranslateIds),
382 LIST_ELEMENT_INFO(kWebMIdVideo, 3, kVideoIds),
383 LIST_ELEMENT_INFO(kWebMIdAudio, 3, kAudioIds),
384 LIST_ELEMENT_INFO(kWebMIdTrackOperation, 3, kTrackOperationIds),
385 LIST_ELEMENT_INFO(kWebMIdTrackCombinePlanes, 4, kTrackCombinePlanesIds),
386 LIST_ELEMENT_INFO(kWebMIdTrackPlane, 5, kTrackPlaneIds),
387 LIST_ELEMENT_INFO(kWebMIdJoinBlocks, 4, kJoinBlocksIds),
388 LIST_ELEMENT_INFO(kWebMIdContentEncodings, 3, kContentEncodingsIds),
389 LIST_ELEMENT_INFO(kWebMIdContentEncoding, 4, kContentEncodingIds),
390 LIST_ELEMENT_INFO(kWebMIdContentCompression, 5, kContentCompressionIds),
391 LIST_ELEMENT_INFO(kWebMIdContentEncryption, 5, kContentEncryptionIds),
392 LIST_ELEMENT_INFO(kWebMIdContentEncAESSettings, 6, kContentEncAESSettingsIds),
393 LIST_ELEMENT_INFO(kWebMIdCues, 1, kCuesIds),
394 LIST_ELEMENT_INFO(kWebMIdCuePoint, 2, kCuePointIds),
395 LIST_ELEMENT_INFO(kWebMIdCueTrackPositions, 3, kCueTrackPositionsIds),
396 LIST_ELEMENT_INFO(kWebMIdCueReference, 4, kCueReferenceIds),
397 LIST_ELEMENT_INFO(kWebMIdAttachments, 1, kAttachmentsIds),
398 LIST_ELEMENT_INFO(kWebMIdAttachedFile, 2, kAttachedFileIds),
399 LIST_ELEMENT_INFO(kWebMIdChapters, 1, kChaptersIds),
400 LIST_ELEMENT_INFO(kWebMIdEditionEntry, 2, kEditionEntryIds),
401 LIST_ELEMENT_INFO(kWebMIdChapterAtom, 3, kChapterAtomIds),
402 LIST_ELEMENT_INFO(kWebMIdChapterTrack, 4, kChapterTrackIds),
403 LIST_ELEMENT_INFO(kWebMIdChapterDisplay, 4, kChapterDisplayIds),
404 LIST_ELEMENT_INFO(kWebMIdChapProcess, 4, kChapProcessIds),
405 LIST_ELEMENT_INFO(kWebMIdChapProcessCommand, 5, kChapProcessCommandIds),
406 LIST_ELEMENT_INFO(kWebMIdTags, 1, kTagsIds),
407 LIST_ELEMENT_INFO(kWebMIdTag, 2, kTagIds),
408 LIST_ELEMENT_INFO(kWebMIdTargets, 3, kTargetsIds),
409 LIST_ELEMENT_INFO(kWebMIdSimpleTag, 3, kSimpleTagIds),
412 // Parses an element header id or size field. These fields are variable length
413 // encoded. The first byte indicates how many bytes the field occupies.
414 // |buf| - The buffer to parse.
415 // |size| - The number of bytes in |buf|
416 // |max_bytes| - The maximum number of bytes the field can be. ID fields
417 // set this to 4 & element size fields set this to 8. If the
418 // first byte indicates a larger field size than this it is a
420 // |mask_first_byte| - For element size fields the field length encoding bits
421 // need to be masked off. This parameter is true for
422 // element size fields and is false for ID field values.
424 // Returns: The number of bytes parsed on success. -1 on error.
425 static int ParseWebMElementHeaderField(const uint8* buf, int size,
426 int max_bytes, bool mask_first_byte,
439 int extra_bytes = -1;
440 bool all_ones = false;
441 for (int i = 0; i < max_bytes; ++i) {
442 if ((ch & mask) != 0) {
444 *num = mask_first_byte ? ch & mask : ch;
445 all_ones = (ch & mask) == mask;
449 mask = 0x80 | mask >> 1;
452 if (extra_bytes == -1)
455 // Return 0 if we need more data.
456 if ((1 + extra_bytes) > size)
461 for (int i = 0; i < extra_bytes; ++i) {
462 ch = buf[bytes_used++];
463 all_ones &= (ch == 0xff);
464 *num = (*num << 8) | ch;
473 int WebMParseElementHeader(const uint8* buf, int size,
474 int* id, int64* element_size) {
478 DCHECK(element_size);
484 int num_id_bytes = ParseWebMElementHeaderField(buf, size, 4, false, &tmp);
486 if (num_id_bytes <= 0)
489 if (tmp == kint64max)
490 tmp = kWebMReservedId;
492 *id = static_cast<int>(tmp);
494 int num_size_bytes = ParseWebMElementHeaderField(buf + num_id_bytes,
498 if (num_size_bytes <= 0)
499 return num_size_bytes;
501 if (tmp == kint64max)
502 tmp = kWebMUnknownSize;
505 DVLOG(3) << "WebMParseElementHeader() : id " << std::hex << *id << std::dec
506 << " size " << *element_size;
507 return num_id_bytes + num_size_bytes;
510 // Finds ElementType for a specific ID.
511 static ElementType FindIdType(int id,
512 const ElementIdInfo* id_info,
515 // Check for global element IDs that can be anywhere.
516 if (id == kWebMIdVoid || id == kWebMIdCRC32)
519 for (int i = 0; i < id_info_count; ++i) {
520 if (id == id_info[i].id_)
521 return id_info[i].type_;
527 // Finds ListElementInfo for a specific ID.
528 static const ListElementInfo* FindListInfo(int id) {
529 for (size_t i = 0; i < arraysize(kListElementInfo); ++i) {
530 if (id == kListElementInfo[i].id_)
531 return &kListElementInfo[i];
537 static int FindListLevel(int id) {
538 const ListElementInfo* list_info = FindListInfo(id);
540 return list_info->level_;
545 static int ParseUInt(const uint8* buf, int size, int id,
546 WebMParserClient* client) {
547 if ((size <= 0) || (size > 8))
550 // Read in the big-endian integer.
552 for (int i = 0; i < size; ++i)
553 value = (value << 8) | buf[i];
555 if (!client->OnUInt(id, value))
561 static int ParseFloat(const uint8* buf, int size, int id,
562 WebMParserClient* client) {
564 if ((size != 4) && (size != 8))
569 // Read the bytes from big-endian form into a native endian integer.
571 for (int i = 0; i < size; ++i)
572 tmp = (tmp << 8) | buf[i];
574 // Use a union to convert the integer bit pattern into a floating point
581 tmp2.src = static_cast<int32>(tmp);
583 } else if (size == 8) {
594 if (!client->OnFloat(id, value))
600 static int ParseBinary(const uint8* buf, int size, int id,
601 WebMParserClient* client) {
602 return client->OnBinary(id, buf, size) ? size : -1;
605 static int ParseString(const uint8* buf, int size, int id,
606 WebMParserClient* client) {
607 const uint8* end = static_cast<const uint8*>(memchr(buf, '\0', size));
608 int length = (end != NULL) ? static_cast<int>(end - buf) : size;
609 std::string str(reinterpret_cast<const char*>(buf), length);
610 return client->OnString(id, str) ? size : -1;
613 static int ParseNonListElement(ElementType type, int id, int64 element_size,
614 const uint8* buf, int size,
615 WebMParserClient* client) {
616 DCHECK_GE(size, element_size);
625 result = ParseUInt(buf, element_size, id, client);
628 result = ParseFloat(buf, element_size, id, client);
631 result = ParseBinary(buf, element_size, id, client);
634 result = ParseString(buf, element_size, id, client);
637 result = element_size;
640 DVLOG(1) << "Unhandled ID type " << type;
644 DCHECK_LE(result, size);
648 WebMParserClient::WebMParserClient() {}
649 WebMParserClient::~WebMParserClient() {}
651 WebMParserClient* WebMParserClient::OnListStart(int id) {
652 DVLOG(1) << "Unexpected list element start with ID " << std::hex << id;
656 bool WebMParserClient::OnListEnd(int id) {
657 DVLOG(1) << "Unexpected list element end with ID " << std::hex << id;
661 bool WebMParserClient::OnUInt(int id, int64 val) {
662 DVLOG(1) << "Unexpected unsigned integer element with ID " << std::hex << id;
666 bool WebMParserClient::OnFloat(int id, double val) {
667 DVLOG(1) << "Unexpected float element with ID " << std::hex << id;
671 bool WebMParserClient::OnBinary(int id, const uint8* data, int size) {
672 DVLOG(1) << "Unexpected binary element with ID " << std::hex << id;
676 bool WebMParserClient::OnString(int id, const std::string& str) {
677 DVLOG(1) << "Unexpected string element with ID " << std::hex << id;
681 WebMListParser::WebMListParser(int id, WebMParserClient* client)
682 : state_(NEED_LIST_HEADER),
684 root_level_(FindListLevel(id)),
685 root_client_(client) {
686 DCHECK_GE(root_level_, 0);
690 WebMListParser::~WebMListParser() {}
692 void WebMListParser::Reset() {
693 ChangeState(NEED_LIST_HEADER);
694 list_state_stack_.clear();
697 int WebMListParser::Parse(const uint8* buf, int size) {
700 if (size < 0 || state_ == PARSE_ERROR || state_ == DONE_PARSING_LIST)
706 const uint8* cur = buf;
708 int bytes_parsed = 0;
710 while (cur_size > 0 && state_ != PARSE_ERROR && state_ != DONE_PARSING_LIST) {
712 int64 element_size = 0;
713 int result = WebMParseElementHeader(cur, cur_size, &element_id,
723 case NEED_LIST_HEADER: {
724 if (element_id != root_id_) {
725 ChangeState(PARSE_ERROR);
729 // Only allow Segment & Cluster to have an unknown size.
730 if (element_size == kWebMUnknownSize &&
731 (element_id != kWebMIdSegment) &&
732 (element_id != kWebMIdCluster)) {
733 ChangeState(PARSE_ERROR);
737 ChangeState(INSIDE_LIST);
738 if (!OnListStart(root_id_, element_size))
745 int header_size = result;
746 const uint8* element_data = cur + header_size;
747 int element_data_size = cur_size - header_size;
749 if (element_size < element_data_size)
750 element_data_size = element_size;
752 result = ParseListElement(header_size, element_id, element_size,
753 element_data, element_data_size);
755 DCHECK_LE(result, header_size + element_data_size);
757 ChangeState(PARSE_ERROR);
766 case DONE_PARSING_LIST:
768 // Shouldn't be able to get here.
775 bytes_parsed += result;
778 return (state_ == PARSE_ERROR) ? -1 : bytes_parsed;
781 bool WebMListParser::IsParsingComplete() const {
782 return state_ == DONE_PARSING_LIST;
785 void WebMListParser::ChangeState(State new_state) {
789 int WebMListParser::ParseListElement(int header_size,
790 int id, int64 element_size,
791 const uint8* data, int size) {
792 DCHECK_GT(list_state_stack_.size(), 0u);
794 ListState& list_state = list_state_stack_.back();
795 DCHECK(list_state.element_info_);
797 const ListElementInfo* element_info = list_state.element_info_;
798 ElementType id_type =
799 FindIdType(id, element_info->id_info_, element_info->id_info_count_);
802 if (id_type == UNKNOWN) {
803 if (list_state.size_ != kWebMUnknownSize ||
804 !IsSiblingOrAncestor(list_state.id_, id)) {
805 DVLOG(1) << "No ElementType info for ID 0x" << std::hex << id;
809 // We've reached the end of a list of unknown size. Update the size now that
810 // we know it and dispatch the end of list calls.
811 list_state.size_ = list_state.bytes_parsed_;
816 // Check to see if all open lists have ended.
817 if (list_state_stack_.size() == 0)
820 list_state = list_state_stack_.back();
823 // Make sure the whole element can fit inside the current list.
824 int64 total_element_size = header_size + element_size;
825 if (list_state.size_ != kWebMUnknownSize &&
826 list_state.size_ < list_state.bytes_parsed_ + total_element_size) {
830 if (id_type == LIST) {
831 list_state.bytes_parsed_ += header_size;
833 if (!OnListStart(id, element_size))
838 // Make sure we have the entire element before trying to parse a non-list
840 if (size < element_size)
843 int bytes_parsed = ParseNonListElement(id_type, id, element_size,
844 data, size, list_state.client_);
845 DCHECK_LE(bytes_parsed, size);
847 // Return if an error occurred or we need more data.
848 // Note: bytes_parsed is 0 for a successful parse of a size 0 element. We
849 // need to check the element_size to disambiguate the "need more data" case
850 // from a successful parse.
851 if (bytes_parsed < 0 || (bytes_parsed == 0 && element_size != 0))
854 int result = header_size + bytes_parsed;
855 list_state.bytes_parsed_ += result;
857 // See if we have reached the end of the current list.
858 if (list_state.bytes_parsed_ == list_state.size_) {
866 bool WebMListParser::OnListStart(int id, int64 size) {
867 const ListElementInfo* element_info = FindListInfo(id);
871 int current_level = root_level_ + list_state_stack_.size() - 1;
872 if (current_level + 1 != element_info->level_)
875 WebMParserClient* current_list_client = NULL;
876 if (!list_state_stack_.empty()) {
877 // Make sure the new list doesn't go past the end of the current list.
878 ListState current_list_state = list_state_stack_.back();
879 if (current_list_state.size_ != kWebMUnknownSize &&
880 current_list_state.size_ < current_list_state.bytes_parsed_ + size)
882 current_list_client = current_list_state.client_;
884 current_list_client = root_client_;
887 WebMParserClient* new_list_client = current_list_client->OnListStart(id);
888 if (!new_list_client)
891 ListState new_list_state = { id, size, 0, element_info, new_list_client };
892 list_state_stack_.push_back(new_list_state);
900 bool WebMListParser::OnListEnd() {
902 for (; !list_state_stack_.empty(); ++lists_ended) {
903 const ListState& list_state = list_state_stack_.back();
905 if (list_state.bytes_parsed_ != list_state.size_)
908 list_state_stack_.pop_back();
910 int64 bytes_parsed = list_state.bytes_parsed_;
911 WebMParserClient* client = NULL;
912 if (!list_state_stack_.empty()) {
913 // Update the bytes_parsed_ for the parent element.
914 list_state_stack_.back().bytes_parsed_ += bytes_parsed;
915 client = list_state_stack_.back().client_;
917 client = root_client_;
920 if (!client->OnListEnd(list_state.id_))
924 DCHECK_GE(lists_ended, 1);
926 if (list_state_stack_.empty())
927 ChangeState(DONE_PARSING_LIST);
932 bool WebMListParser::IsSiblingOrAncestor(int id_a, int id_b) const {
933 DCHECK((id_a == kWebMIdSegment) || (id_a == kWebMIdCluster));
935 if (id_a == kWebMIdCluster) {
936 // kWebMIdCluster siblings.
937 for (size_t i = 0; i < arraysize(kSegmentIds); i++) {
938 if (kSegmentIds[i].id_ == id_b)
943 // kWebMIdSegment siblings.
944 return ((id_b == kWebMIdSegment) || (id_b == kWebMIdEBMLHeader));