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 }