#include "X3D_libXMLLoader.h" #include "libXMLFileElement.h" #include "X3D_Creator.h" #include "X3DAbstractNode.h" #include "X3D_Scene.h" #include #include using namespace std; namespace X3DTK { namespace X3D { typedef struct _X3DParseState X3DParseState; struct _X3DParseState { MFNode _nodeStack; X3DAbstractNode *_root; Creator *_creator; map _nameNodeMap; unsigned int _depth; bool _header; ProcessHistory _history; MFRoute _routes; }; static void x3d_parser_start_document(X3DParseState *state) { state->_root = 0; state->_depth = 0; state->_nodeStack.push_back(0); state->_header = false; state->_history.getProcessMap().clear(); state->_routes.clear(); } static void x3d_parser_end_document(X3DParseState *state) { state->_nodeStack.clear(); state->_nameNodeMap.clear(); } static void x3d_parser_start_element(X3DParseState *state, const xmlChar *name, const xmlChar **attrs) { if (SFString(name) == SFString("X3D")) return; //////////////////////////// header //////////////////////////////////////////////// if (SFString(name) == SFString("head")) { state->_header = true; return; } if (state->_header) { if (SFString(name) == SFString("meta")) { libXMLFileElement e(name, attrs); int index, indexDate; index = e.getIndexAttribute("content"); indexDate = e.getIndexAttribute("date"); if (index != -1) { if (indexDate != -1) state->_history.addEntry(e.getAttribute(index), ProcessHistory::loadTime(e.getAttribute(indexDate))); } } return; } //////////////////////////// Route ///////////////////////////////////////////////// if (SFString(name) == SFString("ROUTE")) { int index; X3DAbstractNode *fromNode = 0; X3DAbstractNode *toNode = 0; SFString fromField, toField; libXMLFileElement e(name, attrs); index = e.getIndexAttribute("fromNode"); if (index != -1) { map::const_iterator it = state->_nameNodeMap.find(e.getAttribute(index)); if (it != state->_nameNodeMap.end()) fromNode = (*it).second; else fromNode = 0; } index = e.getIndexAttribute("toNode"); if (index != -1) { map::const_iterator it = state->_nameNodeMap.find(e.getAttribute(index)); if (it != state->_nameNodeMap.end()) toNode = (*it).second; else toNode = 0; } index = e.getIndexAttribute("fromField"); if (index != -1) fromField = e.getAttribute(index); index = e.getIndexAttribute("toField"); if (index != -1) toField = e.getAttribute(index); X3DRoute *r = X3DRoute::create(fromNode, fromField, toNode, toField); if (r != 0) state->_routes.push_back(r); return; } //////////////////////////// Scene ///////////////////////////////////////////////// if (state->_depth == 0) { libXMLFileElement e(name, attrs); int index; SFNode Father = state->_nodeStack.back(); SFNode N; index = e.getIndexAttribute("USE"); if (index != -1) { map::const_iterator it = state->_nameNodeMap.find(e.getAttribute(index)); if (it != state->_nameNodeMap.end()) N = (*it).second; else N = 0; } else { X3D::X3DNode *cN = state->_creator->createFromName(e.getName()); if (cN == 0) { state->_depth = 1; return; } cN->loadAttributes(&e); N = cN; } index = e.getIndexAttribute("DEF"); if (index != -1) { N->setName(e.getAttribute(index)); state->_nameNodeMap[e.getAttribute(index)] = N; } if (Father != 0) Father->setChild(N); else state->_root = N; state->_nodeStack.push_back(N); } else ++state->_depth; } static void x3d_parser_end_element(X3DParseState *state, const xmlChar *name) { if (SFString(name) == SFString("head")) { state->_header = false; return; } if (state->_header) return; if ((state->_depth == 0) && (state->_nodeStack.size() > 0)) state->_nodeStack.pop_back(); else --state->_depth; } static void x3d_parser_error(X3DParseState *state, const char *msg, ...) { cx3d << "libXMLLoader::error: " << msg << endl; } static void x3d_parser_fatal_error(X3DParseState *state, const char *msg, ...) { cx3d << "libXMLLoader::fatalError: " << msg << endl; } static xmlSAXHandler x3d_parser = { 0, /* internalSubset */ 0, /* isStandalone */ 0, /* hasInternalSubset */ 0, /* hasExternalSubset */ 0, /* resolveEntity */ 0, /* getEntity */ 0, /* entityDecl */ 0, /* notationDecl */ 0, /* attributeDecl */ 0, /* elementDecl */ 0, /* unparsedEntityDecl */ 0, /* setDocumentLocator */ (startDocumentSAXFunc)x3d_parser_start_document, /* startDocument */ (endDocumentSAXFunc)x3d_parser_end_document, /* endDocument */ (startElementSAXFunc)x3d_parser_start_element, /* startElement */ (endElementSAXFunc)x3d_parser_end_element, /* endElement */ 0, /* reference */ 0, /* characters */ 0, /* ignorableWhitespace */ 0, /* processingInstruction */ 0, /* comment */ 0, /* warning */ (errorSAXFunc)x3d_parser_error, /* error */ (fatalErrorSAXFunc)x3d_parser_fatal_error, /* fatalError */ }; libXMLLoader::libXMLLoader(Creator *creator) : X3DXmlLoader(creator) { } libXMLLoader::~libXMLLoader() { } X3D::Scene *libXMLLoader::load(const char *file, bool) const { SFString sfile(file); // Goes to the directory of the file. char *cwd = (char *)malloc(65535); char *value = getcwd(cwd, 65535); if (value == 0) { cx3d << "libXMLLoader::load: unable to get current working directory!" << endl; return 0; } if (chdir(sfile.getPath()) != 0) { cx3d << "libXMLLoader::load: unable to set the current working directory to " << sfile.getPath() << "!" << endl; return 0; } X3DParseState state; state._creator = creator; if (xmlSAXUserParseFile(&x3d_parser, &state, file) < 0) { cx3d << "libXMLLoader::load: unable to load the file" << endl; return 0; } // Goes back to the initial directory. if (chdir(cwd) != 0) { cx3d << "libXMLLoader::load: unable to set the current working directory to !" << cwd << endl; return 0; } free(cwd); X3D::Scene *scene = dynamic_cast(state._root); if (scene != 0) { scene->setFileName(file); ProcessHistory::loadScene(scene, state._history); X3DRoute::loadScene(scene, state._routes); } return scene; } } }