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 4177345 : XmlPugi::XmlPugi() : writer_(this), node_(GNode), attrib_(GAttr) {
18 4177311 : }
19 :
20 8354699 : XmlPugi::~XmlPugi() {
21 4177347 : doc_.reset();
22 8354707 : }
23 :
24 0 : pugi::xml_node XmlPugi::RootNode() {
25 0 : return(doc_.root());
26 : }
27 :
28 1952052 : const char *XmlPugi::ReadNode(const std::string &name) {
29 1952052 : PugiPredicate p1(name);
30 :
31 1952041 : pugi::xml_node node = doc_.find_node(p1);
32 1952039 : if (IsNull(node)) {
33 14382 : return NULL;
34 : }
35 :
36 1937646 : SetContext(node);
37 1937647 : if (node.type() != pugi::node_pi) {
38 3751371 : 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 3627484 : if (node.type() == pugi::node_pcdata ||
42 1813734 : node.type() == pugi::node_cdata)
43 15 : break;
44 : }
45 : }
46 :
47 1937540 : return node.value();
48 :
49 1951991 : }
50 :
51 3175638 : pugi::xml_node XmlPugi::FindNode(const std::string &name) {
52 3175638 : PugiPredicate p1(name);
53 :
54 3175640 : pugi::xml_node node = doc_.find_node(p1);
55 3175623 : return node;
56 3175623 : }
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 98545 : const char *XmlPugi::ReadChildNodeName() {
90 98545 : pugi::xml_node tmp = (node_ == GNode) ? doc_.first_child() :
91 98545 : node_.first_child();
92 98545 : SetContext(tmp);
93 197088 : 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 3883605 : const char *XmlPugi::ReadAttrib(const std::string &str) {
115 3883605 : pugi::xml_attribute tmp = node_.attribute(str.c_str());
116 3883618 : SetContext(node_, tmp);
117 7767179 : 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 4444 : if (ts_ == 0) return -1;
148 4444 : 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 15860 : void XmlPugi::PrintDoc(std::ostream& os) const {
161 15860 : doc_.print(os, " ", pugi::format_raw | pugi::format_no_declaration);
162 15860 : }
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 7692393 : void XmlPugi::SetContext(pugi::xml_node node, pugi::xml_attribute attrib) {
169 7692393 : node_ = node;
170 7692393 : attrib_ = attrib;
171 7692393 : }
172 :
173 1691312 : int XmlPugi::LoadDoc(const std::string &document) {
174 1691312 : RewindDoc();
175 1691315 : doc_.reset();
176 :
177 1691306 : pugi::xml_parse_result ret = doc_.load_buffer(document.c_str(), document.size(),
178 : pugi::parse_default,
179 : pugi::encoding_utf8);
180 1691328 : 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 1691325 : return 0;
187 : }
188 :
189 1691317 : void XmlPugi::RewindDoc() {
190 1691317 : SetContext();
191 1691316 : }
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 0 : int XmlPugi::AddNode(const std::string &key, const std::string &value) {
213 0 : pugi::xml_node node;
214 :
215 0 : if (IsNull(node_)) {
216 0 : node = doc_.append_child(key.c_str());
217 : } else {
218 0 : node = node_.parent().append_child(key.c_str());
219 : }
220 0 : if (value != "") {
221 0 : node.text().set(value.c_str());
222 : }
223 :
224 0 : SetContext(node);
225 0 : return 0;
226 : }
227 :
228 0 : int XmlPugi::DeleteNode(const std::string &key) {
229 0 : PugiPredicate p1(key);
230 0 : pugi::xml_node node = doc_.find_node(p1);
231 0 : if (IsNull(node))
232 0 : return -1;
233 :
234 0 : node.parent().remove_child(key.c_str());
235 0 : return 0;
236 0 : }
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 0 : int XmlPugi::AddChildNode(const std::string &key, const std::string &value) {
251 0 : pugi::xml_node node;
252 :
253 0 : if (IsNull(node_)) {
254 0 : node = doc_.append_child(key.c_str());
255 : } else {
256 0 : node = node_.append_child(key.c_str());
257 : }
258 0 : if (value != "") {
259 0 : node.text().set(value.c_str());
260 : }
261 :
262 0 : SetContext(node);
263 0 : 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 0 : int XmlPugi::AddAttribute(const std::string &key, const std::string &value) {
283 0 : if (IsNull(node_))
284 0 : return -1;
285 :
286 0 : pugi::xml_attribute attrib;
287 :
288 0 : if (IsNull(attrib_) ) {
289 0 : attrib = node_.append_attribute(key.c_str()) = value.c_str();
290 : } else {
291 0 : attrib =
292 0 : node_.insert_attribute_after(key.c_str(), attrib_) = value.c_str();
293 : }
294 :
295 0 : SetContext(node_, attrib);
296 0 : 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 81420 : int XmlPugi::ModifyAttribute(const std::string &key, const std::string &value) {
316 81420 : if (node_.type() == pugi::node_null)
317 0 : return -1;
318 :
319 : //ReadAttrib(key);
320 81420 : pugi::xml_attribute tmp = node_.attribute(key.c_str());
321 81421 : if (IsNull(tmp)) {
322 28 : return -1;
323 : } else {
324 81393 : tmp.set_value(value.c_str());
325 81393 : SetContext(node_, tmp);
326 : }
327 :
328 81393 : return 0;
329 : }
330 :
331 4444 : void XmlPugi::xmpp_buf_write::write(const void *data, size_t sz) {
332 4444 : ref->SetBuf(data, sz);
333 4444 : }
334 :
335 4444 : void XmlPugi::SetBuf(const void *buf, size_t sz) {
336 4444 : memcpy(buf_tmp_ + ts_, buf, sz);
337 4444 : ts_ += sz;
338 4444 : *(buf_tmp_+ts_) = '\0';
339 4444 : }
|