1 /*
2  * $Id$
3  * Copyright (c) 2008-2010, Matroska (non-profit organisation)
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *     * Redistributions of source code must retain the above copyright
9  *       notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above copyright
11  *       notice, this list of conditions and the following disclaimer in the
12  *       documentation and/or other materials provided with the distribution.
13  *     * Neither the name of the Matroska assocation nor the
14  *       names of its contributors may be used to endorse or promote products
15  *       derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY the Matroska association ``AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL The Matroska Foundation BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 #include "ebml/ebml.h"
29 #include "ebml/ebml_internal.h"
30 #include "ebmlcrc.h"
31 
EBML_MasterAddElt(ebml_master * Element,const ebml_context * Context,bool_t SetDefault)32 ebml_element *EBML_MasterAddElt(ebml_master *Element, const ebml_context *Context, bool_t SetDefault)
33 {
34     ebml_element *i;
35 #if !defined(NDEBUG)
36     // check if the sub Context is legal in this Element
37     bool_t IsLegal = 0;
38     const ebml_semantic * Semantic;
39     const ebml_context *ParentContext = Element->Base.Context;
40     for (Semantic=ParentContext->Semantic;Semantic->eClass;Semantic++)
41     {
42         if (Semantic->eClass->Id == Context->Id)
43         {
44             IsLegal = 1;
45             break;
46         }
47     }
48     if (!IsLegal)
49     {
50         for (Semantic=ParentContext->GlobalContext;Semantic->eClass;Semantic++)
51         {
52             if (Semantic->eClass->Id == Context->Id)
53             {
54                 IsLegal = 1;
55                 break;
56             }
57         }
58     }
59     if (!IsLegal)
60         return NULL;
61 #endif
62     i = EBML_ElementCreate(Element,Context,SetDefault,NULL);
63     if (i && EBML_MasterAppend(Element,i)!=ERR_NONE)
64     {
65         NodeDelete((node*)i);
66         i = NULL;
67     }
68     return i;
69 }
70 
EBML_MasterFindFirstElt(ebml_master * Element,const ebml_context * Context,bool_t bCreateIfNull,bool_t SetDefault)71 ebml_element *EBML_MasterFindFirstElt(ebml_master *Element, const ebml_context *Context, bool_t bCreateIfNull, bool_t SetDefault)
72 {
73     ebml_element *i;
74     for (i=EBML_MasterChildren(Element);i;i=EBML_MasterNext(i))
75     {
76         if (i->Context->Id == Context->Id)
77             break;
78     }
79 
80     if (!i && bCreateIfNull)
81         i = EBML_MasterAddElt(Element,Context,SetDefault);
82 
83     return i;
84 }
85 
EBML_MasterFindNextElt(ebml_master * Element,const ebml_element * Current,bool_t bCreateIfNull,bool_t SetDefault)86 ebml_element *EBML_MasterFindNextElt(ebml_master *Element, const ebml_element *Current, bool_t bCreateIfNull, bool_t SetDefault)
87 {
88     ebml_element *i;
89     if (!Current)
90         return NULL;
91 
92     for (i=EBML_MasterNext(Current);i;i=EBML_MasterNext(i))
93     {
94         if (i->Context->Id == Current->Context->Id)
95             break;
96     }
97 
98     if (!i && bCreateIfNull)
99         i = EBML_MasterAddElt(Element,Current->Context,SetDefault);
100 
101     return i;
102 }
103 
EBML_MasterAppend(ebml_master * Element,ebml_element * Append)104 err_t EBML_MasterAppend(ebml_master *Element, ebml_element *Append)
105 {
106     err_t Result;
107 	assert(Node_IsPartOf(Element,EBML_MASTER_CLASS));
108     Result = NodeTree_SetParent(Append,Element,NULL);
109     if (Result==ERR_NONE)
110     {
111         Element->Base.bNeedDataSizeUpdate = 1;
112         Element->Base.bValueIsSet = 1;
113     }
114     return Result;
115 }
116 
EBML_MasterRemove(ebml_master * Element,ebml_element * Append)117 err_t EBML_MasterRemove(ebml_master *Element, ebml_element *Append)
118 {
119     err_t Result = NodeTree_SetParent(Append,NULL,NULL);
120     return Result;
121 }
122 
EBML_MasterCount(const ebml_master * Element)123 size_t EBML_MasterCount(const ebml_master *Element)
124 {
125     size_t Result = 0;
126     ebml_element *i;
127     for (i=EBML_MasterChildren(Element);i;i=EBML_MasterNext(i))
128         ++Result;
129     return Result;
130 }
131 
EbmlCmp(const ebml_element * Element,const ebml_element ** a,const ebml_element ** b)132 static int EbmlCmp(const ebml_element* Element, const ebml_element** a,const ebml_element** b)
133 {
134     if ((*a)->Context->Id == (*b)->Context->Id)
135         return EBML_ElementCmp(*a,*b);
136     return 0;
137 }
138 
EBML_MasterSort(ebml_master * Element,arraycmp Cmp,const void * CmpParam)139 void EBML_MasterSort(ebml_master *Element, arraycmp Cmp, const void* CmpParam)
140 {
141     array Elts;
142     ebml_element *i,**j;
143     ArrayInit(&Elts);
144     for (i=EBML_MasterChildren(Element);i;i=EBML_MasterNext(i))
145         ArrayAppend(&Elts,&i,sizeof(i),64);
146     if (Cmp)
147         ArraySort(&Elts,ebml_element*,Cmp,CmpParam,0);
148     else
149         ArraySort(&Elts,ebml_element*,EbmlCmp,Element,0);
150 
151     // refill the master with the new order
152     EBML_MasterClear(Element);
153     i = NULL;
154     for (j=ARRAYBEGIN(Elts,ebml_element*);j!=ARRAYEND(Elts,ebml_element*);++j)
155     {
156         NodeTree_SetParent(*j,Element,NULL);
157         i = *j;
158     }
159     ArrayClear(&Elts);
160 }
161 
EBML_MasterClear(ebml_master * Element)162 void EBML_MasterClear(ebml_master *Element)
163 {
164     ebml_element *i = EBML_MasterChildren(Element);
165     while (i)
166     {
167         NodeTree_SetParent(i,NULL,NULL);
168         i = EBML_MasterChildren(Element);
169     }
170 }
171 
EBML_MasterErase(ebml_master * Element)172 void EBML_MasterErase(ebml_master *Element)
173 {
174 	while (Element->Base.Base.Children)
175     	NodeTree_DetachAndRelease(Element->Base.Base.Children);
176 }
177 
IsDefaultValue(const ebml_element * Element)178 static bool_t IsDefaultValue(const ebml_element *Element)
179 {
180     return 0;
181     // TODO: a master element has the default value if all the sub elements are unique and have the default value
182 #if 0
183     const ebml_semantic *i;
184     for (i=Element->Context->Semantic;i->eClass;++i)
185     {
186         if (!i->Unique)
187             return 0;
188         if (i->Mandatory && !EBML_MasterFindChild(Element,i->eClass))
189             return 0;
190     }
191     return 1;
192 #endif
193 }
194 
CheckMandatory(const ebml_master * Element,bool_t bWithDefault)195 static bool_t CheckMandatory(const ebml_master *Element, bool_t bWithDefault)
196 {
197     const ebml_semantic *i;
198     for (i=Element->Base.Context->Semantic;i->eClass;++i)
199     {
200         if (i->Mandatory && !EBML_MasterFindChild(Element,i->eClass) && (bWithDefault || !i->eClass->HasDefault))
201             return 0;
202     }
203     return 1;
204 }
205 
EBML_MasterCheckMandatory(const ebml_master * Element,bool_t bWithDefault)206 bool_t EBML_MasterCheckMandatory(const ebml_master *Element, bool_t bWithDefault)
207 {
208 	ebml_element *Child;
209 	if (!CheckMandatory(Element, bWithDefault))
210 		return 0;
211 
212 	for (Child = EBML_MasterChildren(Element); Child; Child = EBML_MasterNext(Child))
213 	{
214 		if (Node_IsPartOf(Child,EBML_MASTER_CLASS) && !EBML_MasterCheckMandatory((ebml_master*)Child, bWithDefault))
215 			return 0;
216 	}
217     return 1;
218 }
219 
NeedsDataSizeUpdate(ebml_element * Element,bool_t bWithDefault)220 static bool_t NeedsDataSizeUpdate(ebml_element *Element, bool_t bWithDefault)
221 {
222     ebml_element *i;
223     if (INHERITED(Element,ebml_element_vmt,EBML_MASTER_CLASS)->NeedsDataSizeUpdate(Element, bWithDefault))
224         return 1;
225 
226     for (i=EBML_MasterChildren(Element);i;i=EBML_MasterNext(i))
227     {
228         if (EBML_ElementNeedsDataSizeUpdate(i,bWithDefault))
229             return 1;
230     }
231     return 0;
232 }
233 
UpdateDataSize(ebml_master * Element,bool_t bWithDefault,bool_t bForceWithoutMandatory)234 static filepos_t UpdateDataSize(ebml_master *Element, bool_t bWithDefault, bool_t bForceWithoutMandatory)
235 {
236     if (EBML_ElementNeedsDataSizeUpdate(Element, bWithDefault))
237     {
238         ebml_element *i;
239 
240 	    //if (!EBML_ElementIsFiniteSize((ebml_element*)Element))
241 	    //	return INVALID_FILEPOS_T;
242 
243 	    if (!bForceWithoutMandatory) {
244 		    assert(CheckMandatory((ebml_master*)Element, bWithDefault));
245         }
246 
247         if (Element->CheckSumStatus)
248             Element->Base.DataSize = 6;
249         else
250     	    Element->Base.DataSize = 0;
251 
252         for (i=EBML_MasterChildren(Element);i;i=EBML_MasterNext(i))
253         {
254             if (!bWithDefault && EBML_ElementIsDefaultValue(i))
255                 continue;
256             EBML_ElementUpdateSize(i,bWithDefault,bForceWithoutMandatory);
257             assert(!EBML_ElementNeedsDataSizeUpdate(i, bWithDefault));
258             if (i->DataSize == INVALID_FILEPOS_T)
259                 return INVALID_FILEPOS_T;
260             Element->Base.DataSize += EBML_ElementFullSize(i,bWithDefault);
261         }
262 #ifdef TODO
263 	    if (bChecksumUsed) {
264 		    Element->DataSize += EBML_ElementFullSize(Element->Checksum,bWithDefault);
265 	    }
266 #endif
267     }
268 
269     return INHERITED(Element,ebml_element_vmt,EBML_MASTER_CLASS)->UpdateDataSize(Element, bWithDefault, bForceWithoutMandatory);
270 }
271 
EBML_MasterAddMandatory(ebml_master * Element,bool_t SetDefault)272 void EBML_MasterAddMandatory(ebml_master *Element, bool_t SetDefault)
273 {
274     const ebml_semantic *i;
275     for (i=Element->Base.Context->Semantic;i->eClass;++i)
276     {
277         if (i->Mandatory && i->Unique)
278             EBML_MasterFindFirstElt(Element,i->eClass,1,SetDefault);
279     }
280 }
281 
PostCreate(ebml_master * Element,bool_t SetDefault)282 static void PostCreate(ebml_master *Element, bool_t SetDefault)
283 {
284     INHERITED(Element,ebml_element_vmt,EBML_MASTER_CLASS)->PostCreate(Element, SetDefault);
285     if (SetDefault)
286     {
287 	    EBML_MasterAddMandatory(Element, SetDefault);
288         Element->Base.bValueIsSet = 1;
289     }
290 }
291 
ReadData(ebml_master * Element,stream * Input,const ebml_parser_context * ParserContext,bool_t AllowDummyElt,int Scope,size_t DepthCheckCRC)292 static err_t ReadData(ebml_master *Element, stream *Input, const ebml_parser_context *ParserContext, bool_t AllowDummyElt, int Scope, size_t DepthCheckCRC)
293 {
294     int UpperEltFound = 0;
295     bool_t bFirst = 1;
296     ebml_element *SubElement = NULL;
297     ebml_crc *CRCElement = NULL;
298     stream *ReadStream = Input;
299     array CrcBuffer;
300     uint8_t *CRCData = NULL;
301     size_t CRCDataSize;
302 
303     // remove all existing elements, including the mandatory ones...
304     NodeTree_Clear((nodetree*)Element);
305     Element->Base.bValueIsSet = 0;
306 
307 	// read blocks and discard the ones we don't care about
308 	if (Element->Base.DataSize > 0 || !EBML_ElementIsFiniteSize((ebml_element*)Element)) {
309         ebml_parser_context Context;
310         filepos_t MaxSizeToRead;
311 
312         if (Stream_Seek(Input,EBML_ElementPositionData((ebml_element*)Element),SEEK_SET)==INVALID_FILEPOS_T)
313             return ERR_END_OF_FILE;
314 
315         MaxSizeToRead = Element->Base.DataSize;
316         Context.UpContext = ParserContext;
317         Context.Context = Element->Base.Context;
318         Context.EndPosition = EBML_ElementPositionEnd((ebml_element*)Element);
319         Context.Profile = ParserContext->Profile;
320         SubElement = EBML_FindNextElement(Input,&Context,&UpperEltFound,AllowDummyElt);
321 		while (SubElement && UpperEltFound<=0 && (!EBML_ElementIsFiniteSize((ebml_element*)Element) || EBML_ElementPositionEnd(SubElement) <= EBML_ElementPositionEnd((ebml_element*)Element)))
322         {
323 			if (!AllowDummyElt && EBML_ElementIsDummy(SubElement)) {
324                 // TODO: this should never happen
325                 EBML_ElementSkipData(SubElement,ReadStream,&Context,NULL,AllowDummyElt);
326 				NodeDelete((node*)SubElement); // forget this unknown element
327                 SubElement = NULL;
328 			}
329             else
330             {
331                 if (EBML_ElementReadData(SubElement,ReadStream,&Context,AllowDummyElt, Scope, DepthCheckCRC?DepthCheckCRC-1:0)==ERR_NONE)
332                 {
333                     if (bFirst && DepthCheckCRC && Scope!=SCOPE_NO_DATA && EBML_ElementIsType(SubElement, &EBML_ContextEbmlCrc32) && CRCElement==NULL)
334                     {
335                         if (EBML_ElementIsFiniteSize((ebml_element*)Element))
336                         {
337                             if (Node_IsPartOf(Input, MEMSTREAM_CLASS))
338                             {
339                                 filepos_t DataPos = Stream_Seek(Input,EBML_ElementPositionEnd(SubElement),SEEK_SET);
340                                 filepos_t OffSet;
341                                 Node_GET(Input,MEMSTREAM_OFFSET,&OffSet);
342                                 Node_GET(Input,MEMSTREAM_PTR,&CRCData);
343                                 CRCData += (DataPos - OffSet);
344                                 CRCDataSize = (size_t)(EBML_ElementDataSize((ebml_element*)Element,1) - EBML_ElementFullSize(SubElement,1));
345                                 Stream_Read(Input, CRCData, CRCDataSize, NULL);
346                             }
347                             else
348                             {
349                                 // read the rest of the element in memory to avoid reading it a second time later
350                                 ArrayInit(&CrcBuffer);
351                                 if (ArrayResize(&CrcBuffer, (size_t)(EBML_ElementPositionEnd((ebml_element*)Element) - EBML_ElementPositionEnd(SubElement)), 0))
352                                 {
353                                     CRCData = ARRAYBEGIN(CrcBuffer,uint8_t);
354                                     CRCDataSize = ARRAYCOUNT(CrcBuffer,uint8_t);
355                                     ReadStream = (stream*)NodeCreate(Element, MEMSTREAM_CLASS);
356                                     if (ReadStream==NULL)
357                                     {
358                                         ReadStream=Input; // revert back to normal reading
359                                         ArrayClear(&CrcBuffer);
360                                     }
361                                     else
362                                     {
363                                         filepos_t Offset = EBML_ElementPositionEnd(SubElement);
364                                         Node_Set(ReadStream, MEMSTREAM_DATA, CRCData, CRCDataSize);
365                                         Node_SET(ReadStream, MEMSTREAM_OFFSET, &Offset);
366                                         Stream_Seek(Input,EBML_ElementPositionEnd(SubElement),SEEK_SET);
367                                         if (Stream_Read(Input, CRCData, CRCDataSize, NULL)!=ERR_NONE)
368                                         {
369                                             ReadStream=Input; // revert back to normal reading
370                                             ArrayClear(&CrcBuffer);
371                                         }
372                                     }
373                                 }
374                             }
375                             CRCElement = (ebml_crc*)SubElement;
376                         }
377                         bFirst = 0;
378                     }
379                     if (CRCElement != (ebml_crc*)SubElement)
380                         EBML_MasterAppend(Element,SubElement);
381 			        // just in case
382                     EBML_ElementSkipData(SubElement,ReadStream,&Context,NULL,AllowDummyElt);
383                 }
384                 else
385                 {
386                     NodeDelete((node*)SubElement);
387                     SubElement = NULL;
388                 }
389 			}
390             if (SubElement)
391 			    MaxSizeToRead = EBML_ElementPositionEnd((ebml_element*)Element) - EBML_ElementPositionEnd(SubElement); // even if it's the default value
392 
393 			if (UpperEltFound > 0) {
394 				UpperEltFound--;
395 				if (UpperEltFound > 0 || (EBML_ElementIsFiniteSize((ebml_element*)Element) && MaxSizeToRead <= 0))
396 					goto processCrc;
397 				continue;
398 			}
399 
400 			if (UpperEltFound < 0) {
401 				UpperEltFound++;
402 				if (UpperEltFound < 0)
403 					goto processCrc;
404 			}
405 
406 			if (EBML_ElementIsFiniteSize((ebml_element*)Element) && MaxSizeToRead <= 0) {
407 				goto processCrc;// this level is finished
408 			}
409 
410 			SubElement = EBML_FindNextElement(ReadStream,&Context,&UpperEltFound,AllowDummyElt);
411 		}
412 	}
413 processCrc:
414     if (CRCData!=NULL)
415     {
416         Element->CheckSumStatus = EBML_CRCMatches(CRCElement, CRCData, CRCDataSize)?2:1;
417         if (CRCData == ARRAYBEGIN(CrcBuffer,uint8_t))
418         {
419             StreamClose(ReadStream);
420             ArrayClear(&CrcBuffer);
421         }
422     }
423 
424     Element->Base.bValueIsSet = 1;
425     if (UpperEltFound>0) // move back to the upper element beginning so that the next loop can find it
426     {
427         assert(SubElement!=NULL);
428         Stream_Seek(Input,SubElement->ElementPosition,SEEK_SET);
429     }
430     return ERR_NONE;
431 }
432 
EBML_MasterUseChecksum(ebml_master * Element,bool_t Use)433 bool_t EBML_MasterUseChecksum(ebml_master *Element, bool_t Use)
434 {
435     if (Use && Element->CheckSumStatus==0)
436     {
437         Element->Base.bNeedDataSizeUpdate = 1;
438         Element->CheckSumStatus = 1;
439         return 1;
440     }
441     if (!Use && Element->CheckSumStatus)
442     {
443         Element->Base.bNeedDataSizeUpdate = 1;
444         Element->CheckSumStatus = 0;
445         return 1;
446     }
447     return 0;
448 }
449 
EBML_MasterIsChecksumValid(const ebml_master * Element)450 bool_t EBML_MasterIsChecksumValid(const ebml_master *Element)
451 {
452     return (Element->CheckSumStatus!=1);
453 }
454 
455 #if defined(CONFIG_EBML_WRITING)
InternalRender(ebml_master * Element,stream * Output,bool_t bForceWithoutMandatory,bool_t bWithDefault,filepos_t * Rendered)456 static err_t InternalRender(ebml_master *Element, stream *Output, bool_t bForceWithoutMandatory, bool_t bWithDefault, filepos_t *Rendered)
457 {
458     ebml_element *i;
459     filepos_t ItemRendered;
460     err_t Err = ERR_NONE;
461     for (i=EBML_MasterChildren(Element);i;i=EBML_MasterNext(i))
462     {
463 		if (!bWithDefault && EBML_ElementIsDefaultValue(i))
464 			continue;
465 		Err = EBML_ElementRender(i,Output, bWithDefault, 0, bForceWithoutMandatory, &ItemRendered);
466         if (Err!=ERR_NONE)
467             return Err;
468         *Rendered += ItemRendered;
469 	}
470     return Err;
471 }
472 
RenderData(ebml_master * Element,stream * Output,bool_t bForceWithoutMandatory,bool_t bWithDefault,filepos_t * Rendered)473 static err_t RenderData(ebml_master *Element, stream *Output, bool_t bForceWithoutMandatory, bool_t bWithDefault, filepos_t *Rendered)
474 {
475     filepos_t _Rendered;
476     err_t Err = ERR_NONE;
477 
478     if (!Rendered)
479         Rendered = &_Rendered;
480     *Rendered = 0;
481 
482 	if (!bForceWithoutMandatory) {
483 		assert(CheckMandatory((ebml_master*)Element, bWithDefault));
484 	}
485 
486 	if (!Element->CheckSumStatus)
487         Err = InternalRender(Element, Output, bForceWithoutMandatory, bWithDefault, Rendered);
488 	else
489     {
490         // render to memory, compute the CRC, write the CRC and then the virtual data
491         array TmpBuf;
492         bool_t IsMemory = Node_IsPartOf(Output,MEMSTREAM_CLASS);
493         ArrayInit(&TmpBuf);
494         if (!IsMemory && !ArrayResize(&TmpBuf, (size_t)Element->Base.DataSize - 6, 0))
495             Err = ERR_OUT_OF_MEMORY;
496         else
497         {
498             ebml_crc *CrcElt = (ebml_crc*)EBML_ElementCreate(Element, &EBML_ContextEbmlCrc32, 0, NULL);
499             if (!CrcElt)
500                 Err = ERR_OUT_OF_MEMORY;
501             else
502             {
503                 if (!IsMemory)
504                 {
505                     stream *VOutput = (stream*)NodeCreate(Element, MEMSTREAM_CLASS);
506                     if (!VOutput)
507                         Err = ERR_OUT_OF_MEMORY;
508                     else
509                     {
510                         filepos_t Offset = Stream_Seek(Output,0,SEEK_CUR) + 6;
511                         Node_Set(VOutput, MEMSTREAM_DATA, ARRAYBEGIN(TmpBuf,uint8_t), ARRAYCOUNT(TmpBuf,uint8_t));
512                         Node_SET(VOutput, MEMSTREAM_OFFSET, &Offset);
513                         Err = InternalRender(Element, VOutput, bForceWithoutMandatory, bWithDefault, Rendered);
514                         assert(Err!=ERR_NONE || *Rendered == ARRAYCOUNT(TmpBuf,uint8_t));
515                         if (Err==ERR_NONE)
516                         {
517                             filepos_t CrcSize;
518                             EBML_CRCAddBuffer(CrcElt, ARRAYBEGIN(TmpBuf,uint8_t), ARRAYCOUNT(TmpBuf,uint8_t));
519                             EBML_CRCFinalize(CrcElt);
520                             Err = EBML_ElementRender((ebml_element*)CrcElt, Output, bWithDefault, 0, bForceWithoutMandatory, &CrcSize);
521                             if (Err==ERR_NONE)
522                             {
523                                 size_t Written;
524                                 Err = Stream_Write(Output, ARRAYBEGIN(TmpBuf,uint8_t), ARRAYCOUNT(TmpBuf,uint8_t), &Written);
525                                 assert(Err!=ERR_NONE || Written == *Rendered);
526                                 *Rendered = Written + CrcSize;
527                             }
528                         }
529                         StreamClose(VOutput);
530                     }
531                 }
532                 else
533                 {
534                     filepos_t VirtualPos = Stream_Seek(Output,6,SEEK_CUR); // pass the CRC for now
535                     Err = InternalRender(Element, Output, bForceWithoutMandatory, bWithDefault, Rendered);
536                     if (Err==ERR_NONE)
537                     {
538                         filepos_t CrcSize;
539                         uint8_t *Data;
540                         Node_GET(Output,MEMSTREAM_OFFSET,&CrcSize);
541                         Node_GET(Output,MEMSTREAM_PTR,&Data);
542                         EBML_CRCAddBuffer(CrcElt, Data + (VirtualPos - CrcSize), (size_t)Element->Base.DataSize-6);
543                         EBML_CRCFinalize(CrcElt);
544                         Stream_Seek(Output,EBML_ElementPositionData((ebml_element*)Element),SEEK_SET);
545                         Err = EBML_ElementRender((ebml_element*)CrcElt, Output, bWithDefault, 0, bForceWithoutMandatory, &CrcSize);
546                         *Rendered = *Rendered + CrcSize;
547                         Stream_Seek(Output,EBML_ElementPositionEnd((ebml_element*)Element),SEEK_SET);
548                     }
549                 }
550                 NodeDelete((node*)CrcElt);
551             }
552         }
553         ArrayClear(&TmpBuf);
554 	}
555 
556 	return Err;
557 }
558 #endif
559 
Copy(const ebml_master * Element,const void * Cookie)560 static ebml_element *Copy(const ebml_master *Element, const void *Cookie)
561 {
562     ebml_element *i, *Elt;
563     ebml_master *Result = (ebml_master*)EBML_ElementCreate(Element,Element->Base.Context,0,Cookie);
564     if (Result)
565     {
566         EBML_MasterErase(Result); // delete the children elements created by default
567         Result->Base.bValueIsSet = Element->Base.bValueIsSet;
568         Result->Base.DataSize = Element->Base.DataSize;
569         Result->Base.ElementPosition = Element->Base.ElementPosition;
570         Result->Base.SizeLength = Element->Base.SizeLength;
571         Result->Base.SizePosition = Element->Base.SizePosition;
572         Result->Base.bNeedDataSizeUpdate = Element->Base.bNeedDataSizeUpdate;
573         Result->CheckSumStatus = Element->CheckSumStatus;
574         for (i=EBML_MasterChildren(Element);i;i=EBML_MasterNext(i))
575         {
576             Elt = EBML_ElementCopy(i,Cookie);
577             if (!Elt || EBML_MasterAppend(Result, Elt)!=ERR_NONE)
578             {
579                 NodeDelete((node*)Result);
580                 Result = NULL;
581                 break;
582             }
583         }
584     }
585     return (ebml_element*)Result;
586 }
587 
RemoveChild(ebml_master * p,ebml_element * Child)588 static void RemoveChild(ebml_master* p,ebml_element* Child)
589 {
590     p->Base.bNeedDataSizeUpdate = 1;
591     INHERITED(p,nodetree_vmt,EBML_MASTER_CLASS)->RemoveChild(p,Child);
592 }
593 
AddChild(ebml_master * p,ebml_element * Child,ebml_element * Before)594 static void AddChild(ebml_master* p,ebml_element* Child,ebml_element* Before)
595 {
596     p->Base.bNeedDataSizeUpdate = 1;
597     INHERITED(p,nodetree_vmt,EBML_MASTER_CLASS)->AddChild(p,Child,Before);
598 }
599 
META_START(EBMLMaster_Class,EBML_MASTER_CLASS)600 META_START(EBMLMaster_Class,EBML_MASTER_CLASS)
601 META_CLASS(SIZE,sizeof(ebml_master))
602 META_VMT(TYPE_FUNC,nodetree_vmt,AddChild,AddChild)
603 META_VMT(TYPE_FUNC,nodetree_vmt,RemoveChild,RemoveChild)
604 META_VMT(TYPE_FUNC,ebml_element_vmt,PostCreate,PostCreate)
605 META_VMT(TYPE_FUNC,ebml_element_vmt,IsDefaultValue,IsDefaultValue)
606 META_VMT(TYPE_FUNC,ebml_element_vmt,UpdateDataSize,UpdateDataSize)
607 META_VMT(TYPE_FUNC,ebml_element_vmt,NeedsDataSizeUpdate,NeedsDataSizeUpdate)
608 META_VMT(TYPE_FUNC,ebml_element_vmt,ReadData,ReadData)
609 META_VMT(TYPE_FUNC,ebml_element_vmt,Copy,Copy)
610 #if defined(CONFIG_EBML_WRITING)
611 META_VMT(TYPE_FUNC,ebml_element_vmt,RenderData,RenderData)
612 #endif
613 META_END(EBML_ELEMENT_CLASS)
614 
615 void EBML_MasterCheckContext(ebml_master *Element, int ProfileMask, bool_t (*ErrCallback)(void *cookie, int type, const tchar_t *ClassName, const ebml_element*), void *cookie)
616 {
617 	tchar_t ClassString[MAXPATH];
618     ebml_element *i, *SubElt;
619     const ebml_semantic *s;
620 	for (i=EBML_MasterChildren(Element);i;i=i?EBML_MasterNext(i):NULL)
621 	{
622         if (!Node_IsPartOf(i,EBML_DUMMY_ID))
623         {
624 		    for (s=Element->Base.Context->Semantic; s->eClass; ++s)
625 		    {
626 			    if (s->eClass->Id == i->Context->Id)
627 			    {
628                     if (s->DisabledProfile & ProfileMask)
629                     {
630 				        Node_FromStr(Element,ClassString,TSIZEOF(ClassString),s->eClass->ElementName);
631                         if (ErrCallback && ErrCallback(cookie,MASTER_CHECK_PROFILE_INVALID,ClassString,i))
632                         {
633                             EBML_MasterRemove(Element,i); // make sure it doesn't remain in the list
634 					        NodeDelete((node*)i);
635 					        i=EBML_MasterChildren(Element);
636                             break;
637                         }
638                     }
639                     if (s->Unique && (SubElt=EBML_MasterFindChild(Element,s->eClass)) && (SubElt=EBML_MasterNextChild(Element,SubElt)))
640                     {
641 		                Node_FromStr(Element,ClassString,TSIZEOF(ClassString),s->eClass->ElementName);
642                         if (ErrCallback && ErrCallback(cookie,MASTER_CHECK_MULTIPLE_UNIQUE,ClassString,SubElt))
643                         {
644                             EBML_MasterRemove(Element,i); // make sure it doesn't remain in the list
645 			                NodeDelete((node*)i);
646 			                i=EBML_MasterChildren(Element);
647                             break;
648                         }
649                     }
650 				    break;
651 			    }
652 		    }
653         }
654 	}
655 
656 	for (s=Element->Base.Context->Semantic; s->eClass; ++s)
657 	{
658 	    if (s->Mandatory && !s->eClass->HasDefault && !EBML_MasterFindChild(Element,s->eClass))
659 	    {
660 		    Node_FromStr(Element,ClassString,TSIZEOF(ClassString),s->eClass->ElementName);
661             if (ErrCallback)
662                 ErrCallback(cookie,MASTER_CHECK_MISSING_MANDATORY,ClassString,NULL);
663 	    }
664 	}
665 }