/*
 * Copyright 2006 The Android Open Source Project
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */
#include "src/xml/SkXMLParser.h"

#include "include/core/SkStream.h"
#include "include/core/SkString.h"
#include "include/core/SkTypes.h"
#include "include/private/SkTemplates.h"
#include "include/private/SkTo.h"
#include "src/core/SkRandom.h"
#include "src/core/SkTime.h"
#include "src/core/SkUtils.h"

#include <expat.h>

#include <vector>

static char const* const gErrorStrings[] = {
    "empty or missing file ",
    "unknown element ",
    "unknown attribute name ",
    "error in attribute value ",
    "duplicate ID ",
    "unknown error "
};

SkXMLParserError::SkXMLParserError() : fCode(kNoError), fLineNumber(-1),
    fNativeCode(-1)
{
    reset();
}

SkXMLParserError::~SkXMLParserError()
{
    // need a virtual destructor for our subclasses
}

void SkXMLParserError::getErrorString(SkString* str) const
{
    SkASSERT(str);
    SkString temp;
    if (fCode != kNoError) {
        if ((unsigned)fCode < std::size(gErrorStrings))
            temp.set(gErrorStrings[fCode - 1]);
        temp.append(fNoun);
    } else
        SkXMLParser::GetNativeErrorString(fNativeCode, &temp);
    str->append(temp);
}

void SkXMLParserError::reset() {
    fCode = kNoError;
    fLineNumber = -1;
    fNativeCode = -1;
}

////////////////

namespace {

// Return a random number based on the clock to be consistent
// across platforms yet hard to guess and not leaking information.
static uint32_t get_hash_salt() {
    static const uint32_t s_salt = []() {
        double nsecs = SkTime::GetNSecs();
        uint64_t timeVal = sk_bit_cast<uint64_t>(nsecs);
        uint32_t seed = static_cast<uint32_t>(timeVal ^ timeVal >> 32);

        SkRandom rand(seed);
        uint32_t salt = rand.nextU();
        while (salt == 0) [[unlikely]] {
            // Expat hash seed must be non-zero or the default cPRNG will be used.
            salt = rand.nextU();
        }
        return salt;
    }();
    return s_salt;
}

const XML_Memory_Handling_Suite sk_XML_alloc = {
    sk_malloc_throw,
    sk_realloc_throw,
    sk_free
};

struct ParsingContext {
    ParsingContext(SkXMLParser* parser)
        : fParser(parser)
        , fXMLParser(XML_ParserCreate_MM(nullptr, &sk_XML_alloc, nullptr)) { }

    void flushText() {
        if (!fBufferedText.empty()) {
            fParser->text(fBufferedText.data(), SkTo<int>(fBufferedText.size()));
            fBufferedText.clear();
        }
    }

    void appendText(const char* txt, size_t len) {
        fBufferedText.insert(fBufferedText.end(), txt, &txt[len]);
    }

    SkXMLParser* fParser;
    SkAutoTCallVProc<std::remove_pointer_t<XML_Parser>, XML_ParserFree> fXMLParser;

private:
    std::vector<char> 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) {
    HANDLER_CONTEXT(data, ctx);
    ctx->flushText();

    ctx->fParser->startElement(tag);

    for (size_t i = 0; attributes[i]; i += 2) {
        ctx->fParser->addAttribute(attributes[i], attributes[i + 1]);
    }
}

void XMLCALL end_element_handler(void* data, const char* 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

SkXMLParser::SkXMLParser(SkXMLParserError* parserError) : fParser(nullptr), fError(parserError)
{
}

SkXMLParser::~SkXMLParser()
{
}

bool SkXMLParser::parse(SkStream& docStream)
{
    ParsingContext ctx(this);
    if (!ctx.fXMLParser) {
        SkDEBUGF("could not create XML parser\n");
        return false;
    }

    // Expat calls to rand_s if no salt is set, which is not allowed on Windows.
    // https://crbug.com/40088338
    // Setting the salt helps prevent DOS with a known hash sequence. Generating a
    // random salt once per process oursevles ensures the salt is non-deterministic
    // and unguessable, while preventing calls to rand_s inside sandboxed processes
    // on Windows.
    XML_SetHashSalt(ctx.fXMLParser, get_hash_salt());

    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);

    XML_Status status = XML_STATUS_OK;
    if (docStream.getMemoryBase() && docStream.hasLength()) {
        const char* base = reinterpret_cast<const char*>(docStream.getMemoryBase());
        status = XML_Parse(ctx.fXMLParser,
                           base + docStream.getPosition(),
                           docStream.getLength() - docStream.getPosition(),
                           true);
    } else {
        static constexpr int kBufferSize = 4096;
        bool done = false;
        do {
            void* buffer = XML_GetBuffer(ctx.fXMLParser, kBufferSize);
            if (!buffer) {
                SkDEBUGF("could not buffer enough to continue\n");
                return false;
            }

            size_t len = docStream.read(buffer, kBufferSize);
            done = docStream.isAtEnd();
            status = XML_ParseBuffer(ctx.fXMLParser, SkToS32(len), done);
            if (XML_STATUS_ERROR == status) {
                break;
            }
        } while (!done);
    }
    if (XML_STATUS_ERROR == status) {
#if defined(SK_DEBUG)
        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);
#endif
        return false;
    }

    return true;
}

bool SkXMLParser::parse(const char doc[], size_t len)
{
    SkMemoryStream docStream(doc, len);
    return this->parse(docStream);
}

void SkXMLParser::GetNativeErrorString(int error, SkString* str)
{

}

bool SkXMLParser::startElement(const char elem[])
{
    return this->onStartElement(elem);
}

bool SkXMLParser::addAttribute(const char name[], const char value[])
{
    return this->onAddAttribute(name, value);
}

bool SkXMLParser::endElement(const char elem[])
{
    return this->onEndElement(elem);
}

bool SkXMLParser::text(const char text[], int len)
{
    return this->onText(text, len);
}

////////////////////////////////////////////////////////////////////////////////

bool SkXMLParser::onStartElement(const char elem[]) {return false; }
bool SkXMLParser::onAddAttribute(const char name[], const char value[]) {return false; }
bool SkXMLParser::onEndElement(const char elem[]) { return false; }
bool SkXMLParser::onText(const char text[], int len) {return false; }
