<commit_before>// Copyright 2015-2020 Elviss Strazdins. All rights reserved.

#include <iterator>
#include <stdexcept>
#include <string>
#include "MtlLoader.hpp"
#include "Bundle.hpp"
#include "Cache.hpp"
#include "../core/Engine.hpp"

namespace ouzel::assets
{
    namespace
    {
        constexpr auto isWhitespace(std::byte c)
        {
            return static_cast<char>(c) == ' ' ||
                static_cast<char>(c) == '\t';
        }

        constexpr auto isNewline(std::byte c)
        {
            return static_cast<char>(c) == '\r' ||
                static_cast<char>(c) == '\n';
        }

        constexpr auto isControlChar(std::byte c)
        {
            return static_cast<std::uint8_t>(c) <= 0x1F;
        }

        void skipWhitespaces(std::vector<std::byte>::const_iterator& iterator,
                             std::vector<std::byte>::const_iterator end)
        {
            while (iterator != end)
                if (isWhitespace(*iterator))
                    ++iterator;
                else
                    break;
        }

        void skipLine(std::vector<std::byte>::const_iterator& iterator,
                      std::vector<std::byte>::const_iterator end)
        {
            while (iterator != end)
            {
                if (isNewline(*iterator))
                {
                    ++iterator;
                    break;
                }

                ++iterator;
            }
        }

        std::string parseString(std::vector<std::byte>::const_iterator& iterator,
                                std::vector<std::byte>::const_iterator end)
        {
            std::string result;

            while (iterator != end && !isControlChar(*iterator) && !isWhitespace(*iterator))
            {
                result.push_back(static_cast<char>(*iterator));
                ++iterator;
            }

            if (result.empty())
                throw std::runtime_error("Invalid string");

            return result;
        }

        float parseFloat(std::vector<std::byte>::const_iterator& iterator,
                         std::vector<std::byte>::const_iterator end)
        {
            std::string value;
            std::uint32_t length = 1;

            if (iterator != end &&
                static_cast<char>(*iterator) == '-')
            {
                value.push_back(static_cast<char>(*iterator));
                ++length;
                ++iterator;
            }

            while (iterator != end &&
                   static_cast<char>(*iterator) >= '0' &&
                   static_cast<char>(*iterator) <= '9')
            {
                value.push_back(static_cast<char>(*iterator));

                ++iterator;
            }

            if (iterator != end &&
                static_cast<char>(*iterator) == '.')
            {
                value.push_back(static_cast<char>(*iterator));
                ++length;
                ++iterator;

                while (iterator != end &&
                       static_cast<char>(*iterator) >= '0' &&
                       static_cast<char>(*iterator) <= '9')
                {
                    value.push_back(static_cast<char>(*iterator));

                    ++iterator;
                }
            }

            // parse exponent
            if (iterator != end &&
                (static_cast<char>(*iterator) == 'e' ||
                 static_cast<char>(*iterator) == 'E'))
            {
                value.push_back(static_cast<char>(*iterator));
                if (++iterator == end)
                    throw std::runtime_error("Invalid exponent");

                if (static_cast<char>(*iterator) == '+' ||
                    static_cast<char>(*iterator) == '-')
                    value.push_back(static_cast<char>(*iterator++));

                if (iterator == end ||
                    static_cast<char>(*iterator) < '0' ||
                    static_cast<char>(*iterator) > '9')
                    throw std::runtime_error("Invalid exponent");

                while (iterator != end &&
                       static_cast<char>(*iterator) >= '0' &&
                       static_cast<char>(*iterator) <= '9')
                {
                    value.push_back(static_cast<char>(*iterator));
                    ++iterator;
                }
            }

            if (value.length() < length) return false;

            return std::stof(value);
        }
    }

    MtlLoader::MtlLoader(Cache& initCache):
        Loader(initCache, Type::material)
    {
    }

    bool MtlLoader::loadAsset(Bundle& bundle,
                              const std::string& name,
                              const std::vector<std::byte>& data,
                              bool mipmaps)
    {
        std::string materialName = name;
        std::shared_ptr<graphics::Texture> diffuseTexture;
        std::shared_ptr<graphics::Texture> ambientTexture;
        Color diffuseColor = Color::white();
        float opacity = 1.0F;

        std::uint32_t materialCount = 0;

        auto iterator = data.cbegin();

        std::string keyword;
        std::string value;

        while (iterator != data.end())
        {
            if (isNewline(*iterator))
            {
                // skip empty lines
                ++iterator;
            }
            else if (static_cast<char>(*iterator) == '#')
            {
                // skip the comment
                skipLine(iterator, data.end());
            }
            else
            {
                skipWhitespaces(iterator, data.end());
                keyword = parseString(iterator, data.end());

                if (keyword == "newmtl")
                {
                    if (materialCount)
                    {
                        auto material = std::make_unique<graphics::Material>();
                        material->blendState = cache.getBlendState(blendAlpha);
                        material->shader = diffuseTexture ? cache.getShader(shaderTexture) : cache.getShader(shaderColor);
                        material->textures[0] = diffuseTexture;
                        material->textures[1] = ambientTexture;
                        material->diffuseColor = diffuseColor;
                        material->opacity = opacity;
                        material->cullMode = graphics::CullMode::back;

                        bundle.setMaterial(materialName, std::move(material));
                    }

                    skipWhitespaces(iterator, data.end());
                    materialName = parseString(iterator, data.end());

                    skipLine(iterator, data.end());

                    diffuseTexture.reset();
                    ambientTexture.reset();
                    diffuseColor = Color::white();
                    opacity = 1.0F;
                }
                else if (keyword == "map_Ka") // ambient texture map
                {
                    skipWhitespaces(iterator, data.end());
                    value = parseString(iterator, data.end());

                    skipLine(iterator, data.end());

                    ambientTexture = cache.getTexture(value);
                }
                else if (keyword == "map_Kd") // diffuse texture map
                {
                    skipWhitespaces(iterator, data.end());
                    value = parseString(iterator, data.end());

                    skipLine(iterator, data.end());

                    diffuseTexture = cache.getTexture(value);

                    if (!diffuseTexture)
                    {
                        bundle.loadAsset(Type::image, value, value, mipmaps);
                        diffuseTexture = cache.getTexture(value);
                    }
                }
                else if (keyword == "Ka") // ambient color
                    skipLine(iterator, data.end());
                else if (keyword == "Kd") // diffuse color
                {
                    float color[4];

                    skipWhitespaces(iterator, data.end());
                    color[0] = parseFloat(iterator, data.end());
                    skipWhitespaces(iterator, data.end());
                    color[1] = parseFloat(iterator, data.end());
                    skipWhitespaces(iterator, data.end());
                    color[2] = parseFloat(iterator, data.end());

                    skipLine(iterator, data.end());

                    color[3] = 1.0F;
                    diffuseColor = Color(color);
                }
                else if (keyword == "Ks") // specular color
                    skipLine(iterator, data.end());
                else if (keyword == "Ke") // emissive color
                    skipLine(iterator, data.end());
                else if (keyword == "d") // opacity
                {
                    skipWhitespaces(iterator, data.end());
                    opacity = parseFloat(iterator, data.end());

                    skipLine(iterator, data.end());
                }
                else if (keyword == "Tr") // transparency
                {
                    float transparency;

                    skipWhitespaces(iterator, data.end());
                    transparency = parseFloat(iterator, data.end());

                    skipLine(iterator, data.end());

                    // d = 1 - Tr
                    opacity = 1.0F - transparency;
                }
                else
                {
                    // skip all unknown commands
                    skipLine(iterator, data.end());
                }

                if (!materialCount) ++materialCount; // if we got at least one attribute, we have an material
            }
        }

        if (materialCount)
        {
            auto material = std::make_unique<graphics::Material>();
            material->blendState = cache.getBlendState(blendAlpha);
            material->shader = cache.getShader(shaderTexture);
            material->textures[0] = diffuseTexture;
            material->textures[1] = ambientTexture;
            material->diffuseColor = diffuseColor;
            material->opacity = opacity;
            material->cullMode = graphics::CullMode::back;

            bundle.setMaterial(materialName, std::move(material));
        }

        return true;
    }
}
<commit_msg>Make transparency const<commit_after>// Copyright 2015-2020 Elviss Strazdins. All rights reserved.

#include <iterator>
#include <stdexcept>
#include <string>
#include "MtlLoader.hpp"
#include "Bundle.hpp"
#include "Cache.hpp"
#include "../core/Engine.hpp"

namespace ouzel::assets
{
    namespace
    {
        constexpr auto isWhitespace(std::byte c)
        {
            return static_cast<char>(c) == ' ' ||
                static_cast<char>(c) == '\t';
        }

        constexpr auto isNewline(std::byte c)
        {
            return static_cast<char>(c) == '\r' ||
                static_cast<char>(c) == '\n';
        }

        constexpr auto isControlChar(std::byte c)
        {
            return static_cast<std::uint8_t>(c) <= 0x1F;
        }

        void skipWhitespaces(std::vector<std::byte>::const_iterator& iterator,
                             std::vector<std::byte>::const_iterator end)
        {
            while (iterator != end)
                if (isWhitespace(*iterator))
                    ++iterator;
                else
                    break;
        }

        void skipLine(std::vector<std::byte>::const_iterator& iterator,
                      std::vector<std::byte>::const_iterator end)
        {
            while (iterator != end)
            {
                if (isNewline(*iterator))
                {
                    ++iterator;
                    break;
                }

                ++iterator;
            }
        }

        std::string parseString(std::vector<std::byte>::const_iterator& iterator,
                                std::vector<std::byte>::const_iterator end)
        {
            std::string result;

            while (iterator != end && !isControlChar(*iterator) && !isWhitespace(*iterator))
            {
                result.push_back(static_cast<char>(*iterator));
                ++iterator;
            }

            if (result.empty())
                throw std::runtime_error("Invalid string");

            return result;
        }

