FreeWRL / FreeX3D 4.3.0
X3DParser.c
1/*
2
3
4???
5
6*/
7
8/****************************************************************************
9 This file is part of the FreeWRL/FreeX3D Distribution.
10
11 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
12
13 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
14 it under the terms of the GNU Lesser Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
25****************************************************************************/
26
27
28#include <config.h>
29#include <system.h>
30#include <display.h>
31#include <internal.h>
32
33#include <libFreeWRL.h>
34
35#include "../vrml_parser/Structs.h"
36#include "../main/headers.h"
37#include "../vrml_parser/CParseGeneral.h"
38#include "../scenegraph/Vector.h"
39#include "../vrml_parser/CFieldDecls.h"
40#include "../world_script/JScript.h"
41#include "../world_script/CScripts.h"
42#include "../world_script/fieldSet.h"
43#include "../vrml_parser/CParseParser.h"
44#include "../vrml_parser/CParseLexer.h"
45#include "../vrml_parser/CParse.h"
46#include "../vrml_parser/CRoutes.h"
47#include "../input/EAIHeaders.h" /* resolving implicit declarations */
48#include "../input/EAIHelpers.h" /* resolving implicit declarations */
49
50#include "X3DParser.h"
51
52
53#include <libxml/parser.h>
54
55typedef xmlSAXHandler* XML_Parser;
56
57/* for now - fill this in later */
58#define XML_GetCurrentLineNumber(aaa) (int)999
59
60
61#define XML_ParserFree(aaa) FREE_IF_NZ(aaa)
62#define XML_SetUserData(aaa,bbb)
63#define XML_STATUS_ERROR -1
64
65/* header file for the X3D parser, only items common between the X3DParser files should be here. */
66
67/*#define X3DPARSERVERBOSE 1*/
68#define PARSING_NODES 1
69#define PARSING_SCRIPT 2
70#define PARSING_PROTODECLARE 3
71#define PARSING_PROTOINTERFACE 4
72#define PARSING_PROTOBODY 5
73#define PARSING_PROTOINSTANCE 6
74#define PARSING_IS 7
75#define PARSING_CONNECT 8
76#define PARSING_EXTERNPROTODECLARE 9
77#define PARSING_FIELD 10
78#define PARSING_PROTOINSTANCE_USE 11
79
80/* for our internal PROTO tables, and, for initializing the XML parser */
81#define PROTOINSTANCE_MAX_LEVELS 50
82
83#define LINE freewrl_XML_GetCurrentLineNumber()
84
85// function prototype...
86struct X3D_Node *broto_search_DEFname(struct X3D_Proto *context, const char *name);
87static struct X3D_Node *DEFNameIndex (const char *name, struct X3D_Node* node, int force);
88
90 Stack *context;
91 Stack *nodes;
92 Stack *atts;
93 Stack *modes;
94 Stack *fields;
95};
96
97static struct xml_user_data *new_xml_user_data(){
98 struct xml_user_data *ud = MALLOCV(sizeof(struct xml_user_data));
99 ud->context = ud->nodes = ud->atts = ud->modes = ud->fields = NULL;
100 ud->context = newVector(struct X3D_Node*,256);
101 ud->context->n = 0;
102 ud->nodes = newVector(struct X3D_Node*,256);
103 ud->nodes->n = 0;
104 ud->atts = newVector(void*,256);
105 ud->atts->n = 0;
106 ud->modes = newVector(int,256);
107 ud->modes->n = 0;
108 ud->fields = newVector(char *,256);
109 ud->fields->n = 0;
110 return ud;
111}
112static void free_xml_user_data(struct xml_user_data *ud){
113 if(ud){
114 deleteVector(struct X3D_Node*,ud->context);
115 deleteVector(struct X3D_Node*,ud->nodes);
116 deleteVector(void*,ud->atts);
117 deleteVector(void*,ud->modes);
118 deleteVector(void*,ud->fields);
119 FREE_IF_NZ(ud);
120 }
121}
122//for push,pop,get the index is the vector index range 0, n-1.
123// Or going from the top top= -1, parent to top = -2.
124#define TOP -1
125//#define BOTTOM 0
126
127//currently context isn't a separate struct, its part of X3D_Proto and X3D_Inline, which have
128//the same structure, and can be cross-cast, and represent a web3d executionContext or context for short
129//and that includes DEFnames, ROUTES, protoDeclares, externProtoDeclares, IMPORTS,EXPORTS,scripts
130
131static void pushContext(void *userData, struct X3D_Node* context){
132 struct xml_user_data *ud = (struct xml_user_data *)userData;
133 if(context->_nodeType != NODE_Proto && context->_nodeType != NODE_Inline)
134 printf("attempt to cast a node of type %d to Proto\n",context->_nodeType);
135 stack_push(struct X3D_Proto*,ud->context,X3D_PROTO(context));
136}
137static struct X3D_Proto* getContext(void *userData, int index){
138 struct xml_user_data *ud = (struct xml_user_data *)userData;
139 //return stack_top(struct X3D_Node*,ud->context);
140 if(index < 0)
141 return vector_get(struct X3D_Proto*,ud->context, vectorSize(ud->context)+index);
142 else
143 return vector_get(struct X3D_Proto*,ud->context, index);
144}
145static void popContext(void *userData){
146 struct xml_user_data *ud = (struct xml_user_data *)userData;
147 stack_pop(struct X3D_Proto*,ud->context);
148}
149
150static void pushNode(void *userData,struct X3D_Node* node){
151 struct xml_user_data *ud = (struct xml_user_data *)userData;
152 stack_push(struct X3D_Node*,ud->nodes,node);
153 stack_push(void* ,ud->atts,NULL);
154}
155static struct X3D_Node* getNode(void *userData, int index){
156 struct xml_user_data *ud = (struct xml_user_data *)userData;
157 if(index < 0)
158 return vector_get(struct X3D_Node*,ud->nodes, vectorSize(ud->nodes)+index);
159 else
160 return vector_get(struct X3D_Node*,ud->nodes, index);
161}
162
163static void popNode(void *userData){
164 struct xml_user_data *ud = (struct xml_user_data *)userData;
165 stack_pop(struct X3D_Node*,ud->nodes);
166 stack_pop(void* ,ud->atts);
167 //stack_pop(void* ,ud->childs);
168}
169
170struct mode_name {
171int mode;
172const char *name;
173} mode_names [] = {
174 {PARSING_NODES,"PARSING_NODES"},
175 {PARSING_SCRIPT,"PARSING_SCRIPT"},
176 {PARSING_PROTODECLARE,"PARSING_PROTODECLARE"},
177 {PARSING_PROTOINTERFACE,"PARSING_PROTOINTERFACE"},
178 {PARSING_PROTOBODY,"PARSING_PROTOBODY"},
179 {PARSING_PROTOINSTANCE,"PARSING_PROTOINSTANCE"},
180 {PARSING_IS,"PARSING_IS"},
181 {PARSING_CONNECT,"PARSING_CONNECT"},
182 {PARSING_EXTERNPROTODECLARE,"PARSING_EXTERNPROTODECLARE"},
183 {PARSING_FIELD,"PARSING_FIELD"},
184 {PARSING_PROTOINSTANCE_USE,"PARSING_PROTOINSTANCE_USE"},
185 {0,NULL},
186};
187
188static void pushMode(void *userData, int parsingmode){
189 struct xml_user_data *ud = (struct xml_user_data *)userData;
190 stack_push(int,ud->modes,parsingmode);
191}
192static int getMode(void *userData, int index){
193 struct xml_user_data *ud = (struct xml_user_data *)userData;
194 //return stack_top(int,ud->modes);
195 if(index < 0)
196 return vector_get(int,ud->modes, vectorSize(ud->modes)+index);
197 else
198 return vector_get(int,ud->modes, index);
199}
200static void popMode(void *userData){
201 struct xml_user_data *ud = (struct xml_user_data *)userData;
202 stack_pop(int,ud->modes);
203}
204
205static void pushField(void *userData, const char *fname){
206 struct xml_user_data *ud = (struct xml_user_data *)userData;
207 stack_push(char *,ud->fields,(char *)fname);
208 if(0) printf("push n=%d\n",ud->fields->n);
209}
210static char * getField(void *userData, int index){
211 struct xml_user_data *ud = (struct xml_user_data *)userData;
212 if(0) printf("get n=%d\n",ud->fields->n);
213 if(index < 0)
214 return vector_get(char *,ud->fields, vectorSize(ud->fields)+index);
215 else
216 return vector_get(char *,ud->fields, index);
217}
218
219static void popField(void *userData){
220 struct xml_user_data *ud = (struct xml_user_data *)userData;
221 stack_pop(char *,ud->fields);
222 if(0) printf("pop n=%d\n",ud->fields->n);
223}
224
225static int XML_ParseFile(xmlSAXHandler *me, void *user_data, const char *myinput, int myinputlen, int recovery) {
226
227 if (xmlSAXUserParseMemory(me, user_data, myinput,myinputlen) == 0) return 0;
228 return XML_STATUS_ERROR;
229}
230
231
232/* basic parser stuff */
233#define XML_CreateParserLevel(aaa) \
234 aaa = MALLOC(xmlSAXHandler *, sizeof (xmlSAXHandler)); \
235 bzero (aaa,sizeof(xmlSAXHandler));
236
237#define XML_SetElementHandler(aaa,bbb,ccc) \
238 aaa->startElement = bbb; \
239 aaa->endElement = ccc;
240
241/* CDATA handling */
242#define XML_SetDefaultHandler(aaa,bbb) /* this is CDATA related too */
243#define XML_SetCdataSectionHandler(aaa,bbb,ccc) \
244 aaa->cdataBlock = endCDATA;
245
246
247
248//#define X3DPARSERVERBOSE 1
249
250//#define PROTO_MARKER 567000
251
252/* If XMLCALL isn't defined, use empty one */
253#ifndef XMLCALL
254 #define XMLCALL
255#endif /* XMLCALL */
256
257//#define MAX_CHILD_ATTRIBUTE_DEPTH 32
258
259typedef struct pX3DParser{
260 struct VRMLLexer *myLexer;// = NULL;
261 Stack* DEFedNodes;// = NULL;
262 int CDATA_TextMallocSize;// = 0;
263 /* for testing Johannes Behrs fieldValue hack for getting data in */
264 int in3_3_fieldValue;// = FALSE;
265 int in3_3_fieldIndex;// = INT_ID_UNDEFINED;
266 /* XML parser variables */
267 int X3DParserRecurseLevel;// = INT_ID_UNDEFINED;
268 XML_Parser x3dparser[PROTOINSTANCE_MAX_LEVELS];
269 XML_Parser currentX3DParser;// = NULL;
270
271 int currentParserMode[PROTOINSTANCE_MAX_LEVELS];
272 int currentParserModeIndex;// = 0; //INT_ID_UNDEFINED;
273 struct xml_user_data *user_data;
274
275}* ppX3DParser;
276
277static void *X3DParser_constructor(){
278 void *v = MALLOCV(sizeof(struct pX3DParser));
279 memset(v,0,sizeof(struct pX3DParser));
280 return v;
281}
282
283void X3DParser_init(struct tX3DParser *t){
284 //public
285 t->parentIndex = -1;
286 t->CDATA_Text = NULL;
287 t->CDATA_Text_curlen = 0;
288 //private
289 t->prv = X3DParser_constructor();
290 {
291 ppX3DParser p = (ppX3DParser)t->prv;
292 p->myLexer = NULL;
293 p->DEFedNodes = NULL;
294 //p->childAttributes= NULL;
295 p->CDATA_TextMallocSize = 0;
296 /* for testing Johannes Behrs fieldValue hack for getting data in */
297 p->in3_3_fieldValue = FALSE;
298 p->in3_3_fieldIndex = INT_ID_UNDEFINED;
299 /* XML parser variables */
300 p->X3DParserRecurseLevel = INT_ID_UNDEFINED;
301 p->currentX3DParser = NULL;
302
303 p->currentParserModeIndex = 0; //INT_ID_UNDEFINED;
304 p->user_data = NULL;
305
306 }
307}
308
309void X3DParser_clear(struct tX3DParser *t){
310 //printf ("X3DParser_clear\n");
311 if(t){
312 ppX3DParser p = (ppX3DParser)t->prv;
313 free_xml_user_data(p->user_data);
314 if(p->myLexer){
315 lexer_destroyData(p->myLexer);
316 FREE_IF_NZ(p->myLexer);
317 }
318 }
319}
320
321 //ppX3DParser p = (ppX3DParser)gglobal()->X3DParser.prv;
322
323
324
325
326#ifdef X3DPARSERVERBOSE
327static const char *parserModeStrings[] = {
328 "unused",
329 "PARSING_NODES",
330 "PARSING_SCRIPT",
331 "PARSING_PROTODECLARE ",
332 "PARSING_PROTOINTERFACE ",
333 "PARSING_PROTOBODY",
334 "PARSING_PROTOINSTANCE",
335 "PARSING_IS",
336 "PARSING_CONNECT",
337 "PARSING_EXTERNPROTODECLARE",
338 "unused high"};
339#endif
340#undef X3DPARSERVERBOSE
341
342
343/* get the line number of the current parser for error purposes */
344int freewrl_XML_GetCurrentLineNumber(void) {
345 ppX3DParser p = (ppX3DParser)gglobal()->X3DParser.prv;
346 if (p->X3DParserRecurseLevel > INT_ID_UNDEFINED)
347 {
348 p->currentX3DParser = p->x3dparser[p->X3DParserRecurseLevel]; /*dont trust current*/
349 return (int) XML_GetCurrentLineNumber(p->currentX3DParser);
350 }
351 return INT_ID_UNDEFINED;
352}
353
354
355/*
356in3_3:
357
3582b) Allow <fieldValue> + extension for all node-types
359-------------------------------------------------------------
360There is already a fieldValue element in current X3D-XML
361spec to specify the value of a ProtoInstance-field.
362To specify a value of a ProtoInstance field looks like this:
363
364<ProtoInstance name='bar' >
365 <fieldValue name='foo' value='TRUE' />
366</ProtoInstance>
367
368We could change the wording in the spec to allow
369<fieldValue>- elements not just for ProtoInstance-nodes
370but for all instances of nodes. In addition we would
371allow element data in fieldValues which will
372be read to the single specified field. This solution
373is not limited to a single field per node but could
374easily handle any number of fields
375
376The 'count' attribute is optional and an idea
377borrowed form the COLLADA specification. The count-value
378could be used to further improve the parser-speed because
379the parser could already reserve the amount of data needed.
380
381<Coordinate3d>
382 <fieldValue name='point' count='4' >
383 0.5 1.0 1.0
384 2.0 2.0 2.0
385 3.0 0.5 1.5
386 4.0 1.4 2.0
387 </fieldValue>
388</Coordinate3d>
389
390pro:
391+ Dynamic solution; we do not have to tag fields
392+ Long term solution, no one-field-per-node limitation
393+ Uses an existing element/concept. No additional complexity
394+ Works with protos
395
396con:
397- Introduces one additional element in the code; data looks not as compact as 2a
398- Allowing attribute and element-data for a single field is redundant; Need to specify how to handle ambiguities
399
400
401*/
402
403/**************************************************************************************/
404
405/* for EAI/SAI - if we have a Node, look up the name in the DEF names */
406char *X3DParser_getNameFromNode(struct X3D_Node* myNode) {
407 indexT ind;
408 struct X3D_Node* node;
409 ppX3DParser p = (ppX3DParser)gglobal()->X3DParser.prv;
410
411 /* printf ("X3DParser_getNameFromNode called on %u, DEFedNodes %u\n",myNode,DEFedNodes); */
412 if (!p->DEFedNodes) return NULL;
413 /* printf ("X3DParser_getNameFromNode, DEFedNodes not null\n"); */
414
415 /* go through the DEFed nodes and match the node pointers */
416 for (ind=0; ind<vectorSize(stack_top(struct Vector*, p->DEFedNodes)); ind++) {
417 node=vector_get(struct X3D_Node*, stack_top(struct Vector*, p->DEFedNodes),ind);
418
419 /* did we have a match? */
420 /* printf ("X3DParser_getNameFromNode, comparing %u and %u at %d\n",myNode,node,ind); */
421 if (myNode == node) {
422 /* we have the index into the lexers name table; return the name */
423 struct Vector *ns;
424 ns = stack_top(struct Vector*, p->myLexer->userNodeNames);
425 return ((char *)vector_get (const char*, ns,ind));
426 }
427 }
428
429 /* not found, return NULL */
430 return NULL;
431}
432
433/* for EAI/SAI - if we have a DEF name, look up the node pointer */
434struct X3D_Node *X3DParser_getNodeFromName(const char *name) {
435 return DEFNameIndex(name,NULL,FALSE);
436}
437
438/**************************************************************************************/
439
440
441
442/* "forget" the DEFs. Keep the table around, though, as the entries will simply be used again. */
443void kill_X3DDefs(void) {
444 int i;
445 ppX3DParser p = (ppX3DParser)gglobal()->X3DParser.prv;
446
447 //FREE_IF_NZ(p->childAttributes);
448 //p->childAttributes = NULL;
449
450printf ("kill_X3DDefs... DEFedNodes %p\n",p->DEFedNodes);
451printf ("kill_X3DDefs... myLexer %p\n",p->myLexer);
452
453 if (p->DEFedNodes != NULL) {
454 for (i=0; i<vectorSize(p->DEFedNodes); i++) {
455 struct Vector * myele = vector_get (struct Vector*, p->DEFedNodes, i);
456
457 /* we DO NOT delete individual elements of this vector, as they are pointers
458 to struct X3D_Node*; these get deleted in the general "Destroy all nodes
459 and fields" routine; kill_X3DNodes(void). */
460 deleteVector (struct Vector *,myele);
461 }
462 deleteVector(struct Vector*, p->DEFedNodes);
463 p->DEFedNodes = NULL;
464 }
465
466 /* now, for the lexer... */
467 if (p->myLexer != NULL) {
468 lexer_destroyData(p->myLexer);
469 deleteLexer(p->myLexer);
470 p->myLexer=NULL;
471 }
472
473 /* do we have a parser for scanning string values to memory? */
474 Parser_deleteParserForScanStringValueToMem();
475}
476
477
478
479/* return a node associated with this name. If the name exists, return the previous node. If not, return
480the new node */
481static struct X3D_Node *DEFNameIndex (const char *name, struct X3D_Node* node, int force) {
482 ppX3DParser p = (ppX3DParser)gglobal()->X3DParser.prv;
483
484 // start off with an error condition...
485
486#ifdef X3DPARSERVERBOSE
487 printf ("DEFNameIndex, p is %p\n",p);
488 printf ("DEFNameIndex, looking for :%s:, force %d nodePointer %u\n",name,force,node);
489 printf ("DEFNameIndex, p->myLexer %p\n",p->myLexer);
490 printf ("DEFNameIndex, stack %p\n",p->DEFedNodes);
491 printf ("DEFNameIndex, p->user_data %p\n",p->user_data);
492#endif
493
494 if (p->user_data != NULL) {
495 //printf ("DEFNameIndex, have p->user_data\n");
496 struct xml_user_data *ud = (struct xml_user_data *)p->user_data;
497 struct X3D_Proto *context2 = getContext(ud,TOP);
498
499 if (ud->context != NULL) {
500 //printf ("so, context2 is %p\n",context2);
501 //printf ("and, DEFnames is %p\n",context2->__DEFnames);
502 //printf ("and, __DEFnames size %d\n",vectorSize(context2->__DEFnames));
503 node = broto_search_DEFname(context2,name);
504 //printf ("found %p\n",node);
505 } else {
506 //printf ("ud->context is NULL...\n");
507 }
508
509 }
510
511#ifdef X3DPARSERVERBOSE
512 if (node != NULL) printf ("DEFNameIndex for %s, returning %u, nt %s\n",
513 name, node,stringNodeType(node->_nodeType));
514 else printf ("DEFNameIndex, node is NULL\n");
515#endif
516
517 return node;
518}
519
520#undef X3DPARSERVERBOSE
521
522
523
524int getFieldFromNodeAndName(struct X3D_Node* node,const char *fieldname, int *type, int *kind, int *iifield, union anyVrml **value);
525int getFieldFromNodeAndNameC(struct X3D_Node* node,const char *fieldname, int *type, int *kind, int *iifield, int *builtIn, union anyVrml **value, const char **cname);
526int getFieldFromNodeAndNameU(struct X3D_Node* node,const char *fieldname, int *type, int *kind, int *iifield, int *builtIn, union anyVrml **value, int *iunca, const char **cname);
527void broto_store_route(struct X3D_Proto* proto, struct X3D_Node* fromNode, int fromOfs, struct X3D_Node* toNode, int toOfs, int ft);
528struct IMEXPORT *broto_search_IMPORTname(struct X3D_Proto *context, const char *name);
529void broto_store_ImportRoute(struct X3D_Proto* proto, char *fromNode, char *fromField, char *toNode, char* toField);
530struct brotoRoute *createNewBrotoRoute();
531void broto_store_broute(struct X3D_Proto* context,struct brotoRoute *route);
532
533static int QA_routeEnd(struct X3D_Proto *context, char* cnode, char* cfield, struct brouteEnd* brend, int isFrom){
534 //checks one end of a route during parsing
535 struct X3D_Node* node;
536 int found = 0;
537
538 brend->weak = 1;
539 brend->cfield = STRDUP(cfield);
540 brend->cnode = STRDUP(cnode);
541
542 node = broto_search_DEFname(context,cnode);
543 if(!node){
544 struct IMEXPORT *imp;
545 imp = broto_search_IMPORTname(context, cnode);
546 if(imp){
547 found = 1;
548 brend->weak = 2;
549 }
550 }else{
551 int idir;
552 int type,kind,ifield,source;
553 void *decl;
554 union anyVrml *value;
555 if(isFrom) idir = PKW_outputOnly;
556 else idir = PKW_inputOnly;
557 found = find_anyfield_by_nameAndRouteDir(node,&value,&kind,&type,cfield,&source,&decl,&ifield,idir); //fieldSynonymCompare for set_ _changed
558 if(found){
559 brend->node = node;
560 brend->weak = 0;
561 brend->ftype = type;
562 brend->ifield = ifield;
563 brend->builtIn = source == 0? TRUE : FALSE;
564 }
565 }
566 return found;
567}
568
569
570void QAandRegister_parsedRoute_B(struct X3D_Proto *context, char* fnode, char* ffield, char* tnode, char* tfield){
571 // used by both x3d and vrml parsers, to quality check each end of a route for validity,
572 // store in context->__ROUTES, and -if instancing scenery- register the route
573 // this version accomodates regular routes and routes starting and/or ending on an IMPORTed node, which
574 // may not show up until the inline is loaded, and which may disappear when the inline is unloaded.
575 int haveFrom, haveTo, ok;
576 struct brotoRoute* route;
577 int ftf,ftt;
578 int allowingVeryWeakRoutes = 1; //this will store char* node, char* field on an end (or 2) for later import updating via js or late IMPORT statement
579
580 ok = FALSE;
581 route = createNewBrotoRoute();
582 haveFrom = QA_routeEnd(context, fnode, ffield, &route->from, 1);
583 haveTo = QA_routeEnd(context, tnode, tfield, &route->to, 0);
584 if((haveFrom && haveTo) || allowingVeryWeakRoutes){
585 ftf = -1;
586 ftt = -1;
587 if( !route->from.weak) ftf = route->from.ftype;
588 if( !route->to.weak) ftt = route->to.ftype;
589 route->ft = ftf > -1 ? ftf : ftt > -1? ftt : -1;
590 route->lastCommand = 0; //not registered
591 if(ftf == ftt && ftf > -1){
592 //regular route, register while we are hear
593 int pflags = context->__protoFlags;
594 char oldwayflag = ciflag_get(pflags,1);
595 char instancingflag = ciflag_get(pflags,0);
596 if(oldwayflag || instancingflag){
597 CRoutes_RegisterSimpleB(route->from.node, route->from.ifield, route->from.builtIn, route->to.node, route->to.ifield, route->to.builtIn, route->ft);
598 route->lastCommand = 1; //registered
599 }
600 //broto_store_route(context,fromNode,fifield,toNode,tifield,ftype); //new way delay until sceneInstance()
601 //broto_store_broute(context,route);
602 ok = TRUE;
603 }else if(route->to.weak || route->from.weak){
604 //broto_store_broute(context,route);
605 ok = TRUE;
606 }
607 }
608 if(ok || allowingVeryWeakRoutes)
609 broto_store_broute(context,route);
610 if(!ok || !(haveFrom && haveTo)){
611 ConsoleMessage("Routing problem: ");
612 /* are the types the same? */
613 if (haveFrom && haveTo && route->from.ftype != route->to.ftype) {
614 ConsoleMessage ("type mismatch %s != %s, ",stringFieldtypeType(route->from.ftype), stringFieldtypeType(route->to.ftype));
615 }
616 if(!haveFrom) ConsoleMessage(" _From_ ");
617 if(!haveTo) ConsoleMessage(" _To_ ");
618 ConsoleMessage ("from %s %s, ",fnode,ffield);
619 ConsoleMessage ("to %s %s\n",tnode,tfield);
620 }
621}
622/******************************************************************************************/
623/* parse a ROUTE statement. Should be like:
624 <ROUTE fromField="fraction_changed" fromNode="TIME0" toField="set_fraction" toNode="COL_INTERP"/>
625*/
626static void parseRoutes_B (void *ud, char **atts) {
627 struct X3D_Proto *context;
628 //struct X3D_Node *fromNode = NULL;
629 //struct X3D_Node *toNode = NULL;
630 int i; //, okf,okt, ftype,fkind,fifield,fsource,ttype,tkind,tifield,tsource;
631 //union anyVrml *fvalue, *tvalue;
632 //void *fdecl,*tdecl;
633 //int error = FALSE;
634 //int isImportRoute;
635 //int fromType;
636 //int toType;
637 char *ffield, *tfield, *fnode, *tnode;
638
639 context = getContext(ud,TOP);
640
641 ffield = tfield = fnode = tnode = NULL;
642 for (i = 0; atts[i]; i += 2) {
643 if (strcmp("fromNode",atts[i]) == 0) {
644 fnode = atts[i+1];
645 } else if (strcmp("toNode",atts[i]) == 0) {
646 tnode = atts[i+1];
647 } else if (strcmp("fromField",atts[i])==0) {
648 ffield = atts[i+1];
649 } else if (strcmp("toField",atts[i]) ==0) {
650 tfield = atts[i+1];
651 }
652 }
653 QAandRegister_parsedRoute_B(context, fnode, ffield, tnode, tfield);
654}
655
656
657/* linkNodeIn - put nodes into parents.
658
659
660WARNING - PROTOS have a two extra groups put in; one to hold while parsing, and one Group that is always there.
661
662<Scene>
663 <ProtoDeclare name='txt001'>
664 <ProtoBody>
665 <Material ambientIntensity='0' diffuseColor='1 0.85 0.7' specularColor='1 0.85 0.7' shininess='0.3'/>
666 </ProtoBody>
667 </ProtoDeclare>
668 <Shape>
669 <Cone/>
670 <Appearance>
671 <ProtoInstance name='txt001'/>
672 </Appearance>
673 </Shape>
674</Scene>
675
676is a good test to see what happens for these nodes.
677
678Note the "PROTO_MARKER" which is assigned to the bottom-most group. This is the group that is created to
679hold the proto expansion, and is passed in to the expandProtoInstance function. So, we KNOW that this
680Group node is the base for the PROTO. If you look at the code to expand the PROTO, the first node is a
681Group node, too. So, we will have a Group, children Group, children actual nodes in file. eg:
682
683 Material
684 Group
685 Group marker = PROTO_MARKER.
686
687Now, in the example above, the "Material" tries to put itself inside an "appearance" field of an Appearance
688node. So, if the parentIndex-1 and parentIndex-2 entry are Groups, and parentIndex-2 has PROTO_MARKER
689set, we know this is a PROTO expansion, so just assign the Material node to the children field, and worry
690about it later.
691
692Ok, later, we have the opposite problem, so we look UP the stack to see what the defaultContainer was
693actually expected to be. This is the "second case" below.
694
695Note that if we are dealing with Groups as Proto Expansions, none of the above is a problem; just if we
696need to put a node into something other than the "children" field.
697
698*/
699int getFieldFromNodeAndName(struct X3D_Node* node,const char *fieldname, int *type, int *kind, int *iifield, union anyVrml **value);
700int indexChildrenName(struct X3D_Node *node);
701struct Multi_Node *childrenField(struct X3D_Node *node);
702#define PPX(A) getTypeNode(X3D_NODE(A)) //possible proto expansion
703
704
705
706static void linkNodeIn_B(void *ud) {
707/* Assumes you have parsed a node, and have it pushed onto the node stack, and
708 now you want to put it in a field in it's parent
709 'children' is a weak field recommendation from either the parent or current node
710 more specific recommendations take priority
7111. when parsing a node, ProtoInstance, field, or fieldvalue,
712 pushField the char* name or fieldoffset of the most likely default field, or NULL if no recommendation for a default
713 Shape would have no default. Transform has children. Inline has __children. GeoLOD has rootnodes.
7142. PopField when coming out of node, ProtoInstance, fieldValue, or field end
7153. In CDATA, startNode, startProtoInstance
716a) in node or protoinstance, look if there's a _defaultContainer for currentNode,
717 and if not null, and not children, look it up in the parent node
718 (may be null, ie geometry might be trying to find a field in a Proto)
719b) get the parent's suggested fieldname off stack, and if not null,
720 lookup in topnode to get type, offsetof and over-ride (example, proto would steer geometry into its __children)
721 - and field or fieldValue would be very specific
722c) look at atts containerField, and if not null and not children, use it.
723 - scene author is trying to over-ride defaults.
724*/
725 struct X3D_Node *node, *typenode, *parent;
726 char *parentsSuggestion; //*ic,
727 int type, kind, iifield, ok, isRootNode, mode;
728 union anyVrml *value = NULL;
729 const char *fname;
730
731 mode = getMode(ud,TOP);
732 node = getNode(ud,TOP);
733 typenode = PPX(node);
734 parent = getNode(ud,TOP-1);
735 if(!node || !parent)return;
736 if(node && !typenode) //empty protobody
737 typenode = node;
738 isRootNode = FALSE;
739 if(parent->_nodeType == NODE_Proto){
740 if(mode == PARSING_PROTOBODY) isRootNode = TRUE;
741 }
742 //if(parent->_nodeType == NODE_TransformSensor)
743 // printf("adding a node to transformsensor\n");
744 if(isRootNode){
745 //if we are adding a rootnode to scene or protobody, it should be added to
746 // the scene/protobody's private __children field
747 // (not to any of the proto's public fields, for example if the proto author called a public field 'children')
748 union anyVrml *valueadd = NULL;
749 ok = getFieldFromNodeAndName(parent,"__children",&type,&kind,&iifield,&valueadd);
750 AddRemoveChildren(parent,&valueadd->mfnode,&node,1,1,__FILE__,__LINE__);
751 }else{
752 int i, ncontainer; //, instanceContainer, i;
753 unsigned int iContainer, jContainer, defaultContainer[3];
754
755 parentsSuggestion = getField(ud,TOP-1);
756
757 //3.a)
758 jContainer = typenode->_defaultContainer;
759 //Jan 2017 I squeezed 3 defaults into an int in generateCode.c, and extract them here
760 //but do I have the right endian math?
761 defaultContainer[0] = (jContainer << 22) >> 22;
762 defaultContainer[1] = (jContainer << 12) >> 22;
763 defaultContainer[2] = (jContainer << 2) >> 22;
764 ncontainer = 1;
765 if(defaultContainer[1])
766 ncontainer = 2;
767 if(defaultContainer[2])
768 ncontainer = 3;
769 for(i=0;i<ncontainer;i++){
770 iContainer = defaultContainer[i];
771 if(iContainer == FIELDNAMES_children) iContainer = 0;
772 value = NULL;
773 fname = NULL;
774 ok = 0;
775 if(iContainer){
776 fname = FIELDNAMES[iContainer];
777 ok = getFieldFromNodeAndName(parent,fname,&type,&kind,&iifield,&value);
778 ok = ok && (kind == PKW_initializeOnly || kind == PKW_inputOutput); //not inputOnly or outputOnly - we can't park nodes there
779 }
780 if(!value && iContainer == FIELDNAMES_children){
781 //if you try and put a transform into a proto, or LOD, or Inline (or switch?) you'll come in
782 //here to get the equivalent-to-children field
783 ok = getFieldFromNodeAndName(parent,"children",&type,&kind,&iifield,&value);
784 ok = ok && (kind == PKW_initializeOnly || kind == PKW_inputOutput); //not inputOnly or outputOnly - we can't park nodes there
785 if(!ok){
786 int kids = indexChildrenName(parent);
787 if(kids > 0){
788 value = (union anyVrml*)childrenField(parent);
789 type = FIELDTYPE_MFNode;
790 }
791 }
792 }
793 if(ok)
794 break;
795 }
796 //3.b)
797 //if(parentsSuggestion) {
798 if(!ok && parentsSuggestion) {
799 //if you're parsing a fieldValue, and your value is an SF or MFnode in a child xml element,
800 //<fieldValue name='myTransform'>
801 // <Transform USE='tommysTransform'/>
802 //</fieldValue>
803 //you'll come in here
804 //don't want to come in here for metadata
805 ok =getFieldFromNodeAndName(parent,parentsSuggestion,&type,&kind,&iifield,&value);
806 }
807
808 if(!value && parent){
809 ok = getFieldFromNodeAndName(parent,"children",&type,&kind,&iifield,&value);
810 if(!ok){
811 int kids = indexChildrenName(parent);
812 if(kids > 0){
813 value = (union anyVrml*)childrenField(parent);
814 type = FIELDTYPE_MFNode;
815 }
816 }
817 }
818
819 if(value){
820 if(type == FIELDTYPE_SFNode){
821 value->sfnode = node;
822 ADD_PARENT(node,parent);
823 }else if(type == FIELDTYPE_MFNode){
824 union anyVrml *valueadd = NULL;
825 ok = 0;
826 if(parent->_nodeType == NODE_Proto){
827 struct X3D_Proto *pparent = X3D_PROTO(parent);
828 char cflag = ciflag_get(pparent->__protoFlags,2);
829 if(cflag == 2) //scene
830 ok = getFieldFromNodeAndName(parent,"addChildren",&type,&kind,&iifield,&valueadd);
831 }
832 if(ok)
833 AddRemoveChildren(parent,&valueadd->mfnode,&node,1,1,__FILE__,__LINE__);
834 else
835 AddRemoveChildren(parent,&value->mfnode,&node,1,1,__FILE__,__LINE__);
836 }
837 }else{
838 printf("no where to put node in parent\n");
839 printf("nodetype=%s parenttype=%s\n",stringNodeType(node->_nodeType),stringNodeType(parent->_nodeType));
840
841 }
842 }
843
844}
845
846
847void Parser_scanStringValueToMem_B(union anyVrml* any, indexT ctype, const char *value, int isXML);
848
849static void endCDATA_B (void *ud, const xmlChar *string, int len) {
850 char *fieldname = getField(ud,TOP);
851 struct X3D_Node *node = getNode(ud,TOP);
852 int type, kind, iifield, ok, handled;
853 union anyVrml *value;
854 ok = getFieldFromNodeAndName(node,fieldname,&type,&kind,&iifield,&value);
855 if(ok){
856 handled = FALSE;
857 if(!strcmp(fieldname,"url")){
858 //Script javascript doesn't parse well as an MFString
859 if(strstr((char*)string,"script")){
860 handled = TRUE;
861 value->mfstring.n = 1;
862 value->mfstring.p = MALLOCV(sizeof(void *));
863 value->mfstring.p[0] = newASCIIString((char *)string);
864 //if(0) printf("copied cdata string= [%s]\n",(struct Uni_String*)(value->mfstring.p[0])->strptr);
865 }
866 }
867 if(!handled)
868 Parser_scanStringValueToMem_B(value, type, (const char*) string, TRUE);
869 }
870}
871
872void endCDATA (void *ud, const xmlChar *string, int len) {
873 endCDATA_B(ud,string,len);
874 return;
875}
876
877
878
879void handleImport_B (struct X3D_Node *nodeptr, char *nodeName,char *nodeImport, char *as);
880static void parseImport_B(void *ud, char **atts) {
881 int i;
882 char *inlinedef, *exporteddef, *as;
883 struct X3D_Proto *context;
884 context = getContext(ud,TOP);
885
886 inlinedef = exporteddef = as = NULL;
887 for (i = 0; atts[i]; i += 2) {
888 printf("import field:%s=%s\n", atts[i], atts[i + 1]);
889 if(!strcmp(atts[i],"inlineDEF")) inlinedef = atts[i+1];
890 if(!strcmp(atts[i],"exportedDEF")) exporteddef = atts[i+1];
891 if(!strcmp(atts[i],"AS")) as = atts[i+1];
892
893 }
894 handleImport_B (X3D_NODE(context), inlinedef, exporteddef, as);
895}
896
897
898void handleExport_B (void *nodeptr, char *node, char *as);
899static void parseExport_B(void *ud, char **atts) {
900 // http://www.web3d.org/documents/specifications/19776-1/V3.3/Part01/concepts.html#IMPORT_EXPORTStatementSyntax
901 int i;
902 char *localdef, *as;
903 struct X3D_Proto *context;
904 context = getContext(ud,TOP);
905
906 localdef = as = NULL;
907 for (i = 0; atts[i]; i += 2) {
908 printf("export field:%s=%s\n", atts[i], atts[i + 1]);
909 if(!strcmp(atts[i],"localDEF")) localdef = atts[i+1];
910 if(!strcmp(atts[i],"AS")) as = atts[i+1];
911 }
912 handleExport_B(context,localdef, as);
913}
914
915
916/* parse a component statement, and send the results along */
917static void parseComponent(char **atts) {
918 int i;
919 int myComponent = INT_ID_UNDEFINED;
920 int myLevel = INT_ID_UNDEFINED;
921
922 /* go through the fields and make sense of them */
923 for (i = 0; atts[i]; i += 2) {
924 /* printf("components field:%s=%s\n", atts[i], atts[i + 1]); */
925 if (strcmp("level",atts[i]) == 0) {
926 if (sscanf(atts[i+1],"%d",&myLevel) != 1) {
927 ConsoleMessage ("Line %d: Expected Component level for component %s, got %s",LINE, atts[i], atts[i+1]);
928 return;
929 }
930 } else if (strcmp("name",atts[i]) == 0) {
931 myComponent = findFieldInCOMPONENTS(atts[i+1]);
932 if (myComponent == INT_ID_UNDEFINED) {
933 ConsoleMessage("Line %d: Component statement, but component name not valid :%s:",LINE,atts[i+1]);
934 return;
935 }
936
937 } else {
938 ConsoleMessage ("Line %d: Unknown fields in Component statement :%s: :%s:",LINE,atts[i], atts[i+1]);
939 }
940 }
941
942 if (myComponent == INT_ID_UNDEFINED) {
943 ConsoleMessage("Line %d: Component statement, but component name not stated",LINE);
944 } else if (myLevel == INT_ID_UNDEFINED) {
945 ConsoleMessage("Line %d: Component statement, but component level not stated",LINE);
946 } else {
947 handleComponent(myComponent,myLevel);
948 }
949}
950
951/* parse the <X3D profile='Immersive' version='3.0' xm... line */
952static void parseX3Dhead(void *ud, char **atts) {
953 int i;
954 int myProfile = -10000; /* something negative, not INT_ID_UNDEFINED... */
955 int versionIndex = INT_ID_UNDEFINED;
956 struct X3D_Proto* ec = (struct X3D_Proto*)getContext(ud,TOP);
957
958 for (i = 0; atts[i]; i += 2) {
959 /* printf("parseX3Dhead: field:%s=%s\n", atts[i], atts[i + 1]); */
960 if (strcmp("profile",atts[i]) == 0) {
961 myProfile = findFieldInPROFILES(atts[i+1]);
962 } else if (strcmp("version",atts[i]) == 0) {
963 versionIndex = i+1;
964 } else {
965 /* printf ("just skipping this data\n"); */
966 }
967 }
968
969 /* now, handle all the found variables */
970 if (myProfile == INT_ID_UNDEFINED) {
971 ConsoleMessage ("expected valid profile in X3D header");
972 } else {
973 /* printf ("X3DParsehead, myProfile %d\n",myProfile); */
974 if (myProfile >= 0) handleProfile (myProfile);
975 }
976
977 if (versionIndex != INT_ID_UNDEFINED) {
978 handleVersion (atts[versionIndex]);
979 //already set to 300 in resources.c when file is initially identified as x3d
980 //we update here with more specific <X3D version='3.3.0'> version
981 ec->__specversion = inputFileVersion[0]*100 + inputFileVersion[1]*10 + inputFileVersion[2];
982 }
983}
984
985static void parseHeader(char **atts) {
986 int i;
987 for (i = 0; atts[i]; i += 2) {
988 /* printf("parseHeader: field:%s=%s\n", atts[i], atts[i + 1]); */
989 }
990}
991static void parseScene(char **atts) {
992 int i;
993 for (i = 0; atts[i]; i += 2) {
994 /* printf("parseScene: field:%s=%s\n", atts[i], atts[i + 1]); */
995 }
996}
997static void parseMeta(char **atts) {
998 int i;
999 for (i = 0; atts[i]; i += 2) {
1000 /* printf("parseMeta field:%s=%s\n", atts[i], atts[i + 1]); */
1001 }
1002}
1003static void parseUnit(void *ud, char **atts) {
1004 double conversionFactor = 1.0;
1005 char *name, *category;
1006 struct X3D_Proto* ec = (struct X3D_Proto*)getContext(ud,TOP);
1007
1008 name = category = NULL;
1009 int i;
1010 for (i = 0; atts[i]; i += 2){
1011 if(!strcmp(atts[i],"name"))
1012 name = atts[i+1];
1013 if(!strcmp(atts[i],"category"))
1014 category = atts[i+1];
1015 if(!strcmp(atts[i],"conversionFactor"))
1016 sscanf(atts[i+1],"%lf",&conversionFactor);
1017 }
1018 handleUnitDataStringString(ec,category, name, conversionFactor);
1019}
1020void deleteMallocedFieldValue(int type,union anyVrml *fieldPtr);
1021static void parseFieldValue_B(void *ud, char **atts) {
1022 int i, type, kind, iifield, builtIn, ok;
1023 const char *fname, *svalue, *cname;
1024 union anyVrml *value;
1025 struct X3D_Node *node = getNode(ud,TOP);
1026
1027 fname = svalue = NULL;
1028 for(i=0;atts[i];i+=2){
1029 if(!strcmp(atts[i],"name")) fname = atts[i+1];
1030 if(!strcmp(atts[i],"value")) svalue = atts[i+1];
1031 }
1032 ok = 0;
1033 cname = NULL;
1034 value = NULL;
1035 builtIn = FALSE;
1036 if(fname){
1037 ok = getFieldFromNodeAndNameC(node,fname,&type,&kind,&iifield,&builtIn,&value,&cname);
1038 }
1039 if(cname && value && svalue){
1040 deleteMallocedFieldValue(type,value);
1041 Parser_scanStringValueToMem_B(value,type,svalue,TRUE);
1042 }
1043 if(cname && (node->_nodeType == NODE_Proto) && !builtIn){
1044 //for protoInstances, whether or not you have a value,
1045 //if you declare a field then you are saying you declare the value null or 0 or default at least.
1046 //so for SFNode fields where <fieldValue><a node></fieldValue> and we get the node later
1047 //whether or not there's a node/value parsed, we are declaring its set even at null.
1048 //therefore alreadyset
1049 //the way to acheive not alreadySet is to not mention the field in your protoInstance.
1050 struct X3D_Proto *pnode;
1051 struct ProtoFieldDecl* pfield;
1052 struct ProtoDefinition* pstruct;
1053 pnode = X3D_PROTO(node);
1054 pstruct = (struct ProtoDefinition*) pnode->__protoDef;
1055 pfield = vector_get(struct ProtoFieldDecl*,pstruct->iface,iifield);
1056 //is there a function for zeroing a fieldValue of anytype? Need it here.
1057 //in xml the MFNode in particular will get 'added to' ie mf.n++ later, so need to clear that
1058 // see tests/protos/questionforexperts_mod.x3d
1059 if(pfield->type == FIELDTYPE_MFNode){
1060 struct Multi_Node* mfn = &pfield->defaultVal.mfnode;
1061 if(mfn->n)
1062 AddRemoveChildren(node,mfn,mfn->p,mfn->n,2,__FILE__,__LINE__);
1063 pfield->defaultVal.mfnode.n = 0;
1064 pfield->defaultVal.mfnode.p = NULL;
1065 }
1066 if(pfield->type == FIELDTYPE_SFNode){
1067 struct X3D_Node **sfn = &pfield->defaultVal.sfnode;
1068 if(*sfn)
1069 AddRemoveSFNodeFieldChild(node,sfn,*sfn,2,__FILE__,__LINE__);
1070 pfield->defaultVal.sfnode = NULL;
1071 }
1072 pfield->alreadySet = TRUE;
1073 }
1074 pushField(ud,cname); //in case there's no value, because its SF or MFNodes in child xml, or in CDATA
1075}
1076static void endFieldValue_B(void *ud){
1077 if(0) printf("endFieldValue\n");
1078 //in x3d, <fieldvalue type=SFNode><a node></fieldValue>
1079
1080 popField(ud);
1081}
1082
1083
1084static void parseIS(void *ud) {
1085 #ifdef X3DPARSERVERBOSE
1086 printf ("parseIS mode is %s\n",parserModeStrings[getMode(ud,TOP)]);
1087 #endif
1088 pushMode(ud,PARSING_IS);
1089
1090}
1091
1092
1093
1094static void endIS(void *ud) {
1095 #ifdef X3DPARSERVERBOSE
1096 printf ("endIS mode is %s\n",parserModeStrings[getMode(ud,TOP)]);
1097 #endif
1098 popMode(ud);
1099}
1100
1101
1102
1103static void endProtoInterfaceTag(void *ud) {
1104 if (getMode(ud,TOP) != PARSING_PROTOINTERFACE) {
1105 ConsoleMessage ("endProtoInterfaceTag: got a </ProtoInterface> but not parsing one at line %d",LINE);
1106 }
1107 /* now, a ProtoInterface should be within a ProtoDeclare, so, make the expected mode PARSING_PROTODECLARE */
1108 //setParserMode(PARSING_PROTODECLARE);
1109 popMode(ud);
1110}
1111static void endProtoBodyTag_B(void *ud, const char *name) {
1112 //pop context
1113 if (getMode(ud,TOP) != PARSING_PROTOBODY) {
1114 ConsoleMessage ("endProtoBodyTag: got a </ProtoBody> but not parsing one at line %d",LINE);
1115 }
1116 popMode(ud);
1117 popContext(ud);
1118}
1119
1120static void endExternProtoDeclareTag_B(void *ud) {
1121 popMode(ud);
1122 popNode(ud);
1123 popField(ud);
1124}
1125
1126static void endProtoDeclareTag_B(void *ud) {
1127 /* ending <ProtoDeclare> */
1128 struct X3D_Proto * proto;
1129 struct Multi_Node *cptr;
1130
1131 if (getMode(ud,TOP) != PARSING_PROTODECLARE) {
1132 ConsoleMessage ("endProtoDeclareTag: got a </ProtoDeclare> but not parsing one at line %d",LINE);
1133 pushMode(ud,PARSING_PROTODECLARE);
1134 }
1135 if(0) printf("end protoDeclare\n");
1136 // set defaultContainer based on 1st child
1137 proto = X3D_PROTO(getNode(ud,TOP));
1138 cptr = NULL;
1139 if(proto->__children.n)
1140 cptr = &proto->__children;
1141 else if(proto->addChildren.n)
1142 cptr = &proto->addChildren;
1143 if(cptr){
1144 struct X3D_Node *c1 = cptr->p[0];
1145 if(c1->_defaultContainer > INT_ID_UNDEFINED)
1146 proto->_defaultContainer = c1->_defaultContainer;
1147 }
1148 popField(ud);
1149 popNode(ud); //I think I should pop the X3DProto off the stack
1150 popMode(ud);
1151}
1152
1153
1154void deep_copy_broto_body2(struct X3D_Proto** proto, struct X3D_Proto** dest);
1155static void endProtoInstance_B(void *ud, const char *name) {
1156 //now that initial field values are set, deep copy the broto body
1157 int mode;
1158 struct X3D_Node *node;
1159 if(0) printf("endProtoInstance_B\n");
1160
1161 node = getNode(ud,TOP);
1162 mode = getMode(ud,TOP);
1163 if(node){
1164 if(node->_nodeType == NODE_Proto || node->_nodeType == NODE_Inline ){
1165 if(mode != PARSING_PROTOINSTANCE_USE){
1166 char pflagdepth;
1167 struct X3D_Proto *pnode = X3D_PROTO(node);
1168 pflagdepth = ciflag_get(pnode->__protoFlags,0); //0 - we're in a protodeclare, 1 - we are instancing live scenery
1169 if( pflagdepth){
1170 //copying the body _after_ the protoInstance field values have been parsed
1171 //allows ISd fields in body nodes to get the pkw_initializeOnly/inputOutput value
1172 //from the protoInstance interface
1173 struct X3D_Proto *pdeclare;
1174 pdeclare = X3D_PROTO(pnode->__prototype);
1175 //if you bomb around here, pdeclare == null, then make sure your scene
1176 // doesn't have protoDeclares with the same name as freewrl builtin types
1177 // because as of Nov 2016 freewrl doesn't allow over-riding builtins with protos,
1178 // and gets confused and bombs
1179 deep_copy_broto_body2(&pdeclare,&pnode);
1180 }
1181 }
1182 }
1183 linkNodeIn_B(ud);
1184 }
1185 popField(ud);
1186 popNode(ud);
1187 popMode(ud);
1188}
1189
1190/* did we get a USE in a proto instance, like:
1191<ProtoInstance name='CamLoader' DEF='Camera1_Bgpic'>
1192 <fieldValue name='imageName' value='Default.jpg'/>
1193 <fieldValue name='relay'>
1194 <Script USE='CameraRelay'/>
1195 </fieldValue>
1196 <fieldValue name='yscale' value='3.0'/>
1197</ProtoInstance>
1198
1199if so, we will be here for the USE fields.
1200
1201
1202*/
1203
1204/********************************************************/
1205
1206
1207void **shaderFields(struct X3D_Node* node){
1208 void **shaderfield;
1209 switch(node->_nodeType){
1210 case NODE_Script:
1211 shaderfield = &X3D_SCRIPT(node)->__scriptObj; break;
1212 case NODE_ComposedShader:
1213 shaderfield = (void**)&X3D_COMPOSEDSHADER(node)->_shaderUserDefinedFields; break;
1214 case NODE_Effect:
1215 shaderfield = (void**)&X3D_EFFECT(node)->_shaderUserDefinedFields; break;
1216 case NODE_ShaderProgram:
1217 shaderfield = (void**)&X3D_SHADERPROGRAM(node)->_shaderUserDefinedFields; break;
1218 case NODE_PackagedShader:
1219 shaderfield = (void**)&X3D_PACKAGEDSHADER(node)->_shaderUserDefinedFields; break;
1220 default:
1221 shaderfield = NULL;
1222 }
1223 return shaderfield;
1224}
1225
1226void broto_store_DEF(struct X3D_Proto* proto,struct X3D_Node* node, const char *name);
1227static void parseAttributes_B(void *ud, char **atts);
1228void add_node_to_broto_context(struct X3D_Proto *context,struct X3D_Node *node);
1229void push_binding_stack_set(struct X3D_Node* layersetnode);
1230void push_next_layerId_from_binding_stack_set(struct X3D_Node* layer);
1231void pop_binding_stack_set();
1232
1233static void startBuiltin_B(void *ud, int myNodeType, const xmlChar *name, char** atts) {
1234 struct X3D_Node *node, *fromDEFtable;
1235 struct X3D_Proto *context;
1236 void **shaderfield;
1237 char pflagdepth;
1238 int kids, i, isUSE;
1239 const char *defname, *suggestedChildField, *containerfield;
1240
1241 suggestedChildField = containerfield = NULL;
1242 context = getContext(ud,TOP);
1243 pflagdepth = ciflag_get(context->__protoFlags,0); //0 - we're in a protodeclare, 1 - we are instancing live scenery
1244 if(0) printf("start builtin %s\n",name);
1245 node = NULL;
1246 defname = NULL;
1247 isUSE = FALSE;
1248 /* go through the attributes; do some here, do others later (in case of PROTO IS fields found) */
1249 for (i = 0; atts[i]; i += 2) {
1250 /* is this a DEF name? if so, record the name and then ignore the field */
1251 if (strcmp ("DEF",atts[i]) == 0) {
1252 defname = atts[i+1];
1253 fromDEFtable = broto_search_DEFname(context,defname);
1254 if (fromDEFtable) {
1255 #ifdef X3DPARSERVERBOSE
1256 printf ("Warning - line %d duplicate DEF name: \'%s\'\n",LINE,atts[i+1]);
1257 #endif
1258 }
1259 } else if (strcmp ("USE",atts[i]) == 0) {
1260 #ifdef X3DPARSERVERBOSE
1261 printf ("this is a USE, name %s\n",atts[i+1]);
1262 #endif
1263
1264 //fromDEFtable = DEFNameIndex ((char *)atts[i+1],node, FALSE);
1265 fromDEFtable = broto_search_DEFname(context,atts[i+1]);
1266 if (!fromDEFtable) {
1267 ConsoleMessage ("Warning - line %d DEF name: \'%s\' not found",LINE,atts[i+1]);
1268 ConsoleMessage("\n");
1269 } else {
1270 #ifdef X3DPARSERVERBOSE
1271 printf ("copying for field %s defName %s\n",atts[i], atts[i+1]);
1272 #endif
1273
1274 /* if (fromDEFtable->_nodeType != fromDEFtable->_nodeType) { */
1275 if (myNodeType != fromDEFtable->_nodeType) {
1276 ConsoleMessage ("Warning, line %d DEF/USE mismatch, '%s', %s != %s", LINE,
1277 atts[i+1],stringNodeType(fromDEFtable->_nodeType), stringNodeType (myNodeType));
1278 } else {
1279 /* Q. should thisNode.referenceCount be decremented or ??? */
1280 node = fromDEFtable;
1281 node->referenceCount++; //dug9 added but should???
1282 //getNode(ud,TOP) = thisNode;
1283 #ifdef X3DPARSERVERBOSE
1284 printf ("successful copying for field %s defName %s\n",atts[i], atts[i+1]);
1285 #endif
1286 isUSE = TRUE;
1287 }
1288 }
1289 } else if(!strcmp(atts[i],"containerField")) containerfield = atts[i+1];
1290 }
1291
1292 if(!isUSE){
1293 if(pflagdepth)
1294 node = createNewX3DNode(myNodeType);
1295 else
1296 node = createNewX3DNode0(myNodeType);
1297 if(defname)
1298 broto_store_DEF(context,node,defname);
1299 }
1300 pushNode(ud,node);
1301
1302 if(containerfield) {
1303 //int builtinField = findFieldInARR(containerfield,FIELDNAMES,FIELDNAMES_COUNT);
1304 int builtinField = findFieldInFIELDNAMES(containerfield);
1305 if(builtinField > INT_ID_UNDEFINED){
1306 //if USE, the DEF could specify containerField that's wrong for the USE
1307 //so we'll keep the original as well, for linkNodeIn
1308 //in theory we should call an update function here, and about 4 other places
1309 // in x3dparser.c
1310 node->_defaultContainer = (node->_defaultContainer << 10) + builtinField;
1311 //printf("new defaultContainer=%u\n",(unsigned int)node->_defaultContainer);
1312 }
1313 }
1314
1315 //linkNodeIn_B(ud);
1316
1317 if(!isUSE){
1318 shaderfield = shaderFields(node);
1319 if(shaderfield)
1320 (*shaderfield) = (void *)new_Shader_ScriptB(node);
1321 //if(node->_nodeType == NODE_Script && pflagdepth)
1322 //initialize script - wait till end element
1323 if(node->_nodeType == NODE_LayerSet)
1324 push_binding_stack_set(node);
1325 if(node->_nodeType == NODE_Layer || node->_nodeType == NODE_LayoutLayer)
1326 push_next_layerId_from_binding_stack_set(node);
1327 if(node->_nodeType == NODE_Inline)
1328 X3D_INLINE(node)->__parentProto = X3D_NODE(context); //when searching for user proto declarations, apparently inlines can search the scene
1329 node->_executionContext = X3D_NODE(context);
1330 add_node_to_broto_context(context,node);
1331
1332 kids = indexChildrenName(node);
1333 if(kids > -1)
1334 suggestedChildField = FIELDNAMES[kids];
1335 if(node->_nodeType == NODE_Script || node->_nodeType == NODE_ShaderPart
1336 || node->_nodeType == NODE_ShaderProgram || node->_nodeType == NODE_EffectPart)
1337 suggestedChildField = FIELDNAMES[FIELDNAMES_url]; //for CDATA
1338
1339 pushField(ud,suggestedChildField);
1340
1341 parseAttributes_B(ud,atts);
1342 }else{
1343 pushField(ud,NULL); //we pop in endBuiltin, so we have to push something
1344 }
1345
1346}
1347void initialize_one_script(struct Shader_Script* ss, const struct Multi_String *url);
1348void applyUnitsToNode(struct X3D_Node *node);
1349static void endBuiltin_B(void *ud, const xmlChar *name){
1350 struct X3D_Node *node;
1351 struct X3D_Proto *context;
1352 char pflagdepth;
1353 node = getNode(ud,TOP);
1354 context = getContext(ud,TOP);
1355 if(0)printf("end builtin %s\n",name);
1356 pflagdepth = ciflag_get(context->__protoFlags,0); //0 - we're in a protodeclare, 1 - we are instancing live scenery
1357 applyUnitsToNode(node);
1358 if(node->_nodeType == NODE_Script && pflagdepth){
1359 struct X3D_Script *sn = X3D_SCRIPT(node);
1360 //overkill -duplicates new_Shader_Script
1361 initialize_one_script(sn->__scriptObj,&sn->url);
1362 //script_initCodeFromMFUri(sn->__scriptObj, &sn->url);
1363 }
1364 if(node->_nodeType == NODE_LayerSet)
1365 pop_binding_stack_set();
1366
1367 linkNodeIn_B(ud);
1368
1369 popNode(ud);
1370 popField(ud);
1371
1372}
1373
1374static xmlChar* fixAmp(const unsigned char *InFieldValue)
1375{
1376 char *fieldValue = (char *)InFieldValue;
1377
1378 //for x3d string '"&amp;"' libxml2 gives us &#38;
1379 //we want & like other browsers get
1380 //we do it by left-shifting over the #38;
1381 //fieldValue - the MFString before splitting into SFs ie ["you & me" "John & Ian"\0]
1382 //except that libxml2 will wrongly give you ["you &#38; me" "John &#38; Ian"\0]
1383 if(fieldValue)
1384 {
1385 char *pp = strstr((char *)fieldValue,"&#38;");
1386 while(pp){
1387 memmove(pp+1,pp+5,strlen(fieldValue) - (pp+1 - fieldValue));
1388 pp = strstr(pp,"&#38;");
1389 /* or the following works if you don't have memmove:
1390 int len, nmove, ii;
1391 len = strlen(fieldValue);
1392 pp++;
1393 nmove = (len+1) - (pp - fieldValue);
1394 for(ii=0;ii<nmove;ii++){
1395 *pp = *(pp+4);
1396 pp++;
1397 }
1398 */
1399 }
1400 }
1401 return (xmlChar *)fieldValue;
1402}
1403int isUnits();
1404void sfunitf(int nodeType,char *fieldname, float *var, int n, int iuncafield);
1405void mfunitrotation(int nodeType,char *fieldname, struct SFRotation *var, int n, int iuncafield);
1406void sfunitd(int nodeType,char *fieldname, double *var, int n, int iuncafield);
1407void mfunit3f(int nodetype,char *fieldname, struct SFVec3f *var, int n, int iuncafield);
1408static void parseAttributes_B(void *ud, char **atts) {
1409 int i, type, kind, iifield, builtIn, iunca, isunits;
1410 struct X3D_Node *node;
1411 const char *cname;
1412 char *name, *svalue;
1413 const char *ignore [] = {"containerField","USE", "DEF"};
1414 union anyVrml *value;
1415
1416 node = getNode(ud,TOP);
1417 isunits = isUnits();
1418 for (i=0; atts[i]; i+=2) {
1419 name = atts[i];
1420 svalue = atts[i+1];
1421 /* see if we have a containerField here */
1422 if(findFieldInARR(name,ignore,3) == INT_ID_UNDEFINED){
1423 cname = NULL;
1424 if(getFieldFromNodeAndNameU(node,name,&type,&kind,&iifield,&builtIn,&value,&iunca,&cname)){
1425 deleteMallocedFieldValue(type,value);
1426 Parser_scanStringValueToMem_B(value, type,svalue, TRUE);
1427 //apply unit conversionFactor to parsed literal field
1428 // (vs above in endBuiltin_B applyUnitsToNode)
1429 if(isunits)
1430 switch(type){
1431 case FIELDTYPE_SFRotation:
1432 sfunitf(node->_nodeType,name,&value->sfrotation.c[3],1,iunca);
1433 break;
1434 case FIELDTYPE_SFFloat:
1435 sfunitf(node->_nodeType,name,&value->sffloat,1,iunca);
1436 break;
1437 case FIELDTYPE_MFFloat:
1438 sfunitf(node->_nodeType,name,value->mffloat.p,value->mffloat.n,iunca);
1439 break;
1440 case FIELDTYPE_SFVec3f:
1441 sfunitf(node->_nodeType,name,value->sfvec3f.c,3,iunca);
1442 break;
1443 case FIELDTYPE_SFVec4f:
1444 if(iunca == UNCA_PLANE)
1445 sfunitf(node->_nodeType,name,&value->sfvec4f.c[3],1,UNCA_LENGTH); //don't scale first 3 wich are a normal
1446 else
1447 sfunitf(node->_nodeType,name,value->sfvec4f.c,4,iunca);
1448 break;
1449 case FIELDTYPE_SFVec2f:
1450 sfunitf(node->_nodeType,name,value->sfvec2f.c,2,iunca);
1451 break;
1452 case FIELDTYPE_MFVec3f:
1453 mfunit3f(node->_nodeType,name,value->mfvec3f.p,value->mfvec3f.n,iunca);
1454 break;
1455 case FIELDTYPE_SFMatrix3f:
1456 sfunitf(node->_nodeType,name,value->sfmatrix3f.c, 9,iunca);
1457 break;
1458 case FIELDTYPE_MFRotation:
1459 mfunitrotation(node->_nodeType,name,value->mfrotation.p,value->mfrotation.n,iunca);
1460 break;
1461 case FIELDTYPE_SFDouble:
1462 sfunitd(node->_nodeType,name,&value->sfdouble,1,iunca);
1463 break;
1464 default:
1465 break;
1466 }
1467 }
1468 }
1469 if(!strcmp(name,"side")){
1470 //stereoscopic experiments
1471 if(!strcmp(svalue,"left"))
1472 node->_renderFlags |= VF_HideRight;
1473 else if(!strcmp(svalue,"right"))
1474 node->_renderFlags |= VF_HideLeft;
1475 //printf("node renderflags=%d\n",node->_renderFlags);
1476 }
1477 }
1478}
1479
1480
1481int findFieldInARR(const char* field, const char** arr, size_t cnt);
1482static void parseScriptProtoField_B(void *ud, char **atts) {
1483 /* new user field definitions -name,type,mode- possibly with fieldvalue anyVrml
1484 - we will be parsing either:
1485 a ProtoDeclare or ExternProtoDeclare (extern will lack fieldValue)
1486 a Script Node or Shader node
1487 - Script field may have fieldValue as child element, or IS/connect as peer
1488 - ProtoDeclare may have fieldValue as child element
1489 */
1490 //struct X3D_Node *node;
1491 int mp_name, mp_accesstype, mp_type, mp_value, i;
1492 int pkwmode, type;
1493 union anyVrml defaultValue; //, *value;
1494 char *fname, *cname;
1495 //value = NULL;
1496 cname = NULL;
1497 mp_name = mp_accesstype = mp_type = mp_value = ID_UNDEFINED;
1498 if(0) printf("start scriptProtoField\n");
1499 /* have a "key" "value" pairing here. They can be in any order; put them into our order */
1500 for (i = 0; atts[i]; i += 2) {
1501 /* skip any "appinfo" or "documentation" fields here */
1502 if ((strcmp("appinfo", atts[i]) != 0) &&
1503 (strcmp("documentation",atts[i]) != 0)) {
1504 if (strcmp(atts[i],"name") == 0) { mp_name = i+1;
1505 } else if (strcmp(atts[i],"accessType") == 0) { mp_accesstype = i+1;
1506 } else if (strcmp(atts[i],"type") == 0) { mp_type = i+1;
1507 } else if (strcmp(atts[i],"value") == 0) { mp_value = i+1;
1508 } else {
1509 ConsoleMessage ("X3D Proto/Script parsing line %d: unknown field type %s",LINE,atts[i]);
1510 return;
1511 }
1512 }
1513 }
1514 if(mp_accesstype > -1 && mp_type > -1 && mp_name > -1){
1515 int valueSet;
1516 pkwmode = findFieldInARR(atts[mp_accesstype], PROTOKEYWORDS, PROTOKEYWORDS_COUNT);
1517 pkwmode = pkwmode > -1? X3DMODE(pkwmode) : pkwmode;
1518 type = findFieldInARR(atts[mp_type],FIELDTYPES,FIELDTYPES_COUNT);
1519 fname = atts[mp_name];
1520 cname = NULL;
1521 //memset(&defaultValue,0,sizeof(union anyVrml));
1522 bzero(&defaultValue, sizeof (union anyVrml));
1523 if(type == FIELDTYPE_SFString)
1524 defaultValue.sfstring = newASCIIString("");
1525 valueSet = FALSE;
1526 if(mp_value > -1){
1527 Parser_scanStringValueToMem_B(&defaultValue, type, atts[mp_value], TRUE);
1528 valueSet = TRUE;
1529 }
1530 if(pkwmode > -1 && type > -1){
1531 struct X3D_Node * node = getNode(ud,TOP);
1532 if(node->_nodeType == NODE_Proto){
1533 struct X3D_Proto *pnode;
1534 struct ProtoFieldDecl* pfield;
1535 struct ProtoDefinition* pstruct;
1536 pnode = X3D_PROTO(node);
1537 pstruct = (struct ProtoDefinition*) pnode->__protoDef;
1538 pfield = newProtoFieldDecl(pkwmode,type,0);
1539 pfield->cname = STRDUP(fname);
1540 cname = pfield->cname;
1541 memcpy(&pfield->defaultVal,&defaultValue,sizeof(union anyVrml));
1542 vector_pushBack(struct ProtoFieldDecl*, pstruct->iface, pfield);
1543 //value = &pfield->defaultVal;
1544 }else{
1545 struct Shader_Script* shader = NULL;
1546 struct ScriptFieldDecl* sfield;
1547 int jsname;
1548 switch(node->_nodeType)
1549 {
1550 case NODE_Script: shader =(struct Shader_Script *)(X3D_SCRIPT(node)->__scriptObj); break;
1551 case NODE_ComposedShader: shader =(struct Shader_Script *)(X3D_COMPOSEDSHADER(node)->_shaderUserDefinedFields); break;
1552 case NODE_Effect: shader =(struct Shader_Script *)(X3D_EFFECT(node)->_shaderUserDefinedFields); break;
1553 case NODE_ShaderProgram: shader =(struct Shader_Script *)(X3D_SHADERPROGRAM(node)->_shaderUserDefinedFields); break;
1554 case NODE_PackagedShader: shader =(struct Shader_Script *)(X3D_PACKAGEDSHADER(node)->_shaderUserDefinedFields); break;
1555 }
1556 jsname = JSparamIndex (fname, atts[mp_type],pkwmode);
1557 cname = getJSparamnames()[jsname].name;
1558 //sfield = newScriptFieldDecl() // too hard to fathom, I'll break it out:
1559 sfield = MALLOC(struct ScriptFieldDecl *, sizeof(struct ScriptFieldDecl));
1560 bzero(sfield,sizeof(struct ScriptFieldDecl));
1561 sfield->fieldDecl = newFieldDecl(pkwmode,type,0,jsname,0); //not using a lexer
1562 memcpy(&sfield->value,&defaultValue,sizeof(union anyVrml));
1563 sfield->valueSet = valueSet; //=(mod!=PKW_initializeOnly);
1564 sfield->eventInSet = FALSE; //flag used for directOutput
1565 vector_pushBack(struct ScriptFieldDecl*, shader->fields, sfield);
1566 //value = &sfield->value;
1567 }
1568 }
1569 }
1570 pushField(ud,cname); //strdup(fname)); //strong recommendation
1571 pushMode(ud,PARSING_FIELD);
1572}
1573
1574/* simple sanity check, and change mode */
1575static void parseProtoInterface (void *ud, char **atts) {
1576 if (getMode(ud,TOP) != PARSING_PROTODECLARE && getMode(ud,TOP) != PARSING_EXTERNPROTODECLARE) {
1577 ConsoleMessage ("got a <ProtoInterface>, but not within a <ProtoDeclare>\n");
1578 }
1579 //setParserMode(PARSING_PROTOINTERFACE);
1580 pushMode(ud,PARSING_PROTOINTERFACE);
1581}
1582void Parser_scanStringValueToMem_B(union anyVrml* any, indexT ctype, const char *value, int isXML);
1583double getunitlengthfactor();
1584static void parseExternProtoDeclare_B (void *ud, char **atts) {
1585 /* 1.create a new proto but not registered node
1586 2.get user type name from atts
1587 3.set flag for shallow/declare
1588 4.add to current context's externProtoDeclare array
1589 5.push on node stack awaiting interface (with no initial values)
1590 */
1591 int i;
1592 char *type_name, *appinfo, *documentation, *containerfield, *url;
1593 struct ProtoDefinition* obj;
1594 struct X3D_Proto* proto;
1595 struct X3D_Proto* parent;
1596 type_name = appinfo = documentation = containerfield = url = NULL;
1597 if(0) printf("in parseExternProtoDeclare_B\n");
1598
1599 proto = createNewX3DNode0(NODE_Proto);
1600 for (i = 0; atts[i]; i += 2) {
1601 #ifdef X3DPARSERVERBOSE
1602 TTY_SPACE
1603 printf ("parseProtoDeclare: field:%s=%s\n", atts[i], atts[i+1]);
1604 #endif
1605
1606 if (!strcmp("name",atts[i]) ) type_name = atts[i+1];
1607 else if(!strcmp("containerField",atts[i])) containerfield = atts[i+1];
1608 else if(!strcmp("appInfo",atts[i])) appinfo = atts[i+1];
1609 else if(!strcmp("documentation",atts[i])) documentation = atts[i+1];
1610 else if(!strcmp("url",atts[i])) url = atts[i+1];
1611 }
1612
1613 parent = (struct X3D_Proto*)getContext(ud,TOP);
1614 obj=newProtoDefinition();
1615
1616 /* did we find the name? */
1617 if (type_name) {
1618 obj->protoName = STRDUP(type_name);
1619 } else {
1620 printf ("warning - have proto but no name, so just copying a default string in\n");
1621 obj->protoName = STRDUP("noProtoNameDefined");
1622 }
1623 type_name = obj->protoName;
1624
1625 if(parent->__externProtoDeclares == NULL)
1626 parent->__externProtoDeclares = newVector(struct X3D_Proto*,4);
1627 vector_pushBack(struct X3D_Proto*,parent->__externProtoDeclares,proto);
1628 proto->__parentProto = X3D_NODE(parent); //me->ptr; //link back to parent proto, for isAvailableProto search
1629 proto->__protoFlags = parent->__protoFlags;
1630 proto->__protoFlags = ciflag_set(proto->__protoFlags,0,0); //((char*)(&proto->__protoFlags))[0] = 0; //shallow instancing of protoInstances inside a protoDeclare
1632 proto->__protoFlags = ciflag_set(proto->__protoFlags,0,2); //((char*)(&proto->__protoFlags))[2] = 0; //this is a protoDeclare we are parsing
1633 proto->__protoFlags = ciflag_set(proto->__protoFlags,1,3); //((char*)(&proto->__protoFlags))[3] = 1; //an externProtoDeclare
1634 //set ProtoDefinition *obj
1635 proto->__protoDef = obj;
1636 proto->__prototype = X3D_NODE(proto); //point to self, so shallow and deep instances will inherit this value
1637 proto->__typename = STRDUP(obj->protoName);
1638 proto->__unitlengthfactor = getunitlengthfactor();
1639 proto->__specversion = inputFileVersion[0]*100 + inputFileVersion[1]*10 + inputFileVersion[2];
1640 if(containerfield){
1641 int builtinField = findFieldInFIELDNAMES(containerfield);
1642 if(builtinField > -1){
1643 proto->_defaultContainer = builtinField;
1644 }
1645 }
1646 if(url){
1647 Parser_scanStringValueToMem_B((union anyVrml*)&proto->url, FIELDTYPE_MFString,url, TRUE);
1648 }
1649 proto->__loadstatus = 0; //= LOAD_INITIAL_STATE
1650 pushMode(ud,PARSING_EXTERNPROTODECLARE);
1651 pushNode(ud,X3D_NODE(proto));
1652 pushField(ud,"__children");
1653
1654}
1655
1656static void parseProtoDeclare_B (void *ud, char **atts) {
1657 /* 1.create a new proto but not registered node
1658 2.get user type name from atts
1659 3.set flag for shallow/declare
1660 4.add to current context's protoDeclare array
1661 5.push on node stack awaiting interface and body
1662 */
1663 int i;
1664 struct X3D_Proto* proto;
1665 char *type_name, *appinfo, *documentation, *containerfield;
1666 struct ProtoDefinition* obj;
1667 struct X3D_Proto* parent;
1668
1669 type_name = appinfo = documentation = containerfield = NULL;
1670 if(0) printf("in start protoDeclare\n");
1671
1672 proto = createNewX3DNode0(NODE_Proto);
1673 for (i = 0; atts[i]; i += 2) {
1674 #ifdef X3DPARSERVERBOSE
1675 TTY_SPACE
1676 printf ("parseProtoDeclare: field:%s=%s\n", atts[i], atts[i+1]);
1677 #endif
1678
1679 if (!strcmp("name",atts[i]) ) type_name = atts[i+1];
1680 else if(!strcmp("containerField",atts[i])) containerfield = atts[i+1];
1681 else if(!strcmp("appInfo",atts[i])) appinfo = atts[i+1];
1682 else if(!strcmp("documentation",atts[i])) documentation = atts[i+1];
1683 }
1684
1685 parent = (struct X3D_Proto*)getContext(ud,TOP);
1686 obj=newProtoDefinition();
1687
1688 /* did we find the name? */
1689 if (type_name) {
1690 obj->protoName = STRDUP(type_name);
1691 } else {
1692 printf ("warning - have proto but no name, so just copying a default string in\n");
1693 obj->protoName = STRDUP("noProtoNameDefined");
1694 }
1695 type_name = obj->protoName;
1696
1697 if(parent->__protoDeclares == NULL)
1698 parent->__protoDeclares = newVector(struct X3D_Proto*,4);
1699 vector_pushBack(struct X3D_Proto*,parent->__protoDeclares,proto);
1700 proto->__parentProto = X3D_NODE(parent); //me->ptr; //link back to parent proto, for isAvailableProto search
1701 proto->__protoFlags = parent->__protoFlags;
1702 proto->__protoFlags = ciflag_set(proto->__protoFlags,0,0); //((char*)(&proto->__protoFlags))[0] = 0; //shallow instancing of protoInstances inside a protoDeclare
1704 proto->__protoFlags = ciflag_set(proto->__protoFlags,0,2); //((char*)(&proto->__protoFlags))[2] = 0; //this is a protoDeclare we are parsing
1705 proto->__protoFlags = ciflag_set(proto->__protoFlags,0,3); //((char*)(&proto->__protoFlags))[3] = 0; //not an externProtoDeclare
1706 //set ProtoDefinition *obj
1707 proto->__protoDef = obj;
1708 proto->__prototype = X3D_NODE(proto); //point to self, so shallow and deep instances will inherit this value
1709 proto->__typename = STRDUP(obj->protoName);
1710 proto->__unitlengthfactor = getunitlengthfactor();
1711 proto->__specversion = inputFileVersion[0]*100 + inputFileVersion[1]*10 + inputFileVersion[2];
1712 if(containerfield){
1713 int builtinField = findFieldInFIELDNAMES(containerfield);
1714 if(builtinField > -1){
1715 proto->_defaultContainer = builtinField;
1716 }
1717 }
1718
1719 pushMode(ud,PARSING_PROTODECLARE);
1720 pushNode(ud,X3D_NODE(proto));
1721 pushField(ud,"__children");
1722}
1723
1724static void parseProtoBody_B (void *ud, char **atts) {
1725 //push proto node on context stack
1726 pushContext(ud,getNode(ud,TOP));
1727 pushMode(ud,PARSING_PROTOBODY);
1728}
1729
1730struct X3D_Proto *brotoInstance(struct X3D_Proto* proto, BOOL ideep);
1731void add_node_to_broto_context(struct X3D_Proto *context,struct X3D_Node *node);
1732void linkNodeIn_B(void *ud);
1733struct X3D_Node *broto_search_DEFname(struct X3D_Proto *context, const char *name);
1734
1735static void parseProtoInstance_B(void *ud, char **atts) {
1736 /*broto version
1737 1. lookup the user (proto) type in current and parent context protoDeclare and externProtoDeclare tables
1738 2. brotoInstance()
1739 3. parse att and any <fieldValue> and IS
1740 4. on end, deep_copy_broto_body2 applying the initial field values parsed.
1741 */
1742 int i, isUSE;
1743 int nameIndex;
1744 //int containerIndex;
1745 //int containerField;
1746 int defNameIndex;
1747 //int protoTableIndex;
1748 struct X3D_Proto *currentContext;
1749 struct X3D_Node *node = NULL;
1750 char pflagdepth;
1751 struct X3D_Node *fromDEFtable;
1752
1753
1754 /* initialization */
1755 nameIndex = INT_ID_UNDEFINED;
1756 //containerIndex = INT_ID_UNDEFINED;
1757 //containerField = INT_ID_UNDEFINED;
1758 defNameIndex = INT_ID_UNDEFINED;
1759 //protoTableIndex = 0;
1760 if(0) printf("parseProtoInstance\n");
1761 isUSE = FALSE;
1762 for (i = 0; atts[i]; i += 2) {
1763 if (strcmp("name",atts[i]) == 0) {
1764 nameIndex=i+1;
1765 } else if (strcmp("containerField",atts[i]) == 0) {
1766 //containerIndex = i+1;
1767 } else if (strcmp("DEF",atts[i]) == 0) {
1768 defNameIndex = i+1;
1769 } else if (strcmp("class",atts[i]) == 0) {
1770 ConsoleMessage ("field \"class\" not currently used in a ProtoInstance parse... sorry");
1771 } else if (strcmp("USE",atts[i]) == 0) {
1772 //ConsoleMessage ("field \"USE\" not currently used in a ProtoInstance parse.. sorry");
1773 isUSE = TRUE;
1774 defNameIndex = i+1;
1775 }
1776 }
1777
1778 currentContext = getContext(ud,TOP);
1779
1780 pflagdepth = ciflag_get(currentContext->__protoFlags,0); //depth 0 we are deep inside protodeclare, depth 1 we are instancing live scenery
1781
1782
1783
1784 if(isUSE){
1785 //ConsoleMessage ("field \"USE\" not currently used in a ProtoInstance parse.. sorry");
1786 char * defname = atts[defNameIndex]; //gets STRDUP();'d inside broto_store_DEF
1787
1788 fromDEFtable = broto_search_DEFname(currentContext,defname);
1789 if (!fromDEFtable) {
1790 ConsoleMessage ("Warning - line %d DEF name: \'%s\' not found",LINE,atts[i+1]);
1791 ConsoleMessage("\n");
1792 } else {
1793 #ifdef X3DPARSERVERBOSE
1794 printf ("copying for field %s defName %s\n",atts[i], atts[i+1]);
1795 #endif
1796
1797 /* if (fromDEFtable->_nodeType != fromDEFtable->_nodeType) { */
1798 if (NODE_Proto != fromDEFtable->_nodeType) {
1799 ConsoleMessage ("Warning, line %d DEF/USE mismatch, '%s', %s != %s", LINE,
1800 atts[i+1],stringNodeType(fromDEFtable->_nodeType), stringNodeType (NODE_Proto));
1801 } else {
1802 /* Q. should thisNode.referenceCount be decremented or ??? */
1803 char* containerfield;
1804 node = fromDEFtable;
1805 node->referenceCount++; //dug9 added but should???
1806 //getNode(ud,TOP) = thisNode;
1807 #ifdef X3DPARSERVERBOSE
1808 printf ("successful copying for field %s defName %s\n",atts[i], atts[i+1]);
1809 #endif
1810 pushNode(ud,node);
1811 containerfield = NULL;
1812 for (i = 0; atts[i]; i += 2) {
1813 if(!strcmp(atts[i],"containerField")) containerfield = atts[i+1];
1814 }
1815 if(containerfield) {
1816 int builtinField = findFieldInFIELDNAMES(containerfield);
1817 if(builtinField > INT_ID_UNDEFINED){
1818 node->_defaultContainer = builtinField;
1819 }
1820 }
1821 pushField(ud,NULL); //no particular default field
1822 pushMode(ud,PARSING_PROTOINSTANCE_USE);
1823 return;
1824 }
1825 }
1826 }else{
1827 /* did we find the name? */
1828 char *protoname;
1829 protoname = NULL;
1830 if (nameIndex != INT_ID_UNDEFINED) {
1831 protoname = atts[nameIndex];
1832 } else {
1833 ConsoleMessage ("\"ProtoInstance\" found, but field \"name\" not found!\n");
1834 }
1835 if(protoname){
1836
1837 struct X3D_Proto *proto;
1838 if( isAvailableBroto(protoname, currentContext , &proto))
1839 {
1840 //struct X3D_Node *parent;
1841 char* containerfield;
1842 /* its a binary proto, new in 2013 */
1843 int idepth = 0; //if its old brotos (2013) don't do depth until sceneInstance. If 2014 broto2, don't do depth here if we're in a protoDeclare or externProtoDeclare
1844 idepth = pflagdepth == 1; //2014 broto2: if we're parsing a scene (or Inline) then deepcopy proto to instance it, else shallow
1845 node=X3D_NODE(brotoInstance(proto,idepth));
1846 node->_executionContext = X3D_NODE(proto);
1847 if (defNameIndex != INT_ID_UNDEFINED){
1848 char * defname = atts[defNameIndex]; //gets STRDUP();'d inside broto_store_DEF
1849 broto_store_DEF(currentContext,node, defname);
1850 }
1851 add_node_to_broto_context(currentContext,node);
1852
1853 pushNode(ud,node);
1854 containerfield = NULL;
1855 for (i = 0; atts[i]; i += 2) {
1856 if(!strcmp(atts[i],"containerField")) containerfield = atts[i+1];
1857 }
1858 if(containerfield) {
1859 int builtinField = findFieldInFIELDNAMES(containerfield);
1860 if(builtinField > INT_ID_UNDEFINED){
1861 node->_defaultContainer = builtinField;
1862 }
1863 }
1864 //linkNodeIn_B(ud);
1865 //parseAttributes_B(ud,atts); //PI uses FieldValue
1866 }else{
1867 pushNode(ud,NULL);
1868 ConsoleMessage ("Attempt to instance undefined prototype typename %s\n",protoname);
1869 }
1870 }
1871 }
1872 pushField(ud,NULL); //no particular default field
1873 pushMode(ud,PARSING_PROTOINSTANCE);
1874
1875}
1876
1877BOOL nodeTypeSupportsUserFields(struct X3D_Node *node);
1878int getFieldFromNodeAndName(struct X3D_Node* node,const char *fieldname, int *type, int *kind, int *iifield, union anyVrml **value);
1879void broto_store_IS(struct X3D_Proto *proto,char *protofieldname,int pmode, int iprotofield, int pBuiltIn, int type,
1880 struct X3D_Node *node, char* nodefieldname, int mode, int ifield, int nBuiltIn, int source);
1881
1882static void parseConnect_B(void *ud, char **atts) {
1883 int i,okp, okn;
1884 struct X3D_Node *node;
1885 struct X3D_Proto *context, *proto;
1886 char *nodefield;
1887 char *protofield;
1888 node = getNode(ud,TOP);
1889 proto = context = getContext(ud,TOP);
1890
1891 nodefield = protofield = NULL;
1892 for(i=0;atts[i];i+=2){
1893 if(!strcmp(atts[i],"nodeField")) nodefield = atts[i+1];
1894 if(!strcmp(atts[i],"protoField")) protofield = atts[i+1];
1895 }
1896 okp = okn = 0;
1897 if(nodefield && protofield){
1898 int ptype, pkind, pifield, pBuiltIn, ntype, nkind, nifield, nBuiltIn;
1899 const char *pname, *nname;
1900 union anyVrml *pvalue, *nvalue;
1901 okp = getFieldFromNodeAndNameC(X3D_NODE(proto),protofield,&ptype, &pkind, &pifield, &pBuiltIn, &pvalue, &pname);
1902 okn = getFieldFromNodeAndNameC(node, nodefield,&ntype, &nkind, &nifield, &nBuiltIn, &nvalue, &nname);
1903 //check its mode
1904 // http://www.web3d.org/files/specifications/19775-1/V3.2/Part01/concepts.html#t-RulesmappingPROTOTYPEdecl
1905 // there's what I call a mode-jive table
1906 // proto interface
1907 // inputOutput initializeOnly inputOnly outputOnly
1908 // node inputOutput jives jives jives jives
1909 // initializeOnly jives
1910 // inputOnly jives
1911 // outputOnly jives
1912 //
1913 // so if our nodefield's mode is inputOutput/exposedField then we are covered for all protoField modes
1914 // otherwise, the nodefield's mode must be the same as the protofield's mode
1915 if(okp && okn)
1916 if(ntype != ptype){
1917 ConsoleMessage("Parser error: IS - we have a name match: %s IS %s found protofield %s\n",
1918 nodefield,protofield,protofield);
1919 ConsoleMessage("...But the types don't match: nodefield %s protofield %s\n",
1920 FIELDTYPES[ntype],FIELDTYPES[ptype]);
1921 okp = 0;
1922 }
1923 if(okp && okn)
1924 if(nkind != PKW_inputOutput && nkind != pkind){
1925 if(pkind != PKW_inputOutput){
1926 ConsoleMessage("Parser Error: IS - we have a name match: %s IS %s found protofield %s\n",
1927 nodefield,protofield,protofield);
1928 ConsoleMessage("...But the modes don't jive: nodefield %s protofield %s\n",
1929 PROTOKEYWORDS[nkind],PROTOKEYWORDS[pkind]);
1930 okp = 0;
1931 }else{
1932 ConsoleMessage("Parser Warning: IS - we have a name match: %s IS %s found protofield %s\n",
1933 nodefield,protofield,protofield);
1934 ConsoleMessage("...But the modes don't jive: nodefield %s protofield %s\n",
1935 PROTOKEYWORDS[nkind],PROTOKEYWORDS[pkind]);
1936 ConsoleMessage("...will thunk\n");
1937 }
1938 }
1939 if(okp && okn){
1940 int source;
1941 //we have an IS that's compatible/jives
1942 //a) copy the value if it's an initializeOnly or inputOutput
1943 if(pkind == PKW_initializeOnly || pkind == PKW_inputOutput)
1944 {
1945 shallow_copy_field(ntype, pvalue , nvalue);
1946 }
1947 //b) register it in the IS-table for our context
1948 source = node->_nodeType == NODE_Proto ? 3 : node->_nodeType == NODE_Script ? 1 : nodeTypeSupportsUserFields(node) ? 2 : 0;
1949 //Q. do I need to convert builtin from field index to offset? if( source == 0) nifield *=5;
1950 broto_store_IS(context,protofield,pkind,pifield,pBuiltIn,ptype,
1951 node,nodefield,nkind,nifield,nBuiltIn,source);
1952 }
1953 }
1954}
1955
1956static void XMLCALL X3DstartElement(void *ud, const xmlChar *iname, const xmlChar **atts) {
1957 int myNodeIndex;
1958 char **myAtts;
1959 int i;
1960 char *blankAtts[] = {NULL,NULL};
1961 const char *name = (const char*) iname; // get around compiler warnings on iPhone, etc...
1962
1963 /* libxml passes NULL, while expat passes {0,0}. Make them the same */
1964 if (atts == NULL) myAtts = blankAtts;
1965 else myAtts = (char **) atts;
1966
1967 #ifdef X3DPARSERVERBOSE
1968 //printf ("startElement: %s : level %d parserMode: %s \n",name,parentIndex,parserModeStrings[getMode(ud,TOP)]);
1969 printf ("X3DstartElement: %s: atts %p\n",name,atts);
1970 //printf ("startElement, myAtts :%p contents %p\n",myAtts,myAtts[0]);
1971 { int i;
1972 for (i = 0; myAtts[i]; i += 2) {
1973 printf(" X3DStartElement field:%s=%s\n", myAtts[i], atts[i + 1]);
1974 }}
1975
1976 //printf ("X3DstartElement - finished looking at myAtts\n\n");
1977 #endif
1978
1979 if(atts)
1980 for (i = 0; atts[i]; i += 2) {
1981 atts[i+1] = fixAmp(atts[i+1]);
1982 }
1983
1984
1985 myNodeIndex = findFieldInNODES(name);
1986
1987 /* is this a "normal" node that can be found in x3d, x3dv and wrl files? */
1988 if (myNodeIndex != INT_ID_UNDEFINED) {
1989 startBuiltin_B(ud,myNodeIndex,(const xmlChar *)name,myAtts);
1990 return;
1991 }
1992 /*in theory, you could search broto prototype typenames here, and if found
1993 assume it's instanced with builtin syntax (instead of ProtoInstance syntax)
1994 if( isAvailableBroto(name, getContext(ud,TOP) , &proto))
1995 */
1996
1997 /* no, it is not. Lets see what else it could be... */
1998 myNodeIndex = findFieldInX3DSPECIAL(name);
1999 if (myNodeIndex != INT_ID_UNDEFINED) {
2000 switch (myNodeIndex) {
2001 case X3DSP_ProtoDeclare:
2002 parseProtoDeclare_B(ud,myAtts);
2003 break;
2004 case X3DSP_ExternProtoDeclare:
2005 parseExternProtoDeclare_B(ud,myAtts);
2006 break;
2007 case X3DSP_ProtoBody:
2008 parseProtoBody_B(ud,myAtts);
2009 break;
2010 case X3DSP_ProtoInterface:
2011 parseProtoInterface(ud,myAtts);
2012 break;
2013 case X3DSP_ProtoInstance:
2014 parseProtoInstance_B(ud,myAtts);
2015 break;
2016 case X3DSP_ROUTE:
2017 parseRoutes_B(ud,myAtts);
2018 break;
2019 case X3DSP_meta: parseMeta(myAtts); break;
2020 case X3DSP_Scene: parseScene(myAtts); break;
2021 case X3DSP_head:
2022 case X3DSP_Header: parseHeader(myAtts); break;
2023 case X3DSP_X3D: parseX3Dhead(ud,myAtts); break;
2024 case X3DSP_fieldValue:
2025 parseFieldValue_B(ud,myAtts);
2026 break;
2027 case X3DSP_field:
2028 parseScriptProtoField_B (ud, myAtts);
2029 break;
2030 case X3DSP_IS: parseIS(ud); break;
2031 case X3DSP_component: parseComponent(myAtts); break;
2032 case X3DSP_EXPORT:
2033 parseExport_B(ud,myAtts);
2034 break;
2035 case X3DSP_IMPORT:
2036 parseImport_B(ud,myAtts);
2037 break;
2038 case X3DSP_connect:
2039 parseConnect_B(ud,myAtts);
2040 break;
2041 case X3DSP_unit:
2042 parseUnit(ud,myAtts); break;
2043 default: printf (" huh? startElement, X3DSPECIAL, but not handled?? %d, :%s:\n",myNodeIndex,X3DSPECIAL[myNodeIndex]);
2044 }
2045 return;
2046 }
2047 printf ("startElement name do not currently handle this one :%s: index %d\n",name,myNodeIndex);
2048}
2049
2050static void endScriptProtoField_B(void *ud) {
2051 if(0) printf("end scriptprotofield\n");
2052 popField(ud);
2053 popMode(ud); //PARSING_FIELD);
2054}
2055
2056
2057static void XMLCALL X3DendElement(void *ud, const xmlChar *iname) {
2058 int myNodeIndex;
2059 const char*name = (const char*) iname;
2060 //ttglobal tg = gglobal();
2061 //ppX3DParser p = (ppX3DParser)tg->X3DParser.prv;
2062
2063 /* printf ("X3DEndElement for %s\n",name); */
2064
2065 #ifdef X3DPARSERVERBOSE
2066 printf ("endElement: %s : parentIndex %d mode %s\n",name,parentIndex,parserModeStrings[getMode(ud,TOP)]);
2067 #endif
2068
2069
2070
2071 myNodeIndex = findFieldInNODES(name);
2072 if (myNodeIndex != INT_ID_UNDEFINED) {
2073 endBuiltin_B(ud,iname);
2074 return;
2075
2076 }
2077
2078
2079
2080 /* no, it is not. Lets see what else it could be... */
2081 myNodeIndex = findFieldInX3DSPECIAL(name);
2082 if (myNodeIndex != INT_ID_UNDEFINED) {
2083 switch (myNodeIndex) {
2084 case X3DSP_ProtoInstance:
2085 endProtoInstance_B(ud,name);
2086 break;
2087 case X3DSP_ProtoInterface:
2088 endProtoInterfaceTag(ud);
2089 break;
2090 case X3DSP_ProtoBody:
2091 endProtoBodyTag_B(ud,name);
2092 break;
2093 case X3DSP_ProtoDeclare:
2094 endProtoDeclareTag_B(ud);
2095 break;
2096 case X3DSP_ExternProtoDeclare:
2097 endExternProtoDeclareTag_B(ud);
2098 break;
2099 case X3DSP_IS:
2100 endIS(ud);
2101 break;
2102 case X3DSP_connect:
2103 case X3DSP_ROUTE:
2104 case X3DSP_meta:
2105 case X3DSP_Scene:
2106 case X3DSP_head:
2107 case X3DSP_Header:
2108 case X3DSP_component:
2109 case X3DSP_EXPORT:
2110 case X3DSP_IMPORT:
2111 case X3DSP_unit:
2112 case X3DSP_X3D: break;
2113 case X3DSP_field:
2114 endScriptProtoField_B(ud);
2115 break;
2116 case X3DSP_fieldValue:
2117 endFieldValue_B(ud);
2118 break;
2119
2120 /* should never do this: */
2121 default:
2122 printf ("endElement: huh? X3DSPECIAL, but not handled?? %s\n",X3DSPECIAL[myNodeIndex]);
2123 }
2124 return;
2125 }
2126
2127 printf ("unhandled endElement name %s index %d\n",name,myNodeIndex);
2128 #ifdef X3DPARSERVERBOSE
2129 printf ("endElement %s\n",name);
2130 #endif
2131}
2132
2133static XML_Parser initializeX3DParser () {
2134 ppX3DParser p = (ppX3DParser)gglobal()->X3DParser.prv;
2135 p->X3DParserRecurseLevel++;
2136
2137 if (p->X3DParserRecurseLevel >= PROTOINSTANCE_MAX_LEVELS) {
2138 ConsoleMessage ("XML_PARSER init: XML file PROTO nested too deep\n");
2139 p->X3DParserRecurseLevel--;
2140 } else {
2141 XML_CreateParserLevel(p->x3dparser[p->X3DParserRecurseLevel]);
2142 XML_SetElementHandler(p->x3dparser[p->X3DParserRecurseLevel], X3DstartElement, X3DendElement);
2143 XML_SetCdataSectionHandler (p->x3dparser[p->X3DParserRecurseLevel], startCDATA, endCDATA);
2144 XML_SetDefaultHandler (p->x3dparser[p->X3DParserRecurseLevel],handleCDATA);
2145 XML_SetUserData(p->x3dparser[p->X3DParserRecurseLevel], &parentIndex);
2146 }
2147 /* printf ("initializeX3DParser, level %d, parser %u\n",x3dparser[X3DParserRecurseLevel]); */
2148 return p->x3dparser[p->X3DParserRecurseLevel];
2149}
2150
2151static void shutdownX3DParser (void *ud) {
2152 ttglobal tg = gglobal();
2153 ppX3DParser p = (ppX3DParser)tg->X3DParser.prv;
2154
2155 /* printf ("shutdownX3DParser, recurseLevel %d\n",X3DParserRecurseLevel); */
2156 XML_ParserFree(p->x3dparser[p->X3DParserRecurseLevel]);
2157 p->X3DParserRecurseLevel--;
2158
2159 /* lets free up memory here for possible PROTO variables */
2160 if (p->X3DParserRecurseLevel == INT_ID_UNDEFINED) {
2161 /* if we are at the bottom of the parser call nesting, lets reset parentIndex */
2162 gglobal()->X3DParser.parentIndex = 0; //setParentIndex( 0 );
2163 //freeProtoMemory ();
2164 }
2165
2166 if (p->X3DParserRecurseLevel < INT_ID_UNDEFINED) {
2167 ConsoleMessage ("XML_PARSER close underflow");
2168 p->X3DParserRecurseLevel = INT_ID_UNDEFINED;
2169 }
2170
2171 /* CDATA text space, free it up */
2172 FREE_IF_NZ(tg->X3DParser.CDATA_Text);
2173 p->CDATA_TextMallocSize = 0;
2174 if (p->X3DParserRecurseLevel > INT_ID_UNDEFINED)
2175 p->currentX3DParser = p->x3dparser[p->X3DParserRecurseLevel];
2176 /* printf ("shutdownX3DParser, current X3DParser %u\n",currentX3DParser); */
2177 popMode(ud);
2178
2179 if(p->DEFedNodes){
2180 int i;
2181 for(i=0;i<vectorSize(p->DEFedNodes);i++){
2182 struct Vector* vd = vector_get(struct Vector*,p->DEFedNodes,i);
2183 deleteVector(struct X3D_Node*,vd);
2184 }
2185 deleteVector(struct Vector*, p->DEFedNodes);
2186 }
2187
2188 /*
2189 * Cleanup function for the XML library.
2190 */
2191 xmlCleanupParser();
2192 /*
2193 * this is to debug memory for regression tests
2194 */
2195 xmlMemoryDump();
2196}
2197
2198int X3DParse (struct X3D_Node* ectx, struct X3D_Node* myParent, const char *inputstring) {
2199 ttglobal tg = gglobal();
2200 ppX3DParser p = (ppX3DParser)tg->X3DParser.prv;
2201 p->currentX3DParser = initializeX3DParser();
2202
2203 //printf ("X3DParse, current X3DParser is %p, p is %p\n",p->currentX3DParser,p);
2204
2205
2206 DEBUG_X3DPARSER ("X3DPARSE on :\n%s:\n",inputstring);
2207 if(p->user_data == NULL){
2208 //just once. We are re-entrant when parsing text protos (trotos)
2209 // and want to keep the stack for the parent scene
2210 p->user_data = new_xml_user_data();
2211 }
2212 pushContext(p->user_data,ectx);
2213 if(myParent->_nodeType == NODE_Proto )
2214 pushField(p->user_data,"__children");
2215 else
2216 pushField(p->user_data,"children");
2217 pushNode(p->user_data,myParent);
2218 pushMode(p->user_data,PARSING_NODES);
2219
2220 if (XML_ParseFile(p->currentX3DParser, p->user_data, inputstring, (int) strlen(inputstring), TRUE) == XML_STATUS_ERROR) {
2221 // http://xmlsoft.org/html/libxml-xmlerror.html
2222 xmlErrorPtr xe = xmlGetLastError();
2223 ConsoleMessage("Xml Error %s \n",xe->message);
2224 ConsoleMessage("Line %d\n",xe->line);
2225 /*
2226 fprintf(stderr,
2227 "%s at line %d\n",
2228 XML_ErrorString(XML_GetErrorCode(currentX3DParser)),
2229 XML_GetCurrentLineNumber(currentX3DParser));
2230 */
2231 popField(p->user_data);
2232 shutdownX3DParser(p->user_data);
2233 Parser_deleteParserForScanStringValueToMem();
2234 return FALSE;
2235 }
2236 popField(p->user_data);
2237 shutdownX3DParser(p->user_data);
2238 Parser_deleteParserForScanStringValueToMem();
2239 return TRUE;
2240}