Line data Source code
1 : /*
2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3 : * Copyright Contributors to the OpenSDN project
4 : */
5 :
6 : #include <boost/algorithm/string/replace.hpp>
7 : #include "xml/xml_base.h"
8 : #include "xml/xml_pugi.h"
9 : #include "base/logging.h"
10 :
11 : // This is internal implementation detail specific to this lib to make
12 : // exposed methods efficient.
13 :
14 : //XmlPugi::tmp_("");
15 : pugi::xml_attribute XmlPugi::GAttr;
16 : pugi::xml_node XmlPugi::GNode;
17 :
18 4165221 : XmlPugi::XmlPugi() : writer_(this), node_(GNode), attrib_(GAttr) {
19 4165164 : }
20 :
21 8330458 : XmlPugi::~XmlPugi() {
22 4165230 : doc_.reset();
23 8330455 : }
24 :
25 0 : pugi::xml_node XmlPugi::RootNode() {
26 0 : return(doc_.root());
27 : }
28 :
29 1948998 : const char *XmlPugi::ReadNode(const std::string &name) {
30 1948998 : PugiPredicate p1(name);
31 :
32 1948980 : pugi::xml_node node = doc_.find_node(p1);
33 1948989 : if (IsNull(node)) {
34 14392 : return NULL;
35 : }
36 :
37 1934583 : SetContext(node);
38 1934580 : if (node.type() != pugi::node_pi) {
39 3744955 : for (node = node.first_child(); node; node = node.next_sibling()) {
40 : // traverse to first plain character data or char data,
41 : // skipping XML comments
42 3620788 : if (node.type() == pugi::node_pcdata ||
43 1810386 : node.type() == pugi::node_cdata)
44 15 : break;
45 : }
46 : }
47 :
48 1934456 : return node.value();
49 :
50 1948921 : }
51 :
52 3169167 : pugi::xml_node XmlPugi::FindNode(const std::string &name) {
53 3169167 : PugiPredicate p1(name);
54 :
55 3169168 : pugi::xml_node node = doc_.find_node(p1);
56 3169160 : return node;
57 3169160 : }
58 :
59 0 : const char *XmlPugi::ReadNodeName(const std::string &name) {
60 0 : PugiPredicate p1(name);
61 :
62 0 : pugi::xml_node node = doc_.find_node(p1);
63 0 : SetContext(node);
64 :
65 0 : return node.name();
66 0 : }
67 :
68 0 : const char *XmlPugi::ReadNodeValue() {
69 0 : pugi::xml_node node = node_;
70 :
71 0 : if (node.type() != pugi::node_pi) {
72 0 : for (node = node.first_child(); node; node = node.next_sibling()) {
73 : // traverse to first plain character data or char data,
74 : // skipping XML comments
75 0 : if (node.type() == pugi::node_pcdata ||
76 0 : node.type() == pugi::node_cdata)
77 0 : break;
78 : }
79 : }
80 0 : return node.value();
81 : }
82 :
83 0 : const char *XmlPugi::ReadChildNode() {
84 0 : pugi::xml_node tmp = (node_ == GNode) ? doc_.first_child() :
85 0 : node_.first_child();
86 0 : SetContext(tmp);
87 0 : return tmp.value();
88 : }
89 :
90 98547 : const char *XmlPugi::ReadChildNodeName() {
91 98547 : pugi::xml_node tmp = (node_ == GNode) ? doc_.first_child() :
92 98549 : node_.first_child();
93 98549 : SetContext(tmp);
94 197099 : return tmp.name();
95 : }
96 :
97 0 : const char *XmlPugi::ReadNextNode() {
98 0 : pugi::xml_node tmp = node_.next_sibling();
99 :
100 0 : SetContext(tmp);
101 0 : return tmp.value();
102 : }
103 :
104 0 : const char *XmlPugi::ReadNextNodeName() {
105 0 : pugi::xml_node tmp = node_.next_sibling();
106 :
107 0 : SetContext(tmp);
108 0 : return tmp.name();
109 : }
110 :
111 0 : void XmlPugi::RewindNode() {
112 0 : SetContext(node_);
113 0 : }
114 :
115 3876940 : const char *XmlPugi::ReadAttrib(const std::string &str) {
116 3876940 : pugi::xml_attribute tmp = node_.attribute(str.c_str());
117 3876975 : SetContext(node_, tmp);
118 7753892 : return tmp.value();
119 : }
120 :
121 0 : const char *XmlPugi::ReadFirstAttrib() {
122 0 : pugi::xml_attribute tmp = node_.first_attribute();
123 0 : SetContext(node_, tmp);
124 0 : return tmp.value();
125 : }
126 :
127 0 : const char *XmlPugi::ReadNextAttrib() {
128 0 : pugi::xml_attribute tmp = attrib_.next_attribute();
129 0 : SetContext(node_, tmp);
130 0 : return tmp.value();
131 : }
132 :
133 0 : void XmlPugi::RewindAttrib() {
134 0 : SetContext(node_, GAttr);
135 0 : }
136 :
137 0 : const char *XmlPugi::ReadParentName() {
138 0 : pugi::xml_node tmp = node_.parent();
139 0 : SetContext(tmp);
140 0 : return tmp.name();
141 : }
142 :
143 4445 : int XmlPugi::WriteDoc(uint8_t *buf) {
144 4445 : buf_tmp_ = buf; // this will be used by writer_->write
145 4445 : ts_ = 0;
146 4445 : doc_.save(writer_, "", pugi::format_default, pugi::encoding_utf8);
147 :
148 4445 : if (ts_ == 0) return -1;
149 4445 : return static_cast<int>(ts_);
150 : }
151 :
152 0 : int XmlPugi::WriteRawDoc(uint8_t *buf) {
153 0 : buf_tmp_ = buf; // this will be used by writer_->write
154 0 : ts_ = 0;
155 0 : doc_.save(writer_, "", pugi::format_raw | pugi::format_no_declaration);
156 :
157 0 : if (ts_ == 0) return -1;
158 0 : return static_cast<int>(ts_);
159 : }
160 :
161 15861 : void XmlPugi::PrintDoc(std::ostream& os) const {
162 15861 : doc_.print(os, " ", pugi::format_raw | pugi::format_no_declaration);
163 15862 : }
164 :
165 0 : void XmlPugi::PrintDocFormatted(std::ostream& os) const {
166 0 : doc_.print(os, " ", pugi::format_indent | pugi::format_no_declaration);
167 0 : }
168 :
169 7683991 : void XmlPugi::SetContext(pugi::xml_node node, pugi::xml_attribute attrib) {
170 7683991 : node_ = node;
171 7683991 : attrib_ = attrib;
172 7683991 : }
173 :
174 1687972 : int XmlPugi::LoadDoc(const std::string &document) {
175 1687972 : RewindDoc();
176 1687976 : doc_.reset();
177 :
178 1687970 : pugi::xml_parse_result ret = doc_.load_buffer(document.c_str(), document.size(),
179 : pugi::parse_default,
180 : pugi::encoding_utf8);
181 1687992 : if (ret == false) {
182 0 : LOG(DEBUG, "XML doc load failed, code: " << ret << " " << ret.description());
183 0 : LOG(DEBUG, "Error offset: " << ret.offset << " (error at [..." << (document.c_str() + ret.offset) << "]");
184 0 : LOG(DEBUG, "Document: " << document);
185 0 : return -1;
186 : }
187 1687989 : return 0;
188 : }
189 :
190 1687977 : void XmlPugi::RewindDoc() {
191 1687977 : SetContext();
192 1687976 : }
193 :
194 0 : void XmlPugi::AppendDoc(const std::string &node_name, XmlBase *a_doc) {
195 0 : std::string str;
196 0 : pugi::xml_node node_s;
197 0 : pugi::xml_node node1;
198 0 : pugi::xml_node node2;
199 :
200 0 : PugiPredicate p1(node_name);
201 0 : node1 = doc_.find_node(p1);
202 0 : SetContext(node1);
203 :
204 0 : XmlPugi *xp = static_cast<XmlPugi *>(a_doc);
205 0 : node_s = xp->doc_.first_child();
206 0 : if (!IsNull(node1)) {
207 0 : node2 = node1.parent().append_copy(node_s);
208 0 : SetContext(node2);
209 : }
210 :
211 0 : }
212 :
213 296 : int XmlPugi::AddNode(const std::string &key, const std::string &value) {
214 296 : pugi::xml_node node;
215 :
216 296 : if (IsNull(node_)) {
217 296 : node = doc_.append_child(key.c_str());
218 : } else {
219 0 : node = node_.parent().append_child(key.c_str());
220 : }
221 296 : if (value != "") {
222 0 : node.text().set(value.c_str());
223 : }
224 :
225 296 : SetContext(node);
226 296 : return 0;
227 : }
228 :
229 245 : int XmlPugi::DeleteNode(const std::string &key) {
230 245 : PugiPredicate p1(key);
231 245 : pugi::xml_node node = doc_.find_node(p1);
232 245 : if (IsNull(node))
233 0 : return -1;
234 :
235 245 : node.parent().remove_child(key.c_str());
236 245 : return 0;
237 245 : }
238 :
239 0 : int XmlPugi::ModifyNode(const std::string &key, const std::string &value) {
240 0 : PugiPredicate p1(key);
241 0 : pugi::xml_node node = doc_.find_node(p1);
242 0 : if (IsNull(node))
243 0 : return -1;
244 :
245 0 : node.text().set(value.c_str());
246 :
247 0 : SetContext(node);
248 0 : return 0;
249 0 : }
250 :
251 1636 : int XmlPugi::AddChildNode(const std::string &key, const std::string &value) {
252 1636 : pugi::xml_node node;
253 :
254 1636 : if (IsNull(node_)) {
255 0 : node = doc_.append_child(key.c_str());
256 : } else {
257 1636 : node = node_.append_child(key.c_str());
258 : }
259 1636 : if (value != "") {
260 32 : node.text().set(value.c_str());
261 : }
262 :
263 1636 : SetContext(node);
264 1636 : return 0;
265 : }
266 :
267 0 : int XmlPugi::AddChildNodeAfter(const std::string &node_name,
268 : const std::string &key,
269 : const std::string &value) {
270 :
271 0 : PugiPredicate p1(node_name);
272 0 : pugi::xml_node node1 = doc_.find_node(p1);
273 0 : SetContext(node1);
274 :
275 0 : if (!IsNull(node1)) {
276 0 : AddChildNode(key, value);
277 : }
278 :
279 0 : return 0;
280 0 : }
281 :
282 :
283 2492 : int XmlPugi::AddAttribute(const std::string &key, const std::string &value) {
284 2492 : if (IsNull(node_))
285 0 : return -1;
286 :
287 2492 : pugi::xml_attribute attrib;
288 :
289 2492 : if (IsNull(attrib_) ) {
290 1623 : attrib = node_.append_attribute(key.c_str()) = value.c_str();
291 : } else {
292 869 : attrib =
293 869 : node_.insert_attribute_after(key.c_str(), attrib_) = value.c_str();
294 : }
295 :
296 2492 : SetContext(node_, attrib);
297 2492 : return 0;
298 : }
299 :
300 0 : int XmlPugi::DeleteAttribute(const std::string &key) {
301 0 : if (IsNull(node_))
302 0 : return -1;
303 0 : pugi::xml_attribute tmp = node_.attribute(key.c_str());
304 : bool res;
305 0 : if (IsNull(tmp)) {
306 0 : return -1;
307 : } else {
308 0 : pugi::xml_attribute attrib = tmp.next_attribute();
309 0 : res = node_.remove_attribute(tmp);
310 0 : SetContext(node_, attrib);
311 0 : return (res ? -1 : 0);
312 : }
313 : return 0;
314 : }
315 :
316 81681 : int XmlPugi::ModifyAttribute(const std::string &key, const std::string &value) {
317 81681 : if (node_.type() == pugi::node_null)
318 0 : return -1;
319 :
320 : //ReadAttrib(key);
321 81681 : pugi::xml_attribute tmp = node_.attribute(key.c_str());
322 81680 : if (IsNull(tmp)) {
323 28 : return -1;
324 : } else {
325 81652 : tmp.set_value(value.c_str());
326 81650 : SetContext(node_, tmp);
327 : }
328 :
329 81649 : return 0;
330 : }
331 :
332 4445 : void XmlPugi::xmpp_buf_write::write(const void *data, size_t sz) {
333 4445 : ref->SetBuf(data, sz);
334 4445 : }
335 :
336 4445 : void XmlPugi::SetBuf(const void *buf, size_t sz) {
337 4445 : memcpy(buf_tmp_ + ts_, buf, sz);
338 4445 : ts_ += sz;
339 4445 : *(buf_tmp_+ts_) = '\0';
340 4445 : }
|