<commit_before>/*
 * Copyright (C) 2010-2014 Jeremy Lainé
 * Contact: https://github.com/jlaine/qdjango
 *
 * This file is part of the QDjango Library.
 *
 * This library 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 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.
 */

#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QtTest>
#include <QUrl>

#include "QDjangoHttpController.h"
#include "QDjangoHttpRequest.h"
#include "QDjangoHttpResponse.h"
#include "QDjangoHttpServer.h"
#include "QDjangoUrlResolver.h"

/** Test QDjangoHttpServer class.
 */
class tst_QDjangoHttpServer : public QObject
{
    Q_OBJECT

private slots:
    void cleanupTestCase();
    void initTestCase();
    void testGet_data();
    void testGet();
    void testPost_data();
    void testPost();

    QDjangoHttpResponse* _q_index(const QDjangoHttpRequest &request);
    QDjangoHttpResponse* _q_error(const QDjangoHttpRequest &request);

private:
    QDjangoHttpServer *httpServer;
};

void tst_QDjangoHttpServer::cleanupTestCase()
{
    httpServer->close();
    delete httpServer;
}

void tst_QDjangoHttpServer::initTestCase()
{
    httpServer = new QDjangoHttpServer;
    httpServer->urls()->set(QRegExp(QLatin1String(QLatin1String("^$"))), this, "_q_index");
    httpServer->urls()->set(QRegExp(QLatin1String("^internal-server-error$")), this, "_q_error");
    QCOMPARE(httpServer->listen(QHostAddress::LocalHost, 8123), true);
}

void tst_QDjangoHttpServer::testGet_data()
{
    QTest::addColumn<QString>("path");
    QTest::addColumn<int>("err");
    QTest::addColumn<QByteArray>("body");

    const QString errorTemplate = QLatin1String(
        ""
        "<title>Error</title>"
        "
%1
"
        "");
#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0))
    int internalServerError = int(QNetworkReply::InternalServerError);
#else
    int internalServerError = int(QNetworkReply::UnknownContentError);
#endif
    QTest::newRow("root") << "/" << int(QNetworkReply::NoError) << QByteArray("method=GET|path=/");
    QTest::newRow("query-string") << "/?message=bar" << int(QNetworkReply::NoError) << QByteArray("method=GET|path=/|get=bar");
    QTest::newRow("not-found") << "/not-found" << int(QNetworkReply::ContentNotFoundError) << errorTemplate.arg(QLatin1String("The document you requested was not found.")).toUtf8();
    QTest::newRow("internal-server-error") << "/internal-server-error" << internalServerError << errorTemplate.arg(QLatin1String("An internal server error was encountered.")).toUtf8();
}

void tst_QDjangoHttpServer::testGet()
{
    QFETCH(QString, path);
    QFETCH(int, err);
    QFETCH(QByteArray, body);

    QNetworkAccessManager network;
    QNetworkReply *reply = network.get(QNetworkRequest(QUrl(QLatin1String("http://127.0.0.1:8123") + path)));

    QEventLoop loop;
    QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();

    QVERIFY(reply);
    QCOMPARE(int(reply->error()), err);
    QCOMPARE(reply->readAll(), body);
    delete reply;
}

void tst_QDjangoHttpServer::testPost_data()
{
    QTest::addColumn<QString>("path");
    QTest::addColumn<QByteArray>("data");
    QTest::addColumn<int>("err");
    QTest::addColumn<QByteArray>("body");

    QTest::newRow("empty") << "/" << QByteArray() << int(QNetworkReply::NoError) << QByteArray("method=POST|path=/");
    QTest::newRow("simple") << "/" << QByteArray("message=bar") << int(QNetworkReply::NoError) << QByteArray("method=POST|path=/|post=bar");
    QTest::newRow("multi") << "/" << QByteArray("bob=wiz&message=bar&zoo=wow") << int(QNetworkReply::NoError) << QByteArray("method=POST|path=/|post=bar");
}

void tst_QDjangoHttpServer::testPost()
{
    QFETCH(QString, path);
    QFETCH(QByteArray, data);
    QFETCH(int, err);
    QFETCH(QByteArray, body);

    QNetworkAccessManager network;
    QNetworkRequest req(QUrl(QLatin1String("http://127.0.0.1:8123") + path));
    req.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
    QNetworkReply *reply = network.post(req, data);

    QEventLoop loop;
    QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();

    QVERIFY(reply);
    QCOMPARE(int(reply->error()), err);
    QCOMPARE(reply->readAll(), body);
    delete reply;
}

QDjangoHttpResponse *tst_QDjangoHttpServer::_q_index(const QDjangoHttpRequest &request)
{
    QDjangoHttpResponse *response = new QDjangoHttpResponse;
    response->setHeader(QLatin1String("Content-Type"), QLatin1String("text/plain"));

    QString output = QLatin1String("method=") + request.method();
    output += QLatin1String("|path=") + request.path();

    const QString getValue = request.get(QLatin1String("message"));
    if (!getValue.isEmpty())
        output += QLatin1String("|get=") + getValue;

    const QString postValue = request.post(QLatin1String("message"));
    if (!postValue.isEmpty())
        output += QLatin1String("|post=") + postValue;

    response->setBody(output.toUtf8());
    return response;
}

QDjangoHttpResponse *tst_QDjangoHttpServer::_q_error(const QDjangoHttpRequest &request)
{
    Q_UNUSED(request);

    return QDjangoHttpController::serveInternalServerError(request);
}

QTEST_MAIN(tst_QDjangoHttpServer)
#include "tst_qdjangohttpserver.moc"
<commit_msg>test HTTP connection close<commit_after>/*
 * Copyright (C) 2010-2014 Jeremy Lainé
 * Contact: https://github.com/jlaine/qdjango
 *
 * This file is part of the QDjango Library.
 *
 * This library 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 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.
 */

#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QtTest>
#include <QUrl>

#include "QDjangoHttpController.h"
#include "QDjangoHttpRequest.h"
#include "QDjangoHttpResponse.h"
#include "QDjangoHttpServer.h"
#include "QDjangoUrlResolver.h"

/** Test QDjangoHttpServer class.
 */
class tst_QDjangoHttpServer : public QObject
{
    Q_OBJECT

private slots:
    void cleanupTestCase();
    void initTestCase();
    void testCloseConnection();
    void testGet_data();
    void testGet();
    void testPost_data();
    void testPost();

    QDjangoHttpResponse* _q_index(const QDjangoHttpRequest &request);
    QDjangoHttpResponse* _q_error(const QDjangoHttpRequest &request);

private:
    QDjangoHttpServer *httpServer;
};

void tst_QDjangoHttpServer::cleanupTestCase()
{
    httpServer->close();
    delete httpServer;
}

void tst_QDjangoHttpServer::initTestCase()
{
    httpServer = new QDjangoHttpServer;
    httpServer->urls()->set(QRegExp(QLatin1String(QLatin1String("^$"))), this, "_q_index");
    httpServer->urls()->set(QRegExp(QLatin1String("^internal-server-error$")), this, "_q_error");
    QCOMPARE(httpServer->listen(QHostAddress::LocalHost, 8123), true);
}

void tst_QDjangoHttpServer::testCloseConnection()
{
    QNetworkAccessManager network;

    QNetworkRequest req(QUrl("http://127.0.0.1:8123/"));
    req.setRawHeader("Connection", "close");

    QNetworkReply *reply = network.get(req);

    QEventLoop loop;
    QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();

    QVERIFY(reply);
    QCOMPARE(reply->error(), QNetworkReply::NoError);
    //QCOMPARE(reply->readAll(), body);
    delete reply;

}

void tst_QDjangoHttpServer::testGet_data()
{
    QTest::addColumn<QString>("path");
    QTest::addColumn<int>("err");
    QTest::addColumn<QByteArray>("body");

    const QString errorTemplate = QLatin1String(
        ""
        "<title>Error</title>"
        "
%1
"
        "");
#if (QT_VERSION >= QT_VERSION_CHECK(5, 3, 0))
    int internalServerError = int(QNetworkReply::InternalServerError);
#else
    int internalServerError = int(QNetworkReply::UnknownContentError);
#endif
    QTest::newRow("root") << "/" << int(QNetworkReply::NoError) << QByteArray("method=GET|path=/");
    QTest::newRow("query-string") << "/?message=bar" << int(QNetworkReply::NoError) << QByteArray("method=GET|path=/|get=bar");
    QTest::newRow("not-found") << "/not-found" << int(QNetworkReply::ContentNotFoundError) << errorTemplate.arg(QLatin1String("The document you requested was not found.")).toUtf8();
    QTest::newRow("internal-server-error") << "/internal-server-error" << internalServerError << errorTemplate.arg(QLatin1String("An internal server error was encountered.")).toUtf8();
}

void tst_QDjangoHttpServer::testGet()
{
    QFETCH(QString, path);
    QFETCH(int, err);
    QFETCH(QByteArray, body);

    QNetworkAccessManager network;
    QNetworkReply *reply = network.get(QNetworkRequest(QUrl(QLatin1String("http://127.0.0.1:8123") + path)));

    QEventLoop loop;
    QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();

    QVERIFY(reply);
    QCOMPARE(int(reply->error()), err);
    QCOMPARE(reply->readAll(), body);
    delete reply;
}

void tst_QDjangoHttpServer::testPost_data()
{
    QTest::addColumn<QString>("path");
    QTest::addColumn<QByteArray>("data");
    QTest::addColumn<int>("err");
    QTest::addColumn<QByteArray>("body");

    QTest::newRow("empty") << "/" << QByteArray() << int(QNetworkReply::NoError) << QByteArray("method=POST|path=/");
    QTest::newRow("simple") << "/" << QByteArray("message=bar") << int(QNetworkReply::NoError) << QByteArray("method=POST|path=/|post=bar");
    QTest::newRow("multi") << "/" << QByteArray("bob=wiz&message=bar&zoo=wow") << int(QNetworkReply::NoError) << QByteArray("method=POST|path=/|post=bar");
}

void tst_QDjangoHttpServer::testPost()
{
    QFETCH(QString, path);
    QFETCH(QByteArray, data);
    QFETCH(int, err);
    QFETCH(QByteArray, body);

    QNetworkAccessManager network;
    QNetworkRequest req(QUrl(QLatin1String("http://127.0.0.1:8123") + path));
    req.setRawHeader("Content-Type", "application/x-www-form-urlencoded");
    QNetworkReply *reply = network.post(req, data);

    QEventLoop loop;
    QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
    loop.exec();

    QVERIFY(reply);
    QCOMPARE(int(reply->error()), err);
    QCOMPARE(reply->readAll(), body);
    delete reply;
}

QDjangoHttpResponse *tst_QDjangoHttpServer::_q_index(const QDjangoHttpRequest &request)
{
    QDjangoHttpResponse *response = new QDjangoHttpResponse;
    response->setHeader(QLatin1String("Content-Type"), QLatin1String("text/plain"));

    QString output = QLatin1String("method=") + request.method();
    output += QLatin1String("|path=") + request.path();

    const QString getValue = request.get(QLatin1String("message"));
    if (!getValue.isEmpty())
        output += QLatin1String("|get=") + getValue;

    const QString postValue = request.post(QLatin1String("message"));
    if (!postValue.isEmpty())
        output += QLatin1String("|post=") + postValue;

    response->setBody(output.toUtf8());
    return response;
}

QDjangoHttpResponse *tst_QDjangoHttpServer::_q_error(const QDjangoHttpRequest &request)
{
    Q_UNUSED(request);

    return QDjangoHttpController::serveInternalServerError(request);
}

