1 /*
2  * $Id: ebmlvoid.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 
IsDefaultValue(const ebml_element * Element)31 static bool_t IsDefaultValue(const ebml_element *Element)
32 {
33     return 0;
34 }
35 
ReadData(ebml_element * Element,stream * Input,const ebml_parser_context * ParserContext,bool_t AllowDummyElt,int Scope,size_t DepthCheckCRC)36 static err_t ReadData(ebml_element *Element, stream *Input, const ebml_parser_context *ParserContext, bool_t AllowDummyElt, int Scope, size_t DepthCheckCRC)
37 {
38 	EBML_ElementSkipData(Element,Input,ParserContext,NULL,AllowDummyElt);
39 	return ERR_NONE;
40 }
41 
42 #if defined(CONFIG_EBML_WRITING)
RenderData(ebml_element * Element,stream * Output,bool_t bForceWithoutMandatory,bool_t bWithDefault,filepos_t * Rendered)43 static err_t RenderData(ebml_element *Element, stream *Output, bool_t bForceWithoutMandatory, bool_t bWithDefault, filepos_t *Rendered)
44 {
45     size_t Written, Left = (size_t)Element->DataSize;
46     err_t Err = ERR_NONE;
47     uint8_t Buf[2*1024]; // write 2 KB chunks at a time
48     memset(Buf,0,sizeof(Buf));
49     while (Err==ERR_NONE && Left)
50     {
51         Err = Stream_Write(Output,Buf,min(Left,sizeof(Buf)),&Written);
52         if (Err == ERR_NONE)
53             Left -= min(Left,sizeof(Buf));
54     }
55     if (Rendered)
56         *Rendered = Element->DataSize - Left;
57     return Err;
58 }
59 #endif
60 
Copy(const ebml_element * Element,const void * Cookie)61 static ebml_element *Copy(const ebml_element *Element, const void *Cookie)
62 {
63     ebml_element *Result = EBML_ElementCreate(Element,Element->Context,0,Cookie);
64     if (Result)
65     {
66         Result->bValueIsSet = Element->bValueIsSet;
67         Result->DataSize = Element->DataSize;
68         Result->ElementPosition = Element->ElementPosition;
69         Result->SizeLength = Element->SizeLength;
70         Result->SizePosition = Element->SizePosition;
71         Result->bNeedDataSizeUpdate = Element->bNeedDataSizeUpdate;
72     }
73     return Result;
74 }
75 
META_START(EBMLVoid_Class,EBML_VOID_CLASS)76 META_START(EBMLVoid_Class,EBML_VOID_CLASS)
77 META_VMT(TYPE_FUNC,ebml_element_vmt,IsDefaultValue,IsDefaultValue)
78 META_VMT(TYPE_FUNC,ebml_element_vmt,ReadData,ReadData)
79 #if defined(CONFIG_EBML_WRITING)
80 META_VMT(TYPE_FUNC,ebml_element_vmt,RenderData,RenderData)
81 #endif
82 META_VMT(TYPE_FUNC,ebml_element_vmt,Copy,Copy)
83 META_END(EBML_ELEMENT_CLASS)
84 
85 #if defined(CONFIG_EBML_WRITING)
86 bool_t EBML_VoidSetFullSize(ebml_element *Void, filepos_t DataSize)
87 {
88     assert(Node_IsPartOf(Void,EBML_VOID_CLASS));
89     Void->DataSize = DataSize - 1 - EBML_CodedSizeLength(DataSize,0,1); // 1 is the length of the Void ID
90     Void->bValueIsSet = 1;
91     Void->bNeedDataSizeUpdate = 0;
92     return Void->DataSize >= 0;
93 }
94 
EBML_VoidReplaceWith(ebml_element * Void,ebml_element * ReplacedWith,stream * Output,bool_t ComeBackAfterward,bool_t bWithDefault)95 filepos_t EBML_VoidReplaceWith(ebml_element *Void, ebml_element *ReplacedWith, stream *Output, bool_t ComeBackAfterward, bool_t bWithDefault)
96 {
97     filepos_t CurrentPosition;
98     assert(Node_IsPartOf(Void,EBML_VOID_CLASS));
99 
100 	EBML_ElementUpdateSize(ReplacedWith,bWithDefault,0);
101 	if (EBML_ElementFullSize(Void,1) < EBML_ElementFullSize(ReplacedWith,1))
102 		// the element can't be written here !
103 		return INVALID_FILEPOS_T;
104 	if (EBML_ElementFullSize(Void,1) - EBML_ElementFullSize(ReplacedWith,1) == 1)
105 		// there is not enough space to put a filling element
106 		return INVALID_FILEPOS_T;
107 
108 	CurrentPosition = Stream_Seek(Output,0,SEEK_CUR);
109 
110     Stream_Seek(Output,Void->ElementPosition,SEEK_SET);
111     EBML_ElementRender(ReplacedWith,Output,bWithDefault,0,1,NULL);
112 
113     if (EBML_ElementFullSize(Void,1) - EBML_ElementFullSize(ReplacedWith,1) > 1)
114     {
115         // fill the rest with another void element
116         ebml_element *aTmp = EBML_ElementCreate(Void,Void->Context,0,NULL);
117         if (aTmp)
118         {
119             filepos_t HeadBefore,HeadAfter;
120             EBML_VoidSetFullSize(aTmp, EBML_ElementFullSize(Void,1) - EBML_ElementFullSize(ReplacedWith,1));
121             HeadBefore = EBML_ElementFullSize(aTmp,1) - aTmp->DataSize;
122             aTmp->DataSize = aTmp->DataSize - EBML_CodedSizeLength(aTmp->DataSize, aTmp->SizeLength, EBML_ElementIsFiniteSize(aTmp));
123             HeadAfter = EBML_ElementFullSize(aTmp,1) - aTmp->DataSize;
124             if (HeadBefore != HeadAfter)
125                 aTmp->SizeLength = (int8_t)(EBML_CodedSizeLength(aTmp->DataSize, aTmp->SizeLength, EBML_ElementIsFiniteSize(aTmp)) - (HeadAfter - HeadBefore));
126             EBML_ElementRenderHead(aTmp,Output,0,NULL);
127             NodeDelete((node*)aTmp);
128         }
129     }
130 
131 	if (ComeBackAfterward)
132         Stream_Seek(Output,CurrentPosition,SEEK_SET);
133 
134 	return EBML_ElementFullSize(Void,1);
135 }
136 #endif
137