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