00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
00035 namespace CEGUI
00036 {
00038
00039
00040
00042
00043 XercesParser::XercesParser(void)
00044 {
00045
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
00059 SAX2XMLReader* reader = createReader(xercesHandler);
00060
00061 try
00062 {
00063
00064 initialiseSchema(reader, schemaName, filename, resourceGroup);
00065
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
00103 delete reader;
00104 }
00105
00106 bool XercesParser::initialiseImpl(void)
00107 {
00108 XERCES_CPP_NAMESPACE_USE;
00109
00110
00111 try
00112 {
00113 XMLPlatformUtils::Initialize();
00114 }
00115 catch(XMLException& exc)
00116 {
00117
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
00124 throw message.c_str();
00125 }
00126
00127 return true;
00128 }
00129
00130 void XercesParser::cleanupImpl(void)
00131 {
00132
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
00190 reader->setFeature(XMLUni::fgXercesSchema, true);
00191 reader->setFeature(XMLUni::fgSAX2CoreValidation, true);
00192 reader->setFeature(XMLUni::fgXercesValidationErrorAsFatal, true);
00193
00194
00195 RawDataContainer rawSchemaData;
00196
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
00203 catch(InvalidRequestException)
00204 {
00205
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
00211 schemaFilename += schemaName;
00212
00213 Logger::getSingleton().logEvent("XercesParser::initialiseSchema - Attempting to load schema from file '" + schemaFilename + "'.");
00214 System::getSingleton().getResourceProvider()->loadRawDataContainer(schemaFilename, rawSchemaData, resourceGroup);
00215 }
00216
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
00224 reader->setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true);
00225
00226
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
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
00243 reader->setFeature(XMLUni::fgSAX2CoreNameSpaces, true);
00244
00245
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
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
00266 try
00267 {
00268 parser->parse(fileData);
00269 }
00270 catch(...)
00271 {
00272
00273 System::getSingleton().getResourceProvider()->unloadRawDataContainer(rawXMLData);
00274
00275 throw;
00276 }
00277
00278
00279 System::getSingleton().getResourceProvider()->unloadRawDataContainer(rawXMLData);
00280 }
00281
00282
00284
00285
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
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 }