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/xmlnsstack.h"
12
13 #include <sstream>
14 #include <string>
15 #include <vector>
16
17 #include "webrtc/libjingle/xmllite/xmlconstants.h"
18 #include "webrtc/libjingle/xmllite/xmlelement.h"
19
20 namespace buzz {
21
XmlnsStack()22 XmlnsStack::XmlnsStack() :
23 pxmlnsStack_(new std::vector<std::string>),
24 pxmlnsDepthStack_(new std::vector<size_t>) {
25 }
26
~XmlnsStack()27 XmlnsStack::~XmlnsStack() {}
28
PushFrame()29 void XmlnsStack::PushFrame() {
30 pxmlnsDepthStack_->push_back(pxmlnsStack_->size());
31 }
32
PopFrame()33 void XmlnsStack::PopFrame() {
34 size_t prev_size = pxmlnsDepthStack_->back();
35 pxmlnsDepthStack_->pop_back();
36 if (prev_size < pxmlnsStack_->size()) {
37 pxmlnsStack_->erase(pxmlnsStack_->begin() + prev_size,
38 pxmlnsStack_->end());
39 }
40 }
41
NsForPrefix(const std::string & prefix)42 std::pair<std::string, bool> XmlnsStack::NsForPrefix(
43 const std::string& prefix) {
44 if (prefix.length() >= 3 &&
45 (prefix[0] == 'x' || prefix[0] == 'X') &&
46 (prefix[1] == 'm' || prefix[1] == 'M') &&
47 (prefix[2] == 'l' || prefix[2] == 'L')) {
48 if (prefix == "xml")
49 return std::make_pair(NS_XML, true);
50 if (prefix == "xmlns")
51 return std::make_pair(NS_XMLNS, true);
52 // Other names with xml prefix are illegal.
53 return std::make_pair(STR_EMPTY, false);
54 }
55
56 std::vector<std::string>::iterator pos;
57 for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) {
58 pos -= 2;
59 if (*pos == prefix)
60 return std::make_pair(*(pos + 1), true);
61 }
62
63 if (prefix == STR_EMPTY)
64 return std::make_pair(STR_EMPTY, true); // default namespace
65
66 return std::make_pair(STR_EMPTY, false); // none found
67 }
68
PrefixMatchesNs(const std::string & prefix,const std::string & ns)69 bool XmlnsStack::PrefixMatchesNs(const std::string& prefix,
70 const std::string& ns) {
71 const std::pair<std::string, bool> match = NsForPrefix(prefix);
72 return match.second && (match.first == ns);
73 }
74
PrefixForNs(const std::string & ns,bool isattr)75 std::pair<std::string, bool> XmlnsStack::PrefixForNs(const std::string& ns,
76 bool isattr) {
77 if (ns == NS_XML)
78 return std::make_pair(std::string("xml"), true);
79 if (ns == NS_XMLNS)
80 return std::make_pair(std::string("xmlns"), true);
81 if (isattr ? ns == STR_EMPTY : PrefixMatchesNs(STR_EMPTY, ns))
82 return std::make_pair(STR_EMPTY, true);
83
84 std::vector<std::string>::iterator pos;
85 for (pos = pxmlnsStack_->end(); pos > pxmlnsStack_->begin(); ) {
86 pos -= 2;
87 if (*(pos + 1) == ns &&
88 (!isattr || !pos->empty()) && PrefixMatchesNs(*pos, ns))
89 return std::make_pair(*pos, true);
90 }
91
92 return std::make_pair(STR_EMPTY, false); // none found
93 }
94
FormatQName(const QName & name,bool isAttr)95 std::string XmlnsStack::FormatQName(const QName& name, bool isAttr) {
96 std::string prefix(PrefixForNs(name.Namespace(), isAttr).first);
97 if (prefix == STR_EMPTY)
98 return name.LocalPart();
99 else
100 return prefix + ':' + name.LocalPart();
101 }
102
AddXmlns(const std::string & prefix,const std::string & ns)103 void XmlnsStack::AddXmlns(const std::string & prefix, const std::string & ns) {
104 pxmlnsStack_->push_back(prefix);
105 pxmlnsStack_->push_back(ns);
106 }
107
RemoveXmlns()108 void XmlnsStack::RemoveXmlns() {
109 pxmlnsStack_->pop_back();
110 pxmlnsStack_->pop_back();
111 }
112
IsAsciiLetter(char ch)113 static bool IsAsciiLetter(char ch) {
114 return ((ch >= 'a' && ch <= 'z') ||
115 (ch >= 'A' && ch <= 'Z'));
116 }
117
AsciiLower(const std::string & s)118 static std::string AsciiLower(const std::string & s) {
119 std::string result(s);
120 size_t i;
121 for (i = 0; i < result.length(); i++) {
122 if (result[i] >= 'A' && result[i] <= 'Z')
123 result[i] += 'a' - 'A';
124 }
125 return result;
126 }
127
SuggestPrefix(const std::string & ns)128 static std::string SuggestPrefix(const std::string & ns) {
129 size_t len = ns.length();
130 size_t i = ns.find_last_of('.');
131 if (i != std::string::npos && len - i <= 4 + 1)
132 len = i; // chop off ".html" or ".xsd" or ".?{0,4}"
133 size_t last = len;
134 while (last > 0) {
135 last -= 1;
136 if (IsAsciiLetter(ns[last])) {
137 size_t first = last;
138 last += 1;
139 while (first > 0) {
140 if (!IsAsciiLetter(ns[first - 1]))
141 break;
142 first -= 1;
143 }
144 if (last - first > 4)
145 last = first + 3;
146 std::string candidate(AsciiLower(ns.substr(first, last - first)));
147 if (candidate.find("xml") != 0)
148 return candidate;
149 break;
150 }
151 }
152 return "ns";
153 }
154
AddNewPrefix(const std::string & ns,bool isAttr)155 std::pair<std::string, bool> XmlnsStack::AddNewPrefix(const std::string& ns,
156 bool isAttr) {
157 if (PrefixForNs(ns, isAttr).second)
158 return std::make_pair(STR_EMPTY, false);
159
160 std::string base(SuggestPrefix(ns));
161 std::string result(base);
162 int i = 2;
163 while (NsForPrefix(result).second) {
164 std::stringstream ss;
165 ss << base;
166 ss << (i++);
167 ss >> result;
168 }
169 AddXmlns(result, ns);
170 return std::make_pair(result, true);
171 }
172
Reset()173 void XmlnsStack::Reset() {
174 pxmlnsStack_->clear();
175 pxmlnsDepthStack_->clear();
176 }
177
178 }
179