<commit_before>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// CLI application
//==============================================================================

#include "cliapplication.h"
#include "cliinterface.h"
#include "cliutils.h"
#include "common.h"
#include "pluginmanager.h"

//==============================================================================

#include <iostream>

//==============================================================================

#include <Qt>

//==============================================================================

#include <QCoreApplication>
#include <QXmlStreamReader>

//==============================================================================

namespace OpenCOR {

//==============================================================================

CliApplication::CliApplication(QCoreApplication *pApp) :
    mApp(pApp),
    mPluginManager(0),
    mLoadedCliPlugins(Plugins())
{
}

//==============================================================================

CliApplication::~CliApplication()
{
    // Delete some internal objects

    delete mPluginManager;
}

//==============================================================================

void CliApplication::loadPlugins()
{
    // Load all the plugins by creating our plugin manager

    mPluginManager = new PluginManager(mApp, false);

    // Keep track of our loaded CLI plugins

    foreach (Plugin *plugin, mPluginManager->loadedPlugins())
        if (qobject_cast<CliInterface *>(plugin->instance()))
            mLoadedCliPlugins << plugin;
}

//==============================================================================

QString CliApplication::pluginDescription(Plugin *pPlugin) const
{
    // Retrieve and return the plugin's default description, stripped out of all
    // its HTML (should it have some)
    // Note: we enclose the CLI plugin's default description within an html
    //       tag so that the stripping out can proceed without any
    //       problem...

    QXmlStreamReader description(""+pPlugin->info()->description()+"");
    QString res = QString();

    while (!description.atEnd())
        if (description.readNext() == QXmlStreamReader::Characters)
            res += description.text();

    return res;
}

//==============================================================================

void CliApplication::about() const
{
    // Output some information about OpenCOR

    version();

    std::cout << qPrintable(Core::osName()) << std::endl;
    std::cout << qPrintable(Core::copyright()) << std::endl;
    std::cout << std::endl;
    std::cout << qPrintable(mApp->applicationName())
              << " is a cross-platform CellML-based modelling environment,"
              << " which can be" << std::endl;
    std::cout << "used to organise, edit, simulate and analyse CellML files."
              << std::endl;
}

//==============================================================================

bool CliApplication::command(const QStringList pArguments, int *pRes) const
{
    // Make sure that we have at least one argument

    if (!pArguments.count())
        return false;

    // Determine whether the command is to be executed by all the CLI plugins or
    // only a given CLI plugin

    static const QString CommandSeparator = "::";

    QString commandName = pArguments.first();
    QString commandPlugin = commandName;
    int commandSeparatorPosition = commandName.indexOf(CommandSeparator);

    if (commandSeparatorPosition != -1) {
        commandPlugin = commandPlugin.remove(commandSeparatorPosition, commandName.length()-commandSeparatorPosition);
        commandName = commandName.remove(0, commandPlugin.length()+CommandSeparator.length());

        // Make sure that the plugin to which the command is to be sent exists

        if (!commandPlugin.isEmpty()) {
            bool pluginFound = false;
            bool pluginHasCliSupport = false;

            foreach (Plugin *plugin, mPluginManager->loadedPlugins())
                if (!commandPlugin.compare(plugin->name())) {
                    pluginFound = true;
                    pluginHasCliSupport = qobject_cast<CliInterface *>(plugin->instance());

                    break;
                }

            if (!pluginFound) {
                std::cout << "Sorry, but the " << qPrintable(commandPlugin) << " plugin could not be found." << std::endl;

                return true;
            } else if (!pluginHasCliSupport) {
                std::cout << "Sorry, but the " << qPrintable(commandPlugin) << " plugin does not support the execution of commands." << std::endl;

                return true;
            }
        }
    } else {
        commandPlugin = QString();
    }

    // Make sure that we have a command name

    if (commandName.isEmpty())
        return false;

    // Make sure that we have at least one CLI-enabled plugin

    if (mLoadedCliPlugins.isEmpty()) {
        std::cout << "Sorry, but no plugins could be found to run the command." << std::endl;

        return true;
    }

    // Send the command to the plugin(s)

    foreach (Plugin *plugin, mLoadedCliPlugins)
        if (    commandPlugin.isEmpty()
            || !commandPlugin.compare(plugin->name())) {
            QStringList arguments = pArguments;

            arguments.removeFirst();
            // Note: since the first argument corresponds to the command
            //       itself...

            if (qobject_cast<CliInterface *>(plugin->instance())->executeCommand(commandName, arguments))
                *pRes = -1;
        }

    return true;
}

//==============================================================================

void CliApplication::help() const
{
    // Output some help

    std::cout << "Usage: " << qPrintable(mApp->applicationName())
              << " [-a|--about] [-c|--command [<plugin>::]<command> <options>] [-h|--help] [-p|--plugins] [-s|--status] [-v|--version] [<files>]"
              << std::endl;
    std::cout << " -a, --about     Display some information about OpenCOR"
              << std::endl;
    std::cout << " -c, --command   Send a command to one or all the CLI plugins"
              << std::endl;
    std::cout << " -h, --help      Display this help information"
              << std::endl;
    std::cout << " -p, --plugins   Display all the CLI plugins"
              << std::endl;
    std::cout << " -s, --status    Display the status of all the plugins"
              << std::endl;
    std::cout << " -v, --version   Display the version of OpenCOR"
              << std::endl;
}

//==============================================================================

void CliApplication::plugins() const
{
    // Output some information about our CLI plugins, so first make sure that we
    // have at least one of them

    if (mLoadedCliPlugins.isEmpty()) {
        std::cout << "Sorry, but no CLI plugins could be found." << std::endl;

        return;
    }

    // First, we retrieve all the CLI plugins information

    QStringList pluginsInfo = QStringList();

    foreach (Plugin *plugin, mLoadedCliPlugins) {
        // Retrieve the CLI plugin and its default description

        QString pluginInfo = plugin->name();
        QString pluginDesc = pluginDescription(plugin);

        if (!pluginDesc.isEmpty())
            pluginInfo += ": "+pluginDesc;

        // Add the plugin information to our list

        pluginsInfo << pluginInfo;
    }

    // Now, we can output the plugin information in alphabetical order

    pluginsInfo.sort(Qt::CaseInsensitive);

    if (pluginsInfo.count() == 1)
        std::cout << "The following CLI plugin is available:" << std::endl;
    else
        std::cout << "The following CLI plugins are available:" << std::endl;

    foreach (const QString &pluginInfo, pluginsInfo)
        std::cout << " - " << qPrintable(pluginInfo) << std::endl;
}

//==============================================================================

void CliApplication::status() const
{
    // Output the status of all the plugins that should (have) normally be(en)
    // loaded, so first make sure that we have at least one of them

    if (mPluginManager->loadedPlugins().isEmpty()) {
        std::cout << "Sorry, but no plugins could be found." << std::endl;

        return;
    }

    // First, we retrieve all the plugins information

    QStringList pluginsInfo = QStringList();

    foreach (Plugin *plugin, mPluginManager->plugins()) {
        // Retrieve the plugin and its status

        QString pluginInfo = plugin->name()+": ";

        // Retrieve the plugin's status

        switch (plugin->status()) {
        case Plugin::NotWanted:
            pluginInfo += "the plugin is not wanted.";

            break;
        case Plugin::NotNeeded:
            pluginInfo += "the plugin is not needed.";

            break;
        case Plugin::NotLoaded:
            pluginInfo += QString("the plugin could not be loaded due to the following problem: %1.").arg(Core::formatErrorMessage(plugin->statusErrors(), false));

            break;
        case Plugin::NotPlugin:
            pluginInfo += "this is not a plugin.";

            break;
        case Plugin::NotCorePlugin:
            pluginInfo += "the plugin claims to be the core plugin, but it is not.";

            break;
        case Plugin::InvalidCorePlugin:
            pluginInfo += "the plugin should be the core plugin, but it does not support the core interface.";

            break;
        case Plugin::NotCliPlugin:
            pluginInfo += "the plugin claims to be CLI-capable, but it does not support the CLI interface.";

            break;
        case Plugin::MissingOrInvalidDependencies:
            if (plugin->statusErrorsCount() == 1)
                pluginInfo += QString("the plugin could not be loaded due to the %1 plugin being missing or invalid.").arg(plugin->statusErrors());
            else
                pluginInfo += QString("the plugin could not be loaded due to missing or invalid plugins:\n%1").arg(plugin->statusErrors());

            break;
        default:
            // Plugin::Loaded

            pluginInfo += "the plugin is loaded and fully functional.";
        }

        // Add the plugin information to our list

        pluginsInfo << pluginInfo;
    }

    // Now, we can output the plugin information in alphabetical order

    pluginsInfo.sort(Qt::CaseInsensitive);

    if (pluginsInfo.count() == 1)
        std::cout << "The following plugin is available:" << std::endl;
    else
        std::cout << "The following plugins are available:" << std::endl;

    foreach (const QString &pluginInfo, pluginsInfo)
        std::cout << " - " << qPrintable(pluginInfo) << std::endl;
}

//==============================================================================

void CliApplication::version() const
{
    // Output the version of OpenCOR

    std::cout << qPrintable(OpenCOR::version(mApp)) << std::endl;
}

//==============================================================================

bool CliApplication::run(int *pRes)
{
    // See what needs doing with the CLI options, if anything

    *pRes = 0;   // By default, everything is fine

    bool aboutOption = false;
    bool commandOption = false;
    bool helpOption = false;
    bool pluginsOption = false;
    bool statusOption = false;
    bool versionOption = false;

    QStringList commandArguments = QStringList();

    foreach (const QString &argument, mApp->arguments())
        if (!argument.compare("-a") || !argument.compare("--about")) {
            aboutOption = true;
        } else if (!argument.compare("-c") || !argument.compare("--command")) {
            commandOption = true;
        } else if (!argument.compare("-h") || !argument.compare("--help")) {
            helpOption = true;
        } else if (!argument.compare("-p") || !argument.compare("--plugins")) {
            pluginsOption = true;
        } else if (!argument.compare("-s") || !argument.compare("--status")) {
            statusOption = true;
        } else if (!argument.compare("-v") || !argument.compare("--version")) {
            versionOption = true;
        } else if (argument.startsWith("-")) {
            // The user provided at least one unknown option

            help();

            *pRes = -1;

            break;
        } else if (commandOption) {
            // Not an option, so we consider it to be part of a command

            commandArguments << argument;
        }

    // Handle the option the user requested, if any

    if (!*pRes) {
        if (aboutOption) {
            about();
        } else if (commandOption) {
            // Make sure that we have at least one argument (which would be the
            // command itself) before loading the plugins and then sending the
            // command to the plugin(s)

            if (commandArguments.isEmpty()) {
                help();
            } else {
                loadPlugins();

                if (!command(commandArguments, pRes))
                    help();
            }
        } else if (helpOption) {
            help();
        } else if (pluginsOption) {
            loadPlugins();

            plugins();
        } else if (statusOption) {
            loadPlugins();

            status();
        } else if (versionOption) {
            version();
        } else {
            // The user didn't provide any option which requires running OpenCOR
            // as a CLI application

            return false;
        }
    }

    return true;
}

//==============================================================================

}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Some minor cleaning up [ci skip].<commit_after>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// CLI application
//==============================================================================

