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