aboutsummaryrefslogtreecommitdiff
path: root/cutl/xml/serializer.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'cutl/xml/serializer.cxx')
-rw-r--r--cutl/xml/serializer.cxx245
1 files changed, 245 insertions, 0 deletions
diff --git a/cutl/xml/serializer.cxx b/cutl/xml/serializer.cxx
new file mode 100644
index 0000000..66c78a4
--- /dev/null
+++ b/cutl/xml/serializer.cxx
@@ -0,0 +1,245 @@
+// file : cutl/xml/serializer.cxx
+// copyright : Copyright (c) 2009-2013 Code Synthesis Tools CC
+// license : MIT; see accompanying LICENSE file
+
+#include <new> // std::bad_alloc
+#include <cstring> // std::strlen
+
+#include <cutl/xml/serializer.hxx>
+
+using namespace std;
+
+namespace cutl
+{
+ namespace xml
+ {
+ // serialization
+ //
+ serialization::
+ ~serialization () throw () {}
+
+ serialization::
+ serialization (const string& n, const string& d)
+ : name_ (n), description_ (d)
+ {
+ if (!n.empty ())
+ {
+ what_ += n;
+ what_ += ": ";
+ }
+
+ what_ += "error: ";
+ what_ += d;
+ }
+
+ char const* serialization::
+ what () const throw ()
+ {
+ return what_.c_str ();
+ }
+
+ // serializer
+ //
+ extern "C" genxStatus
+ genx_write (void* p, constUtf8 us)
+ {
+ // It would have been easier to throw the exception directly,
+ // however, the Genx code is most likely not exception safe.
+ //
+ ostream* os (static_cast<ostream*> (p));
+ const char* s (reinterpret_cast<const char*> (us));
+ os->write (s, static_cast<streamsize> (strlen (s)));
+ return os->good () ? GENX_SUCCESS : GENX_IO_ERROR;
+ }
+
+ extern "C" genxStatus
+ genx_write_bound (void* p, constUtf8 start, constUtf8 end)
+ {
+ ostream* os (static_cast<ostream*> (p));
+ const char* s (reinterpret_cast<const char*> (start));
+ streamsize n (static_cast<streamsize> (end - start));
+ os->write (s, n);
+ return os->good () ? GENX_SUCCESS : GENX_IO_ERROR;
+ }
+
+ extern "C" genxStatus
+ genx_flush (void* p)
+ {
+ ostream* os (static_cast<ostream*> (p));
+ os->flush ();
+ return os->good () ? GENX_SUCCESS : GENX_IO_ERROR;
+ }
+
+ serializer::
+ ~serializer ()
+ {
+ if (s_ != 0)
+ genxDispose (s_);
+ }
+
+ serializer::
+ serializer (ostream& os, const string& name, unsigned short ind)
+ : os_ (os), os_state_ (os.exceptions ()), name_ (name), depth_ (0)
+ {
+ // Temporarily disable exceptions on the stream.
+ //
+ os_.exceptions (ostream::goodbit);
+
+ // Allocate the serializer. Make sure nothing else can throw after
+ // this call since otherwise we will leak it.
+ //
+ s_ = genxNew (0, 0, 0);
+
+ if (s_ == 0)
+ throw bad_alloc ();
+
+ genxSetUserData (s_, &os_);
+
+ if (ind != 0)
+ genxSetPrettyPrint (s_, ind);
+
+ sender_.send = &genx_write;
+ sender_.sendBounded = &genx_write_bound;
+ sender_.flush = &genx_flush;
+
+ if (genxStatus e = genxStartDocSender (s_, &sender_))
+ {
+ string m (genxGetErrorMessage (s_, e));
+ genxDispose (s_);
+ throw serialization (name, m);
+ }
+ }
+
+ void serializer::
+ handle_error (genxStatus e)
+ {
+ switch (e)
+ {
+ case GENX_ALLOC_FAILED:
+ throw bad_alloc ();
+ case GENX_IO_ERROR:
+ // Restoring the original exception state should trigger the
+ // exception. If it doesn't (e.g., because the user didn't
+ // configure the stream to throw), then fall back to the
+ // serialiation exception.
+ //
+ os_.exceptions (os_state_);
+ // Fall through.
+ default:
+ throw serialization (name_, genxGetErrorMessage (s_, e));
+ }
+ }
+
+ void serializer::
+ start_element (const string& ns, const string& name)
+ {
+ if (genxStatus e = genxStartElementLiteral (
+ s_,
+ reinterpret_cast<constUtf8> (ns.empty () ? 0 : ns.c_str ()),
+ reinterpret_cast<constUtf8> (name.c_str ())))
+ handle_error (e);
+
+ depth_++;
+ }
+
+ void serializer::
+ end_element ()
+ {
+ if (genxStatus e = genxEndElement (s_))
+ handle_error (e);
+
+ // Call EndDocument() if we are past the root element.
+ //
+ if (--depth_ == 0)
+ {
+ if (genxStatus e = genxEndDocument (s_))
+ handle_error (e);
+
+ // Also restore the original exception state on the stream.
+ //
+ os_.exceptions (os_state_);
+ }
+ }
+
+ void serializer::
+ start_attribute (const string& ns, const string& name)
+ {
+ if (genxStatus e = genxStartAttributeLiteral (
+ s_,
+ reinterpret_cast<constUtf8> (ns.empty () ? 0 : ns.c_str ()),
+ reinterpret_cast<constUtf8> (name.c_str ())))
+ handle_error (e);
+ }
+
+ void serializer::
+ end_attribute ()
+ {
+ if (genxStatus e = genxEndAttribute (s_))
+ handle_error (e);
+ }
+
+ void serializer::
+ attribute (const string& ns,
+ const string& name,
+ const string& value)
+ {
+ if (genxStatus e = genxAddAttributeLiteral (
+ s_,
+ reinterpret_cast<constUtf8> (ns.empty () ? 0 : ns.c_str ()),
+ reinterpret_cast<constUtf8> (name.c_str ()),
+ reinterpret_cast<constUtf8> (value.c_str ())))
+ handle_error (e);
+ }
+
+ void serializer::
+ characters (const string& value)
+ {
+ if (genxStatus e = genxAddCountedText (
+ s_,
+ reinterpret_cast<constUtf8> (value.c_str ()),
+ static_cast<int> (value.size ())))
+ handle_error (e);
+ }
+
+ void serializer::
+ namespace_decl (const string& ns, const string& p)
+ {
+ if (genxStatus e = ns.empty () && p.empty ()
+ ? genxUnsetDefaultNamespace (s_)
+ : genxAddNamespaceLiteral (
+ s_,
+ reinterpret_cast<constUtf8> (ns.c_str ()),
+ reinterpret_cast<constUtf8> (p.c_str ())))
+ handle_error (e);
+ }
+
+ void serializer::
+ xml_decl (const string& ver, const string& enc, const string& stl)
+ {
+ if (genxStatus e = genxXmlDeclaration (
+ s_,
+ reinterpret_cast<constUtf8> (ver.c_str ()),
+ (enc.empty () ? 0 : reinterpret_cast<constUtf8> (enc.c_str ())),
+ (stl.empty () ? 0 : reinterpret_cast<constUtf8> (stl.c_str ()))))
+ handle_error (e);
+ }
+
+ bool serializer::
+ lookup_namespace_prefix (const string& ns, string& p)
+ {
+ // Currently Genx will create a namespace mapping if one doesn't
+ // already exist.
+ //
+ genxStatus e;
+ genxNamespace gns (
+ genxDeclareNamespace (
+ s_, reinterpret_cast<constUtf8> (ns.c_str ()), 0, &e));
+
+ if (e != GENX_SUCCESS)
+ handle_error (e);
+
+ p = reinterpret_cast<const char*> (genxGetNamespacePrefix (gns));
+ return true;
+ }
+ }
+}