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 22namespace buzz { 23 24 25static void 26StartElementCallback(void * userData, const char *name, const char **atts) { 27 (static_cast<XmlParser *>(userData))->ExpatStartElement(name, atts); 28} 29 30static void 31EndElementCallback(void * userData, const char *name) { 32 (static_cast<XmlParser *>(userData))->ExpatEndElement(name); 33} 34 35static void 36CharacterDataCallback(void * userData, const char *text, int len) { 37 (static_cast<XmlParser *>(userData))->ExpatCharacterData(text, len); 38} 39 40static void 41XmlDeclCallback(void * userData, const char * ver, const char * enc, int st) { 42 (static_cast<XmlParser *>(userData))->ExpatXmlDecl(ver, enc, st); 43} 44 45XmlParser::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 54void 55XmlParser::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 68static bool 69XmlParser_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 77void 78XmlParser::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 104void 105XmlParser::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 115void 116XmlParser::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 125void 126XmlParser::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 150bool 151XmlParser::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 172XmlParser::~XmlParser() { 173 XML_ParserFree(expat_); 174} 175 176void 177XmlParser::ParseXml(XmlParseHandler *pxph, std::string text) { 178 XmlParser parser(pxph); 179 parser.Parse(text.c_str(), text.length(), true); 180} 181 182XmlParser::ParseContext::ParseContext() : 183 xmlnsstack_(), 184 raised_(XML_ERROR_NONE), 185 line_number_(0), 186 column_number_(0), 187 byte_index_(0) { 188} 189 190void 191XmlParser::ParseContext::StartNamespace(const char *prefix, const char *ns) { 192 xmlnsstack_.AddXmlns(*prefix ? prefix : STR_EMPTY, ns); 193} 194 195void 196XmlParser::ParseContext::StartElement() { 197 xmlnsstack_.PushFrame(); 198} 199 200void 201XmlParser::ParseContext::EndElement() { 202 xmlnsstack_.PopFrame(); 203} 204 205QName 206XmlParser::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 227void 228XmlParser::ParseContext::Reset() { 229 xmlnsstack_.Reset(); 230 raised_ = XML_ERROR_NONE; 231} 232 233void 234XmlParser::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 241void 242XmlParser::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 258XmlParser::ParseContext::~ParseContext() { 259} 260 261} // namespace buzz 262