163 lines
3.8 KiB
C++
163 lines
3.8 KiB
C++
#include "seekhead.hpp"
|
|
#include "segment.hpp"
|
|
#include "ebmlreadhelpers.hpp"
|
|
#include "imkvreader.hpp"
|
|
|
|
#include <assert.h>
|
|
|
|
namespace mkvparser
|
|
{
|
|
|
|
namespace
|
|
{
|
|
|
|
long long ParseEntry(IMkvReader* pReader, const EBMLElement& entryInfo, SeekHead::Entry* pEntry)
|
|
{
|
|
assert(pEntry);
|
|
|
|
if (entryInfo.GetPayloadSize() <= 0)
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
pEntry->element_start = entryInfo.GetPos();
|
|
pEntry->element_size = entryInfo.GetSize();
|
|
|
|
long long pos = entryInfo.GetPayloadPos();
|
|
const long long stop = entryInfo.GetEndPos();
|
|
|
|
//parse the container for the level-1 element ID
|
|
|
|
//seekId
|
|
EBMLElement elemInfo;
|
|
long long result = elemInfo.Parse(pReader, pos);
|
|
if (result != 0)
|
|
return result;
|
|
|
|
if (elemInfo.GetID() != 0x13AB) //SeekID ID
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
if (elemInfo.GetEndPos() > stop)
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
//Note that the SeekId payload really is serialized
|
|
//as a "Matroska integer", not as a plain binary value.
|
|
//In fact, Matroska requires that ID values in the
|
|
//stream exactly match the binary representation as listed
|
|
//in the Matroska specification.
|
|
//
|
|
//This parser is more liberal, and permits IDs to have
|
|
//any width. (This could make the representation in the stream
|
|
//different from what's in the spec, but it doesn't matter here,
|
|
//since we always normalize "Matroska integer" values.)
|
|
|
|
long len = 0;
|
|
pEntry->id = ReadUInt(pReader, elemInfo.GetPayloadPos(), len); //payload
|
|
|
|
if (pEntry->id <= 0)
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
pos += elemInfo.GetSize(); //consume SeekID payload
|
|
|
|
//seekPos
|
|
result = elemInfo.Parse(pReader, pos);
|
|
if (result != 0)
|
|
return result;
|
|
|
|
if (elemInfo.GetID() != 0x13AC) //SeekPos ID
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
if (elemInfo.GetEndPos() > stop)
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
pEntry->pos = UnserializeUInt(pReader, elemInfo.GetPayloadPos(), elemInfo.GetPayloadSize());
|
|
|
|
if (pEntry->pos < 0)
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
pos += elemInfo.GetSize(); //consume payload
|
|
|
|
if (pos != stop)
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
return 0; // success
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
|
SeekHead::SeekHead(Segment* pSegment, const EBMLElement& elemInfo)
|
|
: m_pSegment(pSegment)
|
|
, m_elemInfo(elemInfo)
|
|
{
|
|
}
|
|
|
|
|
|
SeekHead::~SeekHead()
|
|
{
|
|
}
|
|
|
|
|
|
long SeekHead::Parse()
|
|
{
|
|
IMkvReader* const pReader = m_pSegment->GetReader();
|
|
|
|
long long pos = m_elemInfo.GetPayloadPos();
|
|
const long long stop = m_elemInfo.GetEndPos();
|
|
|
|
while (pos < stop)
|
|
{
|
|
EBMLElement elemInfo;
|
|
long long result = elemInfo.Parse(pReader, pos);
|
|
if (result != 0)
|
|
return static_cast<long>(result);
|
|
|
|
if (elemInfo.GetID() == 0x0DBB) //SeekEntry ID
|
|
{
|
|
Entry e;
|
|
if (ParseEntry(pReader, elemInfo, &e) == 0)
|
|
{
|
|
m_entries.push_back(e);
|
|
}
|
|
}
|
|
else if (elemInfo.GetID() == 0x6C) //Void ID
|
|
{
|
|
VoidElement e;
|
|
|
|
e.element_start = elemInfo.GetPos();
|
|
e.element_size = elemInfo.GetSize();
|
|
|
|
m_void_elements.push_back(e);
|
|
}
|
|
|
|
pos += elemInfo.GetSize(); //consume payload
|
|
assert(pos <= stop);
|
|
}
|
|
|
|
assert(pos == stop);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
const SeekHead::Entry* SeekHead::GetEntry(int idx) const
|
|
{
|
|
if (idx < 0)
|
|
return 0;
|
|
|
|
if (idx >= static_cast<int>(m_entries.size()))
|
|
return 0;
|
|
|
|
return &m_entries[idx];
|
|
}
|
|
|
|
const SeekHead::VoidElement* SeekHead::GetVoidElement(int idx) const
|
|
{
|
|
if (idx < 0)
|
|
return 0;
|
|
|
|
if (idx >= static_cast<int>(m_void_elements.size()))
|
|
return 0;
|
|
|
|
return &m_void_elements[idx];
|
|
}
|
|
|
|
} // namespace mkvparser
|