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