<commit_before>#include "App.h"
#include "ProgramOptions.h"
#include <string>
#include <iomanip>
#include "FontInfo.h"
#include "utils/extractFileName.h"
#include "external/lodepng/lodepng.h"
#include "utils/getNumberLen.h"

//TODO: read .bmfc files (BMFont configuration file)

std::vector<rbp::RectSize> App::getGlyphRectangles(const Glyphs &glyphs, const std::uint32_t additionalWidth, const std::uint32_t additionalHeight)
{
    std::vector<rbp::RectSize> result;
    for (const auto& kv : glyphs)
    {
        const auto& glyphInfo = kv.second;
        if (!glyphInfo.isEmpty())
            result.emplace_back(glyphInfo.width + additionalWidth, glyphInfo.height + additionalHeight, kv.first);
    }
    return result;
}

App::Glyphs App::collectGlyphInfo(const std::vector<ft::Font>& fonts, const std::set<std::uint32_t>& codes)
{
    Glyphs result;

    for (const auto& id : codes)
    {
        GlyphInfo glyphInfo;

        for (size_t i = 0; i < fonts.size(); ++i)
        {
            if (fonts[i].isGlyphProvided(id))
            {
                ft::Font::GlyphMetrics glyphMetrics = fonts[i].renderGlyph(nullptr, 0, 0, 0, 0, id, 0);
                glyphInfo.fontIndex = i;
                glyphInfo.width = glyphMetrics.width;
                glyphInfo.height = glyphMetrics.height;
                glyphInfo.xAdvance = glyphMetrics.horiAdvance;
                glyphInfo.xOffset = glyphMetrics.horiBearingX;
                glyphInfo.yOffset = fonts[i].yMax - glyphMetrics.horiBearingY;
                break;
            }
        }

        //TODO: add more checks for glyph.
        if (glyphInfo.fontIndex == -1)
        {
            std::cout << "warning: glyph " << id << " not found";
            if (id == 65279)
                std::cout << " (it looks like Unicode byte order mark (BOM))";
            std::cout << "." << std::endl;
        }
        else
            result[id] = glyphInfo;
    }

    return result;
}

std::uint32_t App::arrangeGlyphs(Glyphs& glyphs, const Config& config)
{
    const auto additionalWidth = config.spacing.hor + config.padding.left + config.padding.right;
    const auto additionalHeight = config.spacing.ver + config.padding.up + config.padding.down;
    //TODO: check workAreaW,H
    const auto workAreaW = config.textureSize.w - config.spacing.hor;
    const auto workAreaH = config.textureSize.h - config.spacing.ver;

    auto glyphRectangles = getGlyphRectangles(glyphs, additionalWidth, additionalHeight);

    rbp::MaxRectsBinPack mrbp;
    std::uint32_t pageCount = 0;
    for (;;)
    {
        mrbp.Init(workAreaW, workAreaH);

        std::vector<rbp::Rect> arrangedRectangles;
        mrbp.Insert( glyphRectangles, arrangedRectangles, rbp::MaxRectsBinPack::RectBestAreaFit );
        if ( arrangedRectangles.empty() )
        {
            if ( !glyphRectangles.empty() )
                throw std::runtime_error("can not fit glyphs into texture");
            break;
        }

        for ( const auto& r: arrangedRectangles )
        {
            glyphs[r.tag].x = r.x + config.spacing.hor;
            glyphs[r.tag].y = r.y + config.spacing.ver;
            glyphs[r.tag].page = pageCount;
        }

        ++pageCount;
    }

    return pageCount;
}

void App::savePng(const std::string& fileName, const std::uint32_t* buffer, const std::uint32_t w, const std::uint32_t h, const bool withAlpha)
{
    std::vector<std::uint8_t> png;
    lodepng::State state;

    state.encoder.add_id = 0; // Don't add LodePNG version chunk to save more bytes
    state.encoder.auto_convert = 0;
    state.info_png.color.colortype = withAlpha ? LCT_RGBA : LCT_RGB;
    state.encoder.zlibsettings.windowsize = 32768; // Use maximum possible window size for best compression

    auto error = lodepng::encode(png, reinterpret_cast<const unsigned char*>(buffer), w, h, state);
    if (error)
        throw std::runtime_error("png encoder error " + std::to_string(error) + ": " + lodepng_error_text(error));

    error = lodepng::save_file(png, fileName);
    if (error)
        throw std::runtime_error("png save to file error " + std::to_string(error) + ": " + lodepng_error_text(error));
}

std::vector<std::string> App::renderTextures(const Glyphs& glyphs, const Config& config, const std::vector<ft::Font>& fonts, const std::uint32_t pageCount)
{
    std::vector<std::string> fileNames;

    const auto pageNameDigits = config.disableTextureNameZeroPadding ? 0 : getNumberLen(pageCount - 1);

    for (std::uint32_t page = 0; page < pageCount; ++page)
    {
        std::vector<std::uint32_t> surface(config.textureSize.w * config.textureSize.h, config.color.getBGR());

        // Render every glyph
        //TODO: do not repeat same glyphs (with same index)
        for (const auto& kv: glyphs)
        {
            const auto& glyph = kv.second;
            if (glyph.page != page)
                continue;

            if (!glyph.isEmpty())
            {
                const auto x = glyph.x + config.padding.left;
                const auto y = glyph.y + config.padding.up;

                fonts[glyph.fontIndex].renderGlyph(&surface[0], config.textureSize.w, config.textureSize.h, x, y,
                        kv.first, config.color.getBGR());
            }
        }

        if (!config.backgroundTransparent)
        {
            auto cur = surface.data();
            const auto end = &surface.back();

            const auto fgColor = config.color.getBGR();
            const auto bgColor = config.backgroundColor.getBGR();

            while (cur <= end)
            {
                const std::uint32_t a0 = (*cur) >> 24u;
                const std::uint32_t a1 = 256 - a0;
                const std::uint32_t rb1 = (a1 * (bgColor & 0xFF00FFu)) >> 8u;
                const std::uint32_t rb2 = (a0 * (fgColor & 0xFF00FFu)) >> 8u;
                const std::uint32_t g1  = (a1 * (bgColor & 0x00FF00u)) >> 8u;
                const std::uint32_t g2  = (a0 * (fgColor & 0x00FF00u)) >> 8u;
                *cur =  ((rb1 | rb2) & 0xFF00FFu) + ((g1 | g2) & 0x00FF00u);
                ++cur;
            }
        }

        std::stringstream ss;
        ss << config.output << "_" << std::setfill ('0') << std::setw(pageNameDigits) << page << ".png";
        const auto fileName = ss.str();
        fileNames.push_back(extractFileName(fileName));

        savePng(fileName, &surface[0], config.textureSize.w, config.textureSize.h, config.backgroundTransparent);
    }

    return fileNames;
}

void App::writeFontInfoFile(const Glyphs& glyphs, const Config& config, const std::vector<ft::Font>& fonts, const std::vector<std::string>& fileNames)
{
    FontInfo f;

    f.info.face = fonts[0].getFamilyNameOr("unknown");
    f.info.size = -static_cast<std::int16_t>(config.fontSize);
    f.info.unicode = true;
    f.info.bold = fonts[0].isBold();
    f.info.italic = fonts[0].isItalic();
    f.info.stretchH = 100;
    f.info.aa = 1;
    f.info.padding.up = static_cast<std::uint8_t>(config.padding.up);
    f.info.padding.right = static_cast<std::uint8_t>(config.padding.right);
    f.info.padding.down = static_cast<std::uint8_t>(config.padding.down);
    f.info.padding.left = static_cast<std::uint8_t>(config.padding.left);
    f.info.spacing.horizontal = static_cast<std::uint8_t>(config.spacing.hor);
    f.info.spacing.vertical = static_cast<std::uint8_t>(config.spacing.ver);

    f.common.lineHeight = static_cast<std::uint16_t>(fonts[0].height);
    f.common.base = static_cast<std::uint16_t>(fonts[0].yMax);
    f.common.scaleW = static_cast<std::uint16_t>(config.textureSize.w);
    f.common.scaleH = static_cast<std::uint16_t>(config.textureSize.h);
    f.common.alphaChnl = 0;
    f.common.redChnl = 4;
    f.common.greenChnl = 4;
    f.common.blueChnl = 4;
    f.common.totalHeight = static_cast<std::uint16_t>(fonts[0].totalHeight);

    f.pages = fileNames;

    for (const auto kv: glyphs)
    {
        //TODO: page = 0 for empty glyphs.
        const auto &glyph = kv.second;
        FontInfo::Char c;
        c.id = kv.first;
        if (!glyph.isEmpty())
        {
            c.x = static_cast<std::uint16_t>(glyph.x);
            c.y = static_cast<std::uint16_t>(glyph.y);
            c.width = static_cast<std::uint16_t>(glyph.width + config.padding.left + config.padding.right);
            c.height = static_cast<std::uint16_t>(glyph.height + config.padding.up + config.padding.down);
            c.page = static_cast<std::uint8_t>(glyph.page);
            c.xoffset = static_cast<std::int16_t>(glyph.xOffset - config.padding.left);
            c.yoffset = static_cast<std::int16_t>(glyph.yOffset - config.padding.up);
        }
        c.xadvance = static_cast<std::int16_t>(glyph.xAdvance);
        c.chnl = 15;

        f.chars.push_back(c);
    }

    if (config.includeKerningPairs)
    {
        auto chars(config.chars);

        for (const auto& ch0 : config.chars)
        {
            for (const auto& ch1 : chars)
            {
                const auto k = static_cast<std::int16_t>(fonts[0].getKerning(ch0, ch1));
                if (k)
                {
                    FontInfo::Kerning kerning;
                    kerning.first = ch0;
                    kerning.second = ch1;
                    kerning.amount = k;
                    f.kernings.push_back(kerning);
                }
            }
        }
    }

    f.extraInfo = config.extraInfo;

    const auto dataFileName = config.output + ".fnt";
    switch (config.dataFormat) {
        case Config::DataFormat::Xml:
            f.writeToXmlFile(dataFileName);
            break;
        case Config::DataFormat::Text:
            f.writeToTextFile(dataFileName);
            break;
        case Config::DataFormat::Bin:
            f.writeToBinFile(dataFileName);
            break;
        case Config::DataFormat::Json:
            f.writeToJsonFile(dataFileName);
            break;
    }
}

void App::execute(const int argc, char* argv[])
{
    const auto config = ProgramOptions::parseCommandLine(argc, argv);

    ft::Library library;

    std::vector<ft::Font> fonts;
    for (auto& f: config.fontFile)
        fonts.emplace_back(library, f, config.fontSize, 0, config.monochrome);

    fonts.front().debugInfo();

    auto glyphs = collectGlyphInfo(fonts, config.chars);
    const auto pageCount = arrangeGlyphs(glyphs, config);
    if (config.maxTextureCount != 0 && pageCount > config.maxTextureCount)
        throw std::runtime_error("too many generated textures (more than --max-texture-count)");

    const auto fileNames = renderTextures(glyphs, config, fonts, pageCount);
    writeFontInfoFile(glyphs, config, fonts, fileNames);
}
<commit_msg>Fix info/smooth value in data file<commit_after>#include "App.h"
#include "ProgramOptions.h"
#include <string>
#include <iomanip>
#include "FontInfo.h"
#include "utils/extractFileName.h"
#include "external/lodepng/lodepng.h"
#include "utils/getNumberLen.h"

//TODO: read .bmfc files (BMFont configuration file)

std::vector<rbp::RectSize> App::getGlyphRectangles(const Glyphs &glyphs, const std::uint32_t additionalWidth, const std::uint32_t additionalHeight)
{
    std::vector<rbp::RectSize> result;
    for (const auto& kv : glyphs)
    {
        const auto& glyphInfo = kv.second;
        if (!glyphInfo.isEmpty())
            result.emplace_back(glyphInfo.width + additionalWidth, glyphInfo.height + additionalHeight, kv.first);
    }
    return result;
}

