<commit_before>#include "rmedownloader.h"

#include <QDir>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QPixmap>
#include <QTimer>

#ifdef Q_OS_OSX
#include <QStandardPaths>
#endif

class RmeDownloaderPrivate : public QObject
{
    Q_OBJECT

public:
    explicit RmeDownloaderPrivate(RmeDownloader *downloader);

private:
    void downloadSingleFile();

private slots:
    void singleFileFinished();
    void singleFileError(QNetworkReply::NetworkError e);
    void downloadProgress(quint64 downloaded, quint64 total);

    void run();
    void cancel();

signals:
    void canceled();
    void started();

public:
    // q-ptr
    RmeDownloader *m_downloader;

    // public to RmeDownloader only since this class is always an incomplete type outside rmedownloader.cpp
    QStringList m_downloadSequence;
    QString m_downloadPath;
    bool m_skipExisting;
    bool m_canceled;
    bool m_running;

private:
    // private to RmeDownloaderPrivate only.
    QStringList m_failedList;
    QString m_currentDownloadingFile;
    QDir m_downloadDir;
    QNetworkReply *m_currentDownloadingReply;
    QNetworkAccessManager *m_networkAccessManager;
    QTimer *m_timer;

    quint64 m_lastRecordedDownloadProgress;
};

RmeDownloaderPrivate::RmeDownloaderPrivate(RmeDownloader *downloader)
    : QObject(downloader)
    , m_downloader(downloader)
    , m_skipExisting(false)
    , m_canceled(false)
    , m_running(false)
    , m_currentDownloadingReply(nullptr)
    , m_networkAccessManager(nullptr)
    , m_timer(nullptr)
    , m_lastRecordedDownloadProgress(0u)
{
    connect(this, &RmeDownloaderPrivate::started, this, &RmeDownloaderPrivate::run);
    connect(this, &RmeDownloaderPrivate::canceled, this, &RmeDownloaderPrivate::cancel);
}

void RmeDownloaderPrivate::run()
{
    m_networkAccessManager = new QNetworkAccessManager(this);

    m_timer = new QTimer(this);
    m_timer->setInterval(10000);
    m_timer->setSingleShot(true);
    connect(m_timer, &QTimer::timeout, this, &RmeDownloaderPrivate::cancel);

    m_currentDownloadingReply = nullptr;

    QDir dir;
    m_running = true;
    m_canceled = false;
    QString savePath = m_downloadPath;

    if (!savePath.isEmpty()) {
        if (!dir.cd(savePath)) {
            if (!dir.mkpath(savePath)) {
                //emit error();
                return;
            }
            dir.cd(savePath);
        }
    }
    m_downloadDir = dir;

    downloadSingleFile();
}

void RmeDownloaderPrivate::cancel()
{
    disconnect(m_currentDownloadingReply, ((void (QNetworkReply::*)(QNetworkReply::NetworkError))(&QNetworkReply::error)), this, &RmeDownloaderPrivate::singleFileError);
    disconnect(m_currentDownloadingReply, &QNetworkReply::finished, this, &RmeDownloaderPrivate::singleFileFinished);
    disconnect(m_currentDownloadingReply, &QNetworkReply::downloadProgress, this, &RmeDownloaderPrivate::downloadProgress);

    m_currentDownloadingReply->abort();

    m_failedList << m_currentDownloadingFile;

    QTimer *timer = qobject_cast<QTimer *>(sender());
    if (timer != nullptr)
        qDebug() << m_currentDownloadingFile << "timeout";
    else
        qDebug() << m_currentDownloadingFile << "abort";

    singleFileFinished();
}

RmeDownloader::RmeDownloader()
    : d_ptr(new RmeDownloaderPrivate(this))
{
}

RmeDownloader::~RmeDownloader()
{
    Q_D(RmeDownloader);
    if (d->m_running)
        cancel();
}

void RmeDownloader::start()
{
    Q_D(RmeDownloader);
    emit d->started();
}