QTEST_MAIN(tst_QDjangoHttpServer)
#include "tst_qdjangohttpserver.moc"
<|endoftext|>


<commit_before><commit_msg>Update p10152 - ShellSort.cpp<commit_after><|endoftext|>


<commit_before>/*
* Chemharp, an efficient IO library for chemistry file formats
* Copyright (C) 2015 Guillaume Fraux
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/
*/

/*! @file cerrors.hpp
* Handling C++ errors from the C API
*/

#ifndef HARP_CAPI_ERRORS_H
#define HARP_CAPI_ERRORS_H

#include <string>
#include "chemharp/Logger.hpp"

namespace harp {

//! @brief struct to associate the values of status code to messages.
struct CAPIStatus {
    enum {
        //! Everythig is OK
        SUCESS = 0,
        //! Error in the C++ standard library
        STD_ERROR,
        //! Catch all harp::Error errors
        GENERIC,
        //! Memory error: wrong pre-allocated arrays, ...
        MEMORY,
        //! File error: inexistent, can not open, ...
        FILE,
        //! Error in the C++ standard library
        FORMAT,
        //! Counter for the number of error codes.
        LAST,
    };

    CAPIStatus() {
        messages[SUCESS] = "Operation was sucessfull";
        messages[STD_ERROR] = "Error in C++ runtime. Use chrp_last_error for more informations.";
        messages[GENERIC] = "Error in Chemharp library. Use chrp_last_error for more informations.";
        messages[MEMORY] = "Memory error.";
        messages[FILE] = "Error while reading a file.";
        messages[FORMAT] = "Error while reading a format.";
    }

    /// Retrive the message corresponding to an error code.
    const char* message(int i) const {
        if (i >= 0 && i < LAST)
            return messages[i];
        else
            return "";
    }
    std::string last_error;
private:
    const char* messages[LAST];
};

static CAPIStatus status = CAPIStatus();

#define CATCH_AND_RETURN(exception, retval)           \
    catch(const harp::exception& e) {                 \
        status.last_error = string(e.what());         \
        LOG(ERROR) << e.what() << std::endl;          \
        return retval;                                \
    }

#define CATCH_AND_GOTO(exception)                     \
    catch(const harp::exception& e) {                 \
        status.last_error = string(e.what());         \
        LOG(ERROR) << e.what() << std::endl;          \
        goto error;                                   \
    }

//! Wrap \c instructions in a try/catch bloc automatically, and return a status code
#define CHRP_ERROR_WRAP_RETCODE(instructions)                                  \
    try {                                                                      \
        instructions                                                           \
    }                                                                          \
    CATCH_AND_RETURN(FileError, CAPIStatus::FILE)                              \
    CATCH_AND_RETURN(MemoryError, CAPIStatus::MEMORY)                          \
    CATCH_AND_RETURN(FormatError, CAPIStatus::FORMAT)                          \
    CATCH_AND_RETURN(Error, CAPIStatus::GENERIC)                               \
    catch(const std::exception& e) {                                           \
        status.last_error = string(e.what());                                  \
        return CAPIStatus::STD_ERROR;                                          \
    }                                                                          \
    return CAPIStatus::SUCESS;

//! Wrap \c instructions in a try/catch bloc automatically, and goto the \c error
//! label in case of error.
#define CHRP_ERROR_WRAP(instructions)                                          \
    try {                                                                      \
        instructions                                                           \
    }                                                                          \
    CATCH_AND_GOTO(FileError)                                                  \
    CATCH_AND_GOTO(MemoryError)                                                \
    CATCH_AND_GOTO(FormatError)                                                \
    CATCH_AND_GOTO(Error)                                                      \
    catch(const std::exception& e) {                                           \
        status.last_error = string(e.what());                                  \
        goto error;                                                            \
    }

}

#endif
<commit_msg>Improve naming in chemharp C errors<commit_after>/*
* Chemharp, an efficient IO library for chemistry file formats
* Copyright (C) 2015 Guillaume Fraux
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/
*/

/*! @file cerrors.hpp
* Handling C++ errors from the C API
*/

#ifndef HARP_CAPI_ERRORS_H
#define HARP_CAPI_ERRORS_H

#include <string>
#include "chemharp/Logger.hpp"

namespace harp {

//! @brief struct to associate the values of status code to messages.
struct CAPIStatus {
    enum {
        //! Everythig is OK
        SUCESS = 0,
        //! Error in the C++ standard library
        STD_ERROR,
        //! Catch all harp::Error errors
        CHEMHARP,
        //! Memory error: wrong pre-allocated arrays, ...
        MEMORY,
        //! File error: inexistent, can not open, ...
        FILE,
        //! Error in file formating
        FORMAT,
        //! Counter for the number of error codes.
        LAST,
    };

    CAPIStatus() {
        messages[SUCESS] = "Operation was sucessfull";
        messages[STD_ERROR] = "Error in C++ runtime. Use chrp_last_error for more informations.";
        messages[CHEMHARP] = "Error in Chemharp library. Use chrp_last_error for more informations.";
        messages[MEMORY] = "Memory error.";
        messages[FILE] = "Error while reading a file.";
        messages[FORMAT] = "Error while reading a format.";
    }

    /// Retrive the message corresponding to an error code.
    const char* message(int i) const {
        if (i >= 0 && i < LAST)
            return messages[i];
        else
            return "";
    }
    std::string last_error;
private:
    const char* messages[LAST];
};

static CAPIStatus status = CAPIStatus();

#define CATCH_AND_RETURN(exception, retval)           \
    catch(const harp::exception& e) {                 \
        status.last_error = string(e.what());         \
        LOG(ERROR) << e.what() << std::endl;          \
        return retval;                                \
    }

#define CATCH_AND_GOTO(exception)                     \
    catch(const harp::exception& e) {                 \
        status.last_error = string(e.what());         \
        LOG(ERROR) << e.what() << std::endl;          \
        goto error;                                   \
    }

//! Wrap \c instructions in a try/catch bloc automatically, and return a status code
#define CHRP_ERROR_WRAP_RETCODE(instructions)                                  \
    try {                                                                      \
        instructions                                                           \
    }                                                                          \
    CATCH_AND_RETURN(FileError, CAPIStatus::FILE)                              \
    CATCH_AND_RETURN(MemoryError, CAPIStatus::MEMORY)                          \
    CATCH_AND_RETURN(FormatError, CAPIStatus::FORMAT)                          \
    CATCH_AND_RETURN(Error, CAPIStatus::CHEMHARP)                              \
    catch(const std::exception& e) {                                           \
        status.last_error = string(e.what());                                  \
        return CAPIStatus::STD_ERROR;                                          \
    }                                                                          \
    return CAPIStatus::SUCESS;

//! Wrap \c instructions in a try/catch bloc automatically, and goto the \c error
//! label in case of error.
#define CHRP_ERROR_WRAP(instructions)                                          \
    try {                                                                      \
        instructions                                                           \
    }                                                                          \
    CATCH_AND_GOTO(FileError)                                                  \
    CATCH_AND_GOTO(MemoryError)                                                \
    CATCH_AND_GOTO(FormatError)                                                \
    CATCH_AND_GOTO(Error)                                                      \
    catch(const std::exception& e) {                                           \
        status.last_error = string(e.what());                                  \
        goto error;                                                            \
    }

}

#endif
<|endoftext|>


<commit_before>/*  This file is part of the KDE project.

Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

This library 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 or 3 of the License.

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, see <http://www.gnu.org/licenses/>.

*/

#include <coecntrl.h> // for CCoeControl

#include <QApplication>    // for QApplication::activeWindow
#include <QtCore/private/qcore_symbian_p.h> // for qt_TRect2QRect

#include "utils.h"
#include "videooutput_dsa.h"
#include "videoplayer_dsa.h"

QT_BEGIN_NAMESPACE

using namespace Phonon;
using namespace Phonon::MMF;

// Two-phase constructor idiom is used because construct() calls virtual
// functions and therefore cannot be called from the AbstractVideoPlayer
// C++ constructor.
DsaVideoPlayer* DsaVideoPlayer::create(MediaObject *parent,
                                       const AbstractPlayer *player)
{
    QScopedPointer<DsaVideoPlayer> self(new DsaVideoPlayer(parent, player));
    self->construct();
    return self.take();
}

DsaVideoPlayer::DsaVideoPlayer(MediaObject *parent, const AbstractPlayer *player)
    :   AbstractVideoPlayer(parent, player)
    ,   m_dsaActive(false)
    ,   m_dsaWasActive(false)
{

}

DsaVideoPlayer::~DsaVideoPlayer()
{

}

//-----------------------------------------------------------------------------
// Public functions
//-----------------------------------------------------------------------------

void MMF::DsaVideoPlayer::videoWindowScreenRectChanged()
{
    QRect windowRect = static_cast<DsaVideoOutput *>(m_videoOutput)->videoWindowScreenRect();

    // Clip to physical window size
    // This is due to a defect in the layout when running on S60 3.2, which
    // results in the rectangle of the video widget extending outside the
    // screen in certain circumstances.  These include the initial startup
    // of the mediaplayer demo in portrait mode.  When this rectangle is
    // passed to the CVideoPlayerUtility, no video is rendered.
    const TSize screenSize = m_screenDevice.SizeInPixels();
    const QRect screenRect(0, 0, screenSize.iWidth, screenSize.iHeight);
    windowRect = windowRect.intersected(screenRect);

    // Recalculate scale factors.  Pass 'false' as second parameter in order to
    // suppress application of the change to the player - this is done at the end
    // of the function.
    updateScaleFactors(windowRect.size(), false);

    m_videoScreenRect = qt_QRect2TRect(windowRect);

    parametersChanged(WindowScreenRect | ScaleFactors);
}

void MMF::DsaVideoPlayer::suspendDirectScreenAccess()
{
    m_dsaWasActive = stopDirectScreenAccess();
}

void MMF::DsaVideoPlayer::resumeDirectScreenAccess()
{
    if (m_dsaWasActive) {
        startDirectScreenAccess();
        m_dsaWasActive = false;
    }
}

//-----------------------------------------------------------------------------
// Private functions
//-----------------------------------------------------------------------------

void MMF::DsaVideoPlayer::createPlayer()
{
    // A window handle must be provided in order to construct
    // CVideoPlayerUtility.  If no VideoOutput has yet been connected to this
    // player, we temporarily use the top-level application window handle.
    // No video ever gets rendered into this window; SetDisplayWindowL is
    // always called before rendering actually begins.
    if (!m_window)
        m_window = QApplication::activeWindow()->effectiveWinId()->DrawableWindow();

    const TInt priority = 0;
    const TMdaPriorityPreference preference = EMdaPriorityPreferenceNone;

    CVideoPlayerUtility *player = 0;
    QT_TRAP_THROWING(player = CVideoPlayerUtility::NewL(*this,
                                     priority, preference,
                                     m_wsSession, m_screenDevice,
                                     *m_window,
                                     m_videoScreenRect, m_videoScreenRect));
    m_player.reset(player);

    // CVideoPlayerUtility::NewL starts DSA
    m_dsaActive = true;

    m_player->RegisterForVideoLoadingNotification(*this);
}

