Imported Upstream version 2.91.2
[platform/upstream/libxml++.git] / libxml++ / xsdschema.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++/xsdschema.h>
20
21 #include <libxml/tree.h>
22 #include <libxml/xmlschemas.h>
23
24 namespace
25 {
26   // This class holds an xmlSchemaParserCtxtPtr and releases it on
27   // destruction. This way, we make sure we don't leak it, not even
28   // when an exception is thrown.
29   class XsdSchemaParserContextHolder
30   {
31   public:
32     XsdSchemaParserContextHolder(xmlSchemaParserCtxtPtr ctx): ctx_(ctx) {}
33     ~XsdSchemaParserContextHolder() { if (ctx_) xmlSchemaFreeParserCtxt(ctx_); }
34
35   private:
36     xmlSchemaParserCtxtPtr ctx_;
37   };
38 }
39
40 namespace xmlpp
41 {
42
43 struct XsdSchema::Impl
44 {
45   Impl() : schema(nullptr), document(nullptr) {}
46
47   _xmlSchema* schema;
48   _xmlDoc* document;
49 };
50
51   
52 XsdSchema::XsdSchema()
53 : pimpl_(new Impl)
54 {
55 }
56
57 XsdSchema::XsdSchema(_xmlSchema* schema)
58 : pimpl_(new Impl)
59 {
60   pimpl_->schema = schema;
61 }
62
63 XsdSchema::XsdSchema(const std::string& filename)
64 : pimpl_(new Impl)
65 {
66   parse_file(filename);
67 }
68
69 XsdSchema::XsdSchema(const Document* document)
70 : pimpl_(new Impl)
71 {
72   parse_document(document);
73 }
74
75 XsdSchema::~XsdSchema()
76 {
77   release_underlying();
78 }
79
80 void XsdSchema::parse_file(const std::string& filename)
81 {
82   xmlResetLastError();
83   release_underlying();
84   parse_context(xmlSchemaNewParserCtxt(filename.c_str()));
85 }
86
87 void XsdSchema::parse_memory(const Glib::ustring& contents)
88 {
89   xmlResetLastError();
90   release_underlying();
91   parse_context(xmlSchemaNewMemParserCtxt(contents.c_str(), contents.bytes()));
92 }
93
94 void XsdSchema::parse_document(const Document* document)
95 {
96   if (!document)
97     throw parse_error("XsdSchema::parse_document(): document must not be nullptr.");
98
99   xmlResetLastError();
100   release_underlying();
101
102   // xmlSchemaParse() may modify the document. Take a copy.
103   pimpl_->document = xmlCopyDoc(const_cast<xmlDoc*>(document->cobj()), true); // recursive copy
104   if (!pimpl_->document)
105     throw parse_error("XsdSchema::parse_document(): Could not copy the document.\n" + format_xml_error());
106
107   parse_context(xmlSchemaNewDocParserCtxt(pimpl_->document));
108 }
109
110 void XsdSchema::parse_context(_xmlSchemaParserCtxt* context)
111 {
112   if (!context)
113     throw parse_error("XsdSchema::parse_context(): Could not create parser context.\n" + format_xml_error());
114   
115   XsdSchemaParserContextHolder holder(context);
116
117   pimpl_->schema = xmlSchemaParse(context);
118   if (!pimpl_->schema)
119   {
120     release_underlying();
121     throw parse_error("XsdSchema::parse_context(): Schema could not be parsed.\n" + format_xml_error());
122   }
123 }
124
125 _xmlSchema* XsdSchema::cobj()
126 {
127   return pimpl_->schema;
128 }
129
130 const _xmlSchema* XsdSchema::cobj() const
131 {
132   return pimpl_->schema;
133 }
134
135 void XsdSchema::release_underlying()
136 {
137   if (pimpl_->schema)
138   {
139     xmlSchemaFree(pimpl_->schema);
140     pimpl_->schema = nullptr;
141   }
142
143   if (pimpl_->document)
144   {
145     xmlFreeDoc(pimpl_->document);
146     pimpl_->document = nullptr;
147   }
148 }
149
150 } //namespace xmlpp