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:
matthewjheaney 2012-02-23 20:55:37 -05:00
parent 71d296e44c
commit 6fa7c7611c
4 changed files with 382 additions and 172 deletions

View File

@ -21,7 +21,7 @@ void mkvparser::GetVersion(int& major, int& minor, int& build, int& revision)
major = 1; major = 1;
minor = 0; minor = 0;
build = 0; build = 0;
revision = 22; revision = 23;
} }
long long mkvparser::ReadUInt(IMkvReader* pReader, long long pos, long& len) 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; return E_BUFFER_NOT_FULL;
} }
pBlockEntry = pCluster->GetFirst(); long status = pCluster->GetFirst(pBlockEntry);
if (status < 0) //error
return status;
if (pBlockEntry == 0) //empty cluster if (pBlockEntry == 0) //empty cluster
{ {
@ -5422,10 +5425,17 @@ long Track::GetFirst(const BlockEntry*& pBlockEntry) const
if ((tn == m_info.number) && VetEntry(pBlockEntry)) if ((tn == m_info.number) && VetEntry(pBlockEntry))
return 0; 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; break;
pBlockEntry = pNextEntry;
} }
++i; ++i;
@ -5459,7 +5469,10 @@ long Track::GetNext(
assert(pCluster); assert(pCluster);
assert(!pCluster->EOS()); assert(!pCluster->EOS());
pNextEntry = pCluster->GetNext(pCurrEntry); long status = pCluster->GetNext(pCurrEntry, pNextEntry);
if (status < 0) //error
return status;
for (int i = 0; ; ) for (int i = 0; ; )
{ {
@ -5471,7 +5484,12 @@ long Track::GetNext(
if (pNextBlock->GetTrackNumber() == m_info.number) if (pNextBlock->GetTrackNumber() == m_info.number)
return 0; return 0;
pNextEntry = pCluster->GetNext(pNextEntry); pCurrEntry = pNextEntry;
status = pCluster->GetNext(pCurrEntry, pNextEntry);
if (status < 0) //error
return status;
} }
pCluster = m_pSegment->GetNext(pCluster); pCluster = m_pSegment->GetNext(pCluster);
@ -5514,7 +5532,10 @@ long Track::GetNext(
return E_BUFFER_NOT_FULL; return E_BUFFER_NOT_FULL;
} }
pNextEntry = pCluster->GetFirst(); status = pCluster->GetFirst(pNextEntry);
if (status < 0) //error
return status;
if (pNextEntry == NULL) //empty cluster if (pNextEntry == NULL) //empty cluster
continue; continue;
@ -5632,7 +5653,6 @@ Track::EOSBlock::EOSBlock() :
{ {
} }
BlockEntry::Kind Track::EOSBlock::GetKind() const BlockEntry::Kind Track::EOSBlock::GetKind() const
{ {
return kBlockEOS; return kBlockEOS;
@ -6767,11 +6787,13 @@ long Cluster::Parse(long long& pos, long& len) const
return E_BUFFER_NOT_FULL; return E_BUFFER_NOT_FULL;
} }
Cluster* const this_ = const_cast<Cluster*>(this);
if (id == 0x20) //BlockGroup if (id == 0x20) //BlockGroup
return ParseBlockGroup(size, pos, len); return this_->ParseBlockGroup(size, pos, len);
if (id == 0x23) //SimpleBlock if (id == 0x23) //SimpleBlock
return ParseSimpleBlock(size, pos, len); return this_->ParseSimpleBlock(size, pos, len);
pos += size; //consume payload pos += size; //consume payload
assert((cluster_stop < 0) || (pos <= cluster_stop)); assert((cluster_stop < 0) || (pos <= cluster_stop));
@ -6813,7 +6835,7 @@ long Cluster::Parse(long long& pos, long& len) const
long Cluster::ParseSimpleBlock( long Cluster::ParseSimpleBlock(
long long block_size, long long block_size,
long long& pos, long long& pos,
long& len) const long& len)
{ {
const long long block_start = pos; const long long block_start = pos;
const long long block_stop = pos + block_size; const long long block_stop = pos + block_size;
@ -6915,7 +6937,11 @@ long Cluster::ParseSimpleBlock(
return E_BUFFER_NOT_FULL; 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; m_pos = block_stop;
return 0; //success return 0; //success
@ -6925,7 +6951,7 @@ long Cluster::ParseSimpleBlock(
long Cluster::ParseBlockGroup( long Cluster::ParseBlockGroup(
long long payload_size, long long payload_size,
long long& pos, long long& pos,
long& len) const long& len)
{ {
const long long payload_start = pos; const long long payload_start = pos;
const long long payload_stop = pos + payload_size; const long long payload_stop = pos + payload_size;
@ -7133,7 +7159,11 @@ long Cluster::ParseBlockGroup(
assert(pos == payload_stop); 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; m_pos = payload_stop;
return 0; //success return 0; //success
@ -7595,7 +7625,12 @@ long long Cluster::GetTime() const
long long Cluster::GetFirstTime() 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 if (pEntry == NULL) //empty cluster
return GetTime(); return GetTime();
@ -7609,7 +7644,12 @@ long long Cluster::GetFirstTime() const
long long Cluster::GetLastTime() 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 if (pEntry == NULL) //empty cluster
return GetTime(); return GetTime();
@ -7621,12 +7661,12 @@ long long Cluster::GetLastTime() const
} }
void Cluster::CreateBlock( long Cluster::CreateBlock(
long long id, long long id,
long long pos, //absolute pos of payload 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 if (m_entries_count < 0) //haven't parsed anything yet
{ {
@ -7636,14 +7676,12 @@ void Cluster::CreateBlock(
m_entries_size = 1024; m_entries_size = 1024;
m_entries = new BlockEntry*[m_entries_size]; m_entries = new BlockEntry*[m_entries_size];
ppEntry = m_entries; m_entries_count = 0;
m_entries_count = 1;
} }
else else
{ {
assert(m_entries); assert(m_entries);
assert(m_entries_size > 0); assert(m_entries_size > 0);
assert(m_entries_count > 0);
assert(m_entries_count <= m_entries_size); assert(m_entries_count <= m_entries_size);
if (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 = entries;
m_entries_size = entries_size; m_entries_size = entries_size;
} }
ppEntry = m_entries + m_entries_count;
++m_entries_count;
} }
if (id == 0x20) //BlockGroup ID if (id == 0x20) //BlockGroup ID
CreateBlockGroup(pos, size, ppEntry); return CreateBlockGroup(pos, size);
else else //SimpleBlock ID
{ return CreateSimpleBlock(pos, size);
assert(id == 0x23); //SimpleBlock ID
CreateSimpleBlock(pos, size, ppEntry);
}
} }
void Cluster::CreateBlockGroup( long Cluster::CreateBlockGroup(
long long st, long long st,
long long sz, long long sz)
BlockEntry**& ppEntry) const
{ {
assert(m_entries); assert(m_entries);
assert(m_entries_size > 0); assert(m_entries_size > 0);
assert(ppEntry); assert(m_entries_count >= 0);
assert(ppEntry >= m_entries); assert(m_entries_count < m_entries_size);
const ptrdiff_t idx = ppEntry - m_entries;
assert(idx >= 0);
assert(idx < m_entries_size);
Cluster* const this_ = const_cast<Cluster*>(this);
IMkvReader* const pReader = m_pSegment->m_pReader; IMkvReader* const pReader = m_pSegment->m_pReader;
@ -7769,133 +7794,185 @@ void Cluster::CreateBlockGroup(
assert(bpos >= 0); assert(bpos >= 0);
assert(bsize >= 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 st,
long long sz, long long sz)
BlockEntry**& ppEntry) const
{ {
assert(m_entries); assert(m_entries);
assert(m_entries_size > 0); assert(m_entries_size > 0);
assert(ppEntry); assert(m_entries_count >= 0);
assert(ppEntry >= m_entries); assert(m_entries_count < m_entries_size);
const ptrdiff_t idx = ppEntry - m_entries; const long idx = m_entries_count;
assert(idx >= 0);
assert(idx < m_entries_size);
Cluster* const this_ = const_cast<Cluster*>(this); BlockEntry** const ppEntry = m_entries + idx;
*ppEntry++ = new SimpleBlock(this_, idx, st, sz); 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) if (m_entries_count <= 0)
{ {
long long pos; long long pos;
long len; long len;
const long status = Parse(pos, len); const long status = Parse(pos, len);
assert(status >= 0);
if (m_entries_count <= 0) if (status < 0) //error
return NULL; //empty cluster {
pFirst = NULL;
return status;
}
assert(m_entries); if (m_entries_count <= 0) //empty cluster
assert(m_entries_count > 0); {
pFirst = NULL;
return 0;
}
} }
#endif
const BlockEntry* const pFirst = m_entries[0]; assert(m_entries);
pFirst = m_entries[0];
assert(pFirst); assert(pFirst);
return pFirst; return 0; //success
} }
long Cluster::GetLast(const BlockEntry*& pLast) const
const BlockEntry* Cluster::GetLast() const
{ {
#if 0
LoadBlockEntries();
if ((m_entries == NULL) || (m_entries_count <= 0))
return NULL;
#else
for (;;) for (;;)
{ {
long long pos; long long pos;
long len; long len;
const long status = Parse(pos, 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; break;
} }
if (m_entries_count <= 0) if (m_entries_count <= 0)
return NULL; {
pLast = NULL;
return 0;
}
assert(m_entries); assert(m_entries);
#endif
const long idx = m_entries_count - 1; const long idx = m_entries_count - 1;
const BlockEntry* const pLast = m_entries[idx]; pLast = m_entries[idx];
assert(pLast); 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(pCurr);
assert(m_entries != NULL); assert(m_entries);
assert(m_entries_count > 0); assert(m_entries_count > 0);
size_t idx = pEntry->GetIndex(); size_t idx = pCurr->GetIndex();
assert(idx < size_t(m_entries_count)); assert(idx < size_t(m_entries_count));
assert(m_entries[idx] == pEntry); assert(m_entries[idx] == pCurr);
++idx; ++idx;
#if 0
if (idx >= size_t(m_entries_count))
return NULL;
#else
if (idx >= size_t(m_entries_count)) if (idx >= size_t(m_entries_count))
{ {
long long pos; long long pos;
long len; long len;
const long status = Parse(pos, len); const long status = Parse(pos, len);
assert(status >= 0);
if (status < 0) if (status < 0) //error
return NULL; {
pNext = NULL;
return status;
}
if (status > 0) if (status > 0)
return NULL; {
pNext = NULL;
return 0;
}
assert(m_entries); assert(m_entries);
assert(m_entries_count > 0); assert(m_entries_count > 0);
assert(idx < size_t(m_entries_count)); 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 start,
long long size) : long long size) :
BlockEntry(pCluster, idx), 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 BlockEntry::Kind SimpleBlock::GetKind() const
{ {
return kBlockSimple; return kBlockSimple;
@ -8339,12 +8422,24 @@ BlockGroup::BlockGroup(
long long next, long long next,
long long duration) : long long duration) :
BlockEntry(pCluster, idx), BlockEntry(pCluster, idx),
m_block(block_start, block_size, pCluster->m_pSegment->m_pReader), m_block(block_start, block_size),
m_prev(prev), m_prev(prev),
m_next(next), m_next(next),
m_duration(duration) 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_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; long len;
m_track = ReadUInt(pReader, pos, 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 pos += len; //consume track number
assert((stop - pos) >= 2);
if ((stop - pos) < 2)
return E_FILE_FORMAT_INVALID;
long status; long status;
#if 0
m_timecode = Unserialize2SInt(pReader, pos);
#else
long long value; long long value;
status = UnserializeInt(pReader, pos, 2, value); status = UnserializeInt(pReader, pos, 2, value);
assert(status == 0);
assert(value >= SHRT_MIN); if (status)
assert(value <= SHRT_MAX); 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); m_timecode = static_cast<short>(value);
#endif
pos += 2; pos += 2;
assert((stop - pos) >= 1);
if ((stop - pos) <= 0)
return E_FILE_FORMAT_INVALID;
status = pReader->Read(pos, 1, &m_flags); status = pReader->Read(pos, 1, &m_flags);
assert(status == 0);
#if 0 if (status)
const int invisible = int(m_flags & 0x08) >> 3; return E_FILE_FORMAT_INVALID;
invisible;
assert(!invisible); //TODO
#endif
const int lacing = int(m_flags & 0x06) >> 1; const int lacing = int(m_flags & 0x06) >> 1;
++pos; //consume flags byte ++pos; //consume flags byte
assert(pos <= stop);
if (lacing == 0) //no lacing if (lacing == 0) //no lacing
{ {
if (pos > stop)
return E_FILE_FORMAT_INVALID;
m_frame_count = 1; m_frame_count = 1;
m_frames = new Frame[m_frame_count]; m_frames = new Frame[m_frame_count];
@ -8446,19 +8571,24 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
f.pos = pos; f.pos = pos;
const long long frame_size = stop - 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); 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; unsigned char biased_count;
status = pReader->Read(pos, 1, &biased_count); status = pReader->Read(pos, 1, &biased_count);
assert(status == 0);
if (status)
return E_FILE_FORMAT_INVALID;
++pos; //consume frame count ++pos; //consume frame count
assert(pos <= stop); assert(pos <= stop);
@ -8484,8 +8614,13 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
{ {
unsigned char val; unsigned char val;
if (pos >= stop)
return E_FILE_FORMAT_INVALID;
status = pReader->Read(pos, 1, &val); status = pReader->Read(pos, 1, &val);
assert(status == 0);
if (status)
return E_FILE_FORMAT_INVALID;
++pos; //consume xiph size byte ++pos; //consume xiph size byte
@ -8498,6 +8633,8 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
Frame& f = *pf++; Frame& f = *pf++;
assert(pf < pf_end); assert(pf < pf_end);
f.pos = 0; //patch later
f.len = frame_size; f.len = frame_size;
size += frame_size; //contribution of this frame 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(pf < pf_end);
assert(pos < stop); assert(pos <= stop);
{ {
Frame& f = *pf++; 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; 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; 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); 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 else if (lacing == 2) //fixed-size lacing
{ {
const long long total_size = stop - pos; 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; 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* pf = m_frames;
Frame* const pf_end = pf + m_frame_count; Frame* const pf_end = pf + m_frame_count;
@ -8560,18 +8709,28 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
else else
{ {
assert(lacing == 3); //EBML lacing assert(lacing == 3); //EBML lacing
assert(pos < stop);
if (pos >= stop)
return E_FILE_FORMAT_INVALID;
long size = 0; long size = 0;
int frame_count = m_frame_count; int frame_count = m_frame_count;
long long frame_size = ReadUInt(pReader, pos, len); long long frame_size = ReadUInt(pReader, pos, len);
assert(frame_size > 0);
assert(frame_size <= LONG_MAX); if (frame_size < 0)
assert((pos + len) <= stop); 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 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* pf = m_frames;
Frame* const pf_end = pf + m_frame_count; 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; Frame& curr = *pf;
curr.pos = 0; //patch later
curr.len = static_cast<long>(frame_size); curr.len = static_cast<long>(frame_size);
size += curr.len; //contribution of this frame 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) while (frame_count > 1)
{ {
assert(pos < stop); if (pos >= stop)
return E_FILE_FORMAT_INVALID;
assert(pf < pf_end); assert(pf < pf_end);
const Frame& prev = *pf++; const Frame& prev = *pf++;
assert(pf < pf_end);
assert(prev.len == frame_size); assert(prev.len == frame_size);
assert(pf < pf_end);
Frame& curr = *pf; Frame& curr = *pf;
curr.pos = 0; //patch later
const long long delta_size_ = ReadUInt(pReader, pos, len); 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 pos += len; //consume length of (delta) size
assert(pos <= stop); 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; const long long delta_size = delta_size_ - bias;
frame_size += delta_size; 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); curr.len = static_cast<long>(frame_size);
size += curr.len; //contribution of this frame 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); assert(pf < pf_end);
const Frame& prev = *pf++; const Frame& prev = *pf++;
assert(pf < pf_end);
assert(prev.len == frame_size); assert(prev.len == frame_size);
assert(pf < pf_end);
Frame& curr = *pf++; Frame& curr = *pf++;
assert(pf == pf_end); assert(pf == pf_end);
curr.pos = 0; //patch later
const long long total_size = stop - pos; 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; 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); curr.len = static_cast<long>(frame_size);
} }
@ -8651,12 +8830,8 @@ Block::Block(long long start, long long size_, IMkvReader* pReader) :
assert(pos == stop); assert(pos == stop);
} }
}
return 0; //success
Block::~Block()
{
delete[] m_frames;
} }

View File

@ -80,9 +80,11 @@ public:
const long long m_start; const long long m_start;
const long long m_size; const long long m_size;
Block(long long start, long long size, IMkvReader*); Block(long long start, long long size);
~Block(); ~Block();
long Parse(IMkvReader*);
long long GetTrackNumber() const; long long GetTrackNumber() const;
long long GetTimeCode(const Cluster*) const; //absolute, but not scaled long long GetTimeCode(const Cluster*) const; //absolute, but not scaled
long long GetTime(const Cluster*) const; //absolute, and scaled (ns) long long GetTime(const Cluster*) const; //absolute, and scaled (ns)
@ -126,6 +128,7 @@ protected:
public: public:
virtual ~BlockEntry(); virtual ~BlockEntry();
bool EOS() const; bool EOS() const;
const Cluster* GetCluster() const; const Cluster* GetCluster() const;
long GetIndex() const; long GetIndex() const;
@ -148,6 +151,7 @@ class SimpleBlock : public BlockEntry
public: public:
SimpleBlock(Cluster*, long index, long long start, long long size); SimpleBlock(Cluster*, long index, long long start, long long size);
long Parse();
Kind GetKind() const; Kind GetKind() const;
const Block* GetBlock() const; const Block* GetBlock() const;
@ -173,6 +177,8 @@ public:
long long next, long long next,
long long duration); long long duration);
long Parse();
Kind GetKind() const; Kind GetKind() const;
const Block* GetBlock() const; const Block* GetBlock() const;
@ -345,9 +351,6 @@ protected:
public: public:
EOSBlock(); EOSBlock();
//bool EOS() const;
//const Cluster* GetCluster() const;
//long GetIndex() const;
Kind GetKind() const; Kind GetKind() const;
const Block* GetBlock() const; const Block* GetBlock() const;
}; };
@ -680,9 +683,10 @@ public:
long long GetFirstTime() const; //time (ns) of first (earliest) block long long GetFirstTime() const; //time (ns) of first (earliest) block
long long GetLastTime() const; //time (ns) of last (latest) block long long GetLastTime() const; //time (ns) of last (latest) block
const BlockEntry* GetFirst() const; long GetFirst(const BlockEntry*&) const;
const BlockEntry* GetLast() const; long GetLast(const BlockEntry*&) const;
const BlockEntry* GetNext(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 Track*, long long ns = -1) const;
const BlockEntry* GetEntry( const BlockEntry* GetEntry(
const CuePoint&, const CuePoint&,
@ -731,12 +735,12 @@ private:
mutable long m_entries_size; mutable long m_entries_size;
mutable long m_entries_count; mutable long m_entries_count;
long ParseSimpleBlock(long long, long long&, long&) const; long ParseSimpleBlock(long long, long long&, long&);
long ParseBlockGroup(long long, long long&, long&) const; long ParseBlockGroup(long long, long long&, long&);
void CreateBlock(long long id, long long pos, long long size) const; long CreateBlock(long long id, long long pos, long long size);
void CreateBlockGroup(long long, long long, BlockEntry**&) const; long CreateBlockGroup(long long, long long);
void CreateSimpleBlock(long long, long long, BlockEntry**&) const; long CreateSimpleBlock(long long, long long);
}; };

View File

@ -256,7 +256,16 @@ int main(int argc, char* argv[])
const long long time_ns = pCluster->GetTime(); const long long time_ns = pCluster->GetTime();
printf("\t\tCluster Time (ns)\t: %lld\n", time_ns); 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()) while ((pBlockEntry != NULL) && !pBlockEntry->EOS())
{ {
@ -281,12 +290,20 @@ int main(int argc, char* argv[])
printf("\t\t\t %15ld,%15llx\n", size, offset); 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); pCluster = pSegment->GetNext(pCluster);
} }
done:
delete pSegment; delete pSegment;
return 0; return 0;

View File

@ -317,7 +317,15 @@ int main(int argc, char* argv[]) {
const mkvparser::Cluster* cluster = parser_segment->GetFirst(); const mkvparser::Cluster* cluster = parser_segment->GetFirst();
while ((cluster != NULL) && !cluster->EOS()) { 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()) { while ((block_entry != NULL) && !block_entry->EOS()) {
const mkvparser::Block* const block = block_entry->GetBlock(); 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); cluster = parser_segment->GetNext(cluster);