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 @@ ...@@ -30,6 +30,7 @@
* Ebml Stream parser * Ebml Stream parser
*****************************************************************************/ *****************************************************************************/
EbmlParser::EbmlParser( EbmlStream *es, EbmlElement *el_start, demux_t *p_demux ) : EbmlParser::EbmlParser( EbmlStream *es, EbmlElement *el_start, demux_t *p_demux ) :
p_demux( p_demux ),
m_es( es ), m_es( es ),
mi_level( 1 ), mi_level( 1 ),
m_got( NULL ), m_got( NULL ),
...@@ -103,7 +104,7 @@ void EbmlParser::Up( void ) ...@@ -103,7 +104,7 @@ void EbmlParser::Up( void )
{ {
if( mi_user_level == mi_level ) 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--; mi_user_level--;
...@@ -133,15 +134,17 @@ void EbmlParser::Reset( demux_t *p_demux ) ...@@ -133,15 +134,17 @@ void EbmlParser::Reset( demux_t *p_demux )
m_el[mi_level] = NULL; m_el[mi_level] = NULL;
mi_level--; mi_level--;
} }
this->p_demux = p_demux;
mi_user_level = mi_level = 1; mi_user_level = mi_level = 1;
// a little faster and cleaner // a little faster and cleaner
m_es->I_O().setFilePointer( static_cast<KaxSegment*>(m_el[0])->GetGlobalPosition(0) ); m_es->I_O().setFilePointer( static_cast<KaxSegment*>(m_el[0])->GetGlobalPosition(0) );
mb_dummy = var_InheritBool( p_demux, "mkv-use-dummy" ); mb_dummy = var_InheritBool( p_demux, "mkv-use-dummy" );
} }
EbmlElement *EbmlParser::Get( void ) EbmlElement *EbmlParser::Get( int n_call )
{ {
int i_ulev = 0; int i_ulev = 0;
EbmlElement *p_prev = NULL;
if( mi_user_level != mi_level ) if( mi_user_level != mi_level )
{ {
...@@ -155,24 +158,29 @@ EbmlElement *EbmlParser::Get( void ) ...@@ -155,24 +158,29 @@ EbmlElement *EbmlParser::Get( void )
return ret; return ret;
} }
p_prev = m_el[mi_level];
if( m_el[mi_level] ) if( m_el[mi_level] )
{ {
m_el[mi_level]->SkipData( *m_es, EBML_CONTEXT(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(); vlc_stream_io_callback & io_stream = (vlc_stream_io_callback &) m_es->I_O();
uint64 i_size = io_stream.toRead(); uint64 i_size = io_stream.toRead();
m_el[mi_level] = m_es->FindNextElement( EBML_CONTEXT(m_el[mi_level - 1]), 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(); // mi_remain_size[mi_level] = m_el[mi_level]->GetSize();
if( i_ulev > 0 ) 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 ) while( i_ulev > 0 )
{ {
if( mi_level == 1 ) if( mi_level == 1 )
...@@ -192,9 +200,55 @@ EbmlElement *EbmlParser::Get( void ) ...@@ -192,9 +200,55 @@ EbmlElement *EbmlParser::Get( void )
} }
else if( m_el[mi_level] == NULL ) 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]; return m_el[mi_level];
} }
......
...@@ -39,7 +39,7 @@ class EbmlParser ...@@ -39,7 +39,7 @@ class EbmlParser
void Up( void ); void Up( void );
void Down( void ); void Down( void );
void Reset( demux_t *p_demux ); void Reset( demux_t *p_demux );
EbmlElement *Get( void ); EbmlElement *Get( int n_call = 0 );
void Keep( void ); void Keep( void );
EbmlElement *UnGet( uint64 i_block_pos, uint64 i_cluster_pos ); EbmlElement *UnGet( uint64 i_block_pos, uint64 i_cluster_pos );
...@@ -49,16 +49,17 @@ class EbmlParser ...@@ -49,16 +49,17 @@ class EbmlParser
bool IsTopPresent( EbmlElement * ) const; bool IsTopPresent( EbmlElement * ) const;
private: private:
demux_t *p_demux;
EbmlStream *m_es; EbmlStream *m_es;
int mi_level; int mi_level;
EbmlElement *m_el[10]; EbmlElement *m_el[10];
int64_t mi_remain_size[10]; int64_t mi_remain_size[10];
EbmlElement *m_got; EbmlElement *m_got;
int mi_user_level; int mi_user_level;
bool mb_keep; bool mb_keep;
bool mb_dummy; bool mb_dummy;
}; };
/* This class works around a bug in KaxBlockVirtual implementation */ /* 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