1 /*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "webrtc/libjingle/xmllite/xmlelement.h"
12
13 #include <ostream>
14 #include <sstream>
15 #include <string>
16 #include <vector>
17
18 #include "webrtc/libjingle/xmllite/qname.h"
19 #include "webrtc/libjingle/xmllite/xmlbuilder.h"
20 #include "webrtc/libjingle/xmllite/xmlconstants.h"
21 #include "webrtc/libjingle/xmllite/xmlparser.h"
22 #include "webrtc/libjingle/xmllite/xmlprinter.h"
23 #include "webrtc/base/common.h"
24
25 namespace buzz {
26
~XmlChild()27 XmlChild::~XmlChild() {
28 }
29
IsTextImpl() const30 bool XmlText::IsTextImpl() const {
31 return true;
32 }
33
AsElementImpl() const34 XmlElement* XmlText::AsElementImpl() const {
35 return NULL;
36 }
37
AsTextImpl() const38 XmlText* XmlText::AsTextImpl() const {
39 return const_cast<XmlText *>(this);
40 }
41
SetText(const std::string & text)42 void XmlText::SetText(const std::string& text) {
43 text_ = text;
44 }
45
AddParsedText(const char * buf,int len)46 void XmlText::AddParsedText(const char* buf, int len) {
47 text_.append(buf, len);
48 }
49
AddText(const std::string & text)50 void XmlText::AddText(const std::string& text) {
51 text_ += text;
52 }
53
~XmlText()54 XmlText::~XmlText() {
55 }
56
XmlElement(const QName & name)57 XmlElement::XmlElement(const QName& name) :
58 name_(name),
59 first_attr_(NULL),
60 last_attr_(NULL),
61 first_child_(NULL),
62 last_child_(NULL),
63 cdata_(false) {
64 }
65
XmlElement(const XmlElement & elt)66 XmlElement::XmlElement(const XmlElement& elt) :
67 XmlChild(),
68 name_(elt.name_),
69 first_attr_(NULL),
70 last_attr_(NULL),
71 first_child_(NULL),
72 last_child_(NULL),
73 cdata_(false) {
74
75 // copy attributes
76 XmlAttr* attr;
77 XmlAttr ** plast_attr = &first_attr_;
78 XmlAttr* newAttr = NULL;
79 for (attr = elt.first_attr_; attr; attr = attr->NextAttr()) {
80 newAttr = new XmlAttr(*attr);
81 *plast_attr = newAttr;
82 plast_attr = &(newAttr->next_attr_);
83 }
84 last_attr_ = newAttr;
85
86 // copy children
87 XmlChild* pChild;
88 XmlChild ** ppLast = &first_child_;
89 XmlChild* newChild = NULL;
90
91 for (pChild = elt.first_child_; pChild; pChild = pChild->NextChild()) {
92 if (pChild->IsText()) {
93 newChild = new XmlText(*(pChild->AsText()));
94 } else {
95 newChild = new XmlElement(*(pChild->AsElement()));
96 }
97 *ppLast = newChild;
98 ppLast = &(newChild->next_child_);
99 }
100 last_child_ = newChild;
101
102 cdata_ = elt.cdata_;
103 }
104
XmlElement(const QName & name,bool useDefaultNs)105 XmlElement::XmlElement(const QName& name, bool useDefaultNs) :
106 name_(name),
107 first_attr_(useDefaultNs ? new XmlAttr(QN_XMLNS, name.Namespace()) : NULL),
108 last_attr_(first_attr_),
109 first_child_(NULL),
110 last_child_(NULL),
111 cdata_(false) {
112 }
113
IsTextImpl() const114 bool XmlElement::IsTextImpl() const {
115 return false;
116 }
117
AsElementImpl() const118 XmlElement* XmlElement::AsElementImpl() const {
119 return const_cast<XmlElement *>(this);
120 }
121
AsTextImpl() const122 XmlText* XmlElement::AsTextImpl() const {
123 return NULL;
124 }
125
BodyText() const126 const std::string XmlElement::BodyText() const {
127 if (first_child_ && first_child_->IsText() && last_child_ == first_child_) {
128 return first_child_->AsText()->Text();
129 }
130
131 return std::string();
132 }
133
SetBodyText(const std::string & text)134 void XmlElement::SetBodyText(const std::string& text) {
135 if (text.empty()) {
136 ClearChildren();
137 } else if (first_child_ == NULL) {
138 AddText(text);
139 } else if (first_child_->IsText() && last_child_ == first_child_) {
140 first_child_->AsText()->SetText(text);
141 } else {
142 ClearChildren();
143 AddText(text);
144 }
145 }
146
FirstElementName() const147 const QName XmlElement::FirstElementName() const {
148 const XmlElement* element = FirstElement();
149 if (element == NULL)
150 return QName();
151 return element->Name();
152 }
153
FirstAttr()154 XmlAttr* XmlElement::FirstAttr() {
155 return first_attr_;
156 }
157
Attr(const StaticQName & name) const158 const std::string XmlElement::Attr(const StaticQName& name) const {
159 XmlAttr* attr;
160 for (attr = first_attr_; attr; attr = attr->next_attr_) {
161 if (attr->name_ == name)
162 return attr->value_;
163 }
164 return std::string();
165 }
166
Attr(const QName & name) const167 const std::string XmlElement::Attr(const QName& name) const {
168 XmlAttr* attr;
169 for (attr = first_attr_; attr; attr = attr->next_attr_) {
170 if (attr->name_ == name)
171 return attr->value_;
172 }
173 return std::string();
174 }
175
HasAttr(const StaticQName & name) const176 bool XmlElement::HasAttr(const StaticQName& name) const {
177 XmlAttr* attr;
178 for (attr = first_attr_; attr; attr = attr->next_attr_) {
179 if (attr->name_ == name)
180 return true;
181 }
182 return false;
183 }
184
HasAttr(const QName & name) const185 bool XmlElement::HasAttr(const QName& name) const {
186 XmlAttr* attr;
187 for (attr = first_attr_; attr; attr = attr->next_attr_) {
188 if (attr->name_ == name)
189 return true;
190 }
191 return false;
192 }
193
SetAttr(const QName & name,const std::string & value)194 void XmlElement::SetAttr(const QName& name, const std::string& value) {
195 XmlAttr* attr;
196 for (attr = first_attr_; attr; attr = attr->next_attr_) {
197 if (attr->name_ == name)
198 break;
199 }
200 if (!attr) {
201 attr = new XmlAttr(name, value);
202 if (last_attr_)
203 last_attr_->next_attr_ = attr;
204 else
205 first_attr_ = attr;
206 last_attr_ = attr;
207 return;
208 }
209 attr->value_ = value;
210 }
211
ClearAttr(const QName & name)212 void XmlElement::ClearAttr(const QName& name) {
213 XmlAttr* attr;
214 XmlAttr* last_attr = NULL;
215 for (attr = first_attr_; attr; attr = attr->next_attr_) {
216 if (attr->name_ == name)
217 break;
218 last_attr = attr;
219 }
220 if (!attr)
221 return;
222 if (!last_attr)
223 first_attr_ = attr->next_attr_;
224 else
225 last_attr->next_attr_ = attr->next_attr_;
226 if (last_attr_ == attr)
227 last_attr_ = last_attr;
228 delete attr;
229 }
230
FirstChild()231 XmlChild* XmlElement::FirstChild() {
232 return first_child_;
233 }
234
FirstElement()235 XmlElement* XmlElement::FirstElement() {
236 XmlChild* pChild;
237 for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
238 if (!pChild->IsText())
239 return pChild->AsElement();
240 }
241 return NULL;
242 }
243
NextElement()244 XmlElement* XmlElement::NextElement() {
245 XmlChild* pChild;
246 for (pChild = next_child_; pChild; pChild = pChild->next_child_) {
247 if (!pChild->IsText())
248 return pChild->AsElement();
249 }
250 return NULL;
251 }
252
FirstWithNamespace(const std::string & ns)253 XmlElement* XmlElement::FirstWithNamespace(const std::string& ns) {
254 XmlChild* pChild;
255 for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
256 if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns)
257 return pChild->AsElement();
258 }
259 return NULL;
260 }
261
262 XmlElement *
NextWithNamespace(const std::string & ns)263 XmlElement::NextWithNamespace(const std::string& ns) {
264 XmlChild* pChild;
265 for (pChild = next_child_; pChild; pChild = pChild->next_child_) {
266 if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns)
267 return pChild->AsElement();
268 }
269 return NULL;
270 }
271
272 XmlElement *
FirstNamed(const QName & name)273 XmlElement::FirstNamed(const QName& name) {
274 XmlChild* pChild;
275 for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
276 if (!pChild->IsText() && pChild->AsElement()->Name() == name)
277 return pChild->AsElement();
278 }
279 return NULL;
280 }
281
282 XmlElement *
FirstNamed(const StaticQName & name)283 XmlElement::FirstNamed(const StaticQName& name) {
284 XmlChild* pChild;
285 for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
286 if (!pChild->IsText() && pChild->AsElement()->Name() == name)
287 return pChild->AsElement();
288 }
289 return NULL;
290 }
291
292 XmlElement *
NextNamed(const QName & name)293 XmlElement::NextNamed(const QName& name) {
294 XmlChild* pChild;
295 for (pChild = next_child_; pChild; pChild = pChild->next_child_) {
296 if (!pChild->IsText() && pChild->AsElement()->Name() == name)
297 return pChild->AsElement();
298 }
299 return NULL;
300 }
301
302 XmlElement *
NextNamed(const StaticQName & name)303 XmlElement::NextNamed(const StaticQName& name) {
304 XmlChild* pChild;
305 for (pChild = next_child_; pChild; pChild = pChild->next_child_) {
306 if (!pChild->IsText() && pChild->AsElement()->Name() == name)
307 return pChild->AsElement();
308 }
309 return NULL;
310 }
311
FindOrAddNamedChild(const QName & name)312 XmlElement* XmlElement::FindOrAddNamedChild(const QName& name) {
313 XmlElement* child = FirstNamed(name);
314 if (!child) {
315 child = new XmlElement(name);
316 AddElement(child);
317 }
318
319 return child;
320 }
321
TextNamed(const QName & name) const322 const std::string XmlElement::TextNamed(const QName& name) const {
323 XmlChild* pChild;
324 for (pChild = first_child_; pChild; pChild = pChild->next_child_) {
325 if (!pChild->IsText() && pChild->AsElement()->Name() == name)
326 return pChild->AsElement()->BodyText();
327 }
328 return std::string();
329 }
330
InsertChildAfter(XmlChild * predecessor,XmlChild * next)331 void XmlElement::InsertChildAfter(XmlChild* predecessor, XmlChild* next) {
332 if (predecessor == NULL) {
333 next->next_child_ = first_child_;
334 first_child_ = next;
335 }
336 else {
337 next->next_child_ = predecessor->next_child_;
338 predecessor->next_child_ = next;
339 }
340 }
341
RemoveChildAfter(XmlChild * predecessor)342 void XmlElement::RemoveChildAfter(XmlChild* predecessor) {
343 XmlChild* next;
344
345 if (predecessor == NULL) {
346 next = first_child_;
347 first_child_ = next->next_child_;
348 }
349 else {
350 next = predecessor->next_child_;
351 predecessor->next_child_ = next->next_child_;
352 }
353
354 if (last_child_ == next)
355 last_child_ = predecessor;
356
357 delete next;
358 }
359
AddAttr(const QName & name,const std::string & value)360 void XmlElement::AddAttr(const QName& name, const std::string& value) {
361 ASSERT(!HasAttr(name));
362
363 XmlAttr ** pprev = last_attr_ ? &(last_attr_->next_attr_) : &first_attr_;
364 last_attr_ = (*pprev = new XmlAttr(name, value));
365 }
366
AddAttr(const QName & name,const std::string & value,int depth)367 void XmlElement::AddAttr(const QName& name, const std::string& value,
368 int depth) {
369 XmlElement* element = this;
370 while (depth--) {
371 element = element->last_child_->AsElement();
372 }
373 element->AddAttr(name, value);
374 }
375
AddParsedText(const char * cstr,int len)376 void XmlElement::AddParsedText(const char* cstr, int len) {
377 if (len == 0)
378 return;
379
380 if (last_child_ && last_child_->IsText()) {
381 last_child_->AsText()->AddParsedText(cstr, len);
382 return;
383 }
384 XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_;
385 last_child_ = *pprev = new XmlText(cstr, len);
386 }
387
AddCDATAText(const char * buf,int len)388 void XmlElement::AddCDATAText(const char* buf, int len) {
389 cdata_ = true;
390 AddParsedText(buf, len);
391 }
392
AddText(const std::string & text)393 void XmlElement::AddText(const std::string& text) {
394 if (text == STR_EMPTY)
395 return;
396
397 if (last_child_ && last_child_->IsText()) {
398 last_child_->AsText()->AddText(text);
399 return;
400 }
401 XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_;
402 last_child_ = *pprev = new XmlText(text);
403 }
404
AddText(const std::string & text,int depth)405 void XmlElement::AddText(const std::string& text, int depth) {
406 // note: the first syntax is ambigious for msvc 6
407 // XmlElement* pel(this);
408 XmlElement* element = this;
409 while (depth--) {
410 element = element->last_child_->AsElement();
411 }
412 element->AddText(text);
413 }
414
AddElement(XmlElement * child)415 void XmlElement::AddElement(XmlElement *child) {
416 if (child == NULL)
417 return;
418
419 XmlChild ** pprev = last_child_ ? &(last_child_->next_child_) : &first_child_;
420 *pprev = child;
421 last_child_ = child;
422 child->next_child_ = NULL;
423 }
424
AddElement(XmlElement * child,int depth)425 void XmlElement::AddElement(XmlElement *child, int depth) {
426 XmlElement* element = this;
427 while (depth--) {
428 element = element->last_child_->AsElement();
429 }
430 element->AddElement(child);
431 }
432
ClearNamedChildren(const QName & name)433 void XmlElement::ClearNamedChildren(const QName& name) {
434 XmlChild* prev_child = NULL;
435 XmlChild* next_child;
436 XmlChild* child;
437 for (child = FirstChild(); child; child = next_child) {
438 next_child = child->NextChild();
439 if (!child->IsText() && child->AsElement()->Name() == name)
440 {
441 RemoveChildAfter(prev_child);
442 continue;
443 }
444 prev_child = child;
445 }
446 }
447
ClearAttributes()448 void XmlElement::ClearAttributes() {
449 XmlAttr* attr;
450 for (attr = first_attr_; attr; ) {
451 XmlAttr* to_delete = attr;
452 attr = attr->next_attr_;
453 delete to_delete;
454 }
455 first_attr_ = last_attr_ = NULL;
456 }
457
ClearChildren()458 void XmlElement::ClearChildren() {
459 XmlChild* pchild;
460 for (pchild = first_child_; pchild; ) {
461 XmlChild* to_delete = pchild;
462 pchild = pchild->next_child_;
463 delete to_delete;
464 }
465 first_child_ = last_child_ = NULL;
466 }
467
Str() const468 std::string XmlElement::Str() const {
469 std::stringstream ss;
470 XmlPrinter::PrintXml(&ss, this);
471 return ss.str();
472 }
473
ForStr(const std::string & str)474 XmlElement* XmlElement::ForStr(const std::string& str) {
475 XmlBuilder builder;
476 XmlParser::ParseXml(&builder, str);
477 return builder.CreateElement();
478 }
479
~XmlElement()480 XmlElement::~XmlElement() {
481 XmlAttr* attr;
482 for (attr = first_attr_; attr; ) {
483 XmlAttr* to_delete = attr;
484 attr = attr->next_attr_;
485 delete to_delete;
486 }
487
488 XmlChild* pchild;
489 for (pchild = first_child_; pchild; ) {
490 XmlChild* to_delete = pchild;
491 pchild = pchild->next_child_;
492 delete to_delete;
493 }
494 }
495
496 } // namespace buzz
497