App::Glyphs App::collectGlyphInfo(const std::vector<ft::Font>& fonts, const std::set<std::uint32_t>& codes)
{
    Glyphs result;

    for (const auto& id : codes)
    {
        GlyphInfo glyphInfo;

        for (size_t i = 0; i < fonts.size(); ++i)
        {
            if (fonts[i].isGlyphProvided(id))
            {
                ft::Font::GlyphMetrics glyphMetrics = fonts[i].renderGlyph(nullptr, 0, 0, 0, 0, id, 0);
                glyphInfo.fontIndex = i;
                glyphInfo.width = glyphMetrics.width;
                glyphInfo.height = glyphMetrics.height;
                glyphInfo.xAdvance = glyphMetrics.horiAdvance;
                glyphInfo.xOffset = glyphMetrics.horiBearingX;
                glyphInfo.yOffset = fonts[i].yMax - glyphMetrics.horiBearingY;
                break;
            }
        }

        //TODO: add more checks for glyph.
        if (glyphInfo.fontIndex == -1)
        {
            std::cout << "warning: glyph " << id << " not found";
            if (id == 65279)
                std::cout << " (it looks like Unicode byte order mark (BOM))";
            std::cout << "." << std::endl;
        }
        else
            result[id] = glyphInfo;
    }

    return result;
}

std::uint32_t App::arrangeGlyphs(Glyphs& glyphs, const Config& config)
{
    const auto additionalWidth = config.spacing.hor + config.padding.left + config.padding.right;
    const auto additionalHeight = config.spacing.ver + config.padding.up + config.padding.down;
    //TODO: check workAreaW,H
    const auto workAreaW = config.textureSize.w - config.spacing.hor;
    const auto workAreaH = config.textureSize.h - config.spacing.ver;

    auto glyphRectangles = getGlyphRectangles(glyphs, additionalWidth, additionalHeight);

    rbp::MaxRectsBinPack mrbp;
    std::uint32_t pageCount = 0;
    for (;;)
    {
        mrbp.Init(workAreaW, workAreaH);

        std::vector<rbp::Rect> arrangedRectangles;
        mrbp.Insert( glyphRectangles, arrangedRectangles, rbp::MaxRectsBinPack::RectBestAreaFit );
        if ( arrangedRectangles.empty() )
        {
            if ( !glyphRectangles.empty() )
                throw std::runtime_error("can not fit glyphs into texture");
            break;
        }

        for ( const auto& r: arrangedRectangles )
        {
            glyphs[r.tag].x = r.x + config.spacing.hor;
            glyphs[r.tag].y = r.y + config.spacing.ver;
            glyphs[r.tag].page = pageCount;
        }

        ++pageCount;
    }

    return pageCount;
}

void App::savePng(const std::string& fileName, const std::uint32_t* buffer, const std::uint32_t w, const std::uint32_t h, const bool withAlpha)
{
    std::vector<std::uint8_t> png;
    lodepng::State state;

    state.encoder.add_id = 0; // Don't add LodePNG version chunk to save more bytes
    state.encoder.auto_convert = 0;
    state.info_png.color.colortype = withAlpha ? LCT_RGBA : LCT_RGB;
    state.encoder.zlibsettings.windowsize = 32768; // Use maximum possible window size for best compression

    auto error = lodepng::encode(png, reinterpret_cast<const unsigned char*>(buffer), w, h, state);
    if (error)
        throw std::runtime_error("png encoder error " + std::to_string(error) + ": " + lodepng_error_text(error));

    error = lodepng::save_file(png, fileName);
    if (error)
        throw std::runtime_error("png save to file error " + std::to_string(error) + ": " + lodepng_error_text(error));
}

std::vector<std::string> App::renderTextures(const Glyphs& glyphs, const Config& config, const std::vector<ft::Font>& fonts, const std::uint32_t pageCount)
{
    std::vector<std::string> fileNames;

    const auto pageNameDigits = config.disableTextureNameZeroPadding ? 0 : getNumberLen(pageCount - 1);

    for (std::uint32_t page = 0; page < pageCount; ++page)
    {
        std::vector<std::uint32_t> surface(config.textureSize.w * config.textureSize.h, config.color.getBGR());

        // Render every glyph
        //TODO: do not repeat same glyphs (with same index)
        for (const auto& kv: glyphs)
        {
            const auto& glyph = kv.second;
            if (glyph.page != page)
                continue;

            if (!glyph.isEmpty())
            {
                const auto x = glyph.x + config.padding.left;
                const auto y = glyph.y + config.padding.up;

                fonts[glyph.fontIndex].renderGlyph(&surface[0], config.textureSize.w, config.textureSize.h, x, y,
                        kv.first, config.color.getBGR());
            }
        }

        if (!config.backgroundTransparent)
        {
            auto cur = surface.data();
            const auto end = &surface.back();

            const auto fgColor = config.color.getBGR();
            const auto bgColor = config.backgroundColor.getBGR();

            while (cur <= end)
            {
                const std::uint32_t a0 = (*cur) >> 24u;
                const std::uint32_t a1 = 256 - a0;
                const std::uint32_t rb1 = (a1 * (bgColor & 0xFF00FFu)) >> 8u;
                const std::uint32_t rb2 = (a0 * (fgColor & 0xFF00FFu)) >> 8u;
                const std::uint32_t g1  = (a1 * (bgColor & 0x00FF00u)) >> 8u;
                const std::uint32_t g2  = (a0 * (fgColor & 0x00FF00u)) >> 8u;
                *cur =  ((rb1 | rb2) & 0xFF00FFu) + ((g1 | g2) & 0x00FF00u);
                ++cur;
            }
        }

        std::stringstream ss;
        ss << config.output << "_" << std::setfill ('0') << std::setw(pageNameDigits) << page << ".png";
        const auto fileName = ss.str();
        fileNames.push_back(extractFileName(fileName));

        savePng(fileName, &surface[0], config.textureSize.w, config.textureSize.h, config.backgroundTransparent);
    }

    return fileNames;
}

void App::writeFontInfoFile(const Glyphs& glyphs, const Config& config, const std::vector<ft::Font>& fonts, const std::vector<std::string>& fileNames)
{
    FontInfo f;

    f.info.face = fonts[0].getFamilyNameOr("unknown");
    f.info.size = -static_cast<std::int16_t>(config.fontSize);
    f.info.smooth = config.monochrome;
    f.info.unicode = true;
    f.info.bold = fonts[0].isBold();
    f.info.italic = fonts[0].isItalic();
    f.info.stretchH = 100;
    f.info.aa = 1;
    f.info.padding.up = static_cast<std::uint8_t>(config.padding.up);
    f.info.padding.right = static_cast<std::uint8_t>(config.padding.right);
    f.info.padding.down = static_cast<std::uint8_t>(config.padding.down);
    f.info.padding.left = static_cast<std::uint8_t>(config.padding.left);
    f.info.spacing.horizontal = static_cast<std::uint8_t>(config.spacing.hor);
    f.info.spacing.vertical = static_cast<std::uint8_t>(config.spacing.ver);

    f.common.lineHeight = static_cast<std::uint16_t>(fonts[0].height);
    f.common.base = static_cast<std::uint16_t>(fonts[0].yMax);
    f.common.scaleW = static_cast<std::uint16_t>(config.textureSize.w);
    f.common.scaleH = static_cast<std::uint16_t>(config.textureSize.h);
    f.common.alphaChnl = 0;
    f.common.redChnl = 4;
    f.common.greenChnl = 4;
    f.common.blueChnl = 4;
    f.common.totalHeight = static_cast<std::uint16_t>(fonts[0].totalHeight);

    f.pages = fileNames;

    for (const auto kv: glyphs)
    {
        //TODO: page = 0 for empty glyphs.
        const auto &glyph = kv.second;
        FontInfo::Char c;
        c.id = kv.first;
        if (!glyph.isEmpty())
        {
            c.x = static_cast<std::uint16_t>(glyph.x);
            c.y = static_cast<std::uint16_t>(glyph.y);
            c.width = static_cast<std::uint16_t>(glyph.width + config.padding.left + config.padding.right);
            c.height = static_cast<std::uint16_t>(glyph.height + config.padding.up + config.padding.down);
            c.page = static_cast<std::uint8_t>(glyph.page);
            c.xoffset = static_cast<std::int16_t>(glyph.xOffset - config.padding.left);
            c.yoffset = static_cast<std::int16_t>(glyph.yOffset - config.padding.up);
        }
        c.xadvance = static_cast<std::int16_t>(glyph.xAdvance);
        c.chnl = 15;

        f.chars.push_back(c);
    }

    if (config.includeKerningPairs)
    {
        auto chars(config.chars);

        for (const auto& ch0 : config.chars)
        {
            for (const auto& ch1 : chars)
            {
                const auto k = static_cast<std::int16_t>(fonts[0].getKerning(ch0, ch1));
                if (k)
                {
                    FontInfo::Kerning kerning;
                    kerning.first = ch0;
                    kerning.second = ch1;
                    kerning.amount = k;
                    f.kernings.push_back(kerning);
                }
            }
        }
    }

    f.extraInfo = config.extraInfo;

    const auto dataFileName = config.output + ".fnt";
    switch (config.dataFormat) {
        case Config::DataFormat::Xml:
            f.writeToXmlFile(dataFileName);
            break;
        case Config::DataFormat::Text:
            f.writeToTextFile(dataFileName);
            break;
        case Config::DataFormat::Bin:
            f.writeToBinFile(dataFileName);
            break;
        case Config::DataFormat::Json:
            f.writeToJsonFile(dataFileName);
            break;
    }
}

void App::execute(const int argc, char* argv[])
{
    const auto config = ProgramOptions::parseCommandLine(argc, argv);

    ft::Library library;

    std::vector<ft::Font> fonts;
    for (auto& f: config.fontFile)
        fonts.emplace_back(library, f, config.fontSize, 0, config.monochrome);

    fonts.front().debugInfo();

    auto glyphs = collectGlyphInfo(fonts, config.chars);
    const auto pageCount = arrangeGlyphs(glyphs, config);
    if (config.maxTextureCount != 0 && pageCount > config.maxTextureCount)
        throw std::runtime_error("too many generated textures (more than --max-texture-count)");

    const auto fileNames = renderTextures(glyphs, config, fonts, pageCount);
    writeFontInfoFile(glyphs, config, fonts, fileNames);
}
<|endoftext|>


