• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkXMLParser.h"
9 
10 #include "expat.h"
11 
12 #include "SkStream.h"
13 #include "SkString.h"
14 #include "SkTo.h"
15 #include "SkTypes.h"
16 
17 static char const* const gErrorStrings[] = {
18     "empty or missing file ",
19     "unknown element ",
20     "unknown attribute name ",
21     "error in attribute value ",
22     "duplicate ID ",
23     "unknown error "
24 };
25 
SkXMLParserError()26 SkXMLParserError::SkXMLParserError() : fCode(kNoError), fLineNumber(-1),
27     fNativeCode(-1)
28 {
29     reset();
30 }
31 
~SkXMLParserError()32 SkXMLParserError::~SkXMLParserError()
33 {
34     // need a virtual destructor for our subclasses
35 }
36 
getErrorString(SkString * str) const37 void SkXMLParserError::getErrorString(SkString* str) const
38 {
39     SkASSERT(str);
40     SkString temp;
41     if (fCode != kNoError) {
42         if ((unsigned)fCode < SK_ARRAY_COUNT(gErrorStrings))
43             temp.set(gErrorStrings[fCode - 1]);
44         temp.append(fNoun);
45     } else
46         SkXMLParser::GetNativeErrorString(fNativeCode, &temp);
47     str->append(temp);
48 }
49 
reset()50 void SkXMLParserError::reset() {
51     fCode = kNoError;
52     fLineNumber = -1;
53     fNativeCode = -1;
54 }
55 
56 ////////////////
57 
58 namespace {
59 
60 const XML_Memory_Handling_Suite sk_XML_alloc = {
61     sk_malloc_throw,
62     sk_realloc_throw,
63     sk_free
64 };
65 
66 struct ParsingContext {
ParsingContext__anon189c57350111::ParsingContext67     ParsingContext(SkXMLParser* parser)
68         : fParser(parser)
69         , fXMLParser(XML_ParserCreate_MM(nullptr, &sk_XML_alloc, nullptr)) { }
70 
flushText__anon189c57350111::ParsingContext71     void flushText() {
72         if (!fBufferedText.isEmpty()) {
73             fParser->text(fBufferedText.c_str(), SkTo<int>(fBufferedText.size()));
74             fBufferedText.reset();
75         }
76     }
77 
appendText__anon189c57350111::ParsingContext78     void appendText(const char* txt, size_t len) {
79         fBufferedText.append(txt, len);
80     }
81 
82     SkXMLParser* fParser;
83     SkAutoTCallVProc<skstd::remove_pointer_t<XML_Parser>, XML_ParserFree> fXMLParser;
84 
85 private:
86     SkString fBufferedText;
87 };
88 
89 #define HANDLER_CONTEXT(arg, name) ParsingContext* name = static_cast<ParsingContext*>(arg)
90 
start_element_handler(void * data,const char * tag,const char ** attributes)91 void XMLCALL start_element_handler(void *data, const char* tag, const char** attributes) {
92     HANDLER_CONTEXT(data, ctx);
93     ctx->flushText();
94 
95     ctx->fParser->startElement(tag);
96 
97     for (size_t i = 0; attributes[i]; i += 2) {
98         ctx->fParser->addAttribute(attributes[i], attributes[i + 1]);
99     }
100 }
101 
end_element_handler(void * data,const char * tag)102 void XMLCALL end_element_handler(void* data, const char* tag) {
103     HANDLER_CONTEXT(data, ctx);
104     ctx->flushText();
105 
106     ctx->fParser->endElement(tag);
107 }
108 
text_handler(void * data,const char * txt,int len)109 void XMLCALL text_handler(void *data, const char* txt, int len) {
110     HANDLER_CONTEXT(data, ctx);
111 
112     ctx->appendText(txt, SkTo<size_t>(len));
113 }
114 
entity_decl_handler(void * data,const XML_Char * entityName,int is_parameter_entity,const XML_Char * value,int value_length,const XML_Char * base,const XML_Char * systemId,const XML_Char * publicId,const XML_Char * notationName)115 void XMLCALL entity_decl_handler(void *data,
116                                  const XML_Char *entityName,
117                                  int is_parameter_entity,
118                                  const XML_Char *value,
119                                  int value_length,
120                                  const XML_Char *base,
121                                  const XML_Char *systemId,
122                                  const XML_Char *publicId,
123                                  const XML_Char *notationName) {
124     HANDLER_CONTEXT(data, ctx);
125 
126     SkDebugf("'%s' entity declaration found, stopping processing", entityName);
127     XML_StopParser(ctx->fXMLParser, XML_FALSE);
128 }
129 
130 } // anonymous namespace
131 
SkXMLParser(SkXMLParserError * parserError)132 SkXMLParser::SkXMLParser(SkXMLParserError* parserError) : fParser(nullptr), fError(parserError)
133 {
134 }
135 
~SkXMLParser()136 SkXMLParser::~SkXMLParser()
137 {
138 }
139 
parse(SkStream & docStream)140 bool SkXMLParser::parse(SkStream& docStream)
141 {
142     ParsingContext ctx(this);
143     if (!ctx.fXMLParser) {
144         SkDebugf("could not create XML parser\n");
145         return false;
146     }
147 
148     XML_SetUserData(ctx.fXMLParser, &ctx);
149     XML_SetElementHandler(ctx.fXMLParser, start_element_handler, end_element_handler);
150     XML_SetCharacterDataHandler(ctx.fXMLParser, text_handler);
151 
152     // Disable entity processing, to inhibit internal entity expansion. See expat CVE-2013-0340.
153     XML_SetEntityDeclHandler(ctx.fXMLParser, entity_decl_handler);
154 
155     static const int kBufferSize = 512 SkDEBUGCODE( - 507);
156     bool done = false;
157     do {
158         void* buffer = XML_GetBuffer(ctx.fXMLParser, kBufferSize);
159         if (!buffer) {
160             SkDebugf("could not buffer enough to continue\n");
161             return false;
162         }
163 
164         size_t len = docStream.read(buffer, kBufferSize);
165         done = docStream.isAtEnd();
166         XML_Status status = XML_ParseBuffer(ctx.fXMLParser, SkToS32(len), done);
167         if (XML_STATUS_ERROR == status) {
168             XML_Error error = XML_GetErrorCode(ctx.fXMLParser);
169             int line = XML_GetCurrentLineNumber(ctx.fXMLParser);
170             int column = XML_GetCurrentColumnNumber(ctx.fXMLParser);
171             const XML_LChar* errorString = XML_ErrorString(error);
172             SkDebugf("parse error @%d:%d: %d (%s).\n", line, column, error, errorString);
173             return false;
174         }
175     } while (!done);
176 
177     return true;
178 }
179 
parse(const char doc[],size_t len)180 bool SkXMLParser::parse(const char doc[], size_t len)
181 {
182     SkMemoryStream docStream(doc, len);
183     return this->parse(docStream);
184 }
185 
GetNativeErrorString(int error,SkString * str)186 void SkXMLParser::GetNativeErrorString(int error, SkString* str)
187 {
188 
189 }
190 
startElement(const char elem[])191 bool SkXMLParser::startElement(const char elem[])
192 {
193     return this->onStartElement(elem);
194 }
195 
addAttribute(const char name[],const char value[])196 bool SkXMLParser::addAttribute(const char name[], const char value[])
197 {
198     return this->onAddAttribute(name, value);
199 }
200 
endElement(const char elem[])201 bool SkXMLParser::endElement(const char elem[])
202 {
203     return this->onEndElement(elem);
204 }
205 
text(const char text[],int len)206 bool SkXMLParser::text(const char text[], int len)
207 {
208     return this->onText(text, len);
209 }
210 
211 ////////////////////////////////////////////////////////////////////////////////
212 
onStartElement(const char elem[])213 bool SkXMLParser::onStartElement(const char elem[]) {return false; }
onAddAttribute(const char name[],const char value[])214 bool SkXMLParser::onAddAttribute(const char name[], const char value[]) {return false; }
onEndElement(const char elem[])215 bool SkXMLParser::onEndElement(const char elem[]) { return false; }
onText(const char text[],int len)216 bool SkXMLParser::onText(const char text[], int len) {return false; }
217