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 39 namespace buzz { 40 41 42 static void 43 StartElementCallback(void * userData, const char *name, const char **atts) { 44 (static_cast<XmlParser *>(userData))->ExpatStartElement(name, atts); 45 } 46 47 static void 48 EndElementCallback(void * userData, const char *name) { 49 (static_cast<XmlParser *>(userData))->ExpatEndElement(name); 50 } 51 52 static void 53 CharacterDataCallback(void * userData, const char *text, int len) { 54 (static_cast<XmlParser *>(userData))->ExpatCharacterData(text, len); 55 } 56 57 static void 58 XmlDeclCallback(void * userData, const char * ver, const char * enc, int st) { 59 (static_cast<XmlParser *>(userData))->ExpatXmlDecl(ver, enc, st); 60 } 61 62 XmlParser::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 71 void 72 XmlParser::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 85 static bool 86 XmlParser_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 94 void 95 XmlParser::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 121 void 122 XmlParser::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 132 void 133 XmlParser::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 142 void 143 XmlParser::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 167 bool 168 XmlParser::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 189 XmlParser::~XmlParser() { 190 XML_ParserFree(expat_); 191 } 192 193 void 194 XmlParser::ParseXml(XmlParseHandler *pxph, std::string text) { 195 XmlParser parser(pxph); 196 parser.Parse(text.c_str(), text.length(), true); 197 } 198 199 XmlParser::ParseContext::ParseContext() : 200 xmlnsstack_(), 201 raised_(XML_ERROR_NONE), 202 line_number_(0), 203 column_number_(0), 204 byte_index_(0) { 205 } 206 207 void 208 XmlParser::ParseContext::StartNamespace(const char *prefix, const char *ns) { 209 xmlnsstack_.AddXmlns(*prefix ? prefix : STR_EMPTY, ns); 210 } 211 212 void 213 XmlParser::ParseContext::StartElement() { 214 xmlnsstack_.PushFrame(); 215 } 216 217 void 218 XmlParser::ParseContext::EndElement() { 219 xmlnsstack_.PopFrame(); 220 } 221 222 QName 223 XmlParser::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 244 void 245 XmlParser::ParseContext::Reset() { 246 xmlnsstack_.Reset(); 247 raised_ = XML_ERROR_NONE; 248 } 249 250 void 251 XmlParser::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 258 void 259 XmlParser::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 275 XmlParser::ParseContext::~ParseContext() { 276 } 277 278 } // namespace buzz 279