#include "cliapplication.h"
#include "cliinterface.h"
#include "cliutils.h"
#include "common.h"
#include "pluginmanager.h"

//==============================================================================

#include <iostream>

//==============================================================================

#include <Qt>

//==============================================================================

#include <QCoreApplication>
#include <QXmlStreamReader>

//==============================================================================

namespace OpenCOR {

//==============================================================================

CliApplication::CliApplication(QCoreApplication *pApp) :
    mApp(pApp),
    mPluginManager(0),
    mLoadedCliPlugins(Plugins())
{
}

//==============================================================================

CliApplication::~CliApplication()
{
    // Delete some internal objects

    delete mPluginManager;
}

//==============================================================================

void CliApplication::loadPlugins()
{
    // Load all the plugins by creating our plugin manager

    mPluginManager = new PluginManager(mApp, false);

    // Keep track of our loaded CLI plugins

    foreach (Plugin *plugin, mPluginManager->loadedPlugins())
        if (qobject_cast<CliInterface *>(plugin->instance()))
            mLoadedCliPlugins << plugin;
}

//==============================================================================

QString CliApplication::pluginDescription(Plugin *pPlugin) const
{
    // Retrieve and return the plugin's default description, stripped out of all
    // its HTML (should it have some)
    // Note: we enclose the CLI plugin's default description within an html
    //       tag so that the stripping out can proceed without any
    //       problem...

    QXmlStreamReader description(""+pPlugin->info()->description()+"");
    QString res = QString();

    while (!description.atEnd())
        if (description.readNext() == QXmlStreamReader::Characters)
            res += description.text();

    return res;
}

//==============================================================================

void CliApplication::about() const
{
    // Output some information about OpenCOR

    version();

    std::cout << qPrintable(Core::osName()) << std::endl;
    std::cout << qPrintable(Core::copyright()) << std::endl;
    std::cout << std::endl;
    std::cout << qPrintable(mApp->applicationName())
              << " is a cross-platform CellML-based modelling environment,"
              << " which can be used to organise, edit,"
              << " simulate and analyse CellML files."
              << std::endl;
}

//==============================================================================

bool CliApplication::command(const QStringList pArguments, int *pRes) const
{
    // Make sure that we have at least one argument

    if (!pArguments.count())
        return false;

    // Determine whether the command is to be executed by all the CLI plugins or
    // only a given CLI plugin

    static const QString CommandSeparator = "::";

    QString commandName = pArguments.first();
    QString commandPlugin = commandName;
    int commandSeparatorPosition = commandName.indexOf(CommandSeparator);

    if (commandSeparatorPosition != -1) {
        commandPlugin = commandPlugin.remove(commandSeparatorPosition, commandName.length()-commandSeparatorPosition);
        commandName = commandName.remove(0, commandPlugin.length()+CommandSeparator.length());

        // Make sure that the plugin to which the command is to be sent exists

        if (!commandPlugin.isEmpty()) {
            bool pluginFound = false;
            bool pluginHasCliSupport = false;

            foreach (Plugin *plugin, mPluginManager->loadedPlugins())
                if (!commandPlugin.compare(plugin->name())) {
                    pluginFound = true;
                    pluginHasCliSupport = qobject_cast<CliInterface *>(plugin->instance());

                    break;
                }

            if (!pluginFound) {
                std::cout << "Sorry, but the " << qPrintable(commandPlugin) << " plugin could not be found." << std::endl;

                return true;
            } else if (!pluginHasCliSupport) {
                std::cout << "Sorry, but the " << qPrintable(commandPlugin) << " plugin does not support the execution of commands." << std::endl;

                return true;
            }
        }
    } else {
        commandPlugin = QString();
    }

    // Make sure that we have a command name

    if (commandName.isEmpty())
        return false;

    // Make sure that we have at least one CLI-enabled plugin

    if (mLoadedCliPlugins.isEmpty()) {
        std::cout << "Sorry, but no plugins could be found to run the command." << std::endl;

        return true;
    }

    // Send the command to the plugin(s)

    foreach (Plugin *plugin, mLoadedCliPlugins)
        if (    commandPlugin.isEmpty()
            || !commandPlugin.compare(plugin->name())) {
            QStringList arguments = pArguments;

            arguments.removeFirst();
            // Note: since the first argument corresponds to the command
            //       itself...

            if (qobject_cast<CliInterface *>(plugin->instance())->executeCommand(commandName, arguments))
                *pRes = -1;
        }

    return true;
}

//==============================================================================

void CliApplication::help() const
{
    // Output some help

    std::cout << "Usage: " << qPrintable(mApp->applicationName())
              << " [-a|--about] [-c|--command [<plugin>::]<command> <options>] [-h|--help] [-p|--plugins] [-s|--status] [-v|--version] [<files>]"
              << std::endl;
    std::cout << " -a, --about     Display some information about OpenCOR"
              << std::endl;
    std::cout << " -c, --command   Send a command to one or all the CLI plugins"
              << std::endl;
    std::cout << " -h, --help      Display this help information"
              << std::endl;
    std::cout << " -p, --plugins   Display all the CLI plugins"
              << std::endl;
    std::cout << " -s, --status    Display the status of all the plugins"
              << std::endl;
    std::cout << " -v, --version   Display the version of OpenCOR"
              << std::endl;
}

//==============================================================================

void CliApplication::plugins() const
{
    // Output some information about our CLI plugins, so first make sure that we
    // have at least one of them

    if (mLoadedCliPlugins.isEmpty()) {
        std::cout << "Sorry, but no CLI plugins could be found." << std::endl;

        return;
    }

    // First, we retrieve all the CLI plugins information

    QStringList pluginsInfo = QStringList();

    foreach (Plugin *plugin, mLoadedCliPlugins) {
        // Retrieve the CLI plugin and its default description

        QString pluginInfo = plugin->name();
        QString pluginDesc = pluginDescription(plugin);

        if (!pluginDesc.isEmpty())
            pluginInfo += ": "+pluginDesc;

        // Add the plugin information to our list

        pluginsInfo << pluginInfo;
    }

    // Now, we can output the plugin information in alphabetical order

    pluginsInfo.sort(Qt::CaseInsensitive);

    if (pluginsInfo.count() == 1)
        std::cout << "The following CLI plugin is available:" << std::endl;
    else
        std::cout << "The following CLI plugins are available:" << std::endl;

    foreach (const QString &pluginInfo, pluginsInfo)
        std::cout << " - " << qPrintable(pluginInfo) << std::endl;
}

//==============================================================================

void CliApplication::status() const
{
    // Output the status of all the plugins that should (have) normally be(en)
    // loaded, so first make sure that we have at least one of them

    if (mPluginManager->loadedPlugins().isEmpty()) {
        std::cout << "Sorry, but no plugins could be found." << std::endl;

        return;
    }

    // First, we retrieve all the plugins information

    QStringList pluginsInfo = QStringList();

    foreach (Plugin *plugin, mPluginManager->plugins()) {
        // Retrieve the plugin and its status

        QString pluginInfo = plugin->name()+": ";

        // Retrieve the plugin's status

        switch (plugin->status()) {
        case Plugin::NotWanted:
            pluginInfo += "the plugin is not wanted.";

            break;
        case Plugin::NotNeeded:
            pluginInfo += "the plugin is not needed.";

            break;
        case Plugin::NotLoaded:
            pluginInfo += QString("the plugin could not be loaded due to the following problem: %1.").arg(Core::formatErrorMessage(plugin->statusErrors(), false));

            break;
        case Plugin::NotPlugin:
            pluginInfo += "this is not a plugin.";

            break;
        case Plugin::NotCorePlugin:
            pluginInfo += "the plugin claims to be the core plugin, but it is not.";

            break;
        case Plugin::InvalidCorePlugin:
            pluginInfo += "the plugin should be the core plugin, but it does not support the core interface.";

            break;
        case Plugin::NotCliPlugin:
            pluginInfo += "the plugin claims to be CLI-capable, but it does not support the CLI interface.";

            break;
        case Plugin::MissingOrInvalidDependencies:
            if (plugin->statusErrorsCount() == 1)
                pluginInfo += QString("the plugin could not be loaded due to the %1 plugin being missing or invalid.").arg(plugin->statusErrors());
            else
                pluginInfo += QString("the plugin could not be loaded due to missing or invalid plugins:\n%1").arg(plugin->statusErrors());

            break;
        default:
            // Plugin::Loaded

            pluginInfo += "the plugin is loaded and fully functional.";
        }

        // Add the plugin information to our list

        pluginsInfo << pluginInfo;
    }

    // Now, we can output the plugin information in alphabetical order

    pluginsInfo.sort(Qt::CaseInsensitive);

    if (pluginsInfo.count() == 1)
        std::cout << "The following plugin is available:" << std::endl;
    else
        std::cout << "The following plugins are available:" << std::endl;

    foreach (const QString &pluginInfo, pluginsInfo)
        std::cout << " - " << qPrintable(pluginInfo) << std::endl;
}

//==============================================================================

void CliApplication::version() const
{
    // Output the version of OpenCOR

    std::cout << qPrintable(OpenCOR::version(mApp)) << std::endl;
}

//==============================================================================

bool CliApplication::run(int *pRes)
{
    // See what needs doing with the CLI options, if anything

    *pRes = 0;   // By default, everything is fine

    bool aboutOption = false;
    bool commandOption = false;
    bool helpOption = false;
    bool pluginsOption = false;
    bool statusOption = false;
    bool versionOption = false;

    QStringList commandArguments = QStringList();

    foreach (const QString &argument, mApp->arguments())
        if (!argument.compare("-a") || !argument.compare("--about")) {
            aboutOption = true;
        } else if (!argument.compare("-c") || !argument.compare("--command")) {
            commandOption = true;
        } else if (!argument.compare("-h") || !argument.compare("--help")) {
            helpOption = true;
        } else if (!argument.compare("-p") || !argument.compare("--plugins")) {
            pluginsOption = true;
        } else if (!argument.compare("-s") || !argument.compare("--status")) {
            statusOption = true;
        } else if (!argument.compare("-v") || !argument.compare("--version")) {
            versionOption = true;
        } else if (argument.startsWith("-")) {
            // The user provided at least one unknown option

            help();

            *pRes = -1;

            break;
        } else if (commandOption) {
            // Not an option, so we consider it to be part of a command

            commandArguments << argument;
        }

    // Handle the option the user requested, if any

    if (!*pRes) {
        if (aboutOption) {
            about();
        } else if (commandOption) {
            // Make sure that we have at least one argument (which would be the
            // command itself) before loading the plugins and then sending the
            // command to the plugin(s)

            if (commandArguments.isEmpty()) {
                help();
            } else {
                loadPlugins();

                if (!command(commandArguments, pRes))
                    help();
            }
        } else if (helpOption) {
            help();
        } else if (pluginsOption) {
            loadPlugins();

            plugins();
        } else if (statusOption) {
            loadPlugins();

            status();
        } else if (versionOption) {
            version();
        } else {
            // The user didn't provide any option which requires running OpenCOR
            // as a CLI application

            return false;
        }
    }

    return true;
}

//==============================================================================

}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla 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.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 *
 * A crc32 calculation for __PPC64__ uses the code from https://github.com/antonblanchard/crc32-vpmsum
 * written by Anton Blanchard <anton@au.ibm.com>, IBM
 */

