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