void MMF::DsaVideoPlayer::initVideoOutput()
{
    bool connected = connect(
        m_videoOutput, SIGNAL(videoWindowScreenRectChanged()),
        this, SLOT(videoWindowScreenRectChanged())
    );
    Q_ASSERT(connected);

    connected = connect(
        m_videoOutput, SIGNAL(beginVideoWindowNativePaint()),
        this, SLOT(suspendDirectScreenAccess())
    );
    Q_ASSERT(connected);

    connected = connect(
        m_videoOutput, SIGNAL(endVideoWindowNativePaint()),
        this, SLOT(resumeDirectScreenAccess())
    );
    Q_ASSERT(connected);

    // Suppress warnings in release builds
    Q_UNUSED(connected);

    AbstractVideoPlayer::initVideoOutput();
}

void MMF::DsaVideoPlayer::prepareCompleted()
{
    videoWindowScreenRectChanged();
}

void MMF::DsaVideoPlayer::handleVideoWindowChanged()
{
    if (!m_window) {
        m_window = QApplication::activeWindow()->effectiveWinId()->DrawableWindow();
        m_videoScreenRect = TRect();
    }

    parametersChanged(WindowHandle | WindowScreenRect);
}

#ifndef QT_NO_DEBUG

// The following code is for debugging problems related to video visibility.  It allows
// the VideoPlayer instance to query the window server in order to determine the
// DSA drawing region for the video window.

class CDummyAO : public CActive
{
public:
    CDummyAO() : CActive(CActive::EPriorityStandard) { CActiveScheduler::Add(this); }
    void RunL() { }
    void DoCancel() { }
    TRequestStatus& Status() { return iStatus; }
    void SetActive() { CActive::SetActive(); }
};

void getDsaRegion(RWsSession &session, const RWindowBase &window)
{
    RDirectScreenAccess dsa(session);
    TInt err = dsa.Construct();
    CDummyAO ao;
    RRegion* region;
    err = dsa.Request(region, ao.Status(), window);
    ao.SetActive();
    dsa.Close();
    ao.Cancel();
    if (region) {
        qDebug() << "Phonon::MMF::getDsaRegion count" << region->Count();
        for (int i=0; i<region->Count(); ++i) {
            const TRect& rect = region->RectangleList()[i];
            qDebug() << "Phonon::MMF::getDsaRegion rect"
                << rect.iTl.iX << rect.iTl.iY << rect.iBr.iX << rect.iBr.iY;
        }
        region->Close();
    }
}

#endif // QT_NO_DEBUG

void MMF::DsaVideoPlayer::handleParametersChanged(VideoParameters parameters)
{
    TRACE_CONTEXT(DsaVideoPlayer::handleParametersChanged, EVideoInternal);
    TRACE_ENTRY_0();

#ifndef QT_NO_DEBUG
    getDsaRegion(m_wsSession, *m_window);
#endif

    static const TBool antialias = ETrue;
    int err = KErrNone;

    if (parameters & ScaleFactors) {
        TRAP(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight,
                                            antialias));
        if(KErrNone != err) {
            TRACE("SetScaleFactorL (1) err %d", err);
            setError(tr("Video display error"), err);
        }
    }

    if (KErrNone == err) {
        if (parameters & WindowHandle || parameters & WindowScreenRect) {
            TRAP(err,
                m_player->SetDisplayWindowL(m_wsSession, m_screenDevice,
                                            *m_window,
                                            m_videoScreenRect,
                                            m_videoScreenRect));
        }

        if (KErrNone != err) {
            TRACE("SetDisplayWindowL err %d", err);
            setError(tr("Video display error"), err);
        } else {
            m_dsaActive = true;
            if (parameters & ScaleFactors) {
                TRAP(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight,
                                                    antialias));
                if (KErrNone != err) {
                    TRACE("SetScaleFactorL (2) err %d", err);
                    setError(tr("Video display error"), err);
                }
            }
        }
    }

    TRACE_EXIT_0();
}

void MMF::DsaVideoPlayer::startDirectScreenAccess()
{
    if (!m_dsaActive) {
        TRAPD(err, m_player->StartDirectScreenAccessL());
        if (KErrNone == err)
            m_dsaActive = true;
        else
            setError(tr("Video display error"), err);
    }
}

bool MMF::DsaVideoPlayer::stopDirectScreenAccess()
{
    const bool dsaWasActive = m_dsaActive;
    if (m_dsaActive) {
        TRAPD(err, m_player->StopDirectScreenAccessL());
        if (KErrNone == err)
            m_dsaActive = false;
        else
            setError(tr("Video display error"), err);
    }
    return dsaWasActive;
}

QT_END_NAMESPACE

<commit_msg>Fixed crash in Phonon MMF backend during application shutdown<commit_after>/*  This file is part of the KDE project.

Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).

This library 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 or 3 of the License.

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, see <http://www.gnu.org/licenses/>.

*/

#include <coecntrl.h> // for CCoeControl

#include <QApplication>    // for QApplication::activeWindow
#include <QtCore/private/qcore_symbian_p.h> // for qt_TRect2QRect

#include "utils.h"
#include "videooutput_dsa.h"
#include "videoplayer_dsa.h"

QT_BEGIN_NAMESPACE

using namespace Phonon;
using namespace Phonon::MMF;

// Two-phase constructor idiom is used because construct() calls virtual
// functions and therefore cannot be called from the AbstractVideoPlayer
// C++ constructor.
DsaVideoPlayer* DsaVideoPlayer::create(MediaObject *parent,
                                       const AbstractPlayer *player)
{
    QScopedPointer<DsaVideoPlayer> self(new DsaVideoPlayer(parent, player));
    self->construct();
    return self.take();
}

DsaVideoPlayer::DsaVideoPlayer(MediaObject *parent, const AbstractPlayer *player)
    :   AbstractVideoPlayer(parent, player)
    ,   m_dsaActive(false)
    ,   m_dsaWasActive(false)
{

}

DsaVideoPlayer::~DsaVideoPlayer()
{

}

//-----------------------------------------------------------------------------
// Public functions
//-----------------------------------------------------------------------------

void MMF::DsaVideoPlayer::videoWindowScreenRectChanged()
{
    QRect windowRect = static_cast<DsaVideoOutput *>(m_videoOutput)->videoWindowScreenRect();

    // Clip to physical window size
    // This is due to a defect in the layout when running on S60 3.2, which
    // results in the rectangle of the video widget extending outside the
    // screen in certain circumstances.  These include the initial startup
    // of the mediaplayer demo in portrait mode.  When this rectangle is
    // passed to the CVideoPlayerUtility, no video is rendered.
    const TSize screenSize = m_screenDevice.SizeInPixels();
    const QRect screenRect(0, 0, screenSize.iWidth, screenSize.iHeight);
    windowRect = windowRect.intersected(screenRect);

    // Recalculate scale factors.  Pass 'false' as second parameter in order to
    // suppress application of the change to the player - this is done at the end
    // of the function.
    updateScaleFactors(windowRect.size(), false);

    m_videoScreenRect = qt_QRect2TRect(windowRect);

    parametersChanged(WindowScreenRect | ScaleFactors);
}

void MMF::DsaVideoPlayer::suspendDirectScreenAccess()
{
    m_dsaWasActive = stopDirectScreenAccess();
}

void MMF::DsaVideoPlayer::resumeDirectScreenAccess()
{
    if (m_dsaWasActive) {
        startDirectScreenAccess();
        m_dsaWasActive = false;
    }
}

//-----------------------------------------------------------------------------
// Private functions
//-----------------------------------------------------------------------------

void MMF::DsaVideoPlayer::createPlayer()
{
    // A window handle must be provided in order to construct
    // CVideoPlayerUtility.  If no VideoOutput has yet been connected to this
    // player, we temporarily use the top-level application window handle.
    // No video ever gets rendered into this window; SetDisplayWindowL is
    // always called before rendering actually begins.
    if (!m_window)
        m_window = QApplication::activeWindow()->effectiveWinId()->DrawableWindow();

    const TInt priority = 0;
    const TMdaPriorityPreference preference = EMdaPriorityPreferenceNone;

    CVideoPlayerUtility *player = 0;
    QT_TRAP_THROWING(player = CVideoPlayerUtility::NewL(*this,
                                     priority, preference,
                                     m_wsSession, m_screenDevice,
                                     *m_window,
                                     m_videoScreenRect, m_videoScreenRect));
    m_player.reset(player);

    // CVideoPlayerUtility::NewL starts DSA
    m_dsaActive = true;

    m_player->RegisterForVideoLoadingNotification(*this);
}

void MMF::DsaVideoPlayer::initVideoOutput()
{
    bool connected = connect(
        m_videoOutput, SIGNAL(videoWindowScreenRectChanged()),
        this, SLOT(videoWindowScreenRectChanged())
    );
    Q_ASSERT(connected);

    connected = connect(
        m_videoOutput, SIGNAL(beginVideoWindowNativePaint()),
        this, SLOT(suspendDirectScreenAccess())
    );
    Q_ASSERT(connected);

    connected = connect(
        m_videoOutput, SIGNAL(endVideoWindowNativePaint()),
        this, SLOT(resumeDirectScreenAccess())
    );
    Q_ASSERT(connected);

    // Suppress warnings in release builds
    Q_UNUSED(connected);

    AbstractVideoPlayer::initVideoOutput();
}

void MMF::DsaVideoPlayer::prepareCompleted()
{
    videoWindowScreenRectChanged();
}

void MMF::DsaVideoPlayer::handleVideoWindowChanged()
{
    if (!m_window) {
        if (QWidget *window = QApplication::activeWindow())
            m_window = window->effectiveWinId()->DrawableWindow();
        else
            m_window = 0;
        m_videoScreenRect = TRect();
    }

    parametersChanged(WindowHandle | WindowScreenRect);
}

#ifndef QT_NO_DEBUG

// The following code is for debugging problems related to video visibility.  It allows
// the VideoPlayer instance to query the window server in order to determine the
// DSA drawing region for the video window.

class CDummyAO : public CActive
{
public:
    CDummyAO() : CActive(CActive::EPriorityStandard) { CActiveScheduler::Add(this); }
    void RunL() { }
    void DoCancel() { }
    TRequestStatus& Status() { return iStatus; }
    void SetActive() { CActive::SetActive(); }
};

void getDsaRegion(RWsSession &session, const RWindowBase &window)
{
    RDirectScreenAccess dsa(session);
    TInt err = dsa.Construct();
    CDummyAO ao;
    RRegion* region;
    err = dsa.Request(region, ao.Status(), window);
    ao.SetActive();
    dsa.Close();
    ao.Cancel();
    if (region) {
        qDebug() << "Phonon::MMF::getDsaRegion count" << region->Count();
        for (int i=0; i<region->Count(); ++i) {
            const TRect& rect = region->RectangleList()[i];
            qDebug() << "Phonon::MMF::getDsaRegion rect"
                << rect.iTl.iX << rect.iTl.iY << rect.iBr.iX << rect.iBr.iY;
        }
        region->Close();
    }
}

#endif // QT_NO_DEBUG