<commit_before>/* -*- 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 "WPXSvStream.hxx"
#include <tools/stream.hxx>
#include <unotools/streamwrap.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <limits>
#include <vector>

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::io;

namespace
{
static void splitPath( std::vector<OUString> &rElems, const OUString &rPath )
{
    for (sal_Int32 i = 0; i >= 0;)
        rElems.push_back( rPath.getToken( 0, '/', i ) );
}

} // anonymous namespace

typedef struct
{
    SotStorageRef ref;
} SotStorageRefWrapper;

typedef struct
{
    SotStorageStreamRef ref;
} SotStorageStreamRefWrapper;

class WPXSvInputStreamImpl : public WPXInputStream
{
public :
    WPXSvInputStreamImpl( ::com::sun::star::uno::Reference<
                      ::com::sun::star::io::XInputStream > xStream );
    ~WPXSvInputStreamImpl();

    bool isOLEStream();
    WPXInputStream * getDocumentOLEStream(const char *name);

    const unsigned char *read(unsigned long numBytes, unsigned long &numBytesRead);
    int seek(long offset, WPX_SEEK_TYPE seekType);
    long tell();
    bool atEOS();
private:
    ::std::vector< SotStorageRefWrapper > mxChildrenStorages;
    ::std::vector< SotStorageStreamRefWrapper > mxChildrenStreams;
    ::com::sun::star::uno::Reference<
            ::com::sun::star::io::XInputStream > mxStream;
    ::com::sun::star::uno::Reference<
            ::com::sun::star::io::XSeekable > mxSeekable;
    ::com::sun::star::uno::Sequence< sal_Int8 > maData;
    sal_Int64 mnLength;
};

WPXSvInputStreamImpl::WPXSvInputStreamImpl( Reference< XInputStream > xStream ) :
    WPXInputStream(),
    mxChildrenStorages(),
    mxChildrenStreams(),
    mxStream(xStream),
    mxSeekable(xStream, UNO_QUERY),
    maData(0)
{
    if (!xStream.is() || !mxStream.is())
        mnLength = 0;
    else
    {
        if (!mxSeekable.is())
            mnLength = 0;
        else
        {
            try
            {
                mnLength = mxSeekable->getLength();
            }
            catch ( ... )
            {
                SAL_WARN("writerperfect", "mnLength = mxSeekable->getLength() threw exception");
                mnLength = 0;
            }
        }
    }
}

WPXSvInputStreamImpl::~WPXSvInputStreamImpl()
{
}

const unsigned char *WPXSvInputStreamImpl::read(unsigned long numBytes, unsigned long &numBytesRead)
{
    numBytesRead = 0;

    if (numBytes == 0 || atEOS())
        return 0;

    numBytesRead = mxStream->readSomeBytes (maData, numBytes);
    if (numBytesRead == 0)
        return 0;

    return (const unsigned char *)maData.getConstArray();
}

long WPXSvInputStreamImpl::tell()
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return -1L;
    else
    {
        sal_Int64 tmpPosition = mxSeekable->getPosition();
        if ((tmpPosition < 0) || (tmpPosition > (std::numeric_limits<long>::max)()))
            return -1L;
        return (long)tmpPosition;
    }
}

int WPXSvInputStreamImpl::seek(long offset, WPX_SEEK_TYPE seekType)
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return -1;

    sal_Int64 tmpPosition = mxSeekable->getPosition();
    if ((tmpPosition < 0) || (tmpPosition > (std::numeric_limits<long>::max)()))
        return -1;

    sal_Int64 tmpOffset = offset;
    if (seekType == WPX_SEEK_CUR)
        tmpOffset += tmpPosition;
    if (seekType == WPX_SEEK_END)
        tmpOffset += mnLength;

    int retVal = 0;
    if (tmpOffset < 0)
    {
        tmpOffset = 0;
        retVal = -1;
    }
    if (offset > mnLength)
    {
        tmpOffset = mnLength;
        retVal = -1;
    }

    try
    {
        mxSeekable->seek(tmpOffset);
        return retVal;
    }
    catch (...)
    {
        SAL_WARN("writerperfect", "mxSeekable->seek(offset) threw exception");
        return -1;
    }
}

bool WPXSvInputStreamImpl::atEOS()
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return true;
    return (mxSeekable->getPosition() >= mnLength);
}

bool WPXSvInputStreamImpl::isOLEStream()
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return false;

    sal_Int64 tmpPosition = mxSeekable->getPosition();
    mxSeekable->seek(0);

    SvStream *pStream = utl::UcbStreamHelper::CreateStream( mxStream );
    bool bAns = pStream && SotStorage::IsOLEStorage( pStream );
    if (pStream)
        delete pStream;

    mxSeekable->seek(tmpPosition);

    return bAns;
}

WPXInputStream *WPXSvInputStreamImpl::getDocumentOLEStream(const char *name)
{
    if (!name)
        return 0;
    OUString rPath(name,strlen(name),RTL_TEXTENCODING_UTF8);
    std::vector<OUString> aElems;
    splitPath( aElems, rPath );

    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return 0;

    sal_Int64 tmpPosition = mxSeekable->getPosition();
    mxSeekable->seek(0);

    SvStream *pStream = utl::UcbStreamHelper::CreateStream( mxStream );

    if (!pStream || !SotStorage::IsOLEStorage( pStream ))
    {
        mxSeekable->seek(tmpPosition);
        return 0;
    }

    SotStorageRefWrapper storageRefWrapper;
    storageRefWrapper.ref = new SotStorage( pStream, sal_True );
    mxChildrenStorages.push_back( storageRefWrapper );

    unsigned i = 0;
    while (i < aElems.size())
    {
        if( mxChildrenStorages.back().ref->IsStream(aElems[i]))
            break;
        else if (mxChildrenStorages.back().ref->IsStorage(aElems[i]))
        {
            SotStorageRef tmpParent(mxChildrenStorages.back().ref);
            storageRefWrapper.ref = tmpParent->OpenSotStorage(aElems[i++], STREAM_STD_READ);
            mxChildrenStorages.push_back(storageRefWrapper);
        }
        else
            // should not happen
            return 0;
    }

    // For the while don't return stream in this situation.
    // Later, given how libcdr's zip stream implementation behaves,
    // return the first stream in the storage if there is one.
    if (i >= aElems.size())
        return 0;

    SotStorageStreamRefWrapper storageStreamRefWrapper;
    storageStreamRefWrapper.ref = mxChildrenStorages.back().ref->OpenSotStream( aElems[i], STREAM_STD_READ );
    mxChildrenStreams.push_back( storageStreamRefWrapper );

    mxSeekable->seek(tmpPosition);

    if ( !mxChildrenStreams.back().ref.Is() || mxChildrenStreams.back().ref->GetError() )
    {
        mxSeekable->seek(tmpPosition);
        return 0;
    }

    Reference < XInputStream > xContents(new utl::OSeekableInputStreamWrapper( mxChildrenStreams.back().ref ));
    mxSeekable->seek(tmpPosition);
    if (xContents.is())
        return new WPXSvInputStream( xContents );
    else
        return 0;
}

WPXSvInputStream::WPXSvInputStream( Reference< XInputStream > xStream ) :
    mpImpl(new WPXSvInputStreamImpl(xStream))
{
}

WPXSvInputStream::~WPXSvInputStream()
{
   delete mpImpl;
}

const unsigned char *WPXSvInputStream::read(unsigned long numBytes, unsigned long &numBytesRead)
{
    return mpImpl->read(numBytes, numBytesRead);
}

long WPXSvInputStream::tell()
{
    return mpImpl->tell();
}

int WPXSvInputStream::seek(long offset, WPX_SEEK_TYPE seekType)
{
    return mpImpl->seek(offset, seekType);
}

bool WPXSvInputStream::atEOS()
{
    return mpImpl->atEOS();
}

bool WPXSvInputStream::isOLEStream()
{
    return mpImpl->isOLEStream();
}

WPXInputStream *WPXSvInputStream::getDocumentOLEStream(const char *name)
{
    return mpImpl->getDocumentOLEStream(name);
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>fix seek behind end of stream<commit_after>/* -*- 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 "WPXSvStream.hxx"
#include <tools/stream.hxx>
#include <unotools/streamwrap.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <limits>
#include <vector>

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::io;

namespace
{
static void splitPath( std::vector<OUString> &rElems, const OUString &rPath )
{
    for (sal_Int32 i = 0; i >= 0;)
        rElems.push_back( rPath.getToken( 0, '/', i ) );
}

} // anonymous namespace

typedef struct
{
    SotStorageRef ref;
} SotStorageRefWrapper;

typedef struct
{
    SotStorageStreamRef ref;
} SotStorageStreamRefWrapper;

class WPXSvInputStreamImpl : public WPXInputStream
{
public :
    WPXSvInputStreamImpl( ::com::sun::star::uno::Reference<
                      ::com::sun::star::io::XInputStream > xStream );
    ~WPXSvInputStreamImpl();

    bool isOLEStream();
    WPXInputStream * getDocumentOLEStream(const char *name);

    const unsigned char *read(unsigned long numBytes, unsigned long &numBytesRead);
    int seek(long offset, WPX_SEEK_TYPE seekType);
    long tell();
    bool atEOS();
private:
    ::std::vector< SotStorageRefWrapper > mxChildrenStorages;
    ::std::vector< SotStorageStreamRefWrapper > mxChildrenStreams;
    ::com::sun::star::uno::Reference<
            ::com::sun::star::io::XInputStream > mxStream;
    ::com::sun::star::uno::Reference<
            ::com::sun::star::io::XSeekable > mxSeekable;
    ::com::sun::star::uno::Sequence< sal_Int8 > maData;
    sal_Int64 mnLength;
};

WPXSvInputStreamImpl::WPXSvInputStreamImpl( Reference< XInputStream > xStream ) :
    WPXInputStream(),
    mxChildrenStorages(),
    mxChildrenStreams(),
    mxStream(xStream),
    mxSeekable(xStream, UNO_QUERY),
    maData(0)
{
    if (!xStream.is() || !mxStream.is())
        mnLength = 0;
    else
    {
        if (!mxSeekable.is())
            mnLength = 0;
        else
        {
            try
            {
                mnLength = mxSeekable->getLength();
            }
            catch ( ... )
            {
                SAL_WARN("writerperfect", "mnLength = mxSeekable->getLength() threw exception");
                mnLength = 0;
            }
        }
    }
}

WPXSvInputStreamImpl::~WPXSvInputStreamImpl()
{
}

const unsigned char *WPXSvInputStreamImpl::read(unsigned long numBytes, unsigned long &numBytesRead)
{
    numBytesRead = 0;

    if (numBytes == 0 || atEOS())
        return 0;

    numBytesRead = mxStream->readSomeBytes (maData, numBytes);
    if (numBytesRead == 0)
        return 0;

    return (const unsigned char *)maData.getConstArray();
}

long WPXSvInputStreamImpl::tell()
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return -1L;
    else
    {
        sal_Int64 tmpPosition = mxSeekable->getPosition();
        if ((tmpPosition < 0) || (tmpPosition > (std::numeric_limits<long>::max)()))
            return -1L;
        return (long)tmpPosition;
    }
}

int WPXSvInputStreamImpl::seek(long offset, WPX_SEEK_TYPE seekType)
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return -1;

    sal_Int64 tmpPosition = mxSeekable->getPosition();
    if ((tmpPosition < 0) || (tmpPosition > (std::numeric_limits<long>::max)()))
        return -1;

    sal_Int64 tmpOffset = offset;
    if (seekType == WPX_SEEK_CUR)
        tmpOffset += tmpPosition;
    if (seekType == WPX_SEEK_END)
        tmpOffset += mnLength;

    int retVal = 0;
    if (tmpOffset < 0)
    {
        tmpOffset = 0;
        retVal = -1;
    }
    if (tmpOffset > mnLength)
    {
        tmpOffset = mnLength;
        retVal = -1;
    }

    try
    {
        mxSeekable->seek(tmpOffset);
        return retVal;
    }
    catch (...)
    {
        SAL_WARN("writerperfect", "mxSeekable->seek(offset) threw exception");
        return -1;
    }
}

bool WPXSvInputStreamImpl::atEOS()
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return true;
    return (mxSeekable->getPosition() >= mnLength);
}

bool WPXSvInputStreamImpl::isOLEStream()
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return false;

    sal_Int64 tmpPosition = mxSeekable->getPosition();
    mxSeekable->seek(0);

    SvStream *pStream = utl::UcbStreamHelper::CreateStream( mxStream );
    bool bAns = pStream && SotStorage::IsOLEStorage( pStream );
    if (pStream)
        delete pStream;

    mxSeekable->seek(tmpPosition);

    return bAns;
}

WPXInputStream *WPXSvInputStreamImpl::getDocumentOLEStream(const char *name)
{
    if (!name)
        return 0;
    OUString rPath(name,strlen(name),RTL_TEXTENCODING_UTF8);
    std::vector<OUString> aElems;
    splitPath( aElems, rPath );

    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return 0;

    sal_Int64 tmpPosition = mxSeekable->getPosition();
    mxSeekable->seek(0);

    SvStream *pStream = utl::UcbStreamHelper::CreateStream( mxStream );

    if (!pStream || !SotStorage::IsOLEStorage( pStream ))
    {
        mxSeekable->seek(tmpPosition);
        return 0;
    }

    SotStorageRefWrapper storageRefWrapper;
    storageRefWrapper.ref = new SotStorage( pStream, sal_True );
    mxChildrenStorages.push_back( storageRefWrapper );

    unsigned i = 0;
    while (i < aElems.size())
    {
        if( mxChildrenStorages.back().ref->IsStream(aElems[i]))
            break;
        else if (mxChildrenStorages.back().ref->IsStorage(aElems[i]))
        {
            SotStorageRef tmpParent(mxChildrenStorages.back().ref);
            storageRefWrapper.ref = tmpParent->OpenSotStorage(aElems[i++], STREAM_STD_READ);
            mxChildrenStorages.push_back(storageRefWrapper);
        }
        else
            // should not happen
            return 0;
    }

    // For the while don't return stream in this situation.
    // Later, given how libcdr's zip stream implementation behaves,
    // return the first stream in the storage if there is one.
    if (i >= aElems.size())
        return 0;

    SotStorageStreamRefWrapper storageStreamRefWrapper;
    storageStreamRefWrapper.ref = mxChildrenStorages.back().ref->OpenSotStream( aElems[i], STREAM_STD_READ );
    mxChildrenStreams.push_back( storageStreamRefWrapper );

    mxSeekable->seek(tmpPosition);

    if ( !mxChildrenStreams.back().ref.Is() || mxChildrenStreams.back().ref->GetError() )
    {
        mxSeekable->seek(tmpPosition);
        return 0;
    }

    Reference < XInputStream > xContents(new utl::OSeekableInputStreamWrapper( mxChildrenStreams.back().ref ));
    mxSeekable->seek(tmpPosition);
    if (xContents.is())
        return new WPXSvInputStream( xContents );
    else
        return 0;
}

WPXSvInputStream::WPXSvInputStream( Reference< XInputStream > xStream ) :
    mpImpl(new WPXSvInputStreamImpl(xStream))
{
}

WPXSvInputStream::~WPXSvInputStream()
{
   delete mpImpl;
}

const unsigned char *WPXSvInputStream::read(unsigned long numBytes, unsigned long &numBytesRead)
{
    return mpImpl->read(numBytes, numBytesRead);
}

long WPXSvInputStream::tell()
{
    return mpImpl->tell();
}

int WPXSvInputStream::seek(long offset, WPX_SEEK_TYPE seekType)
{
    return mpImpl->seek(offset, seekType);
}

bool WPXSvInputStream::atEOS()
{
    return mpImpl->atEOS();
}

bool WPXSvInputStream::isOLEStream()
{
    return mpImpl->isOLEStream();
}

WPXInputStream *WPXSvInputStream::getDocumentOLEStream(const char *name)
{
    return mpImpl->getDocumentOLEStream(name);
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>#include "WPXSvStream.h"
#include "filter/FilterInternal.hxx"
#include <tools/stream.hxx>
#include <unotools/streamwrap.hxx>
#include <unotools/ucbstreamhelper.hxx>

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::io;

WPXSvInputStream::WPXSvInputStream( Reference< XInputStream > xStream ) :
        WPXInputStream(true),
        mxChildStorage(),
        mxChildStream(),
        mxStream(xStream),
        mxSeekable(xStream, UNO_QUERY),
        maData(0)
{
    if (!xStream.is() || !mxStream.is())
        mnLength = 0;
    else
    {
        if (!mxSeekable.is())
            mnLength = 0;
        else
        {
            try
            {
                mnLength = mxSeekable->getLength();
            }
            catch ( ... )
            {
                WRITER_DEBUG_MSG(("mnLength = mxSeekable->getLength() threw exception\n"));
                mnLength = 0;
            }
        }
    }
}

WPXSvInputStream::~WPXSvInputStream()
{
}

const uint8_t * WPXSvInputStream::read(size_t numBytes, size_t &numBytesRead)
{
    numBytesRead = 0;

    if (numBytes == 0 || atEOS())
        return 0;

    numBytesRead = mxStream->readSomeBytes (maData, numBytes);
    if (numBytesRead == 0)
        return 0;

    return (const uint8_t *)maData.getConstArray();
}

long WPXSvInputStream::tell()
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return -1L;
    else
        return (long)mxSeekable->getPosition();
}

int WPXSvInputStream::seek(long offset, WPX_SEEK_TYPE seekType)
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return -1;

    sal_Int64 tmpPosition = mxSeekable->getPosition();
    if (seekType == WPX_SEEK_CUR)
        offset += tmpPosition;

    int retVal = 0;
    if (offset < 0)
    {
        offset = 0;
        retVal = -1;
    }
    if (offset > mnLength)
    {
        offset = mnLength;
        retVal = -1;
    }

    try
    {
        mxSeekable->seek(offset);
        return retVal;
    }
    catch (...)
    {
        WRITER_DEBUG_MSG(("mxSeekable->seek(offset) threw exception\n"));
        return -1;
    }
}

bool WPXSvInputStream::atEOS()
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return true;
    return (mxSeekable->getPosition() >= mnLength);
}

bool WPXSvInputStream::isOLEStream()
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return false;

    sal_Int64 tmpPosition = mxSeekable->getPosition();
    mxSeekable->seek(0);

    SvStream *pStream = utl::UcbStreamHelper::CreateStream( mxStream );
    bool bAns = pStream && SotStorage::IsOLEStorage( pStream );
    if (pStream)
        delete pStream;

    mxSeekable->seek(tmpPosition);

    return bAns;
}

WPXInputStream * WPXSvInputStream::getDocumentOLEStream(const char * name)
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return 0;

    sal_Int64 tmpPosition = mxSeekable->getPosition();
    mxSeekable->seek(0);

    SvStream *pStream = utl::UcbStreamHelper::CreateStream( mxStream );

    if (!pStream || !SotStorage::IsOLEStorage( pStream ))
    {
        mxSeekable->seek(tmpPosition);
        return 0;
    }

    mxChildStorage = new SotStorage( pStream, TRUE );

    mxChildStream = mxChildStorage->OpenSotStream(
            rtl::OUString::createFromAscii( name ),
            STREAM_STD_READ );

    mxSeekable->seek(tmpPosition);

    if ( !mxChildStream.Is() || mxChildStream->GetError() )
    {
        mxSeekable->seek(tmpPosition);
        return 0;
    }

    Reference < XInputStream > xContents(new utl::OSeekableInputStreamWrapper( mxChildStream ));
    mxSeekable->seek(tmpPosition);
    if (xContents.is())
        return new WPXSvInputStream( xContents );
    else
        return 0;
}

WPXInputStream * WPXSvInputStream::getDocumentOLEStream()
{
    return getDocumentOLEStream( "PerfectOffice_MAIN" );
}
<commit_msg>INTEGRATION: CWS fsfixes06 (1.6.2); FILE MERGED 2007/02/06 12:49:23 fridrich_strba 1.6.2.1: check some integer related issues more tightly<commit_after>#include "WPXSvStream.h"
#include "filter/FilterInternal.hxx"
#include <tools/stream.hxx>
#include <unotools/streamwrap.hxx>
#include <unotools/ucbstreamhelper.hxx>
#include <limits>

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::io;

WPXSvInputStream::WPXSvInputStream( Reference< XInputStream > xStream ) :
        WPXInputStream(true),
        mxChildStorage(),
        mxChildStream(),
        mxStream(xStream),
        mxSeekable(xStream, UNO_QUERY),
        maData(0)
{
    if (!xStream.is() || !mxStream.is())
        mnLength = 0;
    else
    {
        if (!mxSeekable.is())
            mnLength = 0;
        else
        {
            try
            {
                mnLength = mxSeekable->getLength();
            }
            catch ( ... )
            {
                WRITER_DEBUG_MSG(("mnLength = mxSeekable->getLength() threw exception\n"));
                mnLength = 0;
            }
        }
    }
}

WPXSvInputStream::~WPXSvInputStream()
{
}

const uint8_t * WPXSvInputStream::read(size_t numBytes, size_t &numBytesRead)
{
    numBytesRead = 0;

    if (numBytes == 0 || atEOS())
        return 0;

    numBytesRead = mxStream->readSomeBytes (maData, numBytes);
    if (numBytesRead == 0)
        return 0;

    return (const uint8_t *)maData.getConstArray();
}

long WPXSvInputStream::tell()
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return -1L;
    else
    {
        sal_Int64 tmpPosition = mxSeekable->getPosition();
        if ((tmpPosition < 0) || (tmpPosition > (std::numeric_limits<long>::max)()))
            return -1L;
        return (long)tmpPosition;
    }
}

int WPXSvInputStream::seek(long offset, WPX_SEEK_TYPE seekType)
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return -1;

    sal_Int64 tmpPosition = mxSeekable->getPosition();
    if ((tmpPosition < 0) || (tmpPosition > (std::numeric_limits<long>::max)()))
        return -1;

    sal_Int64 tmpOffset = offset;
    if (seekType == WPX_SEEK_CUR)
        tmpOffset += tmpPosition;

    int retVal = 0;
    if (tmpOffset < 0)
    {
        tmpOffset = 0;
        retVal = -1;
    }
    if (offset > mnLength)
    {
        tmpOffset = mnLength;
        retVal = -1;
    }

    try
    {
        mxSeekable->seek(tmpOffset);
        return retVal;
    }
    catch (...)
    {
        WRITER_DEBUG_MSG(("mxSeekable->seek(offset) threw exception\n"));
        return -1;
    }
}

bool WPXSvInputStream::atEOS()
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return true;
    return (mxSeekable->getPosition() >= mnLength);
}

bool WPXSvInputStream::isOLEStream()
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return false;

    sal_Int64 tmpPosition = mxSeekable->getPosition();
    mxSeekable->seek(0);

    SvStream *pStream = utl::UcbStreamHelper::CreateStream( mxStream );
    bool bAns = pStream && SotStorage::IsOLEStorage( pStream );
    if (pStream)
        delete pStream;

    mxSeekable->seek(tmpPosition);

    return bAns;
}

WPXInputStream * WPXSvInputStream::getDocumentOLEStream(const char * name)
{
    if ((mnLength == 0) || !mxStream.is() || !mxSeekable.is())
        return 0;

    sal_Int64 tmpPosition = mxSeekable->getPosition();
    mxSeekable->seek(0);

    SvStream *pStream = utl::UcbStreamHelper::CreateStream( mxStream );

    if (!pStream || !SotStorage::IsOLEStorage( pStream ))
    {
        mxSeekable->seek(tmpPosition);
        return 0;
    }

    mxChildStorage = new SotStorage( pStream, TRUE );

    mxChildStream = mxChildStorage->OpenSotStream(
            rtl::OUString::createFromAscii( name ),
            STREAM_STD_READ );

    mxSeekable->seek(tmpPosition);

    if ( !mxChildStream.Is() || mxChildStream->GetError() )
    {
        mxSeekable->seek(tmpPosition);
        return 0;
    }

    Reference < XInputStream > xContents(new utl::OSeekableInputStreamWrapper( mxChildStream ));
    mxSeekable->seek(tmpPosition);
    if (xContents.is())
        return new WPXSvInputStream( xContents );
    else
        return 0;
}

WPXInputStream * WPXSvInputStream::getDocumentOLEStream()
{
    return getDocumentOLEStream( "PerfectOffice_MAIN" );
}
<|endoftext|>


<commit_before>#include "CSV.h"

#include <Cursor.h>

#include <utf8proc.h>

#include <fstream>
#include <vector>
#include <cstdio>
#include <charconv>

static inline std::string normalize_nfc(const std::string & input) {
  auto r0 = utf8proc_NFC(reinterpret_cast<const unsigned char *>(input.c_str()));
  std::string r;
  if (r0) {
    r = (const char *)r0;
    free(r0);
  }
  return r;
}

using namespace sqldb;
using namespace std;

static inline vector<string> split(string_view line, char delimiter) {
  vector<string> r;

  if (!line.empty()) {
    size_t i = 0;
    bool in_quote = false;
    string current;
    size_t n = line.size();
    for ( ; i < n; i++) {
      auto c = line[i];
      if (c == '\r') {
	// ignore carriage returns
      } else if (!in_quote && c == '"') {
	in_quote = true;
      } else if (in_quote) {
	if (c == '\\') current += line[++i];
	else if (c == '"') in_quote = false;
	else current += c;
      } else if (c == delimiter) {
	r.push_back(current);
	current.clear();
      } else {
	current += c;
      }
    }
    r.push_back(current);
  }
  return r;
}

class sqldb::CSVFile {
public:
  CSVFile(std::string csv_file, bool has_records) : csv_file_(move(csv_file)) {
    open(has_records);
  }

  void open(bool has_records) {
    in_ = fopen(csv_file_.c_str(), "rb");

    if (in_) {
      // cerr << "getting header\n";

      if (has_records) {
	auto s = get_record();

	// autodetect delimiter
	if (!delimiter_) {
	  size_t best_n = 0;
	  char best_delimiter = 0;
	  for (int i = 0; i < 3; i++) {
	    char d;
	    if (i == 0) d = ',';
	    else if (i == 1) d = ';';
	    else d = '\t';
	    auto tmp = split(s, d);
	    auto n = tmp.size();
	    if (n > best_n) {
	      best_n = n;
	      best_delimiter = d;
	    }
	  }
	  // if there are no delimiters in header, use no delimiter
	  if (best_n) {
	    delimiter_ = best_delimiter;
	  }
	  // cerr << "delimiter = " << delimiter_ << "\n";
	}
	header_row_ = split(s, delimiter_);
      } else {
	header_row_.push_back("Content");
      }
    } else {
      // cerr << "failed to open\n";
    }
  }

  CSVFile(const CSVFile & other) :
    csv_file_(other.csv_file_),
    delimiter_(other.delimiter_),
    next_row_idx_(other.next_row_idx_),
    header_row_(other.header_row_),
    current_row_(other.current_row_),
    input_buffer_(other.input_buffer_),
    row_offsets_(other.row_offsets_)
  {
    in_ = fopen(csv_file_.c_str(), "r");
    if (in_) fseek(in_, ftell(other.in_), SEEK_SET);
  }

  std::string getText(int column_index, std::string default_value) const {
    if (column_index >= 0 && column_index < current_row_.size()) {
      return current_row_[column_index];
    }
    return move(default_value);
  }

  int getNumFields() const { return static_cast<int>(header_row_.size()); }
  std::string getColumnName(int column_index) const {
    auto idx = static_cast<size_t>(column_index);
    return idx < header_row_.size() ? header_row_[idx] : "";
  }

  size_t getNextRowIdx() const { return next_row_idx_; }

  bool seek(size_t row) {
    if (row + 1 == next_row_idx_) {
      return true;
    }
    if (row < row_offsets_.size()) {
      input_buffer_.clear();
      next_row_idx_ = row;
      fseek(in_, row_offsets_[next_row_idx_], SEEK_SET);
      return next();
    }
    if (!row_offsets_.empty()) {
      input_buffer_.clear();
      next_row_idx_ = row_offsets_.size() - 1;
      fseek(in_, row_offsets_.back(), SEEK_SET);
      row -= row_offsets_.size() - 1;
    }
    while (row > 0) {
      bool r = next();
      if (!r) return false;
      row--;
    }
    return next();
  }

  bool next() {
    size_t row_offset = ftell(in_) - input_buffer_.size();
    auto s = get_record();

    if (s.empty()) {
      return false;
    }

    current_row_ = split(s, delimiter_);
    if (next_row_idx_ == row_offsets_.size()) {
      row_offsets_.push_back(row_offset);
    }
    next_row_idx_++;

    return true;
  }

private:
  std::string get_record() {
    while ( 1 ) {
      // std::cerr << "parsing " << input_buffer_.size() << "\n";

      bool quoted = false;
      for (size_t i = 0; i < input_buffer_.size(); i++) {
	if (!quoted && input_buffer_[i] == '"') {
	  quoted = true;
	} else if (input_buffer_[i] == '\\') {
	  i++;
	} else if (quoted && input_buffer_[i] == '"') {
	  quoted = false;
	} else if (!quoted && input_buffer_[i] == '\n') {
	  auto rec = input_buffer_.substr(0, i);
	  // std::cerr << "found record: " << rec << "\n";
	  input_buffer_ = input_buffer_.substr(i + 1);
	  return normalize_nfc(rec);
	}
      }

      // std::cerr << "reading more\n";

      if (in_) {
	char buffer[4096];
	auto r = fread(buffer, 1, 4096, in_);
	if (r > 0) {
	  input_buffer_ += std::string(buffer, r);
	  continue;
	}
      }
      return "";
    }
  }

  std::string csv_file_;
  FILE * in_ = 0;
  char delimiter_ = 0;
  size_t next_row_idx_ = 0;
  std::vector<std::string> header_row_;
  std::vector<std::string> current_row_;
  std::string input_buffer_;
  std::vector<size_t> row_offsets_;
};

class CSVCursor : public Cursor {
public:
  CSVCursor(const std::shared_ptr<sqldb::CSVFile> & csv, int row) : csv_(csv) {
    csv_->seek(row);
  }

  bool next() override { return csv_->next(); }

  std::string getText(int column_index, const std::string default_value = "") override {
    return csv_->getText(column_index, default_value);
  }

  int getNumFields() const override { return csv_->getNumFields(); }

  vector<uint8_t> getBlob(int column_index) override {
    auto v = csv_->getText(column_index, "");
    std::vector<uint8_t> r;
    for (size_t i = 0; i < v.size(); i++) r.push_back(static_cast<uint8_t>(v[i]));
    return r;
  }

  bool isNull(int column_index) const override {
    return csv_->getText(column_index, "").empty();
  }

  std::string getRowKey() const { return csv_->getNextRowIdx() >= 1 ? CSV::formatKey(csv_->getNextRowIdx() - 1) : ""; }

  void set(int column_idx, std::string_view value, bool is_defined = true) override {
    throw std::runtime_error("CSV is read-only");
  }
  void set(int column_idx, int value, bool is_defined = true) override {
    throw std::runtime_error("CSV is read-only");
  }
  void set(int column_idx, long long value, bool is_defined = true) override {
    throw std::runtime_error("CSV is read-only");
  }
  void set(int column_idx, double value, bool is_defined = true) override {
    throw std::runtime_error("CSV is read-only");
  }
  void set(int column_idx, const void * data, size_t len, bool is_defined = true) override {
    throw std::runtime_error("CSV is read-only");
  }
  size_t execute() override {
    throw std::runtime_error("CSV is read-only");
  }

  long long getLastInsertId() const override { return 0; }

private:
  std::shared_ptr<CSVFile> csv_;
};

CSV::CSV(std::string csv_file, bool has_records) : csv_(make_shared<CSVFile>(move(csv_file), has_records)) { }
CSV::CSV(const CSV & other) : csv_(make_shared<CSVFile>(*other.csv_)) { }
CSV::CSV(CSV && other) : csv_(move(other.csv_)) { }

int
CSV::getNumFields() const {
  return csv_->getNumFields();
}

std::string
CSV::getColumnName(int column_index) const {
  return csv_->getColumnName(column_index);
}

unique_ptr<Cursor>
CSV::seek(std::string_view key) {
  int row;
  auto result = std::from_chars(key.data(), key.data() + key.size(), row, 16);
  if (result.ec == std::errc::invalid_argument) {
    return unique_ptr<CSVCursor>(nullptr);
  } else {
    return seek(row);
  }
}

unique_ptr<Cursor>
CSV::seek(int row) {
  return make_unique<CSVCursor>(csv_, row);
}
<commit_msg>handle last record even if it has no line termination, add getColumnName()<commit_after>#include "CSV.h"

#include <Cursor.h>

#include <utf8proc.h>

#include <fstream>
#include <vector>
#include <cstdio>
#include <charconv>

static inline std::string normalize_nfc(const std::string & input) {
  auto r0 = utf8proc_NFC(reinterpret_cast<const unsigned char *>(input.c_str()));
  std::string r;
  if (r0) {
    r = (const char *)r0;
    free(r0);
  }
  return r;
}

using namespace sqldb;
using namespace std;

static inline vector<string> split(string_view line, char delimiter) {
  vector<string> r;

  if (!line.empty()) {
    size_t i = 0;
    bool in_quote = false;
    string current;
    size_t n = line.size();
    for ( ; i < n; i++) {
      auto c = line[i];
      if (c == '\r') {
	// ignore carriage returns
      } else if (!in_quote && c == '"') {
	in_quote = true;
      } else if (in_quote) {
	if (c == '\\') current += line[++i];
	else if (c == '"') in_quote = false;
	else current += c;
      } else if (c == delimiter) {
	r.push_back(current);
	current.clear();
      } else {
	current += c;
      }
    }
    r.push_back(current);
  }
  return r;
}

class sqldb::CSVFile {
public:
  CSVFile(std::string csv_file, bool has_records) : csv_file_(move(csv_file)) {
    open(has_records);
  }

  void open(bool has_records) {
    in_ = fopen(csv_file_.c_str(), "rb");

    if (in_) {
      // cerr << "getting header\n";

      if (has_records) {
	auto s = get_record();

	// autodetect delimiter
	if (!delimiter_) {
	  size_t best_n = 0;
	  char best_delimiter = 0;
	  for (int i = 0; i < 3; i++) {
	    char d;
	    if (i == 0) d = ',';
	    else if (i == 1) d = ';';
	    else d = '\t';
	    auto tmp = split(s, d);
	    auto n = tmp.size();
	    if (n > best_n) {
	      best_n = n;
	      best_delimiter = d;
	    }
	  }
	  // if there are no delimiters in header, use no delimiter
	  if (best_n) {
	    delimiter_ = best_delimiter;
	  }
	  // cerr << "delimiter = " << delimiter_ << "\n";
	}
	header_row_ = split(s, delimiter_);
      } else {
	header_row_.push_back("Content");
      }
    } else {
      // cerr << "failed to open\n";
    }
  }

  CSVFile(const CSVFile & other) :
    csv_file_(other.csv_file_),
    delimiter_(other.delimiter_),
    next_row_idx_(other.next_row_idx_),
    header_row_(other.header_row_),
    current_row_(other.current_row_),
    input_buffer_(other.input_buffer_),
    row_offsets_(other.row_offsets_)
  {
    in_ = fopen(csv_file_.c_str(), "r");
    if (in_) fseek(in_, ftell(other.in_), SEEK_SET);
  }

  std::string getText(int column_index, std::string default_value) const {
    if (column_index >= 0 && column_index < current_row_.size()) {
      return current_row_[column_index];
    }
    return move(default_value);
  }

  int getNumFields() const { return static_cast<int>(header_row_.size()); }
  std::string getColumnName(int column_index) const {
    auto idx = static_cast<size_t>(column_index);
    return idx < header_row_.size() ? header_row_[idx] : "";
  }

  size_t getNextRowIdx() const { return next_row_idx_; }

  bool seek(size_t row) {
    if (row + 1 == next_row_idx_) {
      return true;
    }
    if (row < row_offsets_.size()) {
      input_buffer_.clear();
      next_row_idx_ = row;
      fseek(in_, row_offsets_[next_row_idx_], SEEK_SET);
      return next();
    }
    if (!row_offsets_.empty()) {
      input_buffer_.clear();
      next_row_idx_ = row_offsets_.size() - 1;
      fseek(in_, row_offsets_.back(), SEEK_SET);
      row -= row_offsets_.size() - 1;
    }
    while (row > 0) {
      bool r = next();
      if (!r) return false;
      row--;
    }
    return next();
  }

  bool next() {
    size_t row_offset = ftell(in_) - input_buffer_.size();
    auto s = get_record();

    if (s.empty()) {
      return false;
    }

    current_row_ = split(s, delimiter_);
    if (next_row_idx_ == row_offsets_.size()) {
      row_offsets_.push_back(row_offset);
    }
    next_row_idx_++;

    return true;
  }

private:
  std::string get_record() {
    while ( 1 ) {
      // std::cerr << "parsing " << input_buffer_.size() << "\n";

      bool quoted = false;
      for (size_t i = 0; i < input_buffer_.size(); i++) {
	if (!quoted && input_buffer_[i] == '"') {
	  quoted = true;
	} else if (input_buffer_[i] == '\\') {
	  i++;
	} else if (quoted && input_buffer_[i] == '"') {
	  quoted = false;
	} else if (!quoted && input_buffer_[i] == '\n') {
	  auto rec = input_buffer_.substr(0, i);
	  // std::cerr << "found record: " << rec << "\n";
	  input_buffer_ = input_buffer_.substr(i + 1);
	  return normalize_nfc(rec);
	}
      }

      // std::cerr << "reading more\n";

      if (in_) {
	char buffer[4096];
	auto r = fread(buffer, 1, 4096, in_);
	if (r > 0) {
	  input_buffer_ += std::string(buffer, r);
	  continue;
	}
      }

      // If the last row is not \n terminated, return it anyway
      if (!input_buffer_.empty()) {
	auto rec = input_buffer_;
	input_buffer_.clear();
	return normalize_nfc(rec);
      } else {
	return "";
      }
    }
  }

  std::string csv_file_;
  FILE * in_ = 0;
  char delimiter_ = 0;
  size_t next_row_idx_ = 0;
  std::vector<std::string> header_row_;
  std::vector<std::string> current_row_;
  std::string input_buffer_;
  std::vector<size_t> row_offsets_;
};

class CSVCursor : public Cursor {
public:
  CSVCursor(const std::shared_ptr<sqldb::CSVFile> & csv, int row) : csv_(csv) {
    csv_->seek(row);
  }

  bool next() override { return csv_->next(); }

  std::string getText(int column_index, const std::string default_value = "") override {
    return csv_->getText(column_index, default_value);
  }

  int getNumFields() const override { return csv_->getNumFields(); }

  vector<uint8_t> getBlob(int column_index) override {
    auto v = csv_->getText(column_index, "");
    std::vector<uint8_t> r;
    for (size_t i = 0; i < v.size(); i++) r.push_back(static_cast<uint8_t>(v[i]));
    return r;
  }

  bool isNull(int column_index) const override {
    return csv_->getText(column_index, "").empty();
  }

  std::string getColumnName(int column_index) const override {
    return csv_->getColumnName(column_index);
  }

  std::string getRowKey() const { return csv_->getNextRowIdx() >= 1 ? CSV::formatKey(csv_->getNextRowIdx() - 1) : ""; }

  void set(int column_idx, std::string_view value, bool is_defined = true) override {
    throw std::runtime_error("CSV is read-only");
  }
  void set(int column_idx, int value, bool is_defined = true) override {
    throw std::runtime_error("CSV is read-only");
  }
  void set(int column_idx, long long value, bool is_defined = true) override {
    throw std::runtime_error("CSV is read-only");
  }
  void set(int column_idx, double value, bool is_defined = true) override {
    throw std::runtime_error("CSV is read-only");
  }
  void set(int column_idx, const void * data, size_t len, bool is_defined = true) override {
    throw std::runtime_error("CSV is read-only");
  }
  size_t execute() override {
    throw std::runtime_error("CSV is read-only");
  }

  long long getLastInsertId() const override { return 0; }

private:
  std::shared_ptr<CSVFile> csv_;
};

CSV::CSV(std::string csv_file, bool has_records) : csv_(make_shared<CSVFile>(move(csv_file), has_records)) { }
CSV::CSV(const CSV & other) : csv_(make_shared<CSVFile>(*other.csv_)) { }
CSV::CSV(CSV && other) : csv_(move(other.csv_)) { }

int
CSV::getNumFields() const {
  return csv_->getNumFields();
}

std::string
CSV::getColumnName(int column_index) const {
  return csv_->getColumnName(column_index);
}

unique_ptr<Cursor>
CSV::seek(std::string_view key) {
  int row;
  auto result = std::from_chars(key.data(), key.data() + key.size(), row, 16);
  if (result.ec == std::errc::invalid_argument) {
    return unique_ptr<CSVCursor>(nullptr);
  } else {
    return seek(row);
  }
}

unique_ptr<Cursor>
CSV::seek(int row) {
  return make_unique<CSVCursor>(csv_, row);
}
<|endoftext|>


<commit_before>#include "DFA.h"
#include <string>
#include <stack>
#include <iostream>
using namespace std;
template <class T>
class LinkStack;

//ʽջ
template <class T>
class StackNode
{
	friend class LinkStack<T>;
private:
	T data;
	StackNode<T> *next;
	StackNode(T item = 0, StackNode<T> *p = NULL)
	{
		data = item;
		next = p;
	}
};

// ʽջ
template <class T>
class LinkStack
{
private:
	StackNode<T> *top;
public:
	LinkStack();
	~LinkStack();
	bool IsEmpty();
	int Length();
	void Push(const T &item);
	T Pop();
	T GetTop();
	void Clear();
};
//幹캯
template <class T>
LinkStack<T>::LinkStack()
{
	top = NULL;
}

//
template <class T>
LinkStack<T>::~LinkStack()
{
	Clear();
}
//жջǷΪ
template <class T>
bool LinkStack<T>::IsEmpty()
{
	return(!top);
}
//ջĳ
template <class T>
int LinkStack<T>::Length()
{
	StackNode<T> *temp = new StackNode<T>();
	temp = top;
	int length = 0;
	while (temp)
	{
		temp = temp->next;
		length++;
	}
	return length;
}
//ѹջ
template <class T>
void LinkStack<T>::Push(const T &item)
{
	top = new StackNode<T>(item, top);
}
// (ջ)
template <class T>
T LinkStack<T>::Pop()
{
	if (!IsEmpty())
	{
		StackNode<T> *temp = top;
		top = top->next;
		T value = temp->data;
		delete temp;
		return value;
	}
	else
	{
		cout << "Stack is Empty" << endl;
		exit(1);
	}
}
//ȡջ
template<class T>
T LinkStack<T>::GetTop()
{
	if (!IsEmpty())
		return top->data;
	else
	{
		cout << "The Stack is Empty" << endl;
		exit(1);
	}
}
//ջ
template<class T>
void LinkStack<T>::Clear()
{
	StackNode<T> *temp = new StackNode<T>();
	while (top)
	{
		temp = top;
		top = top->next;
		delete temp;
	}
}
/*
		DFA
*/
//DFA캯
DFA::DFA()
{
	Regex = new char[128];
	RegexPost = new char[128];
	Edge = new char[128];
	EdgeNumber = 0;
	DFAStatesNumber = 0;
	NFAStatesNumber = 0;
	DtranNumber = 0;
	NFATable = new AdjacentTable();
}
//DFA
DFA::~DFA()
{
	delete[] Regex;
	delete[] RegexPost;
	//delete[] Edge;
	//delete[] AcceptStates;
	//NFATable->Clear();
	//DFATable->clear();
}
//ȡ
void DFA::InputRegex()
{
	cout << " ʽ" << endl;
	cin >> Regex;
}
//"."
void DFA::InsertNode()
{
	int i = 0,j, len = strlen(Regex);
	int length = len;
	len--;
	while (len--)
	{
		if (((Regex[i] != '(' && Regex[i] != '.' && Regex[i] != '|')
			|| Regex[i] == ')'|| Regex[i] == '*')
			&& (Regex[i + 1] != ')' && Regex[i + 1] != '.' && Regex[i + 1] != '|' && Regex[i + 1] != '*'))
		{
			for (j =length; j >i;j--)
			{
				Regex[j+1] = Regex[j];
			}
			Regex[i + 1] = '.';
			length++;
			Regex[length] = '\0';
			i++;
		}
		i++;
	}
	cout << endl;
	cout << "     " << endl;
	cout<<Regex << endl;
	cout << "ַȣ" <<length<<endl;
}
//жȼ
int DFA::Precedence(char symbol)
{
	int priority;
	switch (symbol)
	{
	case '|':priority = 1; break;
	case '.':priority = 2; break;
	case '*':priority = 3; break;
	default:priority = 0; break;
	}
	return priority;
}
//ʽתΪ沨ʽ
void DFA::RegextoPost()
{
	int i = 0, j = 0;
	char ch, cl;
	strcpy(RegexPost, "\0");
	LinkStack<char> *Value = new LinkStack<char>();
	LinkStack<char >*Operate = new LinkStack<char>();
	Value->Clear();
	Operate->Clear();
	ch = Regex[i];
	while (ch != '\0')
	{

	}
}
//ɨ沨ʽгַĿ
void DFA::GetEdgeNumber()
{
	int i = 0, j;
	EdgeNumber = 0;
	while (RegexPost[i] != '\0')
	{
		if (RegexPost[i] == '.' || RegexPost[i] == '|' || RegexPost[i] == '*')
		{
			i++;
			continue;
		}
		for (j = 0; j < EdgeNumber; j++)
		{
			if (RegexPost[i] == Edge[j])
				break;
		}
		if (j == EdgeNumber)
		{
			Edge[EdgeNumber] = RegexPost[i];
			EdgeNumber++;
		}
		i++;
	}
	Edge[EdgeNumber] = '\0';
	cout << "\n: ȡַ\n";
	for (i = 0; i<EdgeNumber; i++)
	{
		cout << Edge[i] << ' ';
	}
	cout << "\nַ: " << EdgeNumber
		<< "\n\n------------------------" << endl;
}