        float parseFloat(std::vector<std::byte>::const_iterator& iterator,
                         std::vector<std::byte>::const_iterator end)
        {
            std::string value;
            std::uint32_t length = 1;

            if (iterator != end &&
                static_cast<char>(*iterator) == '-')
            {
                value.push_back(static_cast<char>(*iterator));
                ++length;
                ++iterator;
            }

            while (iterator != end &&
                   static_cast<char>(*iterator) >= '0' &&
                   static_cast<char>(*iterator) <= '9')
            {
                value.push_back(static_cast<char>(*iterator));

                ++iterator;
            }

            if (iterator != end &&
                static_cast<char>(*iterator) == '.')
            {
                value.push_back(static_cast<char>(*iterator));
                ++length;
                ++iterator;

                while (iterator != end &&
                       static_cast<char>(*iterator) >= '0' &&
                       static_cast<char>(*iterator) <= '9')
                {
                    value.push_back(static_cast<char>(*iterator));

                    ++iterator;
                }
            }

            // parse exponent
            if (iterator != end &&
                (static_cast<char>(*iterator) == 'e' ||
                 static_cast<char>(*iterator) == 'E'))
            {
                value.push_back(static_cast<char>(*iterator));
                if (++iterator == end)
                    throw std::runtime_error("Invalid exponent");

                if (static_cast<char>(*iterator) == '+' ||
                    static_cast<char>(*iterator) == '-')
                    value.push_back(static_cast<char>(*iterator++));

                if (iterator == end ||
                    static_cast<char>(*iterator) < '0' ||
                    static_cast<char>(*iterator) > '9')
                    throw std::runtime_error("Invalid exponent");

                while (iterator != end &&
                       static_cast<char>(*iterator) >= '0' &&
                       static_cast<char>(*iterator) <= '9')
                {
                    value.push_back(static_cast<char>(*iterator));
                    ++iterator;
                }
            }

            if (value.length() < length) return false;

            return std::stof(value);
        }
    }

    MtlLoader::MtlLoader(Cache& initCache):
        Loader(initCache, Type::material)
    {
    }

    bool MtlLoader::loadAsset(Bundle& bundle,
                              const std::string& name,
                              const std::vector<std::byte>& data,
                              bool mipmaps)
    {
        std::string materialName = name;
        std::shared_ptr<graphics::Texture> diffuseTexture;
        std::shared_ptr<graphics::Texture> ambientTexture;
        Color diffuseColor = Color::white();
        float opacity = 1.0F;

        std::uint32_t materialCount = 0;

        auto iterator = data.cbegin();

        std::string keyword;
        std::string value;

        while (iterator != data.end())
        {
            if (isNewline(*iterator))
            {
                // skip empty lines
                ++iterator;
            }
            else if (static_cast<char>(*iterator) == '#')
            {
                // skip the comment
                skipLine(iterator, data.end());
            }
            else
            {
                skipWhitespaces(iterator, data.end());
                keyword = parseString(iterator, data.end());

                if (keyword == "newmtl")
                {
                    if (materialCount)
                    {
                        auto material = std::make_unique<graphics::Material>();
                        material->blendState = cache.getBlendState(blendAlpha);
                        material->shader = diffuseTexture ? cache.getShader(shaderTexture) : cache.getShader(shaderColor);
                        material->textures[0] = diffuseTexture;
                        material->textures[1] = ambientTexture;
                        material->diffuseColor = diffuseColor;
                        material->opacity = opacity;
                        material->cullMode = graphics::CullMode::back;

                        bundle.setMaterial(materialName, std::move(material));
                    }

                    skipWhitespaces(iterator, data.end());
                    materialName = parseString(iterator, data.end());

                    skipLine(iterator, data.end());

                    diffuseTexture.reset();
                    ambientTexture.reset();
                    diffuseColor = Color::white();
                    opacity = 1.0F;
                }
                else if (keyword == "map_Ka") // ambient texture map
                {
                    skipWhitespaces(iterator, data.end());
                    value = parseString(iterator, data.end());

                    skipLine(iterator, data.end());

                    ambientTexture = cache.getTexture(value);
                }
                else if (keyword == "map_Kd") // diffuse texture map
                {
                    skipWhitespaces(iterator, data.end());
                    value = parseString(iterator, data.end());

                    skipLine(iterator, data.end());

                    diffuseTexture = cache.getTexture(value);

                    if (!diffuseTexture)
                    {
                        bundle.loadAsset(Type::image, value, value, mipmaps);
                        diffuseTexture = cache.getTexture(value);
                    }
                }
                else if (keyword == "Ka") // ambient color
                    skipLine(iterator, data.end());
                else if (keyword == "Kd") // diffuse color
                {
                    float color[4];

                    skipWhitespaces(iterator, data.end());
                    color[0] = parseFloat(iterator, data.end());
                    skipWhitespaces(iterator, data.end());
                    color[1] = parseFloat(iterator, data.end());
                    skipWhitespaces(iterator, data.end());
                    color[2] = parseFloat(iterator, data.end());

                    skipLine(iterator, data.end());

                    color[3] = 1.0F;
                    diffuseColor = Color(color);
                }
                else if (keyword == "Ks") // specular color
                    skipLine(iterator, data.end());
                else if (keyword == "Ke") // emissive color
                    skipLine(iterator, data.end());
                else if (keyword == "d") // opacity
                {
                    skipWhitespaces(iterator, data.end());
                    opacity = parseFloat(iterator, data.end());

                    skipLine(iterator, data.end());
                }
                else if (keyword == "Tr") // transparency
                {
                    skipWhitespaces(iterator, data.end());
                    const float transparency = parseFloat(iterator, data.end());

                    skipLine(iterator, data.end());

                    // d = 1 - Tr
                    opacity = 1.0F - transparency;
                }
                else
                {
                    // skip all unknown commands
                    skipLine(iterator, data.end());
                }

                if (!materialCount) ++materialCount; // if we got at least one attribute, we have an material
            }
        }

        if (materialCount)
        {
            auto material = std::make_unique<graphics::Material>();
            material->blendState = cache.getBlendState(blendAlpha);
            material->shader = cache.getShader(shaderTexture);
            material->textures[0] = diffuseTexture;
            material->textures[1] = ambientTexture;
            material->diffuseColor = diffuseColor;
            material->opacity = opacity;
            material->cullMode = graphics::CullMode::back;

            bundle.setMaterial(materialName, std::move(material));
        }

        return true;
    }
}
<|endoftext|>


<commit_before>/* This file is part of VoltDB.
 * Copyright (C) 2008-2013 VoltDB Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "storage/CopyOnWriteContext.h"
#include "storage/temptable.h"
#include "storage/tablefactory.h"
#include "storage/CopyOnWriteIterator.h"
#include "storage/tableiterator.h"
#include "common/FatalException.hpp"
#include <algorithm>
#include <cassert>

namespace voltdb {

CopyOnWriteContext::CopyOnWriteContext(PersistentTable *table, TupleSerializer *serializer, int32_t partitionId) :
             m_table(table),
             m_backedUpTuples(TableFactory::getCopiedTempTable(table->databaseId(),
                                                               "COW of " + table->name(),
                                                               table, NULL)),
             m_serializer(serializer), m_pool(2097152, 320), m_blocks(m_table->m_data),
             m_iterator(new CopyOnWriteIterator(table, m_blocks.begin(), m_blocks.end())),
             m_maxTupleLength(serializer->getMaxSerializedTupleSize(table->schema())),
             m_tuple(table->schema()), m_finishedTableScan(false), m_partitionId(partitionId),
             m_tuplesSerialized(0),
             m_expectedTupleCount(static_cast<int32_t>(table->activeTupleCount())) {}

bool CopyOnWriteContext::serializeMore(ReferenceSerializeOutput *out) {
    out->writeInt(m_partitionId);
    int rowsSerialized = 0;
    const std::size_t rowCountPosition = out->reserveBytes(4);

    TableTuple tuple(m_table->schema());
    if (out->remaining() < (m_maxTupleLength + sizeof(int32_t))) {
        throwFatalException("Serialize more should never be called "
                "a 2nd time after return indicating there is no more data");
//        out->writeInt(0);
//        assert(false);
//        return false;
    }

    std::size_t bytesSerialized = 0;
    while (out->remaining() >= (m_maxTupleLength + sizeof(int32_t))) {
        const bool hadMore = m_iterator->next(tuple);

        /**
         * After this finishes scanning the persistent table switch to scanning
         * the temp table with the tuples that were backed up
         */
        if (!hadMore) {
            if (m_finishedTableScan) {
                out->writeIntAt( rowCountPosition, rowsSerialized);
                if (m_tuplesSerialized != m_expectedTupleCount) {
                    throwFatalException(
                            "Expected %d rows but only found %d rows while serializing snapshot",
                            m_expectedTupleCount, m_tuplesSerialized);
                }
                return false;
            } else {
                m_finishedTableScan = true;
                m_iterator.reset(m_backedUpTuples.get()->makeIterator());
                continue;
            }
        }

        const std::size_t tupleStartPosition = out->position();
        m_serializer->serializeTo( tuple, out);
        const std::size_t tupleEndPosition = out->position();
        m_tuplesSerialized++;
        rowsSerialized++;

        /*
         * If this is the table scan, check to see if the tuple is pending delete
         * and return the tuple if it is
         */
        if (!m_finishedTableScan && tuple.isPendingDelete()) {
            assert(!tuple.isPendingDeleteOnUndoRelease());
            if (m_table->m_schema->getUninlinedObjectColumnCount() != 0)
            {
                m_table->decreaseStringMemCount(tuple.getNonInlinedMemorySize());
            }
            tuple.setPendingDeleteFalse();
            tuple.freeObjectColumns();
            CopyOnWriteIterator *iter = static_cast<CopyOnWriteIterator*>(m_iterator.get());
            //Save the extra lookup if possible
            m_table->deleteTupleStorage(tuple, iter->m_currentBlock);
        }

        // If we have serialized more than 512Kb of tuple data, stop for a while
        bytesSerialized += tupleEndPosition - tupleStartPosition;
        if (bytesSerialized >= 1024 * 512) {
            break;
        }
    }
    /*
     * Number of rows serialized is not known until the end. Written at the end so it
     * can be included in the CRC. It will be moved back to the front
     * to match the table serialization format when chunk is read later.
     */
    out->writeIntAt( rowCountPosition, rowsSerialized);
    return true;
}

