| Index: src/xml/SkXMLParser.cpp
|
| diff --git a/src/xml/SkXMLParser.cpp b/src/xml/SkXMLParser.cpp
|
| index 77903cbb056b51daa69707d73aef0837e3662edb..23c4e672b5c33119d1f2cdd8e07d446c166e6c9d 100644
|
| --- a/src/xml/SkXMLParser.cpp
|
| +++ b/src/xml/SkXMLParser.cpp
|
| @@ -8,6 +8,8 @@
|
| #include "expat.h"
|
|
|
| #include "SkStream.h"
|
| +#include "SkString.h"
|
| +#include "SkTypes.h"
|
| #include "SkXMLParser.h"
|
|
|
| static char const* const gErrorStrings[] = {
|
| @@ -59,18 +61,68 @@ const XML_Memory_Handling_Suite sk_XML_alloc = {
|
| sk_free
|
| };
|
|
|
| +struct ParsingContext {
|
| + ParsingContext(SkXMLParser* parser)
|
| + : fParser(parser)
|
| + , fXMLParser(XML_ParserCreate_MM(nullptr, &sk_XML_alloc, nullptr)) { }
|
| +
|
| + void flushText() {
|
| + if (!fBufferedText.isEmpty()) {
|
| + fParser->text(fBufferedText.c_str(), SkTo<int>(fBufferedText.size()));
|
| + fBufferedText.reset();
|
| + }
|
| + }
|
| +
|
| + void appendText(const char* txt, size_t len) {
|
| + fBufferedText.append(txt, len);
|
| + }
|
| +
|
| + SkXMLParser* fParser;
|
| + SkAutoTCallVProc<skstd::remove_pointer_t<XML_Parser>, XML_ParserFree> fXMLParser;
|
| +
|
| +private:
|
| + SkString fBufferedText;
|
| +};
|
| +
|
| +#define HANDLER_CONTEXT(arg, name) ParsingContext* name = static_cast<ParsingContext*>(arg);
|
| +
|
| void XMLCALL start_element_handler(void *data, const char* tag, const char** attributes) {
|
| - SkXMLParser* parser = static_cast<SkXMLParser*>(data);
|
| + HANDLER_CONTEXT(data, ctx);
|
| + ctx->flushText();
|
|
|
| - parser->startElement(tag);
|
| + ctx->fParser->startElement(tag);
|
|
|
| for (size_t i = 0; attributes[i]; i += 2) {
|
| - parser->addAttribute(attributes[i], attributes[i + 1]);
|
| + ctx->fParser->addAttribute(attributes[i], attributes[i + 1]);
|
| }
|
| }
|
|
|
| void XMLCALL end_element_handler(void* data, const char* tag) {
|
| - static_cast<SkXMLParser*>(data)->endElement(tag);
|
| + HANDLER_CONTEXT(data, ctx);
|
| + ctx->flushText();
|
| +
|
| + ctx->fParser->endElement(tag);
|
| +}
|
| +
|
| +void XMLCALL text_handler(void *data, const char* txt, int len) {
|
| + HANDLER_CONTEXT(data, ctx);
|
| +
|
| + ctx->appendText(txt, SkTo<size_t>(len));
|
| +}
|
| +
|
| +void XMLCALL 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) {
|
| + HANDLER_CONTEXT(data, ctx);
|
| +
|
| + SkDebugf("'%s' entity declaration found, stopping processing", entityName);
|
| + XML_StopParser(ctx->fXMLParser, XML_FALSE);
|
| }
|
|
|
| } // anonymous namespace
|
| @@ -85,20 +137,23 @@ SkXMLParser::~SkXMLParser()
|
|
|
| bool SkXMLParser::parse(SkStream& docStream)
|
| {
|
| - SkAutoTCallVProc<skstd::remove_pointer_t<XML_Parser>, XML_ParserFree>
|
| - parser(XML_ParserCreate_MM(nullptr, &sk_XML_alloc, nullptr));
|
| - if (!parser) {
|
| + ParsingContext ctx(this);
|
| + if (!ctx.fXMLParser) {
|
| SkDebugf("could not create XML parser\n");
|
| return false;
|
| }
|
|
|
| - XML_SetUserData(parser, this);
|
| - XML_SetElementHandler(parser, start_element_handler, end_element_handler);
|
| + XML_SetUserData(ctx.fXMLParser, &ctx);
|
| + XML_SetElementHandler(ctx.fXMLParser, start_element_handler, end_element_handler);
|
| + XML_SetCharacterDataHandler(ctx.fXMLParser, text_handler);
|
| +
|
| + // Disable entity processing, to inhibit internal entity expansion. See expat CVE-2013-0340.
|
| + XML_SetEntityDeclHandler(ctx.fXMLParser, entity_decl_handler);
|
|
|
| static const int kBufferSize = 512 SkDEBUGCODE( - 507);
|
| bool done = false;
|
| do {
|
| - void* buffer = XML_GetBuffer(parser, kBufferSize);
|
| + void* buffer = XML_GetBuffer(ctx.fXMLParser, kBufferSize);
|
| if (!buffer) {
|
| SkDebugf("could not buffer enough to continue\n");
|
| return false;
|
| @@ -106,11 +161,11 @@ bool SkXMLParser::parse(SkStream& docStream)
|
|
|
| size_t len = docStream.read(buffer, kBufferSize);
|
| done = docStream.isAtEnd();
|
| - XML_Status status = XML_ParseBuffer(parser, SkToS32(len), done);
|
| + XML_Status status = XML_ParseBuffer(ctx.fXMLParser, SkToS32(len), done);
|
| if (XML_STATUS_ERROR == status) {
|
| - XML_Error error = XML_GetErrorCode(parser);
|
| - int line = XML_GetCurrentLineNumber(parser);
|
| - int column = XML_GetCurrentColumnNumber(parser);
|
| + XML_Error error = XML_GetErrorCode(ctx.fXMLParser);
|
| + int line = XML_GetCurrentLineNumber(ctx.fXMLParser);
|
| + int column = XML_GetCurrentColumnNumber(ctx.fXMLParser);
|
| const XML_LChar* errorString = XML_ErrorString(error);
|
| SkDebugf("parse error @%d:%d: %d (%s).\n", line, column, error, errorString);
|
| return false;
|
|
|