void MMF::DsaVideoPlayer::handleParametersChanged(VideoParameters parameters)
{
    TRACE_CONTEXT(DsaVideoPlayer::handleParametersChanged, EVideoInternal);
    TRACE_ENTRY_0();

    if (!m_window)
        return;

#ifndef QT_NO_DEBUG
    getDsaRegion(m_wsSession, *m_window);
#endif

    static const TBool antialias = ETrue;
    int err = KErrNone;

    if (parameters & ScaleFactors) {
        TRAP(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight,
                                            antialias));
        if(KErrNone != err) {
            TRACE("SetScaleFactorL (1) err %d", err);
            setError(tr("Video display error"), err);
        }
    }

    if (KErrNone == err) {
        if (parameters & WindowHandle || parameters & WindowScreenRect) {
            TRAP(err,
                m_player->SetDisplayWindowL(m_wsSession, m_screenDevice,
                                            *m_window,
                                            m_videoScreenRect,
                                            m_videoScreenRect));
        }

        if (KErrNone != err) {
            TRACE("SetDisplayWindowL err %d", err);
            setError(tr("Video display error"), err);
        } else {
            m_dsaActive = true;
            if (parameters & ScaleFactors) {
                TRAP(err, m_player->SetScaleFactorL(m_scaleWidth, m_scaleHeight,
                                                    antialias));
                if (KErrNone != err) {
                    TRACE("SetScaleFactorL (2) err %d", err);
                    setError(tr("Video display error"), err);
                }
            }
        }
    }

    TRACE_EXIT_0();
}

void MMF::DsaVideoPlayer::startDirectScreenAccess()
{
    if (!m_dsaActive) {
        TRAPD(err, m_player->StartDirectScreenAccessL());
        if (KErrNone == err)
            m_dsaActive = true;
        else
            setError(tr("Video display error"), err);
    }
}

bool MMF::DsaVideoPlayer::stopDirectScreenAccess()
{
    const bool dsaWasActive = m_dsaActive;
    if (m_dsaActive) {
        TRAPD(err, m_player->StopDirectScreenAccessL());
        if (KErrNone == err)
            m_dsaActive = false;
        else
            setError(tr("Video display error"), err);
    }
    return dsaWasActive;
}

QT_END_NAMESPACE

<|endoftext|>


<commit_before>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <af/dim4.hpp>
#include <af/defines.h>
#include <ArrayInfo.hpp>
#include <Array.hpp>
#include <copy.hpp>
#include <fft.hpp>
#include <err_opencl.hpp>
#include <clFFT.h>
#include <math.hpp>
#include <string>
#include <cstdio>

using af::dim4;
using std::string;

namespace opencl
{

#define CLFFT_ERROR_CHECK(call) do {            \
    clfftStatus err = (call);                   \
    if (err!=CLFFT_SUCCESS)                     \
        AF_ERROR("clFFT library call failed",   \
                 AF_ERR_INTERNAL);              \
    } while(0);

// clFFTPlanner will do very basic plan caching.
// it looks for required candidate in mHandles array and returns if found one.
// otherwise, it will create a plan and set it at the mAvailSlotIndex and increment
// the slot index variable in ciruclar fashion 0 to MAX_PLAN_CACHE, then back to zero and repeat.
class clFFTPlanner
{
    friend void find_clfft_plan(clfftPlanHandle &plan,
                                clfftDim rank, size_t *clLengths,
                                size_t *istrides, size_t idist,
                                size_t *ostrides, size_t odist,
                                clfftPrecision precision, size_t batch);

    public:
        static clFFTPlanner& getInstance() {
            static clFFTPlanner single_instance;
            return single_instance;
        }

        ~clFFTPlanner() {
            clfftTeardown();
        }

    private:
        clFFTPlanner() : mAvailSlotIndex(0) {
            clfftInitSetupData(&fftSetup);
            clfftSetup(&fftSetup);
            for(int p=0; p<MAX_PLAN_CACHE; ++p)
                mHandles[p] = 0;
        }
        clFFTPlanner(clFFTPlanner const&);
        void operator=(clFFTPlanner const&);

        static const int MAX_PLAN_CACHE = 5;

        int          mAvailSlotIndex;
        string mKeys[MAX_PLAN_CACHE];

        clfftPlanHandle mHandles[MAX_PLAN_CACHE];

        clfftSetupData  fftSetup;
};

void find_clfft_plan(clfftPlanHandle &plan,
                     clfftDim rank, size_t *clLengths,
                     size_t *istrides, size_t idist,
                     size_t *ostrides, size_t odist,
                     clfftPrecision precision, size_t batch)
{
    clFFTPlanner &planner = clFFTPlanner::getInstance();

    // create the key string
    char key_str_temp[64];
    sprintf(key_str_temp, "%d:", rank);

    string key_string(key_str_temp);

    for(int r=0; r<rank; ++r) {
        sprintf(key_str_temp, "%zu:", clLengths[r]);
        key_string.append(std::string(key_str_temp));
    }

    if(istrides!=NULL) {
        for(int r=0; r<rank; ++r) {
            sprintf(key_str_temp, "%zu:", istrides[r]);
            key_string.append(std::string(key_str_temp));
        }
        sprintf(key_str_temp, "%zu:", idist);
        key_string.append(std::string(key_str_temp));
    }

    if (ostrides!=NULL) {
        for(int r=0; r<rank; ++r) {
            sprintf(key_str_temp, "%zu:", ostrides[r]);
            key_string.append(std::string(key_str_temp));
        }
        sprintf(key_str_temp, "%zu:", odist);
        key_string.append(std::string(key_str_temp));
    }

    sprintf(key_str_temp, "%d:%zu", (int)precision, batch);
    key_string.append(std::string(key_str_temp));

    // find the matching plan_index in the array clFFTPlanner::mKeys
    int plan_index = -1;
    for (int i=0; i<clFFTPlanner::MAX_PLAN_CACHE; ++i) {
        if (key_string==planner.mKeys[i]) {
            plan_index = i;
            break;
        }
    }

    // return mHandles[plan_index] if plan_index valid
    if (plan_index!=-1) {
        plan = planner.mHandles[plan_index];
        return;
    }

    // otherwise create a new plan and set it at mAvailSlotIndex
    // and finally set it to output plan variable
    int slot_index = planner.mAvailSlotIndex;

    clfftStatus res = CLFFT_SUCCESS;

    if (planner.mHandles[slot_index]) {
        res = clfftDestroyPlan(&planner.mHandles[slot_index]);
        planner.mHandles[slot_index] = 0;
    }

    if (res==CLFFT_SUCCESS) {
        clfftPlanHandle temp;

        // getContext() returns object of type Context
        // Context() returns the actual cl_context handle
        clfftStatus res = clfftCreateDefaultPlan(&temp, getContext()(), rank, clLengths);

        switch(res) {
            case CLFFT_INVALID_CONTEXT   : AF_ERROR("clFFT: invalid context   ", AF_ERR_INTERNAL);
            case CLFFT_INVALID_PLATFORM  : AF_ERROR("clFFT: invalid platform  ", AF_ERR_INTERNAL);
            case CLFFT_OUT_OF_HOST_MEMORY: AF_ERROR("clFFT: out of host memory", AF_ERR_INTERNAL);
            case CLFFT_OUT_OF_RESOURCES  : AF_ERROR("clFFT: out of resources  ", AF_ERR_INTERNAL);
            case CLFFT_MEM_OBJECT_ALLOCATION_FAILURE:
                                           AF_ERROR("clFFT: mem object allocation failure", AF_ERR_INTERNAL);
            case CLFFT_NOTIMPLEMENTED    : AF_ERROR("clFFt: feature not implemented", AF_ERR_INTERNAL);
            case CLFFT_SUCCESS:
                {
                    res = clfftSetLayout(temp, CLFFT_COMPLEX_INTERLEAVED, CLFFT_COMPLEX_INTERLEAVED);
                    res = clfftSetPlanBatchSize(temp, batch);
                    res = clfftSetPlanDistance(temp, idist, odist);
                    res = clfftSetPlanInStride(temp, rank, istrides);
                    res = clfftSetPlanOutStride(temp, rank, ostrides);
                    res = clfftSetPlanPrecision(temp, precision);
                    res = clfftSetResultLocation(temp, CLFFT_INPLACE);

                    // getQueue() returns object of type CommandQueue
                    // CommandQueue() returns the actual cl_command_queue handle
                    res = clfftBakePlan(temp, 1, &(getQueue()()), NULL, NULL);

                    plan = temp;
                    planner.mHandles[slot_index] = temp;
                    planner.mKeys[slot_index] = key_string;
                    planner.mAvailSlotIndex = (slot_index + 1)%clFFTPlanner::MAX_PLAN_CACHE;
                }
                break;
            default: AF_ERROR("clFFT: unkown error", AF_ERR_INTERNAL);
        }
    } else
        AF_ERROR("clFFTDestroyPlan call failed", AF_ERR_INTERNAL);
}

template<typename T> struct Precision;
template<> struct Precision<cfloat > { enum {type = CLFFT_SINGLE}; };
template<> struct Precision<cdouble> { enum {type = CLFFT_DOUBLE}; };

template<typename T, int rank, clfftDirection direction>
void clfft_common(Array<T> &arr)
{
    const dim4 dims    = arr.dims();
    const dim4 strides = arr.strides();
    size_t io_strides[]= {(size_t)strides[0],
                          (size_t)strides[1],
                          (size_t)strides[2],
                          (size_t)strides[3]};

    size_t rank_dims[3] = {(size_t)dims[0], (size_t)dims[1], (size_t)dims[2]};

    clfftPlanHandle plan;

    find_clfft_plan(plan, (clfftDim)rank, rank_dims,
                    io_strides, io_strides[rank],
                    io_strides, io_strides[rank],
                    (clfftPrecision)Precision<T>::type,
                    dims[rank]);

    CLFFT_ERROR_CHECK( clfftEnqueueTransform(plan, direction, 1, &(getQueue()()), 0, NULL, NULL, &((*arr.get())()), NULL, NULL) );
}

template<int rank>
void computePaddedDims(dim4 &pdims, dim_type const * const pad)
{
    if (rank==1) {
        pdims[0] = pad[0];
    } else if (rank==2) {
        pdims[0] = pad[0];
        pdims[1] = pad[1];
    } else if (rank==3) {
        pdims[0] = pad[0];
        pdims[1] = pad[1];
        pdims[2] = pad[2];
    }
}

//(currently) true is in clFFT if length is a power of 2,3,5
inline bool isSupLen(dim_type length)
{
    while( length > 1 )
    {
        if( length % 2 == 0 )
            length /= 2;
        else if( length % 3 == 0 )
            length /= 3;
        else if( length % 5 == 0 )
            length /= 5;
        else
            return false;
    }
    return true;
}

template<typename inType, typename outType, int rank, bool isR2C>
Array<outType> fft(Array<inType> const &in, double norm_factor, dim_type const npad, dim_type const * const pad)
{
    ARG_ASSERT(1, (in.isOwner()==true));
    ARG_ASSERT(1, (rank>=1 && rank<=3));

    dim4 dims = in.dims();

    dim4 pdims(1);
    computePaddedDims<rank>(pdims, pad);
    pdims[rank] = in.dims()[rank];

    if (npad>0)
      dims = pdims;

    switch(rank) {
        case 1 : ARG_ASSERT(1, (isSupLen(dims[0]))); break;
        case 2 : ARG_ASSERT(2, ((isSupLen(dims[0]) || isSupLen(dims[1])))); break;
        case 3 : ARG_ASSERT(3, ((isSupLen(dims[0]) || isSupLen(dims[1]) || isSupLen(dims[2])))); break;
        default: AF_ERROR("invalid input dimensions", AF_ERR_SIZE);
    }

    Array<outType> ret = padArray<inType, outType>(in, dims, scalar<outType>(0), norm_factor);

    clfft_common<outType, rank, CLFFT_FORWARD>(ret);

    return ret;
}

