Compare commits

...

3 Commits

Author SHA1 Message Date
matthewjheaney
f031dc1731 preliminary work on parser class
Change-Id: I792fd2a0f08f5383574f583b55e867056db36efe
2012-03-02 19:04:27 -05:00
matthewjheaney
274c641666 initial revision
Change-Id: I31cc4d08f7d5230e97750766414f28774481ab8c
2012-03-02 18:36:50 -05:00
matthewjheaney
6fa7c7611c 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
2012-02-28 14:03:21 -05:00
8 changed files with 628 additions and 172 deletions

View File

@@ -13,6 +13,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sample_muxer", "sample_muxe
{7B1F12CA-0724-430B-B61A-1D357C912CBA} = {7B1F12CA-0724-430B-B61A-1D357C912CBA} {7B1F12CA-0724-430B-B61A-1D357C912CBA} = {7B1F12CA-0724-430B-B61A-1D357C912CBA}
EndProjectSection EndProjectSection
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libwebvtt", "libwebvtt.vcproj", "{9545310B-A6E6-4B42-BB00-655D66B6E3D5}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32 Debug|Win32 = Debug|Win32
@@ -31,6 +33,10 @@ Global
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Debug|Win32.Build.0 = Debug|Win32 {B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Debug|Win32.Build.0 = Debug|Win32
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Release|Win32.ActiveCfg = Release|Win32 {B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Release|Win32.ActiveCfg = Release|Win32
{B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Release|Win32.Build.0 = Release|Win32 {B407561F-1F5E-4798-B9C2-81AB09CFBC16}.Release|Win32.Build.0 = Release|Win32
{9545310B-A6E6-4B42-BB00-655D66B6E3D5}.Debug|Win32.ActiveCfg = Debug|Win32
{9545310B-A6E6-4B42-BB00-655D66B6E3D5}.Debug|Win32.Build.0 = Debug|Win32
{9545310B-A6E6-4B42-BB00-655D66B6E3D5}.Release|Win32.ActiveCfg = Release|Win32
{9545310B-A6E6-4B42-BB00-655D66B6E3D5}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

157
libwebvtt.vcproj Normal file
View File

@@ -0,0 +1,157 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="libwebvtt_2008"
ProjectGUID="{9545310B-A6E6-4B42-BB00-655D66B6E3D5}"
RootNamespace="libwebvtt"
Keyword="Win32Proj"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)..\lib\$(SolutionName)\$(ProjectName)\$(ConfigurationName)"
IntermediateDirectory="$(SolutionDir)..\obj\$(SolutionName)\$(ProjectName)\$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
MinimalRebuild="false"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="4"
DebugInformationFormat="1"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="4"
CharacterSet="1"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
EnableIntrinsicFunctions="true"
PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="0"
WarningLevel="3"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLibrarianTool"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<File
RelativePath=".\webvttparser.cpp"
>
</File>
<File
RelativePath=".\webvttparser.hpp"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

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);

23
webvttparser.cpp Normal file
View File

@@ -0,0 +1,23 @@
#include "webvttparser.hpp"
namespace WebvttParser
{
IReader::IReader()
{
}
IReader::~IReader()
{
}
Parser::Parser(IReader* p) :
m_pReader(p)
{
}
Parser::~Parser()
{
}
} //end namespace WebvttParser

60
webvttparser.hpp Normal file
View File

@@ -0,0 +1,60 @@
#ifndef WEBVTTPARSER_HPP
#define WEBVTTPARSER_HPP
namespace WebvttParser
{
class IReader
{
protected:
IReader();
virtual ~IReader();
public:
virtual int Read(char& c) = 0;
};
class Parser
{
private:
Parser(const Parser&);
Parser& operator=(const Parser&);
public:
Parser(IReader*);
~Parser();
int Parse();
//need to know kind:
// caption, description, metadata, etc
// is this a webvtt stream?
//
//cue identifier
//timestamp (or defaults?) + cue settings
//payload
// preserve each line
//machine states:
// parsing stream id ("webvtt")
// parsing file-wide metadata
// parsing cue
//
//within cue:
// parsing line
// is this a cue identifier or timestamp line?
//
// parsing cue id
// parsing timestamp
// parsing lines, looking for end-of-cue
private:
IReader* const m_pReader;
};
} //end namespace WebvttParser
#endif