- add sources.
[platform/framework/web/crosswalk.git] / src / media / webm / webm_parser.cc
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.
4
5 #include "media/webm/webm_parser.h"
6
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
13
14 #include <iomanip>
15
16 #include "base/logging.h"
17 #include "media/webm/webm_constants.h"
18
19 namespace media {
20
21 enum ElementType {
22   UNKNOWN,
23   LIST,  // Referred to as Master Element in the Matroska spec.
24   UINT,
25   FLOAT,
26   BINARY,
27   STRING,
28   SKIP,
29 };
30
31 struct ElementIdInfo {
32   ElementType type_;
33   int id_;
34 };
35
36 struct ListElementInfo {
37   int id_;
38   int level_;
39   const ElementIdInfo* id_info_;
40   int id_info_count_;
41 };
42
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
47 // right now.
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},
56 };
57
58 static const ElementIdInfo kSegmentIds[] = {
59   {LIST, kWebMIdSeekHead},
60   {LIST, kWebMIdInfo},
61   {LIST, kWebMIdCluster},
62   {LIST, kWebMIdTracks},
63   {LIST, kWebMIdCues},
64   {LIST, kWebMIdAttachments},
65   {LIST, kWebMIdChapters},
66   {LIST, kWebMIdTags},
67 };
68
69 static const ElementIdInfo kSeekHeadIds[] = {
70   {LIST, kWebMIdSeek},
71 };
72
73 static const ElementIdInfo kSeekIds[] = {
74   {BINARY, kWebMIdSeekID},
75   {UINT, kWebMIdSeekPosition},
76 };
77
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},
93 };
94
95 static const ElementIdInfo kChapterTranslateIds[] = {
96   {UINT, kWebMIdChapterTranslateEditionUID},
97   {UINT, kWebMIdChapterTranslateCodec},
98   {BINARY, kWebMIdChapterTranslateID},
99 };
100
101 static const ElementIdInfo kClusterIds[] = {
102   {BINARY, kWebMIdSimpleBlock},
103   {UINT, kWebMIdTimecode},
104   {LIST, kWebMIdSilentTracks},
105   {UINT, kWebMIdPosition},
106   {UINT, kWebMIdPrevSize},
107   {LIST, kWebMIdBlockGroup},
108 };
109
110 static const ElementIdInfo kSilentTracksIds[] = {
111   {UINT, kWebMIdSilentTrackNumber},
112 };
113
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},
123 };
124
125 static const ElementIdInfo kBlockAdditionsIds[] = {
126   {LIST, kWebMIdBlockMore},
127 };
128
129 static const ElementIdInfo kBlockMoreIds[] = {
130   {UINT, kWebMIdBlockAddID},
131   {BINARY, kWebMIdBlockAdditional},
132 };
133
134 static const ElementIdInfo kSlicesIds[] = {
135   {LIST, kWebMIdTimeSlice},
136 };
137
138 static const ElementIdInfo kTimeSliceIds[] = {
139   {UINT, kWebMIdLaceNumber},
140 };
141
142 static const ElementIdInfo kTracksIds[] = {
143   {LIST, kWebMIdTrackEntry},
144 };
145
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},
174 };
175
176 static const ElementIdInfo kTrackTranslateIds[] = {
177   {UINT, kWebMIdTrackTranslateEditionUID},
178   {UINT, kWebMIdTrackTranslateCodec},
179   {BINARY, kWebMIdTrackTranslateTrackID},
180 };
181
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},
198 };
199
200 static const ElementIdInfo kAudioIds[] = {
201   {FLOAT, kWebMIdSamplingFrequency},
202   {FLOAT, kWebMIdOutputSamplingFrequency},
203   {UINT, kWebMIdChannels},
204   {UINT, kWebMIdBitDepth},
205 };
206
207 static const ElementIdInfo kTrackOperationIds[] = {
208   {LIST, kWebMIdTrackCombinePlanes},
209   {LIST, kWebMIdJoinBlocks},
210 };
211
212 static const ElementIdInfo kTrackCombinePlanesIds[] = {
213   {LIST, kWebMIdTrackPlane},
214 };
215
216 static const ElementIdInfo kTrackPlaneIds[] = {
217   {UINT, kWebMIdTrackPlaneUID},
218   {UINT, kWebMIdTrackPlaneType},
219 };
220
221 static const ElementIdInfo kJoinBlocksIds[] = {
222   {UINT, kWebMIdTrackJoinUID},
223 };
224
225 static const ElementIdInfo kContentEncodingsIds[] = {
226   {LIST, kWebMIdContentEncoding},
227 };
228
229 static const ElementIdInfo kContentEncodingIds[] = {
230   {UINT, kWebMIdContentEncodingOrder},
231   {UINT, kWebMIdContentEncodingScope},
232   {UINT, kWebMIdContentEncodingType},
233   {LIST, kWebMIdContentCompression},
234   {LIST, kWebMIdContentEncryption},
235 };
236
237 static const ElementIdInfo kContentCompressionIds[] = {
238   {UINT, kWebMIdContentCompAlgo},
239   {BINARY, kWebMIdContentCompSettings},
240 };
241
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},
250 };
251
252 static const ElementIdInfo kContentEncAESSettingsIds[] = {
253   {UINT, kWebMIdAESSettingsCipherMode},
254 };
255
256 static const ElementIdInfo kCuesIds[] = {
257   {LIST, kWebMIdCuePoint},
258 };
259
260 static const ElementIdInfo kCuePointIds[] = {
261   {UINT, kWebMIdCueTime},
262   {LIST, kWebMIdCueTrackPositions},
263 };
264
265 static const ElementIdInfo kCueTrackPositionsIds[] = {
266   {UINT, kWebMIdCueTrack},
267   {UINT, kWebMIdCueClusterPosition},
268   {UINT, kWebMIdCueBlockNumber},
269   {UINT, kWebMIdCueCodecState},
270   {LIST, kWebMIdCueReference},
271 };
272
273 static const ElementIdInfo kCueReferenceIds[] = {
274   {UINT, kWebMIdCueRefTime},
275 };
276
277 static const ElementIdInfo kAttachmentsIds[] = {
278   {LIST, kWebMIdAttachedFile},
279 };
280
281 static const ElementIdInfo kAttachedFileIds[] = {
282   {STRING, kWebMIdFileDescription},
283   {STRING, kWebMIdFileName},
284   {STRING, kWebMIdFileMimeType},
285   {BINARY, kWebMIdFileData},
286   {UINT, kWebMIdFileUID},
287 };
288
289 static const ElementIdInfo kChaptersIds[] = {
290   {LIST, kWebMIdEditionEntry},
291 };
292
293 static const ElementIdInfo kEditionEntryIds[] = {
294   {UINT, kWebMIdEditionUID},
295   {UINT, kWebMIdEditionFlagHidden},
296   {UINT, kWebMIdEditionFlagDefault},
297   {UINT, kWebMIdEditionFlagOrdered},
298   {LIST, kWebMIdChapterAtom},
299 };
300
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},
313 };
314
315 static const ElementIdInfo kChapterTrackIds[] = {
316   {UINT, kWebMIdChapterTrackNumber},
317 };
318
319 static const ElementIdInfo kChapterDisplayIds[] = {
320   {STRING, kWebMIdChapString},
321   {STRING, kWebMIdChapLanguage},
322   {STRING, kWebMIdChapCountry},
323 };
324
325 static const ElementIdInfo kChapProcessIds[] = {
326   {UINT, kWebMIdChapProcessCodecID},
327   {BINARY, kWebMIdChapProcessPrivate},
328   {LIST, kWebMIdChapProcessCommand},
329 };
330
331 static const ElementIdInfo kChapProcessCommandIds[] = {
332   {UINT, kWebMIdChapProcessTime},
333   {BINARY, kWebMIdChapProcessData},
334 };
335
336 static const ElementIdInfo kTagsIds[] = {
337   {LIST, kWebMIdTag},
338 };
339
340 static const ElementIdInfo kTagIds[] = {
341   {LIST, kWebMIdTargets},
342   {LIST, kWebMIdSimpleTag},
343 };
344
345 static const ElementIdInfo kTargetsIds[] = {
346   {UINT, kWebMIdTargetTypeValue},
347   {STRING, kWebMIdTargetType},
348   {UINT, kWebMIdTagTrackUID},
349   {UINT, kWebMIdTagEditionUID},
350   {UINT, kWebMIdTagChapterUID},
351   {UINT, kWebMIdTagAttachmentUID},
352 };
353
354 static const ElementIdInfo kSimpleTagIds[] = {
355   {STRING, kWebMIdTagName},
356   {STRING, kWebMIdTagLanguage},
357   {UINT, kWebMIdTagDefault},
358   {STRING, kWebMIdTagString},
359   {BINARY, kWebMIdTagBinary},
360 };
361
362 #define LIST_ELEMENT_INFO(id, level, id_info) \
363     { (id), (level), (id_info), arraysize(id_info) }
364
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),
410 };
411
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
419 //               parser error.
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.
423 //
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,
427                                        int64* num) {
428   DCHECK(buf);
429   DCHECK(num);
430
431   if (size < 0)
432     return -1;
433
434   if (size == 0)
435     return 0;
436
437   int mask = 0x80;
438   uint8 ch = buf[0];
439   int extra_bytes = -1;
440   bool all_ones = false;
441   for (int i = 0; i < max_bytes; ++i) {
442     if ((ch & mask) != 0) {
443       mask = ~mask & 0xff;
444       *num = mask_first_byte ? ch & mask : ch;
445       all_ones = (ch & mask) == mask;
446       extra_bytes = i;
447       break;
448     }
449     mask = 0x80 | mask >> 1;
450   }
451
452   if (extra_bytes == -1)
453     return -1;
454
455   // Return 0 if we need more data.
456   if ((1 + extra_bytes) > size)
457     return 0;
458
459   int bytes_used = 1;
460
461   for (int i = 0; i < extra_bytes; ++i) {
462     ch = buf[bytes_used++];
463     all_ones &= (ch == 0xff);
464     *num = (*num << 8) | ch;
465   }
466
467   if (all_ones)
468     *num = kint64max;
469
470   return bytes_used;
471 }
472
473 int WebMParseElementHeader(const uint8* buf, int size,
474                            int* id, int64* element_size) {
475   DCHECK(buf);
476   DCHECK_GE(size, 0);
477   DCHECK(id);
478   DCHECK(element_size);
479
480   if (size == 0)
481     return 0;
482
483   int64 tmp = 0;
484   int num_id_bytes = ParseWebMElementHeaderField(buf, size, 4, false, &tmp);
485
486   if (num_id_bytes <= 0)
487     return num_id_bytes;
488
489   if (tmp == kint64max)
490     tmp = kWebMReservedId;
491
492   *id = static_cast<int>(tmp);
493
494   int num_size_bytes = ParseWebMElementHeaderField(buf + num_id_bytes,
495                                                    size - num_id_bytes,
496                                                    8, true, &tmp);
497
498   if (num_size_bytes <= 0)
499     return num_size_bytes;
500
501   if (tmp == kint64max)
502     tmp = kWebMUnknownSize;
503
504   *element_size = tmp;
505   DVLOG(3) << "WebMParseElementHeader() : id " << std::hex << *id << std::dec
506            << " size " << *element_size;
507   return num_id_bytes + num_size_bytes;
508 }
509
510 // Finds ElementType for a specific ID.
511 static ElementType FindIdType(int id,
512                               const ElementIdInfo* id_info,
513                               int id_info_count) {
514
515   // Check for global element IDs that can be anywhere.
516   if (id == kWebMIdVoid || id == kWebMIdCRC32)
517     return SKIP;
518
519   for (int i = 0; i < id_info_count; ++i) {
520     if (id == id_info[i].id_)
521       return id_info[i].type_;
522   }
523
524   return UNKNOWN;
525 }
526
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];
532   }
533
534   return NULL;
535 }
536
537 static int FindListLevel(int id) {
538   const ListElementInfo* list_info = FindListInfo(id);
539   if (list_info)
540     return list_info->level_;
541
542   return -1;
543 }
544
545 static int ParseUInt(const uint8* buf, int size, int id,
546                      WebMParserClient* client) {
547   if ((size <= 0) || (size > 8))
548     return -1;
549
550   // Read in the big-endian integer.
551   int64 value = 0;
552   for (int i = 0; i < size; ++i)
553     value = (value << 8) | buf[i];
554
555   if (!client->OnUInt(id, value))
556     return -1;
557
558   return size;
559 }
560
561 static int ParseFloat(const uint8* buf, int size, int id,
562                       WebMParserClient* client) {
563
564   if ((size != 4) && (size != 8))
565     return -1;
566
567   double value = -1;
568
569   // Read the bytes from big-endian form into a native endian integer.
570   int64 tmp = 0;
571   for (int i = 0; i < size; ++i)
572     tmp = (tmp << 8) | buf[i];
573
574   // Use a union to convert the integer bit pattern into a floating point
575   // number.
576   if (size == 4) {
577     union {
578       int32 src;
579       float dst;
580     } tmp2;
581     tmp2.src = static_cast<int32>(tmp);
582     value = tmp2.dst;
583   } else if (size == 8) {
584     union {
585       int64 src;
586       double dst;
587     } tmp2;
588     tmp2.src = tmp;
589     value = tmp2.dst;
590   } else {
591     return -1;
592   }
593
594   if (!client->OnFloat(id, value))
595     return -1;
596
597   return size;
598 }
599
600 static int ParseBinary(const uint8* buf, int size, int id,
601                        WebMParserClient* client) {
602   return client->OnBinary(id, buf, size) ? size : -1;
603 }
604
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;
611 }
612
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);
617
618   int result = -1;
619   switch(type) {
620     case LIST:
621       NOTIMPLEMENTED();
622       result = -1;
623       break;
624     case UINT:
625       result = ParseUInt(buf, element_size, id, client);
626       break;
627     case FLOAT:
628       result = ParseFloat(buf, element_size, id, client);
629       break;
630     case BINARY:
631       result = ParseBinary(buf, element_size, id, client);
632       break;
633     case STRING:
634       result = ParseString(buf, element_size, id, client);
635       break;
636     case SKIP:
637       result = element_size;
638       break;
639     default:
640       DVLOG(1) << "Unhandled ID type " << type;
641       return -1;
642   };
643
644   DCHECK_LE(result, size);
645   return result;
646 }
647
648 WebMParserClient::WebMParserClient() {}
649 WebMParserClient::~WebMParserClient() {}
650
651 WebMParserClient* WebMParserClient::OnListStart(int id) {
652   DVLOG(1) << "Unexpected list element start with ID " << std::hex << id;
653   return NULL;
654 }
655
656 bool WebMParserClient::OnListEnd(int id) {
657   DVLOG(1) << "Unexpected list element end with ID " << std::hex << id;
658   return false;
659 }
660
661 bool WebMParserClient::OnUInt(int id, int64 val) {
662   DVLOG(1) << "Unexpected unsigned integer element with ID " << std::hex << id;
663   return false;
664 }
665
666 bool WebMParserClient::OnFloat(int id, double val) {
667   DVLOG(1) << "Unexpected float element with ID " << std::hex << id;
668   return false;
669 }
670
671 bool WebMParserClient::OnBinary(int id, const uint8* data, int size) {
672   DVLOG(1) << "Unexpected binary element with ID " << std::hex << id;
673   return false;
674 }
675
676 bool WebMParserClient::OnString(int id, const std::string& str) {
677   DVLOG(1) << "Unexpected string element with ID " << std::hex << id;
678   return false;
679 }
680
681 WebMListParser::WebMListParser(int id, WebMParserClient* client)
682     : state_(NEED_LIST_HEADER),
683       root_id_(id),
684       root_level_(FindListLevel(id)),
685       root_client_(client) {
686   DCHECK_GE(root_level_, 0);
687   DCHECK(client);
688 }
689
690 WebMListParser::~WebMListParser() {}
691
692 void WebMListParser::Reset() {
693   ChangeState(NEED_LIST_HEADER);
694   list_state_stack_.clear();
695 }
696
697 int WebMListParser::Parse(const uint8* buf, int size) {
698   DCHECK(buf);
699
700   if (size < 0 || state_ == PARSE_ERROR || state_ == DONE_PARSING_LIST)
701     return -1;
702
703   if (size == 0)
704     return 0;
705
706   const uint8* cur = buf;
707   int cur_size = size;
708   int bytes_parsed = 0;
709
710   while (cur_size > 0 && state_ != PARSE_ERROR && state_ != DONE_PARSING_LIST) {
711     int element_id = 0;
712     int64 element_size = 0;
713     int result = WebMParseElementHeader(cur, cur_size, &element_id,
714                                         &element_size);
715
716     if (result < 0)
717       return result;
718
719     if (result == 0)
720       return bytes_parsed;
721
722     switch(state_) {
723       case NEED_LIST_HEADER: {
724         if (element_id != root_id_) {
725           ChangeState(PARSE_ERROR);
726           return -1;
727         }
728
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);
734           return -1;
735         }
736
737         ChangeState(INSIDE_LIST);
738         if (!OnListStart(root_id_, element_size))
739           return -1;
740
741         break;
742       }
743
744       case INSIDE_LIST: {
745         int header_size = result;
746         const uint8* element_data = cur + header_size;
747         int element_data_size = cur_size - header_size;
748
749         if (element_size < element_data_size)
750           element_data_size = element_size;
751
752         result = ParseListElement(header_size, element_id, element_size,
753                                   element_data, element_data_size);
754
755         DCHECK_LE(result, header_size + element_data_size);
756         if (result < 0) {
757           ChangeState(PARSE_ERROR);
758           return -1;
759         }
760
761         if (result == 0)
762           return bytes_parsed;
763
764         break;
765       }
766       case DONE_PARSING_LIST:
767       case PARSE_ERROR:
768         // Shouldn't be able to get here.
769         NOTIMPLEMENTED();
770         break;
771     }
772
773     cur += result;
774     cur_size -= result;
775     bytes_parsed += result;
776   }
777
778   return (state_ == PARSE_ERROR) ? -1 : bytes_parsed;
779 }
780
781 bool WebMListParser::IsParsingComplete() const {
782   return state_ == DONE_PARSING_LIST;
783 }
784
785 void WebMListParser::ChangeState(State new_state) {
786   state_ = new_state;
787 }
788
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);
793
794   ListState& list_state = list_state_stack_.back();
795   DCHECK(list_state.element_info_);
796
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_);
800
801   // Unexpected ID.
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;
806       return -1;
807     }
808
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_;
812
813     if (!OnListEnd())
814       return -1;
815
816     // Check to see if all open lists have ended.
817     if (list_state_stack_.size() == 0)
818       return 0;
819
820     list_state = list_state_stack_.back();
821   }
822
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) {
827     return -1;
828   }
829
830   if (id_type == LIST) {
831     list_state.bytes_parsed_ += header_size;
832
833     if (!OnListStart(id, element_size))
834       return -1;
835     return header_size;
836   }
837
838   // Make sure we have the entire element before trying to parse a non-list
839   // element.
840   if (size < element_size)
841     return 0;
842
843   int bytes_parsed = ParseNonListElement(id_type, id, element_size,
844                                          data, size, list_state.client_);
845   DCHECK_LE(bytes_parsed, size);
846
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))
852     return bytes_parsed;
853
854   int result = header_size + bytes_parsed;
855   list_state.bytes_parsed_ += result;
856
857   // See if we have reached the end of the current list.
858   if (list_state.bytes_parsed_ == list_state.size_) {
859     if (!OnListEnd())
860       return -1;
861   }
862
863   return result;
864 }
865
866 bool WebMListParser::OnListStart(int id, int64 size) {
867   const ListElementInfo* element_info = FindListInfo(id);
868   if (!element_info)
869     return false;
870
871   int current_level = root_level_ + list_state_stack_.size() - 1;
872   if (current_level + 1 != element_info->level_)
873     return false;
874
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)
881       return false;
882     current_list_client = current_list_state.client_;
883   } else {
884     current_list_client = root_client_;
885   }
886
887   WebMParserClient* new_list_client = current_list_client->OnListStart(id);
888   if (!new_list_client)
889     return false;
890
891   ListState new_list_state = { id, size, 0, element_info, new_list_client };
892   list_state_stack_.push_back(new_list_state);
893
894   if (size == 0)
895     return OnListEnd();
896
897   return true;
898 }
899
900 bool WebMListParser::OnListEnd() {
901   int lists_ended = 0;
902   for (; !list_state_stack_.empty(); ++lists_ended) {
903     const ListState& list_state = list_state_stack_.back();
904
905     if (list_state.bytes_parsed_ != list_state.size_)
906       break;
907
908     list_state_stack_.pop_back();
909
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_;
916     } else {
917       client = root_client_;
918     }
919
920     if (!client->OnListEnd(list_state.id_))
921       return false;
922   }
923
924   DCHECK_GE(lists_ended, 1);
925
926   if (list_state_stack_.empty())
927     ChangeState(DONE_PARSING_LIST);
928
929   return true;
930 }
931
932 bool WebMListParser::IsSiblingOrAncestor(int id_a, int id_b) const {
933   DCHECK((id_a == kWebMIdSegment) || (id_a == kWebMIdCluster));
934
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)
939         return true;
940     }
941   }
942
943   // kWebMIdSegment siblings.
944   return ((id_b == kWebMIdSegment) || (id_b == kWebMIdEBMLHeader));
945 }
946
947 }  // namespace media