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