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