diff options
Diffstat (limited to 'chromium/media/webm/webm_parser.cc')
-rw-r--r-- | chromium/media/webm/webm_parser.cc | 947 |
1 files changed, 0 insertions, 947 deletions
diff --git a/chromium/media/webm/webm_parser.cc b/chromium/media/webm/webm_parser.cc deleted file mode 100644 index f1509abb830..00000000000 --- a/chromium/media/webm/webm_parser.cc +++ /dev/null @@ -1,947 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "media/webm/webm_parser.h" - -// This file contains code to parse WebM file elements. It was created -// from information in the Matroska spec. -// http://www.matroska.org/technical/specs/index.html -// This file contains code for encrypted WebM. Current WebM -// encrypted request for comments specification is here -// http://wiki.webmproject.org/encryption/webm-encryption-rfc - -#include <iomanip> - -#include "base/logging.h" -#include "media/webm/webm_constants.h" - -namespace media { - -enum ElementType { - UNKNOWN, - LIST, // Referred to as Master Element in the Matroska spec. - UINT, - FLOAT, - BINARY, - STRING, - SKIP, -}; - -struct ElementIdInfo { - ElementType type_; - int id_; -}; - -struct ListElementInfo { - int id_; - int level_; - const ElementIdInfo* id_info_; - int id_info_count_; -}; - -// The following are tables indicating what IDs are valid sub-elements -// of particular elements. If an element is encountered that doesn't -// appear in the list, a parsing error is signalled. Some elements are -// marked as SKIP because they are valid, but we don't care about them -// right now. -static const ElementIdInfo kEBMLHeaderIds[] = { - {UINT, kWebMIdEBMLVersion}, - {UINT, kWebMIdEBMLReadVersion}, - {UINT, kWebMIdEBMLMaxIDLength}, - {UINT, kWebMIdEBMLMaxSizeLength}, - {STRING, kWebMIdDocType}, - {UINT, kWebMIdDocTypeVersion}, - {UINT, kWebMIdDocTypeReadVersion}, -}; - -static const ElementIdInfo kSegmentIds[] = { - {LIST, kWebMIdSeekHead}, - {LIST, kWebMIdInfo}, - {LIST, kWebMIdCluster}, - {LIST, kWebMIdTracks}, - {LIST, kWebMIdCues}, - {LIST, kWebMIdAttachments}, - {LIST, kWebMIdChapters}, - {LIST, kWebMIdTags}, -}; - -static const ElementIdInfo kSeekHeadIds[] = { - {LIST, kWebMIdSeek}, -}; - -static const ElementIdInfo kSeekIds[] = { - {BINARY, kWebMIdSeekID}, - {UINT, kWebMIdSeekPosition}, -}; - -static const ElementIdInfo kInfoIds[] = { - {BINARY, kWebMIdSegmentUID}, - {STRING, kWebMIdSegmentFilename}, - {BINARY, kWebMIdPrevUID}, - {STRING, kWebMIdPrevFilename}, - {BINARY, kWebMIdNextUID}, - {STRING, kWebMIdNextFilename}, - {BINARY, kWebMIdSegmentFamily}, - {LIST, kWebMIdChapterTranslate}, - {UINT, kWebMIdTimecodeScale}, - {FLOAT, kWebMIdDuration}, - {BINARY, kWebMIdDateUTC}, - {STRING, kWebMIdTitle}, - {STRING, kWebMIdMuxingApp}, - {STRING, kWebMIdWritingApp}, -}; - -static const ElementIdInfo kChapterTranslateIds[] = { - {UINT, kWebMIdChapterTranslateEditionUID}, - {UINT, kWebMIdChapterTranslateCodec}, - {BINARY, kWebMIdChapterTranslateID}, -}; - -static const ElementIdInfo kClusterIds[] = { - {BINARY, kWebMIdSimpleBlock}, - {UINT, kWebMIdTimecode}, - {LIST, kWebMIdSilentTracks}, - {UINT, kWebMIdPosition}, - {UINT, kWebMIdPrevSize}, - {LIST, kWebMIdBlockGroup}, -}; - -static const ElementIdInfo kSilentTracksIds[] = { - {UINT, kWebMIdSilentTrackNumber}, -}; - -static const ElementIdInfo kBlockGroupIds[] = { - {BINARY, kWebMIdBlock}, - {LIST, kWebMIdBlockAdditions}, - {UINT, kWebMIdBlockDuration}, - {UINT, kWebMIdReferencePriority}, - {BINARY, kWebMIdReferenceBlock}, - {BINARY, kWebMIdCodecState}, - {UINT, kWebMIdDiscardPadding}, - {LIST, kWebMIdSlices}, -}; - -static const ElementIdInfo kBlockAdditionsIds[] = { - {LIST, kWebMIdBlockMore}, -}; - -static const ElementIdInfo kBlockMoreIds[] = { - {UINT, kWebMIdBlockAddID}, - {BINARY, kWebMIdBlockAdditional}, -}; - -static const ElementIdInfo kSlicesIds[] = { - {LIST, kWebMIdTimeSlice}, -}; - -static const ElementIdInfo kTimeSliceIds[] = { - {UINT, kWebMIdLaceNumber}, -}; - -static const ElementIdInfo kTracksIds[] = { - {LIST, kWebMIdTrackEntry}, -}; - -static const ElementIdInfo kTrackEntryIds[] = { - {UINT, kWebMIdTrackNumber}, - {UINT, kWebMIdTrackUID}, - {UINT, kWebMIdTrackType}, - {UINT, kWebMIdFlagEnabled}, - {UINT, kWebMIdFlagDefault}, - {UINT, kWebMIdFlagForced}, - {UINT, kWebMIdFlagLacing}, - {UINT, kWebMIdMinCache}, - {UINT, kWebMIdMaxCache}, - {UINT, kWebMIdDefaultDuration}, - {FLOAT, kWebMIdTrackTimecodeScale}, - {UINT, kWebMIdMaxBlockAdditionId}, - {STRING, kWebMIdName}, - {STRING, kWebMIdLanguage}, - {STRING, kWebMIdCodecID}, - {BINARY, kWebMIdCodecPrivate}, - {STRING, kWebMIdCodecName}, - {UINT, kWebMIdAttachmentLink}, - {UINT, kWebMIdCodecDecodeAll}, - {UINT, kWebMIdTrackOverlay}, - {UINT, kWebMIdCodecDelay}, - {UINT, kWebMIdSeekPreRoll}, - {LIST, kWebMIdTrackTranslate}, - {LIST, kWebMIdVideo}, - {LIST, kWebMIdAudio}, - {LIST, kWebMIdTrackOperation}, - {LIST, kWebMIdContentEncodings}, -}; - -static const ElementIdInfo kTrackTranslateIds[] = { - {UINT, kWebMIdTrackTranslateEditionUID}, - {UINT, kWebMIdTrackTranslateCodec}, - {BINARY, kWebMIdTrackTranslateTrackID}, -}; - -static const ElementIdInfo kVideoIds[] = { - {UINT, kWebMIdFlagInterlaced}, - {UINT, kWebMIdStereoMode}, - {UINT, kWebMIdAlphaMode}, - {UINT, kWebMIdPixelWidth}, - {UINT, kWebMIdPixelHeight}, - {UINT, kWebMIdPixelCropBottom}, - {UINT, kWebMIdPixelCropTop}, - {UINT, kWebMIdPixelCropLeft}, - {UINT, kWebMIdPixelCropRight}, - {UINT, kWebMIdDisplayWidth}, - {UINT, kWebMIdDisplayHeight}, - {UINT, kWebMIdDisplayUnit}, - {UINT, kWebMIdAspectRatioType}, - {BINARY, kWebMIdColorSpace}, - {FLOAT, kWebMIdFrameRate}, -}; - -static const ElementIdInfo kAudioIds[] = { - {FLOAT, kWebMIdSamplingFrequency}, - {FLOAT, kWebMIdOutputSamplingFrequency}, - {UINT, kWebMIdChannels}, - {UINT, kWebMIdBitDepth}, -}; - -static const ElementIdInfo kTrackOperationIds[] = { - {LIST, kWebMIdTrackCombinePlanes}, - {LIST, kWebMIdJoinBlocks}, -}; - -static const ElementIdInfo kTrackCombinePlanesIds[] = { - {LIST, kWebMIdTrackPlane}, -}; - -static const ElementIdInfo kTrackPlaneIds[] = { - {UINT, kWebMIdTrackPlaneUID}, - {UINT, kWebMIdTrackPlaneType}, -}; - -static const ElementIdInfo kJoinBlocksIds[] = { - {UINT, kWebMIdTrackJoinUID}, -}; - -static const ElementIdInfo kContentEncodingsIds[] = { - {LIST, kWebMIdContentEncoding}, -}; - -static const ElementIdInfo kContentEncodingIds[] = { - {UINT, kWebMIdContentEncodingOrder}, - {UINT, kWebMIdContentEncodingScope}, - {UINT, kWebMIdContentEncodingType}, - {LIST, kWebMIdContentCompression}, - {LIST, kWebMIdContentEncryption}, -}; - -static const ElementIdInfo kContentCompressionIds[] = { - {UINT, kWebMIdContentCompAlgo}, - {BINARY, kWebMIdContentCompSettings}, -}; - -static const ElementIdInfo kContentEncryptionIds[] = { - {LIST, kWebMIdContentEncAESSettings}, - {UINT, kWebMIdContentEncAlgo}, - {BINARY, kWebMIdContentEncKeyID}, - {BINARY, kWebMIdContentSignature}, - {BINARY, kWebMIdContentSigKeyID}, - {UINT, kWebMIdContentSigAlgo}, - {UINT, kWebMIdContentSigHashAlgo}, -}; - -static const ElementIdInfo kContentEncAESSettingsIds[] = { - {UINT, kWebMIdAESSettingsCipherMode}, -}; - -static const ElementIdInfo kCuesIds[] = { - {LIST, kWebMIdCuePoint}, -}; - -static const ElementIdInfo kCuePointIds[] = { - {UINT, kWebMIdCueTime}, - {LIST, kWebMIdCueTrackPositions}, -}; - -static const ElementIdInfo kCueTrackPositionsIds[] = { - {UINT, kWebMIdCueTrack}, - {UINT, kWebMIdCueClusterPosition}, - {UINT, kWebMIdCueBlockNumber}, - {UINT, kWebMIdCueCodecState}, - {LIST, kWebMIdCueReference}, -}; - -static const ElementIdInfo kCueReferenceIds[] = { - {UINT, kWebMIdCueRefTime}, -}; - -static const ElementIdInfo kAttachmentsIds[] = { - {LIST, kWebMIdAttachedFile}, -}; - -static const ElementIdInfo kAttachedFileIds[] = { - {STRING, kWebMIdFileDescription}, - {STRING, kWebMIdFileName}, - {STRING, kWebMIdFileMimeType}, - {BINARY, kWebMIdFileData}, - {UINT, kWebMIdFileUID}, -}; - -static const ElementIdInfo kChaptersIds[] = { - {LIST, kWebMIdEditionEntry}, -}; - -static const ElementIdInfo kEditionEntryIds[] = { - {UINT, kWebMIdEditionUID}, - {UINT, kWebMIdEditionFlagHidden}, - {UINT, kWebMIdEditionFlagDefault}, - {UINT, kWebMIdEditionFlagOrdered}, - {LIST, kWebMIdChapterAtom}, -}; - -static const ElementIdInfo kChapterAtomIds[] = { - {UINT, kWebMIdChapterUID}, - {UINT, kWebMIdChapterTimeStart}, - {UINT, kWebMIdChapterTimeEnd}, - {UINT, kWebMIdChapterFlagHidden}, - {UINT, kWebMIdChapterFlagEnabled}, - {BINARY, kWebMIdChapterSegmentUID}, - {UINT, kWebMIdChapterSegmentEditionUID}, - {UINT, kWebMIdChapterPhysicalEquiv}, - {LIST, kWebMIdChapterTrack}, - {LIST, kWebMIdChapterDisplay}, - {LIST, kWebMIdChapProcess}, -}; - -static const ElementIdInfo kChapterTrackIds[] = { - {UINT, kWebMIdChapterTrackNumber}, -}; - -static const ElementIdInfo kChapterDisplayIds[] = { - {STRING, kWebMIdChapString}, - {STRING, kWebMIdChapLanguage}, - {STRING, kWebMIdChapCountry}, -}; - -static const ElementIdInfo kChapProcessIds[] = { - {UINT, kWebMIdChapProcessCodecID}, - {BINARY, kWebMIdChapProcessPrivate}, - {LIST, kWebMIdChapProcessCommand}, -}; - -static const ElementIdInfo kChapProcessCommandIds[] = { - {UINT, kWebMIdChapProcessTime}, - {BINARY, kWebMIdChapProcessData}, -}; - -static const ElementIdInfo kTagsIds[] = { - {LIST, kWebMIdTag}, -}; - -static const ElementIdInfo kTagIds[] = { - {LIST, kWebMIdTargets}, - {LIST, kWebMIdSimpleTag}, -}; - -static const ElementIdInfo kTargetsIds[] = { - {UINT, kWebMIdTargetTypeValue}, - {STRING, kWebMIdTargetType}, - {UINT, kWebMIdTagTrackUID}, - {UINT, kWebMIdTagEditionUID}, - {UINT, kWebMIdTagChapterUID}, - {UINT, kWebMIdTagAttachmentUID}, -}; - -static const ElementIdInfo kSimpleTagIds[] = { - {STRING, kWebMIdTagName}, - {STRING, kWebMIdTagLanguage}, - {UINT, kWebMIdTagDefault}, - {STRING, kWebMIdTagString}, - {BINARY, kWebMIdTagBinary}, -}; - -#define LIST_ELEMENT_INFO(id, level, id_info) \ - { (id), (level), (id_info), arraysize(id_info) } - -static const ListElementInfo kListElementInfo[] = { - LIST_ELEMENT_INFO(kWebMIdCluster, 1, kClusterIds), - LIST_ELEMENT_INFO(kWebMIdEBMLHeader, 0, kEBMLHeaderIds), - LIST_ELEMENT_INFO(kWebMIdSegment, 0, kSegmentIds), - LIST_ELEMENT_INFO(kWebMIdSeekHead, 1, kSeekHeadIds), - LIST_ELEMENT_INFO(kWebMIdSeek, 2, kSeekIds), - LIST_ELEMENT_INFO(kWebMIdInfo, 1, kInfoIds), - LIST_ELEMENT_INFO(kWebMIdChapterTranslate, 2, kChapterTranslateIds), - LIST_ELEMENT_INFO(kWebMIdSilentTracks, 2, kSilentTracksIds), - LIST_ELEMENT_INFO(kWebMIdBlockGroup, 2, kBlockGroupIds), - LIST_ELEMENT_INFO(kWebMIdBlockAdditions, 3, kBlockAdditionsIds), - LIST_ELEMENT_INFO(kWebMIdBlockMore, 4, kBlockMoreIds), - LIST_ELEMENT_INFO(kWebMIdSlices, 3, kSlicesIds), - LIST_ELEMENT_INFO(kWebMIdTimeSlice, 4, kTimeSliceIds), - LIST_ELEMENT_INFO(kWebMIdTracks, 1, kTracksIds), - LIST_ELEMENT_INFO(kWebMIdTrackEntry, 2, kTrackEntryIds), - LIST_ELEMENT_INFO(kWebMIdTrackTranslate, 3, kTrackTranslateIds), - LIST_ELEMENT_INFO(kWebMIdVideo, 3, kVideoIds), - LIST_ELEMENT_INFO(kWebMIdAudio, 3, kAudioIds), - LIST_ELEMENT_INFO(kWebMIdTrackOperation, 3, kTrackOperationIds), - LIST_ELEMENT_INFO(kWebMIdTrackCombinePlanes, 4, kTrackCombinePlanesIds), - LIST_ELEMENT_INFO(kWebMIdTrackPlane, 5, kTrackPlaneIds), - LIST_ELEMENT_INFO(kWebMIdJoinBlocks, 4, kJoinBlocksIds), - LIST_ELEMENT_INFO(kWebMIdContentEncodings, 3, kContentEncodingsIds), - LIST_ELEMENT_INFO(kWebMIdContentEncoding, 4, kContentEncodingIds), - LIST_ELEMENT_INFO(kWebMIdContentCompression, 5, kContentCompressionIds), - LIST_ELEMENT_INFO(kWebMIdContentEncryption, 5, kContentEncryptionIds), - LIST_ELEMENT_INFO(kWebMIdContentEncAESSettings, 6, kContentEncAESSettingsIds), - LIST_ELEMENT_INFO(kWebMIdCues, 1, kCuesIds), - LIST_ELEMENT_INFO(kWebMIdCuePoint, 2, kCuePointIds), - LIST_ELEMENT_INFO(kWebMIdCueTrackPositions, 3, kCueTrackPositionsIds), - LIST_ELEMENT_INFO(kWebMIdCueReference, 4, kCueReferenceIds), - LIST_ELEMENT_INFO(kWebMIdAttachments, 1, kAttachmentsIds), - LIST_ELEMENT_INFO(kWebMIdAttachedFile, 2, kAttachedFileIds), - LIST_ELEMENT_INFO(kWebMIdChapters, 1, kChaptersIds), - LIST_ELEMENT_INFO(kWebMIdEditionEntry, 2, kEditionEntryIds), - LIST_ELEMENT_INFO(kWebMIdChapterAtom, 3, kChapterAtomIds), - LIST_ELEMENT_INFO(kWebMIdChapterTrack, 4, kChapterTrackIds), - LIST_ELEMENT_INFO(kWebMIdChapterDisplay, 4, kChapterDisplayIds), - LIST_ELEMENT_INFO(kWebMIdChapProcess, 4, kChapProcessIds), - LIST_ELEMENT_INFO(kWebMIdChapProcessCommand, 5, kChapProcessCommandIds), - LIST_ELEMENT_INFO(kWebMIdTags, 1, kTagsIds), - LIST_ELEMENT_INFO(kWebMIdTag, 2, kTagIds), - LIST_ELEMENT_INFO(kWebMIdTargets, 3, kTargetsIds), - LIST_ELEMENT_INFO(kWebMIdSimpleTag, 3, kSimpleTagIds), -}; - -// Parses an element header id or size field. These fields are variable length -// encoded. The first byte indicates how many bytes the field occupies. -// |buf| - The buffer to parse. -// |size| - The number of bytes in |buf| -// |max_bytes| - The maximum number of bytes the field can be. ID fields -// set this to 4 & element size fields set this to 8. If the -// first byte indicates a larger field size than this it is a -// parser error. -// |mask_first_byte| - For element size fields the field length encoding bits -// need to be masked off. This parameter is true for -// element size fields and is false for ID field values. -// -// Returns: The number of bytes parsed on success. -1 on error. -static int ParseWebMElementHeaderField(const uint8* buf, int size, - int max_bytes, bool mask_first_byte, - int64* num) { - DCHECK(buf); - DCHECK(num); - - if (size < 0) - return -1; - - if (size == 0) - return 0; - - int mask = 0x80; - uint8 ch = buf[0]; - int extra_bytes = -1; - bool all_ones = false; - for (int i = 0; i < max_bytes; ++i) { - if ((ch & mask) != 0) { - mask = ~mask & 0xff; - *num = mask_first_byte ? ch & mask : ch; - all_ones = (ch & mask) == mask; - extra_bytes = i; - break; - } - mask = 0x80 | mask >> 1; - } - - if (extra_bytes == -1) - return -1; - - // Return 0 if we need more data. - if ((1 + extra_bytes) > size) - return 0; - - int bytes_used = 1; - - for (int i = 0; i < extra_bytes; ++i) { - ch = buf[bytes_used++]; - all_ones &= (ch == 0xff); - *num = (*num << 8) | ch; - } - - if (all_ones) - *num = kint64max; - - return bytes_used; -} - -int WebMParseElementHeader(const uint8* buf, int size, - int* id, int64* element_size) { - DCHECK(buf); - DCHECK_GE(size, 0); - DCHECK(id); - DCHECK(element_size); - - if (size == 0) - return 0; - - int64 tmp = 0; - int num_id_bytes = ParseWebMElementHeaderField(buf, size, 4, false, &tmp); - - if (num_id_bytes <= 0) - return num_id_bytes; - - if (tmp == kint64max) - tmp = kWebMReservedId; - - *id = static_cast<int>(tmp); - - int num_size_bytes = ParseWebMElementHeaderField(buf + num_id_bytes, - size - num_id_bytes, - 8, true, &tmp); - - if (num_size_bytes <= 0) - return num_size_bytes; - - if (tmp == kint64max) - tmp = kWebMUnknownSize; - - *element_size = tmp; - DVLOG(3) << "WebMParseElementHeader() : id " << std::hex << *id << std::dec - << " size " << *element_size; - return num_id_bytes + num_size_bytes; -} - -// Finds ElementType for a specific ID. -static ElementType FindIdType(int id, - const ElementIdInfo* id_info, - int id_info_count) { - - // Check for global element IDs that can be anywhere. - if (id == kWebMIdVoid || id == kWebMIdCRC32) - return SKIP; - - for (int i = 0; i < id_info_count; ++i) { - if (id == id_info[i].id_) - return id_info[i].type_; - } - - return UNKNOWN; -} - -// Finds ListElementInfo for a specific ID. -static const ListElementInfo* FindListInfo(int id) { - for (size_t i = 0; i < arraysize(kListElementInfo); ++i) { - if (id == kListElementInfo[i].id_) - return &kListElementInfo[i]; - } - - return NULL; -} - -static int FindListLevel(int id) { - const ListElementInfo* list_info = FindListInfo(id); - if (list_info) - return list_info->level_; - - return -1; -} - -static int ParseUInt(const uint8* buf, int size, int id, - WebMParserClient* client) { - if ((size <= 0) || (size > 8)) - return -1; - - // Read in the big-endian integer. - int64 value = 0; - for (int i = 0; i < size; ++i) - value = (value << 8) | buf[i]; - - if (!client->OnUInt(id, value)) - return -1; - - return size; -} - -static int ParseFloat(const uint8* buf, int size, int id, - WebMParserClient* client) { - - if ((size != 4) && (size != 8)) - return -1; - - double value = -1; - - // Read the bytes from big-endian form into a native endian integer. - int64 tmp = 0; - for (int i = 0; i < size; ++i) - tmp = (tmp << 8) | buf[i]; - - // Use a union to convert the integer bit pattern into a floating point - // number. - if (size == 4) { - union { - int32 src; - float dst; - } tmp2; - tmp2.src = static_cast<int32>(tmp); - value = tmp2.dst; - } else if (size == 8) { - union { - int64 src; - double dst; - } tmp2; - tmp2.src = tmp; - value = tmp2.dst; - } else { - return -1; - } - - if (!client->OnFloat(id, value)) - return -1; - - return size; -} - -static int ParseBinary(const uint8* buf, int size, int id, - WebMParserClient* client) { - return client->OnBinary(id, buf, size) ? size : -1; -} - -static int ParseString(const uint8* buf, int size, int id, - WebMParserClient* client) { - const uint8* end = static_cast<const uint8*>(memchr(buf, '\0', size)); - int length = (end != NULL) ? static_cast<int>(end - buf) : size; - std::string str(reinterpret_cast<const char*>(buf), length); - return client->OnString(id, str) ? size : -1; -} - -static int ParseNonListElement(ElementType type, int id, int64 element_size, - const uint8* buf, int size, - WebMParserClient* client) { - DCHECK_GE(size, element_size); - - int result = -1; - switch(type) { - case LIST: - NOTIMPLEMENTED(); - result = -1; - break; - case UINT: - result = ParseUInt(buf, element_size, id, client); - break; - case FLOAT: - result = ParseFloat(buf, element_size, id, client); - break; - case BINARY: - result = ParseBinary(buf, element_size, id, client); - break; - case STRING: - result = ParseString(buf, element_size, id, client); - break; - case SKIP: - result = element_size; - break; - default: - DVLOG(1) << "Unhandled ID type " << type; - return -1; - }; - - DCHECK_LE(result, size); - return result; -} - -WebMParserClient::WebMParserClient() {} -WebMParserClient::~WebMParserClient() {} - -WebMParserClient* WebMParserClient::OnListStart(int id) { - DVLOG(1) << "Unexpected list element start with ID " << std::hex << id; - return NULL; -} - -bool WebMParserClient::OnListEnd(int id) { - DVLOG(1) << "Unexpected list element end with ID " << std::hex << id; - return false; -} - -bool WebMParserClient::OnUInt(int id, int64 val) { - DVLOG(1) << "Unexpected unsigned integer element with ID " << std::hex << id; - return false; -} - -bool WebMParserClient::OnFloat(int id, double val) { - DVLOG(1) << "Unexpected float element with ID " << std::hex << id; - return false; -} - -bool WebMParserClient::OnBinary(int id, const uint8* data, int size) { - DVLOG(1) << "Unexpected binary element with ID " << std::hex << id; - return false; -} - -bool WebMParserClient::OnString(int id, const std::string& str) { - DVLOG(1) << "Unexpected string element with ID " << std::hex << id; - return false; -} - -WebMListParser::WebMListParser(int id, WebMParserClient* client) - : state_(NEED_LIST_HEADER), - root_id_(id), - root_level_(FindListLevel(id)), - root_client_(client) { - DCHECK_GE(root_level_, 0); - DCHECK(client); -} - -WebMListParser::~WebMListParser() {} - -void WebMListParser::Reset() { - ChangeState(NEED_LIST_HEADER); - list_state_stack_.clear(); -} - -int WebMListParser::Parse(const uint8* buf, int size) { - DCHECK(buf); - - if (size < 0 || state_ == PARSE_ERROR || state_ == DONE_PARSING_LIST) - return -1; - - if (size == 0) - return 0; - - const uint8* cur = buf; - int cur_size = size; - int bytes_parsed = 0; - - while (cur_size > 0 && state_ != PARSE_ERROR && state_ != DONE_PARSING_LIST) { - int element_id = 0; - int64 element_size = 0; - int result = WebMParseElementHeader(cur, cur_size, &element_id, - &element_size); - - if (result < 0) - return result; - - if (result == 0) - return bytes_parsed; - - switch(state_) { - case NEED_LIST_HEADER: { - if (element_id != root_id_) { - ChangeState(PARSE_ERROR); - return -1; - } - - // Only allow Segment & Cluster to have an unknown size. - if (element_size == kWebMUnknownSize && - (element_id != kWebMIdSegment) && - (element_id != kWebMIdCluster)) { - ChangeState(PARSE_ERROR); - return -1; - } - - ChangeState(INSIDE_LIST); - if (!OnListStart(root_id_, element_size)) - return -1; - - break; - } - - case INSIDE_LIST: { - int header_size = result; - const uint8* element_data = cur + header_size; - int element_data_size = cur_size - header_size; - - if (element_size < element_data_size) - element_data_size = element_size; - - result = ParseListElement(header_size, element_id, element_size, - element_data, element_data_size); - - DCHECK_LE(result, header_size + element_data_size); - if (result < 0) { - ChangeState(PARSE_ERROR); - return -1; - } - - if (result == 0) - return bytes_parsed; - - break; - } - case DONE_PARSING_LIST: - case PARSE_ERROR: - // Shouldn't be able to get here. - NOTIMPLEMENTED(); - break; - } - - cur += result; - cur_size -= result; - bytes_parsed += result; - } - - return (state_ == PARSE_ERROR) ? -1 : bytes_parsed; -} - -bool WebMListParser::IsParsingComplete() const { - return state_ == DONE_PARSING_LIST; -} - -void WebMListParser::ChangeState(State new_state) { - state_ = new_state; -} - -int WebMListParser::ParseListElement(int header_size, - int id, int64 element_size, - const uint8* data, int size) { - DCHECK_GT(list_state_stack_.size(), 0u); - - ListState& list_state = list_state_stack_.back(); - DCHECK(list_state.element_info_); - - const ListElementInfo* element_info = list_state.element_info_; - ElementType id_type = - FindIdType(id, element_info->id_info_, element_info->id_info_count_); - - // Unexpected ID. - if (id_type == UNKNOWN) { - if (list_state.size_ != kWebMUnknownSize || - !IsSiblingOrAncestor(list_state.id_, id)) { - DVLOG(1) << "No ElementType info for ID 0x" << std::hex << id; - return -1; - } - - // We've reached the end of a list of unknown size. Update the size now that - // we know it and dispatch the end of list calls. - list_state.size_ = list_state.bytes_parsed_; - - if (!OnListEnd()) - return -1; - - // Check to see if all open lists have ended. - if (list_state_stack_.size() == 0) - return 0; - - list_state = list_state_stack_.back(); - } - - // Make sure the whole element can fit inside the current list. - int64 total_element_size = header_size + element_size; - if (list_state.size_ != kWebMUnknownSize && - list_state.size_ < list_state.bytes_parsed_ + total_element_size) { - return -1; - } - - if (id_type == LIST) { - list_state.bytes_parsed_ += header_size; - - if (!OnListStart(id, element_size)) - return -1; - return header_size; - } - - // Make sure we have the entire element before trying to parse a non-list - // element. - if (size < element_size) - return 0; - - int bytes_parsed = ParseNonListElement(id_type, id, element_size, - data, size, list_state.client_); - DCHECK_LE(bytes_parsed, size); - - // Return if an error occurred or we need more data. - // Note: bytes_parsed is 0 for a successful parse of a size 0 element. We - // need to check the element_size to disambiguate the "need more data" case - // from a successful parse. - if (bytes_parsed < 0 || (bytes_parsed == 0 && element_size != 0)) - return bytes_parsed; - - int result = header_size + bytes_parsed; - list_state.bytes_parsed_ += result; - - // See if we have reached the end of the current list. - if (list_state.bytes_parsed_ == list_state.size_) { - if (!OnListEnd()) - return -1; - } - - return result; -} - -bool WebMListParser::OnListStart(int id, int64 size) { - const ListElementInfo* element_info = FindListInfo(id); - if (!element_info) - return false; - - int current_level = root_level_ + list_state_stack_.size() - 1; - if (current_level + 1 != element_info->level_) - return false; - - WebMParserClient* current_list_client = NULL; - if (!list_state_stack_.empty()) { - // Make sure the new list doesn't go past the end of the current list. - ListState current_list_state = list_state_stack_.back(); - if (current_list_state.size_ != kWebMUnknownSize && - current_list_state.size_ < current_list_state.bytes_parsed_ + size) - return false; - current_list_client = current_list_state.client_; - } else { - current_list_client = root_client_; - } - - WebMParserClient* new_list_client = current_list_client->OnListStart(id); - if (!new_list_client) - return false; - - ListState new_list_state = { id, size, 0, element_info, new_list_client }; - list_state_stack_.push_back(new_list_state); - - if (size == 0) - return OnListEnd(); - - return true; -} - -bool WebMListParser::OnListEnd() { - int lists_ended = 0; - for (; !list_state_stack_.empty(); ++lists_ended) { - const ListState& list_state = list_state_stack_.back(); - - if (list_state.bytes_parsed_ != list_state.size_) - break; - - list_state_stack_.pop_back(); - - int64 bytes_parsed = list_state.bytes_parsed_; - WebMParserClient* client = NULL; - if (!list_state_stack_.empty()) { - // Update the bytes_parsed_ for the parent element. - list_state_stack_.back().bytes_parsed_ += bytes_parsed; - client = list_state_stack_.back().client_; - } else { - client = root_client_; - } - - if (!client->OnListEnd(list_state.id_)) - return false; - } - - DCHECK_GE(lists_ended, 1); - - if (list_state_stack_.empty()) - ChangeState(DONE_PARSING_LIST); - - return true; -} - -bool WebMListParser::IsSiblingOrAncestor(int id_a, int id_b) const { - DCHECK((id_a == kWebMIdSegment) || (id_a == kWebMIdCluster)); - - if (id_a == kWebMIdCluster) { - // kWebMIdCluster siblings. - for (size_t i = 0; i < arraysize(kSegmentIds); i++) { - if (kSegmentIds[i].id_ == id_b) - return true; - } - } - - // kWebMIdSegment siblings. - return ((id_b == kWebMIdSegment) || (id_b == kWebMIdEBMLHeader)); -} - -} // namespace media |