QString RmeDownloader::binDownloadPath()
{
#if defined(Q_OS_WIN)
    QDir currentDir = QDir::current();
    if (!currentDir.cd(QStringLiteral("downloader"))) {
        if (!currentDir.mkdir(QStringLiteral("downloader")))
            return QString();
        currentDir.cd(QStringLiteral("downloader"));
    }
#elif defined(Q_OS_OSX)
    QDir currentDir(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
    if (!currentDir.cd(QStringLiteral("RMEssentials"))) {
        if (!currentDir.mkdir(QStringLiteral("RMEssentials")))
            return QString();
        currentDir.cd(QStringLiteral("RMEssentials"));
    }
#elif defined(Q_OS_ANDROID)
    QDir currentDir(QStringLiteral("/sdcard/RM/res"));
    if (!currentDir.exists()) {
        currentDir = QDir(QStringLiteral("/sdcard"));
        if (!currentDir.mkpath(QStringLiteral("/sdcard/RM/res")))
            return QString();
        currentDir = QDir(QStringLiteral("/sdcard/RM/res"));
    }
#endif

    QString r = currentDir.absolutePath();
    if (!r.endsWith(QStringLiteral("/")))
        r.append(QStringLiteral("/"));

    return r;
}

QString RmeDownloader::songDownloadPath()
{
    QDir currentDir(binDownloadPath());

    if (!currentDir.cd(QStringLiteral("song"))) {
        if (!currentDir.mkdir(QStringLiteral("song")))
            return QString();
        currentDir.cd(QStringLiteral("song"));
    }

    QString r = currentDir.absolutePath();
    if (!r.endsWith(QStringLiteral("/")))
        r.append(QStringLiteral("/"));

    return r;
}

QString RmeDownloader::roleDownloadPath()
{
    QDir currentDir(binDownloadPath());

    if (!currentDir.cd(QStringLiteral("icon"))) {
        if (!currentDir.mkdir(QStringLiteral("icon")))
            return QString();
        currentDir.cd(QStringLiteral("icon"));
    }

    if (!currentDir.cd(QStringLiteral("role"))) {
        if (!currentDir.mkdir(QStringLiteral("role")))
            return QString();
        currentDir.cd(QStringLiteral("role"));
    }

    QString r = currentDir.absolutePath();
    if (!r.endsWith(QStringLiteral("/")))
        r.append(QStringLiteral("/"));

    return r;
}

QString RmeDownloader::noteImageDownloadPath()
{
    QDir currentDir(binDownloadPath());

    if (!currentDir.cd(QStringLiteral("NoteImage"))) {
        if (!currentDir.mkdir(QStringLiteral("NoteImage")))
            return QString();
        currentDir.cd(QStringLiteral("NoteImage"));
    }

    QString r = currentDir.absolutePath();
    if (!r.endsWith(QStringLiteral("/")))
        r.append(QStringLiteral("/"));

    return r;
}

RmeDownloader &RmeDownloader::operator<<(const QString &filename)
{
    Q_D(RmeDownloader);
    d->m_downloadSequence << filename;
    return *this;
}

QStringList RmeDownloader::downloadSequence() const
{
    Q_D(const RmeDownloader);
    return d->m_downloadSequence;
}

QString RmeDownloader::downloadPath() const
{
    Q_D(const RmeDownloader);
    return d->m_downloadPath;
}

void RmeDownloader::setDownloadPath(const QString &sp)
{
    Q_D(RmeDownloader);
    d->m_downloadPath = sp;
}

void RmeDownloader::setSkipExisting(bool skip)
{
    Q_D(RmeDownloader);
    d->m_skipExisting = skip;
}

bool RmeDownloader::skipExisting() const
{
    Q_D(const RmeDownloader);
    return d->m_skipExisting;
}

void RmeDownloaderPrivate::downloadSingleFile()
{
    if (m_downloadSequence.isEmpty()) {
        m_running = false;
        emit m_downloader->allCompleted();
        return;
    } else if (m_canceled) {
        m_running = false;
        m_canceled = false;
        emit m_downloader->canceled();
        return;
    }

    m_currentDownloadingFile = m_downloadSequence.takeFirst();
    bool isAll = m_skipExisting;
    if (isAll) {
        QString filename = QUrl(m_currentDownloadingFile).fileName();
        if (filename.endsWith(QStringLiteral(".jpg"))) { // important hack!!
            filename.chop(4);
            filename.append(QStringLiteral(".png"));
        }

        if (m_downloadDir.exists(filename)) {
            emit m_downloader->singleFileCompleted(m_currentDownloadingFile);
            downloadSingleFile();
            return;
        }
    }
    m_currentDownloadingReply = m_networkAccessManager->get(QNetworkRequest(QUrl(m_currentDownloadingFile)));
    connect(m_currentDownloadingReply, ((void (QNetworkReply::*)(QNetworkReply::NetworkError))(&QNetworkReply::error)), this, &RmeDownloaderPrivate::singleFileError);
    connect(m_currentDownloadingReply, &QNetworkReply::finished, this, &RmeDownloaderPrivate::singleFileFinished);
    connect(m_currentDownloadingReply, &QNetworkReply::downloadProgress, this, &RmeDownloaderPrivate::downloadProgress);

    m_lastRecordedDownloadProgress = 0;
    m_timer->start();
}

void RmeDownloaderPrivate::singleFileError(QNetworkReply::NetworkError /*e*/)
{
    m_failedList << m_currentDownloadingFile;
    if (m_currentDownloadingReply != nullptr)
        qDebug() << m_currentDownloadingReply->errorString();
}

void RmeDownloaderPrivate::downloadProgress(quint64 downloaded, quint64 total)
{
    if (downloaded - m_lastRecordedDownloadProgress > 10000) {
        m_lastRecordedDownloadProgress = downloaded;
        m_timer->start();
    }
    emit m_downloader->downloadProgress(downloaded, total);
}

void RmeDownloaderPrivate::singleFileFinished()
{
    m_timer->stop();
    if (m_failedList.contains(m_currentDownloadingFile)) {
        emit m_downloader->singleFileFailed(m_currentDownloadingFile);
        downloadSingleFile();
    } else {
        if (m_currentDownloadingReply->attribute(QNetworkRequest::RedirectionTargetAttribute).isNull()) {
            QString filename = QUrl(m_currentDownloadingFile).fileName();
            QFile file(m_downloadDir.absoluteFilePath(filename));
            file.open(QIODevice::Truncate | QIODevice::WriteOnly);
            file.write(m_currentDownloadingReply->readAll());
            file.close();

            if (filename.endsWith(QStringLiteral(".jpg"))) { // important hack!!
                QString new_filename = filename;
                new_filename.chop(4);
                new_filename.append(QStringLiteral(".png"));
                //m_downloadDir.rename(filename, new_filename);
                QPixmap pm;
                if (pm.load(m_downloadDir.absoluteFilePath(filename))) {
                    if (pm.save(m_downloadDir.absoluteFilePath(new_filename), "PNG")) {
                        m_downloadDir.remove(filename);
                    } else
                        qDebug() << "save png error " << new_filename;
                } else if (pm.load(m_downloadDir.absoluteFilePath(filename), "PNG")) {
                    if (pm.save(m_downloadDir.absoluteFilePath(new_filename), "PNG")) {
                        m_downloadDir.remove(filename);
                    } else
                        qDebug() << "save png error " << new_filename;
                } else
                    qDebug() << "load jpg error " << filename;
            }

            emit m_downloader->singleFileCompleted(m_currentDownloadingFile);
            downloadSingleFile();
        } else {
            if (m_canceled) {
                emit m_downloader->canceled();
                return;
            }
            QUrl u = m_currentDownloadingReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
            if (u.isRelative())
                u = u.resolved(QUrl(m_currentDownloadingFile));
            qDebug() << "redirect!!" << u;
            m_currentDownloadingFile = u.toString();
            m_currentDownloadingReply = m_networkAccessManager->get(QNetworkRequest(u));
            connect(m_currentDownloadingReply, ((void (QNetworkReply::*)(QNetworkReply::NetworkError))(&QNetworkReply::error)), this, &RmeDownloaderPrivate::singleFileError);
            connect(m_currentDownloadingReply, &QNetworkReply::finished, this, &RmeDownloaderPrivate::singleFileFinished);
            connect(m_currentDownloadingReply, &QNetworkReply::downloadProgress, this, &RmeDownloaderPrivate::downloadProgress);
        }
    }
}

RmeDownloader *operator<<(RmeDownloader *downloader, const QString &filename)
{
    (*downloader) << filename;
    return downloader;
}

void RmeDownloader::cancel()
{
    Q_D(RmeDownloader);
    d->m_canceled = true;
    emit d->canceled();
}

#include "rmedownloader.moc"
<commit_msg>连signal-slot都不用啦<commit_after>#include "rmedownloader.h"

#include <QDir>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QPixmap>
#include <QTimer>

#ifdef Q_OS_OSX
#include <QStandardPaths>
#endif

class RmeDownloaderPrivate : public QObject
{
    Q_OBJECT

public:
    explicit RmeDownloaderPrivate(RmeDownloader *downloader);

private:
    void downloadSingleFile();

public slots:
    void singleFileFinished();
    void singleFileError(QNetworkReply::NetworkError e);
    void downloadProgress(quint64 downloaded, quint64 total);

    void run();
    void cancel();

public:
    // q-ptr
    RmeDownloader *m_downloader;

    // public to RmeDownloader only since this class is always an incomplete type outside rmedownloader.cpp
    QStringList m_downloadSequence;
    QString m_downloadPath;
    bool m_skipExisting;
    bool m_canceled;
    bool m_running;

private:
    // private to RmeDownloaderPrivate only.
    QStringList m_failedList;
    QString m_currentDownloadingFile;
    QDir m_downloadDir;
    QNetworkReply *m_currentDownloadingReply;
    QNetworkAccessManager *m_networkAccessManager;
    QTimer *m_timer;

    quint64 m_lastRecordedDownloadProgress;
};

RmeDownloaderPrivate::RmeDownloaderPrivate(RmeDownloader *downloader)
    : QObject(downloader)
    , m_downloader(downloader)
    , m_skipExisting(false)
    , m_canceled(false)
    , m_running(false)
    , m_currentDownloadingReply(nullptr)
    , m_networkAccessManager(nullptr)
    , m_timer(nullptr)
    , m_lastRecordedDownloadProgress(0u)
{
}

void RmeDownloaderPrivate::run()
{
    m_networkAccessManager = new QNetworkAccessManager(this);

    m_timer = new QTimer(this);
    m_timer->setInterval(10000);
    m_timer->setSingleShot(true);
    connect(m_timer, &QTimer::timeout, this, &RmeDownloaderPrivate::cancel);

    m_currentDownloadingReply = nullptr;

    QDir dir;
    m_running = true;
    m_canceled = false;
    QString savePath = m_downloadPath;

    if (!savePath.isEmpty()) {
        if (!dir.cd(savePath)) {
            if (!dir.mkpath(savePath)) {
                //emit error();
                return;
            }
            dir.cd(savePath);
        }
    }
    m_downloadDir = dir;

    downloadSingleFile();
}

void RmeDownloaderPrivate::cancel()
{
    m_canceled = true;

    disconnect(m_currentDownloadingReply, ((void (QNetworkReply::*)(QNetworkReply::NetworkError))(&QNetworkReply::error)), this, &RmeDownloaderPrivate::singleFileError);
    disconnect(m_currentDownloadingReply, &QNetworkReply::finished, this, &RmeDownloaderPrivate::singleFileFinished);
    disconnect(m_currentDownloadingReply, &QNetworkReply::downloadProgress, this, &RmeDownloaderPrivate::downloadProgress);

    m_currentDownloadingReply->abort();

    m_failedList << m_currentDownloadingFile;

    QTimer *timer = qobject_cast<QTimer *>(sender());
    if (timer != nullptr)
        qDebug() << m_currentDownloadingFile << "timeout";
    else
        qDebug() << m_currentDownloadingFile << "abort";

    singleFileFinished();
}

RmeDownloader::RmeDownloader()
    : d_ptr(new RmeDownloaderPrivate(this))
{
}

RmeDownloader::~RmeDownloader()
{
    Q_D(RmeDownloader);
    if (d->m_running)
        cancel();
}

void RmeDownloader::start()
{
    Q_D(RmeDownloader);
    d->run();
}

QString RmeDownloader::binDownloadPath()
{
#if defined(Q_OS_WIN)
    QDir currentDir = QDir::current();
    if (!currentDir.cd(QStringLiteral("downloader"))) {
        if (!currentDir.mkdir(QStringLiteral("downloader")))
            return QString();
        currentDir.cd(QStringLiteral("downloader"));
    }
#elif defined(Q_OS_OSX)
    QDir currentDir(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
    if (!currentDir.cd(QStringLiteral("RMEssentials"))) {
        if (!currentDir.mkdir(QStringLiteral("RMEssentials")))
            return QString();
        currentDir.cd(QStringLiteral("RMEssentials"));
    }
#elif defined(Q_OS_ANDROID)
    QDir currentDir(QStringLiteral("/sdcard/RM/res"));
    if (!currentDir.exists()) {
        currentDir = QDir(QStringLiteral("/sdcard"));
        if (!currentDir.mkpath(QStringLiteral("/sdcard/RM/res")))
            return QString();
        currentDir = QDir(QStringLiteral("/sdcard/RM/res"));
    }
#endif

    QString r = currentDir.absolutePath();
    if (!r.endsWith(QStringLiteral("/")))
        r.append(QStringLiteral("/"));

    return r;
}

QString RmeDownloader::songDownloadPath()
{
    QDir currentDir(binDownloadPath());

    if (!currentDir.cd(QStringLiteral("song"))) {
        if (!currentDir.mkdir(QStringLiteral("song")))
            return QString();
        currentDir.cd(QStringLiteral("song"));
    }

    QString r = currentDir.absolutePath();
    if (!r.endsWith(QStringLiteral("/")))
        r.append(QStringLiteral("/"));

    return r;
}

QString RmeDownloader::roleDownloadPath()
{
    QDir currentDir(binDownloadPath());

    if (!currentDir.cd(QStringLiteral("icon"))) {
        if (!currentDir.mkdir(QStringLiteral("icon")))
            return QString();
        currentDir.cd(QStringLiteral("icon"));
    }

    if (!currentDir.cd(QStringLiteral("role"))) {
        if (!currentDir.mkdir(QStringLiteral("role")))
            return QString();
        currentDir.cd(QStringLiteral("role"));
    }

    QString r = currentDir.absolutePath();
    if (!r.endsWith(QStringLiteral("/")))
        r.append(QStringLiteral("/"));

    return r;
}

QString RmeDownloader::noteImageDownloadPath()
{
    QDir currentDir(binDownloadPath());

    if (!currentDir.cd(QStringLiteral("NoteImage"))) {
        if (!currentDir.mkdir(QStringLiteral("NoteImage")))
            return QString();
        currentDir.cd(QStringLiteral("NoteImage"));
    }

    QString r = currentDir.absolutePath();
    if (!r.endsWith(QStringLiteral("/")))
        r.append(QStringLiteral("/"));

    return r;
}

RmeDownloader &RmeDownloader::operator<<(const QString &filename)
{
    Q_D(RmeDownloader);
    d->m_downloadSequence << filename;
    return *this;
}

QStringList RmeDownloader::downloadSequence() const
{
    Q_D(const RmeDownloader);
    return d->m_downloadSequence;
}

QString RmeDownloader::downloadPath() const
{
    Q_D(const RmeDownloader);
    return d->m_downloadPath;
}

void RmeDownloader::setDownloadPath(const QString &sp)
{
    Q_D(RmeDownloader);
    d->m_downloadPath = sp;
}

void RmeDownloader::setSkipExisting(bool skip)
{
    Q_D(RmeDownloader);
    d->m_skipExisting = skip;
}

bool RmeDownloader::skipExisting() const
{
    Q_D(const RmeDownloader);
    return d->m_skipExisting;
}

void RmeDownloaderPrivate::downloadSingleFile()
{
    if (m_downloadSequence.isEmpty()) {
        m_running = false;
        emit m_downloader->allCompleted();
        return;
    } else if (m_canceled) {
        m_running = false;
        m_canceled = false;
        emit m_downloader->canceled();
        return;
    }

    m_currentDownloadingFile = m_downloadSequence.takeFirst();
    bool isAll = m_skipExisting;
    if (isAll) {
        QString filename = QUrl(m_currentDownloadingFile).fileName();
        if (filename.endsWith(QStringLiteral(".jpg"))) { // important hack!!
            filename.chop(4);
            filename.append(QStringLiteral(".png"));
        }

        if (m_downloadDir.exists(filename)) {
            emit m_downloader->singleFileCompleted(m_currentDownloadingFile);
            downloadSingleFile();
            return;
        }
    }
    m_currentDownloadingReply = m_networkAccessManager->get(QNetworkRequest(QUrl(m_currentDownloadingFile)));
    connect(m_currentDownloadingReply, ((void (QNetworkReply::*)(QNetworkReply::NetworkError))(&QNetworkReply::error)), this, &RmeDownloaderPrivate::singleFileError);
    connect(m_currentDownloadingReply, &QNetworkReply::finished, this, &RmeDownloaderPrivate::singleFileFinished);
    connect(m_currentDownloadingReply, &QNetworkReply::downloadProgress, this, &RmeDownloaderPrivate::downloadProgress);

    m_lastRecordedDownloadProgress = 0;
    m_timer->start();
}

void RmeDownloaderPrivate::singleFileError(QNetworkReply::NetworkError /*e*/)
{
    m_failedList << m_currentDownloadingFile;
    if (m_currentDownloadingReply != nullptr)
        qDebug() << m_currentDownloadingReply->errorString();
}

void RmeDownloaderPrivate::downloadProgress(quint64 downloaded, quint64 total)
{
    if (downloaded - m_lastRecordedDownloadProgress > 10000) {
        m_lastRecordedDownloadProgress = downloaded;
        m_timer->start();
    }
    emit m_downloader->downloadProgress(downloaded, total);
}

void RmeDownloaderPrivate::singleFileFinished()
{
    m_timer->stop();
    if (m_failedList.contains(m_currentDownloadingFile)) {
        emit m_downloader->singleFileFailed(m_currentDownloadingFile);
        downloadSingleFile();
    } else {
        if (m_currentDownloadingReply->attribute(QNetworkRequest::RedirectionTargetAttribute).isNull()) {
            QString filename = QUrl(m_currentDownloadingFile).fileName();
            QFile file(m_downloadDir.absoluteFilePath(filename));
            file.open(QIODevice::Truncate | QIODevice::WriteOnly);
            file.write(m_currentDownloadingReply->readAll());
            file.close();

            if (filename.endsWith(QStringLiteral(".jpg"))) { // important hack!!
                QString new_filename = filename;
                new_filename.chop(4);
                new_filename.append(QStringLiteral(".png"));
                //m_downloadDir.rename(filename, new_filename);
                QPixmap pm;
                if (pm.load(m_downloadDir.absoluteFilePath(filename))) {
                    if (pm.save(m_downloadDir.absoluteFilePath(new_filename), "PNG")) {
                        m_downloadDir.remove(filename);
                    } else
                        qDebug() << "save png error " << new_filename;
                } else if (pm.load(m_downloadDir.absoluteFilePath(filename), "PNG")) {
                    if (pm.save(m_downloadDir.absoluteFilePath(new_filename), "PNG")) {
                        m_downloadDir.remove(filename);
                    } else
                        qDebug() << "save png error " << new_filename;
                } else
                    qDebug() << "load jpg error " << filename;
            }

            emit m_downloader->singleFileCompleted(m_currentDownloadingFile);
            downloadSingleFile();
        } else {
            if (m_canceled) {
                emit m_downloader->canceled();
                return;
            }
            QUrl u = m_currentDownloadingReply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
            if (u.isRelative())
                u = u.resolved(QUrl(m_currentDownloadingFile));
            qDebug() << "redirect!!" << u;
            m_currentDownloadingFile = u.toString();
            m_currentDownloadingReply = m_networkAccessManager->get(QNetworkRequest(u));
            connect(m_currentDownloadingReply, ((void (QNetworkReply::*)(QNetworkReply::NetworkError))(&QNetworkReply::error)), this, &RmeDownloaderPrivate::singleFileError);
            connect(m_currentDownloadingReply, &QNetworkReply::finished, this, &RmeDownloaderPrivate::singleFileFinished);
            connect(m_currentDownloadingReply, &QNetworkReply::downloadProgress, this, &RmeDownloaderPrivate::downloadProgress);
        }
    }
}

RmeDownloader *operator<<(RmeDownloader *downloader, const QString &filename)
{
    (*downloader) << filename;
    return downloader;
}

void RmeDownloader::cancel()
{
    Q_D(RmeDownloader);
    d->cancel();
}

#include "rmedownloader.moc"
<|endoftext|>


<commit_before>/*

Copyright (c) 2012, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/config.hpp"
#include "libtorrent/rss.hpp"
#include "libtorrent/fingerprint.hpp"
#include "libtorrent/aux_/session_impl.hpp"
#include "libtorrent/http_parser.hpp"

#include "test.hpp"

using namespace libtorrent;

void print_feed(feed_status const& f)
{
	fprintf(stderr, "FEED: %s\n",f.url.c_str());
	if (f.error)
		fprintf(stderr, "ERROR: %s\n", f.error.message().c_str());

	fprintf(stderr, "   %s\n   %s\n", f.title.c_str(), f.description.c_str());
	fprintf(stderr, "   ttl: %d minutes\n", f.ttl);
	fprintf(stderr, "   num items: %d\n", int(f.items.size()));

	for (std::vector<feed_item>::const_iterator i = f.items.begin()
		, end(f.items.end()); i != end; ++i)
	{
		fprintf(stderr, "\033[32m%s\033[0m\n------------------------------------------------------\n"
			"   url: %s\n   size: %"PRId64"\n   info-hash: %s\n   uuid: %s\n   description: %s\n"
			"   comment: %s\n   category: %s\n"
			, i->title.c_str(), i->url.c_str(), i->size
			, i->info_hash.is_all_zeros() ? "" : to_hex(i->info_hash.to_string()).c_str()
			, i->uuid.c_str(), i->description.c_str(), i->comment.c_str(), i->category.c_str());
	}
}

struct rss_expect
{
	rss_expect(int nitems, std::string url, std::string title, size_type size)
		: num_items(nitems), first_url(url), first_title(title), first_size(size)
	{}

	int num_items;
	std::string first_url;
	std::string first_title;
	size_type first_size;
};

void test_feed(std::string const& filename, rss_expect const& expect)
{
	std::vector<char> buffer;
	error_code ec;
	load_file(filename, buffer, ec);
	TEST_CHECK(!ec);

	char* buf = &buffer[0];
	int len = buffer.size();

	char const header[] = "HTTP/1.1 200 OK\r\n"
		"\r\n";

	boost::shared_ptr<aux::session_impl> s = boost::shared_ptr<aux::session_impl>(new aux::session_impl(
		std::make_pair(100, 200), fingerprint("TT", 0, 0, 0 ,0), NULL, 0
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
				, "."
#endif
		));
	s->start_session();

	feed_settings sett;
	sett.auto_download = false;
	sett.auto_map_handles = false;
	boost::shared_ptr<feed> f = boost::shared_ptr<feed>(new feed(*s, sett));
	http_parser parser;
	bool err = false;
	parser.incoming(buffer::const_interval(header, header + sizeof(header)-1), err);
	TEST_CHECK(err == false);

	f->on_feed(error_code(), parser, buf, len);

	feed_status st;
	f->get_feed_status(&st);
	TEST_CHECK(!st.error);

	print_feed(st);

	TEST_CHECK(st.items.size() == expect.num_items);
	if (st.items.size() > 0)
	{
		TEST_CHECK(st.items[0].url == expect.first_url);
		TEST_CHECK(st.items[0].size == expect.first_size);
		TEST_CHECK(st.items[0].title == expect.first_title);
	}

	entry state;
	f->save_state(state);

	fprintf(stderr, "feed_state:\n");
#ifdef TORRENT_DEBUG
	state.print(std::cerr);
#endif

	// TODO: verify some key state is saved in 'state'
}

int test_main()
{
	test_feed("eztv.xml", rss_expect(30, "http://torrent.zoink.it/The.Daily.Show.2012.02.16.(HDTV-LMAO)[VTV].torrent", "The Daily Show 2012-02-16 [HDTV - LMAO]", 183442338));
	test_feed("cb.xml", rss_expect(50, "http://www.clearbits.net/get/1911-norbergfestival-2011.torrent", "Norbergfestival 2011", 1160773632));
	test_feed("kat.xml", rss_expect(25, "http://kat.ph/torrents/benito-di-paula-1975-benito-di-paula-lp-rip-ogg-at-500-jarax4u-t6194897/", "Benito Di Paula - 1975 - Benito Di Paula (LP Rip OGG at 500) [jarax4u]", 168773863));
	test_feed("mn.xml", rss_expect(20, "http://www.mininova.org/get/13203100", "Dexcell - January TwentyTwelve Mix", 137311179));
	test_feed("pb.xml", rss_expect(60, "magnet:?xt=urn:btih:FD4CDDB7BBE722D17A018EFD875EB0695ED7159C&dn=Thompson+Twins+-+1989+-+Big+Trash+%5BMP3%5D", "Thompson Twins - 1989 - Big Trash [MP3]", 100160904));
	return 0;
}

<commit_msg>fix test_rss build<commit_after>/*

Copyright (c) 2012, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/config.hpp"
#include "libtorrent/rss.hpp"
#include "libtorrent/fingerprint.hpp"
#include "libtorrent/aux_/session_impl.hpp"
#include "libtorrent/http_parser.hpp"

#include "test.hpp"

using namespace libtorrent;

void print_feed(feed_status const& f)
{
	fprintf(stderr, "FEED: %s\n",f.url.c_str());
	if (f.error)
		fprintf(stderr, "ERROR: %s\n", f.error.message().c_str());

	fprintf(stderr, "   %s\n   %s\n", f.title.c_str(), f.description.c_str());
	fprintf(stderr, "   ttl: %d minutes\n", f.ttl);
	fprintf(stderr, "   num items: %d\n", int(f.items.size()));

	for (std::vector<feed_item>::const_iterator i = f.items.begin()
		, end(f.items.end()); i != end; ++i)
	{
		fprintf(stderr, "\033[32m%s\033[0m\n------------------------------------------------------\n"
			"   url: %s\n   size: %"PRId64"\n   info-hash: %s\n   uuid: %s\n   description: %s\n"
			"   comment: %s\n   category: %s\n"
			, i->title.c_str(), i->url.c_str(), i->size
			, i->info_hash.is_all_zeros() ? "" : to_hex(i->info_hash.to_string()).c_str()
			, i->uuid.c_str(), i->description.c_str(), i->comment.c_str(), i->category.c_str());
	}
}

struct rss_expect
{
	rss_expect(int nitems, std::string url, std::string title, size_type size)
		: num_items(nitems), first_url(url), first_title(title), first_size(size)
	{}

	int num_items;
	std::string first_url;
	std::string first_title;
	size_type first_size;
};

void test_feed(std::string const& filename, rss_expect const& expect)
{
	std::vector<char> buffer;
	error_code ec;
	load_file(filename, buffer, ec);
	TEST_CHECK(!ec);

	char* buf = &buffer[0];
	int len = buffer.size();

	char const header[] = "HTTP/1.1 200 OK\r\n"
		"\r\n";

	boost::shared_ptr<aux::session_impl> s = boost::shared_ptr<aux::session_impl>(new aux::session_impl(
		std::make_pair(100, 200), fingerprint("TT", 0, 0, 0 ,0), NULL, 0));
	s->start_session();

	feed_settings sett;
	sett.auto_download = false;
	sett.auto_map_handles = false;
	boost::shared_ptr<feed> f = boost::shared_ptr<feed>(new feed(*s, sett));
	http_parser parser;
	bool err = false;
	parser.incoming(buffer::const_interval(header, header + sizeof(header)-1), err);
	TEST_CHECK(err == false);

	f->on_feed(error_code(), parser, buf, len);

	feed_status st;
	f->get_feed_status(&st);
	TEST_CHECK(!st.error);

	print_feed(st);

	TEST_CHECK(st.items.size() == expect.num_items);
	if (st.items.size() > 0)
	{
		TEST_CHECK(st.items[0].url == expect.first_url);
		TEST_CHECK(st.items[0].size == expect.first_size);
		TEST_CHECK(st.items[0].title == expect.first_title);
	}

	entry state;
	f->save_state(state);

	fprintf(stderr, "feed_state:\n");
#ifdef TORRENT_DEBUG
	state.print(std::cerr);
#endif

	// TODO: verify some key state is saved in 'state'
}

int test_main()
{
	test_feed("eztv.xml", rss_expect(30, "http://torrent.zoink.it/The.Daily.Show.2012.02.16.(HDTV-LMAO)[VTV].torrent", "The Daily Show 2012-02-16 [HDTV - LMAO]", 183442338));
	test_feed("cb.xml", rss_expect(50, "http://www.clearbits.net/get/1911-norbergfestival-2011.torrent", "Norbergfestival 2011", 1160773632));
	test_feed("kat.xml", rss_expect(25, "http://kat.ph/torrents/benito-di-paula-1975-benito-di-paula-lp-rip-ogg-at-500-jarax4u-t6194897/", "Benito Di Paula - 1975 - Benito Di Paula (LP Rip OGG at 500) [jarax4u]", 168773863));
	test_feed("mn.xml", rss_expect(20, "http://www.mininova.org/get/13203100", "Dexcell - January TwentyTwelve Mix", 137311179));
	test_feed("pb.xml", rss_expect(60, "magnet:?xt=urn:btih:FD4CDDB7BBE722D17A018EFD875EB0695ED7159C&dn=Thompson+Twins+-+1989+-+Big+Trash+%5BMP3%5D", "Thompson Twins - 1989 - Big Trash [MP3]", 100160904));
	return 0;
}

<|endoftext|>


<commit_before>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/session.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/thread.hpp"
#include "libtorrent/file.hpp"
#include <boost/bind.hpp>
#include <boost/tuple/tuple.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"
#include <fstream>
#include <iostream>

#ifdef TORRENT_USE_OPENSSL
#include <boost/asio/ssl/error.hpp> // for asio::error::get_ssl_category()
#endif

using namespace libtorrent;
using boost::tuples::ignore;

int const alert_mask = alert::all_categories
& ~alert::progress_notification
& ~alert::stats_notification;

struct test_config_t
{
	char const* name;
	bool use_ssl_ports;
	bool seed_has_cert;
	bool downloader_has_cert;
	bool expected_to_complete;
	int peer_errors;
	int ssl_disconnects;
};

test_config_t test_config[] =
{
	{"nobody has a cert (connect to regular port)", false, false, false, false, 0, 0},
	{"nobody has a cert (connect to ssl port)", true, false, false, false, 1, 1},
	{"seed has a cert, but not downloader (connect to regular port)", false, true, false, false, 0, 0},
	{"seed has a cert, but not downloader (connect to ssl port)", true, true, false, false, 1, 1},
	{"downloader has a cert, but not seed (connect to regular port)", false, false, true, false, 0, 0},
	{"downloader has a cert, but not seed (connect to ssl port)", true, false, true, false, 1, 1},
	{"both downloader and seed has a cert (connect to regular port)", false, true, true, false, 0, 0},
#ifdef TORRENT_USE_OPENSSL
	{"both downloader and seed has a cert (connect to ssl port)", true, true, true, true, 0, 0},
#else
	{"both downloader and seed has a cert (connect to ssl port)", true, true, true, false, 0, 0},
#endif
};

int peer_disconnects = 0;
int peer_errors = 0;
int ssl_peer_disconnects = 0;

bool on_alert(alert* a)
{
	if (alert_cast<peer_disconnected_alert>(a))
		++peer_disconnects;
	if (peer_error_alert* e = alert_cast<peer_error_alert>(a))
	{
		++peer_disconnects;
		++peer_errors;

#ifdef TORRENT_USE_OPENSSL
		if (e->error.category() == boost::asio::error::get_ssl_category())
			++ssl_peer_disconnects;
#endif
	}
	return false;
}

void test_ssl(int test_idx, bool use_utp)
{
	// these are declared before the session objects
	// so that they are destructed last. This enables
	// the sessions to destruct in parallel
	session_proxy p1;
	session_proxy p2;

	test_config_t const& test = test_config[test_idx];

	fprintf(stderr, "\n%s TEST: %s Protocol: %s\n\n", time_now_string(), test.name, use_utp ? "uTP": "TCP");

#ifndef TORRENT_USE_OPENSSL
	if (test.use_ssl_ports)
	{
		fprintf(stderr, "N/A\n");
		return;
	}
#endif

	// in case the previous run was terminated
	error_code ec;
	remove_all("tmp1_ssl", ec);
	remove_all("tmp2_ssl", ec);

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48075, 49000), "0.0.0.0", 0, alert_mask);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49075, 50000), "0.0.0.0", 0, alert_mask);

	wait_for_listen(ses1, "ses1");
	wait_for_listen(ses2, "ses2");

	session_settings sett;

	sett.enable_incoming_utp = use_utp;
	sett.enable_outgoing_utp = use_utp;
	sett.enable_incoming_tcp = !use_utp;
	sett.enable_outgoing_tcp = !use_utp;

	sett.ssl_listen = 1024 + rand() % 50000;

	ses1.set_settings(sett);
	sett.ssl_listen += 10;
	ses2.set_settings(sett);

	torrent_handle tor1;
	torrent_handle tor2;

	create_directory("tmp1_ssl", ec);
	std::ofstream file("tmp1_ssl/temporary");
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false, "../ssl/root_ca_cert.pem");
	file.close();

	add_torrent_params addp;
	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;

	wait_for_listen(ses1, "ses1");
	wait_for_listen(ses2, "ses2");

	peer_disconnects = 0;
	ssl_peer_disconnects = 0;
	peer_errors = 0;

	boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0
		, true, false, true, "_ssl", 16 * 1024, &t, false, NULL, true, test.use_ssl_ports);

	if (test.seed_has_cert)
	{
		tor1.set_ssl_certificate(
			combine_path("..", combine_path("ssl", "peer_certificate.pem"))
			, combine_path("..", combine_path("ssl", "peer_private_key.pem"))
			, combine_path("..", combine_path("ssl", "dhparams.pem"))
			, "test");
	}

	if (test.downloader_has_cert)
	{
		tor2.set_ssl_certificate(
			combine_path("..", combine_path("ssl", "peer_certificate.pem"))
			, combine_path("..", combine_path("ssl", "peer_private_key.pem"))
			, combine_path("..", combine_path("ssl", "dhparams.pem"))
			, "test");
	}

#ifdef TORRENT_USE_VALGRIND
	const int timeout = 100;
#else
	const int timeout = 40;
#endif
	for (int i = 0; i < 40; ++i)
	{
		print_alerts(ses1, "ses1", true, true, true, &on_alert);
		print_alerts(ses2, "ses2", true, true, true, &on_alert);

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();

		if (i % 10 == 0)
		{
			std::cerr << time_now_string() << " "
				<< "\033[32m" << int(st1.download_payload_rate / 1000.f) << "kB/s "
				<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
				<< "\033[0m" << int(st1.progress * 100) << "% "
				<< st1.num_peers
				<< ": "
				<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
				<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
				<< "\033[0m" << int(st2.progress * 100) << "% "
				<< st2.num_peers
				<< " cc: " << st2.connect_candidates
				<< std::endl;
		}

		if (peer_disconnects >= 2)
		{
			fprintf(stderr, "too many disconnects (%d), breaking\n", peer_disconnects);
			break;
		}

		if (st2.is_finished) break;

		if (st2.state != torrent_status::downloading)
		{
			static char const* state_str[] =
				{"checking (q)", "checking", "dl metadata"
				, "downloading", "finished", "seeding", "allocating", "checking (r)"};
			std::cerr << "st2 state: " << state_str[st2.state] << std::endl;
		}

		TEST_CHECK(st1.state == torrent_status::seeding
			|| st1.state == torrent_status::checking_files);
		TEST_CHECK(st2.state == torrent_status::downloading
			|| st2.state == torrent_status::checking_resume_data);

		test_sleep(100);
	}

	fprintf(stderr, "peer_errors: %d  expected: %d\n", peer_errors, test.peer_errors);
	TEST_EQUAL(peer_errors, test.peer_errors);
#ifdef TORRENT_USE_OPENSSL
	fprintf(stderr, "ssl_disconnects: %d  expected: %d\n", ssl_peer_disconnects, test.ssl_disconnects);
	TEST_EQUAL(ssl_peer_disconnects, test.ssl_disconnects);
#endif
	fprintf(stderr, "%s: EXPECT: %s\n", time_now_string(), test.expected_to_complete ? "SUCCEESS" : "FAILURE");
	fprintf(stderr, "%s: RESULT: %s\n", time_now_string(), tor2.status().is_seeding ? "SUCCEESS" : "FAILURE");
	TEST_CHECK(tor2.status().is_seeding == test.expected_to_complete);

	// this allows shutting down the sessions in parallel
	p1 = ses1.abort();
	p2 = ses2.abort();
}

int test_main()
{
	using namespace libtorrent;

	// No support for SSL/uTP yet, so always pass in false
	for (int i = 0; i < sizeof(test_config)/sizeof(test_config[0]); ++i)
		test_ssl(i, false);

	error_code ec;
	remove_all("tmp1_ssl", ec);
	remove_all("tmp2_ssl", ec);

	return 0;
}

<commit_msg>fix typo<commit_after>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/session.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/thread.hpp"
#include "libtorrent/file.hpp"
#include <boost/bind.hpp>
#include <boost/tuple/tuple.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"
#include <fstream>
#include <iostream>

#ifdef TORRENT_USE_OPENSSL
#include <boost/asio/ssl/error.hpp> // for asio::error::get_ssl_category()
#endif

using namespace libtorrent;
using boost::tuples::ignore;

int const alert_mask = alert::all_categories
& ~alert::progress_notification
& ~alert::stats_notification;

struct test_config_t
{
	char const* name;
	bool use_ssl_ports;
	bool seed_has_cert;
	bool downloader_has_cert;
	bool expected_to_complete;
	int peer_errors;
	int ssl_disconnects;
};

test_config_t test_config[] =
{
	{"nobody has a cert (connect to regular port)", false, false, false, false, 0, 0},
	{"nobody has a cert (connect to ssl port)", true, false, false, false, 1, 1},
	{"seed has a cert, but not downloader (connect to regular port)", false, true, false, false, 0, 0},
	{"seed has a cert, but not downloader (connect to ssl port)", true, true, false, false, 1, 1},
	{"downloader has a cert, but not seed (connect to regular port)", false, false, true, false, 0, 0},
	{"downloader has a cert, but not seed (connect to ssl port)", true, false, true, false, 1, 1},
	{"both downloader and seed has a cert (connect to regular port)", false, true, true, false, 0, 0},
#ifdef TORRENT_USE_OPENSSL
	{"both downloader and seed has a cert (connect to ssl port)", true, true, true, true, 0, 0},
#else
	{"both downloader and seed has a cert (connect to ssl port)", true, true, true, false, 0, 0},
#endif
};

int peer_disconnects = 0;
int peer_errors = 0;
int ssl_peer_disconnects = 0;

bool on_alert(alert* a)
{
	if (alert_cast<peer_disconnected_alert>(a))
		++peer_disconnects;
	if (peer_error_alert* e = alert_cast<peer_error_alert>(a))
	{
		++peer_disconnects;
		++peer_errors;

#ifdef TORRENT_USE_OPENSSL
		if (e->error.category() == boost::asio::error::get_ssl_category())
			++ssl_peer_disconnects;
#endif
	}
	return false;
}

void test_ssl(int test_idx, bool use_utp)
{
	// these are declared before the session objects
	// so that they are destructed last. This enables
	// the sessions to destruct in parallel
	session_proxy p1;
	session_proxy p2;

	test_config_t const& test = test_config[test_idx];

	fprintf(stderr, "\n%s TEST: %s Protocol: %s\n\n", time_now_string(), test.name, use_utp ? "uTP": "TCP");

#ifndef TORRENT_USE_OPENSSL
	if (test.use_ssl_ports)
	{
		fprintf(stderr, "N/A\n");
		return;
	}
#endif

	// in case the previous run was terminated
	error_code ec;
	remove_all("tmp1_ssl", ec);
	remove_all("tmp2_ssl", ec);

	session ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48075, 49000), "0.0.0.0", 0, alert_mask);
	session ses2(fingerprint("LT", 0, 1, 0, 0), std::make_pair(49075, 50000), "0.0.0.0", 0, alert_mask);

	wait_for_listen(ses1, "ses1");
	wait_for_listen(ses2, "ses2");

	session_settings sett;

	sett.enable_incoming_utp = use_utp;
	sett.enable_outgoing_utp = use_utp;
	sett.enable_incoming_tcp = !use_utp;
	sett.enable_outgoing_tcp = !use_utp;

	sett.ssl_listen = 1024 + rand() % 50000;

	ses1.set_settings(sett);
	sett.ssl_listen += 10;
	ses2.set_settings(sett);

	torrent_handle tor1;
	torrent_handle tor2;

	create_directory("tmp1_ssl", ec);
	std::ofstream file("tmp1_ssl/temporary");
	boost::intrusive_ptr<torrent_info> t = ::create_torrent(&file, 16 * 1024, 13, false, "../ssl/root_ca_cert.pem");
	file.close();

	add_torrent_params addp;
	addp.flags &= ~add_torrent_params::flag_paused;
	addp.flags &= ~add_torrent_params::flag_auto_managed;

	wait_for_listen(ses1, "ses1");
	wait_for_listen(ses2, "ses2");

	peer_disconnects = 0;
	ssl_peer_disconnects = 0;
	peer_errors = 0;

	boost::tie(tor1, tor2, ignore) = setup_transfer(&ses1, &ses2, 0
		, true, false, true, "_ssl", 16 * 1024, &t, false, NULL, true, test.use_ssl_ports);

	if (test.seed_has_cert)
	{
		tor1.set_ssl_certificate(
			combine_path("..", combine_path("ssl", "peer_certificate.pem"))
			, combine_path("..", combine_path("ssl", "peer_private_key.pem"))
			, combine_path("..", combine_path("ssl", "dhparams.pem"))
			, "test");
	}

	if (test.downloader_has_cert)
	{
		tor2.set_ssl_certificate(
			combine_path("..", combine_path("ssl", "peer_certificate.pem"))
			, combine_path("..", combine_path("ssl", "peer_private_key.pem"))
			, combine_path("..", combine_path("ssl", "dhparams.pem"))
			, "test");
	}

#ifdef TORRENT_USE_VALGRIND
	const int timeout = 100;
#else
	const int timeout = 40;
#endif
	for (int i = 0; i < timeout; ++i)
	{
		print_alerts(ses1, "ses1", true, true, true, &on_alert);
		print_alerts(ses2, "ses2", true, true, true, &on_alert);

		torrent_status st1 = tor1.status();
		torrent_status st2 = tor2.status();

		if (i % 10 == 0)
		{
			std::cerr << time_now_string() << " "
				<< "\033[32m" << int(st1.download_payload_rate / 1000.f) << "kB/s "
				<< "\033[33m" << int(st1.upload_payload_rate / 1000.f) << "kB/s "
				<< "\033[0m" << int(st1.progress * 100) << "% "
				<< st1.num_peers
				<< ": "
				<< "\033[32m" << int(st2.download_payload_rate / 1000.f) << "kB/s "
				<< "\033[31m" << int(st2.upload_payload_rate / 1000.f) << "kB/s "
				<< "\033[0m" << int(st2.progress * 100) << "% "
				<< st2.num_peers
				<< " cc: " << st2.connect_candidates
				<< std::endl;
		}

		if (peer_disconnects >= 2)
		{
			fprintf(stderr, "too many disconnects (%d), breaking\n", peer_disconnects);
			break;
		}

		if (st2.is_finished) break;

		if (st2.state != torrent_status::downloading)
		{
			static char const* state_str[] =
				{"checking (q)", "checking", "dl metadata"
				, "downloading", "finished", "seeding", "allocating", "checking (r)"};
			std::cerr << "st2 state: " << state_str[st2.state] << std::endl;
		}

		TEST_CHECK(st1.state == torrent_status::seeding
			|| st1.state == torrent_status::checking_files);
		TEST_CHECK(st2.state == torrent_status::downloading
			|| st2.state == torrent_status::checking_resume_data);

		test_sleep(100);
	}

	fprintf(stderr, "peer_errors: %d  expected: %d\n", peer_errors, test.peer_errors);
	TEST_EQUAL(peer_errors, test.peer_errors);
#ifdef TORRENT_USE_OPENSSL
	fprintf(stderr, "ssl_disconnects: %d  expected: %d\n", ssl_peer_disconnects, test.ssl_disconnects);
	TEST_EQUAL(ssl_peer_disconnects, test.ssl_disconnects);
#endif
	fprintf(stderr, "%s: EXPECT: %s\n", time_now_string(), test.expected_to_complete ? "SUCCEESS" : "FAILURE");
	fprintf(stderr, "%s: RESULT: %s\n", time_now_string(), tor2.status().is_seeding ? "SUCCEESS" : "FAILURE");
	TEST_CHECK(tor2.status().is_seeding == test.expected_to_complete);

	// this allows shutting down the sessions in parallel
	p1 = ses1.abort();
	p2 = ses2.abort();
}

int test_main()
{
	using namespace libtorrent;

	// No support for SSL/uTP yet, so always pass in false
	for (int i = 0; i < sizeof(test_config)/sizeof(test_config[0]); ++i)
		test_ssl(i, false);

	error_code ec;
	remove_all("tmp1_ssl", ec);
	remove_all("tmp2_ssl", ec);

	return 0;
}

<|endoftext|>


<commit_before>#include "RepairPartitioningPrototype.h"
using namespace std;

void RepairPartitioningPrototype::printIDtoWordMapping(unordered_map<unsigned, string>& IDsToWords, ostream& os)
{
	for (unordered_map<unsigned, string>::iterator it = IDsToWords.begin(); it != IDsToWords.end(); it++)
	{
		os << it->first << ": " << it->second << endl;
	}
}

void RepairPartitioningPrototype::writeAssociations(const vector<Association>& associations, ostream& os)
{
	for (size_t i = 0; i < associations.size(); i++)
	{
		os << associations[i];
	}
}

double RepairPartitioningPrototype::runRepairPartitioning(
	vector<vector<unsigned> > versions,
	unordered_map<unsigned, string>& IDsToWords,
	unsigned*& offsetsAllVersions,
	unsigned*& versionPartitionSizes,
	vector<Association>& associations,
	unsigned minFragSize,
	float fragmentationCoefficient,
	unsigned repairStoppingPoint,
	unsigned numLevelsDown,
	unsigned method,
	bool printFragments,
	bool printAssociations)
{
	RepairAlgorithm repairAlg(versions);

	repairAlg.run();

	vector<VersionDataItem> versionData = repairAlg.getVersionData();

	associations = repairAlg.getAssociations();

	// Use the result of repair to get a partitioning of the document
	// Hopefully this partitioning gives us fragments that occur many times
	RepairDocumentPartition partition = RepairDocumentPartition(versionData, associations, numLevelsDown, minFragSize, fragmentationCoefficient, method);

	// The offsets that define fragments, for all versions [v0:f0 v0:f1 v0:f2 v1:f0 v1:f1 v2:f0 v2:f1 ...]
	offsetsAllVersions = partition.getOffsets();

	// The number of fragments in each version
	versionPartitionSizes = partition.getVersionSizes();

	string outputFilename = "./Output/results.txt";

	partition.writeResults(versions, IDsToWords, outputFilename, printFragments, printAssociations);

	if (printAssociations)
	{
		cerr << "*** Associations (symbol -> pair) ***" << endl;
		writeAssociations(associations, cerr);
	}

	stringstream command;
	command << "start " << outputFilename.c_str();
	system(command.str().c_str());

	// repairAlg.cleanup();

	return partition.getScore();
}

double RepairPartitioningPrototype::runRepairPartitioning(
	vector<vector<unsigned> > versions,
	unsigned*& offsetsAllVersions,
	unsigned*& versionPartitionSizes,
	vector<Association>& associations,
	unsigned minFragSize,
	float fragmentationCoefficient,
	unsigned method)
{
	RepairAlgorithm repairAlg(versions);

	repairAlg.run();

	vector<VersionDataItem> versionData = repairAlg.getVersionData();

	associations = repairAlg.getAssociations();

	// Use the result of repair to get a partitioning of the document
	// Hopefully this partitioning gives us fragments that occur many times
	RepairDocumentPartition partition = RepairDocumentPartition(versionData, associations,
		1, minFragSize, fragmentationCoefficient, method);

	// The offsets that define fragments, for all versions [v0:f0 v0:f1 v0:f2 v1:f0 v1:f1 v2:f0 v2:f1 ...]
	offsetsAllVersions = partition.getOffsets();

	// The number of fragments in each version
	versionPartitionSizes = partition.getVersionSizes();

	string outputFilename = "./Output/results.txt";

	unordered_map<unsigned, string> IDsToWords = unordered_map<unsigned, string>();
	partition.writeResults(versions, IDsToWords, outputFilename, false, false);

	// if (printAssociations)
	// {
	// 	cerr << "*** Associations (symbol -> pair) ***" << endl;
	// 	writeAssociations(associations, cerr);
	// }

	// stringstream command;
	// command << "start " << outputFilename.c_str();
	// system(command.str().c_str());

	repairAlg.cleanup();

	return partition.getScore();
}

int RepairPartitioningPrototype::run(int argc, char* argv[])
{
	//createOutputDir();

	//heap, repair
	string test = "repair";

	if (test == "heap")
	{
		RandomHeapTest test = RandomHeapTest(1000);
		exit(0);
	}

	if (test == "repair")
	{
		Profiler::getInstance().start("all");
		string inputFilepath = "./Input/ints/";

		/*
		Initial tests show that minFragSize should be proportional to document size
		*/
		unsigned minFragSize = 10; //in words

		/*
		Initial tests show that repairStoppingPoint shouldn't be too small (repair goes too far for our purposes in this case)
		And it shouldn't be larger than the number of versions (this is trivial, we expect to get repetition
		at most numVersions times for inter-version repetitions)
		*/
		unsigned repairStoppingPoint = 1; //pairs that occur less than this amount of times will not be replaced

		/* To what extent are we willing to fragment? See the partitioning algorithm for how this is used */
		float fragmentationCoefficient = 1.0;

		/* A variable used in the primitive way to partition the tree: just go n levels down */
		unsigned numLevelsDown = 3;

		/* The partitioning alg to use. See Partitioning.h for the enum */
		unsigned method = 0;

		if (argc == 2 && (string) argv[1] == "help")
		{
			cerr << "Usage:" << endl;
			cerr << "\t" << argv[0] << " <directory> <fragmentationCoefficient> <minFragSize> <method>" << endl;
			cerr << "\t" << argv[0] << " <directory> <fragmentationCoefficient> <minFragSize>" << endl;
			cerr << "\t" << argv[0] << " <directory> <fragmentationCoefficient>" << endl;
			cerr << "\t" << argv[0] << " <directory>" << endl;
			cerr << "\t" << argv[0] << "" << endl << endl;

			cerr << "Defaults: " << endl;
			cerr << "\tdirectory: " << inputFilepath << endl;
			cerr << "\tfragmentationCoefficient: " << fragmentationCoefficient << endl;
			cerr << "\tminFragSize: " << minFragSize << endl;
			cerr << "\tmethod: " << method << endl;
			exit(0);
		}

		if (argc > 1)
			inputFilepath = (string)argv[1];

		if (argc > 2)
			fragmentationCoefficient = atof(argv[2]);

		if (argc > 3)
			minFragSize = atoi(argv[3]);

		if (argc > 4)
			method = atoi(argv[4]);

		// if (argc > 3)
		// 	repairStoppingPoint = atoi(argv[3]);

		vector<string> inputFilenames = vector<string>();
		if (getFileNames(inputFilepath, inputFilenames))
			return errno;

		char* text;

		int fileSize;

		vector<vector<unsigned> > versions = vector<vector<unsigned> >(); //each inner vector is the wordIDs for one version

		vector<unsigned> wordIDs;

		unordered_map<unsigned, string> IDsToWords = unordered_map<unsigned, string>();

		unordered_map<unsigned, unsigned> uniqueWordIDs = unordered_map<unsigned, unsigned>();

		for (unsigned i = 0; i < inputFilenames.size(); i++)
		{
			stringstream filenameSS;
			filenameSS << inputFilepath << inputFilenames[i];
			string filename = filenameSS.str();
			text = getText(filename, fileSize);
			if (!text)
				continue;
			wordIDs = stringToWordIDs(text, IDsToWords, uniqueWordIDs);

			if (false)
			{
				cerr << "Version " << i << endl;
				for (unsigned j = 0; j < wordIDs.size(); j++)
				{
					cerr << wordIDs[j] << ",";
				}
				cerr << endl << endl;
			}

			versions.push_back(wordIDs);
			delete text;
			text = NULL;
		}

		// By this time, IDsToWords should contain the mappings of IDs to words in all versions
		// printIDtoWordMapping(IDsToWords);
		// system("pause");

		vector<Association> associations;

		unsigned* offsetsAllVersions(NULL);
		unsigned* versionPartitionSizes(NULL);

		double score;
		/* Both overloads are shown below for testing. Just change the bool to switch. */
		if (false)
		{
			score = runRepairPartitioning(versions, IDsToWords,
				offsetsAllVersions, versionPartitionSizes,
				associations, minFragSize,
				fragmentationCoefficient,
				repairStoppingPoint, numLevelsDown,
				method, true, false);
		}
		else
		{
			score = runRepairPartitioning(versions, offsetsAllVersions,
				versionPartitionSizes,
				associations,
				minFragSize,
				fragmentationCoefficient,
				method);
		}

		return score;
	}
}<commit_msg>commented out output function<commit_after>#include "RepairPartitioningPrototype.h"
using namespace std;