#pragma once

#include <cstdint>
#include <type_traits>
#include <seastar/net/byteorder.hh>

#if defined(__x86_64__) || defined(__i386__)
#include <smmintrin.h>
#else
#include <zlib.h>
#endif

namespace utils {

class crc32 {
    uint32_t _r = 0;
public:
    // All process() functions assume input is in
    // host byte order (i.e. equivalent to storing
    // the value in a buffer and crcing the buffer).
#if defined(__x86_64__) || defined(__i386__)
    // On x86 use the crc32 instruction added in SSE 4.2.
    void process_le(int8_t in) {
        _r = _mm_crc32_u8(_r, in);
    }
    void process_le(uint8_t in) {
        _r = _mm_crc32_u8(_r, in);
    }
    void process_le(int16_t in) {
        _r = _mm_crc32_u16(_r, in);
    }
    void process_le(uint16_t in) {
        _r = _mm_crc32_u16(_r, in);
    }
    void process_le(int32_t in) {
        _r = _mm_crc32_u32(_r, in);
    }
    void process_le(uint32_t in) {
        _r = _mm_crc32_u32(_r, in);
    }
    void process_le(int64_t in) {
        _r = _mm_crc32_u64(_r, in);
    }
    void process_le(uint64_t in) {
        _r = _mm_crc32_u64(_r, in);
    }

    template <typename T>
    void process_be(T in) {
        in = seastar::net::hton(in);
        process_le(in);
    }

    void process(const uint8_t* in, size_t size) {
        if ((reinterpret_cast<uintptr_t>(in) & 1) && size >= 1) {
            process_le(*in);
            ++in;
            --size;
        }
        if ((reinterpret_cast<uintptr_t>(in) & 3) && size >= 2) {
            process_le(*reinterpret_cast<const uint16_t*>(in));
            in += 2;
            size -= 2;
        }
        if ((reinterpret_cast<uintptr_t>(in) & 7) && size >= 4) {
            process_le(*reinterpret_cast<const uint32_t*>(in));
            in += 4;
            size -= 4;
        }
        // FIXME: do in three parallel loops
        while (size >= 8) {
            process_le(*reinterpret_cast<const uint64_t*>(in));
            in += 8;
            size -= 8;
        }
        if (size >= 4) {
            process_le(*reinterpret_cast<const uint32_t*>(in));
            in += 4;
            size -= 4;
        }
        if (size >= 2) {
            process_le(*reinterpret_cast<const uint16_t*>(in));
            in += 2;
            size -= 2;
        }
        if (size >= 1) {
            process_le(*in);
        }
    }
#elif defined(__PPC64__)
    uint32_t crc32_vpmsum(uint32_t crc, const uint8_t* p, size_t len);

    template <class T>
    void process_le(T in) {
        static_assert(std::is_integral<T>::value, "T must be integral type.");
#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
        switch (sizeof(T)) {
        case 2: in = __builtin_bswap16(in); break;
        case 4: in = __builtin_bswap32(in); break;
        case 8: in = __builtin_bswap64(in); break;
        }
#endif
        _r = crc32_vpmsum(_r, reinterpret_cast<const uint8_t*>(&in), sizeof(T));
    }

    template <class T>
    void process_be(T in) {
        static_assert(std::is_integral<T>::value, "T must be integral type.");
        in = seastar::net::hton(in);
        _r = crc32_vpmsum(_r, reinterpret_cast<const uint8_t*>(&in), sizeof(T));
    }

    void process(const uint8_t* in, size_t size) {
        _r = crc32_vpmsum(_r, in, size);
    }
#else
    template <class T>
    void process_le(T in) {
        static_assert(std::is_integral<T>::value, "T must be integral type.");
#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
        switch (sizeof(T)) {
        case 2: in = __builtin_bswap16(in); break;
        case 4: in = __builtin_bswap32(in); break;
        case 8: in = __builtin_bswap64(in); break;
        }
#endif
        _r = ::crc32(_r, reinterpret_cast<const uint8_t*>(&in), sizeof(T));
    }

    template <class T>
    void process_be(T in) {
        static_assert(std::is_integral<T>::value, "T must be integral type.");
        in = seastar::net::hton(in);
        _r = ::crc32(_r, reinterpret_cast<const uint8_t*>(&in), sizeof(T));
    }

    void process(const uint8_t* in, size_t size) {
        _r = ::crc32(_r, in, size);
    }
#endif
    uint32_t get() const {
        return _r;
    }
};

}
<commit_msg>utils: crc: accept FragmentRange<commit_after>/*
 * Copyright (C) 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla 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.
 *
 * Scylla 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 *
 * A crc32 calculation for __PPC64__ uses the code from https://github.com/antonblanchard/crc32-vpmsum
 * written by Anton Blanchard <anton@au.ibm.com>, IBM
 */

#pragma once

#include <cstdint>
#include <type_traits>
#include <seastar/net/byteorder.hh>

#if defined(__x86_64__) || defined(__i386__)
#include <smmintrin.h>
#else
#include <zlib.h>
#endif

#include "utils/fragment_range.hh"

namespace utils {

class crc32 {
    uint32_t _r = 0;
public:
    // All process() functions assume input is in
    // host byte order (i.e. equivalent to storing
    // the value in a buffer and crcing the buffer).
#if defined(__x86_64__) || defined(__i386__)
    // On x86 use the crc32 instruction added in SSE 4.2.
    void process_le(int8_t in) {
        _r = _mm_crc32_u8(_r, in);
    }
    void process_le(uint8_t in) {
        _r = _mm_crc32_u8(_r, in);
    }
    void process_le(int16_t in) {
        _r = _mm_crc32_u16(_r, in);
    }
    void process_le(uint16_t in) {
        _r = _mm_crc32_u16(_r, in);
    }
    void process_le(int32_t in) {
        _r = _mm_crc32_u32(_r, in);
    }
    void process_le(uint32_t in) {
        _r = _mm_crc32_u32(_r, in);
    }
    void process_le(int64_t in) {
        _r = _mm_crc32_u64(_r, in);
    }
    void process_le(uint64_t in) {
        _r = _mm_crc32_u64(_r, in);
    }

    template <typename T>
    void process_be(T in) {
        in = seastar::net::hton(in);
        process_le(in);
    }

    void process(const uint8_t* in, size_t size) {
        if ((reinterpret_cast<uintptr_t>(in) & 1) && size >= 1) {
            process_le(*in);
            ++in;
            --size;
        }
        if ((reinterpret_cast<uintptr_t>(in) & 3) && size >= 2) {
            process_le(*reinterpret_cast<const uint16_t*>(in));
            in += 2;
            size -= 2;
        }
        if ((reinterpret_cast<uintptr_t>(in) & 7) && size >= 4) {
            process_le(*reinterpret_cast<const uint32_t*>(in));
            in += 4;
            size -= 4;
        }
        // FIXME: do in three parallel loops
        while (size >= 8) {
            process_le(*reinterpret_cast<const uint64_t*>(in));
            in += 8;
            size -= 8;
        }
        if (size >= 4) {
            process_le(*reinterpret_cast<const uint32_t*>(in));
            in += 4;
            size -= 4;
        }
        if (size >= 2) {
            process_le(*reinterpret_cast<const uint16_t*>(in));
            in += 2;
            size -= 2;
        }
        if (size >= 1) {
            process_le(*in);
        }
    }
#elif defined(__PPC64__)
    uint32_t crc32_vpmsum(uint32_t crc, const uint8_t* p, size_t len);

    template <class T>
    void process_le(T in) {
        static_assert(std::is_integral<T>::value, "T must be integral type.");
#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
        switch (sizeof(T)) {
        case 2: in = __builtin_bswap16(in); break;
        case 4: in = __builtin_bswap32(in); break;
        case 8: in = __builtin_bswap64(in); break;
        }
#endif
        _r = crc32_vpmsum(_r, reinterpret_cast<const uint8_t*>(&in), sizeof(T));
    }

