• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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