void RepairPartitioningPrototype::printIDtoWordMapping(unordered_map<unsigned, string>& IDsToWords, ostream& os)
{
	for (unordered_map<unsigned, string>::iterator it = IDsToWords.begin(); it != IDsToWords.end(); it++)
	{
		os << it->first << ": " << it->second << endl;
	}
}

void RepairPartitioningPrototype::writeAssociations(const vector<Association>& associations, ostream& os)
{
	for (size_t i = 0; i < associations.size(); i++)
	{
		os << associations[i];
	}
}

double RepairPartitioningPrototype::runRepairPartitioning(
	vector<vector<unsigned> > versions,
	unordered_map<unsigned, string>& IDsToWords,
	unsigned*& offsetsAllVersions,
	unsigned*& versionPartitionSizes,
	vector<Association>& associations,
	unsigned minFragSize,
	float fragmentationCoefficient,
	unsigned repairStoppingPoint,
	unsigned numLevelsDown,
	unsigned method,
	bool printFragments,
	bool printAssociations)
{
	RepairAlgorithm repairAlg(versions);

	repairAlg.run();

	vector<VersionDataItem> versionData = repairAlg.getVersionData();

	associations = repairAlg.getAssociations();

	// Use the result of repair to get a partitioning of the document
	// Hopefully this partitioning gives us fragments that occur many times
	RepairDocumentPartition partition = RepairDocumentPartition(versionData, associations, numLevelsDown, minFragSize, fragmentationCoefficient, method);

	// The offsets that define fragments, for all versions [v0:f0 v0:f1 v0:f2 v1:f0 v1:f1 v2:f0 v2:f1 ...]
	offsetsAllVersions = partition.getOffsets();

	// The number of fragments in each version
	versionPartitionSizes = partition.getVersionSizes();

	string outputFilename = "./Output/results.txt";

	return partition.getScore();

	// partition.writeResults(versions, IDsToWords, outputFilename, printFragments, printAssociations);

	// if (printAssociations)
	// {
	// 	cerr << "*** Associations (symbol -> pair) ***" << endl;
	// 	writeAssociations(associations, cerr);
	// }

	// stringstream command;
	// command << "start " << outputFilename.c_str();
	// system(command.str().c_str());

	// // repairAlg.cleanup();

	// return partition.getScore();
}

