<commit_before>/*
 * DISTRHO Plugin Framework (DPF)
 * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED
#define DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED

#include "../DistrhoUI.hpp"
#include "../../dgl/Application.hpp"

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
# include "../../dgl/src/WindowPrivateData.hpp"
# include "../../dgl/src/pugl.hpp"
#endif

#if defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_DSSI)
# define DISTRHO_UI_IS_STANDALONE 1
#else
# define DISTRHO_UI_IS_STANDALONE 0
#endif

#if defined(DISTRHO_PLUGIN_TARGET_VST2)
# undef DISTRHO_UI_USER_RESIZABLE
# define DISTRHO_UI_USER_RESIZABLE 0
#endif

// -----------------------------------------------------------------------

START_NAMESPACE_DGL

// -----------------------------------------------------------------------
// Plugin Application, will set class name based on plugin details

class PluginApplication : public Application
{
public:
    explicit PluginApplication()
        : Application(DISTRHO_UI_IS_STANDALONE)
    {
        const char* const className = (
#ifdef DISTRHO_PLUGIN_BRAND
            DISTRHO_PLUGIN_BRAND
#else
            DISTRHO_MACRO_AS_STRING(DISTRHO_NAMESPACE)
#endif
            "-" DISTRHO_PLUGIN_NAME
        );
        setClassName(className);
    }

    DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication)
};

// -----------------------------------------------------------------------
// Plugin Window, will pass some Window events to UI

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
// TODO external ui stuff
class PluginWindow
{
    UI* const ui;

public:
    explicit PluginWindow(UI* const uiPtr,
                          PluginApplication& app,
                          const uintptr_t parentWindowHandle,
                          const uint width,
                          const uint height,
                          const double scaleFactor)
        : Window(app, parentWindowHandle, width, height, scaleFactor, DISTRHO_UI_USER_RESIZABLE),
          ui(uiPtr) {}

    uint getWidth() const noexcept
    {
        return ui->getWidth();
    }

    uint getHeight() const noexcept
    {
        return ui->getHeight();
    }

    bool isVisible() const noexcept
    {
        return ui->isRunning();
    }

    uintptr_t getNativeWindowHandle() const noexcept
    {
        return 0;
    }

    DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow)
};
#else
class PluginWindow : public Window
{
    UI* const ui;

public:
    explicit PluginWindow(UI* const uiPtr,
                          PluginApplication& app,
                          const uintptr_t parentWindowHandle,
                          const uint width,
                          const uint height,
                          const double scaleFactor)
        : Window(app, parentWindowHandle, width, height, scaleFactor, DISTRHO_UI_USER_RESIZABLE),
          ui(uiPtr)
    {
        puglBackendEnter(pData->view);
    }

    void leaveContext()
    {
        puglBackendLeave(pData->view);
    }

protected:
    void onFocus(const bool focus, const DGL_NAMESPACE::CrossingMode mode) override
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

        ui->uiFocus(focus, mode);
    }

    void onReshape(const uint width, const uint height) override
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

        ui->uiReshape(width, height);
    }

    void onScaleFactorChanged(const double scaleFactor) override
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

        ui->uiScaleFactorChanged(scaleFactor);
    }

# ifndef DGL_FILE_BROWSER_DISABLED
    void onFileSelected(const char* const filename) override
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

#  if DISTRHO_PLUGIN_WANT_STATEFILES
        if (char* const key = ui->uiData->uiStateFileKeyRequest)
        {
            ui->uiData->uiStateFileKeyRequest = nullptr;
            // notify DSP
            ui->setState(key, filename);
            // notify UI
            ui->stateChanged(key, filename);
            std::free(key);
            return;
        }
#  endif

        ui->uiFileBrowserSelected(filename);
    }
# endif

    DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow)
};
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI

END_NAMESPACE_DGL

// -----------------------------------------------------------------------

START_NAMESPACE_DISTRHO

using DGL_NAMESPACE::PluginApplication;
using DGL_NAMESPACE::PluginWindow;

// -----------------------------------------------------------------------
// UI callbacks

typedef void (*editParamFunc)   (void* ptr, uint32_t rindex, bool started);
typedef void (*setParamFunc)    (void* ptr, uint32_t rindex, float value);
typedef void (*setStateFunc)    (void* ptr, const char* key, const char* value);
typedef void (*sendNoteFunc)    (void* ptr, uint8_t channel, uint8_t note, uint8_t velo);
typedef void (*setSizeFunc)     (void* ptr, uint width, uint height);
typedef bool (*fileRequestFunc) (void* ptr, const char* key);

// -----------------------------------------------------------------------
// UI private data

struct UI::PrivateData {
    // DGL
    PluginApplication app;
    ScopedPointer<PluginWindow> window;

    // DSP
    double   sampleRate;
    uint32_t parameterOffset;
    void*    dspPtr;

    // UI
    uint bgColor;
    uint fgColor;
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
    double scaleFactor;
    uintptr_t winId;
# ifndef DGL_FILE_BROWSER_DISABLED
    char* uiStateFileKeyRequest;
# endif
#endif

    // Callbacks
    void*           callbacksPtr;
    editParamFunc   editParamCallbackFunc;
    setParamFunc    setParamCallbackFunc;
    setStateFunc    setStateCallbackFunc;
    sendNoteFunc    sendNoteCallbackFunc;
    setSizeFunc     setSizeCallbackFunc;
    fileRequestFunc fileRequestCallbackFunc;

    PrivateData() noexcept
        : app(),
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
          window(nullptr),
#endif
          sampleRate(0),
          parameterOffset(0),
          dspPtr(nullptr),
          bgColor(0),
          fgColor(0xffffffff),
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
          scaleFactor(1.0),
          winId(0),
# ifndef DGL_FILE_BROWSER_DISABLED
          uiStateFileKeyRequest(nullptr),
# endif
#endif
          callbacksPtr(nullptr),
          editParamCallbackFunc(nullptr),
          setParamCallbackFunc(nullptr),
          setStateCallbackFunc(nullptr),
          sendNoteCallbackFunc(nullptr),
          setSizeCallbackFunc(nullptr),
          fileRequestCallbackFunc(nullptr)
    {
#if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2)
        parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS;
# if DISTRHO_PLUGIN_WANT_LATENCY
        parameterOffset += 1;
# endif
#endif

#ifdef DISTRHO_PLUGIN_TARGET_LV2
# if (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE)
        parameterOffset += 1;
#  if DISTRHO_PLUGIN_WANT_STATE
        parameterOffset += 1;
#  endif
# endif
#endif
    }

    ~PrivateData() noexcept
    {
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED)
        std::free(uiStateFileKeyRequest);
#endif
    }

    void editParamCallback(const uint32_t rindex, const bool started)
    {
        if (editParamCallbackFunc != nullptr)
            editParamCallbackFunc(callbacksPtr, rindex, started);
    }

    void setParamCallback(const uint32_t rindex, const float value)
    {
        if (setParamCallbackFunc != nullptr)
            setParamCallbackFunc(callbacksPtr, rindex, value);
    }

    void setStateCallback(const char* const key, const char* const value)
    {
        if (setStateCallbackFunc != nullptr)
            setStateCallbackFunc(callbacksPtr, key, value);
    }

    void sendNoteCallback(const uint8_t channel, const uint8_t note, const uint8_t velocity)
    {
        if (sendNoteCallbackFunc != nullptr)
            sendNoteCallbackFunc(callbacksPtr, channel, note, velocity);
    }

    void setSizeCallback(const uint width, const uint height)
    {
        if (setSizeCallbackFunc != nullptr)
            setSizeCallbackFunc(callbacksPtr, width, height);
    }

    // implemented below, after PluginWindow
    bool fileRequestCallback(const char* const key);

    static UI::PrivateData* s_nextPrivateData;
    static PluginWindow& createNextWindow(UI* ui, uint width, uint height);
};

// -----------------------------------------------------------------------
// UI private data fileRequestCallback, which requires PluginWindow definitions

inline bool UI::PrivateData::fileRequestCallback(const char* const key)
{
    if (fileRequestCallbackFunc != nullptr)
        return fileRequestCallbackFunc(callbacksPtr, key);

#if DISTRHO_PLUGIN_WANT_STATEFILES && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED)
    std::free(uiStateFileKeyRequest);
    uiStateFileKeyRequest = strdup(key);
    DISTRHO_SAFE_ASSERT_RETURN(uiStateFileKeyRequest != nullptr, false);

    char title[0xff];
    snprintf(title, sizeof(title)-1u, DISTRHO_PLUGIN_NAME ": %s", key);
    title[sizeof(title)-1u] = '\0';

    Window::FileBrowserOptions opts;
    opts.title = title;
    return window->openFileBrowser(opts);
#endif

    return false;
}

// -----------------------------------------------------------------------

END_NAMESPACE_DISTRHO

#endif // DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED
<commit_msg>Fix build with state files<commit_after>/*
 * DISTRHO Plugin Framework (DPF)
 * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED
#define DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED

#include "../DistrhoUI.hpp"
#include "../../dgl/Application.hpp"

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
# include "../../dgl/src/WindowPrivateData.hpp"
# include "../../dgl/src/pugl.hpp"
#endif

#if defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_DSSI)
# define DISTRHO_UI_IS_STANDALONE 1
#else
# define DISTRHO_UI_IS_STANDALONE 0
#endif

#if defined(DISTRHO_PLUGIN_TARGET_VST2)
# undef DISTRHO_UI_USER_RESIZABLE
# define DISTRHO_UI_USER_RESIZABLE 0
#endif

// -----------------------------------------------------------------------

START_NAMESPACE_DGL

// -----------------------------------------------------------------------
// Plugin Application, will set class name based on plugin details

class PluginApplication : public Application
{
public:
    explicit PluginApplication()
        : Application(DISTRHO_UI_IS_STANDALONE)
    {
        const char* const className = (
#ifdef DISTRHO_PLUGIN_BRAND
            DISTRHO_PLUGIN_BRAND
#else
            DISTRHO_MACRO_AS_STRING(DISTRHO_NAMESPACE)
#endif
            "-" DISTRHO_PLUGIN_NAME
        );
        setClassName(className);
    }

    DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication)
};

// -----------------------------------------------------------------------
// Plugin Window, will pass some Window events to UI

#if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
// TODO external ui stuff
class PluginWindow
{
    UI* const ui;

public:
    explicit PluginWindow(UI* const uiPtr,
                          PluginApplication& app,
                          const uintptr_t parentWindowHandle,
                          const uint width,
                          const uint height,
                          const double scaleFactor)
        : Window(app, parentWindowHandle, width, height, scaleFactor, DISTRHO_UI_USER_RESIZABLE),
          ui(uiPtr) {}

    uint getWidth() const noexcept
    {
        return ui->getWidth();
    }

    uint getHeight() const noexcept
    {
        return ui->getHeight();
    }

    bool isVisible() const noexcept
    {
        return ui->isRunning();
    }

    uintptr_t getNativeWindowHandle() const noexcept
    {
        return 0;
    }

    DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow)
};
#else
class PluginWindow : public Window
{
    UI* const ui;

public:
    explicit PluginWindow(UI* const uiPtr,
                          PluginApplication& app,
                          const uintptr_t parentWindowHandle,
                          const uint width,
                          const uint height,
                          const double scaleFactor)
        : Window(app, parentWindowHandle, width, height, scaleFactor, DISTRHO_UI_USER_RESIZABLE),
          ui(uiPtr)
    {
        puglBackendEnter(pData->view);
    }

    void leaveContext()
    {
        puglBackendLeave(pData->view);
    }

protected:
    void onFocus(const bool focus, const DGL_NAMESPACE::CrossingMode mode) override
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

        ui->uiFocus(focus, mode);
    }

    void onReshape(const uint width, const uint height) override
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

        ui->uiReshape(width, height);
    }

    void onScaleFactorChanged(const double scaleFactor) override
    {
        DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

        ui->uiScaleFactorChanged(scaleFactor);
    }

# ifndef DGL_FILE_BROWSER_DISABLED
    void onFileSelected(const char* filename) override;
# endif

    DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow)
};
#endif // !DISTRHO_PLUGIN_HAS_EXTERNAL_UI

END_NAMESPACE_DGL

// -----------------------------------------------------------------------

START_NAMESPACE_DISTRHO

using DGL_NAMESPACE::PluginApplication;
using DGL_NAMESPACE::PluginWindow;

// -----------------------------------------------------------------------
// UI callbacks

typedef void (*editParamFunc)   (void* ptr, uint32_t rindex, bool started);
typedef void (*setParamFunc)    (void* ptr, uint32_t rindex, float value);
typedef void (*setStateFunc)    (void* ptr, const char* key, const char* value);
typedef void (*sendNoteFunc)    (void* ptr, uint8_t channel, uint8_t note, uint8_t velo);
typedef void (*setSizeFunc)     (void* ptr, uint width, uint height);
typedef bool (*fileRequestFunc) (void* ptr, const char* key);

// -----------------------------------------------------------------------
// UI private data

struct UI::PrivateData {
    // DGL
    PluginApplication app;
    ScopedPointer<PluginWindow> window;

    // DSP
    double   sampleRate;
    uint32_t parameterOffset;
    void*    dspPtr;

    // UI
    uint bgColor;
    uint fgColor;
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
    double scaleFactor;
    uintptr_t winId;
# ifndef DGL_FILE_BROWSER_DISABLED
    char* uiStateFileKeyRequest;
# endif
#endif

    // Callbacks
    void*           callbacksPtr;
    editParamFunc   editParamCallbackFunc;
    setParamFunc    setParamCallbackFunc;
    setStateFunc    setStateCallbackFunc;
    sendNoteFunc    sendNoteCallbackFunc;
    setSizeFunc     setSizeCallbackFunc;
    fileRequestFunc fileRequestCallbackFunc;

    PrivateData() noexcept
        : app(),
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
          window(nullptr),
#endif
          sampleRate(0),
          parameterOffset(0),
          dspPtr(nullptr),
          bgColor(0),
          fgColor(0xffffffff),
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
          scaleFactor(1.0),
          winId(0),
# ifndef DGL_FILE_BROWSER_DISABLED
          uiStateFileKeyRequest(nullptr),
# endif
#endif
          callbacksPtr(nullptr),
          editParamCallbackFunc(nullptr),
          setParamCallbackFunc(nullptr),
          setStateCallbackFunc(nullptr),
          sendNoteCallbackFunc(nullptr),
          setSizeCallbackFunc(nullptr),
          fileRequestCallbackFunc(nullptr)
    {
#if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2)
        parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS;
# if DISTRHO_PLUGIN_WANT_LATENCY
        parameterOffset += 1;
# endif
#endif

#ifdef DISTRHO_PLUGIN_TARGET_LV2
# if (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE)
        parameterOffset += 1;
#  if DISTRHO_PLUGIN_WANT_STATE
        parameterOffset += 1;
#  endif
# endif
#endif
    }

    ~PrivateData() noexcept
    {
#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED)
        std::free(uiStateFileKeyRequest);
#endif
    }

    void editParamCallback(const uint32_t rindex, const bool started)
    {
        if (editParamCallbackFunc != nullptr)
            editParamCallbackFunc(callbacksPtr, rindex, started);
    }

    void setParamCallback(const uint32_t rindex, const float value)
    {
        if (setParamCallbackFunc != nullptr)
            setParamCallbackFunc(callbacksPtr, rindex, value);
    }

    void setStateCallback(const char* const key, const char* const value)
    {
        if (setStateCallbackFunc != nullptr)
            setStateCallbackFunc(callbacksPtr, key, value);
    }

    void sendNoteCallback(const uint8_t channel, const uint8_t note, const uint8_t velocity)
    {
        if (sendNoteCallbackFunc != nullptr)
            sendNoteCallbackFunc(callbacksPtr, channel, note, velocity);
    }

    void setSizeCallback(const uint width, const uint height)
    {
        if (setSizeCallbackFunc != nullptr)
            setSizeCallbackFunc(callbacksPtr, width, height);
    }

    // implemented below, after PluginWindow
    bool fileRequestCallback(const char* const key);

    static UI::PrivateData* s_nextPrivateData;
    static PluginWindow& createNextWindow(UI* ui, uint width, uint height);
};

// -----------------------------------------------------------------------
// UI private data fileRequestCallback, which requires PluginWindow definitions

inline bool UI::PrivateData::fileRequestCallback(const char* const key)
{
    if (fileRequestCallbackFunc != nullptr)
        return fileRequestCallbackFunc(callbacksPtr, key);

#if DISTRHO_PLUGIN_WANT_STATEFILES && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED)
    std::free(uiStateFileKeyRequest);
    uiStateFileKeyRequest = strdup(key);
    DISTRHO_SAFE_ASSERT_RETURN(uiStateFileKeyRequest != nullptr, false);

    char title[0xff];
    snprintf(title, sizeof(title)-1u, DISTRHO_PLUGIN_NAME ": %s", key);
    title[sizeof(title)-1u] = '\0';

    Window::FileBrowserOptions opts;
    opts.title = title;
    return window->openFileBrowser(opts);
#endif

    return false;
}

END_NAMESPACE_DISTRHO

// -----------------------------------------------------------------------
// PluginWindow onFileSelected that require UI::PrivateData definitions

#if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED)
START_NAMESPACE_DGL

inline void PluginWindow::onFileSelected(const char* const filename)
{
    DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);

# if DISTRHO_PLUGIN_WANT_STATEFILES
    if (char* const key = ui->uiData->uiStateFileKeyRequest)
    {
        ui->uiData->uiStateFileKeyRequest = nullptr;
        // notify DSP
        ui->setState(key, filename);
        // notify UI
        ui->stateChanged(key, filename);
        std::free(key);
        return;
    }
# endif

    ui->uiFileBrowserSelected(filename);
}

END_NAMESPACE_DGL
#endif

// -----------------------------------------------------------------------

#endif // DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED
<|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.
 *****************************************************************************/

