#include "X3D_XercesLoader.h" #include "XercesFileElement.h" #include "X3D_Creator.h" #include "X3DAbstractNode.h" #include "X3D_Scene.h" #include #include #include #include #include using namespace std; XERCES_CPP_NAMESPACE_USE namespace X3DTK { namespace X3D { class SAX2X3DHandler : public DefaultHandler { public: SAX2X3DHandler(Creator *creator); ~SAX2X3DHandler(); void startDocument(); void startElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname, const XERCES_CPP_NAMESPACE_QUALIFIER Attributes &attrs); void endElement(const XMLCh *const uri, const XMLCh *const localname, const XMLCh *const qname); void endDocument(); void fatalError(const XERCES_CPP_NAMESPACE_QUALIFIER SAXParseException& exception); void error(const XERCES_CPP_NAMESPACE_QUALIFIER SAXParseException& exception); inline X3DAbstractNode *getRoot() const {return _root;}; inline const ProcessHistory &getHistory() const {return _history;}; inline const MFRoute &getRoutes() const {return _routes;}; private: MFNode _nodeStack; X3DAbstractNode *_root; Creator *_creator; map _nameNodeMap; unsigned int _depth; bool _header; ProcessHistory _history; MFRoute _routes; }; SAX2X3DHandler::SAX2X3DHandler(Creator *creator) : _root(0), _creator(creator), _depth(0), _header(false) { } SAX2X3DHandler::~SAX2X3DHandler() { } void SAX2X3DHandler::startDocument() { _root = 0; _depth = 0; _header = false; _nodeStack.push_back(0); _history.getProcessMap().clear(); _routes.clear(); } void SAX2X3DHandler::startElement(const XMLCh* const, const XMLCh* const, const XMLCh* const qname, const Attributes &attrs) { //_depth == 0, meaning that all the fathers of the node are defined nodes(have a Creation Function) //This variable is used to jump a sub-tree of the graph scene, when an unknown node is met. if (SFString(XMLString::transcode(qname)) == SFString("X3D")) return; //////////////////////////// header //////////////////////////////////////////////// if (SFString(XMLString::transcode(qname)) == SFString("head")) { _header = true; return; } if (_header) { if (SFString(XMLString::transcode(qname)) == SFString("meta")) { XercesFileElement e(XMLString::transcode(qname), &attrs); int index, indexDate; index = e.getIndexAttribute("content"); indexDate = e.getIndexAttribute("date"); if (index != -1) { if (indexDate != -1) _history.addEntry(e.getAttribute(index), ProcessHistory::loadTime(e.getAttribute(indexDate))); } } return; } //////////////////////////// Route ///////////////////////////////////////////////// if (SFString(XMLString::transcode(qname)) == SFString("ROUTE")) { int index; X3DAbstractNode *fromNode = 0; X3DAbstractNode *toNode = 0; SFString fromField, toField; XercesFileElement e(XMLString::transcode(qname), &attrs); index = e.getIndexAttribute("fromNode"); if (index != -1) { map::const_iterator it = _nameNodeMap.find(e.getAttribute(index)); if (it != _nameNodeMap.end()) fromNode = (*it).second; else fromNode = 0; } index = e.getIndexAttribute("toNode"); if (index != -1) { map::const_iterator it = _nameNodeMap.find(e.getAttribute(index)); if (it != _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) _routes.push_back(r); return; } //////////////////////////// Scene ///////////////////////////////////////////////// if (_depth == 0) { XercesFileElement e(XMLString::transcode(qname), &attrs); int index; SFNode Father = _nodeStack.back(); SFNode N; index = e.getIndexAttribute("USE"); if (index != -1) { map::const_iterator it = _nameNodeMap.find(e.getAttribute(index)); if (it != _nameNodeMap.end()) N = (*it).second; else N = 0; } else { X3D::X3DNode *cN = _creator->createFromName(e.getName()); if (cN == 0) { _depth = 1; return; } cN->loadAttributes(&e); N = cN; } index = e.getIndexAttribute("DEF"); if (index != -1) { N->setName(e.getAttribute(index)); _nameNodeMap[e.getAttribute(index)] = N; } if (Father != 0) Father->setChild(N); else _root = N; _nodeStack.push_back(N); } else ++_depth; } void SAX2X3DHandler::endElement(const XMLCh *const, const XMLCh *const, const XMLCh *const qname) { if (SFString(XMLString::transcode(qname)) == SFString("head")) { _header = false; return; } if (_header) return; if ((_depth == 0) && (_nodeStack.size() > 0)) _nodeStack.pop_back(); else --_depth; } void SAX2X3DHandler::endDocument() { _nodeStack.clear(); _nameNodeMap.clear(); } void SAX2X3DHandler::error(const SAXParseException& exception) { char* message = XMLString::transcode(exception.getMessage()); cx3d << "XercesLoader::error: " << message << " at line: " << exception.getLineNumber() << endl; } void SAX2X3DHandler::fatalError(const SAXParseException& exception) { char* message = XMLString::transcode(exception.getMessage()); cx3d << "XercesLoader::fatalError: " << message << " at line: " << exception.getLineNumber() << endl; } class XercesLoaderImplementation { public: XercesLoaderImplementation(){}; XERCES_CPP_NAMESPACE_QUALIFIER SAX2XMLReader* _parser; SAX2X3DHandler *_handler; }; XercesLoader::XercesLoader(Creator *creator) : X3DXmlLoader(creator), _impl(new XercesLoaderImplementation()) { try { XMLPlatformUtils::Initialize(); } catch (const XMLException& toCatch) { char* message = XMLString::transcode(toCatch.getMessage()); cx3d << "XercesLoader::Error during initialization: " << message << endl; XMLString::release(&message); } _impl->_parser = XMLReaderFactory::createXMLReader(); _impl->_parser->setFeature(XMLUni::fgSAX2CoreNameSpaces, true); _impl->_parser->setFeature(XMLUni::fgXercesSchemaFullChecking, false); _impl->_parser->setFeature(XMLUni::fgSAX2CoreNameSpacePrefixes, false); _impl->_handler = new SAX2X3DHandler(creator); _impl->_parser->setContentHandler(_impl->_handler); _impl->_parser->setErrorHandler(_impl->_handler); _impl->_parser->setDTDHandler(_impl->_handler); } XercesLoader::~XercesLoader() { delete _impl->_parser; delete _impl->_handler; } X3D::Scene *XercesLoader::load(const char *file, bool fileValidation) const { SFString sfile(file); if (fileValidation) { _impl->_parser->setFeature(XMLUni::fgXercesLoadExternalDTD, true); _impl->_parser->setFeature(XMLUni::fgXercesSchema, true); _impl->_parser->setFeature(XMLUni::fgSAX2CoreValidation, true); } else { _impl->_parser->setFeature(XMLUni::fgXercesLoadExternalDTD, false); _impl->_parser->setFeature(XMLUni::fgXercesSchema, false); _impl->_parser->setFeature(XMLUni::fgSAX2CoreValidation, false); } // Goes to the directory of the file. char *cwd = (char *)malloc(65535); char *value = getcwd(cwd, 65535); if (value == 0) { cx3d << "XercesLoader::load: unable to get current working directory!" << endl; return 0; } if (chdir(sfile.getPath()) != 0) { cx3d << "XercesLoader::load: unable to set the current working directory to " << sfile.getPath() << "!" << endl; return 0; } try { _impl->_parser->parse(sfile.getFile()); } catch (...) { cx3d << "XercesLoader::load: unexpected Exception!" << endl; } // Goes back to the initial directory. if (chdir(cwd) != 0) { cx3d << "XercesLoader::load: unable to set the current working directory to !" << cwd << endl; return 0; } free(cwd); X3D::Scene *scene = dynamic_cast(_impl->_handler->getRoot()); if (scene != 0) { scene->setFileName(file); ProcessHistory::loadScene(scene, _impl->_handler->getHistory()); X3DRoute::loadScene(scene, _impl->_handler->getRoutes()); } return scene; } } }