/*//Thompson취NFA
void DFA::Thompson()
{
	int i, j;
	char ch;
	int s1, s2;
	LinkStack<int >*States = new LinkStack<int >();
	States->Clear();
	if (strlen(RegexPost) < 1)
	{
		cout << "No Regex Expression Find" << endl;
		exit(1);
	}
	NFATable->SetValue(0, 0);
	i = 1; j = 0;
	ch = RegexPost[i];
	while (ch != '\0')
	{
		if (ch = '.')
		{
			s2 = States->Pop();
		}
	}

}
*/<commit_msg>update<commit_after>#include "DFA.h"
#include <string>
#include <stack>
#include <iostream>
using namespace std;
template <class T>
class LinkStack;

//ʽջ
template <class T>
class StackNode
{
	friend class LinkStack<T>;
private:
	T data;
	StackNode<T> *next;
	StackNode(T item = 0, StackNode<T> *p = NULL)
	{
		data = item;
		next = p;
	}
};

// ʽջ
template <class T>
class LinkStack
{
private:
	StackNode<T> *top;
public:
	LinkStack();
	~LinkStack();
	bool IsEmpty();
	int Length();
	void Push(const T &item);
	T Pop();
	T GetTop();
	void Clear();
};
//幹캯
template <class T>
LinkStack<T>::LinkStack()
{
	top = NULL;
}

