]> git.sesse.net Git - vlc/blob - modules/demux/mkv/Ebml_parser.cpp
Matroska demux: use var_Inherit
[vlc] / modules / demux / mkv / Ebml_parser.cpp
1
2 /*****************************************************************************
3  * mkv.cpp : matroska demuxer
4  *****************************************************************************
5  * Copyright (C) 2003-2004 the VideoLAN team
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
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 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 General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25 #include "Ebml_parser.hpp"
26
27 /*****************************************************************************
28  * Ebml Stream parser
29  *****************************************************************************/
30 EbmlParser::EbmlParser( EbmlStream *es, EbmlElement *el_start, demux_t *p_demux )
31 {
32     int i;
33
34     m_es = es;
35     m_got = NULL;
36     m_el[0] = el_start;
37     mi_remain_size[0] = el_start->GetSize();
38
39     for( i = 1; i < 6; i++ )
40     {
41         m_el[i] = NULL;
42     }
43     mi_level = 1;
44     mi_user_level = 1;
45     mb_keep = false;
46     mb_dummy = var_InheritInteger( p_demux, "mkv-use-dummy" );
47 }
48
49 EbmlParser::~EbmlParser( void )
50 {
51     int i;
52
53     for( i = 1; i < mi_level; i++ )
54     {
55         if( !mb_keep )
56         {
57             delete m_el[i];
58         }
59         mb_keep = false;
60     }
61 }
62
63 EbmlElement* EbmlParser::UnGet( uint64 i_block_pos, uint64 i_cluster_pos )
64 {
65     if ( mi_user_level > mi_level )
66     {
67         while ( mi_user_level != mi_level )
68         {
69             delete m_el[mi_user_level];
70             m_el[mi_user_level] = NULL;
71             mi_user_level--;
72         }
73     }
74     m_got = NULL;
75     mb_keep = false;
76     if ( m_el[1]->GetElementPosition() == i_cluster_pos )
77     {
78         m_es->I_O().setFilePointer( i_block_pos, seek_beginning );
79         return (EbmlMaster*) m_el[1];
80     }
81     else
82     {
83         // seek to the previous Cluster
84         m_es->I_O().setFilePointer( i_cluster_pos, seek_beginning );
85         mi_level--;
86         mi_user_level--;
87         delete m_el[mi_level];
88         m_el[mi_level] = NULL;
89         return NULL;
90     }
91 }
92
93 void EbmlParser::Up( void )
94 {
95     if( mi_user_level == mi_level )
96     {
97         fprintf( stderr," arrrrrrrrrrrrrg Up cannot escape itself\n" );
98     }
99
100     mi_user_level--;
101 }
102
103 void EbmlParser::Down( void )
104 {
105     mi_user_level++;
106     mi_level++;
107 }
108
109 void EbmlParser::Keep( void )
110 {
111     mb_keep = true;
112 }
113
114 int EbmlParser::GetLevel( void )
115 {
116     return mi_user_level;
117 }
118
119 void EbmlParser::Reset( demux_t *p_demux )
120 {
121     while ( mi_level > 0)
122     {
123         delete m_el[mi_level];
124         m_el[mi_level] = NULL;
125         mi_level--;
126     }
127     mi_user_level = mi_level = 1;
128     // a little faster and cleaner
129     m_es->I_O().setFilePointer( static_cast<KaxSegment*>(m_el[0])->GetGlobalPosition(0) );
130     mb_dummy = var_InheritInteger( p_demux, "mkv-use-dummy" );
131 }
132
133
134 /* This function workarounds a bug in KaxBlockVirtual implementation */
135 class KaxBlockVirtualWorkaround : public KaxBlockVirtual
136 {
137 public:
138     void Fix()
139     {
140         if( Data == DataBlock )
141             SetBuffer( NULL, 0 );
142     }
143 };
144
145 EbmlElement *EbmlParser::Get( void )
146 {
147     int i_ulev = 0;
148
149     if( mi_user_level != mi_level )
150     {
151         return NULL;
152     }
153     if( m_got )
154     {
155         EbmlElement *ret = m_got;
156         m_got = NULL;
157
158         return ret;
159     }
160
161     if( m_el[mi_level] )
162     {
163         m_el[mi_level]->SkipData( *m_es, m_el[mi_level]->Generic().Context );
164         if( !mb_keep )
165         {
166             if( MKV_IS_ID( m_el[mi_level], KaxBlockVirtual ) )
167                 static_cast<KaxBlockVirtualWorkaround*>(m_el[mi_level])->Fix();
168             delete m_el[mi_level];
169         }
170         mb_keep = false;
171     }
172
173     m_el[mi_level] = m_es->FindNextElement( m_el[mi_level - 1]->Generic().Context, i_ulev, 0xFFFFFFFFL, mb_dummy != 0, 1 );
174 //    mi_remain_size[mi_level] = m_el[mi_level]->GetSize();
175     if( i_ulev > 0 )
176     {
177         while( i_ulev > 0 )
178         {
179             if( mi_level == 1 )
180             {
181                 mi_level = 0;
182                 return NULL;
183             }
184
185             delete m_el[mi_level - 1];
186             m_got = m_el[mi_level -1] = m_el[mi_level];
187             m_el[mi_level] = NULL;
188
189             mi_level--;
190             i_ulev--;
191         }
192         return NULL;
193     }
194     else if( m_el[mi_level] == NULL )
195     {
196         fprintf( stderr," m_el[mi_level] == NULL\n" );
197     }
198
199     return m_el[mi_level];
200 }
201
202 bool EbmlParser::IsTopPresent( EbmlElement *el )
203 {
204     for( int i = 0; i < mi_level; i++ )
205     {
206         if( m_el[i] && m_el[i] == el )
207             return true;
208     }
209     return false;
210 }
211
212