#include "FsDiscoverer.h"

#include <algorithm>
#include <queue>

#include "factory/FileSystem.h"
#include "filesystem/IDevice.h"
#include "Media.h"
#include "Device.h"
#include "Folder.h"
#include "logging/Logger.h"
#include "MediaLibrary.h"
#include "utils/Filename.h"

FsDiscoverer::FsDiscoverer( std::shared_ptr<factory::IFileSystem> fsFactory, MediaLibrary* ml, DBConnection dbConn )
    : m_ml( ml )
    , m_dbConn( dbConn )
    , m_fsFactory( fsFactory )
{
}

bool FsDiscoverer::discover( const std::string &entryPoint )
{
    // Assume :// denotes a scheme that isn't a file path, and refuse to discover it.
    if ( entryPoint.find( "://" ) != std::string::npos )
        return false;

    std::shared_ptr<fs::IDirectory> fsDir = m_fsFactory->createDirectory( entryPoint );
    {
        auto f = Folder::fromPath( m_dbConn, entryPoint );
        // If the folder exists, we assume it will be handled by reload()
        if ( f != nullptr )
            return true;
    }
    // Otherwise, create a directory and check it for modifications
    if ( fsDir == nullptr )
    {
        LOG_ERROR("Failed to create an IDirectory for ", entryPoint );
        return false;
    }
    auto blist = blacklist();
    if ( isBlacklisted( *fsDir, blist ) == true )
        return false;
    return addFolder( *fsDir, nullptr, blist );
}

void FsDiscoverer::reload()
{
    // Start by checking if previously known devices have been plugged/unplugged
    checkDevices();
    auto rootFolders = Folder::fetchAll( m_dbConn, 0 );
    auto blist = blacklist();
    for ( const auto& f : rootFolders )
    {
        auto folder = m_fsFactory->createDirectory( f->path() );
        if ( folder == nullptr )
        {
            LOG_INFO( "Removing folder ", f->path() );
            m_ml->deleteFolder( f.get() );
            continue;
        }
        checkSubfolders( *folder, *f, blist );
        checkFiles( *folder, *f );
    }
}

void FsDiscoverer::checkDevices()
{
    m_fsFactory->refresh();
    auto devices = Device::fetchAll( m_dbConn );
    for ( auto& d : devices )
    {
        auto deviceFs = m_fsFactory->createDevice( d->uuid() );
        auto fsDevicePresent = deviceFs != nullptr && deviceFs->isPresent();
        if ( d->isPresent() != fsDevicePresent )
        {
            LOG_INFO( "Device ", d->uuid(), " changed presence state: ", d->isPresent(), " -> ", fsDevicePresent );
            d->setPresent( fsDevicePresent );
        }
        else
        {
            LOG_INFO( "Device ", d->uuid(), " unchanged" );
        }
    }
}