    template <class T>
    void process_be(T in) {
        static_assert(std::is_integral<T>::value, "T must be integral type.");
        in = seastar::net::hton(in);
        _r = crc32_vpmsum(_r, reinterpret_cast<const uint8_t*>(&in), sizeof(T));
    }

    void process(const uint8_t* in, size_t size) {
        _r = crc32_vpmsum(_r, in, size);
    }
#else
    template <class T>
    void process_le(T in) {
        static_assert(std::is_integral<T>::value, "T must be integral type.");
#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
        switch (sizeof(T)) {
        case 2: in = __builtin_bswap16(in); break;
        case 4: in = __builtin_bswap32(in); break;
        case 8: in = __builtin_bswap64(in); break;
        }
#endif
        _r = ::crc32(_r, reinterpret_cast<const uint8_t*>(&in), sizeof(T));
    }

    template <class T>
    void process_be(T in) {
        static_assert(std::is_integral<T>::value, "T must be integral type.");
        in = seastar::net::hton(in);
        _r = ::crc32(_r, reinterpret_cast<const uint8_t*>(&in), sizeof(T));
    }

    void process(const uint8_t* in, size_t size) {
        _r = ::crc32(_r, in, size);
    }
#endif

    template<typename FragmentedBuffer>
    GCC6_CONCEPT(requires FragmentRange<FragmentedBuffer>)
    void process_fragmented(const FragmentedBuffer& buffer) {
        using boost::range::for_each;
        for_each(buffer, [this] (bytes_view bv) {
            process(reinterpret_cast<const uint8_t*>(bv.data()), bv.size());
        });
    }

    uint32_t get() const {
        return _r;
    }
};

}
<|endoftext|>


<commit_before>/*
 * TcpIpAsyncClientSsl.hpp
 *
 * Copyright (C) 2009-18 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#ifndef CORE_HTTP_TCP_IP_ASYNC_CLIENT_SSL_HPP
#define CORE_HTTP_TCP_IP_ASYNC_CLIENT_SSL_HPP

#include <boost/scoped_ptr.hpp>

#include <boost/asio/ip/tcp.hpp>

#include "BoostAsioSsl.hpp"

#include <core/http/AsyncClient.hpp>
#include <core/http/TcpIpAsyncConnector.hpp>

namespace rstudio {
namespace core {
namespace http {

class TcpIpAsyncClientSsl
   : public AsyncClient<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> >
{
public:
   TcpIpAsyncClientSsl(boost::asio::io_service& ioService,
                       std::string address,
                       std::string port,
                       bool verify,
                       const std::string& certificateAuthority = std::string(),
                       const boost::posix_time::time_duration& connectionTimeout =
                          boost::posix_time::time_duration(boost::posix_time::pos_infin),
                       const std::string& hostname = std::string() )
     : AsyncClient<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> >(ioService),
       sslContext_(boost::asio::ssl::context::sslv23_client),
       address_(std::move(address)),
       port_(std::move(port)),
       verify_(verify),
       certificateAuthority_(certificateAuthority),
       connectionTimeout_(connectionTimeout)
   {
      if (verify_)
      {
         sslContext_.set_default_verify_paths();
         sslContext_.set_verify_mode(boost::asio::ssl::context::verify_peer);

         if (!certificateAuthority_.empty())
         {
            boost::asio::const_buffer buff(certificateAuthority_.data(), certificateAuthority_.size());
            boost::system::error_code ec;
            sslContext_.add_certificate_authority(buff, ec);
            if (ec)
               LOG_ERROR(Error(ec, ERROR_LOCATION));
         }
      }
      else
      {
         sslContext_.set_verify_mode(boost::asio::ssl::context::verify_none);
      }

      // use scoped ptr so we can call the constructor after we've configured
      // the ssl::context (immediately above)
      ptrSslStream_.reset(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(ioService, sslContext_));

      // Set the SNI so we still work with TLS v1.3
      if (!SSL_set_tlsext_host_name(
            ptrSslStream_->native_handle(),
            (hostname.empty() ? address_.c_str() : hostname.c_str())))
      {
         boost::system::error_code ec{ static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category() };
         LOG_ERROR(Error(ec, ERROR_LOCATION));
      }
   }

protected:

   virtual boost::asio::ssl::stream<boost::asio::ip::tcp::socket>& socket()
   {
      return *(ptrSslStream_);
   }

   virtual void connectAndWriteRequest()
   {
      boost::shared_ptr<TcpIpAsyncConnector> pAsyncConnector(
                  new TcpIpAsyncConnector(ioService(),
                                          &(ptrSslStream_->next_layer())));

      pAsyncConnector->connect(
            address_,
            port_,
            boost::bind(&TcpIpAsyncClientSsl::performHandshake,
                        TcpIpAsyncClientSsl::sharedFromThis()),
            boost::bind(&TcpIpAsyncClientSsl::handleConnectionError,
                        TcpIpAsyncClientSsl::sharedFromThis(),
                        _1),
            connectionTimeout_);
   }

private:

   void performHandshake()
   {
      if (verify_)
      {
         ptrSslStream_->set_verify_callback(
                            boost::asio::ssl::rfc2818_verification(address_));
      }
      ptrSslStream_->async_handshake(
            boost::asio::ssl::stream_base::client,
            boost::bind(&TcpIpAsyncClientSsl::handleHandshake,
                        sharedFromThis(),
                        boost::asio::placeholders::error));
   }

   void handleHandshake(const boost::system::error_code& ec)
   {
      try
      {
         if (!ec)
         {
            // finished handshake, commence with request
            writeRequest();
         }
         else
         {
            handleErrorCode(ec, ERROR_LOCATION);
         }
      }
      CATCH_UNEXPECTED_ASYNC_CLIENT_EXCEPTION
   }

   const boost::shared_ptr<TcpIpAsyncClientSsl> sharedFromThis()
   {
      boost::shared_ptr<AsyncClient<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> > > ptrShared
                                                 = shared_from_this();

      return boost::static_pointer_cast<TcpIpAsyncClientSsl>(ptrShared);
   }

   virtual bool isShutdownError(const boost::system::error_code& ec)
   {
      return util::isSslShutdownError(ec);
   }

private:
   boost::asio::ssl::context sslContext_;
   boost::scoped_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> > ptrSslStream_;
   std::string address_;
   std::string port_;
   bool verify_;
   std::string certificateAuthority_;
   boost::posix_time::time_duration connectionTimeout_;
};

} // namespace http
} // namespace core
} // namespace rstudio

#endif // CORE_HTTP_TCP_IP_ASYNC_CLIENT_SSL_HPP
<commit_msg>improve comment<commit_after>/*
 * TcpIpAsyncClientSsl.hpp
 *
 * Copyright (C) 2009-18 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#ifndef CORE_HTTP_TCP_IP_ASYNC_CLIENT_SSL_HPP
#define CORE_HTTP_TCP_IP_ASYNC_CLIENT_SSL_HPP

#include <boost/scoped_ptr.hpp>

#include <boost/asio/ip/tcp.hpp>

#include "BoostAsioSsl.hpp"

#include <core/http/AsyncClient.hpp>
#include <core/http/TcpIpAsyncConnector.hpp>

namespace rstudio {
namespace core {
namespace http {

class TcpIpAsyncClientSsl
   : public AsyncClient<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> >
{
public:
   TcpIpAsyncClientSsl(boost::asio::io_service& ioService,
                       std::string address,
                       std::string port,
                       bool verify,
                       const std::string& certificateAuthority = std::string(),
                       const boost::posix_time::time_duration& connectionTimeout =
                          boost::posix_time::time_duration(boost::posix_time::pos_infin),
                       const std::string& hostname = std::string() )
     : AsyncClient<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> >(ioService),
       sslContext_(boost::asio::ssl::context::sslv23_client),
       address_(std::move(address)),
       port_(std::move(port)),
       verify_(verify),
       certificateAuthority_(certificateAuthority),
       connectionTimeout_(connectionTimeout)
   {
      if (verify_)
      {
         sslContext_.set_default_verify_paths();
         sslContext_.set_verify_mode(boost::asio::ssl::context::verify_peer);

         if (!certificateAuthority_.empty())
         {
            boost::asio::const_buffer buff(certificateAuthority_.data(), certificateAuthority_.size());
            boost::system::error_code ec;
            sslContext_.add_certificate_authority(buff, ec);
            if (ec)
               LOG_ERROR(Error(ec, ERROR_LOCATION));
         }
      }
      else
      {
         sslContext_.set_verify_mode(boost::asio::ssl::context::verify_none);
      }

      // use scoped ptr so we can call the constructor after we've configured
      // the ssl::context (immediately above)
      ptrSslStream_.reset(new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(ioService, sslContext_));

      // TLS v1.3 requires that the SNI be set, so set the SNI.
      if (!SSL_set_tlsext_host_name(
            ptrSslStream_->native_handle(),
            (hostname.empty() ? address_.c_str() : hostname.c_str())))
      {
         boost::system::error_code ec{ static_cast<int>(::ERR_get_error()), boost::asio::error::get_ssl_category() };
         LOG_ERROR(Error(ec, ERROR_LOCATION));
      }
   }

protected:

   virtual boost::asio::ssl::stream<boost::asio::ip::tcp::socket>& socket()
   {
      return *(ptrSslStream_);
   }

   virtual void connectAndWriteRequest()
   {
      boost::shared_ptr<TcpIpAsyncConnector> pAsyncConnector(
                  new TcpIpAsyncConnector(ioService(),
                                          &(ptrSslStream_->next_layer())));

      pAsyncConnector->connect(
            address_,
            port_,
            boost::bind(&TcpIpAsyncClientSsl::performHandshake,
                        TcpIpAsyncClientSsl::sharedFromThis()),
            boost::bind(&TcpIpAsyncClientSsl::handleConnectionError,
                        TcpIpAsyncClientSsl::sharedFromThis(),
                        _1),
            connectionTimeout_);
   }

private:

   void performHandshake()
   {
      if (verify_)
      {
         ptrSslStream_->set_verify_callback(
                            boost::asio::ssl::rfc2818_verification(address_));
      }
      ptrSslStream_->async_handshake(
            boost::asio::ssl::stream_base::client,
            boost::bind(&TcpIpAsyncClientSsl::handleHandshake,
                        sharedFromThis(),
                        boost::asio::placeholders::error));
   }

   void handleHandshake(const boost::system::error_code& ec)
   {
      try
      {
         if (!ec)
         {
            // finished handshake, commence with request
            writeRequest();
         }
         else
         {
            handleErrorCode(ec, ERROR_LOCATION);
         }
      }
      CATCH_UNEXPECTED_ASYNC_CLIENT_EXCEPTION
   }

   const boost::shared_ptr<TcpIpAsyncClientSsl> sharedFromThis()
   {
      boost::shared_ptr<AsyncClient<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> > > ptrShared
                                                 = shared_from_this();

      return boost::static_pointer_cast<TcpIpAsyncClientSsl>(ptrShared);
   }

   virtual bool isShutdownError(const boost::system::error_code& ec)
   {
      return util::isSslShutdownError(ec);
   }

private:
   boost::asio::ssl::context sslContext_;
   boost::scoped_ptr<boost::asio::ssl::stream<boost::asio::ip::tcp::socket> > ptrSslStream_;
   std::string address_;
   std::string port_;
   bool verify_;
   std::string certificateAuthority_;
   boost::posix_time::time_duration connectionTimeout_;
};

} // namespace http
} // namespace core
} // namespace rstudio

#endif // CORE_HTTP_TCP_IP_ASYNC_CLIENT_SSL_HPP
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it 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.
**
****************************************************************************/

