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