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