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 //APR 22, 2020 I moved nodetype defaultContainerFields to static short NODE_DEFAULT_CONTAINER[][7]
762 //this will expand limit to 8 - one _defaultContainer supplied by scene author, and up to 7 from perl
763 //defaultContainer[0] = (jContainer << 22) >> 22;
764 //defaultContainer[1] = (jContainer << 12) >> 22;
765 //defaultContainer[2] = (jContainer << 2) >> 22;
766 //ncontainer = 1;
767 //if(defaultContainer[1])
768 // ncontainer = 2;
769 //if(defaultContainer[2])
770 // ncontainer = 3;
771 ncontainer = 8;
772 for(i=0;i<ncontainer;i++){
773 if(i==0) iContainer = jContainer;
774 else {
775 struct X3D_Node *typenode = getTypeNode(node);
776 if(typenode){
777 int nt = typenode->_nodeType;
778 iContainer = NODE_DEFAULT_CONTAINER[nt][i-1];
779 }
780 }
781 //iContainer = defaultContainer[i];
782 if(iContainer == FIELDNAMES_children) iContainer = 0;
783 value = NULL;
784 fname = NULL;
785 ok = 0;
786 if(iContainer){
787 fname = FIELDNAMES[iContainer];
788 ok = getFieldFromNodeAndName(parent,fname,&type,&kind,&iifield,&value);
789 ok = ok && (kind == PKW_initializeOnly || kind == PKW_inputOutput); //not inputOnly or outputOnly - we can't park nodes there
790 }
791 if(!value && iContainer == FIELDNAMES_children){
792 //if you try and put a transform into a proto, or LOD, or Inline (or switch?) you'll come in
793 //here to get the equivalent-to-children field
794 ok = getFieldFromNodeAndName(parent,"children",&type,&kind,&iifield,&value);
795 ok = ok && (kind == PKW_initializeOnly || kind == PKW_inputOutput); //not inputOnly or outputOnly - we can't park nodes there
796 if(!ok){
797 int kids = indexChildrenName(parent);
798 if(kids > 0){
799 value = (union anyVrml*)childrenField(parent);
800 type = FIELDTYPE_MFNode;
801 }
802 }
803 }
804 if(ok)
805 break;
806 }
807 //3.b)
808 //if(parentsSuggestion) {
809 if(!ok && parentsSuggestion) {
810 //if you're parsing a fieldValue, and your value is an SF or MFnode in a child xml element,
811 //<fieldValue name='myTransform'>
812 // <Transform USE='tommysTransform'/>
813 //</fieldValue>
814 //you'll come in here
815 //don't want to come in here for metadata
816 ok =getFieldFromNodeAndName(parent,parentsSuggestion,&type,&kind,&iifield,&value);
817 }
818
819 if(!value && parent){
820 ok = getFieldFromNodeAndName(parent,"children",&type,&kind,&iifield,&value);
821 if(!ok){
822 int kids = indexChildrenName(parent);
823 if(kids > 0){
824 value = (union anyVrml*)childrenField(parent);
825 type = FIELDTYPE_MFNode;
826 }
827 }
828 }
829
830 if(value){
831 if(type == FIELDTYPE_SFNode){
832 value->sfnode = node;
833 ADD_PARENT(node,parent);
834 }else if(type == FIELDTYPE_MFNode){
835
836 // this was adding duplicats ie adding to addChildren (calls add_parent),
837 // then opengl utils startofloopnodeupdates was moving rootnode addchildren to __children,
838 // triggering anohter add_parent
839 union anyVrml *valueadd = NULL;
840 ok = 0;
841 if(parent->_nodeType == NODE_Proto){
842 struct X3D_Proto *pparent = X3D_PROTO(parent);
843 char cflag = ciflag_get(pparent->__protoFlags,2);
844 if(cflag == 2) //scene
845 ok = getFieldFromNodeAndName(parent,"addChildren",&type,&kind,&iifield,&valueadd);
846 }
847 if(ok)
848 AddRemoveChildren(parent,&valueadd->mfnode,&node,1,1,__FILE__,__LINE__);
849 else
850
851 AddRemoveChildren(parent,&value->mfnode,&node,1,1,__FILE__,__LINE__);
852 }
853 }else{
854 printf("no where to put node in parent\n");
855 printf("nodetype=%s parenttype=%s\n",stringNodeType(node->_nodeType),stringNodeType(parent->_nodeType));
856
857 }
858 }
859
860}
861
862
863void Parser_scanStringValueToMem_B(union anyVrml* any, indexT ctype, const char *value, int isXML);
864
865static void endCDATA_B (void *ud, const xmlChar *string, int len) {
866 char *fieldname = getField(ud,TOP);
867 struct X3D_Node *node = getNode(ud,TOP);
868 int type, kind, iifield, ok, handled;
869 union anyVrml *value;
870 ok = getFieldFromNodeAndName(node,fieldname,&type,&kind,&iifield,&value);
871 if(ok){
872 handled = FALSE;
873 if(!strcmp(fieldname,"url")){
874 //Script javascript doesn't parse well as an MFString
875 if(strstr((char*)string,"script")){
876 handled = TRUE;
877 value->mfstring.n = 1;
878 value->mfstring.p = MALLOCV(sizeof(void *));
879 value->mfstring.p[0] = newASCIIString((char *)string);
880 //if(0) printf("copied cdata string= [%s]\n",(struct Uni_String*)(value->mfstring.p[0])->strptr);
881 }
882 }
883 if(!handled)
884 Parser_scanStringValueToMem_B(value, type, (const char*) string, TRUE);
885 }
886}
887
888void endCDATA (void *ud, const xmlChar *string, int len) {
889 endCDATA_B(ud,string,len);
890 return;
891}
892
893
894
895void handleImport_B (struct X3D_Node *nodeptr, char *nodeName,char *nodeImport, char *as);
896static void parseImport_B(void *ud, char **atts) {
897 int i;
898 char *inlinedef, *exporteddef, *as;
899 struct X3D_Proto *context;
900 context = getContext(ud,TOP);
901
902 inlinedef = exporteddef = as = NULL;
903 for (i = 0; atts[i]; i += 2) {
904 printf("import field:%s=%s\n", atts[i], atts[i + 1]);
905 if(!strcmp(atts[i],"inlineDEF")) inlinedef = atts[i+1];
906 if(!strcmp(atts[i],"exportedDEF")) exporteddef = atts[i+1];
907 if(!strcmp(atts[i],"AS")) as = atts[i+1];
908
909 }
910 handleImport_B (X3D_NODE(context), inlinedef, exporteddef, as);
911}
912
913
914void handleExport_B (void *nodeptr, char *node, char *as);
915static void parseExport_B(void *ud, char **atts) {
916 // http://www.web3d.org/documents/specifications/19776-1/V3.3/Part01/concepts.html#IMPORT_EXPORTStatementSyntax
917 int i;
918 char *localdef, *as;
919 struct X3D_Proto *context;
920 context = getContext(ud,TOP);
921
922 localdef = as = NULL;
923 for (i = 0; atts[i]; i += 2) {
924 printf("export field:%s=%s\n", atts[i], atts[i + 1]);
925 if(!strcmp(atts[i],"localDEF")) localdef = atts[i+1];
926 if(!strcmp(atts[i],"AS")) as = atts[i+1];
927 }
928 handleExport_B(context,localdef, as);
929}
930
931
932/* parse a component statement, and send the results along */
933static void parseComponent(char **atts) {
934 int i;
935 int myComponent = INT_ID_UNDEFINED;
936 int myLevel = INT_ID_UNDEFINED;
937
938 /* go through the fields and make sense of them */
939 for (i = 0; atts[i]; i += 2) {
940 /* printf("components field:%s=%s\n", atts[i], atts[i + 1]); */
941 if (strcmp("level",atts[i]) == 0) {
942 if (sscanf(atts[i+1],"%d",&myLevel) != 1) {
943 ConsoleMessage ("Line %d: Expected Component level for component %s, got %s",LINE, atts[i], atts[i+1]);
944 return;
945 }
946 } else if (strcmp("name",atts[i]) == 0) {
947 char *comp_name = atts[i+1];
948 if(!strcmp(comp_name,"H-Anim")) comp_name = "HAnim";
949 myComponent = findFieldInCOMPONENTS(comp_name);
950 if (myComponent == INT_ID_UNDEFINED) {
951 ConsoleMessage("Line %d: Component statement, but component name not valid :%s:",LINE,atts[i+1]);
952 return;
953 }
954
955 } else {
956 ConsoleMessage ("Line %d: Unknown fields in Component statement :%s: :%s:",LINE,atts[i], atts[i+1]);
957 }
958 }
959
960 if (myComponent == INT_ID_UNDEFINED) {
961 ConsoleMessage("Line %d: Component statement, but component name not stated",LINE);
962 } else if (myLevel == INT_ID_UNDEFINED) {
963 ConsoleMessage("Line %d: Component statement, but component level not stated",LINE);
964 } else {
965 handleComponent(myComponent,myLevel);
966 }
967}
968
969/* parse the <X3D profile='Immersive' version='3.0' xm... line */
970static void parseX3Dhead(void *ud, char **atts) {
971 int i;
972 int myProfile = -10000; /* something negative, not INT_ID_UNDEFINED... */
973 int versionIndex = INT_ID_UNDEFINED;
974 struct X3D_Proto* ec = (struct X3D_Proto*)getContext(ud,TOP);
975
976 for (i = 0; atts[i]; i += 2) {
977 /* printf("parseX3Dhead: field:%s=%s\n", atts[i], atts[i + 1]); */
978 if (strcmp("profile",atts[i]) == 0) {
979 myProfile = findFieldInPROFILES(atts[i+1]);
980 } else if (strcmp("version",atts[i]) == 0) {
981 versionIndex = i+1;
982 } else {
983 /* printf ("just skipping this data\n"); */
984 }
985 }
986
987 /* now, handle all the found variables */
988 if (myProfile == INT_ID_UNDEFINED) {
989 ConsoleMessage ("expected valid profile in X3D header");
990 } else {
991 /* printf ("X3DParsehead, myProfile %d\n",myProfile); */
992 if (myProfile >= 0) handleProfile (myProfile);
993 }
994
995 if (versionIndex != INT_ID_UNDEFINED) {
996 handleVersion (atts[versionIndex]);
997 //already set to 300 in resources.c when file is initially identified as x3d
998 //we update here with more specific <X3D version='3.3.0'> version
999 ec->__specversion = inputFileVersion[0]*100 + inputFileVersion[1]*10 + inputFileVersion[2];
1000 }
1001}
1002
1003static void parseHeader(char **atts) {
1004 int i;
1005 for (i = 0; atts[i]; i += 2) {
1006 /* printf("parseHeader: field:%s=%s\n", atts[i], atts[i + 1]); */
1007 }
1008}
1009static void parseScene(char **atts) {
1010 int i;
1011 for (i = 0; atts[i]; i += 2) {
1012 /* printf("parseScene: field:%s=%s\n", atts[i], atts[i + 1]); */
1013 }
1014}
1015static void parseMeta(void* ud, char **atts) {
1016 struct X3D_Proto* ec = (struct X3D_Proto*)getContext(ud, TOP);
1017 char* name, * content;
1018 name = NULL;
1019 content = NULL;
1020 int i;
1021 for (i = 0; atts[i]; i += 2) {
1022 /* printf("parseMeta field:%s=%s\n", atts[i], atts[i + 1]); */
1023 if (!strcmp(atts[i], "name"))
1024 name = atts[i + 1];
1025 if (!strcmp(atts[i], "category"))
1026 content = atts[i + 1];
1027 }
1028 handleMetaDataStringString((void*)ec, name, content);
1029}
1030static void parseUnit(void *ud, char **atts) {
1031 double conversionFactor = 1.0;
1032 char *name, *category;
1033 struct X3D_Proto* ec = (struct X3D_Proto*)getContext(ud,TOP);
1034
1035 name = category = NULL;
1036 int i;
1037 for (i = 0; atts[i]; i += 2){
1038 if(!strcmp(atts[i],"name"))
1039 name = atts[i+1];
1040 if(!strcmp(atts[i],"category"))
1041 category = atts[i+1];
1042 if(!strcmp(atts[i],"conversionFactor"))
1043 sscanf(atts[i+1],"%lf",&conversionFactor);
1044 }
1045 handleUnitDataStringString(ec,category, name, conversionFactor);
1046}
1047void deleteMallocedFieldValue(int type,union anyVrml *fieldPtr);
1048static void parseFieldValue_B(void *ud, char **atts) {
1049 int i, type, kind, iifield, builtIn, ok;
1050 const char *fname, *svalue, *cname;
1051 union anyVrml *value;
1052 struct X3D_Node *node = getNode(ud,TOP);
1053
1054 fname = svalue = NULL;
1055 for(i=0;atts[i];i+=2){
1056 if(!strcmp(atts[i],"name")) fname = atts[i+1];
1057 if(!strcmp(atts[i],"value")) svalue = atts[i+1];
1058 }
1059 ok = 0;
1060 cname = NULL;
1061 value = NULL;
1062 builtIn = FALSE;
1063 if(fname){
1064 ok = getFieldFromNodeAndNameC(node,fname,&type,&kind,&iifield,&builtIn,&value,&cname);
1065 }
1066 if(cname && value && svalue){
1067 deleteMallocedFieldValue(type,value);
1068 Parser_scanStringValueToMem_B(value,type,svalue,TRUE);
1069 }
1070 if(cname && (node->_nodeType == NODE_Proto) && !builtIn){
1071 //for protoInstances, whether or not you have a value,
1072 //if you declare a field then you are saying you declare the value null or 0 or default at least.
1073 //so for SFNode fields where <fieldValue><a node></fieldValue> and we get the node later
1074 //whether or not there's a node/value parsed, we are declaring its set even at null.
1075 //therefore alreadyset
1076 //the way to acheive not alreadySet is to not mention the field in your protoInstance.
1077 struct X3D_Proto *pnode;
1078 struct ProtoFieldDecl* pfield;
1079 struct ProtoDefinition* pstruct;
1080 pnode = X3D_PROTO(node);
1081 pstruct = (struct ProtoDefinition*) pnode->__protoDef;
1082 pfield = vector_get(struct ProtoFieldDecl*,pstruct->iface,iifield);
1083 //is there a function for zeroing a fieldValue of anytype? Need it here.
1084 //in xml the MFNode in particular will get 'added to' ie mf.n++ later, so need to clear that
1085 // see tests/protos/questionforexperts_mod.x3d
1086 if(pfield->type == FIELDTYPE_MFNode){
1087 struct Multi_Node* mfn = &pfield->defaultVal.mfnode;
1088 if(mfn->n)
1089 AddRemoveChildren(node,mfn,mfn->p,mfn->n,2,__FILE__,__LINE__);
1090 pfield->defaultVal.mfnode.n = 0;
1091 pfield->defaultVal.mfnode.p = NULL;
1092 }
1093 if(pfield->type == FIELDTYPE_SFNode){
1094 struct X3D_Node **sfn = &pfield->defaultVal.sfnode;
1095 if(*sfn)
1096 AddRemoveSFNodeFieldChild(node,sfn,*sfn,2,__FILE__,__LINE__);
1097 pfield->defaultVal.sfnode = NULL;
1098 }
1099 pfield->alreadySet = TRUE;
1100 }
1101 pushField(ud,cname); //in case there's no value, because its SF or MFNodes in child xml, or in CDATA
1102}
1103static void endFieldValue_B(void *ud){
1104 if(0) printf("endFieldValue\n");
1105 //in x3d, <fieldvalue type=SFNode><a node></fieldValue>
1106
1107 popField(ud);
1108}
1109
1110
1111static void parseIS(void *ud) {
1112 #ifdef X3DPARSERVERBOSE
1113 printf ("parseIS mode is %s\n",parserModeStrings[getMode(ud,TOP)]);
1114 #endif
1115 pushMode(ud,PARSING_IS);
1116
1117}
1118
1119
1120
1121static void endIS(void *ud) {
1122 #ifdef X3DPARSERVERBOSE
1123 printf ("endIS mode is %s\n",parserModeStrings[getMode(ud,TOP)]);
1124 #endif
1125 popMode(ud);
1126}
1127
1128
1129
1130static void endProtoInterfaceTag(void *ud) {
1131 if (getMode(ud,TOP) != PARSING_PROTOINTERFACE) {
1132 ConsoleMessage ("endProtoInterfaceTag: got a </ProtoInterface> but not parsing one at line %d",LINE);
1133 }
1134 /* now, a ProtoInterface should be within a ProtoDeclare, so, make the expected mode PARSING_PROTODECLARE */
1135 //setParserMode(PARSING_PROTODECLARE);
1136 popMode(ud);
1137}
1138static void endProtoBodyTag_B(void *ud, const char *name) {
1139 //pop context
1140 if (getMode(ud,TOP) != PARSING_PROTOBODY) {
1141 ConsoleMessage ("endProtoBodyTag: got a </ProtoBody> but not parsing one at line %d",LINE);
1142 }
1143 popMode(ud);
1144 popContext(ud);
1145}
1146
1147static void endExternProtoDeclareTag_B(void *ud) {
1148 popMode(ud);
1149 popNode(ud);
1150 popField(ud);
1151}
1152
1153static void endProtoDeclareTag_B(void *ud) {
1154 /* ending <ProtoDeclare> */
1155 struct X3D_Proto * proto;
1156 struct Multi_Node *cptr;
1157
1158 if (getMode(ud,TOP) != PARSING_PROTODECLARE) {
1159 ConsoleMessage ("endProtoDeclareTag: got a </ProtoDeclare> but not parsing one at line %d",LINE);
1160 pushMode(ud,PARSING_PROTODECLARE);
1161 }
1162 if(0) printf("end protoDeclare\n");
1163 // set defaultContainer based on 1st child
1164 proto = X3D_PROTO(getNode(ud,TOP));
1165 cptr = NULL;
1166 if(proto->__children.n)
1167 cptr = &proto->__children;
1168 else if(proto->addChildren.n)
1169 cptr = &proto->addChildren;
1170 if(cptr){
1171 struct X3D_Node *c1 = cptr->p[0];
1172 if(c1->_defaultContainer > INT_ID_UNDEFINED)
1173 proto->_defaultContainer = c1->_defaultContainer;
1174 }
1175 popField(ud);
1176 popNode(ud); //I think I should pop the X3DProto off the stack
1177 popMode(ud);
1178}
1179
1180
1181void deep_copy_broto_body2(struct X3D_Proto** proto, struct X3D_Proto** dest);
1182static void endProtoInstance_B(void *ud, const char *name) {
1183 //now that initial field values are set, deep copy the broto body
1184 int mode;
1185 struct X3D_Node *node;
1186 if(0) printf("endProtoInstance_B\n");
1187
1188 node = getNode(ud,TOP);
1189 mode = getMode(ud,TOP);
1190 if(node){
1191 if(node->_nodeType == NODE_Proto || node->_nodeType == NODE_Inline ){
1192 if(mode != PARSING_PROTOINSTANCE_USE){
1193 char pflagdepth;
1194 struct X3D_Proto *pnode = X3D_PROTO(node);
1195 pflagdepth = ciflag_get(pnode->__protoFlags,0); //0 - we're in a protodeclare, 1 - we are instancing live scenery
1196 if( pflagdepth){
1197 //copying the body _after_ the protoInstance field values have been parsed
1198 //allows ISd fields in body nodes to get the pkw_initializeOnly/inputOutput value
1199 //from the protoInstance interface
1200 struct X3D_Proto *pdeclare;
1201 pdeclare = X3D_PROTO(pnode->__prototype);
1202 //if you bomb around here, pdeclare == null, then make sure your scene
1203 // doesn't have protoDeclares with the same name as freewrl builtin types
1204 // because as of Nov 2016 freewrl doesn't allow over-riding builtins with protos,
1205 // and gets confused and bombs
1206 deep_copy_broto_body2(&pdeclare,&pnode);
1207 }
1208 }
1209 }
1210 linkNodeIn_B(ud);
1211 }
1212 popField(ud);
1213 popNode(ud);
1214 popMode(ud);
1215}
1216
1217/* did we get a USE in a proto instance, like:
1218<ProtoInstance name='CamLoader' DEF='Camera1_Bgpic'>
1219 <fieldValue name='imageName' value='Default.jpg'/>
1220 <fieldValue name='relay'>
1221 <Script USE='CameraRelay'/>
1222 </fieldValue>
1223 <fieldValue name='yscale' value='3.0'/>
1224</ProtoInstance>
1225
1226if so, we will be here for the USE fields.
1227
1228
1229*/
1230
1231/********************************************************/
1232
1233
1234void **shaderFields(struct X3D_Node* node){
1235 void **shaderfield;
1236 switch(node->_nodeType){
1237 case NODE_Script:
1238 shaderfield = &X3D_SCRIPT(node)->__scriptObj; break;
1239 case NODE_ComposedShader:
1240 shaderfield = (void**)&X3D_COMPOSEDSHADER(node)->_shaderUserDefinedFields; break;
1241 case NODE_Effect:
1242 shaderfield = (void**)&X3D_EFFECT(node)->_shaderUserDefinedFields; break;
1243 case NODE_ShaderProgram:
1244 shaderfield = (void**)&X3D_SHADERPROGRAM(node)->_shaderUserDefinedFields; break;
1245 case NODE_PackagedShader:
1246 shaderfield = (void**)&X3D_PACKAGEDSHADER(node)->_shaderUserDefinedFields; break;
1247 default:
1248 shaderfield = NULL;
1249 }
1250 return shaderfield;
1251}
1252
1253void broto_store_DEF(struct X3D_Proto* proto,struct X3D_Node* node, const char *name);
1254static void parseAttributes_B(void *ud, char **atts);
1255void add_node_to_broto_context(struct X3D_Proto *context,struct X3D_Node *node);
1256void push_binding_stack_set(struct X3D_Node* layersetnode);
1257void push_next_layerId_from_binding_stack_set(struct X3D_Node* layer);
1258void pop_binding_stack_set();
1259
1260static void startBuiltin_B(void *ud, int myNodeType, const xmlChar *name, char** atts) {
1261 struct X3D_Node *node, *fromDEFtable;
1262 struct X3D_Proto *context;
1263 void **shaderfield;
1264 char pflagdepth;
1265 int kids, i, isUSE;
1266 const char *defname, *suggestedChildField, *containerfield;
1267
1268 suggestedChildField = containerfield = NULL;
1269 context = getContext(ud,TOP);
1270 pflagdepth = ciflag_get(context->__protoFlags,0); //0 - we're in a protodeclare, 1 - we are instancing live scenery
1271 if(0) printf("start builtin %s\n",name);
1272
1273 node = NULL;
1274 defname = NULL;
1275 isUSE = FALSE;
1276 /* go through the attributes; do some here, do others later (in case of PROTO IS fields found) */
1277 for (i = 0; atts[i]; i += 2) {
1278 /* is this a DEF name? if so, record the name and then ignore the field */
1279 if (strcmp ("DEF",atts[i]) == 0) {
1280 defname = atts[i+1];
1281 fromDEFtable = broto_search_DEFname(context,defname);
1282 if (fromDEFtable) {
1283 #ifdef X3DPARSERVERBOSE
1284 printf ("Warning - line %d duplicate DEF name: \'%s\'\n",LINE,atts[i+1]);
1285 #endif
1286 }
1287 } else if (strcmp ("USE",atts[i]) == 0) {
1288 #ifdef X3DPARSERVERBOSE
1289 printf ("this is a USE, name %s\n",atts[i+1]);
1290 #endif
1291
1292 //fromDEFtable = DEFNameIndex ((char *)atts[i+1],node, FALSE);
1293 fromDEFtable = broto_search_DEFname(context,atts[i+1]);
1294 if (!fromDEFtable) {
1295 ConsoleMessage ("Warning - line %d DEF name: \'%s\' not found",LINE,atts[i+1]);
1296 ConsoleMessage("\n");
1297 } else {
1298 #ifdef X3DPARSERVERBOSE
1299 printf ("copying for field %s defName %s\n",atts[i], atts[i+1]);
1300 #endif
1301
1302 /* if (fromDEFtable->_nodeType != fromDEFtable->_nodeType) { */
1303 if (myNodeType != fromDEFtable->_nodeType) {
1304 ConsoleMessage ("Warning, line %d DEF/USE mismatch, '%s', %s != %s", LINE,
1305 atts[i+1],stringNodeType(fromDEFtable->_nodeType), stringNodeType (myNodeType));
1306 } else {
1307 /* Q. should thisNode.referenceCount be decremented or ??? */
1308 node = fromDEFtable;
1309 node->referenceCount++; //dug9 added but should???
1310 //getNode(ud,TOP) = thisNode;
1311 #ifdef X3DPARSERVERBOSE
1312 printf ("successful copying for field %s defName %s\n",atts[i], atts[i+1]);
1313 #endif
1314 isUSE = TRUE;
1315 }
1316 }
1317 } else if(!strcmp(atts[i],"containerField")) containerfield = atts[i+1];
1318 }
1319
1320 if(!isUSE){
1321 if(pflagdepth)
1322 node = createNewX3DNode(myNodeType);
1323 else
1324 node = createNewX3DNode0(myNodeType);
1325 if(defname)
1326 broto_store_DEF(context,node,defname);
1327 }
1328 pushNode(ud,node);
1329
1330 if(containerfield) {
1331 //int builtinField = findFieldInARR(containerfield,FIELDNAMES,FIELDNAMES_COUNT);
1332 int builtinField = findFieldInFIELDNAMES(containerfield);
1333 if(builtinField > INT_ID_UNDEFINED){
1334 //if USE, the DEF could specify containerField that's wrong for the USE
1335 //so we'll keep the original as well, for linkNodeIn
1336 //in theory we should call an update function here, and about 4 other places
1337 // in x3dparser.c
1338 //APR 22, 2020 CHANGE: nodetype default containerfields are in new
1339 //static array NODE_CONTAINER_DEFAULT[][7] and node->_defaultContainer should
1340 // now have just x3d parsing scene file containerField='<some field name in parent>'
1341 //node->_defaultContainer = (node->_defaultContainer << 10) + builtinField;
1342 node->_defaultContainer = builtinField;
1343 //printf("new defaultContainer=%u\n",(unsigned int)node->_defaultContainer);
1344 }
1345 }
1346
1347 //linkNodeIn_B(ud);
1348
1349 if(!isUSE){
1350 shaderfield = shaderFields(node);
1351 if(shaderfield)
1352 (*shaderfield) = (void *)new_Shader_ScriptB(node);
1353 //if(node->_nodeType == NODE_Script && pflagdepth)
1354 //initialize script - wait till end element
1355 if(node->_nodeType == NODE_LayerSet)
1356 push_binding_stack_set(node);
1357 if(node->_nodeType == NODE_Layer || node->_nodeType == NODE_LayoutLayer)
1358 push_next_layerId_from_binding_stack_set(node);
1359 if(node->_nodeType == NODE_Inline)
1360 X3D_INLINE(node)->__parentProto = X3D_NODE(context); //when searching for user proto declarations, apparently inlines can search the scene
1361 node->_executionContext = X3D_NODE(context);
1362 add_node_to_broto_context(context,node);
1363
1364 kids = indexChildrenName(node);
1365 if(kids > -1)
1366 suggestedChildField = FIELDNAMES[kids];
1367 if(node->_nodeType == NODE_Script || node->_nodeType == NODE_ShaderPart
1368 || node->_nodeType == NODE_ShaderProgram || node->_nodeType == NODE_EffectPart)
1369 suggestedChildField = FIELDNAMES[FIELDNAMES_url]; //for CDATA
1370
1371 pushField(ud,suggestedChildField);
1372
1373 parseAttributes_B(ud,atts);
1374 }else{
1375 pushField(ud,NULL); //we pop in endBuiltin, so we have to push something
1376 }
1377
1378}
1379void initialize_one_script(struct Shader_Script* ss, const struct Multi_String *url);
1380void applyUnitsToNode(struct X3D_Node *node);
1381static void endBuiltin_B(void *ud, const xmlChar *name){
1382 struct X3D_Node *node;
1383 struct X3D_Proto *context;
1384 char pflagdepth;
1385 node = getNode(ud,TOP);
1386 context = getContext(ud,TOP);
1387 if(0)printf("end builtin %s\n",name);
1388 pflagdepth = ciflag_get(context->__protoFlags,0); //0 - we're in a protodeclare, 1 - we are instancing live scenery
1389 applyUnitsToNode(node);
1390 if(node->_nodeType == NODE_Script && pflagdepth){
1391 struct X3D_Script *sn = X3D_SCRIPT(node);
1392 //overkill -duplicates new_Shader_Script
1393 initialize_one_script(sn->__scriptObj,&sn->url);
1394 //script_initCodeFromMFUri(sn->__scriptObj, &sn->url);
1395 }
1396 if(node->_nodeType == NODE_LayerSet)
1397 pop_binding_stack_set();
1398
1399 linkNodeIn_B(ud);
1400
1401 popNode(ud);
1402 popField(ud);
1403
1404}
1405struct X3D_Proto* availableBroto(void* ud, const char* name) {
1406 struct X3D_Proto* proto = NULL;
1407 char nonconstname[1000];
1408 strcpy(nonconstname, name);
1409 struct X3D_Proto* context = getContext(ud, TOP);
1410 if (isAvailableBroto(nonconstname, context, &proto)) return proto;
1411 return NULL;
1412}
1413void startProto_B(void* ud, const char* name, struct X3D_Proto* nodetype, const xmlChar** atts) {
1414
1415 //printf("starting proto %s\n", name);
1416 struct X3D_Node* node;
1417 struct X3D_Proto* fromDEFtable;
1418 struct X3D_Proto* context;
1419 char pflagdepth;
1420 int kids, i, isUSE, visibleIndex, displayBBoxIndex;
1421 const char* defname, * suggestedChildField, * containerfield;
1422 suggestedChildField = containerfield = NULL;
1423 context = getContext(ud, TOP);
1424 pflagdepth = ciflag_get(context->__protoFlags, 0); //0 - we're in a protodeclare, 1 - we are instancing live scenery
1425 if (0) printf("start proto %s\n", name);
1426
1427 node = NULL;
1428 defname = NULL;
1429 isUSE = FALSE;
1430 visibleIndex = -1;
1431 displayBBoxIndex = -1;
1432 /* go through the attributes; do some here, do others later (in case of PROTO IS fields found) */
1433 for (i = 0; atts[i]; i += 2) {
1434 /* is this a DEF name? if so, record the name and then ignore the field */
1435 if (strcmp("DEF", atts[i]) == 0) {
1436 defname = atts[i + 1];
1437 fromDEFtable = (struct X3D_Proto*)broto_search_DEFname(context, defname);
1438 }
1439 else if (strcmp("USE", atts[i]) == 0) {
1440 //fromDEFtable = DEFNameIndex ((char *)atts[i+1],node, FALSE);
1441 fromDEFtable = (struct X3D_Proto*)broto_search_DEFname(context, atts[i + 1]);
1442 if (!fromDEFtable) {
1443 ConsoleMessage("Warning - line %d DEF name: \'%s\' not found", LINE, atts[i + 1]);
1444 ConsoleMessage("\n");
1445 }
1446 else {
1447 if (fromDEFtable->_nodeType != NODE_Proto || strcmp(X3D_PROTO(fromDEFtable->__prototype)->__typename, X3D_PROTO(nodetype->__prototype)->__typename)) {
1448
1449 ConsoleMessage("Warning, line %d DEF/USE mismatch, '%s', %s != %s", LINE,
1450 atts[i + 1], fromDEFtable->__typename, nodetype->__typename); // stringNodeType(myNodeType->name));
1451 }
1452 else {
1453 /* Q. should thisNode.referenceCount be decremented or ??? */
1454 node = X3D_NODE(fromDEFtable);
1455 node->referenceCount++; //dug9 added but should???
1456 isUSE = TRUE;
1457 }
1458 }
1459 }
1460 else if (!strcmp(atts[i], "containerField"))
1461 containerfield = atts[i + 1];
1462 else if (strcmp("visible", atts[i]) == 0) {
1463 visibleIndex = i + 1;
1464 }
1465 else if (strcmp("displayBBox", atts[i]) == 0) {
1466 displayBBoxIndex = i + 1;
1467 }
1468 }
1469
1470 if (!isUSE) {
1471 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
1472 idepth = pflagdepth == 1; //2014 broto2: if we're parsing a scene (or Inline) then deepcopy proto to instance it, else shallow
1473 node = X3D_NODE(brotoInstance(nodetype, idepth));
1474 node->_executionContext = X3D_NODE(context);
1475
1476 if (defname) {
1477 broto_store_DEF(context, node, defname);
1478 }
1479 add_node_to_broto_context(context, node);
1480
1481 if (containerfield) {
1482 int builtinField = findFieldInFIELDNAMES(containerfield);
1483 if (builtinField > INT_ID_UNDEFINED) {
1484 node->_defaultContainer = builtinField;
1485 }
1486 }
1487 kids = indexChildrenName(node);
1488 if (kids > -1)
1489 suggestedChildField = FIELDNAMES[kids];
1490 pushField(ud, suggestedChildField);
1491 //if (0) {
1492 // //builtin method
1493 // parseAttributes_B(ud, atts);
1494 //}
1495 //else
1496 {
1497 const char *fname, *svalue;
1498 const char* ignore[] = { "containerField","USE", "DEF", "visible", "displayBBox", NULL };
1499 //parse_fieldValue_b method, except SFNode, MFNode still need separate old-fashioned fieldValue elements
1500 for (i = 0; atts[i]; i += 2) {
1501 fname = atts[i];
1502 svalue = atts[i + 1];
1503 if (findFieldInARR(fname, ignore, 5) == INT_ID_UNDEFINED) {
1504 int ok, builtIn, type, kind, iifield;
1505 char* cname;
1506 union anyVrml *value;
1507 ok = 0;
1508 cname = NULL;
1509 value = NULL;
1510 builtIn = FALSE;
1511 if (fname) {
1512 ok = getFieldFromNodeAndNameC(node, fname, &type, &kind, &iifield, &builtIn, &value, (const char **)&cname);
1513 }
1514 if (cname && value && svalue) {
1515 deleteMallocedFieldValue(type, value);
1516 Parser_scanStringValueToMem_B(value, type, svalue, TRUE);
1517 }
1518 if (cname && (node->_nodeType == NODE_Proto) && !builtIn) {
1519 struct X3D_Proto* pnode;
1520 struct ProtoFieldDecl* pfield;
1521 struct ProtoDefinition* pstruct;
1522 pnode = X3D_PROTO(node);
1523 pstruct = (struct ProtoDefinition*)pnode->__protoDef;
1524 pfield = vector_get(struct ProtoFieldDecl*, pstruct->iface, iifield);
1525 pfield->alreadySet = TRUE;
1526 }
1527 }
1528 }
1529 }
1530
1531 if (visibleIndex != INT_ID_UNDEFINED) {
1532 if (!strcmp(atts[visibleIndex], "false"))
1533 X3D_PROTO(node)->visible = FALSE;
1534 }
1535 if (displayBBoxIndex != INT_ID_UNDEFINED) {
1536 if (!strcmp(atts[displayBBoxIndex], "true"))
1537 X3D_PROTO(node)->bboxDisplay = TRUE;
1538 }
1539 struct X3D_Proto* ptype, * pdest;
1540 ptype = X3D_PROTO(X3D_PROTO(node)->__prototype);
1541 pdest = X3D_PROTO(node);
1542 deep_copy_broto_body2(&ptype, &pdest);
1543
1544 }
1545 else {
1546 pushField(ud, NULL); //we pop in endBuiltin, so we have to push something
1547 }
1548 pushNode(ud, node);
1549
1550}
1551void endProto_B(void* ud, const char* name, struct X3D_Proto* proto) {
1552 //printf("ending proto %s\n", name);
1553 struct X3D_Node* node;
1554 struct X3D_Proto* context;
1555 char pflagdepth;
1556 node = getNode(ud, TOP);
1557 context = getContext(ud, TOP);
1558 if (0)printf("endProto_B %s\n", name);
1559 pflagdepth = ciflag_get(context->__protoFlags, 0); //0 - we're in a protodeclare, 1 - we are instancing live scenery
1560 applyUnitsToNode(node);
1561
1562 linkNodeIn_B(ud); //recurses - did something wrong above.
1563
1564 popNode(ud);
1565 popField(ud);
1566
1567}
1568static xmlChar* fixAmp(const unsigned char *InFieldValue)
1569{
1570 char *fieldValue = (char *)InFieldValue;
1571
1572 //for x3d string '"&amp;"' libxml2 gives us &#38;
1573 //we want & like other browsers get
1574 //we do it by left-shifting over the #38;
1575 //fieldValue - the MFString before splitting into SFs ie ["you & me" "John & Ian"\0]
1576 //except that libxml2 will wrongly give you ["you &#38; me" "John &#38; Ian"\0]
1577 if(fieldValue)
1578 {
1579 char *pp = strstr((char *)fieldValue,"&#38;");
1580 while(pp){
1581 memmove(pp+1,pp+5,strlen(fieldValue) - (pp+1 - fieldValue));
1582 pp = strstr(pp,"&#38;");
1583 /* or the following works if you don't have memmove:
1584 int len, nmove, ii;
1585 len = strlen(fieldValue);
1586 pp++;
1587 nmove = (len+1) - (pp - fieldValue);
1588 for(ii=0;ii<nmove;ii++){
1589 *pp = *(pp+4);
1590 pp++;
1591 }
1592 */
1593 }
1594 }
1595 return (xmlChar *)fieldValue;
1596}
1597int isUnits();
1598void sfunitf(int nodeType,char *fieldname, float *var, int n, int iuncafield);
1599void mfunitrotation(int nodeType,char *fieldname, struct SFRotation *var, int n, int iuncafield);
1600void sfunitd(int nodeType,char *fieldname, double *var, int n, int iuncafield);
1601void mfunit3f(int nodetype,char *fieldname, struct SFVec3f *var, int n, int iuncafield);
1602static void parseAttributes_B(void *ud, char **atts) {
1603 int i, type, kind, iifield, builtIn, iunca, isunits;
1604 struct X3D_Node *node;
1605 const char *cname;
1606 char *name, *svalue;
1607 const char *ignore [] = {"containerField","USE", "DEF"};
1608 union anyVrml *value;
1609
1610 node = getNode(ud,TOP);
1611 isunits = isUnits();
1612 for (i=0; atts[i]; i+=2) {
1613 name = atts[i];
1614 svalue = atts[i+1];
1615 /* see if we have a containerField here */
1616 if(findFieldInARR(name,ignore,3) == INT_ID_UNDEFINED){
1617 cname = NULL;
1618 if(getFieldFromNodeAndNameU(node,name,&type,&kind,&iifield,&builtIn,&value,&iunca,&cname)){
1619 deleteMallocedFieldValue(type,value);
1620 Parser_scanStringValueToMem_B(value, type,svalue, TRUE);
1621 //apply unit conversionFactor to parsed literal field
1622 // (vs above in endBuiltin_B applyUnitsToNode)
1623 if(isunits)
1624 switch(type){
1625 case FIELDTYPE_SFRotation:
1626 sfunitf(node->_nodeType,name,&value->sfrotation.c[3],1,iunca);
1627 break;
1628 case FIELDTYPE_SFFloat:
1629 sfunitf(node->_nodeType,name,&value->sffloat,1,iunca);
1630 break;
1631 case FIELDTYPE_MFFloat:
1632 sfunitf(node->_nodeType,name,value->mffloat.p,value->mffloat.n,iunca);
1633 break;
1634 case FIELDTYPE_SFVec3f:
1635 sfunitf(node->_nodeType,name,value->sfvec3f.c,3,iunca);
1636 break;
1637 case FIELDTYPE_SFVec4f:
1638 if(iunca == UNCA_PLANE)
1639 sfunitf(node->_nodeType,name,&value->sfvec4f.c[3],1,UNCA_LENGTH); //don't scale first 3 wich are a normal
1640 else
1641 sfunitf(node->_nodeType,name,value->sfvec4f.c,4,iunca);
1642 break;
1643 case FIELDTYPE_SFVec2f:
1644 sfunitf(node->_nodeType,name,value->sfvec2f.c,2,iunca);
1645 break;
1646 case FIELDTYPE_MFVec3f:
1647 mfunit3f(node->_nodeType,name,value->mfvec3f.p,value->mfvec3f.n,iunca);
1648 break;
1649 case FIELDTYPE_SFMatrix3f:
1650 sfunitf(node->_nodeType,name,value->sfmatrix3f.c, 9,iunca);
1651 break;
1652 case FIELDTYPE_MFRotation:
1653 mfunitrotation(node->_nodeType,name,value->mfrotation.p,value->mfrotation.n,iunca);
1654 break;
1655 case FIELDTYPE_SFDouble:
1656 sfunitd(node->_nodeType,name,&value->sfdouble,1,iunca);
1657 break;
1658 default:
1659 break;
1660 }
1661 }
1662 }
1663 if(!strcmp(name,"side")){
1664 //stereoscopic experiments
1665 if(!strcmp(svalue,"left"))
1666 node->_renderFlags |= VF_HideRight;
1667 else if(!strcmp(svalue,"right"))
1668 node->_renderFlags |= VF_HideLeft;
1669 //printf("node renderflags=%d\n",node->_renderFlags);
1670 }
1671 }
1672}
1673
1674
1675int findFieldInARR(const char* field, const char** arr, size_t cnt);
1676static void parseScriptProtoField_B(void *ud, char **atts) {
1677 /* new user field definitions -name,type,mode- possibly with fieldvalue anyVrml
1678 - we will be parsing either:
1679 a ProtoDeclare or ExternProtoDeclare (extern will lack fieldValue)
1680 a Script Node or Shader node
1681 - Script field may have fieldValue as child element, or IS/connect as peer
1682 - ProtoDeclare may have fieldValue as child element
1683 */
1684 //struct X3D_Node *node;
1685 int mp_name, mp_accesstype, mp_type, mp_value, i;
1686 int pkwmode, type;
1687 union anyVrml defaultValue; //, *value;
1688 char *fname, *cname;
1689 //value = NULL;
1690 cname = NULL;
1691 mp_name = mp_accesstype = mp_type = mp_value = ID_UNDEFINED;
1692 if(0) printf("start scriptProtoField\n");
1693 /* have a "key" "value" pairing here. They can be in any order; put them into our order */
1694 for (i = 0; atts[i]; i += 2) {
1695 /* skip any "appinfo" or "documentation" fields here */
1696 if ((strcmp("appinfo", atts[i]) != 0) &&
1697 (strcmp("documentation",atts[i]) != 0)) {
1698 if (strcmp(atts[i],"name") == 0) { mp_name = i+1;
1699 } else if (strcmp(atts[i],"accessType") == 0) { mp_accesstype = i+1;
1700 } else if (strcmp(atts[i],"type") == 0) { mp_type = i+1;
1701 } else if (strcmp(atts[i],"value") == 0) { mp_value = i+1;
1702 } else {
1703 ConsoleMessage ("X3D Proto/Script parsing line %d: unknown field type %s",LINE,atts[i]);
1704 return;
1705 }
1706 }
1707 }
1708 if(mp_accesstype > -1 && mp_type > -1 && mp_name > -1){
1709 int valueSet;
1710 pkwmode = findFieldInARR(atts[mp_accesstype], PROTOKEYWORDS, PROTOKEYWORDS_COUNT);
1711 pkwmode = pkwmode > -1? X3DMODE(pkwmode) : pkwmode;
1712 type = findFieldInARR(atts[mp_type],FIELDTYPES,FIELDTYPES_COUNT);
1713 fname = atts[mp_name];
1714 cname = NULL;
1715 //memset(&defaultValue,0,sizeof(union anyVrml));
1716 bzero(&defaultValue, sizeof (union anyVrml));
1717 if(type == FIELDTYPE_SFString)
1718 defaultValue.sfstring = newASCIIString("");
1719 valueSet = FALSE;
1720 if(mp_value > -1){
1721 Parser_scanStringValueToMem_B(&defaultValue, type, atts[mp_value], TRUE);
1722 valueSet = TRUE;
1723 }
1724 if(pkwmode > -1 && type > -1){
1725 struct X3D_Node * node = getNode(ud,TOP);
1726 if(node->_nodeType == NODE_Proto){
1727 struct X3D_Proto *pnode;
1728 struct ProtoFieldDecl* pfield;
1729 struct ProtoDefinition* pstruct;
1730 pnode = X3D_PROTO(node);
1731 pstruct = (struct ProtoDefinition*) pnode->__protoDef;
1732 pfield = newProtoFieldDecl(pkwmode,type,0);
1733 pfield->cname = STRDUP(fname);
1734 cname = pfield->cname;
1735 memcpy(&pfield->defaultVal,&defaultValue,sizeof(union anyVrml));
1736 vector_pushBack(struct ProtoFieldDecl*, pstruct->iface, pfield);
1737 //value = &pfield->defaultVal;
1738 }else{
1739 struct Shader_Script* shader = NULL;
1740 struct ScriptFieldDecl* sfield;
1741 int jsname;
1742 switch(node->_nodeType)
1743 {
1744 case NODE_Script: shader =(struct Shader_Script *)(X3D_SCRIPT(node)->__scriptObj); break;
1745 case NODE_ComposedShader: shader =(struct Shader_Script *)(X3D_COMPOSEDSHADER(node)->_shaderUserDefinedFields); break;
1746 case NODE_Effect: shader =(struct Shader_Script *)(X3D_EFFECT(node)->_shaderUserDefinedFields); break;
1747 case NODE_ShaderProgram: shader =(struct Shader_Script *)(X3D_SHADERPROGRAM(node)->_shaderUserDefinedFields); break;
1748 case NODE_PackagedShader: shader =(struct Shader_Script *)(X3D_PACKAGEDSHADER(node)->_shaderUserDefinedFields); break;
1749 }
1750 jsname = JSparamIndex (fname, atts[mp_type],pkwmode);
1751 cname = getJSparamnames()[jsname].name;
1752 //sfield = newScriptFieldDecl() // too hard to fathom, I'll break it out:
1753 sfield = MALLOC(struct ScriptFieldDecl *, sizeof(struct ScriptFieldDecl));
1754 bzero(sfield,sizeof(struct ScriptFieldDecl));
1755 sfield->fieldDecl = newFieldDecl(pkwmode,type,0,jsname,0); //not using a lexer
1756 memcpy(&sfield->value,&defaultValue,sizeof(union anyVrml));
1757 sfield->valueSet = valueSet; //=(mod!=PKW_initializeOnly);
1758 sfield->eventInSet = FALSE; //flag used for directOutput
1759 vector_pushBack(struct ScriptFieldDecl*, shader->fields, sfield);
1760 //value = &sfield->value;
1761 }
1762 }
1763 }
1764 pushField(ud,cname); //strdup(fname)); //strong recommendation
1765 pushMode(ud,PARSING_FIELD);
1766}
1767
1768/* simple sanity check, and change mode */
1769static void parseProtoInterface (void *ud, char **atts) {
1770 if (getMode(ud,TOP) != PARSING_PROTODECLARE && getMode(ud,TOP) != PARSING_EXTERNPROTODECLARE) {
1771 ConsoleMessage ("got a <ProtoInterface>, but not within a <ProtoDeclare>\n");
1772 }
1773 //setParserMode(PARSING_PROTOINTERFACE);
1774 pushMode(ud,PARSING_PROTOINTERFACE);
1775}
1776void Parser_scanStringValueToMem_B(union anyVrml* any, indexT ctype, const char *value, int isXML);
1777double getunitlengthfactor();
1778static void parseExternProtoDeclare_B (void *ud, char **atts) {
1779 /* 1.create a new proto but not registered node
1780 2.get user type name from atts
1781 3.set flag for shallow/declare
1782 4.add to current context's externProtoDeclare array
1783 5.push on node stack awaiting interface (with no initial values)
1784 */
1785 int i;
1786 char *type_name, *appinfo, *documentation, *containerfield, *url;
1787 struct ProtoDefinition* obj;
1788 struct X3D_Proto* proto;
1789 struct X3D_Proto* parent;
1790 type_name = appinfo = documentation = containerfield = url = NULL;
1791 if(0) printf("in parseExternProtoDeclare_B\n");
1792
1793 proto = createNewX3DNode0(NODE_Proto);
1794 for (i = 0; atts[i]; i += 2) {
1795 #ifdef X3DPARSERVERBOSE
1796 TTY_SPACE
1797 printf ("parseProtoDeclare: field:%s=%s\n", atts[i], atts[i+1]);
1798 #endif
1799
1800 if (!strcmp("name",atts[i]) ) type_name = atts[i+1];
1801 else if(!strcmp("containerField",atts[i])) containerfield = atts[i+1];
1802 else if(!strcmp("appInfo",atts[i])) appinfo = atts[i+1];
1803 else if(!strcmp("documentation",atts[i])) documentation = atts[i+1];
1804 else if(!strcmp("url",atts[i])) url = atts[i+1];
1805 }
1806
1807 parent = (struct X3D_Proto*)getContext(ud,TOP);
1808 obj=newProtoDefinition();
1809
1810 /* did we find the name? */
1811 if (type_name) {
1812 obj->protoName = STRDUP(type_name);
1813 } else {
1814 printf ("warning - have proto but no name, so just copying a default string in\n");
1815 obj->protoName = STRDUP("noProtoNameDefined");
1816 }
1817 type_name = obj->protoName;
1818
1819 if(parent->__externProtoDeclares == NULL)
1820 parent->__externProtoDeclares = newVector(struct X3D_Proto*,4);
1821 vector_pushBack(struct X3D_Proto*,parent->__externProtoDeclares,proto);
1822 proto->__parentProto = X3D_NODE(parent); //me->ptr; //link back to parent proto, for isAvailableProto search
1823 proto->__protoFlags = parent->__protoFlags;
1824 proto->__protoFlags = ciflag_set(proto->__protoFlags,0,0); //((char*)(&proto->__protoFlags))[0] = 0; //shallow instancing of protoInstances inside a protoDeclare
1826 proto->__protoFlags = ciflag_set(proto->__protoFlags,0,2); //((char*)(&proto->__protoFlags))[2] = 0; //this is a protoDeclare we are parsing
1827 proto->__protoFlags = ciflag_set(proto->__protoFlags,1,3); //((char*)(&proto->__protoFlags))[3] = 1; //an externProtoDeclare
1828 //set ProtoDefinition *obj
1829 proto->__protoDef = obj;
1830 proto->__prototype = X3D_NODE(proto); //point to self, so shallow and deep instances will inherit this value
1831 proto->__typename = STRDUP(obj->protoName);
1832 proto->__unitlengthfactor = getunitlengthfactor();
1833 proto->__specversion = inputFileVersion[0]*100 + inputFileVersion[1]*10 + inputFileVersion[2];
1834 if(containerfield){
1835 int builtinField = findFieldInFIELDNAMES(containerfield);
1836 if(builtinField > -1){
1837 proto->_defaultContainer = builtinField;
1838 }
1839 }
1840 if(url){
1841 Parser_scanStringValueToMem_B((union anyVrml*)&proto->url, FIELDTYPE_MFString,url, TRUE);
1842 }
1843 proto->__loadstatus = 0; //= LOAD_INITIAL_STATE
1844 pushMode(ud,PARSING_EXTERNPROTODECLARE);
1845 pushNode(ud,X3D_NODE(proto));
1846 pushField(ud,"__children");
1847
1848}
1849#define LOAD_STABLE 10
1850static void parseProtoInclude(void* ud, char** atts) {
1851 /* load a wrl/x3d proto scene (non-live)
1852 * synchronously (wait for loading to finish before returning)
1853 * and put the extern proto declares into the current scene for instancing.
1854 */
1855 int i;
1856 char* names, * url;
1857 struct X3D_Proto* proto;
1858 struct X3D_Proto* parent;
1859 names = url = NULL;
1860 if (0) printf("in parseProtoInclude\n");
1861
1862 proto = createNewX3DNode0(NODE_Proto);
1863 for (i = 0; atts[i]; i += 2) {
1864 if (!strcmp("names", atts[i])) names = atts[i + 1];
1865 else if (!strcmp("url", atts[i])) url = atts[i + 1];
1866 }
1867 parent = (struct X3D_Proto*)getContext(ud, TOP);
1868 if (url) {
1869 Parser_scanStringValueToMem_B((union anyVrml*)&proto->url, FIELDTYPE_MFString, url, TRUE);
1870 }
1871 proto->__protoFlags = parent->__protoFlags;
1872 proto->__protoFlags = ciflag_set(proto->__protoFlags, 0, 0); //((char*)(&proto->__protoFlags))[0] = 0; //shallow instancing of protoInstances inside a protoDeclare
1874 proto->__protoFlags = ciflag_set(proto->__protoFlags, 0, 2); //((char*)(&proto->__protoFlags))[2] = 0; //this is a protoDeclare we are parsing
1875 proto->__protoFlags = ciflag_set(proto->__protoFlags, 1, 3); //((char*)(&proto->__protoFlags))[3] = 1; //an externProtoDeclare
1876
1877 proto->__loadstatus = 0; //= LOAD_INITIAL_STATE
1878 // PROBLEM: The parsers are single threaded with thread state stacks
1879 // we queue up scenes to be parsed. we don't push and pop scenes. Yet.
1880 do {
1881 load_externProtoDeclare(proto);
1882 sleep(200);
1883 } while (proto->__loadstatus != LOAD_STABLE);
1884 printf("library %s loaded\n", proto->url.p[0]->strptr);
1885 //pushMode(ud, PARSING_EXTERNPROTODECLARE);
1886 //pushNode(ud, X3D_NODE(proto));
1887 //pushField(ud, "__children");
1888
1889
1890}
1891static void parseProtoDeclare_B (void *ud, char **atts) {
1892 /* 1.create a new proto but not registered node
1893 2.get user type name from atts
1894 3.set flag for shallow/declare
1895 4.add to current context's protoDeclare array
1896 5.push on node stack awaiting interface and body
1897 */
1898 int i;
1899 struct X3D_Proto* proto;
1900 char *type_name, *appinfo, *documentation, *containerfield;
1901 struct ProtoDefinition* obj;
1902 struct X3D_Proto* parent;
1903
1904 type_name = appinfo = documentation = containerfield = NULL;
1905 if(0) printf("in start protoDeclare\n");
1906
1907 proto = createNewX3DNode0(NODE_Proto);
1908 for (i = 0; atts[i]; i += 2) {
1909 #ifdef X3DPARSERVERBOSE
1910 TTY_SPACE
1911 printf ("parseProtoDeclare: field:%s=%s\n", atts[i], atts[i+1]);
1912 #endif
1913
1914 if (!strcmp("name",atts[i]) ) type_name = atts[i+1];
1915 else if(!strcmp("containerField",atts[i])) containerfield = atts[i+1];
1916 else if(!strcmp("appInfo",atts[i])) appinfo = atts[i+1];
1917 else if(!strcmp("documentation",atts[i])) documentation = atts[i+1];
1918 }
1919
1920 parent = (struct X3D_Proto*)getContext(ud,TOP);
1921 obj=newProtoDefinition();
1922
1923 /* did we find the name? */
1924 if (type_name) {
1925 obj->protoName = STRDUP(type_name);
1926 } else {
1927 printf ("warning - have proto but no name, so just copying a default string in\n");
1928 obj->protoName = STRDUP("noProtoNameDefined");
1929 }
1930 type_name = obj->protoName;
1931
1932 if(parent->__protoDeclares == NULL)
1933 parent->__protoDeclares = newVector(struct X3D_Proto*,4);
1934 vector_pushBack(struct X3D_Proto*,parent->__protoDeclares,proto);
1935 proto->__parentProto = X3D_NODE(parent); //me->ptr; //link back to parent proto, for isAvailableProto search
1936 proto->__protoFlags = parent->__protoFlags;
1937 proto->__protoFlags = ciflag_set(proto->__protoFlags,0,0); //((char*)(&proto->__protoFlags))[0] = 0; //shallow instancing of protoInstances inside a protoDeclare
1939 proto->__protoFlags = ciflag_set(proto->__protoFlags,0,2); //((char*)(&proto->__protoFlags))[2] = 0; //this is a protoDeclare we are parsing
1940 proto->__protoFlags = ciflag_set(proto->__protoFlags,0,3); //((char*)(&proto->__protoFlags))[3] = 0; //not an externProtoDeclare
1941 //set ProtoDefinition *obj
1942 proto->__protoDef = obj;
1943 proto->__prototype = X3D_NODE(proto); //point to self, so shallow and deep instances will inherit this value
1944 proto->__typename = STRDUP(obj->protoName);
1945 proto->__unitlengthfactor = getunitlengthfactor();
1946 proto->__specversion = inputFileVersion[0]*100 + inputFileVersion[1]*10 + inputFileVersion[2];
1947 if(containerfield){
1948 int builtinField = findFieldInFIELDNAMES(containerfield);
1949 if(builtinField > -1){
1950 proto->_defaultContainer = builtinField;
1951 }
1952 }
1953
1954 pushMode(ud,PARSING_PROTODECLARE);
1955 pushNode(ud,X3D_NODE(proto));
1956 pushField(ud,"__children");
1957}
1958
1959static void parseProtoBody_B (void *ud, char **atts) {
1960 //push proto node on context stack
1961 pushContext(ud,getNode(ud,TOP));
1962 pushMode(ud,PARSING_PROTOBODY);
1963}
1964
1965struct X3D_Proto *brotoInstance(struct X3D_Proto* proto, BOOL ideep);
1966void add_node_to_broto_context(struct X3D_Proto *context,struct X3D_Node *node);
1967void linkNodeIn_B(void *ud);
1968struct X3D_Node *broto_search_DEFname(struct X3D_Proto *context, const char *name);
1969
1970static void parseProtoInstance_B(void *ud, char **atts) {
1971 /*broto version
1972 1. lookup the user (proto) type in current and parent context protoDeclare and externProtoDeclare tables
1973 2. brotoInstance()
1974 3. parse att and any <fieldValue> and IS
1975 4. on end, deep_copy_broto_body2 applying the initial field values parsed.
1976 */
1977 int i, isUSE;
1978 int nameIndex;
1979 //int containerIndex;
1980 //int containerField;
1981 int defNameIndex, visibleIndex, displayBBoxIndex;
1982 //int protoTableIndex;
1983 struct X3D_Proto *currentContext;
1984 struct X3D_Node *node = NULL;
1985 char pflagdepth;
1986 struct X3D_Node *fromDEFtable;
1987
1988
1989 /* initialization */
1990 nameIndex = INT_ID_UNDEFINED;
1991 visibleIndex = displayBBoxIndex = nameIndex;
1992 //containerIndex = INT_ID_UNDEFINED;
1993 //containerField = INT_ID_UNDEFINED;
1994 defNameIndex = INT_ID_UNDEFINED;
1995 //protoTableIndex = 0;
1996 if(0) printf("parseProtoInstance\n");
1997 isUSE = FALSE;
1998 for (i = 0; atts[i]; i += 2) {
1999 if (strcmp("name",atts[i]) == 0) {
2000 nameIndex=i+1;
2001 } else if (strcmp("containerField",atts[i]) == 0) {
2002 //containerIndex = i+1;
2003 } else if (strcmp("DEF",atts[i]) == 0) {
2004 defNameIndex = i+1;
2005 } else if (strcmp("class",atts[i]) == 0) {
2006 ConsoleMessage ("field \"class\" not currently used in a ProtoInstance parse... sorry");
2007 } else if (strcmp("USE",atts[i]) == 0) {
2008 //ConsoleMessage ("field \"USE\" not currently used in a ProtoInstance parse.. sorry");
2009 isUSE = TRUE;
2010 defNameIndex = i+1;
2011 } else if (strcmp("visible",atts[i]) == 0) {
2012 visibleIndex = i+1;
2013 } else if (strcmp("displayBBox",atts[i]) == 0) {
2014 displayBBoxIndex = i+1;
2015 }
2016 }
2017
2018 currentContext = getContext(ud,TOP);
2019
2020 pflagdepth = ciflag_get(currentContext->__protoFlags,0); //depth 0 we are deep inside protodeclare, depth 1 we are instancing live scenery
2021
2022
2023
2024 if(isUSE){
2025 //ConsoleMessage ("field \"USE\" not currently used in a ProtoInstance parse.. sorry");
2026 char * defname = atts[defNameIndex]; //gets STRDUP();'d inside broto_store_DEF
2027
2028 fromDEFtable = broto_search_DEFname(currentContext,defname);
2029 if (!fromDEFtable) {
2030 ConsoleMessage ("Warning - line %d DEF name: \'%s\' not found",LINE,atts[i+1]);
2031 ConsoleMessage("\n");
2032 } else {
2033 #ifdef X3DPARSERVERBOSE
2034 printf ("copying for field %s defName %s\n",atts[i], atts[i+1]);
2035 #endif
2036
2037 /* if (fromDEFtable->_nodeType != fromDEFtable->_nodeType) { */
2038 if (NODE_Proto != fromDEFtable->_nodeType) {
2039 ConsoleMessage ("Warning, line %d DEF/USE mismatch, '%s', %s != %s", LINE,
2040 atts[i+1],stringNodeType(fromDEFtable->_nodeType), stringNodeType (NODE_Proto));
2041 } else {
2042 /* Q. should thisNode.referenceCount be decremented or ??? */
2043 char* containerfield;
2044 node = fromDEFtable;
2045 node->referenceCount++; //dug9 added but should???
2046 //getNode(ud,TOP) = thisNode;
2047 #ifdef X3DPARSERVERBOSE
2048 printf ("successful copying for field %s defName %s\n",atts[i], atts[i+1]);
2049 #endif
2050 pushNode(ud,node);
2051 containerfield = NULL;
2052 for (i = 0; atts[i]; i += 2) {
2053 if(!strcmp(atts[i],"containerField")) containerfield = atts[i+1];
2054 }
2055 if(containerfield) {
2056 int builtinField = findFieldInFIELDNAMES(containerfield);
2057 if(builtinField > INT_ID_UNDEFINED){
2058 node->_defaultContainer = builtinField;
2059 }
2060 }
2061 pushField(ud,NULL); //no particular default field
2062 pushMode(ud,PARSING_PROTOINSTANCE_USE);
2063 return;
2064 }
2065 }
2066 }else{
2067 /* did we find the name? */
2068 char *protoname;
2069 protoname = NULL;
2070 if (nameIndex != INT_ID_UNDEFINED) {
2071 protoname = atts[nameIndex];
2072 } else {
2073 ConsoleMessage ("\"ProtoInstance\" found, but field \"name\" not found!\n");
2074 }
2075 if(protoname){
2076
2077 struct X3D_Proto *proto;
2078 if( isAvailableBroto(protoname, currentContext , &proto))
2079 {
2080 //struct X3D_Node *parent;
2081 char* containerfield;
2082 /* its a binary proto, new in 2013 */
2083 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
2084 idepth = pflagdepth == 1; //2014 broto2: if we're parsing a scene (or Inline) then deepcopy proto to instance it, else shallow
2085 node=X3D_NODE(brotoInstance(proto,idepth));
2086 node->_executionContext = X3D_NODE(proto);
2087 if (defNameIndex != INT_ID_UNDEFINED){
2088 char * defname = atts[defNameIndex]; //gets STRDUP();'d inside broto_store_DEF
2089 broto_store_DEF(currentContext,node, defname);
2090 }
2091 add_node_to_broto_context(currentContext,node);
2092
2093 pushNode(ud,node);
2094 containerfield = NULL;
2095 for (i = 0; atts[i]; i += 2) {
2096 if(!strcmp(atts[i],"containerField")) containerfield = atts[i+1];
2097 }
2098 if(containerfield) {
2099 int builtinField = findFieldInFIELDNAMES(containerfield);
2100 if(builtinField > INT_ID_UNDEFINED){
2101 node->_defaultContainer = builtinField;
2102 }
2103 }
2104 if(visibleIndex != INT_ID_UNDEFINED){
2105 if(!strcmp(atts[visibleIndex],"false"))
2106 X3D_PROTO(node)->visible = FALSE;
2107 }
2108 if(displayBBoxIndex != INT_ID_UNDEFINED){
2109 if(!strcmp(atts[displayBBoxIndex],"true"))
2110 X3D_PROTO(node)->bboxDisplay = TRUE;
2111 }
2112
2113 //linkNodeIn_B(ud);
2114 //parseAttributes_B(ud,atts); //PI uses FieldValue
2115 }else{
2116 pushNode(ud,NULL);
2117 ConsoleMessage ("Attempt to instance undefined prototype typename %s\n",protoname);
2118 }
2119 }
2120 }
2121 pushField(ud,NULL); //no particular default field
2122 pushMode(ud,PARSING_PROTOINSTANCE);
2123
2124}
2125
2126BOOL nodeTypeSupportsUserFields(struct X3D_Node *node);
2127int getFieldFromNodeAndName(struct X3D_Node* node,const char *fieldname, int *type, int *kind, int *iifield, union anyVrml **value);
2128void broto_store_IS(struct X3D_Proto *proto,char *protofieldname,int pmode, int iprotofield, int pBuiltIn, int type,
2129 struct X3D_Node *node, char* nodefieldname, int mode, int ifield, int nBuiltIn, int source);
2130
2131static void parseConnect_B(void *ud, char **atts) {
2132 int i,okp, okn;
2133 struct X3D_Node *node;
2134 struct X3D_Proto *context, *proto;
2135 char *nodefield;
2136 char *protofield;
2137 node = getNode(ud,TOP);
2138 proto = context = getContext(ud,TOP);
2139
2140 nodefield = protofield = NULL;
2141 for(i=0;atts[i];i+=2){
2142 if(!strcmp(atts[i],"nodeField")) nodefield = atts[i+1];
2143 if(!strcmp(atts[i],"protoField")) protofield = atts[i+1];
2144 }
2145 okp = okn = 0;
2146 if(nodefield && protofield){
2147 int ptype, pkind, pifield, pBuiltIn, ntype, nkind, nifield, nBuiltIn;
2148 const char *pname, *nname;
2149 union anyVrml *pvalue, *nvalue;
2150 okp = getFieldFromNodeAndNameC(X3D_NODE(proto),protofield,&ptype, &pkind, &pifield, &pBuiltIn, &pvalue, &pname);
2151 okn = getFieldFromNodeAndNameC(node, nodefield,&ntype, &nkind, &nifield, &nBuiltIn, &nvalue, &nname);
2152 //check its mode
2153 // http://www.web3d.org/files/specifications/19775-1/V3.2/Part01/concepts.html#t-RulesmappingPROTOTYPEdecl
2154 // there's what I call a mode-jive table
2155 // proto interface
2156 // inputOutput initializeOnly inputOnly outputOnly
2157 // node inputOutput jives jives jives jives
2158 // initializeOnly jives
2159 // inputOnly jives
2160 // outputOnly jives
2161 //
2162 // so if our nodefield's mode is inputOutput/exposedField then we are covered for all protoField modes
2163 // otherwise, the nodefield's mode must be the same as the protofield's mode
2164 if(okp && okn)
2165 if(ntype != ptype){
2166 ConsoleMessage("Parser error: IS - we have a name match: %s IS %s found protofield %s\n",
2167 nodefield,protofield,protofield);
2168 ConsoleMessage("...But the types don't match: nodefield %s protofield %s\n",
2169 FIELDTYPES[ntype],FIELDTYPES[ptype]);
2170 okp = 0;
2171 }
2172 if(okp && okn)
2173 if(nkind != PKW_inputOutput && nkind != pkind){
2174 if(pkind != PKW_inputOutput){
2175 ConsoleMessage("Parser Error: IS - we have a name match: %s IS %s found protofield %s\n",
2176 nodefield,protofield,protofield);
2177 ConsoleMessage("...But the modes don't jive: nodefield %s protofield %s\n",
2178 PROTOKEYWORDS[nkind],PROTOKEYWORDS[pkind]);
2179 okp = 0;
2180 }else{
2181 ConsoleMessage("Parser Warning: IS - we have a name match: %s IS %s found protofield %s\n",
2182 nodefield,protofield,protofield);
2183 ConsoleMessage("...But the modes don't jive: nodefield %s protofield %s\n",
2184 PROTOKEYWORDS[nkind],PROTOKEYWORDS[pkind]);
2185 ConsoleMessage("...will thunk\n");
2186 }
2187 }
2188 if(okp && okn){
2189 int source;
2190 //we have an IS that's compatible/jives
2191 //a) copy the value if it's an initializeOnly or inputOutput
2192 if(pkind == PKW_initializeOnly || pkind == PKW_inputOutput)
2193 {
2194 shallow_copy_field(ntype, pvalue , nvalue);
2195 }
2196 //b) register it in the IS-table for our context
2197 source = node->_nodeType == NODE_Proto ? 3 : node->_nodeType == NODE_Script ? 1 : nodeTypeSupportsUserFields(node) ? 2 : 0;
2198 //Q. do I need to convert builtin from field index to offset? if( source == 0) nifield *=5;
2199 broto_store_IS(context,protofield,pkind,pifield,pBuiltIn,ptype,
2200 node,nodefield,nkind,nifield,nBuiltIn,source);
2201 }
2202 }
2203}
2204
2205
2206static void XMLCALL X3DstartElement(void *ud, const xmlChar *iname, const xmlChar **atts) {
2207 int myNodeIndex;
2208 char **myAtts;
2209 int i;
2210 char *blankAtts[] = {NULL,NULL};
2211 const char *name = (const char*) iname; // get around compiler warnings on iPhone, etc...
2212
2213 /* libxml passes NULL, while expat passes {0,0}. Make them the same */
2214 if (atts == NULL) myAtts = blankAtts;
2215 else myAtts = (char **) atts;
2216
2217 #ifdef X3DPARSERVERBOSE
2218 //printf ("startElement: %s : level %d parserMode: %s \n",name,parentIndex,parserModeStrings[getMode(ud,TOP)]);
2219 printf ("X3DstartElement: %s: atts %p\n",name,atts);
2220 printf ("startElement, myAtts :%p contents %p\n",myAtts,myAtts[0]);
2221 { int i;
2222 for (i = 0; myAtts[i]; i += 2) {
2223 printf(" X3DStartElement field:%s=%s\n", myAtts[i], atts[i + 1]);
2224 }}
2225
2226 //printf ("X3DstartElement - finished looking at myAtts\n\n");
2227 #endif
2228
2229 if(atts)
2230 for (i = 0; atts[i]; i += 2) {
2231 atts[i+1] = fixAmp(atts[i+1]);
2232 }
2233
2234
2235 myNodeIndex = findFieldInNODES(name);
2236
2237 /* is this a "normal" node that can be found in x3d, x3dv and wrl files? */
2238 if (myNodeIndex != INT_ID_UNDEFINED) {
2239 startBuiltin_B(ud,myNodeIndex,(const xmlChar *)name,myAtts);
2240 return;
2241 }
2242
2243 /* no, it is not. Lets see what else it could be... */
2244 myNodeIndex = findFieldInX3DSPECIAL(name);
2245 if (myNodeIndex != INT_ID_UNDEFINED) {
2246 switch (myNodeIndex) {
2247 case X3DSP_ProtoDeclare:
2248 parseProtoDeclare_B(ud,myAtts);
2249 break;
2250 case X3DSP_ExternProtoDeclare:
2251 parseExternProtoDeclare_B(ud,myAtts);
2252 break;
2253 case X3DSP_ProtoBody:
2254 parseProtoBody_B(ud,myAtts);
2255 break;
2256 case X3DSP_ProtoInterface:
2257 parseProtoInterface(ud,myAtts);
2258 break;
2259 case X3DSP_ProtoInstance:
2260 parseProtoInstance_B(ud,myAtts);
2261 break;
2262 case X3DSP_ProtoInclude:
2263 parseProtoInclude(ud, myAtts);
2264 break;
2265 case X3DSP_ROUTE:
2266 parseRoutes_B(ud,myAtts);
2267 break;
2268 case X3DSP_meta: parseMeta(ud, myAtts); break;
2269 case X3DSP_Scene: parseScene(myAtts); break;
2270 case X3DSP_head:
2271 case X3DSP_Header: parseHeader(myAtts); break;
2272 case X3DSP_X3D: parseX3Dhead(ud,myAtts); break;
2273 case X3DSP_fieldValue:
2274 parseFieldValue_B(ud,myAtts);
2275 break;
2276 case X3DSP_field:
2277 parseScriptProtoField_B (ud, myAtts);
2278 break;
2279 case X3DSP_IS: parseIS(ud); break;
2280 case X3DSP_component: parseComponent(myAtts); break;
2281 case X3DSP_EXPORT:
2282 parseExport_B(ud,myAtts);
2283 break;
2284 case X3DSP_IMPORT:
2285 parseImport_B(ud,myAtts);
2286 break;
2287 case X3DSP_connect:
2288 parseConnect_B(ud,myAtts);
2289 break;
2290 case X3DSP_unit:
2291 parseUnit(ud,myAtts); break;
2292 default: printf (" huh? startElement, X3DSPECIAL, but not handled?? %d, :%s:\n",myNodeIndex,X3DSPECIAL[myNodeIndex]);
2293 }
2294 return;
2295 }
2296 /*in theory, you could search broto prototype typenames here, and if found
2297 assume it's instanced with builtin syntax (instead of ProtoInstance syntax)
2298 if( isAvailableBroto(name, getContext(ud,TOP) , &proto))
2299 */
2300 struct X3D_Proto* isProto = availableBroto(ud, name);
2301 if(isProto){
2302 startProto_B(ud, name, isProto, (const xmlChar **)myAtts);
2303 return;
2304 }
2305
2306 printf ("startElement name do not currently handle this one :%s: index %d\n",name,myNodeIndex);
2307}
2308
2309static void endScriptProtoField_B(void *ud) {
2310 if(0) printf("end scriptprotofield\n");
2311 popField(ud);
2312 popMode(ud); //PARSING_FIELD);
2313}
2314
2315
2316static void XMLCALL X3DendElement(void *ud, const xmlChar *iname) {
2317 int myNodeIndex;
2318 const char *name = (const char*) iname;
2319 //ttglobal tg = gglobal();
2320 //ppX3DParser p = (ppX3DParser)tg->X3DParser.prv;
2321
2322 /* printf ("X3DEndElement for %s\n",name); */
2323
2324 #ifdef X3DPARSERVERBOSE
2325 printf ("endElement: %s : parentIndex %d mode %s\n",name,parentIndex,parserModeStrings[getMode(ud,TOP)]);
2326 #endif
2327
2328
2329
2330 myNodeIndex = findFieldInNODES(name);
2331 if (myNodeIndex != INT_ID_UNDEFINED) {
2332 endBuiltin_B(ud,iname);
2333 return;
2334
2335 }
2336
2337
2338
2339 /* no, it is not. Lets see what else it could be... */
2340 myNodeIndex = findFieldInX3DSPECIAL(name);
2341 if (myNodeIndex != INT_ID_UNDEFINED) {
2342 switch (myNodeIndex) {
2343 case X3DSP_ProtoInstance:
2344 endProtoInstance_B(ud,name);
2345 break;
2346 case X3DSP_ProtoInterface:
2347 endProtoInterfaceTag(ud);
2348 break;
2349 case X3DSP_ProtoBody:
2350 endProtoBodyTag_B(ud,name);
2351 break;
2352 case X3DSP_ProtoDeclare:
2353 endProtoDeclareTag_B(ud);
2354 break;
2355 case X3DSP_ExternProtoDeclare:
2356 endExternProtoDeclareTag_B(ud);
2357 break;
2358 case X3DSP_IS:
2359 endIS(ud);
2360 break;
2361 case X3DSP_connect:
2362 case X3DSP_ROUTE:
2363 case X3DSP_meta:
2364 case X3DSP_Scene:
2365 case X3DSP_head:
2366 case X3DSP_Header:
2367 case X3DSP_component:
2368 case X3DSP_EXPORT:
2369 case X3DSP_IMPORT:
2370 case X3DSP_unit:
2371 case X3DSP_X3D: break;
2372 case X3DSP_field:
2373 endScriptProtoField_B(ud);
2374 break;
2375 case X3DSP_fieldValue:
2376 endFieldValue_B(ud);
2377 break;
2378
2379 /* should never do this: */
2380 default:
2381 printf ("endElement: huh? X3DSPECIAL, but not handled?? %s\n",X3DSPECIAL[myNodeIndex]);
2382 }
2383 return;
2384 }
2385
2386 struct X3D_Proto* proto = availableBroto(ud, name);
2387 if (proto) {
2388 endProto_B(ud, name, proto);
2389 return;
2390 }
2391
2392 printf ("unhandled endElement name %s index %d\n",name,myNodeIndex);
2393 #ifdef X3DPARSERVERBOSE
2394 printf ("endElement %s\n",name);
2395 #endif
2396}
2397
2398static XML_Parser initializeX3DParser () {
2399 ppX3DParser p = (ppX3DParser)gglobal()->X3DParser.prv;
2400 p->X3DParserRecurseLevel++;
2401
2402 if (p->X3DParserRecurseLevel >= PROTOINSTANCE_MAX_LEVELS) {
2403 ConsoleMessage ("XML_PARSER init: XML file PROTO nested too deep\n");
2404 p->X3DParserRecurseLevel--;
2405 } else {
2406 XML_CreateParserLevel(p->x3dparser[p->X3DParserRecurseLevel]);
2407 XML_SetElementHandler(p->x3dparser[p->X3DParserRecurseLevel], X3DstartElement, X3DendElement);
2408 XML_SetCdataSectionHandler (p->x3dparser[p->X3DParserRecurseLevel], startCDATA, endCDATA);
2409 XML_SetDefaultHandler (p->x3dparser[p->X3DParserRecurseLevel],handleCDATA);
2410 XML_SetUserData(p->x3dparser[p->X3DParserRecurseLevel], &parentIndex);
2411 }
2412 /* printf ("initializeX3DParser, level %d, parser %u\n",x3dparser[X3DParserRecurseLevel]); */
2413 return p->x3dparser[p->X3DParserRecurseLevel];
2414}
2415
2416static void shutdownX3DParser (void *ud) {
2417 ttglobal tg = gglobal();
2418 ppX3DParser p = (ppX3DParser)tg->X3DParser.prv;
2419
2420 /* printf ("shutdownX3DParser, recurseLevel %d\n",X3DParserRecurseLevel); */
2421 XML_ParserFree(p->x3dparser[p->X3DParserRecurseLevel]);
2422 p->X3DParserRecurseLevel--;
2423
2424 /* lets free up memory here for possible PROTO variables */
2425 if (p->X3DParserRecurseLevel == INT_ID_UNDEFINED) {
2426 /* if we are at the bottom of the parser call nesting, lets reset parentIndex */
2427 gglobal()->X3DParser.parentIndex = 0; //setParentIndex( 0 );
2428 //freeProtoMemory ();
2429 }
2430
2431 if (p->X3DParserRecurseLevel < INT_ID_UNDEFINED) {
2432 ConsoleMessage ("XML_PARSER close underflow");
2433 p->X3DParserRecurseLevel = INT_ID_UNDEFINED;
2434 }
2435
2436 /* CDATA text space, free it up */
2437 FREE_IF_NZ(tg->X3DParser.CDATA_Text);
2438 p->CDATA_TextMallocSize = 0;
2439 if (p->X3DParserRecurseLevel > INT_ID_UNDEFINED)
2440 p->currentX3DParser = p->x3dparser[p->X3DParserRecurseLevel];
2441 /* printf ("shutdownX3DParser, current X3DParser %u\n",currentX3DParser); */
2442 popMode(ud);
2443
2444 if(p->DEFedNodes){
2445 int i;
2446 for(i=0;i<vectorSize(p->DEFedNodes);i++){
2447 struct Vector* vd = vector_get(struct Vector*,p->DEFedNodes,i);
2448 deleteVector(struct X3D_Node*,vd);
2449 }
2450 deleteVector(struct Vector*, p->DEFedNodes);
2451 }
2452
2453 /*
2454 * Cleanup function for the XML library.
2455 */
2456 xmlCleanupParser();
2457 /*
2458 * this is to debug memory for regression tests
2459 */
2460 xmlMemoryDump();
2461}
2462
2463int X3DParse (struct X3D_Node* ectx, struct X3D_Node* myParent, const char *inputstring) {
2464 ttglobal tg = gglobal();
2465 ppX3DParser p = (ppX3DParser)tg->X3DParser.prv;
2466 p->currentX3DParser = initializeX3DParser();
2467
2468 //printf ("X3DParse, current X3DParser is %p, p is %p\n",p->currentX3DParser,p);
2469
2470
2471 DEBUG_X3DPARSER ("X3DPARSE on :\n%s:\n",inputstring);
2472 if(p->user_data == NULL){
2473 //just once. We are re-entrant when parsing text protos (trotos)
2474 // and want to keep the stack for the parent scene
2475 p->user_data = new_xml_user_data();
2476 }
2477 pushContext(p->user_data,ectx);
2478 if(myParent->_nodeType == NODE_Proto )
2479 pushField(p->user_data,"__children");
2480 else
2481 pushField(p->user_data,"children");
2482 pushNode(p->user_data,myParent);
2483 pushMode(p->user_data,PARSING_NODES);
2484
2485 if (XML_ParseFile(p->currentX3DParser, p->user_data, inputstring, (int) strlen(inputstring), TRUE) == XML_STATUS_ERROR) {
2486 // http://xmlsoft.org/html/libxml-xmlerror.html
2487 xmlErrorPtr xe = xmlGetLastError();
2488 ConsoleMessage("Xml Error %s \n",xe->message);
2489 ConsoleMessage("Line %d\n",xe->line);
2490 /*
2491 fprintf(stderr,
2492 "%s at line %d\n",
2493 XML_ErrorString(XML_GetErrorCode(currentX3DParser)),
2494 XML_GetCurrentLineNumber(currentX3DParser));
2495 */
2496 popField(p->user_data);
2497 shutdownX3DParser(p->user_data);
2498 Parser_deleteParserForScanStringValueToMem();
2499 return FALSE;
2500 }
2501 popField(p->user_data);
2502 shutdownX3DParser(p->user_data);
2503 Parser_deleteParserForScanStringValueToMem();
2504 return TRUE;
2505}