Block parsing is now robust
Previously, parsing of a Block element was done inside its constructor. Parsing errors were handled via assertion checks, but this only works in practice if there are no actual errors in the file. We did come across a file, however, that used EMBL-style lacing, but the lacing was done incorrectly and so the parse asserted. This isn't acceptable for a production system, and more a graceful handling of parse errors was needed. The code was restructured such that the Block object's ctor does only trivial initialization of member variables. A separate Parse method was added, that is called after the object is constructed. If the parse succeeds all is well, otherwise the object is destroyed and the error is reported to the caller. This commit fixes bug tracker issue #398, described here: http://code.google.com/p/webm/issues/detail?id=398 Change-Id: Ib95ca95d0eec08cf670b308c461e42ed8345e890
This commit is contained in:
parent
71d296e44c
commit
6fa7c7611c
487
mkvparser.cpp
487
mkvparser.cpp
@ -21,7 +21,7 @@ void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision)
|
||||
major = 1;
|
||||
minor = 0;
|
||||
build = 0;
|
||||
revision = 22;
|
||||
revision = 23;
|
||||
}
|
||||
|
||||
long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len)
|
||||
@ -5404,7 +5404,10 @@ long Track::GetFirst(const BlockEntry*& pBlockEntry) const
|
||||
return E_BUFFER_NOT_FULL;
|
||||
}
|
||||
|
||||
pBlockEntry = pCluster->GetFirst();
|
||||
long status = pCluster->GetFirst(pBlockEntry);
|
||||
|
||||
if (status < 0) //error
|
||||
return status;
|
||||
|
||||
if (pBlockEntry == 0) //empty cluster
|
||||
{
|
||||
@ -5422,10 +5425,17 @@ long Track::GetFirst(const BlockEntry*& pBlockEntry) const
|
||||
if ((tn == m_info.number) && VetEntry(pBlockEntry))
|
||||
return 0;
|
||||
|
||||
pBlockEntry = pCluster->GetNext(pBlockEntry);
|
||||
const BlockEntry* pNextEntry;
|
||||
|
||||
if (pBlockEntry == 0)
|
||||
status = pCluster->GetNext(pBlockEntry, pNextEntry);
|
||||
|
||||
if (status < 0) //error
|
||||
return status;
|
||||
|
||||
if (pNextEntry == 0)
|
||||
break;
|
||||
|
||||
pBlockEntry = pNextEntry;
|
||||
}
|
||||
|
||||
++i;
|
||||
@ -5459,7 +5469,10 @@ long Track::GetNext(
|
||||
assert(pCluster);
|
||||
assert(!pCluster->EOS());
|
||||
|
||||
pNextEntry = pCluster->GetNext(pCurrEntry);
|
||||
long status = pCluster->GetNext(pCurrEntry, pNextEntry);
|
||||
|
||||
if (status < 0) //error
|
||||
return status;
|
||||
|
||||
for (int i = 0; ; )
|
||||
{
|
||||
@ -5471,7 +5484,12 @@ long Track::GetNext(
|
||||
if (pNextBlock->GetTrackNumber() == m_info.number)
|
||||
return 0;
|
||||
|
||||
pNextEntry = pCluster->GetNext(pNextEntry);
|
||||
pCurrEntry = pNextEntry;
|
||||
|
||||
status = pCluster->GetNext(pCurrEntry, pNextEntry);
|
||||
|
||||
if (status < 0) //error
|
||||
return status;
|
||||
}
|
||||
|
||||
pCluster = m_pSegment->GetNext(pCluster);
|
||||
@ -5514,7 +5532,10 @@ long Track::GetNext(
|
||||
return E_BUFFER_NOT_FULL;
|
||||
}
|
||||
|
||||
pNextEntry = pCluster->GetFirst();
|
||||
status = pCluster->GetFirst(pNextEntry);
|
||||
|
||||
if (status < 0) //error
|
||||
return status;
|
||||
|
||||
if (pNextEntry == NULL) //empty cluster
|
||||
continue;
|
||||
@ -5632,7 +5653,6 @@ Track::EOSBlock::EOSBlock() :
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
BlockEntry::Kind Track::EOSBlock::GetKind() const
|
||||
{
|
||||
return kBlockEOS;
|
||||
@ -6767,11 +6787,13 @@ long Cluster::Parse(long long& pos, long& len) const
|
||||
return E_BUFFER_NOT_FULL;
|
||||
}
|
||||
|
||||
Cluster* const this_ = const_cast<Cluster*>(this);
|
||||
|
||||
if (id == 0x20) //BlockGroup
|
||||
return ParseBlockGroup(size, pos, len);
|
||||
return this_->ParseBlockGroup(size, pos, len);
|
||||
|
||||
if (id == 0x23) //SimpleBlock
|
||||
return ParseSimpleBlock(size, pos, len);
|
||||
return this_->ParseSimpleBlock(size, pos, len);
|
||||
|
||||
pos += size; //consume payload
|
||||
assert((cluster_stop < 0) || (pos <= cluster_stop));
|
||||
@ -6813,7 +6835,7 @@ long Cluster::Parse(long long& pos, long& len) const
|
||||
long Cluster::ParseSimpleBlock(
|
||||
long long block_size,
|
||||
long long& pos,
|
||||
long& len) const
|
||||
long& len)
|
||||
{
|
||||
const long long block_start = pos;
|
||||
const long long block_stop = pos + block_size;
|
||||
@ -6915,7 +6937,11 @@ long Cluster::ParseSimpleBlock(
|
||||
return E_BUFFER_NOT_FULL;
|
||||
}
|
||||
|
||||
CreateBlock(0x23, block_start, block_size); //simple block id
|
||||
status = CreateBlock(0x23, block_start, block_size); //simple block id
|
||||
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
m_pos = block_stop;
|
||||
|
||||
return 0; //success
|
||||
@ -6925,7 +6951,7 @@ long Cluster::ParseSimpleBlock(
|
||||
long Cluster::ParseBlockGroup(
|
||||
long long payload_size,
|
||||
long long& pos,
|
||||
long& len) const
|
||||
long& len)
|
||||
{
|
||||
const long long payload_start = pos;
|
||||
const long long payload_stop = pos + payload_size;
|
||||
@ -7133,7 +7159,11 @@ long Cluster::ParseBlockGroup(
|
||||
|
||||
assert(pos == payload_stop);
|
||||
|
||||
CreateBlock(0x20, payload_start, payload_size); //BlockGroup ID
|
||||
status = CreateBlock(0x20, payload_start, payload_size); //BlockGroup ID
|
||||
|
||||
if (status != 0)
|
||||
return status;
|
||||
|
||||
m_pos = payload_stop;
|
||||
|
||||
return 0; //success
|
||||
@ -7595,7 +7625,12 @@ long long Cluster::GetTime() const
|
||||
|
||||
long long Cluster::GetFirstTime() const
|
||||
{
|
||||
const BlockEntry* const pEntry = GetFirst();
|
||||
const BlockEntry* pEntry;
|
||||
|
||||
const long status = GetFirst(pEntry);
|
||||
|
||||
if (status < 0) //error
|
||||
return status;
|
||||
|
||||
if (pEntry == NULL) //empty cluster
|
||||
return GetTime();
|
||||
@ -7609,7 +7644,12 @@ long long Cluster::GetFirstTime() const
|
||||
|
||||
long long Cluster::GetLastTime() const
|
||||
{
|
||||
const BlockEntry* const pEntry = GetLast();
|
||||
const BlockEntry* pEntry;
|
||||
|
||||
const long status = GetLast(pEntry);
|
||||
|
||||
if (status < 0) //error
|
||||
return status;
|
||||
|
||||
if (pEntry == NULL) //empty cluster
|
||||
return GetTime();
|
||||
@ -7621,12 +7661,12 @@ long long Cluster::GetLastTime() const
|
||||
}
|
||||
|
||||
|
||||
void Cluster::CreateBlock(
|
||||
long Cluster::CreateBlock(
|
||||
long long id,
|
||||
long long pos, //absolute pos of payload
|
||||
long long size) const
|
||||
long long size)
|
||||
{
|
||||
BlockEntry** ppEntry;
|
||||
assert((id == 0x20) || (id == 0x23)); //BlockGroup or SimpleBlock
|
||||
|
||||
if (m_entries_count < 0) //haven't parsed anything yet
|
||||
{
|
||||
@ -7636,14 +7676,12 @@ void Cluster::CreateBlock(
|
||||
m_entries_size = 1024;
|
||||
m_entries = new BlockEntry*[m_entries_size];
|
||||
|
||||
ppEntry = m_entries;
|
||||
m_entries_count = 1;
|
||||
m_entries_count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(m_entries);
|
||||
assert(m_entries_size > 0);
|
||||
assert(m_entries_count > 0);
|
||||
assert(m_entries_count <= m_entries_size);
|
||||
|
||||
if (m_entries_count >= m_entries_size)
|
||||
@ -7666,36 +7704,23 @@ void Cluster::CreateBlock(
|
||||
m_entries = entries;
|
||||
m_entries_size = entries_size;
|
||||
}
|
||||
|
||||
ppEntry = m_entries + m_entries_count;
|
||||
++m_entries_count;
|
||||
}
|
||||
|
||||
if (id == 0x20) //BlockGroup ID
|
||||
CreateBlockGroup(pos, size, ppEntry);
|
||||
else
|
||||
{
|
||||
assert(id == 0x23); //SimpleBlock ID
|
||||
CreateSimpleBlock(pos, size, ppEntry);
|
||||
}
|
||||
return CreateBlockGroup(pos, size);
|
||||
else //SimpleBlock ID
|
||||
return CreateSimpleBlock(pos, size);
|
||||
}
|
||||
|
||||
|
||||
void Cluster::CreateBlockGroup(
|
||||
long Cluster::CreateBlockGroup(
|
||||
long long st,
|
||||
long long sz,
|
||||
BlockEntry**& ppEntry) const
|
||||
long long sz)
|
||||
{
|
||||
assert(m_entries);
|
||||
assert(m_entries_size > 0);
|
||||
assert(ppEntry);
|
||||
assert(ppEntry >= m_entries);
|
||||
|
||||
const ptrdiff_t idx = ppEntry - m_entries;
|
||||
assert(idx >= 0);
|
||||
assert(idx < m_entries_size);
|
||||
|
||||
Cluster* const this_ = const_cast<Cluster*>(this);
|
||||
assert(m_entries_count >= 0);
|
||||
assert(m_entries_count < m_entries_size);
|
||||
|
||||
IMkvReader* const pReader = m_pSegment->m_pReader;
|
||||
|
||||
@ -7769,133 +7794,185 @@ void Cluster::CreateBlockGroup(
|
||||
assert(bpos >= 0);
|
||||
assert(bsize >= 0);
|
||||
|
||||
*ppEntry++ = new BlockGroup(this_, idx, bpos, bsize, prev, next, duration);
|
||||
const long idx = m_entries_count;
|
||||
|
||||
BlockEntry** const ppEntry = m_entries + idx;
|
||||
BlockEntry*& pEntry = *ppEntry;
|
||||
|
||||
pEntry = new (std::nothrow) BlockGroup(
|
||||
this,
|
||||
idx,
|
||||
bpos,
|
||||
bsize,
|
||||
prev,
|
||||
next,
|
||||
duration);
|
||||
|
||||
if (pEntry == NULL)
|
||||
return -1; //generic error
|
||||
|
||||
BlockGroup* const p = static_cast<BlockGroup*>(pEntry);
|
||||
|
||||
const long status = p->Parse();
|
||||
|
||||
if (status == 0) //success
|
||||
{
|
||||
++m_entries_count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
delete pEntry;
|
||||
pEntry = 0;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Cluster::CreateSimpleBlock(
|
||||
long Cluster::CreateSimpleBlock(
|
||||
long long st,
|
||||
long long sz,
|
||||
BlockEntry**& ppEntry) const
|
||||
long long sz)
|
||||
{
|
||||
assert(m_entries);
|
||||
assert(m_entries_size > 0);
|
||||
assert(ppEntry);
|
||||
assert(ppEntry >= m_entries);
|
||||
assert(m_entries_count >= 0);
|
||||
assert(m_entries_count < m_entries_size);
|
||||
|
||||
const ptrdiff_t idx = ppEntry - m_entries;
|
||||
assert(idx >= 0);
|
||||
assert(idx < m_entries_size);
|
||||
const long idx = m_entries_count;
|
||||
|
||||
Cluster* const this_ = const_cast<Cluster*>(this);
|
||||
*ppEntry++ = new SimpleBlock(this_, idx, st, sz);
|
||||
BlockEntry** const ppEntry = m_entries + idx;
|
||||
BlockEntry*& pEntry = *ppEntry;
|
||||
|
||||
pEntry = new (std::nothrow) SimpleBlock(this, idx, st, sz);
|
||||
|
||||
if (pEntry == NULL)
|
||||
return -1; //generic error
|
||||
|
||||
SimpleBlock* const p = static_cast<SimpleBlock*>(pEntry);
|
||||
|
||||
const long status = p->Parse();
|
||||
|
||||
if (status == 0)
|
||||
{
|
||||
++m_entries_count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
delete pEntry;
|
||||
pEntry = 0;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
const BlockEntry* Cluster::GetFirst() const
|
||||
long Cluster::GetFirst(const BlockEntry*& pFirst) const
|
||||
{
|
||||
#if 0
|
||||
LoadBlockEntries();
|
||||
|
||||
if ((m_entries == NULL) || (m_entries_count <= 0))
|
||||
return NULL;
|
||||
#else
|
||||
if (m_entries_count <= 0)
|
||||
{
|
||||
long long pos;
|
||||
long len;
|
||||
|
||||
const long status = Parse(pos, len);
|
||||
assert(status >= 0);
|
||||
|
||||
if (m_entries_count <= 0)
|
||||
return NULL; //empty cluster
|
||||
if (status < 0) //error
|
||||
{
|
||||
pFirst = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
assert(m_entries);
|
||||
assert(m_entries_count > 0);
|
||||
if (m_entries_count <= 0) //empty cluster
|
||||
{
|
||||
pFirst = NULL;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const BlockEntry* const pFirst = m_entries[0];
|
||||
assert(m_entries);
|
||||
|
||||
pFirst = m_entries[0];
|
||||
assert(pFirst);
|
||||
|
||||
return pFirst;
|
||||
return 0; //success
|
||||
}
|
||||
|
||||
|
||||
const BlockEntry* Cluster::GetLast() const
|
||||
long Cluster::GetLast(const BlockEntry*& pLast) const
|
||||
{
|
||||
#if 0
|
||||
LoadBlockEntries();
|
||||
|
||||
if ((m_entries == NULL) || (m_entries_count <= 0))
|
||||
return NULL;
|
||||
#else
|
||||
for (;;)
|
||||
{
|
||||
long long pos;
|
||||
long len;
|
||||
|
||||
const long status = Parse(pos, len);
|
||||
assert(status >= 0);
|
||||
|
||||
if (status != 0) //no new block
|
||||
if (status < 0) //error
|
||||
{
|
||||
pLast = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
if (status > 0) //no new block
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_entries_count <= 0)
|
||||
return NULL;
|
||||
{
|
||||
pLast = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(m_entries);
|
||||
#endif
|
||||
|
||||
const long idx = m_entries_count - 1;
|
||||
|
||||
const BlockEntry* const pLast = m_entries[idx];
|
||||
pLast = m_entries[idx];
|
||||
assert(pLast);
|
||||
|
||||
return pLast;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const BlockEntry* Cluster::GetNext(const BlockEntry* pEntry) const
|
||||
long Cluster::GetNext(
|
||||
const BlockEntry* pCurr,
|
||||
const BlockEntry*& pNext) const
|
||||
{
|
||||
assert(pEntry);
|
||||
assert(m_entries != NULL);
|
||||
assert(pCurr);
|
||||
assert(m_entries);
|
||||
assert(m_entries_count > 0);
|
||||
|
||||
size_t idx = pEntry->GetIndex();
|
||||
size_t idx = pCurr->GetIndex();
|
||||
assert(idx < size_t(m_entries_count));
|
||||
assert(m_entries[idx] == pEntry);
|
||||
assert(m_entries[idx] == pCurr);
|
||||
|
||||
++idx;
|
||||
|
||||
#if 0
|
||||
if (idx >= size_t(m_entries_count))
|
||||
return NULL;
|
||||
#else
|
||||
if (idx >= size_t(m_entries_count))
|
||||
{
|
||||
long long pos;
|
||||
long len;
|
||||
|
||||
const long status = Parse(pos, len);
|
||||
assert(status >= 0);
|
||||
|
||||
if (status < 0)
|
||||
return NULL;
|
||||
if (status < 0) //error
|
||||
{
|
||||
pNext = NULL;
|
||||
return status;
|
||||
}
|
||||
|
||||
if (status > 0)
|
||||
return NULL;
|
||||
{
|
||||
pNext = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(m_entries);
|
||||
assert(m_entries_count > 0);
|
||||
assert(idx < size_t(m_entries_count));
|
||||
}
|
||||
#endif
|
||||
|
||||
return m_entries[idx];
|
||||
pNext = m_entries[idx];
|
||||
assert(pNext);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -8313,11 +8390,17 @@ SimpleBlock::SimpleBlock(
|
||||
long long start,
|
||||
long long size) :
|
||||
BlockEntry(pCluster, idx),
|
||||
m_block(start, size, pCluster->m_pSegment->m_pReader)
|
||||
m_block(start, size)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
long SimpleBlock::Parse()
|
||||
{
|
||||
return m_block.Parse(m_pCluster->m_pSegment->m_pReader);
|
||||
}
|
||||
|
||||
|
||||
BlockEntry::Kind SimpleBlock::GetKind() const
|
||||
{
|
||||
return kBlockSimple;
|
||||
@ -8339,12 +8422,24 @@ BlockGroup::BlockGroup(
|
||||
long long next,
|
||||
long long duration) :
|
||||
BlockEntry(pCluster, idx),
|
||||
m_block(block_start, block_size, pCluster->m_pSegment->m_pReader),
|
||||
m_block(block_start, block_size),
|
||||
m_prev(prev),
|
||||
m_next(next),
|
||||
m_duration(duration)
|
||||
{
|
||||
m_block.SetKey((prev > 0) && (next <= 0));
|
||||
}
|
||||
|
||||
|
||||
long BlockGroup::Parse()
|
||||
{
|
||||
const long status = m_block.Parse(m_pCluster->m_pSegment->m_pReader);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
m_block.SetKey((m_prev > 0) && (m_next <= 0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -8389,56 +8484,86 @@ long long BlockGroup::GetNextTimeCode() const
|
||||
}
|
||||
|
||||
|
||||
Block::Block(long long start, long long size_, IMkvReader* pReader) :
|
||||
Block::Block(long long start, long long size_) :
|
||||
m_start(start),
|
||||
m_size(size_)
|
||||
m_size(size_),
|
||||
m_track(0),
|
||||
m_timecode(-1),
|
||||
m_flags(0),
|
||||
m_frames(NULL),
|
||||
m_frame_count(-1)
|
||||
{
|
||||
long long pos = start;
|
||||
const long long stop = start + size_;
|
||||
}
|
||||
|
||||
|
||||
Block::~Block()
|
||||
{
|
||||
delete[] m_frames;
|
||||
}
|
||||
|
||||
|
||||
long Block::Parse(IMkvReader* pReader)
|
||||
{
|
||||
assert(pReader);
|
||||
assert(m_start >= 0);
|
||||
assert(m_size >= 0);
|
||||
assert(m_track <= 0);
|
||||
assert(m_frames == NULL);
|
||||
assert(m_frame_count <= 0);
|
||||
|
||||
long long pos = m_start;
|
||||
const long long stop = m_start + m_size;
|
||||
|
||||
long len;
|
||||
|
||||
m_track = ReadUInt(pReader, pos, len);
|
||||
assert(m_track > 0);
|
||||
assert((pos + len) <= stop);
|
||||
|
||||
if (m_track <= 0)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
if ((pos + len) > stop)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
pos += len; //consume track number
|
||||
assert((stop - pos) >= 2);
|
||||
|
||||
if ((stop - pos) < 2)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
long status;
|
||||
|
||||
#if 0
|
||||
m_timecode = Unserialize2SInt(pReader, pos);
|
||||
#else
|
||||
long long value;
|
||||
|
||||
status = UnserializeInt(pReader, pos, 2, value);
|
||||
assert(status == 0);
|
||||
assert(value >= SHRT_MIN);
|
||||
assert(value <= SHRT_MAX);
|
||||
|
||||
if (status)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
if (value < SHRT_MIN)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
if (value > SHRT_MAX)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
m_timecode = static_cast<short>(value);
|
||||
#endif
|
||||
|
||||
pos += 2;
|
||||
assert((stop - pos) >= 1);
|
||||
|
||||
if ((stop - pos) <= 0)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
status = pReader->Read(pos, 1, &m_flags);
|
||||
assert(status == 0);
|
||||
|
||||
#if 0
|
||||
const int invisible = int(m_flags & 0x08) >> 3;
|
||||
invisible;
|
||||
assert(!invisible); //TODO
|
||||
#endif
|
||||
if (status)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
const int lacing = int(m_flags & 0x06) >> 1;
|
||||
|
||||
++pos; //consume flags byte
|
||||
assert(pos <= stop);
|
||||
|
||||
if (lacing == 0) //no lacing
|
||||
{
|
||||
if (pos > stop)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
m_frame_count = 1;
|
||||
m_frames = new Frame[m_frame_count];
|
||||
|
||||
@ -8446,19 +8571,24 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
|
||||
f.pos = pos;
|
||||
|
||||
const long long frame_size = stop - pos;
|
||||
assert(frame_size <= LONG_MAX);
|
||||
|
||||
if (frame_size > LONG_MAX)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
f.len = static_cast<long>(frame_size);
|
||||
|
||||
return;
|
||||
return 0; //success
|
||||
}
|
||||
|
||||
assert(pos < stop);
|
||||
if (pos >= stop)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
unsigned char biased_count;
|
||||
|
||||
status = pReader->Read(pos, 1, &biased_count);
|
||||
assert(status == 0);
|
||||
|
||||
if (status)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
++pos; //consume frame count
|
||||
assert(pos <= stop);
|
||||
@ -8484,8 +8614,13 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
|
||||
{
|
||||
unsigned char val;
|
||||
|
||||
if (pos >= stop)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
status = pReader->Read(pos, 1, &val);
|
||||
assert(status == 0);
|
||||
|
||||
if (status)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
++pos; //consume xiph size byte
|
||||
|
||||
@ -8498,6 +8633,8 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
|
||||
Frame& f = *pf++;
|
||||
assert(pf < pf_end);
|
||||
|
||||
f.pos = 0; //patch later
|
||||
|
||||
f.len = frame_size;
|
||||
size += frame_size; //contribution of this frame
|
||||
|
||||
@ -8505,17 +8642,25 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
|
||||
}
|
||||
|
||||
assert(pf < pf_end);
|
||||
assert(pos < stop);
|
||||
assert(pos <= stop);
|
||||
|
||||
{
|
||||
Frame& f = *pf++;
|
||||
assert(pf == pf_end);
|
||||
|
||||
if (pf != pf_end)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
f.pos = 0; //patch later
|
||||
|
||||
const long long total_size = stop - pos;
|
||||
assert(total_size > size);
|
||||
|
||||
if (total_size < size)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
const long long frame_size = total_size - size;
|
||||
assert(frame_size <= LONG_MAX);
|
||||
|
||||
if (frame_size > LONG_MAX)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
f.len = static_cast<long>(frame_size);
|
||||
}
|
||||
@ -8535,10 +8680,14 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
|
||||
else if (lacing == 2) //fixed-size lacing
|
||||
{
|
||||
const long long total_size = stop - pos;
|
||||
assert((total_size % m_frame_count) == 0);
|
||||
|
||||
if ((total_size % m_frame_count) != 0)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
const long long frame_size = total_size / m_frame_count;
|
||||
assert(frame_size <= LONG_MAX);
|
||||
|
||||
if (frame_size > LONG_MAX)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
Frame* pf = m_frames;
|
||||
Frame* const pf_end = pf + m_frame_count;
|
||||
@ -8560,18 +8709,28 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
|
||||
else
|
||||
{
|
||||
assert(lacing == 3); //EBML lacing
|
||||
assert(pos < stop);
|
||||
|
||||
if (pos >= stop)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
long size = 0;
|
||||
int frame_count = m_frame_count;
|
||||
|
||||
long long frame_size = ReadUInt(pReader, pos, len);
|
||||
assert(frame_size > 0);
|
||||
assert(frame_size <= LONG_MAX);
|
||||
assert((pos + len) <= stop);
|
||||
|
||||
if (frame_size < 0)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
if (frame_size > LONG_MAX)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
if ((pos + len) > stop)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
pos += len; //consume length of size of first frame
|
||||
assert((pos + frame_size) <= stop);
|
||||
|
||||
if ((pos + frame_size) > stop)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
Frame* pf = m_frames;
|
||||
Frame* const pf_end = pf + m_frame_count;
|
||||
@ -8579,6 +8738,8 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
|
||||
{
|
||||
Frame& curr = *pf;
|
||||
|
||||
curr.pos = 0; //patch later
|
||||
|
||||
curr.len = static_cast<long>(frame_size);
|
||||
size += curr.len; //contribution of this frame
|
||||
}
|
||||
@ -8587,18 +8748,27 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
|
||||
|
||||
while (frame_count > 1)
|
||||
{
|
||||
assert(pos < stop);
|
||||
if (pos >= stop)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
assert(pf < pf_end);
|
||||
|
||||
const Frame& prev = *pf++;
|
||||
assert(pf < pf_end);
|
||||
assert(prev.len == frame_size);
|
||||
|
||||
assert(pf < pf_end);
|
||||
|
||||
Frame& curr = *pf;
|
||||
|
||||
curr.pos = 0; //patch later
|
||||
|
||||
const long long delta_size_ = ReadUInt(pReader, pos, len);
|
||||
assert(delta_size_ >= 0);
|
||||
assert((pos + len) <= stop);
|
||||
|
||||
if (delta_size_ < 0)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
if ((pos + len) > stop)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
pos += len; //consume length of (delta) size
|
||||
assert(pos <= stop);
|
||||
@ -8608,8 +8778,12 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
|
||||
const long long delta_size = delta_size_ - bias;
|
||||
|
||||
frame_size += delta_size;
|
||||
assert(frame_size > 0);
|
||||
assert(frame_size <= LONG_MAX);
|
||||
|
||||
if (frame_size < 0)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
if (frame_size > LONG_MAX)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
curr.len = static_cast<long>(frame_size);
|
||||
size += curr.len; //contribution of this frame
|
||||
@ -8618,23 +8792,28 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
|
||||
}
|
||||
|
||||
{
|
||||
assert(pos < stop);
|
||||
assert(pos <= stop);
|
||||
assert(pf < pf_end);
|
||||
|
||||
const Frame& prev = *pf++;
|
||||
assert(pf < pf_end);
|
||||
assert(prev.len == frame_size);
|
||||
|
||||
assert(pf < pf_end);
|
||||
|
||||
Frame& curr = *pf++;
|
||||
assert(pf == pf_end);
|
||||
|
||||
curr.pos = 0; //patch later
|
||||
|
||||
const long long total_size = stop - pos;
|
||||
assert(total_size > 0);
|
||||
assert(total_size > size);
|
||||
|
||||
if (total_size < size)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
frame_size = total_size - size;
|
||||
assert(frame_size > 0);
|
||||
assert(frame_size <= LONG_MAX);
|
||||
|
||||
if (frame_size > LONG_MAX)
|
||||
return E_FILE_FORMAT_INVALID;
|
||||
|
||||
curr.len = static_cast<long>(frame_size);
|
||||
}
|
||||
@ -8651,12 +8830,8 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
|
||||
|
||||
assert(pos == stop);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Block::~Block()
|
||||
{
|
||||
delete[] m_frames;
|
||||
return 0; //success
|
||||
}
|
||||
|
||||
|
||||
|
@ -80,9 +80,11 @@ public:
|
||||
const long long m_start;
|
||||
const long long m_size;
|
||||
|
||||
Block(long long start, long long size, IMkvReader*);
|
||||
Block(long long start, long long size);
|
||||
~Block();
|
||||
|
||||
long Parse(IMkvReader*);
|
||||
|
||||
long long GetTrackNumber() const;
|
||||
long long GetTimeCode(const Cluster*) const; //absolute, but not scaled
|
||||
long long GetTime(const Cluster*) const; //absolute, and scaled (ns)
|
||||
@ -126,6 +128,7 @@ protected:
|
||||
|
||||
public:
|
||||
virtual ~BlockEntry();
|
||||
|
||||
bool EOS() const;
|
||||
const Cluster* GetCluster() const;
|
||||
long GetIndex() const;
|
||||
@ -148,6 +151,7 @@ class SimpleBlock : public BlockEntry
|
||||
|
||||
public:
|
||||
SimpleBlock(Cluster*, long index, long long start, long long size);
|
||||
long Parse();
|
||||
|
||||
Kind GetKind() const;
|
||||
const Block* GetBlock() const;
|
||||
@ -173,6 +177,8 @@ public:
|
||||
long long next,
|
||||
long long duration);
|
||||
|
||||
long Parse();
|
||||
|
||||
Kind GetKind() const;
|
||||
const Block* GetBlock() const;
|
||||
|
||||
@ -345,9 +351,6 @@ protected:
|
||||
public:
|
||||
EOSBlock();
|
||||
|
||||
//bool EOS() const;
|
||||
//const Cluster* GetCluster() const;
|
||||
//long GetIndex() const;
|
||||
Kind GetKind() const;
|
||||
const Block* GetBlock() const;
|
||||
};
|
||||
@ -680,9 +683,10 @@ public:
|
||||
long long GetFirstTime() const; //time (ns) of first (earliest) block
|
||||
long long GetLastTime() const; //time (ns) of last (latest) block
|
||||
|
||||
const BlockEntry* GetFirst() const;
|
||||
const BlockEntry* GetLast() const;
|
||||
const BlockEntry* GetNext(const BlockEntry*) const;
|
||||
long GetFirst(const BlockEntry*&) const;
|
||||
long GetLast(const BlockEntry*&) const;
|
||||
long GetNext(const BlockEntry* curr, const BlockEntry*& next) const;
|
||||
|
||||
const BlockEntry* GetEntry(const Track*, long long ns = -1) const;
|
||||
const BlockEntry* GetEntry(
|
||||
const CuePoint&,
|
||||
@ -731,12 +735,12 @@ private:
|
||||
mutable long m_entries_size;
|
||||
mutable long m_entries_count;
|
||||
|
||||
long ParseSimpleBlock(long long, long long&, long&) const;
|
||||
long ParseBlockGroup(long long, long long&, long&) const;
|
||||
long ParseSimpleBlock(long long, long long&, long&);
|
||||
long ParseBlockGroup(long long, long long&, long&);
|
||||
|
||||
void CreateBlock(long long id, long long pos, long long size) const;
|
||||
void CreateBlockGroup(long long, long long, BlockEntry**&) const;
|
||||
void CreateSimpleBlock(long long, long long, BlockEntry**&) const;
|
||||
long CreateBlock(long long id, long long pos, long long size);
|
||||
long CreateBlockGroup(long long, long long);
|
||||
long CreateSimpleBlock(long long, long long);
|
||||
|
||||
};
|
||||
|
||||
|
21
sample.cpp
21
sample.cpp
@ -256,7 +256,16 @@ int main(int argc, char* argv[])
|
||||
const long long time_ns = pCluster->GetTime();
|
||||
printf("\t\tCluster Time (ns)\t: %lld\n", time_ns);
|
||||
|
||||
const BlockEntry* pBlockEntry = pCluster->GetFirst();
|
||||
const BlockEntry* pBlockEntry;
|
||||
|
||||
long status = pCluster->GetFirst(pBlockEntry);
|
||||
|
||||
if (status < 0) //error
|
||||
{
|
||||
printf("\t\tError parsing first block of cluster\n");
|
||||
fflush(stdout);
|
||||
goto done;
|
||||
}
|
||||
|
||||
while ((pBlockEntry != NULL) && !pBlockEntry->EOS())
|
||||
{
|
||||
@ -281,12 +290,20 @@ int main(int argc, char* argv[])
|
||||
printf("\t\t\t %15ld,%15llx\n", size, offset);
|
||||
}
|
||||
|
||||
pBlockEntry = pCluster->GetNext(pBlockEntry);
|
||||
status = pCluster->GetNext(pBlockEntry, pBlockEntry);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("\t\t\tError parsing next block of cluster\n");
|
||||
fflush(stdout);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
pCluster = pSegment->GetNext(pCluster);
|
||||
}
|
||||
|
||||
done:
|
||||
delete pSegment;
|
||||
return 0;
|
||||
|
||||
|
@ -317,7 +317,15 @@ int main(int argc, char* argv[]) {
|
||||
const mkvparser::Cluster* cluster = parser_segment->GetFirst();
|
||||
|
||||
while ((cluster != NULL) && !cluster->EOS()) {
|
||||
const mkvparser::BlockEntry* block_entry = cluster->GetFirst();
|
||||
const mkvparser::BlockEntry* block_entry;
|
||||
|
||||
long status = cluster->GetFirst(block_entry);
|
||||
|
||||
if (status)
|
||||
{
|
||||
printf("\n Could not get first block of cluster.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
while ((block_entry != NULL) && !block_entry->EOS()) {
|
||||
const mkvparser::Block* const block = block_entry->GetBlock();
|
||||
@ -362,7 +370,13 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
}
|
||||
|
||||
block_entry = cluster->GetNext(block_entry);
|
||||
status = cluster->GetNext(block_entry, block_entry);
|
||||
|
||||
if (status)
|
||||
{
|
||||
printf("\n Could not get next block of cluster.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
cluster = parser_segment->GetNext(cluster);
|
||||
|
Loading…
x
Reference in New Issue
Block a user