/* Copyright (C) 2001-2006, William Joseph. All Rights Reserved. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #if !defined(INCLUDED_XML_XMLPARSER_H) #define INCLUDED_XML_XMLPARSER_H #include #include #include "ixml.h" #include "libxml/parser.h" #include "convert.h" class TextInputStream; class SAXElement : public XMLElement { public: SAXElement(const char* name, const char** atts) : m_name(name), m_atts(atts) { } const char* name() const { return m_name; } const char* attribute(const char* name) const { if(m_atts != 0) { for(const char** att = m_atts; *att != 0; att+=2) { if(strcmp(*att, name) == 0) { return *(++att); } } } return ""; } void forEachAttribute(XMLAttrVisitor& visitor) const { if(m_atts != 0) { for(const char** att = m_atts; *att != 0; att+=2) { visitor.visit(*att, *(att+1)); } } } private: const char* m_name; const char** m_atts; }; #include class FormattedVA { public: const char* m_format; va_list& m_arguments; FormattedVA(const char* format, va_list& m_arguments) : m_format(format), m_arguments(m_arguments) { } }; class Formatted { public: const char* m_format; va_list m_arguments; Formatted(const char* format, ...) : m_format(format) { va_start(m_arguments, format); } ~Formatted() { va_end(m_arguments); } }; #ifdef WIN32 #if _MSC_VER < 1400 #define vsnprintf std::vsnprintf #endif #endif template inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const FormattedVA& formatted) { char buffer[1024]; ostream.write(buffer, vsnprintf(buffer, 1023, formatted.m_format, formatted.m_arguments)); return ostream; } template inline TextOutputStreamType& ostream_write(TextOutputStreamType& ostream, const Formatted& formatted) { char buffer[1024]; ostream.write(buffer, vsnprintf(buffer, 1023, formatted.m_format, formatted.m_arguments)); return ostream; } class XMLSAXImporter { XMLImporter& m_importer; xmlSAXHandler m_sax; static void startElement(void *user_data, const xmlChar *name, const xmlChar **atts) { SAXElement element(reinterpret_cast(name), reinterpret_cast(atts)); reinterpret_cast(user_data)->m_importer.pushElement(element); } static void endElement(void *user_data, const xmlChar *name) { reinterpret_cast(user_data)->m_importer.popElement(reinterpret_cast(name)); } static void characters(void *user_data, const xmlChar *ch, int len) { reinterpret_cast(user_data)->m_importer << ConvertUTF8ToLocale(StringRange(reinterpret_cast(ch), reinterpret_cast(ch + len))); } static void warning(void *user_data, const char *msg, ...) { va_list args; va_start(args, msg); globalErrorStream() << "XML WARNING: " << FormattedVA(msg, args); va_end(args); } static void error(void *user_data, const char *msg, ...) { va_list args; va_start(args, msg); globalErrorStream() << "XML ERROR: " << FormattedVA(msg, args); va_end(args); } public: XMLSAXImporter(XMLImporter& importer) : m_importer(importer) { m_sax.internalSubset = 0; m_sax.isStandalone = 0; m_sax.hasInternalSubset = 0; m_sax.hasExternalSubset = 0; m_sax.resolveEntity = 0; m_sax.getEntity = 0; m_sax.entityDecl = 0; m_sax.notationDecl = 0; m_sax.attributeDecl = 0; m_sax.elementDecl = 0; m_sax.unparsedEntityDecl = 0; m_sax.setDocumentLocator = 0; m_sax.startDocument = 0; m_sax.endDocument = 0; m_sax.startElement = startElement; m_sax.endElement = endElement; m_sax.reference = 0; m_sax.characters = characters; m_sax.ignorableWhitespace = 0; m_sax.processingInstruction = 0; m_sax.comment = 0; m_sax.warning = warning; m_sax.error = error; m_sax.fatalError = 0; m_sax.getParameterEntity = 0; m_sax.cdataBlock = 0; m_sax.externalSubset = 0; m_sax.initialized = 1; } xmlSAXHandler* callbacks() { return &m_sax; } void* context() { return this; } }; class XMLStreamParser : public XMLExporter { enum unnamed0 { BUFSIZE = 1024 }; public: XMLStreamParser(TextInputStream& istream) : m_istream(istream) { } virtual void exportXML(XMLImporter& importer) { bool wellFormed = false; char chars[BUFSIZE]; std::size_t res = m_istream.read(chars, 4); if (res > 0) { XMLSAXImporter sax(importer); xmlParserCtxtPtr ctxt = xmlCreatePushParserCtxt(sax.callbacks(), sax.context(), chars, static_cast(res), 0); ctxt->replaceEntities = 1; while ((res = m_istream.read(chars, BUFSIZE)) > 0) { xmlParseChunk(ctxt, chars, static_cast(res), 0); } xmlParseChunk(ctxt, chars, 0, 1); wellFormed = (ctxt->wellFormed == 1); xmlFreeParserCtxt(ctxt); } //return wellFormed; } private: TextInputStream& m_istream; }; #endif