bool CopyOnWriteContext::canSafelyFreeTuple(TableTuple tuple) {
    if (tuple.isDirty() || m_finishedTableScan) {
        return true;
    }

    /**
     * Find out which block the address is contained in. Lower bound returns the first entry
     * in the index >= the address. Unless the address happens to be equal then the block
     * we are looking for is probably the previous entry. Then check if the address fits
     * in the previous entry. If it doesn't then the block is something new.
     */
    char *address = tuple.address();
    TBMapI i =
                            m_blocks.lower_bound(address);
    if (i == m_blocks.end() && m_blocks.empty()) {
        return true;
    }
    if (i == m_blocks.end()) {
        i--;
        if (i.key() + m_table->m_tableAllocationSize < address) {
            return true;
        }
        //OK it is in the very last block
    } else {
        if (i.key() != address) {
            i--;
            if (i.key() + m_table->m_tableAllocationSize < address) {
                return true;
            }
            //OK... this is in this particular block
        }
    }

    const char *blockStartAddress = i.key();

    /**
     * Now check where this is relative to the COWIterator.
     */
    CopyOnWriteIterator *iter = reinterpret_cast<CopyOnWriteIterator*>(m_iterator.get());
    return !iter->needToDirtyTuple(blockStartAddress, address);
}

void CopyOnWriteContext::markTupleDirty(TableTuple tuple, bool newTuple) {
    /**
     * If this an update or a delete of a tuple that is already dirty then no further action is
     * required.
     */
    if (!newTuple && tuple.isDirty()) {
        return;
    }

    /**
     * If the table has been scanned already there is no need to continue marking tuples dirty
     * If the tuple is dirty then it has already been backed up.
     */
    if (m_finishedTableScan) {
        tuple.setDirtyFalse();
        return;
    }

    /**
     * Find out which block the address is contained in.
     */
    char *address = tuple.address();
    TBMapI i =
                            m_blocks.lower_bound(address);
    if (i == m_blocks.end() && m_blocks.empty()) {
        tuple.setDirtyFalse();
        return;
    }
    if (i == m_blocks.end()) {
        i--;
        if (i.key() + m_table->m_tableAllocationSize < address) {
            tuple.setDirtyFalse();
            return;
        }
        //OK it is in the very last block
    } else {
        if (i.key() != address) {
            i--;
            if (i.key() + m_table->m_tableAllocationSize < address) {
                tuple.setDirtyFalse();
                return;
            }
            //OK... this is in this particular block
        }
    }

    const char *blockStartAddress = i.key();

    /**
     * Now check where this is relative to the COWIterator.
     */
    CopyOnWriteIterator *iter = reinterpret_cast<CopyOnWriteIterator*>(m_iterator.get());
    if (iter->needToDirtyTuple(blockStartAddress, address)) {
        tuple.setDirtyTrue();
        /**
         * Don't back up a newly introduced tuple, just mark it as dirty.
         */
        if (!newTuple) {
            m_backedUpTuples->insertTupleNonVirtualWithDeepCopy(tuple, &m_pool);
        }
    } else {
        tuple.setDirtyFalse();
        return;
    }
}

void CopyOnWriteContext::notifyBlockWasCompactedAway(TBPtr block) {
    assert(!m_finishedTableScan);
    CopyOnWriteIterator *iter = static_cast<CopyOnWriteIterator*>(m_iterator.get());
    if (iter->m_blockIterator != m_blocks.end()) {
        TBPtr nextBlock = iter->m_blockIterator.data();
        //The next block is the one that was compacted away
        //Need to move the iterator forward to skip it
        if (nextBlock == block) {
            iter->m_blockIterator++;

            //There is another block after the one that was compacted away
            if (iter->m_blockIterator != m_blocks.end()) {
                TBPtr newNextBlock = iter->m_blockIterator.data();
                m_blocks.erase(block->address());
                iter->m_blockIterator = m_blocks.find(newNextBlock->address());
                iter->m_end = m_blocks.end();
                assert(iter->m_blockIterator != m_blocks.end());
            } else {
                //No block after the one compacted away
                //set everything to end
                m_blocks.erase(block->address());
                iter->m_blockIterator = m_blocks.end();
                iter->m_end = m_blocks.end();
            }
        } else {
            //Some random block was compacted away. Remove it and regenerate the iterator
            m_blocks.erase(block->address());
            iter->m_blockIterator = m_blocks.find(nextBlock->address());
            iter->m_end = m_blocks.end();
            assert(iter->m_blockIterator != m_blocks.end());
        }
    }
}

CopyOnWriteContext::~CopyOnWriteContext() {}

}
<commit_msg>Change from fatal exception to log so people can still get their data out.<commit_after>/* This file is part of VoltDB.
 * Copyright (C) 2008-2013 VoltDB Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with VoltDB.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "storage/CopyOnWriteContext.h"
#include "storage/temptable.h"
#include "storage/tablefactory.h"
#include "storage/CopyOnWriteIterator.h"
#include "storage/tableiterator.h"
#include "common/FatalException.hpp"
#include "logging/LogManager.h"
#include <algorithm>
#include <cassert>

namespace voltdb {

CopyOnWriteContext::CopyOnWriteContext(PersistentTable *table, TupleSerializer *serializer, int32_t partitionId) :
             m_table(table),
             m_backedUpTuples(TableFactory::getCopiedTempTable(table->databaseId(),
                                                               "COW of " + table->name(),
                                                               table, NULL)),
             m_serializer(serializer), m_pool(2097152, 320), m_blocks(m_table->m_data),
             m_iterator(new CopyOnWriteIterator(table, m_blocks.begin(), m_blocks.end())),
             m_maxTupleLength(serializer->getMaxSerializedTupleSize(table->schema())),
             m_tuple(table->schema()), m_finishedTableScan(false), m_partitionId(partitionId),
             m_tuplesSerialized(0),
             m_expectedTupleCount(static_cast<int32_t>(table->activeTupleCount())) {}

bool CopyOnWriteContext::serializeMore(ReferenceSerializeOutput *out) {
    out->writeInt(m_partitionId);
    int rowsSerialized = 0;
    const std::size_t rowCountPosition = out->reserveBytes(4);

    TableTuple tuple(m_table->schema());
    if (out->remaining() < (m_maxTupleLength + sizeof(int32_t))) {
        throwFatalException("Serialize more should never be called "
                "a 2nd time after return indicating there is no more data");
//        out->writeInt(0);
//        assert(false);
//        return false;
    }

    std::size_t bytesSerialized = 0;
    while (out->remaining() >= (m_maxTupleLength + sizeof(int32_t))) {
        const bool hadMore = m_iterator->next(tuple);

        /**
         * After this finishes scanning the persistent table switch to scanning
         * the temp table with the tuples that were backed up
         */
        if (!hadMore) {
            if (m_finishedTableScan) {
                out->writeIntAt( rowCountPosition, rowsSerialized);
                if (m_tuplesSerialized != m_expectedTupleCount) {
                    char message[1024 * 16];
                    snprintf(message, 1024 * 16, "Expected %d rows but only found %d rows while serializing snapshot",
                            m_expectedTupleCount, m_tuplesSerialized);
                    LogManager::getThreadLogger(LOGGERID_HOST)->log(LOGLEVEL_ERROR, message);
                }
                return false;
            } else {
                m_finishedTableScan = true;
                m_iterator.reset(m_backedUpTuples.get()->makeIterator());
                continue;
            }
        }

        const std::size_t tupleStartPosition = out->position();
        m_serializer->serializeTo( tuple, out);
        const std::size_t tupleEndPosition = out->position();
        m_tuplesSerialized++;
        rowsSerialized++;

        /*
         * If this is the table scan, check to see if the tuple is pending delete
         * and return the tuple if it is
         */
        if (!m_finishedTableScan && tuple.isPendingDelete()) {
            assert(!tuple.isPendingDeleteOnUndoRelease());
            if (m_table->m_schema->getUninlinedObjectColumnCount() != 0)
            {
                m_table->decreaseStringMemCount(tuple.getNonInlinedMemorySize());
            }
            tuple.setPendingDeleteFalse();
            tuple.freeObjectColumns();
            CopyOnWriteIterator *iter = static_cast<CopyOnWriteIterator*>(m_iterator.get());
            //Save the extra lookup if possible
            m_table->deleteTupleStorage(tuple, iter->m_currentBlock);
        }

        // If we have serialized more than 512Kb of tuple data, stop for a while
        bytesSerialized += tupleEndPosition - tupleStartPosition;
        if (bytesSerialized >= 1024 * 512) {
            break;
        }
    }
    /*
     * Number of rows serialized is not known until the end. Written at the end so it
     * can be included in the CRC. It will be moved back to the front
     * to match the table serialization format when chunk is read later.
     */
    out->writeIntAt( rowCountPosition, rowsSerialized);
    return true;
}

bool CopyOnWriteContext::canSafelyFreeTuple(TableTuple tuple) {
    if (tuple.isDirty() || m_finishedTableScan) {
        return true;
    }

    /**
     * Find out which block the address is contained in. Lower bound returns the first entry
     * in the index >= the address. Unless the address happens to be equal then the block
     * we are looking for is probably the previous entry. Then check if the address fits
     * in the previous entry. If it doesn't then the block is something new.
     */
    char *address = tuple.address();
    TBMapI i =
                            m_blocks.lower_bound(address);
    if (i == m_blocks.end() && m_blocks.empty()) {
        return true;
    }
    if (i == m_blocks.end()) {
        i--;
        if (i.key() + m_table->m_tableAllocationSize < address) {
            return true;
        }
        //OK it is in the very last block
    } else {
        if (i.key() != address) {
            i--;
            if (i.key() + m_table->m_tableAllocationSize < address) {
                return true;
            }
            //OK... this is in this particular block
        }
    }

    const char *blockStartAddress = i.key();

    /**
     * Now check where this is relative to the COWIterator.
     */
    CopyOnWriteIterator *iter = reinterpret_cast<CopyOnWriteIterator*>(m_iterator.get());
    return !iter->needToDirtyTuple(blockStartAddress, address);
}

