]> git.sesse.net Git - vlc/blob - modules/demux/mkv/Ebml_parser.cpp
dash: fix invalid C++11 suffix literals
[vlc] / modules / demux / mkv / Ebml_parser.cpp
1
2 /*****************************************************************************
3  * EbmlParser for the matroska demuxer
4  *****************************************************************************
5  * Copyright (C) 2003-2004 VLC authors and VideoLAN
6  * $Id$
7  *
8  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9  *          Steve Lhomme <steve.lhomme@free.fr>
10  *
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.
15  *
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.
20  *
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  *****************************************************************************/
25
26 #include "Ebml_parser.hpp"
27 #include "stream_io_callback.hpp"
28
29 /*****************************************************************************
30  * Ebml Stream parser
31  *****************************************************************************/
32 EbmlParser::EbmlParser( EbmlStream *es, EbmlElement *el_start, demux_t *p_demux ) :
33     p_demux( p_demux ),
34     m_es( es ),
35     mi_level( 1 ),
36     m_got( NULL ),
37     mi_user_level( 1 ),
38     mb_keep( false )
39 {
40     mi_remain_size[0] = el_start->GetSize();
41     memset( m_el, 0, 6 * sizeof( *m_el ) );
42     m_el[0] = el_start;
43     mb_dummy = var_InheritBool( p_demux, "mkv-use-dummy" );
44 }
45
46 EbmlParser::~EbmlParser( void )
47 {
48     if( !mi_level )
49     {
50         assert( !mb_keep );
51         delete m_el[1];
52         return;
53     }
54
55     for( int i = 1; i <= mi_level; i++ )
56     {
57         if( !mb_keep )
58         {
59             delete m_el[i];
60         }
61         mb_keep = false;
62     }
63 }
64
65 EbmlElement* EbmlParser::UnGet( uint64 i_block_pos, uint64 i_cluster_pos )
66 {
67     if ( mi_user_level > mi_level )
68     {
69         while ( mi_user_level != mi_level )
70         {
71             delete m_el[mi_user_level];
72             m_el[mi_user_level] = NULL;
73             mi_user_level--;
74         }
75     }
76
77     /* Avoid data skip in BlockGet */
78     delete m_el[mi_level];
79     m_el[mi_level] = NULL;
80
81     m_got = NULL;
82     mb_keep = false;
83     if ( m_el[1] && m_el[1]->GetElementPosition() == i_cluster_pos )
84     {
85         m_es->I_O().setFilePointer( i_block_pos, seek_beginning );
86         return m_el[1];
87     }
88     else
89     {
90         // seek to the previous Cluster
91         m_es->I_O().setFilePointer( i_cluster_pos, seek_beginning );
92         while(mi_level > 1)
93         {
94             mi_level--;
95             mi_user_level--;
96             delete m_el[mi_level];
97             m_el[mi_level] = NULL;
98         }
99         return NULL;
100     }
101 }
102
103 void EbmlParser::Up( void )
104 {
105     if( mi_user_level == mi_level )
106     {
107         msg_Warn( p_demux, "MKV/Ebml Parser: Up cannot escape itself" );
108     }
109
110     mi_user_level--;
111 }
112
113 void EbmlParser::Down( void )
114 {
115     mi_user_level++;
116     mi_level++;
117 }
118
119 void EbmlParser::Keep( void )
120 {
121     mb_keep = true;
122 }
123
124 void EbmlParser::Unkeep()
125 {
126     mb_keep = false;
127 }
128
129 int EbmlParser::GetLevel( void ) const
130 {
131     return mi_user_level;
132 }
133
134 void EbmlParser::Reset( demux_t *p_demux )
135 {
136     while ( mi_level > 0)
137     {
138         delete m_el[mi_level];
139         m_el[mi_level] = NULL;
140         mi_level--;
141     }
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" );
147 }
148
149 EbmlElement *EbmlParser::Get( int n_call )
150 {
151     int i_ulev = 0;
152     EbmlElement *p_prev = NULL;
153
154     if( mi_user_level != mi_level )
155     {
156         return NULL;
157     }
158     if( m_got )
159     {
160         EbmlElement *ret = m_got;
161         m_got = NULL;
162
163         return ret;
164     }
165
166     p_prev = m_el[mi_level];
167     if( m_el[mi_level] )
168     {
169         m_el[mi_level]->SkipData( *m_es, EBML_CONTEXT(m_el[mi_level]) );
170
171     }
172
173     /* Ignore unknown level 0 or 1 elements */
174     m_el[mi_level] = m_es->FindNextElement( EBML_CONTEXT(m_el[mi_level - 1]),
175                                             i_ulev, UINT64_MAX,
176                                             (  mb_dummy | (mi_level > 1) ), 1 );
177     if( i_ulev > 0 )
178     {
179         if( p_prev )
180         {
181             if( !mb_keep )
182             {
183                 if( MKV_IS_ID( p_prev, KaxBlockVirtual ) )
184                     static_cast<KaxBlockVirtualWorkaround*>(p_prev)->Fix();
185                 delete p_prev;
186             }
187             mb_keep = false;
188         }
189         while( i_ulev > 0 )
190         {
191             if( mi_level == 1 )
192             {
193                 mi_level = 0;
194                 return NULL;
195             }
196
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;
200
201             mi_level--;
202             i_ulev--;
203         }
204         return NULL;
205     }
206     else if( m_el[mi_level] == NULL )
207     {
208         msg_Warn( p_demux,"MKV/Ebml Parser: m_el[mi_level] == NULL\n" );
209     }
210     else if( m_el[mi_level]->IsDummy() && !mb_dummy )
211     {
212         bool b_bad_position = false;
213         /* We got a dummy element but don't want those...
214          * perform a sanity check */
215         if( !mi_level )
216         {
217             msg_Err(p_demux, "Got invalid lvl 0 element... Aborting");
218             return NULL;
219         }
220
221         if( p_prev && p_prev->IsFiniteSize() &&
222             p_prev->GetEndPosition() != m_el[mi_level]->GetElementPosition() &&
223             mi_level > 1 )
224         {
225             msg_Err( p_demux, "Dummy Element at unexpected position... corrupted file?" );
226             b_bad_position = true;
227         }
228
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() ) )
232         {
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 );
237         }
238         else
239         {
240             /* Too large, misplaced or 10 successive dummy elements */
241             msg_Err( p_demux,
242                      "Dummy element too large or misplaced at %" PRIu64 "... skipping to next upper element",
243                      m_el[mi_level]->GetElementPosition() );
244
245             if( mi_level >= 1 &&
246                 m_el[mi_level]->GetElementPosition() >= m_el[mi_level-1]->GetEndPosition() )
247             {
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;
252
253                 mi_level--;
254                 return NULL;
255             }
256
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]) );
260             return Get();
261         }
262     }
263
264     if( p_prev )
265     {
266         if( !mb_keep )
267         {
268             if( MKV_IS_ID( p_prev, KaxBlockVirtual ) )
269                 static_cast<KaxBlockVirtualWorkaround*>(p_prev)->Fix();
270             delete p_prev;
271         }
272         mb_keep = false;
273     }
274     return m_el[mi_level];
275 }
276
277 bool EbmlParser::IsTopPresent( EbmlElement *el ) const
278 {
279     for( int i = 0; i < mi_level; i++ )
280     {
281         if( m_el[i] && m_el[i] == el )
282             return true;
283     }
284     return false;
285 }
286