OLD | NEW |
| (Empty) |
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 | |
OLD | NEW |