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 38 XmlnsStack::XmlnsStack() : 39 pxmlnsStack_(new std::vector<std::string>), 40 pxmlnsDepthStack_(new std::vector<size_t>) { 41 } 42 43 XmlnsStack::~XmlnsStack() {} 44 45 void 46 XmlnsStack::PushFrame() { 47 pxmlnsDepthStack_->push_back(pxmlnsStack_->size()); 48 } 49 50 void 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 * 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 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> 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 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 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 133 XmlnsStack::RemoveXmlns() { 134 pxmlnsStack_->pop_back(); 135 pxmlnsStack_->pop_back(); 136 } 137 138 static bool IsAsciiLetter(char ch) { 139 return ((ch >= 'a' && ch <= 'z') || 140 (ch >= 'A' && ch <= 'Z')); 141 } 142 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 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> 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 199 void XmlnsStack::Reset() { 200 pxmlnsStack_->clear(); 201 pxmlnsDepthStack_->clear(); 202 } 203 204 } 205