template<typename T, int rank>
Array<T> ifft(Array<T> const &in, double norm_factor, dim_type const npad, dim_type const * const pad)
{
    ARG_ASSERT(1, (in.isOwner()==true));
    ARG_ASSERT(1, (rank>=1 && rank<=3));

    dim4 dims = in.dims();

    dim4 pdims(1);
    computePaddedDims<rank>(pdims, pad);
    pdims[rank] = in.dims()[rank];

    if (npad>0)
      dims = pdims;

    // the input norm_factor is further scaled
    // based on the input dimensions to match
    // cuFFT behavior
    for (int i=0; i<rank; i++)
        norm_factor *= dims[i];

    switch(rank) {
        case 1 : ARG_ASSERT(1, (isSupLen(dims[0]))); break;
        case 2 : ARG_ASSERT(2, ((isSupLen(dims[0]) || isSupLen(dims[1])))); break;
        case 3 : ARG_ASSERT(3, ((isSupLen(dims[0]) || isSupLen(dims[1]) || isSupLen(dims[2])))); break;
        default: AF_ERROR("invalid input dimensions", AF_ERR_SIZE);
    }

    Array<T> ret = padArray<T, T>(in, dims, scalar<T>(0), norm_factor);

    clfft_common<T, rank, CLFFT_BACKWARD>(ret);

    return ret;
}

#define INSTANTIATE1(T1, T2)\
    template Array<T2> fft <T1, T2, 1, true >(const Array<T1> &in, double norm_factor, dim_type const npad, dim_type const * const pad); \
    template Array<T2> fft <T1, T2, 2, true >(const Array<T1> &in, double norm_factor, dim_type const npad, dim_type const * const pad); \
    template Array<T2> fft <T1, T2, 3, true >(const Array<T1> &in, double norm_factor, dim_type const npad, dim_type const * const pad);

INSTANTIATE1(float  , cfloat )
INSTANTIATE1(double , cdouble)

#define INSTANTIATE2(T)\
    template Array<T> fft <T, T, 1, false>(const Array<T> &in, double norm_factor, dim_type const npad, dim_type const * const pad); \
    template Array<T> fft <T, T, 2, false>(const Array<T> &in, double norm_factor, dim_type const npad, dim_type const * const pad); \
    template Array<T> fft <T, T, 3, false>(const Array<T> &in, double norm_factor, dim_type const npad, dim_type const * const pad); \
    template Array<T> ifft<T, 1>(const Array<T> &in, double norm_factor, dim_type const npad, dim_type const * const pad); \
    template Array<T> ifft<T, 2>(const Array<T> &in, double norm_factor, dim_type const npad, dim_type const * const pad); \
    template Array<T> ifft<T, 3>(const Array<T> &in, double norm_factor, dim_type const npad, dim_type const * const pad);

INSTANTIATE2(cfloat )
INSTANTIATE2(cdouble)

}
<commit_msg>Call garbageCollect() when CLFFT plan creation fails and try again<commit_after>/*******************************************************
 * Copyright (c) 2014, ArrayFire
 * All rights reserved.
 *
 * This file is distributed under 3-clause BSD license.
 * The complete license agreement can be obtained at:
 * http://arrayfire.com/licenses/BSD-3-Clause
 ********************************************************/

#include <af/dim4.hpp>
#include <af/defines.h>
#include <ArrayInfo.hpp>
#include <Array.hpp>
#include <copy.hpp>
#include <fft.hpp>
#include <err_opencl.hpp>
#include <clFFT.h>
#include <math.hpp>
#include <string>
#include <cstdio>
#include <memory.hpp>

using af::dim4;
using std::string;

namespace opencl
{

static void CLFFT_ERROR(clfftStatus err)
{
    switch(err) {
    case CLFFT_INVALID_CONTEXT   : AF_ERROR("clFFT: invalid context   ", AF_ERR_INTERNAL);
    case CLFFT_INVALID_PLATFORM  : AF_ERROR("clFFT: invalid platform  ", AF_ERR_INTERNAL);
    case CLFFT_OUT_OF_HOST_MEMORY: AF_ERROR("clFFT: out of host memory", AF_ERR_INTERNAL);
    case CLFFT_OUT_OF_RESOURCES  : AF_ERROR("clFFT: out of resources  ", AF_ERR_INTERNAL);
    case CLFFT_MEM_OBJECT_ALLOCATION_FAILURE:
        AF_ERROR("clFFT: mem object allocation failure", AF_ERR_INTERNAL);
    case CLFFT_NOTIMPLEMENTED    : AF_ERROR("clFFt: feature not implemented", AF_ERR_INTERNAL);
    case CLFFT_SUCCESS: return;
    default: AF_ERROR("clFFT: unkown error", AF_ERR_INTERNAL);
    }
}

#define CLFFT_CHECK(call) do {                          \
        clfftStatus err = (call);                       \
        if (err!=CLFFT_SUCCESS) {                       \
            garbageCollect();                           \
            err = (call);                               \
        }                                               \
        if (err != CLFFT_SUCCESS)   CLFFT_ERROR(err);   \
    } while(0)

// clFFTPlanner will do very basic plan caching.
// it looks for required candidate in mHandles array and returns if found one.
// otherwise, it will create a plan and set it at the mAvailSlotIndex and increment
// the slot index variable in ciruclar fashion 0 to MAX_PLAN_CACHE, then back to zero and repeat.
class clFFTPlanner
{
    friend void find_clfft_plan(clfftPlanHandle &plan,
                                clfftDim rank, size_t *clLengths,
                                size_t *istrides, size_t idist,
                                size_t *ostrides, size_t odist,
                                clfftPrecision precision, size_t batch);

    public:
        static clFFTPlanner& getInstance() {
            static clFFTPlanner single_instance;
            return single_instance;
        }

        ~clFFTPlanner() {
            clfftTeardown();
        }

    private:
        clFFTPlanner() : mAvailSlotIndex(0) {
            clfftInitSetupData(&fftSetup);
            clfftSetup(&fftSetup);
            for(int p=0; p<MAX_PLAN_CACHE; ++p)
                mHandles[p] = 0;
        }
        clFFTPlanner(clFFTPlanner const&);
        void operator=(clFFTPlanner const&);

        static const int MAX_PLAN_CACHE = 5;

        int          mAvailSlotIndex;
        string mKeys[MAX_PLAN_CACHE];

        clfftPlanHandle mHandles[MAX_PLAN_CACHE];

        clfftSetupData  fftSetup;
};

void find_clfft_plan(clfftPlanHandle &plan,
                     clfftDim rank, size_t *clLengths,
                     size_t *istrides, size_t idist,
                     size_t *ostrides, size_t odist,
                     clfftPrecision precision, size_t batch)
{
    clFFTPlanner &planner = clFFTPlanner::getInstance();

    // create the key string
    char key_str_temp[64];
    sprintf(key_str_temp, "%d:", rank);

    string key_string(key_str_temp);

    for(int r=0; r<rank; ++r) {
        sprintf(key_str_temp, "%zu:", clLengths[r]);
        key_string.append(std::string(key_str_temp));
    }

    if(istrides!=NULL) {
        for(int r=0; r<rank; ++r) {
            sprintf(key_str_temp, "%zu:", istrides[r]);
            key_string.append(std::string(key_str_temp));
        }
        sprintf(key_str_temp, "%zu:", idist);
        key_string.append(std::string(key_str_temp));
    }

    if (ostrides!=NULL) {
        for(int r=0; r<rank; ++r) {
            sprintf(key_str_temp, "%zu:", ostrides[r]);
            key_string.append(std::string(key_str_temp));
        }
        sprintf(key_str_temp, "%zu:", odist);
        key_string.append(std::string(key_str_temp));
    }

    sprintf(key_str_temp, "%d:%zu", (int)precision, batch);
    key_string.append(std::string(key_str_temp));

    // find the matching plan_index in the array clFFTPlanner::mKeys
    int plan_index = -1;
    for (int i=0; i<clFFTPlanner::MAX_PLAN_CACHE; ++i) {
        if (key_string==planner.mKeys[i]) {
            plan_index = i;
            break;
        }
    }

    // return mHandles[plan_index] if plan_index valid
    if (plan_index!=-1) {
        plan = planner.mHandles[plan_index];
        return;
    }

    // otherwise create a new plan and set it at mAvailSlotIndex
    // and finally set it to output plan variable
    int slot_index = planner.mAvailSlotIndex;

    if (planner.mHandles[slot_index]) {
        CLFFT_CHECK(clfftDestroyPlan(&planner.mHandles[slot_index]));
        planner.mHandles[slot_index] = 0;
    }

    clfftPlanHandle temp;

    // getContext() returns object of type Context
    // Context() returns the actual cl_context handle
    CLFFT_CHECK(clfftCreateDefaultPlan(&temp, getContext()(), rank, clLengths));

    CLFFT_CHECK(clfftSetLayout(temp, CLFFT_COMPLEX_INTERLEAVED, CLFFT_COMPLEX_INTERLEAVED));
    CLFFT_CHECK(clfftSetPlanBatchSize(temp, batch));
    CLFFT_CHECK(clfftSetPlanDistance(temp, idist, odist));
    CLFFT_CHECK(clfftSetPlanInStride(temp, rank, istrides));
    CLFFT_CHECK(clfftSetPlanOutStride(temp, rank, ostrides));
    CLFFT_CHECK(clfftSetPlanPrecision(temp, precision));
    CLFFT_CHECK(clfftSetResultLocation(temp, CLFFT_INPLACE));

    // getQueue() returns object of type CommandQueue
    // CommandQueue() returns the actual cl_command_queue handle
    CLFFT_CHECK(clfftBakePlan(temp, 1, &(getQueue()()), NULL, NULL));

    plan = temp;
    planner.mHandles[slot_index] = temp;
    planner.mKeys[slot_index] = key_string;
    planner.mAvailSlotIndex = (slot_index + 1)%clFFTPlanner::MAX_PLAN_CACHE;
}

template<typename T> struct Precision;
template<> struct Precision<cfloat > { enum {type = CLFFT_SINGLE}; };
template<> struct Precision<cdouble> { enum {type = CLFFT_DOUBLE}; };

template<typename T, int rank, clfftDirection direction>
void clfft_common(Array<T> &arr)
{
    const dim4 dims    = arr.dims();
    const dim4 strides = arr.strides();
    size_t io_strides[]= {(size_t)strides[0],
                          (size_t)strides[1],
                          (size_t)strides[2],
                          (size_t)strides[3]};

    size_t rank_dims[3] = {(size_t)dims[0], (size_t)dims[1], (size_t)dims[2]};

    clfftPlanHandle plan;

    find_clfft_plan(plan, (clfftDim)rank, rank_dims,
                    io_strides, io_strides[rank],
                    io_strides, io_strides[rank],
                    (clfftPrecision)Precision<T>::type,
                    dims[rank]);

    CLFFT_CHECK( clfftEnqueueTransform(plan, direction, 1, &(getQueue()()), 0, NULL, NULL, &((*arr.get())()), NULL, NULL) );
}

template<int rank>
void computePaddedDims(dim4 &pdims, dim_type const * const pad)
{
    if (rank==1) {
        pdims[0] = pad[0];
    } else if (rank==2) {
        pdims[0] = pad[0];
        pdims[1] = pad[1];
    } else if (rank==3) {
        pdims[0] = pad[0];
        pdims[1] = pad[1];
        pdims[2] = pad[2];
    }
}

//(currently) true is in clFFT if length is a power of 2,3,5
inline bool isSupLen(dim_type length)
{
    while( length > 1 )
    {
        if( length % 2 == 0 )
            length /= 2;
        else if( length % 3 == 0 )
            length /= 3;
        else if( length % 5 == 0 )
            length /= 5;
        else
            return false;
    }
    return true;
}

