summaryrefslogtreecommitdiff
path: root/compiled
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2012-03-28 14:59:51 (GMT)
committerChristian Mollekopf <chrigi_1@fastmail.fm>2012-03-28 14:59:51 (GMT)
commit1288bf09e5f92b5123d4e5b127b904353bceba80 (patch)
tree6906983becfd2bdeae28e2740f89685256de304c /compiled
parent987217d13ca95c4d77b423f4c468e69986321386 (diff)
downloadlibkolabxml-1288bf09e5f92b5123d4e5b127b904353bceba80.tar.gz
got rid of the libkolabxml subdirectory
Diffstat (limited to 'compiled')
-rw-r--r--compiled/README20
-rw-r--r--compiled/XMLParserWrapper.cpp295
-rw-r--r--compiled/XMLParserWrapper.h89
-rw-r--r--compiled/grammar-input-stream.cxx115
-rw-r--r--compiled/grammar-input-stream.hxx53
-rw-r--r--compiled/xsdbin.cxx505
6 files changed, 1077 insertions, 0 deletions
diff --git a/compiled/README b/compiled/README
new file mode 100644
index 0000000..c2ff791
--- /dev/null
+++ b/compiled/README
@@ -0,0 +1,20 @@
+Code needed to compile schemas so they can be embeeded into the binary.
+
+According to the xsd example in xsd/examples/cxx/tree/embedded/
+
+xsdbin.cxx
+ Tool for converting one or more XML Schema files to the compressed binary
+ representation. The output is written as a pair of C++ source files
+ containing the array with the binary data. Use the --help option to see
+ the tool's usage information.
+
+library-schema.hxx
+library-schema.cxx
+ Binary representation of the library.xsd schema. These files are generated
+ by the xsdbin tool.
+
+grammar-input-stream.hxx
+grammar-input-stream.cxx
+ Input stream implementation with the special-purpose schema grammar
+ decompression algorithm. It is used to load the binary schema representation
+ produced by the xsdbin tool.
diff --git a/compiled/XMLParserWrapper.cpp b/compiled/XMLParserWrapper.cpp
new file mode 100644
index 0000000..96e859c
--- /dev/null
+++ b/compiled/XMLParserWrapper.cpp
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2011 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "XMLParserWrapper.h"
+
+#include <memory> // std::auto_ptr
+#include <fstream>
+#include <iostream>
+
+#include <xercesc/dom/DOM.hpp>
+#include <xercesc/util/XMLUniDefs.hpp> // chLatin_*
+#include <xercesc/util/PlatformUtils.hpp>
+#include <xercesc/validators/common/Grammar.hpp> // xercesc::Grammar
+#include <xercesc/framework/Wrapper4InputSource.hpp>
+
+#if _XERCES_VERSION >= 30000
+# include <xercesc/framework/XMLGrammarPoolImpl.hpp>
+#else
+# include <xercesc/internal/XMLGrammarPoolImpl.hpp>
+#endif
+
+#include <xsd/cxx/xml/string.hxx>
+#include <xsd/cxx/xml/dom/auto-ptr.hxx>
+#include <xsd/cxx/xml/dom/bits/error-handler-proxy.hxx>
+#include <xsd/cxx/xml/sax/std-input-source.hxx>
+
+#include <xsd/cxx/tree/error-handler.hxx>
+
+#include <boost/thread.hpp>
+
+#include "kolabformat-xcal-schema.hxx"
+#include "grammar-input-stream.hxx"
+
+XMLParserWrapper::XMLParserWrapper()
+: ehp(eh),
+ parser(0),
+ gp(0)
+{
+ // We need to initialize the Xerces-C++ runtime because we
+ // are doing the XML-to-DOM parsing ourselves.
+ //
+ xercesc::XMLPlatformUtils::Initialize ();
+ init();
+}
+
+
+XMLParserWrapper::~XMLParserWrapper()
+{
+ delete parser;
+ delete gp;
+ xercesc::XMLPlatformUtils::Terminate ();
+
+}
+
+boost::thread_specific_ptr<XMLParserWrapper> ptr;
+
+XMLParserWrapper& XMLParserWrapper::inst()
+{
+ XMLParserWrapper *t = ptr.get();
+ if (!t) {
+ t = new XMLParserWrapper();
+ ptr.reset(t);
+ }
+ return *t;
+}
+
+
+void XMLParserWrapper::init()
+{
+ using namespace std;
+
+ if (parser) {
+ return;
+ }
+ try
+ {
+ using namespace xercesc;
+ namespace xml = xsd::cxx::xml;
+ namespace tree = xsd::cxx::tree;
+ // Create and load the grammar pool.
+ //
+ MemoryManager* mm (XMLPlatformUtils::fgMemoryManager);
+
+ gp = new XMLGrammarPoolImpl (mm);
+
+ try
+ {
+ grammar_input_stream is (iCalendar_schema, sizeof (iCalendar_schema));
+ gp->deserializeGrammars(&is);
+ }
+ catch(const XSerializationException& e)
+ {
+ cerr << "unable to load schema: " << xml::transcode<char> (e.getMessage ()) << endl;
+ return;
+ }
+
+ // Lock the grammar pool. This is necessary if we plan to use the
+ // same grammar pool in multiple threads (this way we can reuse the
+ // same grammar in multiple parsers). Locking the pool disallows any
+ // modifications to the pool, such as an attempt by one of the threads
+ // to cache additional schemas.
+ //
+ gp->lockPool ();
+
+ // Get an implementation of the Load-Store (LS) interface.
+ //
+ const XMLCh ls_id [] = {chLatin_L, chLatin_S, chNull};
+
+ DOMImplementation* impl (
+ DOMImplementationRegistry::getDOMImplementation (ls_id));
+
+ #if _XERCES_VERSION >= 30000
+
+ // Xerces-C++ 3.0.0 and later.
+ //
+ parser = impl->createLSParser (
+ DOMImplementationLS::MODE_SYNCHRONOUS, 0, mm, gp);
+
+ DOMConfiguration* conf (parser->getDomConfig ());
+
+ // Discard comment nodes in the document.
+ //
+ conf->setParameter (XMLUni::fgDOMComments, false);
+
+ // Enable datatype normalization.
+ //
+ conf->setParameter (XMLUni::fgDOMDatatypeNormalization, true);
+
+ // Do not create EntityReference nodes in the DOM tree. No
+ // EntityReference nodes will be created, only the nodes
+ // corresponding to their fully expanded substitution text
+ // will be created.
+ //
+ conf->setParameter (XMLUni::fgDOMEntities, false);
+
+ // Perform namespace processing.
+ //
+ conf->setParameter (XMLUni::fgDOMNamespaces, true);
+
+ // Do not include ignorable whitespace in the DOM tree.
+ //
+ conf->setParameter (XMLUni::fgDOMElementContentWhitespace, false);
+
+ // Enable validation.
+ //
+ conf->setParameter (XMLUni::fgDOMValidate, true);
+ conf->setParameter (XMLUni::fgXercesSchema, true);
+ conf->setParameter (XMLUni::fgXercesSchemaFullChecking, false);
+
+ // Xerces-C++ 3.1.0 is the first version with working multi import
+ // support.
+ //
+ #if _XERCES_VERSION >= 30100
+ conf->setParameter (XMLUni::fgXercesHandleMultipleImports, true);
+ #endif
+
+ // Use the loaded grammar during parsing.
+ //
+ conf->setParameter (XMLUni::fgXercesUseCachedGrammarInParse, true);
+
+ // Disable loading schemas via other means (e.g., schemaLocation).
+ //
+ conf->setParameter (XMLUni::fgXercesLoadSchema, false);
+
+ // We will release the DOM document ourselves.
+ //
+ conf->setParameter (XMLUni::fgXercesUserAdoptsDOMDocument, true);
+
+
+
+ // Set error handler.
+ //
+// tree::error_handler<char> eh;
+// xml::dom::bits::error_handler_proxy<char> ehp (eh);
+ conf->setParameter (XMLUni::fgDOMErrorHandler, &ehp); //TODO does conf take a copy or should the ehp object live on?
+
+ #else // _XERCES_VERSION >= 30000
+
+ // Same as above but for Xerces-C++ 2 series.
+ //
+ parser = impl->createDOMBuilder(
+ DOMImplementationLS::MODE_SYNCHRONOUS, 0, mm, gp);
+
+
+ parser->setFeature (XMLUni::fgDOMComments, false);
+ parser->setFeature (XMLUni::fgDOMDatatypeNormalization, true);
+ parser->setFeature (XMLUni::fgDOMEntities, false);
+ parser->setFeature (XMLUni::fgDOMNamespaces, true);
+ parser->setFeature (XMLUni::fgDOMWhitespaceInElementContent, false);
+ parser->setFeature (XMLUni::fgDOMValidation, true);
+ parser->setFeature (XMLUni::fgXercesSchema, true);
+ parser->setFeature (XMLUni::fgXercesSchemaFullChecking, false);
+ parser->setFeature (XMLUni::fgXercesUseCachedGrammarInParse, true);
+ parser->setFeature (XMLUni::fgXercesUserAdoptsDOMDocument, true);
+
+ //tree::error_handler<char> eh;
+// xml::dom::bits::error_handler_proxy<char> ehp (eh);
+ parser->setErrorHandler (&ehp);
+
+ #endif // _XERCES_VERSION >= 30000
+
+ // Parse XML documents.
+ //
+
+ }
+ catch (const xml_schema::exception& e) {
+ cout << "schema exception" << endl;
+ cerr << e << endl;
+ } catch (const std::ios_base::failure&) {
+ cerr << ": unable to open or read failure" << endl;
+ }
+
+}
+
+xsd::cxx::xml::dom::auto_ptr< xercesc::DOMDocument > XMLParserWrapper::parseFile(const std::string& url)
+{
+ try {
+ std::ifstream ifs;
+ ifs.exceptions (std::ifstream::badbit | std::ifstream::failbit); //TODO handle exceptions
+ ifs.open (url.c_str());
+ return parse(ifs, url);
+ } catch (const std::ios_base::failure&)
+ {
+ std::cerr << ": unable to open or read failure" << std::endl;
+ }
+ return xsd::cxx::xml::dom::auto_ptr< xercesc::DOMDocument >();
+}
+
+xsd::cxx::xml::dom::auto_ptr< xercesc::DOMDocument > XMLParserWrapper::parseString(const std::string& s)
+{
+ std::istringstream is(s);
+ return parse(is, ""); //TODO set identifier?
+}
+
+
+xml_schema::dom::auto_ptr<xercesc::DOMDocument> XMLParserWrapper::parse(std::istream &ifs, const std::string &name)
+{
+ using namespace std;
+
+ try
+ {
+ using namespace xercesc;
+ namespace xml = xsd::cxx::xml;
+ namespace tree = xsd::cxx::tree;
+
+ // Parse XML documents.
+ //
+ {
+ // Wrap the standard input stream.
+ //
+ xml::sax::std_input_source isrc (ifs, name);
+ Wrapper4InputSource wrap (&isrc, false);
+
+ // Parse XML to DOM.
+ //
+ #if _XERCES_VERSION >= 30000
+ xml_schema::dom::auto_ptr<DOMDocument> doc (parser->parse (&wrap));
+ #else
+ xml_schema::dom::auto_ptr<DOMDocument> doc (parser->parse (wrap));
+ #endif
+
+ eh.throw_if_failed<xml_schema::parsing> ();
+ return doc;
+ }
+ }
+ catch (const xml_schema::exception& e)
+ {
+ cerr << "schema exception" << endl;
+ cerr << e << endl;
+ }
+ catch (const std::ios_base::failure&)
+ {
+ cerr << ": unable to open or read failure" << endl;
+ }
+ catch (...)
+ {
+ cerr << ": unknown exception thrown" << endl;
+ }
+ eh.reset();
+ return xml_schema::dom::auto_ptr<xercesc::DOMDocument>();
+}
diff --git a/compiled/XMLParserWrapper.h b/compiled/XMLParserWrapper.h
new file mode 100644
index 0000000..86a76c1
--- /dev/null
+++ b/compiled/XMLParserWrapper.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2011 Christian Mollekopf <mollekopf@kolabsys.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef XMLPARSER_WRAPPER_H
+#define XMLPARSER_WRAPPER_H
+
+#include <string>
+#include <memory>
+#include <bindings/kolabformat-xcal.hxx>
+#include <xsd/cxx/tree/error-handler.hxx>
+#include <boost/scoped_ptr.hpp>
+#include <xsd/cxx/xml/dom/bits/error-handler-proxy.hxx>
+
+#if _XERCES_VERSION >= 30000
+# include <xercesc/dom/DOMLSParser.hpp>
+# include <xercesc/dom/DOMLSException.hpp>
+#else
+# include <xercesc/dom/DOMBuilder.hpp>
+#endif
+
+#include <xercesc/framework/XMLGrammarPool.hpp>
+
+/**
+ * This wrapper controls the lifetime of the parser object.
+ *
+ * Initializing the parser is much more expensive than parsing a single XML document, therefore the parser should be reused if possible.
+ *
+ * It might make sense to use a singleton internally to keep the parser alive between usages. Alternatively this object can be kept alive for as long as it makes sense.
+ *
+ * This class also encapsulates the initialization of the whole parser, which must be done manually because precomiled schemas are used (which greatly improves the initialization performance).
+ *
+ * Writing the document is static and doesn't need any initialization and is therefore not wrapped by this object.
+ *
+ */
+
+class XMLParserWrapper {
+public:
+ XMLParserWrapper();
+ ~XMLParserWrapper();
+
+ /**
+ * Threadsafe singleton. One Xerces instance is created per thread (threadlocal).
+ * Access via singleton to reuse parser.
+ */
+ static XMLParserWrapper &inst();
+
+ xml_schema::dom::auto_ptr<xercesc::DOMDocument> parseFile(const std::string &url);
+ xml_schema::dom::auto_ptr<xercesc::DOMDocument> parseString(const std::string &s);
+ xml_schema::dom::auto_ptr<xercesc::DOMDocument> parse(std::istream &ifs, const std::string &name);
+private:
+ void init();
+ xsd::cxx::tree::error_handler<char> eh;
+ xsd::cxx::xml::dom::bits::error_handler_proxy<char> ehp;
+
+ #if _XERCES_VERSION >= 30000
+ xercesc::DOMLSParser *parser;
+ #else
+ xercesc::DOMBuilder *parser;
+ #endif
+ xercesc::XMLGrammarPool *gp;
+};
+
+
+#endif
+
+
+
+
+
+
+
+
+
+
+
diff --git a/compiled/grammar-input-stream.cxx b/compiled/grammar-input-stream.cxx
new file mode 100644
index 0000000..0c94ea6
--- /dev/null
+++ b/compiled/grammar-input-stream.cxx
@@ -0,0 +1,115 @@
+// file : examples/cxx/tree/embedded/grammar-input-stream.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#include <cassert>
+#include "grammar-input-stream.hxx"
+
+grammar_input_stream::
+grammar_input_stream (const XMLByte* data, std::size_t size)
+ : data_ (data),
+ size_ (size),
+ pos_ (0),
+ vpos_ (0),
+ cseq_ (0),
+ add_zero_ (false)
+{
+}
+
+#if _XERCES_VERSION >= 30000
+XMLFilePos grammar_input_stream::
+curPos () const
+{
+ return static_cast<XMLFilePos> (vpos_);
+}
+#else
+unsigned int grammar_input_stream::
+curPos () const
+{
+ return static_cast<unsigned int> (vpos_);
+}
+#endif
+
+#if _XERCES_VERSION >= 30000
+XMLSize_t grammar_input_stream::
+readBytes (XMLByte* const buf, const XMLSize_t size)
+#else
+unsigned int grammar_input_stream::
+readBytes (XMLByte* const buf, const unsigned int size)
+#endif
+{
+ std::size_t i (0);
+
+ // Add a zero from the alternating sequence if it didn't
+ // fit on the previous read.
+ //
+ if (add_zero_)
+ {
+ buf[i++] = 0;
+ add_zero_ = false;
+ }
+
+ // If have an unfinished sequential sequence, output it now.
+ //
+ if (cseq_ != 0 && !alt_)
+ {
+ for (; cseq_ != 0 && i < size; --cseq_)
+ buf[i++] = 0;
+ }
+
+ for (; i < size && pos_ < size_;)
+ {
+ XMLByte b = buf[i++] = data_[pos_++];
+
+ // See if we are in a compression sequence.
+ //
+ if (cseq_ != 0)
+ {
+ if (i < size)
+ buf[i++] = 0;
+ else
+ add_zero_ = true; // Add it on the next read.
+
+ cseq_--;
+ continue;
+ }
+
+ // If we are not in a compression sequence and this byte is
+ // not zero then we are done.
+ //
+ if (b != 0)
+ continue;
+
+ // We have a zero.
+ //
+ assert (pos_ < size_); // There has to be another byte.
+ unsigned char v (static_cast<unsigned char> (data_[pos_++]));
+ alt_ = (v & 128) != 0;
+ cseq_ = v & 127;
+
+ // If it is a sequential sequence, output as many zeros as
+ // we can.
+ //
+ if (!alt_)
+ {
+ for (; cseq_ != 0 && i < size; --cseq_)
+ buf[i++] = 0;
+ }
+ }
+
+ vpos_ += i;
+
+#if _XERCES_VERSION >= 30000
+ return static_cast<XMLSize_t> (i);
+#else
+ return static_cast<unsigned int> (i);
+#endif
+}
+
+#if _XERCES_VERSION >= 30000
+const XMLCh* grammar_input_stream::
+getContentType () const
+{
+ return 0;
+}
+#endif
diff --git a/compiled/grammar-input-stream.hxx b/compiled/grammar-input-stream.hxx
new file mode 100644
index 0000000..a1b73c6
--- /dev/null
+++ b/compiled/grammar-input-stream.hxx
@@ -0,0 +1,53 @@
+// file : examples/cxx/tree/embedded/grammar-input-stream.hxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+#ifndef GRAMMAR_INPUT_STREAM_HXX
+#define GRAMMAR_INPUT_STREAM_HXX
+
+#include <cstddef>
+#include <xercesc/util/BinInputStream.hpp>
+
+// Memory buffer input stream with the special-purpose schema
+// grammar decompression.
+//
+class grammar_input_stream: public xercesc::BinInputStream
+{
+public :
+ grammar_input_stream (const XMLByte* data, std::size_t size);
+
+#if _XERCES_VERSION >= 30000
+
+ virtual XMLFilePos
+ curPos () const;
+
+ virtual XMLSize_t
+ readBytes (XMLByte* const buf, const XMLSize_t size);
+
+ virtual const XMLCh*
+ getContentType () const;
+
+#else
+
+ virtual unsigned int
+ curPos () const;
+
+ virtual unsigned int
+ readBytes (XMLByte* const buf, const unsigned int size);
+
+#endif
+
+private :
+ const XMLByte* data_;
+ std::size_t size_;
+ std::size_t pos_;
+ std::size_t vpos_;
+
+ // Compression data.
+ //
+ size_t cseq_; // Number of bytes left in a compression sequence.
+ bool alt_; // Alternating or sequential sequence.
+ bool add_zero_; // Add a zero on the next read.
+};
+
+#endif // GRAMMAR_INPUT_STREAM_HXX
diff --git a/compiled/xsdbin.cxx b/compiled/xsdbin.cxx
new file mode 100644
index 0000000..53e2533
--- /dev/null
+++ b/compiled/xsdbin.cxx
@@ -0,0 +1,505 @@
+// file : examples/cxx/tree/embedded/xsdbin.cxx
+// author : Boris Kolpackov <boris@codesynthesis.com>
+// copyright : not copyrighted - public domain
+
+// This program loads the XML Schema file(s) and converts them to
+// the Xerces-C++ binary schema format which can then be embedded
+// into C++ programs and used to validate XML documents. The output
+// is written as a C++ source file containing the array with the
+// binary data.
+//
+
+#include <string>
+#include <memory> // std::auto_ptr
+#include <cstddef> // std::size_t
+#include <fstream>
+#include <iostream>
+
+#include <xercesc/util/XMLUni.hpp>
+#include <xercesc/util/XMLString.hpp>
+#include <xercesc/util/PlatformUtils.hpp>
+#include <xercesc/util/XercesVersion.hpp>
+
+#include <xercesc/internal/BinMemOutputStream.hpp>
+#include <xercesc/validators/common/Grammar.hpp>
+
+#include <xercesc/sax/ErrorHandler.hpp>
+#include <xercesc/sax/SAXParseException.hpp>
+#include <xercesc/sax2/SAX2XMLReader.hpp>
+#include <xercesc/sax2/XMLReaderFactory.hpp>
+
+#if _XERCES_VERSION >= 30000
+# include <xercesc/framework/XMLGrammarPoolImpl.hpp>
+#else
+# include <xercesc/internal/XMLGrammarPoolImpl.hpp>
+#endif
+
+using namespace std;
+using namespace xercesc;
+
+class error_handler: public ErrorHandler
+{
+public:
+ error_handler ()
+ : failed_ (false)
+ {
+ }
+
+ bool
+ failed () const
+ {
+ return failed_;
+ }
+
+ enum severity {s_warning, s_error, s_fatal};
+
+ virtual void
+ warning (const SAXParseException&);
+
+ virtual void
+ error (const SAXParseException&);
+
+ virtual void
+ fatalError (const SAXParseException&);
+
+ virtual void
+ resetErrors ()
+ {
+ failed_ = false;
+ }
+
+ void
+ handle (const SAXParseException&, severity);
+
+private:
+ bool failed_;
+};
+
+void
+cxx_escape (string&);
+
+int
+main (int argc, char* argv[])
+{
+ const char* hxx_suffix = "-schema.hxx";
+ const char* cxx_suffix = "-schema.cxx";
+
+ string name;
+ string base;
+ string outdir;
+
+ class usage {};
+
+ int argi (1);
+ bool help (false);
+ bool multi_import (true);
+ bool verbose (false);
+
+ try
+ {
+ for (; argi < argc; ++argi)
+ {
+ string a (argv[argi]);
+
+ if (a == "--help")
+ {
+ help = true;
+ throw usage ();
+ }
+ else if (a == "--verbose")
+ {
+ verbose = true;
+ }
+ else if (a == "--hxx-suffix")
+ {
+ if (++argi >= argc)
+ throw usage ();
+
+ hxx_suffix = argv[argi];
+ }
+ else if (a == "--cxx-suffix")
+ {
+ if (++argi >= argc)
+ throw usage ();
+
+ cxx_suffix = argv[argi];
+ }
+ else if (a == "--output-dir")
+ {
+ if (++argi >= argc)
+ throw usage ();
+
+ outdir = argv[argi];
+ }
+ else if (a == "--array-name")
+ {
+ if (++argi >= argc)
+ throw usage ();
+
+ name = argv[argi];
+ }
+ else if (a == "--disable-multi-import")
+ {
+ multi_import = false;
+ }
+ else
+ break;
+ }
+
+ if (argi >= argc)
+ {
+ cerr << "no input file specified" << endl;
+ throw usage ();
+ }
+
+ base = argv[argi];
+ }
+ catch (usage const&)
+ {
+ cerr << "Usage: " << argv[0] << " [options] <files>" << endl
+ << "Options:" << endl
+ << " --help Print usage information and exit." << endl
+ << " --verbose Print progress information." << endl
+ << " --output-dir <dir> Write generated files to <dir>." << endl
+ << " --hxx-suffix <sfx> Header file suffix instead of '-schema.hxx'." << endl
+ << " --cxx-suffix <sfx> Source file suffix instead of '-schema.cxx'." << endl
+ << " --array-name <name> Binary data array name." << endl
+ << " --disable-multi-import Disable multiple import support." << endl
+ << endl;
+
+ return help ? 0 : 1;
+ }
+
+ XMLPlatformUtils::Initialize ();
+
+ {
+ MemoryManager* mm (XMLPlatformUtils::fgMemoryManager);
+
+ auto_ptr<XMLGrammarPool> gp (new XMLGrammarPoolImpl (mm));
+
+ // Load the schemas into grammar pool.
+ //
+ {
+ auto_ptr<SAX2XMLReader> parser (
+ XMLReaderFactory::createXMLReader (mm, gp.get ()));
+
+ parser->setFeature (XMLUni::fgSAX2CoreNameSpaces, true);
+ parser->setFeature (XMLUni::fgSAX2CoreNameSpacePrefixes, true);
+ parser->setFeature (XMLUni::fgSAX2CoreValidation, true);
+ parser->setFeature (XMLUni::fgXercesSchema, true);
+ parser->setFeature (XMLUni::fgXercesSchemaFullChecking, true);
+ parser->setFeature (XMLUni::fgXercesValidationErrorAsFatal, true);
+
+ // Xerces-C++ 3.1.0 is the first version with working multi import
+ // support.
+ //
+#if _XERCES_VERSION >= 30100
+ parser->setFeature (XMLUni::fgXercesHandleMultipleImports, multi_import);
+#endif
+
+ error_handler eh;
+ parser->setErrorHandler (&eh);
+
+ for (; argi < argc; ++argi)
+ {
+ if (verbose)
+ cerr << "loading " << argv[argi] << endl;
+
+ if (!parser->loadGrammar (argv[argi], Grammar::SchemaGrammarType, true))
+ {
+ cerr << argv[argi] << ": error: unable to load" << endl;
+ return 1;
+ }
+
+ if (eh.failed ())
+ return 1;
+ }
+ }
+
+ // Get the binary representation.
+ //
+ BinMemOutputStream data;
+
+ try
+ {
+ gp->serializeGrammars (&data);
+ }
+ catch (const XSerializationException& e)
+ {
+ char* msg (XMLString::transcode (e.getMessage ()));
+ cerr << "error: " << msg << endl;
+ XMLString::release (&msg);
+ return 1;
+ }
+
+ size_t n (static_cast<size_t> (data.curPos ()));
+ const unsigned char* buf (
+ static_cast<const unsigned char*> (data.getRawBuffer ()));
+
+ if (verbose)
+ cerr << "uncomressed data size " << n << " bytes" << endl;
+
+ // Compress zeros.
+ //
+ size_t cn (0);
+ unsigned char* cbuf = new unsigned char[n];
+
+ size_t cseq (0); // Number of bytes left in a compression sequence.
+ bool alt (false); // Alternating or sequential sequence.
+
+ for (size_t i (0); i < n;)
+ {
+ unsigned char v (buf[i++]);
+
+ // See if we are in a compression sequence.
+ //
+ if (cseq != 0)
+ {
+ // See if this byte needs to be copied.
+ //
+ if (alt && cseq % 2 == 0)
+ cbuf[cn++] = v;
+
+ cseq--;
+ continue;
+ }
+
+ // If we are not in a compression sequence and this byte is
+ // not zero then simply copy it.
+ //
+ if (v != 0)
+ {
+ cbuf[cn++] = v;
+ continue;
+ }
+
+ // We have a zero.
+ //
+ cbuf[cn++] = 0;
+
+ // See if we can start a new compression sequence.
+ //
+ if (i < n)
+ {
+ if (buf[i] == 0)
+ {
+ // Sequential sequence. See how far it runs.
+ //
+ alt = false;
+
+ for (cseq = 1; cseq < 127 && cseq + i < n; cseq++)
+ if (buf[cseq + i] != 0)
+ break;
+ }
+ else if (i + 1 < n && buf[i + 1] == 0)
+ {
+ // Alternating sequence. See how far it runs.
+ //
+ alt = true;
+
+ for (cseq = 1; cseq < 127 && cseq * 2 + i + 1 < n; cseq++)
+ {
+ if (buf[cseq * 2 + i + 1] != 0)
+ break;
+
+ // For longer sequences prefer sequential to alternating.
+ //
+ if (cseq > 2 &&
+ buf[cseq * 2 + i] == 0 &&
+ buf[(cseq - 1) * 2 + i] == 0 &&
+ buf[(cseq - 2) * 2 + i] == 0)
+ {
+ cseq -= 2;
+ break;
+ }
+ }
+
+ cseq *= 2;
+ }
+ }
+
+ if (cseq != 0)
+ {
+ cbuf[cn++] = static_cast<unsigned char> (
+ alt ? (128 | cseq / 2) : cseq);
+ }
+ else
+ cbuf[cn++] = 0;
+ }
+
+ if (verbose)
+ cerr << "comressed data size " << cn << " bytes" << endl;
+
+ buf = cbuf;
+ n = cn;
+
+ // Figure out the file names.
+ //
+ string::size_type p (base.rfind ('/')), p1 (base.rfind ('\\'));
+
+ if (p1 != string::npos && p1 > p)
+ p = p1;
+
+ if (p != string::npos)
+ base = string (base, p + 1);
+
+ p = base.rfind ('.');
+
+ if (p != string::npos)
+ base.resize (p);
+
+ string hxx (base + hxx_suffix);
+ string cxx (base + cxx_suffix);
+
+ if (!outdir.empty ())
+ {
+#if defined (WIN32) || defined (__WIN32__)
+ hxx = outdir + '\\' + hxx;
+ cxx = outdir + '\\' + cxx;
+#else
+ hxx = outdir + '/' + hxx;
+ cxx = outdir + '/' + cxx;
+#endif
+ }
+
+ if (name.empty ())
+ {
+ name = base + "_schema";
+ cxx_escape (name);
+ }
+
+ // Write header.
+ //
+ {
+ ofstream os (hxx.c_str ());
+
+ if (!os.is_open ())
+ {
+ cerr << hxx << ": error: unable to open" << endl;
+ return 1;
+ }
+
+ os << "// Automatically generated. Do not edit." << endl
+ << "//" << endl
+ << endl
+ << "#include <xercesc/util/XercesDefs.hpp>" << endl
+ << endl
+ << "extern const XMLByte " << name << "[" << n << "UL];" << endl;
+ }
+
+ {
+ ofstream os (cxx.c_str ());
+
+ if (!os.is_open ())
+ {
+ cerr << cxx << ": error: unable to open" << endl;
+ return 1;
+ }
+
+ os << "// Automatically generated. Do not edit." << endl
+ << "//" << endl
+ << endl
+ << "#include <xercesc/util/XercesDefs.hpp>" << endl
+ << "#include <xercesc/util/XercesVersion.hpp>" << endl
+ << endl
+ << "#if XERCES_GRAMMAR_SERIALIZATION_LEVEL != " <<
+ XERCES_GRAMMAR_SERIALIZATION_LEVEL << endl
+ << "# error incompatible Xerces-C++ version detected" << endl
+ << "#endif" << endl
+ << endl
+ << "extern const XMLByte " << name << "[" << n << "UL] =" << endl
+ << "{";
+
+ for (size_t i (0); i < n; ++i)
+ {
+ if (i != 0)
+ os << ',';
+
+ os << (i % 12 == 0 ? "\n " : " ") << "0x";
+ os.width (2);
+ os.fill ('0');
+ os << hex << static_cast<unsigned short> (buf[i]);
+ }
+
+ os << endl
+ << "};" << endl
+ << endl;
+ }
+
+ delete[] cbuf;
+ }
+
+ XMLPlatformUtils::Terminate ();
+}
+
+void
+cxx_escape (string& s)
+{
+ for (string::size_type i (0); i < s.size (); ++i)
+ {
+ char& c (s[i]);
+
+ if (i == 0)
+ {
+ if (!((c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ c == '_'))
+ c = '_';
+ }
+ else
+ {
+ if (!((c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') ||
+ c == '_'))
+ c = '_';
+ }
+ }
+}
+
+void error_handler::
+warning (const SAXParseException& e)
+{
+ handle (e, s_warning);
+}
+
+void error_handler::
+error (const SAXParseException& e)
+{
+ failed_ = true;
+ handle (e, s_error);
+}
+
+void error_handler::
+fatalError (const SAXParseException& e)
+{
+ failed_ = true;
+ handle (e, s_fatal);
+}
+
+void error_handler::
+handle (const SAXParseException& e, severity s)
+{
+ const XMLCh* xid (e.getPublicId ());
+
+ if (xid == 0)
+ xid = e.getSystemId ();
+
+ char* id (XMLString::transcode (xid));
+ char* msg (XMLString::transcode (e.getMessage ()));
+
+ cerr << id << ":";
+
+#if _XERCES_VERSION >= 30000
+ cerr << e.getLineNumber () << ":" << e.getColumnNumber () << " ";
+#else
+ XMLSSize_t l (e.getLineNumber ());
+ XMLSSize_t c (e.getColumnNumber ());
+ cerr << (l == -1 ? 0 : l) << ":" << (c == -1 ? 0 : c) << " ";
+#endif
+
+ cerr << (s == s_warning ? "warning: " : "error: ") << msg << endl;
+
+ XMLString::release (&id);
+ XMLString::release (&msg);
+}