serializer.cxx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. // file : xml/serializer.cxx
  2. // copyright : Copyright (c) 2013-2014 Code Synthesis Tools CC
  3. // license : MIT; see accompanying LICENSE file
  4. #include <new> // std::bad_alloc
  5. #include <cstring> // std::strlen
  6. #include <xml/serializer>
  7. using namespace std;
  8. namespace xml
  9. {
  10. // serialization
  11. //
  12. serialization::
  13. ~serialization () throw () {}
  14. serialization::
  15. serialization (const string& n, const string& d)
  16. : name_ (n), description_ (d)
  17. {
  18. init ();
  19. }
  20. serialization::
  21. serialization (const serializer& s, const std::string& d)
  22. : name_ (s.output_name ()), description_ (d)
  23. {
  24. init ();
  25. }
  26. void serialization::
  27. init ()
  28. {
  29. if (!name_.empty ())
  30. {
  31. what_ += name_;
  32. what_ += ": ";
  33. }
  34. what_ += "error: ";
  35. what_ += description_;
  36. }
  37. char const* serialization::
  38. what () const throw ()
  39. {
  40. return what_.c_str ();
  41. }
  42. // serializer
  43. //
  44. extern "C" genxStatus
  45. genx_write (void* p, constUtf8 us)
  46. {
  47. // It would have been easier to throw the exception directly,
  48. // however, the Genx code is most likely not exception safe.
  49. //
  50. ostream* os (static_cast<ostream*> (p));
  51. const char* s (reinterpret_cast<const char*> (us));
  52. os->write (s, static_cast<streamsize> (strlen (s)));
  53. return os->good () ? GENX_SUCCESS : GENX_IO_ERROR;
  54. }
  55. extern "C" genxStatus
  56. genx_write_bound (void* p, constUtf8 start, constUtf8 end)
  57. {
  58. ostream* os (static_cast<ostream*> (p));
  59. const char* s (reinterpret_cast<const char*> (start));
  60. streamsize n (static_cast<streamsize> (end - start));
  61. os->write (s, n);
  62. return os->good () ? GENX_SUCCESS : GENX_IO_ERROR;
  63. }
  64. extern "C" genxStatus
  65. genx_flush (void* p)
  66. {
  67. ostream* os (static_cast<ostream*> (p));
  68. os->flush ();
  69. return os->good () ? GENX_SUCCESS : GENX_IO_ERROR;
  70. }
  71. serializer::
  72. ~serializer ()
  73. {
  74. if (s_ != 0)
  75. genxDispose (s_);
  76. }
  77. serializer::
  78. serializer (ostream& os, const string& oname, unsigned short ind)
  79. : os_ (os), os_state_ (os.exceptions ()), oname_ (oname), depth_ (0)
  80. {
  81. // Temporarily disable exceptions on the stream.
  82. //
  83. os_.exceptions (ostream::goodbit);
  84. // Allocate the serializer. Make sure nothing else can throw after
  85. // this call since otherwise we will leak it.
  86. //
  87. s_ = genxNew (0, 0, 0);
  88. if (s_ == 0)
  89. throw bad_alloc ();
  90. genxSetUserData (s_, &os_);
  91. if (ind != 0)
  92. genxSetPrettyPrint (s_, ind);
  93. sender_.send = &genx_write;
  94. sender_.sendBounded = &genx_write_bound;
  95. sender_.flush = &genx_flush;
  96. if (genxStatus e = genxStartDocSender (s_, &sender_))
  97. {
  98. string m (genxGetErrorMessage (s_, e));
  99. genxDispose (s_);
  100. throw serialization (oname, m);
  101. }
  102. }
  103. void serializer::
  104. handle_error (genxStatus e)
  105. {
  106. switch (e)
  107. {
  108. case GENX_ALLOC_FAILED:
  109. throw bad_alloc ();
  110. case GENX_IO_ERROR:
  111. // Restoring the original exception state should trigger the
  112. // exception. If it doesn't (e.g., because the user didn't
  113. // configure the stream to throw), then fall back to the
  114. // serialiation exception.
  115. //
  116. os_.exceptions (os_state_);
  117. // Fall through.
  118. default:
  119. throw serialization (oname_, genxGetErrorMessage (s_, e));
  120. }
  121. }
  122. void serializer::
  123. start_element (const string& ns, const string& name)
  124. {
  125. if (genxStatus e = genxStartElementLiteral (
  126. s_,
  127. reinterpret_cast<constUtf8> (ns.empty () ? 0 : ns.c_str ()),
  128. reinterpret_cast<constUtf8> (name.c_str ())))
  129. handle_error (e);
  130. depth_++;
  131. }
  132. void serializer::
  133. end_element ()
  134. {
  135. if (genxStatus e = genxEndElement (s_))
  136. handle_error (e);
  137. // Call EndDocument() if we are past the root element.
  138. //
  139. if (--depth_ == 0)
  140. {
  141. if (genxStatus e = genxEndDocument (s_))
  142. handle_error (e);
  143. // Also restore the original exception state on the stream.
  144. //
  145. os_.exceptions (os_state_);
  146. }
  147. }
  148. void serializer::
  149. element (const string& ns, const string& n, const string& v)
  150. {
  151. start_element (ns, n);
  152. element (v);
  153. }
  154. void serializer::
  155. start_attribute (const string& ns, const string& name)
  156. {
  157. if (genxStatus e = genxStartAttributeLiteral (
  158. s_,
  159. reinterpret_cast<constUtf8> (ns.empty () ? 0 : ns.c_str ()),
  160. reinterpret_cast<constUtf8> (name.c_str ())))
  161. handle_error (e);
  162. }
  163. void serializer::
  164. end_attribute ()
  165. {
  166. if (genxStatus e = genxEndAttribute (s_))
  167. handle_error (e);
  168. }
  169. void serializer::
  170. attribute (const string& ns,
  171. const string& name,
  172. const string& value)
  173. {
  174. if (genxStatus e = genxAddAttributeLiteral (
  175. s_,
  176. reinterpret_cast<constUtf8> (ns.empty () ? 0 : ns.c_str ()),
  177. reinterpret_cast<constUtf8> (name.c_str ()),
  178. reinterpret_cast<constUtf8> (value.c_str ())))
  179. handle_error (e);
  180. }
  181. void serializer::
  182. characters (const string& value)
  183. {
  184. if (genxStatus e = genxAddCountedText (
  185. s_,
  186. reinterpret_cast<constUtf8> (value.c_str ()), value.size ()))
  187. handle_error (e);
  188. }
  189. void serializer::
  190. namespace_decl (const string& ns, const string& p)
  191. {
  192. if (genxStatus e = ns.empty () && p.empty ()
  193. ? genxUnsetDefaultNamespace (s_)
  194. : genxAddNamespaceLiteral (
  195. s_,
  196. reinterpret_cast<constUtf8> (ns.c_str ()),
  197. reinterpret_cast<constUtf8> (p.c_str ())))
  198. handle_error (e);
  199. }
  200. void serializer::
  201. xml_decl (const string& ver, const string& enc, const string& stl)
  202. {
  203. if (genxStatus e = genxXmlDeclaration (
  204. s_,
  205. reinterpret_cast<constUtf8> (ver.c_str ()),
  206. (enc.empty () ? 0 : reinterpret_cast<constUtf8> (enc.c_str ())),
  207. (stl.empty () ? 0 : reinterpret_cast<constUtf8> (stl.c_str ()))))
  208. handle_error (e);
  209. }
  210. bool serializer::
  211. lookup_namespace_prefix (const string& ns, string& p)
  212. {
  213. // Currently Genx will create a namespace mapping if one doesn't
  214. // already exist.
  215. //
  216. genxStatus e;
  217. genxNamespace gns (
  218. genxDeclareNamespace (
  219. s_, reinterpret_cast<constUtf8> (ns.c_str ()), 0, &e));
  220. if (e != GENX_SUCCESS)
  221. handle_error (e);
  222. p = reinterpret_cast<const char*> (genxGetNamespacePrefix (gns));
  223. return true;
  224. }
  225. }