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