Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

CEGUIXercesParser.cpp

Go to the documentation of this file.
00001 /************************************************************************
00002     filename:   CEGUIXercesParser.cpp
00003     created:    Sat Mar 12 2005
00004     author:     Paul D Turner
00005 *************************************************************************/
00006 /*************************************************************************
00007     Crazy Eddie's GUI System (http://www.cegui.org.uk)
00008     Copyright (C)2004 - 2005 Paul D Turner (paul@cegui.org.uk)
00009  
00010     This library is free software; you can redistribute it and/or
00011     modify it under the terms of the GNU Lesser General Public
00012     License as published by the Free Software Foundation; either
00013     version 2.1 of the License, or (at your option) any later version.
00014  
00015     This library is distributed in the hope that it will be useful,
00016     but WITHOUT ANY WARRANTY; without even the implied warranty of
00017     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018     Lesser General Public License for more details.
00019  
00020     You should have received a copy of the GNU Lesser General Public
00021     License along with this library; if not, write to the Free Software
00022     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023 *************************************************************************/
00024 #include "CEGUIXercesParser.h"
00025 #include "CEGUIString.h"
00026 #include "CEGUIExceptions.h"
00027 #include "CEGUILogger.h"
00028 #include "CEGUIResourceProvider.h"
00029 #include "CEGUISystem.h"
00030 #include "CEGUIXMLHandler.h"
00031 #include "CEGUIXMLAttributes.h"
00032 #include "CEGUIPropertyHelper.h"
00033 
00034 // Start of CEGUI namespace section
00035 namespace CEGUI
00036 {
00038     //
00039     // XercesParser methods
00040     //
00042 
00043     XercesParser::XercesParser(void)
00044     {
00045         // set ID string
00046         d_identifierString = "CEGUI::XercesParser - Official Xerces-C++ based parser module for CEGUI";
00047     }
00048 
00049     XercesParser::~XercesParser(void)
00050     {}
00051 
00052     void XercesParser::parseXMLFile(XMLHandler& handler, const String& filename, const String& schemaName, const String& resourceGroup)
00053     {
00054         XERCES_CPP_NAMESPACE_USE;
00055 
00056         XercesHandler xercesHandler(handler);
00057 
00058         // create parser
00059         SAX2XMLReader* reader = createReader(xercesHandler);
00060 
00061         try
00062         {
00063             // set up schema
00064             initialiseSchema(reader, schemaName, filename, resourceGroup);
00065             // do parse
00066             doParse(reader, filename, resourceGroup);
00067         }
00068         catch(const XMLException& exc)
00069         {
00070             if (exc.getCode() != XMLExcepts::NoError)
00071             {
00072                 delete reader;
00073 
00074                 char* excmsg = XMLString::transcode(exc.getMessage());
00075                 String message((utf8*)"XercesParser::parseXMLFile - An error occurred at line nr. " + PropertyHelper::uintToString((uint)exc.getSrcLine()) + " while parsing XML file '" + filename + "'.  Additional information: ");
00076                 message += excmsg;
00077                 XMLString::release(&excmsg);
00078 
00079                 throw FileIOException(message);
00080             }
00081 
00082         }
00083         catch(const SAXParseException& exc)
00084         {
00085             delete reader;
00086 
00087             char* excmsg = XMLString::transcode(exc.getMessage());
00088             String message((utf8*)"XercesParser::parseXMLFile - An error occurred at line nr. " + PropertyHelper::uintToString((uint)exc.getLineNumber()) + " while parsing XML file '" + filename + "'.  Additional information: ");
00089             message += excmsg;
00090             XMLString::release(&excmsg);
00091 
00092             throw FileIOException(message);
00093         }
00094         catch(...)
00095         {
00096             delete reader;
00097 
00098             Logger::getSingleton().logEvent("XercesParser::parseXMLFile - An unexpected error occurred while parsing XML file '" + filename + "'.", Errors);
00099             throw;
00100         }
00101 
00102         // cleanup
00103         delete reader;
00104     }
00105 
00106     bool XercesParser::initialiseImpl(void)
00107     {
00108         XERCES_CPP_NAMESPACE_USE;
00109 
00110         // initialise Xerces-C XML system
00111         try
00112         {
00113             XMLPlatformUtils::Initialize();
00114         }
00115         catch(XMLException& exc)
00116         {
00117             // prepare a message about the failure
00118             char* excmsg = XMLString::transcode(exc.getMessage());
00119             String message((utf8*)"An exception occurred while initialising the Xerces-C XML system.  Additional information: ");
00120             message += (utf8*)excmsg;
00121             XMLString::release(&excmsg);
00122 
00123             // throw a std::exception (because it won't try and use logger, which may not be available)
00124             throw message.c_str();
00125         }
00126 
00127         return true;
00128     }
00129 
00130     void XercesParser::cleanupImpl(void)
00131     {
00132         // cleanup XML stuff
00133         XERCES_CPP_NAMESPACE_USE;
00134         XMLPlatformUtils::Terminate();
00135     }
00136     
00137     void XercesParser::populateAttributesBlock(const XERCES_CPP_NAMESPACE::Attributes& src, XMLAttributes& dest)
00138     {
00139         String attributeName;
00140         String attributeValue;
00141 
00142         for (uint i = 0; i < src.getLength(); ++i)
00143         {
00144             attributeName = transcodeXmlCharToString(src.getLocalName(i));
00145             attributeValue = transcodeXmlCharToString(src.getValue(i));
00146             dest.add(attributeName, attributeValue);
00147         }
00148     }
00149 
00150     String XercesParser::transcodeXmlCharToString(const XMLCh* const xmlch_str)
00151     {
00152         XERCES_CPP_NAMESPACE_USE;
00153 
00154         XMLTransService::Codes  res;
00155         XMLTranscoder* transcoder = XMLPlatformUtils::fgTransService->makeNewTranscoderFor(XMLRecognizer::UTF_8, res, 4096, XMLPlatformUtils::fgMemoryManager );
00156 
00157         if (res == XMLTransService::Ok)
00158         {
00159             String out;
00160             utf8 outBuff[128];
00161             unsigned int outputLength;
00162             unsigned int eaten = 0;
00163             unsigned int offset = 0;
00164             unsigned int inputLength = XMLString::stringLen(xmlch_str);
00165 
00166             while (inputLength)
00167             {
00168                 outputLength = transcoder->transcodeTo(xmlch_str + offset, inputLength, outBuff, 128, eaten, XMLTranscoder::UnRep_RepChar);
00169                 out.append(outBuff, outputLength);
00170                 offset += eaten;
00171                 inputLength -= eaten;
00172             }
00173 
00174             delete transcoder;
00175 
00176             return out;
00177         }
00178         else
00179         {
00180             throw GenericException((utf8*)"XercesParser::transcodeXmlCharToString - Internal Error: Could not create UTF-8 string transcoder.");
00181         }
00182 
00183     }
00184 
00185     void XercesParser::initialiseSchema(XERCES_CPP_NAMESPACE::SAX2XMLReader* reader, const String& schemaName, const String& xmlFilename, const String& resourceGroup)
00186     {
00187         XERCES_CPP_NAMESPACE_USE;
00188 
00189         // enable schema use and set validation options
00190         reader->setFeature(XMLUni::fgXercesSchema, true);
00191         reader->setFeature(XMLUni::fgSAX2CoreValidation, true);
00192         reader->setFeature(XMLUni::fgXercesValidationErrorAsFatal, true);
00193 
00194         // load in the raw schema data
00195         RawDataContainer rawSchemaData;
00196         // try base filename first
00197         try
00198         {
00199             Logger::getSingleton().logEvent("XercesParser::initialiseSchema - Attempting to load schema from file '" + schemaName + "'.");
00200             System::getSingleton().getResourceProvider()->loadRawDataContainer(schemaName, rawSchemaData, resourceGroup);
00201         }
00202         // oops, no file.  Try an alternative instead...
00203         catch(InvalidRequestException)
00204         {
00205             // get path from filename
00206             String schemaFilename;
00207             size_t pos = xmlFilename.rfind("/");
00208             if (pos == String::npos) pos = xmlFilename.rfind("\\");
00209             if (pos != String::npos) schemaFilename.assign(xmlFilename, 0, pos + 1);
00210             // append schema filename
00211             schemaFilename += schemaName;
00212             // re-try the load operation.
00213             Logger::getSingleton().logEvent("XercesParser::initialiseSchema - Attempting to load schema from file '" + schemaFilename + "'.");
00214             System::getSingleton().getResourceProvider()->loadRawDataContainer(schemaFilename, rawSchemaData, resourceGroup);
00215         }
00216         // wrap schema data in a xerces MemBufInputSource object
00217         MemBufInputSource  schemaData(
00218             rawSchemaData.getDataPtr(),
00219             static_cast<const unsigned int>(rawSchemaData.getSize()),
00220             schemaName.c_str(),
00221             false);
00222         reader->loadGrammar(schemaData, Grammar::SchemaGrammarType, true);
00223         // enable grammar reuse
00224         reader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
00225 
00226         // set schema for usage
00227         XMLCh* pval = XMLString::transcode(schemaName.c_str());
00228         reader->setProperty(XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation, pval);
00229         XMLString::release(&pval);
00230         Logger::getSingleton().logEvent("XercesParser::initialiseSchema - XML schema file '" + schemaName + "' has been initialised.");
00231 
00232         // use resource provider to release loaded schema data (if it supports this)
00233         System::getSingleton().getResourceProvider()->unloadRawDataContainer(rawSchemaData);
00234     }
00235 
00236     XERCES_CPP_NAMESPACE::SAX2XMLReader* XercesParser::createReader(XERCES_CPP_NAMESPACE::DefaultHandler& handler)
00237     {
00238         XERCES_CPP_NAMESPACE_USE;
00239 
00240         SAX2XMLReader* reader = XMLReaderFactory::createXMLReader();
00241 
00242         // set basic settings we want from parser
00243         reader->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
00244 
00245         // set handlers
00246         reader->setContentHandler(&handler);
00247         reader->setErrorHandler(&handler);
00248 
00249         return reader;
00250     }
00251 
00252     void XercesParser::doParse(XERCES_CPP_NAMESPACE::SAX2XMLReader* parser, const String& xmlFilename, const String& resourceGroup)
00253     {
00254         XERCES_CPP_NAMESPACE_USE;
00255 
00256         // use resource provider to load file data
00257         RawDataContainer rawXMLData;
00258         System::getSingleton().getResourceProvider()->loadRawDataContainer(xmlFilename, rawXMLData, resourceGroup);
00259         MemBufInputSource  fileData(
00260             rawXMLData.getDataPtr(),
00261             static_cast<const unsigned int>(rawXMLData.getSize()),
00262             xmlFilename.c_str(),
00263             false);
00264 
00265          // perform parse
00266          try
00267          {
00268              parser->parse(fileData);
00269          }
00270          catch(...)
00271          {
00272              // use resource provider to release loaded XML source (if it supports this)
00273              System::getSingleton().getResourceProvider()->unloadRawDataContainer(rawXMLData);
00274 
00275              throw;
00276          }
00277 
00278          // use resource provider to release loaded XML source (if it supports this)
00279          System::getSingleton().getResourceProvider()->unloadRawDataContainer(rawXMLData);
00280     }
00281 
00282     
00284     //
00285     // XercesHandler methods
00286     //
00288 
00289     XercesHandler::XercesHandler(XMLHandler& handler) :
00290             d_handler(handler)
00291     {}
00292 
00293     XercesHandler::~XercesHandler(void)
00294     {}
00295 
00296     void XercesHandler::startElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname, const XERCES_CPP_NAMESPACE::Attributes& attrs)
00297     {
00298         XMLAttributes cegui_attributes;
00299         XercesParser::populateAttributesBlock(attrs, cegui_attributes);
00300 
00301         String element(XercesParser::transcodeXmlCharToString(localname));
00302 
00303         d_handler.elementStart(element, cegui_attributes);
00304     }
00305 
00306     void XercesHandler::endElement(const XMLCh* const uri, const XMLCh* const localname, const XMLCh* const qname)
00307     {
00308         String element(XercesParser::transcodeXmlCharToString(localname));
00309 
00310         d_handler.elementEnd(element);
00311     }
00312 
00313     void XercesHandler::warning (const XERCES_CPP_NAMESPACE::SAXParseException &exc)
00314     {
00315         XERCES_CPP_NAMESPACE_USE;
00316 
00317         // prepare a message about the warning
00318         char* excmsg = XMLString::transcode(exc.getMessage());
00319         String message("Xerces warning: ");
00320         message += (utf8*)excmsg;
00321         XMLString::release(&excmsg);
00322         Logger::getSingleton().logEvent(message);
00323     }
00324 
00325     void XercesHandler::error (const XERCES_CPP_NAMESPACE::SAXParseException &exc)
00326     {
00327         throw exc;
00328     }
00329 
00330     void XercesHandler::fatalError (const XERCES_CPP_NAMESPACE::SAXParseException &exc)
00331     {
00332         throw exc;
00333     }
00334 
00335 } // End of  CEGUI namespace section

Generated on Wed Sep 7 09:56:35 2005 for Crazy Eddies GUI System by  doxygen 1.4.3