bool FsDiscoverer::checkSubfolders( fs::IDirectory& parentFolderFs, Folder& parentFolder, const std::vector<std::shared_ptr<Folder>> blacklist ) const
{
    // Load the folders we already know of:
    LOG_INFO( "Checking for modifications in ", parentFolderFs.path() );
    auto subFoldersInDB = Folder::fetchAll( m_dbConn, parentFolder.id() );
    for ( const auto& subFolderPath : parentFolderFs.dirs() )
    {
        auto subFolder = m_fsFactory->createDirectory( subFolderPath );
        if ( subFolder == nullptr )
            continue;

        auto it = std::find_if( begin( subFoldersInDB ), end( subFoldersInDB ), [subFolderPath](const std::shared_ptr<Folder>& f) {
            return f->path() == subFolderPath;
        });
        // We don't know this folder, it's a new one
        if ( it == end( subFoldersInDB ) )
        {
            // Check if it is blacklisted
            if ( isBlacklisted( *subFolder, blacklist ) == true )
            {
                LOG_INFO( "Ignoring blacklisted folder: ", subFolderPath );
                continue;
            }
            LOG_INFO( "New folder detected: ", subFolderPath );
            addFolder( *subFolder, &parentFolder, blacklist );
            continue;
        }
        auto folderInDb = *it;
        // In any case, check for modifications, as a change related to a mountpoint might
        // not update the folder modification date.
        // Also, relying on the modification date probably isn't portable
        checkSubfolders( *subFolder, *folderInDb, blacklist );
        checkFiles( *subFolder, *folderInDb );
        subFoldersInDB.erase( it );
    }
    // Now all folders we had in DB but haven't seen from the FS must have been deleted.
    for ( auto f : subFoldersInDB )
    {
        LOG_INFO( "Folder ", f->path(), " not found in FS, deleting it" );
        m_ml->deleteFolder( f.get() );
    }
    LOG_INFO( "Done checking subfolders in ", parentFolderFs.path() );
    return true;
}

void FsDiscoverer::checkFiles( fs::IDirectory& parentFolderFs, Folder& parentFolder ) const
{
    LOG_INFO( "Checking file in ", parentFolderFs.path() );
    static const std::string req = "SELECT * FROM " + policy::MediaTable::Name
            + " WHERE folder_id = ?";
    auto files = Media::fetchAll<Media>( m_dbConn, req, parentFolder.id() );
    for ( const auto& filePath : parentFolderFs.files() )
    {
        auto it = std::find_if( begin( files ), end( files ), [filePath](const std::shared_ptr<IMedia>& f) {
            return f->mrl() == filePath;
        });
        if ( it == end( files ) )
        {
            m_ml->addFile( filePath, parentFolder, parentFolderFs );
            continue;
        }
        auto file = m_fsFactory->createFile( filePath );
        if ( file->lastModificationDate() == (*it)->lastModificationDate() )
        {
            // Unchanged file
            files.erase( it );
            continue;
        }
        LOG_INFO( "Forcing file refresh ", filePath );
        m_ml->deleteFile( (*it).get() );
        m_ml->addFile( filePath, parentFolder, parentFolderFs );
        files.erase( it );
    }
    for ( auto file : files )
    {
        LOG_INFO( "File ", file->mrl(), " not found on filesystem, deleting it" );
        m_ml->deleteFile( file.get() );
    }
    LOG_INFO( "Done checking files ", parentFolderFs.path() );
}

std::vector<std::shared_ptr<Folder> > FsDiscoverer::blacklist() const
{
    static const std::string req = "SELECT * FROM " + policy::FolderTable::Name + " WHERE is_blacklisted = 1";
    return sqlite::Tools::fetchAll<Folder, Folder>( m_dbConn, req );
}

bool FsDiscoverer::isBlacklisted( const fs::IDirectory& directory, const std::vector<std::shared_ptr<Folder>>& blacklist ) const
{
    auto deviceFs = directory.device();
    //FIXME: We could avoid fetching the device if the directory is non removable.
    auto device = Device::fromUuid( m_dbConn, deviceFs->uuid() );
    // When blacklisting, we would insert the device if we haven't encoutered it yet.
    // So when reading, a missing device means a non-blacklisted device.
    if ( device == nullptr )
        return false;
    auto deviceId = device->id();

    return std::find_if( begin( blacklist ), end( blacklist ), [&directory, deviceId]( const std::shared_ptr<Folder>& f ) {
        return f->path() == directory.path() && f->deviceId() == deviceId;
    }) != end( blacklist );
}

bool FsDiscoverer::addFolder( fs::IDirectory& folder, Folder* parentFolder, const std::vector<std::shared_ptr<Folder>>& blacklist ) const
{
    auto deviceFs = folder.device();
    // We are creating a folder, there has to be a device containing it.
    assert( deviceFs != nullptr );
    auto device = Device::fromUuid( m_dbConn, deviceFs->uuid() );
    if ( device == nullptr )
    {
        LOG_INFO( "Creating new device in DB ", deviceFs->uuid() );
        device = Device::create( m_dbConn, deviceFs->uuid(), deviceFs->isRemovable() );
    }

    auto f = Folder::create( m_dbConn, folder.path(),
                             parentFolder != nullptr ? parentFolder->id() : 0,
                             *device, *deviceFs );
    if ( f == nullptr )
        return false;
    checkFiles( folder, *f );
    checkSubfolders( folder, *f, blacklist );
    return true;
}

<commit_msg>FsDiscover: Check if the folder exists before checking if we know about it<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.
 *****************************************************************************/

#include "FsDiscoverer.h"

#include <algorithm>
#include <queue>

#include "factory/FileSystem.h"
#include "filesystem/IDevice.h"
#include "Media.h"
#include "Device.h"
#include "Folder.h"
#include "logging/Logger.h"
#include "MediaLibrary.h"
#include "utils/Filename.h"

FsDiscoverer::FsDiscoverer( std::shared_ptr<factory::IFileSystem> fsFactory, MediaLibrary* ml, DBConnection dbConn )
    : m_ml( ml )
    , m_dbConn( dbConn )
    , m_fsFactory( fsFactory )
{
}

bool FsDiscoverer::discover( const std::string &entryPoint )
{
    // Assume :// denotes a scheme that isn't a file path, and refuse to discover it.
    if ( entryPoint.find( "://" ) != std::string::npos )
        return false;

    std::shared_ptr<fs::IDirectory> fsDir = m_fsFactory->createDirectory( entryPoint );
    // Otherwise, create a directory and check it for modifications
    if ( fsDir == nullptr )
    {
        LOG_ERROR("Failed to create an IDirectory for ", entryPoint );
        return false;
    }
    auto f = Folder::fromPath( m_dbConn, fsDir->path() );
    // If the folder exists, we assume it will be handled by reload()
    if ( f != nullptr )
        return true;
    auto blist = blacklist();
    if ( isBlacklisted( *fsDir, blist ) == true )
        return false;
    return addFolder( *fsDir, nullptr, blist );
}

void FsDiscoverer::reload()
{
    // Start by checking if previously known devices have been plugged/unplugged
    checkDevices();
    auto rootFolders = Folder::fetchAll( m_dbConn, 0 );
    auto blist = blacklist();
    for ( const auto& f : rootFolders )
    {
        auto folder = m_fsFactory->createDirectory( f->path() );
        if ( folder == nullptr )
        {
            LOG_INFO( "Removing folder ", f->path() );
            m_ml->deleteFolder( f.get() );
            continue;
        }
        checkSubfolders( *folder, *f, blist );
        checkFiles( *folder, *f );
    }
}

void FsDiscoverer::checkDevices()
{
    m_fsFactory->refresh();
    auto devices = Device::fetchAll( m_dbConn );
    for ( auto& d : devices )
    {
        auto deviceFs = m_fsFactory->createDevice( d->uuid() );
        auto fsDevicePresent = deviceFs != nullptr && deviceFs->isPresent();
        if ( d->isPresent() != fsDevicePresent )
        {
            LOG_INFO( "Device ", d->uuid(), " changed presence state: ", d->isPresent(), " -> ", fsDevicePresent );
            d->setPresent( fsDevicePresent );
        }
        else
        {
            LOG_INFO( "Device ", d->uuid(), " unchanged" );
        }
    }
}

bool FsDiscoverer::checkSubfolders( fs::IDirectory& parentFolderFs, Folder& parentFolder, const std::vector<std::shared_ptr<Folder>> blacklist ) const
{
    // Load the folders we already know of:
    LOG_INFO( "Checking for modifications in ", parentFolderFs.path() );
    auto subFoldersInDB = Folder::fetchAll( m_dbConn, parentFolder.id() );
    for ( const auto& subFolderPath : parentFolderFs.dirs() )
    {
        auto subFolder = m_fsFactory->createDirectory( subFolderPath );
        if ( subFolder == nullptr )
            continue;

        auto it = std::find_if( begin( subFoldersInDB ), end( subFoldersInDB ), [subFolderPath](const std::shared_ptr<Folder>& f) {
            return f->path() == subFolderPath;
        });
        // We don't know this folder, it's a new one
        if ( it == end( subFoldersInDB ) )
        {
            // Check if it is blacklisted
            if ( isBlacklisted( *subFolder, blacklist ) == true )
            {
                LOG_INFO( "Ignoring blacklisted folder: ", subFolderPath );
                continue;
            }
            LOG_INFO( "New folder detected: ", subFolderPath );
            addFolder( *subFolder, &parentFolder, blacklist );
            continue;
        }
        auto folderInDb = *it;
        // In any case, check for modifications, as a change related to a mountpoint might
        // not update the folder modification date.
        // Also, relying on the modification date probably isn't portable
        checkSubfolders( *subFolder, *folderInDb, blacklist );
        checkFiles( *subFolder, *folderInDb );
        subFoldersInDB.erase( it );
    }
    // Now all folders we had in DB but haven't seen from the FS must have been deleted.
    for ( auto f : subFoldersInDB )
    {
        LOG_INFO( "Folder ", f->path(), " not found in FS, deleting it" );
        m_ml->deleteFolder( f.get() );
    }
    LOG_INFO( "Done checking subfolders in ", parentFolderFs.path() );
    return true;
}

