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.
5 #include "media/formats/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 "base/numerics/safe_conversions.h"
18 #include "media/formats/webm/webm_constants.h"
24 LIST
, // Referred to as Master Element in the Matroska spec.
32 struct ElementIdInfo
{
37 struct ListElementInfo
{
40 const ElementIdInfo
* id_info_
;
44 // The following are tables indicating what IDs are valid sub-elements
45 // of particular elements. If an element is encountered that doesn't
46 // appear in the list, a parsing error is signalled. Some elements are
47 // marked as SKIP because they are valid, but we don't care about them
49 static const ElementIdInfo kEBMLHeaderIds
[] = {
50 {UINT
, kWebMIdEBMLVersion
},
51 {UINT
, kWebMIdEBMLReadVersion
},
52 {UINT
, kWebMIdEBMLMaxIDLength
},
53 {UINT
, kWebMIdEBMLMaxSizeLength
},
54 {STRING
, kWebMIdDocType
},
55 {UINT
, kWebMIdDocTypeVersion
},
56 {UINT
, kWebMIdDocTypeReadVersion
},
59 static const ElementIdInfo kSegmentIds
[] = {
60 {LIST
, kWebMIdSeekHead
},
62 {LIST
, kWebMIdCluster
},
63 {LIST
, kWebMIdTracks
},
65 {LIST
, kWebMIdAttachments
},
66 {LIST
, kWebMIdChapters
},
70 static const ElementIdInfo kSeekHeadIds
[] = {
74 static const ElementIdInfo kSeekIds
[] = {
75 {BINARY
, kWebMIdSeekID
},
76 {UINT
, kWebMIdSeekPosition
},
79 static const ElementIdInfo kInfoIds
[] = {
80 {BINARY
, kWebMIdSegmentUID
},
81 {STRING
, kWebMIdSegmentFilename
},
82 {BINARY
, kWebMIdPrevUID
},
83 {STRING
, kWebMIdPrevFilename
},
84 {BINARY
, kWebMIdNextUID
},
85 {STRING
, kWebMIdNextFilename
},
86 {BINARY
, kWebMIdSegmentFamily
},
87 {LIST
, kWebMIdChapterTranslate
},
88 {UINT
, kWebMIdTimecodeScale
},
89 {FLOAT
, kWebMIdDuration
},
90 {BINARY
, kWebMIdDateUTC
},
91 {STRING
, kWebMIdTitle
},
92 {STRING
, kWebMIdMuxingApp
},
93 {STRING
, kWebMIdWritingApp
},
96 static const ElementIdInfo kChapterTranslateIds
[] = {
97 {UINT
, kWebMIdChapterTranslateEditionUID
},
98 {UINT
, kWebMIdChapterTranslateCodec
},
99 {BINARY
, kWebMIdChapterTranslateID
},
102 static const ElementIdInfo kClusterIds
[] = {
103 {BINARY
, kWebMIdSimpleBlock
},
104 {UINT
, kWebMIdTimecode
},
105 {LIST
, kWebMIdSilentTracks
},
106 {UINT
, kWebMIdPosition
},
107 {UINT
, kWebMIdPrevSize
},
108 {LIST
, kWebMIdBlockGroup
},
111 static const ElementIdInfo kSilentTracksIds
[] = {
112 {UINT
, kWebMIdSilentTrackNumber
},
115 static const ElementIdInfo kBlockGroupIds
[] = {
116 {BINARY
, kWebMIdBlock
},
117 {LIST
, kWebMIdBlockAdditions
},
118 {UINT
, kWebMIdBlockDuration
},
119 {UINT
, kWebMIdReferencePriority
},
120 {BINARY
, kWebMIdReferenceBlock
},
121 {BINARY
, kWebMIdCodecState
},
122 {BINARY
, kWebMIdDiscardPadding
},
123 {LIST
, kWebMIdSlices
},
126 static const ElementIdInfo kBlockAdditionsIds
[] = {
127 {LIST
, kWebMIdBlockMore
},
130 static const ElementIdInfo kBlockMoreIds
[] = {
131 {UINT
, kWebMIdBlockAddID
},
132 {BINARY
, kWebMIdBlockAdditional
},
135 static const ElementIdInfo kSlicesIds
[] = {
136 {LIST
, kWebMIdTimeSlice
},
139 static const ElementIdInfo kTimeSliceIds
[] = {
140 {UINT
, kWebMIdLaceNumber
},
143 static const ElementIdInfo kTracksIds
[] = {
144 {LIST
, kWebMIdTrackEntry
},
147 static const ElementIdInfo kTrackEntryIds
[] = {
148 {UINT
, kWebMIdTrackNumber
},
149 {BINARY
, kWebMIdTrackUID
},
150 {UINT
, kWebMIdTrackType
},
151 {UINT
, kWebMIdFlagEnabled
},
152 {UINT
, kWebMIdFlagDefault
},
153 {UINT
, kWebMIdFlagForced
},
154 {UINT
, kWebMIdFlagLacing
},
155 {UINT
, kWebMIdMinCache
},
156 {UINT
, kWebMIdMaxCache
},
157 {UINT
, kWebMIdDefaultDuration
},
158 {FLOAT
, kWebMIdTrackTimecodeScale
},
159 {UINT
, kWebMIdMaxBlockAdditionId
},
160 {STRING
, kWebMIdName
},
161 {STRING
, kWebMIdLanguage
},
162 {STRING
, kWebMIdCodecID
},
163 {BINARY
, kWebMIdCodecPrivate
},
164 {STRING
, kWebMIdCodecName
},
165 {UINT
, kWebMIdAttachmentLink
},
166 {UINT
, kWebMIdCodecDecodeAll
},
167 {UINT
, kWebMIdTrackOverlay
},
168 {UINT
, kWebMIdCodecDelay
},
169 {UINT
, kWebMIdSeekPreRoll
},
170 {LIST
, kWebMIdTrackTranslate
},
171 {LIST
, kWebMIdVideo
},
172 {LIST
, kWebMIdAudio
},
173 {LIST
, kWebMIdTrackOperation
},
174 {LIST
, kWebMIdContentEncodings
},
177 static const ElementIdInfo kTrackTranslateIds
[] = {
178 {UINT
, kWebMIdTrackTranslateEditionUID
},
179 {UINT
, kWebMIdTrackTranslateCodec
},
180 {BINARY
, kWebMIdTrackTranslateTrackID
},
183 static const ElementIdInfo kVideoIds
[] = {
184 {UINT
, kWebMIdFlagInterlaced
},
185 {UINT
, kWebMIdStereoMode
},
186 {UINT
, kWebMIdAlphaMode
},
187 {UINT
, kWebMIdPixelWidth
},
188 {UINT
, kWebMIdPixelHeight
},
189 {UINT
, kWebMIdPixelCropBottom
},
190 {UINT
, kWebMIdPixelCropTop
},
191 {UINT
, kWebMIdPixelCropLeft
},
192 {UINT
, kWebMIdPixelCropRight
},
193 {UINT
, kWebMIdDisplayWidth
},
194 {UINT
, kWebMIdDisplayHeight
},
195 {UINT
, kWebMIdDisplayUnit
},
196 {UINT
, kWebMIdAspectRatioType
},
197 {BINARY
, kWebMIdColorSpace
},
198 {FLOAT
, kWebMIdFrameRate
},
201 static const ElementIdInfo kAudioIds
[] = {
202 {FLOAT
, kWebMIdSamplingFrequency
},
203 {FLOAT
, kWebMIdOutputSamplingFrequency
},
204 {UINT
, kWebMIdChannels
},
205 {UINT
, kWebMIdBitDepth
},
208 static const ElementIdInfo kTrackOperationIds
[] = {
209 {LIST
, kWebMIdTrackCombinePlanes
},
210 {LIST
, kWebMIdJoinBlocks
},
213 static const ElementIdInfo kTrackCombinePlanesIds
[] = {
214 {LIST
, kWebMIdTrackPlane
},
217 static const ElementIdInfo kTrackPlaneIds
[] = {
218 {UINT
, kWebMIdTrackPlaneUID
},
219 {UINT
, kWebMIdTrackPlaneType
},
222 static const ElementIdInfo kJoinBlocksIds
[] = {
223 {UINT
, kWebMIdTrackJoinUID
},
226 static const ElementIdInfo kContentEncodingsIds
[] = {
227 {LIST
, kWebMIdContentEncoding
},
230 static const ElementIdInfo kContentEncodingIds
[] = {
231 {UINT
, kWebMIdContentEncodingOrder
},
232 {UINT
, kWebMIdContentEncodingScope
},
233 {UINT
, kWebMIdContentEncodingType
},
234 {LIST
, kWebMIdContentCompression
},
235 {LIST
, kWebMIdContentEncryption
},
238 static const ElementIdInfo kContentCompressionIds
[] = {
239 {UINT
, kWebMIdContentCompAlgo
},
240 {BINARY
, kWebMIdContentCompSettings
},
243 static const ElementIdInfo kContentEncryptionIds
[] = {
244 {LIST
, kWebMIdContentEncAESSettings
},
245 {UINT
, kWebMIdContentEncAlgo
},
246 {BINARY
, kWebMIdContentEncKeyID
},
247 {BINARY
, kWebMIdContentSignature
},
248 {BINARY
, kWebMIdContentSigKeyID
},
249 {UINT
, kWebMIdContentSigAlgo
},
250 {UINT
, kWebMIdContentSigHashAlgo
},
253 static const ElementIdInfo kContentEncAESSettingsIds
[] = {
254 {UINT
, kWebMIdAESSettingsCipherMode
},
257 static const ElementIdInfo kCuesIds
[] = {
258 {LIST
, kWebMIdCuePoint
},
261 static const ElementIdInfo kCuePointIds
[] = {
262 {UINT
, kWebMIdCueTime
},
263 {LIST
, kWebMIdCueTrackPositions
},
266 static const ElementIdInfo kCueTrackPositionsIds
[] = {
267 {UINT
, kWebMIdCueTrack
},
268 {UINT
, kWebMIdCueClusterPosition
},
269 {UINT
, kWebMIdCueBlockNumber
},
270 {UINT
, kWebMIdCueCodecState
},
271 {LIST
, kWebMIdCueReference
},
274 static const ElementIdInfo kCueReferenceIds
[] = {
275 {UINT
, kWebMIdCueRefTime
},
278 static const ElementIdInfo kAttachmentsIds
[] = {
279 {LIST
, kWebMIdAttachedFile
},
282 static const ElementIdInfo kAttachedFileIds
[] = {
283 {STRING
, kWebMIdFileDescription
},
284 {STRING
, kWebMIdFileName
},
285 {STRING
, kWebMIdFileMimeType
},
286 {BINARY
, kWebMIdFileData
},
287 {UINT
, kWebMIdFileUID
},
290 static const ElementIdInfo kChaptersIds
[] = {
291 {LIST
, kWebMIdEditionEntry
},
294 static const ElementIdInfo kEditionEntryIds
[] = {
295 {UINT
, kWebMIdEditionUID
},
296 {UINT
, kWebMIdEditionFlagHidden
},
297 {UINT
, kWebMIdEditionFlagDefault
},
298 {UINT
, kWebMIdEditionFlagOrdered
},
299 {LIST
, kWebMIdChapterAtom
},
302 static const ElementIdInfo kChapterAtomIds
[] = {
303 {UINT
, kWebMIdChapterUID
},
304 {UINT
, kWebMIdChapterTimeStart
},
305 {UINT
, kWebMIdChapterTimeEnd
},
306 {UINT
, kWebMIdChapterFlagHidden
},
307 {UINT
, kWebMIdChapterFlagEnabled
},
308 {BINARY
, kWebMIdChapterSegmentUID
},
309 {UINT
, kWebMIdChapterSegmentEditionUID
},
310 {UINT
, kWebMIdChapterPhysicalEquiv
},
311 {LIST
, kWebMIdChapterTrack
},
312 {LIST
, kWebMIdChapterDisplay
},
313 {LIST
, kWebMIdChapProcess
},
316 static const ElementIdInfo kChapterTrackIds
[] = {
317 {UINT
, kWebMIdChapterTrackNumber
},
320 static const ElementIdInfo kChapterDisplayIds
[] = {
321 {STRING
, kWebMIdChapString
},
322 {STRING
, kWebMIdChapLanguage
},
323 {STRING
, kWebMIdChapCountry
},
326 static const ElementIdInfo kChapProcessIds
[] = {
327 {UINT
, kWebMIdChapProcessCodecID
},
328 {BINARY
, kWebMIdChapProcessPrivate
},
329 {LIST
, kWebMIdChapProcessCommand
},
332 static const ElementIdInfo kChapProcessCommandIds
[] = {
333 {UINT
, kWebMIdChapProcessTime
},
334 {BINARY
, kWebMIdChapProcessData
},
337 static const ElementIdInfo kTagsIds
[] = {
341 static const ElementIdInfo kTagIds
[] = {
342 {LIST
, kWebMIdTargets
},
343 {LIST
, kWebMIdSimpleTag
},
346 static const ElementIdInfo kTargetsIds
[] = {
347 {UINT
, kWebMIdTargetTypeValue
},
348 {STRING
, kWebMIdTargetType
},
349 {UINT
, kWebMIdTagTrackUID
},
350 {UINT
, kWebMIdTagEditionUID
},
351 {UINT
, kWebMIdTagChapterUID
},
352 {UINT
, kWebMIdTagAttachmentUID
},
355 static const ElementIdInfo kSimpleTagIds
[] = {
356 {STRING
, kWebMIdTagName
},
357 {STRING
, kWebMIdTagLanguage
},
358 {UINT
, kWebMIdTagDefault
},
359 {STRING
, kWebMIdTagString
},
360 {BINARY
, kWebMIdTagBinary
},
363 #define LIST_ELEMENT_INFO(id, level, id_info) \
364 { (id), (level), (id_info), arraysize(id_info) }
366 static const ListElementInfo kListElementInfo
[] = {
367 LIST_ELEMENT_INFO(kWebMIdCluster
, 1, kClusterIds
),
368 LIST_ELEMENT_INFO(kWebMIdEBMLHeader
, 0, kEBMLHeaderIds
),
369 LIST_ELEMENT_INFO(kWebMIdSegment
, 0, kSegmentIds
),
370 LIST_ELEMENT_INFO(kWebMIdSeekHead
, 1, kSeekHeadIds
),
371 LIST_ELEMENT_INFO(kWebMIdSeek
, 2, kSeekIds
),
372 LIST_ELEMENT_INFO(kWebMIdInfo
, 1, kInfoIds
),
373 LIST_ELEMENT_INFO(kWebMIdChapterTranslate
, 2, kChapterTranslateIds
),
374 LIST_ELEMENT_INFO(kWebMIdSilentTracks
, 2, kSilentTracksIds
),
375 LIST_ELEMENT_INFO(kWebMIdBlockGroup
, 2, kBlockGroupIds
),
376 LIST_ELEMENT_INFO(kWebMIdBlockAdditions
, 3, kBlockAdditionsIds
),
377 LIST_ELEMENT_INFO(kWebMIdBlockMore
, 4, kBlockMoreIds
),
378 LIST_ELEMENT_INFO(kWebMIdSlices
, 3, kSlicesIds
),
379 LIST_ELEMENT_INFO(kWebMIdTimeSlice
, 4, kTimeSliceIds
),
380 LIST_ELEMENT_INFO(kWebMIdTracks
, 1, kTracksIds
),
381 LIST_ELEMENT_INFO(kWebMIdTrackEntry
, 2, kTrackEntryIds
),
382 LIST_ELEMENT_INFO(kWebMIdTrackTranslate
, 3, kTrackTranslateIds
),
383 LIST_ELEMENT_INFO(kWebMIdVideo
, 3, kVideoIds
),
384 LIST_ELEMENT_INFO(kWebMIdAudio
, 3, kAudioIds
),
385 LIST_ELEMENT_INFO(kWebMIdTrackOperation
, 3, kTrackOperationIds
),
386 LIST_ELEMENT_INFO(kWebMIdTrackCombinePlanes
, 4, kTrackCombinePlanesIds
),
387 LIST_ELEMENT_INFO(kWebMIdTrackPlane
, 5, kTrackPlaneIds
),
388 LIST_ELEMENT_INFO(kWebMIdJoinBlocks
, 4, kJoinBlocksIds
),
389 LIST_ELEMENT_INFO(kWebMIdContentEncodings
, 3, kContentEncodingsIds
),
390 LIST_ELEMENT_INFO(kWebMIdContentEncoding
, 4, kContentEncodingIds
),
391 LIST_ELEMENT_INFO(kWebMIdContentCompression
, 5, kContentCompressionIds
),
392 LIST_ELEMENT_INFO(kWebMIdContentEncryption
, 5, kContentEncryptionIds
),
393 LIST_ELEMENT_INFO(kWebMIdContentEncAESSettings
, 6, kContentEncAESSettingsIds
),
394 LIST_ELEMENT_INFO(kWebMIdCues
, 1, kCuesIds
),
395 LIST_ELEMENT_INFO(kWebMIdCuePoint
, 2, kCuePointIds
),
396 LIST_ELEMENT_INFO(kWebMIdCueTrackPositions
, 3, kCueTrackPositionsIds
),
397 LIST_ELEMENT_INFO(kWebMIdCueReference
, 4, kCueReferenceIds
),
398 LIST_ELEMENT_INFO(kWebMIdAttachments
, 1, kAttachmentsIds
),
399 LIST_ELEMENT_INFO(kWebMIdAttachedFile
, 2, kAttachedFileIds
),
400 LIST_ELEMENT_INFO(kWebMIdChapters
, 1, kChaptersIds
),
401 LIST_ELEMENT_INFO(kWebMIdEditionEntry
, 2, kEditionEntryIds
),
402 LIST_ELEMENT_INFO(kWebMIdChapterAtom
, 3, kChapterAtomIds
),
403 LIST_ELEMENT_INFO(kWebMIdChapterTrack
, 4, kChapterTrackIds
),
404 LIST_ELEMENT_INFO(kWebMIdChapterDisplay
, 4, kChapterDisplayIds
),
405 LIST_ELEMENT_INFO(kWebMIdChapProcess
, 4, kChapProcessIds
),
406 LIST_ELEMENT_INFO(kWebMIdChapProcessCommand
, 5, kChapProcessCommandIds
),
407 LIST_ELEMENT_INFO(kWebMIdTags
, 1, kTagsIds
),
408 LIST_ELEMENT_INFO(kWebMIdTag
, 2, kTagIds
),
409 LIST_ELEMENT_INFO(kWebMIdTargets
, 3, kTargetsIds
),
410 LIST_ELEMENT_INFO(kWebMIdSimpleTag
, 3, kSimpleTagIds
),
413 // Parses an element header id or size field. These fields are variable length
414 // encoded. The first byte indicates how many bytes the field occupies.
415 // |buf| - The buffer to parse.
416 // |size| - The number of bytes in |buf|
417 // |max_bytes| - The maximum number of bytes the field can be. ID fields
418 // set this to 4 & element size fields set this to 8. If the
419 // first byte indicates a larger field size than this it is a
421 // |mask_first_byte| - For element size fields the field length encoding bits
422 // need to be masked off. This parameter is true for
423 // element size fields and is false for ID field values.
425 // Returns: The number of bytes parsed on success. -1 on error.
426 static int ParseWebMElementHeaderField(const uint8
* buf
, int size
,
427 int max_bytes
, bool mask_first_byte
,
440 int extra_bytes
= -1;
441 bool all_ones
= false;
442 for (int i
= 0; i
< max_bytes
; ++i
) {
443 if ((ch
& mask
) != 0) {
445 *num
= mask_first_byte
? ch
& mask
: ch
;
446 all_ones
= (ch
& mask
) == mask
;
450 mask
= 0x80 | mask
>> 1;
453 if (extra_bytes
== -1)
456 // Return 0 if we need more data.
457 if ((1 + extra_bytes
) > size
)
462 for (int i
= 0; i
< extra_bytes
; ++i
) {
463 ch
= buf
[bytes_used
++];
464 all_ones
&= (ch
== 0xff);
465 *num
= (*num
<< 8) | ch
;
474 int WebMParseElementHeader(const uint8
* buf
, int size
,
475 int* id
, int64
* element_size
) {
479 DCHECK(element_size
);
485 int num_id_bytes
= ParseWebMElementHeaderField(buf
, size
, 4, false, &tmp
);
487 if (num_id_bytes
<= 0)
490 if (tmp
== kint64max
)
491 tmp
= kWebMReservedId
;
493 *id
= static_cast<int>(tmp
);
495 int num_size_bytes
= ParseWebMElementHeaderField(buf
+ num_id_bytes
,
499 if (num_size_bytes
<= 0)
500 return num_size_bytes
;
502 if (tmp
== kint64max
)
503 tmp
= kWebMUnknownSize
;
506 DVLOG(3) << "WebMParseElementHeader() : id " << std::hex
<< *id
<< std::dec
507 << " size " << *element_size
;
508 return num_id_bytes
+ num_size_bytes
;
511 // Finds ElementType for a specific ID.
512 static ElementType
FindIdType(int id
,
513 const ElementIdInfo
* id_info
,
516 // Check for global element IDs that can be anywhere.
517 if (id
== kWebMIdVoid
|| id
== kWebMIdCRC32
)
520 for (int i
= 0; i
< id_info_count
; ++i
) {
521 if (id
== id_info
[i
].id_
)
522 return id_info
[i
].type_
;
528 // Finds ListElementInfo for a specific ID.
529 static const ListElementInfo
* FindListInfo(int id
) {
530 for (size_t i
= 0; i
< arraysize(kListElementInfo
); ++i
) {
531 if (id
== kListElementInfo
[i
].id_
)
532 return &kListElementInfo
[i
];
538 static int FindListLevel(int id
) {
539 const ListElementInfo
* list_info
= FindListInfo(id
);
541 return list_info
->level_
;
546 static int ParseUInt(const uint8
* buf
, int size
, int id
,
547 WebMParserClient
* client
) {
548 if ((size
<= 0) || (size
> 8))
551 // Read in the big-endian integer.
553 for (int i
= 0; i
< size
; ++i
)
554 value
= (value
<< 8) | buf
[i
];
556 // We use int64 in place of uint64 everywhere for convenience. See this bug
557 // for more details: http://crbug.com/366750#c3
558 if (!base::IsValueInRangeForNumericType
<int64
>(value
))
561 if (!client
->OnUInt(id
, value
))
567 static int ParseFloat(const uint8
* buf
, int size
, int id
,
568 WebMParserClient
* client
) {
570 if ((size
!= 4) && (size
!= 8))
575 // Read the bytes from big-endian form into a native endian integer.
577 for (int i
= 0; i
< size
; ++i
)
578 tmp
= (tmp
<< 8) | buf
[i
];
580 // Use a union to convert the integer bit pattern into a floating point
587 tmp2
.src
= static_cast<int32
>(tmp
);
589 } else if (size
== 8) {
600 if (!client
->OnFloat(id
, value
))
606 static int ParseBinary(const uint8
* buf
, int size
, int id
,
607 WebMParserClient
* client
) {
608 return client
->OnBinary(id
, buf
, size
) ? size
: -1;
611 static int ParseString(const uint8
* buf
, int size
, int id
,
612 WebMParserClient
* client
) {
613 const uint8
* end
= static_cast<const uint8
*>(memchr(buf
, '\0', size
));
614 int length
= (end
!= NULL
) ? static_cast<int>(end
- buf
) : size
;
615 std::string
str(reinterpret_cast<const char*>(buf
), length
);
616 return client
->OnString(id
, str
) ? size
: -1;
619 static int ParseNonListElement(ElementType type
, int id
, int64 element_size
,
620 const uint8
* buf
, int size
,
621 WebMParserClient
* client
) {
622 DCHECK_GE(size
, element_size
);
631 result
= ParseUInt(buf
, element_size
, id
, client
);
634 result
= ParseFloat(buf
, element_size
, id
, client
);
637 result
= ParseBinary(buf
, element_size
, id
, client
);
640 result
= ParseString(buf
, element_size
, id
, client
);
643 result
= element_size
;
646 DVLOG(1) << "Unhandled ID type " << type
;
650 DCHECK_LE(result
, size
);
654 WebMParserClient::WebMParserClient() {}
655 WebMParserClient::~WebMParserClient() {}
657 WebMParserClient
* WebMParserClient::OnListStart(int id
) {
658 DVLOG(1) << "Unexpected list element start with ID " << std::hex
<< id
;
662 bool WebMParserClient::OnListEnd(int id
) {
663 DVLOG(1) << "Unexpected list element end with ID " << std::hex
<< id
;
667 bool WebMParserClient::OnUInt(int id
, int64 val
) {
668 DVLOG(1) << "Unexpected unsigned integer element with ID " << std::hex
<< id
;
672 bool WebMParserClient::OnFloat(int id
, double val
) {
673 DVLOG(1) << "Unexpected float element with ID " << std::hex
<< id
;
677 bool WebMParserClient::OnBinary(int id
, const uint8
* data
, int size
) {
678 DVLOG(1) << "Unexpected binary element with ID " << std::hex
<< id
;
682 bool WebMParserClient::OnString(int id
, const std::string
& str
) {
683 DVLOG(1) << "Unexpected string element with ID " << std::hex
<< id
;
687 WebMListParser::WebMListParser(int id
, WebMParserClient
* client
)
688 : state_(NEED_LIST_HEADER
),
690 root_level_(FindListLevel(id
)),
691 root_client_(client
) {
692 DCHECK_GE(root_level_
, 0);
696 WebMListParser::~WebMListParser() {}
698 void WebMListParser::Reset() {
699 ChangeState(NEED_LIST_HEADER
);
700 list_state_stack_
.clear();
703 int WebMListParser::Parse(const uint8
* buf
, int size
) {
706 if (size
< 0 || state_
== PARSE_ERROR
|| state_
== DONE_PARSING_LIST
)
712 const uint8
* cur
= buf
;
714 int bytes_parsed
= 0;
716 while (cur_size
> 0 && state_
!= PARSE_ERROR
&& state_
!= DONE_PARSING_LIST
) {
718 int64 element_size
= 0;
719 int result
= WebMParseElementHeader(cur
, cur_size
, &element_id
,
729 case NEED_LIST_HEADER
: {
730 if (element_id
!= root_id_
) {
731 ChangeState(PARSE_ERROR
);
735 // Only allow Segment & Cluster to have an unknown size.
736 if (element_size
== kWebMUnknownSize
&&
737 (element_id
!= kWebMIdSegment
) &&
738 (element_id
!= kWebMIdCluster
)) {
739 ChangeState(PARSE_ERROR
);
743 ChangeState(INSIDE_LIST
);
744 if (!OnListStart(root_id_
, element_size
))
751 int header_size
= result
;
752 const uint8
* element_data
= cur
+ header_size
;
753 int element_data_size
= cur_size
- header_size
;
755 if (element_size
< element_data_size
)
756 element_data_size
= element_size
;
758 result
= ParseListElement(header_size
, element_id
, element_size
,
759 element_data
, element_data_size
);
761 DCHECK_LE(result
, header_size
+ element_data_size
);
763 ChangeState(PARSE_ERROR
);
772 case DONE_PARSING_LIST
:
774 // Shouldn't be able to get here.
781 bytes_parsed
+= result
;
784 return (state_
== PARSE_ERROR
) ? -1 : bytes_parsed
;
787 bool WebMListParser::IsParsingComplete() const {
788 return state_
== DONE_PARSING_LIST
;
791 void WebMListParser::ChangeState(State new_state
) {
795 int WebMListParser::ParseListElement(int header_size
,
796 int id
, int64 element_size
,
797 const uint8
* data
, int size
) {
798 DCHECK_GT(list_state_stack_
.size(), 0u);
800 ListState
& list_state
= list_state_stack_
.back();
801 DCHECK(list_state
.element_info_
);
803 const ListElementInfo
* element_info
= list_state
.element_info_
;
804 ElementType id_type
=
805 FindIdType(id
, element_info
->id_info_
, element_info
->id_info_count_
);
808 if (id_type
== UNKNOWN
) {
809 if (list_state
.size_
!= kWebMUnknownSize
||
810 !IsSiblingOrAncestor(list_state
.id_
, id
)) {
811 DVLOG(1) << "No ElementType info for ID 0x" << std::hex
<< id
;
815 // We've reached the end of a list of unknown size. Update the size now that
816 // we know it and dispatch the end of list calls.
817 list_state
.size_
= list_state
.bytes_parsed_
;
822 // Check to see if all open lists have ended.
823 if (list_state_stack_
.size() == 0)
826 list_state
= list_state_stack_
.back();
829 // Make sure the whole element can fit inside the current list.
830 int64 total_element_size
= header_size
+ element_size
;
831 if (list_state
.size_
!= kWebMUnknownSize
&&
832 list_state
.size_
< list_state
.bytes_parsed_
+ total_element_size
) {
836 if (id_type
== LIST
) {
837 list_state
.bytes_parsed_
+= header_size
;
839 if (!OnListStart(id
, element_size
))
844 // Make sure we have the entire element before trying to parse a non-list
846 if (size
< element_size
)
849 int bytes_parsed
= ParseNonListElement(id_type
, id
, element_size
,
850 data
, size
, list_state
.client_
);
851 DCHECK_LE(bytes_parsed
, size
);
853 // Return if an error occurred or we need more data.
854 // Note: bytes_parsed is 0 for a successful parse of a size 0 element. We
855 // need to check the element_size to disambiguate the "need more data" case
856 // from a successful parse.
857 if (bytes_parsed
< 0 || (bytes_parsed
== 0 && element_size
!= 0))
860 int result
= header_size
+ bytes_parsed
;
861 list_state
.bytes_parsed_
+= result
;
863 // See if we have reached the end of the current list.
864 if (list_state
.bytes_parsed_
== list_state
.size_
) {
872 bool WebMListParser::OnListStart(int id
, int64 size
) {
873 const ListElementInfo
* element_info
= FindListInfo(id
);
877 int current_level
= root_level_
+ list_state_stack_
.size() - 1;
878 if (current_level
+ 1 != element_info
->level_
)
881 WebMParserClient
* current_list_client
= NULL
;
882 if (!list_state_stack_
.empty()) {
883 // Make sure the new list doesn't go past the end of the current list.
884 ListState current_list_state
= list_state_stack_
.back();
885 if (current_list_state
.size_
!= kWebMUnknownSize
&&
886 current_list_state
.size_
< current_list_state
.bytes_parsed_
+ size
)
888 current_list_client
= current_list_state
.client_
;
890 current_list_client
= root_client_
;
893 WebMParserClient
* new_list_client
= current_list_client
->OnListStart(id
);
894 if (!new_list_client
)
897 ListState new_list_state
= { id
, size
, 0, element_info
, new_list_client
};
898 list_state_stack_
.push_back(new_list_state
);
906 bool WebMListParser::OnListEnd() {
908 for (; !list_state_stack_
.empty(); ++lists_ended
) {
909 const ListState
& list_state
= list_state_stack_
.back();
910 int64 bytes_parsed
= list_state
.bytes_parsed_
;
911 int id
= list_state
.id_
;
913 if (bytes_parsed
!= list_state
.size_
)
916 list_state_stack_
.pop_back();
918 WebMParserClient
* client
= NULL
;
919 if (!list_state_stack_
.empty()) {
920 // Update the bytes_parsed_ for the parent element.
921 list_state_stack_
.back().bytes_parsed_
+= bytes_parsed
;
922 client
= list_state_stack_
.back().client_
;
924 client
= root_client_
;
927 if (!client
->OnListEnd(id
))
931 DCHECK_GE(lists_ended
, 1);
933 if (list_state_stack_
.empty())
934 ChangeState(DONE_PARSING_LIST
);
939 bool WebMListParser::IsSiblingOrAncestor(int id_a
, int id_b
) const {
940 DCHECK((id_a
== kWebMIdSegment
) || (id_a
== kWebMIdCluster
));
942 if (id_a
== kWebMIdCluster
) {
943 // kWebMIdCluster siblings.
944 for (size_t i
= 0; i
< arraysize(kSegmentIds
); i
++) {
945 if (kSegmentIds
[i
].id_
== id_b
)
950 // kWebMIdSegment siblings.
951 return ((id_b
== kWebMIdSegment
) || (id_b
== kWebMIdEBMLHeader
));