//
template <class T>
LinkStack<T>::~LinkStack()
{
	Clear();
}
//жջǷΪ
template <class T>
bool LinkStack<T>::IsEmpty()
{
	return(!top);
}
//ջĳ
template <class T>
int LinkStack<T>::Length()
{
	StackNode<T> *temp = new StackNode<T>();
	temp = top;
	int length = 0;
	while (temp)
	{
		temp = temp->next;
		length++;
	}
	return length;
}
//ѹջ
template <class T>
void LinkStack<T>::Push(const T &item)
{
	top = new StackNode<T>(item, top);
}
// (ջ)
template <class T>
T LinkStack<T>::Pop()
{
	if (!IsEmpty())
	{
		StackNode<T> *temp = top;
		top = top->next;
		T value = temp->data;
		delete temp;
		return value;
	}
	else
	{
		cout << "Stack is Empty" << endl;
		exit(1);
	}
}
//ȡջ
template<class T>
T LinkStack<T>::GetTop()
{
	if (!IsEmpty())
		return top->data;
	else
	{
		cout << "The Stack is Empty" << endl;
		exit(1);
	}
}
//ջ
template<class T>
void LinkStack<T>::Clear()
{
	StackNode<T> *temp = new StackNode<T>();
	while (top)
	{
		temp = top;
		top = top->next;
		delete temp;
	}
}
/*
		DFA
*/
//DFA캯
DFA::DFA()
{
	Regex = new char[128];
	RegexPost = new char[128];
	Edge = new char[128];
	EdgeNumber = 0;
	DFAStatesNumber = 0;
	NFAStatesNumber = 0;
	DtranNumber = 0;
	NFATable = new AdjacentTable();
}
//DFA
DFA::~DFA()
{
	delete[] Regex;
	delete[] RegexPost;
	//delete[] Edge;
	//delete[] AcceptStates;
	//NFATable->Clear();
	//DFATable->clear();
}
//ȡ
void DFA::InputRegex()
{
	cout << " ʽ" << endl;
	cin >> Regex;
}
//"."
void DFA::InsertNode()
{
	int i = 0,j, len = strlen(Regex);
	int length = len;
	len--;
	while (len--)
	{
		if (((Regex[i] != '(' && Regex[i] != '.' && Regex[i] != '|')
			|| Regex[i] == ')'|| Regex[i] == '*')
			&& (Regex[i + 1] != ')' && Regex[i + 1] != '.' && Regex[i + 1] != '|' && Regex[i + 1] != '*'))
		{
			for (j =length; j >i;j--)
			{
				Regex[j+1] = Regex[j];
			}
			Regex[i + 1] = '.';
			length++;
			Regex[length] = '\0';
			i++;
		}
		i++;
	}
	cout << endl;
	cout << "     " << endl;
	cout<<Regex << endl;
	cout << "ַȣ" <<length<<endl;
}
//жȼ
int DFA::Precedence(char symbol)
{
	int priority;
	switch (symbol)
	{
	case '|':priority = 1; break;
	case '.':priority = 2; break;
	case '*':priority = 3; break;
	default:priority = 0; break;
	}
	return priority;
}
//ʽתΪ沨ʽ
void DFA::RegextoPost()
{
	int i = 0, j = 0;
	char ch, cl;
	strcpy(RegexPost, "\0");
	LinkStack<char> *Value = new LinkStack<char>();
	Value->Clear();
	ch = Regex[i];
	Value->Push('#');
	ch = Regex[i];
	while (ch != '\0')
	{
		if (ch == '(')
		{
			Value->Push(ch);
			ch = Regex[++i];
		}
		else if (ch == ')')
		{
			while (Value->GetTop() != '(')
			{
				RegexPost[j++] = Value->Pop();
			}
			Value->Pop();
			ch = Regex[++i];
		}
		else if ((ch == '|') || (ch == '*') || (ch == '.'))
		{
			cl = Value->GetTop();
			while (Precedence(cl) >= Precedence(ch))
			{
				RegexPost[j++] = cl;
				Value->Pop();
				cl = Value->GetTop();
			}
			Value->Push(ch);
			ch = Regex[++i];
		}
		else
		{
			RegexPost[j++] = ch;
			ch = Regex[++i];
		}
	}
	ch = Value->Pop();
	while ((ch == '|') || (ch == '*') || (ch == '.'))
	{
		RegexPost[j++] = ch;
		ch = Value->Pop();
	}
	RegexPost[j] = '\0';
	Value->Clear();
	cout << "\nڶ: תΪ׺ʽ\n"
		<< RegexPost << "\n"
		<< "ַ: " << strlen(RegexPost)
		<< "\n\n------------------------" << endl;
}
//ɨ沨ʽгַĿ
void DFA::GetEdgeNumber()
{
	int i = 0, j;
	EdgeNumber = 0;
	while (RegexPost[i] != '\0')
	{
		if (RegexPost[i] == '.' || RegexPost[i] == '|' || RegexPost[i] == '*')
		{
			i++;
			continue;
		}
		for (j = 0; j < EdgeNumber; j++)
		{
			if (RegexPost[i] == Edge[j])
				break;
		}
		if (j == EdgeNumber)
		{
			Edge[EdgeNumber] = RegexPost[i];
			EdgeNumber++;
		}
		i++;
	}
	Edge[EdgeNumber] = '\0';
	cout << "\n: ȡַ\n";
	for (i = 0; i<EdgeNumber; i++)
	{
		cout << Edge[i] << ' ';
	}
	cout << "\nַ: " << EdgeNumber
		<< "\n\n------------------------" << endl;
}

