• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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