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/xmlparser.h"
     12 
     13 #include <string>
     14 #include <vector>
     15 
     16 #include "webrtc/libjingle/xmllite/xmlconstants.h"
     17 #include "webrtc/libjingle/xmllite/xmlelement.h"
     18 #include "webrtc/libjingle/xmllite/xmlnsstack.h"
     19 #include "webrtc/libjingle/xmllite/xmlnsstack.h"
     20 #include "webrtc/base/common.h"
     21 
     22 namespace buzz {
     23 
     24 
     25 static void
     26 StartElementCallback(void * userData, const char *name, const char **atts) {
     27   (static_cast<XmlParser *>(userData))->ExpatStartElement(name, atts);
     28 }
     29 
     30 static void
     31 EndElementCallback(void * userData, const char *name) {
     32   (static_cast<XmlParser *>(userData))->ExpatEndElement(name);
     33 }
     34 
     35 static void
     36 CharacterDataCallback(void * userData, const char *text, int len) {
     37   (static_cast<XmlParser *>(userData))->ExpatCharacterData(text, len);
     38 }
     39 
     40 static void
     41 XmlDeclCallback(void * userData, const char * ver, const char * enc, int st) {
     42   (static_cast<XmlParser *>(userData))->ExpatXmlDecl(ver, enc, st);
     43 }
     44 
     45 XmlParser::XmlParser(XmlParseHandler *pxph) :
     46     pxph_(pxph), sentError_(false) {
     47   expat_ = XML_ParserCreate(NULL);
     48   XML_SetUserData(expat_, this);
     49   XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback);
     50   XML_SetCharacterDataHandler(expat_, CharacterDataCallback);
     51   XML_SetXmlDeclHandler(expat_, XmlDeclCallback);
     52 }
     53 
     54 void
     55 XmlParser::Reset() {
     56   if (!XML_ParserReset(expat_, NULL)) {
     57     XML_ParserFree(expat_);
     58     expat_ = XML_ParserCreate(NULL);
     59   }
     60   XML_SetUserData(expat_, this);
     61   XML_SetElementHandler(expat_, StartElementCallback, EndElementCallback);
     62   XML_SetCharacterDataHandler(expat_, CharacterDataCallback);
     63   XML_SetXmlDeclHandler(expat_, XmlDeclCallback);
     64   context_.Reset();
     65   sentError_ = false;
     66 }
     67 
     68 static bool
     69 XmlParser_StartsWithXmlns(const char *name) {
     70   return name[0] == 'x' &&
     71          name[1] == 'm' &&
     72          name[2] == 'l' &&
     73          name[3] == 'n' &&
     74          name[4] == 's';
     75 }
     76 
     77 void
     78 XmlParser::ExpatStartElement(const char *name, const char **atts) {
     79   if (context_.RaisedError() != XML_ERROR_NONE)
     80     return;
     81   const char **att;
     82   context_.StartElement();
     83   for (att = atts; *att; att += 2) {
     84     if (XmlParser_StartsWithXmlns(*att)) {
     85       if ((*att)[5] == '\0') {
     86         context_.StartNamespace("", *(att + 1));
     87       }
     88       else if ((*att)[5] == ':') {
     89         if (**(att + 1) == '\0') {
     90           // In XML 1.0 empty namespace illegal with prefix (not in 1.1)
     91           context_.RaiseError(XML_ERROR_SYNTAX);
     92           return;
     93         }
     94         context_.StartNamespace((*att) + 6, *(att + 1));
     95       }
     96     }
     97   }
     98   context_.SetPosition(XML_GetCurrentLineNumber(expat_),
     99                        XML_GetCurrentColumnNumber(expat_),
    100                        XML_GetCurrentByteIndex(expat_));
    101   pxph_->StartElement(&context_, name, atts);
    102 }
    103 
    104 void
    105 XmlParser::ExpatEndElement(const char *name) {
    106   if (context_.RaisedError() != XML_ERROR_NONE)
    107     return;
    108   context_.EndElement();
    109   context_.SetPosition(XML_GetCurrentLineNumber(expat_),
    110                        XML_GetCurrentColumnNumber(expat_),
    111                        XML_GetCurrentByteIndex(expat_));
    112   pxph_->EndElement(&context_, name);
    113 }
    114 
    115 void
    116 XmlParser::ExpatCharacterData(const char *text, int len) {
    117   if (context_.RaisedError() != XML_ERROR_NONE)
    118     return;
    119   context_.SetPosition(XML_GetCurrentLineNumber(expat_),
    120                        XML_GetCurrentColumnNumber(expat_),
    121                        XML_GetCurrentByteIndex(expat_));
    122   pxph_->CharacterData(&context_, text, len);
    123 }
    124 
    125 void
    126 XmlParser::ExpatXmlDecl(const char * ver, const char * enc, int standalone) {
    127   if (context_.RaisedError() != XML_ERROR_NONE)
    128     return;
    129 
    130   if (ver && std::string("1.0") != ver) {
    131     context_.RaiseError(XML_ERROR_SYNTAX);
    132     return;
    133   }
    134 
    135   if (standalone == 0) {
    136     context_.RaiseError(XML_ERROR_SYNTAX);
    137     return;
    138   }
    139 
    140   if (enc && !((enc[0] == 'U' || enc[0] == 'u') &&
    141                (enc[1] == 'T' || enc[1] == 't') &&
    142                (enc[2] == 'F' || enc[2] == 'f') &&
    143                 enc[3] == '-' && enc[4] =='8')) {
    144     context_.RaiseError(XML_ERROR_INCORRECT_ENCODING);
    145     return;
    146   }
    147 
    148 }
    149 
    150 bool
    151 XmlParser::Parse(const char *data, size_t len, bool isFinal) {
    152   if (sentError_)
    153     return false;
    154 
    155   if (XML_Parse(expat_, data, static_cast<int>(len), isFinal) !=
    156       XML_STATUS_OK) {
    157     context_.SetPosition(XML_GetCurrentLineNumber(expat_),
    158                          XML_GetCurrentColumnNumber(expat_),
    159                          XML_GetCurrentByteIndex(expat_));
    160     context_.RaiseError(XML_GetErrorCode(expat_));
    161   }
    162 
    163   if (context_.RaisedError() != XML_ERROR_NONE) {
    164     sentError_ = true;
    165     pxph_->Error(&context_, context_.RaisedError());
    166     return false;
    167   }
    168 
    169   return true;
    170 }
    171 
    172 XmlParser::~XmlParser() {
    173   XML_ParserFree(expat_);
    174 }
    175 
    176 void
    177 XmlParser::ParseXml(XmlParseHandler *pxph, std::string text) {
    178   XmlParser parser(pxph);
    179   parser.Parse(text.c_str(), text.length(), true);
    180 }
    181 
    182 XmlParser::ParseContext::ParseContext() :
    183     xmlnsstack_(),
    184     raised_(XML_ERROR_NONE),
    185     line_number_(0),
    186     column_number_(0),
    187     byte_index_(0) {
    188 }
    189 
    190 void
    191 XmlParser::ParseContext::StartNamespace(const char *prefix, const char *ns) {
    192   xmlnsstack_.AddXmlns(*prefix ? prefix : STR_EMPTY, ns);
    193 }
    194 
    195 void
    196 XmlParser::ParseContext::StartElement() {
    197   xmlnsstack_.PushFrame();
    198 }
    199 
    200 void
    201 XmlParser::ParseContext::EndElement() {
    202   xmlnsstack_.PopFrame();
    203 }
    204 
    205 QName
    206 XmlParser::ParseContext::ResolveQName(const char* qname, bool isAttr) {
    207   const char *c;
    208   for (c = qname; *c; ++c) {
    209     if (*c == ':') {
    210       const std::pair<std::string, bool> result =
    211           xmlnsstack_.NsForPrefix(std::string(qname, c - qname));
    212       if (!result.second)
    213         return QName();
    214       return QName(result.first, c + 1);
    215     }
    216   }
    217   if (isAttr)
    218     return QName(STR_EMPTY, qname);
    219 
    220   std::pair<std::string, bool> result = xmlnsstack_.NsForPrefix(STR_EMPTY);
    221   if (!result.second)
    222     return QName();
    223 
    224   return QName(result.first, qname);
    225 }
    226 
    227 void
    228 XmlParser::ParseContext::Reset() {
    229   xmlnsstack_.Reset();
    230   raised_ = XML_ERROR_NONE;
    231 }
    232 
    233 void
    234 XmlParser::ParseContext::SetPosition(int line, int column,
    235                                           long byte_index) {
    236   line_number_ = line;
    237   column_number_ = column;
    238   byte_index_ = byte_index;
    239 }
    240 
    241 void
    242 XmlParser::ParseContext::GetPosition(unsigned long * line,
    243                                      unsigned long * column,
    244                                      unsigned long * byte_index) {
    245   if (line != NULL) {
    246     *line = static_cast<unsigned long>(line_number_);
    247   }
    248 
    249   if (column != NULL) {
    250     *column = static_cast<unsigned long>(column_number_);
    251   }
    252 
    253   if (byte_index != NULL) {
    254     *byte_index = static_cast<unsigned long>(byte_index_);
    255   }
    256 }
    257 
    258 XmlParser::ParseContext::~ParseContext() {
    259 }
    260 
    261 }  // namespace buzz
    262