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
StartElementCallback(void * userData,const char * name,const char ** atts)26 StartElementCallback(void * userData, const char *name, const char **atts) {
27 (static_cast<XmlParser *>(userData))->ExpatStartElement(name, atts);
28 }
29
30 static void
EndElementCallback(void * userData,const char * name)31 EndElementCallback(void * userData, const char *name) {
32 (static_cast<XmlParser *>(userData))->ExpatEndElement(name);
33 }
34
35 static void
CharacterDataCallback(void * userData,const char * text,int len)36 CharacterDataCallback(void * userData, const char *text, int len) {
37 (static_cast<XmlParser *>(userData))->ExpatCharacterData(text, len);
38 }
39
40 static void
XmlDeclCallback(void * userData,const char * ver,const char * enc,int st)41 XmlDeclCallback(void * userData, const char * ver, const char * enc, int st) {
42 (static_cast<XmlParser *>(userData))->ExpatXmlDecl(ver, enc, st);
43 }
44
XmlParser(XmlParseHandler * pxph)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
Reset()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
XmlParser_StartsWithXmlns(const char * name)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
ExpatStartElement(const char * name,const char ** atts)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
ExpatEndElement(const char * name)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
ExpatCharacterData(const char * text,int len)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
ExpatXmlDecl(const char * ver,const char * enc,int standalone)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
Parse(const char * data,size_t len,bool isFinal)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
~XmlParser()172 XmlParser::~XmlParser() {
173 XML_ParserFree(expat_);
174 }
175
176 void
ParseXml(XmlParseHandler * pxph,std::string text)177 XmlParser::ParseXml(XmlParseHandler *pxph, std::string text) {
178 XmlParser parser(pxph);
179 parser.Parse(text.c_str(), text.length(), true);
180 }
181
ParseContext()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
StartNamespace(const char * prefix,const char * ns)191 XmlParser::ParseContext::StartNamespace(const char *prefix, const char *ns) {
192 xmlnsstack_.AddXmlns(*prefix ? prefix : STR_EMPTY, ns);
193 }
194
195 void
StartElement()196 XmlParser::ParseContext::StartElement() {
197 xmlnsstack_.PushFrame();
198 }
199
200 void
EndElement()201 XmlParser::ParseContext::EndElement() {
202 xmlnsstack_.PopFrame();
203 }
204
205 QName
ResolveQName(const char * qname,bool isAttr)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
Reset()228 XmlParser::ParseContext::Reset() {
229 xmlnsstack_.Reset();
230 raised_ = XML_ERROR_NONE;
231 }
232
233 void
SetPosition(int line,int column,long byte_index)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
GetPosition(unsigned long * line,unsigned long * column,unsigned long * byte_index)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
~ParseContext()258 XmlParser::ParseContext::~ParseContext() {
259 }
260
261 } // namespace buzz
262