#include "mscalableimage.h"
#include "mscalableimage_p.h"
#include "mgles2renderer.h"

#include <mtheme.h>

#include <QPainter>
#include <MDebug>
#include <MComponentData>
#include <MDebug>

MScalableImagePrivate::MScalableImagePrivate()
    : m_imageType(MScalable9), m_image(NULL),
      m_useGLRenderer(false), q_ptr(NULL)
{
}

MScalableImagePrivate::~MScalableImagePrivate()
{
}

void MScalableImagePrivate::validateSize() const
{
    if (!m_image) {
        return;
    }

    int w = m_image->width();
    int h = m_image->height();

    int cornerWidth = 0;
    int cornerHeight = 0;
    if (m_imageType == MScalable9) {
        cornerWidth =  m_preferredMargins.left() + m_preferredMargins.right();
        cornerHeight = m_preferredMargins.top() + m_preferredMargins.bottom();
    }

    if ( (w < cornerWidth || h < cornerHeight) && !(w == 1 && h == 1) ) //1x1 means a temporary pixmap
        mWarning("MScalableImage") << QString("The size of the image '%1', %2x%3, is smaller than combined corner size %4x%5. This might cause rendering artifacts.").arg(pixmapId).arg(w).arg(h).arg(cornerWidth).arg(cornerHeight);
}

void MScalableImagePrivate::drawScalable9(int x, int y, int w, int h, QPainter *painter) const
{
    QMargins margins = m_preferredMargins;

    if( w == -1 )
        w = m_image->width();
    if( h == -1 )
        h = m_image->height();

    int cornerWidth = 0;
    int cornerHeight = 0;
    if( m_imageType == MScalable9 ) {
        cornerWidth = margins.left() + margins.right();
        cornerHeight = margins.top() + margins.bottom();
    }

    //Make sure that the size of the drawn image is
    //bigger than the 4 corner blocks. If necessary,
    //use smaller border values than those set with setBorders API
    //call.
    if (w < cornerWidth) {
        margins.setLeft(qMax(0, margins.left() - (cornerWidth - w + 1) / 2));
        margins.setRight(qMax(0, margins.right() - (cornerWidth - w + 1) / 2));
    }
    if (h < cornerHeight) {
        margins.setTop(qMax(0, margins.top() - (cornerHeight - h + 1) / 2));
        margins.setBottom(qMax(0, margins.bottom() - (cornerHeight - h + 1) / 2));
    }

    if (w <= 0 || h <= 0) {
        // this should really not happen
        mWarning("MScalableImage") <<
            "Received request to draw pixmap of invalid size" << w << "x" << h;
        return;
    }

    //the image is used in it's native size
    //no need to scale just draw it
    QSize requiredSize(w, h);
    if (m_image->size() == requiredSize) {
        painter->drawPixmap(x, y, *m_image);
        return;
    }
    else {
        //the image doesn't fit directly into the required size.
        //check whether or not we're allowed to cache
        bool docache = MComponentData::softwareRendering();

        if (docache) {
            //software rendering is not fast when scaling pixmaps, so we use the
            //global pixmap cache to avoid rescaling more than needed.
            //
            //TODO: this cache gets thrashed a bit with widgetsgallery, may want to look into possibly
            //increasing the size of QPixmapCache.
            QString key = QString("msi-%1-%2,%3").arg((*m_image).cacheKey()).arg(w).arg(h);
            QPixmap scaled;
            if (QPixmapCache::find(key, &scaled)) {
                //cached! draw and we're done
                painter->drawPixmap(x, y, scaled);
                return;
            }

            // draw into cache
            scaled = QPixmap(requiredSize);
            scaled.fill(Qt::transparent);
            QPainter p;
            p.begin(&scaled);
            p.setRenderHint(QPainter::SmoothPixmapTransform);
            qDrawBorderPixmap(&p, QRect(0, 0, w, h), margins, *m_image);
            p.end();

            // draw to screen
            painter->drawPixmap(x, y, scaled);
            QPixmapCache::insert(key, scaled);
        } else {
            // caching isn't permitted for this case; scale and render direct to screen.
            bool enabled = painter->renderHints() & QPainter::SmoothPixmapTransform;
            painter->setRenderHint(QPainter::SmoothPixmapTransform);
            qDrawBorderPixmap(painter, QRect(x, y, w, h), margins, *m_image);
            painter->setRenderHint(QPainter::SmoothPixmapTransform, enabled);
        }
    }
}

void MScalableImagePrivate::drawScalable1(int x, int y, int w, int h, QPainter *painter) const
{
    //the image is used in it's native size
    //no need to scale just draw it
    if( m_image->size() == QSize(w, h) ) {
        painter->drawPixmap(QRect(x, y, w, h), *m_image, m_image->rect());
    }
    //the image needs some scaling, draw the image using smooth scaling
    else {
        bool enabled = painter->renderHints() & QPainter::SmoothPixmapTransform;
        painter->setRenderHint(QPainter::SmoothPixmapTransform);
        painter->drawPixmap(QRect(x, y, w, h), *m_image, m_image->rect());
        painter->setRenderHint(QPainter::SmoothPixmapTransform, enabled);
    }
}

MScalableImage::MScalableImage()
    : d_ptr(new MScalableImagePrivate())
{
    Q_D(MScalableImage);
    d->q_ptr = this;
}

MScalableImage::MScalableImage(const QPixmap *pixmap, int left, int right, int top, int bottom, const QString &pixmapId)
    : d_ptr(new MScalableImagePrivate())
{
    Q_D(MScalableImage);
    d->q_ptr = this;

    setBorders(left, right, top, bottom);

    d->m_image = pixmap;
    d->pixmapId = pixmapId;
    d->validateSize();
}

MScalableImage::MScalableImage(MScalableImagePrivate *dd)
    : d_ptr(dd)
{
    Q_D(MScalableImage);
    d->q_ptr = this;
}

MScalableImage::~MScalableImage()
{
    delete d_ptr;
}

void MScalableImage::borders(int *left, int *right, int *top, int *bottom) const
{
    Q_D(const MScalableImage);

    if (left != NULL) {
        *left = d->m_preferredMargins.left();
    }
    if (right != NULL) {
        *right = d->m_preferredMargins.right();
    }
    if (top != NULL) {
        *top = d->m_preferredMargins.top();
    }
    if (bottom != NULL) {
        *bottom = d->m_preferredMargins.bottom();
    }
}

void MScalableImage::setBorders(int left, int right, int top, int bottom)
{
    Q_D(MScalableImage);

    d->m_preferredMargins = QMargins(left, top, right, bottom);

    if (d->m_preferredMargins.isNull()) {
        d->m_imageType = MScalableImagePrivate::MScalable1;
    }
    /*else if( (top == 0 && bottom == 0) ) {//&& (right != 0 && left != 0 ) ) {
        d->m_imageType = MScalableImagePrivate::MScalable3H;
        mDebug("MScalableImage) << "************** MScalable3H *************";
    }
    else if( (right == 0 && left == 0) ) {//&& (top != 0 &&  bottom != 0 ) ) {
        d->m_imageType = MScalableImagePrivate::MScalable3V;
        mDebug("MScalableImage) << "************** MScalable3V *************";
    }*/
    else {
        d->m_imageType = MScalableImagePrivate::MScalable9;
    }
    d->validateSize();
}

void MScalableImage::setPixmap(const QPixmap *pixmap)
{
    Q_D(MScalableImage);

    d->m_image = pixmap;
    d->pixmapId = "";

    d->validateSize();
}

const QPixmap *MScalableImage::pixmap() const
{
    Q_D(const MScalableImage);
    return d->m_image;
}

void MScalableImage::draw(int x, int y, int w, int h, QPainter *painter) const
{
    Q_D(const MScalableImage);

    if (!d->m_image) {
        mWarning("MScalableImage") << "MScalableImage::draw() scalable image: " << d->pixmapId << " not properly initialized yet";
        painter->fillRect(QRect(x, y, w, h), QColor(255, 0, 0));
        return;
    }

    switch (d->m_imageType) {
    case MScalableImagePrivate::MScalable1:
        d->drawScalable1(x, y, w, h, painter);
        break;
    case MScalableImagePrivate::MScalable9:
        d->drawScalable9(x, y, w, h, painter);
        break;
    default:
        mWarning("MScalableImage") << d->pixmapId << " draw() unsupported type " << d->m_imageType;
    }
}

void MScalableImage::draw(const QPoint &pos, const QSize &size, QPainter *painter) const
{
    draw(pos.x(), pos.y(), size.width(), size.height(), painter);
}

void MScalableImage::draw(const QRect &rect, QPainter *painter) const
{
    draw(rect.x(), rect.y(), rect.width(), rect.height(), painter);
}

