• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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