template<typename inType, typename outType, int rank, bool isR2C>
Array<outType> fft(Array<inType> const &in, double norm_factor, dim_type const npad, dim_type const * const pad)
{
    ARG_ASSERT(1, (in.isOwner()==true));
    ARG_ASSERT(1, (rank>=1 && rank<=3));

    dim4 dims = in.dims();

    dim4 pdims(1);
    computePaddedDims<rank>(pdims, pad);
    pdims[rank] = in.dims()[rank];

    if (npad>0)
      dims = pdims;

    switch(rank) {
        case 1 : ARG_ASSERT(1, (isSupLen(dims[0]))); break;
        case 2 : ARG_ASSERT(2, ((isSupLen(dims[0]) || isSupLen(dims[1])))); break;
        case 3 : ARG_ASSERT(3, ((isSupLen(dims[0]) || isSupLen(dims[1]) || isSupLen(dims[2])))); break;
        default: AF_ERROR("invalid input dimensions", AF_ERR_SIZE);
    }

    Array<outType> ret = padArray<inType, outType>(in, dims, scalar<outType>(0), norm_factor);

    clfft_common<outType, rank, CLFFT_FORWARD>(ret);

    return ret;
}

template<typename T, int rank>
Array<T> ifft(Array<T> const &in, double norm_factor, dim_type const npad, dim_type const * const pad)
{
    ARG_ASSERT(1, (in.isOwner()==true));
    ARG_ASSERT(1, (rank>=1 && rank<=3));

    dim4 dims = in.dims();

    dim4 pdims(1);
    computePaddedDims<rank>(pdims, pad);
    pdims[rank] = in.dims()[rank];

    if (npad>0)
      dims = pdims;

    // the input norm_factor is further scaled
    // based on the input dimensions to match
    // cuFFT behavior
    for (int i=0; i<rank; i++)
        norm_factor *= dims[i];

    switch(rank) {
        case 1 : ARG_ASSERT(1, (isSupLen(dims[0]))); break;
        case 2 : ARG_ASSERT(2, ((isSupLen(dims[0]) || isSupLen(dims[1])))); break;
        case 3 : ARG_ASSERT(3, ((isSupLen(dims[0]) || isSupLen(dims[1]) || isSupLen(dims[2])))); break;
        default: AF_ERROR("invalid input dimensions", AF_ERR_SIZE);
    }

    Array<T> ret = padArray<T, T>(in, dims, scalar<T>(0), norm_factor);

    clfft_common<T, rank, CLFFT_BACKWARD>(ret);

    return ret;
}

#define INSTANTIATE1(T1, T2)\
    template Array<T2> fft <T1, T2, 1, true >(const Array<T1> &in, double norm_factor, dim_type const npad, dim_type const * const pad); \
    template Array<T2> fft <T1, T2, 2, true >(const Array<T1> &in, double norm_factor, dim_type const npad, dim_type const * const pad); \
    template Array<T2> fft <T1, T2, 3, true >(const Array<T1> &in, double norm_factor, dim_type const npad, dim_type const * const pad);

INSTANTIATE1(float  , cfloat )
INSTANTIATE1(double , cdouble)

#define INSTANTIATE2(T)\
    template Array<T> fft <T, T, 1, false>(const Array<T> &in, double norm_factor, dim_type const npad, dim_type const * const pad); \
    template Array<T> fft <T, T, 2, false>(const Array<T> &in, double norm_factor, dim_type const npad, dim_type const * const pad); \
    template Array<T> fft <T, T, 3, false>(const Array<T> &in, double norm_factor, dim_type const npad, dim_type const * const pad); \
    template Array<T> ifft<T, 1>(const Array<T> &in, double norm_factor, dim_type const npad, dim_type const * const pad); \
    template Array<T> ifft<T, 2>(const Array<T> &in, double norm_factor, dim_type const npad, dim_type const * const pad); \
    template Array<T> ifft<T, 3>(const Array<T> &in, double norm_factor, dim_type const npad, dim_type const * const pad);

INSTANTIATE2(cfloat )
INSTANTIATE2(cdouble)

}
<|endoftext|>


<commit_before>#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <babylon/babylon_stl_util.h>
#include <babylon/engines/null_engine.h>
#include <babylon/engines/scene.h>
#include <babylon/meshes/buffer.h>
#include <babylon/meshes/geometry.h>
#include <babylon/meshes/vertex_buffer.h>

std::unique_ptr<BABYLON::Engine> createSubject()
{
  using namespace BABYLON;
  NullEngineOptions options;
  options.renderHeight          = 256;
  options.renderWidth           = 256;
  options.textureSize           = 256;
  options.deterministicLockstep = false;
  options.lockstepMaxSteps      = 1;
  return NullEngine::New(options);
}

TEST(TestGeometry, TestVec3FloatColor)
{
  using namespace BABYLON;
  // vec3 float color tightly packed
  auto subject = createSubject();
  auto scene   = Scene::New(subject.get());
  Float32Array data{0.4f, 0.4f, 0.4f, 0.6f, 0.6f, 0.6f,
                    0.8f, 0.8f, 0.8f, 1.f,  1.f,  1.f};
  auto buffer       = std::make_unique<Buffer>(subject.get(), data, false);
  auto vertexBuffer = std::make_shared<VertexBuffer>(
    subject.get(), buffer.get(), VertexBuffer::ColorKind, false, std::nullopt,
    std::nullopt, std::nullopt, std::nullopt, 3);

  auto geometry = Geometry::New("geometry1", scene.get());
  geometry->setVerticesBuffer(vertexBuffer);
  IndicesArray indices{0u, 1u, 2u, 3u};
  geometry->setIndices(indices, 4);

  auto result = geometry->getVerticesData(VertexBuffer::ColorKind);
  EXPECT_THAT(result, ::testing::ContainerEq(data));
}
<commit_msg>Updated Geometry unit test name<commit_after>#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include <babylon/babylon_stl_util.h>
#include <babylon/engines/null_engine.h>
#include <babylon/engines/scene.h>
#include <babylon/meshes/buffer.h>
#include <babylon/meshes/geometry.h>
#include <babylon/meshes/vertex_buffer.h>

/**
 * @brief Create a new engine subject before each test.
 */
std::unique_ptr<BABYLON::Engine> createSubject()
{
  using namespace BABYLON;
  NullEngineOptions options;
  options.renderHeight          = 256;
  options.renderWidth           = 256;
  options.textureSize           = 256;
  options.deterministicLockstep = false;
  options.lockstepMaxSteps      = 1;
  return NullEngine::New(options);
}

TEST(TestGeometry, TestGetVerticesData_Vec3FloatColor)
{
  using namespace BABYLON;
  // vec3 float color tightly packed
  auto subject = createSubject();
  auto scene   = Scene::New(subject.get());
  Float32Array data{0.4f, 0.4f, 0.4f, 0.6f, 0.6f, 0.6f,
                    0.8f, 0.8f, 0.8f, 1.f,  1.f,  1.f};
  auto buffer       = std::make_unique<Buffer>(subject.get(), data, false);
  auto vertexBuffer = std::make_shared<VertexBuffer>(
    subject.get(), buffer.get(), VertexBuffer::ColorKind, false, std::nullopt,
    std::nullopt, std::nullopt, std::nullopt, 3);

  auto geometry = Geometry::New("geometry1", scene.get());
  geometry->setVerticesBuffer(vertexBuffer);
  IndicesArray indices{0u, 1u, 2u, 3u};
  geometry->setIndices(indices, 4);

  auto result = geometry->getVerticesData(VertexBuffer::ColorKind);
  EXPECT_THAT(result, ::testing::ContainerEq(data));
}
<|endoftext|>


<commit_before>/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBitmap.h"
#include "SkErrorInternals.h"
#include "SkValidatingReadBuffer.h"
#include "SkStream.h"
#include "SkTypeface.h"

SkValidatingReadBuffer::SkValidatingReadBuffer(const void* data, size_t size) :
    fError(false) {
    this->setMemory(data, size);
    this->setFlags(SkReadBuffer::kValidation_Flag);
}

SkValidatingReadBuffer::~SkValidatingReadBuffer() {
}

bool SkValidatingReadBuffer::validate(bool isValid) {
    if (!fError && !isValid) {
        // When an error is found, send the read cursor to the end of the stream
        fReader.skip(fReader.available());
        fError = true;
    }
    return !fError;
}

bool SkValidatingReadBuffer::isValid() const {
    return !fError;
}

void SkValidatingReadBuffer::setMemory(const void* data, size_t size) {
    this->validate(IsPtrAlign4(data) && (SkAlign4(size) == size));
    if (!fError) {
        fReader.setMemory(data, size);
    }
}

const void* SkValidatingReadBuffer::skip(size_t size) {
    size_t inc = SkAlign4(size);
    const void* addr = fReader.peek();
    this->validate(IsPtrAlign4(addr) && fReader.isAvailable(inc));
    if (!fError) {
        fReader.skip(size);
    }
    return addr;
}

// All the methods in this file funnel down into either readInt(), readScalar() or skip(),
// followed by a memcpy. So we've got all our validation in readInt(), readScalar() and skip();
// if they fail they'll return a zero value or skip nothing, respectively, and set fError to
// true, which the caller should check to see if an error occurred during the read operation.

bool SkValidatingReadBuffer::readBool() {
    uint32_t value = this->readInt();
    // Boolean value should be either 0 or 1
    this->validate(!(value & ~1));
    return value != 0;
}

SkColor SkValidatingReadBuffer::readColor() {
    return this->readInt();
}

SkFixed SkValidatingReadBuffer::readFixed() {
    return this->readInt();
}

int32_t SkValidatingReadBuffer::readInt() {
    const size_t inc = sizeof(int32_t);
    this->validate(IsPtrAlign4(fReader.peek()) && fReader.isAvailable(inc));
    return fError ? 0 : fReader.readInt();
}

SkScalar SkValidatingReadBuffer::readScalar() {
    const size_t inc = sizeof(SkScalar);
    this->validate(IsPtrAlign4(fReader.peek()) && fReader.isAvailable(inc));
    return fError ? 0 : fReader.readScalar();
}

uint32_t SkValidatingReadBuffer::readUInt() {
    return this->readInt();
}

int32_t SkValidatingReadBuffer::read32() {
    return this->readInt();
}

void SkValidatingReadBuffer::readString(SkString* string) {
    const size_t len = this->readUInt();
    const void* ptr = fReader.peek();
    const char* cptr = (const char*)ptr;

    // skip over the string + '\0' and then pad to a multiple of 4
    const size_t alignedSize = SkAlign4(len + 1);
    this->skip(alignedSize);
    if (!fError) {
        this->validate(cptr[len] == '\0');
    }
    if (!fError) {
        string->set(cptr, len);
    }
}

void* SkValidatingReadBuffer::readEncodedString(size_t* length, SkPaint::TextEncoding encoding) {
    const int32_t encodingType = this->readInt();
    this->validate(encodingType == encoding);
    *length = this->readInt();
    const void* ptr = this->skip(SkAlign4(*length));
    void* data = nullptr;
    if (!fError) {
        data = sk_malloc_throw(*length);
        memcpy(data, ptr, *length);
    }
    return data;
}

void SkValidatingReadBuffer::readPoint(SkPoint* point) {
    point->fX = this->readScalar();
    point->fY = this->readScalar();
}