void MScalableImage::enableOptimizedRendering(bool enable)
{
    Q_D(MScalableImage);
    d->m_useGLRenderer = enable;
}

void MScalableImage::draw(const QRect &rect, const QPoint& pixmapOffset, const QPixmap* pixmap, QPainter *painter) const
{
    if(!pixmap || pixmap->isNull()) {
        // if the pixmap is not valid, draw without filling
        draw(rect, painter);
        return;
    }
    // TODO: create HW version with proper shaders (2 textures, 2 sets of texcoords + shader)

    // SLOW: SW fallback, create temporary render target
    QImage image(rect.size(), QImage::Format_ARGB32);
    image.fill(Qt::transparent);

    // paint scalable image to target
    QPainter imagePainter(&image);
    draw(QPoint(0,0), rect.size(), &imagePainter);

    // post process the resulting image (add mask)
    QImage fillImage = pixmap->toImage();
    int sourceWidth = fillImage.width();
    int sourceHeight = fillImage.height();

    int width = image.width();
    int height = image.height();

    for (int y = 0; y < height; ++y) {
        // target scanline
        uint* target = (uint *) image.scanLine(y);
        // source scanline (tiled)
        const uint* source = (const uint *) fillImage.scanLine(pixmapOffset.y() + (y % sourceHeight));
        for (int x = 0; x < width; ++x) {
            // tile the x coordinate
            uint color = *(source + ((pixmapOffset.x() + x) % sourceWidth));
            // alpha comes from target, colour from source
            *target = ((*target) & 0xff000000) | (color & 0x00ffffff);
            target++;
        }
    }

    painter->drawImage(rect, image);
}

<commit_msg>Fixes: NB#178254 - Rendering performance drop on N900<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it 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.
**
****************************************************************************/

#include "mscalableimage.h"
#include "mscalableimage_p.h"
#include "mgles2renderer.h"

#include <mtheme.h>

#include <QPainter>
#include <MDebug>
#include <MComponentData>
#include <MDebug>

MScalableImagePrivate::MScalableImagePrivate()
    : m_imageType(MScalable9), m_image(NULL),
      m_useGLRenderer(false), q_ptr(NULL)
{
}

MScalableImagePrivate::~MScalableImagePrivate()
{
}

void MScalableImagePrivate::validateSize() const
{
    if (!m_image) {
        return;
    }

    int w = m_image->width();
    int h = m_image->height();

    int cornerWidth = 0;
    int cornerHeight = 0;
    if (m_imageType == MScalable9) {
        cornerWidth =  m_preferredMargins.left() + m_preferredMargins.right();
        cornerHeight = m_preferredMargins.top() + m_preferredMargins.bottom();
    }

    if ( (w < cornerWidth || h < cornerHeight) && !(w == 1 && h == 1) ) //1x1 means a temporary pixmap
        mWarning("MScalableImage") << QString("The size of the image '%1', %2x%3, is smaller than combined corner size %4x%5. This might cause rendering artifacts.").arg(pixmapId).arg(w).arg(h).arg(cornerWidth).arg(cornerHeight);
}

void MScalableImagePrivate::drawScalable9(int x, int y, int w, int h, QPainter *painter) const
{
    QMargins margins = m_preferredMargins;

    if( w == -1 )
        w = m_image->width();
    if( h == -1 )
        h = m_image->height();

    int cornerWidth = 0;
    int cornerHeight = 0;
    if( m_imageType == MScalable9 ) {
        cornerWidth = margins.left() + margins.right();
        cornerHeight = margins.top() + margins.bottom();
    }

    //Make sure that the size of the drawn image is
    //bigger than the 4 corner blocks. If necessary,
    //use smaller border values than those set with setBorders API
    //call.
    if (w < cornerWidth) {
        margins.setLeft(qMax(0, margins.left() - (cornerWidth - w + 1) / 2));
        margins.setRight(qMax(0, margins.right() - (cornerWidth - w + 1) / 2));
    }
    if (h < cornerHeight) {
        margins.setTop(qMax(0, margins.top() - (cornerHeight - h + 1) / 2));
        margins.setBottom(qMax(0, margins.bottom() - (cornerHeight - h + 1) / 2));
    }

    if (w <= 0 || h <= 0) {
        // this should really not happen
        mWarning("MScalableImage") <<
            "Received request to draw pixmap of invalid size" << w << "x" << h;
        return;
    }

    //the image is used in it's native size
    //no need to scale just draw it
    QSize requiredSize(w, h);
    if (m_image->size() == requiredSize) {
        painter->drawPixmap(x, y, *m_image);
        return;
    }
    else {
        //the image doesn't fit directly into the required size.
        //check whether or not we're allowed to cache
        bool docache = MComponentData::softwareRendering();

        if (docache) {
            //software rendering is not fast when scaling pixmaps, so we use the
            //global pixmap cache to avoid rescaling more than needed.
            //
            //TODO: this cache gets thrashed a bit with widgetsgallery, may want to look into possibly
            //increasing the size of QPixmapCache.
            QString key = QString("msi-%1-%2,%3").arg((*m_image).cacheKey()).arg(w).arg(h);
            QPixmap scaled;
            if (QPixmapCache::find(key, &scaled)) {
                //cached! draw and we're done
                painter->drawPixmap(x, y, scaled);
                return;
            }

            // draw into cache
            scaled = QPixmap(requiredSize);
            scaled.fill(Qt::transparent);
            QPainter p;
            p.begin(&scaled);
            p.setRenderHint(QPainter::SmoothPixmapTransform);
            qDrawBorderPixmap(&p, QRect(0, 0, w, h), margins, *m_image);
            p.end();

            // draw to screen
            painter->drawPixmap(x, y, scaled);
            QPixmapCache::insert(key, scaled);
        } else {
            // caching isn't permitted for this case; scale and render direct to screen.
            #if defined(HAVE_N900)
                // don't use smooth pixmap transformation on the N900, as this
                // decreases the performance
                qDrawBorderPixmap(painter, QRect(x, y, w, h), margins, *m_image);
            #else
                bool enabled = painter->renderHints() & QPainter::SmoothPixmapTransform;
                painter->setRenderHint(QPainter::SmoothPixmapTransform);
                qDrawBorderPixmap(painter, QRect(x, y, w, h), margins, *m_image);
                painter->setRenderHint(QPainter::SmoothPixmapTransform, enabled);
            #endif
        }
    }
}

void MScalableImagePrivate::drawScalable1(int x, int y, int w, int h, QPainter *painter) const
{
#if defined(HAVE_N900)
    // don't use smooth pixmap transformation on the N900, as this
    // decreases the performance
    painter->drawPixmap(QRect(x, y, w, h), *m_image, m_image->rect());
#else
    //the image is used in it's native size
    //no need to scale just draw it
    if( m_image->size() == QSize(w, h) ) {
        painter->drawPixmap(QRect(x, y, w, h), *m_image, m_image->rect());
    }
    //the image needs some scaling, draw the image using smooth scaling
    else {
        bool enabled = painter->renderHints() & QPainter::SmoothPixmapTransform;
        painter->setRenderHint(QPainter::SmoothPixmapTransform);
        painter->drawPixmap(QRect(x, y, w, h), *m_image, m_image->rect());
        painter->setRenderHint(QPainter::SmoothPixmapTransform, enabled);
    }
#endif
}

MScalableImage::MScalableImage()
    : d_ptr(new MScalableImagePrivate())
{
    Q_D(MScalableImage);
    d->q_ptr = this;
}

MScalableImage::MScalableImage(const QPixmap *pixmap, int left, int right, int top, int bottom, const QString &pixmapId)
    : d_ptr(new MScalableImagePrivate())
{
    Q_D(MScalableImage);
    d->q_ptr = this;

    setBorders(left, right, top, bottom);

    d->m_image = pixmap;
    d->pixmapId = pixmapId;
    d->validateSize();
}

MScalableImage::MScalableImage(MScalableImagePrivate *dd)
    : d_ptr(dd)
{
    Q_D(MScalableImage);
    d->q_ptr = this;
}

MScalableImage::~MScalableImage()
{
    delete d_ptr;
}

void MScalableImage::borders(int *left, int *right, int *top, int *bottom) const
{
    Q_D(const MScalableImage);

    if (left != NULL) {
        *left = d->m_preferredMargins.left();
    }
    if (right != NULL) {
        *right = d->m_preferredMargins.right();
    }
    if (top != NULL) {
        *top = d->m_preferredMargins.top();
    }
    if (bottom != NULL) {
        *bottom = d->m_preferredMargins.bottom();
    }
}

void MScalableImage::setBorders(int left, int right, int top, int bottom)
{
    Q_D(MScalableImage);

    d->m_preferredMargins = QMargins(left, top, right, bottom);

    if (d->m_preferredMargins.isNull()) {
        d->m_imageType = MScalableImagePrivate::MScalable1;
    }
    /*else if( (top == 0 && bottom == 0) ) {//&& (right != 0 && left != 0 ) ) {
        d->m_imageType = MScalableImagePrivate::MScalable3H;
        mDebug("MScalableImage) << "************** MScalable3H *************";
    }
    else if( (right == 0 && left == 0) ) {//&& (top != 0 &&  bottom != 0 ) ) {
        d->m_imageType = MScalableImagePrivate::MScalable3V;
        mDebug("MScalableImage) << "************** MScalable3V *************";
    }*/
    else {
        d->m_imageType = MScalableImagePrivate::MScalable9;
    }
    d->validateSize();
}

void MScalableImage::setPixmap(const QPixmap *pixmap)
{
    Q_D(MScalableImage);

    d->m_image = pixmap;
    d->pixmapId = "";

    d->validateSize();
}

const QPixmap *MScalableImage::pixmap() const
{
    Q_D(const MScalableImage);
    return d->m_image;
}

