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