void FsDiscoverer::checkFiles( fs::IDirectory& parentFolderFs, Folder& parentFolder ) const
{
    LOG_INFO( "Checking file in ", parentFolderFs.path() );
    static const std::string req = "SELECT * FROM " + policy::MediaTable::Name
            + " WHERE folder_id = ?";
    auto files = Media::fetchAll<Media>( m_dbConn, req, parentFolder.id() );
    for ( const auto& filePath : parentFolderFs.files() )
    {
        auto it = std::find_if( begin( files ), end( files ), [filePath](const std::shared_ptr<IMedia>& f) {
            return f->mrl() == filePath;
        });
        if ( it == end( files ) )
        {
            m_ml->addFile( filePath, parentFolder, parentFolderFs );
            continue;
        }
        auto file = m_fsFactory->createFile( filePath );
        if ( file->lastModificationDate() == (*it)->lastModificationDate() )
        {
            // Unchanged file
            files.erase( it );
            continue;
        }
        LOG_INFO( "Forcing file refresh ", filePath );
        m_ml->deleteFile( (*it).get() );
        m_ml->addFile( filePath, parentFolder, parentFolderFs );
        files.erase( it );
    }
    for ( auto file : files )
    {
        LOG_INFO( "File ", file->mrl(), " not found on filesystem, deleting it" );
        m_ml->deleteFile( file.get() );
    }
    LOG_INFO( "Done checking files ", parentFolderFs.path() );
}

std::vector<std::shared_ptr<Folder> > FsDiscoverer::blacklist() const
{
    static const std::string req = "SELECT * FROM " + policy::FolderTable::Name + " WHERE is_blacklisted = 1";
    return sqlite::Tools::fetchAll<Folder, Folder>( m_dbConn, req );
}

bool FsDiscoverer::isBlacklisted( const fs::IDirectory& directory, const std::vector<std::shared_ptr<Folder>>& blacklist ) const
{
    auto deviceFs = directory.device();
    //FIXME: We could avoid fetching the device if the directory is non removable.
    auto device = Device::fromUuid( m_dbConn, deviceFs->uuid() );
    // When blacklisting, we would insert the device if we haven't encoutered it yet.
    // So when reading, a missing device means a non-blacklisted device.
    if ( device == nullptr )
        return false;
    auto deviceId = device->id();

    return std::find_if( begin( blacklist ), end( blacklist ), [&directory, deviceId]( const std::shared_ptr<Folder>& f ) {
        return f->path() == directory.path() && f->deviceId() == deviceId;
    }) != end( blacklist );
}

bool FsDiscoverer::addFolder( fs::IDirectory& folder, Folder* parentFolder, const std::vector<std::shared_ptr<Folder>>& blacklist ) const
{
    auto deviceFs = folder.device();
    // We are creating a folder, there has to be a device containing it.
    assert( deviceFs != nullptr );
    auto device = Device::fromUuid( m_dbConn, deviceFs->uuid() );
    if ( device == nullptr )
    {
        LOG_INFO( "Creating new device in DB ", deviceFs->uuid() );
        device = Device::create( m_dbConn, deviceFs->uuid(), deviceFs->isRemovable() );
    }

    auto f = Folder::create( m_dbConn, folder.path(),
                             parentFolder != nullptr ? parentFolder->id() : 0,
                             *device, *deviceFs );
    if ( f == nullptr )
        return false;
    checkFiles( folder, *f );
    checkSubfolders( folder, *f, blacklist );
    return true;
}

<|endoftext|>


<commit_before>#include "topic.h"
#include "consumer.h"

using namespace std;

Consumer::Consumer(const std::string& root, const std::string& topic, const std::string& name, TopicOpt* opt) : _topic(EnvManager::getEnv(root)->getTopic(topic)), _name(name), _current(-1), _lastOffset(0), _env(nullptr), _db(0), _rtxn(nullptr), _cursor(nullptr) {
    if (opt) {
        _opt = *opt;
    } else {
        /* Default opt */
        _opt.chunkSize = 1024 * 1024 * 1024;
        _opt.chunksToKeep = 8;
    }

    Txn txn(_topic->getEnv(), NULL);
    openHead(&txn);
    txn.commit();
}

Consumer::~Consumer() {
    closeCurrent();
}

void Consumer::pull(BatchType& result, size_t cnt) {
    result.reserve(cnt);
    bool shouldRotate = false;

    {
        Txn txn(_topic->getEnv(), NULL);
        mdb_txn_renew(_rtxn);

        uint64_t head = _topic->getConsumerHead(txn, _name);
        int rc = _cursor->seek(head);

        if (rc == 0) {
            for (; rc == 0 && cnt > 0; --cnt) {
                uint64_t offset = *(uint64_t*)_cursor->key().mv_data;
                const char* data = (const char*)_cursor->val().mv_data;
                size_t len = _cursor->val().mv_size;
                result.push_back(ItemType(offset, data, len));
                rc = _cursor->next();
            }
        } else {
            if (rc != MDB_NOTFOUND) cout << "Consumer seek error: " << mdb_strerror(rc) << endl;

            if (head <= _topic->getProducerHead(txn)) {
                shouldRotate = true;
            }
        }
    }

    if (shouldRotate) {
        rotate();
        pull(result, cnt);
    }
}

void Consumer::openHead(Txn* txn) {
    _current = _topic->getConsumerHeadFile(*txn, _name, _current);
    char path[4096];
    _topic->getChunkFilePath(path, _current);

    mdb_env_create(&_env);
    mdb_env_set_mapsize(_env, _opt.chunkSize);
    int rc = mdb_env_open(_env, path, MDB_RDONLY | MDB_NOSYNC | MDB_NOSUBDIR, 0664);

    int cleared = 0;
    mdb_reader_check(_env, &cleared);

    if (rc != 0) {
        mdb_env_close(_env);
        _env = nullptr;
        printf("Producer open error.\n%s\n", mdb_strerror(rc));
        return;
    }

    MDB_txn *otxn;
    mdb_txn_begin(_env, NULL, 0, &otxn);
    mdb_dbi_open(otxn, NULL, MDB_CREATE, &_db);
    mdb_set_compare(otxn, _db, mdbIntCmp<uint64_t>);
    mdb_txn_commit(otxn);

    mdb_txn_begin(_env, NULL, MDB_RDONLY, &_rtxn);
    _cursor = new MDBCursor(_db, _rtxn);
    mdb_txn_reset(_rtxn);
}

void Consumer::closeCurrent() {
    delete _cursor;
    mdb_txn_abort(_rtxn);
    mdb_dbi_close(_env, _db);
    mdb_env_close(_env);
}

void Consumer::rotate() {
    Txn txn(_topic->getEnv(), NULL);
    closeCurrent();
    openHead(&txn);
    txn.commit();
}<commit_msg>use template function.<commit_after>#include "topic.h"
#include "consumer.h"

using namespace std;

Consumer::Consumer(const std::string& root, const std::string& topic, const std::string& name, TopicOpt* opt) : _topic(EnvManager::getEnv(root)->getTopic(topic)), _name(name), _current(-1), _lastOffset(0), _env(nullptr), _db(0), _rtxn(nullptr), _cursor(nullptr) {
    if (opt) {
        _opt = *opt;
    } else {
        /* Default opt */
        _opt.chunkSize = 1024 * 1024 * 1024;
        _opt.chunksToKeep = 8;
    }

    Txn txn(_topic->getEnv(), NULL);
    openHead(&txn);
    txn.commit();
}

Consumer::~Consumer() {
    closeCurrent();
}

void Consumer::pull(BatchType& result, size_t cnt) {
    result.reserve(cnt);
    bool shouldRotate = false;

    {
        Txn txn(_topic->getEnv(), NULL);
        mdb_txn_renew(_rtxn);

        uint64_t head = _topic->getConsumerHead(txn, _name);
        int rc = _cursor->seek(head);

        if (rc == 0) {
            for (; rc == 0 && cnt > 0; --cnt) {
                uint64_t offset = _cursor->key<uint64_t>();
                const char* data = (const char*)_cursor->val().mv_data;
                size_t len = _cursor->val().mv_size;
                result.push_back(ItemType(offset, data, len));
                rc = _cursor->next();
            }
        } else {
            if (rc != MDB_NOTFOUND) cout << "Consumer seek error: " << mdb_strerror(rc) << endl;

            if (head <= _topic->getProducerHead(txn)) {
                shouldRotate = true;
            }
        }
    }

    if (shouldRotate) {
        rotate();
        pull(result, cnt);
    }
}

void Consumer::openHead(Txn* txn) {
    _current = _topic->getConsumerHeadFile(*txn, _name, _current);
    char path[4096];
    _topic->getChunkFilePath(path, _current);

    mdb_env_create(&_env);
    mdb_env_set_mapsize(_env, _opt.chunkSize);
    int rc = mdb_env_open(_env, path, MDB_RDONLY | MDB_NOSYNC | MDB_NOSUBDIR, 0664);

    int cleared = 0;
    mdb_reader_check(_env, &cleared);

    if (rc != 0) {
        mdb_env_close(_env);
        _env = nullptr;
        printf("Producer open error.\n%s\n", mdb_strerror(rc));
        return;
    }

    MDB_txn *otxn;
    mdb_txn_begin(_env, NULL, 0, &otxn);
    mdb_dbi_open(otxn, NULL, MDB_CREATE, &_db);
    mdb_set_compare(otxn, _db, mdbIntCmp<uint64_t>);
    mdb_txn_commit(otxn);

    mdb_txn_begin(_env, NULL, MDB_RDONLY, &_rtxn);
    _cursor = new MDBCursor(_db, _rtxn);
    mdb_txn_reset(_rtxn);
}

void Consumer::closeCurrent() {
    delete _cursor;
    mdb_txn_abort(_rtxn);
    mdb_dbi_close(_env, _db);
    mdb_env_close(_env);
}

void Consumer::rotate() {
    Txn txn(_topic->getEnv(), NULL);
    closeCurrent();
    openHead(&txn);
    txn.commit();
}<|endoftext|>


<commit_before>/*
*/

#include "control.h"
#include "lineFollowing/lineFollowing.h"
#include "objectFollowing/objectFollowing.h"
#include "manual/manual.h"

