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/xmlbuilder.h"
12
13#include <set>
14#include <vector>
15#include "webrtc/libjingle/xmllite/xmlconstants.h"
16#include "webrtc/libjingle/xmllite/xmlelement.h"
17#include "webrtc/base/common.h"
18
19namespace buzz {
20
21XmlBuilder::XmlBuilder() :
22  pelCurrent_(NULL),
23  pelRoot_(),
24  pvParents_(new std::vector<XmlElement *>()) {
25}
26
27void
28XmlBuilder::Reset() {
29  pelRoot_.reset();
30  pelCurrent_ = NULL;
31  pvParents_->clear();
32}
33
34XmlElement *
35XmlBuilder::BuildElement(XmlParseContext * pctx,
36                              const char * name, const char ** atts) {
37  QName tagName(pctx->ResolveQName(name, false));
38  if (tagName.IsEmpty())
39    return NULL;
40
41  XmlElement * pelNew = new XmlElement(tagName);
42
43  if (!*atts)
44    return pelNew;
45
46  std::set<QName> seenNonlocalAtts;
47
48  while (*atts) {
49    QName attName(pctx->ResolveQName(*atts, true));
50    if (attName.IsEmpty()) {
51      delete pelNew;
52      return NULL;
53    }
54
55    // verify that namespaced names are unique
56    if (!attName.Namespace().empty()) {
57      if (seenNonlocalAtts.count(attName)) {
58        delete pelNew;
59        return NULL;
60      }
61      seenNonlocalAtts.insert(attName);
62    }
63
64    pelNew->AddAttr(attName, std::string(*(atts + 1)));
65    atts += 2;
66  }
67
68  return pelNew;
69}
70
71void
72XmlBuilder::StartElement(XmlParseContext * pctx,
73                              const char * name, const char ** atts) {
74  XmlElement * pelNew = BuildElement(pctx, name, atts);
75  if (pelNew == NULL) {
76    pctx->RaiseError(XML_ERROR_SYNTAX);
77    return;
78  }
79
80  if (!pelCurrent_) {
81    pelCurrent_ = pelNew;
82    pelRoot_.reset(pelNew);
83    pvParents_->push_back(NULL);
84  } else {
85    pelCurrent_->AddElement(pelNew);
86    pvParents_->push_back(pelCurrent_);
87    pelCurrent_ = pelNew;
88  }
89}
90
91void
92XmlBuilder::EndElement(XmlParseContext * pctx, const char * name) {
93  RTC_UNUSED(pctx);
94  RTC_UNUSED(name);
95  pelCurrent_ = pvParents_->back();
96  pvParents_->pop_back();
97}
98
99void
100XmlBuilder::CharacterData(XmlParseContext * pctx,
101                               const char * text, int len) {
102  RTC_UNUSED(pctx);
103  if (pelCurrent_) {
104    pelCurrent_->AddParsedText(text, len);
105  }
106}
107
108void
109XmlBuilder::Error(XmlParseContext * pctx, XML_Error err) {
110  RTC_UNUSED(pctx);
111  RTC_UNUSED(err);
112  pelRoot_.reset(NULL);
113  pelCurrent_ = NULL;
114  pvParents_->clear();
115}
116
117XmlElement *
118XmlBuilder::CreateElement() {
119  return pelRoot_.release();
120}
121
122XmlElement *
123XmlBuilder::BuiltElement() {
124  return pelRoot_.get();
125}
126
127XmlBuilder::~XmlBuilder() {
128}
129
130}  // namespace buzz
131