Commit 6f8e8326 authored by Denis Charmet's avatar Denis Charmet

Handle with resilience unknown ebml elements

Fix #7884 and #7887 by implementing the first proposition.
parent ca80c3e8
......@@ -30,6 +30,7 @@
* Ebml Stream parser
*****************************************************************************/
EbmlParser::EbmlParser( EbmlStream *es, EbmlElement *el_start, demux_t *p_demux ) :
p_demux( p_demux ),
m_es( es ),
mi_level( 1 ),
m_got( NULL ),
......@@ -103,7 +104,7 @@ void EbmlParser::Up( void )
{
if( mi_user_level == mi_level )
{
fprintf( stderr,"MKV/Ebml Parser: Up cannot escape itself\n" );
msg_Warn( p_demux, "MKV/Ebml Parser: Up cannot escape itself" );
}
mi_user_level--;
......@@ -133,15 +134,17 @@ void EbmlParser::Reset( demux_t *p_demux )
m_el[mi_level] = NULL;
mi_level--;
}
this->p_demux = p_demux;
mi_user_level = mi_level = 1;
// a little faster and cleaner
m_es->I_O().setFilePointer( static_cast<KaxSegment*>(m_el[0])->GetGlobalPosition(0) );
mb_dummy = var_InheritBool( p_demux, "mkv-use-dummy" );
}
EbmlElement *EbmlParser::Get( void )
EbmlElement *EbmlParser::Get( int n_call )
{
int i_ulev = 0;
EbmlElement *p_prev = NULL;
if( mi_user_level != mi_level )
{
......@@ -155,24 +158,29 @@ EbmlElement *EbmlParser::Get( void )
return ret;
}
p_prev = m_el[mi_level];
if( m_el[mi_level] )
{
m_el[mi_level]->SkipData( *m_es, EBML_CONTEXT(m_el[mi_level]) );
if( !mb_keep )
{
if( MKV_IS_ID( m_el[mi_level], KaxBlockVirtual ) )
static_cast<KaxBlockVirtualWorkaround*>(m_el[mi_level])->Fix();
delete m_el[mi_level];
}
mb_keep = false;
}
vlc_stream_io_callback & io_stream = (vlc_stream_io_callback &) m_es->I_O();
uint64 i_size = io_stream.toRead();
m_el[mi_level] = m_es->FindNextElement( EBML_CONTEXT(m_el[mi_level - 1]),
i_ulev, i_size, mb_dummy, 1 );
i_ulev, i_size, true, 1 );
// mi_remain_size[mi_level] = m_el[mi_level]->GetSize();
if( i_ulev > 0 )
{
if( p_prev )
{
if( !mb_keep )
{
if( MKV_IS_ID( p_prev, KaxBlockVirtual ) )
static_cast<KaxBlockVirtualWorkaround*>(p_prev)->Fix();
delete p_prev;
}
mb_keep = false;
}
while( i_ulev > 0 )
{
if( mi_level == 1 )
......@@ -192,9 +200,55 @@ EbmlElement *EbmlParser::Get( void )
}
else if( m_el[mi_level] == NULL )
{
fprintf( stderr,"MKV/Ebml Parser: m_el[mi_level] == NULL\n" );
msg_Warn( p_demux,"MKV/Ebml Parser: m_el[mi_level] == NULL\n" );
}
else if( m_el[mi_level]->IsDummy() && !mb_dummy )
{
bool b_bad_position = false;
/* We got a dummy element but don't want those...
* perform a sanity check */
if( !mi_level )
{
msg_Err(p_demux, "Got invalid lvl 0 element... Aborting");
return NULL;
}
if( p_prev && p_prev->IsFiniteSize() &&
p_prev->GetEndPosition() != m_el[mi_level]->GetElementPosition())
{
msg_Err( p_demux, "Dummy Element at unexpected position... corrupted file?" );
b_bad_position = true;
}
if( n_call < 10 && !b_bad_position && m_el[mi_level]->IsFiniteSize() &&
( !m_el[mi_level-1]->IsFiniteSize() ||
m_el[mi_level]->GetEndPosition() <= m_el[mi_level-1]->GetEndPosition() ) )
{
/* The element fits inside its upper element */
msg_Warn( p_demux, "Dummy element found... skipping it" );
return Get( ++n_call );
}
else
{
/* Too large, misplaced or 10 successive dummy elements */
msg_Err( p_demux, "Dummy element too large or misplaced... skipping to next upper element" );
delete m_el[mi_level];
m_el[mi_level] = NULL;
m_el[mi_level - 1]->SkipData( *m_es, EBML_CONTEXT(m_el[mi_level - 1]) );
return Get();
}
}
if( p_prev )
{
if( !mb_keep )
{
if( MKV_IS_ID( p_prev, KaxBlockVirtual ) )
static_cast<KaxBlockVirtualWorkaround*>(p_prev)->Fix();
delete p_prev;
}
mb_keep = false;
}
return m_el[mi_level];
}
......
......@@ -39,7 +39,7 @@ class EbmlParser
void Up( void );
void Down( void );
void Reset( demux_t *p_demux );
EbmlElement *Get( void );
EbmlElement *Get( int n_call = 0 );
void Keep( void );
EbmlElement *UnGet( uint64 i_block_pos, uint64 i_cluster_pos );
......@@ -49,16 +49,17 @@ class EbmlParser
bool IsTopPresent( EbmlElement * ) const;
private:
demux_t *p_demux;
EbmlStream *m_es;
int mi_level;
int mi_level;
EbmlElement *m_el[10];
int64_t mi_remain_size[10];
EbmlElement *m_got;
int mi_user_level;
bool mb_keep;
bool mb_dummy;
int mi_user_level;
bool mb_keep;
bool mb_dummy;
};
/* This class works around a bug in KaxBlockVirtual implementation */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment