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
25namespace buzz {
26
27XmlChild::~XmlChild() {
28}
29
30bool XmlText::IsTextImpl() const {
31  return true;
32}
33
34XmlElement* XmlText::AsElementImpl() const {
35  return NULL;
36}
37
38XmlText* XmlText::AsTextImpl() const {
39  return const_cast<XmlText *>(this);
40}
41
42void XmlText::SetText(const std::string& text) {
43  text_ = text;
44}
45
46void XmlText::AddParsedText(const char* buf, int len) {
47  text_.append(buf, len);
48}
49
50void XmlText::AddText(const std::string& text) {
51  text_ += text;
52}
53
54XmlText::~XmlText() {
55}
56
57XmlElement::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
66XmlElement::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
105XmlElement::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
114bool XmlElement::IsTextImpl() const {
115  return false;
116}
117
118XmlElement* XmlElement::AsElementImpl() const {
119  return const_cast<XmlElement *>(this);
120}
121
122XmlText* XmlElement::AsTextImpl() const {
123  return NULL;
124}
125
126const 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
134void 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
147const QName XmlElement::FirstElementName() const {
148  const XmlElement* element = FirstElement();
149  if (element == NULL)
150    return QName();
151  return element->Name();
152}
153
154XmlAttr* XmlElement::FirstAttr() {
155  return first_attr_;
156}
157
158const 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
167const 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
176bool 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
185bool 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
194void 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
212void 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
231XmlChild* XmlElement::FirstChild() {
232  return first_child_;
233}
234
235XmlElement* 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
244XmlElement* 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
253XmlElement* 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
262XmlElement *
263XmlElement::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
272XmlElement *
273XmlElement::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
282XmlElement *
283XmlElement::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
292XmlElement *
293XmlElement::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
302XmlElement *
303XmlElement::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
312XmlElement* 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
322const 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
331void 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
342void 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
360void 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
367void 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
376void 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
388void XmlElement::AddCDATAText(const char* buf, int len) {
389  cdata_ = true;
390  AddParsedText(buf, len);
391}
392
393void 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
405void 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
415void 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
425void 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
433void 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
448void 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
458void 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
468std::string XmlElement::Str() const {
469  std::stringstream ss;
470  XmlPrinter::PrintXml(&ss, this);
471  return ss.str();
472}
473
474XmlElement* XmlElement::ForStr(const std::string& str) {
475  XmlBuilder builder;
476  XmlParser::ParseXml(&builder, str);
477  return builder.CreateElement();
478}
479
480XmlElement::~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