void CopyOnWriteContext::markTupleDirty(TableTuple tuple, bool newTuple) {
    /**
     * If this an update or a delete of a tuple that is already dirty then no further action is
     * required.
     */
    if (!newTuple && tuple.isDirty()) {
        return;
    }

    /**
     * If the table has been scanned already there is no need to continue marking tuples dirty
     * If the tuple is dirty then it has already been backed up.
     */
    if (m_finishedTableScan) {
        tuple.setDirtyFalse();
        return;
    }

    /**
     * Find out which block the address is contained in.
     */
    char *address = tuple.address();
    TBMapI i =
                            m_blocks.lower_bound(address);
    if (i == m_blocks.end() && m_blocks.empty()) {
        tuple.setDirtyFalse();
        return;
    }
    if (i == m_blocks.end()) {
        i--;
        if (i.key() + m_table->m_tableAllocationSize < address) {
            tuple.setDirtyFalse();
            return;
        }
        //OK it is in the very last block
    } else {
        if (i.key() != address) {
            i--;
            if (i.key() + m_table->m_tableAllocationSize < address) {
                tuple.setDirtyFalse();
                return;
            }
            //OK... this is in this particular block
        }
    }

    const char *blockStartAddress = i.key();

    /**
     * Now check where this is relative to the COWIterator.
     */
    CopyOnWriteIterator *iter = reinterpret_cast<CopyOnWriteIterator*>(m_iterator.get());
    if (iter->needToDirtyTuple(blockStartAddress, address)) {
        tuple.setDirtyTrue();
        /**
         * Don't back up a newly introduced tuple, just mark it as dirty.
         */
        if (!newTuple) {
            m_backedUpTuples->insertTupleNonVirtualWithDeepCopy(tuple, &m_pool);
        }
    } else {
        tuple.setDirtyFalse();
        return;
    }
}

void CopyOnWriteContext::notifyBlockWasCompactedAway(TBPtr block) {
    assert(!m_finishedTableScan);
    CopyOnWriteIterator *iter = static_cast<CopyOnWriteIterator*>(m_iterator.get());
    if (iter->m_blockIterator != m_blocks.end()) {
        TBPtr nextBlock = iter->m_blockIterator.data();
        //The next block is the one that was compacted away
        //Need to move the iterator forward to skip it
        if (nextBlock == block) {
            iter->m_blockIterator++;

            //There is another block after the one that was compacted away
            if (iter->m_blockIterator != m_blocks.end()) {
                TBPtr newNextBlock = iter->m_blockIterator.data();
                m_blocks.erase(block->address());
                iter->m_blockIterator = m_blocks.find(newNextBlock->address());
                iter->m_end = m_blocks.end();
                assert(iter->m_blockIterator != m_blocks.end());
            } else {
                //No block after the one compacted away
                //set everything to end
                m_blocks.erase(block->address());
                iter->m_blockIterator = m_blocks.end();
                iter->m_end = m_blocks.end();
            }
        } else {
            //Some random block was compacted away. Remove it and regenerate the iterator
            m_blocks.erase(block->address());
            iter->m_blockIterator = m_blocks.find(nextBlock->address());
            iter->m_end = m_blocks.end();
            assert(iter->m_blockIterator != m_blocks.end());
        }
    }
}

CopyOnWriteContext::~CopyOnWriteContext() {}

}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#include <libport/locale.hh>
#include <libport/format.hh>

