1 /*
2  * $Id: matroskamain.c 830 2012-05-12 15:44:37Z robux4 $
3  * Copyright (c) 2008-2011, 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 #include "matroska/matroska.h"
29 #include "matroska/matroska_sem.h"
30 #include "matroska/matroska_internal.h"
31 #if defined(HAVE_ZLIB)
32 #include "zlib/zlib.h"
33 #elif defined(CONFIG_ZLIB)
34 #include "zlib.h"
35 #endif
36 #if defined(CONFIG_BZLIB)
37 #include <bzlib.h>
38 #endif
39 #if defined(CONFIG_LZO1X)
40 #include "minilzo.h"
41 #endif
42 #if defined(MATROSKA_LIBRARY)
43 #include "matroska2_project.h"
44 #endif
45 
46 const ebml_semantic EBML_SemanticMatroska[] = {
47     {1, 0, &EBML_ContextHead        ,0},
48     {1, 0, &MATROSKA_ContextSegment ,0},
49     {0, 0, NULL ,0} // end of the table
50 };
51 const ebml_context MATROSKA_ContextStream = {FOURCC('M','K','X','_'), EBML_MASTER_CLASS, 0, 0, "Matroska Stream", EBML_SemanticMatroska, EBML_SemanticGlobals, NULL};
52 
MATROSKA_Init(nodecontext * p)53 err_t MATROSKA_Init(nodecontext *p)
54 {
55 #if defined(MATROSKA_LIBRARY)
56     tchar_t LibName[MAXPATH];
57 #endif
58     err_t Err = EBML_Init(p);
59     if (Err == ERR_NONE)
60     {
61 #if defined(MATROSKA_LIBRARY)
62         tcscpy_s(LibName,TSIZEOF(LibName),PROJECT_NAME T(" v") PROJECT_VERSION);
63         Node_SetData(p,CONTEXT_LIBMATROSKA_VERSION,TYPE_STRING,LibName);
64 #endif
65     }
66     return Err;
67 }
68 
MATROSKA_Done(nodecontext * p)69 err_t MATROSKA_Done(nodecontext *p)
70 {
71     return EBML_Done(p);
72 }
73 
74 
75 #define MATROSKA_CUE_SEGMENTINFO     0x100
76 #define MATROSKA_CUE_BLOCK           0x101
77 
78 #define MATROSKA_CLUSTER_READ_SEGMENTINFO  0x100
79 #define MATROSKA_CLUSTER_WRITE_SEGMENTINFO 0x101
80 
81 #define MATROSKA_SEEKPOINT_ELEMENT   0x100
82 
83 #define LACING_NONE  0
84 #define LACING_XIPH  1
85 #define LACING_FIXED 2
86 #define LACING_EBML  3
87 #define LACING_AUTO  4
88 
89 struct matroska_cuepoint
90 {
91     ebml_master Base;
92     ebml_master *SegInfo;
93     matroska_block *Block;
94 };
95 
96 struct matroska_cluster
97 {
98     ebml_master Base;
99     ebml_master *ReadSegInfo;
100     ebml_master *WriteSegInfo;
101     timecode_t GlobalTimecode;
102 };
103 
104 struct matroska_seekpoint
105 {
106     ebml_master Base;
107     ebml_element *Link;
108 };
109 
110 struct matroska_trackentry
111 {
112     ebml_master Base;
113     bool_t CodecPrivateCompressed;
114 };
115 
BlockTrackChanged(matroska_block * Block)116 static err_t BlockTrackChanged(matroska_block *Block)
117 {
118 	Block->Base.Base.bNeedDataSizeUpdate = 1;
119 	return ERR_NONE;
120 }
121 
ClusterTimeChanged(matroska_cluster * Cluster)122 static err_t ClusterTimeChanged(matroska_cluster *Cluster)
123 {
124     timecode_t ClusterTimecode;
125 #if defined(CONFIG_EBML_WRITING)
126     timecode_t BlockTimecode;
127     ebml_element *Elt, *GBlock;
128 #endif
129 
130 	Cluster->Base.Base.bNeedDataSizeUpdate = 1;
131     ClusterTimecode = MATROSKA_ClusterTimecode(Cluster);
132     MATROSKA_ClusterSetTimecode(Cluster, ClusterTimecode);
133 #if defined(CONFIG_EBML_WRITING)
134     for (Elt = EBML_MasterChildren(Cluster); Elt; Elt = EBML_MasterNext(Elt))
135     {
136         if (EBML_ElementIsType(Elt, &MATROSKA_ContextBlockGroup))
137         {
138             for (GBlock = EBML_MasterChildren(Elt);GBlock;GBlock=EBML_MasterNext(GBlock))
139             {
140                 if (EBML_ElementIsType(GBlock, &MATROSKA_ContextBlock))
141                 {
142                     BlockTimecode = MATROSKA_BlockTimecode((matroska_block*)GBlock);
143                     if (BlockTimecode!=INVALID_TIMECODE_T)
144                         MATROSKA_BlockSetTimecode((matroska_block*)GBlock, BlockTimecode, ClusterTimecode);
145                     break;
146                 }
147             }
148         }
149         else if (EBML_ElementIsType(Elt, &MATROSKA_ContextSimpleBlock))
150         {
151             BlockTimecode = MATROSKA_BlockTimecode((matroska_block*)Elt);
152             if (BlockTimecode!=INVALID_TIMECODE_T)
153                 MATROSKA_BlockSetTimecode((matroska_block*)Elt, BlockTimecode, ClusterTimecode);
154         }
155     }
156 #endif
157     return ERR_NONE;
158 }
159 
CheckCompression(matroska_block * Block)160 static err_t CheckCompression(matroska_block *Block)
161 {
162     ebml_master *Elt, *Header;
163     assert(Block->ReadTrack!=NULL);
164     Elt = (ebml_master*)EBML_MasterFindChild(Block->ReadTrack, &MATROSKA_ContextContentEncodings);
165     if (Elt)
166     {
167         if (ARRAYCOUNT(Block->Data,uint8_t))
168             return ERR_INVALID_PARAM; // we cannot adjust sizes if the data are already read
169 
170         Elt = (ebml_master*)EBML_MasterFindChild(Elt, &MATROSKA_ContextContentEncoding);
171         if (EBML_MasterChildren(Elt))
172         {
173             if (EBML_MasterNext(Elt))
174                 return ERR_INVALID_DATA; // TODO support cascaded compression/encryption
175 
176             Elt = (ebml_master*)EBML_MasterFindChild(Elt, &MATROSKA_ContextContentCompression);
177             if (!Elt)
178                 return ERR_INVALID_DATA; // TODO: support encryption
179 
180             Header = (ebml_master*)EBML_MasterGetChild(Elt, &MATROSKA_ContextContentCompAlgo);
181 #if defined(CONFIG_ZLIB) || defined(CONFIG_LZO1X) || defined(CONFIG_BZLIB)
182             if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER)
183 #if defined(CONFIG_ZLIB)
184                     if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_ZLIB)
185 #endif
186 #if defined(CONFIG_LZO1X)
187                     if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_LZO1X)
188 #endif
189 #if defined(CONFIG_BZLIB)
190                     if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_BZLIB)
191 #endif
192 #else
193             if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER)
194 #endif
195                 return ERR_INVALID_DATA;
196 
197             if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_HEADER)
198             {
199                 Header = (ebml_master*)EBML_MasterFindChild(Elt, &MATROSKA_ContextContentCompSettings);
200                 if (Header)
201                 {
202                     uint32_t *i;
203         		    for (i=ARRAYBEGIN(Block->SizeList,uint32_t);i!=ARRAYEND(Block->SizeList,uint32_t);++i)
204                         *i += (uint32_t)Header->Base.DataSize;
205                 }
206             }
207         }
208     }
209     return ERR_NONE;
210 }
211 
MATROSKA_LinkBlockWithReadTracks(matroska_block * Block,ebml_master * Tracks,bool_t UseForWriteToo)212 err_t MATROSKA_LinkBlockWithReadTracks(matroska_block *Block, ebml_master *Tracks, bool_t UseForWriteToo)
213 {
214     ebml_element *Track;
215     ebml_integer *TrackNum;
216     bool_t WasLinked = Block->ReadTrack!=NULL;
217 
218     assert(EBML_ElementIsType((ebml_element*)Tracks, &MATROSKA_ContextTracks));
219     assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
220     for (Track=EBML_MasterChildren(Tracks);Track;Track=EBML_MasterNext(Track))
221     {
222         TrackNum = (ebml_integer*)EBML_MasterFindChild((ebml_master*)Track,&MATROSKA_ContextTrackNumber);
223         if (TrackNum && ((ebml_element*)TrackNum)->bValueIsSet && EBML_IntegerValue(TrackNum)==Block->TrackNumber)
224         {
225             Node_SET(Block,MATROSKA_BLOCK_READ_TRACK,&Track);
226 #if defined(CONFIG_EBML_WRITING)
227             if (UseForWriteToo)
228                 Node_SET(Block,MATROSKA_BLOCK_WRITE_TRACK,&Track);
229 #endif
230             if (WasLinked)
231                 return ERR_NONE;
232             return CheckCompression(Block);
233         }
234     }
235     return ERR_INVALID_DATA;
236 }
237 
MATROSKA_LinkBlockReadTrack(matroska_block * Block,ebml_master * Track,bool_t UseForWriteToo)238 err_t MATROSKA_LinkBlockReadTrack(matroska_block *Block, ebml_master *Track, bool_t UseForWriteToo)
239 {
240     ebml_integer *TrackNum;
241     bool_t WasLinked = Block->ReadTrack!=NULL;
242 
243     assert(EBML_ElementIsType((ebml_element*)Track, &MATROSKA_ContextTrackEntry));
244     assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
245     TrackNum = (ebml_integer*)EBML_MasterFindChild(Track,&MATROSKA_ContextTrackNumber);
246     if (TrackNum && ((ebml_element*)TrackNum)->bValueIsSet)
247     {
248         Block->TrackNumber = (uint16_t)EBML_IntegerValue(TrackNum);
249         Node_SET(Block,MATROSKA_BLOCK_READ_TRACK,&Track);
250 #if defined(CONFIG_EBML_WRITING)
251         if (UseForWriteToo)
252             Node_SET(Block,MATROSKA_BLOCK_WRITE_TRACK,&Track);
253 #endif
254         if (WasLinked)
255             return ERR_NONE;
256         return CheckCompression(Block);
257     }
258     return ERR_INVALID_DATA;
259 }
260 
261 #if defined(CONFIG_EBML_WRITING)
MATROSKA_LinkBlockWithWriteTracks(matroska_block * Block,ebml_master * Tracks)262 err_t MATROSKA_LinkBlockWithWriteTracks(matroska_block *Block, ebml_master *Tracks)
263 {
264     ebml_master *Track;
265     ebml_integer *TrackNum;
266     bool_t WasLinked = Block->WriteTrack!=NULL;
267 
268     assert(EBML_ElementIsType((ebml_element*)Tracks, &MATROSKA_ContextTracks));
269     assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
270     for (Track=(ebml_master*)EBML_MasterChildren(Tracks);Track;Track=(ebml_master*)EBML_MasterNext(Track))
271     {
272         TrackNum = (ebml_integer*)EBML_MasterFindChild(Track,&MATROSKA_ContextTrackNumber);
273         if (TrackNum && ((ebml_element*)TrackNum)->bValueIsSet && EBML_IntegerValue(TrackNum)==Block->TrackNumber)
274         {
275             Node_SET(Block,MATROSKA_BLOCK_WRITE_TRACK,&Track);
276             if (WasLinked)
277                 return ERR_NONE;
278             return CheckCompression(Block);
279         }
280     }
281     return ERR_INVALID_DATA;
282 }
283 
MATROSKA_LinkBlockWriteTrack(matroska_block * Block,ebml_master * Track)284 err_t MATROSKA_LinkBlockWriteTrack(matroska_block *Block, ebml_master *Track)
285 {
286     ebml_integer *TrackNum;
287     bool_t WasLinked = Block->WriteTrack!=NULL;
288 
289     assert(EBML_ElementIsType((ebml_element*)Track, &MATROSKA_ContextTrackEntry));
290     assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
291     TrackNum = (ebml_integer*)EBML_MasterFindChild(Track,&MATROSKA_ContextTrackNumber);
292     if (TrackNum && ((ebml_element*)TrackNum)->bValueIsSet)
293     {
294         Block->TrackNumber = (uint16_t)EBML_IntegerValue(TrackNum);
295         Node_SET(Block,MATROSKA_BLOCK_WRITE_TRACK,&Track);
296         if (WasLinked)
297             return ERR_NONE;
298         return CheckCompression(Block);
299     }
300     return ERR_INVALID_DATA;
301 }
302 #endif
303 
MATROSKA_BlockReadTrack(const matroska_block * Block)304 ebml_element *MATROSKA_BlockReadTrack(const matroska_block *Block)
305 {
306     ebml_element *Track;
307     if (Node_GET((node*)Block,MATROSKA_BLOCK_READ_TRACK,&Track)!=ERR_NONE)
308         return NULL;
309     return Track;
310 }
311 
312 #if defined(CONFIG_EBML_WRITING)
MATROSKA_BlockWriteTrack(const matroska_block * Block)313 ebml_element *MATROSKA_BlockWriteTrack(const matroska_block *Block)
314 {
315     ebml_element *Track;
316     if (Node_GET((node*)Block,MATROSKA_BLOCK_WRITE_TRACK,&Track)!=ERR_NONE)
317         return NULL;
318     return Track;
319 }
320 #endif
321 
MATROSKA_LinkMetaSeekElement(matroska_seekpoint * MetaSeek,ebml_element * Link)322 err_t MATROSKA_LinkMetaSeekElement(matroska_seekpoint *MetaSeek, ebml_element *Link)
323 {
324     assert(EBML_ElementIsType((ebml_element*)MetaSeek, &MATROSKA_ContextSeek));
325     Node_SET(MetaSeek,MATROSKA_SEEKPOINT_ELEMENT,&Link);
326     return ERR_NONE;
327 }
328 
MATROSKA_MetaSeekID(const matroska_seekpoint * MetaSeek)329 fourcc_t MATROSKA_MetaSeekID(const matroska_seekpoint *MetaSeek)
330 {
331 	ebml_element *SeekID;
332     assert(EBML_ElementIsType((ebml_element*)MetaSeek, &MATROSKA_ContextSeek));
333     SeekID = EBML_MasterFindChild((ebml_master*)MetaSeek, &MATROSKA_ContextSeekID);
334 	if (!SeekID)
335 		return 0;
336 	return EBML_BufferToID(EBML_BinaryGetData((ebml_binary*)SeekID));
337 }
338 
MATROSKA_MetaSeekIsClass(const matroska_seekpoint * MetaSeek,const ebml_context * Class)339 bool_t MATROSKA_MetaSeekIsClass(const matroska_seekpoint *MetaSeek, const ebml_context *Class)
340 {
341     return MATROSKA_MetaSeekID(MetaSeek) == Class->Id;
342 }
343 
MATROSKA_MetaSeekPosInSegment(const matroska_seekpoint * MetaSeek)344 filepos_t MATROSKA_MetaSeekPosInSegment(const matroska_seekpoint *MetaSeek)
345 {
346 	ebml_integer *SeekPos;
347     assert(EBML_ElementIsType((ebml_element*)MetaSeek, &MATROSKA_ContextSeek));
348 	SeekPos = (ebml_integer*)EBML_MasterFindChild((ebml_master*)MetaSeek, &MATROSKA_ContextSeekPosition);
349 	if (!SeekPos)
350 		return INVALID_FILEPOS_T;
351 	return EBML_IntegerValue(SeekPos);
352 }
353 
MATROSKA_MetaSeekAbsolutePos(const matroska_seekpoint * MetaSeek)354 filepos_t MATROSKA_MetaSeekAbsolutePos(const matroska_seekpoint *MetaSeek)
355 {
356 	filepos_t RelPos = MATROSKA_MetaSeekPosInSegment(MetaSeek);
357 	ebml_element *RSegment;
358 	if (RelPos==INVALID_FILEPOS_T)
359 		return INVALID_FILEPOS_T;
360 
361     RSegment = EBML_ElementParent(MetaSeek);
362     while (RSegment && !EBML_ElementIsType(RSegment, &MATROSKA_ContextSegment))
363         RSegment = EBML_ElementParent(RSegment);
364     if (!RSegment)
365         return INVALID_FILEPOS_T;
366 
367 	return RelPos + EBML_ElementPositionData(RSegment);
368 }
369 
MATROSKA_MetaSeekUpdate(matroska_seekpoint * MetaSeek)370 err_t MATROSKA_MetaSeekUpdate(matroska_seekpoint *MetaSeek)
371 {
372     ebml_element *WSeekID, *WSeekPosSegmentInfo, *RSegment, *Link = NULL;
373     size_t IdSize;
374     err_t Err;
375     uint8_t IdBuffer[4];
376 
377     if (Node_IsPartOf(MetaSeek,EBML_VOID_CLASS))
378         return ERR_NONE;
379 
380     assert(EBML_ElementIsType((ebml_element*)MetaSeek, &MATROSKA_ContextSeek));
381     RSegment = EBML_ElementParent(MetaSeek);
382     while (RSegment && !EBML_ElementIsType(RSegment, &MATROSKA_ContextSegment))
383         RSegment = EBML_ElementParent(RSegment);
384     if (!RSegment)
385         return ERR_INVALID_DATA;
386 
387     Err = Node_GET(MetaSeek,MATROSKA_SEEKPOINT_ELEMENT,&Link);
388     if (Err != ERR_NONE)
389         return Err;
390     if (Link==NULL)
391         return ERR_INVALID_DATA;
392 
393     WSeekID = EBML_MasterFindFirstElt((ebml_master*)MetaSeek,&MATROSKA_ContextSeekID,1,0);
394     IdSize = EBML_FillBufferID(IdBuffer,sizeof(IdBuffer),Link->Context->Id);
395     EBML_BinarySetData((ebml_binary*)WSeekID,IdBuffer,IdSize);
396 
397     WSeekPosSegmentInfo = EBML_MasterFindFirstElt((ebml_master*)MetaSeek,&MATROSKA_ContextSeekPosition,1,0);
398     EBML_IntegerSetValue((ebml_integer*)WSeekPosSegmentInfo, Link->ElementPosition - EBML_ElementPositionData(RSegment));
399 
400     return Err;
401 }
402 
MATROSKA_LinkClusterReadSegmentInfo(matroska_cluster * Cluster,ebml_master * SegmentInfo,bool_t UseForWriteToo)403 err_t MATROSKA_LinkClusterReadSegmentInfo(matroska_cluster *Cluster, ebml_master *SegmentInfo, bool_t UseForWriteToo)
404 {
405     assert(EBML_ElementIsType((ebml_element*)Cluster, &MATROSKA_ContextCluster));
406     assert(EBML_ElementIsType((ebml_element*)SegmentInfo, &MATROSKA_ContextInfo));
407     Node_SET(Cluster,MATROSKA_CLUSTER_READ_SEGMENTINFO,&SegmentInfo);
408     if (UseForWriteToo)
409         Node_SET(Cluster,MATROSKA_CLUSTER_WRITE_SEGMENTINFO,&SegmentInfo);
410     return ERR_NONE;
411 }
412 
413 #if defined(CONFIG_EBML_WRITING)
MATROSKA_LinkClusterWriteSegmentInfo(matroska_cluster * Cluster,ebml_master * SegmentInfo)414 err_t MATROSKA_LinkClusterWriteSegmentInfo(matroska_cluster *Cluster, ebml_master *SegmentInfo)
415 {
416     assert(EBML_ElementIsType((ebml_element*)Cluster, &MATROSKA_ContextCluster));
417     assert(EBML_ElementIsType((ebml_element*)SegmentInfo, &MATROSKA_ContextInfo));
418     Node_SET(Cluster,MATROSKA_CLUSTER_WRITE_SEGMENTINFO,&SegmentInfo);
419     return ERR_NONE;
420 }
421 #endif
422 
MATROSKA_LinkBlockReadSegmentInfo(matroska_block * Block,ebml_master * SegmentInfo,bool_t UseForWriteToo)423 err_t MATROSKA_LinkBlockReadSegmentInfo(matroska_block *Block, ebml_master *SegmentInfo, bool_t UseForWriteToo)
424 {
425     assert(EBML_ElementIsType((ebml_element*)SegmentInfo, &MATROSKA_ContextInfo));
426     assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
427     Node_SET(Block,MATROSKA_BLOCK_READ_SEGMENTINFO,&SegmentInfo);
428 #if defined(CONFIG_EBML_WRITING)
429     if (UseForWriteToo)
430         Node_SET(Block,MATROSKA_BLOCK_WRITE_SEGMENTINFO,&SegmentInfo);
431 #endif
432     return ERR_NONE;
433 }
434 
435 #if defined(CONFIG_EBML_WRITING)
MATROSKA_LinkBlockWriteSegmentInfo(matroska_block * Block,ebml_master * SegmentInfo)436 err_t MATROSKA_LinkBlockWriteSegmentInfo(matroska_block *Block, ebml_master *SegmentInfo)
437 {
438     assert(EBML_ElementIsType((ebml_element*)SegmentInfo, &MATROSKA_ContextInfo));
439     assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
440     Node_SET(Block,MATROSKA_BLOCK_WRITE_SEGMENTINFO,&SegmentInfo);
441     return ERR_NONE;
442 }
443 #endif
444 
MATROSKA_BlockReadSegmentInfo(const matroska_block * Block)445 ebml_element *MATROSKA_BlockReadSegmentInfo(const matroska_block *Block)
446 {
447     ebml_element *SegmentInfo;
448     if (Node_GET((node*)Block,MATROSKA_BLOCK_READ_SEGMENTINFO,&SegmentInfo)!=ERR_NONE)
449         return NULL;
450     return SegmentInfo;
451 }
452 
453 #if defined(CONFIG_EBML_WRITING)
MATROSKA_BlockWriteSegmentInfo(const matroska_block * Block)454 ebml_element *MATROSKA_BlockWriteSegmentInfo(const matroska_block *Block)
455 {
456     ebml_element *SegmentInfo;
457     if (Node_GET((node*)Block,MATROSKA_BLOCK_WRITE_SEGMENTINFO,&SegmentInfo)!=ERR_NONE)
458         return NULL;
459     return SegmentInfo;
460 }
461 #endif
462 
MATROSKA_LinkCueSegmentInfo(matroska_cuepoint * Cue,ebml_master * SegmentInfo)463 err_t MATROSKA_LinkCueSegmentInfo(matroska_cuepoint *Cue, ebml_master *SegmentInfo)
464 {
465     assert(EBML_ElementIsType((ebml_element*)Cue, &MATROSKA_ContextCuePoint));
466     assert(EBML_ElementIsType((ebml_element*)SegmentInfo, &MATROSKA_ContextInfo));
467     Node_SET(Cue,MATROSKA_CUE_SEGMENTINFO,&SegmentInfo);
468     return ERR_NONE;
469 }
470 
MATROSKA_LinkCuePointBlock(matroska_cuepoint * CuePoint,matroska_block * Block)471 err_t MATROSKA_LinkCuePointBlock(matroska_cuepoint *CuePoint, matroska_block *Block)
472 {
473     assert(EBML_ElementIsType((ebml_element*)CuePoint, &MATROSKA_ContextCuePoint));
474     assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
475     Node_SET(CuePoint,MATROSKA_CUE_BLOCK,&Block);
476     return ERR_NONE;
477 }
478 
MATROSKA_BlockCmp(const matroska_block * BlockA,const matroska_block * BlockB)479 static int MATROSKA_BlockCmp(const matroska_block *BlockA, const matroska_block *BlockB)
480 {
481     timecode_t TimeA = MATROSKA_BlockTimecode((matroska_block*)BlockA);
482     timecode_t TimeB = MATROSKA_BlockTimecode((matroska_block*)BlockB);
483     if (TimeA != TimeB)
484         return (int)((TimeA - TimeB)/100000);
485     return MATROSKA_BlockTrackNum(BlockB) - MATROSKA_BlockTrackNum(BlockA); // usually the first track is video, so put audio/subs first
486 }
487 
ClusterEltCmp(const matroska_cluster * Cluster,const ebml_element ** a,const ebml_element ** b)488 static int ClusterEltCmp(const matroska_cluster* Cluster, const ebml_element** a,const ebml_element** b)
489 {
490     const matroska_block *BlockA = NULL,*BlockB = NULL;
491     if (EBML_ElementIsType(*a, &MATROSKA_ContextTimecode))
492         return -1;
493     if (EBML_ElementIsType(*b, &MATROSKA_ContextTimecode))
494         return 1;
495 
496     if (EBML_ElementIsType(*a, &MATROSKA_ContextSimpleBlock))
497         BlockA = (const matroska_block *)*a;
498     else if (EBML_ElementIsType(*a, &MATROSKA_ContextBlockGroup))
499         BlockA = (const matroska_block *)EBML_MasterFindChild((ebml_master*)*a,&MATROSKA_ContextBlock);
500     if (EBML_ElementIsType(*b, &MATROSKA_ContextSimpleBlock))
501         BlockB = (const matroska_block *)*b;
502     else if (EBML_ElementIsType(*a, &MATROSKA_ContextBlockGroup))
503         BlockB = (const matroska_block *)EBML_MasterFindChild((ebml_master*)*b,&MATROSKA_ContextBlock);
504     if (BlockA != NULL && BlockB != NULL)
505         return MATROSKA_BlockCmp(BlockA,BlockB);
506 
507     assert(0); // unsupported comparison
508     return 0;
509 }
510 
MATROSKA_ClusterSort(matroska_cluster * Cluster)511 void MATROSKA_ClusterSort(matroska_cluster *Cluster)
512 {
513     EBML_MasterSort((ebml_master*)Cluster,(arraycmp)ClusterEltCmp,Cluster);
514 }
515 
MATROSKA_ClusterSetTimecode(matroska_cluster * Cluster,timecode_t Timecode)516 void MATROSKA_ClusterSetTimecode(matroska_cluster *Cluster, timecode_t Timecode)
517 {
518 	ebml_integer *TimecodeElt;
519 #if defined(CONFIG_EBML_WRITING)
520     ebml_element *Elt, *GBlock;
521     timecode_t BlockTimeCode;
522 #endif
523 
524     assert(EBML_ElementIsType((ebml_element*)Cluster, &MATROSKA_ContextCluster));
525     Cluster->GlobalTimecode = Timecode;
526     TimecodeElt = (ebml_integer*)EBML_MasterGetChild((ebml_master*)Cluster,&MATROSKA_ContextTimecode);
527 #if defined(CONFIG_EBML_WRITING)
528 	assert(Cluster->WriteSegInfo);
529 	EBML_IntegerSetValue(TimecodeElt, Scale64(Timecode,1,MATROSKA_SegmentInfoTimecodeScale(Cluster->WriteSegInfo)));
530     // update all the blocks LocalTimecode
531     for (Elt = EBML_MasterChildren(Cluster); Elt; Elt = EBML_MasterNext(Elt))
532     {
533         if (EBML_ElementIsType(Elt, &MATROSKA_ContextBlockGroup))
534         {
535             for (GBlock = EBML_MasterChildren(Elt);GBlock;GBlock=EBML_MasterNext(GBlock))
536             {
537                 if (EBML_ElementIsType(GBlock, &MATROSKA_ContextBlock))
538                 {
539                     BlockTimeCode = MATROSKA_BlockTimecode((matroska_block*)GBlock);
540                     if (BlockTimeCode!=INVALID_TIMECODE_T)
541                         MATROSKA_BlockSetTimecode((matroska_block*)GBlock, BlockTimeCode, Timecode);
542                     break;
543                 }
544             }
545         }
546         else if (EBML_ElementIsType(Elt, &MATROSKA_ContextSimpleBlock))
547         {
548             BlockTimeCode = MATROSKA_BlockTimecode((matroska_block*)Elt);
549             if (BlockTimeCode!=INVALID_TIMECODE_T)
550                 MATROSKA_BlockSetTimecode((matroska_block*)Elt, BlockTimeCode, Timecode);
551         }
552     }
553 #else
554 	assert(Cluster->ReadSegInfo);
555 	EBML_IntegerSetValue(TimecodeElt, Scale64(Timecode,1,MATROSKA_SegmentInfoTimecodeScale(Cluster->ReadSegInfo)));
556 #endif
557 }
558 
MATROSKA_ClusterTimecode(matroska_cluster * Cluster)559 timecode_t MATROSKA_ClusterTimecode(matroska_cluster *Cluster)
560 {
561     assert(EBML_ElementIsType((ebml_element*)Cluster, &MATROSKA_ContextCluster));
562     if (Cluster->GlobalTimecode == INVALID_TIMECODE_T)
563     {
564         ebml_integer *Timecode = (ebml_integer*)EBML_MasterFindChild((ebml_master*)Cluster,&MATROSKA_ContextTimecode);
565         if (Timecode)
566             Cluster->GlobalTimecode = EBML_IntegerValue(Timecode) * MATROSKA_SegmentInfoTimecodeScale(Cluster->ReadSegInfo);
567     }
568     return Cluster->GlobalTimecode;
569 }
570 
MATROSKA_ClusterTimecodeScale(matroska_cluster * Cluster,bool_t Read)571 timecode_t MATROSKA_ClusterTimecodeScale(matroska_cluster *Cluster, bool_t Read)
572 {
573 #if defined(CONFIG_EBML_WRITING)
574     if (!Read)
575         return MATROSKA_SegmentInfoTimecodeScale(Cluster->WriteSegInfo);
576 #endif
577     return MATROSKA_SegmentInfoTimecodeScale(Cluster->ReadSegInfo);
578 }
579 
MATROSKA_BlockSetTimecode(matroska_block * Block,timecode_t Timecode,timecode_t ClusterTimecode)580 err_t MATROSKA_BlockSetTimecode(matroska_block *Block, timecode_t Timecode, timecode_t ClusterTimecode)
581 {
582 	int64_t InternalTimecode;
583     assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
584     assert(Timecode!=INVALID_TIMECODE_T);
585 #if defined(CONFIG_EBML_WRITING)
586 	InternalTimecode = Scale64(Timecode - ClusterTimecode,1,(int64_t)(MATROSKA_SegmentInfoTimecodeScale(Block->WriteSegInfo) * MATROSKA_TrackTimecodeScale(Block->WriteTrack)));
587 #else
588 	InternalTimecode = Scale64(Timecode - ClusterTimecode,1,(int64_t)(MATROSKA_SegmentInfoTimecodeScale(Block->ReadSegInfo) * MATROSKA_TrackTimecodeScale(Block->ReadTrack)));
589 #endif
590 	if (InternalTimecode > 32767 || InternalTimecode < -32768)
591 		return ERR_INVALID_DATA;
592 	Block->LocalTimecode = (int16_t)InternalTimecode;
593     Block->LocalTimecodeUsed = 1;
594 	return ERR_NONE;
595 }
596 
MATROSKA_BlockTimecode(matroska_block * Block)597 timecode_t MATROSKA_BlockTimecode(matroska_block *Block)
598 {
599     ebml_element *Cluster;
600     assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
601 	if (Block->GlobalTimecode!=INVALID_TIMECODE_T)
602 		return Block->GlobalTimecode;
603     if (Block->ReadTrack==NULL)
604         return INVALID_TIMECODE_T;
605     assert(Block->LocalTimecodeUsed);
606     Cluster = EBML_ElementParent(Block);
607     while (Cluster && !EBML_ElementIsType(Cluster, &MATROSKA_ContextCluster))
608         Cluster = EBML_ElementParent(Cluster);
609     if (!Cluster)
610         return INVALID_TIMECODE_T;
611     Block->GlobalTimecode = MATROSKA_ClusterTimecode((matroska_cluster*)Cluster) + (timecode_t)(Block->LocalTimecode * MATROSKA_SegmentInfoTimecodeScale(Block->ReadSegInfo) * MATROSKA_TrackTimecodeScale(Block->ReadTrack));
612     MATROSKA_BlockSetTimecode(Block, Block->GlobalTimecode, MATROSKA_ClusterTimecode((matroska_cluster*)Cluster));
613     return Block->GlobalTimecode;
614 }
615 
MATROSKA_BlockTrackNum(const matroska_block * Block)616 int16_t MATROSKA_BlockTrackNum(const matroska_block *Block)
617 {
618     assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
619     assert(Block->LocalTimecodeUsed);
620     return Block->TrackNumber;
621 }
622 
MATROSKA_BlockKeyframe(const matroska_block * Block)623 bool_t MATROSKA_BlockKeyframe(const matroska_block *Block)
624 {
625     ebml_master *BlockGroup;
626     ebml_integer *Duration;
627 
628     assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
629     if (Block->IsKeyframe)
630         return 1;
631 
632 	if (!EBML_ElementIsType((const ebml_element*)Block, &MATROSKA_ContextBlock))
633         return 0;
634 
635 	BlockGroup = (ebml_master*)EBML_ElementParent(Block);
636     if (!BlockGroup || !Node_IsPartOf(BlockGroup,MATROSKA_BLOCKGROUP_CLASS))
637         return 0;
638 
639 	if (EBML_MasterFindChild(BlockGroup,&MATROSKA_ContextReferenceBlock))
640         return 0;
641 
642     Duration = (ebml_integer*)EBML_MasterFindChild(BlockGroup,&MATROSKA_ContextBlockDuration);
643 	if (Duration!=NULL && EBML_IntegerValue(Duration)==0)
644         return 0;
645 
646     return 1;
647 }
648 
MATROSKA_BlockDiscardable(const matroska_block * Block)649 bool_t MATROSKA_BlockDiscardable(const matroska_block *Block)
650 {
651     assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
652 	if (EBML_ElementIsType((const ebml_element*)Block, &MATROSKA_ContextBlock))
653         return 0;
654 	return Block->IsDiscardable;
655 }
656 
MATROSKA_BlockSetKeyframe(matroska_block * Block,bool_t Set)657 void MATROSKA_BlockSetKeyframe(matroska_block *Block, bool_t Set)
658 {
659     assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
660 	Block->IsKeyframe = Set;
661 }
662 
MATROSKA_BlockSetDiscardable(matroska_block * Block,bool_t Set)663 void MATROSKA_BlockSetDiscardable(matroska_block *Block, bool_t Set)
664 {
665     assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
666 	if (EBML_ElementIsType((const ebml_element*)Block, &MATROSKA_ContextSimpleBlock))
667     	Block->IsDiscardable = Set;
668 }
669 
MATROSKA_BlockLaced(const matroska_block * Block)670 bool_t MATROSKA_BlockLaced(const matroska_block *Block)
671 {
672     assert(Node_IsPartOf(Block,MATROSKA_BLOCK_CLASS));
673     assert(Block->LocalTimecodeUsed);
674     return Block->Lacing != LACING_NONE;
675 }
676 
MATROSKA_CueTrackNum(const matroska_cuepoint * Cue)677 int16_t MATROSKA_CueTrackNum(const matroska_cuepoint *Cue)
678 {
679     ebml_master *Position;
680     ebml_integer *CueTrack;
681     assert(EBML_ElementIsType((ebml_element*)Cue, &MATROSKA_ContextCuePoint));
682     Position = (ebml_master*)EBML_MasterFindChild((ebml_master*)Cue,&MATROSKA_ContextCueTrackPositions);
683     if (!Position)
684         return -1;
685     CueTrack = (ebml_integer*)EBML_MasterFindChild(Position,&MATROSKA_ContextCueTrack);
686     if (!CueTrack)
687         return -1;
688     return (int16_t)EBML_IntegerValue(CueTrack);
689 }
690 
MATROSKA_CuesSort(ebml_master * Cues)691 void MATROSKA_CuesSort(ebml_master *Cues)
692 {
693     assert(EBML_ElementIsType((ebml_element*)Cues, &MATROSKA_ContextCues));
694     EBML_MasterSort(Cues,NULL,NULL);
695 }
696 
MATROSKA_AttachmentSort(ebml_master * Attachments)697 void MATROSKA_AttachmentSort(ebml_master *Attachments)
698 {
699     assert(EBML_ElementIsType((ebml_element*)Attachments, &MATROSKA_ContextAttachments));
700     EBML_MasterSort(Attachments,NULL,NULL);
701 }
702 
MATROSKA_SegmentInfoTimecodeScale(const ebml_master * SegmentInfo)703 timecode_t MATROSKA_SegmentInfoTimecodeScale(const ebml_master *SegmentInfo)
704 {
705     ebml_integer *TimecodeScale = NULL;
706     if (SegmentInfo)
707     {
708         assert(EBML_ElementIsType((ebml_element*)SegmentInfo, &MATROSKA_ContextInfo));
709         TimecodeScale = (ebml_integer*)EBML_MasterFindChild((ebml_master*)SegmentInfo,&MATROSKA_ContextTimecodeScale);
710     }
711     if (!TimecodeScale)
712         return MATROSKA_ContextTimecodeScale.DefaultValue;
713     return EBML_IntegerValue(TimecodeScale);
714 }
715 
MATROSKA_TrackTimecodeScale(const ebml_master * Track)716 double MATROSKA_TrackTimecodeScale(const ebml_master *Track)
717 {
718     ebml_element *TimecodeScale;
719     assert(EBML_ElementIsType((ebml_element*)Track, &MATROSKA_ContextTrackEntry));
720     TimecodeScale = EBML_MasterFindChild((ebml_master*)Track,&MATROSKA_ContextTrackTimecodeScale);
721     if (!TimecodeScale)
722         return MATROSKA_ContextTrackTimecodeScale.DefaultValue;
723     return ((ebml_float*)TimecodeScale)->Value;
724 }
725 
MATROSKA_CueTimecode(const matroska_cuepoint * Cue)726 timecode_t MATROSKA_CueTimecode(const matroska_cuepoint *Cue)
727 {
728     ebml_integer *TimeCode;
729     assert(EBML_ElementIsType((ebml_element*)Cue, &MATROSKA_ContextCuePoint));
730     TimeCode = (ebml_integer*) EBML_MasterFindChild((ebml_master*)Cue,&MATROSKA_ContextCueTime);
731     if (!TimeCode)
732         return INVALID_TIMECODE_T;
733     return EBML_IntegerValue(TimeCode) * MATROSKA_SegmentInfoTimecodeScale(Cue->SegInfo);
734 }
735 
MATROSKA_CuePosInSegment(const matroska_cuepoint * Cue)736 filepos_t MATROSKA_CuePosInSegment(const matroska_cuepoint *Cue)
737 {
738     ebml_element *TimeCode;
739     assert(EBML_ElementIsType((ebml_element*)Cue, &MATROSKA_ContextCuePoint));
740     TimeCode = EBML_MasterFindChild((ebml_master*)Cue,&MATROSKA_ContextCueTrackPositions);
741     if (!TimeCode)
742         return INVALID_TIMECODE_T;
743     TimeCode = EBML_MasterFindChild((ebml_master*)TimeCode,&MATROSKA_ContextCueClusterPosition);
744     if (!TimeCode)
745         return INVALID_TIMECODE_T;
746     return EBML_IntegerValue((ebml_integer*)TimeCode);
747 }
748 
MATROSKA_CuePointUpdate(matroska_cuepoint * Cue,ebml_element * Segment)749 err_t MATROSKA_CuePointUpdate(matroska_cuepoint *Cue, ebml_element *Segment)
750 {
751     ebml_element *TimecodeElt, *Elt, *PosInCluster;
752     ebml_integer *TrackNum;
753     assert(EBML_ElementIsType((ebml_element*)Cue, &MATROSKA_ContextCuePoint));
754     assert(Cue->Block);
755     assert(Cue->SegInfo);
756     assert(Segment); // we need the segment location
757 	EBML_MasterErase((ebml_master*)Cue);
758 	EBML_MasterAddMandatory((ebml_master*)Cue,1);
759     TimecodeElt = EBML_MasterGetChild((ebml_master*)Cue,&MATROSKA_ContextCueTime);
760     if (!TimecodeElt)
761         return ERR_OUT_OF_MEMORY;
762     EBML_IntegerSetValue((ebml_integer*)TimecodeElt, Scale64(MATROSKA_BlockTimecode(Cue->Block),1,MATROSKA_SegmentInfoTimecodeScale(Cue->SegInfo)));
763 
764     Elt = EBML_MasterGetChild((ebml_master*)Cue,&MATROSKA_ContextCueTrackPositions);
765     if (!Elt)
766         return ERR_OUT_OF_MEMORY;
767 	TrackNum = (ebml_integer*)EBML_MasterGetChild((ebml_master*)Elt,&MATROSKA_ContextCueTrack);
768     if (!TrackNum)
769         return ERR_OUT_OF_MEMORY;
770 	EBML_IntegerSetValue(TrackNum, MATROSKA_BlockTrackNum(Cue->Block));
771 
772     PosInCluster = EBML_MasterGetChild((ebml_master*)Elt,&MATROSKA_ContextCueClusterPosition);
773     if (!PosInCluster)
774         return ERR_OUT_OF_MEMORY;
775     Elt = EBML_ElementParent(Cue->Block);
776     while (Elt && !EBML_ElementIsType(Elt, &MATROSKA_ContextCluster))
777         Elt = EBML_ElementParent(Elt);
778     if (!Elt)
779         return ERR_INVALID_DATA;
780 
781     assert(Elt->ElementPosition != INVALID_FILEPOS_T);
782 
783     EBML_IntegerSetValue((ebml_integer*)PosInCluster, Elt->ElementPosition - EBML_ElementPositionData(Segment));
784 
785     return ERR_NONE;
786 }
787 
MATROSKA_GetBlockForTimecode(matroska_cluster * Cluster,timecode_t Timecode,int16_t Track)788 matroska_block *MATROSKA_GetBlockForTimecode(matroska_cluster *Cluster, timecode_t Timecode, int16_t Track)
789 {
790     ebml_element *Block, *GBlock;
791     for (Block = EBML_MasterChildren(Cluster);Block;Block=EBML_MasterNext(Block))
792     {
793         if (EBML_ElementIsType(Block, &MATROSKA_ContextBlockGroup))
794         {
795             for (GBlock = EBML_MasterChildren(Block);GBlock;GBlock=EBML_MasterNext(GBlock))
796             {
797                 if (EBML_ElementIsType(GBlock, &MATROSKA_ContextBlock))
798                 {
799                     if (MATROSKA_BlockTrackNum((matroska_block*)GBlock) == Track &&
800                         MATROSKA_BlockTimecode((matroska_block*)GBlock) == Timecode)
801                     {
802                         return (matroska_block*)GBlock;
803                     }
804                 }
805             }
806         }
807         else if (EBML_ElementIsType(Block, &MATROSKA_ContextSimpleBlock))
808         {
809             if (MATROSKA_BlockTrackNum((matroska_block*)Block) == Track &&
810                 MATROSKA_BlockTimecode((matroska_block*)Block) == Timecode)
811             {
812                 return (matroska_block*)Block;
813             }
814         }
815     }
816     return NULL;
817 }
818 
MATROSKA_LinkClusterBlocks(matroska_cluster * Cluster,ebml_master * RSegmentInfo,ebml_master * Tracks,bool_t KeepUnmatched)819 void MATROSKA_LinkClusterBlocks(matroska_cluster *Cluster, ebml_master *RSegmentInfo, ebml_master *Tracks, bool_t KeepUnmatched)
820 {
821     ebml_element *Block, *GBlock,*NextBlock;
822 
823 	assert(Node_IsPartOf(Cluster,MATROSKA_CLUSTER_CLASS));
824 	assert(EBML_ElementIsType((ebml_element*)RSegmentInfo, &MATROSKA_ContextInfo));
825 	assert(EBML_ElementIsType((ebml_element*)Tracks, &MATROSKA_ContextTracks));
826 
827 	// link each Block/SimpleBlock with its Track and SegmentInfo
828 	MATROSKA_LinkClusterReadSegmentInfo(Cluster,RSegmentInfo,1);
829 	for (Block = EBML_MasterChildren(Cluster);Block;Block=NextBlock)
830 	{
831         NextBlock = EBML_MasterNext(Block);
832 		if (EBML_ElementIsType(Block, &MATROSKA_ContextBlockGroup))
833 		{
834 			for (GBlock = EBML_MasterChildren(Block);GBlock;GBlock=EBML_MasterNext(GBlock))
835 			{
836 				if (EBML_ElementIsType(GBlock, &MATROSKA_ContextBlock))
837 				{
838 					if (MATROSKA_LinkBlockWithReadTracks((matroska_block*)GBlock,Tracks,1)!=ERR_NONE && !KeepUnmatched)
839                         NodeDelete((node*)Block);
840                     else
841 					    MATROSKA_LinkBlockReadSegmentInfo((matroska_block*)GBlock,RSegmentInfo,1);
842 					break;
843 				}
844 			}
845 		}
846 		else if (EBML_ElementIsType(Block, &MATROSKA_ContextSimpleBlock))
847 		{
848 			if (MATROSKA_LinkBlockWithReadTracks((matroska_block*)Block,Tracks,1)!=ERR_NONE && !KeepUnmatched)
849                 NodeDelete((node*)Block);
850             else
851     			MATROSKA_LinkBlockReadSegmentInfo((matroska_block*)Block,RSegmentInfo,1);
852 		}
853 	}
854 }
855 
856 
GetBlockHeadSize(const matroska_block * Element)857 static size_t GetBlockHeadSize(const matroska_block *Element)
858 {
859     assert(Element->TrackNumber < 0x4000);
860     if (Element->TrackNumber < 0x80)
861         return 4;
862     else
863         return 5;
864 }
865 
MATROSKA_BlockReleaseData(matroska_block * Block,bool_t IncludingNotRead)866 err_t MATROSKA_BlockReleaseData(matroska_block *Block, bool_t IncludingNotRead)
867 {
868     if (!IncludingNotRead && Block->GlobalTimecode==INVALID_TIMECODE_T)
869         return ERR_NONE;
870     ArrayClear(&Block->Data);
871     Block->Base.Base.bValueIsSet = 0;
872     if (ARRAYCOUNT(Block->SizeListIn,int32_t))
873     {
874         // recover the size of each lace in SizeList for later reading
875         int32_t *i,*o;
876         assert(ARRAYCOUNT(Block->SizeListIn,int32_t) == ARRAYCOUNT(Block->SizeList,int32_t));
877         for (i=ARRAYBEGIN(Block->SizeListIn,int32_t),o=ARRAYBEGIN(Block->SizeList,int32_t);i!=ARRAYEND(Block->SizeListIn,int32_t);++i,++o)
878             *o = *i;
879         ArrayClear(&Block->SizeListIn);
880     }
881     return ERR_NONE;
882 }
883 
MATROSKA_BlockSkipToFrame(const matroska_block * Block,stream * Input,size_t FrameNum)884 err_t MATROSKA_BlockSkipToFrame(const matroska_block *Block, stream *Input, size_t FrameNum)
885 {
886 	uint32_t *i;
887 	filepos_t SeekPos = EBML_ElementPositionData((ebml_element*)Block);
888 	if (FrameNum >= ARRAYCOUNT(Block->SizeList,uint32_t))
889 		return ERR_INVALID_PARAM;
890 	if (Block->Lacing == LACING_NONE)
891 		SeekPos += GetBlockHeadSize(Block);
892 	else
893 	{
894 		SeekPos = Block->FirstFrameLocation;
895 		for (i=ARRAYBEGIN(Block->SizeList,uint32_t);FrameNum;--FrameNum,++i)
896 			SeekPos += *i;
897 	}
898 	if (Stream_Seek(Input,SeekPos,SEEK_SET) != SeekPos)
899 		return ERR_READ;
900 	return ERR_NONE;
901 }
902 
903 // TODO: support zero copy reading (read the frames directly into a buffer with a callback per frame)
904 //       pass the Input stream and the amount to read per frame, give the timecode of the frame and get the end timecode in return, get an error code if reading failed
MATROSKA_BlockReadData(matroska_block * Element,stream * Input)905 err_t MATROSKA_BlockReadData(matroska_block *Element, stream *Input)
906 {
907     size_t Read,BufSize;
908     size_t NumFrame;
909     err_t Err = ERR_NONE;
910     ebml_element *Elt, *Elt2, *Header = NULL;
911     uint8_t *InBuf;
912     int CompressionScope = MATROSKA_COMPR_SCOPE_BLOCK;
913 
914     if (!Element->Base.Base.bValueIsSet)
915     {
916         // find out if compressed headers are used
917         assert(Element->ReadTrack!=NULL);
918         Elt = EBML_MasterFindChild(Element->ReadTrack, &MATROSKA_ContextContentEncodings);
919         if (Elt)
920         {
921             Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncoding);
922             if (EBML_MasterChildren(Elt))
923             {
924                 if (EBML_MasterNext(Elt))
925                     return ERR_NOT_SUPPORTED; // TODO support cascaded compression/encryption
926 
927                 Elt2 = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncodingScope);
928                 if (Elt2)
929                     CompressionScope = (int)EBML_IntegerValue((ebml_integer*)Elt2);
930 
931                 Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompression);
932                 if (!Elt)
933                     return ERR_NOT_SUPPORTED; // TODO: support encryption
934 
935                 Header = EBML_MasterGetChild((ebml_master*)Elt, &MATROSKA_ContextContentCompAlgo);
936 #if defined(CONFIG_ZLIB) || defined(CONFIG_LZO1X) || defined(CONFIG_BZLIB)
937                 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER)
938 #if defined(CONFIG_ZLIB)
939                     if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_ZLIB)
940 #endif
941 #if defined(CONFIG_LZO1X)
942                     if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_LZO1X)
943 #endif
944 #if defined(CONFIG_BZLIB)
945                     if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_BZLIB)
946 #endif
947 #else
948                 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER)
949 #endif
950                     return ERR_INVALID_DATA;
951 
952                 if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_HEADER)
953                     Header = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompSettings);
954             }
955         }
956 
957 #if !defined(CONFIG_ZLIB) && !defined(CONFIG_LZO1X) && !defined(CONFIG_BZLIB)
958         if (Header && Header->Context==&MATROSKA_ContextContentCompAlgo)
959             return ERR_NOT_SUPPORTED;
960 #endif
961 
962         if (Header && Header->Context==&MATROSKA_ContextContentCompAlgo && !(CompressionScope & MATROSKA_COMPR_SCOPE_BLOCK))
963             Header = NULL;
964 
965         Stream_Seek(Input,Element->FirstFrameLocation,SEEK_SET);
966         if (Header)
967             ArrayCopy(&Element->SizeListIn, &Element->SizeList);
968         switch (Element->Lacing)
969         {
970         case LACING_NONE:
971 #if defined(CONFIG_ZLIB) || defined(CONFIG_LZO1X) || defined(CONFIG_BZLIB)
972             if (Header && Header->Context==&MATROSKA_ContextContentCompAlgo)
973             {
974                 // zlib handling, read the buffer in temp memory
975                 array TmpBuf;
976                 ArrayInit(&TmpBuf);
977                 if (!ArrayResize(&TmpBuf,(size_t)ARRAYBEGIN(Element->SizeList,int32_t)[0],0))
978                     Err = ERR_OUT_OF_MEMORY;
979                 InBuf = ARRAYBEGIN(TmpBuf,uint8_t);
980                 Err = Stream_Read(Input,InBuf,(size_t)ARRAYBEGIN(Element->SizeList,int32_t)[0],&Read);
981                 if (Err==ERR_NONE)
982                 {
983                     if (Read!=(size_t)ARRAYBEGIN(Element->SizeList,int32_t)[0])
984                         Err = ERR_READ;
985                     else
986                     {
987 #if defined(CONFIG_ZLIB)
988                         if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_ZLIB)
989                         {
990                             // get the ouput size, adjust the Element->SizeList value, write in Element->Data
991                             z_stream stream;
992                             int Res;
993                             memset(&stream,0,sizeof(stream));
994                             Res = inflateInit(&stream);
995                             if (Res != Z_OK)
996                                 Err = ERR_INVALID_DATA;
997                             else
998                             {
999                                 size_t Count = 0;
1000                                 stream.next_in = InBuf;
1001                                 stream.avail_in = ARRAYBEGIN(Element->SizeList,int32_t)[0];
1002                                 stream.next_out = ARRAYBEGIN(Element->Data,uint8_t);
1003                                 do {
1004                                     Count = stream.next_out - ARRAYBEGIN(Element->Data,uint8_t);
1005                                     stream.avail_out = 1024;
1006                                     if (!ArrayResize(&Element->Data, Count + stream.avail_out, 0))
1007                                     {
1008                                         Res = Z_MEM_ERROR;
1009                                         break;
1010                                     }
1011                                     stream.next_out = ARRAYBEGIN(Element->Data,uint8_t) + Count;
1012                                     Res = inflate(&stream, Z_NO_FLUSH);
1013                                     if (Res!=Z_STREAM_END && Res!=Z_OK)
1014                                         break;
1015                                 } while (Res!=Z_STREAM_END && stream.avail_in && !stream.avail_out);
1016                                 ArrayResize(&Element->Data, stream.total_out, 0);
1017                                 ARRAYBEGIN(Element->SizeList,int32_t)[0] = stream.total_out;
1018                                 inflateEnd(&stream);
1019                                 if (Res != Z_STREAM_END)
1020                                     Err = ERR_INVALID_DATA;
1021                             }
1022                         }
1023 #endif
1024 #if defined(CONFIG_LZO1X)
1025                         if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_LZO1X)
1026                         {
1027                             if (lzo_init() != LZO_E_OK)
1028                                 Err = ERR_INVALID_DATA;
1029                             else
1030                             {
1031                                 lzo_uint outSize = max(2048, ARRAYBEGIN(Element->SizeList,int32_t)[0] << 2);
1032                                 if (!ArrayResize(&Element->Data, outSize, 0))
1033                                     Err = ERR_OUT_OF_MEMORY;
1034                                 else
1035                                 {
1036                                     if (lzo1x_decompress_safe(InBuf, ARRAYBEGIN(Element->SizeList,int32_t)[0], ARRAYBEGIN(Element->Data,uint8_t), &outSize, NULL) != LZO_E_OK)
1037                                         Err = ERR_INVALID_DATA;
1038                                     else
1039                                     {
1040                                         ARRAYBEGIN(Element->SizeList,int32_t)[0] = outSize;
1041                                         ArrayResize(&Element->Data,outSize,0);
1042                                     }
1043                                 }
1044                             }
1045                         }
1046 #endif
1047 #if defined(CONFIG_BZLIB)
1048                         if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_BZLIB)
1049                         {
1050                             unsigned int outSize = ARRAYBEGIN(Element->SizeList,int32_t)[0] << 2;
1051                             bz_stream strm;
1052                             int Res;
1053 
1054                             if (!ArrayResize(&Element->Data, outSize, 0))
1055                                 Err = ERR_OUT_OF_MEMORY;
1056                             else
1057                             {
1058                                strm.bzalloc = NULL;
1059                                strm.bzfree = NULL;
1060                                strm.opaque = NULL;
1061                                if (BZ2_bzDecompressInit (&strm, 0, 1) != BZ_OK)
1062                                    Err = ERR_INVALID_DATA;
1063                                else
1064                                {
1065                                     size_t Count = 0;
1066                                     strm.next_in = (char*)InBuf;
1067                                     strm.avail_in = ARRAYBEGIN(Element->SizeList,int32_t)[0];
1068                                     strm.next_out = ARRAYBEGIN(Element->Data,char);
1069                                     strm.avail_out = 0;
1070 
1071                                     do {
1072                                         Count = strm.next_out - ARRAYBEGIN(Element->Data,char);
1073                                         strm.avail_out = 1024;
1074                                         if (!ArrayResize(&Element->Data, Count + strm.avail_out, 0))
1075                                         {
1076                                             Res = BZ_MEM_ERROR;
1077                                             break;
1078                                         }
1079                                         strm.next_out = ARRAYBEGIN(Element->Data,char) + Count;
1080                                         Res = BZ2_bzDecompress(&strm);
1081                                         if (Res!=BZ_STREAM_END && Res!=BZ_OK)
1082                                             break;
1083                                     } while (Res!=BZ_STREAM_END && strm.avail_in && !strm.avail_out);
1084                                     ArrayResize(&Element->Data, strm.total_out_lo32, 0);
1085                                     ARRAYBEGIN(Element->SizeList,int32_t)[0] = strm.total_out_lo32;
1086                                     BZ2_bzDecompressEnd(&strm);
1087                                     if (Res != BZ_STREAM_END)
1088                                         Err = ERR_INVALID_DATA;
1089                                 }
1090                             }
1091                         }
1092 #endif
1093                     }
1094                 }
1095                 ArrayClear(&TmpBuf);
1096             }
1097             else
1098 #endif
1099             {
1100                 if (!ArrayResize(&Element->Data,(size_t)ARRAYBEGIN(Element->SizeList,int32_t)[0],0))
1101                 {
1102                     Err = ERR_OUT_OF_MEMORY;
1103                     goto failed;
1104                 }
1105                 InBuf = ARRAYBEGIN(Element->Data,uint8_t);
1106                 if (Header)
1107                 {
1108                     memcpy(InBuf,ARRAYBEGIN(((ebml_binary*)Header)->Data,uint8_t),(size_t)Header->DataSize);
1109                     InBuf += (size_t)Header->DataSize;
1110                 }
1111                 Err = Stream_Read(Input,InBuf,(size_t)(ARRAYBEGIN(Element->SizeList,int32_t)[0] - (Header?Header->DataSize:0)),&Read);
1112                 if (Err != ERR_NONE)
1113                     goto failed;
1114                 if (Read + (Header?Header->DataSize:0) != (size_t)ARRAYBEGIN(Element->SizeList,int32_t)[0])
1115                 {
1116                     Err = ERR_READ;
1117                     goto failed;
1118                 }
1119             }
1120             break;
1121         case LACING_EBML:
1122         case LACING_XIPH:
1123         case LACING_FIXED:
1124             Read = 0;
1125             BufSize = 0;
1126             for (NumFrame=0;NumFrame<ARRAYCOUNT(Element->SizeList,int32_t);++NumFrame)
1127                 BufSize += ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame];
1128 #if defined(CONFIG_ZLIB) || defined(CONFIG_LZO1X) || defined(CONFIG_BZLIB)
1129             if (Header && Header->Context==&MATROSKA_ContextContentCompAlgo)
1130             {
1131                 // zlib handling, read the buffer in temp memory
1132                 // get the ouput size, adjust the Element->SizeList value, write in Element->Data
1133                 array TmpBuf;
1134                 int32_t FrameSize;
1135                 size_t OutSize = 0;
1136 
1137                 ArrayInit(&TmpBuf);
1138                 if (!ArrayResize(&TmpBuf,BufSize,0))
1139                 {
1140                     Err = ERR_OUT_OF_MEMORY;
1141                     goto failed;
1142                 }
1143                 InBuf = ARRAYBEGIN(TmpBuf,uint8_t);
1144                 Err = Stream_Read(Input,InBuf,BufSize,&Read);
1145                 if (Err != ERR_NONE || Read!=BufSize)
1146                 {
1147                     if (Err==ERR_NONE)
1148                         Err = ERR_READ;
1149                     ArrayClear(&TmpBuf);
1150                     goto failed;
1151                 }
1152                 for (NumFrame=0;Err==ERR_NONE && NumFrame<ARRAYCOUNT(Element->SizeList,int32_t);++NumFrame)
1153                 {
1154 #if defined(CONFIG_ZLIB)
1155                     if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_ZLIB)
1156                     {
1157                         z_stream stream;
1158                         int Res;
1159                         memset(&stream,0,sizeof(stream));
1160                         Res = inflateInit(&stream);
1161                         if (Res != Z_OK)
1162                             Err = ERR_INVALID_DATA;
1163                         else
1164                         {
1165                             size_t Count;
1166                             stream.next_in = InBuf;
1167                             stream.avail_in = FrameSize = ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame];
1168                             stream.next_out = ARRAYBEGIN(Element->Data,uint8_t) + OutSize;
1169                             do {
1170                                 Count = stream.next_out - ARRAYBEGIN(Element->Data,uint8_t);
1171                                 if (!ArrayResize(&Element->Data, Count + 1024, 0))
1172                                 {
1173                                     Res = Z_MEM_ERROR;
1174                                     break;
1175                                 }
1176                                 stream.avail_out = ARRAYCOUNT(Element->Data,uint8_t) - Count;
1177                                 stream.next_out = ARRAYBEGIN(Element->Data,uint8_t) + Count;
1178                                 Res = inflate(&stream, Z_NO_FLUSH);
1179                                 if (Res!=Z_STREAM_END && Res!=Z_OK)
1180                                     break;
1181                             } while (Res!=Z_STREAM_END && stream.avail_in && !stream.avail_out);
1182                             ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame] = stream.total_out;
1183                             OutSize += stream.total_out;
1184                             inflateEnd(&stream);
1185                             if (Res != Z_STREAM_END)
1186                                 Err = ERR_INVALID_DATA;
1187                         }
1188                     }
1189 #endif
1190 #if defined(CONFIG_LZO1X)
1191                     if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_LZO1X)
1192                     {
1193                         if (lzo_init() != LZO_E_OK)
1194                             Err = ERR_INVALID_DATA;
1195                         else
1196                         {
1197                             lzo_uint outSize = max(2048, ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame] << 2);
1198                             FrameSize = ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame];
1199                             if (!ArrayResize(&Element->Data, OutSize + outSize, 0))
1200                                 Err = ERR_OUT_OF_MEMORY;
1201                             else
1202                             {
1203                                 if (lzo1x_decompress_safe(InBuf, ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame], ARRAYBEGIN(Element->Data,uint8_t) + OutSize, &outSize, NULL) != LZO_E_OK)
1204                                     Err = ERR_INVALID_DATA;
1205                                 else
1206                                 {
1207                                     OutSize += outSize;
1208                                     ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame] = outSize;
1209                                     ArrayResize(&Element->Data,OutSize,0);
1210                                 }
1211                             }
1212                         }
1213                     }
1214 #endif
1215 #if defined(CONFIG_BZLIB)
1216                     if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_BZLIB)
1217                     {
1218                         bz_stream stream;
1219                         int Res;
1220                         memset(&stream,0,sizeof(stream));
1221                         Res = BZ2_bzDecompressInit (&stream, 0, 1);
1222                         if (Res != BZ_OK)
1223                             Err = ERR_INVALID_DATA;
1224                         else
1225                         {
1226                             size_t Count;
1227                             stream.next_in = (char*)InBuf;
1228                             stream.avail_in = FrameSize = ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame];
1229                             stream.next_out = ARRAYBEGIN(Element->Data,char) + OutSize;
1230                             do {
1231                                 Count = stream.next_out - ARRAYBEGIN(Element->Data,char);
1232                                 if (!ArrayResize(&Element->Data, Count + 1024, 0))
1233                                 {
1234                                     Res = BZ_MEM_ERROR;
1235                                     break;
1236                                 }
1237                                 stream.avail_out = ARRAYCOUNT(Element->Data,uint8_t) - Count;
1238                                 stream.next_out = ARRAYBEGIN(Element->Data,char) + Count;
1239                                 Res = BZ2_bzDecompress(&stream);
1240                                 if (Res!=BZ_STREAM_END && Res!=BZ_OK)
1241                                     break;
1242                             } while (Res!=BZ_STREAM_END && stream.avail_in && !stream.avail_out);
1243                             ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame] = stream.total_out_lo32;
1244                             OutSize += stream.total_out_lo32;
1245                             BZ2_bzDecompressEnd(&stream);
1246                             if (Res != BZ_STREAM_END)
1247                                 Err = ERR_INVALID_DATA;
1248                         }
1249                     }
1250 #endif
1251                     InBuf += FrameSize;
1252                 }
1253                 ArrayResize(&Element->Data, OutSize, 0); // shrink the buffer
1254                 ArrayClear(&TmpBuf);
1255             }
1256             else
1257 #endif
1258             {
1259                 if (!ArrayResize(&Element->Data,BufSize,0))
1260                 {
1261                     Err = ERR_OUT_OF_MEMORY;
1262                     goto failed;
1263                 }
1264                 if (!Header)
1265                 {
1266                     //assert(BufSize + Element->FirstFrameLocation == Element->Base.Base.DataSize);
1267                     Err = Stream_Read(Input,ARRAYBEGIN(Element->Data,uint8_t),BufSize,&BufSize);
1268                 }
1269                 else
1270                 {
1271                     InBuf = ARRAYBEGIN(Element->Data,uint8_t);
1272                     for (NumFrame=0;NumFrame<ARRAYCOUNT(Element->SizeList,int32_t);++NumFrame)
1273                     {
1274                         memcpy(InBuf,ARRAYBEGIN(((ebml_binary*)Header)->Data,uint8_t),(size_t)Header->DataSize);
1275                         InBuf += (size_t)Header->DataSize;
1276                         Read = ARRAYBEGIN(Element->SizeList,int32_t)[NumFrame] - (int32_t)Header->DataSize;
1277                         BufSize = Read;
1278                         assert(InBuf + Read <= ARRAYEND(Element->Data,uint8_t));
1279                         Err = Stream_Read(Input,InBuf,BufSize,&Read);
1280                         if (Err != ERR_NONE || Read!=BufSize)
1281                             goto failed;
1282                         InBuf += Read;
1283                     }
1284                 }
1285             }
1286             if (Err != ERR_NONE)
1287                 goto failed;
1288             break;
1289         default:
1290             assert(0); // we should support the other lacing modes
1291             Err = ERR_NOT_SUPPORTED;
1292             goto failed;
1293         }
1294         Element->Base.Base.bValueIsSet = 1;
1295     }
1296 
1297 #if defined(CONFIG_EBML_WRITING)
1298 	if (Element->ReadTrack != Element->WriteTrack || Element->ReadSegInfo != Element->WriteSegInfo)
1299 		// TODO: only if the track compression/timecode scale is different
1300 		Element->Base.Base.bNeedDataSizeUpdate = 1;
1301 #endif
1302 
1303 failed:
1304     return Err;
1305 }
1306 
SetBlockParent(matroska_block * Block,void * Parent,void * Before)1307 static err_t SetBlockParent(matroska_block *Block, void* Parent, void* Before)
1308 {
1309 	// update the timecode
1310 	timecode_t AbsTimeCode;
1311 	err_t Result = ERR_NONE;
1312 	if (Block->LocalTimecodeUsed && Parent && NodeTree_Parent(Block))
1313 	{
1314 		assert(Node_IsPartOf(Parent,MATROSKA_CLUSTER_CLASS));
1315 		AbsTimeCode = MATROSKA_BlockTimecode(Block);
1316         assert(AbsTimeCode != INVALID_TIMECODE_T);
1317 		Result = MATROSKA_BlockSetTimecode(Block,AbsTimeCode,MATROSKA_ClusterTimecode((matroska_cluster*)Parent));
1318 	}
1319 	if (Result==ERR_NONE)
1320 		Result = INHERITED(Block,nodetree_vmt,MATROSKA_BLOCK_CLASS)->SetParent(Block, Parent, Before);
1321 	return Result;
1322 }
1323 
SetBlockGroupParent(ebml_master * Element,void * Parent,void * Before)1324 static err_t SetBlockGroupParent(ebml_master *Element, void* Parent, void* Before)
1325 {
1326 	// update the timecode
1327 	err_t Result = ERR_NONE;
1328 	matroska_block *Block = (matroska_block*)EBML_MasterFindChild(Element, &MATROSKA_ContextBlock);
1329 	timecode_t AbsTimeCode;
1330 	if (Block && Block->LocalTimecodeUsed && Parent && NodeTree_Parent(Block) && NodeTree_Parent(NodeTree_Parent(Block)))
1331 	{
1332 		assert(Node_IsPartOf(Parent,MATROSKA_CLUSTER_CLASS));
1333 		AbsTimeCode = MATROSKA_BlockTimecode(Block);
1334         assert(AbsTimeCode != INVALID_TIMECODE_T);
1335 		Result = MATROSKA_BlockSetTimecode(Block,AbsTimeCode,MATROSKA_ClusterTimecode((matroska_cluster*)Parent));
1336 	}
1337 	if (Result==ERR_NONE)
1338 		Result = INHERITED(Element,nodetree_vmt,MATROSKA_BLOCKGROUP_CLASS)->SetParent(Element, Parent, Before);
1339 	return Result;
1340 }
1341 
ReadBigBinaryData(ebml_binary * Element,stream * Input,const ebml_parser_context * ParserContext,bool_t AllowDummyElt,int Scope,size_t DepthCheckCRC)1342 static err_t ReadBigBinaryData(ebml_binary *Element, stream *Input, const ebml_parser_context *ParserContext, bool_t AllowDummyElt, int Scope, size_t DepthCheckCRC)
1343 {
1344     if (Scope == SCOPE_PARTIAL_DATA)
1345     {
1346         EBML_ElementSkipData((ebml_element*)Element,Input,ParserContext,NULL,AllowDummyElt);
1347         return ERR_NONE;
1348     }
1349     return INHERITED(Element,ebml_element_vmt,MATROSKA_BIGBINARY_CLASS)->ReadData(Element, Input, ParserContext, AllowDummyElt, Scope, DepthCheckCRC);
1350 }
1351 
ReadBlockData(matroska_block * Element,stream * Input,const ebml_parser_context * ParserContext,bool_t AllowDummyElt,int Scope)1352 static err_t ReadBlockData(matroska_block *Element, stream *Input, const ebml_parser_context *ParserContext, bool_t AllowDummyElt, int Scope)
1353 {
1354     err_t Result;
1355 	uint8_t _TempHead[5];
1356 	uint8_t *cursor = _TempHead;
1357 	uint8_t *_tmpBuf;
1358 	uint8_t BlockHeadSize = 4; // default when the TrackNumber is < 16
1359 
1360     assert(!Element->Base.Base.bValueIsSet);
1361     Element->Base.Base.bValueIsSet = 0;
1362 
1363     if (Scope == SCOPE_NO_DATA)
1364         return ERR_NONE;
1365 
1366     if (Stream_Seek(Input,EBML_ElementPositionData((ebml_element*)Element),SEEK_SET)==INVALID_FILEPOS_T)
1367     {
1368         Result = ERR_READ;
1369         goto failed;
1370     }
1371 
1372 	Result = Stream_Read(Input,_TempHead, 5, NULL);
1373     if (Result != ERR_NONE)
1374         goto failed;
1375 	// update internal values
1376 	Element->TrackNumber = *cursor++;
1377 	if (Element->TrackNumber & 0x80)
1378 		Element->TrackNumber &= 0x7F;
1379     else
1380     {
1381 		// there is extra data
1382 		if ((Element->TrackNumber & 0x40) == 0)
1383         {
1384 			// We don't support track numbers that large !
1385             Result = ERR_INVALID_DATA;
1386             goto failed;
1387 		}
1388 		Element->TrackNumber = (Element->TrackNumber & 0x3F) << 8;
1389 		Element->TrackNumber += *cursor++;
1390 		BlockHeadSize++;
1391 	}
1392 
1393 	Element->LocalTimecode = LOAD16BE(cursor);
1394 	Element->LocalTimecodeUsed = 1;
1395 	cursor += 2;
1396 
1397 	if (EBML_ElementIsType((ebml_element*)Element, &MATROSKA_ContextSimpleBlock))
1398     {
1399 		Element->IsKeyframe = (*cursor & 0x80) != 0;
1400 		Element->IsDiscardable = (*cursor & 0x01) != 0;
1401 	}
1402 	Element->Invisible = (*cursor & 0x08) >> 3;
1403 	Element->Lacing = (*cursor++ & 0x06) >> 1;
1404 
1405     Element->FirstFrameLocation = EBML_ElementPositionData((ebml_element*)Element) + BlockHeadSize;
1406 
1407     if (cursor == &_TempHead[4])
1408 		_TempHead[0] = _TempHead[4];
1409 	else
1410 		Result += Stream_Read(Input,_TempHead, 1, NULL);
1411 
1412 	// put all Frames in the list
1413 	if (Element->Lacing == LACING_NONE)
1414     {
1415 		ArrayResize(&Element->SizeList,sizeof(int32_t),0);
1416         ARRAYBEGIN(Element->SizeList,int32_t)[0] = (size_t)Element->Base.Base.DataSize - BlockHeadSize;
1417     }
1418     else
1419     {
1420 		// read the number of frames in the lace
1421 		uint32_t LastBufferSize = (size_t)Element->Base.Base.DataSize - BlockHeadSize - 1; // 1 for number of frame
1422 		uint8_t FrameNum = _TempHead[0]; // number of frames in the lace - 1
1423 		// read the list of frame sizes
1424 		uint8_t Index;
1425 		int32_t FrameSize;
1426 		size_t SizeRead;
1427 		filepos_t SizeUnknown;
1428 
1429         Element->FirstFrameLocation++; // for the number of frame
1430 		ArrayResize(&Element->SizeList,sizeof(int32_t)*(FrameNum + 1),0);
1431 
1432 		switch (Element->Lacing)
1433 		{
1434 		case LACING_XIPH:
1435 			for (Index=0; Index<FrameNum; Index++)
1436             {
1437 				// get the size of the frame
1438 				FrameSize = 0;
1439 				do {
1440 					Result += Stream_Read(Input,_TempHead, 1, NULL);
1441 					FrameSize += _TempHead[0];
1442 					LastBufferSize--;
1443 
1444 					Element->FirstFrameLocation++;
1445 				} while (_TempHead[0] == 0xFF);
1446 
1447 				ARRAYBEGIN(Element->SizeList,int32_t)[Index] = FrameSize;
1448 				LastBufferSize -= FrameSize;
1449 			}
1450 			ARRAYBEGIN(Element->SizeList,int32_t)[Index] = LastBufferSize;
1451 			break;
1452 		case LACING_EBML:
1453 			SizeRead = LastBufferSize;
1454             _tmpBuf = malloc(FrameNum*4);
1455 			cursor = _tmpBuf; /// \warning assume the mean size will be coded in less than 4 bytes
1456 			Result += Stream_Read(Input,cursor, FrameNum*4,NULL);
1457 			FrameSize = (int32_t)EBML_ReadCodedSizeValue(cursor, &SizeRead, &SizeUnknown);
1458 			ARRAYBEGIN(Element->SizeList,int32_t)[0] = FrameSize;
1459 			cursor += SizeRead;
1460 			LastBufferSize -= FrameSize + SizeRead;
1461 
1462 			for (Index=1; Index<FrameNum; Index++)
1463             {
1464 				// get the size of the frame
1465 				SizeRead = LastBufferSize;
1466 				FrameSize += (int32_t)EBML_ReadCodedSizeSignedValue(cursor, &SizeRead, &SizeUnknown);
1467 				ARRAYBEGIN(Element->SizeList,int32_t)[Index] = FrameSize;
1468 				cursor += SizeRead;
1469 				LastBufferSize -= FrameSize + SizeRead;
1470 			}
1471 
1472 			Element->FirstFrameLocation += cursor - _tmpBuf;
1473 
1474 			ARRAYBEGIN(Element->SizeList,int32_t)[Index] = LastBufferSize;
1475 			free(_tmpBuf);
1476 			break;
1477 		case LACING_FIXED:
1478 			for (Index=0; Index<=FrameNum; Index++)
1479 				// get the size of the frame
1480 				ARRAYBEGIN(Element->SizeList,int32_t)[Index] = LastBufferSize / (FrameNum + 1);
1481 			break;
1482 		default: // other lacing not supported
1483 			assert(0);
1484 		}
1485 	}
1486 
1487     if (Scope == SCOPE_PARTIAL_DATA)
1488 	{
1489 		if (Stream_Seek(Input,Element->Lacing==LACING_NONE ? (EBML_ElementPositionData((ebml_element*)Element) + BlockHeadSize) : Element->FirstFrameLocation,SEEK_SET)==INVALID_FILEPOS_T)
1490 			Result = ERR_READ;
1491 		else
1492 			Result = ERR_NONE;
1493 	}
1494     else
1495         Result = MATROSKA_BlockReadData(Element, Input);
1496 
1497 failed:
1498     return Result;
1499 }
1500 
MATROSKA_BlockGetFrame(const matroska_block * Block,size_t FrameNum,matroska_frame * Frame,bool_t WithData)1501 err_t MATROSKA_BlockGetFrame(const matroska_block *Block, size_t FrameNum, matroska_frame *Frame, bool_t WithData)
1502 {
1503     size_t i;
1504 
1505     assert(!WithData || Block->Base.Base.bValueIsSet);
1506     if (WithData && !ARRAYCOUNT(Block->Data,uint8_t))
1507         return ERR_READ;
1508     if (FrameNum >= ARRAYCOUNT(Block->SizeList,uint32_t))
1509         return ERR_INVALID_PARAM;
1510 
1511 	Frame->Data = WithData ? ARRAYBEGIN(Block->Data,uint8_t) : NULL;
1512     Frame->Timecode = MATROSKA_BlockTimecode((matroska_block*)Block);
1513     for (i=0;i<FrameNum;++i)
1514     {
1515         if (WithData) Frame->Data += ARRAYBEGIN(Block->SizeList,uint32_t)[i];
1516         if (Frame->Timecode != INVALID_TIMECODE_T)
1517         {
1518             if (i < ARRAYCOUNT(Block->Durations,timecode_t) && ARRAYBEGIN(Block->Durations,timecode_t)[i] != INVALID_TIMECODE_T)
1519                 Frame->Timecode += ARRAYBEGIN(Block->Durations,timecode_t)[i];
1520             else
1521                 Frame->Timecode = INVALID_TIMECODE_T;
1522         }
1523     }
1524 
1525     Frame->Size = ARRAYBEGIN(Block->SizeList,uint32_t)[i];
1526     if (FrameNum < ARRAYCOUNT(Block->Durations,timecode_t))
1527         Frame->Duration = ARRAYBEGIN(Block->Durations,timecode_t)[i];
1528     else
1529         Frame->Duration = INVALID_TIMECODE_T;
1530     return ERR_NONE;
1531 }
1532 
MATROSKA_BlockAppendFrame(matroska_block * Block,const matroska_frame * Frame,timecode_t ClusterTimecode)1533 err_t MATROSKA_BlockAppendFrame(matroska_block *Block, const matroska_frame *Frame, timecode_t ClusterTimecode)
1534 {
1535     if (!Block->Base.Base.bValueIsSet && Frame->Timecode!=INVALID_TIMECODE_T)
1536         MATROSKA_BlockSetTimecode(Block,Frame->Timecode,ClusterTimecode);
1537     ArrayAppend(&Block->Data,Frame->Data,Frame->Size,0);
1538     ArrayAppend(&Block->Durations,&Frame->Duration,sizeof(Frame->Duration),0);
1539     ArrayAppend(&Block->SizeList,&Frame->Size,sizeof(Frame->Size),0);
1540     Block->Base.Base.bValueIsSet = 1;
1541     Block->Base.Base.bNeedDataSizeUpdate = 1;
1542     Block->Lacing = LACING_AUTO;
1543     return ERR_NONE;
1544 }
1545 
1546 #if defined(CONFIG_ZLIB)
UnCompressFrameZLib(const uint8_t * Cursor,size_t CursorSize,array * OutBuf,size_t * FrameSize,size_t * ArrayOffset)1547 err_t UnCompressFrameZLib(const uint8_t *Cursor, size_t CursorSize, array *OutBuf, size_t *FrameSize, size_t *ArrayOffset)
1548 {
1549     z_stream stream;
1550     int Res;
1551     err_t Err = ERR_NONE;
1552 
1553     memset(&stream,0,sizeof(stream));
1554     Res = inflateInit(&stream);
1555     if (Res != Z_OK)
1556         Err = ERR_INVALID_DATA;
1557     else
1558     {
1559         size_t Count;
1560         stream.next_in = Cursor;
1561         stream.avail_in = CursorSize;
1562         stream.next_out = ARRAYBEGIN(*OutBuf,uint8_t) + *ArrayOffset;
1563         do {
1564             Count = stream.next_out - ARRAYBEGIN(*OutBuf,uint8_t);
1565             if (!ArrayResize(OutBuf, Count + 1024, 0))
1566             {
1567                 Res = Z_MEM_ERROR;
1568                 break;
1569             }
1570             stream.avail_out = ARRAYCOUNT(*OutBuf,uint8_t) - Count;
1571             stream.next_out = ARRAYBEGIN(*OutBuf,uint8_t) + Count;
1572             Res = inflate(&stream, Z_NO_FLUSH);
1573             if (Res!=Z_STREAM_END && Res!=Z_OK)
1574                 break;
1575         } while (Res!=Z_STREAM_END && stream.avail_in && !stream.avail_out);
1576         *FrameSize = stream.total_out;
1577         *ArrayOffset = *ArrayOffset + stream.total_out;
1578         inflateEnd(&stream);
1579         if (Res != Z_STREAM_END)
1580             Err = ERR_INVALID_DATA;
1581     }
1582     return Err;
1583 }
1584 
1585 #if defined(CONFIG_EBML_WRITING)
CompressFrameZLib(const uint8_t * Cursor,size_t CursorSize,uint8_t ** OutBuf,size_t * OutSize)1586 err_t CompressFrameZLib(const uint8_t *Cursor, size_t CursorSize, uint8_t **OutBuf, size_t *OutSize)
1587 {
1588     err_t Err = ERR_NONE;
1589     z_stream stream;
1590     size_t Count;
1591     array TmpBuf;
1592     int Res;
1593 
1594     memset(&stream,0,sizeof(stream));
1595     if (deflateInit(&stream, 9)!=Z_OK)
1596         return ERR_INVALID_DATA;
1597     stream.next_in = (Bytef*)Cursor;
1598     stream.avail_in = CursorSize;
1599     Count = 0;
1600     ArrayInit(&TmpBuf);
1601     stream.next_out = ARRAYBEGIN(TmpBuf,uint8_t);
1602     do {
1603         Count = stream.next_out - ARRAYBEGIN(TmpBuf,uint8_t);
1604         if (!ArrayResize(&TmpBuf,CursorSize + Count,0))
1605         {
1606             ArrayClear(&TmpBuf);
1607             Err = ERR_OUT_OF_MEMORY;
1608             break;
1609         }
1610         stream.avail_out = ARRAYCOUNT(TmpBuf,uint8_t) - Count;
1611         stream.next_out = ARRAYBEGIN(TmpBuf,uint8_t) + Count;
1612         Res = deflate(&stream, Z_FINISH);
1613     } while (stream.avail_out==0 && Res!=Z_STREAM_END);
1614 
1615     if (OutBuf && OutSize)
1616         // TODO: write directly in the output buffer
1617         memcpy(*OutBuf, ARRAYBEGIN(TmpBuf,uint8_t), min(*OutSize, stream.total_out));
1618     ArrayClear(&TmpBuf);
1619 
1620     if (OutSize)
1621         *OutSize = stream.total_out;
1622 
1623     deflateEnd(&stream);
1624 
1625     return Err;
1626 }
1627 #endif // CONFIG_EBML_WRITING
1628 #endif // CONFIG_ZLIB
1629 
GetBlockFrameSize(const matroska_block * Element,size_t Frame,const ebml_element * Header,int CompScope)1630 static filepos_t GetBlockFrameSize(const matroska_block *Element, size_t Frame, const ebml_element *Header, int CompScope)
1631 {
1632     if (Frame >= ARRAYCOUNT(Element->SizeList,int32_t))
1633         return 0;
1634 
1635     if (!Header || (CompScope & MATROSKA_COMPR_SCOPE_BLOCK)==0)
1636         return ARRAYBEGIN(Element->SizeList,int32_t)[Frame];
1637     if (Header->Context==&MATROSKA_ContextContentCompAlgo)
1638     {
1639         // handle zlib
1640         size_t OutSize;
1641         const int32_t *Size = ARRAYBEGIN(Element->SizeList,int32_t);
1642         const uint8_t *Data = ARRAYBEGIN(Element->Data,uint8_t);
1643         while (Frame)
1644         {
1645             Data += *Size;
1646             ++Size;
1647             --Frame;
1648         }
1649         OutSize = *Size;
1650         assert(Element->Base.Base.bValueIsSet);
1651 #if defined(CONFIG_EBML_WRITING) && defined(CONFIG_ZLIB)
1652         if (!Element->Base.Base.bValueIsSet || CompressFrameZLib(Data,*Size,NULL,&OutSize)!=ERR_NONE)
1653 #else
1654         if (!Element->Base.Base.bValueIsSet)
1655 #endif
1656             return *Size; // we can't tell the final size without decoding the data
1657         return OutSize;
1658     }
1659     return ARRAYBEGIN(Element->SizeList,int32_t)[Frame] - Header->DataSize; // header stripping
1660 }
1661 
1662 #if defined(CONFIG_EBML_WRITING)
GetBestLacingType(const matroska_block * Element)1663 static char GetBestLacingType(const matroska_block *Element)
1664 {
1665 	int XiphLacingSize, EbmlLacingSize;
1666     size_t i;
1667     int32_t DataSize;
1668     ebml_element *Elt, *Elt2, *Header = NULL;
1669     int CompressionScope = MATROSKA_COMPR_SCOPE_BLOCK;
1670 
1671 	if (ARRAYCOUNT(Element->SizeList,int32_t) <= 1)
1672 		return LACING_NONE;
1673 
1674     DataSize = ARRAYBEGIN(Element->SizeList,int32_t)[0];
1675     for (i=1;i<ARRAYCOUNT(Element->SizeList,int32_t);++i)
1676     {
1677         if (ARRAYBEGIN(Element->SizeList,int32_t)[i]!=DataSize)
1678             break;
1679     }
1680     if (i==ARRAYCOUNT(Element->SizeList,int32_t))
1681         return LACING_FIXED;
1682 
1683     // find out if compressed headers are used
1684     assert(Element->WriteTrack!=NULL);
1685     Elt = EBML_MasterFindChild(Element->WriteTrack, &MATROSKA_ContextContentEncodings);
1686     if (Elt)
1687     {
1688         Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncoding);
1689         if (EBML_MasterChildren(Elt))
1690         {
1691             if (EBML_MasterNext(Elt))
1692                 return 0; // TODO support cascaded compression/encryption
1693 
1694             Elt2 = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncodingScope);
1695             if (Elt2)
1696                 CompressionScope = EBML_IntegerValue((ebml_integer*)Elt2);
1697 
1698             Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompression);
1699             if (!Elt)
1700                 return 0; // TODO: support encryption
1701 
1702             Header = EBML_MasterGetChild((ebml_master*)Elt, &MATROSKA_ContextContentCompAlgo);
1703 #if defined(CONFIG_ZLIB)
1704             if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER && EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_ZLIB)
1705 #else
1706             if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER)
1707 #endif
1708                 return 0;
1709 
1710             if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_HEADER)
1711                 Header = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompSettings);
1712         }
1713     }
1714 
1715     XiphLacingSize = 0;
1716     for (i=0;i<ARRAYCOUNT(Element->SizeList,int32_t)-1;++i)
1717     {
1718         DataSize = (int32_t)GetBlockFrameSize(Element, i, Header, CompressionScope);
1719         while (DataSize >= 0xFF)
1720         {
1721             XiphLacingSize++;
1722             DataSize -= 0xFF;
1723         }
1724         XiphLacingSize++;
1725     }
1726 
1727     EbmlLacingSize = EBML_CodedSizeLength(GetBlockFrameSize(Element, 0, Header, CompressionScope),0,1);
1728     for (i=1;i<ARRAYCOUNT(Element->SizeList,int32_t)-1;++i)
1729     {
1730         DataSize = (int32_t)GetBlockFrameSize(Element, i, Header, CompressionScope) - DataSize;
1731         EbmlLacingSize += EBML_CodedSizeLengthSigned(DataSize,0);
1732     }
1733 
1734     if (XiphLacingSize < EbmlLacingSize)
1735 		return LACING_XIPH;
1736 	else
1737 		return LACING_EBML;
1738 }
1739 
RenderBlockData(matroska_block * Element,stream * Output,bool_t bForceWithoutMandatory,bool_t bWithDefault,filepos_t * Rendered)1740 static err_t RenderBlockData(matroska_block *Element, stream *Output, bool_t bForceWithoutMandatory, bool_t bWithDefault, filepos_t *Rendered)
1741 {
1742     err_t Err = ERR_NONE;
1743     uint8_t BlockHead[5], *Cursor;
1744     size_t ToWrite, Written, BlockHeadSize = 4;
1745     ebml_element *Elt, *Elt2, *Header = NULL;
1746     int32_t *i;
1747     int CompressionScope = MATROSKA_COMPR_SCOPE_BLOCK;
1748     assert(Element->Lacing != LACING_AUTO);
1749 
1750     if (Element->TrackNumber < 0x80)
1751     {
1752         BlockHead[0] = 0x80 | (Element->TrackNumber & 0xFF);
1753         Cursor = &BlockHead[1];
1754     }
1755     else if (Element->TrackNumber < 0x4000)
1756     {
1757         BlockHead[0] = 0x40 | (Element->TrackNumber >> 8);
1758         BlockHead[1] = Element->TrackNumber & 0xFF;
1759         Cursor = &BlockHead[2];
1760         BlockHeadSize = 5;
1761     }
1762     else
1763         return ERR_INVALID_DATA;
1764 
1765     STORE16BE(Cursor,Element->LocalTimecode);
1766     Cursor += 2;
1767 
1768     *Cursor = 0;
1769     if (Element->Invisible)
1770         *Cursor |= 0x08;
1771     *Cursor |= Element->Lacing << 1;
1772     if (EBML_ElementIsType((ebml_element*)Element, &MATROSKA_ContextSimpleBlock))
1773     {
1774         if (Element->IsKeyframe)
1775             *Cursor |= 0x80;
1776         if (Element->IsDiscardable)
1777             *Cursor |= 0x01;
1778     }
1779 
1780     Err = Stream_Write(Output,BlockHead,BlockHeadSize,&Written);
1781     if (Err != ERR_NONE)
1782         goto failed;
1783     if (Written != BlockHeadSize)
1784     {
1785         Err = ERR_WRITE;
1786         goto failed;
1787     }
1788     if (Rendered)
1789         *Rendered = Written;
1790 
1791     assert(Element->WriteTrack!=NULL);
1792     Elt = EBML_MasterFindChild(Element->WriteTrack, &MATROSKA_ContextContentEncodings);
1793     if (Elt)
1794     {
1795         Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncoding);
1796         if (EBML_MasterChildren(Elt))
1797         {
1798             if (EBML_MasterNext(Elt))
1799                 return ERR_INVALID_DATA; // TODO support cascaded compression/encryption
1800 
1801             Elt2 = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncodingScope);
1802             if (Elt2)
1803                 CompressionScope = EBML_IntegerValue((ebml_integer*)Elt2);
1804 
1805             Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompression);
1806             if (!Elt)
1807                 return ERR_INVALID_DATA; // TODO: support encryption
1808 
1809             Header = EBML_MasterGetChild((ebml_master*)Elt, &MATROSKA_ContextContentCompAlgo);
1810 #if defined(CONFIG_ZLIB)
1811             if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER && EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_ZLIB)
1812 #else
1813             if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER)
1814 #endif
1815 			{
1816 				Err = ERR_NOT_SUPPORTED;
1817 				goto failed;
1818 			}
1819 
1820             if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_HEADER)
1821                 Header = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompSettings);
1822         }
1823     }
1824 
1825 #if !defined(CONFIG_ZLIB)
1826     if (Header && Header->Context==&MATROSKA_ContextContentCompAlgo)
1827     {
1828         Err = ERR_NOT_SUPPORTED;
1829         goto failed;
1830     }
1831 #endif
1832 
1833     if (Element->Lacing == LACING_AUTO)
1834         Element->Lacing = GetBestLacingType(Element);
1835     if (Element->Lacing != LACING_NONE)
1836     {
1837         uint8_t *LaceHead = malloc(1 + ARRAYCOUNT(Element->SizeList,int32_t)*4);
1838         size_t i,LaceSize = 1;
1839         int32_t DataSize, PrevSize;
1840         if (!LaceHead)
1841         {
1842             Err = ERR_OUT_OF_MEMORY;
1843             goto failed;
1844         }
1845         LaceHead[0] = (ARRAYCOUNT(Element->SizeList,int32_t)-1) & 0xFF; // number of elements in the lace
1846         if (Element->Lacing == LACING_EBML)
1847         {
1848             DataSize = (int32_t)GetBlockFrameSize(Element, 0, Header, CompressionScope);
1849             LaceSize += EBML_CodedValueLength(DataSize,EBML_CodedSizeLength(DataSize,0,1),LaceHead+LaceSize, 1);
1850             for (i=1;i<ARRAYCOUNT(Element->SizeList,int32_t)-1;++i)
1851             {
1852                 PrevSize = DataSize;
1853                 DataSize = (int32_t)GetBlockFrameSize(Element, i, Header, CompressionScope);
1854                 LaceSize += EBML_CodedValueLengthSigned(DataSize-PrevSize,EBML_CodedSizeLengthSigned(DataSize-PrevSize,0),LaceHead+LaceSize);
1855             }
1856         }
1857         else if (Element->Lacing == LACING_XIPH)
1858         {
1859             for (i=0;i<ARRAYCOUNT(Element->SizeList,int32_t)-1;++i)
1860             {
1861                 DataSize = (int32_t)GetBlockFrameSize(Element, i, Header, CompressionScope);
1862                 while (DataSize >= 0xFF)
1863                 {
1864                     LaceHead[LaceSize++] = 0xFF;
1865                     DataSize -= 0xFF;
1866                 }
1867                 LaceHead[LaceSize++] = (uint8_t)DataSize;
1868             }
1869         }
1870         else if (Element->Lacing == LACING_FIXED)
1871         {
1872             // nothing to write
1873         }
1874         assert(LaceSize <= (1 + ARRAYCOUNT(Element->SizeList,int32_t)*4));
1875         Err = Stream_Write(Output,LaceHead,LaceSize,&Written);
1876         if (Err != ERR_NONE)
1877             goto failed;
1878         if (Rendered)
1879             *Rendered += Written;
1880         free(LaceHead);
1881     }
1882     Node_SET(Element,MATROSKA_BLOCK_READ_TRACK,&Element->WriteTrack); // now use the write track for consecutive read of the same element
1883 
1884     Cursor = ARRAYBEGIN(Element->Data,uint8_t);
1885     if (Header && (CompressionScope & MATROSKA_COMPR_SCOPE_BLOCK))
1886     {
1887         if (Header && Header->Context==&MATROSKA_ContextContentCompAlgo)
1888         {
1889 #if defined(CONFIG_ZLIB)
1890             uint8_t *OutBuf;
1891             array TmpBuf;
1892             ArrayInit(&TmpBuf);
1893             for (i=ARRAYBEGIN(Element->SizeList,int32_t);i!=ARRAYEND(Element->SizeList,int32_t);++i)
1894             {
1895                 if (!ArrayResize(&TmpBuf,*i + 100,0))
1896                 {
1897                     ArrayClear(&TmpBuf);
1898                     Err = ERR_OUT_OF_MEMORY;
1899                     break;
1900                 }
1901                 OutBuf = ARRAYBEGIN(TmpBuf,uint8_t);
1902                 ToWrite = ARRAYCOUNT(TmpBuf,uint8_t);
1903                 if (CompressFrameZLib(Cursor, *i, &OutBuf, &ToWrite) != ERR_NONE)
1904                 {
1905                     ArrayClear(&TmpBuf);
1906                     Err = ERR_OUT_OF_MEMORY;
1907                     break;
1908                 }
1909 
1910                 Err = Stream_Write(Output,OutBuf,ToWrite,&Written);
1911                 ArrayClear(&TmpBuf);
1912                 if (Rendered)
1913                     *Rendered += Written;
1914                 Cursor += *i;
1915                 if (Err!=ERR_NONE)
1916                     break;
1917             }
1918 #endif
1919         }
1920         else
1921         {
1922             // header compression
1923             for (i=ARRAYBEGIN(Element->SizeList,int32_t);i!=ARRAYEND(Element->SizeList,int32_t);++i)
1924             {
1925                 assert(memcmp(Cursor,ARRAYBEGIN(((ebml_binary*)Header)->Data,uint8_t),(size_t)Header->DataSize)==0);
1926                 if (memcmp(Cursor,ARRAYBEGIN(((ebml_binary*)Header)->Data,uint8_t),(size_t)Header->DataSize)!=0)
1927                 {
1928                     Err = ERR_INVALID_DATA;
1929                     goto failed;
1930                 }
1931                 Cursor += Header->DataSize;
1932                 ToWrite = *i - (size_t)Header->DataSize;
1933                 Err = Stream_Write(Output,Cursor,ToWrite,&Written);
1934                 if (Rendered)
1935                     *Rendered += Written;
1936                 Cursor += Written;
1937             }
1938         }
1939     }
1940     else
1941     {
1942         ToWrite = ARRAYCOUNT(Element->Data,uint8_t);
1943         Err = Stream_Write(Output,Cursor,ToWrite,&Written);
1944         if (Rendered)
1945             *Rendered += Written;
1946     }
1947 
1948 failed:
1949     return Err;
1950 }
1951 #endif
1952 
CopyBlockInfo(const matroska_block * Element,const void * Cookie)1953 static matroska_block *CopyBlockInfo(const matroska_block *Element, const void *Cookie)
1954 {
1955     matroska_block *Result = (matroska_block*)INHERITED(Element,ebml_element_vmt,Node_ClassId(Element))->Copy(Element,Cookie);
1956     if (Result)
1957     {
1958         Result->TrackNumber = Element->TrackNumber;
1959         Result->IsKeyframe = Element->IsKeyframe;
1960         Result->IsDiscardable = Element->IsDiscardable;
1961         Result->Invisible = Element->Invisible;
1962 #if 0 // computed once blocks are added
1963         Result->LocalTimecode = Element->LocalTimecode;
1964         Result->LocalTimecodeUsed = Element->LocalTimecodeUsed;
1965 	    Result->GlobalTimecode = Element->GlobalTimecode;
1966         Result->Lacing = Element->Lacing;
1967         Result->FirstFrameLocation = Element->FirstFrameLocation;
1968         array SizeList = Element->; // int32_t
1969         array Data = Element->; // uint8_t
1970         array Durations = Element->; // timecode_t
1971 #else
1972         Result->Base.Base.bValueIsSet = 0;
1973 #endif
1974         Node_SET(Result,MATROSKA_BLOCK_READ_TRACK,&Element->ReadTrack);
1975         Node_SET(Result,MATROSKA_BLOCK_READ_SEGMENTINFO,&Element->ReadSegInfo);
1976 #if defined(CONFIG_EBML_WRITING)
1977         Node_SET(Result,MATROSKA_BLOCK_WRITE_TRACK,&Element->WriteTrack);
1978         Node_SET(Result,MATROSKA_BLOCK_WRITE_SEGMENTINFO,&Element->WriteSegInfo);
1979 #endif
1980     }
1981     return Result;
1982 }
1983 
UpdateBlockSize(matroska_block * Element,bool_t bWithDefault,bool_t bForceWithoutMandatory)1984 static filepos_t UpdateBlockSize(matroska_block *Element, bool_t bWithDefault, bool_t bForceWithoutMandatory)
1985 {
1986     int CompressionScope = MATROSKA_COMPR_SCOPE_BLOCK;
1987     if (EBML_ElementNeedsDataSizeUpdate(Element, bWithDefault))
1988     {
1989         ebml_element *Header = NULL;
1990 #if defined(CONFIG_EBML_WRITING)
1991         ebml_element *Elt, *Elt2;
1992         if (Element->Lacing == LACING_AUTO)
1993             Element->Lacing = GetBestLacingType(Element);
1994 
1995         assert(Element->WriteTrack!=NULL);
1996         Elt = EBML_MasterFindChild(Element->WriteTrack, &MATROSKA_ContextContentEncodings);
1997         if (Elt)
1998         {
1999             Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncoding);
2000             if (EBML_MasterChildren(Elt))
2001             {
2002                 if (EBML_MasterNext(Elt))
2003                     return ERR_INVALID_DATA; // TODO support cascaded compression/encryption
2004 
2005                 Elt2 = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentEncodingScope);
2006                 if (Elt2)
2007                     CompressionScope = EBML_IntegerValue((ebml_integer*)Elt2);
2008 
2009                 Elt = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompression);
2010                 if (!Elt)
2011                     return ERR_INVALID_DATA; // TODO: support encryption
2012 
2013                 Header = EBML_MasterGetChild((ebml_master*)Elt, &MATROSKA_ContextContentCompAlgo);
2014 #if defined(CONFIG_ZLIB)
2015                 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER && EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_ZLIB)
2016 #else
2017                 if (EBML_IntegerValue((ebml_integer*)Header)!=MATROSKA_BLOCK_COMPR_HEADER)
2018 #endif
2019                     return ERR_INVALID_DATA;
2020 
2021                 if (EBML_IntegerValue((ebml_integer*)Header)==MATROSKA_BLOCK_COMPR_HEADER)
2022                     Header = EBML_MasterFindChild((ebml_master*)Elt, &MATROSKA_ContextContentCompSettings);
2023             }
2024         }
2025 #else
2026         assert(Element->Lacing!=LACING_AUTO);
2027 #endif
2028 
2029         if (Element->Lacing == LACING_NONE)
2030         {
2031             assert(ARRAYCOUNT(Element->SizeList,int32_t) == 1);
2032             Element->Base.Base.DataSize = GetBlockHeadSize(Element) + GetBlockFrameSize(Element,0,Header, CompressionScope);
2033         }
2034         else if (Element->Lacing == LACING_EBML)
2035         {
2036             size_t i;
2037             filepos_t PrevSize, Size;
2038             filepos_t Result = GetBlockHeadSize(Element) + 1; // 1 for the number of frames
2039             Size = GetBlockFrameSize(Element,0,Header, CompressionScope);
2040             Result += EBML_CodedSizeLength(Size,0,1) + Size;
2041             for (i=1;i<ARRAYCOUNT(Element->SizeList,int32_t)-1;++i)
2042             {
2043                 PrevSize = Size;
2044                 Size = GetBlockFrameSize(Element,i,Header, CompressionScope);
2045                 Result += Size + EBML_CodedSizeLengthSigned(Size - PrevSize,0);
2046             }
2047             Result += GetBlockFrameSize(Element,i,Header, CompressionScope);
2048             Element->Base.Base.DataSize = Result;
2049         }
2050         else if (Element->Lacing == LACING_XIPH)
2051         {
2052             size_t i;
2053             filepos_t Size;
2054             filepos_t Result = GetBlockHeadSize(Element) + 1; // 1 for the number of frames
2055             for (i=0;i<ARRAYCOUNT(Element->SizeList,int32_t)-1;++i)
2056             {
2057                 Size = GetBlockFrameSize(Element,i,Header, CompressionScope);
2058                 Result += (Size / 0xFF + 1) + Size;
2059             }
2060             Result += GetBlockFrameSize(Element,i,Header, CompressionScope);
2061             Element->Base.Base.DataSize = Result;
2062         }
2063         else if (Element->Lacing == LACING_FIXED)
2064         {
2065             size_t i;
2066             filepos_t Result = GetBlockHeadSize(Element) + 1; // 1 for the number of frames
2067             for (i=0;i<ARRAYCOUNT(Element->SizeList,int32_t);++i)
2068                 Result += GetBlockFrameSize(Element,i,Header, CompressionScope);
2069             Element->Base.Base.DataSize = Result;
2070         }
2071 #ifdef TODO
2072         char LacingHere;
2073 	    // compute the final size of the data
2074 	    switch (ARRAYCOUNT(Element->SizeList,int32_t))
2075         {
2076 		    case 0:
2077 			    Element->Base.Base.DataSize = 0;
2078 			    break;
2079 		    case 1:
2080 			    Element->Base.Base.DataSize = 4 + *ARRAYBEGIN(Element->SizeList,int32_t);
2081 			    break;
2082 		    default:
2083 			    Element->Base.Base.DataSize = 4 + 1; // 1 for the lacing head
2084 			    if (Element->Lacing == LACING_AUTO)
2085 				    LacingHere = GetBestLacingType(Element);
2086 			    else
2087 				    LacingHere = Element->Lacing;
2088 			    switch (LacingHere)
2089 			    {
2090 			    case LACING_XIPH:
2091 				    for (i=0; i<myBuffers.size()-1; i++) {
2092 					    SetSize_(GetSize() + myBuffers[i]->DataSize() + (myBuffers[i]->DataSize() / 0xFF + 1));
2093 				    }
2094 				    break;
2095 			    case LACING_EBML:
2096 				    SetSize_(GetSize() + myBuffers[0]->DataSize() + CodedSizeLength(myBuffers[0]->DataSize(), 0, IsFiniteSize()));
2097 				    for (i=1; i<myBuffers.size()-1; i++) {
2098 					    SetSize_(GetSize() + myBuffers[i]->DataSize() + CodedSizeLengthSigned(int64(myBuffers[i]->DataSize()) - int64(myBuffers[i-1]->DataSize()), 0));
2099 				    }
2100 				    break;
2101 			    case LACING_FIXED:
2102 				    for (i=0; i<myBuffers.size()-1; i++) {
2103 					    SetSize_(GetSize() + myBuffers[i]->DataSize());
2104 				    }
2105 				    break;
2106 			    default:
2107 				    assert(0);
2108 			    }
2109 			    // DataSize of the last frame (not in lace)
2110 			    SetSize_(GetSize() + myBuffers[i]->DataSize());
2111 			    break;
2112 	    }
2113 
2114 	    if (Element->Base.Base.DataSize && Element->TrackNumber >= 0x80)
2115 		    ++Element->Base.Base.DataSize; // the size will be coded with one more octet
2116 #endif
2117     }
2118 
2119     // skip the EBML_BINARY_CLASS version as we have another internal buffer
2120 	return INHERITED(Element,ebml_element_vmt,EBML_BINARY_CLASS)->UpdateDataSize(Element, bWithDefault, bForceWithoutMandatory);
2121 }
2122 
CmpCuePoint(const matroska_cuepoint * a,const matroska_cuepoint * b)2123 static int CmpCuePoint(const matroska_cuepoint* a,const matroska_cuepoint* b)
2124 {
2125 	// returns a > b
2126     timecode_t TA = MATROSKA_CueTimecode(a);
2127     timecode_t TB = MATROSKA_CueTimecode(b);
2128     int NA,NB;
2129     if (TB < TA)
2130         return 1;
2131     if (TB > TA)
2132         return -1;
2133     NA = MATROSKA_CueTrackNum(a);
2134     NB = MATROSKA_CueTrackNum(b);
2135     if (NB < NA)
2136         return 1;
2137     if (NB > NA)
2138         return -1;
2139     return 0;
2140 }
2141 
CmpAttachedFile(const ebml_master * a,const ebml_master * b)2142 static int CmpAttachedFile(const ebml_master* a,const ebml_master* b)
2143 {
2144 	// returns a > b
2145 	// sort cover art names according to http://www.matroska.org/technical/cover_art/index.html
2146 	tchar_t FilenameA[MAXPATH];
2147 	tchar_t FilenameB[MAXPATH];
2148 	bool_t CoverA=0,CoverB=0;
2149 	bool_t LandCoverA=0,LandCoverB=0;
2150 	bool_t SmallCoverA=0,SmallCoverB=0;
2151 	ebml_element *NameA = EBML_MasterFindChild(a,&MATROSKA_ContextFileName);
2152 	ebml_element *NameB = EBML_MasterFindChild(b,&MATROSKA_ContextFileName);
2153 
2154 	if (NameB==NULL)
2155 		return -1;
2156 	if (NameA==NULL)
2157 		return 1;
2158 
2159 	EBML_StringGet((ebml_string*)NameA,FilenameA,TSIZEOF(FilenameA));
2160 	EBML_StringGet((ebml_string*)NameB,FilenameB,TSIZEOF(FilenameB));
2161 
2162 	if (tcsisame_ascii(FilenameA, T("cover.jpg")) || tcsisame_ascii(FilenameA, T("cover.png")))
2163 		CoverA = 1;
2164 	else if (tcsisame_ascii(FilenameA, T("cover_land.jpg")) || tcsisame_ascii(FilenameA, T("cover_land.png")))
2165 		LandCoverA = 1;
2166 	else if (tcsisame_ascii(FilenameA, T("small_cover.jpg")) || tcsisame_ascii(FilenameA, T("small_cover.png")))
2167 	{
2168 		CoverA = 1;
2169 		SmallCoverA = 1;
2170 	}
2171 	else if (tcsisame_ascii(FilenameA, T("small_cover_land.jpg")) || tcsisame_ascii(FilenameA, T("small_cover_land.png")))
2172 	{
2173 		LandCoverA = 1;
2174 		SmallCoverA = 1;
2175 	}
2176 
2177 	if (tcsisame_ascii(FilenameB, T("cover.jpg")) || tcsisame_ascii(FilenameB, T("cover.png")))
2178 		CoverB = 1;
2179 	else if (tcsisame_ascii(FilenameB, T("cover_land.jpg")) || tcsisame_ascii(FilenameB, T("cover_land.png")))
2180 		LandCoverB = 1;
2181 	else if (tcsisame_ascii(FilenameB, T("small_cover.jpg")) || tcsisame_ascii(FilenameB, T("small_cover.png")))
2182 	{
2183 		CoverB = 1;
2184 		SmallCoverB = 1;
2185 	}
2186 	else if (tcsisame_ascii(FilenameB, T("small_cover_land.jpg")) || tcsisame_ascii(FilenameB, T("small_cover_land.png")))
2187 	{
2188 		LandCoverB = 1;
2189 		SmallCoverB = 1;
2190 	}
2191 
2192 	if (!CoverA && !CoverB && !LandCoverA && !LandCoverB)
2193 		return tcscmp(FilenameA,FilenameB);
2194 
2195 	// cover.jpg comes first
2196 	if (CoverA && !SmallCoverA)
2197 		return -1;
2198 	if (CoverB && !SmallCoverB)
2199 		return 1;
2200 	if (CoverA == CoverB || LandCoverA == LandCoverB)
2201 		return SmallCoverA - SmallCoverB;
2202 	if (CoverA || LandCoverA)
2203 	{
2204 		if (CoverB)
2205 			return 1;
2206 		return -1;
2207 	}
2208 
2209 	if (CoverA)
2210 		return -1;
2211 	return 1;
2212 }
2213 
MATROSKA_CuesGetTimecodeStart(const ebml_element * Cues,timecode_t Timecode)2214 matroska_cuepoint *MATROSKA_CuesGetTimecodeStart(const ebml_element *Cues, timecode_t Timecode)
2215 {
2216 	matroska_cuepoint *Elt,*Prev=NULL;
2217 
2218 	assert(Cues!=NULL);
2219 	assert(EBML_ElementIsType(Cues, &MATROSKA_ContextCues));
2220 	if (Timecode==INVALID_TIMECODE_T)
2221 		return NULL;
2222 
2223 	for (Elt=(matroska_cuepoint*)EBML_MasterChildren(Cues);Elt;Prev=Elt, Elt=(matroska_cuepoint*)EBML_MasterNext(Elt))
2224 	{
2225 		if (MATROSKA_CueTimecode(Elt) > Timecode)
2226 			break;
2227 	}
2228 
2229 	return Prev ? Prev : (matroska_cuepoint*)EBML_MasterChildren(Cues);
2230 }
2231 
ValidateSizeSegUID(const ebml_binary * p)2232 static bool_t ValidateSizeSegUID(const ebml_binary *p)
2233 {
2234     uint8_t test[16];
2235 	if (p->Base.DataSize != 16 || !EBML_ElementIsFiniteSize((const ebml_element *)p))
2236         return 0;
2237     if (!p->Base.bValueIsSet)
2238         return 1;
2239     memset(test,0,sizeof(test));
2240     return memcmp(ARRAYBEGIN(p->Data,uint8_t),test,16)!=0; // make sure the value is not 0
2241 }
2242 
CreateBlock(matroska_block * p)2243 static err_t CreateBlock(matroska_block *p)
2244 {
2245 	p->GlobalTimecode = INVALID_TIMECODE_T;
2246 	return ERR_NONE;
2247 }
2248 
CreateCluster(matroska_cluster * p)2249 static err_t CreateCluster(matroska_cluster *p)
2250 {
2251 	p->GlobalTimecode = INVALID_TIMECODE_T;
2252     return ERR_NONE;
2253 }
2254 
ReadTrackEntry(matroska_trackentry * Element,stream * Input,const ebml_parser_context * ParserContext,bool_t AllowDummyElt,int Scope,size_t DepthCheckCRC)2255 static err_t ReadTrackEntry(matroska_trackentry *Element, stream *Input, const ebml_parser_context *ParserContext, bool_t AllowDummyElt, int Scope, size_t DepthCheckCRC)
2256 {
2257     err_t Result = INHERITED(Element,ebml_element_vmt,MATROSKA_TRACKENTRY_CLASS)->ReadData(Element, Input, ParserContext, AllowDummyElt, Scope, DepthCheckCRC);
2258     if (Result==ERR_NONE)
2259     {
2260         ebml_element *Encodings = EBML_MasterFindChild(Element,&MATROSKA_ContextContentEncodings);
2261         if (Encodings)
2262         {
2263             ebml_element *Elt2 = EBML_MasterFindChild((ebml_master*)Encodings,&MATROSKA_ContextContentEncoding);
2264             if (Elt2)
2265             {
2266                 ebml_element *Elt =  EBML_MasterFindChild((ebml_master*)Elt2,&MATROSKA_ContextContentCompression);
2267                 if (Elt)
2268                 {
2269                     ebml_integer *Scope =  (ebml_integer*)EBML_MasterFindChild((ebml_master*)Elt2,&MATROSKA_ContextContentEncodingScope);
2270                     Element->CodecPrivateCompressed = Scope && (EBML_IntegerValue(Scope) & MATROSKA_COMPR_SCOPE_PRIVATE)!=0;
2271                 }
2272             }
2273         }
2274     }
2275     return Result;
2276 }
2277 
UpdateDataSizeTrackEntry(matroska_trackentry * Element,bool_t bWithDefault,bool_t bForceWithoutMandatory)2278 static filepos_t UpdateDataSizeTrackEntry(matroska_trackentry *Element, bool_t bWithDefault, bool_t bForceWithoutMandatory)
2279 {
2280 #if defined(CONFIG_ZLIB)
2281     bool_t CodecPrivateCompressed = 0;
2282     ebml_integer *Scope = NULL;
2283     ebml_element *Encodings = EBML_MasterFindChild(Element,&MATROSKA_ContextContentEncodings);
2284     if (Encodings)
2285     {
2286         ebml_element *Elt2 = EBML_MasterFindChild((ebml_master*)Encodings,&MATROSKA_ContextContentEncoding);
2287         if (Elt2)
2288         {
2289             ebml_element *Elt =  EBML_MasterFindChild((ebml_master*)Elt2,&MATROSKA_ContextContentCompression);
2290             if (Elt)
2291             {
2292                 Scope = (ebml_integer*)EBML_MasterFindChild((ebml_master*)Elt2,&MATROSKA_ContextContentEncodingScope);
2293                 CodecPrivateCompressed = Scope && (EBML_IntegerValue(Scope) & MATROSKA_COMPR_SCOPE_PRIVATE)!=0;
2294             }
2295         }
2296     }
2297 
2298     if (CodecPrivateCompressed != Element->CodecPrivateCompressed)
2299     {
2300         ebml_binary *CodecPrivate = (ebml_binary*)EBML_MasterFindChild(Element,&MATROSKA_ContextCodecPrivate);
2301         if (!Element->CodecPrivateCompressed)
2302         {
2303             // compress the codec private
2304             if (CodecPrivate)
2305             {
2306                 size_t CompressedSize = ARRAYCOUNT(CodecPrivate->Data,uint8_t);
2307                 uint8_t *Compressed = malloc(CompressedSize);
2308                 if (CompressFrameZLib(ARRAYBEGIN(CodecPrivate->Data,uint8_t), (size_t)CodecPrivate->Base.DataSize, &Compressed, &CompressedSize)==ERR_NONE)
2309                 {
2310                     if (EBML_BinarySetData(CodecPrivate, Compressed, CompressedSize)==ERR_NONE)
2311                         Element->CodecPrivateCompressed = 1;
2312                 }
2313                 free(Compressed);
2314             }
2315             if (!Element->CodecPrivateCompressed)
2316                 EBML_IntegerSetValue(Scope, EBML_IntegerValue(Scope) ^ MATROSKA_COMPR_SCOPE_PRIVATE);
2317         }
2318         else
2319         {
2320             if (CodecPrivate)
2321             {
2322                 size_t CompressedSize = ARRAYCOUNT(CodecPrivate->Data,uint8_t);
2323                 size_t Offset = 0;
2324                 array Compressed;
2325 
2326                 ArrayInit(&Compressed);
2327                 if (UnCompressFrameZLib(ARRAYBEGIN(CodecPrivate->Data,uint8_t), (size_t)CodecPrivate->Base.DataSize, &Compressed, &CompressedSize, &Offset)==ERR_NONE)
2328                 {
2329                     if (EBML_BinarySetData(CodecPrivate, ARRAYBEGIN(Compressed,uint8_t), CompressedSize)==ERR_NONE)
2330                         Element->CodecPrivateCompressed = 0;
2331                 }
2332                 ArrayClear(&Compressed);
2333             }
2334             else
2335                 Element->CodecPrivateCompressed = 0;
2336             if (Element->CodecPrivateCompressed)
2337             {
2338                 // TODO: add in the Compression header that the header is still compressed
2339             }
2340         }
2341     }
2342 #endif
2343     return INHERITED(Element,ebml_element_vmt,MATROSKA_TRACKENTRY_CLASS)->UpdateDataSize(Element, bWithDefault, bForceWithoutMandatory);
2344 }
2345 
CopyTrackEntry(const matroska_trackentry * Element,const void * Cookie)2346 static matroska_trackentry *CopyTrackEntry(const matroska_trackentry *Element, const void *Cookie)
2347 {
2348     matroska_trackentry *Result = (matroska_trackentry*)INHERITED(Element,ebml_element_vmt,MATROSKA_TRACKENTRY_CLASS)->Copy(Element, Cookie);
2349     if (Result)
2350         Result->CodecPrivateCompressed = Element->CodecPrivateCompressed;
2351     return Result;
2352 }
2353 
2354 
MATROSKA_TrackGetBlockCompression(const matroska_trackentry * TrackEntry)2355 int MATROSKA_TrackGetBlockCompression(const matroska_trackentry *TrackEntry)
2356 {
2357     ebml_element *Encodings, *Elt, *Elt2;
2358     assert(Node_IsPartOf(TrackEntry, MATROSKA_TRACKENTRY_CLASS));
2359     Encodings = EBML_MasterFindChild(TrackEntry,&MATROSKA_ContextContentEncodings);
2360     if (!Encodings)
2361         return MATROSKA_BLOCK_COMPR_NONE;
2362     Elt2 = EBML_MasterFindChild((ebml_master*)Encodings,&MATROSKA_ContextContentEncoding);
2363     if (!Elt2)
2364         return MATROSKA_BLOCK_COMPR_NONE;
2365     Elt =  EBML_MasterGetChild((ebml_master*)Elt2,&MATROSKA_ContextContentEncodingScope);
2366     if (!(EBML_IntegerValue((ebml_integer*)Elt) & MATROSKA_COMPR_SCOPE_BLOCK))
2367         return MATROSKA_BLOCK_COMPR_NONE;
2368     Elt =  EBML_MasterFindChild((ebml_master*)Elt2,&MATROSKA_ContextContentCompression);
2369     if (!Elt)
2370         return MATROSKA_BLOCK_COMPR_NONE;
2371     Elt2 = EBML_MasterGetChild((ebml_master*)Elt,&MATROSKA_ContextContentCompAlgo);
2372     return (int)EBML_IntegerValue((ebml_integer*)Elt2);
2373 }
2374 
MATROSKA_TrackSetCompressionZlib(matroska_trackentry * TrackEntry,int Scope)2375 bool_t MATROSKA_TrackSetCompressionZlib(matroska_trackentry *TrackEntry, int Scope)
2376 {
2377     // force zlib compression
2378     bool_t HadEncoding;
2379     ebml_element *Encodings, *Elt, *Elt2;
2380     assert(Node_IsPartOf(TrackEntry, MATROSKA_TRACKENTRY_CLASS));
2381     // remove the previous compression and the new optimized one
2382     Encodings = EBML_MasterFindChild(TrackEntry,&MATROSKA_ContextContentEncodings);
2383     HadEncoding = Encodings!=NULL;
2384     if (Encodings!=NULL)
2385         NodeDelete((node*)Encodings);
2386 
2387     if (Scope!=0)
2388     {
2389         Encodings = EBML_MasterGetChild((ebml_master*)TrackEntry,&MATROSKA_ContextContentEncodings);
2390         Elt2 = EBML_MasterGetChild((ebml_master*)Encodings,&MATROSKA_ContextContentEncoding);
2391 
2392         Elt =  EBML_MasterGetChild((ebml_master*)Elt2,&MATROSKA_ContextContentEncodingScope);
2393         EBML_IntegerSetValue((ebml_integer*)Elt, Scope);
2394 
2395         Elt =  EBML_MasterGetChild((ebml_master*)Elt2,&MATROSKA_ContextContentCompression);
2396         Elt2 = EBML_MasterGetChild((ebml_master*)Elt,&MATROSKA_ContextContentCompAlgo);
2397         EBML_IntegerSetValue((ebml_integer*)Elt2, MATROSKA_BLOCK_COMPR_ZLIB);
2398     }
2399     return HadEncoding;
2400 }
2401 
MATROSKA_TrackSetCompressionHeader(matroska_trackentry * TrackEntry,const uint8_t * Header,size_t HeaderSize)2402 bool_t MATROSKA_TrackSetCompressionHeader(matroska_trackentry *TrackEntry, const uint8_t *Header, size_t HeaderSize)
2403 {
2404     bool_t HadEncoding;
2405     ebml_element *Encodings, *Elt, *Elt2;
2406     assert(Node_IsPartOf(TrackEntry, MATROSKA_TRACKENTRY_CLASS));
2407     // remove the previous compression and the new optimized one
2408     Encodings = EBML_MasterFindChild(TrackEntry,&MATROSKA_ContextContentEncodings);
2409     HadEncoding = Encodings!=NULL;
2410     if (Encodings!=NULL)
2411         NodeDelete((node*)Encodings);
2412 
2413     if (Header && HeaderSize)
2414     {
2415         Encodings = EBML_MasterGetChild((ebml_master*)TrackEntry,&MATROSKA_ContextContentEncodings);
2416         Elt2 = EBML_MasterGetChild((ebml_master*)Encodings,&MATROSKA_ContextContentEncoding);
2417 
2418         Elt =  EBML_MasterGetChild((ebml_master*)Elt2,&MATROSKA_ContextContentCompression);
2419         Elt2 = EBML_MasterGetChild((ebml_master*)Elt,&MATROSKA_ContextContentCompAlgo);
2420         EBML_IntegerSetValue((ebml_integer*)Elt2, MATROSKA_BLOCK_COMPR_HEADER);
2421         Elt2 = EBML_MasterGetChild((ebml_master*)Elt,&MATROSKA_ContextContentCompSettings);
2422         EBML_BinarySetData((ebml_binary*)Elt2, Header, HeaderSize);
2423     }
2424     return HadEncoding;
2425 }
2426 
MATROSKA_TrackSetCompressionNone(matroska_trackentry * TrackEntry)2427 bool_t MATROSKA_TrackSetCompressionNone(matroska_trackentry *TrackEntry)
2428 {
2429     ebml_element *Encodings = EBML_MasterFindChild(TrackEntry,&MATROSKA_ContextContentEncodings);
2430     assert(Node_IsPartOf(TrackEntry, MATROSKA_TRACKENTRY_CLASS));
2431     if (!Encodings)
2432         return 0;
2433     NodeDelete((node*)Encodings);
2434     return 1;
2435 }
2436 
2437 
2438 META_START(Matroska_Class,MATROSKA_BLOCK_CLASS)
2439 META_CLASS(SIZE,sizeof(matroska_block))
2440 META_CLASS(CREATE,CreateBlock)
2441 META_VMT(TYPE_FUNC,nodetree_vmt,SetParent,SetBlockParent)
2442 META_VMT(TYPE_FUNC,ebml_element_vmt,ReadData,ReadBlockData)
2443 META_VMT(TYPE_FUNC,ebml_element_vmt,UpdateDataSize,UpdateBlockSize)
2444 #if defined(CONFIG_EBML_WRITING)
2445 META_VMT(TYPE_FUNC,ebml_element_vmt,RenderData,RenderBlockData)
2446 #endif
2447 META_VMT(TYPE_FUNC,ebml_element_vmt,Copy,CopyBlockInfo)
2448 META_DATA(TYPE_ARRAY,0,matroska_block,SizeList)
2449 META_DATA(TYPE_ARRAY,0,matroska_block,SizeListIn)
2450 META_DATA(TYPE_ARRAY,0,matroska_block,Data)
2451 META_DATA(TYPE_ARRAY,0,matroska_block,Durations)
2452 META_PARAM(TYPE,MATROSKA_BLOCK_READ_TRACK,TYPE_NODE)
2453 META_DATA_UPDATE_CMP(TYPE_NODE_REF,MATROSKA_BLOCK_READ_TRACK,matroska_block,ReadTrack,BlockTrackChanged)
2454 META_PARAM(TYPE,MATROSKA_BLOCK_READ_SEGMENTINFO,TYPE_NODE)
2455 META_DATA_UPDATE_CMP(TYPE_NODE_REF,MATROSKA_BLOCK_READ_SEGMENTINFO,matroska_block,ReadSegInfo,BlockTrackChanged)
2456 #if defined(CONFIG_EBML_WRITING)
2457 META_PARAM(TYPE,MATROSKA_BLOCK_WRITE_TRACK,TYPE_NODE)
2458 META_DATA_UPDATE_CMP(TYPE_NODE_REF,MATROSKA_BLOCK_WRITE_TRACK,matroska_block,WriteTrack,BlockTrackChanged)
2459 META_PARAM(TYPE,MATROSKA_BLOCK_WRITE_SEGMENTINFO,TYPE_NODE)
2460 META_DATA_UPDATE_CMP(TYPE_NODE_REF,MATROSKA_BLOCK_WRITE_SEGMENTINFO,matroska_block,WriteSegInfo,BlockTrackChanged)
2461 #endif
2462 META_END_CONTINUE(EBML_BINARY_CLASS)
2463 
2464 META_START_CONTINUE(MATROSKA_BLOCKGROUP_CLASS)
2465 META_VMT(TYPE_FUNC,nodetree_vmt,SetParent,SetBlockGroupParent)
2466 META_END_CONTINUE(EBML_MASTER_CLASS)
2467 
2468 META_START_CONTINUE(MATROSKA_BIGBINARY_CLASS)
2469 META_VMT(TYPE_FUNC,ebml_element_vmt,ReadData,ReadBigBinaryData)
2470 META_END_CONTINUE(EBML_BINARY_CLASS)
2471 
2472 META_START_CONTINUE(MATROSKA_CUEPOINT_CLASS)
2473 META_CLASS(SIZE,sizeof(matroska_cuepoint))
2474 META_VMT(TYPE_FUNC,ebml_element_vmt,Cmp,CmpCuePoint)
2475 META_PARAM(TYPE,MATROSKA_CUE_SEGMENTINFO,TYPE_NODE)
2476 META_DATA(TYPE_NODE_REF,MATROSKA_CUE_SEGMENTINFO,matroska_cuepoint,SegInfo)
2477 META_PARAM(TYPE,MATROSKA_CUE_BLOCK,TYPE_NODE)
2478 META_DATA(TYPE_NODE_REF,MATROSKA_CUE_BLOCK,matroska_cuepoint,Block)
2479 META_END_CONTINUE(EBML_MASTER_CLASS)
2480 
2481 META_START_CONTINUE(MATROSKA_CLUSTER_CLASS)
2482 META_CLASS(SIZE,sizeof(matroska_cluster))
2483 META_CLASS(CREATE,CreateCluster)
2484 META_PARAM(TYPE,MATROSKA_CLUSTER_READ_SEGMENTINFO,TYPE_NODE)
2485 META_DATA(TYPE_NODE_REF,MATROSKA_CLUSTER_READ_SEGMENTINFO,matroska_cluster,ReadSegInfo)
2486 META_PARAM(TYPE,MATROSKA_CLUSTER_WRITE_SEGMENTINFO,TYPE_NODE)
2487 META_DATA_UPDATE_CMP(TYPE_NODE_REF,MATROSKA_CLUSTER_WRITE_SEGMENTINFO,matroska_cluster,WriteSegInfo,ClusterTimeChanged)
2488 META_END_CONTINUE(EBML_MASTER_CLASS)
2489 
2490 META_START_CONTINUE(MATROSKA_SEEKPOINT_CLASS)
2491 META_CLASS(SIZE,sizeof(matroska_seekpoint))
2492 META_PARAM(TYPE,MATROSKA_SEEKPOINT_ELEMENT,TYPE_NODE)
2493 META_DATA(TYPE_NODE_REF,MATROSKA_SEEKPOINT_ELEMENT,matroska_seekpoint,Link)
2494 META_END_CONTINUE(EBML_MASTER_CLASS)
2495 
2496 META_START_CONTINUE(MATROSKA_TRACKENTRY_CLASS)
2497 META_CLASS(SIZE,sizeof(matroska_trackentry))
2498 META_VMT(TYPE_FUNC,ebml_element_vmt,ReadData,ReadTrackEntry)
2499 META_VMT(TYPE_FUNC,ebml_element_vmt,UpdateDataSize,UpdateDataSizeTrackEntry)
2500 META_VMT(TYPE_FUNC,ebml_element_vmt,Copy,CopyTrackEntry)
2501 META_END_CONTINUE(EBML_MASTER_CLASS)
2502 
2503 META_START_CONTINUE(MATROSKA_SEGMENTUID_CLASS)
2504 META_VMT(TYPE_FUNC,ebml_element_vmt,ValidateSize,ValidateSizeSegUID)
2505 META_END_CONTINUE(EBML_BINARY_CLASS)
2506 
2507 META_START_CONTINUE(MATROSKA_ATTACHMENT_CLASS)
2508 META_VMT(TYPE_FUNC,ebml_element_vmt,Cmp,CmpAttachedFile)
2509 META_END(EBML_MASTER_CLASS)
2510