Home | History | Annotate | Download | only in xmllite
      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 
     22 XmlnsStack::XmlnsStack() :
     23   pxmlnsStack_(new std::vector<std::string>),
     24   pxmlnsDepthStack_(new std::vector<size_t>) {
     25 }
     26 
     27 XmlnsStack::~XmlnsStack() {}
     28 
     29 void XmlnsStack::PushFrame() {
     30   pxmlnsDepthStack_->push_back(pxmlnsStack_->size());
     31 }
     32 
     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 
     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 
     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 
     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 
     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 
    103 void XmlnsStack::AddXmlns(const std::string & prefix, const std::string & ns) {
    104   pxmlnsStack_->push_back(prefix);
    105   pxmlnsStack_->push_back(ns);
    106 }
    107 
    108 void XmlnsStack::RemoveXmlns() {
    109   pxmlnsStack_->pop_back();
    110   pxmlnsStack_->pop_back();
    111 }
    112 
    113 static bool IsAsciiLetter(char ch) {
    114   return ((ch >= 'a' && ch <= 'z') ||
    115           (ch >= 'A' && ch <= 'Z'));
    116 }
    117 
    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 
    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 
    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 
    173 void XmlnsStack::Reset() {
    174   pxmlnsStack_->clear();
    175   pxmlnsDepthStack_->clear();
    176 }
    177 
    178 }
    179