NCBI C++ ToolKit
dtd.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /*
2  * Redistribution and use in source and binary forms, with or without
3  * modification, are permitted provided that the following conditions
4  * are met:
5  *
6  * 1. Redistributions of source code must retain the above copyright
7  * notice, this list of conditions and the following disclaimer.
8  * 2. Redistributions in binary form must reproduce the above copyright
9  * notice, this list of conditions and the following disclaimer in
10  * the documentation and/or other materials provided with the
11  * distribution.
12  * 3. Neither the name of the Author nor the names of its contributors
13  * may be used to endorse or promote products derived from this software
14  * without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
19  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
20  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /*
31  * $Id: dtd.cpp 101294 2023-11-28 14:10:36Z satskyse $
32  */
33 
34 /** @file
35  * This file contains the implementation of the xml::dtd class.
36 **/
37 
38 // xmlwrapp includes
39 #include <misc/xmlwrapp/dtd.hpp>
42 #include "document_impl.hpp"
43 #include "utility.hpp"
44 #include "https_input_impl.hpp"
45 
46 // standard includes
47 #include <stdexcept>
48 #include <cstdio>
49 #include <string.h>
50 #include <memory>
51 
52 // libxml includes
53 #include <libxml/valid.h>
54 #include <libxml/parser.h>
55 
56 
57 using namespace xml;
58 using namespace xml::impl;
59 
60 
61 namespace {
62  extern "C" void cb_dtd_error (void *v, const char *message, ...);
63  extern "C" void cb_dtd_warning (void *v, const char *message, ...);
64 }
65 
68 
69  xmlDtdPtr dtd_;
70  bool owned_;
71 };
72 
73 
74 static std::string get_dtd_parsing_error_message(const char* filename)
75 {
76  FILE *test(fopen(filename, "r"));
77  std::string message;
78  if (test != NULL) {
79  fclose(test);
80  return std::string("unable to parse DTD ") + filename;
81  }
82  return std::string("cannot open DTD ") + filename;
83 }
84 
85 
86 // There is a hope that libxml2 will be extended eventually and
87 // will provide the detailed errors and warnings for the parsed
88 // dtd file.
89 dtd::dtd (const char* filename, error_messages* messages,
90  warnings_as_errors_type how) : pimpl_(NULL)
91 {
92  if (!filename)
93  throw xml::exception("invalid file name");
94  std::unique_ptr<dtd_impl> ap(pimpl_ = new dtd_impl);
95 
96  if (messages)
97  messages->get_messages().clear();
98 
99  // Wrap the libxml2 call with an https error collecting
100  if (messages)
102  pimpl_->dtd_ = xmlParseDTD(0, reinterpret_cast<const xmlChar*>(filename));
103  if (messages)
105 
106  if (pimpl_->dtd_ == NULL) {
107  // It is a common case that the file does not exist or cannot be
108  // opened. libxml2 does not recognise it so make a test here to
109  // have a better error message.
110  error_messages dtd_parser_messages_;
113  0, filename);
114  if (messages)
115  messages->get_messages().push_back(msg);
116  dtd_parser_messages_.get_messages().push_back(msg);
117  throw parser_exception(dtd_parser_messages_);
118  }
119  ap.release();
120 }
121 
122 dtd::dtd () : pimpl_(new dtd_impl)
123 {}
124 
125 bool dtd::validate (const document& doc, error_messages* messages,
126  warnings_as_errors_type how) const
127 {
128  if (!pimpl_->dtd_)
129  throw xml::exception("dtd has not been loaded");
130 
131  error_messages * temp(messages);
132  std::unique_ptr<error_messages> msgs;
133  if (!messages)
134  msgs.reset(temp = new error_messages);
135 
136  xmlValidCtxt vctxt;
137 
138  memset(&vctxt, 0, sizeof(vctxt));
139  vctxt.error = cb_dtd_error;
140  vctxt.warning = cb_dtd_warning;
141  vctxt.userData = temp;
142 
143  temp->get_messages().clear();
144 
145  int retCode = xmlValidateDtd(&vctxt, doc.pimpl_->doc_, pimpl_->dtd_);
146 
147  if (retCode == 0)
148  return false;
149  if (static_cast<error_messages*>(vctxt.userData)->has_errors())
150  return false;
151  if (static_cast<error_messages*>(vctxt.userData)->has_warnings()) {
152  if (how == type_warnings_are_errors)
153  return false;
154  }
155  return true;
156 }
157 
159  if (pimpl_ != NULL) {
160  if (pimpl_->owned_ && pimpl_->dtd_)
161  xmlFreeDtd(pimpl_->dtd_);
162  delete pimpl_;
163  }
164 }
165 
166 dtd::dtd(dtd &&other) :
167  pimpl_(other.pimpl_)
168 {
169  other.pimpl_ = NULL;
170 }
171 
173 {
174  if (this != &other) {
175  if (pimpl_ != NULL) {
176  if (pimpl_->owned_ && pimpl_->dtd_)
177  xmlFreeDtd(pimpl_->dtd_);
178  delete pimpl_;
179  }
180  pimpl_ = other.pimpl_;
181  other.pimpl_ = NULL;
182  }
183  return *this;
184 }
185 
186 void dtd::set_dtd_data (void *data) {
187  pimpl_->owned_ = false;
188  pimpl_->dtd_ = static_cast<xmlDtdPtr>(data);
189 }
190 
191 // The document needs access to the raw dtd pointer to set external subset
192 void* dtd::get_raw_pointer (void) const {
193  return pimpl_->dtd_;
194 }
195 
196 const char* dtd::get_public_id (void) const {
197  return reinterpret_cast<const char*>(pimpl_->dtd_->ExternalID);
198 }
199 
200 const char* dtd::get_system_id (void) const {
201  return reinterpret_cast<const char*>(pimpl_->dtd_->SystemID);
202 }
203 
204 const char* dtd::get_name (void) const {
205  return reinterpret_cast<const char*>(pimpl_->dtd_->name);
206 }
207 
208 namespace {
209  void register_error_helper (error_message::message_type mt,
210  void *v,
211  const std::string &message) {
212  try {
213  error_messages *p = static_cast<error_messages*>(v);
214  if (p) {
215  long line = xmlLastError.line;
216  if (line < 0)
217  line = 0;
218  std::string filename;
219  if (xmlLastError.file != NULL)
220  filename = xmlLastError.file;
221  p->get_messages().push_back(error_message(message, mt,
222  line, filename));
223  }
224  } catch (...) {}
225  }
226 
227  extern "C" void cb_dtd_error (void *v, const char *message, ...) {
228  std::string temporary;
229 
230  va_list ap;
231  va_start(ap, message);
232  printf2string(temporary, message, ap);
233  va_end(ap);
234 
235  register_error_helper(error_message::type_error, v, temporary);
236  }
237 
238  extern "C" void cb_dtd_warning (void *v, const char *message, ...) {
239  std::string temporary;
240 
241  va_list ap;
242  va_start(ap, message);
243  printf2string(temporary, message, ap);
244  va_end(ap);
245 
246  register_error_helper(error_message::type_warning, v, temporary);
247  }
248 }
249 
#define true
Definition: bool.h:35
The xml::document class is used to hold the XML tree and various bits of information about it.
Definition: document.hpp:80
impl::doc_impl * pimpl_
Definition: document.hpp:770
The xml::dtd class represents an XML dtd from a file.
Definition: dtd.hpp:62
virtual ~dtd()
Destroy the object.
Definition: dtd.cpp:158
bool validate(const document &doc, error_messages *messages, warnings_as_errors_type how=type_warnings_are_errors) const
Validate the given XML document.
Definition: dtd.cpp:125
const char * get_public_id(void) const
Get the public ID.
Definition: dtd.cpp:196
impl::dtd_impl * pimpl_
Definition: dtd.hpp:140
void * get_raw_pointer(void) const
Definition: dtd.cpp:192
dtd & operator=(dtd &&other)
Moving assignment.
Definition: dtd.cpp:172
dtd()
Definition: dtd.cpp:122
const char * get_system_id(void) const
Get the system ID.
Definition: dtd.cpp:200
void set_dtd_data(void *data)
Definition: dtd.cpp:186
const char * get_name(void) const
Get the name.
Definition: dtd.cpp:204
The xml::error_message class is used to store a single error message which may appear while parsing o...
Definition: errors.hpp:50
message_type
A type for different type of errors.
Definition: errors.hpp:53
@ type_warning
warning
Definition: errors.hpp:56
@ type_error
error
Definition: errors.hpp:55
The xml::error_messages class is used to store all the error message which are collected while parsin...
Definition: errors.hpp:137
const error_messages_type & get_messages(void) const
Get the error messages.
Definition: errors.cpp:98
bool has_warnings(void) const
Check if there are warnings in the error messages.
Definition: errors.cpp:118
bool has_errors(void) const
Check if there are errors in the error messages.
Definition: errors.cpp:122
This exception class is thrown by xmlwrapp for all runtime XML-related errors along with the xml::par...
Definition: exception.hpp:64
The xml::parser_exception class is used to store parsing and validating exception information.
Definition: errors.hpp:214
static std::string get_dtd_parsing_error_message(const char *filename)
Definition: dtd.cpp:74
XML dtd API for XmlWrapp.
string
Definition: cgiapp.hpp:687
#define NULL
Definition: ncbistd.hpp:225
This file contains the definition of the xml::document class.
This file contains the definition of the xml::exception class.
void clear_https_messages(void)
void printf2string(std::string &s, const char *message, va_list ap)
Definition: utility.cpp:79
void collect_https_messages(xml::error_messages &append_to)
XML library namespace.
Definition: attributes.hpp:57
warnings_as_errors_type
A type for different approaches to process warnings.
Definition: errors.hpp:259
@ type_warnings_are_errors
Treat warnings as errors.
Definition: errors.hpp:260
xmlDtdPtr dtd_
Definition: dtd.cpp:69
int test(int srctype, const void *srcdata, int srclen, int dsttype, int dstlen)
Definition: t0019.c:43
Modified on Mon Dec 11 02:41:22 2023 by modify_doxy.py rev. 669887