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