double RepairPartitioningPrototype::runRepairPartitioning(
	vector<vector<unsigned> > versions,
	unsigned*& offsetsAllVersions,
	unsigned*& versionPartitionSizes,
	vector<Association>& associations,
	unsigned minFragSize,
	float fragmentationCoefficient,
	unsigned method)
{
	RepairAlgorithm repairAlg(versions);

	repairAlg.run();

	vector<VersionDataItem> versionData = repairAlg.getVersionData();

	associations = repairAlg.getAssociations();

	// Use the result of repair to get a partitioning of the document
	// Hopefully this partitioning gives us fragments that occur many times
	RepairDocumentPartition partition = RepairDocumentPartition(versionData, associations,
		1, minFragSize, fragmentationCoefficient, method);

	// The offsets that define fragments, for all versions [v0:f0 v0:f1 v0:f2 v1:f0 v1:f1 v2:f0 v2:f1 ...]
	offsetsAllVersions = partition.getOffsets();

	// The number of fragments in each version
	versionPartitionSizes = partition.getVersionSizes();

	// string outputFilename = "./Output/results.txt";

	// unordered_map<unsigned, string> IDsToWords = unordered_map<unsigned, string>();
	// partition.writeResults(versions, IDsToWords, outputFilename, false, false);

	// if (printAssociations)
	// {
	// 	cerr << "*** Associations (symbol -> pair) ***" << endl;
	// 	writeAssociations(associations, cerr);
	// }

	// stringstream command;
	// command << "start " << outputFilename.c_str();
	// system(command.str().c_str());

	repairAlg.cleanup();

	return partition.getScore();
}

