1 /*
2  * $Id: ebmlstring.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 
31 #if defined(CONFIG_EBML_UNICODE)
EBML_UniStringSetValue(ebml_string * Element,const tchar_t * Value)32 err_t EBML_UniStringSetValue(ebml_string *Element,const tchar_t *Value)
33 {
34     char Data[2048];
35     if (!Node_IsPartOf(Element,EBML_UNISTRING_CLASS))
36         return ERR_INVALID_DATA;
37     Node_ToUTF8(Element,Data,sizeof(Data)-1,Value);
38     Data[sizeof(Data)-1] = 0;
39     return EBML_StringSetValue(Element,Data);
40 }
41 #endif
42 
EBML_StringSetValue(ebml_string * Element,const char * Value)43 err_t EBML_StringSetValue(ebml_string *Element,const char *Value)
44 {
45     if (Element->Base.bValueIsSet && Element->Buffer)
46         free((char*)Element->Buffer);
47     Element->Buffer = strdup(Value);
48     Element->Base.bValueIsSet = 1;
49     Element->Base.DataSize = strlen(Element->Buffer);
50     Element->Base.bNeedDataSizeUpdate = 0;
51     return ERR_NONE;
52 }
53 
EBML_StringGet(ebml_string * Element,tchar_t * Out,size_t OutLen)54 void EBML_StringGet(ebml_string *Element,tchar_t *Out, size_t OutLen)
55 {
56 	if (!Element->Buffer)
57 	{
58 		if (OutLen)
59 			*Out = 0;
60 	}
61 	else
62 	{
63 #if defined(CONFIG_EBML_UNICODE)
64 		if (Node_IsPartOf(Element,EBML_UNISTRING_CLASS))
65 			Node_FromUTF8(Element,Out,OutLen,Element->Buffer);
66 		else
67 #endif
68 			Node_FromStr(Element,Out,OutLen,Element->Buffer);
69 	}
70 }
71 
ReadData(ebml_string * Element,stream * Input,const ebml_parser_context * ParserContext,bool_t AllowDummyElt,int Scope,size_t DepthCheckCRC)72 static err_t ReadData(ebml_string *Element, stream *Input, const ebml_parser_context *ParserContext, bool_t AllowDummyElt, int Scope, size_t DepthCheckCRC)
73 {
74     err_t Result;
75     char *Buffer;
76 
77     Element->Base.bValueIsSet = 0;
78 
79     if (Scope == SCOPE_NO_DATA)
80         return ERR_NONE;
81 
82     if (Stream_Seek(Input,EBML_ElementPositionData((ebml_element*)Element),SEEK_SET)==INVALID_FILEPOS_T)
83     {
84         Result = ERR_READ;
85         goto failed;
86     }
87 
88     Buffer = malloc((size_t)Element->Base.DataSize+1);
89     if (!Buffer)
90         return ERR_OUT_OF_MEMORY;
91 
92     Result = Stream_Read(Input,Buffer,(size_t)Element->Base.DataSize,NULL);
93     if (Result != ERR_NONE)
94         goto failed;
95 
96     Buffer[Element->Base.DataSize] = 0;
97     Element->Buffer = Buffer;
98     Element->Base.bValueIsSet = 1;
99     return ERR_NONE;
100 
101 failed:
102     free(Buffer);
103     Element->Buffer = NULL;
104     return Result;
105 }
106 
107 #if defined(CONFIG_EBML_WRITING)
RenderData(ebml_string * Element,stream * Output,bool_t bForceWithoutMandatory,bool_t bWithDefault,filepos_t * Rendered)108 static err_t RenderData(ebml_string *Element, stream *Output, bool_t bForceWithoutMandatory, bool_t bWithDefault, filepos_t *Rendered)
109 {
110     size_t Written;
111     err_t Err = Stream_Write(Output,Element->Buffer,(size_t)Element->Base.DataSize,&Written);
112     if (Rendered)
113         *Rendered = Written;
114     if ((Err == ERR_NONE) && (Element->Base.DefaultSize > (int)Element->Base.DataSize))
115     {
116         char *Padding = malloc(Element->Base.DefaultSize - (int)Element->Base.DataSize);
117         if (!Padding)
118             return ERR_OUT_OF_MEMORY;
119         memset(Padding,0,Element->Base.DefaultSize - (int)Element->Base.DataSize);
120         Err = Stream_Write(Output,Padding,Element->Base.DefaultSize - (int)Element->Base.DataSize,&Written);
121         if (Rendered)
122             *Rendered += Written;
123         free(Padding);
124     }
125     return Err;
126 }
127 #endif
128 
129 #if 0
130 err_t EBML_AsciiStringRead(ebml_string *Element, stream *Input, tchar_t *Out, size_t OutLen)
131 {
132     if (Node_IsPartOf(Element,EBML_STRING_CLASS))
133         return ERR_INVALID_DATA;
134     else
135     {
136         err_t Result = EBML_ElementReadData(Element, Input);
137         if (Result != ERR_NONE)
138             return Result;
139         Node_FromStr(Element,Out,OutLen,Element->Buffer);
140         return Result;
141     }
142 }
143 
144 err_t EBML_UnicodeStringRead(ebml_string *Element, stream *Input, tchar_t *Out, size_t OutLen)
145 {
146     if (Node_IsPartOf(Element,EBML_UNISTRING_CLASS))
147         return ERR_INVALID_DATA;
148     else
149     {
150         err_t Result = EBML_ElementReadData(Element, Input);
151         if (Result != ERR_NONE)
152             return Result;
153         Node_FromUTF8(Element,Out,OutLen,Element->Buffer);
154         return Result;
155     }
156 }
157 #endif
158 
Delete(ebml_string * p)159 static void Delete(ebml_string *p)
160 {
161     if (p->Buffer)
162         free((char*)p->Buffer);
163 }
164 
UpdateDataSize(ebml_string * Element,bool_t bWithDefault,bool_t bForceWithoutMandatory)165 static filepos_t UpdateDataSize(ebml_string *Element, bool_t bWithDefault, bool_t bForceWithoutMandatory)
166 {
167     if (EBML_ElementNeedsDataSizeUpdate(Element, bWithDefault))
168         Element->Base.DataSize = strlen(Element->Buffer);
169 
170 	return INHERITED(Element,ebml_element_vmt,EBML_STRING_CLASS)->UpdateDataSize(Element, bWithDefault, bForceWithoutMandatory);
171 }
172 
UpdateDataSizeUni(ebml_string * Element,bool_t bWithDefault,bool_t bForceWithoutMandatory)173 static filepos_t UpdateDataSizeUni(ebml_string *Element, bool_t bWithDefault, bool_t bForceWithoutMandatory)
174 {
175     if (EBML_ElementNeedsDataSizeUpdate(Element, bWithDefault))
176         Element->Base.DataSize = strlen(Element->Buffer);
177 
178 	return INHERITED(Element,ebml_element_vmt,EBML_UNISTRING_CLASS)->UpdateDataSize(Element, bWithDefault, bForceWithoutMandatory);
179 }
180 
IsDefaultValue(const ebml_string * Element)181 static bool_t IsDefaultValue(const ebml_string *Element)
182 {
183     return Element->Base.Context->HasDefault && (!Element->Base.bValueIsSet || strcmp(Element->Buffer,(const char*)Element->Base.Context->DefaultValue)==0);
184 }
185 
PostCreateString(ebml_element * Element,bool_t SetDefault)186 static void PostCreateString(ebml_element *Element, bool_t SetDefault)
187 {
188     INHERITED(Element,ebml_element_vmt,EBML_STRING_CLASS)->PostCreate(Element, SetDefault);
189     if (SetDefault && Element->Context->HasDefault)
190         EBML_StringSetValue((ebml_string*)Element, (const char *)Element->Context->DefaultValue);
191 }
192 
PostCreateUniString(ebml_element * Element,bool_t SetDefault)193 static void PostCreateUniString(ebml_element *Element, bool_t SetDefault)
194 {
195     INHERITED(Element,ebml_element_vmt,EBML_UNISTRING_CLASS)->PostCreate(Element, SetDefault);
196     if (SetDefault && Element->Context->HasDefault)
197         EBML_StringSetValue((ebml_string*)Element, (const char *)Element->Context->DefaultValue);
198 }
199 
Copy(const ebml_string * Element,const void * Cookie)200 static ebml_string *Copy(const ebml_string *Element, const void *Cookie)
201 {
202     ebml_string *Result = (ebml_string*)EBML_ElementCreate(Element,Element->Base.Context,0,Cookie);
203     if (Result)
204     {
205         Result->Buffer = strdup(Element->Buffer);
206         Result->Base.bValueIsSet = Element->Base.bValueIsSet;
207         Result->Base.DataSize = Element->Base.DataSize;
208         Result->Base.ElementPosition = Element->Base.ElementPosition;
209         Result->Base.SizeLength = Element->Base.SizeLength;
210         Result->Base.SizePosition = Element->Base.SizePosition;
211         Result->Base.bNeedDataSizeUpdate = Element->Base.bNeedDataSizeUpdate;
212     }
213     return Result;
214 }
215 
216 META_START(EBMLString_Class,EBML_STRING_CLASS)
217 META_CLASS(SIZE,sizeof(ebml_string))
218 META_CLASS(DELETE,Delete)
219 META_VMT(TYPE_FUNC,ebml_element_vmt,ReadData,ReadData)
220 META_VMT(TYPE_FUNC,ebml_element_vmt,IsDefaultValue,IsDefaultValue)
221 META_VMT(TYPE_FUNC,ebml_element_vmt,UpdateDataSize,UpdateDataSize)
222 #if defined(CONFIG_EBML_WRITING)
223 META_VMT(TYPE_FUNC,ebml_element_vmt,RenderData,RenderData)
224 #endif
225 META_VMT(TYPE_FUNC,ebml_element_vmt,PostCreate,PostCreateString)
226 META_VMT(TYPE_FUNC,ebml_element_vmt,Copy,Copy)
227 META_END_CONTINUE(EBML_ELEMENT_CLASS)
228 
229 META_START_CONTINUE(EBML_UNISTRING_CLASS)
230 META_CLASS(SIZE,sizeof(ebml_string))
231 META_CLASS(DELETE,Delete)
232 META_VMT(TYPE_FUNC,ebml_element_vmt,ReadData,ReadData)
233 META_VMT(TYPE_FUNC,ebml_element_vmt,IsDefaultValue,IsDefaultValue)
234 META_VMT(TYPE_FUNC,ebml_element_vmt,UpdateDataSize,UpdateDataSizeUni)
235 #if defined(CONFIG_EBML_WRITING)
236 META_VMT(TYPE_FUNC,ebml_element_vmt,RenderData,RenderData)
237 #endif
238 META_VMT(TYPE_FUNC,ebml_element_vmt,PostCreate,PostCreateUniString)
239 META_VMT(TYPE_FUNC,ebml_element_vmt,Copy,Copy)
240 META_END(EBML_ELEMENT_CLASS)
241