1 /*
2 * $Id$
3 * Copyright (c) 2011, 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
29 /**
30 * A tool to generate the libmatroska2 semantic files
31 * input: specdata.xml
32 * output: matroska_sem.c / matroska_sem.h
33 */
34
35 #include "data2lib2_stdafx.h"
36 #include "spec_element.h"
37
38 typedef struct table_extras
39 {
40 bool_t StartedGlobal;
41 bool_t PassedEBML;
42 bool_t IsLast;
43 bool_t InTags;
44 int CurrLevel;
45
46 } table_extras;
47
AddElementSemantic(textwriter * CFile,const SpecElement * elt,bool_t InRecursive)48 static void AddElementSemantic(textwriter *CFile, const SpecElement *elt, bool_t InRecursive)
49 {
50 TextPrintf(CFile, T(" {%d, %d, &MATROSKA_Context%s, "), InRecursive?0:(elt->Mandatory?1:0), elt->Multiple?0:1, elt->Name);
51 if (elt->InWebM && elt->MinVersion==1 && !elt->MaxVersion && elt->InDivX)
52 TextWrite(CFile, T("0"));
53 else {
54 bool_t hasData = 0;
55 if (!elt->MinVersion || elt->MinVersion>1) {
56 if (hasData)
57 TextWrite(CFile, T("|"));
58 hasData = 1;
59 TextWrite(CFile, T("PROFILE_MATROSKA_V1"));
60 }
61 if (!elt->MinVersion || elt->MinVersion>2 || (elt->MaxVersion && elt->MaxVersion<2)) {
62 if (hasData)
63 TextWrite(CFile, T("|"));
64 hasData = 1;
65 TextWrite(CFile, T("PROFILE_MATROSKA_V2"));
66 }
67 if (!elt->MinVersion || elt->MinVersion>3 || (elt->MaxVersion && elt->MaxVersion<3)) {
68 if (hasData)
69 TextWrite(CFile, T("|"));
70 hasData = 1;
71 TextWrite(CFile, T("PROFILE_MATROSKA_V3"));
72 }
73 if (!elt->MinVersion || elt->MinVersion>4 || (elt->MaxVersion && elt->MaxVersion<4)) {
74 if (hasData)
75 TextWrite(CFile, T("|"));
76 hasData = 1;
77 TextWrite(CFile, T("PROFILE_MATROSKA_V4"));
78 }
79 if (!elt->InDivX) {
80 if (hasData)
81 TextWrite(CFile, T("|"));
82 hasData = 1;
83 TextWrite(CFile, T("PROFILE_DIVX"));
84 }
85 if (!elt->InWebM) {
86 if (hasData)
87 TextWrite(CFile, T("|"));
88 hasData = 1;
89 TextWrite(CFile, T("PROFILE_WEBM"));
90 }
91 }
92 if (InRecursive)
93 TextWrite(CFile, T("}, // recursive\n"));
94 else
95 TextWrite(CFile, T("},\n"));
96 }
97
IsValidElement(const SpecElement * elt)98 static bool_t IsValidElement(const SpecElement *elt)
99 {
100 return elt->InWebM || elt->MinVersion || elt->InDivX;
101 }
102
OutputElementDefinition(const SpecElement ** pElt,const SpecElement ** EltEnd,textwriter * CFile,table_extras * Extras)103 static void OutputElementDefinition(const SpecElement **pElt, const SpecElement **EltEnd, textwriter *CFile, table_extras *Extras)
104 {
105 const SpecElement *elt = *pElt;
106
107 if (pElt==EltEnd)
108 return;
109
110 if (elt->Type==EBML_MASTER)
111 {
112 const SpecElement **sub;
113 for (sub = pElt+1; sub!=EltEnd; ++sub)
114 {
115 if ((*sub)->Level<= elt->Level && (*sub)->Level>=0)
116 break;
117 if ((*sub)->Level== elt->Level+1)
118 OutputElementDefinition(sub, EltEnd, CFile, Extras);
119 }
120 }
121
122 //if (!IsValidElement(elt)) TextWrite(CFile, T("// not supported "));
123
124 if (elt->Type != EBML_unknown && elt->Name[0])
125 {
126 if (elt->Level==-1 && !Extras->StartedGlobal)
127 {
128 Extras->StartedGlobal = 1;
129 }
130
131 if (elt->Level>=0 && Extras->StartedGlobal)
132 {
133 Extras->StartedGlobal = 0;
134 }
135
136 if (elt->Level==0 || (elt->Level==1 && Extras->PassedEBML))
137 {
138 Extras->InTags = 0;
139 }
140 Extras->CurrLevel = elt->Level;
141
142 if (Extras->PassedEBML)
143 {
144 const tchar_t *s;
145 intptr_t value;
146
147 if (elt->Type==EBML_MASTER)
148 {
149 const SpecElement **sub;
150
151 // write the semantic
152 TextPrintf(CFile, T("\nconst ebml_semantic EBML_Semantic%s[] = {\n"), elt->Name);
153 if (elt->Recursive)
154 AddElementSemantic(CFile, elt, 1);
155 for (sub = pElt+1; sub!=EltEnd; ++sub)
156 {
157 if ((*sub)->Level<= elt->Level)
158 break;
159 if ((*sub)->Level== elt->Level+1)
160 {
161 //if (!IsValidElement(*sub)) TextWrite(CFile, T("// "));
162 AddElementSemantic(CFile, *sub, 0);
163 }
164 }
165 TextWrite(CFile, T(" {0, 0, NULL ,0} // end of the table\n};\n"));
166 }
167
168 TextPrintf(CFile, T("const ebml_context MATROSKA_Context%s = {0x%X, "), elt->Name, elt->Id);
169 if (elt->Id==0x4DBB)
170 TextWrite(CFile, T("MATROSKA_SEEKPOINT_CLASS, "));
171 else if (elt->Id==0xAE)
172 TextWrite(CFile, T("MATROSKA_TRACKENTRY_CLASS, "));
173 else if (elt->Id==0x73A4 || elt->Id==0x3CB923 || elt->Id==0x3EB923)
174 TextWrite(CFile, T("MATROSKA_SEGMENTUID_CLASS, "));
175 else if (elt->Id==0xA3 || elt->Id==0xA1)
176 TextWrite(CFile, T("MATROSKA_BLOCK_CLASS, "));
177 else if (elt->Id==0xA0)
178 TextWrite(CFile, T("MATROSKA_BLOCKGROUP_CLASS, "));
179 else if (elt->Id==0x1F43B675)
180 TextWrite(CFile, T("MATROSKA_CLUSTER_CLASS, "));
181 else if (elt->Id==0xBB)
182 TextWrite(CFile, T("MATROSKA_CUEPOINT_CLASS, "));
183 else if (elt->Id==0x465C)
184 TextWrite(CFile, T("MATROSKA_BIGBINARY_CLASS, "));
185 else if (elt->Id==0x61A7)
186 TextWrite(CFile, T("MATROSKA_ATTACHMENT_CLASS, "));
187 else switch (elt->Type)
188 {
189 case EBML_MASTER:
190 TextWrite(CFile, T("EBML_MASTER_CLASS, "));
191 break;
192 case EBML_INTEGER:
193 TextWrite(CFile, T("EBML_SINTEGER_CLASS, "));
194 break;
195 case EBML_UNSIGNED_INTEGER:
196 if (tcsisame_ascii(elt->Range,T("0-1")))
197 TextWrite(CFile, T("EBML_BOOLEAN_CLASS, "));
198 else
199 TextWrite(CFile, T("EBML_INTEGER_CLASS, "));
200 break;
201 case EBML_DATE:
202 TextWrite(CFile, T("EBML_DATE_CLASS, "));
203 break;
204 case EBML_FLOAT:
205 TextWrite(CFile, T("EBML_FLOAT_CLASS, "));
206 break;
207 case EBML_STRING:
208 TextWrite(CFile, T("EBML_STRING_CLASS, "));
209 break;
210 case EBML_UNICODE_STRING:
211 TextWrite(CFile, T("EBML_UNISTRING_CLASS, "));
212 break;
213 case EBML_BINARY:
214 TextWrite(CFile, T("EBML_BINARY_CLASS, "));
215 break;
216 }
217 switch (elt->Type)
218 {
219 case EBML_INTEGER:
220 case EBML_UNSIGNED_INTEGER:
221 case EBML_DATE:
222 s = elt->DefaultValue;
223 if (!elt->DefaultValue[0])
224 TextWrite(CFile, T("0, 0, ")); // no default value
225 else if (ExprIsInt(&s,&value))
226 TextPrintf(CFile, T("1, (intptr_t)%d, "), value);
227 else
228 TextPrintf(CFile, T("0, 0, "), s); // not supported
229 break;
230 case EBML_FLOAT:
231 s = elt->DefaultValue;
232 if (!elt->DefaultValue[0])
233 TextWrite(CFile, T("0, 0, ")); // no default value
234 else if (ExprIsInt(&s,&value))
235 TextPrintf(CFile, T("1, (intptr_t)%s, "), elt->DefaultValue);
236 else
237 TextPrintf(CFile, T("0, 0, "), s); // not supported
238 break;
239 case EBML_STRING:
240 case EBML_UNICODE_STRING:
241 if (!elt->DefaultValue[0])
242 TextWrite(CFile, T("0, 0, ")); // no default value
243 else
244 TextPrintf(CFile, T("1, (intptr_t)\"%s\", "), elt->DefaultValue);
245 break;
246 default:
247 TextPrintf(CFile, T("0, 0, "), elt->DefaultValue);
248 break;
249 }
250
251 TextPrintf(CFile, T("\"%s\", "), elt->Name);
252 if (elt->Type!=EBML_MASTER)
253 TextWrite(CFile, T("NULL, "));
254 else
255 TextPrintf(CFile, T("EBML_Semantic%s, "), elt->Name);
256 TextWrite(CFile, T("EBML_SemanticGlobals, "));
257 TextWrite(CFile, T("NULL};\n"));
258 }
259 }
260 }
261
OutputElementDeclaration(const SpecElement ** pElt,const SpecElement ** EltEnd,textwriter * CFile,table_extras * Extras)262 static void OutputElementDeclaration(const SpecElement **pElt, const SpecElement **EltEnd, textwriter *CFile, table_extras *Extras)
263 {
264 const SpecElement *elt = *pElt;
265
266 if (pElt==EltEnd)
267 return;
268
269 if (elt->Type==EBML_MASTER)
270 {
271 const SpecElement **sub;
272 for (sub = pElt+1; sub!=EltEnd; ++sub)
273 {
274 if ((*sub)->Level<= elt->Level && (*sub)->Level>=0)
275 break;
276 if ((*sub)->Level== elt->Level+1)
277 OutputElementDeclaration(sub, EltEnd, CFile, Extras);
278 }
279 }
280
281 if (elt->Type != EBML_unknown && elt->Name[0])
282 {
283 if (elt->Level==-1 && !Extras->StartedGlobal)
284 {
285 Extras->StartedGlobal = 1;
286 }
287
288 if (elt->Level>=0 && Extras->StartedGlobal)
289 {
290 Extras->StartedGlobal = 0;
291 }
292
293 if (elt->Level==0 || (elt->Level==1 && Extras->PassedEBML))
294 {
295 Extras->InTags = 0;
296 }
297 Extras->CurrLevel = elt->Level;
298
299 if (Extras->PassedEBML)
300 {
301 TextPrintf(CFile, T("extern const ebml_context MATROSKA_Context%s;\n"), elt->Name);
302 if (elt->Type==EBML_MASTER)
303 TextWrite(CFile, T("\n"));
304 }
305 }
306 }
307
ReadLevel(parser * p,array * Elements)308 static void ReadLevel(parser *p, array *Elements)
309 {
310 tchar_t Element[MAXDATA], String[MAXDATA], Value[MAXLINE];
311
312 for (;;) {
313 if (ParserElementContent(p,Value,TSIZEOF(Value)) && Value[0])
314 {
315 }
316 else if (ParserIsElementNested(p, Element, TSIZEOF(Element)))
317 {
318 if (tcsisame_ascii(Element,T("element")))
319 {
320 SpecElement *Dumper = (SpecElement*)NodeCreate(p->Context, SPEC_ELEMENT_CLASS);
321 ReadSpecElement(Dumper, p);
322 ArrayAppend(Elements, &Dumper, sizeof(Dumper), 128);
323 }
324 else
325 {
326 while (ParserIsAttrib(p, String, TSIZEOF(String)))
327 {
328 if (ParserAttribString(p, Value, TSIZEOF(Value))) {
329 if (tcsisame_ascii(String,T("id")))
330 tcsreplace(Value,TSIZEOF(Value),T(" "),T("_"));
331 }
332 }
333
334 if (p->ElementEof)
335 p->ElementEof = 0;
336 else
337 ReadLevel(p, Elements);
338 }
339 }
340 else
341 {
342 ParserSkipAfter(p,'>');
343 break;
344 }
345 }
346 }
347
META_START(SpecElement_Class,SPEC_ELEMENT_CLASS)348 META_START(SpecElement_Class,SPEC_ELEMENT_CLASS)
349 META_CLASS(SIZE,sizeof(SpecElement))
350 META_END(NODE_CLASS)
351
352
353 static void OutputCHeader(textwriter *CFile, bool_t WithInclude)
354 {
355 TextWrite(CFile, T("/*\n"));
356 TextWrite(CFile, T(" * DO NOT EDIT, GENERATED WITH DATA2LIB2\n"));
357 TextWrite(CFile, T(" *\n"));
358 TextPrintf(CFile, T(" * $Id$\n"));
359 TextWrite(CFile, T(" * Copyright (c) 2008-2011, Matroska (non-profit organisation)\n"));
360 TextWrite(CFile, T(" * All rights reserved.\n"));
361 TextWrite(CFile, T(" *\n"));
362 TextWrite(CFile, T(" * Redistribution and use in source and binary forms, with or without\n"));
363 TextWrite(CFile, T(" * modification, are permitted provided that the following conditions are met:\n"));
364 TextWrite(CFile, T(" * * Redistributions of source code must retain the above copyright\n"));
365 TextWrite(CFile, T(" * notice, this list of conditions and the following disclaimer.\n"));
366 TextWrite(CFile, T(" * * Redistributions in binary form must reproduce the above copyright\n"));
367 TextWrite(CFile, T(" * notice, this list of conditions and the following disclaimer in the\n"));
368 TextWrite(CFile, T(" * documentation and/or other materials provided with the distribution.\n"));
369 TextWrite(CFile, T(" * * Neither the name of the Matroska assocation nor the\n"));
370 TextWrite(CFile, T(" * names of its contributors may be used to endorse or promote products\n"));
371 TextWrite(CFile, T(" * derived from this software without specific prior written permission.\n"));
372 TextWrite(CFile, T(" *\n"));
373 TextWrite(CFile, T(" * THIS SOFTWARE IS PROVIDED BY the Matroska association ``AS IS'' AND ANY\n"));
374 TextWrite(CFile, T(" * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"));
375 TextWrite(CFile, T(" * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n"));
376 TextWrite(CFile, T(" * DISCLAIMED. IN NO EVENT SHALL The Matroska Foundation BE LIABLE FOR ANY\n"));
377 TextWrite(CFile, T(" * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n"));
378 TextWrite(CFile, T(" * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n"));
379 TextWrite(CFile, T(" * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND\n"));
380 TextWrite(CFile, T(" * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"));
381 TextWrite(CFile, T(" * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n"));
382 TextWrite(CFile, T(" * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"));
383 TextWrite(CFile, T(" */\n"));
384 TextWrite(CFile, T("#include \"matroska/matroska.h\"\n"));
385 if (WithInclude) TextWrite(CFile, T("#include \"matroska/matroska_sem.h\"\n"));
386 TextWrite(CFile, T("#include \"matroska/matroska_internal.h\"\n"));
387 TextWrite(CFile, T("\n"));
388 }
389
390
main(void)391 int main(void)
392 {
393 parsercontext p;
394 parser parseIn;
395 stream *Input = NULL,*OutputC = NULL,*OutputH = NULL;
396 array Elements;
397 SpecElement **element;
398 //tchar_t Element[MAXLINE], String[MAXLINE], Value[MAXLINE];
399
400 ParserContext_Init(&p,NULL,NULL,NULL);
401 StdAfx_Init((nodemodule*)&p);
402
403 Input = StreamOpen(&p,T("specdata.xml"),SFLAG_RDONLY/*|SFLAG_BUFFERED*/);
404 OutputC = StreamOpen(&p,T("matroska_sem.c"),SFLAG_WRONLY|SFLAG_CREATE);
405 OutputH = StreamOpen(&p,T("matroska_sem.h"),SFLAG_WRONLY|SFLAG_CREATE);
406
407 memset(&parseIn, 0, sizeof(parseIn));
408 ArrayInit(&Elements);
409
410 if (ParserStreamXML(&parseIn, Input, &p, T("table"), 0)==ERR_NONE)
411 {
412 textwriter CFile;
413 table_extras Extras;
414
415 ReadLevel(&parseIn, &Elements);
416
417 memset(&Extras,0,sizeof(Extras));
418 memset(&CFile,0,sizeof(CFile));
419 Extras.CurrLevel = -1;
420
421 CFile.Stream = OutputC;
422 OutputCHeader(&CFile, 1);
423
424 for (element=ARRAYBEGIN(Elements,SpecElement*); element!=ARRAYEND(Elements,SpecElement*);++element) {
425 if ((element+1) == ARRAYEND(Elements,SpecElement*))
426 Extras.IsLast = 1;
427 if ((*element)->Id == 0x18538067)
428 {
429 Extras.PassedEBML = 1;
430 OutputElementDefinition(element, ARRAYEND(Elements,SpecElement*), &CFile, &Extras);
431 break;
432 }
433 }
434
435 memset(&Extras,0,sizeof(Extras));
436 Extras.CurrLevel = -1;
437
438 CFile.Stream = OutputH;
439 OutputCHeader(&CFile, 0);
440
441 TextWrite(&CFile, T("#ifndef MATROSKA_SEMANTIC_H\n"));
442 TextWrite(&CFile, T("#define MATROSKA_SEMANTIC_H\n\n"));
443
444 for (element=ARRAYBEGIN(Elements,SpecElement*); element!=ARRAYEND(Elements,SpecElement*);++element) {
445 if ((element+1) == ARRAYEND(Elements,SpecElement*))
446 Extras.IsLast = 1;
447 if ((*element)->Id == 0x18538067)
448 {
449 Extras.PassedEBML = 1;
450 OutputElementDeclaration(element, ARRAYEND(Elements,SpecElement*), &CFile, &Extras);
451 break;
452 }
453 }
454
455 TextWrite(&CFile, T("#endif // MATROSKA_SEMANTIC_H\n"));
456 }
457
458 for (element=ARRAYBEGIN(Elements,SpecElement*); element!=ARRAYEND(Elements,SpecElement*);++element)
459 NodeDelete((node*)*element);
460 ArrayClear(&Elements);
461
462 StreamClose(Input);
463 StreamClose(OutputC);
464 StreamClose(OutputH);
465
466 StdAfx_Done((nodemodule*)&p);
467 ParserContext_Done(&p);
468 return 0;
469 }
470
471