int RepairPartitioningPrototype::run(int argc, char* argv[])
{
	//createOutputDir();

	//heap, repair
	string test = "repair";

	if (test == "heap")
	{
		RandomHeapTest test = RandomHeapTest(1000);
		exit(0);
	}

	if (test == "repair")
	{
		Profiler::getInstance().start("all");
		string inputFilepath = "./Input/ints/";

		/*
		Initial tests show that minFragSize should be proportional to document size
		*/
		unsigned minFragSize = 10; //in words

		/*
		Initial tests show that repairStoppingPoint shouldn't be too small (repair goes too far for our purposes in this case)
		And it shouldn't be larger than the number of versions (this is trivial, we expect to get repetition
		at most numVersions times for inter-version repetitions)
		*/
		unsigned repairStoppingPoint = 1; //pairs that occur less than this amount of times will not be replaced

		/* To what extent are we willing to fragment? See the partitioning algorithm for how this is used */
		float fragmentationCoefficient = 1.0;

		/* A variable used in the primitive way to partition the tree: just go n levels down */
		unsigned numLevelsDown = 3;

		/* The partitioning alg to use. See Partitioning.h for the enum */
		unsigned method = 0;

		if (argc == 2 && (string) argv[1] == "help")
		{
			cerr << "Usage:" << endl;
			cerr << "\t" << argv[0] << " <directory> <fragmentationCoefficient> <minFragSize> <method>" << endl;
			cerr << "\t" << argv[0] << " <directory> <fragmentationCoefficient> <minFragSize>" << endl;
			cerr << "\t" << argv[0] << " <directory> <fragmentationCoefficient>" << endl;
			cerr << "\t" << argv[0] << " <directory>" << endl;
			cerr << "\t" << argv[0] << "" << endl << endl;

			cerr << "Defaults: " << endl;
			cerr << "\tdirectory: " << inputFilepath << endl;
			cerr << "\tfragmentationCoefficient: " << fragmentationCoefficient << endl;
			cerr << "\tminFragSize: " << minFragSize << endl;
			cerr << "\tmethod: " << method << endl;
			exit(0);
		}

		if (argc > 1)
			inputFilepath = (string)argv[1];

		if (argc > 2)
			fragmentationCoefficient = atof(argv[2]);

		if (argc > 3)
			minFragSize = atoi(argv[3]);

		if (argc > 4)
			method = atoi(argv[4]);

		// if (argc > 3)
		// 	repairStoppingPoint = atoi(argv[3]);

		vector<string> inputFilenames = vector<string>();
		if (getFileNames(inputFilepath, inputFilenames))
			return errno;

		char* text;

		int fileSize;

		vector<vector<unsigned> > versions = vector<vector<unsigned> >(); //each inner vector is the wordIDs for one version

		vector<unsigned> wordIDs;

		unordered_map<unsigned, string> IDsToWords = unordered_map<unsigned, string>();

		unordered_map<unsigned, unsigned> uniqueWordIDs = unordered_map<unsigned, unsigned>();

		for (unsigned i = 0; i < inputFilenames.size(); i++)
		{
			stringstream filenameSS;
			filenameSS << inputFilepath << inputFilenames[i];
			string filename = filenameSS.str();
			text = getText(filename, fileSize);
			if (!text)
				continue;
			wordIDs = stringToWordIDs(text, IDsToWords, uniqueWordIDs);

			if (false)
			{
				cerr << "Version " << i << endl;
				for (unsigned j = 0; j < wordIDs.size(); j++)
				{
					cerr << wordIDs[j] << ",";
				}
				cerr << endl << endl;
			}

			versions.push_back(wordIDs);
			delete text;
			text = NULL;
		}

		// By this time, IDsToWords should contain the mappings of IDs to words in all versions
		// printIDtoWordMapping(IDsToWords);
		// system("pause");

		vector<Association> associations;

		unsigned* offsetsAllVersions(NULL);
		unsigned* versionPartitionSizes(NULL);

		double score;
		/* Both overloads are shown below for testing. Just change the bool to switch. */
		if (false)
		{
			score = runRepairPartitioning(versions, IDsToWords,
				offsetsAllVersions, versionPartitionSizes,
				associations, minFragSize,
				fragmentationCoefficient,
				repairStoppingPoint, numLevelsDown,
				method, true, false);
		}
		else
		{
			score = runRepairPartitioning(versions, offsetsAllVersions,
				versionPartitionSizes,
				associations,
				minFragSize,
				fragmentationCoefficient,
				method);
		}

		return score;
	}
}<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: DialogListBox.cxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 18:29:36 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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.
 *
 *    This library 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 library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"
