/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#include <string.h>
#include <vector>
#include <tools/vcompat.hxx>
#include <cstdio>
#include <tools/stream.hxx>
#include <vcl/font/EOTConverter.hxx>
#include <osl/endian.h>
#include <font/TTFStructure.hxx>
#include <font/TTFReader.hxx>

namespace font
{
namespace
{
// Writes padding, length and string data to font output
void writeNameTableString(font::TTFFont& rFont,
                          std::unique_ptr<NameTableHandler>& pNameTableHandler,
                          font::NameID eNameID, std::vector<sal_uInt8>& rEotOutput)
{
    sal_uInt64 nOffset = 0;
    sal_uInt16 nLength = 0;

    // Padding
    rEotOutput.push_back(0);
    rEotOutput.push_back(0);

    if (pNameTableHandler
        && pNameTableHandler->findEnglishUnicodeNameOffset(eNameID, nOffset, nLength))
    {
        // Length
        rEotOutput.push_back(sal_uInt8((nLength + 2) & 0xff));
        rEotOutput.push_back(sal_uInt8((nLength + 2) >> 8));

        OUString aString = rFont.getNameTableString(nOffset, nLength);
        for (sal_Int32 i = 0; i < aString.getLength(); i++)
        {
            sal_Unicode nUniChar = aString[i];
            rEotOutput.push_back(sal_uInt8(nUniChar & 0xff));
            rEotOutput.push_back(sal_uInt8(nUniChar >> 8));
        }
        // null terminated
        rEotOutput.push_back(sal_uInt8(0));
        rEotOutput.push_back(sal_uInt8(0));
    }
    else
    {
        // Length 0
        rEotOutput.push_back(sal_uInt8(0));
        rEotOutput.push_back(sal_uInt8(0));
    }
}
}

bool EOTConverter::convert(std::vector<sal_uInt8>& rEotOutput)
{
    font::TTFFont aFont(mrFontDataContainer);

    rEotOutput.clear();
    rEotOutput.resize(sizeof(EOTHeader));

    EOTHeader* pEot = reinterpret_cast<EOTHeader*>(rEotOutput.data());
    pEot->nFontDataSize = mrFontDataContainer.size();
    pEot->nVersion = 0x00020002;
    pEot->nFlags = 0;
    pEot->nCharset = 0;
    pEot->nMagicNumber = 0x504c;
    pEot->nReserved1 = 0;
    pEot->nReserved2 = 0;
    pEot->nReserved3 = 0;
    pEot->nReserved4 = 0;

    auto pHandler = aFont.getTableEntriesHandler();
    if (!pHandler)
        return false;

    const font::OS2Table* pOS2 = pHandler->getOS2Table();
    if (pOS2)
    {
        for (sal_uInt32 n = 0; n < 10; n++)
            pEot->nFontPANOSE[n] = pOS2->nPanose[n];

        pEot->nItalic = pOS2->nFsSelection & 0x01;
        pEot->nWeight = pOS2->nWeightClass;
        pEot->nFsType = pOS2->nFsType;
        pEot->nUnicodeRange1 = pOS2->nUnicodeRange1;
        pEot->nUnicodeRange2 = pOS2->nUnicodeRange2;
        pEot->nUnicodeRange3 = pOS2->nUnicodeRange3;
        pEot->nUnicodeRange4 = pOS2->nUnicodeRange4;
        pEot->nCodePageRange1 = pOS2->nCodePageRange1;
        pEot->nCodePageRange2 = pOS2->nCodePageRange2;
    }

    const font::HeadTable* pHeadTable = pHandler->getHeadTable();
    if (pHeadTable)
    {
        pEot->nCheckSumAdjustment = pHeadTable->nCheckSumAdjustment;
    }

    auto pNameTableHandler = pHandler->getNameTableHandler();

    writeNameTableString(aFont, pNameTableHandler, font::NameID::FamilyName, rEotOutput);
    writeNameTableString(aFont, pNameTableHandler, font::NameID::SubfamilyName, rEotOutput);
    writeNameTableString(aFont, pNameTableHandler, font::NameID::Version, rEotOutput);
    writeNameTableString(aFont, pNameTableHandler, font::NameID::FullFontName, rEotOutput);

    // Padding5
    rEotOutput.push_back(0);
    rEotOutput.push_back(0);

    // Root String Size
    rEotOutput.push_back(0);
    rEotOutput.push_back(0);

    // Root String CheckSum (for size 0)
    rEotOutput.push_back(0x42);
    rEotOutput.push_back(0x53);
    rEotOutput.push_back(0x47);
    rEotOutput.push_back(0x50);

    // EUDC CodePage
    rEotOutput.push_back(0xE4);
    rEotOutput.push_back(0x04);
    rEotOutput.push_back(0x00);
    rEotOutput.push_back(0x00);

    // Padding6
    rEotOutput.push_back(0);
    rEotOutput.push_back(0);

    // Signature Size = should be 0x0000
    rEotOutput.push_back(0);
    rEotOutput.push_back(0);

    // EUDC Flags
    rEotOutput.push_back(0);
    rEotOutput.push_back(0);
    rEotOutput.push_back(0);
    rEotOutput.push_back(0);

    // EUDC Font Size = 0
    rEotOutput.push_back(0);
    rEotOutput.push_back(0);
    rEotOutput.push_back(0);
    rEotOutput.push_back(0);

    // rEOTOutput could've been reallocated - need to reinterpret that.
    pEot = reinterpret_cast<EOTHeader*>(rEotOutput.data());
    pEot->nEotSize = rEotOutput.size() + mrFontDataContainer.size();

    rEotOutput.insert(rEotOutput.end(), mrFontDataContainer.begin(), mrFontDataContainer.end());

    return true;
}

} // end font namespace

int TestEOT(const void* data, sal_uInt32 size)
{
    const sal_uInt8* bytes = static_cast<const sal_uInt8*>(data);
    std::vector<sal_uInt8> input(bytes, bytes + size);

    std::vector<sal_uInt8> aEOT;
    font::FontDataContainer aContainer(input);
    font::EOTConverter aConverter(aContainer);
    return aConverter.convert(aEOT) ? 1 : 0;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
