bes  Updated for version 3.20.13
BESXMLWriter.cc
1 /*
2  * BESXMLWriter.cpp
3  *
4  * Created on: Jul 28, 2010
5  * Author: jimg
6  */
7 
8 // Copyright (c) 2013 OPeNDAP, Inc. Author: James Gallagher
9 // <jgallagher@opendap.org>, Patrick West <pwest@opendap.org>
10 // Nathan Potter <npotter@opendap.org>
11 //
12 // modify it under the terms of the GNU Lesser General Public License
13 // as published by the Free Software Foundation; either version 2.1 of
14 // the License, or (at your option) any later version.
15 //
16 // This library is distributed in the hope that it will be useful, but
17 // WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
20 //
21 // License along with this library; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 // 02110-1301 U\ SA
24 //
25 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI.
26 // 02874-0112.
27 
28 #include "BESXMLWriter.h"
29 
30 #include <libxml/encoding.h>
31 #include <libxml/xmlwriter.h>
32 
33 #include <BESInternalFatalError.h>
34 
35 static const char *ENCODING = "ISO-8859-1";
36 // Hack
37 static const char *HAI_NS = "https://xml.opendap.org/ns/bes/admin/1.0#";
38 constexpr int XML_BUF_SIZE = 2000000;
39 
40 BESXMLWriter::BESXMLWriter() // : d_ns_uri(HAI_NS)
41 {
42  LIBXML_TEST_VERSION;
43 
44  /* Create a new XML buffer, to which the XML document will be
45  * written */
46  try {
47  if (!(d_doc_buf = xmlBufferCreateSize(XML_BUF_SIZE)))
48  throw BESInternalFatalError("Error allocating the xml buffer", __FILE__, __LINE__);
49 
50  xmlBufferSetAllocationScheme(d_doc_buf, XML_BUFFER_ALLOC_DOUBLEIT);
51 
52  /* Create a new XmlWriter for memory, with no compression.
53  * Remark: there is no compression for this kind of xmlTextWriter */
54  if (!(d_writer = xmlNewTextWriterMemory(d_doc_buf, 0)))
55  throw BESInternalFatalError("Error allocating memory for xml writer", __FILE__, __LINE__);
56 
57  if (xmlTextWriterSetIndent(d_writer, 4) < 0)
58  throw BESInternalFatalError("Error starting indentation for response document ", __FILE__, __LINE__);
59 
60  if (xmlTextWriterSetIndentString(d_writer, (const xmlChar*) " ") < 0)
61  throw BESInternalFatalError("Error setting indentation for response document ", __FILE__, __LINE__);
62 
63  d_started = true;
64  d_ended = false;
65 
66  /* Start the document with the xml default for the version,
67  * encoding ISO 8859-1 and the default for the standalone
68  * declaration. MY_ENCODING defined at top of this file*/
69  if (xmlTextWriterStartDocument(d_writer, NULL, ENCODING, NULL) < 0)
70  throw BESInternalFatalError("Error starting xml response document", __FILE__, __LINE__);
71 
72  /* Start an element named "Dataset". Since this is the first element,
73  * this will be the root element of the document */
74  if (xmlTextWriterStartElementNS(d_writer, (const xmlChar*) "hai", (const xmlChar*) "BesAdminCmd", (const xmlChar*) HAI_NS) < 0)
75  throw BESInternalFatalError("Error starting the response element for response ", __FILE__, __LINE__);
76  }
77  catch (BESInternalFatalError &e) {
78  m_cleanup();
79  throw;
80  }
81 }
82 
83 BESXMLWriter::~BESXMLWriter()
84 {
85  m_cleanup();
86 }
87 
88 void BESXMLWriter::m_cleanup()
89 {
90  // make sure the buffer and writer are all cleaned up
91  if (d_writer) {
92  xmlFreeTextWriter(d_writer);
93  d_writer = nullptr;
94  }
95  if (d_doc_buf) {
96  xmlBufferFree(d_doc_buf);
97  d_doc_buf = nullptr;
98  }
99 
100  d_started = false;
101  d_ended = false;
102 }
103 
104 const char *BESXMLWriter::get_doc()
105 {
106  if (d_writer && d_started) {
107  // this should end the response element
108  if (xmlTextWriterEndElement(d_writer) < 0)
109  throw BESInternalFatalError("Error ending Dataset element.", __FILE__, __LINE__);
110 
111  if (xmlTextWriterEndDocument(d_writer) < 0)
112  throw BESInternalFatalError("Error ending the document", __FILE__, __LINE__);
113 
114  d_ended = true;
115 
116  // must call this before getting the buffer content. Odd, but appears to be true.
117  // jhrg
118  xmlFreeTextWriter(d_writer);
119  d_writer = nullptr;
120  }
121 
122  // get the xml document as a string and return
123  if (!d_doc_buf->content)
124  throw BESInternalFatalError("Error retrieving response document as string", __FILE__, __LINE__);
125 
126  return (const char *) d_doc_buf->content;
127 }
exception thrown if an internal error is found and is fatal to the BES