/*//Thompson취NFA
void DFA::Thompson()
{
	int i, j;
	char ch;
	int s1, s2;
	LinkStack<int >*States = new LinkStack<int >();
	States->Clear();
	if (strlen(RegexPost) < 1)
	{
		cout << "No Regex Expression Find" << endl;
		exit(1);
	}
	NFATable->SetValue(0, 0);
	i = 1; j = 0;
	ch = RegexPost[i];
	while (ch != '\0')
	{
		if (ch = '.')
		{
			s2 = States->Pop();
		}
	}

}
*/<|endoftext|>


<commit_before>#include "algorithm2D.h"

Algorithm2D::Algorithm2D()
{

    //Load the previously stored templates if there are any
    std::cerr<<"GET NUMBER OF TEMPLATES: "<<dataparser.getNumberTemplates()<<std::endl;
    if(dataparser.getNumberTemplates()>1)
    {
        std::cerr<<"1"<<std::endl;
        this->descriptors=dataparser.getTemplates();
        std::cerr<<"1"<<std::endl;
        std::cerr<<"descriptors size"<<descriptors.size()<<std::endl;

        alg2D.resize(descriptors.size());

        //Add the descriptors to each algorithm & train them
        for (unsigned int i =0; i<descriptors.size(); i++)
        {
            try
            {
                alg2D[i].add(this->descriptors[i]);
                alg2D[i].train();
            }
            catch (std::exception & e)
            {}
        }
        std::cerr<<"1"<<std::endl;

    }

    matched_object_id=-1;
    this->object_number=0;

}