#define FRAISE(Format, ...)                                             \
  throw std::runtime_error(libport::format(Format, ## __VA_ARGS__))

namespace libport
{
  std::string
  setlocale(const std::string& cat, boost::optional<std::string> loc)
  {
    int c = -1;
#define CASE(Name)                              \
    if (cat == #Name) c = Name
    CASE(LC_ALL);
    CASE(LC_COLLATE);
    CASE(LC_CTYPE);
// Courtesy of MS Windows.
#if defined LC_MESSAGES
    CASE(LC_MESSAGES);
#endif
    CASE(LC_MONETARY);
    CASE(LC_NUMERIC);
    CASE(LC_TIME);
#undef CASE
    if (c == -1)
      FRAISE("invalid category: %s", cat);
    if (const char *r = std::setlocale(c, loc ? loc.get().c_str() : 0))
      return r;
    if (!loc)
      FRAISE("cannot get locale %s", cat);
    else if (loc.get() == "")
      FRAISE("cannot set locale %s", cat);
    else
      FRAISE("cannot set locale %s to %s", cat, loc.get());
  }
}
<commit_msg>Libport.Locale: portability.<commit_after>/*
 * Copyright (C) 2011, Gostai S.A.S.
 *
 * This software is provided "as is" without warranty of any kind,
 * either expressed or implied, including but not limited to the
 * implied warranties of fitness for a particular purpose.
 *
 * See the LICENSE file for more information.
 */

#include <libport/locale.hh>
#include <libport/format.hh>

#define FRAISE(Format, ...)                                             \
  throw std::runtime_error(libport::format(Format, ## __VA_ARGS__))

namespace libport
{
  std::string
  setlocale(const std::string& cat, boost::optional<std::string> loc)
  {
    int c = -1;
#define CASE(Name)                              \
    if (cat == #Name) c = Name
    CASE(LC_ALL);
    CASE(LC_COLLATE);
    CASE(LC_CTYPE);
// Courtesy of MS Windows.
#if defined LC_MESSAGES
    CASE(LC_MESSAGES);
#endif
    CASE(LC_MONETARY);
    CASE(LC_NUMERIC);
    CASE(LC_TIME);
#undef CASE
    if (c == -1)
      FRAISE("invalid category: %s", cat);
    if (const char *r = ::setlocale(c, loc ? loc.get().c_str() : 0))
      return r;
    if (!loc)
      FRAISE("cannot get locale %s", cat);
    else if (loc.get() == "")
      FRAISE("cannot set locale %s", cat);
    else
      FRAISE("cannot set locale %s to %s", cat, loc.get());
  }
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include "DeviceLister.h"

#if WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)

#include "logging/Logger.h"
#include "utils/Charsets.h"

#include <memory>
#include <sstream>

#include <windows.h>

namespace medialibrary
{
namespace fs
{

std::vector<std::tuple<std::string, std::string, bool>> DeviceLister::devices() const
{
    TCHAR volumeName[MAX_PATH];
    auto handle = FindFirstVolume( volumeName, sizeof(volumeName) );
    if ( handle == INVALID_HANDLE_VALUE )
    {
        std::stringstream ss;
        ss << "Failed to list devices (error code" << GetLastError() << ')';
        throw std::runtime_error( ss.str() );
    }
    std::unique_ptr<typename std::remove_pointer<HANDLE>::type, decltype(&FindVolumeClose)>
            uh( handle, &FindVolumeClose );
    std::vector<std::tuple<std::string, std::string, bool>> res;
    for ( BOOL success =  TRUE; ; success = FindNextVolume( handle, volumeName, sizeof( volumeName ) ) )
    {
        if ( success == FALSE )
        {
            auto err = GetLastError();
            if ( err == ERROR_NO_MORE_FILES )
                break;
            std::stringstream ss;
            ss << "Failed to list devices (error code" << err << ')';
            throw std::runtime_error( ss.str() );
        }

        auto lastChar = wcslen( volumeName ) - 1;
        if ( volumeName[0] != L'\\' || volumeName[1] != L'\\' || volumeName[2] != L'?' ||
             volumeName[3] != L'\\' || volumeName[lastChar] != L'\\' )
            continue;

        TCHAR buffer[MAX_PATH + 1];
        DWORD buffLength = sizeof( buffer );

        if ( GetVolumePathNamesForVolumeName( volumeName, buffer, buffLength, &buffLength ) == 0 )
            continue;
        std::string mountpoint = std::string{ "file://" } + charset::FromWide( buffer ).get();

        // Filter out anything which isn't a removable or fixed drive. We don't care about network
        // drive here.
        auto type = GetDriveType( buffer );
        if ( type != DRIVE_REMOVABLE && type != DRIVE_FIXED )
            continue;

        std::string uuid =  charset::FromWide( volumeName ).get();

        LOG_INFO( "Discovered device ", uuid, "; mounted on ", mountpoint, "; removable: ",
                  type == DRIVE_REMOVABLE ? "yes" : "no" );
        res.emplace_back( std::make_tuple( uuid, mountpoint, type == DRIVE_REMOVABLE ) );
    }
    return res;
}

}
}

#endif
<commit_msg>win32: DeviceLister: Use toMrl instead of a manual conversion<commit_after>/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#if HAVE_CONFIG_H
# include "config.h"
#endif

#include "DeviceLister.h"

#if WINAPI_FAMILY_PARTITION (WINAPI_PARTITION_DESKTOP)

#include "logging/Logger.h"
#include "utils/Charsets.h"
#include "utils/Filename.h"

#include <memory>
#include <sstream>

#include <windows.h>

namespace medialibrary
{
namespace fs
{

std::vector<std::tuple<std::string, std::string, bool>> DeviceLister::devices() const
{
    TCHAR volumeName[MAX_PATH];
    auto handle = FindFirstVolume( volumeName, sizeof(volumeName) );
    if ( handle == INVALID_HANDLE_VALUE )
    {
        std::stringstream ss;
        ss << "Failed to list devices (error code" << GetLastError() << ')';
        throw std::runtime_error( ss.str() );
    }
    std::unique_ptr<typename std::remove_pointer<HANDLE>::type, decltype(&FindVolumeClose)>
            uh( handle, &FindVolumeClose );
    std::vector<std::tuple<std::string, std::string, bool>> res;
    for ( BOOL success =  TRUE; ; success = FindNextVolume( handle, volumeName, sizeof( volumeName ) ) )
    {
        if ( success == FALSE )
        {
            auto err = GetLastError();
            if ( err == ERROR_NO_MORE_FILES )
                break;
            std::stringstream ss;
            ss << "Failed to list devices (error code" << err << ')';
            throw std::runtime_error( ss.str() );
        }

        auto lastChar = wcslen( volumeName ) - 1;
        if ( volumeName[0] != L'\\' || volumeName[1] != L'\\' || volumeName[2] != L'?' ||
             volumeName[3] != L'\\' || volumeName[lastChar] != L'\\' )
            continue;

        TCHAR buffer[MAX_PATH + 1];
        DWORD buffLength = sizeof( buffer );

        if ( GetVolumePathNamesForVolumeName( volumeName, buffer, buffLength, &buffLength ) == 0 )
            continue;
        std::string mountpoint = charset::FromWide( buffer ).get();

        // Filter out anything which isn't a removable or fixed drive. We don't care about network
        // drive here.
        auto type = GetDriveType( buffer );
        if ( type != DRIVE_REMOVABLE && type != DRIVE_FIXED )
            continue;

        std::string uuid =  charset::FromWide( volumeName ).get();

        LOG_INFO( "Discovered device ", uuid, "; mounted on ", mountpoint, "; removable: ",
                  type == DRIVE_REMOVABLE ? "yes" : "no" );
        res.emplace_back( std::make_tuple( uuid, utils::file::toMrl( mountpoint ),
                                           type == DRIVE_REMOVABLE ) );
    }
    return res;
}

}
}

#endif
<|endoftext|>


<commit_before>/**
 * @file
 * String formatting code.
 * Much of this code was adapted from Python's string formatting
 * code, but the actual formatting of individual items is done
 * by constructing printf formats and using them. Ugly, but easy.
 * There may be some dodgy assumptions about lengths here.
 */

#include "angort.h"
#include <ctype.h>
#define max(a,b) ((a)>(b)?(a):(b))

namespace angort {

static void formatSignedInt(char *s,int i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dd",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatUnsignedInt(char *s,unsigned int i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%du",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatSignedLong(char *s,long i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dld",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatUnsignedLong(char *s,unsigned long i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dlu",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatHexInt(char *s,unsigned int i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dx",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}
static void formatHexLong(char *s,unsigned long i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dlx",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatFloat(char *s,double f,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    if(precision!=-9999)
        sprintf(format,"%%%s%d.%df",zeropad?"0":"",negpad?-width:width,precision);
    else
        sprintf(format,"%%%s%df",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,f);
}

static void formatFloat2(char *s,double f,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    if(precision!=-9999)
        sprintf(format,"%%%s%d.%dg",zeropad?"0":"",negpad?-width:width,precision);
    else
        sprintf(format,"%%%s%dg",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,f);
}

static void formatScientific(char *s,double f,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    if(precision!=-9999)
        sprintf(format,"%%%s%d.%de",zeropad?"0":"",negpad?-width:width,precision);
    else
        sprintf(format,"%%%s%de",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,f);
}

static void formatString(char *s,const char *in,int width,int precision, bool negpad){
    char format[32];
    snprintf(format,20,"%%%ds",negpad?-width:width);
    sprintf(s,format,in);
}

void format(Value *out,Value *formatVal,ArrayList<Value> *items){

    // sorry, it actually has to be a string.
    if(formatVal->t != Types::tString)
        throw RUNT(EX_TYPE,"format must be a string");

    const char *format = Types::tString->getData(formatVal);

    ArrayListIterator<Value> iter(items);
    ReadLock lock(items);
    iter.first();

    unsigned int width,precision;

    // pass 1, work out the buffer size
    int size=0;
    int strsz;
    for(const char *f = format;*f;f++){
        precision=0;
        width=0;
        if(*f=='%'){
            const char *p = f++;
            if(*f=='-')f++;
            while(isdigit(*f))
                width = (width*10) + (*f++ - '0');
            if(*f=='.'){
                f++;
                while(isdigit(*f))
                    precision = (precision*10) + (*f++ - '0');
            }
            while(*f && *f!='%' && !isalpha(*f))
                ;
            if((*f=='l' || *f=='z') && (f[1]=='d' || f[1]=='u' || f[1]=='x'))
                ++f; // skip length flag (dealt with in pass 2)
            switch(*f){
            case 'c':
                // fall through
            case '%':
                size++;
                break;
            case 'd':case 'u':case 'x':
                // 50 should be plenty
                iter.next();
                size+=max(50,width);
                break;
            case 'f':
            case 'g':
            case 'e':
                iter.next();
                size+=50; // got to draw the line somewhere.
                break;
            case 's':{
                const StringBuffer& b = iter.current()->toString();
                strsz = max(strlen(b.get()),width);
                size+=strsz;
                iter.next();
                break;
            }
            default://unknown code; just add the rest of the string in. Ugh.
                size+=strlen(p);
                goto expand;
                break;
            }
        } else
            size++;
    }
expand:
    // now allocate a temporary buffer
    char *base=(char *)malloc(size+2);
    memset(base,0,size+1);
    char *s = base;

    // pass 2 - do the formatting
    iter.first();
    for(const char *f = format;*f;f++){
        if(*f=='%'){
            bool isLong=false;
            bool zeropad=false;
            bool negpad=false;
            const char *p = f++;
            precision=-9999; // rogue value for "no precision"
            width=0;
            if(*f=='-'){
                negpad=true;
                f++;
            }
            if(*f=='0')
                zeropad=true;
            while(isdigit(*f))
                width = (width*10) + (*f++ - '0');
            if(*f=='.'){
                precision=0;
                f++;
                while(isdigit(*f))
                    precision = (precision*10) + (*f++ - '0');
            }
            while(*f && *f!='%' && !isalpha(*f))
                f++;
            // length flags
            if((*f=='l' || *f=='z') && (f[1]=='d' || f[1]=='u' || f[1]=='x')){
                if(*f=='l')isLong=true;
                ++f;
            }

            switch(*f){
            case '%':
                *s++ = '%';
                break;
            case 'c':
                *s++ = iter.current()->toInt();
                iter.next();
                break;
            case 'd':
                if(isLong)
                    formatSignedLong(s,iter.current()->toLong(),width,precision,zeropad,negpad);
                else
                    formatSignedInt(s,iter.current()->toInt(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'u':
                if(isLong)
                    formatUnsignedLong(s,iter.current()->toLong(),width,precision,zeropad,negpad);
                else
                    formatUnsignedInt(s,iter.current()->toInt(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'x':
                if(isLong)
                    formatHexInt(s,iter.current()->toInt(),width,precision,zeropad,negpad);
                else
                    formatHexLong(s,iter.current()->toInt(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'f':
                formatFloat(s,iter.current()->toDouble(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'g':
                formatFloat2(s,iter.current()->toDouble(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'e':
                formatScientific(s,iter.current()->toDouble(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 's':{
                const StringBuffer& b = iter.current()->toString();
                formatString(s,b.get(),width,precision,negpad);
                s+=strlen(s);
                iter.next();
                break;
            }
            default:
                strcpy(s,p);
                s+=strlen(s);
                goto end;
            }
        } else
            *s++ = *f;
    }
end:
    *s=0;
    Types::tString->set(out,base);
    free(base);
}

}
<commit_msg>format now throws if we get an unknown % specification<commit_after>/**
 * @file
 * String formatting code.
 * Much of this code was adapted from Python's string formatting
 * code, but the actual formatting of individual items is done
 * by constructing printf formats and using them. Ugly, but easy.
 * There may be some dodgy assumptions about lengths here.
 */

#include "angort.h"
#include <ctype.h>
#define max(a,b) ((a)>(b)?(a):(b))

namespace angort {

static void formatSignedInt(char *s,int i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dd",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatUnsignedInt(char *s,unsigned int i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%du",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatSignedLong(char *s,long i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dld",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatUnsignedLong(char *s,unsigned long i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dlu",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatHexInt(char *s,unsigned int i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dx",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}
static void formatHexLong(char *s,unsigned long i,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    sprintf(format,"%%%s%dlx",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,i);
}

static void formatFloat(char *s,double f,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    if(precision!=-9999)
        sprintf(format,"%%%s%d.%df",zeropad?"0":"",negpad?-width:width,precision);
    else
        sprintf(format,"%%%s%df",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,f);
}

static void formatFloat2(char *s,double f,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    if(precision!=-9999)
        sprintf(format,"%%%s%d.%dg",zeropad?"0":"",negpad?-width:width,precision);
    else
        sprintf(format,"%%%s%dg",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,f);
}

static void formatScientific(char *s,double f,int width,int precision, bool zeropad, bool negpad){
    char format[32];
    if(precision!=-9999)
        sprintf(format,"%%%s%d.%de",zeropad?"0":"",negpad?-width:width,precision);
    else
        sprintf(format,"%%%s%de",zeropad?"0":"",negpad?-width:width);
    sprintf(s,format,f);
}

static void formatString(char *s,const char *in,int width,int precision, bool negpad){
    char format[32];
    snprintf(format,20,"%%%ds",negpad?-width:width);
    sprintf(s,format,in);
}

void format(Value *out,Value *formatVal,ArrayList<Value> *items){

    // sorry, it actually has to be a string.
    if(formatVal->t != Types::tString)
        throw RUNT(EX_TYPE,"format must be a string");

    const char *format = Types::tString->getData(formatVal);

    ArrayListIterator<Value> iter(items);
    ReadLock lock(items);
    iter.first();

    unsigned int width,precision;

    // pass 1, work out the buffer size
    int size=0;
    int strsz;
    for(const char *f = format;*f;f++){
        precision=0;
        width=0;
        if(*f=='%'){
            const char *p = f++;
            if(*f=='-')f++;
            while(isdigit(*f))
                width = (width*10) + (*f++ - '0');
            if(*f=='.'){
                f++;
                while(isdigit(*f))
                    precision = (precision*10) + (*f++ - '0');
            }
            while(*f && *f!='%' && !isalpha(*f))
                ;
            if((*f=='l' || *f=='z') && (f[1]=='d' || f[1]=='u' || f[1]=='x'))
                ++f; // skip length flag (dealt with in pass 2)
            switch(*f){
            case 'c':
                // fall through
            case '%':
                size++;
                break;
            case 'd':case 'u':case 'x':
                // 50 should be plenty
                iter.next();
                size+=max(50,width);
                break;
            case 'f':
            case 'g':
            case 'e':
                iter.next();
                size+=50; // got to draw the line somewhere.
                break;
            case 's':{
                const StringBuffer& b = iter.current()->toString();
                strsz = max(strlen(b.get()),width);
                size+=strsz;
                iter.next();
                break;
            }
            default://unknown code; throw.
                throw RUNT(EX_BADPARAM,"").set("unknown format in format specification: %c",*f);
            }
        } else
            size++;
    }
expand:
    // now allocate a temporary buffer
    char *base=(char *)malloc(size+2);
    memset(base,0,size+1);
    char *s = base;

    // pass 2 - do the formatting
    iter.first();
    for(const char *f = format;*f;f++){
        if(*f=='%'){
            bool isLong=false;
            bool zeropad=false;
            bool negpad=false;
            const char *p = f++;
            precision=-9999; // rogue value for "no precision"
            width=0;
            if(*f=='-'){
                negpad=true;
                f++;
            }
            if(*f=='0')
                zeropad=true;
            while(isdigit(*f))
                width = (width*10) + (*f++ - '0');
            if(*f=='.'){
                precision=0;
                f++;
                while(isdigit(*f))
                    precision = (precision*10) + (*f++ - '0');
            }
            while(*f && *f!='%' && !isalpha(*f))
                f++;
            // length flags
            if((*f=='l' || *f=='z') && (f[1]=='d' || f[1]=='u' || f[1]=='x')){
                if(*f=='l')isLong=true;
                ++f;
            }

            switch(*f){
            case '%':
                *s++ = '%';
                break;
            case 'c':
                *s++ = iter.current()->toInt();
                iter.next();
                break;
            case 'd':
                if(isLong)
                    formatSignedLong(s,iter.current()->toLong(),width,precision,zeropad,negpad);
                else
                    formatSignedInt(s,iter.current()->toInt(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'u':
                if(isLong)
                    formatUnsignedLong(s,iter.current()->toLong(),width,precision,zeropad,negpad);
                else
                    formatUnsignedInt(s,iter.current()->toInt(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'x':
                if(isLong)
                    formatHexInt(s,iter.current()->toInt(),width,precision,zeropad,negpad);
                else
                    formatHexLong(s,iter.current()->toInt(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'f':
                formatFloat(s,iter.current()->toDouble(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'g':
                formatFloat2(s,iter.current()->toDouble(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 'e':
                formatScientific(s,iter.current()->toDouble(),width,precision,zeropad,negpad);
                s+=strlen(s);
                iter.next();
                break;
            case 's':{
                const StringBuffer& b = iter.current()->toString();
                formatString(s,b.get(),width,precision,negpad);
                s+=strlen(s);
                iter.next();
                break;
            }
            default:
                strcpy(s,p);
                s+=strlen(s);
                goto end;
            }
        } else
            *s++ = *f;
    }
end:
    *s=0;
    Types::tString->set(out,base);
    free(base);
}

}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of Qt Creator.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "maemopackagecreationstep.h"

#include "maemoconstants.h"
#include "maemopackagecreationwidget.h"
#include "maemotoolchain.h"

#include <projectexplorer/projectexplorerconstants.h>
#include <qt4buildconfiguration.h>
#include <qt4project.h>
#include <qt4target.h>

#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore/QProcess>
#include <QtCore/QProcessEnvironment>
#include <QtCore/QStringBuilder>
#include <QtGui/QWidget>

using namespace ProjectExplorer::Constants;
using ProjectExplorer::BuildConfiguration;
using ProjectExplorer::BuildStepConfigWidget;
using ProjectExplorer::Task;

namespace Qt4ProjectManager {
namespace Internal {

MaemoPackageCreationStep::MaemoPackageCreationStep(BuildConfiguration *buildConfig)
    : ProjectExplorer::BuildStep(buildConfig, CreatePackageId)
{
}

MaemoPackageCreationStep::MaemoPackageCreationStep(BuildConfiguration *buildConfig,
    MaemoPackageCreationStep *other)
    : BuildStep(buildConfig, other)
{

}

bool MaemoPackageCreationStep::init()
{
    return true;
}

void MaemoPackageCreationStep::run(QFutureInterface<bool> &fi)
{
    fi.reportResult(createPackage());
}

BuildStepConfigWidget *MaemoPackageCreationStep::createConfigWidget()
{
    return new MaemoPackageCreationWidget(this);
}

bool MaemoPackageCreationStep::createPackage()
{
    if (!packagingNeeded())
        return true;

    emit addOutput(tr("Creating package file ..."));
    QFile configFile(targetRoot() % QLatin1String("/config.sh"));
    if (!configFile.open(QIODevice::ReadOnly)) {
        raiseError(tr("Cannot open MADDE config file '%1'.")
                   .arg(nativePath(configFile)));
        return false;
    }

    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    const QString &path = QDir::toNativeSeparators(maddeRoot() + QLatin1Char('/'));

    const QLatin1String key("PATH");
    QString colon = QLatin1String(":");
#ifdef Q_OS_WIN
    colon = QLatin1String(";");
    env.insert(key, targetRoot() % "/bin" % colon % env.value(key));
    env.insert(key, path % QLatin1String("bin") % colon % env.value(key));
#endif
    env.insert(key, path % QLatin1String("madbin") % colon % env.value(key));
    env.insert(QLatin1String("PERL5LIB"), path % QLatin1String("madlib/perl5"));

    const QString projectDir = QFileInfo(executable()).absolutePath();
    env.insert(QLatin1String("PWD"), projectDir);

    const QRegExp envPattern(QLatin1String("([^=]+)=[\"']?([^;\"']+)[\"']? ;.*"));
    QByteArray line;
    do {
        line = configFile.readLine(200);
        if (envPattern.exactMatch(line))
            env.insert(envPattern.cap(1), envPattern.cap(2));
    } while (!line.isEmpty());

    QProcess buildProc;
    buildProc.setProcessEnvironment(env);
    buildProc.setWorkingDirectory(projectDir);

    if (!QFileInfo(projectDir + QLatin1String("/debian")).exists()) {
        const QString command = QLatin1String("dh_make -s -n -p ")
            % executableFileName().toLower() % versionString();
        if (!runCommand(buildProc, command))
            return false;
        QFile rulesFile(projectDir + QLatin1String("/debian/rules"));
        if (!rulesFile.open(QIODevice::ReadWrite)) {
            raiseError(tr("Packaging Error: Cannot open file '%1'.")
                       .arg(nativePath(rulesFile)));
            return false;
        }

        QByteArray rulesContents = rulesFile.readAll();
        rulesContents.replace("DESTDIR", "INSTALL_ROOT");
        rulesFile.resize(0);
        rulesFile.write(rulesContents);
        if (rulesFile.error() != QFile::NoError) {
            raiseError(tr("Packaging Error: Cannot write file '%1'.")
                       .arg(nativePath(rulesFile)));
            return false;
        }
    }

    if (!runCommand(buildProc, QLatin1String("dh_installdirs")))
        return false;

    const QString targetFile(projectDir % QLatin1String("/debian/")
        % executableFileName().toLower() % executableFilePathOnTarget());
    if (QFile::exists(targetFile)) {
        if (!QFile::remove(targetFile)) {
            raiseError(tr("Packaging Error: Could not replace file '%1'.")
                       .arg(QDir::toNativeSeparators(targetFile)));
            return false;
        }
    }
    if (!QFile::copy(executable(), targetFile)) {
        raiseError(tr("Packaging Error: Could not copy '%1' to '%2'.")
                   .arg(QDir::toNativeSeparators(executable()))
                   .arg(QDir::toNativeSeparators(targetFile)));
        return false;
    }

    const QStringList commands = QStringList() << QLatin1String("dh_link")
        << QLatin1String("dh_fixperms") << QLatin1String("dh_installdeb")
        << QLatin1String("dh_shlibdeps") << QLatin1String("dh_gencontrol")
        << QLatin1String("dh_md5sums") << QLatin1String("dh_builddeb --destdir=.");
    foreach (const QString &command, commands) {
        if (!runCommand(buildProc, command))
            return false;
    }

    emit addOutput(tr("Package created."));
    return true;
}

bool MaemoPackageCreationStep::runCommand(QProcess &proc, const QString &command)
{
    emit addOutput(tr("Package Creation: Running command '%1'.").arg(command));
    QString perl;
#ifdef Q_OS_WIN
    perl = maddeRoot() + QLatin1String("/bin/perl.exe ");
#endif
    proc.start(perl + maddeRoot() % QLatin1String("/madbin/") % command);
    proc.write("\n"); // For dh_make
    if (!proc.waitForFinished(100000) && proc.error() == QProcess::Timedout) {
        raiseError(tr("Packaging failed."),
                   tr("Packaging Error: Command '%1' timed out.").arg(command));
        return false;
    }
    if (proc.exitCode() != 0) {
        const QString mainMessage = tr("Packaging Error: Command '%1' failed.")
                                    .arg(command);
        raiseError(mainMessage, mainMessage + QLatin1Char(' ')
                   + tr("Output was: ") + proc.readAllStandardError());
        return false;
    }
    return true;
}

const Qt4BuildConfiguration *MaemoPackageCreationStep::qt4BuildConfiguration() const
{
    return static_cast<Qt4BuildConfiguration *>(buildConfiguration());
}

QString MaemoPackageCreationStep::executable() const
{
    const TargetInformation &ti = qt4BuildConfiguration()->qt4Target()
        ->qt4Project()->rootProjectNode()->targetInformation();
    if (!ti.valid)
        return QString();

    return QDir::toNativeSeparators(QDir::cleanPath(ti.workingDir
        + QLatin1Char('/') + ti.target));
}

QString MaemoPackageCreationStep::executableFileName() const
{
    return QFileInfo(executable()).fileName();
}

const MaemoToolChain *MaemoPackageCreationStep::maemoToolChain() const
{
    return static_cast<MaemoToolChain *>(qt4BuildConfiguration()->toolChain());
}

QString MaemoPackageCreationStep::maddeRoot() const
{
    return maemoToolChain()->maddeRoot();
}

QString MaemoPackageCreationStep::targetRoot() const
{
    return maemoToolChain()->targetRoot();
}

bool MaemoPackageCreationStep::packagingNeeded() const
{
    // TODO: When the package contents get user-modifiable, we need
    // to check whether files have been added and/or removed and whether
    // the newest one is newer than the package.
    // For the first check, we should have a switch that the widget sets
    // to true when the user has changed the package contents and which
    // we set to false after a successful package creation.
    QFileInfo packageInfo(packageFilePath());
    return !packageInfo.exists()
        || packageInfo.lastModified() <= QFileInfo(executable()).lastModified();
}

QString MaemoPackageCreationStep::packageFilePath() const
{
    QFileInfo execInfo(executable());
    return execInfo.path() % QDir::separator() % execInfo.fileName().toLower()
        % versionString() % QLatin1String("_armel.deb");
}

QString MaemoPackageCreationStep::executableFilePathOnTarget() const
{
    return QLatin1String("/usr/bin/") % executableFileName();
}

QString MaemoPackageCreationStep::versionString() const
{
    return QLatin1String("_0.1");
}

QString MaemoPackageCreationStep::nativePath(const QFile &file) const
{
    return QDir::toNativeSeparators(QFileInfo(file).filePath());
}

void MaemoPackageCreationStep::raiseError(const QString &shortMsg,
                                          const QString &detailedMsg)
{
    emit addOutput(detailedMsg.isNull() ? shortMsg : detailedMsg);
    emit addTask(Task(Task::Error, shortMsg, QString(), -1,
                      TASK_CATEGORY_BUILDSYSTEM));
}

const QLatin1String MaemoPackageCreationStep::CreatePackageId("Qt4ProjectManager.MaemoPackageCreationStep");

} // namespace Internal
} // namespace Qt4ProjectManager
<commit_msg>Maemo: For packaging errors, add dh_* stdout to the error message.<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of Qt Creator.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "maemopackagecreationstep.h"

#include "maemoconstants.h"
#include "maemopackagecreationwidget.h"
#include "maemotoolchain.h"

#include <projectexplorer/projectexplorerconstants.h>
#include <qt4buildconfiguration.h>
#include <qt4project.h>
#include <qt4target.h>

#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore/QProcess>
#include <QtCore/QProcessEnvironment>
#include <QtCore/QStringBuilder>
#include <QtGui/QWidget>

using namespace ProjectExplorer::Constants;
using ProjectExplorer::BuildConfiguration;
using ProjectExplorer::BuildStepConfigWidget;
using ProjectExplorer::Task;

namespace Qt4ProjectManager {
namespace Internal {

MaemoPackageCreationStep::MaemoPackageCreationStep(BuildConfiguration *buildConfig)
    : ProjectExplorer::BuildStep(buildConfig, CreatePackageId)
{
}

MaemoPackageCreationStep::MaemoPackageCreationStep(BuildConfiguration *buildConfig,
    MaemoPackageCreationStep *other)
    : BuildStep(buildConfig, other)
{

}

bool MaemoPackageCreationStep::init()
{
    return true;
}

void MaemoPackageCreationStep::run(QFutureInterface<bool> &fi)
{
    fi.reportResult(createPackage());
}

BuildStepConfigWidget *MaemoPackageCreationStep::createConfigWidget()
{
    return new MaemoPackageCreationWidget(this);
}

bool MaemoPackageCreationStep::createPackage()
{
    if (!packagingNeeded())
        return true;

    emit addOutput(tr("Creating package file ..."));
    QFile configFile(targetRoot() % QLatin1String("/config.sh"));
    if (!configFile.open(QIODevice::ReadOnly)) {
        raiseError(tr("Cannot open MADDE config file '%1'.")
                   .arg(nativePath(configFile)));
        return false;
    }

    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    const QString &path = QDir::toNativeSeparators(maddeRoot() + QLatin1Char('/'));

    const QLatin1String key("PATH");
    QString colon = QLatin1String(":");
#ifdef Q_OS_WIN
    colon = QLatin1String(";");
    env.insert(key, targetRoot() % "/bin" % colon % env.value(key));
    env.insert(key, path % QLatin1String("bin") % colon % env.value(key));
#endif
    env.insert(key, path % QLatin1String("madbin") % colon % env.value(key));
    env.insert(QLatin1String("PERL5LIB"), path % QLatin1String("madlib/perl5"));

    const QString projectDir = QFileInfo(executable()).absolutePath();
    env.insert(QLatin1String("PWD"), projectDir);

    const QRegExp envPattern(QLatin1String("([^=]+)=[\"']?([^;\"']+)[\"']? ;.*"));
    QByteArray line;
    do {
        line = configFile.readLine(200);
        if (envPattern.exactMatch(line))
            env.insert(envPattern.cap(1), envPattern.cap(2));
    } while (!line.isEmpty());

    QProcess buildProc;
    buildProc.setProcessEnvironment(env);
    buildProc.setWorkingDirectory(projectDir);

    if (!QFileInfo(projectDir + QLatin1String("/debian")).exists()) {
        const QString command = QLatin1String("dh_make -s -n -p ")
            % executableFileName().toLower() % versionString();
        if (!runCommand(buildProc, command))
            return false;
        QFile rulesFile(projectDir + QLatin1String("/debian/rules"));
        if (!rulesFile.open(QIODevice::ReadWrite)) {
            raiseError(tr("Packaging Error: Cannot open file '%1'.")
                       .arg(nativePath(rulesFile)));
            return false;
        }

        QByteArray rulesContents = rulesFile.readAll();
        rulesContents.replace("DESTDIR", "INSTALL_ROOT");
        rulesFile.resize(0);
        rulesFile.write(rulesContents);
        if (rulesFile.error() != QFile::NoError) {
            raiseError(tr("Packaging Error: Cannot write file '%1'.")
                       .arg(nativePath(rulesFile)));
            return false;
        }
    }

    if (!runCommand(buildProc, QLatin1String("dh_installdirs")))
        return false;

    const QString targetFile(projectDir % QLatin1String("/debian/")
        % executableFileName().toLower() % executableFilePathOnTarget());
    if (QFile::exists(targetFile)) {
        if (!QFile::remove(targetFile)) {
            raiseError(tr("Packaging Error: Could not replace file '%1'.")
                       .arg(QDir::toNativeSeparators(targetFile)));
            return false;
        }
    }
    if (!QFile::copy(executable(), targetFile)) {
        raiseError(tr("Packaging Error: Could not copy '%1' to '%2'.")
                   .arg(QDir::toNativeSeparators(executable()))
                   .arg(QDir::toNativeSeparators(targetFile)));
        return false;
    }

    const QStringList commands = QStringList() << QLatin1String("dh_link")
        << QLatin1String("dh_fixperms") << QLatin1String("dh_installdeb")
        << QLatin1String("dh_shlibdeps") << QLatin1String("dh_gencontrol")
        << QLatin1String("dh_md5sums") << QLatin1String("dh_builddeb --destdir=.");
    foreach (const QString &command, commands) {
        if (!runCommand(buildProc, command))
            return false;
    }

    emit addOutput(tr("Package created."));
    return true;
}

bool MaemoPackageCreationStep::runCommand(QProcess &proc, const QString &command)
{
    emit addOutput(tr("Package Creation: Running command '%1'.").arg(command));
    QString perl;
#ifdef Q_OS_WIN
    perl = maddeRoot() + QLatin1String("/bin/perl.exe ");
#endif
    proc.start(perl + maddeRoot() % QLatin1String("/madbin/") % command);
    proc.write("\n"); // For dh_make
    if (!proc.waitForFinished(100000) && proc.error() == QProcess::Timedout) {
        raiseError(tr("Packaging failed."),
                   tr("Packaging Error: Command '%1' timed out.").arg(command));
        return false;
    }
    if (proc.exitCode() != 0) {
        const QString mainMessage = tr("Packaging Error: Command '%1' failed.")
                                    .arg(command);
        raiseError(mainMessage, mainMessage + QLatin1Char(' ')
                   + tr("Output was: ") + proc.readAllStandardError()
                   + QLatin1Char('\n') + proc.readAllStandardOutput());
        return false;
    }
    return true;
}

const Qt4BuildConfiguration *MaemoPackageCreationStep::qt4BuildConfiguration() const
{
    return static_cast<Qt4BuildConfiguration *>(buildConfiguration());
}

QString MaemoPackageCreationStep::executable() const
{
    const TargetInformation &ti = qt4BuildConfiguration()->qt4Target()
        ->qt4Project()->rootProjectNode()->targetInformation();
    if (!ti.valid)
        return QString();

    return QDir::toNativeSeparators(QDir::cleanPath(ti.workingDir
        + QLatin1Char('/') + ti.target));
}

QString MaemoPackageCreationStep::executableFileName() const
{
    return QFileInfo(executable()).fileName();
}

const MaemoToolChain *MaemoPackageCreationStep::maemoToolChain() const
{
    return static_cast<MaemoToolChain *>(qt4BuildConfiguration()->toolChain());
}

QString MaemoPackageCreationStep::maddeRoot() const
{
    return maemoToolChain()->maddeRoot();
}

QString MaemoPackageCreationStep::targetRoot() const
{
    return maemoToolChain()->targetRoot();
}

bool MaemoPackageCreationStep::packagingNeeded() const
{
    // TODO: When the package contents get user-modifiable, we need
    // to check whether files have been added and/or removed and whether
    // the newest one is newer than the package.
    // For the first check, we should have a switch that the widget sets
    // to true when the user has changed the package contents and which
    // we set to false after a successful package creation.
    QFileInfo packageInfo(packageFilePath());
    return !packageInfo.exists()
        || packageInfo.lastModified() <= QFileInfo(executable()).lastModified();
}

QString MaemoPackageCreationStep::packageFilePath() const
{
    QFileInfo execInfo(executable());
    return execInfo.path() % QDir::separator() % execInfo.fileName().toLower()
        % versionString() % QLatin1String("_armel.deb");
}

QString MaemoPackageCreationStep::executableFilePathOnTarget() const
{
    return QLatin1String("/usr/bin/") % executableFileName();
}

QString MaemoPackageCreationStep::versionString() const
{
    return QLatin1String("_0.1");
}

QString MaemoPackageCreationStep::nativePath(const QFile &file) const
{
    return QDir::toNativeSeparators(QFileInfo(file).filePath());
}

void MaemoPackageCreationStep::raiseError(const QString &shortMsg,
                                          const QString &detailedMsg)
{
    emit addOutput(detailedMsg.isNull() ? shortMsg : detailedMsg);
    emit addTask(Task(Task::Error, shortMsg, QString(), -1,
                      TASK_CATEGORY_BUILDSYSTEM));
}

const QLatin1String MaemoPackageCreationStep::CreatePackageId("Qt4ProjectManager.MaemoPackageCreationStep");

} // namespace Internal
} // namespace Qt4ProjectManager
<|endoftext|>


<commit_before>#include <pcl/features/multiscale_feature_persistence.h>
#include <pcl/io/pcd_io.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/features/normal_3d.h>
#include <pcl/features/fpfh.h>

#include <pcl/visualization/cloud_viewer.h>

using namespace pcl;

const Eigen::Vector4f subsampling_leaf_size (0.01, 0.01, 0.01, 0.0);
const float normal_estimation_search_radius = 0.05;

void
subsampleAndCalculateNormals (PointCloud<PointXYZ>::Ptr &cloud,
                              PointCloud<PointXYZ>::Ptr &cloud_subsampled,
                              PointCloud<Normal>::Ptr &cloud_subsampled_normals)
{
  cloud_subsampled = PointCloud<PointXYZ>::Ptr (new PointCloud<PointXYZ> ());
  VoxelGrid<PointXYZ> subsampling_filter;
  subsampling_filter.setInputCloud (cloud);
  subsampling_filter.setLeafSize (subsampling_leaf_size);
  subsampling_filter.filter (*cloud_subsampled);

  cloud_subsampled_normals = PointCloud<Normal>::Ptr (new PointCloud<Normal> ());
  NormalEstimation<PointXYZ, Normal> normal_estimation_filter;
  normal_estimation_filter.setInputCloud (cloud_subsampled);
  pcl::search::KdTree<PointXYZ>::Ptr search_tree (new pcl::search::KdTree<PointXYZ>);
  normal_estimation_filter.setSearchMethod (search_tree);
  normal_estimation_filter.setRadiusSearch (normal_estimation_search_radius);
  normal_estimation_filter.compute (*cloud_subsampled_normals);
}

int
main (int argc, char **argv)
{
  if (argc != 2)
  {
    PCL_ERROR ("Syntax: ./multiscale_feature_persistence_example [path_to_cloud.pcl]\n");
    return -1;
  }

  PointCloud<PointXYZ>::Ptr cloud_scene (new PointCloud<PointXYZ> ());
  PCDReader reader;
  reader.read (argv[1], *cloud_scene);

  PointCloud<PointXYZ>::Ptr cloud_subsampled;
  PointCloud<Normal>::Ptr cloud_subsampled_normals;
  subsampleAndCalculateNormals (cloud_scene, cloud_subsampled, cloud_subsampled_normals);

  PCL_INFO ("STATS:\ninitial point cloud size: %u\nsubsampled point cloud size: %u\n", cloud_scene->points.size (), cloud_subsampled->points.size ());
  visualization::CloudViewer viewer ("Multiscale Feature Persistence Example Visualization");
  viewer.showCloud (cloud_scene, "scene");

  MultiscaleFeaturePersistence<PointXYZ, FPFHSignature33> feature_persistence;
  std::vector<float> scale_values;
  for (float x = 2.0; x < 3.6; x += 0.35)
    scale_values.push_back (x / 100.0);
  feature_persistence.setScalesVector (scale_values);
  feature_persistence.setAlpha (1.3);
  FPFHEstimation<PointXYZ, Normal, FPFHSignature33>::Ptr fpfh_estimation (new FPFHEstimation<PointXYZ, Normal, FPFHSignature33> ());
  fpfh_estimation->setInputCloud (cloud_subsampled);
  fpfh_estimation->setInputNormals (cloud_subsampled_normals);
  pcl::search::KdTree<PointXYZ>::Ptr tree (new pcl::search::KdTree<PointXYZ> ());
  fpfh_estimation->setSearchMethod (tree);
  feature_persistence.setFeatureEstimator (fpfh_estimation);
  feature_persistence.setDistanceMetric (pcl::CS);

  PointCloud<FPFHSignature33>::Ptr output_features (new PointCloud<FPFHSignature33> ());
  boost::shared_ptr<std::vector<int> > output_indices (new std::vector<int> ());
  feature_persistence.determinePersistentFeatures (*output_features, output_indices);

  PCL_INFO ("persistent features cloud size: %u\n", output_features->points.size ());

  ExtractIndices<PointXYZ> extract_indices_filter;
  extract_indices_filter.setInputCloud (cloud_subsampled);
  extract_indices_filter.setIndices (output_indices);
  PointCloud<PointXYZ>::Ptr persistent_features_locations (new PointCloud<PointXYZ> ());
  extract_indices_filter.filter (*persistent_features_locations);

  viewer.showCloud (persistent_features_locations, "persistent features");
  PCL_INFO ("Persistent features have been computed. Waiting for the user to quit the visualization window.\n");

//  io::savePCDFileASCII ("persistent_features.pcd", *persistent_features_locations);
//  PCL_INFO ("\nPersistent feature locations written to persistent_features.pcd\n");

  while (!viewer.wasStopped (50));

  return 0;
}
<commit_msg>added missing header<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2009-2012, Willow Garage, Inc.
 *
 *  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 of conditions 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 materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  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 OWNER 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 <pcl/features/multiscale_feature_persistence.h>
#include <pcl/io/pcd_io.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/features/normal_3d.h>
#include <pcl/features/fpfh.h>

#include <pcl/visualization/cloud_viewer.h>

using namespace pcl;

const Eigen::Vector4f subsampling_leaf_size (0.01, 0.01, 0.01, 0.0);
const float normal_estimation_search_radius = 0.05;

void
subsampleAndCalculateNormals (PointCloud<PointXYZ>::Ptr &cloud,
                              PointCloud<PointXYZ>::Ptr &cloud_subsampled,
                              PointCloud<Normal>::Ptr &cloud_subsampled_normals)
{
  cloud_subsampled = PointCloud<PointXYZ>::Ptr (new PointCloud<PointXYZ> ());
  VoxelGrid<PointXYZ> subsampling_filter;
  subsampling_filter.setInputCloud (cloud);
  subsampling_filter.setLeafSize (subsampling_leaf_size);
  subsampling_filter.filter (*cloud_subsampled);

  cloud_subsampled_normals = PointCloud<Normal>::Ptr (new PointCloud<Normal> ());
  NormalEstimation<PointXYZ, Normal> normal_estimation_filter;
  normal_estimation_filter.setInputCloud (cloud_subsampled);
  pcl::search::KdTree<PointXYZ>::Ptr search_tree (new pcl::search::KdTree<PointXYZ>);
  normal_estimation_filter.setSearchMethod (search_tree);
  normal_estimation_filter.setRadiusSearch (normal_estimation_search_radius);
  normal_estimation_filter.compute (*cloud_subsampled_normals);
}

int
main (int argc, char **argv)
{
  if (argc != 2)
  {
    PCL_ERROR ("Syntax: ./multiscale_feature_persistence_example [path_to_cloud.pcl]\n");
    return -1;
  }

  PointCloud<PointXYZ>::Ptr cloud_scene (new PointCloud<PointXYZ> ());
  PCDReader reader;
  reader.read (argv[1], *cloud_scene);

  PointCloud<PointXYZ>::Ptr cloud_subsampled;
  PointCloud<Normal>::Ptr cloud_subsampled_normals;
  subsampleAndCalculateNormals (cloud_scene, cloud_subsampled, cloud_subsampled_normals);

  PCL_INFO ("STATS:\ninitial point cloud size: %u\nsubsampled point cloud size: %u\n", cloud_scene->points.size (), cloud_subsampled->points.size ());
  visualization::CloudViewer viewer ("Multiscale Feature Persistence Example Visualization");
  viewer.showCloud (cloud_scene, "scene");

  MultiscaleFeaturePersistence<PointXYZ, FPFHSignature33> feature_persistence;
  std::vector<float> scale_values;
  for (float x = 2.0; x < 3.6; x += 0.35)
    scale_values.push_back (x / 100.0);
  feature_persistence.setScalesVector (scale_values);
  feature_persistence.setAlpha (1.3);
  FPFHEstimation<PointXYZ, Normal, FPFHSignature33>::Ptr fpfh_estimation (new FPFHEstimation<PointXYZ, Normal, FPFHSignature33> ());
  fpfh_estimation->setInputCloud (cloud_subsampled);
  fpfh_estimation->setInputNormals (cloud_subsampled_normals);
  pcl::search::KdTree<PointXYZ>::Ptr tree (new pcl::search::KdTree<PointXYZ> ());
  fpfh_estimation->setSearchMethod (tree);
  feature_persistence.setFeatureEstimator (fpfh_estimation);
  feature_persistence.setDistanceMetric (pcl::CS);

  PointCloud<FPFHSignature33>::Ptr output_features (new PointCloud<FPFHSignature33> ());
  boost::shared_ptr<std::vector<int> > output_indices (new std::vector<int> ());
  feature_persistence.determinePersistentFeatures (*output_features, output_indices);

  PCL_INFO ("persistent features cloud size: %u\n", output_features->points.size ());

  ExtractIndices<PointXYZ> extract_indices_filter;
  extract_indices_filter.setInputCloud (cloud_subsampled);
  extract_indices_filter.setIndices (output_indices);
  PointCloud<PointXYZ>::Ptr persistent_features_locations (new PointCloud<PointXYZ> ());
  extract_indices_filter.filter (*persistent_features_locations);

  viewer.showCloud (persistent_features_locations, "persistent features");
  PCL_INFO ("Persistent features have been computed. Waiting for the user to quit the visualization window.\n");

//  io::savePCDFileASCII ("persistent_features.pcd", *persistent_features_locations);
//  PCL_INFO ("\nPersistent feature locations written to persistent_features.pcd\n");

  while (!viewer.wasStopped (50));

  return 0;
}
<|endoftext|>