/*
*/
Control::Control() {
  //Initializing Message
  printf("Connecting to the drone\n");
  printf("If there is no version number response in the next 10 seconds, please restart the drone and code.\n");
  fflush(stdout);

  flight_log = fopen(flightLog.c_str(), "w");
  green = CV_RGB(0,255,0);

  //Connect to drone
  if (!ardrone.open()) {
    throw "Failed to initialize.";
  }

  //Set drone trim on flat surface
  ardrone.setFlatTrim();

  //initialize flying mode code
  manualFlying = new ManualFlying(this);
  objectFollowing = new ObjectFollowing(this);
  lineFollowing = new LineFollowing(this);

  //Print default command information
  printf("To disconnect, press the ESC key\n\n");
  printf("Currently the drone is in manual mode.\n");
  printf("Use the b key for manual mode, the n key for object following, and the m key for line following. The number keys can be used to set a speed. Use spacebar to take off and land, which is required before any control can be executed.\n\n");
}

void Control::fly() {
  //Execute flying instruction code
  switch (flyingMode) {
    case Manual:
      manualFlying->fly();
      break;
    case ObjectFollow:
      objectFollowing->fly();
      break;
    case LineFollow:
      lineFollowing->fly();
      break;
  }

  return;
}

/*
  Detect ESC key press and
*/
bool Control::getKey(int wait) {
  //Escape key
  key = cv::waitKey(wait);
  if (key == 0x1b) { return false; }
  return true;
}

/*
*/
void Control::changeSpeed() {
  if ((key >= '0') && (key <= '9')) //number keys
  {
    speed = (key-'0')*0.1;
  }
}

/*
*/
void Control::getImage() {
//Get an image
  image = ardrone.getImage();
}

/*
  Switch between flying modes
*/
void Control::detectFlyingMode() {

  if (key == 'b') {
    flyingMode = Manual;
    ardrone.setCamera(0);
    printf("Manual flying mode is enabled\n");
    printf("Press n for object following and m for line following\n");
    printf("While in manual mode, use q and a for up and down, t and g for forward and backward, and f and h for left and right. Press space to take off.\n\n");
  }
  else if (key == 'n') {
    flyingMode = ObjectFollow;
    ardrone.setCamera(0);
    printf("Object Following flying mode is enabled\n");
    printf("Press b for manual and m for line following\n");
    printf("While in object following mode, use l to toggle learning a specific color. Press space to take off after learning a color.\n\n");
  }
  else if (key == 'm') {
    flyingMode = LineFollow;
    ardrone.setCamera(1);
    printf("Line Following flying mode is enabled\n");
    printf("Press b for manual and n for object following\n");
    printf("No control for line following yet exists\n\n");
  }
}

/*
  Take off / Landing
*/
void Control::detectTakeoff() {
  if (key == ' ') { //spacebar
    if (ardrone.onGround()) {
      ardrone.takeoff();
      fprintf(flight_log, "TAKEOFF\n");
      takeoff_time = time(0);
    }
    else {
      ardrone.landing();
      fprintf(flight_log, "LAND\n");
    }
  }
}

/*
*/
void Control::overlayControl() {

  char modeDisplay[80]; //print buffer for flying mode
  char speedDisplay[80]; //print buffer for speed
  char flyingDisplay[80]; //print buffer for if flying
  char batteryDisplay[80]; //print buffer for battery
  char altitudeDisplay[80]; //print buffer for altitude

  char vxDisplay[80]; //print buffer for x (forward/reverse) velocity
  char vyDisplay[80]; //print buffer for y (sideways) velocity
  char vzDisplay[80]; //print buffer for z (up/down) velocity
  char vrDisplay[80]; //print buffer for r rotational velocity

  if (flyingMode == Manual) {
    sprintf(modeDisplay, "Manual Mode");

    sprintf(vxDisplay, "vx = %3.2f", velocities.vx);
    sprintf(vyDisplay, "vy = %3.2f", velocities.vy);
    sprintf(vzDisplay, "vz = %3.2f", velocities.vz);
    sprintf(vrDisplay, "vr = %3.2f", velocities.vr);

    putText(image, vxDisplay, cvPoint(30,120), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);
    putText(image, vyDisplay, cvPoint(30,140), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);
    putText(image, vzDisplay, cvPoint(30,160), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);
    putText(image, vrDisplay, cvPoint(30,180), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);
  }
  else if (ObjectFollow) {
    sprintf(modeDisplay, "Object Following Mode");
  }
  else if (LineFollow) {
    sprintf(modeDisplay, "Line Following Mode");
  }

  if (ardrone.onGround()) {
    sprintf(flyingDisplay, "Landed");
  }
  else {
    sprintf(flyingDisplay, "Flying");
  }

  altitude = ardrone.getAltitude();
  sprintf(speedDisplay, "Speed = %3.2f", speed);
  sprintf(batteryDisplay, "Battery = %d", ardrone.getBatteryPercentage());
  sprintf(altitudeDisplay, "Altitude = %f", ardrone.getAltitude());

  //add flying mode to overlay
  putText(image, modeDisplay, cvPoint(30,20), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);

  //add grounded or flying to overlay
  putText(image, flyingDisplay, cvPoint(30,40), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);

  //add battery percentage to overlay
  putText(image, batteryDisplay, cvPoint(30,60), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);

  //add altitude to overlay
  putText(image, altitudeDisplay, cvPoint(30,80), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);

  //add speed to overlay
  putText(image, speedDisplay, cvPoint(30,100), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);

  cv::namedWindow("camera", CV_WINDOW_NORMAL);
  cv::resizeWindow("camera", 700, 400);
  cv::imshow("camera", image); //Display the camera feed
}

/*
 */
void Control::move() {
  ardrone.move3D(velocities.vx * speed, velocities.vy * speed, velocities.vz, velocities.vr);

  return;
}

/*
   Close connection to drone
 */
void Control::close() {

  //Close flying modes
  manualFlying->close();
  objectFollowing->close();
  lineFollowing->close();

  //close connections with drone
  ardrone.close();

  return;
}

<commit_msg>Add wii-remote controls for main control.<commit_after>/*
*/

#include "control.h"
#include "lineFollowing/lineFollowing.h"
#include "objectFollowing/objectFollowing.h"
#include "manual/manual.h"

/*
*/
Control::Control() {
  //Initializing Message
  printf("Connecting to the drone\n");
  printf("If there is no version number response in the next 10 seconds, please restart the drone and code.\n");
  fflush(stdout);

  flight_log = fopen(flightLog.c_str(), "w");
  green = CV_RGB(0,255,0);

  //Connect to drone
  if (!ardrone.open()) {
    throw "Failed to initialize.";
  }

  //Set drone trim on flat surface
  ardrone.setFlatTrim();

  //initialize flying mode code
  manualFlying = new ManualFlying(this);
  objectFollowing = new ObjectFollowing(this);
  lineFollowing = new LineFollowing(this);

  //Print default command information
  printf("To disconnect, press the ESC key\n\n");
  printf("Currently the drone is in manual mode.\n");
  printf("Use the b key for manual mode, the n key for object following, and the m key for line following. The number keys can be used to set a speed. Use spacebar to take off and land, which is required before any control can be executed.\n\n");
}

void Control::fly() {
  //Execute flying instruction code
  switch (flyingMode) {
    case Manual:
      manualFlying->fly();
      break;
    case ObjectFollow:
      objectFollowing->fly();
      break;
    case LineFollow:
      lineFollowing->fly();
      break;
  }

  return;
}

/*
  Detect ESC key press and
*/
bool Control::getKey(int wait) {
  key = cv::waitKey(wait);
  if (key == 0x1b) { return false; } //Escape key
  return true;
}

/*
*/
void Control::changeSpeed() {
  if ((key >= '0') && (key <= '9')) { //number keys
    speed = (key-'0')*0.1;
  }

  //Alternate controls for wii remote
  if (key == '+') {
    speed = speed + 0.1;
  }
  if (key == '-') {
    speed = speed - 0.1;
  }

}

/*
*/
void Control::getImage() {
//Get an image
  image = ardrone.getImage();
}

/*
  Switch between flying modes
*/
void Control::detectFlyingMode() {

  if (key == 'b') {
    flyingMode = Manual;
  }
  else if (key == 'n') {
    flyingMode = ObjectFollow;
  }
  else if (key == 'm') {
    flyingMode = LineFollow;
  }

  if (key == 'v') {
    if (flyingMode == Manual) {
      flyingMode = ObjectFollow;
    }
    else if (flyingMode == ObjectFollow) {
      flyingMode = LineFollow;
    }
    else if (flyingMode == LineFollow) {
      flyingMode = Manual;
    }
  }

  if (flyingMode == Manual) {
    ardrone.setCamera(0);
    printf("Manual flying mode is enabled\n");
    printf("Press n for object following and m for line following\n");
    printf("While in manual mode, use q and a for up and down, t and g for forward and backward, and f and h for left and right. Press space to take off.\n\n");
  }
  else if (flyingMode == ObjectFollow) {
    ardrone.setCamera(0);
    printf("Object Following flying mode is enabled\n");
    printf("Press b for manual and m for line following\n");
    printf("While in object following mode, use l to toggle learning a specific color. Press space to take off after learning a color.\n\n");
  }
  else if (flyingMode == LineFollow) {
    ardrone.setCamera(1);
    printf("Line Following flying mode is enabled\n");
    printf("Press b for manual and n for object following\n");
    printf("No control for line following yet exists\n\n");
  }

}

/*
  Take off / Landing
*/
void Control::detectTakeoff() {
  if (key == ' ') { //spacebar
    if (ardrone.onGround()) {
      ardrone.takeoff();
      fprintf(flight_log, "TAKEOFF\n");
      takeoff_time = time(0);
    }
    else {
      ardrone.landing();
      fprintf(flight_log, "LAND\n");
    }
  }
}

