• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * libjingle
3  * Copyright 2004--2005, Google Inc.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  *  1. Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *  2. Redistributions in binary form must reproduce the above copyright notice,
11  *     this list of conditions and the following disclaimer in the documentation
12  *     and/or other materials provided with the distribution.
13  *  3. The name of the author may not be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <string>
29 #include <iostream>
30 #include <vector>
31 #include <sstream>
32 
33 #include "talk/base/common.h"
34 #include "talk/xmllite/xmlelement.h"
35 #include "talk/xmllite/qname.h"
36 #include "talk/xmllite/xmlparser.h"
37 #include "talk/xmllite/xmlbuilder.h"
38 #include "talk/xmllite/xmlprinter.h"
39 #include "talk/xmllite/xmlconstants.h"
40 
41 namespace buzz {
42 
43 const QName QN_EMPTY(true, STR_EMPTY, STR_EMPTY);
44 const QName QN_XMLNS(true, STR_EMPTY, STR_XMLNS);
45 
46 
~XmlChild()47 XmlChild::~XmlChild() {
48 }
49 
50 bool
IsTextImpl() const51 XmlText::IsTextImpl() const {
52   return true;
53 }
54 
55 XmlElement *
AsElementImpl() const56 XmlText::AsElementImpl() const {
57   return NULL;
58 }
59 
60 XmlText *
AsTextImpl() const61 XmlText::AsTextImpl() const {
62   return const_cast<XmlText *>(this);
63 }
64 
65 void
SetText(const std::string & text)66 XmlText::SetText(const std::string & text) {
67   text_ = text;
68 }
69 
70 void
AddParsedText(const char * buf,int len)71 XmlText::AddParsedText(const char * buf, int len) {
72   text_.append(buf, len);
73 }
74 
75 void
AddText(const std::string & text)76 XmlText::AddText(const std::string & text) {
77   text_ += text;
78 }
79 
~XmlText()80 XmlText::~XmlText() {
81 }
82 
XmlElement(const QName & name)83 XmlElement::XmlElement(const QName & name) :
84     name_(name),
85     pFirstAttr_(NULL),
86     pLastAttr_(NULL),
87     pFirstChild_(NULL),
88     pLastChild_(NULL),
89     cdata_(false) {
90 }
91 
XmlElement(const XmlElement & elt)92 XmlElement::XmlElement(const XmlElement & elt) :
93     XmlChild(),
94     name_(elt.name_),
95     pFirstAttr_(NULL),
96     pLastAttr_(NULL),
97     pFirstChild_(NULL),
98     pLastChild_(NULL),
99     cdata_(false) {
100 
101   // copy attributes
102   XmlAttr * pAttr;
103   XmlAttr ** ppLastAttr = &pFirstAttr_;
104   XmlAttr * newAttr = NULL;
105   for (pAttr = elt.pFirstAttr_; pAttr; pAttr = pAttr->NextAttr()) {
106     newAttr = new XmlAttr(*pAttr);
107     *ppLastAttr = newAttr;
108     ppLastAttr = &(newAttr->pNextAttr_);
109   }
110   pLastAttr_ = newAttr;
111 
112   // copy children
113   XmlChild * pChild;
114   XmlChild ** ppLast = &pFirstChild_;
115   XmlChild * newChild = NULL;
116 
117   for (pChild = elt.pFirstChild_; pChild; pChild = pChild->NextChild()) {
118     if (pChild->IsText()) {
119       newChild = new XmlText(*(pChild->AsText()));
120     } else {
121       newChild = new XmlElement(*(pChild->AsElement()));
122     }
123     *ppLast = newChild;
124     ppLast = &(newChild->pNextChild_);
125   }
126   pLastChild_ = newChild;
127 
128   cdata_ = elt.cdata_;
129 }
130 
XmlElement(const QName & name,bool useDefaultNs)131 XmlElement::XmlElement(const QName & name, bool useDefaultNs) :
132   name_(name),
133   pFirstAttr_(useDefaultNs ? new XmlAttr(QN_XMLNS, name.Namespace()) : NULL),
134   pLastAttr_(pFirstAttr_),
135   pFirstChild_(NULL),
136   pLastChild_(NULL),
137   cdata_(false) {
138 }
139 
140 bool
IsTextImpl() const141 XmlElement::IsTextImpl() const {
142   return false;
143 }
144 
145 XmlElement *
AsElementImpl() const146 XmlElement::AsElementImpl() const {
147   return const_cast<XmlElement *>(this);
148 }
149 
150 XmlText *
AsTextImpl() const151 XmlElement::AsTextImpl() const {
152   return NULL;
153 }
154 
155 const std::string &
BodyText() const156 XmlElement::BodyText() const {
157   if (pFirstChild_ && pFirstChild_->IsText() && pLastChild_ == pFirstChild_) {
158     return pFirstChild_->AsText()->Text();
159   }
160 
161   return STR_EMPTY;
162 }
163 
164 void
SetBodyText(const std::string & text)165 XmlElement::SetBodyText(const std::string & text) {
166   if (text == STR_EMPTY) {
167     ClearChildren();
168   } else if (pFirstChild_ == NULL) {
169     AddText(text);
170   } else if (pFirstChild_->IsText() && pLastChild_ == pFirstChild_) {
171     pFirstChild_->AsText()->SetText(text);
172   } else {
173     ClearChildren();
174     AddText(text);
175   }
176 }
177 
178 const QName &
FirstElementName() const179 XmlElement::FirstElementName() const {
180   const XmlElement * element = FirstElement();
181   if (element == NULL)
182     return QN_EMPTY;
183   return element->Name();
184 }
185 
186 XmlAttr *
FirstAttr()187 XmlElement::FirstAttr() {
188   return pFirstAttr_;
189 }
190 
191 const std::string &
Attr(const QName & name) const192 XmlElement::Attr(const QName & name) const {
193   XmlAttr * pattr;
194   for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) {
195     if (pattr->name_ == name)
196       return pattr->value_;
197   }
198   return STR_EMPTY;
199 }
200 
201 bool
HasAttr(const QName & name) const202 XmlElement::HasAttr(const QName & name) const {
203   XmlAttr * pattr;
204   for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) {
205     if (pattr->name_ == name)
206       return true;
207   }
208   return false;
209 }
210 
211 void
SetAttr(const QName & name,const std::string & value)212 XmlElement::SetAttr(const QName & name, const std::string & value) {
213   XmlAttr * pattr;
214   for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) {
215     if (pattr->name_ == name)
216       break;
217   }
218   if (!pattr) {
219     pattr = new XmlAttr(name, value);
220     if (pLastAttr_)
221       pLastAttr_->pNextAttr_ = pattr;
222     else
223       pFirstAttr_ = pattr;
224     pLastAttr_ = pattr;
225     return;
226   }
227   pattr->value_ = value;
228 }
229 
230 void
ClearAttr(const QName & name)231 XmlElement::ClearAttr(const QName & name) {
232   XmlAttr * pattr;
233   XmlAttr *pLastAttr = NULL;
234   for (pattr = pFirstAttr_; pattr; pattr = pattr->pNextAttr_) {
235     if (pattr->name_ == name)
236       break;
237     pLastAttr = pattr;
238   }
239   if (!pattr)
240     return;
241   if (!pLastAttr)
242     pFirstAttr_ = pattr->pNextAttr_;
243   else
244     pLastAttr->pNextAttr_ = pattr->pNextAttr_;
245   if (pLastAttr_ == pattr)
246     pLastAttr_ = pLastAttr;
247   delete pattr;
248 }
249 
250 XmlChild *
FirstChild()251 XmlElement::FirstChild() {
252   return pFirstChild_;
253 }
254 
255 XmlElement *
FirstElement()256 XmlElement::FirstElement() {
257   XmlChild * pChild;
258   for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) {
259     if (!pChild->IsText())
260       return pChild->AsElement();
261   }
262   return NULL;
263 }
264 
265 XmlElement *
NextElement()266 XmlElement::NextElement() {
267   XmlChild * pChild;
268   for (pChild = pNextChild_; pChild; pChild = pChild->pNextChild_) {
269     if (!pChild->IsText())
270       return pChild->AsElement();
271   }
272   return NULL;
273 }
274 
275 XmlElement *
FirstWithNamespace(const std::string & ns)276 XmlElement::FirstWithNamespace(const std::string & ns) {
277   XmlChild * pChild;
278   for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) {
279     if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns)
280       return pChild->AsElement();
281   }
282   return NULL;
283 }
284 
285 XmlElement *
NextWithNamespace(const std::string & ns)286 XmlElement::NextWithNamespace(const std::string & ns) {
287   XmlChild * pChild;
288   for (pChild = pNextChild_; pChild; pChild = pChild->pNextChild_) {
289     if (!pChild->IsText() && pChild->AsElement()->Name().Namespace() == ns)
290       return pChild->AsElement();
291   }
292   return NULL;
293 }
294 
295 XmlElement *
FirstNamed(const QName & name)296 XmlElement::FirstNamed(const QName & name) {
297   XmlChild * pChild;
298   for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) {
299     if (!pChild->IsText() && pChild->AsElement()->Name() == name)
300       return pChild->AsElement();
301   }
302   return NULL;
303 }
304 
305 XmlElement *
NextNamed(const QName & name)306 XmlElement::NextNamed(const QName & name) {
307   XmlChild * pChild;
308   for (pChild = pNextChild_; pChild; pChild = pChild->pNextChild_) {
309     if (!pChild->IsText() && pChild->AsElement()->Name() == name)
310       return pChild->AsElement();
311   }
312   return NULL;
313 }
314 
FindOrAddNamedChild(const QName & name)315 XmlElement* XmlElement::FindOrAddNamedChild(const QName& name) {
316   XmlElement* child = FirstNamed(name);
317   if (!child) {
318     child = new XmlElement(name);
319     AddElement(child);
320   }
321 
322   return child;
323 }
324 
325 const std::string &
TextNamed(const QName & name) const326 XmlElement::TextNamed(const QName & name) const {
327   XmlChild * pChild;
328   for (pChild = pFirstChild_; pChild; pChild = pChild->pNextChild_) {
329     if (!pChild->IsText() && pChild->AsElement()->Name() == name)
330       return pChild->AsElement()->BodyText();
331   }
332   return STR_EMPTY;
333 }
334 
335 void
InsertChildAfter(XmlChild * pPredecessor,XmlChild * pNext)336 XmlElement::InsertChildAfter(XmlChild * pPredecessor, XmlChild * pNext) {
337   if (pPredecessor == NULL) {
338     pNext->pNextChild_ = pFirstChild_;
339     pFirstChild_ = pNext;
340   }
341   else {
342     pNext->pNextChild_ = pPredecessor->pNextChild_;
343     pPredecessor->pNextChild_ = pNext;
344   }
345 }
346 
347 void
RemoveChildAfter(XmlChild * pPredecessor)348 XmlElement::RemoveChildAfter(XmlChild * pPredecessor) {
349   XmlChild * pNext;
350 
351   if (pPredecessor == NULL) {
352     pNext = pFirstChild_;
353     pFirstChild_ = pNext->pNextChild_;
354   }
355   else {
356     pNext = pPredecessor->pNextChild_;
357     pPredecessor->pNextChild_ = pNext->pNextChild_;
358   }
359 
360   if (pLastChild_ == pNext)
361     pLastChild_ = pPredecessor;
362 
363   delete pNext;
364 }
365 
366 void
AddAttr(const QName & name,const std::string & value)367 XmlElement::AddAttr(const QName & name, const std::string & value) {
368   ASSERT(!HasAttr(name));
369 
370   XmlAttr ** pprev = pLastAttr_ ? &(pLastAttr_->pNextAttr_) : &pFirstAttr_;
371   pLastAttr_ = (*pprev = new XmlAttr(name, value));
372 }
373 
374 void
AddAttr(const QName & name,const std::string & value,int depth)375 XmlElement::AddAttr(const QName & name, const std::string & value,
376                          int depth) {
377   XmlElement * element = this;
378   while (depth--) {
379     element = element->pLastChild_->AsElement();
380   }
381   element->AddAttr(name, value);
382 }
383 
384 void
AddParsedText(const char * cstr,int len)385 XmlElement::AddParsedText(const char * cstr, int len) {
386   if (len == 0)
387     return;
388 
389   if (pLastChild_ && pLastChild_->IsText()) {
390     pLastChild_->AsText()->AddParsedText(cstr, len);
391     return;
392   }
393   XmlChild ** pprev = pLastChild_ ? &(pLastChild_->pNextChild_) : &pFirstChild_;
394   pLastChild_ = *pprev = new XmlText(cstr, len);
395 }
396 
397 void
AddCDATAText(const char * buf,int len)398 XmlElement::AddCDATAText(const char * buf, int len) {
399   cdata_ = true;
400   AddParsedText(buf, len);
401 }
402 
403 void
AddText(const std::string & text)404 XmlElement::AddText(const std::string & text) {
405   if (text == STR_EMPTY)
406     return;
407 
408   if (pLastChild_ && pLastChild_->IsText()) {
409     pLastChild_->AsText()->AddText(text);
410     return;
411   }
412   XmlChild ** pprev = pLastChild_ ? &(pLastChild_->pNextChild_) : &pFirstChild_;
413   pLastChild_ = *pprev = new XmlText(text);
414 }
415 
416 void
AddText(const std::string & text,int depth)417 XmlElement::AddText(const std::string & text, int depth) {
418   // note: the first syntax is ambigious for msvc 6
419   // XmlElement * pel(this);
420   XmlElement * element = this;
421   while (depth--) {
422     element = element->pLastChild_->AsElement();
423   }
424   element->AddText(text);
425 }
426 
427 void
AddElement(XmlElement * pelChild)428 XmlElement::AddElement(XmlElement *pelChild) {
429   if (pelChild == NULL)
430     return;
431 
432   XmlChild ** pprev = pLastChild_ ? &(pLastChild_->pNextChild_) : &pFirstChild_;
433   pLastChild_ = *pprev = pelChild;
434   pelChild->pNextChild_ = NULL;
435 }
436 
437 void
AddElement(XmlElement * pelChild,int depth)438 XmlElement::AddElement(XmlElement *pelChild, int depth) {
439   XmlElement * element = this;
440   while (depth--) {
441     element = element->pLastChild_->AsElement();
442   }
443   element->AddElement(pelChild);
444 }
445 
446 void
ClearNamedChildren(const QName & name)447 XmlElement::ClearNamedChildren(const QName & name) {
448   XmlChild * prev_child = NULL;
449   XmlChild * next_child;
450   XmlChild * child;
451   for (child = FirstChild(); child; child = next_child) {
452     next_child = child->NextChild();
453     if (!child->IsText() && child->AsElement()->Name() == name)
454     {
455       RemoveChildAfter(prev_child);
456       continue;
457     }
458     prev_child = child;
459   }
460 }
461 
462 void
ClearAttributes()463 XmlElement::ClearAttributes() {
464   XmlAttr * pattr;
465   for (pattr = pFirstAttr_; pattr; ) {
466     XmlAttr * pToDelete = pattr;
467     pattr = pattr->pNextAttr_;
468     delete pToDelete;
469   }
470   pFirstAttr_ = pLastAttr_ = NULL;
471 }
472 
473 void
ClearChildren()474 XmlElement::ClearChildren() {
475   XmlChild * pchild;
476   for (pchild = pFirstChild_; pchild; ) {
477     XmlChild * pToDelete = pchild;
478     pchild = pchild->pNextChild_;
479     delete pToDelete;
480   }
481   pFirstChild_ = pLastChild_ = NULL;
482 }
483 
484 std::string
Str() const485 XmlElement::Str() const {
486   std::stringstream ss;
487   Print(&ss, NULL, 0);
488   return ss.str();
489 }
490 
491 XmlElement *
ForStr(const std::string & str)492 XmlElement::ForStr(const std::string & str) {
493   XmlBuilder builder;
494   XmlParser::ParseXml(&builder, str);
495   return builder.CreateElement();
496 }
497 
498 void
Print(std::ostream * pout,std::string xmlns[],int xmlnsCount) const499 XmlElement::Print(
500     std::ostream * pout, std::string xmlns[], int xmlnsCount) const {
501   XmlPrinter::PrintXml(pout, this, xmlns, xmlnsCount);
502 }
503 
~XmlElement()504 XmlElement::~XmlElement() {
505   XmlAttr * pattr;
506   for (pattr = pFirstAttr_; pattr; ) {
507     XmlAttr * pToDelete = pattr;
508     pattr = pattr->pNextAttr_;
509     delete pToDelete;
510   }
511 
512   XmlChild * pchild;
513   for (pchild = pFirstChild_; pchild; ) {
514     XmlChild * pToDelete = pchild;
515     pchild = pchild->pNextChild_;
516     delete pToDelete;
517   }
518 }
519 
520 }
521