1 /*
2  * $Id$
3  * Copyright (c) 2008-2010, Matroska (non-profit organisation)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *     * Redistributions of source code must retain the above copyright
9  *       notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above copyright
11  *       notice, this list of conditions and the following disclaimer in the
12  *       documentation and/or other materials provided with the distribution.
13  *     * Neither the name of the Matroska assocation nor the
14  *       names of its contributors may be used to endorse or promote products
15  *       derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY the Matroska association ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL The Matroska Foundation BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "MatroskaParser.h"
30 
31 #define MAX_TRACKS 32 // safety
32 
33 #if defined(TARGET_WIN)
34 #define snprintf _snprintf
35 #endif
36 
37 #define HAALI_STREAM_CLASS FOURCC('H','A','L','S')
38 typedef struct haali_stream
39 {
40 	stream Base;
41 	InputStream *io;
42 
43 } haali_stream;
44 
45 struct MatroskaFile
46 {
47 	haali_stream *Input;
48 	ebml_element *Segment;
49 	ebml_element *SegmentInfo;
50 	ebml_element *TrackList;
51 	ebml_element *CueList;
52 	SegmentInfo Seg;
53 
54 	ebml_parser_context L0Context;
55 	ebml_parser_context L1Context;
56 
57 	ebml_element *CurrentCluster;
58 	matroska_block *CurrentBlock;
59 	size_t CurrentFrame;
60 	ebml_parser_context ClusterContext;
61 
62 	filepos_t pSegmentInfo;
63 	filepos_t pTracks;
64 	filepos_t pCues;
65 	filepos_t pAttachments;
66 	filepos_t pChapters;
67 	filepos_t pTags;
68 	filepos_t pFirstCluster;
69 
70 	int trackMask;
71 	int flags;
72 
73 	array Tracks;
74 	array Tags;
75 	array Chapters;
76 	array Attachments;
77 };
78 
mkv_SetTrackMask(MatroskaFile * File,int Mask)79 void mkv_SetTrackMask(MatroskaFile *File, int Mask)
80 {
81 	File->trackMask = Mask;
82 	// TODO: the original code is handling a queue
83 }
84 
mkv_GetTags(MatroskaFile * File,Tag ** pTags,unsigned * Count)85 void mkv_GetTags(MatroskaFile *File, Tag **pTags, unsigned *Count)
86 {
87 	*pTags = ARRAYBEGIN(File->Tags,Tag);
88 	*Count = ARRAYCOUNT(File->Tags,Tag);
89 }
90 
mkv_GetAttachments(MatroskaFile * File,Attachment ** pAttachements,unsigned * Count)91 void mkv_GetAttachments(MatroskaFile *File, Attachment **pAttachements, unsigned *Count)
92 {
93 	*pAttachements = ARRAYBEGIN(File->Attachments,Attachment);
94 	*Count = ARRAYCOUNT(File->Attachments,Attachment);
95 }
96 
mkv_GetChapters(MatroskaFile * File,Chapter ** pChapters,unsigned * Count)97 void mkv_GetChapters(MatroskaFile *File, Chapter **pChapters, unsigned *Count)
98 {
99 	*pChapters = ARRAYBEGIN(File->Chapters,Chapter);
100 	*Count = ARRAYCOUNT(File->Chapters,Chapter);
101 }
102 
mkv_GetTrackInfo(MatroskaFile * File,size_t n)103 TrackInfo *mkv_GetTrackInfo(MatroskaFile *File, size_t n)
104 {
105 	if (n>=ARRAYCOUNT(File->Tracks,TrackInfo))
106 		return NULL;
107 	return ARRAYBEGIN(File->Tracks,TrackInfo) + n;
108 }
109 
mkv_GetFileInfo(MatroskaFile * File)110 SegmentInfo *mkv_GetFileInfo(MatroskaFile *File)
111 {
112 	return &File->Seg;
113 }
114 
mkv_GetNumTracks(MatroskaFile * File)115 size_t mkv_GetNumTracks(MatroskaFile *File)
116 {
117 	return ARRAYCOUNT(File->Tracks,TrackInfo);
118 }
119 
CheckMatroskaHead(ebml_element * Head,char * err_msg,size_t err_msgSize)120 static bool_t CheckMatroskaHead(ebml_element *Head, char *err_msg, size_t err_msgSize)
121 {
122 	tchar_t DocType[MAXPATH];
123 	ebml_element *Elt;
124 	Elt = EBML_MasterFindFirstElt(Head,&EBML_ContextReadVersion,1,1);
125 	if (!Elt)
126 	{
127 		strncpy(err_msg,"Out of memory",err_msgSize);
128 		return 0;
129 	}
130 	if (EBML_IntegerValue(Elt) > EBML_MAX_VERSION)
131 	{
132 		snprintf(err_msg,err_msgSize,"File requires version %d EBML parser",(int)EBML_IntegerValue(Elt));
133 		return 0;
134 	}
135 
136 	Elt = EBML_MasterFindFirstElt(Head,&EBML_ContextDocTypeReadVersion,1,1);
137 	if (!Elt)
138 	{
139 		strncpy(err_msg,"Out of memory",err_msgSize);
140 		return 0;
141 	}
142 	if (EBML_IntegerValue(Elt) > MATROSKA_VERSION)
143 	{
144 		snprintf(err_msg,err_msgSize,"File requires version %d Matroska parser",(int)EBML_IntegerValue(Elt));
145 		return 0;
146 	}
147 
148 	Elt = EBML_MasterFindFirstElt(Head,&EBML_ContextMaxIdLength,1,1);
149 	if (!Elt)
150 	{
151 		strncpy(err_msg,"Out of memory",err_msgSize);
152 		return 0;
153 	}
154 	if (EBML_IntegerValue(Elt) > EBML_MAX_ID)
155 	{
156 		snprintf(err_msg,err_msgSize,"File has identifiers longer than %d",(int)EBML_IntegerValue(Elt));
157 		return 0;
158 	}
159 
160 	Elt = EBML_MasterFindFirstElt(Head,&EBML_ContextMaxSizeLength,1,1);
161 	if (!Elt)
162 	{
163 		strncpy(err_msg,"Out of memory",err_msgSize);
164 		return 0;
165 	}
166 	if (EBML_IntegerValue(Elt) > EBML_MAX_SIZE)
167 	{
168 		snprintf(err_msg,err_msgSize,"File has integers longer than %d",(int)EBML_IntegerValue(Elt));
169 		return 0;
170 	}
171 
172 	Elt = EBML_MasterFindFirstElt(Head,&EBML_ContextDocType,1,1);
173 	if (!Elt)
174 	{
175 		strncpy(err_msg,"Out of memory",err_msgSize);
176 		return 0;
177 	}
178 	EBML_StringGet((ebml_string*)Elt,DocType,TSIZEOF(DocType));
179 	if (!tcsisame_ascii(DocType,T("matroska")) && !tcsisame_ascii(DocType,T("webm")))
180 	{
181 		snprintf(err_msg,err_msgSize,"Unsupported DocType: %s",((ebml_string*)Elt)->Buffer);
182 		return 0;
183 	}
184 	return 1;
185 }
186 
parseSeekHead(ebml_element * SeekHead,MatroskaFile * File,char * err_msg,size_t err_msgSize)187 static bool_t parseSeekHead(ebml_element *SeekHead, MatroskaFile *File, char *err_msg, size_t err_msgSize)
188 {
189 	ebml_parser_context RContext;
190 	ebml_element *Elt,*EltId;
191 	fourcc_t EltID;
192 	filepos_t SegStart = EBML_ElementPositionData(File->Segment);
193 	assert(SegStart!=INVALID_FILEPOS_T);
194 
195 	RContext.Context = SeekHead->Context;
196 	if (EBML_ElementIsFiniteSize(SeekHead))
197 		RContext.EndPosition = EBML_ElementPositionEnd(SeekHead);
198 	else
199 		RContext.EndPosition = INVALID_FILEPOS_T;
200 	RContext.UpContext = &File->L1Context;
201 	if (EBML_ElementReadData(SeekHead,(stream*)File->Input,&RContext,1,SCOPE_ALL_DATA)!=ERR_NONE)
202 	{
203 		strncpy(err_msg,"Failed to read the EBML head",err_msgSize);
204 		return 0;
205 	}
206 
207 	Elt = EBML_MasterFindFirstElt(SeekHead,&MATROSKA_ContextSeek,0,0);
208 	while (Elt)
209 	{
210 		EltId = EBML_MasterFindFirstElt(Elt,&MATROSKA_ContextSeekId,0,0);
211 		if (EltId && EltId->DataSize > EBML_MAX_ID)
212 		{
213 			snprintf(err_msg,err_msgSize,"Invalid ID size in parseSeekEntry: %d",(int)EltId->DataSize);
214 			return 0;
215 		}
216 		EltID = MATROSKA_MetaSeekID((matroska_seekpoint *)Elt);
217 		if (EltID == MATROSKA_ContextSegmentInfo.Id)
218 			File->pSegmentInfo = MATROSKA_MetaSeekPosInSegment((matroska_seekpoint *)Elt) + SegStart;
219 		else if (EltID == MATROSKA_ContextTracks.Id)
220 			File->pTracks = MATROSKA_MetaSeekPosInSegment((matroska_seekpoint *)Elt) + SegStart;
221 		else if (EltID == MATROSKA_ContextCues.Id)
222 			File->pCues = MATROSKA_MetaSeekPosInSegment((matroska_seekpoint *)Elt) + SegStart;
223 		else if (EltID == MATROSKA_ContextAttachments.Id)
224 			File->pAttachments = MATROSKA_MetaSeekPosInSegment((matroska_seekpoint *)Elt) + SegStart;
225 		else if (EltID == MATROSKA_ContextChapters.Id)
226 			File->pChapters = MATROSKA_MetaSeekPosInSegment((matroska_seekpoint *)Elt) + SegStart;
227 		else if (EltID == MATROSKA_ContextTags.Id)
228 			File->pTags = MATROSKA_MetaSeekPosInSegment((matroska_seekpoint *)Elt) + SegStart;
229 		Elt = EBML_MasterFindNextElt(SeekHead,Elt,0,0);
230 	}
231 
232 	return 1;
233 }
234 
parseSegmentInfo(ebml_element * SegmentInfo,MatroskaFile * File,char * err_msg,size_t err_msgSize)235 static bool_t parseSegmentInfo(ebml_element *SegmentInfo, MatroskaFile *File, char *err_msg, size_t err_msgSize)
236 {
237 	ebml_parser_context RContext;
238 	ebml_element *Elt;
239 	double duration = -1.0;
240 
241 	RContext.Context = SegmentInfo->Context;
242 	if (EBML_ElementIsFiniteSize(SegmentInfo))
243 		RContext.EndPosition = EBML_ElementPositionEnd(SegmentInfo);
244 	else
245 		RContext.EndPosition = INVALID_FILEPOS_T;
246     RContext.UpContext = &File->L1Context;
247 	if (EBML_ElementReadData(SegmentInfo,(stream*)File->Input,&RContext,1,SCOPE_ALL_DATA)!=ERR_NONE)
248 	{
249 		strncpy(err_msg,"Failed to read the Segment Info",err_msgSize);
250 		File->pSegmentInfo = INVALID_FILEPOS_T;
251 		return 0;
252 	}
253 	File->pSegmentInfo = SegmentInfo->ElementPosition;
254 	File->SegmentInfo = SegmentInfo;
255 	File->Seg.TimecodeScale = MATROSKA_ContextTimecodeScale.DefaultValue;
256 
257 	for (Elt = EBML_MasterChildren(SegmentInfo);Elt;Elt = EBML_MasterNext(Elt))
258 	{
259 		if (Elt->Context->Id == MATROSKA_ContextTimecodeScale.Id)
260 		{
261 			File->Seg.TimecodeScale = EBML_IntegerValue(Elt);
262 			if (File->Seg.TimecodeScale==0)
263 			{
264 				strncpy(err_msg,"Segment timecode scale is zero",err_msgSize);
265 				return 0;
266 			}
267 		}
268 		else if (Elt->Context->Id == MATROSKA_ContextDuration.Id)
269 		{
270 			duration = ((ebml_float*)Elt)->Value;
271 		}
272 		else if (Elt->Context->Id == MATROSKA_ContextSegmentDate.Id)
273 		{
274 			File->Seg.DateUTC = EBML_DateTime((ebml_date*)Elt);
275 		}
276 		else if (Elt->Context->Id == MATROSKA_ContextSegmentTitle.Id)
277 		{
278 			File->Seg.Title = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
279 			strcpy(File->Seg.Title,((ebml_string*)Elt)->Buffer);
280 		}
281 		else if (Elt->Context->Id == MATROSKA_ContextMuxingApp.Id)
282 		{
283 			File->Seg.MuxingApp = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
284 			strcpy(File->Seg.MuxingApp,((ebml_string*)Elt)->Buffer);
285 		}
286 		else if (Elt->Context->Id == MATROSKA_ContextWritingApp.Id)
287 		{
288 			File->Seg.WritingApp = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
289 			strcpy(File->Seg.WritingApp,((ebml_string*)Elt)->Buffer);
290 		}
291 		else if (Elt->Context->Id == MATROSKA_ContextSegmentUid.Id)
292 		{
293 			if (Elt->DataSize!=16)
294 			{
295 				snprintf(err_msg,err_msgSize,"SegmentUID size is not %d bytes",(int)Elt->DataSize);
296 				return 0;
297 			}
298 			memcpy(File->Seg.UID,EBML_BinaryGetData((ebml_binary*)Elt),sizeof(File->Seg.UID));
299 		}
300 		else if (Elt->Context->Id == MATROSKA_ContextPrevUid.Id)
301 		{
302 			if (Elt->DataSize!=16)
303 			{
304 				snprintf(err_msg,err_msgSize,"PrevUID size is not %d bytes",(int)Elt->DataSize);
305 				return 0;
306 			}
307 			memcpy(File->Seg.PrevUID,EBML_BinaryGetData((ebml_binary*)Elt),sizeof(File->Seg.PrevUID));
308 		}
309 		else if (Elt->Context->Id == MATROSKA_ContextNextUid.Id)
310 		{
311 			if (Elt->DataSize!=16)
312 			{
313 				snprintf(err_msg,err_msgSize,"NextUID size is not %d bytes",(int)Elt->DataSize);
314 				return 0;
315 			}
316 			memcpy(File->Seg.NextUID,EBML_BinaryGetData((ebml_binary*)Elt),sizeof(File->Seg.NextUID));
317 		}
318 		else if (Elt->Context->Id == MATROSKA_ContextSegmentFilename.Id)
319 		{
320 			File->Seg.Filename = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
321 			strcpy(File->Seg.Filename,((ebml_string*)Elt)->Buffer);
322 		}
323 		else if (Elt->Context->Id == MATROSKA_ContextPrevFilename.Id)
324 		{
325 			File->Seg.PrevFilename = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
326 			strcpy(File->Seg.Filename,((ebml_string*)Elt)->Buffer);
327 		}
328 		else if (Elt->Context->Id == MATROSKA_ContextNextFilename.Id)
329 		{
330 			File->Seg.NextFilename = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
331 			strcpy(File->Seg.Filename,((ebml_string*)Elt)->Buffer);
332 		}
333 	}
334 	if (duration > 0.0)
335 		File->Seg.Duration = (timecode_t)(duration * File->Seg.TimecodeScale);
336 
337 	return 1;
338 }
339 
releaseTrackEntry(TrackInfo * track,InputStream * io)340 static void releaseTrackEntry(TrackInfo *track, InputStream *io)
341 {
342 	if (track->CodecPrivate) io->memfree(io, track->CodecPrivate);
343 	if (track->Name) io->memfree(io, track->Name);
344 }
345 
parseTrackEntry(ebml_element * Track,MatroskaFile * File,char * err_msg,size_t err_msgSize)346 static bool_t parseTrackEntry(ebml_element *Track, MatroskaFile *File, char *err_msg, size_t err_msgSize)
347 {
348 	TrackInfo track,*Tracks;
349 	ebml_element *Elt,*TElt;
350 
351 	if (ARRAYCOUNT(File->Tracks,TrackInfo) >= MAX_TRACKS)
352 		return 0;
353 
354 	memset(&track,0,sizeof(track));
355 	track.DefaultDuration = INVALID_TIMECODE_T;
356 	track.Enabled = MATROSKA_ContextTrackEnabled.DefaultValue;
357 	track.Default = MATROSKA_ContextTrackDefault.DefaultValue;
358 	track.Lacing = MATROSKA_ContextTrackLacing.DefaultValue;
359 	track.DecodeAll = MATROSKA_ContextTrackCodecDecodeAll.DefaultValue;
360 	track.TimecodeScale = (float)MATROSKA_ContextTrackTimecodeScale.DefaultValue;
361 	memcpy(track.Language, "eng", 4);
362 
363 	for (Elt = EBML_MasterChildren(Track);Elt;Elt = EBML_MasterNext(Elt))
364 	{
365 		if (Elt->Context->Id == MATROSKA_ContextTrackNumber.Id)
366 			track.Number = (int)EBML_IntegerValue(Elt);
367 		else if (Elt->Context->Id == MATROSKA_ContextTrackNumber.Id)
368 			track.UID = EBML_IntegerValue(Elt);
369 		else if (Elt->Context->Id == MATROSKA_ContextTrackType.Id)
370 		{
371 			if (EBML_IntegerValue(Elt)==0 || EBML_IntegerValue(Elt)>254)
372 			{
373 				snprintf(err_msg,err_msgSize,"Invalid track type: %d",(int)EBML_IntegerValue(Elt));
374 				goto fail;
375 			}
376 			track.Type = (uint8_t)EBML_IntegerValue(Elt);
377 		}
378 		else if (Elt->Context->Id == MATROSKA_ContextTrackEnabled.Id)
379 			track.Enabled = EBML_IntegerValue(Elt)!=0;
380 		else if (Elt->Context->Id == MATROSKA_ContextTrackDefault.Id)
381 			track.Default = EBML_IntegerValue(Elt)!=0;
382 		else if (Elt->Context->Id == MATROSKA_ContextTrackLacing.Id)
383 			track.Lacing = EBML_IntegerValue(Elt)!=0;
384 		else if (Elt->Context->Id == MATROSKA_ContextTrackCodecDecodeAll.Id)
385 			track.DecodeAll = EBML_IntegerValue(Elt)!=0;
386 		else if (Elt->Context->Id == MATROSKA_ContextTrackMinCache.Id)
387 		{
388 			if (EBML_IntegerValue(Elt) > 0xFF)
389 			{
390 				snprintf(err_msg,err_msgSize,"MinCache is too large: %d",(int)EBML_IntegerValue(Elt));
391 				goto fail;
392 			}
393 			track.MinCache = (uint8_t)EBML_IntegerValue(Elt);
394 		}
395 		else if (Elt->Context->Id == MATROSKA_ContextTrackMaxCache.Id)
396 		{
397 			if (EBML_IntegerValue(Elt) > 0x7FFFFFFF)
398 			{
399 				snprintf(err_msg,err_msgSize,"MaxCache is too large: %d",(int)EBML_IntegerValue(Elt));
400 				goto fail;
401 			}
402 			track.MaxCache = (size_t)EBML_IntegerValue(Elt);
403 		}
404 		else if (Elt->Context->Id == MATROSKA_ContextTrackDefaultDuration.Id)
405 			track.DefaultDuration = EBML_IntegerValue(Elt);
406 		else if (Elt->Context->Id == MATROSKA_ContextTrackTimecodeScale.Id)
407 			track.TimecodeScale = (float)((ebml_float*)Elt)->Value;
408 		else if (Elt->Context->Id == MATROSKA_ContextTrackMaxBlockAdditionID.Id)
409 			track.MaxBlockAdditionID = (size_t)EBML_IntegerValue(Elt);
410 		else if (Elt->Context->Id == MATROSKA_ContextTrackLanguage.Id)
411 		{
412 			size_t copy = (Elt->DataSize>3) ? 3 : (size_t)Elt->DataSize;
413 			memcpy(track.Language,((ebml_string*)Elt)->Buffer,copy);
414 			memset(track.Language + copy,0,4-copy);
415 		}
416 		else if (Elt->Context->Id == MATROSKA_ContextTrackCodecID.Id)
417 		{
418 			track.CodecID = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
419 			strcpy(track.CodecID,((ebml_string*)Elt)->Buffer);
420 		}
421 		else if (Elt->Context->Id == MATROSKA_ContextTrackCodecPrivate.Id)
422 		{
423 			if (Elt->DataSize > 256*1024)
424 			{
425 				snprintf(err_msg,err_msgSize,"CodecPrivate is too large: %d",(int)EBML_IntegerValue(Elt));
426 				goto fail;
427 			}
428 			track.CodecPrivateSize = (size_t)(Elt->DataSize);
429 			track.CodecPrivate = File->Input->io->memalloc(File->Input->io, track.CodecPrivateSize);
430 			memcpy(track.CodecPrivate,EBML_BinaryGetData((ebml_binary*)Elt),track.CodecPrivateSize);
431 		}
432 		else if (Elt->Context->Id == MATROSKA_ContextTrackOverlay.Id)
433 		{
434 			if (EBML_IntegerValue(Elt)==0 || EBML_IntegerValue(Elt)>254)
435 			{
436 				snprintf(err_msg,err_msgSize,"Track number in TrackOverlay is too large: %d",(int)EBML_IntegerValue(Elt));
437 				goto fail;
438 			}
439 			track.TrackOverlay = (uint8_t)EBML_IntegerValue(Elt);
440 		}
441 		else if (Elt->Context->Id == MATROSKA_ContextTrackVideo.Id)
442 		{
443 			for (TElt = EBML_MasterChildren(Elt);TElt;TElt = EBML_MasterNext(TElt))
444 			{
445 				if (TElt->Context->Id == MATROSKA_ContextTrackVideoInterlaced.Id)
446 					track.AV.Video.Interlaced = EBML_IntegerValue(TElt)!=0;
447 				else if (TElt->Context->Id == MATROSKA_ContextTrackVideoStereo.Id)
448 				{
449 					if (TElt->DataSize > 3)
450 					{
451 						snprintf(err_msg,err_msgSize,"Invalid stereo mode: %d",(int)EBML_IntegerValue(TElt));
452 						goto fail;
453 					}
454 					track.AV.Video.StereoMode = (uint8_t)EBML_IntegerValue(TElt);
455 				}
456 				else if (TElt->Context->Id == MATROSKA_ContextTrackVideoPixelWidth.Id)
457 				{
458 					if (EBML_IntegerValue(TElt) > 0xFFFFFFFF)
459 					{
460 						snprintf(err_msg,err_msgSize,"PixelWidth is too large: %d",(int)EBML_IntegerValue(TElt));
461 						goto fail;
462 					}
463 					track.AV.Video.PixelWidth = (uint32_t)EBML_IntegerValue(TElt);
464 					if (!track.AV.Video.DisplayWidth)
465 						track.AV.Video.DisplayWidth = track.AV.Video.PixelWidth;
466 				}
467 				else if (TElt->Context->Id == MATROSKA_ContextTrackVideoPixelHeight.Id)
468 				{
469 					if (EBML_IntegerValue(TElt) > 0xFFFFFFFF)
470 					{
471 						snprintf(err_msg,err_msgSize,"PixelHeight is too large: %d",(int)EBML_IntegerValue(TElt));
472 						goto fail;
473 					}
474 					track.AV.Video.PixelHeight = (uint32_t)EBML_IntegerValue(TElt);
475 					if (!track.AV.Video.DisplayHeight)
476 						track.AV.Video.DisplayHeight = track.AV.Video.PixelHeight;
477 				}
478 				else if (TElt->Context->Id == MATROSKA_ContextTrackVideoDisplayWidth.Id)
479 				{
480 					if (EBML_IntegerValue(TElt) > 0xFFFFFFFF)
481 					{
482 						snprintf(err_msg,err_msgSize,"DisplayWidth is too large: %d",(int)EBML_IntegerValue(TElt));
483 						goto fail;
484 					}
485 					track.AV.Video.DisplayWidth = (uint32_t)EBML_IntegerValue(TElt);
486 				}
487 				else if (TElt->Context->Id == MATROSKA_ContextTrackVideoDisplayHeight.Id)
488 				{
489 					if (EBML_IntegerValue(TElt) > 0xFFFFFFFF)
490 					{
491 						snprintf(err_msg,err_msgSize,"DisplayHeight is too large: %d",(int)EBML_IntegerValue(TElt));
492 						goto fail;
493 					}
494 					track.AV.Video.DisplayHeight = (uint32_t)EBML_IntegerValue(TElt);
495 				}
496 				else if (TElt->Context->Id == MATROSKA_ContextTrackVideoDisplayUnit.Id)
497 				{
498 					if (EBML_IntegerValue(TElt) > 2)
499 					{
500 						snprintf(err_msg,err_msgSize,"DisplayUnit is too large: %d",(int)EBML_IntegerValue(TElt));
501 						goto fail;
502 					}
503 					track.AV.Video.DisplayUnit = (uint8_t)EBML_IntegerValue(TElt);
504 				}
505 				else if (TElt->Context->Id == MATROSKA_ContextTrackVideoDisplayUnit.Id)
506 				{
507 					if (EBML_IntegerValue(TElt) > 2)
508 					{
509 						snprintf(err_msg,err_msgSize,"AspectRatioType is too large: %d",(int)EBML_IntegerValue(TElt));
510 						goto fail;
511 					}
512 					track.AV.Video.AspectRatioType = (uint8_t)EBML_IntegerValue(TElt);
513 				}
514 				else if (TElt->Context->Id == MATROSKA_ContextTrackVideoPixelCropBottom.Id)
515 				{
516 					if (EBML_IntegerValue(TElt) > 0xFFFFFFFF)
517 					{
518 						snprintf(err_msg,err_msgSize,"PixelCropBottom is too large: %d",(int)EBML_IntegerValue(TElt));
519 						goto fail;
520 					}
521 					track.AV.Video.CropB = (uint32_t)EBML_IntegerValue(TElt);
522 				}
523 				else if (TElt->Context->Id == MATROSKA_ContextTrackVideoPixelCropTop.Id)
524 				{
525 					if (EBML_IntegerValue(TElt) > 0xFFFFFFFF)
526 					{
527 						snprintf(err_msg,err_msgSize,"PixelCropTop is too large: %d",(int)EBML_IntegerValue(TElt));
528 						goto fail;
529 					}
530 					track.AV.Video.CropT = (uint32_t)EBML_IntegerValue(TElt);
531 				}
532 				else if (TElt->Context->Id == MATROSKA_ContextTrackVideoPixelCropLeft.Id)
533 				{
534 					if (EBML_IntegerValue(TElt) > 0xFFFFFFFF)
535 					{
536 						snprintf(err_msg,err_msgSize,"PixelCropLeft is too large: %d",(int)EBML_IntegerValue(TElt));
537 						goto fail;
538 					}
539 					track.AV.Video.CropL = (uint32_t)EBML_IntegerValue(TElt);
540 				}
541 				else if (TElt->Context->Id == MATROSKA_ContextTrackVideoPixelCropRight.Id)
542 				{
543 					if (EBML_IntegerValue(TElt) > 0xFFFFFFFF)
544 					{
545 						snprintf(err_msg,err_msgSize,"PixelCropRight is too large: %d",(int)EBML_IntegerValue(TElt));
546 						goto fail;
547 					}
548 					track.AV.Video.CropR = (uint32_t)EBML_IntegerValue(TElt);
549 				}
550 				else if (TElt->Context->Id == MATROSKA_ContextTrackVideoColourSpace.Id)
551 				{
552 					if (TElt->DataSize != 4)
553 					{
554 						snprintf(err_msg,err_msgSize,"ColourSpace is too large: %d",TElt->DataSize);
555 						goto fail;
556 					}
557 					track.AV.Video.ColourSpace = LOAD32LE(EBML_BinaryGetData((ebml_binary*)TElt));
558 				}
559 				else if (TElt->Context->Id == MATROSKA_ContextTrackVideoGammaValue.Id)
560 					track.AV.Video.GammaValue = (float)((ebml_float*)TElt)->Value;
561 			}
562 		}
563 		else if (Elt->Context->Id == MATROSKA_ContextTrackAudio.Id)
564 		{
565 			track.AV.Audio.Channels = (uint8_t)MATROSKA_ContextTrackAudioChannels.DefaultValue;
566 			track.AV.Audio.SamplingFreq = (float)MATROSKA_ContextTrackAudioSamplingFreq.DefaultValue;
567 
568 			for (TElt = EBML_MasterChildren(Elt);TElt;TElt = EBML_MasterNext(TElt))
569 			{
570 				if (TElt->Context->Id == MATROSKA_ContextTrackAudioSamplingFreq.Id)
571 				{
572 					track.AV.Audio.SamplingFreq = (float)((ebml_float*)TElt)->Value;
573 				}
574 				else if (TElt->Context->Id == MATROSKA_ContextTrackAudioOutputSamplingFreq.Id)
575 					track.AV.Audio.OutputSamplingFreq = (float)((ebml_float*)TElt)->Value;
576 				else if (TElt->Context->Id == MATROSKA_ContextTrackAudioChannels.Id)
577 				{
578 					if (EBML_IntegerValue(TElt)==0 || EBML_IntegerValue(TElt)>0xFF)
579 					{
580 						snprintf(err_msg,err_msgSize,"Invalid Channels value: %d",(int)EBML_IntegerValue(TElt));
581 						goto fail;
582 					}
583 					track.AV.Audio.Channels = (uint8_t)EBML_IntegerValue(TElt);
584 				}
585 				else if (TElt->Context->Id == MATROSKA_ContextTrackAudioBitDepth.Id)
586 				{
587 					if (EBML_IntegerValue(TElt)==0 || EBML_IntegerValue(TElt)>0xFF)
588 					{
589 						snprintf(err_msg,err_msgSize,"Invalid BitDepth value: %d",(int)EBML_IntegerValue(TElt));
590 						goto fail;
591 					}
592 					track.AV.Audio.BitDepth = (uint8_t)EBML_IntegerValue(TElt);
593 				}
594 			}
595 			if (!track.AV.Audio.OutputSamplingFreq)
596 				track.AV.Audio.OutputSamplingFreq = track.AV.Audio.SamplingFreq;
597 		}
598 		// TODO: ContentEncoding
599 	}
600 
601 	if (!track.CodecID)
602 	{
603 		strncpy(err_msg,"Track has no Codec ID",err_msgSize);
604 		goto fail;
605 	}
606 
607 	// check for duplicate track UID entries
608     if (track.UID)
609     {
610         for (Tracks=ARRAYBEGIN(File->Tracks,TrackInfo);Tracks!=ARRAYEND(File->Tracks,TrackInfo);++Tracks)
611         {
612             if (Tracks->UID == track.UID)
613             {
614                 snprintf(err_msg,err_msgSize,"A track with UID 0x" PRIx64 " already exists",track.UID);
615                 goto fail;
616             }
617         }
618     }
619 
620 	ArrayAppend(&File->Tracks,&track,sizeof(track),256);
621 	return 1;
622 
623 fail:
624 	releaseTrackEntry(&track, File->Input->io);
625 	return 0;
626 }
627 
parseTracks(ebml_element * Tracks,MatroskaFile * File,char * err_msg,size_t err_msgSize)628 static bool_t parseTracks(ebml_element *Tracks, MatroskaFile *File, char *err_msg, size_t err_msgSize)
629 {
630 	ebml_parser_context RContext;
631 	ebml_element *Elt;
632 
633 	RContext.Context = Tracks->Context;
634 	if (EBML_ElementIsFiniteSize(Tracks))
635 		RContext.EndPosition = EBML_ElementPositionEnd(Tracks);
636 	else
637 		RContext.EndPosition = INVALID_FILEPOS_T;
638     RContext.UpContext = &File->L1Context;
639 	if (EBML_ElementReadData(Tracks,(stream*)File->Input,&RContext,1,SCOPE_ALL_DATA)!=ERR_NONE)
640 	{
641 		strncpy(err_msg,"Failed to read the Tracks",err_msgSize);
642 		File->pTracks = INVALID_FILEPOS_T;
643 		return 0;
644 	}
645 	File->pTracks = Tracks->ElementPosition;
646 
647 	for (Elt = EBML_MasterChildren(Tracks);Elt;Elt = EBML_MasterNext(Elt))
648 	{
649 		if (Elt->Context->Id == MATROSKA_ContextTrackEntry.Id)
650 			if (!parseTrackEntry(Elt, File, err_msg, err_msgSize))
651 				break;
652 	}
653 	File->TrackList = Tracks;
654 
655 	return 1;
656 }
657 
parseCues(ebml_element * Cues,MatroskaFile * File,char * err_msg,size_t err_msgSize)658 static bool_t parseCues(ebml_element *Cues, MatroskaFile *File, char *err_msg, size_t err_msgSize)
659 {
660 	ebml_parser_context RContext;
661 
662 	RContext.Context = Cues->Context;
663 	if (EBML_ElementIsFiniteSize(Cues))
664 		RContext.EndPosition = EBML_ElementPositionEnd(Cues);
665 	else
666 		RContext.EndPosition = INVALID_FILEPOS_T;
667     RContext.UpContext = &File->L1Context;
668 	if (EBML_ElementReadData(Cues,(stream*)File->Input,&RContext,1,SCOPE_ALL_DATA)!=ERR_NONE)
669 	{
670 		strncpy(err_msg,"Failed to read the Cues",err_msgSize);
671 		File->pCues = INVALID_FILEPOS_T;
672 		return 0;
673 	}
674 	File->pCues = Cues->ElementPosition;
675 	File->CueList = Cues;
676 
677 	return 1;
678 }
679 
parseAttachments(ebml_element * Attachments,MatroskaFile * File,char * err_msg,size_t err_msgSize)680 static bool_t parseAttachments(ebml_element *Attachments, MatroskaFile *File, char *err_msg, size_t err_msgSize)
681 {
682 	ebml_parser_context RContext;
683     ebml_element *Elt, *Elt2;
684     size_t Count;
685     Attachment *At;
686 
687 	RContext.Context = Attachments->Context;
688 	if (EBML_ElementIsFiniteSize(Attachments))
689 		RContext.EndPosition = EBML_ElementPositionEnd(Attachments);
690 	else
691 		RContext.EndPosition = INVALID_FILEPOS_T;
692     RContext.UpContext = &File->L1Context;
693 	if (EBML_ElementReadData(Attachments,(stream*)File->Input,&RContext,1,SCOPE_PARTIAL_DATA)!=ERR_NONE)
694 	{
695 		strncpy(err_msg,"Failed to read the Attachments",err_msgSize);
696 		File->pAttachments = INVALID_FILEPOS_T;
697 		return 0;
698 	}
699 	File->pAttachments = Attachments->ElementPosition;
700 
701     Count=0;
702     Elt = EBML_MasterFindFirstElt(Attachments, &MATROSKA_ContextAttachedFile, 0,0);
703     while (Elt)
704     {
705         ++Count;
706         Elt = EBML_MasterFindNextElt(Attachments, Elt, 0,0);
707     }
708     ArrayResize(&File->Attachments,Count*sizeof(Attachment),0);
709     ArrayZero(&File->Attachments);
710 
711     for (Elt = EBML_MasterFindFirstElt(Attachments, &MATROSKA_ContextAttachedFile, 0,0),At=ARRAYBEGIN(File->Attachments,Attachment);
712         At!=ARRAYEND(File->Attachments,Attachment); ++At, Elt = EBML_MasterFindNextElt(Attachments, Elt, 0,0))
713     {
714         At->Length = INVALID_FILEPOS_T;
715         At->Position = INVALID_FILEPOS_T;
716         for (Elt2=EBML_MasterChildren(Elt);Elt2;Elt2=EBML_MasterNext(Elt2))
717         {
718             if (Elt2->Context->Id == MATROSKA_ContextAttachedFileName.Id)
719             {
720                 At->Name = File->Input->io->memalloc(File->Input->io, (size_t)(Elt2->DataSize+1));
721 			    strcpy(At->Name,((ebml_string*)Elt2)->Buffer);
722             }
723             else if (Elt2->Context->Id == MATROSKA_ContextAttachedFileData.Id)
724             {
725                 At->Position = EBML_ElementPositionData(Elt2);
726                 At->Length = Elt2->DataSize;
727             }
728             else if (Elt2->Context->Id == MATROSKA_ContextAttachedFileUID.Id)
729                 At->UID = EBML_IntegerValue(Elt2);
730             else if (Elt2->Context->Id == MATROSKA_ContextAttachedFileMimeType.Id)
731             {
732                 At->MimeType = File->Input->io->memalloc(File->Input->io, (size_t)(Elt2->DataSize+1));
733 			    strcpy(At->MimeType,((ebml_string*)Elt2)->Buffer);
734             }
735             else if (Elt2->Context->Id == MATROSKA_ContextAttachedFileDescription.Id)
736             {
737                 At->Description = File->Input->io->memalloc(File->Input->io, (size_t)(Elt2->DataSize+1));
738 			    strcpy(At->Description,((ebml_string*)Elt2)->Buffer);
739             }
740         }
741     }
742 
743 	return 1;
744 }
745 
addChapterDisplay(ebml_element * ChapterDisplay,MatroskaFile * File,struct Chapter * Chapter)746 static bool_t addChapterDisplay(ebml_element *ChapterDisplay, MatroskaFile *File, struct Chapter *Chapter)
747 {
748 	struct ChapterDisplay *pDisplay,Display;
749 	ebml_element *Elt;
750 
751 	if (!ArrayAppend(&Chapter->aDisplays,&Display,sizeof(struct ChapterDisplay),512))
752 		return 0;
753 	pDisplay = ARRAYEND(Chapter->aDisplays,struct ChapterDisplay)-1;
754 	memset(pDisplay,0,sizeof(*pDisplay));
755 	memcpy(pDisplay->Language, (char*)MATROSKA_ContextChapterLanguage.DefaultValue, 4);
756 
757 	for (Elt=EBML_MasterChildren(ChapterDisplay); Elt; Elt=EBML_MasterNext(Elt))
758 	{
759 		if (Elt->Context->Id == MATROSKA_ContextChapterString.Id)
760 		{
761 			pDisplay->String = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
762 			strcpy(pDisplay->String,((ebml_string*)Elt)->Buffer);
763 		}
764 		else if (Elt->Context->Id == MATROSKA_ContextChapterLanguage.Id)
765 		{
766 			size_t copy = (Elt->DataSize>3) ? 3 : (size_t)Elt->DataSize;
767 			memcpy(pDisplay->Language,((ebml_string*)Elt)->Buffer,copy);
768 			memset(pDisplay->Language + copy,0,4-copy);
769 		}
770 		else if (Elt->Context->Id == MATROSKA_ContextChapterCountry.Id)
771 		{
772 			size_t copy = (Elt->DataSize>3) ? 3 : (size_t)Elt->DataSize;
773 			memcpy(pDisplay->Country,((ebml_string*)Elt)->Buffer,copy);
774 			memset(pDisplay->Country+ copy,0,4-copy);
775 		}
776 	}
777 
778 	return 1;
779 }
780 
parseChapter(ebml_element * Chapter,MatroskaFile * File,char * err_msg,size_t err_msgSize,struct Chapter * Parent,array * Editions)781 static bool_t parseChapter(ebml_element *Chapter, MatroskaFile *File, char *err_msg, size_t err_msgSize, struct Chapter *Parent, array *Editions)
782 {
783 	struct Chapter *pChapter,Chap;
784 	ebml_element *Elt;
785 
786 	pChapter = &Chap;
787 	for (Elt=EBML_MasterChildren(Chapter); Elt; Elt=EBML_MasterNext(Elt))
788 	{
789 		if (Elt->Context->Id == MATROSKA_ContextChapterAtom.Id)
790 		{
791 			if (!ArrayAppend(&Parent->aChildren,&Chap,sizeof(Chap),512))
792 				return 0;
793 			pChapter = ARRAYEND(Parent->aChildren,struct Chapter)-1;
794 			memset(pChapter,0,sizeof(*pChapter));
795 			pChapter->Start = INVALID_TIMECODE_T;
796 			if (!parseChapter(Elt,File,err_msg,err_msgSize,pChapter,NULL))
797 				ArrayRemove(&Parent->aChildren,struct Chapter,pChapter,NULL,NULL);
798 		}
799 		// Atom
800 		else if (Elt->Context->Id == MATROSKA_ContextChapterUID.Id)
801 			Parent->UID = EBML_IntegerValue(Elt);
802 		else if (Elt->Context->Id == MATROSKA_ContextChapterTimeStart.Id)
803 			Parent->Start = EBML_IntegerValue(Elt);
804 		else if (Elt->Context->Id == MATROSKA_ContextChapterTimeEnd.Id)
805 			Parent->End = EBML_IntegerValue(Elt);
806 		else if (Elt->Context->Id == MATROSKA_ContextChapterHidden.Id)
807 			Parent->Hidden = EBML_IntegerValue(Elt)!=0;
808 		else if (Elt->Context->Id == MATROSKA_ContextChapterEnabled.Id)
809 			Parent->Enabled = EBML_IntegerValue(Elt)!=0;
810 		else if (Elt->Context->Id == MATROSKA_ContextChapterDisplay.Id)
811 			addChapterDisplay(Elt, File, Parent);
812 		// Edition
813 		else if (Elt->Context->Id == MATROSKA_ContextEditionUID.Id)
814 			Parent->UID = EBML_IntegerValue(Elt);
815 		else if (Elt->Context->Id == MATROSKA_ContextEditionHidden.Id)
816 			Parent->Hidden = EBML_IntegerValue(Elt)!=0;
817 		else if (Elt->Context->Id == MATROSKA_ContextEditionDefault.Id)
818 			Parent->Default = EBML_IntegerValue(Elt)!=0;
819 		else if (Elt->Context->Id == MATROSKA_ContextEditionOrdered.Id)
820 			Parent->Ordered = EBML_IntegerValue(Elt)!=0;
821 	}
822 
823 	Parent->nChildren = ARRAYCOUNT(Parent->aChildren,struct Chapter);
824 	Parent->Children = ARRAYBEGIN(Parent->aChildren,struct Chapter);
825 	Parent->nDisplay = ARRAYCOUNT(Parent->aDisplays,struct ChapterDisplay);
826 	Parent->Display = ARRAYBEGIN(Parent->aDisplays,struct ChapterDisplay);
827 
828 	return 1;
829 }
830 
parseChapters(ebml_element * Chapters,MatroskaFile * File,char * err_msg,size_t err_msgSize)831 static bool_t parseChapters(ebml_element *Chapters, MatroskaFile *File, char *err_msg, size_t err_msgSize)
832 {
833 	ebml_parser_context RContext;
834 	struct Chapter *pChapter,Chap;
835 	ebml_element *Elt;
836 
837 	RContext.Context = Chapters->Context;
838 	if (EBML_ElementIsFiniteSize(Chapters))
839 		RContext.EndPosition = EBML_ElementPositionEnd(Chapters);
840 	else
841 		RContext.EndPosition = INVALID_FILEPOS_T;
842     RContext.UpContext = &File->L1Context;
843 	if (EBML_ElementReadData(Chapters,(stream*)File->Input,&RContext,1,SCOPE_ALL_DATA)!=ERR_NONE)
844 	{
845 		strncpy(err_msg,"Failed to read the Chapters",err_msgSize);
846 		File->pChapters = INVALID_FILEPOS_T;
847 		return 0;
848 	}
849 	File->pChapters = Chapters->ElementPosition;
850 
851 	pChapter = &Chap;
852 	memset(pChapter,0,sizeof(*pChapter));
853 	Chap.Start = INVALID_TIMECODE_T;
854 	Chap.Ordered = MATROSKA_ContextEditionOrdered.DefaultValue;
855 	Chap.Hidden = MATROSKA_ContextEditionHidden.DefaultValue;
856 	Chap.Default = MATROSKA_ContextEditionDefault.DefaultValue;
857 	for (Elt=EBML_MasterChildren(Chapters); Elt; Elt=EBML_MasterNext(Elt))
858 	{
859 		if (Elt->Context->Id == MATROSKA_ContextChapterEntry.Id)
860 		{
861 			if (!ArrayAppend(&File->Chapters,&Chap,sizeof(Chap),512))
862 				return 0;
863 			pChapter = ARRAYEND(File->Chapters,struct Chapter)-1;
864 			if (!parseChapter(Elt, File, err_msg, err_msgSize, pChapter, &File->Chapters))
865 				ArrayRemove(&File->Chapters,struct Chapter,pChapter,NULL,NULL);
866 		}
867 	}
868 
869 	return 1;
870 }
871 
parseTargets(ebml_element * Targets,MatroskaFile * File,char * err_msg,size_t err_msgSize,struct Tag * Parent)872 static bool_t parseTargets(ebml_element *Targets, MatroskaFile *File, char *err_msg, size_t err_msgSize, struct Tag *Parent)
873 {
874 	ebml_element *Elt;
875 	uint8_t Level;
876 	struct Target *pTarget,Target;
877 
878 	Elt = EBML_MasterFindFirstElt(Targets, &MATROSKA_ContextTagTargetTypeValue, 1, 1);
879 	if (!Elt || EBML_IntegerValue(Elt) > 0xFF)
880 		return 0;
881 
882 	Level = (uint8_t)EBML_IntegerValue(Elt);
883 
884 	pTarget = &Target;
885 	memset(pTarget,0,sizeof(*pTarget));
886 	for (Elt=EBML_MasterChildren(Targets); Elt; Elt=EBML_MasterNext(Elt))
887 	{
888 		if (Elt->Context->Id == MATROSKA_ContextTagTargetTrackUID.Id)
889 		{
890 			if (!ArrayAppend(&Parent->aTargets,&Target,sizeof(Target),512))
891 				return 0;
892 			pTarget = ARRAYEND(Parent->aTargets,struct Target)-1;
893 			pTarget->Type = TARGET_TRACK;
894 			pTarget->UID = EBML_IntegerValue(Elt);
895 			pTarget->Level = Level;
896 		}
897 		else if (Elt->Context->Id == MATROSKA_ContextTagTargetChapterUID.Id)
898 		{
899 			if (!ArrayAppend(&Parent->aTargets,&Target,sizeof(Target),512))
900 				return 0;
901 			pTarget = ARRAYEND(Parent->aTargets,struct Target)-1;
902 			pTarget->Type = TARGET_CHAPTER;
903 			pTarget->UID = EBML_IntegerValue(Elt);
904 			pTarget->Level = Level;
905 		}
906 		else if (Elt->Context->Id == MATROSKA_ContextTagTargetAttachmentUID.Id)
907 		{
908 			if (!ArrayAppend(&Parent->aTargets,&Target,sizeof(Target),512))
909 				return 0;
910 			pTarget = ARRAYEND(Parent->aTargets,struct Target)-1;
911 			pTarget->Type = TARGET_ATTACHMENT;
912 			pTarget->UID = EBML_IntegerValue(Elt);
913 			pTarget->Level = Level;
914 		}
915 		else if (Elt->Context->Id == MATROSKA_ContextTagTargetEditionUID.Id)
916 		{
917 			if (!ArrayAppend(&Parent->aTargets,&Target,sizeof(Target),512))
918 				return 0;
919 			pTarget = ARRAYEND(Parent->aTargets,struct Target)-1;
920 			pTarget->Type = TARGET_EDITION;
921 			pTarget->UID = EBML_IntegerValue(Elt);
922 			pTarget->Level = Level;
923 		}
924 	}
925 
926 	return 1;
927 }
928 
parseSimpleTag(ebml_element * SimpleTag,MatroskaFile * File,char * err_msg,size_t err_msgSize,struct Tag * Parent)929 static bool_t parseSimpleTag(ebml_element *SimpleTag, MatroskaFile *File, char *err_msg, size_t err_msgSize, struct Tag *Parent)
930 {
931 	ebml_element *Elt;
932 	struct SimpleTag simpleTag;
933 
934 	memset(&simpleTag,0,sizeof(simpleTag));
935 	simpleTag.Default = MATROSKA_ContextTagDefault.DefaultValue;
936 	memcpy(simpleTag.Language, (const char*)MATROSKA_ContextTagLanguage.DefaultValue, 4);
937 	for (Elt=EBML_MasterChildren(SimpleTag); Elt; Elt=EBML_MasterNext(Elt))
938 	{
939 		if (Elt->Context->Id == MATROSKA_ContextTagName.Id)
940 		{
941 			simpleTag.Name = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
942 			strcpy(simpleTag.Name,((ebml_string*)Elt)->Buffer);
943 		}
944 		else if (Elt->Context->Id == MATROSKA_ContextTagString.Id)
945 		{
946 			simpleTag.Value = File->Input->io->memalloc(File->Input->io, (size_t)(Elt->DataSize+1));
947 			strcpy(simpleTag.Value,((ebml_string*)Elt)->Buffer);
948 		}
949 		else if (Elt->Context->Id == MATROSKA_ContextTagLanguage.Id)
950 		{
951 			size_t copy = (Elt->DataSize>3) ? 3 : (size_t)Elt->DataSize;
952 			memcpy(simpleTag.Language,((ebml_string*)Elt)->Buffer,copy);
953 			memset(simpleTag.Language + copy,0,4-copy);
954 		}
955 		else if (Elt->Context->Id == MATROSKA_ContextTagString.Id)
956 			simpleTag.Default = EBML_IntegerValue(Elt)!=0;
957 	}
958 
959 	if (!simpleTag.Value || !simpleTag.Name || !ArrayAppend(&Parent->aSimpleTags,&simpleTag,sizeof(simpleTag),256))
960 	{
961 		if (simpleTag.Value) File->Input->io->memfree(File->Input->io, simpleTag.Value);
962 		if (simpleTag.Name) File->Input->io->memfree(File->Input->io, simpleTag.Name);
963 		return 0;
964 	}
965 
966 	Elt = EBML_MasterFindFirstElt(SimpleTag, &MATROSKA_ContextSimpleTag, 0, 0);
967 	while (Elt)
968 	{
969 		parseSimpleTag(Elt, File, err_msg, err_msgSize, Parent);
970 		Elt = EBML_MasterFindNextElt(SimpleTag, Elt, 0, 0);
971 	}
972 
973 	return 1;
974 }
975 
parseTag(ebml_element * Tag,MatroskaFile * File,char * err_msg,size_t err_msgSize,struct Tag * Parent)976 static bool_t parseTag(ebml_element *Tag, MatroskaFile *File, char *err_msg, size_t err_msgSize, struct Tag *Parent)
977 {
978 	ebml_element *Elt;
979 
980 	for (Elt=EBML_MasterChildren(Tag); Elt; Elt=EBML_MasterNext(Elt))
981 	{
982 		if (Elt->Context->Id == MATROSKA_ContextTagTargets.Id)
983 			parseTargets(Elt,File,err_msg,err_msgSize,Parent);
984 		else if (Elt->Context->Id == MATROSKA_ContextSimpleTag.Id)
985 			parseSimpleTag(Elt,File,err_msg,err_msgSize,Parent);
986 	}
987 
988 	Parent->Targets = ARRAYBEGIN(Parent->aTargets,struct Target);
989 	Parent->nTargets = ARRAYCOUNT(Parent->aTargets,struct Target);
990 	Parent->SimpleTags = ARRAYBEGIN(Parent->aSimpleTags,struct SimpleTag);
991 	Parent->nSimpleTags = ARRAYCOUNT(Parent->aSimpleTags,struct SimpleTag);
992 
993 	return 1;
994 }
995 
parseTags(ebml_element * Tags,MatroskaFile * File,char * err_msg,size_t err_msgSize)996 static bool_t parseTags(ebml_element *Tags, MatroskaFile *File, char *err_msg, size_t err_msgSize)
997 {
998 	ebml_parser_context RContext;
999 	struct Tag *pTag,Tag;
1000 	ebml_element *Elt;
1001 
1002 	RContext.Context = Tags->Context;
1003 	if (EBML_ElementIsFiniteSize(Tags))
1004 		RContext.EndPosition = EBML_ElementPositionEnd(Tags);
1005 	else
1006 		RContext.EndPosition = INVALID_FILEPOS_T;
1007     RContext.UpContext = &File->L1Context;
1008 	if (EBML_ElementReadData(Tags,(stream*)File->Input,&RContext,1,SCOPE_ALL_DATA)!=ERR_NONE)
1009 	{
1010 		strncpy(err_msg,"Failed to read the Tags",err_msgSize);
1011 		File->pTags = INVALID_FILEPOS_T;
1012 		return 0;
1013 	}
1014 	File->pTags = Tags->ElementPosition;
1015 
1016 	pTag = &Tag;
1017 	memset(pTag,0,sizeof(*pTag));
1018 	for (Elt=EBML_MasterChildren(Tags); Elt; Elt=EBML_MasterNext(Elt))
1019 	{
1020 		if (Elt->Context->Id == MATROSKA_ContextTag.Id)
1021 		{
1022 			if (!ArrayAppend(&File->Tags,&Tag,sizeof(Tag),512))
1023 				return 0;
1024 			pTag = ARRAYEND(File->Tags,struct Tag)-1;
1025 			if (!parseTag(Elt, File, err_msg, err_msgSize, pTag))
1026 				ArrayRemove(&File->Tags,struct Tag,pTag,NULL,NULL);
1027 		}
1028 	}
1029 
1030 
1031 	return 1;
1032 }
1033 
mkv_Open(InputStream * io,char * err_msg,size_t err_msgSize)1034 MatroskaFile *mkv_Open(InputStream *io, char *err_msg, size_t err_msgSize)
1035 {
1036 	int UpperLevel;
1037 	ebml_element *Head, *Elt;
1038 
1039 	MatroskaFile *File = io->memalloc(io,sizeof(*File));
1040 	if (!File)
1041 	{
1042 		strncpy(err_msg,"Out of memory",err_msgSize);
1043 		return NULL;
1044 	}
1045 
1046 	memset(File,0,sizeof(*File));
1047 	File->pSegmentInfo = INVALID_FILEPOS_T;
1048 	File->pTracks = INVALID_FILEPOS_T;
1049 	File->pCues = INVALID_FILEPOS_T;
1050 	File->pAttachments = INVALID_FILEPOS_T;
1051 	File->pChapters = INVALID_FILEPOS_T;
1052 	File->pTags = INVALID_FILEPOS_T;
1053 	File->pFirstCluster = INVALID_FILEPOS_T;
1054 
1055 	io->progress(io,0,0);
1056 	io->ioseek(io,0,SEEK_SET);
1057 
1058 	// find a segment
1059 	File->Input = (haali_stream*)NodeCreate(io->AnyNode,HAALI_STREAM_CLASS);
1060 	if (!File->Input)
1061 	{
1062 		strncpy(err_msg,"Out of memory",err_msgSize);
1063 		return NULL;
1064 	}
1065 	File->Input->io = io;
1066 
1067 	File->L0Context.Context = &MATROSKA_ContextStream;
1068     File->L0Context.EndPosition = File->Input->io->getfilesize(File->Input->io);
1069     File->L0Context.UpContext = NULL;
1070 	UpperLevel = 0;
1071 	Head = EBML_FindNextElement((stream*)File->Input,&File->L0Context,&UpperLevel,0);
1072 	if (!Head)
1073 	{
1074 		strncpy(err_msg,"Out of memory",err_msgSize);
1075 		return NULL;
1076 	}
1077 
1078 	if (Head->Context->Id == MATROSKA_ContextSegment.Id)
1079 	{
1080 		strncpy(err_msg,"First element in file is not EBML",err_msgSize);
1081 		return NULL;
1082 	}
1083 
1084 	if (EBML_ElementReadData(Head,(stream*)File->Input,&File->L0Context,1,SCOPE_ALL_DATA)!=ERR_NONE)
1085 	{
1086 		strncpy(err_msg,"Failed to read the EBML head",err_msgSize);
1087 		NodeDelete((node*)Head);
1088 		return NULL;
1089 	}
1090 	if (!CheckMatroskaHead(Head,err_msg,err_msgSize))
1091 	{
1092 		NodeDelete((node*)Head);
1093 		return NULL;
1094 	}
1095 	NodeDelete((node*)Head);
1096 
1097 	File->Segment = EBML_FindNextElement((stream*)File->Input,&File->L0Context,&UpperLevel,0);
1098 	if (!File->Segment)
1099 	{
1100 		strncpy(err_msg,"No segments found in the file",err_msgSize);
1101 		return NULL;
1102 	}
1103 
1104 	// we want to read data until we find a seekhead or a trackinfo
1105     File->L1Context.Context = File->Segment->Context;
1106 	if (EBML_ElementIsFiniteSize(File->Segment))
1107 		File->L1Context.EndPosition = EBML_ElementPositionEnd(File->Segment);
1108 	else
1109 		File->L1Context.EndPosition = INVALID_FILEPOS_T;
1110     File->L1Context.UpContext = &File->L0Context;
1111 	UpperLevel = 0;
1112 	Head = EBML_FindNextElement((stream*)File->Input,&File->L1Context,&UpperLevel,0);
1113 	while (Head && (!EBML_ElementIsFiniteSize(File->Segment) || EBML_ElementPositionEnd(File->Segment) >= EBML_ElementPositionEnd(Head)))
1114 	{
1115 		if (Head->Context->Id == MATROSKA_ContextSeekHead.Id)
1116 		{
1117 			parseSeekHead(Head, File, err_msg, err_msgSize);
1118 			NodeDelete((node*)Head);
1119 		}
1120 		else if (Head->Context->Id == MATROSKA_ContextSegmentInfo.Id)
1121 			parseSegmentInfo(Head, File, err_msg, err_msgSize);
1122 		else if (Head->Context->Id == MATROSKA_ContextTracks.Id)
1123 			parseTracks(Head, File, err_msg, err_msgSize);
1124 		else if (Head->Context->Id == MATROSKA_ContextCues.Id)
1125 			parseCues(Head, File, err_msg, err_msgSize);
1126 		else if (Head->Context->Id == MATROSKA_ContextAttachments.Id)
1127         {
1128 			parseAttachments(Head, File, err_msg, err_msgSize);
1129 			NodeDelete((node*)Head);
1130 		}
1131 		else if (Head->Context->Id == MATROSKA_ContextChapters.Id)
1132 		{
1133 			parseChapters(Head, File, err_msg, err_msgSize);
1134 			NodeDelete((node*)Head);
1135 		}
1136 		else if (Head->Context->Id == MATROSKA_ContextTags.Id)
1137 		{
1138 			parseTags(Head, File, err_msg, err_msgSize);
1139 			NodeDelete((node*)Head);
1140 		}
1141 		else
1142 		{
1143 			if (Head->Context->Id==MATROSKA_ContextCluster.Id && File->pFirstCluster==INVALID_FILEPOS_T)
1144 				File->pFirstCluster = Head->ElementPosition;
1145 			Elt = EBML_ElementSkipData(Head,(stream*)File->Input,&File->L1Context,NULL,1);
1146 			NodeDelete((node*)Head);
1147 			if (Elt)
1148 			{
1149 				Head = Elt;
1150 				continue;
1151 			}
1152 		}
1153 		Head = EBML_FindNextElement((stream*)File->Input,&File->L1Context,&UpperLevel,0);
1154 	}
1155 
1156 	if (File->CueList && File->SegmentInfo)
1157 	{
1158 		for (Elt = EBML_MasterChildren(File->CueList);Elt;Elt = EBML_MasterNext(Elt))
1159 		{
1160 			if (Elt->Context->Id == MATROSKA_ContextCuePoint.Id)
1161 				MATROSKA_LinkCueSegmentInfo((matroska_cuepoint*)Elt, File->SegmentInfo);
1162 		}
1163 
1164 		MATROSKA_CuesSort(File->CueList);
1165 	}
1166 
1167 	return File;
1168 }
1169 
releaseAttachments(array * Attachments,MatroskaFile * File)1170 static void releaseAttachments(array *Attachments, MatroskaFile *File)
1171 {
1172     Attachment *At;
1173     for (At=ARRAYBEGIN(File->Attachments,Attachment); At!=ARRAYEND(File->Attachments,Attachment); ++At)
1174     {
1175         if (At->Name) File->Input->io->memfree(File->Input->io, At->Name);
1176         if (At->MimeType) File->Input->io->memfree(File->Input->io, At->MimeType);
1177         if (At->Description) File->Input->io->memfree(File->Input->io, At->Description);
1178     }
1179 	ArrayClear(Attachments);
1180 }
1181 
releaseChapterDisplays(array * ChapterDisplays,MatroskaFile * File)1182 static void releaseChapterDisplays(array *ChapterDisplays, MatroskaFile *File)
1183 {
1184 	struct ChapterDisplay *pChapter;
1185 
1186 	for (pChapter = ARRAYBEGIN(*ChapterDisplays,struct ChapterDisplay); pChapter != ARRAYEND(*ChapterDisplays,struct ChapterDisplay); ++pChapter)
1187 		File->Input->io->memfree(File->Input->io, pChapter->String);
1188 	ArrayClear(ChapterDisplays);
1189 }
1190 
releaseChapters(array * Chapters,MatroskaFile * File)1191 static void releaseChapters(array *Chapters, MatroskaFile *File)
1192 {
1193 	struct Chapter *pChapter;
1194 
1195 	for (pChapter = ARRAYBEGIN(*Chapters,struct Chapter); pChapter != ARRAYEND(*Chapters,struct Chapter); ++pChapter)
1196 	{
1197 		releaseChapterDisplays(&pChapter->aDisplays, File);
1198 		releaseChapters(&pChapter->aChildren,File);
1199 	}
1200 
1201 	ArrayClear(Chapters);
1202 }
1203 
releaseSimpleTags(array * SimpleTags,MatroskaFile * File)1204 static void releaseSimpleTags(array *SimpleTags, MatroskaFile *File)
1205 {
1206 	struct SimpleTag *pSimpleTag;
1207 	for (pSimpleTag = ARRAYBEGIN(*SimpleTags,struct SimpleTag); pSimpleTag != ARRAYEND(*SimpleTags,struct SimpleTag); ++pSimpleTag)
1208 	{
1209 		if (pSimpleTag->Name) File->Input->io->memfree(File->Input->io, pSimpleTag->Name);
1210 		if (pSimpleTag->Value) File->Input->io->memfree(File->Input->io, pSimpleTag->Value);
1211 	}
1212 	ArrayClear(SimpleTags);
1213 }
1214 
releaseTags(array * Tags,MatroskaFile * File)1215 static void releaseTags(array *Tags, MatroskaFile *File)
1216 {
1217 	struct Tag *pTag;
1218 
1219 	for (pTag = ARRAYBEGIN(*Tags,struct Tag); pTag != ARRAYEND(*Tags,struct Tag); ++pTag)
1220 	{
1221 		releaseSimpleTags(&pTag->aSimpleTags, File);
1222 		ArrayClear(&pTag->aTargets);
1223 	}
1224 
1225 	ArrayClear(Tags);
1226 }
1227 
mkv_Close(MatroskaFile * File)1228 void mkv_Close(MatroskaFile *File)
1229 {
1230 	if (File->Seg.Filename) File->Input->io->memfree(File->Input->io, File->Seg.Filename);
1231 	if (File->Seg.PrevFilename) File->Input->io->memfree(File->Input->io, File->Seg.PrevFilename);
1232 	if (File->Seg.NextFilename) File->Input->io->memfree(File->Input->io, File->Seg.NextFilename);
1233 	if (File->Seg.Title) File->Input->io->memfree(File->Input->io, File->Seg.Title);
1234 	if (File->Seg.MuxingApp) File->Input->io->memfree(File->Input->io, File->Seg.MuxingApp);
1235 	if (File->Seg.WritingApp) File->Input->io->memfree(File->Input->io, File->Seg.WritingApp);
1236 
1237 	ArrayClear(&File->Tracks);
1238     releaseAttachments(&File->Attachments, File);
1239 	releaseChapters(&File->Chapters, File);
1240 	releaseTags(&File->Tags, File);
1241 
1242 	if (File->TrackList) NodeDelete((node*)File->TrackList);
1243 	if (File->CueList) NodeDelete((node*)File->CueList);
1244 	if (File->SegmentInfo) NodeDelete((node*)File->SegmentInfo);
1245 	if (File->Segment) NodeDelete((node*)File->Segment);
1246 	if (File->Input) NodeDelete((node*)File->Input);
1247 }
1248 
mkv_ReadFrame(MatroskaFile * File,int mask,unsigned int * track,ulonglong * StartTime,ulonglong * EndTime,ulonglong * FilePos,unsigned int * FrameSize,void ** FrameRef,unsigned int * FrameFlags)1249 int mkv_ReadFrame(MatroskaFile *File, int mask, unsigned int *track, ulonglong *StartTime, ulonglong *EndTime, ulonglong *FilePos, unsigned int *FrameSize,
1250                 void** FrameRef, unsigned int *FrameFlags)
1251 {
1252 	ebml_element *Elt = NULL,*Elt2;
1253 	TrackInfo *tr;
1254 	int16_t TrackNum;
1255 	matroska_frame Frame;
1256 	bool_t Skip;
1257 	unsigned int Track;
1258 	int UpperLevel = 0;
1259 
1260 	if (FrameFlags)
1261 		*FrameFlags = 0;
1262 	if (!track)
1263 		track = &Track;
1264 	*track = (unsigned int)-1;
1265 
1266 	for (;;)
1267 	{
1268 		if (!File->CurrentCluster)
1269 		{
1270 			for (;;)
1271 			{
1272 				if (!Elt)
1273 					Elt = EBML_FindNextElement((stream*)File->Input,&File->L1Context,&UpperLevel,0);
1274 				File->CurrentCluster = Elt;
1275 				if (!File->CurrentCluster)
1276 					return EOF;
1277 				if (UpperLevel)
1278 				{
1279 					// TODO: changing segments not supported yet
1280 					NodeDelete((node*)File->CurrentCluster);
1281 					return EOF;
1282 				}
1283 				if (File->CurrentCluster->Context->Id == MATROSKA_ContextCluster.Id)
1284 					break;
1285 
1286 				Elt = File->CurrentCluster;
1287 				File->CurrentCluster = EBML_ElementSkipData(File->CurrentCluster,(stream*)File->Input,&File->L1Context,NULL,1);
1288 				NodeDelete((node*)Elt);
1289 				Elt = NULL;
1290 			}
1291 
1292 			MATROSKA_LinkClusterReadSegmentInfo((matroska_cluster*)File->CurrentCluster,File->SegmentInfo,1);
1293 			File->ClusterContext.Context = &MATROSKA_ContextCluster;
1294 			if (EBML_ElementIsFiniteSize(File->CurrentCluster))
1295 				File->ClusterContext.EndPosition = EBML_ElementPositionEnd(File->CurrentCluster);
1296 			else
1297 				File->ClusterContext.EndPosition = INVALID_FILEPOS_T;
1298 			File->ClusterContext.UpContext = &File->L1Context;
1299 
1300 			File->CurrentBlock = NULL;
1301 			File->CurrentFrame = 0;
1302 		}
1303 
1304 		Elt = NULL;
1305 		while (!File->CurrentBlock)
1306 		{
1307 			if (!Elt)
1308 			{
1309 				UpperLevel = 0;
1310 				Elt = EBML_FindNextElement((stream*)File->Input,&File->ClusterContext,&UpperLevel,1);
1311 			}
1312 			if (!Elt || UpperLevel>0)
1313 			{
1314 				NodeDelete((node*)File->CurrentCluster);
1315 				File->CurrentCluster = NULL;
1316 				--UpperLevel;
1317 				break; // go to the next Cluster
1318 			}
1319 
1320 			Skip = 0;
1321 			if (Elt->Context->Id == MATROSKA_ContextClusterTimecode.Id)
1322 			{
1323 				if (EBML_ElementReadData(Elt,(stream*)File->Input,&File->ClusterContext,1, SCOPE_ALL_DATA)!=ERR_NONE)
1324 					return EOF; // TODO: memory leak
1325 				Elt2 = EBML_MasterFindFirstElt(File->CurrentCluster,&MATROSKA_ContextClusterTimecode,1,1);
1326 				if (!Elt2)
1327 					return EOF; // TODO: memory leak
1328 				EBML_IntegerSetValue((ebml_integer*)Elt2,EBML_IntegerValue(Elt));
1329 				NodeDelete((node*)Elt);
1330 				Elt = NULL;
1331 			}
1332 			else if (Elt->Context->Id == MATROSKA_ContextClusterSimpleBlock.Id)
1333 			{
1334 				if (EBML_ElementReadData(Elt,(stream*)File->Input,&File->ClusterContext,1, SCOPE_PARTIAL_DATA)!=ERR_NONE)
1335 					return EOF; // TODO: memory leak
1336 
1337 				TrackNum = MATROSKA_BlockTrackNum((matroska_block*)Elt);
1338 				for (*track=0, tr=ARRAYBEGIN(File->Tracks,TrackInfo);tr!=ARRAYEND(File->Tracks,TrackInfo);++tr,(*track)++)
1339 					if (TrackNum==tr->Number)
1340 						break;
1341 				if (tr==ARRAYEND(File->Tracks,TrackInfo) || (1<<*track & File->trackMask)!=0)
1342 					Skip = 1;
1343 				else
1344 				{
1345 					EBML_MasterAppend(File->CurrentCluster, Elt);
1346 					MATROSKA_LinkBlockWithReadTracks((matroska_block*)Elt,File->TrackList,1);
1347 					MATROSKA_LinkBlockReadSegmentInfo((matroska_block*)Elt,File->SegmentInfo,1);
1348 					File->CurrentBlock = (matroska_block*)Elt;
1349 				}
1350 			}
1351 			else if (Elt->Context->Id == MATROSKA_ContextClusterBlockGroup.Id)
1352 			{
1353 				if (EBML_ElementReadData(Elt,(stream*)File->Input,&File->ClusterContext,1, SCOPE_PARTIAL_DATA)!=ERR_NONE)
1354 					return EOF; // TODO: memory leak
1355 
1356 				Elt2 = EBML_MasterFindFirstElt(Elt, &MATROSKA_ContextClusterBlock, 0, 0);
1357 				if (!Elt2)
1358 					Skip = 1;
1359 				else
1360 				{
1361 					TrackNum = MATROSKA_BlockTrackNum((matroska_block*)Elt2);
1362 					for (*track=0, tr=ARRAYBEGIN(File->Tracks,TrackInfo);tr!=ARRAYEND(File->Tracks,TrackInfo);++tr,(*track)++)
1363 						if (TrackNum==tr->Number)
1364 							break;
1365 
1366 					if (tr==ARRAYEND(File->Tracks,TrackInfo) || (1<<*track & File->trackMask)!=0)
1367 						Skip = 1;
1368 					else
1369 					{
1370 						EBML_MasterAppend(File->CurrentCluster, Elt);
1371 						MATROSKA_LinkBlockWithReadTracks((matroska_block*)Elt2,File->TrackList,1);
1372 						MATROSKA_LinkBlockReadSegmentInfo((matroska_block*)Elt2,File->SegmentInfo,1);
1373 						File->CurrentBlock = (matroska_block*)Elt2;
1374 					}
1375 				}
1376 			}
1377 			else Skip = 1;
1378 
1379 			if (Skip)
1380 			{
1381 				Elt2 = Elt;
1382 				Elt = EBML_ElementSkipData(Elt2,(stream*)File->Input,&File->L1Context,NULL,1);
1383 				NodeDelete((node*)Elt2);
1384 			}
1385 		}
1386 		if (File->CurrentCluster && File->CurrentBlock)
1387 			break;
1388 	}
1389 
1390 	assert(File->CurrentBlock!=NULL);
1391 	if (MATROSKA_BlockGetFrame(File->CurrentBlock,File->CurrentFrame,&Frame,0)!=ERR_NONE)
1392 		return -1; // TODO: memory leaks
1393 
1394 	if (*track==(unsigned int)-1)
1395 	{
1396 		TrackNum = MATROSKA_BlockTrackNum(File->CurrentBlock);
1397 		for (*track=0, tr=ARRAYBEGIN(File->Tracks,TrackInfo);tr!=ARRAYEND(File->Tracks,TrackInfo);++tr,(*track)++)
1398 			if (TrackNum==tr->Number)
1399 				break;
1400 	}
1401 
1402 	if (Frame.Timecode!=INVALID_TIMECODE_T)
1403 	{
1404 		if (StartTime)
1405 			*StartTime = Frame.Timecode;
1406 		if (EndTime && Frame.Duration != INVALID_TIMECODE_T)
1407 			*EndTime = Frame.Timecode + Frame.Duration;
1408 	}
1409 
1410 	if (FilePos)
1411 		*FilePos = ((ebml_element*)File->CurrentBlock)->ElementPosition;
1412 	if (FrameFlags)
1413 	{
1414 		if (Frame.Timecode == INVALID_TIMECODE_T)
1415 			*FrameFlags |= FRAME_UNKNOWN_START;
1416 		if (Frame.Duration == INVALID_TIMECODE_T)
1417 			*FrameFlags |= FRAME_UNKNOWN_END;
1418 		if (MATROSKA_BlockKeyframe(File->CurrentBlock))
1419 			*FrameFlags |= FRAME_KF;
1420 	}
1421 	MATROSKA_BlockSkipToFrame(File->CurrentBlock, (stream*)File->Input, File->CurrentFrame);
1422 	*FrameRef = File->Input->io->makeref(File->Input->io,MATROSKA_BlockGetLength(File->CurrentBlock,File->CurrentFrame++));
1423 
1424 	if (File->CurrentFrame >= MATROSKA_BlockGetFrameCount(File->CurrentBlock))
1425 	{
1426 		File->CurrentBlock = NULL;
1427 		File->CurrentFrame = 0;
1428 	}
1429 
1430 	return 0;
1431 }
1432 
SeekToPos(MatroskaFile * File,filepos_t SeekPos)1433 static void SeekToPos(MatroskaFile *File, filepos_t SeekPos)
1434 {
1435 	if (File->CurrentBlock)
1436 	{
1437 		NodeDelete((node*)File->CurrentBlock);
1438 		File->CurrentBlock = NULL;
1439 	}
1440 	File->CurrentFrame = 0;
1441 	if (File->CurrentCluster && File->CurrentCluster->ElementPosition!=SeekPos)
1442 	{
1443 		NodeDelete((node*)File->CurrentCluster);
1444 		File->CurrentCluster = NULL;
1445 	}
1446 	File->Input->io->ioseek(File->Input->io,SeekPos,SEEK_SET);
1447 }
1448 
mkv_Seek(MatroskaFile * File,timecode_t timecode,int flags)1449 void mkv_Seek(MatroskaFile *File, timecode_t timecode, int flags)
1450 {
1451 	matroska_cuepoint *CuePoint;
1452 	filepos_t SeekPos;
1453 
1454 	if (File->flags & MKVF_AVOID_SEEKS || File->pFirstCluster==INVALID_FILEPOS_T || timecode==INVALID_TIMECODE_T)
1455 		return;
1456 
1457 	if (timecode==0)
1458 	{
1459 		SeekToPos(File, File->pFirstCluster);
1460 		return;
1461 	}
1462 	if (!File->CueList)
1463 		return;
1464 
1465 	CuePoint = MATROSKA_CuesGetTimecodeStart(File->CueList,timecode);
1466 	if (CuePoint==NULL)
1467 		return;
1468 
1469 	SeekPos = MATROSKA_CuePosInSegment(CuePoint) + EBML_ElementPositionData(File->Segment);
1470 	SeekToPos(File, SeekPos);
1471 }
1472 
mkv_TruncFloat(float f)1473 int mkv_TruncFloat(float f)
1474 {
1475 	return (int)f;
1476 }
1477 
Seek(haali_stream * p,filepos_t Pos,int SeekMode)1478 static filepos_t Seek(haali_stream *p ,filepos_t Pos,int SeekMode)
1479 {
1480 	if (!(Pos == 0 && SeekMode==SEEK_CUR))
1481 		p->io->ioseek(p->io,Pos,SeekMode);
1482 	return p->io->iotell(p->io);
1483 }
1484 
Read(haali_stream * p,void * Data,size_t Size,size_t * pReaded)1485 static err_t Read(haali_stream* p,void* Data,size_t Size,size_t* pReaded)
1486 {
1487 	size_t Readed;
1488 	if (!pReaded)
1489 		pReaded = &Readed;
1490 	*pReaded = p->io->ioread(p->io,Data,Size);
1491 	if (Size && *pReaded!=Size)
1492 		return ERR_END_OF_FILE;
1493 	return ERR_NONE;
1494 }
1495 
1496 META_START(HaaliStream_Class,HAALI_STREAM_CLASS)
1497 META_CLASS(SIZE,sizeof(haali_stream))
1498 META_VMT(TYPE_FUNC,stream_vmt,Seek,Seek)
1499 META_VMT(TYPE_FUNC,stream_vmt,Read,Read)
1500 META_END(STREAM_CLASS)
1501