229 lines
No EOL
4.9 KiB
C++
229 lines
No EOL
4.9 KiB
C++
#include "ebmlheader.hpp"
|
|
#include "imkvreader.hpp"
|
|
#include "ebmlreadhelpers.hpp"
|
|
#include "mkvprofiler.hpp"
|
|
|
|
#include <stddef.h>
|
|
#include <assert.h>
|
|
|
|
namespace mkvparser
|
|
{
|
|
|
|
EBMLHeader::EBMLHeader() :
|
|
m_docType(NULL)
|
|
{
|
|
Init();
|
|
}
|
|
|
|
EBMLHeader::~EBMLHeader()
|
|
{
|
|
mem::Free(m_docType);
|
|
}
|
|
|
|
void EBMLHeader::Init()
|
|
{
|
|
m_version = 1;
|
|
m_readVersion = 1;
|
|
m_maxIdLength = 4;
|
|
m_maxSizeLength = 8;
|
|
|
|
if (m_docType)
|
|
{
|
|
mem::Free(m_docType);
|
|
m_docType = NULL;
|
|
}
|
|
|
|
m_docTypeVersion = 1;
|
|
m_docTypeReadVersion = 1;
|
|
}
|
|
|
|
long long EBMLHeader::Parse(
|
|
IMkvReader* pReader,
|
|
long long& pos)
|
|
{
|
|
PROFILER_SCOPED_EVENT("webm::EBMLHeader::Parse");
|
|
|
|
assert(pReader);
|
|
|
|
long long total, available;
|
|
|
|
long status = pReader->Length(&total, &available);
|
|
|
|
if (status < 0) //error
|
|
return status;
|
|
|
|
pos = 0;
|
|
long long end = (available >= 1024) ? 1024 : available;
|
|
|
|
for (;;)
|
|
{
|
|
unsigned char b = 0;
|
|
|
|
while (pos < end)
|
|
{
|
|
status = pReader->Read(pos, 1, &b);
|
|
|
|
if (status < 0) //error
|
|
return status;
|
|
|
|
if (b == 0x1A)
|
|
break;
|
|
|
|
++pos;
|
|
}
|
|
|
|
if (b != 0x1A)
|
|
{
|
|
if (pos >= 1024)
|
|
return E_FILE_FORMAT_INVALID; //don't bother looking anymore
|
|
|
|
if ((total >= 0) && ((total - available) < 5))
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
return available + 5; //5 = 4-byte ID + 1st byte of size
|
|
}
|
|
|
|
if ((total >= 0) && ((total - pos) < 5))
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
if ((available - pos) < 5)
|
|
return pos + 5; //try again later
|
|
|
|
long len;
|
|
|
|
const long long result = ReadUInt(pReader, pos, len);
|
|
|
|
if (result < 0) //error
|
|
return result;
|
|
|
|
if (result == 0x0A45DFA3) //EBML Header ID
|
|
{
|
|
pos += len; //consume ID
|
|
break;
|
|
}
|
|
|
|
++pos; //throw away just the 0x1A byte, and try again
|
|
}
|
|
|
|
//pos designates start of size field
|
|
|
|
//get length of size field
|
|
|
|
long len;
|
|
long long result = GetUIntLength(pReader, pos, len);
|
|
|
|
if (result < 0) //error
|
|
return result;
|
|
|
|
if (result > 0) //need more data
|
|
return result;
|
|
|
|
assert(len > 0);
|
|
assert(len <= 8);
|
|
|
|
if ((total >= 0) && ((total - pos) < len))
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
if ((available - pos) < len)
|
|
return pos + len; //try again later
|
|
|
|
//get the EBML header size
|
|
|
|
result = ReadUInt(pReader, pos, len);
|
|
|
|
if (result < 0) //error
|
|
return result;
|
|
|
|
pos += len; //consume size field
|
|
|
|
//pos now designates start of payload
|
|
|
|
if ((total >= 0) && ((total - pos) < result))
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
if ((available - pos) < result)
|
|
return pos + result;
|
|
|
|
end = pos + result;
|
|
|
|
Init();
|
|
|
|
while (pos < end)
|
|
{
|
|
long long id, size;
|
|
|
|
status = ParseElementHeader(
|
|
pReader,
|
|
pos,
|
|
end,
|
|
id,
|
|
size);
|
|
|
|
if (status < 0) //error
|
|
return status;
|
|
|
|
if (size == 0) //weird
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
if (id == 0x0286) //version
|
|
{
|
|
m_version = UnserializeUInt(pReader, pos, size);
|
|
|
|
if (m_version <= 0)
|
|
return E_FILE_FORMAT_INVALID;
|
|
}
|
|
else if (id == 0x02F7) //read version
|
|
{
|
|
m_readVersion = UnserializeUInt(pReader, pos, size);
|
|
|
|
if (m_readVersion <= 0)
|
|
return E_FILE_FORMAT_INVALID;
|
|
}
|
|
else if (id == 0x02F2) //max id length
|
|
{
|
|
m_maxIdLength = UnserializeUInt(pReader, pos, size);
|
|
|
|
if (m_maxIdLength <= 0)
|
|
return E_FILE_FORMAT_INVALID;
|
|
}
|
|
else if (id == 0x02F3) //max size length
|
|
{
|
|
m_maxSizeLength = UnserializeUInt(pReader, pos, size);
|
|
|
|
if (m_maxSizeLength <= 0)
|
|
return E_FILE_FORMAT_INVALID;
|
|
}
|
|
else if (id == 0x0282) //doctype
|
|
{
|
|
if (m_docType)
|
|
return E_FILE_FORMAT_INVALID;
|
|
|
|
status = UnserializeString(pReader, pos, size, m_docType);
|
|
|
|
if (status) //error
|
|
return status;
|
|
}
|
|
else if (id == 0x0287) //doctype version
|
|
{
|
|
m_docTypeVersion = UnserializeUInt(pReader, pos, size);
|
|
|
|
if (m_docTypeVersion <= 0)
|
|
return E_FILE_FORMAT_INVALID;
|
|
}
|
|
else if (id == 0x0285) //doctype read version
|
|
{
|
|
m_docTypeReadVersion = UnserializeUInt(pReader, pos, size);
|
|
|
|
if (m_docTypeReadVersion <= 0)
|
|
return E_FILE_FORMAT_INVALID;
|
|
}
|
|
|
|
pos += size;
|
|
}
|
|
|
|
assert(pos == end);
|
|
return 0;
|
|
}
|
|
|
|
|
|
} // namespace mkvparser
|