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