void SkValidatingReadBuffer::readMatrix(SkMatrix* matrix) {
    size_t size = 0;
    if (!fError) {
        size = matrix->readFromMemory(fReader.peek(), fReader.available());
        this->validate((SkAlign4(size) == size) && (0 != size));
    }
    if (!fError) {
        (void)this->skip(size);
    }
}

void SkValidatingReadBuffer::readIRect(SkIRect* rect) {
    const void* ptr = this->skip(sizeof(SkIRect));
    if (!fError) {
        memcpy(rect, ptr, sizeof(SkIRect));
    }
}

void SkValidatingReadBuffer::readRect(SkRect* rect) {
    const void* ptr = this->skip(sizeof(SkRect));
    if (!fError) {
        memcpy(rect, ptr, sizeof(SkRect));
    }
}

void SkValidatingReadBuffer::readRegion(SkRegion* region) {
    size_t size = 0;
    if (!fError) {
        size = region->readFromMemory(fReader.peek(), fReader.available());
        this->validate((SkAlign4(size) == size) && (0 != size));
    }
    if (!fError) {
        (void)this->skip(size);
    }
}

void SkValidatingReadBuffer::readPath(SkPath* path) {
    size_t size = 0;
    if (!fError) {
        size = path->readFromMemory(fReader.peek(), fReader.available());
        this->validate((SkAlign4(size) == size) && (0 != size));
    }
    if (!fError) {
        (void)this->skip(size);
    }
}

bool SkValidatingReadBuffer::readArray(void* value, size_t size, size_t elementSize) {
    const uint32_t count = this->getArrayCount();
    this->validate(size == count);
    (void)this->skip(sizeof(uint32_t)); // Skip array count
    const uint64_t byteLength64 = sk_64_mul(count, elementSize);
    const size_t byteLength = count * elementSize;
    this->validate(byteLength == byteLength64);
    const void* ptr = this->skip(SkAlign4(byteLength));
    if (!fError) {
        memcpy(value, ptr, byteLength);
        return true;
    }
    return false;
}

bool SkValidatingReadBuffer::readByteArray(void* value, size_t size) {
    return readArray(static_cast<unsigned char*>(value), size, sizeof(unsigned char));
}

bool SkValidatingReadBuffer::readColorArray(SkColor* colors, size_t size) {
    return readArray(colors, size, sizeof(SkColor));
}

bool SkValidatingReadBuffer::readIntArray(int32_t* values, size_t size) {
    return readArray(values, size, sizeof(int32_t));
}

bool SkValidatingReadBuffer::readPointArray(SkPoint* points, size_t size) {
    return readArray(points, size, sizeof(SkPoint));
}

bool SkValidatingReadBuffer::readScalarArray(SkScalar* values, size_t size) {
    return readArray(values, size, sizeof(SkScalar));
}

uint32_t SkValidatingReadBuffer::getArrayCount() {
    const size_t inc = sizeof(uint32_t);
    fError = fError || !IsPtrAlign4(fReader.peek()) || !fReader.isAvailable(inc);
    return fError ? 0 : *(uint32_t*)fReader.peek();
}

SkTypeface* SkValidatingReadBuffer::readTypeface() {
    // TODO: Implement this (securely) when needed
    return nullptr;
}

bool SkValidatingReadBuffer::validateAvailable(size_t size) {
    return this->validate((size <= SK_MaxU32) && fReader.isAvailable(static_cast<uint32_t>(size)));
}

SkFlattenable* SkValidatingReadBuffer::readFlattenable(SkFlattenable::Type type) {
    SkString name;
    this->readString(&name);
    if (fError) {
        return nullptr;
    }

    // Is this the type we wanted ?
    const char* cname = name.c_str();
    SkFlattenable::Type baseType;
    if (!SkFlattenable::NameToType(cname, &baseType) || (baseType != type)) {
        return nullptr;
    }

    SkFlattenable::Factory factory = SkFlattenable::NameToFactory(cname);
    if (nullptr == factory) {
        return nullptr; // writer failed to give us the flattenable
    }

    // if we get here, factory may still be null, but if that is the case, the
    // failure was ours, not the writer.
    SkFlattenable* obj = nullptr;
    uint32_t sizeRecorded = this->readUInt();
    if (factory) {
        size_t offset = fReader.offset();
        obj = (*factory)(*this);
        // check that we read the amount we expected
        size_t sizeRead = fReader.offset() - offset;
        this->validate(sizeRecorded == sizeRead);
        if (fError) {
            // we could try to fix up the offset...
            SkSafeUnref(obj);
            obj = nullptr;
        }
    } else {
        // we must skip the remaining data
        this->skip(sizeRecorded);
        SkASSERT(false);
    }
    return obj;
}

void SkValidatingReadBuffer::skipFlattenable() {
    SkString name;
    this->readString(&name);
    if (fError) {
        return;
    }
    uint32_t sizeRecorded = this->readUInt();
    this->skip(sizeRecorded);
}
<commit_msg>SkValidatingReadBuffer: make sure we don't call readTypeface().<commit_after>/*
 * Copyright 2013 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkBitmap.h"
#include "SkErrorInternals.h"
#include "SkValidatingReadBuffer.h"
#include "SkStream.h"
#include "SkTypeface.h"

SkValidatingReadBuffer::SkValidatingReadBuffer(const void* data, size_t size) :
    fError(false) {
    this->setMemory(data, size);
    this->setFlags(SkReadBuffer::kValidation_Flag);
}

SkValidatingReadBuffer::~SkValidatingReadBuffer() {
}

bool SkValidatingReadBuffer::validate(bool isValid) {
    if (!fError && !isValid) {
        // When an error is found, send the read cursor to the end of the stream
        fReader.skip(fReader.available());
        fError = true;
    }
    return !fError;
}

bool SkValidatingReadBuffer::isValid() const {
    return !fError;
}

void SkValidatingReadBuffer::setMemory(const void* data, size_t size) {
    this->validate(IsPtrAlign4(data) && (SkAlign4(size) == size));
    if (!fError) {
        fReader.setMemory(data, size);
    }
}

const void* SkValidatingReadBuffer::skip(size_t size) {
    size_t inc = SkAlign4(size);
    const void* addr = fReader.peek();
    this->validate(IsPtrAlign4(addr) && fReader.isAvailable(inc));
    if (!fError) {
        fReader.skip(size);
    }
    return addr;
}

// All the methods in this file funnel down into either readInt(), readScalar() or skip(),
// followed by a memcpy. So we've got all our validation in readInt(), readScalar() and skip();
// if they fail they'll return a zero value or skip nothing, respectively, and set fError to
// true, which the caller should check to see if an error occurred during the read operation.

bool SkValidatingReadBuffer::readBool() {
    uint32_t value = this->readInt();
    // Boolean value should be either 0 or 1
    this->validate(!(value & ~1));
    return value != 0;
}

SkColor SkValidatingReadBuffer::readColor() {
    return this->readInt();
}

SkFixed SkValidatingReadBuffer::readFixed() {
    return this->readInt();
}

int32_t SkValidatingReadBuffer::readInt() {
    const size_t inc = sizeof(int32_t);
    this->validate(IsPtrAlign4(fReader.peek()) && fReader.isAvailable(inc));
    return fError ? 0 : fReader.readInt();
}

SkScalar SkValidatingReadBuffer::readScalar() {
    const size_t inc = sizeof(SkScalar);
    this->validate(IsPtrAlign4(fReader.peek()) && fReader.isAvailable(inc));
    return fError ? 0 : fReader.readScalar();
}

uint32_t SkValidatingReadBuffer::readUInt() {
    return this->readInt();
}

int32_t SkValidatingReadBuffer::read32() {
    return this->readInt();
}

void SkValidatingReadBuffer::readString(SkString* string) {
    const size_t len = this->readUInt();
    const void* ptr = fReader.peek();
    const char* cptr = (const char*)ptr;

    // skip over the string + '\0' and then pad to a multiple of 4
    const size_t alignedSize = SkAlign4(len + 1);
    this->skip(alignedSize);
    if (!fError) {
        this->validate(cptr[len] == '\0');
    }
    if (!fError) {
        string->set(cptr, len);
    }
}

void* SkValidatingReadBuffer::readEncodedString(size_t* length, SkPaint::TextEncoding encoding) {
    const int32_t encodingType = this->readInt();
    this->validate(encodingType == encoding);
    *length = this->readInt();
    const void* ptr = this->skip(SkAlign4(*length));
    void* data = nullptr;
    if (!fError) {
        data = sk_malloc_throw(*length);
        memcpy(data, ptr, *length);
    }
    return data;
}

void SkValidatingReadBuffer::readPoint(SkPoint* point) {
    point->fX = this->readScalar();
    point->fY = this->readScalar();
}

void SkValidatingReadBuffer::readMatrix(SkMatrix* matrix) {
    size_t size = 0;
    if (!fError) {
        size = matrix->readFromMemory(fReader.peek(), fReader.available());
        this->validate((SkAlign4(size) == size) && (0 != size));
    }
    if (!fError) {
        (void)this->skip(size);
    }
}

void SkValidatingReadBuffer::readIRect(SkIRect* rect) {
    const void* ptr = this->skip(sizeof(SkIRect));
    if (!fError) {
        memcpy(rect, ptr, sizeof(SkIRect));
    }
}

void SkValidatingReadBuffer::readRect(SkRect* rect) {
    const void* ptr = this->skip(sizeof(SkRect));
    if (!fError) {
        memcpy(rect, ptr, sizeof(SkRect));
    }
}

void SkValidatingReadBuffer::readRegion(SkRegion* region) {
    size_t size = 0;
    if (!fError) {
        size = region->readFromMemory(fReader.peek(), fReader.available());
        this->validate((SkAlign4(size) == size) && (0 != size));
    }
    if (!fError) {
        (void)this->skip(size);
    }
}

void SkValidatingReadBuffer::readPath(SkPath* path) {
    size_t size = 0;
    if (!fError) {
        size = path->readFromMemory(fReader.peek(), fReader.available());
        this->validate((SkAlign4(size) == size) && (0 != size));
    }
    if (!fError) {
        (void)this->skip(size);
    }
}

bool SkValidatingReadBuffer::readArray(void* value, size_t size, size_t elementSize) {
    const uint32_t count = this->getArrayCount();
    this->validate(size == count);
    (void)this->skip(sizeof(uint32_t)); // Skip array count
    const uint64_t byteLength64 = sk_64_mul(count, elementSize);
    const size_t byteLength = count * elementSize;
    this->validate(byteLength == byteLength64);
    const void* ptr = this->skip(SkAlign4(byteLength));
    if (!fError) {
        memcpy(value, ptr, byteLength);
        return true;
    }
    return false;
}

bool SkValidatingReadBuffer::readByteArray(void* value, size_t size) {
    return readArray(static_cast<unsigned char*>(value), size, sizeof(unsigned char));
}

bool SkValidatingReadBuffer::readColorArray(SkColor* colors, size_t size) {
    return readArray(colors, size, sizeof(SkColor));
}

bool SkValidatingReadBuffer::readIntArray(int32_t* values, size_t size) {
    return readArray(values, size, sizeof(int32_t));
}

bool SkValidatingReadBuffer::readPointArray(SkPoint* points, size_t size) {
    return readArray(points, size, sizeof(SkPoint));
}

bool SkValidatingReadBuffer::readScalarArray(SkScalar* values, size_t size) {
    return readArray(values, size, sizeof(SkScalar));
}

