1 /*
2  *			GPAC - Multimedia Framework C SDK
3  *
4  *			Authors: Jean Le Feuvre
5  *			Copyright (c) Telecom ParisTech 2004-2012
6  *					All rights reserved
7  *
8  *  This file is part of GPAC / MPEG4 Scene Graph Generator sub-project
9  *
10  *  GPAC is free software; you can redistribute it and/or modify
11  *  it under the terms of the GNU Lesser General Public License as published by
12  *  the Free Software Foundation; either version 2, or (at your option)
13  *  any later version.
14  *
15  *  GPAC is distributed in the hope that it will be useful,
16  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *  GNU Lesser General Public License for more details.
19  *
20  *  You should have received a copy of the GNU Lesser General Public
21  *  License along with this library; see the file COPYING.  If not, write to
22  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  */
25 
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 
30 #undef _DEBUG
31 #undef DEBUG
32 
33 #include <gpac/list.h>
34 
35 
36 #include <time.h>
37 
38 
39 #define COPYRIGHT_SCENE "/*\n *			GPAC - Multimedia Framework C SDK\n *\n *			Authors: Jean Le Feuvre\n *			Copyright (c) Telecom ParisTech 2000-2012\n *					All rights reserved\n *\n *  This file is part of GPAC / Scene Graph sub-project\n *\n *  GPAC is free software; you can redistribute it and/or modify\n *  it under the terms of the GNU Lesser General Public License as published by\n *  the Free Software Foundation; either version 2, or (at your option)\n *  any later version.\n *\n *  GPAC is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU Lesser General Public License for more details.	\n *\n *  You should have received a copy of the GNU Lesser General Public\n *  License along with this library; see the file COPYING.  If not, write to\n *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n */\n"
40 #define COPYRIGHT_BIFS "/*\n *			GPAC - Multimedia Framework C SDK\n *\n *			Authors: Jean Le Feuvre\n *			Copyright (c) Telecom ParisTech 2000-2012\n *					All rights reserved\n *\n *  This file is part of GPAC / BIFS codec sub-project\n *\n *  GPAC is free software; you can redistribute it and/or modify\n *  it under the terms of the GNU Lesser General Public License as published by\n *  the Free Software Foundation; either version 2, or (at your option)\n *  any later version.\n *\n *  GPAC is distributed in the hope that it will be useful,\n *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n *  GNU Lesser General Public License for more details.	\n *\n *  You should have received a copy of the GNU Lesser General Public\n *  License along with this library; see the file COPYING.  If not, write to\n *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.\n *\n */\n"
41 
42 static char *CurrentLine;
43 
PrintUsage()44 void PrintUsage()
45 {
46 	printf("MPEG4Gen [-p file] [template_file_v1 (template_file_v2 ...) ]\n"
47 	       "\nGPAC MPEG4 Scene Graph generator. Usage:\n"
48 	       "-p: listing file of nodes to exclude from tables\n"
49 	       "Template files MUST be fed in order\n"
50 	       "\n"
51 	       "Generated Files are directly updated in the GPAC distribution - do NOT try to change this\n\n"
52 	       "Written by Jean Le Feuvre - Copyright (c) Telecom ParisTech 2000-2012\n"
53 	      );
54 }
55 
56 //a node field
57 typedef struct
58 {
59 	char type[50];
60 	//SFxxx, MFxxx
61 	char familly[50];
62 	//name
63 	char name[1000];
64 	//default value
65 	char def[100];
66 	//bounds
67 	u32 hasBounds;
68 	char b_min[20];
69 	char b_max[20];
70 	//Quant
71 	u32 hasQuant;
72 	char quant_type[50];
73 	char qt13_bits[50];
74 	//Anim
75 	u32 hasAnim;
76 	u32 AnimType;
77 
78 } BField;
79 
80 //NDTs
81 
82 //a BIFS node
83 typedef struct
84 {
85 	char name[1000];
86 	//NDT info. NDT are created in alphabetical order
87 	GF_List *NDT;
88 	//0: normal, 1: special
89 	u32 codingType;
90 	u32 version;
91 
92 	GF_List *Fields;
93 
94 	//coding types
95 	u8 hasDef, hasIn, hasOut, hasDyn;
96 	u8 hasAQInfo;
97 
98 	u8 hasDefault;
99 
100 	u8 skip_impl;
101 
102 	char Child_NDT_Name[1000];
103 } BNode;
104 
105 
skip_sep(char * sep)106 void skip_sep(char *sep)
107 {
108 	//skip separaors
109 	while (*CurrentLine && strchr(sep, *CurrentLine)) {
110 		CurrentLine = CurrentLine + 1;
111 		//end of line - no token
112 		if (*CurrentLine == '\n') return;
113 	}
114 }
115 
116 //note that we increment the line no matter what
GetNextToken(char * token,char * sep)117 u32 GetNextToken(char *token, char *sep)
118 {
119 	u32 i , j = 0;
120 
121 	strcpy(token, "");
122 
123 	//skip separaors
124 	while (*CurrentLine && strchr(sep, *CurrentLine)) {
125 		CurrentLine = CurrentLine + 1;
126 		j ++;
127 		//end of line - no token
128 		if (*CurrentLine == '\n') return 0;
129 	}
130 
131 	//copy token untill next blank
132 	i=0;
133 	while (1) {
134 		//bad line
135 		if (! *CurrentLine) {
136 			token[i] = 0;
137 			return 0;
138 		}
139 		//end of token or end of line
140 		if (strchr(sep, *CurrentLine) || (*CurrentLine == '\n') ) {
141 			token[i] = 0;
142 			CurrentLine = CurrentLine + 1;
143 			return i;
144 		} else {
145 			token[i] = *CurrentLine;
146 		}
147 		CurrentLine = CurrentLine + 1;
148 		i++;
149 		j++;
150 	}
151 	return 1;
152 }
153 
154 
155 char szFixedVal[5000];
GetFixedPrintout(char * val)156 char *GetFixedPrintout(char *val)
157 {
158 	if (!strcmp(val, "FIX_MIN") || !strcmp(val, "FIX_MAX")) return val;
159 	/*composite texture...*/
160 	if (!strcmp(val, "65535")) return "FIX_MAX /*WARNING: modified to allow 16.16 fixed point version!!*/";
161 	sprintf(szFixedVal, "FLT2FIX(%s)", val);
162 	return szFixedVal;
163 }
164 
BlankField()165 BField *BlankField()
166 {
167 	BField *n = gf_malloc(sizeof(BField));
168 	memset(n, 0, sizeof(BField));
169 	return n;
170 }
171 
172 
BlankNode()173 BNode *BlankNode()
174 {
175 	BNode *n = gf_malloc(sizeof(BNode));
176 	memset(n, 0, sizeof(BNode));
177 	n->NDT = gf_list_new();
178 	n->Fields = gf_list_new();
179 	return n;
180 }
181 
IsNDT(GF_List * NDTs,char * famName)182 u8 IsNDT(GF_List *NDTs, char *famName)
183 {
184 	u32 i;
185 	for (i=0; i<gf_list_count(NDTs); i++) {
186 		char *ndtName = gf_list_get(NDTs, i);
187 		//remove SF / MF as we don't need that
188 		if (!strcmp(ndtName+2, famName+2)) return 1;
189 	}
190 	return 0;
191 }
192 
CheckInTable(char * token,GF_List * NDTs)193 void CheckInTable(char *token, GF_List *NDTs)
194 {
195 	u32 i;
196 	char *p;
197 	for (i=0; i<gf_list_count(NDTs); i++) {
198 		p = gf_list_get(NDTs, i);
199 		if (!strcmp(p, token)) return;
200 	}
201 	p = gf_malloc(strlen(token)+1);
202 	strcpy(p, token);
203 	gf_list_add(NDTs, p);
204 }
205 
206 /*type: 0: header, 1: source*/
BeginFile(char * name,u32 type)207 FILE *BeginFile(char *name, u32 type)
208 {
209 	FILE *f;
210 	char *cprt = COPYRIGHT_SCENE;
211 	char sPath[GF_MAX_PATH];
212 
213 	if (!type) {
214 		if (!strcmp(name, "NDT")) {
215 			sprintf(sPath, "..%c..%c..%cinclude%cgpac%cinternal%cbifs_tables.h", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR);
216 			cprt = COPYRIGHT_BIFS;
217 		}
218 		/*nodes_mpeg4.h is exported*/
219 		else {
220 			sprintf(sPath, "..%c..%c..%cinclude%cgpac%cnodes_mpeg4.h", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR);
221 		}
222 	} else {
223 		if (!stricmp(name, "NDT")) {
224 			sprintf(sPath, "..%c..%c..%csrc%cbifs%cbifs_node_tables.c", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR);
225 			cprt = COPYRIGHT_BIFS;
226 		} else {
227 			sprintf(sPath, "..%c..%c..%csrc%cscenegraph%c%s.c", GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, name);
228 		}
229 	}
230 
231 	f = gf_fopen(sPath, "wt");
232 	fprintf(f, "%s\n", cprt);
233 
234 
235 
236 	{
237 		time_t rawtime;
238 		time(&rawtime);
239 		fprintf(f, "\n/*\n\tDO NOT MOFIFY - File generated on GMT %s\n\tBY MPEG4Gen for GPAC Version %s\n*/\n\n", asctime(gmtime(&rawtime)), GPAC_VERSION);
240 	}
241 
242 	if (!type) {
243 		fprintf(f, "#ifndef _%s_H\n", name);
244 		fprintf(f, "#define _%s_H\n\n", name);
245 		if (!strcmp(name, "nodes_mpeg4")) {
246 			fprintf(f, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n");
247 		}
248 	}
249 	return f;
250 }
251 
EndFile(FILE * f,char * name,u32 type)252 void EndFile(FILE *f, char *name, u32 type)
253 {
254 	if (!type) {
255 		if (!strcmp(name, "nodes_mpeg4")) {
256 			fprintf(f, "#ifdef __cplusplus\n}\n#endif\n\n");
257 		}
258 		fprintf(f, "\n\n#endif\t\t/*_%s_H*/\n\n", name);
259 	}
260 	gf_fclose(f);
261 }
262 
TranslateToken(char * token)263 void TranslateToken(char *token)
264 {
265 	if (!strcmp(token, "+I") || !strcmp(token, "I")) {
266 		strcpy(token, "FIX_MAX");
267 	}
268 	else if (!strcmp(token, "-I")) {
269 		strcpy(token, "FIX_MIN");
270 	}
271 }
272 
273 
274 
WriteNodesFile(GF_List * BNodes,GF_List * NDTs,u32 NumVersions)275 void WriteNodesFile(GF_List *BNodes, GF_List *NDTs, u32 NumVersions)
276 {
277 	FILE *f;
278 	u32 i, j;
279 	BNode *n;
280 	BField *bf;
281 	Bool hasViewport;
282 
283 	f = BeginFile("nodes_mpeg4", 0);
284 
285 	fprintf(f, "#include <gpac/scenegraph_vrml.h>\n\n");
286 	fprintf(f, "#ifndef GPAC_DISABLE_VRML\n\n");
287 
288 
289 	//write all tags
290 	fprintf(f, "\n\nenum {\n");
291 
292 	for (i=0; i<gf_list_count(BNodes); i++) {
293 		n = gf_list_get(BNodes, i);
294 		if (i)
295 			fprintf(f, ",\n\tTAG_MPEG4_%s", n->name);
296 		else
297 			fprintf(f, "\tTAG_MPEG4_%s = GF_NODE_RANGE_FIRST_MPEG4", n->name);
298 	}
299 	fprintf(f, ",\n\tTAG_LastImplementedMPEG4\n};\n\n");
300 
301 	for (i=0; i<gf_list_count(BNodes); i++) {
302 		n = gf_list_get(BNodes, i);
303 		if (n->skip_impl) continue;
304 
305 		fprintf(f, "typedef struct _tag%s\n{\n", n->name);
306 		fprintf(f, "\tBASE_NODE\n");
307 
308 		/*write children field*/
309 		for (j=0; j<gf_list_count(n->Fields); j++) {
310 			bf = gf_list_get(n->Fields, j);
311 			if (!stricmp(bf->name, "addChildren") || !strcmp(bf->name, "removeChildren")) continue;
312 			if (!strcmp(bf->name, "children") && stricmp(n->name, "audioBuffer")) {
313 				fprintf(f, "\tVRML_CHILDREN\n");
314 				break;
315 			}
316 		}
317 		for (j=0; j<gf_list_count(n->Fields); j++) {
318 			bf = gf_list_get(n->Fields, j);
319 
320 			if (!strcmp(bf->name, "addChildren") || !strcmp(bf->name, "removeChildren")) continue;
321 			if (!strcmp(bf->name, "children") && stricmp(n->name, "audioBuffer")) continue;
322 
323 			//write remaining fields
324 			//eventIn fields are handled as pointer to functions, called by the route manager
325 			if (!strcmp(bf->type, "eventIn")) {
326 				if (strstr(bf->familly, "Node")) {
327 					fprintf(f, "\tGF_Node *%s;\t/*eventIn*/\n",bf->name);
328 				} else {
329 					fprintf(f, "\t%s %s;\t/*eventIn*/\n", bf->familly, bf->name);
330 				}
331 				fprintf(f, "\tvoid (*on_%s)(GF_Node *pThis, struct _route *route);\t/*eventInHandler*/\n", bf->name);
332 			} else if (!strcmp(bf->type, "eventOut")) {
333 				//eventOut fields are handled as an opaque stack pointing to the route manager
334 				//this will be refined once the route is in place
335 				//we will likely need a function such as:
336 				//	void SignalRoute(route_stack, node, par)
337 				fprintf(f, "\t%s %s;\t/*eventOut*/\n", bf->familly, bf->name);
338 			} else if (strstr(bf->familly, "Node")) {
339 				//this is a POINTER to a node
340 				if (strstr(bf->familly, "SF")) {
341 					fprintf(f, "\tGF_Node *%s;\t/*%s*/\n", bf->name, bf->type);
342 				} else {
343 					//this is a POINTER to a chain
344 					fprintf(f, "\tGF_ChildNodeItem *%s;\t/*%s*/\n", bf->name, bf->type);
345 				}
346 			} else {
347 				fprintf(f, "\t%s %s;\t/*%s*/\n", bf->familly, bf->name, bf->type);
348 			}
349 		}
350 		if (!strcmp(n->name, "CacheTexture")) {
351 			fprintf(f, "\t/*GPAC private*/\n");
352 			fprintf(f, "\tu8 *data;\n");
353 			fprintf(f, "\tu32 data_len;\n");
354 		}
355 		if (!strcmp(n->name, "BitWrapper")) {
356 			fprintf(f, "\t/*GPAC private*/\n");
357 			fprintf(f, "\tu32 buffer_len;\n");
358 		}
359 		fprintf(f, "} M_%s;\n\n\n", n->name);
360 	}
361 
362 
363 	hasViewport = 0;
364 	//all NDTs are defined in v1
365 	fprintf(f, "/*NodeDataType tags*/\nenum {\n");
366 	for (i=0; i<gf_list_count(NDTs); i++) {
367 		char *NDTName = gf_list_get(NDTs, i);
368 		if (!i) {
369 			fprintf(f, "\tNDT_%s = 1", NDTName);
370 		} else {
371 			fprintf(f, ",\n\tNDT_%s", NDTName);
372 		}
373 
374 		if (strcmp(NDTName, "SFViewportNode")) hasViewport = 1;
375 	}
376 	//template fix: some node use NDT_SFViewportNode but the table is empty-> not generated
377 	if (!hasViewport) fprintf(f, ",\n\tNDT_SFViewportNode");
378 	fprintf(f, "\n};\n\n");
379 
380 
381 	fprintf(f, "/*All BIFS versions handled*/\n");
382 	fprintf(f, "#define GF_BIFS_NUM_VERSION\t\t%d\n\n", NumVersions);
383 	fprintf(f, "enum {\n");
384 	for (i=0; i<NumVersions; i++) {
385 		if (!i) {
386 			fprintf(f, "\tGF_BIFS_V1 = 1,\n");
387 		} else {
388 			fprintf(f, "\tGF_BIFS_V%d,\n", i+1);
389 		}
390 	}
391 	fprintf(f, "\tGF_BIFS_LAST_VERSION = GF_BIFS_V%d\n};\n\n", i);
392 	fprintf(f, "\n\n");
393 	fprintf(f, "#endif /*GPAC_DISABLE_VRML*/\n\n");
394 
395 	EndFile(f, "nodes_mpeg4", 0);
396 
397 }
398 
399 
IsNodeInTable(BNode * node,char * NDTName)400 u32 IsNodeInTable(BNode *node, char *NDTName)
401 {
402 	u32 i;
403 
404 	for (i=0; i<gf_list_count(node->NDT); i++) {
405 		char *ndt = gf_list_get(node->NDT, i);
406 		if (!strcmp(ndt, NDTName)) return 1;
407 	}
408 	return 0;
409 }
410 
GetBitsCount(u32 MaxVal)411 u32 GetBitsCount(u32 MaxVal)
412 {
413 	u32 k=0;
414 
415 	while ((s32) MaxVal > ((1<<k)-1) ) k+=1;
416 	return k;
417 }
418 
GetNDTCount(char * NDTName,GF_List * BNodes,u32 Version)419 u32 GetNDTCount(char *NDTName, GF_List *BNodes, u32 Version)
420 {
421 	u32 i, nodeCount;
422 
423 	//V1 begins at 0
424 	if (Version == 1) {
425 		nodeCount = 0;
426 	}
427 	//V2 at 2 (0 reserved + 1 proto)
428 	else if (Version == 2) {
429 		nodeCount = 2;
430 	}
431 	//other at 1 (0 reserved, no proto)
432 	else {
433 		nodeCount = 1;
434 	}
435 	for (i=0; i<gf_list_count(BNodes); i++) {
436 		BNode *n = gf_list_get(BNodes, i);
437 		if (n->version != Version) continue;
438 		if (!IsNodeInTable(n, NDTName)) continue;
439 		nodeCount++;
440 	}
441 	return nodeCount;
442 
443 }
444 
WriteNDT_H(FILE * f,GF_List * BNodes,GF_List * NDTs,u32 Version)445 void WriteNDT_H(FILE *f, GF_List *BNodes, GF_List *NDTs, u32 Version)
446 {
447 	u32 i, j, first, count;
448 	BNode *n;
449 
450 
451 	fprintf(f, "\n\n/* NDT BIFS Version %d */\n\n", Version);
452 
453 	//for all NDTs
454 	for (i=0; i<gf_list_count(NDTs); i++) {
455 		char *NDTName = gf_list_get(NDTs, i);
456 		count = GetNDTCount(NDTName, BNodes, Version);
457 		if (Version == 2) {
458 			count -= 2;
459 		} else if (Version > 2) {
460 			count -= 1;
461 		}
462 		if (!count) continue;
463 
464 		//numBits
465 		fprintf(f, "#define %s_V%d_NUMBITS\t\t%d\n", NDTName, Version, GetBitsCount(count + ( (Version == 2) ? 1 : 0) ) );
466 		fprintf(f, "#define %s_V%d_Count\t%d\n\n", NDTName, Version, count);
467 
468 		fprintf(f, "static const u32 %s_V%d_TypeToTag[%d] = {\n", NDTName, Version, count);
469 		first = 1;
470 		//browse each node.
471 		for (j=0; j<gf_list_count(BNodes); j++) {
472 			n = gf_list_get(BNodes, j);
473 			if (n->version != Version) continue;
474 			if (!IsNodeInTable(n, NDTName)) continue;
475 
476 			if (first) {
477 				fprintf(f, " TAG_MPEG4_%s", n->name);
478 				first = 0;
479 			} else {
480 				fprintf(f, ", TAG_MPEG4_%s", n->name);
481 			}
482 		}
483 		fprintf(f, "\n};\n\n");
484 
485 	}
486 
487 	fprintf(f, "\nu32 NDT_V%d_GetNumBits(u32 NDT_Tag);\n", Version);
488 	fprintf(f, "u32 NDT_V%d_GetNodeTag(u32 Context_NDT_Tag, u32 NodeType);\n", Version);
489 	fprintf(f, "u32 NDT_V%d_GetNodeType(u32 NDT_Tag, u32 NodeTag);\n", Version);
490 
491 	fprintf(f, "\n\n");
492 }
493 
494 //write the NDTs functions for v1 nodes
495 //all our internal handling is in TAG_MPEG4_#nodename because we need an homogeneous
496 //namespace for all nodes (v1, v2, v3 and v4)
497 //the NDT functions will perform the translation from the NDT value to the absolute
498 //TAG of the node
WriteNDT_Dec(FILE * f,GF_List * BNodes,GF_List * NDTs,u32 Version)499 void WriteNDT_Dec(FILE *f, GF_List *BNodes, GF_List *NDTs, u32 Version)
500 {
501 	char *NDTName;
502 	u32 i, count;
503 
504 	//NodeTag complete translation
505 	fprintf(f, "\n\n\nu32 NDT_V%d_GetNodeTag(u32 Context_NDT_Tag, u32 NodeType)\n{\n\tif (!NodeType) return 0;\n", Version);
506 
507 	//handle version
508 	fprintf(f, "\t/* adjust according to the table version */\n");
509 	if (Version == 2) {
510 		fprintf(f, "\t/* v2: 0 reserved for extensions, 1 reserved for protos */\n");
511 		fprintf(f, "\tif (NodeType == 1) return 0;\n");
512 		fprintf(f, "\tNodeType -= 2;\n");
513 	} else {
514 		fprintf(f, "\t/* v%d: 0 reserved for extensions */\n", Version);
515 		fprintf(f, "\tNodeType -= 1;\n");
516 	}
517 
518 	fprintf(f, "\tswitch (Context_NDT_Tag) {\n");
519 
520 	for (i=0; i<gf_list_count(NDTs); i++) {
521 		NDTName = gf_list_get(NDTs, i);
522 
523 		count = GetNDTCount(NDTName, BNodes, Version);
524 		if (Version == 2) {
525 			count -= 2;
526 		} else if (Version > 2) {
527 			count -= 1;
528 		}
529 		if (!count) continue;
530 
531 		fprintf(f, "\tcase NDT_%s:\n\t\tif (NodeType >= %s_V%d_Count) return 0;\n", NDTName, NDTName, Version);
532 		fprintf(f, "\t\treturn %s_V%d_TypeToTag[NodeType];\n", NDTName, Version);
533 	}
534 	fprintf(f, "\tdefault:\n\t\treturn 0;\n\t}\n}");
535 
536 	//NDT codec bits
537 	fprintf(f, "\n\n\nu32 NDT_V%d_GetNumBits(u32 NDT_Tag)\n{\n\tswitch (NDT_Tag) {\n", Version);
538 
539 	for (i=0; i<gf_list_count(NDTs); i++) {
540 		NDTName = gf_list_get(NDTs, i);
541 
542 		count = GetNDTCount(NDTName, BNodes, Version);
543 		if (Version == 2) {
544 			count -= 2;
545 		} else if (Version > 2) {
546 			count -= 1;
547 		}
548 		if (!count) continue;
549 
550 		fprintf(f, "\tcase NDT_%s:\n\t\treturn %s_V%d_NUMBITS;\n", NDTName, NDTName, Version);
551 	}
552 	/*all tables have 1 node in v2 for proto coding*/
553 	fprintf(f, "\tdefault:\n\t\treturn %d;\n\t}\n}\n\n", (Version==2) ? 1 : 0);
554 }
555 
556 
WriteNDT_Enc(FILE * f,GF_List * BNodes,GF_List * NDTs,u32 Version)557 void WriteNDT_Enc(FILE *f, GF_List *BNodes, GF_List *NDTs, u32 Version)
558 {
559 	u32 i, count;
560 
561 	fprintf(f, "u32 NDT_V%d_GetNodeType(u32 NDT_Tag, u32 NodeTag)\n{\n\tif(!NDT_Tag || !NodeTag) return 0;\n\tswitch(NDT_Tag) {\n", Version);
562 	for (i=0; i<gf_list_count(NDTs); i++) {
563 		char *NDTName = gf_list_get(NDTs, i);
564 		count = GetNDTCount(NDTName, BNodes, Version);
565 		if (Version == 2) {
566 			count -= 2;
567 		} else if (Version > 2) {
568 			count -= 1;
569 		}
570 		if (!count) continue;
571 		fprintf(f, "\tcase NDT_%s:\n\t\treturn ALL_GetNodeType(%s_V%d_TypeToTag, %s_V%d_Count, NodeTag, GF_BIFS_V%d);\n", NDTName, NDTName, Version, NDTName, Version, Version);
572 	}
573 	fprintf(f, "\tdefault:\n\t\treturn 0;\n\t}\n}\n\n");
574 }
575 
576 
577 
WriteNodeFields(FILE * f,BNode * n)578 void WriteNodeFields(FILE *f, BNode *n)
579 {
580 	u32 i, first;
581 	BField *bf;
582 	u32 NbDef, NbIn, NbOut, NbDyn, hasAQ;
583 
584 	NbDef = NbIn = NbOut = NbDyn = hasAQ = 0;
585 	for (i=0; i<gf_list_count(n->Fields); i++) {
586 		bf = gf_list_get(n->Fields, i);
587 		if (!strcmp(bf->type, "field") || !strcmp(bf->type, "exposedField")) {
588 			NbDef += 1;
589 		}
590 		if (!strcmp(bf->type, "eventIn") || !strcmp(bf->type, "exposedField")) {
591 			NbIn += 1;
592 			//check for anim
593 			if (bf->hasAnim) NbDyn += 1;
594 		}
595 		if (!strcmp(bf->type, "eventOut") || !strcmp(bf->type, "exposedField")) {
596 			NbOut += 1;
597 		}
598 		if (bf->hasAnim || bf->hasQuant) hasAQ = 1;
599 	}
600 
601 	n->hasAQInfo = hasAQ;
602 
603 	//write the def2all table
604 	if (NbDef) {
605 		first = 1;
606 		fprintf(f, "static const u16 %s_Def2All[] = { ", n->name);
607 		for (i=0; i<gf_list_count(n->Fields); i++) {
608 			bf = gf_list_get(n->Fields, i);
609 			if (strcmp(bf->type, "field") && strcmp(bf->type, "exposedField")) continue;
610 			if (first) {
611 				fprintf(f, "%d", i);
612 				first = 0;
613 			} else {
614 				fprintf(f, ", %d", i);
615 			}
616 		}
617 		fprintf(f, "};\n");
618 	}
619 	//write the in2all table
620 	if (NbIn) {
621 		first = 1;
622 		fprintf(f, "static const u16 %s_In2All[] = { ", n->name);
623 		for (i=0; i<gf_list_count(n->Fields); i++) {
624 			bf = gf_list_get(n->Fields, i);
625 			if (strcmp(bf->type, "eventIn") && strcmp(bf->type, "exposedField")) continue;
626 			if (first) {
627 				fprintf(f, "%d", i);
628 				first = 0;
629 			} else {
630 				fprintf(f, ", %d", i);
631 			}
632 		}
633 		fprintf(f, "};\n");
634 	}
635 	//write the out2all table
636 	if (NbOut) {
637 		first = 1;
638 		fprintf(f, "static const u16 %s_Out2All[] = { ", n->name);
639 		for (i=0; i<gf_list_count(n->Fields); i++) {
640 			bf = gf_list_get(n->Fields, i);
641 			if (strcmp(bf->type, "eventOut") && strcmp(bf->type, "exposedField")) continue;
642 			if (first) {
643 				fprintf(f, "%d", i);
644 				first = 0;
645 			} else {
646 				fprintf(f, ", %d", i);
647 			}
648 		}
649 		fprintf(f, "};\n");
650 	}
651 	//then write the dyn2all table
652 	if (NbDyn) {
653 		first = 1;
654 		fprintf(f, "static const u16 %s_Dyn2All[] = { ", n->name);
655 		for (i=0; i<gf_list_count(n->Fields); i++) {
656 			bf = gf_list_get(n->Fields, i);
657 			if (strcmp(bf->type, "eventIn") && strcmp(bf->type, "exposedField")) continue;
658 			if (!bf->hasAnim) continue;
659 			if (first) {
660 				fprintf(f, "%d", i);
661 				first = 0;
662 			} else {
663 				fprintf(f, ", %d", i);
664 			}
665 		}
666 		fprintf(f, "};\n");
667 	}
668 
669 	n->hasDef = NbDef;
670 	n->hasDyn = NbDyn;
671 	n->hasIn = NbIn;
672 	n->hasOut = NbOut;
673 
674 
675 	fprintf(f, "\nstatic u32 %s_get_field_count(GF_Node *node, u8 IndexMode)\n{\n", n->name);
676 	fprintf(f, "\tswitch(IndexMode) {\n");
677 
678 	fprintf(f, "\tcase GF_SG_FIELD_CODING_IN: return %d;\n", NbIn);
679 	fprintf(f, "\tcase GF_SG_FIELD_CODING_DEF: return %d;\n", NbDef);
680 	fprintf(f, "\tcase GF_SG_FIELD_CODING_OUT: return %d;\n", NbOut);
681 	fprintf(f, "\tcase GF_SG_FIELD_CODING_DYN: return %d;\n", NbDyn);
682 	fprintf(f, "\tdefault:\n");
683 	fprintf(f, "\t\treturn %d;\n", gf_list_count(n->Fields));
684 	fprintf(f, "\t}");
685 
686 	fprintf(f, "\n}\n");
687 
688 	fprintf(f, "\nstatic GF_Err %s_get_field_index(GF_Node *n, u32 inField, u8 IndexMode, u32 *allField)\n{\n", n->name);
689 	fprintf(f, "\tswitch(IndexMode) {\n");
690 
691 	if (NbIn) {
692 		fprintf(f, "\tcase GF_SG_FIELD_CODING_IN:\n");
693 		fprintf(f, "\t\t*allField = %s_In2All[inField];\n\t\treturn GF_OK;\n", n->name);
694 	}
695 	if (NbDef) {
696 		fprintf(f, "\tcase GF_SG_FIELD_CODING_DEF:\n");
697 		fprintf(f, "\t\t*allField = %s_Def2All[inField];\n\t\treturn GF_OK;\n", n->name);
698 	}
699 	if (NbOut) {
700 		fprintf(f, "\tcase GF_SG_FIELD_CODING_OUT:\n");
701 		fprintf(f, "\t\t*allField = %s_Out2All[inField];\n\t\treturn GF_OK;\n", n->name);
702 	}
703 	if (NbDyn) {
704 		fprintf(f, "\tcase GF_SG_FIELD_CODING_DYN:\n");
705 		fprintf(f, "\t\t*allField = %s_Dyn2All[inField];\n\t\treturn GF_OK;\n", n->name);
706 	}
707 
708 	fprintf(f, "\tdefault:\n");
709 	fprintf(f, "\t\treturn GF_BAD_PARAM;\n");
710 	fprintf(f, "\t}");
711 
712 	fprintf(f, "\n}\n");
713 
714 
715 	fprintf(f, "static GF_Err %s_get_field(GF_Node *node, GF_FieldInfo *info)\n{\n\tswitch (info->fieldIndex) {\n", n->name);
716 	for (i=0; i<gf_list_count(n->Fields); i++) {
717 		bf = gf_list_get(n->Fields, i);
718 
719 		fprintf(f, "\tcase %d:\n", i);
720 
721 		fprintf(f, "\t\tinfo->name = \"%s\";\n", (bf->name[0]=='_') ? bf->name+1 : bf->name);
722 
723 		//skip all eventIn
724 		if (!strcmp(bf->type, "eventIn")) {
725 			fprintf(f, "\t\tinfo->eventType = GF_SG_EVENT_IN;\n");
726 			fprintf(f, "\t\tinfo->on_event_in = ((M_%s *)node)->on_%s;\n", n->name, bf->name);
727 		}
728 		else if (!strcmp(bf->type, "eventOut")) {
729 			fprintf(f, "\t\tinfo->eventType = GF_SG_EVENT_OUT;\n");
730 		}
731 		else if (!strcmp(bf->type, "field")) {
732 			fprintf(f, "\t\tinfo->eventType = GF_SG_EVENT_FIELD;\n");
733 		}
734 		else {
735 			fprintf(f, "\t\tinfo->eventType = GF_SG_EVENT_EXPOSED_FIELD;\n");
736 		}
737 
738 		if (strstr(bf->familly, "Node")) {
739 			if (strstr(bf->familly, "MF")) {
740 				fprintf(f, "\t\tinfo->fieldType = GF_SG_VRML_MFNODE;\n");
741 			} else {
742 				fprintf(f, "\t\tinfo->fieldType = GF_SG_VRML_SFNODE;\n");
743 			}
744 			//always remove the SF or MF, as all NDTs are SFXXX
745 			fprintf(f, "\t\tinfo->NDTtype = NDT_SF%s;\n", bf->familly+2);
746 			fprintf(f, "\t\tinfo->far_ptr = & ((M_%s *)node)->%s;\n", n->name, bf->name);
747 		} else {
748 			char szName[20];
749 			strcpy(szName, bf->familly);
750 			strupr(szName);
751 			//no ext type
752 			fprintf(f, "\t\tinfo->fieldType = GF_SG_VRML_%s;\n", szName);
753 			fprintf(f, "\t\tinfo->far_ptr = & ((M_%s *) node)->%s;\n", n->name, bf->name);
754 		}
755 		fprintf(f, "\t\treturn GF_OK;\n");
756 	}
757 	fprintf(f, "\tdefault:\n\t\treturn GF_BAD_PARAM;\n\t}\n}\n\n");
758 
759 	fprintf(f, "\nstatic s32 %s_get_field_index_by_name(char *name)\n{\n", n->name);
760 	for (i=0; i<gf_list_count(n->Fields); i++) {
761 		bf = gf_list_get(n->Fields, i);
762 		fprintf(f, "\tif (!strcmp(\"%s\", name)) return %d;\n", (bf->name[0]=='_') ? bf->name+1 : bf->name, i);
763 	}
764 	fprintf(f, "\treturn -1;\n\t}\n");
765 }
766 
767 
768 //write the Quantization info for each node field(Quant and BIFS-Anim info)
WriteNodeQuant(FILE * f,BNode * n)769 void WriteNodeQuant(FILE *f, BNode *n)
770 {
771 	u32 i;
772 	fprintf(f, "static Bool %s_get_aq_info(GF_Node *n, u32 FieldIndex, u8 *QType, u8 *AType, Fixed *b_min, Fixed *b_max, u32 *QT13_bits)\n{\n\tswitch (FieldIndex) {\n", n->name);
773 
774 	for (i=0; i<gf_list_count(n->Fields) ; i++ ) {
775 		BField *bf = gf_list_get(n->Fields, i);
776 		if (!bf->hasAnim && !bf->hasQuant) continue;
777 
778 		fprintf(f, "\tcase %d:\n", i);
779 		//Anim Type
780 		fprintf(f, "\t\t*AType = %d;\n", bf->AnimType);
781 		//Quant Type
782 		fprintf(f, "\t\t*QType = %s;\n", bf->quant_type);
783 		if (!strcmp(bf->quant_type, "13"))
784 			fprintf(f, "\t\t*QT13_bits = %s;\n", bf->qt13_bits);
785 
786 		//Bounds
787 		if (bf->hasBounds) {
788 			if (!strcmp(bf->b_min, "+I") || !strcmp(bf->b_min, " +I") || !strcmp(bf->b_min, "I")) {
789 				fprintf(f, "\t\t*b_min = FIX_MAX;\n");
790 			} else if (!strcmp(bf->b_min, "-I")  || !strcmp(bf->b_min, "-65536")) {
791 				fprintf(f, "\t\t*b_min = FIX_MIN;\n");
792 			} else {
793 				fprintf(f, "\t\t*b_min = %s;\n", GetFixedPrintout(bf->b_min));
794 			}
795 			if (!strcmp(bf->b_max, "+I") || !strcmp(bf->b_max, " +I") || !strcmp(bf->b_max, "I") || !strcmp(bf->b_max, "65535")) {
796 				fprintf(f, "\t\t*b_max = FIX_MAX;\n");
797 			} else {
798 				fprintf(f, "\t\t*b_max = %s;\n", GetFixedPrintout(bf->b_max));
799 			}
800 		}
801 		fprintf(f, "\t\treturn 1;\n");
802 	}
803 	fprintf(f, "\tdefault:\n\t\treturn 0;\n\t}\n}\n\n");
804 }
805 
WriteNodeCode(GF_List * BNodes)806 void WriteNodeCode(GF_List *BNodes)
807 {
808 	FILE *f;
809 	char token[20], tok[20];
810 	char *store;
811 	u32 i, j, k, go;
812 	BField *bf;
813 	BNode *n;
814 
815 	f = BeginFile("mpeg4_nodes", 1);
816 
817 	fprintf(f, "#include <gpac/nodes_mpeg4.h>\n\n");
818 	fprintf(f, "\n#include <gpac/internal/scenegraph_dev.h>\n");
819 
820 	fprintf(f, "\n#ifndef GPAC_DISABLE_VRML\n");
821 
822 
823 	for (k=0; k<gf_list_count(BNodes); k++) {
824 		Bool is_parent = 0;
825 		n = gf_list_get(BNodes, k);
826 
827 		if (n->skip_impl) continue;
828 
829 		fprintf(f, "\n/*\n\t%s Node deletion\n*/\n\n", n->name);
830 		fprintf(f, "static void %s_Del(GF_Node *node)\n{\n\tM_%s *p = (M_%s *) node;\n", n->name, n->name, n->name);
831 
832 		for (i=0; i<gf_list_count(n->Fields); i++) {
833 			bf = gf_list_get(n->Fields, i);
834 			//nothing on child events
835 			if (!strcmp(bf->name, "addChildren")) continue;
836 			if (!strcmp(bf->name, "removeChildren")) continue;
837 
838 			//delete all children node
839 			if (!strcmp(bf->name, "children") && stricmp(n->name, "audioBuffer")) {
840 				is_parent = 1;
841 				continue;
842 			}
843 
844 			//delete ALL fields that must be deleted: this includes eventIn and out since
845 			//all fields are defined in the node
846 			if (!strcmp(bf->familly, "MFInt")
847 			        || !strcmp(bf->familly, "MFFloat")
848 			        || !strcmp(bf->familly, "MFDouble")
849 			        || !strcmp(bf->familly, "MFBool")
850 			        || !strcmp(bf->familly, "MFInt32")
851 			        || !strcmp(bf->familly, "MFColor")
852 			        || !strcmp(bf->familly, "MFRotation")
853 			        || !strcmp(bf->familly, "MFString")
854 			        || !strcmp(bf->familly, "MFTime")
855 			        || !strcmp(bf->familly, "MFVec2f")
856 			        || !strcmp(bf->familly, "MFVec3f")
857 			        || !strcmp(bf->familly, "MFVec4f")
858 			        || !strcmp(bf->familly, "MFVec2d")
859 			        || !strcmp(bf->familly, "MFVec3d")
860 			        || !strcmp(bf->familly, "MFURL")
861 			        || !strcmp(bf->familly, "MFScript")
862 			        || !strcmp(bf->familly, "SFString")
863 			        || !strcmp(bf->familly, "SFURL")
864 			        || !strcmp(bf->familly, "SFImage")
865 					|| !strcmp(bf->familly, "MFAttrRef")
866 			   ) {
867 				char szName[500];
868 				strcpy(szName, bf->familly);
869 				strlwr(szName);
870 				fprintf(f, "\tgf_sg_%s_del(p->%s);\n", szName, bf->name);
871 			}
872 			else if (!strcmp(bf->familly, "SFCommandBuffer")) {
873 				fprintf(f, "\tgf_sg_sfcommand_del(p->%s);\n", bf->name);
874 			}
875 			else if (strstr(bf->familly, "Node")) {
876 				//this is a POINTER to a node
877 				if (strstr(bf->familly, "SF")) {
878 					fprintf(f, "\tgf_node_unregister((GF_Node *) p->%s, (GF_Node *) p);\t\n", bf->name);
879 				} else {
880 					//this is a POINTER to a chain
881 					fprintf(f, "\tgf_node_unregister_children((GF_Node *) p, p->%s);\t\n", bf->name);
882 				}
883 			}
884 		}
885 		if (!strcmp(n->name, "CacheTexture")) {
886 			fprintf(f, "\tif (p->data) gf_free(p->data);\n");
887 		}
888 		if (is_parent) fprintf(f, "\tgf_sg_vrml_parent_destroy((GF_Node *) p);\t\n");
889 		fprintf(f, "\tgf_node_free((GF_Node *) p);\n}\n\n");
890 
891 		//node fields
892 		WriteNodeFields(f, n);
893 		WriteNodeQuant(f, n);
894 
895 		//
896 		//		Constructor
897 		//
898 
899 		fprintf(f, "\n\nGF_Node *%s_Create()\n{\n\tM_%s *p;\n\tGF_SAFEALLOC(p, M_%s);\n", n->name, n->name, n->name);
900 		fprintf(f, "\tif(!p) return NULL;\n");
901 		fprintf(f, "\tgf_node_setup((GF_Node *)p, TAG_MPEG4_%s);\n", n->name);
902 
903 		for (i=0; i<gf_list_count(n->Fields); i++) {
904 			bf = gf_list_get(n->Fields, i);
905 			//setup all children node
906 			if (!strcmp(bf->name, "children") && stricmp(n->name, "audioBuffer")) {
907 				fprintf(f, "\tgf_sg_vrml_parent_setup((GF_Node *) p);\n");
908 				break;
909 			}
910 			else if ( strstr(bf->familly, "Node") && strncmp(bf->type, "event", 5) ) {
911 #if 0
912 				//this is a POINTER to a node
913 				if (strstr(bf->familly, "MF")) {
914 					//this is a POINTER to a chain
915 					fprintf(f, "\tp->%s = gf_list_new();\t\n", bf->name);
916 				}
917 #endif
918 			}
919 			/*special case for SFCommandBuffer: we also create a command list*/
920 			if (!stricmp(bf->familly, "SFCommandBuffer")) {
921 				fprintf(f, "\tp->%s.commandList = gf_list_new();\t\n", bf->name);
922 			}
923 		}
924 
925 		//check if we have a child node
926 		for (i=0; i<gf_list_count(n->Fields); i++) {
927 			bf = gf_list_get(n->Fields, i);
928 			if ( !strcmp(bf->name, "children") ||
929 			        ( !strstr(bf->type, "event") && strstr(bf->familly, "MF") && strstr(bf->familly, "Node")) ) {
930 				sprintf(n->Child_NDT_Name, "NDT_SF%s", bf->familly+2);
931 				break;
932 			}
933 		}
934 
935 		fprintf(f, "\n\t/*default field values*/\n");
936 
937 		for (i=0; i<gf_list_count(n->Fields); i++) {
938 			bf = gf_list_get(n->Fields, i);
939 
940 			//nothing on eventIn or Out
941 			if (!strcmp(bf->type, "eventIn")) continue;
942 			if (!strcmp(bf->type, "eventOut")) continue;
943 
944 			if (!strcmp(bf->def, "")) continue;
945 
946 			//no default on nodes
947 			if (strstr(bf->familly, "Node")) continue;
948 			//extract default falue
949 
950 			//
951 			//		SF Fields
952 			//
953 
954 			//SFBool
955 			if (!strcmp(bf->familly, "SFBool")) {
956 				if (!strcmp(bf->def, "1") || !strcmp(bf->def, "TRUE"))
957 					fprintf(f, "\tp->%s = 1;\n", bf->name);
958 			}
959 			//SFFloat
960 			else if (!strcmp(bf->familly, "SFFloat")) {
961 				fprintf(f, "\tp->%s = %s;\n", bf->name, GetFixedPrintout(bf->def));
962 			}
963 			//SFTime
964 			else if (!strcmp(bf->familly, "SFTime")) {
965 				fprintf(f, "\tp->%s = %s;\n", bf->name, bf->def);
966 			}
967 			//SFInt32
968 			else if (!strcmp(bf->familly, "SFInt32")) {
969 				fprintf(f, "\tp->%s = %s;\n", bf->name, bf->def);
970 			}
971 			//SFURL
972 			else if (!strcmp(bf->familly, "SFURL")) {
973 				if (strcmp(bf->def, "NULL"))
974 					fprintf(f, "\tp->%s = %s;\n", bf->name, bf->def);
975 			}
976 			//SFColor
977 			else if (!strcmp(bf->familly, "SFColor")) {
978 				CurrentLine = bf->def;
979 				GetNextToken(token, " ");
980 				TranslateToken(token);
981 
982 				fprintf(f, "\tp->%s.red = %s;\n", bf->name, GetFixedPrintout(token));
983 				GetNextToken(token, " ");
984 				fprintf(f, "\tp->%s.green = %s;\n", bf->name, GetFixedPrintout(token));
985 				GetNextToken(token, " ");
986 				fprintf(f, "\tp->%s.blue = %s;\n", bf->name, GetFixedPrintout(token));
987 			}
988 			//SFVec2f
989 			else if (!strcmp(bf->familly, "SFVec2f")) {
990 				CurrentLine = bf->def;
991 				GetNextToken(token, " ");
992 				TranslateToken(token);
993 				fprintf(f, "\tp->%s.x = %s;\n", bf->name, GetFixedPrintout(token));
994 				GetNextToken(token, " ");
995 				TranslateToken(token);
996 				fprintf(f, "\tp->%s.y = %s;\n", bf->name, GetFixedPrintout(token));
997 			}
998 			//SFVec3f
999 			else if (!strcmp(bf->familly, "SFVec3f")) {
1000 				CurrentLine = bf->def;
1001 				GetNextToken(token, " ");
1002 				TranslateToken(token);
1003 				fprintf(f, "\tp->%s.x = %s;\n", bf->name, GetFixedPrintout(token));
1004 
1005 				GetNextToken(token, " ");
1006 				TranslateToken(token);
1007 				fprintf(f, "\tp->%s.y = %s;\n", bf->name, GetFixedPrintout(token));
1008 
1009 				GetNextToken(token, " ");
1010 				TranslateToken(token);
1011 				fprintf(f, "\tp->%s.z = %s;\n", bf->name, GetFixedPrintout(token));
1012 			}
1013 			//SFVec4f & SFRotation
1014 			else if (!strcmp(bf->familly, "SFVec4f") || !strcmp(bf->familly, "SFRotation")) {
1015 				CurrentLine = bf->def;
1016 				GetNextToken(token, " ");
1017 				TranslateToken(token);
1018 				fprintf(f, "\tp->%s.x = %s;\n", bf->name, GetFixedPrintout(token));
1019 
1020 				GetNextToken(token, " ");
1021 				TranslateToken(token);
1022 				fprintf(f, "\tp->%s.y = %s;\n", bf->name, GetFixedPrintout(token));
1023 
1024 				GetNextToken(token, " ");
1025 				TranslateToken(token);
1026 				fprintf(f, "\tp->%s.z = %s;\n", bf->name, GetFixedPrintout(token));
1027 
1028 				GetNextToken(token, " ");
1029 				TranslateToken(token);
1030 				fprintf(f, "\tp->%s.q = %s;\n", bf->name, GetFixedPrintout(token));
1031 			}
1032 			//SFString
1033 			else if (!strcmp(bf->familly, "SFString")) {
1034 				fprintf(f, "\tp->%s.buffer = (char*)gf_malloc(sizeof(char) * %u);\n", bf->name, (u32) strlen(bf->def)+1);
1035 				fprintf(f, "\tstrcpy(p->%s.buffer, \"%s\");\n", bf->name, bf->def);
1036 			}
1037 
1038 			//
1039 			//		MF Fields
1040 			//
1041 			//MFFloat
1042 			else if (!strcmp(bf->familly, "MFFloat")) {
1043 				j = 0;
1044 				CurrentLine = bf->def;
1045 				while (GetNextToken(token, " ,")) j++;
1046 				j+=1;
1047 				fprintf(f, "\tp->%s.vals = (SFFloat*)gf_malloc(sizeof(SFFloat)*%d);\n", bf->name, j);
1048 				fprintf(f, "\tp->%s.count = %d;\n", bf->name, j);
1049 				j = 0;
1050 				go = 1;
1051 				CurrentLine = bf->def;
1052 				while (go) {
1053 					if (!GetNextToken(token, " ,")) go = 0;
1054 					TranslateToken(token);
1055 					fprintf(f, "\tp->%s.vals[%d] = %s;\n", bf->name, j, GetFixedPrintout(token));
1056 					j+=1;
1057 				}
1058 			}
1059 			//MFVec2f
1060 			else if (!strcmp(bf->familly, "MFVec2f")) {
1061 				j = 0;
1062 				CurrentLine = bf->def;
1063 				while (GetNextToken(token, ",")) j++;
1064 				j+=1;
1065 				fprintf(f, "\tp->%s.vals = (SFVec2f*)gf_malloc(sizeof(SFVec2f)*%d);\n", bf->name, j);
1066 				fprintf(f, "\tp->%s.count = %d;\n", bf->name, j);
1067 				j = 0;
1068 				go = 1;
1069 				CurrentLine = bf->def;
1070 				while (go) {
1071 					if (!GetNextToken(token, ",")) go = 0;
1072 					store = CurrentLine;
1073 					CurrentLine = token;
1074 					GetNextToken(tok, " ");
1075 					TranslateToken(tok);
1076 					fprintf(f, "\tp->%s.vals[%d].x = %s;\n", bf->name, j, GetFixedPrintout(tok));
1077 					GetNextToken(tok, " ");
1078 					TranslateToken(tok);
1079 					fprintf(f, "\tp->%s.vals[%d].y = %s;\n", bf->name, j, GetFixedPrintout(tok));
1080 					j+=1;
1081 					CurrentLine = store;
1082 				}
1083 			}
1084 			//MFVec3f
1085 			else if (!strcmp(bf->familly, "MFVec3f")) {
1086 				j = 0;
1087 				CurrentLine = bf->def;
1088 				while (GetNextToken(token, ",")) j++;
1089 				j+=1;
1090 				fprintf(f, "\tp->%s.vals = (SFVec3f *)gf_malloc(sizeof(SFVec3f)*%d);\n", bf->name, j);
1091 				fprintf(f, "\tp->%s.count = %d;\n", bf->name, j);
1092 				j = 0;
1093 				go = 1;
1094 				CurrentLine = bf->def;
1095 				while (go) {
1096 					if (!GetNextToken(token, ",")) go = 0;
1097 					store = CurrentLine;
1098 					CurrentLine = token;
1099 					GetNextToken(tok, " ");
1100 					TranslateToken(tok);
1101 					fprintf(f, "\tp->%s.vals[%d].x = %s;\n", bf->name, j, GetFixedPrintout(tok));
1102 					GetNextToken(tok, " ");
1103 					TranslateToken(tok);
1104 					fprintf(f, "\tp->%s.vals[%d].y = %s;\n", bf->name, j, GetFixedPrintout(tok));
1105 					GetNextToken(tok, " ");
1106 					TranslateToken(tok);
1107 					fprintf(f, "\tp->%s.vals[%d].z = %s;\n", bf->name, j, GetFixedPrintout(tok));
1108 					j+=1;
1109 					CurrentLine = store;
1110 				}
1111 			}
1112 			//MFVec4f
1113 			else if (!strcmp(bf->familly, "MFVec4f") || !strcmp(bf->familly, "MFRotation")) {
1114 				j = 0;
1115 				CurrentLine = bf->def;
1116 				while (GetNextToken(token, ",")) j++;
1117 				j+=1;
1118 				fprintf(f, "\tp->%s.vals = (GF_Vec4*)gf_malloc(sizeof(GF_Vec4)*%d);\n", bf->name, j);
1119 				fprintf(f, "\tp->%s.count = %d;\n", bf->name, j);
1120 				j = 0;
1121 				go = 1;
1122 				CurrentLine = bf->def;
1123 				while (go) {
1124 					if (!GetNextToken(token, ",")) go = 0;
1125 					store = CurrentLine;
1126 					CurrentLine = token;
1127 					GetNextToken(tok, " ");
1128 					TranslateToken(tok);
1129 					fprintf(f, "\tp->%s.vals[%d].x = %s;\n", bf->name, j, GetFixedPrintout(tok));
1130 					GetNextToken(tok, " ");
1131 					TranslateToken(tok);
1132 					fprintf(f, "\tp->%s.vals[%d].y = %s;\n", bf->name, j, GetFixedPrintout(tok));
1133 					GetNextToken(tok, " ");
1134 					TranslateToken(tok);
1135 					fprintf(f, "\tp->%s.vals[%d].z = %s;\n", bf->name, j, GetFixedPrintout(tok));
1136 					GetNextToken(tok, " ");
1137 					TranslateToken(tok);
1138 					fprintf(f, "\tp->%s.vals[%d].q = %s;\n", bf->name, j, GetFixedPrintout(tok));
1139 					j+=1;
1140 					CurrentLine = store;
1141 				}
1142 			}
1143 			//MFInt32
1144 			else if (!strcmp(bf->familly, "MFInt32")) {
1145 				j = 0;
1146 				CurrentLine = bf->def;
1147 				while (GetNextToken(token, ",")) j++;
1148 				j+=1;
1149 				fprintf(f, "\tp->%s.vals = (SFInt32*)gf_malloc(sizeof(SFInt32)*%d);\n", bf->name, j);
1150 				fprintf(f, "\tp->%s.count = %d;\n", bf->name, j);
1151 				j = 0;
1152 				go = 1;
1153 				CurrentLine = bf->def;
1154 				while (go) {
1155 					if (!GetNextToken(token, ",")) go = 0;
1156 					store = CurrentLine;
1157 					CurrentLine = token;
1158 					GetNextToken(tok, " ");
1159 					fprintf(f, "\tp->%s.vals[%d] = %s;\n", bf->name, j, tok);
1160 					j+=1;
1161 					CurrentLine = store;
1162 				}
1163 			}
1164 			//MFColor
1165 			else if (!strcmp(bf->familly, "MFColor")) {
1166 				j = 0;
1167 				CurrentLine = bf->def;
1168 				while (GetNextToken(token, ",")) j++;
1169 				j+=1;
1170 				fprintf(f, "\tp->%s.vals = (SFColor*)gf_malloc(sizeof(SFColor)*%d);\n", bf->name, j);
1171 				fprintf(f, "\tp->%s.count = %d;\n", bf->name, j);
1172 				j = 0;
1173 				go = 1;
1174 				CurrentLine = bf->def;
1175 				while (go) {
1176 					if (!GetNextToken(token, ",")) go = 0;
1177 					store = CurrentLine;
1178 					CurrentLine = token;
1179 					GetNextToken(tok, " ");
1180 					fprintf(f, "\tp->%s.vals[%d].red = %s;\n", bf->name, j, GetFixedPrintout(tok));
1181 					GetNextToken(tok, " ");
1182 					fprintf(f, "\tp->%s.vals[%d].green = %s;\n", bf->name, j, GetFixedPrintout(tok));
1183 					GetNextToken(tok, " ");
1184 					fprintf(f, "\tp->%s.vals[%d].blue = %s;\n", bf->name, j, GetFixedPrintout(tok));
1185 					j+=1;
1186 					CurrentLine = store;
1187 				}
1188 			}
1189 			//MFString
1190 			else if (!strcmp(bf->familly, "MFString")) {
1191 				j = 0;
1192 				CurrentLine = bf->def;
1193 				while (GetNextToken(token, ",")) j++;
1194 				j+=1;
1195 				fprintf(f, "\tp->%s.vals = (char**)gf_malloc(sizeof(SFString)*%d);\n", bf->name, j);
1196 				fprintf(f, "\tp->%s.count = %d;\n", bf->name, j);
1197 				j = 0;
1198 				go = 1;
1199 				CurrentLine = bf->def;
1200 				while (go) {
1201 					if (!GetNextToken(token, ",")) go = 0;
1202 					store = CurrentLine;
1203 					CurrentLine = token;
1204 					GetNextToken(tok, " \"");
1205 					fprintf(f, "\tp->%s.vals[%d] = (char*)gf_malloc(sizeof(char) * %u);\n", bf->name, j, (u32) strlen(tok)+1);
1206 					fprintf(f, "\tstrcpy(p->%s.vals[%d], \"%s\");\n", bf->name, j, tok);
1207 					j+=1;
1208 					CurrentLine = store;
1209 				}
1210 			}
1211 			//MFTime
1212 			else if (!strcmp(bf->familly, "MFTime")) {
1213 				j = 0;
1214 				CurrentLine = bf->def;
1215 				while (GetNextToken(token, ",")) j++;
1216 				j+=1;
1217 				fprintf(f, "\tp->%s.vals = (SFTime*)gf_malloc(sizeof(SFTime)*%d);\n", bf->name, j);
1218 				fprintf(f, "\tp->%s.count = %d;\n", bf->name, j);
1219 				j = 0;
1220 				go = 1;
1221 				CurrentLine = bf->def;
1222 				while (go) {
1223 					if (!GetNextToken(token, ",")) go = 0;
1224 					store = CurrentLine;
1225 					CurrentLine = token;
1226 					GetNextToken(tok, " \"");
1227 					TranslateToken(tok);
1228 					fprintf(f, "\tp->%s.vals[%d] = %s;\n", bf->name, j, tok);
1229 					j+=1;
1230 					CurrentLine = store;
1231 				}
1232 			}
1233 
1234 			//other nodes
1235 			else if (!strcmp(bf->familly, "SFImage")) {
1236 				//we currently only have SFImage, with NO texture so do nothing
1237 			}
1238 			//unknown init (for debug)
1239 			else {
1240 				fprintf(f, "UNKNOWN FIELD (%s);\n", bf->familly);
1241 
1242 			}
1243 		}
1244 		fprintf(f, "\treturn (GF_Node *)p;\n}\n\n");
1245 
1246 	}
1247 
1248 	fprintf(f, "\n\n\n");
1249 
1250 	//creator function
1251 	fprintf(f, "GF_Node *gf_sg_mpeg4_node_new(u32 NodeTag)\n{\n\tswitch (NodeTag) {\n");
1252 	for (i=0; i<gf_list_count(BNodes); i++) {
1253 		n = gf_list_get(BNodes, i);
1254 		if (!n->skip_impl) {
1255 			fprintf(f, "\tcase TAG_MPEG4_%s:\n\t\treturn %s_Create();\n", n->name, n->name);
1256 		}
1257 	}
1258 	fprintf(f, "\tdefault:\n\t\treturn NULL;\n\t}\n}\n\n");
1259 
1260 	fprintf(f, "const char *gf_sg_mpeg4_node_get_class_name(u32 NodeTag)\n{\n\tswitch (NodeTag) {\n");
1261 	for (i=0; i<gf_list_count(BNodes); i++) {
1262 		n = gf_list_get(BNodes, i);
1263 		if (!n->skip_impl) fprintf(f, "\tcase TAG_MPEG4_%s:\n\t\treturn \"%s\";\n", n->name, n->name);
1264 	}
1265 	fprintf(f, "\tdefault:\n\t\treturn \"Unknown Node\";\n\t}\n}\n\n");
1266 
1267 	fprintf(f, "void gf_sg_mpeg4_node_del(GF_Node *node)\n{\n\tswitch (node->sgprivate->tag) {\n");
1268 	for (i=0; i<gf_list_count(BNodes); i++) {
1269 		n = gf_list_get(BNodes, i);
1270 		if (!n->skip_impl) {
1271 			fprintf(f, "\tcase TAG_MPEG4_%s:\n\t\t%s_Del(node); return;\n", n->name, n->name);
1272 		}
1273 	}
1274 	fprintf(f, "\tdefault:\n\t\treturn;\n\t}\n}\n\n");
1275 
1276 	fprintf(f, "u32 gf_sg_mpeg4_node_get_field_count(GF_Node *node, u8 code_mode)\n{\n\tswitch (node->sgprivate->tag) {\n");
1277 	for (i=0; i<gf_list_count(BNodes); i++) {
1278 		n = gf_list_get(BNodes, i);
1279 		if (!n->skip_impl) {
1280 			fprintf(f, "\tcase TAG_MPEG4_%s:return %s_get_field_count(node, code_mode);\n", n->name, n->name);
1281 		}
1282 	}
1283 	fprintf(f, "\tdefault:\n\t\treturn 0;\n\t}\n}\n\n");
1284 
1285 	fprintf(f, "GF_Err gf_sg_mpeg4_node_get_field(GF_Node *node, GF_FieldInfo *field)\n{\n\tswitch (node->sgprivate->tag) {\n");
1286 	for (i=0; i<gf_list_count(BNodes); i++) {
1287 		n = gf_list_get(BNodes, i);
1288 		if (!n->skip_impl) {
1289 			fprintf(f, "\tcase TAG_MPEG4_%s: return %s_get_field(node, field);\n", n->name, n->name);
1290 		}
1291 	}
1292 	fprintf(f, "\tdefault:\n\t\treturn GF_BAD_PARAM;\n\t}\n}\n\n");
1293 
1294 	fprintf(f, "GF_Err gf_sg_mpeg4_node_get_field_index(GF_Node *node, u32 inField, u8 code_mode, u32 *fieldIndex)\n{\n\tswitch (node->sgprivate->tag) {\n");
1295 	for (i=0; i<gf_list_count(BNodes); i++) {
1296 		n = gf_list_get(BNodes, i);
1297 		if (!n->skip_impl) {
1298 			fprintf(f, "\tcase TAG_MPEG4_%s: return %s_get_field_index(node, inField, code_mode, fieldIndex);\n", n->name, n->name);
1299 		}
1300 	}
1301 	fprintf(f, "\tdefault:\n\t\treturn GF_BAD_PARAM;\n\t}\n}\n\n");
1302 
1303 	fprintf(f, "Bool gf_sg_mpeg4_node_get_aq_info(GF_Node *node, u32 FieldIndex, u8 *QType, u8 *AType, Fixed *b_min, Fixed *b_max, u32 *QT13_bits)\n{\n\tswitch (node->sgprivate->tag) {\n");
1304 	for (i=0; i<gf_list_count(BNodes); i++) {
1305 		n = gf_list_get(BNodes, i);
1306 		if (!n->skip_impl) {
1307 			fprintf(f, "\tcase TAG_MPEG4_%s: return %s_get_aq_info(node, FieldIndex, QType, AType, b_min, b_max, QT13_bits);\n", n->name, n->name);
1308 		}
1309 	}
1310 	fprintf(f, "\tdefault:\n\t\treturn 0;\n\t}\n}\n\n");
1311 
1312 	fprintf(f, "u32 gf_sg_mpeg4_node_get_child_ndt(GF_Node *node)\n{\n\tswitch (node->sgprivate->tag) {\n");
1313 	for (i=0; i<gf_list_count(BNodes); i++) {
1314 		n = gf_list_get(BNodes, i);
1315 		if (!n->skip_impl && strlen(n->Child_NDT_Name) ) {
1316 			fprintf(f, "\tcase TAG_MPEG4_%s: return %s;\n", n->name, n->Child_NDT_Name);
1317 		}
1318 	}
1319 	fprintf(f, "\tdefault:\n\t\treturn 0;\n\t}\n}\n\n");
1320 
1321 
1322 	fprintf(f, "\nu32 gf_node_mpeg4_type_by_class_name(const char *node_name)\n{\n\tif(!node_name) return 0;\n");
1323 	for (i=0; i<gf_list_count(BNodes); i++) {
1324 		n = gf_list_get(BNodes, i);
1325 		if (n->skip_impl) continue;
1326 		fprintf(f, "\tif (!strcmp(node_name, \"%s\")) return TAG_MPEG4_%s;\n", n->name, n->name);
1327 	}
1328 	fprintf(f, "\treturn 0;\n}\n\n");
1329 
1330 	fprintf(f, "s32 gf_sg_mpeg4_node_get_field_index_by_name(GF_Node *node, char *name)\n{\n\tswitch (node->sgprivate->tag) {\n");
1331 	for (i=0; i<gf_list_count(BNodes); i++) {
1332 		n = gf_list_get(BNodes, i);
1333 		if (!n->skip_impl) {
1334 			fprintf(f, "\tcase TAG_MPEG4_%s: return %s_get_field_index_by_name(name);\n", n->name, n->name);
1335 		}
1336 	}
1337 	fprintf(f, "\tdefault:\n\t\treturn -1;\n\t}\n}\n\n");
1338 
1339 	fprintf(f, "\n#endif /*GPAC_DISABLE_VRML*/\n");
1340 
1341 	EndFile(f, "", 1);
1342 }
1343 
ParseTemplateFile(FILE * nodes,GF_List * BNodes,GF_List * NDTs,u32 version)1344 void ParseTemplateFile(FILE *nodes, GF_List *BNodes, GF_List *NDTs, u32 version)
1345 {
1346 	char sLine[2000];
1347 	char token[100];
1348 	char *p;
1349 	BNode *n;
1350 	BField *f;
1351 	u32 j, i, k;
1352 
1353 	//get lines one by one
1354 	n = NULL;
1355 	while (!feof(nodes)) {
1356 		fgets(sLine, 2000, nodes);
1357 		//skip comment and empty lines
1358 		if (sLine[0] == '#') continue;
1359 		if (sLine[0] == '\n') continue;
1360 
1361 		CurrentLine = sLine;
1362 
1363 		//parse the line till end of line
1364 		while (GetNextToken(token, " \t")) {
1365 
1366 			//this is a new node
1367 			if (!strcmp(token, "PROTO") ) {
1368 				n = BlankNode();
1369 				n->version = version;
1370 				gf_list_add(BNodes, n);
1371 
1372 				//get its name
1373 				GetNextToken(n->name, " \t[");
1374 				//extract the NDTs
1375 				GetNextToken(token, "\t[ %#=");
1376 				if (strcmp(token, "NDT")) {
1377 					printf("Corrupted template file\n");
1378 					return;
1379 				}
1380 				while (1) {
1381 					GetNextToken(token, "=, \t");
1382 					//done with NDTs
1383 					if (token[0] == '%') break;
1384 
1385 					//update the NDT list
1386 					CheckInTable(token, NDTs);
1387 					p = gf_malloc(strlen(token)+1);
1388 					strcpy(p, token);
1389 					gf_list_add(n->NDT, p);
1390 				}
1391 
1392 				//extract the coding type
1393 				if (strcmp(token, "%COD")) {
1394 					printf("Corrupted template file\n");
1395 					return;
1396 				} else {
1397 					GetNextToken(token, "= ");
1398 					if (token[0] == 'N') {
1399 						n->codingType = 0;
1400 					} else {
1401 						n->codingType = 1;
1402 					}
1403 				}
1404 			}
1405 			//this is NOT a field
1406 			else if (token[0] == ']' || token[0] == '{' || token[0] == '}' ) {
1407 				break;
1408 			}
1409 			//parse a field
1410 			else {
1411 				if (!n) {
1412 					printf("Corrupted template file\n");
1413 					return;
1414 				}
1415 				f = BlankField();
1416 				gf_list_add(n->Fields, f);
1417 
1418 				//get the field type
1419 				strcpy(f->type, token);
1420 				GetNextToken(f->familly, " \t");
1421 				GetNextToken(f->name, " \t");
1422 				//fix for our own code :(
1423 				if (!strcmp(f->name, "tag")) strcpy(f->name, "_tag");
1424 				if (!strcmp(f->name, "auto")) strcpy(f->name, "_auto");
1425 
1426 				//has default
1427 				skip_sep(" \t");
1428 				if (GetNextToken(token, "#\t")) {
1429 					j=0;
1430 					while (token[j] == ' ') j+=1;
1431 					if (token[j] == '[') j+=1;
1432 					if (token[j] == '"') j+=1;
1433 
1434 					if (token[j] != '"' && token[j] != ']') {
1435 						strcpy(f->def, token+j);
1436 						j=1;
1437 						while (j) {
1438 							switch (f->def[strlen(f->def)-1]) {
1439 							case ' ':
1440 							case '"':
1441 							case ']':
1442 								f->def[strlen(f->def)-1] = 0;
1443 								break;
1444 							default:
1445 								j=0;
1446 								break;
1447 							}
1448 						}
1449 					} else {
1450 						strcpy(f->def, "");
1451 					}
1452 					if (!strcmp(f->familly, "SFFloat")) {
1453 						if (!strcmp(f->def, "+I") || !strcmp(f->def, "I")) {
1454 							strcpy(f->def, "FIX_MAX");
1455 						} else if (!strcmp(f->def, "-I")) {
1456 							strcpy(f->def, "FIX_MIN");
1457 						}
1458 					} else if (!strcmp(f->familly, "SFTime")) {
1459 						if (!strcmp(f->def, "+I") || !strcmp(f->def, "I")) {
1460 							strcpy(f->def, "FIX_MAX");
1461 						} else if (!strcmp(f->def, "-I")) {
1462 							strcpy(f->def, "FIX_MIN");
1463 						}
1464 					} else if (!strcmp(f->familly, "SFInt32")) {
1465 						if (!strcmp(f->def, "+I") || !strcmp(f->def, "I")) {
1466 							strcpy(f->def, "0x80000000");
1467 						} else if (!strcmp(f->def, "-I")) {
1468 							strcpy(f->def, "GF_INT_MIN");
1469 						}
1470 					}
1471 				}
1472 				//has other
1473 				while (GetNextToken(token, " \t#%=")) {
1474 					switch (token[0]) {
1475 					//bounds
1476 					case 'b':
1477 						f->hasBounds = 1;
1478 						GetNextToken(f->b_min, "[(,");
1479 						GetNextToken(f->b_max, ")]");
1480 						break;
1481 					case 'q':
1482 						f->hasQuant = 1;
1483 						GetNextToken(f->quant_type, " \t");
1484 						if (!strcmp(f->quant_type, "13"))
1485 							GetNextToken(f->qt13_bits, " \t");
1486 						break;
1487 					case 'a':
1488 						f->hasAnim = 1;
1489 						GetNextToken(token, " \t");
1490 						f->AnimType = atoi(token);
1491 						break;
1492 					default:
1493 						break;
1494 					}
1495 				}
1496 			}
1497 		}
1498 	}
1499 
1500 
1501 	for (k=0; k<gf_list_count(BNodes); k++) {
1502 		n = gf_list_get(BNodes, k);
1503 
1504 		for (i=0; i<gf_list_count(n->Fields); i++) {
1505 			f = gf_list_get(n->Fields, i);
1506 			//nothing on events
1507 			if (!strcmp(f->type, "eventIn")) continue;
1508 			if (!strcmp(f->type, "eventOut")) continue;
1509 			if (!strcmp(f->def, "")) continue;
1510 			if (strstr(f->familly, "Node")) continue;
1511 			n->hasDefault = 1;
1512 		}
1513 	}
1514 }
1515 
1516 
WriteNodeDump(FILE * f,BNode * n)1517 void WriteNodeDump(FILE *f, BNode *n)
1518 {
1519 	u32 i;
1520 
1521 	fprintf(f, "static const char *%s_FieldName[] = {\n", n->name);
1522 	for (i=0; i<gf_list_count(n->Fields); i++) {
1523 		BField *bf = gf_list_get(n->Fields, i);
1524 		if (!i) {
1525 			fprintf(f, " \"%s\"", bf->name);
1526 		} else {
1527 			fprintf(f, ", \"%s\"", bf->name);
1528 		}
1529 	}
1530 	fprintf(f, "\n};\n\n");
1531 }
1532 
parse_profile(GF_List * nodes,FILE * prof)1533 void parse_profile(GF_List *nodes, FILE *prof)
1534 {
1535 	char sLine[2000];
1536 	BNode *n;
1537 	Bool found;
1538 	u32 i;
1539 
1540 	while (!feof(prof)) {
1541 		fgets(sLine, 2000, prof);
1542 		//skip comment and empty lines
1543 		if (sLine[0] == '#') continue;
1544 		if (sLine[0] == '\n') continue;
1545 		if (strstr(sLine, "Proximity"))
1546 			found = 0;
1547 		found = 1;
1548 		while (found) {
1549 			switch (sLine[strlen(sLine)-1]) {
1550 			case '\n':
1551 			case '\r':
1552 			case ' ':
1553 				sLine[strlen(sLine)-1] = 0;
1554 				break;
1555 			default:
1556 				found = 0;
1557 				break;
1558 			}
1559 		}
1560 
1561 //		if (0 && !stricmp(sLine, "Appearance") || !stricmp(sLine, "Shape") || !stricmp(sLine, "Sound2D") ) {
1562 		if (0) {
1563 			printf("Warning: cannot disable node %s (required in all BIFS profiles)\n", sLine);
1564 		} else {
1565 			found = 0;
1566 			for (i=0; i<gf_list_count(nodes); i++) {
1567 				n = gf_list_get(nodes, i);
1568 				if (!stricmp(n->name, sLine)) {
1569 					n->skip_impl = 1;
1570 					found = 1;
1571 					break;
1572 				}
1573 			}
1574 			if (!found) printf("cannot disable %s: node not found\n", sLine);
1575 		}
1576 	}
1577 }
1578 
format_bit_string(char * str,u32 val,u32 nb_bits)1579 char *format_bit_string(char *str, u32 val, u32 nb_bits)
1580 {
1581 	u32 i, len;
1582 	strcpy(str, "");
1583 	while (nb_bits) {
1584 		strcat(str, (val%2) ? "1" : "0");
1585 		val>>=1;
1586 		nb_bits--;
1587 	}
1588 	len = strlen(str);
1589 	for (i=0; i<len/2; i++) {
1590 		char c = str[i];
1591 		str[i] = str[len-i-1];
1592 		str[len-i-1]=c;
1593 	}
1594 	return str;
1595 }
1596 
get_nb_bits(u32 MaxVal)1597 u32 get_nb_bits(u32 MaxVal)
1598 {
1599 	u32 k=1;
1600 	if (!MaxVal) return 0;
1601 	MaxVal--;
1602 	while (MaxVal > ((1<<k)-1) ) k+=1;
1603 	return k;
1604 }
1605 
generate_ndts(GF_List * NDTs,GF_List * nodes,u32 nbVersion)1606 void generate_ndts(GF_List *NDTs, GF_List *nodes, u32 nbVersion)
1607 {
1608 	u32 nb_nodes, nb_ndt, i, j, k, nb_bits, idx, l;
1609 	char szStr[100];
1610 	nb_ndt = gf_list_count(NDTs);
1611 	nb_nodes = gf_list_count(nodes);
1612 	for (i=0; i<nbVersion; i++) {
1613 		char szFile[100];
1614 		FILE *f;
1615 		sprintf(szFile, "NdtListV%d.html", i+1);
1616 		f = gf_fopen(szFile, "wt");
1617 
1618 		fprintf(f, "<html>\n"\
1619 		        "<head>\n"\
1620 		        "<meta name=\"Author\" content=\"Jean Le Feuvre - GPAC %s\">\n"\
1621 		        "<title>NdtListV%d.html</title>\n"\
1622 		        "</head>\n"\
1623 		        "<body>\n"\
1624 		        "<title>Node Coding Tables for BIFS Version %d group</title>\n"
1625 		        ,gf_gpac_version(), i+1, i+1);
1626 
1627 		for (j=0; j<nb_ndt; j++) {
1628 			u32 nb_in_ndt = 0;
1629 			char *ndt = gf_list_get(NDTs, j);
1630 			for (k=0; k<nb_nodes; k++) {
1631 				BNode *n = gf_list_get(nodes, k);
1632 				if (n->version != i+1) continue;
1633 				if (!IsNodeInTable(n, ndt)) continue;
1634 				nb_in_ndt ++;
1635 			}
1636 
1637 			if (!nb_in_ndt) continue;
1638 
1639 			fprintf(f, "<BR><a name=\"%s\">\n"\
1640 			        "<TABLE BORDER COLS=\"10\" CELLSPACING=\"0\" WIDTH=\"100%%\">\n"\
1641 			        "<TD COLSPAN=\"2\" width=\"200\"><B>%s</B></TD>\n"\
1642 			        "<TD COLSPAN=\"4\"><B>%u nodes</B></TD>\n", ndt, ndt, nb_in_ndt);
1643 
1644 			nb_bits = GetBitsCount(nb_in_ndt);
1645 			fprintf(f, "<TR><TD>reserved</TD><TD><P align=CENTER>%s</TD><TD><P align=RIGHT>&nbsp;</TD><TD><P align=RIGHT>&nbsp;</TD><TD><P align=RIGHT>&nbsp;</TD><TD><P align=RIGHT>&nbsp;</TD></TR>\n", format_bit_string(szStr, 0, nb_bits));
1646 
1647 			idx = 1;
1648 			for (k=0; k<nb_nodes; k++) {
1649 				BNode *n = gf_list_get(nodes, k);
1650 				if (n->version != i+1) continue;
1651 				if (!IsNodeInTable(n, ndt)) continue;
1652 
1653 
1654 				n->hasDef = n->hasIn = n->hasOut = n->hasDyn = 0;
1655 				for (l=0; l<gf_list_count(n->Fields); l++) {
1656 					BField *bf = gf_list_get(n->Fields, l);
1657 					if (!strcmp(bf->type, "field") || !strcmp(bf->type, "exposedField")) {
1658 						n->hasDef += 1;
1659 					}
1660 					if (!strcmp(bf->type, "eventIn") || !strcmp(bf->type, "exposedField")) {
1661 						n->hasIn += 1;
1662 						//check for anim
1663 						if (bf->hasAnim) n->hasDyn += 1;
1664 					}
1665 					if (!strcmp(bf->type, "eventOut") || !strcmp(bf->type, "exposedField")) {
1666 						n->hasOut += 1;
1667 					}
1668 				}
1669 
1670 				fprintf(f, "<TR><TD>%s</TD><TD><P align=CENTER>%s</TD><TD><P align=RIGHT>%d DEF bits</TD><TD><P align=RIGHT>%d IN bits</TD><TD><P align=RIGHT>%d OUT bits</TD><TD><P align=RIGHT>%d DYN bits</TD></TR>\n", n->name, format_bit_string(szStr, idx, nb_bits), get_nb_bits(n->hasDef), get_nb_bits(n->hasIn), get_nb_bits(n->hasOut), get_nb_bits(n->hasDyn));
1671 				idx++;
1672 			}
1673 
1674 			fprintf(f, "</TABLE>\n");
1675 		}
1676 		gf_fclose(f);
1677 	}
1678 
1679 }
1680 
main(int argc,char ** argv)1681 int main (int argc, char **argv)
1682 {
1683 	Bool generate_ndt = 0;
1684 	char szTempFile[1024];
1685 	FILE *nodes, *ndt_c, *ndt_h, *fskip;
1686 	GF_List *BNodes, *NDTs;
1687 	u32 i, j, nbVersion;
1688 	BNode *n;
1689 	BField *bf;
1690 
1691 	if (argc < 1) {
1692 		PrintUsage();
1693 		return 0;
1694 	}
1695 
1696 	BNodes = gf_list_new();
1697 	NDTs = gf_list_new();
1698 
1699 
1700 
1701 	fskip = NULL;
1702 	if (argc>1) {
1703 		i=1;
1704 		if (!strcmp(argv[i], "-ndt")) {
1705 			generate_ndt = 1;
1706 		} else if (argv[i][0]=='-') {
1707 			fskip = gf_fopen(argv[i+1], "rt");
1708 			if (!fskip) {
1709 				printf("file %s not found\n", argv[i+1]);
1710 				return 0;
1711 			}
1712 			i+=2;
1713 		}
1714 	}
1715 	nbVersion=1;
1716 	while (1) {
1717 		sprintf(szTempFile, "templates%u.txt", nbVersion);
1718 		nodes = gf_fopen(szTempFile, "rt");
1719 		if (!nodes) {
1720 			sprintf(szTempFile, "template%u.txt", nbVersion);
1721 			nodes = gf_fopen(szTempFile, "rt");
1722 		}
1723 		if (!nodes) break;
1724 
1725 		//all nodes are in the same list but we keep version info
1726 		ParseTemplateFile(nodes, BNodes, NDTs, nbVersion);
1727 
1728 
1729 		//special case for viewport: it is present in V1 but empty
1730 		if (nbVersion==1) CheckInTable("SFViewportNode", NDTs);
1731 		nbVersion++;
1732 		gf_fclose(nodes);
1733 	}
1734 	nbVersion--;
1735 	printf("BIFS tables parsed: %d versions\n", nbVersion);
1736 
1737 	if (generate_ndt) {
1738 		generate_ndts(NDTs, BNodes, nbVersion);
1739 		goto exit;
1740 	}
1741 
1742 	if (fskip) {
1743 		parse_profile(BNodes, fskip);
1744 		gf_fclose(fskip);
1745 	}
1746 
1747 	//write the nodes def
1748 	WriteNodesFile(BNodes, NDTs, nbVersion);
1749 	//write all nodes init stuff
1750 	WriteNodeCode(BNodes);
1751 
1752 	//write all NDTs
1753 	ndt_h = BeginFile("NDT", 0);
1754 	ndt_c = BeginFile("NDT", 1);
1755 
1756 	fprintf(ndt_h, "#include <gpac/nodes_mpeg4.h>\n\n");
1757 	fprintf(ndt_h, "\n\n#ifndef GPAC_DISABLE_BIFS\n");
1758 
1759 	fprintf(ndt_c, "\n\n#include <gpac/internal/bifs_tables.h>\n");
1760 	fprintf(ndt_c, "\n\n#ifndef GPAC_DISABLE_BIFS\n");
1761 
1762 	//prepare the encoding file
1763 	fprintf(ndt_h, "\n\nu32 ALL_GetNodeType(const u32 *table, const u32 count, u32 NodeTag, u32 Version);\n\n");
1764 	fprintf(ndt_c, "\n\nu32 ALL_GetNodeType(const u32 *table, const u32 count, u32 NodeTag, u32 Version)\n{\n\tu32 i = 0;");
1765 	fprintf(ndt_c, "\n\twhile (i<count) {\n\t\tif (table[i] == NodeTag) goto found;\n\t\ti++;\n\t}\n\treturn 0;\nfound:\n\tif (Version == 2) return i+2;\n\treturn i+1;\n}\n\n");
1766 
1767 	//write the NDT
1768 	for (i=0; i<nbVersion; i++) {
1769 		//write header
1770 		WriteNDT_H(ndt_h, BNodes, NDTs, i+1);
1771 		//write decoding code
1772 		WriteNDT_Dec(ndt_c, BNodes, NDTs, i+1);
1773 		//write encoding code
1774 		WriteNDT_Enc(ndt_c, BNodes, NDTs, i+1);
1775 	}
1776 
1777 
1778 
1779 	fprintf(ndt_c, "\n\nu32 gf_bifs_ndt_get_node_type(u32 NDT_Tag, u32 NodeType, u32 Version)\n{\n\tswitch (Version) {\n");
1780 	for (i=0; i<nbVersion; i++) {
1781 		fprintf(ndt_c, "\tcase GF_BIFS_V%d:\n\t\treturn NDT_V%d_GetNodeTag(NDT_Tag, NodeType);\n", i+1, i+1);
1782 	}
1783 	fprintf(ndt_c, "\tdefault:\n\t\treturn 0;\n\t}\n}");
1784 
1785 	fprintf(ndt_c, "\n\nu32 gf_bifs_get_ndt_bits(u32 NDT_Tag, u32 Version)\n{\n\tswitch (Version) {\n");
1786 	for (i=0; i<nbVersion; i++) {
1787 		fprintf(ndt_c, "\tcase GF_BIFS_V%d:\n\t\treturn NDT_V%d_GetNumBits(NDT_Tag);\n", i+1, i+1);
1788 	}
1789 	fprintf(ndt_c, "\tdefault:\n\t\treturn 0;\n\t}\n}");
1790 
1791 	fprintf(ndt_c, "\n\nu32 gf_bifs_get_node_type(u32 NDT_Tag, u32 NodeTag, u32 Version)\n{\n\tswitch (Version) {\n");
1792 	for (i=0; i<nbVersion; i++) {
1793 		fprintf(ndt_c, "\tcase GF_BIFS_V%d:\n\t\treturn NDT_V%d_GetNodeType(NDT_Tag, NodeTag);\n", i+1, i+1);
1794 	}
1795 	fprintf(ndt_c, "\tdefault:\n\t\treturn 0;\n\t}\n}");
1796 
1797 	fprintf(ndt_h, "\nu32 NDT_GetChildTable(u32 NodeTag);\n");
1798 	fprintf(ndt_h, "\n\n");
1799 
1800 	//NDT checking
1801 	fprintf(ndt_c, "u32 GetChildrenNDT(GF_Node *node)\n{\n\tif (!node) return 0;\n\tswitch (gf_node_get_tag(node)) {\n");
1802 	for (i=0; i<gf_list_count(BNodes); i++) {
1803 		n = gf_list_get(BNodes, i);
1804 		if (n->skip_impl) continue;
1805 		for (j=0; j<gf_list_count(n->Fields); j++) {
1806 			bf = gf_list_get(n->Fields, j);
1807 			if (!strcmp(bf->name, "children")) {
1808 				fprintf(ndt_c, "\tcase TAG_MPEG4_%s:\n\t\treturn NDT_SF%s;\n", n->name, bf->familly+2);
1809 				break;
1810 			}
1811 		}
1812 	}
1813 	fprintf(ndt_c, "\tdefault:\n\t\treturn 0;\n\t}\n}\n\n");
1814 	fprintf(ndt_c, "\n\n#endif /*GPAC_DISABLE_BIFS*/\n\n");
1815 
1816 	fprintf(ndt_h, "\n\n#endif /*GPAC_DISABLE_BIFS*/\n\n");
1817 	EndFile(ndt_h, "NDT", 0);
1818 	EndFile(ndt_c, "", 1);
1819 
1820 
1821 exit:
1822 	//free NDTs
1823 	while (gf_list_count(NDTs)) {
1824 		char *tmp = gf_list_get(NDTs, 0);
1825 		gf_free(tmp);
1826 		gf_list_rem(NDTs, 0);
1827 	}
1828 	gf_list_del(NDTs);
1829 	//free nodes
1830 	while (gf_list_count(BNodes)) {
1831 		n = gf_list_get(BNodes, 0);
1832 		gf_list_rem(BNodes, 0);
1833 		while (gf_list_count(n->NDT)) {
1834 			char *tmp = gf_list_get(n->NDT, 0);
1835 			gf_free(tmp);
1836 			gf_list_rem(n->NDT, 0);
1837 		}
1838 		gf_list_del(n->NDT);
1839 		while (gf_list_count(n->Fields)) {
1840 			bf = gf_list_get(n->Fields, 0);
1841 			gf_free(bf);
1842 			gf_list_rem(n->Fields, 0);
1843 		}
1844 		gf_list_del(n->Fields);
1845 		gf_free(n);
1846 	}
1847 	gf_list_del(BNodes);
1848 
1849 	return 0;
1850 }
1851 
1852