#include "DialogListBox.hxx"

namespace sd
{

DialogListBox::DialogListBox( Window* pParent, WinBits nWinStyle ) :
    Control( pParent, nWinStyle ),
    mpChild( 0 )
{
    mpVScrollBar    = new ScrollBar( this, WB_VSCROLL | WB_DRAG );
    mpHScrollBar    = new ScrollBar( this, WB_HSCROLL | WB_DRAG );
    mpScrollBarBox  = new ScrollBarBox( this );

    Link aLink( LINK( this, DialogListBox, ScrollBarHdl ) );
    mpVScrollBar->SetScrollHdl( aLink );
    mpHScrollBar->SetScrollHdl( aLink );

    mbVScroll       = false;
    mbHScroll       = false;
    mbAutoHScroll   = ( nWinStyle & WB_AUTOHSCROLL ) ? true : false;
}

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

DialogListBox::~DialogListBox()
{
    delete mpHScrollBar;
    delete mpVScrollBar;
    delete mpScrollBarBox;
    delete mpChild;
}

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

void DialogListBox::SetChildWindow( Window* pChild, const Size& rMinSize )
{
    if( mpChild )
        delete mpChild;

    mpChild = pChild;
    maMinSize = rMinSize;
    ImplResizeControls();
    ImplCheckScrollBars();
}

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

void DialogListBox::GetFocus()
{
    if( mpChild )
        mpChild->GrabFocus();
}

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

::Window* DialogListBox::GetPreferredKeyInputWindow()
{
    if( mpChild )
        return mpChild;
    else
        return this;
}

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

void DialogListBox::Resize()
{
    Control::Resize();
    ImplResizeControls();
    ImplCheckScrollBars();
}

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

IMPL_LINK( DialogListBox, ScrollBarHdl, ScrollBar*, pSB )
{
    ImplResizeChild();
    return 1;
}

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

void DialogListBox::ImplCheckScrollBars()
{
    bool bArrange = false;

    Size aOutSz = GetOutputSizePixel();

    // vert. ScrollBar
    if( aOutSz.Height() < maMinSize.Height() )
    {
        if( !mbVScroll )
            bArrange = true;
        mbVScroll = true;
    }
    else
    {
        if( mbVScroll )
            bArrange = true;
        mbVScroll = false;
    }

    // horz. ScrollBar
    if( mbAutoHScroll )
    {
        long nWidth = aOutSz.Width();
        if ( mbVScroll )
            nWidth -= mpVScrollBar->GetSizePixel().Width();
        if( nWidth < maMinSize.Width() )
        {
            if( !mbHScroll )
                bArrange = true;
            mbHScroll = true;

            if ( !mbVScroll )
            {
                int nHeight = aOutSz.Height() - mpHScrollBar->GetSizePixel().Height();
                if( nHeight < maMinSize.Height() )
                {
                    if( !mbVScroll )
                        bArrange = true;
                    mbVScroll = true;
                }
            }
        }
        else
        {
            if( mbHScroll )
                bArrange = true;
            mbHScroll = false;
        }
    }

    if( bArrange )
        ImplResizeControls();

    ImplInitScrollBars();
}

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

void DialogListBox::ImplInitScrollBars()
{
    if( mpChild )
    {
        Size aOutSize( GetOutputSizePixel() );
        if( mbHScroll ) aOutSize.Height() -= mpHScrollBar->GetSizePixel().Height();
        if( mbVScroll ) aOutSize.Width() -= mpVScrollBar->GetSizePixel().Width();

        if ( mbVScroll )
        {
            mpVScrollBar->SetRangeMax( maMinSize.Height() );
            mpVScrollBar->SetVisibleSize( aOutSize.Height() );
            mpVScrollBar->SetPageSize( 16 );
        }

        if ( mbHScroll )
        {
            mpHScrollBar->SetRangeMax( maMinSize.Width() );
            mpHScrollBar->SetVisibleSize( aOutSize.Width() );
            mpHScrollBar->SetPageSize( 16 );
        }
    }
}

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

void DialogListBox::ImplResizeControls()
{
    Size aOutSz( GetOutputSizePixel() );
    long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
    nSBWidth = CalcZoom( nSBWidth );

    maInnerSize = aOutSz;
    if ( mbVScroll )
        maInnerSize.Width() -= nSBWidth;
    if ( mbHScroll )
        maInnerSize.Height() -= nSBWidth;

    // ScrollBarBox
    if( mbVScroll && mbHScroll )
    {
        Point aBoxPos( maInnerSize.Width(), maInnerSize.Height() );
        mpScrollBarBox->SetPosSizePixel( aBoxPos, Size( nSBWidth, nSBWidth ) );
        mpScrollBarBox->Show();
    }
    else
    {
        mpScrollBarBox->Hide();
    }

    // vert. ScrollBar
    if( mbVScroll )
    {
        // Scrollbar on left or right side?
        Point aVPos( aOutSz.Width() - nSBWidth, 0 );
        mpVScrollBar->SetPosSizePixel( aVPos, Size( nSBWidth, maInnerSize.Height() ) );
        mpVScrollBar->Show();
    }
    else
    {
        mpVScrollBar->Hide();
    }

    // horz. ScrollBar
    if( mbHScroll )
    {
        Point aHPos( 0, aOutSz.Height() - nSBWidth );
        mpHScrollBar->SetPosSizePixel( aHPos, Size( maInnerSize.Width(), nSBWidth ) );
        mpHScrollBar->Show();
    }
    else
    {
        mpHScrollBar->Hide();
    }

    ImplResizeChild();
}

void DialogListBox::ImplResizeChild()
{
    Point aWinPos;
    Size aSize( maInnerSize );

    int nOffset;
    if( mbHScroll )
    {
        nOffset = mpHScrollBar->GetThumbPos();
        aWinPos.X() = -nOffset;
        aSize.Width() += nOffset;
    }

    if( mbVScroll )
    {
        nOffset = mpVScrollBar->GetThumbPos();
        aWinPos.Y() = -nOffset;
        aSize.Height() += nOffset;
    }

    mpChild->SetPosSizePixel( aWinPos, aSize );
}

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

void DialogListBox::StateChanged( StateChangedType nType )
{
    if ( nType == STATE_CHANGE_INITSHOW )
    {
        ImplCheckScrollBars();
    }
    else if ( ( nType == STATE_CHANGE_UPDATEMODE ) || ( nType == STATE_CHANGE_DATA ) )
    {
        BOOL bUpdate = IsUpdateMode();
        mpChild->SetUpdateMode( bUpdate );
        if ( bUpdate && IsReallyVisible() )
            ImplCheckScrollBars();
    }
    else if( nType == STATE_CHANGE_ENABLE )
    {
        mpHScrollBar->Enable( IsEnabled() );
        mpVScrollBar->Enable( IsEnabled() );
        mpScrollBarBox->Enable( IsEnabled() );
        Invalidate();
    }
    else if ( nType == STATE_CHANGE_ZOOM )
    {
        mpChild->SetZoom( GetZoom() );
        Resize();
    }
    else if ( nType == STATE_CHANGE_CONTROLFONT )
    {
        mpChild->SetControlFont( GetControlFont() );
    }
    else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
    {
        mpChild->SetControlForeground( GetControlForeground() );
    }
    else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
    {
        mpChild->SetControlBackground( GetControlBackground() );
    }

    Control::StateChanged( nType );
}

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

long DialogListBox::Notify( NotifyEvent& rNEvt )
{
    long nDone = 0;
    if ( rNEvt.GetType() == EVENT_COMMAND )
    {
        const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
        if ( rCEvt.GetCommand() == COMMAND_WHEEL )
        {
            const CommandWheelData* pData = rCEvt.GetWheelData();
            if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
            {
                nDone = HandleScrollCommand( rCEvt, mpHScrollBar, mpVScrollBar );
            }
        }
    }

    return nDone ? nDone : Window::Notify( rNEvt );
}

} //  namespace sd
<commit_msg>INTEGRATION: CWS sdwarningsbegone (1.4.38); FILE MERGED 2006/11/22 12:41:42 cl 1.4.38.1: #i69285# warning free code changes for unxlngi6.pro<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: DialogListBox.cxx,v $
 *
 *  $Revision: 1.5 $
 *
 *  last change: $Author: kz $ $Date: 2006-12-12 16:52:11 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    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.
 *
 *    This library 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 library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sd.hxx"