void MScalableImage::draw(int x, int y, int w, int h, QPainter *painter) const
{
    Q_D(const MScalableImage);

    if (!d->m_image) {
        mWarning("MScalableImage") << "MScalableImage::draw() scalable image: " << d->pixmapId << " not properly initialized yet";
        painter->fillRect(QRect(x, y, w, h), QColor(255, 0, 0));
        return;
    }

    switch (d->m_imageType) {
    case MScalableImagePrivate::MScalable1:
        d->drawScalable1(x, y, w, h, painter);
        break;
    case MScalableImagePrivate::MScalable9:
        d->drawScalable9(x, y, w, h, painter);
        break;
    default:
        mWarning("MScalableImage") << d->pixmapId << " draw() unsupported type " << d->m_imageType;
    }
}

void MScalableImage::draw(const QPoint &pos, const QSize &size, QPainter *painter) const
{
    draw(pos.x(), pos.y(), size.width(), size.height(), painter);
}

void MScalableImage::draw(const QRect &rect, QPainter *painter) const
{
    draw(rect.x(), rect.y(), rect.width(), rect.height(), painter);
}

void MScalableImage::enableOptimizedRendering(bool enable)
{
    Q_D(MScalableImage);
    d->m_useGLRenderer = enable;
}

void MScalableImage::draw(const QRect &rect, const QPoint& pixmapOffset, const QPixmap* pixmap, QPainter *painter) const
{
    if(!pixmap || pixmap->isNull()) {
        // if the pixmap is not valid, draw without filling
        draw(rect, painter);
        return;
    }
    // TODO: create HW version with proper shaders (2 textures, 2 sets of texcoords + shader)

    // SLOW: SW fallback, create temporary render target
    QImage image(rect.size(), QImage::Format_ARGB32);
    image.fill(Qt::transparent);

    // paint scalable image to target
    QPainter imagePainter(&image);
    draw(QPoint(0,0), rect.size(), &imagePainter);

    // post process the resulting image (add mask)
    QImage fillImage = pixmap->toImage();
    int sourceWidth = fillImage.width();
    int sourceHeight = fillImage.height();

    int width = image.width();
    int height = image.height();

    for (int y = 0; y < height; ++y) {
        // target scanline
        uint* target = (uint *) image.scanLine(y);
        // source scanline (tiled)
        const uint* source = (const uint *) fillImage.scanLine(pixmapOffset.y() + (y % sourceHeight));
        for (int x = 0; x < width; ++x) {
            // tile the x coordinate
            uint color = *(source + ((pixmapOffset.x() + x) % sourceWidth));
            // alpha comes from target, colour from source
            *target = ((*target) & 0xff000000) | (color & 0x00ffffff);
            target++;
        }
    }

    painter->drawImage(rect, image);
}

<|endoftext|>


<commit_before>#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ds3.h"
#include "test.h"
#include <boost/test/unit_test.hpp>
#include "checksum.h"

#define FILE_TEMPLATE "bulk-XXXXXX"

BOOST_AUTO_TEST_CASE( bulk_get ) {
    uint64_t i, n;
    uint64_t file_index = 0;
    ds3_request* request = NULL;
    ds3_error* error = NULL;
    ds3_bulk_response* completed_job = NULL;
    ds3_get_bucket_response* response = NULL;
    ds3_bulk_response* bulk_response = NULL;
    ds3_bulk_object_list* object_list = NULL;
    ds3_get_available_chunks_response* chunk_response = NULL;
    bool retry_get;

    ds3_client* client = get_client();
    const char* bucket_name = "unit_test_bucket";
    char* orignal_file_path [5];

    char** tmp_files;

    populate_with_objects(client, bucket_name);

    request = ds3_init_get_bucket(bucket_name);
    error = ds3_get_bucket(client, request, &response);

    ds3_free_request(request);

    BOOST_REQUIRE(error == NULL);

    tmp_files = (char**) calloc(response->num_objects, sizeof(char*));

    object_list = ds3_convert_object_list(response->objects, response->num_objects);

    ds3_free_bucket_response(response);

    request = ds3_init_get_bulk(bucket_name, object_list, NONE);
    error = ds3_bulk(client, request, &bulk_response);

    ds3_free_request(request);
    ds3_free_bulk_object_list(object_list);

    BOOST_REQUIRE(error == NULL);

    do {
        retry_get = false;
        request = ds3_init_get_available_chunks(bulk_response->job_id->value);

        error = ds3_get_available_chunks(client, request, &chunk_response);

        ds3_free_request(request);

        BOOST_REQUIRE(error == NULL);

        BOOST_REQUIRE(chunk_response != NULL);

        if (chunk_response->object_list->list_size == 0) {
            // if this happens we need to try the request
            retry_get = true;
            BOOST_TEST_MESSAGE( "Hit retry, sleeping for: " << chunk_response->retry_after) ;
            sleep(chunk_response->retry_after);
        }

    } while(retry_get);

    BOOST_REQUIRE(error == NULL);

    bool checksum_passed = true;

    for (i = 0; i < chunk_response->object_list->list_size; i++) {
        ds3_bulk_object_list* chunk_object_list = chunk_response->object_list->list[i];
        for(n = 0; n < chunk_object_list->size; n++, file_index++) {
            FILE* w_file;
            ds3_bulk_object current_obj = chunk_object_list->list[n];
            request = ds3_init_get_object_for_job(bucket_name, current_obj.name->value, current_obj.offset, bulk_response->job_id->value);
            orignal_file_path[file_index] = current_obj.name->value;
            tmp_files[file_index] = (char*) calloc(12, sizeof(char));
            memcpy(tmp_files[file_index], FILE_TEMPLATE, 11);
            w_file = fopen(tmp_files[file_index], "w+");
            error = ds3_get_object(client, request, w_file, ds3_write_to_file);
            ds3_free_request(request);
            fclose(w_file);
            handle_error(error);
            printf("------Performing Data Integrity Test-------\n");
            checksum_passed = checksum_passed && compare_hash(orignal_file_path[file_index],tmp_files[file_index]);
            printf("\n");
        }
    }

    for (i = 0; i < file_index; i++) {
        unlink(tmp_files[i]);
        free(tmp_files[i]);
    }

    free(tmp_files);

    BOOST_CHECK(checksum_passed == true);

    // check to make sure that the 'job' has completed
    request = ds3_init_get_job(bulk_response->job_id->value);
    error = ds3_get_job(client, request, &completed_job);

    BOOST_CHECK(completed_job != NULL);
    BOOST_CHECK(completed_job->status == COMPLETED);

    ds3_free_request(request);
    ds3_free_available_chunks_response(chunk_response);
    ds3_free_bulk_response(completed_job);
    ds3_free_bulk_response(bulk_response);

    clear_bucket(client, bucket_name);
    free_client(client);
    handle_error(error);
}

BOOST_AUTO_TEST_CASE( max_upload_size ) {
    uint64_t i, n;
    uint64_t file_index = 0;
    ds3_request* request = NULL;
    ds3_error* error = NULL;
    ds3_bulk_response* completed_job = NULL;
    ds3_get_bucket_response* response = NULL;
    ds3_bulk_response* bulk_response = NULL;
    ds3_bulk_object_list* object_list = NULL;
    ds3_get_available_chunks_response* chunk_response = NULL;
    bool retry_get;

    ds3_client* client = get_client();
    const char* bucket_name = "unit_test_bucket";
    char* orignal_file_path [5];

    char** tmp_files;

    populate_with_objects(client, bucket_name, 10485760);

    request = ds3_init_get_bucket(bucket_name);
    error = ds3_get_bucket(client, request, &response);

    ds3_free_request(request);

    BOOST_REQUIRE(error == NULL);

    tmp_files = (char**) calloc(response->num_objects, sizeof(char*));

    object_list = ds3_convert_object_list(response->objects, response->num_objects);

    ds3_free_bucket_response(response);

    request = ds3_init_get_bulk(bucket_name, object_list, NONE);
    error = ds3_bulk(client, request, &bulk_response);

    ds3_free_request(request);
    ds3_free_bulk_object_list(object_list);

    BOOST_REQUIRE(error == NULL);

    do {
        retry_get = false;
        request = ds3_init_get_available_chunks(bulk_response->job_id->value);

        error = ds3_get_available_chunks(client, request, &chunk_response);

        ds3_free_request(request);

        BOOST_REQUIRE(error == NULL);

        BOOST_REQUIRE(chunk_response != NULL);

        BOOST_REQUIRE(chunk_response != NULL);

        if (chunk_response->object_list->list_size == 0) {
            // if this happens we need to try the request
            retry_get = true;
            BOOST_TEST_MESSAGE( "Hit retry, sleeping for: " << chunk_response->retry_after) ;
            sleep(chunk_response->retry_after);
        }

    } while(retry_get);

    BOOST_REQUIRE(error == NULL);

    bool checksum_passed = true;

    for (i = 0; i < chunk_response->object_list->list_size; i++) {
        ds3_bulk_object_list* chunk_object_list = chunk_response->object_list->list[i];
        for(n = 0; n < chunk_object_list->size; n++, file_index++) {
            FILE* w_file;
            ds3_bulk_object current_obj = chunk_object_list->list[n];
            request = ds3_init_get_object_for_job(bucket_name, current_obj.name->value, current_obj.offset, bulk_response->job_id->value);
            orignal_file_path[file_index] = current_obj.name->value;
            tmp_files[file_index] = (char*) calloc(12, sizeof(char));
            memcpy(tmp_files[file_index], FILE_TEMPLATE, 11);
            w_file = fopen(tmp_files[file_index], "w+");
            error = ds3_get_object(client, request, w_file, ds3_write_to_file);
            ds3_free_request(request);
            fclose(w_file);
            handle_error(error);
            printf("------Performing Data Integrity Test-------\n");
            checksum_passed = checksum_passed && compare_hash(orignal_file_path[file_index],tmp_files[file_index]);
            printf("\n");
        }
    }

    for (i = 0; i < file_index; i++) {
        unlink(tmp_files[i]);
        free(tmp_files[i]);
    }

    free(tmp_files);

    BOOST_CHECK(checksum_passed == true);

    // check to make sure that the 'job' has completed
    request = ds3_init_get_job(bulk_response->job_id->value);
    error = ds3_get_job(client, request, &completed_job);

    BOOST_CHECK(completed_job != NULL);
    BOOST_CHECK(completed_job->status == COMPLETED);

    ds3_free_request(request);
    ds3_free_available_chunks_response(chunk_response);
    ds3_free_bulk_response(completed_job);
    ds3_free_bulk_response(bulk_response);

    clear_bucket(client, bucket_name);
    free_client(client);
    handle_error(error);
}