/*
*/
void Control::overlayControl() {

  char modeDisplay[80]; //print buffer for flying mode
  char speedDisplay[80]; //print buffer for speed
  char flyingDisplay[80]; //print buffer for if flying
  char batteryDisplay[80]; //print buffer for battery
  char altitudeDisplay[80]; //print buffer for altitude

  char vxDisplay[80]; //print buffer for x (forward/reverse) velocity
  char vyDisplay[80]; //print buffer for y (sideways) velocity
  char vzDisplay[80]; //print buffer for z (up/down) velocity
  char vrDisplay[80]; //print buffer for r rotational velocity

  if (flyingMode == Manual) {
    sprintf(modeDisplay, "Manual Mode");

    sprintf(vxDisplay, "vx = %3.2f", velocities.vx);
    sprintf(vyDisplay, "vy = %3.2f", velocities.vy);
    sprintf(vzDisplay, "vz = %3.2f", velocities.vz);
    sprintf(vrDisplay, "vr = %3.2f", velocities.vr);

    putText(image, vxDisplay, cvPoint(30,120), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);
    putText(image, vyDisplay, cvPoint(30,140), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);
    putText(image, vzDisplay, cvPoint(30,160), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);
    putText(image, vrDisplay, cvPoint(30,180), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);
  }
  else if (ObjectFollow) {
    sprintf(modeDisplay, "Object Following Mode");
  }
  else if (LineFollow) {
    sprintf(modeDisplay, "Line Following Mode");
  }

  if (ardrone.onGround()) {
    sprintf(flyingDisplay, "Landed");
  }
  else {
    sprintf(flyingDisplay, "Flying");
  }

  altitude = ardrone.getAltitude();
  sprintf(speedDisplay, "Speed = %3.2f", speed);
  sprintf(batteryDisplay, "Battery = %d", ardrone.getBatteryPercentage());
  sprintf(altitudeDisplay, "Altitude = %f", ardrone.getAltitude());

  //add flying mode to overlay
  putText(image, modeDisplay, cvPoint(30,20), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);

  //add grounded or flying to overlay
  putText(image, flyingDisplay, cvPoint(30,40), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);

  //add battery percentage to overlay
  putText(image, batteryDisplay, cvPoint(30,60), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);

  //add altitude to overlay
  putText(image, altitudeDisplay, cvPoint(30,80), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);

  //add speed to overlay
  putText(image, speedDisplay, cvPoint(30,100), cv::FONT_HERSHEY_COMPLEX_SMALL, 0.8, green, 1, CV_AA);

  cv::namedWindow("camera", CV_WINDOW_NORMAL);
  cv::resizeWindow("camera", 700, 400);
  cv::imshow("camera", image); //Display the camera feed
}

/*
 */
void Control::move() {
  ardrone.move3D(velocities.vx * speed, velocities.vy * speed, velocities.vz, velocities.vr);

  return;
}

/*
   Close connection to drone
 */
void Control::close() {

  //Close flying modes
  manualFlying->close();
  objectFollowing->close();
  lineFollowing->close();

  //close connections with drone
  ardrone.close();

  return;
}

<|endoftext|>


<commit_before>// Copyright (c) 2009-2012 The Bitcoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <openssl/aes.h>
#include <openssl/evp.h>
#include <vector>
#include <string>

#include "crypter.h"
#include "scrypt.h"

bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
{
    if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
        return false;

    int i = 0;
    if (nDerivationMethod == 0)
    {
        i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
                          (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, vchKey.data(), vchIV.data());
    }

    if (nDerivationMethod == 1)
    {
        // Passphrase conversion
        uint256 scryptHash = scrypt_salted_multiround_hash((const void*)strKeyData.c_str(), strKeyData.size(), &chSalt[0], 8, nRounds);

        i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
                          (unsigned char *)&scryptHash, sizeof scryptHash, nRounds, vchKey.data(), vchIV.data());
        OPENSSL_cleanse(&scryptHash, sizeof scryptHash);
    }

    if (i != (int)WALLET_CRYPTO_KEY_SIZE)
    {
        OPENSSL_cleanse(vchKey.data(), vchKey.size());
        OPENSSL_cleanse(vchIV.data(), vchIV.size());
        return false;
    }

    fKeySet = true;
    return true;
}

bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
{
    if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_KEY_SIZE)
        return false;

    memcpy(vchKey.data(), chNewKey.data(), chNewKey.size());
    memcpy(vchIV.data(), chNewIV.data(), chNewIV.size());

    fKeySet = true;
    return true;
}

bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const
{
    if (!fKeySet)
        return false;

    // max ciphertext len for a n bytes of plaintext is
    // n + AES_BLOCK_SIZE - 1 bytes
    int nLen = vchPlaintext.size();
    int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
    vchCiphertext = std::vector<unsigned char> (nCLen);

    bool fOk = true;

    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if(!ctx)
        throw std::runtime_error("Error allocating cipher context");

    if (fOk) fOk = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, vchKey.data(), vchIV.data());
    if (fOk) fOk = EVP_EncryptUpdate(ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen);
    if (fOk) fOk = EVP_EncryptFinal_ex(ctx, (&vchCiphertext[0])+nCLen, &nFLen);
    EVP_CIPHER_CTX_free(ctx);

    if (!fOk) return false;

    vchCiphertext.resize(nCLen + nFLen);
    return true;
}

bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const
{
    if (!fKeySet)
        return false;

    // plaintext will always be equal to or lesser than length of ciphertext
    int nLen = vchCiphertext.size();
    int nPLen = nLen, nFLen = 0;

    vchPlaintext = CKeyingMaterial(nPLen);

    bool fOk = true;

    EVP_CIPHER_CTX *ctx= EVP_CIPHER_CTX_new();
    if(!ctx)
        throw std::runtime_error("Error allocating cipher context");

    if (fOk) fOk = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, vchKey.data(), vchIV.data());
    if (fOk) fOk = EVP_DecryptUpdate(ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen);
    if (fOk) fOk = EVP_DecryptFinal_ex(ctx, (&vchPlaintext[0])+nPLen, &nFLen);
    EVP_CIPHER_CTX_free(ctx);

    if (!fOk) return false;

    vchPlaintext.resize(nPLen + nFLen);
    return true;
}

bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
{
    CCrypter cKeyCrypter;
    std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
    memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
    if(!cKeyCrypter.SetKey(vMasterKey, chIV))
        return false;
    return cKeyCrypter.Encrypt((CKeyingMaterial)vchPlaintext, vchCiphertext);
}

bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CSecret& vchPlaintext)
{
    CCrypter cKeyCrypter;
    std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
    memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
    if(!cKeyCrypter.SetKey(vMasterKey, chIV))
        return false;
    return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
}
<commit_msg>Use agnostic memory zeroing from Bitcoin<commit_after>// Copyright (c) 2009-2012 The Bitcoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <openssl/aes.h>
#include <openssl/evp.h>
#include <vector>
#include <string>

#include "crypter.h"
#include "scrypt.h"

bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
{
    if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
        return false;

    int i = 0;
    if (nDerivationMethod == 0)
    {
        i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
                          (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, vchKey.data(), vchIV.data());
    }

    if (nDerivationMethod == 1)
    {
        // Passphrase conversion
        uint256 scryptHash = scrypt_salted_multiround_hash((const void*)strKeyData.c_str(), strKeyData.size(), &chSalt[0], 8, nRounds);

        i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0],
                          (unsigned char *)&scryptHash, sizeof scryptHash, nRounds, vchKey.data(), vchIV.data());
        memory_cleanse(&scryptHash, sizeof scryptHash);
    }

    if (i != (int)WALLET_CRYPTO_KEY_SIZE)
    {
        memory_cleanse(vchKey.data(), vchKey.size());
        memory_cleanse(vchIV.data(), vchIV.size());
        return false;
    }

    fKeySet = true;
    return true;
}

bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector<unsigned char>& chNewIV)
{
    if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_KEY_SIZE)
        return false;

    memcpy(vchKey.data(), chNewKey.data(), chNewKey.size());
    memcpy(vchIV.data(), chNewIV.data(), chNewIV.size());

    fKeySet = true;
    return true;
}

bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector<unsigned char> &vchCiphertext) const
{
    if (!fKeySet)
        return false;

    // max ciphertext len for a n bytes of plaintext is
    // n + AES_BLOCK_SIZE - 1 bytes
    int nLen = vchPlaintext.size();
    int nCLen = nLen + AES_BLOCK_SIZE, nFLen = 0;
    vchCiphertext = std::vector<unsigned char> (nCLen);

    bool fOk = true;

    EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
    if(!ctx)
        throw std::runtime_error("Error allocating cipher context");

    if (fOk) fOk = EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, vchKey.data(), vchIV.data());
    if (fOk) fOk = EVP_EncryptUpdate(ctx, &vchCiphertext[0], &nCLen, &vchPlaintext[0], nLen);
    if (fOk) fOk = EVP_EncryptFinal_ex(ctx, (&vchCiphertext[0])+nCLen, &nFLen);
    EVP_CIPHER_CTX_free(ctx);

    if (!fOk) return false;

    vchCiphertext.resize(nCLen + nFLen);
    return true;
}

bool CCrypter::Decrypt(const std::vector<unsigned char>& vchCiphertext, CKeyingMaterial& vchPlaintext) const
{
    if (!fKeySet)
        return false;

    // plaintext will always be equal to or lesser than length of ciphertext
    int nLen = vchCiphertext.size();
    int nPLen = nLen, nFLen = 0;

    vchPlaintext = CKeyingMaterial(nPLen);

    bool fOk = true;

    EVP_CIPHER_CTX *ctx= EVP_CIPHER_CTX_new();
    if(!ctx)
        throw std::runtime_error("Error allocating cipher context");

    if (fOk) fOk = EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, vchKey.data(), vchIV.data());
    if (fOk) fOk = EVP_DecryptUpdate(ctx, &vchPlaintext[0], &nPLen, &vchCiphertext[0], nLen);
    if (fOk) fOk = EVP_DecryptFinal_ex(ctx, (&vchPlaintext[0])+nPLen, &nFLen);
    EVP_CIPHER_CTX_free(ctx);

    if (!fOk) return false;

    vchPlaintext.resize(nPLen + nFLen);
    return true;
}

bool EncryptSecret(CKeyingMaterial& vMasterKey, const CSecret &vchPlaintext, const uint256& nIV, std::vector<unsigned char> &vchCiphertext)
{
    CCrypter cKeyCrypter;
    std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
    memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
    if(!cKeyCrypter.SetKey(vMasterKey, chIV))
        return false;
    return cKeyCrypter.Encrypt((CKeyingMaterial)vchPlaintext, vchCiphertext);
}

bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector<unsigned char>& vchCiphertext, const uint256& nIV, CSecret& vchPlaintext)
{
    CCrypter cKeyCrypter;
    std::vector<unsigned char> chIV(WALLET_CRYPTO_KEY_SIZE);
    memcpy(&chIV[0], &nIV, WALLET_CRYPTO_KEY_SIZE);
    if(!cKeyCrypter.SetKey(vMasterKey, chIV))
        return false;
    return cKeyCrypter.Decrypt(vchCiphertext, *((CKeyingMaterial*)&vchPlaintext));
}
<|endoftext|>


<commit_before>#include "PDBHelper.h"
#include "../Misc/Trace.hpp"

#include <cstdint>
#include <sstream>