#include "DialogListBox.hxx"

namespace sd
{

DialogListBox::DialogListBox( Window* pParent, WinBits nWinStyle ) :
    Control( pParent, nWinStyle ),
    mpChild( 0 )
{
    mpVScrollBar    = new ScrollBar( this, WB_VSCROLL | WB_DRAG );
    mpHScrollBar    = new ScrollBar( this, WB_HSCROLL | WB_DRAG );
    mpScrollBarBox  = new ScrollBarBox( this );

    Link aLink( LINK( this, DialogListBox, ScrollBarHdl ) );
    mpVScrollBar->SetScrollHdl( aLink );
    mpHScrollBar->SetScrollHdl( aLink );

    mbVScroll       = false;
    mbHScroll       = false;
    mbAutoHScroll   = ( nWinStyle & WB_AUTOHSCROLL ) ? true : false;
}

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

DialogListBox::~DialogListBox()
{
    delete mpHScrollBar;
    delete mpVScrollBar;
    delete mpScrollBarBox;
    delete mpChild;
}

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

void DialogListBox::SetChildWindow( Window* pChild, const Size& rMinSize )
{
    if( mpChild )
        delete mpChild;

    mpChild = pChild;
    maMinSize = rMinSize;
    ImplResizeControls();
    ImplCheckScrollBars();
}

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

void DialogListBox::GetFocus()
{
    if( mpChild )
        mpChild->GrabFocus();
}

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

::Window* DialogListBox::GetPreferredKeyInputWindow()
{
    if( mpChild )
        return mpChild;
    else
        return this;
}

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

void DialogListBox::Resize()
{
    Control::Resize();
    ImplResizeControls();
    ImplCheckScrollBars();
}

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

IMPL_LINK( DialogListBox, ScrollBarHdl, ScrollBar*, EMPTYARG )
{
    ImplResizeChild();
    return 1;
}

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

void DialogListBox::ImplCheckScrollBars()
{
    bool bArrange = false;

    Size aOutSz = GetOutputSizePixel();

    // vert. ScrollBar
    if( aOutSz.Height() < maMinSize.Height() )
    {
        if( !mbVScroll )
            bArrange = true;
        mbVScroll = true;
    }
    else
    {
        if( mbVScroll )
            bArrange = true;
        mbVScroll = false;
    }

    // horz. ScrollBar
    if( mbAutoHScroll )
    {
        long nWidth = aOutSz.Width();
        if ( mbVScroll )
            nWidth -= mpVScrollBar->GetSizePixel().Width();
        if( nWidth < maMinSize.Width() )
        {
            if( !mbHScroll )
                bArrange = true;
            mbHScroll = true;

            if ( !mbVScroll )
            {
                int nHeight = aOutSz.Height() - mpHScrollBar->GetSizePixel().Height();
                if( nHeight < maMinSize.Height() )
                {
                    if( !mbVScroll )
                        bArrange = true;
                    mbVScroll = true;
                }
            }
        }
        else
        {
            if( mbHScroll )
                bArrange = true;
            mbHScroll = false;
        }
    }

    if( bArrange )
        ImplResizeControls();

    ImplInitScrollBars();
}

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

void DialogListBox::ImplInitScrollBars()
{
    if( mpChild )
    {
        Size aOutSize( GetOutputSizePixel() );
        if( mbHScroll ) aOutSize.Height() -= mpHScrollBar->GetSizePixel().Height();
        if( mbVScroll ) aOutSize.Width() -= mpVScrollBar->GetSizePixel().Width();

        if ( mbVScroll )
        {
            mpVScrollBar->SetRangeMax( maMinSize.Height() );
            mpVScrollBar->SetVisibleSize( aOutSize.Height() );
            mpVScrollBar->SetPageSize( 16 );
        }

        if ( mbHScroll )
        {
            mpHScrollBar->SetRangeMax( maMinSize.Width() );
            mpHScrollBar->SetVisibleSize( aOutSize.Width() );
            mpHScrollBar->SetPageSize( 16 );
        }
    }
}

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

void DialogListBox::ImplResizeControls()
{
    Size aOutSz( GetOutputSizePixel() );
    long nSBWidth = GetSettings().GetStyleSettings().GetScrollBarSize();
    nSBWidth = CalcZoom( nSBWidth );

    maInnerSize = aOutSz;
    if ( mbVScroll )
        maInnerSize.Width() -= nSBWidth;
    if ( mbHScroll )
        maInnerSize.Height() -= nSBWidth;

    // ScrollBarBox
    if( mbVScroll && mbHScroll )
    {
        Point aBoxPos( maInnerSize.Width(), maInnerSize.Height() );
        mpScrollBarBox->SetPosSizePixel( aBoxPos, Size( nSBWidth, nSBWidth ) );
        mpScrollBarBox->Show();
    }
    else
    {
        mpScrollBarBox->Hide();
    }

    // vert. ScrollBar
    if( mbVScroll )
    {
        // Scrollbar on left or right side?
        Point aVPos( aOutSz.Width() - nSBWidth, 0 );
        mpVScrollBar->SetPosSizePixel( aVPos, Size( nSBWidth, maInnerSize.Height() ) );
        mpVScrollBar->Show();
    }
    else
    {
        mpVScrollBar->Hide();
    }

    // horz. ScrollBar
    if( mbHScroll )
    {
        Point aHPos( 0, aOutSz.Height() - nSBWidth );
        mpHScrollBar->SetPosSizePixel( aHPos, Size( maInnerSize.Width(), nSBWidth ) );
        mpHScrollBar->Show();
    }
    else
    {
        mpHScrollBar->Hide();
    }

    ImplResizeChild();
}

void DialogListBox::ImplResizeChild()
{
    Point aWinPos;
    Size aSize( maInnerSize );

    int nOffset;
    if( mbHScroll )
    {
        nOffset = mpHScrollBar->GetThumbPos();
        aWinPos.X() = -nOffset;
        aSize.Width() += nOffset;
    }

    if( mbVScroll )
    {
        nOffset = mpVScrollBar->GetThumbPos();
        aWinPos.Y() = -nOffset;
        aSize.Height() += nOffset;
    }

    mpChild->SetPosSizePixel( aWinPos, aSize );
}

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

void DialogListBox::StateChanged( StateChangedType nType )
{
    if ( nType == STATE_CHANGE_INITSHOW )
    {
        ImplCheckScrollBars();
    }
    else if ( ( nType == STATE_CHANGE_UPDATEMODE ) || ( nType == STATE_CHANGE_DATA ) )
    {
        BOOL bUpdate = IsUpdateMode();
        mpChild->SetUpdateMode( bUpdate );
        if ( bUpdate && IsReallyVisible() )
            ImplCheckScrollBars();
    }
    else if( nType == STATE_CHANGE_ENABLE )
    {
        mpHScrollBar->Enable( IsEnabled() );
        mpVScrollBar->Enable( IsEnabled() );
        mpScrollBarBox->Enable( IsEnabled() );
        Invalidate();
    }
    else if ( nType == STATE_CHANGE_ZOOM )
    {
        mpChild->SetZoom( GetZoom() );
        Resize();
    }
    else if ( nType == STATE_CHANGE_CONTROLFONT )
    {
        mpChild->SetControlFont( GetControlFont() );
    }
    else if ( nType == STATE_CHANGE_CONTROLFOREGROUND )
    {
        mpChild->SetControlForeground( GetControlForeground() );
    }
    else if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
    {
        mpChild->SetControlBackground( GetControlBackground() );
    }

    Control::StateChanged( nType );
}

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

long DialogListBox::Notify( NotifyEvent& rNEvt )
{
    long nDone = 0;
    if ( rNEvt.GetType() == EVENT_COMMAND )
    {
        const CommandEvent& rCEvt = *rNEvt.GetCommandEvent();
        if ( rCEvt.GetCommand() == COMMAND_WHEEL )
        {
            const CommandWheelData* pData = rCEvt.GetWheelData();
            if( !pData->GetModifier() && ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) )
            {
                nDone = HandleScrollCommand( rCEvt, mpHScrollBar, mpVScrollBar );
            }
        }
    }

