[vlc-commits] Handle with resilience unknown ebml elements
Denis Charmet
git at videolan.org
Sat Dec 29 19:09:33 CET 2012
vlc/vlc-2.0 | branch: master | Denis Charmet <typx at dinauz.org> | Wed Dec 26 18:58:41 2012 +0100| [120934306d80655cae490bc444df159a80ac72ba] | committer: Jean-Baptiste Kempf
Handle with resilience unknown ebml elements
Fix #7884 and #7887 by implementing the first proposition.
(cherry picked from commit 6f8e8326ef82029d868d3c4729c9fd64e41a06f2)
Signed-off-by: Jean-Baptiste Kempf <jb at videolan.org>
> http://git.videolan.org/gitweb.cgi/vlc/vlc-2.0.git/?a=commit;h=120934306d80655cae490bc444df159a80ac72ba
---
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 6c3aa67..64c6705 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 cc72ed4..2eb50ab 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 */
More information about the vlc-commits
mailing list