BOOST_AUTO_TEST_CASE( convert_list_helper ) {
    const char* books[4] ={"beowulf.txt", "sherlock_holmes.txt", "tale_of_two_cities.txt", "ulysses.txt"};
    ds3_bulk_object_list* obj_list;

    obj_list = ds3_convert_file_list_with_basepath(books, 4, "resources/");

    BOOST_CHECK(strcmp(obj_list->list[0].name->value, "beowulf.txt") == 0);
    BOOST_CHECK(obj_list->list[0].length == 294059);

    ds3_free_bulk_object_list(obj_list);
}

BOOST_AUTO_TEST_CASE( directory_size ) {
    const char* books[1] ={"resources"};
    ds3_bulk_object_list* obj_list;

    obj_list = ds3_convert_file_list_with_basepath(books, 1, NULL);

    BOOST_CHECK(strcmp(obj_list->list[0].name->value, "resources") == 0);
    BOOST_CHECK(obj_list->list[0].length == 0);

    ds3_free_bulk_object_list(obj_list);
}
<commit_msg>removed incorrect line<commit_after>#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ds3.h"
#include "test.h"
#include <boost/test/unit_test.hpp>
#include "checksum.h"

#define FILE_TEMPLATE "bulk-XXXXXX"

BOOST_AUTO_TEST_CASE( bulk_get ) {
    uint64_t i, n;
    uint64_t file_index = 0;
    ds3_request* request = NULL;
    ds3_error* error = NULL;
    ds3_bulk_response* completed_job = NULL;
    ds3_get_bucket_response* response = NULL;
    ds3_bulk_response* bulk_response = NULL;
    ds3_bulk_object_list* object_list = NULL;
    ds3_get_available_chunks_response* chunk_response = NULL;
    bool retry_get;

    ds3_client* client = get_client();
    const char* bucket_name = "unit_test_bucket";
    char* orignal_file_path [5];

    char** tmp_files;

    populate_with_objects(client, bucket_name);

    request = ds3_init_get_bucket(bucket_name);
    error = ds3_get_bucket(client, request, &response);

    ds3_free_request(request);

    BOOST_REQUIRE(error == NULL);

    tmp_files = (char**) calloc(response->num_objects, sizeof(char*));

    object_list = ds3_convert_object_list(response->objects, response->num_objects);

    ds3_free_bucket_response(response);

    request = ds3_init_get_bulk(bucket_name, object_list, NONE);
    error = ds3_bulk(client, request, &bulk_response);

    ds3_free_request(request);
    ds3_free_bulk_object_list(object_list);

    BOOST_REQUIRE(error == NULL);

    do {
        retry_get = false;
        request = ds3_init_get_available_chunks(bulk_response->job_id->value);

        error = ds3_get_available_chunks(client, request, &chunk_response);

        ds3_free_request(request);

        BOOST_REQUIRE(error == NULL);

        BOOST_REQUIRE(chunk_response != NULL);

        if (chunk_response->object_list->list_size == 0) {
            // if this happens we need to try the request
            retry_get = true;
            BOOST_TEST_MESSAGE( "Hit retry, sleeping for: " << chunk_response->retry_after) ;
            sleep(chunk_response->retry_after);
        }

    } while(retry_get);

    BOOST_REQUIRE(error == NULL);

    bool checksum_passed = true;

    for (i = 0; i < chunk_response->object_list->list_size; i++) {
        ds3_bulk_object_list* chunk_object_list = chunk_response->object_list->list[i];
        for(n = 0; n < chunk_object_list->size; n++, file_index++) {
            FILE* w_file;
            ds3_bulk_object current_obj = chunk_object_list->list[n];
            request = ds3_init_get_object_for_job(bucket_name, current_obj.name->value, current_obj.offset, bulk_response->job_id->value);
            orignal_file_path[file_index] = current_obj.name->value;
            tmp_files[file_index] = (char*) calloc(12, sizeof(char));
            memcpy(tmp_files[file_index], FILE_TEMPLATE, 11);
            w_file = fopen(tmp_files[file_index], "w+");
            error = ds3_get_object(client, request, w_file, ds3_write_to_file);
            ds3_free_request(request);
            fclose(w_file);
            handle_error(error);
            printf("------Performing Data Integrity Test-------\n");
            checksum_passed = checksum_passed && compare_hash(orignal_file_path[file_index],tmp_files[file_index]);
            printf("\n");
        }
    }

    for (i = 0; i < file_index; i++) {
        unlink(tmp_files[i]);
        free(tmp_files[i]);
    }

    free(tmp_files);

    BOOST_CHECK(checksum_passed == true);

    // check to make sure that the 'job' has completed
    request = ds3_init_get_job(bulk_response->job_id->value);
    error = ds3_get_job(client, request, &completed_job);

    BOOST_CHECK(completed_job != NULL);
    BOOST_CHECK(completed_job->status == COMPLETED);

    ds3_free_request(request);
    ds3_free_available_chunks_response(chunk_response);
    ds3_free_bulk_response(completed_job);
    ds3_free_bulk_response(bulk_response);

    clear_bucket(client, bucket_name);
    free_client(client);
    handle_error(error);
}

BOOST_AUTO_TEST_CASE( max_upload_size ) {
    uint64_t i, n;
    uint64_t file_index = 0;
    ds3_request* request = NULL;
    ds3_error* error = NULL;
    ds3_bulk_response* completed_job = NULL;
    ds3_get_bucket_response* response = NULL;
    ds3_bulk_response* bulk_response = NULL;
    ds3_bulk_object_list* object_list = NULL;
    ds3_get_available_chunks_response* chunk_response = NULL;
    bool retry_get;

    ds3_client* client = get_client();
    const char* bucket_name = "unit_test_bucket";
    char* orignal_file_path [5];

    char** tmp_files;

    populate_with_objects(client, bucket_name, 10485760);

    request = ds3_init_get_bucket(bucket_name);
    error = ds3_get_bucket(client, request, &response);

    ds3_free_request(request);

    BOOST_REQUIRE(error == NULL);

    tmp_files = (char**) calloc(response->num_objects, sizeof(char*));

    object_list = ds3_convert_object_list(response->objects, response->num_objects);

    ds3_free_bucket_response(response);

    request = ds3_init_get_bulk(bucket_name, object_list, NONE);
    error = ds3_bulk(client, request, &bulk_response);

    ds3_free_request(request);
    ds3_free_bulk_object_list(object_list);

    BOOST_REQUIRE(error == NULL);

    do {
        retry_get = false;
        request = ds3_init_get_available_chunks(bulk_response->job_id->value);

        error = ds3_get_available_chunks(client, request, &chunk_response);

        ds3_free_request(request);

        BOOST_REQUIRE(error == NULL);

        BOOST_REQUIRE(chunk_response != NULL);

        if (chunk_response->object_list->list_size == 0) {
            // if this happens we need to try the request
            retry_get = true;
            BOOST_TEST_MESSAGE( "Hit retry, sleeping for: " << chunk_response->retry_after) ;
            sleep(chunk_response->retry_after);
        }

    } while(retry_get);

    BOOST_REQUIRE(error == NULL);

    bool checksum_passed = true;

    for (i = 0; i < chunk_response->object_list->list_size; i++) {
        ds3_bulk_object_list* chunk_object_list = chunk_response->object_list->list[i];
        for(n = 0; n < chunk_object_list->size; n++, file_index++) {
            FILE* w_file;
            ds3_bulk_object current_obj = chunk_object_list->list[n];
            request = ds3_init_get_object_for_job(bucket_name, current_obj.name->value, current_obj.offset, bulk_response->job_id->value);
            orignal_file_path[file_index] = current_obj.name->value;
            tmp_files[file_index] = (char*) calloc(12, sizeof(char));
            memcpy(tmp_files[file_index], FILE_TEMPLATE, 11);
            w_file = fopen(tmp_files[file_index], "w+");
            error = ds3_get_object(client, request, w_file, ds3_write_to_file);
            ds3_free_request(request);
            fclose(w_file);
            handle_error(error);
            printf("------Performing Data Integrity Test-------\n");
            checksum_passed = checksum_passed && compare_hash(orignal_file_path[file_index],tmp_files[file_index]);
            printf("\n");
        }
    }

    for (i = 0; i < file_index; i++) {
        unlink(tmp_files[i]);
        free(tmp_files[i]);
    }

    free(tmp_files);

    BOOST_CHECK(checksum_passed == true);

    // check to make sure that the 'job' has completed
    request = ds3_init_get_job(bulk_response->job_id->value);
    error = ds3_get_job(client, request, &completed_job);

    BOOST_CHECK(completed_job != NULL);
    BOOST_CHECK(completed_job->status == COMPLETED);

    ds3_free_request(request);
    ds3_free_available_chunks_response(chunk_response);
    ds3_free_bulk_response(completed_job);
    ds3_free_bulk_response(bulk_response);

    clear_bucket(client, bucket_name);
    free_client(client);
    handle_error(error);
}

BOOST_AUTO_TEST_CASE( convert_list_helper ) {
    const char* books[4] ={"beowulf.txt", "sherlock_holmes.txt", "tale_of_two_cities.txt", "ulysses.txt"};
    ds3_bulk_object_list* obj_list;

    obj_list = ds3_convert_file_list_with_basepath(books, 4, "resources/");

    BOOST_CHECK(strcmp(obj_list->list[0].name->value, "beowulf.txt") == 0);
    BOOST_CHECK(obj_list->list[0].length == 294059);

    ds3_free_bulk_object_list(obj_list);
}

BOOST_AUTO_TEST_CASE( directory_size ) {
    const char* books[1] ={"resources"};
    ds3_bulk_object_list* obj_list;

    obj_list = ds3_convert_file_list_with_basepath(books, 1, NULL);

    BOOST_CHECK(strcmp(obj_list->list[0].name->value, "resources") == 0);
    BOOST_CHECK(obj_list->list[0].length == 0);

    ds3_free_bulk_object_list(obj_list);
}
<|endoftext|>