1 /*
2 * $Id: ebmlmain.c 836 2012-08-26 13:06:04Z robux4 $
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 #if defined(EBML_LIBRARY)
31 # if defined(EBML_LEGACY_API)
32 # include "ebml2_legacy_project.h"
33 # else
34 # include "ebml2_project.h"
35 # endif
36 #endif
37
38 extern const nodemeta BufStream_Class[];
39 extern const nodemeta MemStream_Class[];
40 extern const nodemeta Streams_Class[];
41 #if defined(CONFIG_EBML_UNICODE)
42 extern const nodemeta LangStr_Class[];
43 extern const nodemeta UrlPart_Class[];
44 # if defined(CONFIG_STDIO)
45 extern const nodemeta Stdio_Class[];
46 # endif
47 #endif
48
49 extern const nodemeta EBMLElement_Class[];
50 extern const nodemeta EBMLMaster_Class[];
51 extern const nodemeta EBMLBinary_Class[];
52 extern const nodemeta EBMLString_Class[];
53 extern const nodemeta EBMLInteger_Class[];
54 extern const nodemeta EBMLCRC_Class[];
55 extern const nodemeta EBMLDate_Class[];
56 extern const nodemeta EBMLVoid_Class[];
57
EBML_Init(nodecontext * p)58 err_t EBML_Init(nodecontext *p)
59 {
60 // TODO: only when used as standalone (no coremake & core-c in the rest of the project)
61 #if defined(EBML_LIBRARY)
62 tchar_t LibName[MAXPATH];
63 tcscpy_s(LibName,TSIZEOF(LibName),PROJECT_NAME T(" v") PROJECT_VERSION);
64 Node_SetData(p,CONTEXT_LIBEBML_VERSION,TYPE_STRING,LibName);
65 #endif
66
67 NodeRegisterClassEx((nodemodule*)p,BufStream_Class);
68 NodeRegisterClassEx((nodemodule*)p,MemStream_Class);
69 NodeRegisterClassEx((nodemodule*)p,Streams_Class);
70 #if defined(CONFIG_EBML_UNICODE)
71 NodeRegisterClassEx((nodemodule*)p,LangStr_Class);
72 NodeRegisterClassEx((nodemodule*)p,UrlPart_Class);
73 # if defined(CONFIG_STDIO)
74 NodeRegisterClassEx((nodemodule*)p,Stdio_Class);
75 # endif
76 #endif
77
78 NodeRegisterClassEx((nodemodule*)p,EBMLElement_Class);
79 NodeRegisterClassEx((nodemodule*)p,EBMLMaster_Class);
80 NodeRegisterClassEx((nodemodule*)p,EBMLBinary_Class);
81 NodeRegisterClassEx((nodemodule*)p,EBMLString_Class);
82 NodeRegisterClassEx((nodemodule*)p,EBMLInteger_Class);
83 NodeRegisterClassEx((nodemodule*)p,EBMLDate_Class);
84 NodeRegisterClassEx((nodemodule*)p,EBMLCRC_Class);
85 NodeRegisterClassEx((nodemodule*)p,EBMLVoid_Class);
86
87 return ERR_NONE;
88 }
89
EBML_Done(nodecontext * p)90 err_t EBML_Done(nodecontext *p)
91 {
92 return ERR_NONE;
93 }
94
95 CONTEXT_CONST ebml_context EBML_ContextDummy = {0xFF, EBML_DUMMY_ID, 0, 0, "DummyElement", NULL, NULL};
96
97 CONTEXT_CONST ebml_context EBML_ContextVersion = {0x4286, EBML_INTEGER_CLASS, 1, EBML_MAX_VERSION, "EBMLVersion", NULL, EBML_SemanticGlobals};
98 CONTEXT_CONST ebml_context EBML_ContextReadVersion = {0x42F7, EBML_INTEGER_CLASS, 1, EBML_MAX_VERSION, "EBMLReadVersion", NULL, EBML_SemanticGlobals};
99 CONTEXT_CONST ebml_context EBML_ContextMaxIdLength = {0x42F2, EBML_INTEGER_CLASS, 1, EBML_MAX_ID, "EBMLMaxIdLength", NULL, EBML_SemanticGlobals};
100 CONTEXT_CONST ebml_context EBML_ContextMaxSizeLength = {0x42F3, EBML_INTEGER_CLASS, 1, EBML_MAX_SIZE, "EBMLMaxSizeLength", NULL, EBML_SemanticGlobals};
101 CONTEXT_CONST ebml_context EBML_ContextDocType = {0x4282, EBML_STRING_CLASS, 1, (intptr_t)"matroska", "EBMLDocType", NULL, EBML_SemanticGlobals};
102 CONTEXT_CONST ebml_context EBML_ContextDocTypeVersion = {0x4287, EBML_INTEGER_CLASS, 1, 1, "EBMLDocTypeVersion", NULL, EBML_SemanticGlobals};
103 CONTEXT_CONST ebml_context EBML_ContextDocTypeReadVersion = {0x4285, EBML_INTEGER_CLASS, 1, 1, "EBMLDocTypeReadVersion", NULL, EBML_SemanticGlobals};
104
105 static const ebml_semantic EBML_SemanticHead[] = {
106 {1, 1, &EBML_ContextVersion},
107 {1, 1, &EBML_ContextReadVersion},
108 {1, 1, &EBML_ContextMaxIdLength},
109 {1, 1, &EBML_ContextMaxSizeLength},
110 {1, 1, &EBML_ContextDocType},
111 {1, 1, &EBML_ContextDocTypeVersion},
112 {1, 1, &EBML_ContextDocTypeReadVersion},
113 {0, 0, NULL} // end of the table
114 };
115 CONTEXT_CONST ebml_context EBML_ContextHead = {0x1A45DFA3, EBML_MASTER_CLASS, 0, 0, "EBMLHead\0mfthis", EBML_SemanticHead, EBML_SemanticGlobals};
116
117
118 CONTEXT_CONST ebml_context EBML_ContextEbmlVoid = {0xEC, EBML_VOID_CLASS, 0, 0, "EBMLVoid", NULL, NULL};
119 CONTEXT_CONST ebml_context EBML_ContextEbmlCrc32 = {0xBF, EBML_CRC_CLASS, 0, 0, "EBMLCrc32", NULL, NULL};
120
121 const ebml_semantic EBML_SemanticGlobals[] = {
122 {0, 0, &EBML_ContextEbmlVoid},
123 {0, 1, &EBML_ContextEbmlCrc32},
124 {0, 0, NULL} // end of the table
125 };
126
127 static const ebml_context EBML_ContextGlobals = {0, 0, 0, 0, "GlobalContext", EBML_SemanticGlobals, EBML_SemanticGlobals};
128
EBML_ReadCodedSizeValue(const uint8_t * InBuffer,size_t * BufferSize,filepos_t * SizeUnknown)129 filepos_t EBML_ReadCodedSizeValue(const uint8_t *InBuffer, size_t *BufferSize, filepos_t *SizeUnknown)
130 {
131 uint8_t SizeBitMask = 1 << 7;
132 filepos_t Result = 0x7F;
133 unsigned int SizeIdx, PossibleSizeLength = 0;
134 uint8_t PossibleSize[8];
135 unsigned int i;
136
137 *SizeUnknown = 0x7F; // the last bit is discarded when computing the size
138 for (SizeIdx = 0; SizeIdx < *BufferSize && SizeIdx < 8; SizeIdx++) {
139 if (InBuffer[0] & (SizeBitMask >> SizeIdx)) {
140 // ID found
141 PossibleSizeLength = SizeIdx + 1;
142 SizeBitMask >>= SizeIdx;
143 for (SizeIdx = 0; SizeIdx < PossibleSizeLength; SizeIdx++) {
144 PossibleSize[SizeIdx] = InBuffer[SizeIdx];
145 }
146 for (SizeIdx = 0; SizeIdx < PossibleSizeLength - 1; SizeIdx++) {
147 Result <<= 7;
148 Result |= 0xFF;
149 }
150
151 Result = 0;
152 Result |= PossibleSize[0] & ~SizeBitMask;
153 for (i = 1; i<PossibleSizeLength; i++) {
154 Result <<= 8;
155 Result |= PossibleSize[i];
156 }
157
158 *BufferSize = PossibleSizeLength;
159
160 return Result;
161 }
162 *SizeUnknown <<= 7;
163 *SizeUnknown |= 0xFF;
164 }
165
166 *BufferSize = 0;
167 return 0;
168 }
169
EBML_ReadCodedSizeSignedValue(const uint8_t * InBuffer,size_t * BufferSize,filepos_t * SizeUnknown)170 filepos_t EBML_ReadCodedSizeSignedValue(const uint8_t *InBuffer, size_t *BufferSize, filepos_t *SizeUnknown)
171 {
172 filepos_t Result = EBML_ReadCodedSizeValue(InBuffer, BufferSize, SizeUnknown);
173
174 if (*BufferSize != 0)
175 {
176 switch (*BufferSize)
177 {
178 case 1:
179 Result -= 63;
180 break;
181 case 2:
182 Result -= 8191;
183 break;
184 case 3:
185 Result -= 1048575L;
186 break;
187 case 4:
188 Result -= 134217727L;
189 break;
190 }
191 }
192
193 return Result;
194 }
195
EBML_IdFromBuffer(const uint8_t * PossibleId,int8_t IdLength)196 static fourcc_t EBML_IdFromBuffer(const uint8_t *PossibleId, int8_t IdLength)
197 {
198 if (IdLength == 1)
199 return FOURCCBE(0,0,0,PossibleId[0]);
200 if (IdLength == 2)
201 return FOURCCBE(0,0,PossibleId[0],PossibleId[1]);
202 if (IdLength == 3)
203 return FOURCCBE(0,PossibleId[0],PossibleId[1],PossibleId[2]);
204 return FOURCCBE(PossibleId[0],PossibleId[1],PossibleId[2],PossibleId[3]);
205 }
206
EBML_IdMatch(const uint8_t * PossibleId,int8_t IdLength,fourcc_t ContextId)207 static bool_t EBML_IdMatch(const uint8_t *PossibleId, int8_t IdLength, fourcc_t ContextId)
208 {
209 return ContextId == EBML_IdFromBuffer(PossibleId,IdLength);
210 }
211
EBML_ElementCreate(anynode * Any,const ebml_context * Context,bool_t SetDefault,const void * Cookie)212 ebml_element *EBML_ElementCreate(anynode *Any, const ebml_context *Context, bool_t SetDefault, const void *Cookie)
213 {
214 ebml_element *Result;
215 Result = (ebml_element*)NodeCreate(Any,Context->Class);
216 if (Result!=NULL)
217 {
218 Result->Context = Context;
219 #if defined(EBML_LEGACY_API)
220 assert(Context->PostCreate); // for projects with legacy access
221 #endif
222 if (Context->PostCreate)
223 Context->PostCreate(Result,Cookie);
224 VMT_FUNC(Result,ebml_element_vmt)->PostCreate(Result, SetDefault);
225 }
226 return Result;
227 }
228
CreateElement(anynode * Any,const uint8_t * PossibleId,int8_t IdLength,const ebml_context * Context,ebml_master * Parent)229 static ebml_element *CreateElement(anynode *Any, const uint8_t *PossibleId, int8_t IdLength, const ebml_context *Context, ebml_master *Parent)
230 {
231 ebml_element *Result;
232 assert(Context!=NULL);
233 if (EBML_IdMatch(PossibleId, IdLength, Context->Id))
234 {
235 Result = EBML_ElementCreate(Any,Context,0,NULL);
236 }
237 else
238 {
239 Result = EBML_ElementCreate(Any,&EBML_ContextDummy,0,NULL);
240 if (Result!=NULL)
241 {
242 // Fill a temp context
243 ebml_dummy *Dummy = (ebml_dummy*)Result;
244 memcpy(&Dummy->DummyContext,&EBML_ContextDummy,sizeof(Dummy->DummyContext));
245 Dummy->DummyContext.Id = EBML_IdFromBuffer(PossibleId,IdLength);
246 Result->Context = &Dummy->DummyContext;
247 }
248 }
249 if (Result && Parent)
250 {
251 assert(Node_IsPartOf(Parent,EBML_MASTER_CLASS));
252 EBML_MasterAppend(Parent,Result);
253 }
254 return Result;
255 }
256
EBML_ElementCreateUsingContext(void * AnyNode,const uint8_t * PossibleId,int8_t IdLength,const ebml_parser_context * Context,int * LowLevel,bool_t IsGlobalContext,bool_t bAllowDummy)257 static ebml_element *EBML_ElementCreateUsingContext(void *AnyNode, const uint8_t *PossibleId, int8_t IdLength, const ebml_parser_context *Context,
258 int *LowLevel, bool_t IsGlobalContext, bool_t bAllowDummy)
259 {
260 int MaxLowerLevel=1; //TODO: remove ?
261 // unsigned int ContextIndex;
262 ebml_element *Result = NULL;
263 const ebml_semantic *Semantic;
264
265 if (!Context || !Context->Context || !Context->Context->Semantic)
266 return NULL;
267
268 // elements at the current level
269 for (Semantic=Context->Context->Semantic;Semantic->eClass;Semantic++)
270 {
271 if (EBML_IdMatch(PossibleId, IdLength, Semantic->eClass->Id)) // && (bAllowDummy || bAllowOutOfProfile || !(Context->Profile & Semantic->DisabledProfile)))
272 {
273 Result = EBML_ElementCreate(AnyNode,Semantic->eClass,0,NULL);
274 return Result;
275 }
276 }
277
278 // global elements
279 assert(Context->Context->GlobalContext != NULL); // global should always exist, at least the EBML ones
280 if (Context->Context->GlobalContext == Context->Context->Semantic)
281 return NULL;
282 else
283 {
284 ebml_context ContextGlobals;
285 ebml_parser_context GlobalContext;
286
287 ContextGlobals.Semantic = Context->Context->GlobalContext;
288 ContextGlobals.GlobalContext = Context->Context->GlobalContext;
289
290 GlobalContext.Context = &ContextGlobals;
291 GlobalContext.UpContext = Context;
292 GlobalContext.EndPosition = INVALID_FILEPOS_T;
293 GlobalContext.Profile = Context->Profile;
294 (*LowLevel)--;
295 MaxLowerLevel--;
296 // recursive is good, but be carefull...
297 Result = EBML_ElementCreateUsingContext(AnyNode,PossibleId,IdLength,&GlobalContext,LowLevel,1,bAllowDummy);
298 if (Result)
299 return Result;
300 (*LowLevel)++;
301 MaxLowerLevel++;
302 }
303
304 #ifdef TODO
305 // parent elements
306 if (Context.MasterElt != NULL && aID == Context.MasterElt->GlobalId) {
307 (*LowLevel)++; // already one level up (same as context)
308 return &Context.MasterElt->Create();
309 }
310 #endif
311
312 // check wether it's not part of an upper context
313 if (Context->UpContext != NULL) {
314 (*LowLevel)++;
315 MaxLowerLevel++;
316 return EBML_ElementCreateUsingContext(AnyNode, PossibleId, IdLength, Context->UpContext, LowLevel, IsGlobalContext, bAllowDummy);
317 }
318
319 // dummy fallback
320 if (!IsGlobalContext && bAllowDummy && IdLength!=0) {
321 (*LowLevel) = 0;
322 Result = CreateElement(AnyNode,PossibleId,IdLength,Context->Context,NULL);
323 }
324
325 return Result;
326 }
327
EBML_FindNextId(stream * Input,const ebml_context * Context,size_t MaxDataSize)328 ebml_element *EBML_FindNextId(stream *Input, const ebml_context *Context, size_t MaxDataSize)
329 {
330 filepos_t aElementPosition, aSizePosition;
331 filepos_t SizeFound=0, SizeUnknown;
332 int ReadSize;
333 uint8_t BitMask;
334 uint8_t PossibleId[4];
335 uint8_t PossibleSize[8]; // we don't support size stored in more than 64 bits
336 bool_t bElementFound = 0;
337 int8_t PossibleID_Length = 0;
338 size_t _SizeLength;
339 uint8_t PossibleSizeLength = 0;
340 ebml_element *Result = NULL;
341
342 while (!bElementFound)
343 {
344 aElementPosition = Stream_Seek(Input,0,SEEK_CUR);
345 ReadSize = 0;
346 BitMask = 1 << 7;
347 for (;;)
348 {
349 if (Stream_ReadOneOrMore(Input,&PossibleId[PossibleID_Length], 1, NULL)!=ERR_NONE)
350 break;
351 ReadSize++;
352 if (ReadSize == PossibleID_Length)
353 return NULL; // No more data ?
354 if (++PossibleID_Length > 4)
355 return NULL; // we don't support element IDs over class D
356 if (PossibleId[0] & BitMask)
357 {
358 bElementFound = 1;
359 break;
360 }
361 BitMask >>= 1;
362 }
363
364 // read the data size
365 aSizePosition = Stream_Seek(Input,0,SEEK_CUR);
366 do {
367 if (PossibleSizeLength >= 8)
368 // Size is larger than 8 bytes
369 return NULL;
370
371 if (Stream_ReadOneOrMore(Input,&PossibleSize[PossibleSizeLength++], 1, NULL)!=ERR_NONE)
372 break;
373 ReadSize++;
374 _SizeLength = PossibleSizeLength;
375 SizeFound = EBML_ReadCodedSizeValue(&PossibleSize[0], &_SizeLength, &SizeUnknown);
376 } while (_SizeLength == 0);
377 }
378
379 // look for the ID in the provided context
380 Result = CreateElement(Input, PossibleId, PossibleID_Length, Context,NULL);
381 assert(Result != NULL);
382 #if 0
383 if (PossibleID_Length==4)
384 printf("Elt: size %d id %d %02X%02X%02X%02X\n",SizeFound,PossibleID_Length,PossibleId[0],PossibleId[1],PossibleId[2],PossibleId[3]);
385 else if (PossibleID_Length==3)
386 printf("Elt: size %d id %d %02X%02X%02X\n",SizeFound,PossibleID_Length,PossibleId[0],PossibleId[1],PossibleId[2]);
387 else if (PossibleID_Length==2)
388 printf("Elt: size %d id %d %02X%02X\n",SizeFound,PossibleID_Length,PossibleId[0],PossibleId[1]);
389 else if (PossibleID_Length==1)
390 printf("Elt: size %d id %d %02X\n",SizeFound,PossibleID_Length,PossibleId[0]);
391 #endif
392 Result->SizeLength = PossibleSizeLength;
393 Result->DataSize = SizeFound;
394 if (!EBML_ElementValidateSize(Result) || (SizeFound != SizeUnknown && MaxDataSize < (size_t)Result->DataSize))
395 {
396 NodeDelete((node*)Result);
397 return NULL;
398 }
399 Result->ElementPosition = aElementPosition;
400 Result->SizePosition = aSizePosition;
401
402 return Result;
403 }
404
EBML_CodedSizeLength(filepos_t Length,uint8_t SizeLength,bool_t bSizeIsFinite)405 uint8_t EBML_CodedSizeLength(filepos_t Length, uint8_t SizeLength, bool_t bSizeIsFinite)
406 {
407 int CodedSize;
408 if (!bSizeIsFinite)
409 CodedSize = 1;
410 else
411 {
412 // prepare the head of the size (000...01xxxxxx)
413 // optimal size
414 if (Length < 127) // 2^7 - 1
415 CodedSize = 1;
416 else if (Length < 16383) // 2^14 - 1
417 CodedSize = 2;
418 else if (Length < 2097151) // 2^21 - 1
419 CodedSize = 3;
420 else if (Length < 268435455) // 2^28 - 1
421 CodedSize = 4;
422 else CodedSize = 5;
423 }
424
425 if (SizeLength && CodedSize < SizeLength)
426 // defined size
427 CodedSize = SizeLength;
428
429 return (uint8_t)CodedSize;
430 }
431
EBML_CodedSizeLengthSigned(filepos_t Length,uint8_t SizeLength)432 uint8_t EBML_CodedSizeLengthSigned(filepos_t Length, uint8_t SizeLength)
433 {
434 int CodedSize;
435 // prepare the head of the size (000...01xxxxxx)
436 // optimal size
437 if (Length > -64 && Length < 64) // 2^6
438 CodedSize = 1;
439 else if (Length > -8192 && Length < 8192) // 2^13
440 CodedSize = 2;
441 else if (Length > -1048576 && Length < 1048576) // 2^20
442 CodedSize = 3;
443 else if (Length > -134217728 && Length < 134217728) // 2^27
444 CodedSize = 4;
445 else CodedSize = 5;
446
447 if (SizeLength > 0 && CodedSize < SizeLength)
448 // defined size
449 CodedSize = SizeLength;
450
451 return (uint8_t)CodedSize;
452 }
453
454
EBML_CodedValueLength(filepos_t Length,size_t CodedSize,uint8_t * OutBuffer,bool_t bSizeIsFinite)455 uint8_t EBML_CodedValueLength(filepos_t Length, size_t CodedSize, uint8_t *OutBuffer, bool_t bSizeIsFinite)
456 {
457 int _SizeMask = 0xFF;
458 size_t i;
459 #if 0
460 if (CodedSize==3)
461 printf("%08X ",(int)Length);
462 #endif
463 if (!bSizeIsFinite)
464 Length=MAX_FILEPOS;
465 OutBuffer[0] = (uint8_t)(1 << (8 - CodedSize));
466 for (i=1; i<CodedSize; ++i)
467 {
468 OutBuffer[CodedSize-i] = (uint8_t)(Length & 0xFF);
469 Length >>= 8;
470 _SizeMask >>= 1;
471 }
472 // first one use a OR with the "EBML size head"
473 OutBuffer[0] |= Length & 0xFF & _SizeMask;
474 #if 0
475 if (CodedSize==3)
476 printf("%02X%02X%02X\n",OutBuffer[0],OutBuffer[1],OutBuffer[2]);
477 #endif
478 return (uint8_t)CodedSize;
479 }
480
EBML_CodedValueLengthSigned(filepos_t Length,size_t CodedSize,uint8_t * OutBuffer)481 uint8_t EBML_CodedValueLengthSigned(filepos_t Length, size_t CodedSize, uint8_t * OutBuffer)
482 {
483 if (Length > -64 && Length < 64) // 2^6
484 Length += 63;
485 else if (Length > -8192 && Length < 8192) // 2^13
486 Length += 8191;
487 else if (Length > -1048576 && Length < 1048576) // 2^20
488 Length += 1048575;
489 else if (Length > -134217728 && Length < 134217728) // 2^27
490 Length += 134217727;
491
492 return EBML_CodedValueLength(Length, CodedSize, OutBuffer, 1);
493 }
494
495
EBML_FindNextElement(stream * Input,const ebml_parser_context * pContext,int * UpperLevels,bool_t AllowDummyElt)496 ebml_element *EBML_FindNextElement(stream *Input, const ebml_parser_context *pContext, int *UpperLevels, bool_t AllowDummyElt)
497 {
498 uint8_t PossibleID_Length = 0;
499 uint8_t PossibleIdNSize[16];
500 int PossibleSizeLength;
501 filepos_t SizeUnknown;
502 int8_t SizeIdx,ReadIndex = 0; // trick for the algo, start index at 0
503 uint32_t ReadSize = 0;
504 filepos_t SizeFound;
505 bool_t bFound;
506 int UpperLevel_original = *UpperLevels;
507 filepos_t CurrentPos;
508 filepos_t StartPos = Stream_Seek(Input,0,SEEK_CUR);
509 ebml_parser_context OrigContext;
510 const ebml_parser_context *Context = &OrigContext;
511
512 if (StartPos == INVALID_FILEPOS_T)
513 return NULL;
514
515 assert(Context != NULL);
516 OrigContext = *pContext;
517
518 // adjust the Context to allow the StartPos to make sense
519 while (Context && Context->EndPosition != INVALID_FILEPOS_T && (StartPos >= Context->EndPosition))
520 {
521 if (Context->UpContext==NULL)
522 break;
523 Context = Context->UpContext;
524 (*UpperLevels)++;
525 }
526
527 do {
528 size_t _SizeLength;
529
530 // read a potential ID
531 do {
532 uint8_t IdBitMask = 1 << 7;
533
534 assert(ReadIndex < 16);
535 // build the ID with the current Read Buffer
536 bFound = 0;
537 for (SizeIdx = 0; SizeIdx < ReadIndex && SizeIdx < 4; SizeIdx++) {
538 if (PossibleIdNSize[0] & (IdBitMask >> SizeIdx)) {
539 // ID found
540 PossibleID_Length = SizeIdx + 1;
541 IdBitMask >>= SizeIdx;
542 bFound = 1;
543 break;
544 }
545 }
546 if (bFound)
547 break;
548 if (Context->EndPosition == StartPos+ReadSize)
549 break; // we should not read further than our limit
550
551 if (ReadIndex >= 4) {
552 // ID not found
553 // shift left the read octets
554 memmove(&PossibleIdNSize[0],&PossibleIdNSize[1], --ReadIndex);
555 }
556
557 if (Stream_ReadOneOrMore(Input,&PossibleIdNSize[ReadIndex++], 1, NULL)!=ERR_NONE)
558 return NULL; // no more data ?
559 ReadSize++;
560
561 } while (!bFound);
562
563 SizeIdx = ReadIndex;
564 ReadIndex = ReadIndex - PossibleID_Length;
565
566 // read the data size
567 PossibleSizeLength = ReadIndex;
568 bFound = 0;
569 while (1)
570 {
571 _SizeLength = PossibleSizeLength;
572 SizeFound = EBML_ReadCodedSizeValue(&PossibleIdNSize[PossibleID_Length], &_SizeLength, &SizeUnknown);
573 if (_SizeLength != 0) {
574 bFound = 1;
575 break;
576 }
577 if (PossibleSizeLength >= 8)
578 break;
579 if (Context->EndPosition == StartPos+ReadSize)
580 break; // we should not read further than our limit
581 if (Stream_ReadOneOrMore(Input,&PossibleIdNSize[SizeIdx++], 1, NULL)!=ERR_NONE)
582 return NULL;
583 ReadSize++;
584 PossibleSizeLength++;
585 }
586
587 CurrentPos = Stream_Seek(Input,0,SEEK_CUR);
588 if (bFound)
589 {
590 // make sure the element we found is contained in the Context
591 if (SizeFound != SizeUnknown)
592 {
593 while (Context && Context->EndPosition != INVALID_FILEPOS_T && (CurrentPos + SizeFound - SizeIdx > Context->EndPosition))
594 {
595 if (AllowDummyElt || Context->UpContext==NULL)
596 {
597 bFound = 0;
598 break;
599 }
600 Context = Context->UpContext;
601 (*UpperLevels)++;
602 }
603 }
604 }
605
606 if (bFound)
607 {
608 // find the element in the context and use the correct creator
609 int LevelChange = 0;
610 ebml_element *Result = EBML_ElementCreateUsingContext(Input, PossibleIdNSize, PossibleID_Length, Context, &LevelChange, 0, AllowDummyElt);
611 if (Result != NULL)
612 {
613 if (AllowDummyElt || !EBML_ElementIsDummy(Result)) {
614 assert(_SizeLength <= 8);
615 Result->SizeLength = (int8_t)_SizeLength;
616 Result->DataSize = SizeFound;
617
618 if (AllowDummyElt && !EBML_ElementValidateSize(Result) && !EBML_ElementIsDummy(Result))
619 {
620 // the element has a good ID but wrong size, so replace with a dummy
621 NodeDelete((node*)Result);
622 Result = CreateElement(Input, PossibleIdNSize, PossibleID_Length, &EBML_ContextDummy, NULL);
623 Result->SizeLength = (int8_t)_SizeLength;
624 Result->DataSize = SizeFound;
625 }
626
627 // LevelChange values
628 // -1 : global element
629 // 0 : child
630 // 1 : same level
631 // + : further parent
632 if (EBML_ElementValidateSize(Result))
633 {
634 if (SizeFound == SizeUnknown)
635 {
636 EBML_ElementSetInfiniteSize(Result, 1);
637 Result->DataSize = INVALID_FILEPOS_T;
638 }
639
640 if (LevelChange > 0)
641 *UpperLevels += LevelChange;
642 Result->SizePosition = CurrentPos - SizeIdx + PossibleID_Length;
643 Result->ElementPosition = Result->SizePosition - PossibleID_Length;
644 // place the file at the beggining of the data
645 Stream_Seek(Input,Result->SizePosition + _SizeLength,SEEK_SET);
646 return Result;
647 }
648 }
649 NodeDelete((node*)Result);
650 }
651 }
652
653 if (Context->EndPosition!=INVALID_FILEPOS_T && Context->EndPosition <= CurrentPos)
654 {
655 if (AllowDummyElt)
656 {
657 int LevelChange = 0;
658 ebml_element *Result = EBML_ElementCreateUsingContext(Input, PossibleIdNSize, PossibleID_Length, Context, &LevelChange, 0, 1);
659 if (Result != NULL)
660 {
661 if (LevelChange > 0)
662 *UpperLevels += LevelChange;
663 Result->SizePosition = CurrentPos - SizeIdx + PossibleID_Length;
664 Result->ElementPosition = Result->SizePosition - PossibleID_Length;
665 Result->DataSize = 0;
666 Result->SizeLength = (int8_t)(Context->EndPosition - Result->SizePosition);
667 // place the file at the end of the element
668 Stream_Seek(Input,Context->EndPosition,SEEK_SET);
669 return Result;
670 }
671 }
672 break; // we should not read further than our limit
673 }
674
675 // recover all the data in the buffer minus one byte
676 ReadIndex = SizeIdx - 1;
677 memmove(&PossibleIdNSize[0], &PossibleIdNSize[1], ReadIndex);
678 *UpperLevels = UpperLevel_original;
679 OrigContext = *pContext;
680 Context = &OrigContext;
681 } while (Context->EndPosition==INVALID_FILEPOS_T || (Context->EndPosition > CurrentPos - SizeIdx + PossibleID_Length));
682
683 return NULL;
684 }
685