1 /*
2 * $Id: ebmlelement.c 642 2010-11-28 08:38:47Z 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
ValidateSize(const ebml_element * p)31 static bool_t ValidateSize(const ebml_element *p)
32 {
33 return 1;
34 }
35
PostCreate(ebml_element * Element,bool_t SetDefault)36 static void PostCreate(ebml_element *Element, bool_t SetDefault)
37 {
38 Element->DefaultSize = -1;
39 Element->ElementPosition = INVALID_FILEPOS_T;
40 Element->SizePosition = INVALID_FILEPOS_T;
41 }
42
NeedsDataSizeUpdate(ebml_element * Element,bool_t bWithDefault)43 static bool_t NeedsDataSizeUpdate(ebml_element *Element, bool_t bWithDefault)
44 {
45 if (!Element->bNeedDataSizeUpdate)
46 return 0;
47 if (!bWithDefault && EBML_ElementIsDefaultValue(Element))
48 return 0;
49 return 1;
50 }
51
UpdateDataSize(ebml_element * Element,bool_t bWithDefault,bool_t bForceWithoutMandatory)52 static filepos_t UpdateDataSize(ebml_element *Element, bool_t bWithDefault, bool_t bForceWithoutMandatory)
53 {
54 if (!bWithDefault && EBML_ElementIsDefaultValue(Element))
55 return 0;
56
57 if (Element->DefaultSize > Element->DataSize)
58 Element->DataSize = Element->DefaultSize;
59
60 Element->bNeedDataSizeUpdate = 0;
61 #if !defined(NDEBUG)
62 assert(!EBML_ElementNeedsDataSizeUpdate(Element, bWithDefault));
63 #endif
64 return Element->DataSize;
65 }
66
Create(ebml_element * Element)67 static err_t Create(ebml_element *Element)
68 {
69 Element->DataSize = INVALID_FILEPOS_T;
70 Element->bNeedDataSizeUpdate = 1;
71 return ERR_NONE;
72 }
73
META_START(EBMLElement_Class,EBML_ELEMENT_CLASS)74 META_START(EBMLElement_Class,EBML_ELEMENT_CLASS)
75 META_CLASS(SIZE,sizeof(ebml_element))
76 META_CLASS(VMT_SIZE,sizeof(ebml_element_vmt))
77 META_CLASS(FLAGS,CFLAG_ABSTRACT)
78 META_CLASS(CREATE,Create)
79 META_VMT(TYPE_FUNC,ebml_element_vmt,PostCreate,PostCreate)
80 META_VMT(TYPE_FUNC,ebml_element_vmt,ValidateSize,ValidateSize)
81 META_VMT(TYPE_FUNC,ebml_element_vmt,UpdateDataSize,UpdateDataSize)
82 META_VMT(TYPE_FUNC,ebml_element_vmt,NeedsDataSizeUpdate,NeedsDataSizeUpdate)
83
84 META_PARAM(TYPE,EBML_ELEMENT_INFINITESIZE,TYPE_BOOLEAN)
85 META_DYNAMIC(TYPE_BOOLEAN,EBML_ELEMENT_INFINITESIZE)
86
87 META_PARAM(TYPE,EBML_ELEMENT_OBJECT,TYPE_PTR)
88 META_DYNAMIC(TYPE_PTR,EBML_ELEMENT_OBJECT)
89
90 META_END_CONTINUE(NODETREE_CLASS)
91
92 META_START_CONTINUE(EBML_DUMMY_ID)
93 META_CLASS(SIZE,sizeof(ebml_dummy))
94 META_END(EBML_BINARY_CLASS)
95
96 bool_t EBML_ElementIsFiniteSize(const ebml_element *Element)
97 {
98 return (Node_GetData((const node*)Element,EBML_ELEMENT_INFINITESIZE,TYPE_BOOLEAN) == 0);
99 }
100
EBML_ElementSetInfiniteSize(const ebml_element * Element,bool_t Set)101 void EBML_ElementSetInfiniteSize(const ebml_element *Element, bool_t Set)
102 {
103 bool_t b = Set;
104 Node_SetData((node*)Element,EBML_ELEMENT_INFINITESIZE,TYPE_BOOLEAN,&b);
105 }
106
EBML_ElementIsDummy(const ebml_element * Element)107 bool_t EBML_ElementIsDummy(const ebml_element *Element)
108 {
109 return Node_IsPartOf(Element,EBML_DUMMY_ID);
110 }
111
EBML_ElementSkipData(ebml_element * p,stream * Input,const ebml_parser_context * Context,ebml_element * TestReadElt,bool_t AllowDummyElt)112 ebml_element *EBML_ElementSkipData(ebml_element *p, stream *Input, const ebml_parser_context *Context, ebml_element *TestReadElt, bool_t AllowDummyElt)
113 {
114 ebml_element *Result = NULL;
115 if (EBML_ElementIsFiniteSize(p)) {
116 assert(TestReadElt == NULL);
117 assert(p->ElementPosition < p->SizePosition);
118 Stream_Seek(Input, EBML_ElementPositionEnd(p), SEEK_SET);
119 } else {
120 // read elements until an upper element is found
121 int bUpperElement = 0; // trick to call FindNextID correctly
122 Result = EBML_FindNextElement(Input, Context, &bUpperElement, AllowDummyElt);
123 if (Result != NULL)
124 Stream_Seek(Input, EBML_ElementPositionData(Result), SEEK_SET);
125 }
126 return Result;
127 }
128
EBML_ElementContext(const ebml_element * Element)129 const ebml_context *EBML_ElementContext(const ebml_element *Element)
130 {
131 return Element->Context;
132 }
133
EBML_ElementFullSize(const ebml_element * Element,bool_t bWithDefault)134 filepos_t EBML_ElementFullSize(const ebml_element *Element, bool_t bWithDefault)
135 {
136 if (!bWithDefault && EBML_ElementIsDefaultValue(Element))
137 return INVALID_FILEPOS_T; // won't be saved
138 return Element->DataSize + GetIdLength(Element->Context->Id) + EBML_CodedSizeLength(Element->DataSize, Element->SizeLength, EBML_ElementIsFiniteSize(Element));
139 }
140
EBML_ElementDataSize(const ebml_element * Element,bool_t bWithDefault)141 filepos_t EBML_ElementDataSize(const ebml_element *Element, bool_t bWithDefault)
142 {
143 return Element->DataSize;
144 }
145
EBML_ElementForceDataSize(ebml_element * Element,filepos_t Size)146 void EBML_ElementForceDataSize(ebml_element *Element, filepos_t Size)
147 {
148 Element->DataSize = Size;
149 }
150
EBML_ElementSizeLength(const ebml_element * Element)151 uint8_t EBML_ElementSizeLength(const ebml_element *Element)
152 {
153 return Element->SizeLength;
154 }
155
EBML_ElementSetSizeLength(ebml_element * Element,uint8_t SizeLength)156 void EBML_ElementSetSizeLength(ebml_element *Element, uint8_t SizeLength)
157 {
158 Element->SizeLength = SizeLength;
159 }
160
EBML_ElementIsType(const ebml_element * Element,const ebml_context * Context)161 bool_t EBML_ElementIsType(const ebml_element *Element, const ebml_context *Context)
162 {
163 return Element->Context->Id == Context->Id;
164 }
165
EBML_ElementClassID(const ebml_element * Element)166 fourcc_t EBML_ElementClassID(const ebml_element *Element)
167 {
168 return Element->Context->Id;
169 }
170
EBML_ElementPosition(const ebml_element * Element)171 filepos_t EBML_ElementPosition(const ebml_element *Element)
172 {
173 return Element->ElementPosition;
174 }
175
EBML_ElementForcePosition(ebml_element * Element,filepos_t Pos)176 void EBML_ElementForcePosition(ebml_element *Element, filepos_t Pos)
177 {
178 Element->ElementPosition = Pos;
179 }
180
EBML_ElementPositionData(const ebml_element * Element)181 filepos_t EBML_ElementPositionData(const ebml_element *Element)
182 {
183 if (!EBML_ElementIsFiniteSize(Element))
184 {
185 if (!Element->SizeLength)
186 return INVALID_FILEPOS_T;
187 return Element->SizePosition + Element->SizeLength;
188 }
189 else
190 return Element->SizePosition + EBML_CodedSizeLength(Element->DataSize,Element->SizeLength,1);
191 }
192
EBML_ElementPositionEnd(const ebml_element * Element)193 filepos_t EBML_ElementPositionEnd(const ebml_element *Element)
194 {
195 if (!EBML_ElementIsFiniteSize(Element))
196 return INVALID_FILEPOS_T; // the end position is unknown
197 else
198 return Element->SizePosition + EBML_CodedSizeLength(Element->DataSize,Element->SizeLength,1) + Element->DataSize;
199 }
200
EBML_ElementInfiniteForceSize(ebml_element * Element,filepos_t NewSize)201 bool_t EBML_ElementInfiniteForceSize(ebml_element *Element, filepos_t NewSize)
202 {
203 int OldSizeLen;
204 filepos_t OldSize;
205
206 assert(!EBML_ElementIsFiniteSize(Element));
207 if (EBML_ElementIsFiniteSize(Element))
208 return 0;
209
210 OldSizeLen = EBML_CodedSizeLength(Element->DataSize, Element->SizeLength, EBML_ElementIsFiniteSize(Element));
211 OldSize = Element->DataSize;
212 Element->DataSize = NewSize;
213
214 if (EBML_CodedSizeLength(Element->DataSize, Element->SizeLength, EBML_ElementIsFiniteSize(Element)) == OldSizeLen)
215 {
216 EBML_ElementSetInfiniteSize(Element,1);
217 return 1;
218 }
219 Element->DataSize = OldSize;
220
221 return 0;
222 }
223
GetIdLength(fourcc_t Id)224 size_t GetIdLength(fourcc_t Id)
225 {
226 if ((Id & 0xFFFFFF00)==0)
227 return 1;
228 if ((Id & 0xFFFF0000)==0)
229 return 2;
230 if ((Id & 0xFF000000)==0)
231 return 3;
232 return 4;
233 }
234
EBML_FillBufferID(uint8_t * Buffer,size_t BufSize,fourcc_t Id)235 size_t EBML_FillBufferID(uint8_t *Buffer, size_t BufSize, fourcc_t Id)
236 {
237 size_t i,FinalHeadSize = GetIdLength(Id);
238 if (BufSize < FinalHeadSize)
239 return 0;
240 for (i=0;i<FinalHeadSize;++i)
241 Buffer[FinalHeadSize-i-1] = (uint8_t)(Id >> (i<<3));
242 return FinalHeadSize;
243 }
244
EBML_IdToString(tchar_t * Out,size_t OutLen,fourcc_t Id)245 size_t EBML_IdToString(tchar_t *Out, size_t OutLen, fourcc_t Id)
246 {
247 size_t i,FinalHeadSize = GetIdLength(Id);
248 if (OutLen < FinalHeadSize*4+1)
249 return 0;
250 Out[0] = 0;
251 for (i=0;i<4;++i)
252 {
253 if (Out[0] || (Id >> 8*(3-i)) & 0xFF)
254 stcatprintf_s(Out,OutLen,T("[%02X]"),(Id >> 8*(3-i)) & 0xFF);
255 }
256 return FinalHeadSize*4;
257 }
258
EBML_BufferToID(const uint8_t * Buffer)259 fourcc_t EBML_BufferToID(const uint8_t *Buffer)
260 {
261 if (Buffer[0] & 0x80)
262 return (fourcc_t)Buffer[0];
263 if (Buffer[0] & 0x40)
264 return (fourcc_t)((Buffer[0] << 8) + Buffer[1]);
265 if (Buffer[0] & 0x20)
266 return (fourcc_t)((Buffer[0] << 16) + (Buffer[1] << 8) + Buffer[2]);
267 if (Buffer[0] & 0x10)
268 return (fourcc_t)((Buffer[0] << 24) + (Buffer[1] << 16) + (Buffer[2] << 8) + Buffer[3]);
269 return 0;
270 }
271
272 #if defined(CONFIG_EBML_WRITING)
EBML_ElementRender(ebml_element * Element,stream * Output,bool_t bWithDefault,bool_t bKeepPosition,bool_t bForceWithoutMandatory,filepos_t * Rendered)273 err_t EBML_ElementRender(ebml_element *Element, stream *Output, bool_t bWithDefault, bool_t bKeepPosition, bool_t bForceWithoutMandatory, filepos_t *Rendered)
274 {
275 err_t Result;
276 filepos_t _Rendered,WrittenSize;
277 #if !defined(NDEBUG)
278 filepos_t SupposedSize;
279 #endif
280
281 if (!Rendered)
282 Rendered = &_Rendered;
283 *Rendered = 0;
284
285 assert(Element->bValueIsSet || (bWithDefault && EBML_ElementIsDefaultValue(Element))); // an element is been rendered without a value set !!!
286 // it may be a mandatory element without a default value
287
288 if (!(Element->bValueIsSet || (bWithDefault && EBML_ElementIsDefaultValue(Element))))
289 return ERR_INVALID_DATA;
290
291 if (!bWithDefault && EBML_ElementIsDefaultValue(Element))
292 return ERR_INVALID_DATA;
293
294 #if !defined(NDEBUG)
295 if (EBML_ElementNeedsDataSizeUpdate(Element, bWithDefault))
296 SupposedSize = EBML_ElementUpdateSize(Element, bWithDefault, bForceWithoutMandatory);
297 else
298 SupposedSize = Element->DataSize;
299 #else
300 if (EBML_ElementNeedsDataSizeUpdate(Element, bWithDefault))
301 EBML_ElementUpdateSize(Element, bWithDefault, bForceWithoutMandatory);
302 #endif
303 Result = EBML_ElementRenderHead(Element, Output, bKeepPosition, &WrittenSize);
304 *Rendered += WrittenSize;
305 if (Result != ERR_NONE)
306 return Result;
307
308 Result = EBML_ElementRenderData(Element, Output, bForceWithoutMandatory, bWithDefault, &WrittenSize);
309 #if !defined(NDEBUG)
310 if (SupposedSize != INVALID_FILEPOS_T) assert(WrittenSize == SupposedSize);
311 #endif
312 *Rendered += WrittenSize;
313
314 return Result;
315 }
316
EBML_ElementRenderHead(ebml_element * Element,stream * Output,bool_t bKeepPosition,filepos_t * Rendered)317 err_t EBML_ElementRenderHead(ebml_element *Element, stream *Output, bool_t bKeepPosition, filepos_t *Rendered)
318 {
319 err_t Err;
320 uint8_t FinalHead[4+8]; // Class D + 64 bits coded size
321 size_t i,FinalHeadSize;
322 int CodedSize;
323 filepos_t PosAfter,PosBefore = Stream_Seek(Output,0,SEEK_CUR);
324
325 FinalHeadSize = EBML_FillBufferID(FinalHead,sizeof(FinalHead),Element->Context->Id);
326
327 CodedSize = EBML_CodedSizeLength(Element->DataSize, Element->SizeLength, EBML_ElementIsFiniteSize(Element));
328 EBML_CodedValueLength(Element->DataSize, CodedSize, &FinalHead[FinalHeadSize], EBML_ElementIsFiniteSize(Element));
329 FinalHeadSize += CodedSize;
330
331 Err = Stream_Write(Output, FinalHead, FinalHeadSize, &i);
332 PosAfter = Stream_Seek(Output,0,SEEK_CUR);
333 if (!bKeepPosition) {
334 Element->ElementPosition = PosAfter - FinalHeadSize;
335 Element->SizePosition = Element->ElementPosition + GetIdLength(Element->Context->Id);
336 }
337 if (Rendered)
338 *Rendered = PosAfter - PosBefore;
339 return Err;
340 }
341 #endif
342
EBML_ElementGetName(const ebml_element * Element,tchar_t * Out,size_t OutLen)343 void EBML_ElementGetName(const ebml_element *Element, tchar_t *Out, size_t OutLen)
344 {
345 Node_FromStr(Element,Out,OutLen,Element->Context->ElementName);
346 }
347
EBML_ElementGetClassName(const ebml_element * Element)348 const char *EBML_ElementGetClassName(const ebml_element *Element)
349 {
350 return Element->Context->ElementName;
351 }