vlc | branch: master | Denis Charmet <[email protected]> | Wed Dec 26 18:58:41 2012 +0100| [6f8e8326ef82029d868d3c4729c9fd64e41a06f2] | committer: Denis Charmet
Handle with resilience unknown ebml elements Fix #7884 and #7887 by implementing the first proposition. > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=6f8e8326ef82029d868d3c4729c9fd64e41a06f2 --- modules/demux/mkv/Ebml_parser.cpp | 76 +++++++++++++++++++++++++++++++------ modules/demux/mkv/Ebml_parser.hpp | 11 +++--- 2 files changed, 71 insertions(+), 16 deletions(-) diff --git a/modules/demux/mkv/Ebml_parser.cpp b/modules/demux/mkv/Ebml_parser.cpp index d7490b8..2283e92 100644 --- a/modules/demux/mkv/Ebml_parser.cpp +++ b/modules/demux/mkv/Ebml_parser.cpp @@ -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]; } diff --git a/modules/demux/mkv/Ebml_parser.hpp b/modules/demux/mkv/Ebml_parser.hpp index 86a856e..40abafd 100644 --- a/modules/demux/mkv/Ebml_parser.hpp +++ b/modules/demux/mkv/Ebml_parser.hpp @@ -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 */ _______________________________________________ vlc-commits mailing list [email protected] http://mailman.videolan.org/listinfo/vlc-commits
