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