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