From 5e527213a2430bb3018e5eebd909aef294edf9b5 Mon Sep 17 00:00:00 2001 From: Karen Arutyunov Date: Fri, 18 Dec 2020 18:48:46 +0300 Subject: Switch to build2 --- xsd-examples/cxx/tree/compression/.gitignore | 2 + xsd-examples/cxx/tree/compression/README | 48 +++++ xsd-examples/cxx/tree/compression/buildfile | 28 +++ .../tree/compression/compressed-format-target.cxx | 152 ++++++++++++++++ .../tree/compression/compressed-format-target.hxx | 91 ++++++++++ .../tree/compression/compressed-input-source.cxx | 195 +++++++++++++++++++++ .../tree/compression/compressed-input-source.hxx | 121 +++++++++++++ xsd-examples/cxx/tree/compression/driver.cxx | 124 +++++++++++++ xsd-examples/cxx/tree/compression/library.xml.gz | Bin 0 -> 486 bytes xsd-examples/cxx/tree/compression/library.xsd | 72 ++++++++ xsd-examples/cxx/tree/compression/testscript | 4 + 11 files changed, 837 insertions(+) create mode 100644 xsd-examples/cxx/tree/compression/.gitignore create mode 100644 xsd-examples/cxx/tree/compression/README create mode 100644 xsd-examples/cxx/tree/compression/buildfile create mode 100644 xsd-examples/cxx/tree/compression/compressed-format-target.cxx create mode 100644 xsd-examples/cxx/tree/compression/compressed-format-target.hxx create mode 100644 xsd-examples/cxx/tree/compression/compressed-input-source.cxx create mode 100644 xsd-examples/cxx/tree/compression/compressed-input-source.hxx create mode 100644 xsd-examples/cxx/tree/compression/driver.cxx create mode 100644 xsd-examples/cxx/tree/compression/library.xml.gz create mode 100644 xsd-examples/cxx/tree/compression/library.xsd create mode 100644 xsd-examples/cxx/tree/compression/testscript (limited to 'xsd-examples/cxx/tree/compression') diff --git a/xsd-examples/cxx/tree/compression/.gitignore b/xsd-examples/cxx/tree/compression/.gitignore new file mode 100644 index 0000000..f7293f9 --- /dev/null +++ b/xsd-examples/cxx/tree/compression/.gitignore @@ -0,0 +1,2 @@ +library.?xx +out.xml.gz diff --git a/xsd-examples/cxx/tree/compression/README b/xsd-examples/cxx/tree/compression/README new file mode 100644 index 0000000..f163970 --- /dev/null +++ b/xsd-examples/cxx/tree/compression/README @@ -0,0 +1,48 @@ +This example shows how to compress an XML document during serialization +and decompress it during parsing. The example uses the compression +functionality provided by the zlib library[1] which needs to be installed +in order to build and run this example. It should also be fairly straight- +forward to modify the code in this example to use other compression +libraries. + +[1] http://www.zlib.net + +The example consists of the following files: + +library.xsd + XML Schema which describes a library of books. + +library.xml.gz + Sample XML instance document compressed using the gzip format. + +compressed-format-target.hxx +compressed-format-target.cxx + Implementation of the Xerces-C++ XMLFormatTarget interface with the on- + the-fly compression support. You can use it in your application to add + XML compression. + +compressed-input-source.hxx +compressed-input-source.cxx + Implementation of the Xerces-C++ InputSource interface with the on-the- + fly decompression support. You can use it in your application to add + XML decompression. + +library.hxx +library.cxx + C++ types that represent the given vocabulary and a set of parsing + functions that convert XML instance documents to a tree-like in-memory + object model. These are generated by XSD from library.xsd. + +driver.cxx + Driver for the example. It first creates the compressed_input_source + object and passes it to one of the parsing functions that constructs + the object model from the compressed input file. It then prints the + content of the object model to STDERR. Finally, the driver creates the + compressed_format_target object and passes it to one of the serialization + functions which converts the object model back to the compressed XML. + +To run the example on the sample XML document simply execute: + +$ ./driver library.xml.gz + +The serialization output is written to the out.xml.gz file. diff --git a/xsd-examples/cxx/tree/compression/buildfile b/xsd-examples/cxx/tree/compression/buildfile new file mode 100644 index 0000000..6997339 --- /dev/null +++ b/xsd-examples/cxx/tree/compression/buildfile @@ -0,0 +1,28 @@ +# file : cxx/tree/compression/buildfile +# license : not copyrighted - public domain + +import libs = libxsd%lib{xsd} +import libs += libxerces-c%lib{xerces-c} +import libs += libz%lib{z} + +./: exe{driver} file{library.xml.gz} doc{README} + +exe{driver}: {hxx cxx}{* -library} {hxx ixx cxx}{library} $libs testscript + +<{hxx ixx cxx}{library}>: xsd{library} $xsd +{{ + diag xsd ($<[0]) # @@ TMP + + $xsd cxx-tree --std c++11 \ + --generate-inline \ + --generate-serialization \ + --generate-ostream \ + --output-dir $out_base \ + $path($<[0]) +}} + +cxx.poptions =+ "-I$out_base" "-I$src_base" + +# Define XSD_CXX11 since we include libxsd headers directly. +# +cxx.poptions += -DXSD_CXX11 diff --git a/xsd-examples/cxx/tree/compression/compressed-format-target.cxx b/xsd-examples/cxx/tree/compression/compressed-format-target.cxx new file mode 100644 index 0000000..2d150a0 --- /dev/null +++ b/xsd-examples/cxx/tree/compression/compressed-format-target.cxx @@ -0,0 +1,152 @@ +// file : cxx/tree/compression/compressed-format-target.cxx +// copyright : not copyrighted - public domain + +#include +#include // std::memcpy + +#include "compressed-format-target.hxx" + +using namespace std; + +// +// compression_failure +// + +const char* compression_failure:: +what () const throw () +{ + return "compression failure"; +} + +// +// compressed_format_target +// + +compressed_format_target:: +compressed_format_target (ostream& os, compression_type t) + : os_ (os), closed_ (false), n_ (0) + { + zs_.zalloc = Z_NULL; + zs_.zfree = Z_NULL; + zs_.opaque = Z_NULL; + + int window = 0; + + switch (t) + { + case raw: + { + window = -15; + break; + } + case zlib: + { + window = 15; + break; + } + case gzip: + { + window = 16 + 15; + break; + } + } + + int r (deflateInit2 (&zs_, + Z_DEFAULT_COMPRESSION, + Z_DEFLATED, + window, + 8, + Z_DEFAULT_STRATEGY)); + if (r != Z_OK) + throw compression_failure (r); + } + +compressed_format_target:: +~compressed_format_target () +{ + try + { + // Close the free the compression stream. + // + if (!closed_) + close (); + } + catch (...) + { + } + + deflateEnd (&zs_); +} + +void compressed_format_target:: +writeChars (const XMLByte* const buf, + const XMLSize_t size, + xercesc::XMLFormatter* const) +{ + // Flush the buffer if the block is too large or if we don't have + // any space left. + // + if ((size >= buf_size_ / 8 || n_ + size > buf_size_) && n_ != 0) + { + write (in_, n_); + n_ = 0; + } + + if (size < buf_size_ / 8) + { + memcpy (in_ + n_, reinterpret_cast (buf), size); + n_ += size; + } + else + write (reinterpret_cast (buf), size); +} + + +void compressed_format_target:: +flush () +{ + if (n_ != 0) + { + write (in_, n_); + n_ = 0; + } + + if (!os_.fail ()) + os_.flush (); +} + +void compressed_format_target:: +close () +{ + write (in_, n_, true); + n_ = 0; + + if (!os_.fail ()) + os_.flush (); + + closed_ = true; +} + +void compressed_format_target:: +write (const char* buf, size_t size, bool flush) +{ + zs_.next_in = reinterpret_cast (const_cast (buf)); + zs_.avail_in = static_cast (size); + + do + { + zs_.next_out = reinterpret_cast (out_); + zs_.avail_out = buf_size_; + + int r (deflate (&zs_, flush ? Z_FINISH : Z_NO_FLUSH)); + + if (r != Z_OK && r != Z_BUF_ERROR && r != Z_STREAM_END) + throw compression_failure (r); + + size_t n (buf_size_ - zs_.avail_out); + + if (!os_.fail () && n > 0) + os_.write (out_, static_cast (n)); + + } while (zs_.avail_out == 0); +} diff --git a/xsd-examples/cxx/tree/compression/compressed-format-target.hxx b/xsd-examples/cxx/tree/compression/compressed-format-target.hxx new file mode 100644 index 0000000..0061cfa --- /dev/null +++ b/xsd-examples/cxx/tree/compression/compressed-format-target.hxx @@ -0,0 +1,91 @@ +// file : cxx/tree/compression/compressed-format-target.hxx +// copyright : not copyrighted - public domain + +#ifndef COMPRESSED_FORMAT_TARGET_HXX +#define COMPRESSED_FORMAT_TARGET_HXX + +#include + +#include +#include // std::size_t +#include + +#include + +struct compression_failure: std::exception +{ + explicit + compression_failure (int code) + : code_ (code) + { + } + + int + code () const + { + return code_; + } + + const char* + message () const + { + return zError (code_); + } + + virtual const char* + what () const throw (); + +private: + int code_; +}; + +// Xerces-C++ XMLFormatTarget interface implementation with on-the-fly, +// zlib-based compression. +// +class compressed_format_target: public xercesc::XMLFormatTarget +{ +public: + enum compression_type + { + raw, + zlib, + gzip + }; + + compressed_format_target (std::ostream&, compression_type); + + virtual + ~compressed_format_target (); + + virtual void + writeChars (const XMLByte* const buf, + const XMLSize_t size, + xercesc::XMLFormatter* const); + + virtual void + flush (); + + // Close the compressed stream by writing out the zlib or gzip trailer. + // This function is automatically called from the destructor but you + // may want to call it explicitly to be able to catch any exceptions + // that it might throw. + // + void + close (); + +private: + void + write (const char* buf, std::size_t size, bool flush = false); + +private: + std::ostream& os_; + z_stream zs_; + bool closed_; + + static const std::size_t buf_size_ = 65536; + char in_[buf_size_]; + char out_[buf_size_]; + size_t n_; +}; + +#endif // COMPRESSED_FORMAT_TARGET_HXX diff --git a/xsd-examples/cxx/tree/compression/compressed-input-source.cxx b/xsd-examples/cxx/tree/compression/compressed-input-source.cxx new file mode 100644 index 0000000..03be960 --- /dev/null +++ b/xsd-examples/cxx/tree/compression/compressed-input-source.cxx @@ -0,0 +1,195 @@ +// file : cxx/tree/compression/compressed-input-source.cxx +// copyright : not copyrighted - public domain + +#include + +#include + +#include "compressed-input-source.hxx" + +using namespace std; +using namespace xercesc; +namespace xml = xsd::cxx::xml; + +// +// decompression_failure +// + +const char* decompression_failure:: +what () const throw () +{ + return "decompression failure"; +} + +// +// compressed_input_source +// + +compressed_input_source:: +compressed_input_source (istream& is, compression_type t) + : is_ (&is), type_ (t) +{ +} + +compressed_input_source:: +compressed_input_source (istream& is, + compression_type t, + const string& sysid) + : InputSource (xml::string (sysid).c_str ()), is_ (&is), type_ (t) +{ +} + +compressed_input_source:: +compressed_input_source (istream& is, + compression_type t, + const string& sysid, + const string& pubid) + : xercesc::InputSource (xml::string (sysid).c_str (), + xml::string (pubid).c_str ()), + is_ (&is), + type_ (t) +{ +} + +BinInputStream* compressed_input_source:: +makeStream () const +{ + if (is_ == 0) + throw copy (); + + istream& is (*is_); + is_ = 0; + return new compressed_input_stream ( + is, static_cast (type_)); +} + +// +// compressed_input_stream +// + +compressed_input_stream:: +compressed_input_stream (istream& is, compression_type t) + : is_ (is), end_ (false), pos_ (0) +{ + zs_.zalloc = Z_NULL; + zs_.zfree = Z_NULL; + zs_.opaque = Z_NULL; + zs_.next_in = Z_NULL; + zs_.avail_in = 0; + + int window = 0; + + switch (t) + { + case raw: + { + window = -15; + break; + } + case zlib: + { + window = 15; + break; + } + case gzip: + { + window = 16 + 15; + break; + } + } + + int r (inflateInit2 (&zs_, window)); + + if (r != Z_OK) + throw decompression_failure (r); +} + +compressed_input_stream:: +~compressed_input_stream () +{ + inflateEnd (&zs_); +} + +XMLFilePos compressed_input_stream:: +curPos () const +{ + return static_cast (pos_); +} + +XMLSize_t compressed_input_stream:: +readBytes (XMLByte* const buf, const XMLSize_t size) +{ + if (end_) + return 0; + + // Keep calling inflate() until we fill up the buffer or reach the + // end of stream. If we run out of input data, call the underlying + // stream for more. + // + zs_.next_out = reinterpret_cast (buf); + zs_.avail_out = static_cast (size); + + int r; + + do + { + if (zs_.avail_in == 0) + { + zs_.avail_in = static_cast (read ()); + zs_.next_in = reinterpret_cast (const_cast (in_)); + + if (zs_.avail_in == 0) + throw decompression_failure (Z_DATA_ERROR); + } + + r = inflate (&zs_, Z_NO_FLUSH); + + if (r != Z_OK && r != Z_STREAM_END) + throw decompression_failure (r); + + } while (r != Z_STREAM_END && zs_.avail_out != 0); + + if (r == Z_STREAM_END) + end_ = true; + + size_t n (size - zs_.avail_out); + pos_ += n; + + return static_cast (n); +} + +const XMLCh* compressed_input_stream:: +getContentType () const +{ + return 0; +} + +size_t compressed_input_stream:: +read () +{ + // Some implementations don't clear gcount if you call read() on a + // stream that is in the eof state. + // + if (is_.eof ()) + return 0; + + // Unset the exception failbit while we are working with the stream. + // + ios_base::iostate old (is_.exceptions ()); + is_.exceptions (old & ~ios_base::failbit); + + is_.read (in_, static_cast (buf_size_)); + + // Clear the fail bit if it was caused by eof and restore the original + // exception state. If there are any pending errors then the exception + // will be thrown now. + // + if (is_.fail () && is_.eof ()) + is_.clear (is_.rdstate () & ~ios_base::failbit); + + is_.exceptions (old); + + // Make sure that if we failed, we won't be called again. + // + return !is_.fail () ? static_cast (is_.gcount ()) : 0; +} diff --git a/xsd-examples/cxx/tree/compression/compressed-input-source.hxx b/xsd-examples/cxx/tree/compression/compressed-input-source.hxx new file mode 100644 index 0000000..706433b --- /dev/null +++ b/xsd-examples/cxx/tree/compression/compressed-input-source.hxx @@ -0,0 +1,121 @@ +// file : cxx/tree/compression/compressed-input-source.hxx +// copyright : not copyrighted - public domain + +#ifndef COMPRESSED_INPUT_SOURCE_HXX +#define COMPRESSED_INPUT_SOURCE_HXX + +#include + +#include +#include +#include // std::size_t +#include + +#include +#include + +struct decompression_failure: std::exception +{ + explicit + decompression_failure (int code) + : code_ (code) + { + } + + int + code () const + { + return code_; + } + + const char* + message () const + { + return zError (code_); + } + + virtual const char* + what () const throw (); + +private: + int code_; +}; + +// Xerces-C++ InputSource interface implementation with on-the-fly, zlib- +// based decompression. +// +class compressed_input_source: public xercesc::InputSource +{ +public: + enum compression_type + { + raw, + zlib, + gzip + }; + + compressed_input_source (std::istream&, compression_type); + + compressed_input_source (std::istream&, + compression_type, + const std::string& system_id); + + compressed_input_source (std::istream&, + compression_type, + const std::string& system_id, + const std::string& public_id); + + struct copy {}; + + // Throws the copy exception if this function is called more than once. + // + virtual xercesc::BinInputStream* + makeStream () const; + +private: + mutable std::istream* is_; + compression_type type_; +}; + +// Xerces-C++ BinInputStream interface implementation with on-the-fly, zlib- +// based decompression. +// +class compressed_input_stream: public xercesc::BinInputStream +{ +public: + enum compression_type + { + raw, + zlib, + gzip + }; + + compressed_input_stream (std::istream&, compression_type); + + virtual + ~compressed_input_stream (); + + virtual XMLFilePos + curPos () const; + + virtual XMLSize_t + readBytes (XMLByte* const buf, const XMLSize_t size); + + virtual const XMLCh* + getContentType () const; + +private: + std::size_t + read (); + +private: + std::istream& is_; + z_stream zs_; + bool end_; + + static const std::size_t buf_size_ = 65536; + char in_[buf_size_]; + std::size_t pos_; // Current decompressed stream position. +}; + +#endif // COMPRESSED_INPUT_SOURCE_HXX diff --git a/xsd-examples/cxx/tree/compression/driver.cxx b/xsd-examples/cxx/tree/compression/driver.cxx new file mode 100644 index 0000000..15d842b --- /dev/null +++ b/xsd-examples/cxx/tree/compression/driver.cxx @@ -0,0 +1,124 @@ +// file : cxx/tree/compression/driver.cxx +// copyright : not copyrighted - public domain + +#include // std::unique_ptr +#include +#include + +#include + +#include "library.hxx" + +#include "compressed-input-source.hxx" +#include "compressed-format-target.hxx" + +using namespace std; + +int +main (int argc, char* argv[]) +{ + if (argc != 2) + { + cerr << "usage: " << argv[0] << " library.xml.gz" << endl; + return 1; + } + + int r (0); + + // We need to initialize the Xerces-C++ runtime because we are + // using the Xerces-C++ input/output interfaces. + // + xercesc::XMLPlatformUtils::Initialize (); + + try + { + using namespace library; + + // Read in the XML file and obtain its object model. + // + ifstream ifs; + ifs.exceptions (ifstream::badbit | ifstream::failbit); + ifs.open (argv[1], ifstream::in | ifstream::binary); + + compressed_input_source cis (ifs, compressed_input_source::gzip, argv[1]); + + unique_ptr c ( + catalog_ (cis, xml_schema::flags::dont_initialize)); + + + // Let's print what we've got. + // + for (catalog::book_const_iterator bi (c->book ().begin ()); + bi != c->book ().end (); + ++bi) + { + cerr << endl + << "ID : " << bi->id () << endl + << "ISBN : " << bi->isbn () << endl + << "Title : " << bi->title () << endl + << "Genre : " << bi->genre () << endl; + + for (book::author_const_iterator ai (bi->author ().begin ()); + ai != bi->author ().end (); + ++ai) + { + cerr << "Author : " << ai->name () << endl; + cerr << " Born : " << ai->born () << endl; + + if (ai->died ()) + cerr << " Died : " << *ai->died () << endl; + + if (ai->recommends ()) + cerr << " Recommends : " << (*ai->recommends ())->title () << endl; + } + + cerr << "Available : " << std::boolalpha << bi->available () << endl; + } + + // Prepare namespace mapping and schema location information. + // + xml_schema::namespace_infomap map; + + map["lib"].name = "http://www.codesynthesis.com/library"; + map["lib"].schema = "library.xsd"; + + ofstream ofs; + ofs.exceptions (ofstream::badbit | ofstream::failbit | ofstream::eofbit); + ofs.open ("out.xml.gz", ofstream::out | ofstream::binary); + + compressed_format_target cft (ofs, compressed_format_target::gzip); + + // Write it out. + // + catalog_ (cft, *c, map, "UTF-8", xml_schema::flags::dont_initialize); + + // Write out the compression stream trailer. If we don't do this + // explicitly, it will be done automatically in the cft's destructor + // but then any exceptions that might be throws will be ignored. + // + cft.close(); + } + catch (const xml_schema::exception& e) + { + cerr << e << endl; + r = 1; + } + catch (const compression_failure& e) + { + cerr << "compression failure: " << e.message () << endl; + r = 1; + } + catch (const decompression_failure& e) + { + cerr << "decompression failure: " << e.message () << endl; + r = 1; + } + catch (const ios_base::failure&) + { + cerr << "file open or read/write failure" << endl; + r = 1; + } + + xercesc::XMLPlatformUtils::Terminate (); + return r; +} diff --git a/xsd-examples/cxx/tree/compression/library.xml.gz b/xsd-examples/cxx/tree/compression/library.xml.gz new file mode 100644 index 0000000..dd71159 Binary files /dev/null and b/xsd-examples/cxx/tree/compression/library.xml.gz differ diff --git a/xsd-examples/cxx/tree/compression/library.xsd b/xsd-examples/cxx/tree/compression/library.xsd new file mode 100644 index 0000000..a741e7e --- /dev/null +++ b/xsd-examples/cxx/tree/compression/library.xsd @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/xsd-examples/cxx/tree/compression/testscript b/xsd-examples/cxx/tree/compression/testscript new file mode 100644 index 0000000..649de5a --- /dev/null +++ b/xsd-examples/cxx/tree/compression/testscript @@ -0,0 +1,4 @@ +# file : cxx/tree/compression/testscript +# license : not copyrighted - public domain + +$* $src_base/library.xml.gz &out.xml.gz 2>| : compressed-out -- cgit v1.1