Imported Upstream version 2.91.2
[platform/upstream/libxml++.git] / libxml++ / validators / xsdvalidator.cc
1 /* Copyright (C) 2014 The libxml++ development team
2  *
3  * This file is part of libxml++.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include "libxml++/validators/xsdvalidator.h"
20 #include "libxml++/xsdschema.h"
21
22 #include <libxml/xmlschemas.h>
23
24 namespace xmlpp
25 {
26
27 struct XsdValidator::Impl
28 {
29   Impl() : schema(nullptr), is_schema_owner(false), context(nullptr) {}
30
31   XsdSchema* schema;
32   bool is_schema_owner;
33   _xmlSchemaValidCtxt* context;
34 };
35
36
37 XsdValidator::XsdValidator()
38 : pimpl_(new Impl)
39 {
40 }
41
42 XsdValidator::XsdValidator(const std::string& filename)
43 : pimpl_(new Impl)
44 {
45   parse_file(filename);
46 }
47
48 XsdValidator::XsdValidator(const Document* document)
49 : pimpl_(new Impl)
50 {
51   parse_document(document);
52 }
53
54 XsdValidator::XsdValidator(XsdSchema* schema, bool take_ownership)
55 : pimpl_(new Impl)
56 {
57   set_schema(schema, take_ownership);
58 }
59
60 XsdValidator::~XsdValidator()
61 {
62   release_underlying();
63 }
64
65 void XsdValidator::parse_file(const std::string& filename)
66 {
67   set_schema(new XsdSchema(filename), true);
68 }
69
70 void XsdValidator::parse_memory(const Glib::ustring& contents)
71 {
72   std::unique_ptr<XsdSchema> schema(new XsdSchema());
73   schema->parse_memory(contents);
74   set_schema(schema.release(), true);
75 }
76
77 void XsdValidator::parse_document(const Document* document)
78 {
79   set_schema(new XsdSchema(document), true);
80 }
81
82 void XsdValidator::set_schema(XsdSchema* schema, bool take_ownership)
83 {
84   release_underlying();
85   pimpl_->schema = schema;
86   pimpl_->is_schema_owner = take_ownership;
87 }
88
89 void XsdValidator::release_underlying()
90 {
91   if (pimpl_->context)
92   {
93     xmlSchemaFreeValidCtxt(pimpl_->context);
94     pimpl_->context = nullptr;
95   }
96
97   if (pimpl_->schema)
98   {
99     if (pimpl_->is_schema_owner)
100       delete pimpl_->schema;
101     pimpl_->schema = nullptr;
102   }
103
104   SchemaValidatorBase::release_underlying();
105 }
106
107 XsdSchema* XsdValidator::get_schema()
108 {
109   return pimpl_->schema;
110 }
111
112 const XsdSchema* XsdValidator::get_schema() const
113 {
114   return pimpl_->schema;
115 }
116
117 XsdValidator::operator bool() const noexcept
118 {
119   return pimpl_->schema && pimpl_->schema->cobj();
120 }
121
122
123 void XsdValidator::initialize_context()
124 {
125   xmlSchemaSetValidErrors(pimpl_->context, &callback_validity_error, &callback_validity_warning, this);
126   SchemaValidatorBase::initialize_context();
127 }
128
129
130 void XsdValidator::validate(const Document* document)
131 {
132   if (!document)
133     throw internal_error("XsdValidator::validate(): document must not be nullptr.");
134
135   if (!*this)
136     throw internal_error("XsdValidator::validate(): Must have a schema to validate document");
137
138   // A context is required at this stage only
139   if (!pimpl_->context)
140     pimpl_->context = xmlSchemaNewValidCtxt(pimpl_->schema->cobj());
141
142   if (!pimpl_->context)
143     throw internal_error("XsdValidator::validate(): Could not create validating context");
144
145   xmlResetLastError();
146   initialize_context();
147
148   const int res = xmlSchemaValidateDoc(pimpl_->context, const_cast<xmlDoc*>(document->cobj()));
149   if (res != 0)
150   {
151     check_for_exception();
152
153     auto error_str = format_xml_error();
154     if (error_str.empty())
155       error_str = "Error code from xmlSchemaValidateDoc(): " + Glib::ustring::format(res);
156     throw validity_error("Document failed XSD schema validation.\n" + error_str);
157   }
158 }
159
160 void XsdValidator::validate(const std::string& filename)
161 {
162   if (!*this)
163     throw internal_error("XsdValidator::validate(): Must have a schema to validate file.");
164
165   // A context is required at this stage only
166   if (!pimpl_->context)
167     pimpl_->context = xmlSchemaNewValidCtxt(pimpl_->schema->cobj());
168
169   if (!pimpl_->context)
170     throw internal_error("XsdValidator::validate(): Could not create validating context");
171
172   xmlResetLastError();
173   initialize_context();
174
175   const int res = xmlSchemaValidateFile(pimpl_->context, filename.c_str(), 0);
176   if (res != 0)
177   {
178     check_for_exception();
179
180     auto error_str = format_xml_error();
181     if (error_str.empty())
182       error_str = "Error code from xmlSchemaValidateFile(): " + Glib::ustring::format(res);
183     throw validity_error("XML file failed XSD schema validation.\n" + error_str);
184   }
185 }
186
187 } // namespace xmlpp