#define CHECK_SUCCESS(e)\
{ \
    HRESULT hresult = (e); \
    if(FAILED(hresult)) \
    { \
        BLACKBONE_TRACE( "PDB: %s: (%s) failed with HRESULT 0x%08x", __FUNCTION__, #e , hresult ); \
        return hresult; \
    } \
}

namespace blackbone
{

PDBHelper::PDBHelper()
{
    CoInitialize( nullptr );

    // If _NT_SYMBOL_PATH exists, use it
    wchar_t path[MAX_PATH] = { };
    if (GetEnvironmentVariableW( L"_NT_SYMBOL_PATH", path, _countof( path ) ) == 0)
    {
        if (GetTempPathW( _countof( path ), path ) != 0)
        {
            std::wstringstream wss;
            wss << L"srv*" << path << L"Symbols*http://msdl.microsoft.com/download/symbols";
            _sympath = wss.str();
        }
    }
}

PDBHelper::~PDBHelper()
{
    // Must be released before CoUninitialize
    _global.Release();
    _session.Release();
    _source.Release();

    CoUninitialize();
}

/// <summary>
/// Initialize symbols for target file
/// </summary>
/// <param name="file">Fully qualified path to target PE file</param>
/// <param name="base">Base ptr to add to RVAs</param>
/// <returns>Status code</returns>
HRESULT PDBHelper::Init( const std::wstring& file, ptr_t base /*= 0*/ )
{
    CHECK_SUCCESS( CoCreateDiaDataSource() );
    CHECK_SUCCESS( _source->loadDataForExe( file.c_str(), _sympath.empty() ? nullptr : _sympath.c_str(), nullptr ) );
    CHECK_SUCCESS( _source->openSession( &_session ) );
    CHECK_SUCCESS( _session->get_globalScope( &_global ) );

    _base = base;
    return PopulateSymbols();
}

/// <summary>
/// Get symbol RVA
/// </summary>
/// <param name="symName">Symbol name</param>
/// <param name="result">Resulting RVA</param>
/// <returns>Status code</returns>
HRESULT PDBHelper::GetSymAddress( const std::wstring& symName, ptr_t& result )
{
    auto found = _cache.find( symName );
    if (found != _cache.end())
    {
        result = _base + found->second;
        return S_OK;
    }

    return E_PDB_DBG_NOT_FOUND;
}

/// <summary>
/// Initialize DIA
/// </summary>
/// <returns>Status code</returns>
HRESULT PDBHelper::CoCreateDiaDataSource()
{
    const auto pSource = reinterpret_cast<void**>(&_source);

    // Try to get from COM
    HRESULT hr = CoCreateInstance( CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER, __uuidof(IDiaDataSource), pSource );

    // Retry with direct export call
    if (hr == REGDB_E_CLASSNOTREG)
    {
        HMODULE hMod = LoadLibraryW( L"msdia140.dll" );
        if (!hMod)
        {
            const auto err = GetLastError();
            BLACKBONE_TRACE( "PDB: Failed to load msdia140.dll, error 0x%08x", err );
            return HRESULT_FROM_WIN32( err );
        }

        auto DllGetClassObject = reinterpret_cast<BOOL( WINAPI* )(REFCLSID, REFIID, LPVOID)>(GetProcAddress( hMod, "DllGetClassObject" ));
        if (!DllGetClassObject)
        {
            const auto err = GetLastError();
            BLACKBONE_TRACE( "PDB: Failed to get DllGetClassObject from msdia140.dll" );
            return HRESULT_FROM_WIN32( err );
        }

        CComPtr<IClassFactory> classFactory;
        CHECK_SUCCESS( DllGetClassObject( CLSID_DiaSource, IID_IClassFactory, &classFactory ) );
        hr = classFactory->CreateInstance( nullptr, IID_IDiaDataSource, pSource );
    }

    if (FAILED( hr ))
    {
        BLACKBONE_TRACE( "PDB: %s failed with HRESULT 0x%08x", __FUNCTION__, hr );
    }

    return hr;
}

/// <summary>
/// Build module symbol map
/// </summary>
/// <returns>Status code</returns>
HRESULT PDBHelper::PopulateSymbols()
{
    CComPtr<IDiaEnumSymbols> symbols;
    CHECK_SUCCESS( _global->findChildren( SymTagNull, nullptr, nsNone, &symbols ) );

    ULONG count = 0;
    CComPtr<IDiaSymbol> symbol;
    while (SUCCEEDED( symbols->Next( 1, &symbol, &count ) ) && count != 0)
    {
        DWORD rva = 0;
        BSTR name = nullptr;

        symbol->get_relativeVirtualAddress( &rva );
        symbol->get_undecoratedName( &name );

        if (name && rva)
        {
            std::wstring wname( name );

            // Remove x86 __stdcall decoration
            if (wname[0] == L'@' || wname[0] == L'_')
            {
                wname.erase( 0, 1 );
            }

            auto pos = wname.rfind( L'@' );
            if (pos != wname.npos)
            {
                wname.erase( pos );
            }

            _cache.emplace( std::move( wname ), rva );
        }

        symbol.Release();
    }

    return S_OK;
}

}<commit_msg>Fixed a memory leak in PDBHelper<commit_after>#include "PDBHelper.h"
#include "../Misc/Trace.hpp"

#include <cstdint>
#include <sstream>

#define CHECK_SUCCESS(e)\
{ \
    HRESULT hresult = (e); \
    if(FAILED(hresult)) \
    { \
        BLACKBONE_TRACE( "PDB: %s: (%s) failed with HRESULT 0x%08x", __FUNCTION__, #e , hresult ); \
        return hresult; \
    } \
}

namespace blackbone
{

PDBHelper::PDBHelper()
{
    CoInitialize( nullptr );

    // If _NT_SYMBOL_PATH exists, use it
    wchar_t path[MAX_PATH] = { };
    if (GetEnvironmentVariableW( L"_NT_SYMBOL_PATH", path, _countof( path ) ) == 0)
    {
        if (GetTempPathW( _countof( path ), path ) != 0)
        {
            std::wstringstream wss;
            wss << L"srv*" << path << L"Symbols*http://msdl.microsoft.com/download/symbols";
            _sympath = wss.str();
        }
    }
}

PDBHelper::~PDBHelper()
{
    // Must be released before CoUninitialize
    _global.Release();
    _session.Release();
    _source.Release();

    CoUninitialize();
}

/// <summary>
/// Initialize symbols for target file
/// </summary>
/// <param name="file">Fully qualified path to target PE file</param>
/// <param name="base">Base ptr to add to RVAs</param>
/// <returns>Status code</returns>
HRESULT PDBHelper::Init( const std::wstring& file, ptr_t base /*= 0*/ )
{
    CHECK_SUCCESS( CoCreateDiaDataSource() );
    CHECK_SUCCESS( _source->loadDataForExe( file.c_str(), _sympath.empty() ? nullptr : _sympath.c_str(), nullptr ) );
    CHECK_SUCCESS( _source->openSession( &_session ) );
    CHECK_SUCCESS( _session->get_globalScope( &_global ) );

    _base = base;
    return PopulateSymbols();
}

/// <summary>
/// Get symbol RVA
/// </summary>
/// <param name="symName">Symbol name</param>
/// <param name="result">Resulting RVA</param>
/// <returns>Status code</returns>
HRESULT PDBHelper::GetSymAddress( const std::wstring& symName, ptr_t& result )
{
    auto found = _cache.find( symName );
    if (found != _cache.end())
    {
        result = _base + found->second;
        return S_OK;
    }

    return E_PDB_DBG_NOT_FOUND;
}

/// <summary>
/// Initialize DIA
/// </summary>
/// <returns>Status code</returns>
HRESULT PDBHelper::CoCreateDiaDataSource()
{
    const auto pSource = reinterpret_cast<void**>(&_source);

    // Try to get from COM
    HRESULT hr = CoCreateInstance( CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER, __uuidof(IDiaDataSource), pSource );

    // Retry with direct export call
    if (hr == REGDB_E_CLASSNOTREG)
    {
        HMODULE hMod = LoadLibraryW( L"msdia140.dll" );
        if (!hMod)
        {
            const auto err = GetLastError();
            BLACKBONE_TRACE( "PDB: Failed to load msdia140.dll, error 0x%08x", err );
            return HRESULT_FROM_WIN32( err );
        }

        auto DllGetClassObject = reinterpret_cast<BOOL( WINAPI* )(REFCLSID, REFIID, LPVOID)>(GetProcAddress( hMod, "DllGetClassObject" ));
        if (!DllGetClassObject)
        {
            const auto err = GetLastError();
            BLACKBONE_TRACE( "PDB: Failed to get DllGetClassObject from msdia140.dll" );
            return HRESULT_FROM_WIN32( err );
        }

        CComPtr<IClassFactory> classFactory;
        CHECK_SUCCESS( DllGetClassObject( CLSID_DiaSource, IID_IClassFactory, &classFactory ) );
        hr = classFactory->CreateInstance( nullptr, IID_IDiaDataSource, pSource );
    }

    if (FAILED( hr ))
    {
        BLACKBONE_TRACE( "PDB: %s failed with HRESULT 0x%08x", __FUNCTION__, hr );
    }

    return hr;
}

/// <summary>
/// Build module symbol map
/// </summary>
/// <returns>Status code</returns>
HRESULT PDBHelper::PopulateSymbols()
{
    CComPtr<IDiaEnumSymbols> symbols;
    CHECK_SUCCESS( _global->findChildren( SymTagNull, nullptr, nsNone, &symbols ) );

    ULONG count = 0;
    CComPtr<IDiaSymbol> symbol;
    while (SUCCEEDED( symbols->Next( 1, &symbol, &count ) ) && count != 0)
    {
        DWORD rva = 0;
        CComBSTR name;

        symbol->get_relativeVirtualAddress( &rva );
        symbol->get_undecoratedName( &name );

        if (name && rva)
        {
            std::wstring wname( name );

            // Remove x86 __stdcall decoration
            if (wname[0] == L'@' || wname[0] == L'_')
            {
                wname.erase( 0, 1 );
            }

            auto pos = wname.rfind( L'@' );
            if (pos != wname.npos)
            {
                wname.erase( pos );
            }

            _cache.emplace( std::move( wname ), rva );
        }

        symbol.Release();
    }

    return S_OK;
}

}
<|endoftext|>


<commit_before>#include "PDBHelper.h"
#include "../Misc/Trace.hpp"

#include <cstdint>
#include <sstream>

#define CHECK_SUCCESS(e)\
{ \
    HRESULT hresult = (e); \
    if(FAILED(hresult)) \
    { \
        BLACKBONE_TRACE( "PDB: %s: (%s) failed with HRESULT 0x%08x", __FUNCTION__, #e , hresult ); \
        return hresult; \
    } \
}

namespace blackbone
{

PDBHelper::PDBHelper()
{
    CoInitialize( nullptr );

    // If _NT_SYMBOL_PATH exists, use it
    wchar_t path[MAX_PATH] = { };
    if (GetEnvironmentVariableW( L"_NT_SYMBOL_PATH", path, _countof( path ) ) == 0)
    {
        if (GetTempPathW( _countof( path ), path ) != 0)
        {
            std::wstringstream wss;
            wss << L"srv*" << path << L"Symbols*http://msdl.microsoft.com/download/symbols";
            _sympath = wss.str();
        }
    }
}

PDBHelper::~PDBHelper()
{
    // Must be released before CoUninitialize
    _global.Release();
    _session.Release();
    _source.Release();

    CoUninitialize();
}

/// <summary>
/// Initialize symbols for target file
/// </summary>
/// <param name="file">Fully qualified path to target PE file</param>
/// <param name="base">Base ptr to add to RVAs</param>
/// <returns>Status code</returns>
HRESULT PDBHelper::Init( const std::wstring& file, ptr_t base /*= 0*/ )
{
    CHECK_SUCCESS( CoCreateDiaDataSource() );
    CHECK_SUCCESS( _source->loadDataForExe( file.c_str(), _sympath.empty() ? nullptr : _sympath.c_str(), nullptr ) );
    CHECK_SUCCESS( _source->openSession( &_session ) );
    CHECK_SUCCESS( _session->get_globalScope( &_global ) );

    _base = base;
    return PopulateSymbols();
}

/// <summary>
/// Get symbol RVA
/// </summary>
/// <param name="symName">Symbol name</param>
/// <param name="result">Resulting RVA</param>
/// <returns>Status code</returns>
HRESULT PDBHelper::GetSymAddress( const std::wstring& symName, ptr_t& result )
{
    auto found = _cache.find( symName );
    if (found != _cache.end())
    {
        result = _base + found->second;
        return S_OK;
    }

    return E_PDB_DBG_NOT_FOUND;
}

/// <summary>
/// Initialize DIA
/// </summary>
/// <returns>Status code</returns>
HRESULT PDBHelper::CoCreateDiaDataSource()
{
    const auto pSource = reinterpret_cast<void**>(&_source);

    // Try to get from COM
    HRESULT hr = CoCreateInstance( CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER, __uuidof(IDiaDataSource), pSource );

    // Retry with direct export call
    if (hr == REGDB_E_CLASSNOTREG)
    {
        HMODULE hMod = LoadLibraryW( L"msdia140.dll" );
        if (!hMod)
        {
            BLACKBONE_TRACE( "PDB: Failed to load msdia140.dll, error 0x08%x", GetLastError() );
            return HRESULT_FROM_WIN32( GetLastError() );
        }

        auto DllGetClassObject = reinterpret_cast<BOOL( WINAPI* )(REFCLSID, REFIID, LPVOID)>(GetProcAddress( hMod, "DllGetClassObject" ));
        if (!DllGetClassObject)
        {
            BLACKBONE_TRACE( "PDB: Failed to get DllGetClassObject from msdia140.dll" );
            return HRESULT_FROM_WIN32( GetLastError() );
        }

        CComPtr<IClassFactory> classFactory;
        CHECK_SUCCESS( DllGetClassObject( CLSID_DiaSource, IID_IClassFactory, &classFactory ) );
        hr = classFactory->CreateInstance( nullptr, IID_IDiaDataSource, pSource );
    }

    if (FAILED( hr ))
    {
        BLACKBONE_TRACE( "PDB: %s failed with HRESULT 0x08%x", __FUNCTION__, hr );
    }

    return hr;
}

/// <summary>
/// Build module symbol map
/// </summary>
/// <returns>Status code</returns>
HRESULT PDBHelper::PopulateSymbols()
{
    CComPtr<IDiaEnumSymbols> symbols;
    CHECK_SUCCESS( _global->findChildren( SymTagNull, nullptr, nsNone, &symbols ) );

    ULONG count = 0;
    CComPtr<IDiaSymbol> symbol;
    while (SUCCEEDED( symbols->Next( 1, &symbol, &count ) ) && count != 0)
    {
        DWORD rva = 0;
        BSTR name = nullptr;

        symbol->get_relativeVirtualAddress( &rva );
        symbol->get_undecoratedName( &name );

        if (name && rva)
        {
            std::wstring wname( name );

            // Remove x86 __stdcall decoration
            if (wname[0] == L'@' || wname[0] == L'_')
            {
                wname.erase( 0, 1 );
            }

            auto pos = wname.rfind( L'@' );
            if (pos != wname.npos)
            {
                wname.erase( pos );
            }

            _cache.emplace( std::move( wname ), rva );
        }

        symbol.Release();
    }

    return S_OK;
}

}<commit_msg>fixed crash when no msdia is present<commit_after>#include "PDBHelper.h"
#include "../Misc/Trace.hpp"

#include <cstdint>
#include <sstream>

#define CHECK_SUCCESS(e)\
{ \
    HRESULT hresult = (e); \
    if(FAILED(hresult)) \
    { \
        BLACKBONE_TRACE( "PDB: %s: (%s) failed with HRESULT 0x%08x", __FUNCTION__, #e , hresult ); \
        return hresult; \
    } \
}

namespace blackbone
{

PDBHelper::PDBHelper()
{
    CoInitialize( nullptr );

    // If _NT_SYMBOL_PATH exists, use it
    wchar_t path[MAX_PATH] = { };
    if (GetEnvironmentVariableW( L"_NT_SYMBOL_PATH", path, _countof( path ) ) == 0)
    {
        if (GetTempPathW( _countof( path ), path ) != 0)
        {
            std::wstringstream wss;
            wss << L"srv*" << path << L"Symbols*http://msdl.microsoft.com/download/symbols";
            _sympath = wss.str();
        }
    }
}

PDBHelper::~PDBHelper()
{
    // Must be released before CoUninitialize
    _global.Release();
    _session.Release();
    _source.Release();

    CoUninitialize();
}

/// <summary>
/// Initialize symbols for target file
/// </summary>
/// <param name="file">Fully qualified path to target PE file</param>
/// <param name="base">Base ptr to add to RVAs</param>
/// <returns>Status code</returns>
HRESULT PDBHelper::Init( const std::wstring& file, ptr_t base /*= 0*/ )
{
    CHECK_SUCCESS( CoCreateDiaDataSource() );
    CHECK_SUCCESS( _source->loadDataForExe( file.c_str(), _sympath.empty() ? nullptr : _sympath.c_str(), nullptr ) );
    CHECK_SUCCESS( _source->openSession( &_session ) );
    CHECK_SUCCESS( _session->get_globalScope( &_global ) );

    _base = base;
    return PopulateSymbols();
}

/// <summary>
/// Get symbol RVA
/// </summary>
/// <param name="symName">Symbol name</param>
/// <param name="result">Resulting RVA</param>
/// <returns>Status code</returns>
HRESULT PDBHelper::GetSymAddress( const std::wstring& symName, ptr_t& result )
{
    auto found = _cache.find( symName );
    if (found != _cache.end())
    {
        result = _base + found->second;
        return S_OK;
    }

    return E_PDB_DBG_NOT_FOUND;
}

/// <summary>
/// Initialize DIA
/// </summary>
/// <returns>Status code</returns>
HRESULT PDBHelper::CoCreateDiaDataSource()
{
    const auto pSource = reinterpret_cast<void**>(&_source);

    // Try to get from COM
    HRESULT hr = CoCreateInstance( CLSID_DiaSource, nullptr, CLSCTX_INPROC_SERVER, __uuidof(IDiaDataSource), pSource );

    // Retry with direct export call
    if (hr == REGDB_E_CLASSNOTREG)
    {
        HMODULE hMod = LoadLibraryW( L"msdia140.dll" );
        if (!hMod)
        {
            const auto err = GetLastError();
            BLACKBONE_TRACE( "PDB: Failed to load msdia140.dll, error 0x08%x", err );
            return HRESULT_FROM_WIN32( err );
        }

        auto DllGetClassObject = reinterpret_cast<BOOL( WINAPI* )(REFCLSID, REFIID, LPVOID)>(GetProcAddress( hMod, "DllGetClassObject" ));
        if (!DllGetClassObject)
        {
            const auto err = GetLastError();
            BLACKBONE_TRACE( "PDB: Failed to get DllGetClassObject from msdia140.dll" );
            return HRESULT_FROM_WIN32( err );
        }

        CComPtr<IClassFactory> classFactory;
        CHECK_SUCCESS( DllGetClassObject( CLSID_DiaSource, IID_IClassFactory, &classFactory ) );
        hr = classFactory->CreateInstance( nullptr, IID_IDiaDataSource, pSource );
    }

    if (FAILED( hr ))
    {
        BLACKBONE_TRACE( "PDB: %s failed with HRESULT 0x08%x", __FUNCTION__, hr );
    }

    return hr;
}

/// <summary>
/// Build module symbol map
/// </summary>
/// <returns>Status code</returns>
HRESULT PDBHelper::PopulateSymbols()
{
    CComPtr<IDiaEnumSymbols> symbols;
    CHECK_SUCCESS( _global->findChildren( SymTagNull, nullptr, nsNone, &symbols ) );

    ULONG count = 0;
    CComPtr<IDiaSymbol> symbol;
    while (SUCCEEDED( symbols->Next( 1, &symbol, &count ) ) && count != 0)
    {
        DWORD rva = 0;
        BSTR name = nullptr;

        symbol->get_relativeVirtualAddress( &rva );
        symbol->get_undecoratedName( &name );

        if (name && rva)
        {
            std::wstring wname( name );

            // Remove x86 __stdcall decoration
            if (wname[0] == L'@' || wname[0] == L'_')
            {
                wname.erase( 0, 1 );
            }

            auto pos = wname.rfind( L'@' );
            if (pos != wname.npos)
            {
                wname.erase( pos );
            }

            _cache.emplace( std::move( wname ), rva );
        }

        symbol.Release();
    }

    return S_OK;
}

}<|endoftext|>