Home | History | Annotate | Download | only in webm
      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
    948