void Algorithm2D::add_descriptors(const TFG::HandImageConstPtr & msg)
{

    //convert from ros image msg to opencv image
    cv_bridge::CvImagePtr cv_ptr;
    for (unsigned int i=0; i<msg->image.size(); i++)
    {
        try
        {
            cv_ptr = cv_bridge::toCvCopy(msg->image[i], sensor_msgs::image_encodings::MONO8);
        }
        catch (cv_bridge::Exception& e)
        {
            ROS_ERROR("cv_bridge exception: %s", e.what());
        }

        cv::Mat image_cv=cv_ptr->image.clone();

        //        ROS_ERROR("OBJECT NUMBER %d DESCRIPTORS SIZE %d", object_number, descriptors.size());

        //add the new view to the descriptors matrix
        image_cv.convertTo(image_cv,CV_32F );

        descriptors[this->object_number].push_back(image_cv);
    }
}

//REMEMBER TO CHANGE SET_NEW_OBJECT TO TRUE WHENEVER WE ARE LEARNING A NEW OBJECT!!!!!
void Algorithm2D::train2D()
{
    try{

        //add the descriptors vector to the 2D algorithm
        //        ROS_ERROR("OBJECT NUMBER %d DESCRIPTORS SIZE %d ALGORITHMS SIZE %d", object_number, descriptors.size(), alg2D.size());

        alg2D[this->object_number].add(descriptors[this->object_number]);

        //train the 2D algorithm with the new view
        alg2D[this->object_number].train();

    }
    catch (std::exception & e)
    {}

    //store template
    dataparser.save_template_2D(this->descriptors[this->object_number], this->object_number);

    //store algorithm
    dataparser.save_algorithm_2D(alg2D[this->object_number], this->object_number);

}

//void Algorithm2D::train3D ()
//{
//    //train 3D features

//    //store template

//    //store algorithm
//}

void Algorithm2D ::set_new_object(bool new_object)
{
    this->new_object=new_object;

    if(this->new_object)
    {
        descriptors.push_back(std::vector<cv::Mat> ());
        alg2D.push_back(cv::FlannBasedMatcher ());

        //        alg2D.resize(alg2D.size()+1);
        //        descriptors.resize(descriptors.size()+1);

    }

    this->object_number=alg2D.size()-1;

}

int Algorithm2D :: match2D(const TFG::HandImageConstPtr & msg)
{
    cv_bridge::CvImagePtr cv_ptr;

    //resulting object id

    for (unsigned int i=0; i<msg->image.size(); i++)
    {
        //transform from ROS msg to OpenCV msg
        try
        {
            cv_ptr = cv_bridge::toCvCopy(msg->image[i], sensor_msgs::image_encodings::BGR8);
        }
        catch (cv_bridge::Exception& e)
        {
            ROS_ERROR("cv_bridge exception: %s", e.what());
        }

        //threshold used in the flann_comparison
        float  threshold=300;

        try{
            //compare FLANN
            matched_object_id=this->flann_comparison(cv_ptr->image, threshold);
        }
        catch(std::exception & e)
        {}
    }

    return matched_object_id;
}

int Algorithm2D:: flann_comparison (cv::Mat  &desc1,float threshold)
{
    //vector that will store the ratios of similarity between the new image and the templates
    std::vector< float> ratio;
    //resize the vector
    ratio.resize(descriptors.size());

    //vector to store the distances between descriptors
    std::vector<std::vector< cv::DMatch > >matches;
    //resize the vector
    matches.resize(descriptors.size());

    //Store good matches, using the threshold ratio
    std::vector<std::vector< cv::DMatch > >good_matches;
    good_matches.resize(descriptors.size());

    //    std::cerr<<"In flann_comparison function, alg2d.size(): "<<alg2D.size()<<std::endl<<"descriptors.size(): "<<descriptors.size()<<std::endl<< "descriptors[object_number].size(): "<<descriptors[object_number].size()<<std::endl;

    //for each algorithm, match the new descriptors with the algorithm's information
    for (unsigned int object_number=0; object_number<descriptors.size(); object_number++)
    {
        desc1.convertTo(desc1, CV_32F);

        //match each algorithm with the new cv::Mat and output the result in the matches vector
        alg2D[object_number].match( desc1, matches[object_number]);

        //        std::cerr<<"Number of matches: "<<matches[object_number].size()<<std::endl;

        //decide which are the good matches (i.e. matches whose distance is lower than the threshold) of the above matches
        for( unsigned int i = 0; i < matches[object_number].size(); i++ )
        {
            if( matches[object_number][i].distance < threshold )
                good_matches[object_number].push_back( matches[object_number][i]);
        }

        //cout <<good_matches.size()<<endl<<matches.size()<<endl;

        //The ratio is defined as the number of good_matches  over the number of total matches
        //This ratio is defined for each algorithm. Since each algorithm will be used for each object, this will be the similarity with this object

        if (matches[object_number].size()>0)
        {
            ratio[object_number]=(float)(good_matches[object_number].size()/matches[object_number].size());
        }

        else if (matches[object_number].size()<=0)
        {
            ratio[object_number]=-1;
        }

        //        std::cerr<<"Comparison with object "<<object_number<<" ratio: "<<ratio[object_number]<<std::endl;

    }
    int object_id;

    //Obtain the object ID as the vector position with the maximum of the ratios
    object_id=std::distance(ratio.begin(),std::max_element(ratio.begin(), ratio.end()));

    std::cerr<<"Ratio recognized object: "<<ratio[object_id]<<std::endl;
    return object_id;
}
<commit_msg>trying to figure out the cause of the assertion failed in algorithm2D -backup-<commit_after>#include "algorithm2D.h"

Algorithm2D::Algorithm2D()
{

    //Load the previously stored templates if there are any
    std::cerr<<"GET NUMBER OF TEMPLATES: "<<dataparser.getNumberTemplates()<<std::endl;
    if(dataparser.getNumberTemplates()>1)
    {
        std::cerr<<"1"<<std::endl;
        this->descriptors=dataparser.getTemplates();
        std::cerr<<"1"<<std::endl;
        std::cerr<<"descriptors size"<<descriptors.size()<<std::endl;

        alg2D.resize(descriptors.size());

        //Add the descriptors to each algorithm & train them
        for (unsigned int i =0; i<descriptors.size(); i++)
        {
            try
            {
                alg2D[i].add(this->descriptors[i]);
                alg2D[i].train();
            }
            catch (std::exception & e)
            {}
        }
        std::cerr<<"1"<<std::endl;

    }

    matched_object_id=-1;
    this->object_number=0;

}

void Algorithm2D::add_descriptors(const TFG::HandImageConstPtr & msg)
{

    //convert from ros image msg to opencv image
    cv_bridge::CvImagePtr cv_ptr;
    for (unsigned int i=0; i<msg->image.size(); i++)
    {
        try
        {
            cv_ptr = cv_bridge::toCvCopy(msg->image[i], sensor_msgs::image_encodings::MONO8);
        }
        catch (cv_bridge::Exception& e)
        {
            ROS_ERROR("cv_bridge exception: %s", e.what());
        }

        cv::Mat image_cv=cv_ptr->image.clone();

        //        ROS_ERROR("OBJECT NUMBER %d DESCRIPTORS SIZE %d", object_number, descriptors.size());

        //add the new view to the descriptors matrix
        image_cv.convertTo(image_cv,CV_32F);

        descriptors[this->object_number].push_back(image_cv);
    }
}

//REMEMBER TO CHANGE SET_NEW_OBJECT TO TRUE WHENEVER WE ARE LEARNING A NEW OBJECT!!!!!
void Algorithm2D::train2D()
{
    try{

        //add the descriptors vector to the 2D algorithm
        //        ROS_ERROR("OBJECT NUMBER %d DESCRIPTORS SIZE %d ALGORITHMS SIZE %d", object_number, descriptors.size(), alg2D.size());

//        alg2D[this->object_number].add(descriptors[this->object_number]);

        //train the 2D algorithm with the new view
//        alg2D[this->object_number].train();

    }
    catch (std::exception & e)
    {}

    //store template
    dataparser.save_template_2D(this->descriptors[this->object_number], this->object_number);

    //store algorithm
    dataparser.save_algorithm_2D(alg2D[this->object_number], this->object_number);

}

//void Algorithm2D::train3D ()
//{
//    //train 3D features

//    //store template

//    //store algorithm
//}

void Algorithm2D ::set_new_object(bool new_object)
{
    this->new_object=new_object;

    if(this->new_object)
    {
        descriptors.push_back(std::vector<cv::Mat> ());
        alg2D.push_back(cv::FlannBasedMatcher ());

        //        std::cerr<<"descriptors & alg2D size: "<<descriptors.size()<<" "<<alg2D.size()<<std::endl;
    }

    this->object_number=alg2D.size()-1;
}

int Algorithm2D :: match2D(const TFG::HandImageConstPtr & msg)
{
    cv_bridge::CvImagePtr cv_ptr;

    //resulting object id

    for (unsigned int i=0; i<msg->image.size(); i++)
    {
        //transform from ROS msg to OpenCV msg
        try
        {
            cv_ptr = cv_bridge::toCvCopy(msg->image[i], sensor_msgs::image_encodings::BGR8);
        }
        catch (cv_bridge::Exception& e)
        {
            ROS_ERROR("cv_bridge exception: %s", e.what());
        }

        //threshold used in the flann_comparison
        float  threshold=300;

        try{
            //compare FLANN
            matched_object_id=this->flann_comparison(cv_ptr->image, threshold);
        }
        catch(std::exception & e)
        {}
    }

    return matched_object_id;
}

