Imported Upstream version 2.39.1
[platform/upstream/libxml++.git] / libxml++ / validators / validator.cc
1 /* xml++.cc
2  * libxml++ and this file are copyright (C) 2000 by Ari Johnson
3  * (C) 2002-2004 by the libxml dev team and
4  * are covered by the GNU Lesser General Public License, which should be
5  * included with libxml++ as the file COPYING.
6  */
7
8 #include "libxml++/validators/validator.h"
9
10 #include <libxml/parser.h>
11
12 #include <cstdarg> //For va_list.
13 #include <memory> //For auto_ptr.
14
15 namespace xmlpp {
16
17 Validator::Validator()
18 : valid_(nullptr), exception_(nullptr)
19 {
20 }
21
22 Validator::~Validator()
23 {
24   release_underlying();
25 }
26
27 void Validator::initialize_valid()
28 {
29   // valid_ is used only by DtdValidator.
30   //TODO: When we can break ABI, move valid_ to DtdValidator.
31   if (valid_)
32   {
33     //Tell the validation context about the callbacks:
34     valid_->error = &callback_validity_error;
35     valid_->warning = &callback_validity_warning;
36
37     //Allow the callback_validity_*() methods to retrieve the C++ instance:
38     valid_->userData = this;
39   }
40
41   //Clear these temporary buffers too:
42   validate_error_.erase();
43   validate_warning_.erase();
44 }
45
46 void Validator::release_underlying()
47 {
48   if(valid_)
49   {
50     valid_->userData = nullptr; //Not really necessary.
51
52     xmlFreeValidCtxt(valid_);
53     valid_ = nullptr;
54   }
55 }
56
57 void Validator::on_validity_error(const Glib::ustring& message)
58 {
59   //Throw an exception later when the whole message has been received:
60   validate_error_ += message;
61 }
62
63 void Validator::on_validity_warning(const Glib::ustring& message)
64 {
65   //Throw an exception later when the whole message has been received:
66   validate_warning_ += message;
67 }
68
69 void Validator::check_for_validity_messages()
70 {
71   Glib::ustring msg(exception_ ? exception_->what() : "");
72   bool validity_msg = false;
73
74   if (!validate_error_.empty())
75   {
76     validity_msg = true;
77     msg += "\nValidity error:\n" + validate_error_;
78     validate_error_.erase();
79   }
80
81   if (!validate_warning_.empty())
82   {
83     validity_msg = true;
84     msg += "\nValidity warning:\n" + validate_warning_;
85     validate_warning_.erase();
86   }
87
88   if (validity_msg)
89   {
90     delete exception_;
91     exception_ = new validity_error(msg);
92   }
93 }
94
95 void Validator::callback_validity_error(void* valid_, const char* msg, ...)
96 {
97   auto validator = static_cast<Validator*>(valid_);
98
99   if(validator)
100   {
101     //Convert the ... to a string:
102     va_list arg;
103     char buff[1024]; //TODO: Larger/Shared
104
105     va_start(arg, msg);
106     vsnprintf(buff, sizeof(buff)/sizeof(buff[0]), msg, arg);
107     va_end(arg);
108
109     try
110     {
111       validator->on_validity_error(Glib::ustring(buff));
112     }
113     catch(const exception& e)
114     {
115       validator->handleException(e);
116     }
117   }
118 }
119
120 void Validator::callback_validity_warning(void* valid_, const char* msg, ...)
121 {
122   auto validator = static_cast<Validator*>(valid_);
123
124   if(validator)
125   {
126     //Convert the ... to a string:
127     va_list arg;
128     char buff[1024]; //TODO: Larger/Shared
129
130     va_start(arg, msg);
131     vsnprintf(buff, sizeof(buff)/sizeof(buff[0]), msg, arg);
132     va_end(arg);
133
134     try
135     {
136       validator->on_validity_warning(Glib::ustring(buff));
137     }
138     catch(const exception& e)
139     {
140       validator->handleException(e);
141     }
142   }
143 }
144
145 void Validator::handleException(const exception& e)
146 {
147   delete exception_;
148   exception_ = e.Clone();
149
150   // Don't delete the DTD validation context or schema validation context
151   // while validating. It would cause accesses to deallocated memory in libxml2
152   // functions after the return from Validator::callback_validity_...().
153   // Parser::handleException() calls xmlStopParser(), but there is no
154   // xmlStopValidator() or similar function to call here.
155   // We don't throw the exception here, since it would have to pass through
156   // C functions. That's not guaranteed to work. It might work, but it depends
157   // on the C compiler and the options used when building libxml2.
158
159   //release_underlying();
160 }
161
162 void Validator::check_for_exception()
163 {
164   check_for_validity_messages();
165
166   if(exception_)
167   {
168     std::auto_ptr<exception> tmp(exception_);
169     exception_ = nullptr;
170     tmp->Raise();
171   }
172 }
173
174 } // namespace xmlpp