uint32_t SkValidatingReadBuffer::getArrayCount() {
    const size_t inc = sizeof(uint32_t);
    fError = fError || !IsPtrAlign4(fReader.peek()) || !fReader.isAvailable(inc);
    return fError ? 0 : *(uint32_t*)fReader.peek();
}

SkTypeface* SkValidatingReadBuffer::readTypeface() {
    SkASSERT(false);
    // TODO: Implement this (securely) when needed
    return nullptr;
}

bool SkValidatingReadBuffer::validateAvailable(size_t size) {
    return this->validate((size <= SK_MaxU32) && fReader.isAvailable(static_cast<uint32_t>(size)));
}

SkFlattenable* SkValidatingReadBuffer::readFlattenable(SkFlattenable::Type type) {
    SkString name;
    this->readString(&name);
    if (fError) {
        return nullptr;
    }

    // Is this the type we wanted ?
    const char* cname = name.c_str();
    SkFlattenable::Type baseType;
    if (!SkFlattenable::NameToType(cname, &baseType) || (baseType != type)) {
        return nullptr;
    }

    SkFlattenable::Factory factory = SkFlattenable::NameToFactory(cname);
    if (nullptr == factory) {
        return nullptr; // writer failed to give us the flattenable
    }

    // if we get here, factory may still be null, but if that is the case, the
    // failure was ours, not the writer.
    SkFlattenable* obj = nullptr;
    uint32_t sizeRecorded = this->readUInt();
    if (factory) {
        size_t offset = fReader.offset();
        obj = (*factory)(*this);
        // check that we read the amount we expected
        size_t sizeRead = fReader.offset() - offset;
        this->validate(sizeRecorded == sizeRead);
        if (fError) {
            // we could try to fix up the offset...
            SkSafeUnref(obj);
            obj = nullptr;
        }
    } else {
        // we must skip the remaining data
        this->skip(sizeRecorded);
        SkASSERT(false);
    }
    return obj;
}

void SkValidatingReadBuffer::skipFlattenable() {
    SkString name;
    this->readString(&name);
    if (fError) {
        return;
    }
    uint32_t sizeRecorded = this->readUInt();
    this->skip(sizeRecorded);
}
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2013-2015 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. 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.
 *
 * 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 <inviwo/core/util/commandlineparser.h>

namespace inviwo {

CommandLineParser::CommandLineParser() : CommandLineParser(0, nullptr) {}

CommandLineParser::CommandLineParser(int argc, char** argv)
    : argc_(argc)
    , argv_(argv)
    , cmdQuiet_(
          "Inviwo, Interactive Visualization Workshop, a rapid prototyping environment for "
          "interactive visualizations",
          ' ', IVW_VERSION, false)
    , cmd_(
          "Inviwo, Interactive Visualization Workshop, a rapid prototyping environment for "
          "interactive visualizations",
          ' ', IVW_VERSION)
    , workspace_("w", "workspace", "Specify workspace to open", false, "", "workspace file")
    , outputPath_("o", "output", "Specify output path", false, "", "output path")
    , logfile_("l", "logfile", "Write log messages to file.", false, "", "logfile")
    , noSplashScreen_("n", "nosplash", "Pass this flag if you do not want to show a splash screen.")
    , quitAfterStartup_("q", "quit", "Pass this flag if you want to close inviwo after startup.")
    , wildcard_()
    , helpQuiet_("h", "help", "")
    , versionQuiet_("v", "version", "") {
    cmdQuiet_.add(workspace_);
    cmdQuiet_.add(outputPath_);
    cmdQuiet_.add(quitAfterStartup_);
    cmdQuiet_.add(noSplashScreen_);
    cmdQuiet_.add(logfile_);
    cmdQuiet_.add(helpQuiet_);
    cmdQuiet_.add(versionQuiet_);
    cmdQuiet_.add(wildcard_);

    cmd_.add(workspace_);
    cmd_.add(outputPath_);
    cmd_.add(quitAfterStartup_);
    cmd_.add(noSplashScreen_);
    cmd_.add(logfile_);

    parse(Mode::Quiet);
}

CommandLineParser::~CommandLineParser() {}

const std::string CommandLineParser::getOutputPath() const {
    if (outputPath_.isSet()) return (outputPath_.getValue());

    return "";
}

const std::string CommandLineParser::getWorkspacePath() const {
    if (workspace_.isSet()) return (workspace_.getValue());

    return "";
}

void CommandLineParser::parse(int argc, char** argv, Mode mode) {
    switch (mode) {
        case inviwo::CommandLineParser::Mode::Normal: {
            helpQuiet_.reset();
            versionQuiet_.reset();
            try {
                if (argc > 0) {
                    cmd_.reset();
                    cmd_.parse(argc, argv);
                }
            } catch (TCLAP::ArgException& e) {
                std::cerr << "error: " << e.error() << " for arg " << e.argId()
                          << std::endl;  // catch exceptions
            }
            break;
        }

        case inviwo::CommandLineParser::Mode::Quiet: {
            try {
                if (argc > 0) {
                    cmdQuiet_.reset();
                    cmdQuiet_.parse(argc, argv);
                }
            } catch (...) {
            }
            break;
        }
        default:
            break;
    }
}

void CommandLineParser::parse(Mode mode) { parse(argc_, argv_, mode); }

const std::string CommandLineParser::getLogToFileFileName() const {
    if (logfile_.isSet())
        return (logfile_.getValue());
    else
        return "";
}

bool CommandLineParser::getQuitApplicationAfterStartup() const {
    return quitAfterStartup_.getValue();
}

bool CommandLineParser::getShowSplashScreen() const {
    if (versionQuiet_.isSet() || helpQuiet_.isSet())
        return false;
    else
        return !(noSplashScreen_.isSet());
}

bool CommandLineParser::getLoadWorkspaceFromArg() const {
    if (workspace_.isSet()) {
        std::string values = workspace_.getValue();
        assert(values.size() != 0);
        return true;
    }

    return false;
}

bool CommandLineParser::getLogToFile() const {
    if (logfile_.isSet()) {
        std::string values = logfile_.getValue();
        assert(values.size() != 0);
        return true;
    }

    return false;
}

void CommandLineParser::processCallbacks() {
    std::sort(callbacks_.begin(), callbacks_.end(),
              [](typename decltype(callbacks_)::value_type& a,
                 typename decltype(callbacks_)::value_type& b) {
                  return std::get<0>(a) < std::get<0>(b);
              });
    for (auto& elem : callbacks_) {
        if (std::get<1>(elem)->isSet()) {
            std::get<2>(elem)();
        }
    }
}

void CommandLineParser::add(TCLAP::Arg* arg) { cmd_.add(arg); }

void CommandLineParser::add(TCLAP::Arg* arg, std::function<void()> callback, int priority) {
    cmd_.add(arg);
    callbacks_.push_back(std::make_tuple(priority, arg, callback));
}

}  // namespace
<commit_msg>Core: Jenkins fix<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2013-2015 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. 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.
 *
 * 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 <inviwo/core/util/commandlineparser.h>

namespace inviwo {

CommandLineParser::CommandLineParser() : CommandLineParser(0, nullptr) {}

CommandLineParser::CommandLineParser(int argc, char** argv)
    : argc_(argc)
    , argv_(argv)
    , cmdQuiet_(
          "Inviwo, Interactive Visualization Workshop, a rapid prototyping environment for "
          "interactive visualizations",
          ' ', IVW_VERSION, false)
    , cmd_(
          "Inviwo, Interactive Visualization Workshop, a rapid prototyping environment for "
          "interactive visualizations",
          ' ', IVW_VERSION)
    , workspace_("w", "workspace", "Specify workspace to open", false, "", "workspace file")
    , outputPath_("o", "output", "Specify output path", false, "", "output path")
    , logfile_("l", "logfile", "Write log messages to file.", false, "", "logfile")
    , noSplashScreen_("n", "nosplash", "Pass this flag if you do not want to show a splash screen.")
    , quitAfterStartup_("q", "quit", "Pass this flag if you want to close inviwo after startup.")
    , wildcard_()
    , helpQuiet_("h", "help", "")
    , versionQuiet_("v", "version", "") {
    cmdQuiet_.add(workspace_);
    cmdQuiet_.add(outputPath_);
    cmdQuiet_.add(quitAfterStartup_);
    cmdQuiet_.add(noSplashScreen_);
    cmdQuiet_.add(logfile_);
    cmdQuiet_.add(helpQuiet_);
    cmdQuiet_.add(versionQuiet_);
    cmdQuiet_.add(wildcard_);

    cmd_.add(workspace_);
    cmd_.add(outputPath_);
    cmd_.add(quitAfterStartup_);
    cmd_.add(noSplashScreen_);
    cmd_.add(logfile_);

    parse(Mode::Quiet);
}

CommandLineParser::~CommandLineParser() {}

const std::string CommandLineParser::getOutputPath() const {
    if (outputPath_.isSet()) return (outputPath_.getValue());

    return "";
}

const std::string CommandLineParser::getWorkspacePath() const {
    if (workspace_.isSet()) return (workspace_.getValue());

    return "";
}

void CommandLineParser::parse(int argc, char** argv, Mode mode) {
    switch (mode) {
        case inviwo::CommandLineParser::Mode::Normal: {
            helpQuiet_.reset();
            versionQuiet_.reset();
            try {
                if (argc > 0) {
                    cmd_.reset();
                    cmd_.parse(argc, argv);
                }
            } catch (TCLAP::ArgException& e) {
                std::cerr << "error: " << e.error() << " for arg " << e.argId()
                          << std::endl;  // catch exceptions
            }
            break;
        }

        case inviwo::CommandLineParser::Mode::Quiet: {
            try {
                if (argc > 0) {
                    cmdQuiet_.reset();
                    cmdQuiet_.parse(argc, argv);
                }
            } catch (...) {
            }
            break;
        }
        default:
            break;
    }
}

void CommandLineParser::parse(Mode mode) { parse(argc_, argv_, mode); }

const std::string CommandLineParser::getLogToFileFileName() const {
    if (logfile_.isSet())
        return (logfile_.getValue());
    else
        return "";
}

bool CommandLineParser::getQuitApplicationAfterStartup() const {
    return quitAfterStartup_.getValue();
}

bool CommandLineParser::getShowSplashScreen() const {
    if (versionQuiet_.isSet() || helpQuiet_.isSet())
        return false;
    else
        return !(noSplashScreen_.isSet());
}

bool CommandLineParser::getLoadWorkspaceFromArg() const {
    if (workspace_.isSet()) {
        std::string values = workspace_.getValue();
        assert(values.size() != 0);
        return true;
    }

    return false;
}

bool CommandLineParser::getLogToFile() const {
    if (logfile_.isSet()) {
        std::string values = logfile_.getValue();
        assert(values.size() != 0);
        return true;
    }

    return false;
}

void CommandLineParser::processCallbacks() {
    std::sort(callbacks_.begin(), callbacks_.end(),
              [](const typename decltype(callbacks_)::value_type& a,
                 const typename decltype(callbacks_)::value_type& b) {
                  return std::get<0>(a) < std::get<0>(b);
              });
    for (auto& elem : callbacks_) {
        if (std::get<1>(elem)->isSet()) {
            std::get<2>(elem)();
        }
    }
}

void CommandLineParser::add(TCLAP::Arg* arg) { cmd_.add(arg); }

void CommandLineParser::add(TCLAP::Arg* arg, std::function<void()> callback, int priority) {
    cmd_.add(arg);
    callbacks_.push_back(std::make_tuple(priority, arg, callback));
}

}  // namespace
<|endoftext|>