int Algorithm2D:: flann_comparison (cv::Mat  &desc1,float threshold)
{
    //vector that will store the ratios of similarity between the new image and the templates
    std::vector< float> ratio;
    //resize the vector
    ratio.resize(descriptors.size());

    //vector to store the distances between descriptors
    std::vector<std::vector< cv::DMatch > >matches;
    //resize the vector
    matches.resize(descriptors.size());

    //Store good matches, using the threshold ratio
    std::vector<std::vector< cv::DMatch > >good_matches;
    good_matches.resize(descriptors.size());

    //    std::cerr<<"In flann_comparison function, alg2d.size(): "<<alg2D.size()<<std::endl<<"descriptors.size(): "<<descriptors.size()<<std::endl<< "descriptors[object_number].size(): "<<descriptors[object_number].size()<<std::endl;

    //for each algorithm, match the new descriptors with the algorithm's information
    for (unsigned int object_number=0; object_number<descriptors.size(); object_number++)
    {
        desc1.convertTo(desc1, CV_32F);

        for (unsigned int j=0; j<descriptors[object_number].size(); j++)
        {
        //match each algorithm with the new cv::Mat and output the result in the matches vector
            std::cerr<<"desc1.type: "<<desc1.type()<<"descriptors[][].type: "<<descriptors[object_number][j].type()<<std::endl;
            //throws here the assertion!
            alg2D[object_number].match( desc1,descriptors[object_number][j], matches[object_number]);
            std::cerr<<"Iteration number "<<object_number<<std::endl;

        }

        //        std::cerr<<"Number of matches: "<<matches[object_number].size()<<std::endl;

        //decide which are the good matches (i.e. matches whose distance is lower than the threshold) of the above matches
        for( unsigned int i = 0; i < matches[object_number].size(); i++ )
        {
            if( matches[object_number][i].distance < threshold )
                good_matches[object_number].push_back( matches[object_number][i]);
        }

        //cout <<good_matches.size()<<endl<<matches.size()<<endl;

        //The ratio is defined as the number of good_matches  over the number of total matches
        //This ratio is defined for each algorithm. Since each algorithm will be used for each object, this will be the similarity with this object

        if (matches[object_number].size()>0)
        {
            ratio[object_number]=(float)(good_matches[object_number].size()/matches[object_number].size());
        }

        else if (matches[object_number].size()<=0)
        {
            ratio[object_number]=-1;
        }

        std::cerr<<"Comparison with object "<<object_number<<" ratio: "<<ratio[object_number]<<std::endl;

    }
    int object_id;

    //Obtain the object ID as the vector position with the maximum of the ratios
    object_id=std::distance(ratio.begin(),std::max_element(ratio.begin(), ratio.end()));

    std::cerr<<"Ratio recognized object: "<<ratio[object_id]<<std::endl;
    return object_id;
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include "TConfig.h"
#include "TLogging.h"
#include "TFileUtil.h"

namespace tyr { namespace basic {

AppendFile::AppendFile(StringArg fname)
  : stream_(fopen(fname.c_str(), "ae"))
  , written_bytes_(0) {
  assert(nullptr != stream_);
  setvbuf(stream_, buffer_, _IOFBF, sizeof(buffer_));
}

AppendFile::~AppendFile(void) {
  fclose(stream_);
}

void AppendFile::append(const char* buf, size_t len) {
  size_t n = write(buf, len);
  size_t remain = len - n;
  while (remain > 0) {
    size_t x = write(buf + n, remain);
    if (0 == x) {
      int err = ferror(stream_);
      if (0 != err)
        fprintf(stderr, "AppendFile::append - faield %s\n", strerror_tl(err));
      break;
    }
    n += x;
    remain = len - n;
  }

  written_bytes_ += len;
}

void AppendFile::flush(void) {
  fflush(stream_);
}

size_t AppendFile::write(const char* buf, size_t len) {
#if defined(TYR_WINDOWS)
  return _fwrite_nolock(buf, 1, len, stream_);
#else
  return fwrite_unlocked(buf, 1, len, stream_);
#endif
}

}}
<commit_msg>:apple: fix(basic): fixed no fwrite_unlocked functions for macOS<commit_after>// Copyright (c) 2016 ASMlover. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include "TConfig.h"
#include "TLogging.h"
#include "TFileUtil.h"

namespace tyr { namespace basic {

AppendFile::AppendFile(StringArg fname)
  : stream_(fopen(fname.c_str(), "ae"))
  , written_bytes_(0) {
  assert(nullptr != stream_);
  setvbuf(stream_, buffer_, _IOFBF, sizeof(buffer_));
}

AppendFile::~AppendFile(void) {
  fclose(stream_);
}

void AppendFile::append(const char* buf, size_t len) {
  size_t n = write(buf, len);
  size_t remain = len - n;
  while (remain > 0) {
    size_t x = write(buf + n, remain);
    if (0 == x) {
      int err = ferror(stream_);
      if (0 != err)
        fprintf(stderr, "AppendFile::append - faield %s\n", strerror_tl(err));
      break;
    }
    n += x;
    remain = len - n;
  }

  written_bytes_ += len;
}

void AppendFile::flush(void) {
  fflush(stream_);
}

size_t AppendFile::write(const char* buf, size_t len) {
#if defined(TYR_WINDOWS)
  return _fwrite_nolock(buf, 1, len, stream_);
#elif defined(TYR_DARWIN)
  return fwrite(buf, 1, len, stream_);
#else
  return fwrite_unlocked(buf, 1, len, stream_);
#endif
}

}}
<|endoftext|>


<commit_before>#include "projectpanel.h"
#include "ui_projectpanel.h"

#include <QAction>
#include <QDesktopWidget>
#include <QFileDialog>
#include <QMenu>
#include <QVariant>

#include "entity/entity.h"
#include "project/projecttreeobjectitem.h"
#include "script/scriptfile.h"
#include "world/tileworld.h"
#include "world/tileset.h"

#include "newentitydialog.h"
#include "newtilesetdialog.h"
#include "mainwindow.h"
#include "projectmodel.h"
#include "projectsettingsdialog.h"
#include "project.h"
#include "tileviewwindow.h"

ProjectPanel::ProjectPanel(MainWindow& mainwindow) :
    DockPanel(mainwindow),
    ui(new Ui::ProjectPanel),
    mpProject(nullptr),
    mpProjectModel(nullptr)
{
    ui->setupUi(this);

    mpProjectModel = new ProjectModel();
    ui->treeProject->setModel(mpProjectModel);

    connect(&mainwindow, SIGNAL(projectChanged(Project*)), SLOT(on_projectChanged(Project*)));
    connect(ui->actionAdd_Existing, SIGNAL(triggered()), SLOT(on_addExisting_triggered()));
    connect(ui->actionSettings, SIGNAL(triggered()), SLOT(on_settings_triggered()));
}

ProjectPanel::~ProjectPanel()
{
    delete ui;
}

// - Overrides

void ProjectPanel::contextMenuEvent(QContextMenuEvent *event)
{
    if ( mpProject )
    {
        QMenu menu(this);
        menu.addAction(ui->actionAdd_Existing);
        menu.addAction(ui->actionSettings);
        menu.exec(event->globalPos());
    }
}

// - Notifications

void ProjectPanel::worldActivated(TileWorld* /* pworld */)
{
    // not really relevant here
}

// - Slots

void ProjectPanel::on_addExisting_triggered()
{
    QString file = QFileDialog::getOpenFileName(this, tr("Select Existing File"), mpProject->getScriptPath(), tr("Script files (*.as)"));
    if  ( file.length() > 0 )
    {
        QFileInfo info(file);

        QString resourcepath = QString("scripts") + QDir::separator() + mpProject->getName() + QDir::separator() + info.fileName();
        QString filepath = mpProject->getBasePath() + QDir::separator() + resourcepath;
        ScriptFile* pscript = new ScriptFile(filepath);
        pscript->setResourceName(resourcepath);

        mpProject->addScript(pscript);
    }
}

void ProjectPanel::on_settings_triggered()
{
    ProjectSettingsDialog dlg(QApplication::desktop());
    dlg.setModal(true);
    dlg.exec();
}

void ProjectPanel::on_projectChanged(Project *pproject)
{
    if ( mpProject != pproject )
    {
        mpProject = pproject;

        mpProjectModel->setProject(pproject);
    }
}

void ProjectPanel::on_treeProject_clicked(const QModelIndex& index)
{
    QVariant data = mpProjectModel->resourceData(index);
    if ( data.isValid() && data.canConvert<ResourceHandle>() )
    {
        ResourceHandle handle = data.value<ResourceHandle>();
        if ( handle->getType() == Resource::eObject )
        {
            getMainWindow().setSelectedEntity(&static_cast<Entity&>(*handle));
        }
    }
}

void ProjectPanel::on_treeProject_activated(const QModelIndex &index)
{
    QVariant data = mpProjectModel->resourceData(index);
    if ( !data.isValid() )
        return;

    if ( data.canConvert<ResourceHandle>() )
    {
        ResourceHandle handle = data.value<ResourceHandle>();
        switch ( handle->getType() )
        {
            case Resource::eObject:
                NewEntityDialog::edit(static_cast<Entity&>(*handle));
                break;
            case Resource::eWorld:
                getMainWindow().showWorld(static_cast<TileWorld&>(*handle));
                break;
            case Resource::eScript:
                getMainWindow().showScript(static_cast<ScriptFile&>(*handle));
                break;
            case Resource::eTileSet:
                NewTileSetDialog::edit(static_cast<TileSet&>(*handle));
                break;
        }
    }
}
<commit_msg>Build fix<commit_after>#include "projectpanel.h"
#include "ui_projectpanel.h"

#include <QAction>
#include <QDesktopWidget>
#include <QFileDialog>
#include <QMenu>
#include <QVariant>
#include <QContextMenuEvent>

#include "entity/entity.h"
#include "project/projecttreeobjectitem.h"
#include "script/scriptfile.h"
#include "world/tileworld.h"
#include "world/tileset.h"

#include "newentitydialog.h"
#include "newtilesetdialog.h"
#include "mainwindow.h"
#include "projectmodel.h"
#include "projectsettingsdialog.h"
#include "project.h"
#include "tileviewwindow.h"

ProjectPanel::ProjectPanel(MainWindow& mainwindow) :
    DockPanel(mainwindow),
    ui(new Ui::ProjectPanel),
    mpProject(nullptr),
    mpProjectModel(nullptr)
{
    ui->setupUi(this);

    mpProjectModel = new ProjectModel();
    ui->treeProject->setModel(mpProjectModel);

    connect(&mainwindow, SIGNAL(projectChanged(Project*)), SLOT(on_projectChanged(Project*)));
    connect(ui->actionAdd_Existing, SIGNAL(triggered()), SLOT(on_addExisting_triggered()));
    connect(ui->actionSettings, SIGNAL(triggered()), SLOT(on_settings_triggered()));
}

ProjectPanel::~ProjectPanel()
{
    delete ui;
}

// - Overrides

void ProjectPanel::contextMenuEvent(QContextMenuEvent *event)
{
    if ( mpProject )
    {
        QMenu menu(this);
        menu.addAction(ui->actionAdd_Existing);
        menu.addAction(ui->actionSettings);
        menu.exec(event->globalPos());
    }
}

// - Notifications

void ProjectPanel::worldActivated(TileWorld* /* pworld */)
{
    // not really relevant here
}

// - Slots

void ProjectPanel::on_addExisting_triggered()
{
    QString file = QFileDialog::getOpenFileName(this, tr("Select Existing File"), mpProject->getScriptPath(), tr("Script files (*.as)"));
    if  ( file.length() > 0 )
    {
        QFileInfo info(file);

        QString resourcepath = QString("scripts") + QDir::separator() + mpProject->getName() + QDir::separator() + info.fileName();
        QString filepath = mpProject->getBasePath() + QDir::separator() + resourcepath;
        ScriptFile* pscript = new ScriptFile(filepath);
        pscript->setResourceName(resourcepath);

        mpProject->addScript(pscript);
    }
}

void ProjectPanel::on_settings_triggered()
{
    ProjectSettingsDialog dlg(QApplication::desktop());
    dlg.setModal(true);
    dlg.exec();
}

void ProjectPanel::on_projectChanged(Project *pproject)
{
    if ( mpProject != pproject )
    {
        mpProject = pproject;

        mpProjectModel->setProject(pproject);
    }
}

void ProjectPanel::on_treeProject_clicked(const QModelIndex& index)
{
    QVariant data = mpProjectModel->resourceData(index);
    if ( data.isValid() && data.canConvert<ResourceHandle>() )
    {
        ResourceHandle handle = data.value<ResourceHandle>();
        if ( handle->getType() == Resource::eObject )
        {
            getMainWindow().setSelectedEntity(&static_cast<Entity&>(*handle));
        }
    }
}

void ProjectPanel::on_treeProject_activated(const QModelIndex &index)
{
    QVariant data = mpProjectModel->resourceData(index);
    if ( !data.isValid() )
        return;

    if ( data.canConvert<ResourceHandle>() )
    {
        ResourceHandle handle = data.value<ResourceHandle>();
        switch ( handle->getType() )
        {
            case Resource::eObject:
                NewEntityDialog::edit(static_cast<Entity&>(*handle));
                break;
            case Resource::eWorld:
                getMainWindow().showWorld(static_cast<TileWorld&>(*handle));
                break;
            case Resource::eScript:
                getMainWindow().showScript(static_cast<ScriptFile&>(*handle));
                break;
            case Resource::eTileSet:
                NewTileSetDialog::edit(static_cast<TileSet&>(*handle));
                break;
        }
    }
}
<|endoftext|>