FreeWRL/FreeX3D  3.0.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 
55 typedef 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...
86 struct X3D_Node *broto_search_DEFname(struct X3D_Proto *context, const char *name);
87 static 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 
97 static 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 }
112 static 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 
131 static 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 }
137 static 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 }
145 static 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 
150 static 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 }
155 static 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 
163 static 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 
170 struct mode_name {
171 int mode;
172 const 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 
188 static 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 }
192 static 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 }
200 static void popMode(void *userData){
201  struct xml_user_data *ud = (struct xml_user_data *)userData;
202  stack_pop(int,ud->modes);
203 }
204 
205 static 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 }
210 static 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 
219 static 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 
225 static 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 
259 typedef 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 
277 static void *X3DParser_constructor(){
278  void *v = MALLOCV(sizeof(struct pX3DParser));
279  memset(v,0,sizeof(struct pX3DParser));
280  return v;
281 }
282 
283 void 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 
309 void 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
327 static 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 */
344 int 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 /*
356 in3_3:
357 
358 2b) Allow <fieldValue> + extension for all node-types
359 -------------------------------------------------------------
360 There is already a fieldValue element in current X3D-XML
361 spec to specify the value of a ProtoInstance-field.
362 To specify a value of a ProtoInstance field looks like this:
363 
364 <ProtoInstance name='bar' >
365  <fieldValue name='foo' value='TRUE' />
366 </ProtoInstance>
367 
368 We could change the wording in the spec to allow
369 <fieldValue>- elements not just for ProtoInstance-nodes
370 but for all instances of nodes. In addition we would
371 allow element data in fieldValues which will
372 be read to the single specified field. This solution
373 is not limited to a single field per node but could
374 easily handle any number of fields
375 
376 The 'count' attribute is optional and an idea
377 borrowed form the COLLADA specification. The count-value
378 could be used to further improve the parser-speed because
379 the 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 
390 pro:
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 
396 con:
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 */
406 char *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 */
434 struct 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. */
443 void 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 
450 printf ("kill_X3DDefs... DEFedNodes %p\n",p->DEFedNodes);
451 printf ("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
480 the new node */
481 static 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 
524 int getFieldFromNodeAndName(struct X3D_Node* node,const char *fieldname, int *type, int *kind, int *iifield, union anyVrml **value);
525 void broto_store_route(struct X3D_Proto* proto, struct X3D_Node* fromNode, int fromOfs, struct X3D_Node* toNode, int toOfs, int ft);
526 struct IMEXPORT *broto_search_IMPORTname(struct X3D_Proto *context, char *name);
527 void broto_store_ImportRoute(struct X3D_Proto* proto, char *fromNode, char *fromField, char *toNode, char* toField);
528 struct brotoRoute *createNewBrotoRoute();
529 void broto_store_broute(struct X3D_Proto* context,struct brotoRoute *route);
530 
531 static int QA_routeEnd(struct X3D_Proto *context, char* cnode, char* cfield, struct brouteEnd* brend, int isFrom){
532  //checks one end of a route during parsing
533  struct X3D_Node* node;
534  int found = 0;
535 
536  brend->weak = 1;
537  brend->cfield = STRDUP(cfield);
538  brend->cnode = STRDUP(cnode);
539 
540  node = broto_search_DEFname(context,cnode);
541  if(!node){
542  struct IMEXPORT *imp;
543  imp = broto_search_IMPORTname(context, cnode);
544  if(imp){
545  found = 1;
546  brend->weak = 2;
547  }
548  }else{
549  int idir;
550  int type,kind,ifield,source;
551  void *decl;
552  union anyVrml *value;
553  if(isFrom) idir = PKW_outputOnly;
554  else idir = PKW_inputOnly;
555  found = find_anyfield_by_nameAndRouteDir(node,&value,&kind,&type,cfield,&source,&decl,&ifield,idir); //fieldSynonymCompare for set_ _changed
556  if(found){
557  brend->node = node;
558  brend->weak = 0;
559  brend->ftype = type;
560  brend->ifield = ifield;
561  }
562  }
563  return found;
564 }
565 
566 
567 void QAandRegister_parsedRoute_B(struct X3D_Proto *context, char* fnode, char* ffield, char* tnode, char* tfield){
568  // used by both x3d and vrml parsers, to quality check each end of a route for validity,
569  // store in context->__ROUTES, and -if instancing scenery- register the route
570  // this version accomodates regular routes and routes starting and/or ending on an IMPORTed node, which
571  // may not show up until the inline is loaded, and which may disappear when the inline is unloaded.
572  int haveFrom, haveTo, ok;
573  struct brotoRoute* route;
574  int ftf,ftt;
575  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
576 
577  ok = FALSE;
578  route = createNewBrotoRoute();
579  haveFrom = QA_routeEnd(context, fnode, ffield, &route->from, 1);
580  haveTo = QA_routeEnd(context, tnode, tfield, &route->to, 0);
581  if((haveFrom && haveTo) || allowingVeryWeakRoutes){
582  ftf = -1;
583  ftt = -1;
584  if( !route->from.weak) ftf = route->from.ftype;
585  if( !route->to.weak) ftt = route->to.ftype;
586  route->ft = ftf > -1 ? ftf : ftt > -1? ftt : -1;
587  route->lastCommand = 0; //not registered
588  if(ftf == ftt && ftf > -1){
589  //regular route, register while we are hear
590  int pflags = context->__protoFlags;
591  char oldwayflag = ciflag_get(pflags,1);
592  char instancingflag = ciflag_get(pflags,0);
593  if(oldwayflag || instancingflag){
594  CRoutes_RegisterSimpleB(route->from.node, route->from.ifield, route->to.node, route->to.ifield, route->ft);
595  route->lastCommand = 1; //registered
596  }
597  //broto_store_route(context,fromNode,fifield,toNode,tifield,ftype); //new way delay until sceneInstance()
598  //broto_store_broute(context,route);
599  ok = TRUE;
600  }else if(route->to.weak || route->from.weak){
601  //broto_store_broute(context,route);
602  ok = TRUE;
603  }
604  }
605  if(ok || allowingVeryWeakRoutes)
606  broto_store_broute(context,route);
607  if(!ok || !(haveFrom && haveTo)){
608  ConsoleMessage("Routing problem: ");
609  /* are the types the same? */
610  if (haveFrom && haveTo && route->from.ftype != route->to.ftype) {
611  ConsoleMessage ("type mismatch %s != %s, ",stringFieldtypeType(route->from.ftype), stringFieldtypeType(route->to.ftype));
612  }
613  if(!haveFrom) ConsoleMessage(" _From_ ");
614  if(!haveTo) ConsoleMessage(" _To_ ");
615  ConsoleMessage ("from %s %s, ",fnode,ffield);
616  ConsoleMessage ("to %s %s\n",tnode,tfield);
617  }
618 }
619 /******************************************************************************************/
620 /* parse a ROUTE statement. Should be like:
621  <ROUTE fromField="fraction_changed" fromNode="TIME0" toField="set_fraction" toNode="COL_INTERP"/>
622 */
623 static void parseRoutes_B (void *ud, char **atts) {
624  struct X3D_Proto *context;
625  //struct X3D_Node *fromNode = NULL;
626  //struct X3D_Node *toNode = NULL;
627  int i; //, okf,okt, ftype,fkind,fifield,fsource,ttype,tkind,tifield,tsource;
628  //union anyVrml *fvalue, *tvalue;
629  //void *fdecl,*tdecl;
630  //int error = FALSE;
631  //int isImportRoute;
632  //int fromType;
633  //int toType;
634  char *ffield, *tfield, *fnode, *tnode;
635 
636  context = getContext(ud,TOP);
637 
638  ffield = tfield = fnode = tnode = NULL;
639  for (i = 0; atts[i]; i += 2) {
640  if (strcmp("fromNode",atts[i]) == 0) {
641  fnode = atts[i+1];
642  } else if (strcmp("toNode",atts[i]) == 0) {
643  tnode = atts[i+1];
644  } else if (strcmp("fromField",atts[i])==0) {
645  ffield = atts[i+1];
646  } else if (strcmp("toField",atts[i]) ==0) {
647  tfield = atts[i+1];
648  }
649  }
650  QAandRegister_parsedRoute_B(context, fnode, ffield, tnode, tfield);
651 }
652 
653 
654 /* linkNodeIn - put nodes into parents.
655 
656 
657 WARNING - PROTOS have a two extra groups put in; one to hold while parsing, and one Group that is always there.
658 
659 <Scene>
660  <ProtoDeclare name='txt001'>
661  <ProtoBody>
662  <Material ambientIntensity='0' diffuseColor='1 0.85 0.7' specularColor='1 0.85 0.7' shininess='0.3'/>
663  </ProtoBody>
664  </ProtoDeclare>
665  <Shape>
666  <Cone/>
667  <Appearance>
668  <ProtoInstance name='txt001'/>
669  </Appearance>
670  </Shape>
671 </Scene>
672 
673 is a good test to see what happens for these nodes.
674 
675 Note the "PROTO_MARKER" which is assigned to the bottom-most group. This is the group that is created to
676 hold the proto expansion, and is passed in to the expandProtoInstance function. So, we KNOW that this
677 Group node is the base for the PROTO. If you look at the code to expand the PROTO, the first node is a
678 Group node, too. So, we will have a Group, children Group, children actual nodes in file. eg:
679 
680  Material
681  Group
682  Group marker = PROTO_MARKER.
683 
684 Now, in the example above, the "Material" tries to put itself inside an "appearance" field of an Appearance
685 node. So, if the parentIndex-1 and parentIndex-2 entry are Groups, and parentIndex-2 has PROTO_MARKER
686 set, we know this is a PROTO expansion, so just assign the Material node to the children field, and worry
687 about it later.
688 
689 Ok, later, we have the opposite problem, so we look UP the stack to see what the defaultContainer was
690 actually expected to be. This is the "second case" below.
691 
692 Note that if we are dealing with Groups as Proto Expansions, none of the above is a problem; just if we
693 need to put a node into something other than the "children" field.
694 
695 */
696 int getFieldFromNodeAndName(struct X3D_Node* node,const char *fieldname, int *type, int *kind, int *iifield, union anyVrml **value);
697 int indexChildrenName(struct X3D_Node *node);
698 struct Multi_Node *childrenField(struct X3D_Node *node);
699 #define PPX(A) getTypeNode(X3D_NODE(A)) //possible proto expansion
700 
701 
702 
703 static void linkNodeIn_B(void *ud) {
704 /* Assumes you have parsed a node, and have it pushed onto the node stack, and
705  now you want to put it in a field in it's parent
706  'children' is a weak field recommendation from either the parent or current node
707  more specific recommendations take priority
708 1. when parsing a node, ProtoInstance, field, or fieldvalue,
709  pushField the char* name or fieldoffset of the most likely default field, or NULL if no recommendation for a default
710  Shape would have no default. Transform has children. Inline has __children. GeoLOD has rootnodes.
711 2. PopField when coming out of node, ProtoInstance, fieldValue, or field end
712 3. In CDATA, startNode, startProtoInstance
713 a) in node or protoinstance, look if there's a _defaultContainer for currentNode,
714  and if not null, and not children, look it up in the parent node
715  (may be null, ie geometry might be trying to find a field in a Proto)
716 b) get the parent's suggested fieldname off stack, and if not null,
717  lookup in topnode to get type, offsetof and over-ride (example, proto would steer geometry into its __children)
718  - and field or fieldValue would be very specific
719 c) look at atts containerField, and if not null and not children, use it.
720  - scene author is trying to over-ride defaults.
721 */
722  struct X3D_Node *node, *typenode, *parent;
723  char *parentsSuggestion; //*ic,
724  int type, kind, iifield, ok, isRootNode, mode;
725  union anyVrml *value;
726  const char *fname;
727 
728  mode = getMode(ud,TOP);
729  node = getNode(ud,TOP);
730  typenode = PPX(node);
731  parent = getNode(ud,TOP-1);
732  if(!node || !parent)return;
733  if(node && !typenode) //empty protobody
734  typenode = node;
735  isRootNode = FALSE;
736  if(parent->_nodeType == NODE_Proto){
737  if(mode == PARSING_PROTOBODY) isRootNode = TRUE;
738  }
739  //if(parent->_nodeType == NODE_TransformSensor)
740  // printf("adding a node to transformsensor\n");
741  if(isRootNode){
742  //if we are adding a rootnode to scene or protobody, it should be added to
743  // the scene/protobody's private __children field
744  // (not to any of the proto's public fields, for example if the proto author called a public field 'children')
745  union anyVrml *valueadd = NULL;
746  ok = getFieldFromNodeAndName(parent,"__children",&type,&kind,&iifield,&valueadd);
747  AddRemoveChildren(parent,&valueadd->mfnode,&node,1,1,__FILE__,__LINE__);
748  }else{
749  int i, ncontainer; //, instanceContainer, i;
750  unsigned int iContainer, jContainer, defaultContainer[3];
751 
752  parentsSuggestion = getField(ud,TOP-1);
753 
754  //3.a)
755  jContainer = typenode->_defaultContainer;
756  //Jan 2017 I squeezed 3 defaults into an int in generateCode.c, and extract them here
757  //but do I have the right endian math?
758  defaultContainer[0] = (jContainer << 22) >> 22;
759  defaultContainer[1] = (jContainer << 12) >> 22;
760  defaultContainer[2] = (jContainer << 2) >> 22;
761  ncontainer = 1;
762  if(defaultContainer[1])
763  ncontainer = 2;
764  if(defaultContainer[2])
765  ncontainer = 3;
766  for(i=0;i<ncontainer;i++){
767  iContainer = defaultContainer[i];
768  if(iContainer == FIELDNAMES_children) iContainer = 0;
769  value = NULL;
770  fname = NULL;
771  ok = 0;
772  if(iContainer){
773  fname = FIELDNAMES[iContainer];
774  ok = getFieldFromNodeAndName(parent,fname,&type,&kind,&iifield,&value);
775  ok = ok && (kind == PKW_initializeOnly || kind == PKW_inputOutput); //not inputOnly or outputOnly - we can't park nodes there
776  }
777  if(!value && iContainer == FIELDNAMES_children){
778  //if you try and put a transform into a proto, or LOD, or Inline (or switch?) you'll come in
779  //here to get the equivalent-to-children field
780  ok = getFieldFromNodeAndName(parent,"children",&type,&kind,&iifield,&value);
781  ok = ok && (kind == PKW_initializeOnly || kind == PKW_inputOutput); //not inputOnly or outputOnly - we can't park nodes there
782  if(!ok){
783  int kids = indexChildrenName(parent);
784  if(kids > 0){
785  value = (union anyVrml*)childrenField(parent);
786  type = FIELDTYPE_MFNode;
787  }
788  }
789  }
790  if(ok)
791  break;
792  }
793  //3.b)
794  //if(parentsSuggestion) {
795  if(!ok && parentsSuggestion) {
796  //if you're parsing a fieldValue, and your value is an SF or MFnode in a child xml element,
797  //<fieldValue name='myTransform'>
798  // <Transform USE='tommysTransform'/>
799  //</fieldValue>
800  //you'll come in here
801  //don't want to come in here for metadata
802  ok =getFieldFromNodeAndName(parent,parentsSuggestion,&type,&kind,&iifield,&value);
803  }
804 
805  if(!value && parent){
806  ok = getFieldFromNodeAndName(parent,"children",&type,&kind,&iifield,&value);
807  if(!ok){
808  int kids = indexChildrenName(parent);
809  if(kids > 0){
810  value = (union anyVrml*)childrenField(parent);
811  type = FIELDTYPE_MFNode;
812  }
813  }
814  }
815 
816  if(value){
817  if(type == FIELDTYPE_SFNode){
818  value->sfnode = node;
819  ADD_PARENT(node,parent);
820  }else if(type == FIELDTYPE_MFNode){
821  union anyVrml *valueadd = NULL;
822  ok = 0;
823  if(parent->_nodeType == NODE_Proto){
824  struct X3D_Proto *pparent = X3D_PROTO(parent);
825  char cflag = ciflag_get(pparent->__protoFlags,2);
826  if(cflag == 2) //scene
827  ok = getFieldFromNodeAndName(parent,"addChildren",&type,&kind,&iifield,&valueadd);
828  }
829  if(ok)
830  AddRemoveChildren(parent,&valueadd->mfnode,&node,1,1,__FILE__,__LINE__);
831  else
832  AddRemoveChildren(parent,&value->mfnode,&node,1,1,__FILE__,__LINE__);
833  }
834  }else{
835  printf("no where to put node in parent\n");
836  printf("nodetype=%s parenttype=%s\n",stringNodeType(node->_nodeType),stringNodeType(parent->_nodeType));
837 
838  }
839  }
840 
841 }
842 
843 
844 void Parser_scanStringValueToMem_B(union anyVrml* any, indexT ctype, const char *value, int isXML);
845 
846 static void endCDATA_B (void *ud, const xmlChar *string, int len) {
847  char *fieldname = getField(ud,TOP);
848  struct X3D_Node *node = getNode(ud,TOP);
849  int type, kind, iifield, ok, handled;
850  union anyVrml *value;
851  ok = getFieldFromNodeAndName(node,fieldname,&type,&kind,&iifield,&value);
852  if(ok){
853  handled = FALSE;
854  if(!strcmp(fieldname,"url")){
855  //Script javascript doesn't parse well as an MFString
856  if(strstr((char*)string,"script")){
857  handled = TRUE;
858  value->mfstring.n = 1;
859  value->mfstring.p = MALLOCV(sizeof(void *));
860  value->mfstring.p[0] = newASCIIString((char *)string);
861  //if(0) printf("copied cdata string= [%s]\n",(struct Uni_String*)(value->mfstring.p[0])->strptr);
862  }
863  }
864  if(!handled)
865  Parser_scanStringValueToMem_B(value, type, (const char*) string, TRUE);
866  }
867 }
868 
869 void endCDATA (void *ud, const xmlChar *string, int len) {
870  endCDATA_B(ud,string,len);
871  return;
872 }
873 
874 
875 
876 void handleImport_B (struct X3D_Node *nodeptr, char *nodeName,char *nodeImport, char *as);
877 static void parseImport_B(void *ud, char **atts) {
878  int i;
879  char *inlinedef, *exporteddef, *as;
880  struct X3D_Proto *context;
881  context = getContext(ud,TOP);
882 
883  inlinedef = exporteddef = as = NULL;
884  for (i = 0; atts[i]; i += 2) {
885  printf("import field:%s=%s\n", atts[i], atts[i + 1]);
886  if(!strcmp(atts[i],"inlineDEF")) inlinedef = atts[i+1];
887  if(!strcmp(atts[i],"exportedDEF")) exporteddef = atts[i+1];
888  if(!strcmp(atts[i],"AS")) as = atts[i+1];
889 
890  }
891  handleImport_B (X3D_NODE(context), inlinedef, exporteddef, as);
892 }
893 
894 
895 void handleExport_B (void *nodeptr, char *node, char *as);
896 static void parseExport_B(void *ud, char **atts) {
897  // http://www.web3d.org/documents/specifications/19776-1/V3.3/Part01/concepts.html#IMPORT_EXPORTStatementSyntax
898  int i;
899  char *localdef, *as;
900  struct X3D_Proto *context;
901  context = getContext(ud,TOP);
902 
903  localdef = as = NULL;
904  for (i = 0; atts[i]; i += 2) {
905  printf("export field:%s=%s\n", atts[i], atts[i + 1]);
906  if(!strcmp(atts[i],"localDEF")) localdef = atts[i+1];
907  if(!strcmp(atts[i],"AS")) as = atts[i+1];
908  }
909  handleExport_B(context,localdef, as);
910 }
911 
912 
913 /* parse a component statement, and send the results along */
914 static void parseComponent(char **atts) {
915  int i;
916  int myComponent = INT_ID_UNDEFINED;
917  int myLevel = INT_ID_UNDEFINED;
918 
919  /* go through the fields and make sense of them */
920  for (i = 0; atts[i]; i += 2) {
921  /* printf("components field:%s=%s\n", atts[i], atts[i + 1]); */
922  if (strcmp("level",atts[i]) == 0) {
923  if (sscanf(atts[i+1],"%d",&myLevel) != 1) {
924  ConsoleMessage ("Line %d: Expected Component level for component %s, got %s",LINE, atts[i], atts[i+1]);
925  return;
926  }
927  } else if (strcmp("name",atts[i]) == 0) {
928  myComponent = findFieldInCOMPONENTS(atts[i+1]);
929  if (myComponent == INT_ID_UNDEFINED) {
930  ConsoleMessage("Line %d: Component statement, but component name not valid :%s:",LINE,atts[i+1]);
931  return;
932  }
933 
934  } else {
935  ConsoleMessage ("Line %d: Unknown fields in Component statement :%s: :%s:",LINE,atts[i], atts[i+1]);
936  }
937  }
938 
939  if (myComponent == INT_ID_UNDEFINED) {
940  ConsoleMessage("Line %d: Component statement, but component name not stated",LINE);
941  } else if (myLevel == INT_ID_UNDEFINED) {
942  ConsoleMessage("Line %d: Component statement, but component level not stated",LINE);
943  } else {
944  handleComponent(myComponent,myLevel);
945  }
946 }
947 
948 /* parse the <X3D profile='Immersive' version='3.0' xm... line */
949 static void parseX3Dhead(char **atts) {
950  int i;
951  int myProfile = -10000; /* something negative, not INT_ID_UNDEFINED... */
952  int versionIndex = INT_ID_UNDEFINED;
953 
954  for (i = 0; atts[i]; i += 2) {
955  /* printf("parseX3Dhead: field:%s=%s\n", atts[i], atts[i + 1]); */
956  if (strcmp("profile",atts[i]) == 0) {
957  myProfile = findFieldInPROFILES(atts[i+1]);
958  } else if (strcmp("version",atts[i]) == 0) {
959  versionIndex = i+1;
960  } else {
961  /* printf ("just skipping this data\n"); */
962  }
963  }
964 
965  /* now, handle all the found variables */
966  if (myProfile == INT_ID_UNDEFINED) {
967  ConsoleMessage ("expected valid profile in X3D header");
968  } else {
969  /* printf ("X3DParsehead, myProfile %d\n",myProfile); */
970  if (myProfile >= 0) handleProfile (myProfile);
971  }
972 
973  if (versionIndex != INT_ID_UNDEFINED) {
974  handleVersion (atts[versionIndex]);
975  }
976 }
977 
978 static void parseHeader(char **atts) {
979  int i;
980  for (i = 0; atts[i]; i += 2) {
981  /* printf("parseHeader: field:%s=%s\n", atts[i], atts[i + 1]); */
982  }
983 }
984 static void parseScene(char **atts) {
985  int i;
986  for (i = 0; atts[i]; i += 2) {
987  /* printf("parseScene: field:%s=%s\n", atts[i], atts[i + 1]); */
988  }
989 }
990 static void parseMeta(char **atts) {
991  int i;
992  for (i = 0; atts[i]; i += 2) {
993  /* printf("parseMeta field:%s=%s\n", atts[i], atts[i + 1]); */
994  }
995 }
996 void deleteMallocedFieldValue(int type,union anyVrml *fieldPtr);
997 static void parseFieldValue_B(void *ud, char **atts) {
998  int i, type, kind, iifield, ok;
999  const char *fname, *svalue, *cname;
1000  union anyVrml *value;
1001  struct X3D_Node *node = getNode(ud,TOP);
1002 
1003  if(0) printf("parseFieldValue\n");
1004  fname = svalue = NULL;
1005  for(i=0;atts[i];i+=2){
1006  if(!strcmp(atts[i],"name")) fname = atts[i+1];
1007  if(!strcmp(atts[i],"value")) svalue = atts[i+1];
1008  }
1009  ok = 0;
1010  cname = NULL;
1011  value = NULL;
1012  if(fname){
1013  ok = getFieldFromNodeAndName(node,fname,&type,&kind,&iifield,&value);
1014  if(ok){
1015  //get a pointer to a heap version of the field name (because atts vanishes on return)
1016  ok = getFieldFromNodeAndIndex(node, iifield, &cname, &type, &kind, &value);
1017  }
1018  }
1019  if(cname && value && svalue){
1020  deleteMallocedFieldValue(type,value);
1021  Parser_scanStringValueToMem_B(value,type,svalue,TRUE);
1022  }
1023  if(cname && (node->_nodeType == NODE_Proto)){
1024  //for protoInstances, whether or not you have a value,
1025  //if you declare a field then you are saying you declare the value null or 0 or default at least.
1026  //so for SFNode fields where <fieldValue><a node></fieldValue> and we get the node later
1027  //whether or not there's a node/value parsed, we are declaring its set even at null.
1028  //therefore alreadyset
1029  //the way to acheive not alreadySet is to not mention the field in your protoInstance.
1030  struct X3D_Proto *pnode;
1031  struct ProtoFieldDecl* pfield;
1032  struct ProtoDefinition* pstruct;
1033  pnode = X3D_PROTO(node);
1034  pstruct = (struct ProtoDefinition*) pnode->__protoDef;
1035  pfield = vector_get(struct ProtoFieldDecl*,pstruct->iface,iifield);
1036  //is there a function for zeroing a fieldValue of anytype? Need it here.
1037  //in xml the MFNode in particular will get 'added to' ie mf.n++ later, so need to clear that
1038  // see tests/protos/questionforexperts_mod.x3d
1039  if(pfield->type == FIELDTYPE_MFNode){
1040  struct Multi_Node* mfn = &pfield->defaultVal.mfnode;
1041  if(mfn->n)
1042  AddRemoveChildren(node,mfn,mfn->p,mfn->n,2,__FILE__,__LINE__);
1043  pfield->defaultVal.mfnode.n = 0;
1044  pfield->defaultVal.mfnode.p = NULL;
1045  }
1046  if(pfield->type == FIELDTYPE_SFNode){
1047  struct X3D_Node **sfn = &pfield->defaultVal.sfnode;
1048  if(*sfn)
1049  AddRemoveSFNodeFieldChild(node,sfn,*sfn,2,__FILE__,__LINE__);
1050  pfield->defaultVal.sfnode = NULL;
1051  }
1052  pfield->alreadySet = TRUE;
1053  }
1054 
1055  pushField(ud,cname); //in case there's no value, because its SF or MFNodes in child xml, or in CDATA
1056 }
1057 static void endFieldValue_B(void *ud){
1058  if(0) printf("endFieldValue\n");
1059  //in x3d, <fieldvalue type=SFNode><a node></fieldValue>
1060 
1061  popField(ud);
1062 }
1063 
1064 
1065 static void parseIS(void *ud) {
1066  #ifdef X3DPARSERVERBOSE
1067  printf ("parseIS mode is %s\n",parserModeStrings[getMode(ud,TOP)]);
1068  #endif
1069  pushMode(ud,PARSING_IS);
1070 
1071 }
1072 
1073 
1074 
1075 static void endIS(void *ud) {
1076  #ifdef X3DPARSERVERBOSE
1077  printf ("endIS mode is %s\n",parserModeStrings[getMode(ud,TOP)]);
1078  #endif
1079  popMode(ud);
1080 }
1081 
1082 
1083 
1084 static void endProtoInterfaceTag(void *ud) {
1085  if (getMode(ud,TOP) != PARSING_PROTOINTERFACE) {
1086  ConsoleMessage ("endProtoInterfaceTag: got a </ProtoInterface> but not parsing one at line %d",LINE);
1087  }
1088  /* now, a ProtoInterface should be within a ProtoDeclare, so, make the expected mode PARSING_PROTODECLARE */
1089  //setParserMode(PARSING_PROTODECLARE);
1090  popMode(ud);
1091 }
1092 static void endProtoBodyTag_B(void *ud, const char *name) {
1093  //pop context
1094  if (getMode(ud,TOP) != PARSING_PROTOBODY) {
1095  ConsoleMessage ("endProtoBodyTag: got a </ProtoBody> but not parsing one at line %d",LINE);
1096  }
1097  popMode(ud);
1098  popContext(ud);
1099 }
1100 
1101 static void endExternProtoDeclareTag_B(void *ud) {
1102  popMode(ud);
1103  popNode(ud);
1104  popField(ud);
1105 }
1106 
1107 static void endProtoDeclareTag_B(void *ud) {
1108  /* ending <ProtoDeclare> */
1109  struct X3D_Proto * proto;
1110  struct Multi_Node *cptr;
1111 
1112  if (getMode(ud,TOP) != PARSING_PROTODECLARE) {
1113  ConsoleMessage ("endProtoDeclareTag: got a </ProtoDeclare> but not parsing one at line %d",LINE);
1114  pushMode(ud,PARSING_PROTODECLARE);
1115  }
1116  if(0) printf("end protoDeclare\n");
1117  // set defaultContainer based on 1st child
1118  proto = X3D_PROTO(getNode(ud,TOP));
1119  cptr = NULL;
1120  if(proto->__children.n)
1121  cptr = &proto->__children;
1122  else if(proto->addChildren.n)
1123  cptr = &proto->addChildren;
1124  if(cptr){
1125  struct X3D_Node *c1 = cptr->p[0];
1126  if(c1->_defaultContainer > INT_ID_UNDEFINED)
1127  proto->_defaultContainer = c1->_defaultContainer;
1128  }
1129  popField(ud);
1130  popNode(ud); //I think I should pop the X3DProto off the stack
1131  popMode(ud);
1132 }
1133 
1134 
1135 void deep_copy_broto_body2(struct X3D_Proto** proto, struct X3D_Proto** dest);
1136 static void endProtoInstance_B(void *ud, const char *name) {
1137  //now that initial field values are set, deep copy the broto body
1138  int mode;
1139  struct X3D_Node *node;
1140  if(0) printf("endProtoInstance_B\n");
1141 
1142  node = getNode(ud,TOP);
1143  mode = getMode(ud,TOP);
1144  if(node){
1145  if(node->_nodeType == NODE_Proto || node->_nodeType == NODE_Inline ){
1146  if(mode != PARSING_PROTOINSTANCE_USE){
1147  char pflagdepth;
1148  struct X3D_Proto *pnode = X3D_PROTO(node);
1149  pflagdepth = ciflag_get(pnode->__protoFlags,0); //0 - we're in a protodeclare, 1 - we are instancing live scenery
1150  if( pflagdepth){
1151  //copying the body _after_ the protoInstance field values have been parsed
1152  //allows ISd fields in body nodes to get the pkw_initializeOnly/inputOutput value
1153  //from the protoInstance interface
1154  struct X3D_Proto *pdeclare;
1155  pdeclare = X3D_PROTO(pnode->__prototype);
1156  //if you bomb around here, pdeclare == null, then make sure your scene
1157  // doesn't have protoDeclares with the same name as freewrl builtin types
1158  // because as of Nov 2016 freewrl doesn't allow over-riding builtins with protos,
1159  // and gets confused and bombs
1160  deep_copy_broto_body2(&pdeclare,&pnode);
1161  }
1162  }
1163  }
1164  linkNodeIn_B(ud);
1165  }
1166  popField(ud);
1167  popNode(ud);
1168  popMode(ud);
1169 }
1170 
1171 /* did we get a USE in a proto instance, like:
1172 <ProtoInstance name='CamLoader' DEF='Camera1_Bgpic'>
1173  <fieldValue name='imageName' value='Default.jpg'/>
1174  <fieldValue name='relay'>
1175  <Script USE='CameraRelay'/>
1176  </fieldValue>
1177  <fieldValue name='yscale' value='3.0'/>
1178 </ProtoInstance>
1179 
1180 if so, we will be here for the USE fields.
1181 
1182 
1183 */
1184 
1185 /********************************************************/
1186 
1187 
1188 void **shaderFields(struct X3D_Node* node){
1189  void **shaderfield;
1190  switch(node->_nodeType){
1191  case NODE_Script:
1192  shaderfield = &X3D_SCRIPT(node)->__scriptObj; break;
1193  case NODE_ComposedShader:
1194  shaderfield = (void**)&X3D_COMPOSEDSHADER(node)->_shaderUserDefinedFields; break;
1195  case NODE_Effect:
1196  shaderfield = (void**)&X3D_EFFECT(node)->_shaderUserDefinedFields; break;
1197  case NODE_ShaderProgram:
1198  shaderfield = (void**)&X3D_SHADERPROGRAM(node)->_shaderUserDefinedFields; break;
1199  case NODE_PackagedShader:
1200  shaderfield = (void**)&X3D_PACKAGEDSHADER(node)->_shaderUserDefinedFields; break;
1201  default:
1202  shaderfield = NULL;
1203  }
1204  return shaderfield;
1205 }
1206 
1207 void broto_store_DEF(struct X3D_Proto* proto,struct X3D_Node* node, const char *name);
1208 static void parseAttributes_B(void *ud, char **atts);
1209 void add_node_to_broto_context(struct X3D_Proto *context,struct X3D_Node *node);
1210 void push_binding_stack_set(struct X3D_Node* layersetnode);
1211 void push_next_layerId_from_binding_stack_set(struct X3D_Node* layer);
1212 void pop_binding_stack_set();
1213 
1214 static void startBuiltin_B(void *ud, int myNodeType, const xmlChar *name, char** atts) {
1215  struct X3D_Node *node, *fromDEFtable;
1216  struct X3D_Proto *context;
1217  void **shaderfield;
1218  char pflagdepth;
1219  int kids, i, isUSE;
1220  const char *defname, *suggestedChildField, *containerfield;
1221 
1222  suggestedChildField = containerfield = NULL;
1223  context = getContext(ud,TOP);
1224  pflagdepth = ciflag_get(context->__protoFlags,0); //0 - we're in a protodeclare, 1 - we are instancing live scenery
1225  if(0) printf("start builtin %s\n",name);
1226  node = NULL;
1227  defname = NULL;
1228  isUSE = FALSE;
1229  /* go through the attributes; do some here, do others later (in case of PROTO IS fields found) */
1230  for (i = 0; atts[i]; i += 2) {
1231  /* is this a DEF name? if so, record the name and then ignore the field */
1232  if (strcmp ("DEF",atts[i]) == 0) {
1233  defname = atts[i+1];
1234  fromDEFtable = broto_search_DEFname(context,defname);
1235  if (fromDEFtable) {
1236  #ifdef X3DPARSERVERBOSE
1237  printf ("Warning - line %d duplicate DEF name: \'%s\'\n",LINE,atts[i+1]);
1238  #endif
1239  }
1240  } else if (strcmp ("USE",atts[i]) == 0) {
1241  #ifdef X3DPARSERVERBOSE
1242  printf ("this is a USE, name %s\n",atts[i+1]);
1243  #endif
1244 
1245  //fromDEFtable = DEFNameIndex ((char *)atts[i+1],node, FALSE);
1246  fromDEFtable = broto_search_DEFname(context,atts[i+1]);
1247  if (!fromDEFtable) {
1248  ConsoleMessage ("Warning - line %d DEF name: \'%s\' not found",LINE,atts[i+1]);
1249  ConsoleMessage("\n");
1250  } else {
1251  #ifdef X3DPARSERVERBOSE
1252  printf ("copying for field %s defName %s\n",atts[i], atts[i+1]);
1253  #endif
1254 
1255  /* if (fromDEFtable->_nodeType != fromDEFtable->_nodeType) { */
1256  if (myNodeType != fromDEFtable->_nodeType) {
1257  ConsoleMessage ("Warning, line %d DEF/USE mismatch, '%s', %s != %s", LINE,
1258  atts[i+1],stringNodeType(fromDEFtable->_nodeType), stringNodeType (myNodeType));
1259  } else {
1260  /* Q. should thisNode.referenceCount be decremented or ??? */
1261  node = fromDEFtable;
1262  node->referenceCount++; //dug9 added but should???
1263  //getNode(ud,TOP) = thisNode;
1264  #ifdef X3DPARSERVERBOSE
1265  printf ("successful copying for field %s defName %s\n",atts[i], atts[i+1]);
1266  #endif
1267  isUSE = TRUE;
1268  }
1269  }
1270  } else if(!strcmp(atts[i],"containerField")) containerfield = atts[i+1];
1271  }
1272 
1273  if(!isUSE){
1274  if(pflagdepth)
1275  node = createNewX3DNode(myNodeType);
1276  else
1277  node = createNewX3DNode0(myNodeType);
1278  if(defname)
1279  broto_store_DEF(context,node,defname);
1280  }
1281  pushNode(ud,node);
1282 
1283  if(containerfield) {
1284  //int builtinField = findFieldInARR(containerfield,FIELDNAMES,FIELDNAMES_COUNT);
1285  int builtinField = findFieldInFIELDNAMES(containerfield);
1286  if(builtinField > INT_ID_UNDEFINED){
1287  //if USE, the DEF could specify containerField that's wrong for the USE
1288  //so we'll keep the original as well, for linkNodeIn
1289  //in theory we should call an update function here, and about 4 other places
1290  // in x3dparser.c
1291  node->_defaultContainer = (node->_defaultContainer << 10) + builtinField;
1292  //printf("new defaultContainer=%u\n",(unsigned int)node->_defaultContainer);
1293  }
1294  }
1295 
1296  //linkNodeIn_B(ud);
1297 
1298  if(!isUSE){
1299  shaderfield = shaderFields(node);
1300  if(shaderfield)
1301  (*shaderfield) = (void *)new_Shader_ScriptB(node);
1302  //if(node->_nodeType == NODE_Script && pflagdepth)
1303  //initialize script - wait till end element
1304  if(node->_nodeType == NODE_LayerSet)
1305  push_binding_stack_set(node);
1306  if(node->_nodeType == NODE_Layer || node->_nodeType == NODE_LayoutLayer)
1307  push_next_layerId_from_binding_stack_set(node);
1308  if(node->_nodeType == NODE_Inline)
1309  X3D_INLINE(node)->__parentProto = X3D_NODE(context); //when searching for user proto declarations, apparently inlines can search the scene
1310  node->_executionContext = X3D_NODE(context);
1311  add_node_to_broto_context(context,node);
1312 
1313  kids = indexChildrenName(node);
1314  if(kids > -1)
1315  suggestedChildField = FIELDNAMES[kids];
1316  if(node->_nodeType == NODE_Script || node->_nodeType == NODE_ShaderPart
1317  || node->_nodeType == NODE_ShaderProgram || node->_nodeType == NODE_EffectPart)
1318  suggestedChildField = FIELDNAMES[FIELDNAMES_url]; //for CDATA
1319 
1320  pushField(ud,suggestedChildField);
1321 
1322  parseAttributes_B(ud,atts);
1323  }else{
1324  pushField(ud,NULL); //we pop in endBuiltin, so we have to push something
1325  }
1326 
1327 }
1328 void initialize_one_script(struct Shader_Script* ss, const struct Multi_String *url);
1329 
1330 static void endBuiltin_B(void *ud, const xmlChar *name){
1331  struct X3D_Node *node;
1332  struct X3D_Proto *context;
1333  char pflagdepth;
1334  node = getNode(ud,TOP);
1335  context = getContext(ud,TOP);
1336  if(0)printf("end builtin %s\n",name);
1337  pflagdepth = ciflag_get(context->__protoFlags,0); //0 - we're in a protodeclare, 1 - we are instancing live scenery
1338  if(node->_nodeType == NODE_Script && pflagdepth){
1339  struct X3D_Script *sn = X3D_SCRIPT(node);
1340  //overkill -duplicates new_Shader_Script
1341  initialize_one_script(sn->__scriptObj,&sn->url);
1342  //script_initCodeFromMFUri(sn->__scriptObj, &sn->url);
1343  }
1344  if(node->_nodeType == NODE_LayerSet)
1345  pop_binding_stack_set();
1346 
1347  linkNodeIn_B(ud);
1348 
1349  popNode(ud);
1350  popField(ud);
1351 
1352 }
1353 
1354 static xmlChar* fixAmp(const unsigned char *InFieldValue)
1355 {
1356  char *fieldValue = (char *)InFieldValue;
1357 
1358  //for x3d string '"&amp;"' libxml2 gives us &#38;
1359  //we want & like other browsers get
1360  //we do it by left-shifting over the #38;
1361  //fieldValue - the MFString before splitting into SFs ie ["you & me" "John & Ian"\0]
1362  //except that libxml2 will wrongly give you ["you &#38; me" "John &#38; Ian"\0]
1363  if(fieldValue)
1364  {
1365  char *pp = strstr((char *)fieldValue,"&#38;");
1366  while(pp){
1367  memmove(pp+1,pp+5,strlen(fieldValue) - (pp+1 - fieldValue));
1368  pp = strstr(pp,"&#38;");
1369  /* or the following works if you don't have memmove:
1370  int len, nmove, ii;
1371  len = strlen(fieldValue);
1372  pp++;
1373  nmove = (len+1) - (pp - fieldValue);
1374  for(ii=0;ii<nmove;ii++){
1375  *pp = *(pp+4);
1376  pp++;
1377  }
1378  */
1379  }
1380  }
1381  return (xmlChar *)fieldValue;
1382 }
1383 static void parseAttributes_B(void *ud, char **atts) {
1384  int i, type, kind, iifield;
1385  struct X3D_Node *node;
1386  char *name, *svalue;
1387  const char *ignore [] = {"containerField","USE", "DEF"};
1388  union anyVrml *value;
1389 
1390  node = getNode(ud,TOP);
1391  for (i=0; atts[i]; i+=2) {
1392  name = atts[i];
1393  svalue = atts[i+1];
1394  /* see if we have a containerField here */
1395  if(findFieldInARR(name,ignore,3) == INT_ID_UNDEFINED){
1396  if(getFieldFromNodeAndName(node,name,&type,&kind,&iifield,&value)){
1397  deleteMallocedFieldValue(type,value);
1398  Parser_scanStringValueToMem_B(value, type,svalue, TRUE);
1399  }
1400  }
1401  if(!strcmp(name,"side")){
1402  //stereoscopic experiments
1403  if(!strcmp(svalue,"left"))
1404  node->_renderFlags |= VF_HideRight;
1405  else if(!strcmp(svalue,"right"))
1406  node->_renderFlags |= VF_HideLeft;
1407  //printf("node renderflags=%d\n",node->_renderFlags);
1408  }
1409  }
1410 }
1411 
1412 
1413 int findFieldInARR(const char* field, const char** arr, size_t cnt);
1414 static void parseScriptProtoField_B(void *ud, char **atts) {
1415  /* new user field definitions -name,type,mode- possibly with fieldvalue anyVrml
1416  - we will be parsing either:
1417  a ProtoDeclare or ExternProtoDeclare (extern will lack fieldValue)
1418  a Script Node or Shader node
1419  - Script field may have fieldValue as child element, or IS/connect as peer
1420  - ProtoDeclare may have fieldValue as child element
1421  */
1422  //struct X3D_Node *node;
1423  int mp_name, mp_accesstype, mp_type, mp_value, i;
1424  int pkwmode, type;
1425  union anyVrml defaultValue; //, *value;
1426  char *fname, *cname;
1427  //value = NULL;
1428  cname = NULL;
1429  mp_name = mp_accesstype = mp_type = mp_value = ID_UNDEFINED;
1430  if(0) printf("start scriptProtoField\n");
1431  /* have a "key" "value" pairing here. They can be in any order; put them into our order */
1432  for (i = 0; atts[i]; i += 2) {
1433  /* skip any "appinfo" or "documentation" fields here */
1434  if ((strcmp("appinfo", atts[i]) != 0) &&
1435  (strcmp("documentation",atts[i]) != 0)) {
1436  if (strcmp(atts[i],"name") == 0) { mp_name = i+1;
1437  } else if (strcmp(atts[i],"accessType") == 0) { mp_accesstype = i+1;
1438  } else if (strcmp(atts[i],"type") == 0) { mp_type = i+1;
1439  } else if (strcmp(atts[i],"value") == 0) { mp_value = i+1;
1440  } else {
1441  ConsoleMessage ("X3D Proto/Script parsing line %d: unknown field type %s",LINE,atts[i]);
1442  return;
1443  }
1444  }
1445  }
1446  if(mp_accesstype > -1 && mp_type > -1 && mp_name > -1){
1447  int valueSet;
1448  pkwmode = findFieldInARR(atts[mp_accesstype], PROTOKEYWORDS, PROTOKEYWORDS_COUNT);
1449  pkwmode = pkwmode > -1? X3DMODE(pkwmode) : pkwmode;
1450  type = findFieldInARR(atts[mp_type],FIELDTYPES,FIELDTYPES_COUNT);
1451  fname = atts[mp_name];
1452  cname = NULL;
1453  //memset(&defaultValue,0,sizeof(union anyVrml));
1454  bzero(&defaultValue, sizeof (union anyVrml));
1455  if(type == FIELDTYPE_SFString)
1456  defaultValue.sfstring = newASCIIString("");
1457  valueSet = FALSE;
1458  if(mp_value > -1){
1459  Parser_scanStringValueToMem_B(&defaultValue, type, atts[mp_value], TRUE);
1460  valueSet = TRUE;
1461  }
1462  if(pkwmode > -1 && type > -1){
1463  struct X3D_Node * node = getNode(ud,TOP);
1464  if(node->_nodeType == NODE_Proto){
1465  struct X3D_Proto *pnode;
1466  struct ProtoFieldDecl* pfield;
1467  struct ProtoDefinition* pstruct;
1468  pnode = X3D_PROTO(node);
1469  pstruct = (struct ProtoDefinition*) pnode->__protoDef;
1470  pfield = newProtoFieldDecl(pkwmode,type,0);
1471  pfield->cname = STRDUP(fname);
1472  cname = pfield->cname;
1473  memcpy(&pfield->defaultVal,&defaultValue,sizeof(union anyVrml));
1474  vector_pushBack(struct ProtoFieldDecl*, pstruct->iface, pfield);
1475  //value = &pfield->defaultVal;
1476  }else{
1477  struct Shader_Script* shader = NULL;
1478  struct ScriptFieldDecl* sfield;
1479  int jsname;
1480  switch(node->_nodeType)
1481  {
1482  case NODE_Script: shader =(struct Shader_Script *)(X3D_SCRIPT(node)->__scriptObj); break;
1483  case NODE_ComposedShader: shader =(struct Shader_Script *)(X3D_COMPOSEDSHADER(node)->_shaderUserDefinedFields); break;
1484  case NODE_Effect: shader =(struct Shader_Script *)(X3D_EFFECT(node)->_shaderUserDefinedFields); break;
1485  case NODE_ShaderProgram: shader =(struct Shader_Script *)(X3D_SHADERPROGRAM(node)->_shaderUserDefinedFields); break;
1486  case NODE_PackagedShader: shader =(struct Shader_Script *)(X3D_PACKAGEDSHADER(node)->_shaderUserDefinedFields); break;
1487  }
1488  jsname = JSparamIndex (fname, atts[mp_type]);
1489  cname = getJSparamnames()[jsname].name;
1490  //sfield = newScriptFieldDecl() // too hard to fathom, I'll break it out:
1491  sfield = MALLOC(struct ScriptFieldDecl *, sizeof(struct ScriptFieldDecl));
1492  bzero(sfield,sizeof(struct ScriptFieldDecl));
1493  sfield->fieldDecl = newFieldDecl(pkwmode,type,0,jsname,0); //not using a lexer
1494  memcpy(&sfield->value,&defaultValue,sizeof(union anyVrml));
1495  sfield->valueSet = valueSet; //=(mod!=PKW_initializeOnly);
1496  sfield->eventInSet = FALSE; //flag used for directOutput
1497  vector_pushBack(struct ScriptFieldDecl*, shader->fields, sfield);
1498  //value = &sfield->value;
1499  }
1500  }
1501  }
1502  pushField(ud,cname); //strdup(fname)); //strong recommendation
1503  pushMode(ud,PARSING_FIELD);
1504 }
1505 
1506 /* simple sanity check, and change mode */
1507 static void parseProtoInterface (void *ud, char **atts) {
1508  if (getMode(ud,TOP) != PARSING_PROTODECLARE && getMode(ud,TOP) != PARSING_EXTERNPROTODECLARE) {
1509  ConsoleMessage ("got a <ProtoInterface>, but not within a <ProtoDeclare>\n");
1510  }
1511  //setParserMode(PARSING_PROTOINTERFACE);
1512  pushMode(ud,PARSING_PROTOINTERFACE);
1513 }
1514 void Parser_scanStringValueToMem_B(union anyVrml* any, indexT ctype, const char *value, int isXML);
1515 
1516 static void parseExternProtoDeclare_B (void *ud, char **atts) {
1517  /* 1.create a new proto but not registered node
1518  2.get user type name from atts
1519  3.set flag for shallow/declare
1520  4.add to current context's externProtoDeclare array
1521  5.push on node stack awaiting interface (with no initial values)
1522  */
1523  int i;
1524  char *type_name, *appinfo, *documentation, *containerfield, *url;
1525  struct ProtoDefinition* obj;
1526  struct X3D_Proto* proto;
1527  struct X3D_Proto* parent;
1528  type_name = appinfo = documentation = containerfield = url = NULL;
1529  if(0) printf("in parseExternProtoDeclare_B\n");
1530 
1531  proto = createNewX3DNode0(NODE_Proto);
1532  for (i = 0; atts[i]; i += 2) {
1533  #ifdef X3DPARSERVERBOSE
1534  TTY_SPACE
1535  printf ("parseProtoDeclare: field:%s=%s\n", atts[i], atts[i+1]);
1536  #endif
1537 
1538  if (!strcmp("name",atts[i]) ) type_name = atts[i+1];
1539  else if(!strcmp("containerField",atts[i])) containerfield = atts[i+1];
1540  else if(!strcmp("appInfo",atts[i])) appinfo = atts[i+1];
1541  else if(!strcmp("documentation",atts[i])) documentation = atts[i+1];
1542  else if(!strcmp("url",atts[i])) url = atts[i+1];
1543  }
1544 
1545  parent = (struct X3D_Proto*)getContext(ud,TOP);
1546  obj=newProtoDefinition();
1547 
1548  /* did we find the name? */
1549  if (type_name) {
1550  obj->protoName = STRDUP(type_name);
1551  } else {
1552  printf ("warning - have proto but no name, so just copying a default string in\n");
1553  obj->protoName = STRDUP("noProtoNameDefined");
1554  }
1555  type_name = obj->protoName;
1556 
1557  if(parent->__externProtoDeclares == NULL)
1558  parent->__externProtoDeclares = newVector(struct X3D_Proto*,4);
1559  vector_pushBack(struct X3D_Proto*,parent->__externProtoDeclares,proto);
1560  proto->__parentProto = X3D_NODE(parent); //me->ptr; //link back to parent proto, for isAvailableProto search
1561  proto->__protoFlags = parent->__protoFlags;
1562  proto->__protoFlags = ciflag_set(proto->__protoFlags,0,0); //((char*)(&proto->__protoFlags))[0] = 0; //shallow instancing of protoInstances inside a protoDeclare
1564  proto->__protoFlags = ciflag_set(proto->__protoFlags,0,2); //((char*)(&proto->__protoFlags))[2] = 0; //this is a protoDeclare we are parsing
1565  proto->__protoFlags = ciflag_set(proto->__protoFlags,1,3); //((char*)(&proto->__protoFlags))[3] = 1; //an externProtoDeclare
1566  //set ProtoDefinition *obj
1567  proto->__protoDef = obj;
1568  proto->__prototype = X3D_NODE(proto); //point to self, so shallow and deep instances will inherit this value
1569  proto->__typename = STRDUP(obj->protoName);
1570  if(containerfield){
1571  int builtinField = findFieldInFIELDNAMES(containerfield);
1572  if(builtinField > -1){
1573  proto->_defaultContainer = builtinField;
1574  }
1575  }
1576  if(url){
1577  Parser_scanStringValueToMem_B((union anyVrml*)&proto->url, FIELDTYPE_MFString,url, TRUE);
1578  }
1579  proto->__loadstatus = 0; //= LOAD_INITIAL_STATE
1580  pushMode(ud,PARSING_EXTERNPROTODECLARE);
1581  pushNode(ud,X3D_NODE(proto));
1582  pushField(ud,"__children");
1583 
1584 }
1585 
1586 static void parseProtoDeclare_B (void *ud, char **atts) {
1587  /* 1.create a new proto but not registered node
1588  2.get user type name from atts
1589  3.set flag for shallow/declare
1590  4.add to current context's protoDeclare array
1591  5.push on node stack awaiting interface and body
1592  */
1593  int i;
1594  struct X3D_Proto* proto;
1595  char *type_name, *appinfo, *documentation, *containerfield;
1596  struct ProtoDefinition* obj;
1597  struct X3D_Proto* parent;
1598 
1599  type_name = appinfo = documentation = containerfield = NULL;
1600  if(0) printf("in start protoDeclare\n");
1601 
1602  proto = createNewX3DNode0(NODE_Proto);
1603  for (i = 0; atts[i]; i += 2) {
1604  #ifdef X3DPARSERVERBOSE
1605  TTY_SPACE
1606  printf ("parseProtoDeclare: field:%s=%s\n", atts[i], atts[i+1]);
1607  #endif
1608 
1609  if (!strcmp("name",atts[i]) ) type_name = atts[i+1];
1610  else if(!strcmp("containerField",atts[i])) containerfield = atts[i+1];
1611  else if(!strcmp("appInfo",atts[i])) appinfo = atts[i+1];
1612  else if(!strcmp("documentation",atts[i])) documentation = atts[i+1];
1613  }
1614 
1615  parent = (struct X3D_Proto*)getContext(ud,TOP);
1616  obj=newProtoDefinition();
1617 
1618  /* did we find the name? */
1619  if (type_name) {
1620  obj->protoName = STRDUP(type_name);
1621  } else {
1622  printf ("warning - have proto but no name, so just copying a default string in\n");
1623  obj->protoName = STRDUP("noProtoNameDefined");
1624  }
1625  type_name = obj->protoName;
1626 
1627  if(parent->__protoDeclares == NULL)
1628  parent->__protoDeclares = newVector(struct X3D_Proto*,4);
1629  vector_pushBack(struct X3D_Proto*,parent->__protoDeclares,proto);
1630  proto->__parentProto = X3D_NODE(parent); //me->ptr; //link back to parent proto, for isAvailableProto search
1631  proto->__protoFlags = parent->__protoFlags;
1632  proto->__protoFlags = ciflag_set(proto->__protoFlags,0,0); //((char*)(&proto->__protoFlags))[0] = 0; //shallow instancing of protoInstances inside a protoDeclare
1634  proto->__protoFlags = ciflag_set(proto->__protoFlags,0,2); //((char*)(&proto->__protoFlags))[2] = 0; //this is a protoDeclare we are parsing
1635  proto->__protoFlags = ciflag_set(proto->__protoFlags,0,3); //((char*)(&proto->__protoFlags))[3] = 0; //not an externProtoDeclare
1636  //set ProtoDefinition *obj
1637  proto->__protoDef = obj;
1638  proto->__prototype = X3D_NODE(proto); //point to self, so shallow and deep instances will inherit this value
1639  proto->__typename = STRDUP(obj->protoName);
1640  if(containerfield){
1641  int builtinField = findFieldInFIELDNAMES(containerfield);
1642  if(builtinField > -1){
1643  proto->_defaultContainer = builtinField;
1644  }
1645  }
1646 
1647  pushMode(ud,PARSING_PROTODECLARE);
1648  pushNode(ud,X3D_NODE(proto));
1649  pushField(ud,"__children");
1650 }
1651 
1652 static void parseProtoBody_B (void *ud, char **atts) {
1653  //push proto node on context stack
1654  pushContext(ud,getNode(ud,TOP));
1655  pushMode(ud,PARSING_PROTOBODY);
1656 }
1657 
1658 struct X3D_Proto *brotoInstance(struct X3D_Proto* proto, BOOL ideep);
1659 void add_node_to_broto_context(struct X3D_Proto *context,struct X3D_Node *node);
1660 void linkNodeIn_B(void *ud);
1661 struct X3D_Node *broto_search_DEFname(struct X3D_Proto *context, const char *name);
1662 
1663 static void parseProtoInstance_B(void *ud, char **atts) {
1664  /*broto version
1665  1. lookup the user (proto) type in current and parent context protoDeclare and externProtoDeclare tables
1666  2. brotoInstance()
1667  3. parse att and any <fieldValue> and IS
1668  4. on end, deep_copy_broto_body2 applying the initial field values parsed.
1669  */
1670  int i, isUSE;
1671  int nameIndex;
1672  //int containerIndex;
1673  //int containerField;
1674  int defNameIndex;
1675  //int protoTableIndex;
1676  char *protoname;
1677  struct X3D_Proto *currentContext;
1678  struct X3D_Node *node = NULL;
1679  char pflagdepth;
1680  struct X3D_Node *fromDEFtable;
1681 
1682 
1683  /* initialization */
1684  nameIndex = INT_ID_UNDEFINED;
1685  //containerIndex = INT_ID_UNDEFINED;
1686  //containerField = INT_ID_UNDEFINED;
1687  defNameIndex = INT_ID_UNDEFINED;
1688  //protoTableIndex = 0;
1689  if(0) printf("parseProtoInstance\n");
1690  isUSE = FALSE;
1691  for (i = 0; atts[i]; i += 2) {
1692  if (strcmp("name",atts[i]) == 0) {
1693  nameIndex=i+1;
1694  } else if (strcmp("containerField",atts[i]) == 0) {
1695  //containerIndex = i+1;
1696  } else if (strcmp("DEF",atts[i]) == 0) {
1697  defNameIndex = i+1;
1698  } else if (strcmp("class",atts[i]) == 0) {
1699  ConsoleMessage ("field \"class\" not currently used in a ProtoInstance parse... sorry");
1700  } else if (strcmp("USE",atts[i]) == 0) {
1701  //ConsoleMessage ("field \"USE\" not currently used in a ProtoInstance parse.. sorry");
1702  isUSE = TRUE;
1703  defNameIndex = i+1;
1704  }
1705  }
1706 
1707  currentContext = getContext(ud,TOP);
1708 
1709  pflagdepth = ciflag_get(currentContext->__protoFlags,0); //depth 0 we are deep inside protodeclare, depth 1 we are instancing live scenery
1710 
1711  /* did we find the name? */
1712  protoname = NULL;
1713  if (nameIndex != INT_ID_UNDEFINED) {
1714  protoname = atts[nameIndex];
1715  } else {
1716  ConsoleMessage ("\"ProtoInstance\" found, but field \"name\" not found!\n");
1717  }
1718 
1719 
1720  if(protoname){
1721  if(isUSE){
1722  //ConsoleMessage ("field \"USE\" not currently used in a ProtoInstance parse.. sorry");
1723  char * defname = atts[defNameIndex]; //gets STRDUP();'d inside broto_store_DEF
1724 
1725  fromDEFtable = broto_search_DEFname(currentContext,defname);
1726  if (!fromDEFtable) {
1727  ConsoleMessage ("Warning - line %d DEF name: \'%s\' not found",LINE,atts[i+1]);
1728  ConsoleMessage("\n");
1729  } else {
1730  #ifdef X3DPARSERVERBOSE
1731  printf ("copying for field %s defName %s\n",atts[i], atts[i+1]);
1732  #endif
1733 
1734  /* if (fromDEFtable->_nodeType != fromDEFtable->_nodeType) { */
1735  if (NODE_Proto != fromDEFtable->_nodeType) {
1736  ConsoleMessage ("Warning, line %d DEF/USE mismatch, '%s', %s != %s", LINE,
1737  atts[i+1],stringNodeType(fromDEFtable->_nodeType), stringNodeType (NODE_Proto));
1738  } else {
1739  /* Q. should thisNode.referenceCount be decremented or ??? */
1740  char* containerfield;
1741  node = fromDEFtable;
1742  node->referenceCount++; //dug9 added but should???
1743  //getNode(ud,TOP) = thisNode;
1744  #ifdef X3DPARSERVERBOSE
1745  printf ("successful copying for field %s defName %s\n",atts[i], atts[i+1]);
1746  #endif
1747  pushNode(ud,node);
1748  containerfield = NULL;
1749  for (i = 0; atts[i]; i += 2) {
1750  if(!strcmp(atts[i],"containerField")) containerfield = atts[i+1];
1751  }
1752  if(containerfield) {
1753  int builtinField = findFieldInFIELDNAMES(containerfield);
1754  if(builtinField > INT_ID_UNDEFINED){
1755  node->_defaultContainer = builtinField;
1756  }
1757  }
1758  pushField(ud,NULL); //no particular default field
1759  pushMode(ud,PARSING_PROTOINSTANCE_USE);
1760  return;
1761  }
1762  }
1763  }else{
1764  struct X3D_Proto *proto;
1765  if( isAvailableBroto(protoname, currentContext , &proto))
1766  {
1767  //struct X3D_Node *parent;
1768  char* containerfield;
1769  /* its a binary proto, new in 2013 */
1770  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
1771  idepth = pflagdepth == 1; //2014 broto2: if we're parsing a scene (or Inline) then deepcopy proto to instance it, else shallow
1772  node=X3D_NODE(brotoInstance(proto,idepth));
1773  node->_executionContext = X3D_NODE(proto);
1774  if (defNameIndex != INT_ID_UNDEFINED){
1775  char * defname = atts[defNameIndex]; //gets STRDUP();'d inside broto_store_DEF
1776  broto_store_DEF(currentContext,node, defname);
1777  }
1778  add_node_to_broto_context(currentContext,node);
1779 
1780  pushNode(ud,node);
1781  containerfield = NULL;
1782  for (i = 0; atts[i]; i += 2) {
1783  if(!strcmp(atts[i],"containerField")) containerfield = atts[i+1];
1784  }
1785  if(containerfield) {
1786  int builtinField = findFieldInFIELDNAMES(containerfield);
1787  if(builtinField > INT_ID_UNDEFINED){
1788  node->_defaultContainer = builtinField;
1789  }
1790  }
1791  //linkNodeIn_B(ud);
1792  //parseAttributes_B(ud,atts); //PI uses FieldValue
1793  }else{
1794  pushNode(ud,NULL);
1795  ConsoleMessage ("Attempt to instance undefined prototype typename %s\n",protoname);
1796  }
1797  }
1798  }
1799  pushField(ud,NULL); //no particular default field
1800  pushMode(ud,PARSING_PROTOINSTANCE);
1801 
1802 }
1803 
1804 BOOL nodeTypeSupportsUserFields(struct X3D_Node *node);
1805 int getFieldFromNodeAndName(struct X3D_Node* node,const char *fieldname, int *type, int *kind, int *iifield, union anyVrml **value);
1806 void broto_store_IS(struct X3D_Proto *proto,char *protofieldname,int pmode, int iprotofield, int type,
1807  struct X3D_Node *node, char* nodefieldname, int mode, int ifield, int source);
1808 
1809 static void parseConnect_B(void *ud, char **atts) {
1810  int i,okp, okn;
1811  struct X3D_Node *node;
1812  struct X3D_Proto *context, *proto;
1813  char *nodefield, *protofield;
1814  node = getNode(ud,TOP);
1815  proto = context = getContext(ud,TOP);
1816 
1817  nodefield = protofield = NULL;
1818  for(i=0;atts[i];i+=2){
1819  if(!strcmp(atts[i],"nodeField")) nodefield = atts[i+1];
1820  if(!strcmp(atts[i],"protoField")) protofield = atts[i+1];
1821  }
1822  okp = okn = 0;
1823  if(nodefield && protofield){
1824  int ptype, pkind, pifield, ntype, nkind, nifield;
1825  union anyVrml *pvalue, *nvalue;
1826  okp = getFieldFromNodeAndName(X3D_NODE(proto),protofield,&ptype, &pkind, &pifield, &pvalue);
1827  okn = getFieldFromNodeAndName(node, nodefield,&ntype, &nkind, &nifield, &nvalue);
1828  //check its mode
1829  // http://www.web3d.org/files/specifications/19775-1/V3.2/Part01/concepts.html#t-RulesmappingPROTOTYPEdecl
1830  // there's what I call a mode-jive table
1831  // proto interface
1832  // inputOutput initializeOnly inputOnly outputOnly
1833  // node inputOutput jives jives jives jives
1834  // initializeOnly jives
1835  // inputOnly jives
1836  // outputOnly jives
1837  //
1838  // so if our nodefield's mode is inputOutput/exposedField then we are covered for all protoField modes
1839  // otherwise, the nodefield's mode must be the same as the protofield's mode
1840  if(okp && okn)
1841  if(ntype != ptype){
1842  ConsoleMessage("Parser error: IS - we have a name match: %s IS %s found protofield %s\n",
1843  nodefield,protofield,protofield);
1844  ConsoleMessage("...But the types don't match: nodefield %s protofield %s\n",
1845  FIELDTYPES[ntype],FIELDTYPES[ptype]);
1846  okp = 0;
1847  }
1848  if(okp && okn)
1849  if(nkind != PKW_inputOutput && nkind != pkind){
1850  if(pkind != PKW_inputOutput){
1851  ConsoleMessage("Parser Error: IS - we have a name match: %s IS %s found protofield %s\n",
1852  nodefield,protofield,protofield);
1853  ConsoleMessage("...But the modes don't jive: nodefield %s protofield %s\n",
1854  PROTOKEYWORDS[nkind],PROTOKEYWORDS[pkind]);
1855  okp = 0;
1856  }else{
1857  ConsoleMessage("Parser Warning: IS - we have a name match: %s IS %s found protofield %s\n",
1858  nodefield,protofield,protofield);
1859  ConsoleMessage("...But the modes don't jive: nodefield %s protofield %s\n",
1860  PROTOKEYWORDS[nkind],PROTOKEYWORDS[pkind]);
1861  ConsoleMessage("...will thunk\n");
1862  }
1863  }
1864  if(okp && okn){
1865  int source;
1866  //we have an IS that's compatible/jives
1867  //a) copy the value if it's an initializeOnly or inputOutput
1868  if(pkind == PKW_initializeOnly || pkind == PKW_inputOutput)
1869  {
1870  shallow_copy_field(ntype, pvalue , nvalue);
1871  }
1872  //b) register it in the IS-table for our context
1873  source = node->_nodeType == NODE_Proto ? 3 : node->_nodeType == NODE_Script ? 1 : nodeTypeSupportsUserFields(node) ? 2 : 0;
1874  //Q. do I need to convert builtin from field index to offset? if( source == 0) nifield *=5;
1875  broto_store_IS(context,protofield,pkind,pifield,ptype,
1876  node,nodefield,nkind,nifield,source);
1877  }
1878  }
1879 }
1880 
1881 static void XMLCALL X3DstartElement(void *ud, const xmlChar *iname, const xmlChar **atts) {
1882  int myNodeIndex;
1883  char **myAtts;
1884  int i;
1885  char *blankAtts[] = {NULL,NULL};
1886  const char *name = (const char*) iname; // get around compiler warnings on iPhone, etc...
1887 
1888  /* libxml passes NULL, while expat passes {0,0}. Make them the same */
1889  if (atts == NULL) myAtts = blankAtts;
1890  else myAtts = (char **) atts;
1891 
1892  #ifdef X3DPARSERVERBOSE
1893  //printf ("startElement: %s : level %d parserMode: %s \n",name,parentIndex,parserModeStrings[getMode(ud,TOP)]);
1894  printf ("X3DstartElement: %s: atts %p\n",name,atts);
1895  //printf ("startElement, myAtts :%p contents %p\n",myAtts,myAtts[0]);
1896  { int i;
1897  for (i = 0; myAtts[i]; i += 2) {
1898  printf(" X3DStartElement field:%s=%s\n", myAtts[i], atts[i + 1]);
1899  }}
1900 
1901  //printf ("X3DstartElement - finished looking at myAtts\n\n");
1902  #endif
1903 
1904  if(atts)
1905  for (i = 0; atts[i]; i += 2) {
1906  atts[i+1] = fixAmp(atts[i+1]);
1907  }
1908 
1909 
1910  myNodeIndex = findFieldInNODES(name);
1911 
1912  /* is this a "normal" node that can be found in x3d, x3dv and wrl files? */
1913  if (myNodeIndex != INT_ID_UNDEFINED) {
1914  startBuiltin_B(ud,myNodeIndex,(const xmlChar *)name,myAtts);
1915  return;
1916  }
1917  /*in theory, you could search broto prototype typenames here, and if found
1918  assume it's instanced with builtin syntax (instead of ProtoInstance syntax)
1919  if( isAvailableBroto(name, getContext(ud,TOP) , &proto))
1920  */
1921 
1922  /* no, it is not. Lets see what else it could be... */
1923  myNodeIndex = findFieldInX3DSPECIAL(name);
1924  if (myNodeIndex != INT_ID_UNDEFINED) {
1925  switch (myNodeIndex) {
1926  case X3DSP_ProtoDeclare:
1927  parseProtoDeclare_B(ud,myAtts);
1928  break;
1929  case X3DSP_ExternProtoDeclare:
1930  parseExternProtoDeclare_B(ud,myAtts);
1931  break;
1932  case X3DSP_ProtoBody:
1933  parseProtoBody_B(ud,myAtts);
1934  break;
1935  case X3DSP_ProtoInterface:
1936  parseProtoInterface(ud,myAtts);
1937  break;
1938  case X3DSP_ProtoInstance:
1939  parseProtoInstance_B(ud,myAtts);
1940  break;
1941  case X3DSP_ROUTE:
1942  parseRoutes_B(ud,myAtts);
1943  break;
1944  case X3DSP_meta: parseMeta(myAtts); break;
1945  case X3DSP_Scene: parseScene(myAtts); break;
1946  case X3DSP_head:
1947  case X3DSP_Header: parseHeader(myAtts); break;
1948  case X3DSP_X3D: parseX3Dhead(myAtts); break;
1949  case X3DSP_fieldValue:
1950  parseFieldValue_B(ud,myAtts);
1951  break;
1952  case X3DSP_field:
1953  parseScriptProtoField_B (ud, myAtts);
1954  break;
1955  case X3DSP_IS: parseIS(ud); break;
1956  case X3DSP_component: parseComponent(myAtts); break;
1957  case X3DSP_EXPORT:
1958  parseExport_B(ud,myAtts);
1959  break;
1960  case X3DSP_IMPORT:
1961  parseImport_B(ud,myAtts);
1962  break;
1963  case X3DSP_connect:
1964  parseConnect_B(ud,myAtts);
1965  break;
1966 
1967  default: printf (" huh? startElement, X3DSPECIAL, but not handled?? %d, :%s:\n",myNodeIndex,X3DSPECIAL[myNodeIndex]);
1968  }
1969  return;
1970  }
1971 
1972  printf ("startElement name do not currently handle this one :%s: index %d\n",name,myNodeIndex);
1973 }
1974 
1975 static void endScriptProtoField_B(void *ud) {
1976  if(0) printf("end scriptprotofield\n");
1977  popField(ud);
1978  popMode(ud); //PARSING_FIELD);
1979 }
1980 
1981 
1982 static void XMLCALL X3DendElement(void *ud, const xmlChar *iname) {
1983  int myNodeIndex;
1984  const char*name = (const char*) iname;
1985  //ttglobal tg = gglobal();
1986  //ppX3DParser p = (ppX3DParser)tg->X3DParser.prv;
1987 
1988  /* printf ("X3DEndElement for %s\n",name); */
1989 
1990  #ifdef X3DPARSERVERBOSE
1991  printf ("endElement: %s : parentIndex %d mode %s\n",name,parentIndex,parserModeStrings[getMode(ud,TOP)]);
1992  #endif
1993 
1994 
1995 
1996  myNodeIndex = findFieldInNODES(name);
1997  if (myNodeIndex != INT_ID_UNDEFINED) {
1998  endBuiltin_B(ud,iname);
1999  return;
2000 
2001  }
2002 
2003 
2004 
2005  /* no, it is not. Lets see what else it could be... */
2006  myNodeIndex = findFieldInX3DSPECIAL(name);
2007  if (myNodeIndex != INT_ID_UNDEFINED) {
2008  switch (myNodeIndex) {
2009  case X3DSP_ProtoInstance:
2010  endProtoInstance_B(ud,name);
2011  break;
2012  case X3DSP_ProtoInterface:
2013  endProtoInterfaceTag(ud);
2014  break;
2015  case X3DSP_ProtoBody:
2016  endProtoBodyTag_B(ud,name);
2017  break;
2018  case X3DSP_ProtoDeclare:
2019  endProtoDeclareTag_B(ud);
2020  break;
2021  case X3DSP_ExternProtoDeclare:
2022  endExternProtoDeclareTag_B(ud);
2023  break;
2024  case X3DSP_IS:
2025  endIS(ud);
2026  break;
2027  case X3DSP_connect:
2028  case X3DSP_ROUTE:
2029  case X3DSP_meta:
2030  case X3DSP_Scene:
2031  case X3DSP_head:
2032  case X3DSP_Header:
2033  case X3DSP_component:
2034  case X3DSP_EXPORT:
2035  case X3DSP_IMPORT:
2036  case X3DSP_X3D: break;
2037  case X3DSP_field:
2038  endScriptProtoField_B(ud);
2039  break;
2040  case X3DSP_fieldValue:
2041  endFieldValue_B(ud);
2042  break;
2043 
2044  /* should never do this: */
2045  default:
2046  printf ("endElement: huh? X3DSPECIAL, but not handled?? %s\n",X3DSPECIAL[myNodeIndex]);
2047  }
2048  return;
2049  }
2050 
2051  printf ("unhandled endElement name %s index %d\n",name,myNodeIndex);
2052  #ifdef X3DPARSERVERBOSE
2053  printf ("endElement %s\n",name);
2054  #endif
2055 }
2056 
2057 static XML_Parser initializeX3DParser () {
2058  ppX3DParser p = (ppX3DParser)gglobal()->X3DParser.prv;
2059  p->X3DParserRecurseLevel++;
2060 
2061  if (p->X3DParserRecurseLevel >= PROTOINSTANCE_MAX_LEVELS) {
2062  ConsoleMessage ("XML_PARSER init: XML file PROTO nested too deep\n");
2063  p->X3DParserRecurseLevel--;
2064  } else {
2065  XML_CreateParserLevel(p->x3dparser[p->X3DParserRecurseLevel]);
2066  XML_SetElementHandler(p->x3dparser[p->X3DParserRecurseLevel], X3DstartElement, X3DendElement);
2067  XML_SetCdataSectionHandler (p->x3dparser[p->X3DParserRecurseLevel], startCDATA, endCDATA);
2068  XML_SetDefaultHandler (p->x3dparser[p->X3DParserRecurseLevel],handleCDATA);
2069  XML_SetUserData(p->x3dparser[p->X3DParserRecurseLevel], &parentIndex);
2070  }
2071  /* printf ("initializeX3DParser, level %d, parser %u\n",x3dparser[X3DParserRecurseLevel]); */
2072  return p->x3dparser[p->X3DParserRecurseLevel];
2073 }
2074 
2075 static void shutdownX3DParser (void *ud) {
2076  ttglobal tg = gglobal();
2077  ppX3DParser p = (ppX3DParser)tg->X3DParser.prv;
2078 
2079  /* printf ("shutdownX3DParser, recurseLevel %d\n",X3DParserRecurseLevel); */
2080  XML_ParserFree(p->x3dparser[p->X3DParserRecurseLevel]);
2081  p->X3DParserRecurseLevel--;
2082 
2083  /* lets free up memory here for possible PROTO variables */
2084  if (p->X3DParserRecurseLevel == INT_ID_UNDEFINED) {
2085  /* if we are at the bottom of the parser call nesting, lets reset parentIndex */
2086  gglobal()->X3DParser.parentIndex = 0; //setParentIndex( 0 );
2087  //freeProtoMemory ();
2088  }
2089 
2090  if (p->X3DParserRecurseLevel < INT_ID_UNDEFINED) {
2091  ConsoleMessage ("XML_PARSER close underflow");
2092  p->X3DParserRecurseLevel = INT_ID_UNDEFINED;
2093  }
2094 
2095  /* CDATA text space, free it up */
2096  FREE_IF_NZ(tg->X3DParser.CDATA_Text);
2097  p->CDATA_TextMallocSize = 0;
2098  if (p->X3DParserRecurseLevel > INT_ID_UNDEFINED)
2099  p->currentX3DParser = p->x3dparser[p->X3DParserRecurseLevel];
2100  /* printf ("shutdownX3DParser, current X3DParser %u\n",currentX3DParser); */
2101  popMode(ud);
2102 
2103  if(p->DEFedNodes){
2104  int i;
2105  for(i=0;i<vectorSize(p->DEFedNodes);i++){
2106  struct Vector* vd = vector_get(struct Vector*,p->DEFedNodes,i);
2107  deleteVector(struct X3D_Node*,vd);
2108  }
2109  deleteVector(struct Vector*, p->DEFedNodes);
2110  }
2111 
2112  /*
2113  * Cleanup function for the XML library.
2114  */
2115  xmlCleanupParser();
2116  /*
2117  * this is to debug memory for regression tests
2118  */
2119  xmlMemoryDump();
2120 }
2121 
2122 int X3DParse (struct X3D_Node* ectx, struct X3D_Node* myParent, const char *inputstring) {
2123  ttglobal tg = gglobal();
2124  ppX3DParser p = (ppX3DParser)tg->X3DParser.prv;
2125  p->currentX3DParser = initializeX3DParser();
2126 
2127  //printf ("X3DParse, current X3DParser is %p, p is %p\n",p->currentX3DParser,p);
2128 
2129 
2130  DEBUG_X3DPARSER ("X3DPARSE on :\n%s:\n",inputstring);
2131  if(p->user_data == NULL){
2132  //just once. We are re-entrant when parsing text protos (trotos)
2133  // and want to keep the stack for the parent scene
2134  p->user_data = new_xml_user_data();
2135  }
2136  pushContext(p->user_data,ectx);
2137  if(myParent->_nodeType == NODE_Proto )
2138  pushField(p->user_data,"__children");
2139  else
2140  pushField(p->user_data,"children");
2141  pushNode(p->user_data,myParent);
2142  pushMode(p->user_data,PARSING_NODES);
2143 
2144  if (XML_ParseFile(p->currentX3DParser, p->user_data, inputstring, (int) strlen(inputstring), TRUE) == XML_STATUS_ERROR) {
2145  // http://xmlsoft.org/html/libxml-xmlerror.html
2146  xmlErrorPtr xe = xmlGetLastError();
2147  ConsoleMessage("Xml Error %s \n",xe->message);
2148  ConsoleMessage("Line %d\n",xe->line);
2149  /*
2150  fprintf(stderr,
2151  "%s at line %d\n",
2152  XML_ErrorString(XML_GetErrorCode(currentX3DParser)),
2153  XML_GetCurrentLineNumber(currentX3DParser));
2154  */
2155  popField(p->user_data);
2156  shutdownX3DParser(p->user_data);
2157  Parser_deleteParserForScanStringValueToMem();
2158  return FALSE;
2159  }
2160  popField(p->user_data);
2161  shutdownX3DParser(p->user_data);
2162  Parser_deleteParserForScanStringValueToMem();
2163  return TRUE;
2164 }
Definition: Vector.h:36