2 /*****************************************************************************
3 * EbmlParser for the matroska demuxer
4 *****************************************************************************
5 * Copyright (C) 2003-2004 VLC authors and VideoLAN
8 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9 * Steve Lhomme <steve.lhomme@free.fr>
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU Lesser General Public License as published by
13 * the Free Software Foundation; either version 2.1 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public License
22 * along with this program; if not, write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 *****************************************************************************/
26 #include "Ebml_parser.hpp"
27 #include "stream_io_callback.hpp"
29 /*****************************************************************************
31 *****************************************************************************/
32 EbmlParser::EbmlParser( EbmlStream *es, EbmlElement *el_start, demux_t *p_demux ) :
40 mi_remain_size[0] = el_start->GetSize();
41 memset( m_el, 0, 6 * sizeof( *m_el ) );
43 mb_dummy = var_InheritBool( p_demux, "mkv-use-dummy" );
46 EbmlParser::~EbmlParser( void )
55 for( int i = 1; i <= mi_level; i++ )
65 EbmlElement* EbmlParser::UnGet( uint64 i_block_pos, uint64 i_cluster_pos )
67 if ( mi_user_level > mi_level )
69 while ( mi_user_level != mi_level )
71 delete m_el[mi_user_level];
72 m_el[mi_user_level] = NULL;
77 /* Avoid data skip in BlockGet */
78 delete m_el[mi_level];
79 m_el[mi_level] = NULL;
83 if ( m_el[1] && m_el[1]->GetElementPosition() == i_cluster_pos )
85 m_es->I_O().setFilePointer( i_block_pos, seek_beginning );
90 // seek to the previous Cluster
91 m_es->I_O().setFilePointer( i_cluster_pos, seek_beginning );
96 delete m_el[mi_level];
97 m_el[mi_level] = NULL;
103 void EbmlParser::Up( void )
105 if( mi_user_level == mi_level )
107 msg_Warn( p_demux, "MKV/Ebml Parser: Up cannot escape itself" );
113 void EbmlParser::Down( void )
119 void EbmlParser::Keep( void )
124 void EbmlParser::Unkeep()
129 int EbmlParser::GetLevel( void ) const
131 return mi_user_level;
134 void EbmlParser::Reset( demux_t *p_demux )
136 while ( mi_level > 0)
138 delete m_el[mi_level];
139 m_el[mi_level] = NULL;
142 this->p_demux = p_demux;
143 mi_user_level = mi_level = 1;
144 // a little faster and cleaner
145 m_es->I_O().setFilePointer( static_cast<KaxSegment*>(m_el[0])->GetGlobalPosition(0) );
146 mb_dummy = var_InheritBool( p_demux, "mkv-use-dummy" );
149 EbmlElement *EbmlParser::Get( int n_call )
152 EbmlElement *p_prev = NULL;
154 if( mi_user_level != mi_level )
160 EbmlElement *ret = m_got;
166 p_prev = m_el[mi_level];
169 m_el[mi_level]->SkipData( *m_es, EBML_CONTEXT(m_el[mi_level]) );
173 /* Ignore unknown level 0 or 1 elements */
174 m_el[mi_level] = m_es->FindNextElement( EBML_CONTEXT(m_el[mi_level - 1]),
176 ( mb_dummy | (mi_level > 1) ), 1 );
183 if( MKV_IS_ID( p_prev, KaxBlockVirtual ) )
184 static_cast<KaxBlockVirtualWorkaround*>(p_prev)->Fix();
197 delete m_el[mi_level - 1];
198 m_got = m_el[mi_level -1] = m_el[mi_level];
199 m_el[mi_level] = NULL;
206 else if( m_el[mi_level] == NULL )
208 msg_Warn( p_demux,"MKV/Ebml Parser: m_el[mi_level] == NULL\n" );
210 else if( m_el[mi_level]->IsDummy() && !mb_dummy )
212 bool b_bad_position = false;
213 /* We got a dummy element but don't want those...
214 * perform a sanity check */
217 msg_Err(p_demux, "Got invalid lvl 0 element... Aborting");
221 if( p_prev && p_prev->IsFiniteSize() &&
222 p_prev->GetEndPosition() != m_el[mi_level]->GetElementPosition() &&
225 msg_Err( p_demux, "Dummy Element at unexpected position... corrupted file?" );
226 b_bad_position = true;
229 if( n_call < 10 && !b_bad_position && m_el[mi_level]->IsFiniteSize() &&
230 ( !m_el[mi_level-1]->IsFiniteSize() ||
231 m_el[mi_level]->GetEndPosition() <= m_el[mi_level-1]->GetEndPosition() ) )
233 /* The element fits inside its upper element */
234 msg_Warn( p_demux, "Dummy element found %" PRIu64 "... skipping it",
235 m_el[mi_level]->GetElementPosition() );
236 return Get( ++n_call );
240 /* Too large, misplaced or 10 successive dummy elements */
242 "Dummy element too large or misplaced at %" PRIu64 "... skipping to next upper element",
243 m_el[mi_level]->GetElementPosition() );
246 m_el[mi_level]->GetElementPosition() >= m_el[mi_level-1]->GetEndPosition() )
248 msg_Err(p_demux, "This element is outside its known parent... upping level");
249 delete m_el[mi_level - 1];
250 m_got = m_el[mi_level -1] = m_el[mi_level];
251 m_el[mi_level] = NULL;
257 delete m_el[mi_level];
258 m_el[mi_level] = NULL;
259 m_el[mi_level - 1]->SkipData( *m_es, EBML_CONTEXT(m_el[mi_level - 1]) );
268 if( MKV_IS_ID( p_prev, KaxBlockVirtual ) )
269 static_cast<KaxBlockVirtualWorkaround*>(p_prev)->Fix();
274 return m_el[mi_level];
277 bool EbmlParser::IsTopPresent( EbmlElement *el ) const
279 for( int i = 0; i < mi_level; i++ )
281 if( m_el[i] && m_el[i] == el )