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 "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 
     26 SkXMLParserError::SkXMLParserError() : fCode(kNoError), fLineNumber(-1),
     27     fNativeCode(-1)
     28 {
     29     reset();
     30 }
     31 
     32 SkXMLParserError::~SkXMLParserError()
     33 {
     34     // need a virtual destructor for our subclasses
     35 }
     36 
     37 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 
     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 {
     67     ParsingContext(SkXMLParser* parser)
     68         : fParser(parser)
     69         , fXMLParser(XML_ParserCreate_MM(nullptr, &sk_XML_alloc, nullptr)) { }
     70 
     71     void flushText() {
     72         if (!fBufferedText.isEmpty()) {
     73             fParser->text(fBufferedText.c_str(), SkTo<int>(fBufferedText.size()));
     74             fBufferedText.reset();
     75         }
     76     }
     77 
     78     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 
     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 
    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 
    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 
    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 
    132 SkXMLParser::SkXMLParser(SkXMLParserError* parserError) : fParser(nullptr), fError(parserError)
    133 {
    134 }
    135 
    136 SkXMLParser::~SkXMLParser()
    137 {
    138 }
    139 
    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 
    180 bool SkXMLParser::parse(const char doc[], size_t len)
    181 {
    182     SkMemoryStream docStream(doc, len);
    183     return this->parse(docStream);
    184 }
    185 
    186 void SkXMLParser::GetNativeErrorString(int error, SkString* str)
    187 {
    188 
    189 }
    190 
    191 bool SkXMLParser::startElement(const char elem[])
    192 {
    193     return this->onStartElement(elem);
    194 }
    195 
    196 bool SkXMLParser::addAttribute(const char name[], const char value[])
    197 {
    198     return this->onAddAttribute(name, value);
    199 }
    200 
    201 bool SkXMLParser::endElement(const char elem[])
    202 {
    203     return this->onEndElement(elem);
    204 }
    205 
    206 bool SkXMLParser::text(const char text[], int len)
    207 {
    208     return this->onText(text, len);
    209 }
    210 
    211 ////////////////////////////////////////////////////////////////////////////////
    212 
    213 bool SkXMLParser::onStartElement(const char elem[]) {return false; }
    214 bool SkXMLParser::onAddAttribute(const char name[], const char value[]) {return false; }
    215 bool SkXMLParser::onEndElement(const char elem[]) { return false; }
    216 bool SkXMLParser::onText(const char text[], int len) {return false; }
    217