    return nDone ? nDone : Window::Notify( rNEvt );
}

} //  namespace sd
<|endoftext|>


<commit_before><commit_msg>이름 정규식 버그 수정<commit_after><|endoftext|>


<commit_before>//
// Copyright (C) 2013-2018 University of Amsterdam
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#include "sharedmemory.h"

#include "processinfo.h"
#include "tempfiles.h"

#include <sstream>

#include "log.h"

using namespace std;
using namespace boost;

interprocess::managed_shared_memory *SharedMemory::_memory = NULL;
string SharedMemory::_memoryName;

DataSet *SharedMemory::createDataSet()
{
	if (_memory == NULL)
	{
		stringstream ss;
		ss << "JASP-DATA-";
		ss << ProcessInfo::currentPID();
		_memoryName = ss.str();

		TempFiles::addShmemFileName(_memoryName);

		interprocess::shared_memory_object::remove(_memoryName.c_str());
		_memory = new interprocess::managed_shared_memory(interprocess::create_only, _memoryName.c_str(), 6 * 1024 * 1024);
	}

	DataSet * data = _memory->construct<DataSet>(interprocess::unique_instance)(_memory);
	return data;
}

DataSet *SharedMemory::retrieveDataSet(unsigned long parentPID)
{
	DataSet * data = nullptr;
	try
	{
		if (_memory == nullptr)
		{
			if(parentPID == 0)
				parentPID = ProcessInfo::parentPID();

			_memoryName = "JASP-DATA-" + std::to_string(parentPID);
			_memory		= new interprocess::managed_shared_memory(interprocess::open_only, _memoryName.c_str());
		}

		data = _memory->find<DataSet>(interprocess::unique_instance).first;
	}
	catch (const interprocess::interprocess_exception& e)
	{
		data = nullptr;

	}

	return data;
}

DataSet *SharedMemory::enlargeDataSet(DataSet *)
{
	size_t extraSize = _memory->get_size();

	Log::log() << "SharedMemory::enlargeDataSet to " << extraSize << std::endl;

	delete _memory;

	interprocess::managed_shared_memory::grow(_memoryName.c_str(), extraSize);
	_memory = new interprocess::managed_shared_memory(interprocess::open_only, _memoryName.c_str());

	DataSet *dataSet = retrieveDataSet();
	dataSet->setSharedMemory(_memory);

	return dataSet;
}

void SharedMemory::deleteDataSet(DataSet *dataSet)
{
	_memory->destroy_ptr(dataSet);
}

void SharedMemory::unloadDataSet()
{
	if(_memory != NULL)
		delete _memory;

	_memory = NULL;
}
<commit_msg>Add log when no data set is found in shared memory<commit_after>//
// Copyright (C) 2013-2018 University of Amsterdam
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

#include "sharedmemory.h"

#include "processinfo.h"
#include "tempfiles.h"

#include <sstream>

#include "log.h"

using namespace std;
using namespace boost;

interprocess::managed_shared_memory *SharedMemory::_memory = NULL;
string SharedMemory::_memoryName;

DataSet *SharedMemory::createDataSet()
{
	if (_memory == NULL)
	{
		stringstream ss;
		ss << "JASP-DATA-";
		ss << ProcessInfo::currentPID();
		_memoryName = ss.str();

		TempFiles::addShmemFileName(_memoryName);

		interprocess::shared_memory_object::remove(_memoryName.c_str());
		_memory = new interprocess::managed_shared_memory(interprocess::create_only, _memoryName.c_str(), 6 * 1024 * 1024);
	}

	DataSet * data = _memory->construct<DataSet>(interprocess::unique_instance)(_memory);
	return data;
}

DataSet *SharedMemory::retrieveDataSet(unsigned long parentPID)
{
	DataSet * data = nullptr;
	try
	{
		if (_memory == nullptr)
		{
			if(parentPID == 0)
				parentPID = ProcessInfo::parentPID();

			_memoryName = "JASP-DATA-" + std::to_string(parentPID);
			_memory		= new interprocess::managed_shared_memory(interprocess::open_only, _memoryName.c_str());
		}

		data = _memory->find<DataSet>(interprocess::unique_instance).first;
	}
	catch (const interprocess::interprocess_exception& e)
	{
		Log::log() << "Error when retrieving the data set: " << e.what() << std::endl;
		data = nullptr;
	}

	if (data == nullptr)
		Log::log() << "No data set found in shared memory with name: " << _memoryName << std::endl;

	return data;
}

DataSet *SharedMemory::enlargeDataSet(DataSet *)
{
	size_t extraSize = _memory->get_size();

	Log::log() << "SharedMemory::enlargeDataSet to " << extraSize << std::endl;

	delete _memory;

	interprocess::managed_shared_memory::grow(_memoryName.c_str(), extraSize);
	_memory = new interprocess::managed_shared_memory(interprocess::open_only, _memoryName.c_str());

	DataSet *dataSet = retrieveDataSet();
	dataSet->setSharedMemory(_memory);

	return dataSet;
}

void SharedMemory::deleteDataSet(DataSet *dataSet)
{
	_memory->destroy_ptr(dataSet);
}

void SharedMemory::unloadDataSet()
{
	if(_memory != NULL)
		delete _memory;

	_memory = NULL;
}
<|endoftext|>