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

#include "chainparamsbase.h"
#include "clientversion.h"
#include "rpcclient.h"
#include "rpcprotocol.h"
#include "util.h"
#include "utilstrencodings.h"

#include <boost/filesystem/operations.hpp>

#define _(x) std::string(x) /* Keep the _() around in case gettext or such will be used later to translate non-UI */

using namespace std;
using namespace boost;
using namespace boost::asio;
using namespace json_spirit;

std::string HelpMessageCli()
{
    string strUsage;
    strUsage += _("Options:") + "\n";
    strUsage += "  -?                     " + _("This help message") + "\n";
    strUsage += "  -conf=<file>           " + strprintf(_("Specify configuration file (default: %s)"), "moneta.conf") + "\n";
    strUsage += "  -datadir=<dir>         " + _("Specify data directory") + "\n";
    strUsage += "  -testnet               " + _("Use the test network") + "\n";
    strUsage += "  -regtest               " + _("Enter regression test mode, which uses a special chain in which blocks can be "
                                                "solved instantly. This is intended for regression testing tools and app development.") + "\n";
    strUsage += "  -rpcconnect=<ip>       " + strprintf(_("Send commands to node running on <ip> (default: %s)"), "127.0.0.1") + "\n";
    strUsage += "  -rpcport=<port>        " + strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), 7333, 17333) + "\n";
    strUsage += "  -rpcwait               " + _("Wait for RPC server to start") + "\n";
    strUsage += "  -rpcuser=<user>        " + _("Username for JSON-RPC connections") + "\n";
    strUsage += "  -rpcpassword=<pw>      " + _("Password for JSON-RPC connections") + "\n";

    strUsage += "\n" + _("SSL options: (see the Moneta Wiki for SSL setup instructions)") + "\n";
    strUsage += "  -rpcssl                " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n";

    return strUsage;
}

//////////////////////////////////////////////////////////////////////////////
//
// Start
//

//
// Exception thrown on connection error.  This error is used to determine
// when to wait if -rpcwait is given.
//
class CConnectionFailed : public std::runtime_error
{
public:

    explicit inline CConnectionFailed(const std::string& msg) :
        std::runtime_error(msg)
    {}

};

static bool AppInitRPC(int argc, char* argv[])
{
    //
    // Parameters
    //
    ParseParameters(argc, argv);
    if (argc<2 || mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version")) {
        std::string strUsage = _("Litcoin Core RPC client version") + " " + FormatFullVersion() + "\n";
        if (!mapArgs.count("-version")) {
            strUsage += "\n" + _("Usage:") + "\n" +
                  "  moneta-cli [options] <command> [params]  " + _("Send command to Moneta Core") + "\n" +
                  "  moneta-cli [options] help                " + _("List commands") + "\n" +
                  "  moneta-cli [options] help <command>      " + _("Get help for a command") + "\n";

            strUsage += "\n" + HelpMessageCli();
        }

        fprintf(stdout, "%s", strUsage.c_str());
        return false;
    }
    if (!boost::filesystem::is_directory(GetDataDir(false))) {
        fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
        return false;
    }
    try {
        ReadConfigFile(mapArgs, mapMultiArgs);
    } catch(std::exception &e) {
        fprintf(stderr,"Error reading configuration file: %s\n", e.what());
        return false;
    }
    // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
    if (!SelectBaseParamsFromCommandLine()) {
        fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
        return false;
    }
    return true;
}

Object CallRPC(const string& strMethod, const Array& params)
{
    if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
        throw runtime_error(strprintf(
            _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
              "If the file does not exist, create it with owner-readable-only file permissions."),
                GetConfigFile().string().c_str()));

    // Connect to localhost
    bool fUseSSL = GetBoolArg("-rpcssl", false);
    asio::io_service io_service;
    ssl::context context(io_service, ssl::context::sslv23);
    context.set_options(ssl::context::no_sslv2 | ssl::context::no_sslv3);
    asio::ssl::stream<asio::ip::tcp::socket> sslStream(io_service, context);
    SSLIOStreamDevice<asio::ip::tcp> d(sslStream, fUseSSL);
    iostreams::stream< SSLIOStreamDevice<asio::ip::tcp> > stream(d);

    const bool fConnected = d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(BaseParams().RPCPort())));
    if (!fConnected)
        throw CConnectionFailed("couldn't connect to server");

    // HTTP basic authentication
    string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
    map<string, string> mapRequestHeaders;
    mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;

    // Send request
    string strRequest = JSONRPCRequest(strMethod, params, 1);
    string strPost = HTTPPost(strRequest, mapRequestHeaders);
    stream << strPost << std::flush;

    // Receive HTTP reply status
    int nProto = 0;
    int nStatus = ReadHTTPStatus(stream, nProto);

    // Receive HTTP reply message headers and body
    map<string, string> mapHeaders;
    string strReply;
    ReadHTTPMessage(stream, mapHeaders, strReply, nProto, std::numeric_limits<size_t>::max());

    if (nStatus == HTTP_UNAUTHORIZED)
        throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
    else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR)
        throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
    else if (strReply.empty())
        throw runtime_error("no response from server");

    // Parse reply
    Value valReply;
    if (!read_string(strReply, valReply))
        throw runtime_error("couldn't parse reply from server");
    const Object& reply = valReply.get_obj();
    if (reply.empty())
        throw runtime_error("expected reply to have result, error and id properties");

    return reply;
}

int CommandLineRPC(int argc, char *argv[])
{
    string strPrint;
    int nRet = 0;
    try {
        // Skip switches
        while (argc > 1 && IsSwitchChar(argv[1][0])) {
            argc--;
            argv++;
        }

        // Method
        if (argc < 2)
            throw runtime_error("too few parameters");
        string strMethod = argv[1];

        // Parameters default to strings
        std::vector<std::string> strParams(&argv[2], &argv[argc]);
        Array params = RPCConvertValues(strMethod, strParams);

        // Execute and handle connection failures with -rpcwait
        const bool fWait = GetBoolArg("-rpcwait", false);
        do {
            try {
                const Object reply = CallRPC(strMethod, params);

                // Parse reply
                const Value& result = find_value(reply, "result");
                const Value& error  = find_value(reply, "error");

                if (error.type() != null_type) {
                    // Error
                    const int code = find_value(error.get_obj(), "code").get_int();
                    if (fWait && code == RPC_IN_WARMUP)
                        throw CConnectionFailed("server in warmup");
                    strPrint = "error: " + write_string(error, false);
                    nRet = abs(code);
                } else {
                    // Result
                    if (result.type() == null_type)
                        strPrint = "";
                    else if (result.type() == str_type)
                        strPrint = result.get_str();
                    else
                        strPrint = write_string(result, true);
                }

                // Connection succeeded, no need to retry.
                break;
            }
            catch (const CConnectionFailed& e) {
                if (fWait)
                    MilliSleep(1000);
                else
                    throw;
            }
        } while (fWait);
    }
    catch (boost::thread_interrupted) {
        throw;
    }
    catch (std::exception& e) {
        strPrint = string("error: ") + e.what();
        nRet = EXIT_FAILURE;
    }
    catch (...) {
        PrintExceptionContinue(NULL, "CommandLineRPC()");
        throw;
    }

    if (strPrint != "") {
        fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
    }
    return nRet;
}

int main(int argc, char* argv[])
{
    SetupEnvironment();

    try {
        if(!AppInitRPC(argc, argv))
            return EXIT_FAILURE;
    }
    catch (std::exception& e) {
        PrintExceptionContinue(&e, "AppInitRPC()");
        return EXIT_FAILURE;
    } catch (...) {
        PrintExceptionContinue(NULL, "AppInitRPC()");
        return EXIT_FAILURE;
    }

    int ret = EXIT_FAILURE;
    try {
        ret = CommandLineRPC(argc, argv);
    }
    catch (std::exception& e) {
        PrintExceptionContinue(&e, "CommandLineRPC()");
    } catch (...) {
        PrintExceptionContinue(NULL, "CommandLineRPC()");
    }
    return ret;
}
<commit_msg>Update moneta-cli.cpp<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "chainparamsbase.h"
#include "clientversion.h"
#include "rpcclient.h"
#include "rpcprotocol.h"
#include "util.h"
#include "utilstrencodings.h"

#include <boost/filesystem/operations.hpp>

#define _(x) std::string(x) /* Keep the _() around in case gettext or such will be used later to translate non-UI */

using namespace std;
using namespace boost;
using namespace boost::asio;
using namespace json_spirit;

std::string HelpMessageCli()
{
    string strUsage;
    strUsage += _("Options:") + "\n";
    strUsage += "  -?                     " + _("This help message") + "\n";
    strUsage += "  -conf=<file>           " + strprintf(_("Specify configuration file (default: %s)"), "moneta.conf") + "\n";
    strUsage += "  -datadir=<dir>         " + _("Specify data directory") + "\n";
    strUsage += "  -testnet               " + _("Use the test network") + "\n";
    strUsage += "  -regtest               " + _("Enter regression test mode, which uses a special chain in which blocks can be "
                                                "solved instantly. This is intended for regression testing tools and app development.") + "\n";
    strUsage += "  -rpcconnect=<ip>       " + strprintf(_("Send commands to node running on <ip> (default: %s)"), "127.0.0.1") + "\n";
    strUsage += "  -rpcport=<port>        " + strprintf(_("Connect to JSON-RPC on <port> (default: %u or testnet: %u)"), 7333, 17333) + "\n";
    strUsage += "  -rpcwait               " + _("Wait for RPC server to start") + "\n";
    strUsage += "  -rpcuser=<user>        " + _("Username for JSON-RPC connections") + "\n";
    strUsage += "  -rpcpassword=<pw>      " + _("Password for JSON-RPC connections") + "\n";

    strUsage += "\n" + _("SSL options: (see the Moneta Wiki for SSL setup instructions)") + "\n";
    strUsage += "  -rpcssl                " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n";

    return strUsage;
}

//////////////////////////////////////////////////////////////////////////////
//
// Start
//

//
// Exception thrown on connection error.  This error is used to determine
// when to wait if -rpcwait is given.
//
class CConnectionFailed : public std::runtime_error
{
public:

    explicit inline CConnectionFailed(const std::string& msg) :
        std::runtime_error(msg)
    {}

};

static bool AppInitRPC(int argc, char* argv[])
{
    //
    // Parameters
    //
    ParseParameters(argc, argv);
    if (argc<2 || mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version")) {
        std::string strUsage = _("Moneta Core RPC client version") + " " + FormatFullVersion() + "\n";
        if (!mapArgs.count("-version")) {
            strUsage += "\n" + _("Usage:") + "\n" +
                  "  moneta-cli [options] <command> [params]  " + _("Send command to Moneta Core") + "\n" +
                  "  moneta-cli [options] help                " + _("List commands") + "\n" +
                  "  moneta-cli [options] help <command>      " + _("Get help for a command") + "\n";

            strUsage += "\n" + HelpMessageCli();
        }

        fprintf(stdout, "%s", strUsage.c_str());
        return false;
    }
    if (!boost::filesystem::is_directory(GetDataDir(false))) {
        fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
        return false;
    }
    try {
        ReadConfigFile(mapArgs, mapMultiArgs);
    } catch(std::exception &e) {
        fprintf(stderr,"Error reading configuration file: %s\n", e.what());
        return false;
    }
    // Check for -testnet or -regtest parameter (BaseParams() calls are only valid after this clause)
    if (!SelectBaseParamsFromCommandLine()) {
        fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
        return false;
    }
    return true;
}

Object CallRPC(const string& strMethod, const Array& params)
{
    if (mapArgs["-rpcuser"] == "" && mapArgs["-rpcpassword"] == "")
        throw runtime_error(strprintf(
            _("You must set rpcpassword=<password> in the configuration file:\n%s\n"
              "If the file does not exist, create it with owner-readable-only file permissions."),
                GetConfigFile().string().c_str()));

    // Connect to localhost
    bool fUseSSL = GetBoolArg("-rpcssl", false);
    asio::io_service io_service;
    ssl::context context(io_service, ssl::context::sslv23);
    context.set_options(ssl::context::no_sslv2 | ssl::context::no_sslv3);
    asio::ssl::stream<asio::ip::tcp::socket> sslStream(io_service, context);
    SSLIOStreamDevice<asio::ip::tcp> d(sslStream, fUseSSL);
    iostreams::stream< SSLIOStreamDevice<asio::ip::tcp> > stream(d);

    const bool fConnected = d.connect(GetArg("-rpcconnect", "127.0.0.1"), GetArg("-rpcport", itostr(BaseParams().RPCPort())));
    if (!fConnected)
        throw CConnectionFailed("couldn't connect to server");

    // HTTP basic authentication
    string strUserPass64 = EncodeBase64(mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]);
    map<string, string> mapRequestHeaders;
    mapRequestHeaders["Authorization"] = string("Basic ") + strUserPass64;

    // Send request
    string strRequest = JSONRPCRequest(strMethod, params, 1);
    string strPost = HTTPPost(strRequest, mapRequestHeaders);
    stream << strPost << std::flush;

    // Receive HTTP reply status
    int nProto = 0;
    int nStatus = ReadHTTPStatus(stream, nProto);

    // Receive HTTP reply message headers and body
    map<string, string> mapHeaders;
    string strReply;
    ReadHTTPMessage(stream, mapHeaders, strReply, nProto, std::numeric_limits<size_t>::max());

    if (nStatus == HTTP_UNAUTHORIZED)
        throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
    else if (nStatus >= 400 && nStatus != HTTP_BAD_REQUEST && nStatus != HTTP_NOT_FOUND && nStatus != HTTP_INTERNAL_SERVER_ERROR)
        throw runtime_error(strprintf("server returned HTTP error %d", nStatus));
    else if (strReply.empty())
        throw runtime_error("no response from server");

    // Parse reply
    Value valReply;
    if (!read_string(strReply, valReply))
        throw runtime_error("couldn't parse reply from server");
    const Object& reply = valReply.get_obj();
    if (reply.empty())
        throw runtime_error("expected reply to have result, error and id properties");

    return reply;
}

int CommandLineRPC(int argc, char *argv[])
{
    string strPrint;
    int nRet = 0;
    try {
        // Skip switches
        while (argc > 1 && IsSwitchChar(argv[1][0])) {
            argc--;
            argv++;
        }

        // Method
        if (argc < 2)
            throw runtime_error("too few parameters");
        string strMethod = argv[1];

        // Parameters default to strings
        std::vector<std::string> strParams(&argv[2], &argv[argc]);
        Array params = RPCConvertValues(strMethod, strParams);

        // Execute and handle connection failures with -rpcwait
        const bool fWait = GetBoolArg("-rpcwait", false);
        do {
            try {
                const Object reply = CallRPC(strMethod, params);

                // Parse reply
                const Value& result = find_value(reply, "result");
                const Value& error  = find_value(reply, "error");

                if (error.type() != null_type) {
                    // Error
                    const int code = find_value(error.get_obj(), "code").get_int();
                    if (fWait && code == RPC_IN_WARMUP)
                        throw CConnectionFailed("server in warmup");
                    strPrint = "error: " + write_string(error, false);
                    nRet = abs(code);
                } else {
                    // Result
                    if (result.type() == null_type)
                        strPrint = "";
                    else if (result.type() == str_type)
                        strPrint = result.get_str();
                    else
                        strPrint = write_string(result, true);
                }

                // Connection succeeded, no need to retry.
                break;
            }
            catch (const CConnectionFailed& e) {
                if (fWait)
                    MilliSleep(1000);
                else
                    throw;
            }
        } while (fWait);
    }
    catch (boost::thread_interrupted) {
        throw;
    }
    catch (std::exception& e) {
        strPrint = string("error: ") + e.what();
        nRet = EXIT_FAILURE;
    }
    catch (...) {
        PrintExceptionContinue(NULL, "CommandLineRPC()");
        throw;
    }

    if (strPrint != "") {
        fprintf((nRet == 0 ? stdout : stderr), "%s\n", strPrint.c_str());
    }
    return nRet;
}

int main(int argc, char* argv[])
{
    SetupEnvironment();

    try {
        if(!AppInitRPC(argc, argv))
            return EXIT_FAILURE;
    }
    catch (std::exception& e) {
        PrintExceptionContinue(&e, "AppInitRPC()");
        return EXIT_FAILURE;
    } catch (...) {
        PrintExceptionContinue(NULL, "AppInitRPC()");
        return EXIT_FAILURE;
    }

    int ret = EXIT_FAILURE;
    try {
        ret = CommandLineRPC(argc, argv);
    }
    catch (std::exception& e) {
        PrintExceptionContinue(&e, "CommandLineRPC()");
    } catch (...) {
        PrintExceptionContinue(NULL, "CommandLineRPC()");
    }
    return ret;
}
<|endoftext|>


<commit_before>/* Copyright (C) 2005-2008, Thorvald Natvig <thorvald@natvig.com>
   Copyright (C) 2008, Mikkel Krautz <mikkel@krautz.dk>

   All rights reserved.

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

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

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION 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 "LCD.h"
#include "Player.h"
#include "Channel.h"
#include "Global.h"
#include "Message.h"
#include "ServerHandler.h"

QList<LCDEngineNew> *LCDEngineRegistrar::qlInitializers;

LCDEngineRegistrar::LCDEngineRegistrar(LCDEngineNew n) {
	if (! qlInitializers)
		qlInitializers = new QList<LCDEngineNew>();
	this->n = n;
	qlInitializers->append(n);
}

LCDEngineRegistrar::~LCDEngineRegistrar() {
	qlInitializers->removeAll(n);
}

static ConfigWidget *LCDConfigDialogNew(Settings &st) {
	return new LCDConfig(st);
}

class LCDDeviceManager : public DeferInit {
	protected:
		ConfigRegistrar *crLCD;
	public:
		QList<LCDEngine *> qlEngines;
		QList<LCDDevice *> qlDevices;
		void initialize();
		void destroy();
};

void LCDDeviceManager::initialize() {
	foreach (LCDEngineNew engine, *LCDEngineRegistrar::qlInitializers) {
		LCDEngine *e = engine();
		qlEngines.append(e);

		foreach(LCDDevice *d, e->devices()) {
			qlDevices << d;
		}
	}
	if (qlDevices.count() > 0) {
		crLCD = new ConfigRegistrar(5900, LCDConfigDialogNew);
	} else {
		crLCD = NULL;
	}
}

void LCDDeviceManager::destroy() {
	qlDevices.clear();
	foreach (LCDEngine *e, qlEngines) {
		delete e;
	}
	if (crLCD)
		delete crLCD;
}

static LCDDeviceManager devmgr;

/* --- */

LCDConfig::LCDConfig(Settings &st) : ConfigWidget(st) {
	setupUi(this);

	QTreeWidgetItem *qtwi;
	foreach (LCDDevice *d, devmgr.qlDevices) {
		qtwi = new QTreeWidgetItem(qtwDevices);

		qtwi->setFlags(Qt::ItemIsEnabled |Qt::ItemIsUserCheckable);

		qtwi->setText(0, d->name());
		qtwi->setToolTip(0, d->name());

		LCDDevice::Type type = d->type();
		QString qsType;
		if (type == LCDDevice::GraphicLCD)
			qsType = tr("Graphic");
		else if (type == LCDDevice::CharacterLCD)
			qsType = tr("Character");

		qtwi->setText(1, qsType);
		qtwi->setToolTip(1, qsType);

		QSize size = d->size();
		QString qsSize = QString::fromLatin1("%1x%2").arg(size.width()).arg(size.height());
		qtwi->setText(2, qsSize);
		qtwi->setToolTip(2, qsSize);

		qtwi->setCheckState(3, Qt::Unchecked);
		qtwi->setToolTip(3, tr("Enable this device"));
	}
}

bool LCDConfig::expert(bool) {
	return false;
}

QString LCDConfig::title() const {
	return tr("LCD");
}

QIcon LCDConfig::icon() const {
	return QIcon(QLatin1String("skin:config_lcd.png"));
}

void LCDConfig::load(const Settings &r) {
	QList<QTreeWidgetItem *> qlItems = qtwDevices->findItems(QString(), Qt::MatchContains);
	foreach(QTreeWidgetItem *qtwi, qlItems) {
		QString qsName = qtwi->text(0);
		bool enabled = r.qmLCDDevices.contains(qsName) ? r.qmLCDDevices.value(qsName) : true;
		qtwi->setCheckState(3, enabled ? Qt::Checked : Qt::Unchecked);
	}

	loadSlider(qsMinColWidth, r.iLCDPlayerViewMinColWidth);
	loadSlider(qsSplitterWidth, r.iLCDPlayerViewSplitterWidth);
}

void LCDConfig::save() const {
	QList<QTreeWidgetItem *> qlItems = qtwDevices->findItems(QString(), Qt::MatchContains);

	foreach(QTreeWidgetItem *qtwi, qlItems) {
		QString qsName = qtwi->text(0);
		s.qmLCDDevices.insert(qsName, qtwi->checkState(3) == Qt::Checked);
	}

	s.iLCDPlayerViewMinColWidth = qsMinColWidth->value();
	s.iLCDPlayerViewSplitterWidth = qsSplitterWidth->value();
}

void LCDConfig::accept() const {
	foreach (LCDDevice *d, devmgr.qlDevices) {
		bool enabled = s.qmLCDDevices.value(d->name());
		d->setEnabled(enabled);
	}
	g.lcd->updatePlayerView();
}

void LCDConfig::on_qsMinColWidth_valueChanged(int v) {
	qlMinColWidth->setText(QString::number(v));
}

void LCDConfig::on_qsSplitterWidth_valueChanged(int v) {
	qlSplitterWidth->setText(QString::number(v));
}

/* --- */

LCD::LCD() : QObject() {
	qfNormal = QFont(QString::fromLatin1("Arial"), 7);
	qfBold = qfNormal;
	qfBold.setBold(true);
	qfItalic = qfNormal;
	qfItalic.setItalic(true);
	qfItalicBold = qfBold;
	qfItalic.setItalic(true);

	QFontMetrics qfm(qfNormal);

	// Font metrics are broken, and unfortunately means we loose a lot of font space.
//	iFontHeight = qfm.height();
	iFontHeight = 10;

	initBuffers();

	iFrameIndex = 0;

	qtTimer = new QTimer(this);
	connect(qtTimer, SIGNAL(timeout()), this, SLOT(tick()));

	foreach (LCDDevice *d, devmgr.qlDevices) {
		bool enabled = g.s.qmLCDDevices.contains(d->name()) ? g.s.qmLCDDevices.value(d->name()) : true;
		d->setEnabled(enabled);
	}
	qiLogo = QImage(QLatin1String("skin:mumble.48x48.png")).convertToFormat(QImage::Format_MonoLSB);
	updatePlayerView();
}

void LCD::tick() {
	iFrameIndex ++;
	updatePlayerView();
}

void LCD::initBuffers() {
	foreach (LCDDevice *d, devmgr.qlDevices) {
		QSize size = d->size();
		if (! qhImageBuffers.contains(size)) {
			size_t buflen = (size.width() * size.height()) / 8;
			qhImageBuffers[size] = new unsigned char[buflen];
			qhImages[size] = new QImage(qhImageBuffers[size], size.width(), size.height(), QImage::Format_MonoLSB);
		 }
	}
}

void LCD::destroyBuffers() {
	foreach (QImage *img, qhImages)
		delete img;
	qhImages.clear();

	foreach(unsigned char *buf, qhImageBuffers)
		delete buf;
	qhImageBuffers.clear();
}

static bool playerSort(const Player *a, const Player *b) {
	return a->qsName < b->qsName;
}

static bool channelSort(const Channel *home, const Channel *a, const Channel *b) {
	if ((a == home) && (a != b))
		return true;
	else if ((b == home) && (a != b))
		return false;
	return a->qsName < b->qsName;
}

struct ListEntry {
	QString qsString;
	bool bBold;
	bool bItalic;
	ListEntry(const QString &qs, bool bB, bool bI) : qsString(qs), bBold(bB), bItalic(bI) {};
};

void LCD::updatePlayerView() {
	if (qhImages.count() == 0)
		return;

	QStringList qslTalking;
	Player *me = g.uiSession ? ClientPlayer::get(g.uiSession) : NULL;
	Channel *home = me ? me->cChannel : NULL;
	bool alert = false;

	foreach (const QSize &size, qhImages.keys()) {
		QImage *img = qhImages.value(size);
		QPainter painter(img);
		painter.setRenderHints(0, true);
		painter.setPen(Qt::color1);
		painter.setFont(qfNormal);

		img->fill(Qt::color0);

		if (! me) {
			painter.drawImage(0,0,qiLogo);
			painter.drawText(60,20, tr("Not connected"));
			continue;
		}

		QList<Channel *> qlLinks = home->allLinks().toList();

		qSort(qlLinks.begin(), qlLinks.end(), boost::bind(channelSort, home, _1, _2));

		const int iWidth = size.width();
		const int iHeight = size.height();
		const int iPlayersPerColumn = iHeight / iFontHeight;
		const int iSplitterWidth = g.s.iLCDPlayerViewSplitterWidth;

		QList<struct ListEntry> entries;
		QList<struct ListEntry> talking;

		int iCount = 0;

		foreach(Channel *c, qlLinks) {
			QList<Player *> players = c->qlPlayers;
			qSort(players.begin(), players.end(), playerSort);
			if ((players.count() > 0) && (((iCount+1) % iPlayersPerColumn) == 0)) {
				entries << ListEntry(QString(), false, false);
				iCount++;
			}
			entries << ListEntry(QString::fromLatin1("[%1]").arg(c->qsName), false, false);
			iCount++;

			foreach(const Player *p, players) {
				entries << ListEntry(p->qsName, p->bTalking, false);
				iCount++;
				if (p->bTalking) {
					alert = true;
					talking << ListEntry(p->qsName, true, (c != home));
				}
			}
		}

		const int iPlayerColumns = (iCount + iPlayersPerColumn - 1) / iPlayersPerColumn;

		int iColumns = iPlayerColumns;
		int iColumnWidth;

		while (iColumns >= 1) {
			iColumnWidth = (iWidth - (iColumns-1)*iSplitterWidth) / iColumns;
			if (iColumnWidth >= g.s.iLCDPlayerViewMinColWidth)
				break;
			--iColumns;
		}

		if (iColumns == iPlayerColumns) {
			talking = entries;
			if (qtTimer->isActive())
				qtTimer->stop();
		} else {
			if (! qtTimer->isActive())
				qtTimer->start(2000);
			while (talking.count() % iPlayersPerColumn) {
				talking << ListEntry(QString(), false, false);
			}
			int iSkipped = (iPlayerColumns - iColumns + talking.count() / iPlayersPerColumn);
			for(int i=(iFrameIndex % (iSkipped+1))*iPlayersPerColumn;i<entries.count();i++)
				talking << entries.at(i);
		}

		QRect bound;
		int row = 0, col = 0;

		foreach(const ListEntry &le, talking) {
				if (row >= iPlayersPerColumn) {
					row = 0;
					++col;
				}
				if (col > iColumns)
					break;

				if (! le.qsString.isEmpty()) {
					if (le.bBold && le.bItalic)
						painter.setFont(qfItalicBold);
					else if (le.bBold)
						painter.setFont(qfBold);
					else if (le.bItalic)
						painter.setFont(qfItalic);
					else
						painter.setFont(qfNormal);
					painter.drawText(QRect(col * (iColumnWidth  + iSplitterWidth),
										   row * iFontHeight, iColumnWidth, iFontHeight+2), Qt::AlignLeft, le.qsString);
				}
				++row;
		}
	}

	foreach (LCDDevice *d, devmgr.qlDevices) {
		LCDDevice::Type type = d->type();
		if (type == LCDDevice::GraphicLCD) {
			QImage *img = qhImages[d->size()];
			if (! img)
				continue;
			d->blitImage(img, alert);
		} else if (type == LCDDevice::CharacterLCD) {
			/* TODO. */
			qWarning("LCD: Unable to draw to Character LCD.");
		}
	}
}

LCD::~LCD() {
	destroyBuffers();
}

/* --- */

LCDEngine::LCDEngine() : QObject() {
}

LCDEngine::~LCDEngine() {
}

LCDDevice::LCDDevice() {
}

LCDDevice::~LCDDevice() {
}

/* --- */

uint qHash(const QSize &size) {
	return ((size.width() & 0xffff) << 16) | (size.height() & 0xffff);
}
<commit_msg>Fix for crash with no LCD devices present.<commit_after>/* Copyright (C) 2005-2008, Thorvald Natvig <thorvald@natvig.com>
   Copyright (C) 2008, Mikkel Krautz <mikkel@krautz.dk>

   All rights reserved.

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

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

   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION 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 "LCD.h"
#include "Player.h"
#include "Channel.h"
#include "Global.h"
#include "Message.h"
#include "ServerHandler.h"

QList<LCDEngineNew> *LCDEngineRegistrar::qlInitializers;

LCDEngineRegistrar::LCDEngineRegistrar(LCDEngineNew n) {
	if (! qlInitializers)
		qlInitializers = new QList<LCDEngineNew>();
	this->n = n;
	qlInitializers->append(n);
}

LCDEngineRegistrar::~LCDEngineRegistrar() {
	qlInitializers->removeAll(n);
}

static ConfigWidget *LCDConfigDialogNew(Settings &st) {
	return new LCDConfig(st);
}

class LCDDeviceManager : public DeferInit {
	protected:
		ConfigRegistrar *crLCD;
	public:
		QList<LCDEngine *> qlEngines;
		QList<LCDDevice *> qlDevices;
		void initialize();
		void destroy();
};

void LCDDeviceManager::initialize() {
	if (LCDEngineRegistrar::qlInitializers) {
		foreach (LCDEngineNew engine, *LCDEngineRegistrar::qlInitializers) {
			LCDEngine *e = engine();
			qlEngines.append(e);

			foreach(LCDDevice *d, e->devices()) {
				qlDevices << d;
			}
		}
	}
	if (qlDevices.count() > 0) {
		crLCD = new ConfigRegistrar(5900, LCDConfigDialogNew);
	} else {
		crLCD = NULL;
	}
}

void LCDDeviceManager::destroy() {
	qlDevices.clear();
	foreach (LCDEngine *e, qlEngines) {
		delete e;
	}
	if (crLCD)
		delete crLCD;
}

static LCDDeviceManager devmgr;

/* --- */

LCDConfig::LCDConfig(Settings &st) : ConfigWidget(st) {
	setupUi(this);

	QTreeWidgetItem *qtwi;
	foreach (LCDDevice *d, devmgr.qlDevices) {
		qtwi = new QTreeWidgetItem(qtwDevices);

		qtwi->setFlags(Qt::ItemIsEnabled |Qt::ItemIsUserCheckable);

		qtwi->setText(0, d->name());
		qtwi->setToolTip(0, d->name());

		LCDDevice::Type type = d->type();
		QString qsType;
		if (type == LCDDevice::GraphicLCD)
			qsType = tr("Graphic");
		else if (type == LCDDevice::CharacterLCD)
			qsType = tr("Character");

		qtwi->setText(1, qsType);
		qtwi->setToolTip(1, qsType);

		QSize size = d->size();
		QString qsSize = QString::fromLatin1("%1x%2").arg(size.width()).arg(size.height());
		qtwi->setText(2, qsSize);
		qtwi->setToolTip(2, qsSize);

		qtwi->setCheckState(3, Qt::Unchecked);
		qtwi->setToolTip(3, tr("Enable this device"));
	}
}

bool LCDConfig::expert(bool) {
	return false;
}

QString LCDConfig::title() const {
	return tr("LCD");
}

QIcon LCDConfig::icon() const {
	return QIcon(QLatin1String("skin:config_lcd.png"));
}

void LCDConfig::load(const Settings &r) {
	QList<QTreeWidgetItem *> qlItems = qtwDevices->findItems(QString(), Qt::MatchContains);
	foreach(QTreeWidgetItem *qtwi, qlItems) {
		QString qsName = qtwi->text(0);
		bool enabled = r.qmLCDDevices.contains(qsName) ? r.qmLCDDevices.value(qsName) : true;
		qtwi->setCheckState(3, enabled ? Qt::Checked : Qt::Unchecked);
	}

	loadSlider(qsMinColWidth, r.iLCDPlayerViewMinColWidth);
	loadSlider(qsSplitterWidth, r.iLCDPlayerViewSplitterWidth);
}

void LCDConfig::save() const {
	QList<QTreeWidgetItem *> qlItems = qtwDevices->findItems(QString(), Qt::MatchContains);

	foreach(QTreeWidgetItem *qtwi, qlItems) {
		QString qsName = qtwi->text(0);
		s.qmLCDDevices.insert(qsName, qtwi->checkState(3) == Qt::Checked);
	}

	s.iLCDPlayerViewMinColWidth = qsMinColWidth->value();
	s.iLCDPlayerViewSplitterWidth = qsSplitterWidth->value();
}

void LCDConfig::accept() const {
	foreach (LCDDevice *d, devmgr.qlDevices) {
		bool enabled = s.qmLCDDevices.value(d->name());
		d->setEnabled(enabled);
	}
	g.lcd->updatePlayerView();
}

void LCDConfig::on_qsMinColWidth_valueChanged(int v) {
	qlMinColWidth->setText(QString::number(v));
}

void LCDConfig::on_qsSplitterWidth_valueChanged(int v) {
	qlSplitterWidth->setText(QString::number(v));
}

/* --- */

LCD::LCD() : QObject() {
	qfNormal = QFont(QString::fromLatin1("Arial"), 7);
	qfBold = qfNormal;
	qfBold.setBold(true);
	qfItalic = qfNormal;
	qfItalic.setItalic(true);
	qfItalicBold = qfBold;
	qfItalic.setItalic(true);

	QFontMetrics qfm(qfNormal);

	// Font metrics are broken, and unfortunately means we loose a lot of font space.
//	iFontHeight = qfm.height();
	iFontHeight = 10;

	initBuffers();

	iFrameIndex = 0;

	qtTimer = new QTimer(this);
	connect(qtTimer, SIGNAL(timeout()), this, SLOT(tick()));

	foreach (LCDDevice *d, devmgr.qlDevices) {
		bool enabled = g.s.qmLCDDevices.contains(d->name()) ? g.s.qmLCDDevices.value(d->name()) : true;
		d->setEnabled(enabled);
	}
	qiLogo = QImage(QLatin1String("skin:mumble.48x48.png")).convertToFormat(QImage::Format_MonoLSB);
	updatePlayerView();
}

void LCD::tick() {
	iFrameIndex ++;
	updatePlayerView();
}

void LCD::initBuffers() {
	foreach (LCDDevice *d, devmgr.qlDevices) {
		QSize size = d->size();
		if (! qhImageBuffers.contains(size)) {
			size_t buflen = (size.width() * size.height()) / 8;
			qhImageBuffers[size] = new unsigned char[buflen];
			qhImages[size] = new QImage(qhImageBuffers[size], size.width(), size.height(), QImage::Format_MonoLSB);
		 }
	}
}

void LCD::destroyBuffers() {
	foreach (QImage *img, qhImages)
		delete img;
	qhImages.clear();

	foreach(unsigned char *buf, qhImageBuffers)
		delete buf;
	qhImageBuffers.clear();
}

static bool playerSort(const Player *a, const Player *b) {
	return a->qsName < b->qsName;
}

static bool channelSort(const Channel *home, const Channel *a, const Channel *b) {
	if ((a == home) && (a != b))
		return true;
	else if ((b == home) && (a != b))
		return false;
	return a->qsName < b->qsName;
}

struct ListEntry {
	QString qsString;
	bool bBold;
	bool bItalic;
	ListEntry(const QString &qs, bool bB, bool bI) : qsString(qs), bBold(bB), bItalic(bI) {};
};

void LCD::updatePlayerView() {
	if (qhImages.count() == 0)
		return;

	QStringList qslTalking;
	Player *me = g.uiSession ? ClientPlayer::get(g.uiSession) : NULL;
	Channel *home = me ? me->cChannel : NULL;
	bool alert = false;

	foreach (const QSize &size, qhImages.keys()) {
		QImage *img = qhImages.value(size);
		QPainter painter(img);
		painter.setRenderHints(0, true);
		painter.setPen(Qt::color1);
		painter.setFont(qfNormal);

		img->fill(Qt::color0);

		if (! me) {
			painter.drawImage(0,0,qiLogo);
			painter.drawText(60,20, tr("Not connected"));
			continue;
		}

		QList<Channel *> qlLinks = home->allLinks().toList();

		qSort(qlLinks.begin(), qlLinks.end(), boost::bind(channelSort, home, _1, _2));

		const int iWidth = size.width();
		const int iHeight = size.height();
		const int iPlayersPerColumn = iHeight / iFontHeight;
		const int iSplitterWidth = g.s.iLCDPlayerViewSplitterWidth;

		QList<struct ListEntry> entries;
		QList<struct ListEntry> talking;

		int iCount = 0;

		foreach(Channel *c, qlLinks) {
			QList<Player *> players = c->qlPlayers;
			qSort(players.begin(), players.end(), playerSort);
			if ((players.count() > 0) && (((iCount+1) % iPlayersPerColumn) == 0)) {
				entries << ListEntry(QString(), false, false);
				iCount++;
			}
			entries << ListEntry(QString::fromLatin1("[%1]").arg(c->qsName), false, false);
			iCount++;

			foreach(const Player *p, players) {
				entries << ListEntry(p->qsName, p->bTalking, false);
				iCount++;
				if (p->bTalking) {
					alert = true;
					talking << ListEntry(p->qsName, true, (c != home));
				}
			}
		}

		const int iPlayerColumns = (iCount + iPlayersPerColumn - 1) / iPlayersPerColumn;

		int iColumns = iPlayerColumns;
		int iColumnWidth;

		while (iColumns >= 1) {
			iColumnWidth = (iWidth - (iColumns-1)*iSplitterWidth) / iColumns;
			if (iColumnWidth >= g.s.iLCDPlayerViewMinColWidth)
				break;
			--iColumns;
		}

		if (iColumns == iPlayerColumns) {
			talking = entries;
			if (qtTimer->isActive())
				qtTimer->stop();
		} else {
			if (! qtTimer->isActive())
				qtTimer->start(2000);
			while (talking.count() % iPlayersPerColumn) {
				talking << ListEntry(QString(), false, false);
			}
			int iSkipped = (iPlayerColumns - iColumns + talking.count() / iPlayersPerColumn);
			for(int i=(iFrameIndex % (iSkipped+1))*iPlayersPerColumn;i<entries.count();i++)
				talking << entries.at(i);
		}

		QRect bound;
		int row = 0, col = 0;

		foreach(const ListEntry &le, talking) {
				if (row >= iPlayersPerColumn) {
					row = 0;
					++col;
				}
				if (col > iColumns)
					break;

				if (! le.qsString.isEmpty()) {
					if (le.bBold && le.bItalic)
						painter.setFont(qfItalicBold);
					else if (le.bBold)
						painter.setFont(qfBold);
					else if (le.bItalic)
						painter.setFont(qfItalic);
					else
						painter.setFont(qfNormal);
					painter.drawText(QRect(col * (iColumnWidth  + iSplitterWidth),
										   row * iFontHeight, iColumnWidth, iFontHeight+2), Qt::AlignLeft, le.qsString);
				}
				++row;
		}
	}

	foreach (LCDDevice *d, devmgr.qlDevices) {
		LCDDevice::Type type = d->type();
		if (type == LCDDevice::GraphicLCD) {
			QImage *img = qhImages[d->size()];
			if (! img)
				continue;
			d->blitImage(img, alert);
		} else if (type == LCDDevice::CharacterLCD) {
			/* TODO. */
			qWarning("LCD: Unable to draw to Character LCD.");
		}
	}
}

LCD::~LCD() {
	destroyBuffers();
}

/* --- */

LCDEngine::LCDEngine() : QObject() {
}

LCDEngine::~LCDEngine() {
}

LCDDevice::LCDDevice() {
}

LCDDevice::~LCDDevice() {
}

/* --- */

uint qHash(const QSize &size) {
	return ((size.width() & 0xffff) << 16) | (size.height() & 0xffff);
}
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/
#include <osg/CopyOp>
#include <osg/Node>
#include <osg/StateSet>
#include <osg/Texture>
#include <osg/Drawable>
#include <osg/Array>
#include <osg/PrimitiveSet>
#include <osg/Shape>

using namespace osg;

#define COPY_OP( TYPE, FLAG ) \
TYPE* CopyOp::operator() (const TYPE* obj) const \
{ \
    if (obj && _flags&FLAG) \
        return dynamic_cast<TYPE*>( obj->clone(*this) ); \
    else \
        return const_cast<TYPE*>(obj); \
}

COPY_OP( Object,         DEEP_COPY_OBJECTS );
COPY_OP( Node,           DEEP_COPY_NODES );
COPY_OP( Drawable,       DEEP_COPY_DRAWABLES );
COPY_OP( StateSet,       DEEP_COPY_STATESETS );
COPY_OP( Texture,        DEEP_COPY_TEXTURES );
COPY_OP( Image,          DEEP_COPY_IMAGES );
COPY_OP( Array,          DEEP_COPY_DRAWABLES );
COPY_OP( PrimitiveSet,   DEEP_COPY_PRIMITIVES );
COPY_OP( Shape,          DEEP_COPY_SHAPES );
COPY_OP( Uniform,        DEEP_COPY_UNIFORMS );

Referenced* CopyOp::operator() (const Referenced* ref) const
{
    return const_cast<Referenced*>(ref);
}

StateAttribute* CopyOp::operator() (const StateAttribute* attr) const
{
    if (attr && _flags&DEEP_COPY_STATEATTRIBUTES)
    {
        const Texture* textbase = dynamic_cast<const Texture*>(attr);
        if (textbase)
        {
            return operator()(textbase);
        }
        else
        {
            return dynamic_cast<StateAttribute*>(attr->clone(*this));
        }
    }
    else
        return const_cast<StateAttribute*>(attr);
}

<commit_msg>Fixed the COPY_OP( Array, DEEP_COPY_ARRAYS); entry.<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * 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
 * OpenSceneGraph Public License for more details.
*/
#include <osg/CopyOp>
#include <osg/Node>
#include <osg/StateSet>
#include <osg/Texture>
#include <osg/Drawable>
#include <osg/Array>
#include <osg/PrimitiveSet>
#include <osg/Shape>

using namespace osg;

#define COPY_OP( TYPE, FLAG ) \
TYPE* CopyOp::operator() (const TYPE* obj) const \
{ \
    if (obj && _flags&FLAG) \
        return dynamic_cast<TYPE*>( obj->clone(*this) ); \
    else \
        return const_cast<TYPE*>(obj); \
}

COPY_OP( Object,         DEEP_COPY_OBJECTS );
COPY_OP( Node,           DEEP_COPY_NODES );
COPY_OP( Drawable,       DEEP_COPY_DRAWABLES );
COPY_OP( StateSet,       DEEP_COPY_STATESETS );
COPY_OP( Texture,        DEEP_COPY_TEXTURES );
COPY_OP( Image,          DEEP_COPY_IMAGES );
COPY_OP( Array,          DEEP_COPY_ARRAYS );
COPY_OP( PrimitiveSet,   DEEP_COPY_PRIMITIVES );
COPY_OP( Shape,          DEEP_COPY_SHAPES );
COPY_OP( Uniform,        DEEP_COPY_UNIFORMS );

Referenced* CopyOp::operator() (const Referenced* ref) const
{
    return const_cast<Referenced*>(ref);
}

StateAttribute* CopyOp::operator() (const StateAttribute* attr) const
{
    if (attr && _flags&DEEP_COPY_STATEATTRIBUTES)
    {
        const Texture* textbase = dynamic_cast<const Texture*>(attr);
        if (textbase)
        {
            return operator()(textbase);
        }
        else
        {
            return dynamic_cast<StateAttribute*>(attr->clone(*this));
        }
    }
    else
        return const_cast<StateAttribute*>(attr);
}

<|endoftext|>


<commit_before>#pragma once

#include <string>
#include <memory>

#include <utki/debug.hpp>
#include <utki/config.hpp>
#include <utki/Buf.hpp>
#include <utki/Unique.hpp>

#include "exception.hpp"

namespace papki{

/**
 * @brief Abstract interface to a file system.
 * This class represents an abstract interface to a file system.
 */
class file{
	mutable std::string path_var;

	mutable bool isOpened_var = false;

	mutable size_t curPos_var = 0;//holds current position from file beginning

public:

	/**
	 * @brief Modes of opening the file.
	 */
	enum class mode{
		read, /// Open existing file for read only.
		READ = read, //TODO: deprecaed, remove.
		write, /// Open existing file for read and write.
		WRITE = write, //TODO: deprecated, remove.
		create, /// Create new file and open it for read and write. If file exists it will be replaced by empty file.
		CREATE = create //TODO: deprecated, remove.
	};

	//TODO: deprecated, remove.
	typedef mode mode;

protected:
	mode ioMode; // mode only matters when file is opened

	/**
	 * @brief Constructor.
	 * @param pathName - initial path to set to the newly created file instance.
	 */
	file(const std::string& pathName = std::string()) :
			path_var(pathName)
	{}

public:
	file(const file&) = delete;
	file(file&&) = delete;
	file& operator=(const file&) = delete;

	/**
	 * @brief Destructor.
	 * This destructor does not call Close() method, but it has an ASSERT which checks if the file is closed.
	 * The file shall be closed upon the object destruction, all the implementations should
	 * assure that.
	 */
	virtual ~file()noexcept{
		ASSERT(!this->isOpened())
	}

	/**
	 * @brief Set the path for this file instance.
	 * @param pathName - the path to a file or directory.
	 */
	void setPath(const std::string& pathName)const{
		if(this->isOpened()){
			throw utki::invalid_state("papki::file::set_path(): Cannot set path when file is opened");
		}

		this->setPathInternal(pathName);
	}

protected:
	virtual void setPathInternal(const std::string& pathName)const{
		this->path_var = pathName;
	}

public:

	/**
	 * @brief Get the current path being held by this file instance.
	 * @return The path this file instance holds.
	 */
	const std::string& path()const noexcept{
		return this->path_var;
	}

	/**
	 * @brief Get current position from beginning of the file.
	 * @return Current position from beginning of the file
	 */
	size_t curPos()const noexcept{
		return this->curPos_var;
	}

	/**
	 * @brief Get file extension.
	 * Returns a string containing the tail part of the file path, everything that
	 * goes after the last dot character ('.') in the file path string.
	 * I.e. if the file path is '/home/user/some.file.txt' then the return value
	 * will be 'txt'.
	 * Note, that on *nix systems if the file name starts with a dot then this file is treated as hidden,
	 * in that case it is thought that the file has no extension. I.e., for example
	 * , if the file path is '/home/user/.myfile' then the file has no extension and this function
	 * will return an empty string. Although, if the file path is '/home/user/.myfile.txt' then the file
	 * does have an extension and the function will return 'txt'.
	 * @return String representing file extension.
	 */
	std::string ext()const;

	/**
	 * @brief Get directory part of the path.
	 * Example: if path is '/home/user/some.file.txt' then the return value
	 * will be '/home/user/'.
	 * @return String representation of directory part of the path.
	 */
	std::string dir()const;

	/**
	 * @brief Get file part of the path.
	 * Example: if path is '/home/user/some.file.txt' then the return value
	 * will be 'some.file.txt'.
	 * @return String representation of directory part of the path.
	 */
	std::string notDir()const;

	/**
	 * @brief Open file.
	 * Opens file for reading/writing or creates the file.
	 * @param mode - file opening mode (reading/writing/create).
	 * @throw utki::invalid_state - if file is already opened.
	 */
	void open(mode mode){
		if(this->isOpened()){
			throw utki::invalid_state("papki::file::open(): file is already opened");
		}
		if(this->isDir()){
			throw utki::invalid_state("file refers to directory. Directory cannot be opened.");
		}
		this->openInternal(mode);

		//set open mode
		if(mode == mode::create){
			this->ioMode = mode::write;
		}else{
			this->ioMode = mode;
		}

		this->isOpened_var = true;

		this->curPos_var = 0;
	};

	/**
	 * @brief Open file for reading.
	 * This is equivalent to Open(mode::read);
	 * @throw utki::invalid_state - if file is already opened.
	 */
	void open()const{
		const_cast<file*>(this)->open(mode::read);
	}

protected:
	/**
	 * @brief Open file, internal implementation.
	 * Derived class should override this function with its own implementation.
	 * @param mode - opening mode.
	 */
	virtual void openInternal(mode io_mode) = 0;

public:
	/**
	 * @brief Close file.
	 */
	void close()const noexcept{
		if(!this->isOpened()){
			return;
		}
		this->closeInternal();
		this->isOpened_var = false;
	}

protected:
	/**
	 * @brief Close file, internal implementation.
	 * Derived class should override this function with its own implementation.
	 */
	virtual void closeInternal()const noexcept = 0;

public:
	/**
	 * @brief Check if the file is opened.
	 * @return true - if the file is opened.
	 * @return false - otherwise.
	 */
	bool isOpened()const noexcept{
		return this->isOpened_var;
	}

	/**
	 * @brief Returns true if path points to directory.
	 * Determines if the current path is a directory.
	 * This function just checks if the path finishes with '/'
	 * character, and if it does then it is a directory.
	 * Empty path refers to the current directory.
	 * @return true - if current path points to a directory.
	 * @return false - otherwise.
	 */
	bool isDir()const noexcept;

	/**
	 * @brief Get list of files and subdirectories of a directory.
	 * If this file instance holds a path to a directory then this method
	 * can be used to obtain the contents of the directory.
	 * @param maxEntries - maximum number of entries in the returned list. 0 means no limit.
	 * @return The array of string objects representing the directory entries.
	 */
	virtual std::vector<std::string> listDirContents(size_t maxEntries = 0)const;

	/**
	 * @brief Read data from file.
	 * All sane file systems should support file reading.
	 * Returns number of bytes actually read. It always reads the requested number
	 * of bytes, unless end of file reached, in which case the return value will
	 * be less than number of bytes to read was requested by argument.
	 * @param buf - buffer where to store the read data.
	 * @return Number of bytes actually read. Shall always be equal to number of bytes requested to read
	 *         except the case when end of file reached.
	 * @throw utki::invalid_state - if file is not opened.
	 */
	size_t read(utki::Buf<std::uint8_t> buf)const;

protected:
	/**
	 * @brief Read data from file.
	 * Override this function to implement reading routine. This function is called
	 * by Read() method after it has done some safety checks.
	 * It is assumed that the whole passed buffer needs to be filled with data.
	 * @param buf - buffer to fill with read data.
	 * @return number of bytes actually read.
	 */
	virtual size_t readInternal(utki::Buf<std::uint8_t> buf)const{
		throw utki::exception("readInternal(): unsupported");
	}

public:
	/**
	 * @brief Write data to file.
	 * Not all file systems support writing to a file, some file systems are read-only.
	 * @param buf - buffer holding the data to write.
	 * @return Number of bytes actually written. Normally, should always write all the passed data,
	 *         the only reasonable case when less data is written is when there is no more free space
	 *         in the file system.
	 * @throw utki::invalid_state - if file is not opened or opened for reading only.
	 */
	size_t write(const utki::Buf<std::uint8_t> buf);

protected:
	/**
	 * @brief Write data to file.
	 * Override this function to implement writing routine. This function is called
	 * by Write() method after it has done some safety checks.
	 * It is assumed that the whole passed buffer needs to be written to the file.
	 * @param buf - buffer containing the data to write.
	 * @return number of bytes actually written.
	 */
	virtual size_t writeInternal(const utki::Buf<std::uint8_t> buf){
		throw utki::exception("writeInternal(): unsupported");
	}

public:
	/**
	 * @brief Seek forward.
	 * Seek file pointer forward relatively to current position.
	 * There is a default implementation of this function which uses Read() method
	 * to skip the specified number of bytes by reading the data and wasting it away.
	 * It will not go beyond the end of file.
	 * @param numBytesToSeek - number of bytes to skip.
	 * @return number of bytes actually skipped.
	 * @throw utki::invalid_state - if file is not opened.
	 */
	size_t seekForward(size_t numBytesToSeek)const{
		if(!this->isOpened()){
			throw utki::invalid_state("seekForward(): file is not opened");
		}
		size_t ret = this->seekForwardInternal(numBytesToSeek);
		this->curPos_var += ret;
		return ret;
	}

protected:
	/**
	 * @brief Seek forward, internal implementation.
	 * This function is called by SeekForward() after it has done some safety checks.
	 * Derived class may override this function with its own implementation.
	 * Otherwise, there is a default implementation which just reads and wastes
	 * necessary amount of bytes.
	 * @param numBytesToSeek - number of bytes to seek.
	 * @return number of bytes actually skipped.
	 */
	virtual size_t seekForwardInternal(size_t numBytesToSeek)const;

public:

	/**
	 * @brief Seek backwards.
	 * Seek file pointer backwards relatively to he current position. Not all file systems
	 * support seeking backwards.
	 * @param numBytesToSeek - number of bytes to skip.
	 * @return number of bytes actually skipped.
	 * @throw utki::invalid_state - if file is not opened.
	 */
	size_t seekBackward(size_t numBytesToSeek)const{
		if(!this->isOpened()){
			throw utki::invalid_state("seekBackward(): file is not opened");
		}
		size_t ret = this->seekBackwardInternal(numBytesToSeek);
		ASSERT(ret <= this->curPos_var)
		this->curPos_var -= ret;
		return ret;
	}

protected:
	/**
	 * @brief Seek backwards, internal implementation.
	 * This function is called by SeekBackward() after it has done some safety checks.
	 * Derived class may override this function with its own implementation.
	 * @param numBytesToSeek - number of bytes to seek.
	 * @return number of bytes actually skipped.
	 */
	virtual size_t seekBackwardInternal(size_t numBytesToSeek)const{
		throw utki::exception("SeekBackward(): unsupported");
	}

public:

	/**
	 * @brief Seek to the beginning of the file.
	 * There is a default implementation of this operation by just closing and opening the file again.
	 * @throw utki::invalid_state - if file is not opened.
	 */
	void rewind()const{
		if(!this->isOpened()){
			throw utki::invalid_state("Rewind(): file is not opened");
		}
		this->rewindInternal();
		this->curPos_var = 0;
	}

protected:
	/**
	 * @brief Rewind, internal implementation.
	 * This function is called by Rewind() after it has done some safety checks.
	 * Derived class may override this function with its own implementation.
	 */
	virtual void rewindInternal()const{
		mode m = this->ioMode;
		this->close();
		const_cast<file*>(this)->open(m);
	}

public:

	/**
	 * @brief Create directory.
	 * If this file instance is a directory then try to create that directory on
	 * file system. Not all file systems are writable, so not all of them support
	 * directory creation.
	 * @throw utki::invalid_state - if file is opened.
	 */
	virtual void makeDir();

public:
	/**
	 * @brief Load the entire file into the RAM.
	 * @param maxBytesToLoad - maximum bytes to load. Default value is the maximum limit the size_t type can hold.
	 * @return Array containing loaded file data.
	 * @throw utki::invalid_state - if file is already opened.
	 */
	std::vector<std::uint8_t> loadWholeFileIntoMemory(size_t maxBytesToLoad = size_t(-1))const;

	/**
	 * @brief Check for file/directory existence.
	 * @return true - if file/directory exists.
	 * @return false - otherwise.
	 */
	virtual bool exists()const;

	/**
	 * @brief Creates another file object of same implementation.
	 * Creates a 'clone' of the file system implementation represented by this object.
	 * It does not copy current file path or open/close state etc. Spawned object is in
	 * initial state.
	 * @return Newly spawned file object.
	 */
	virtual std::unique_ptr<file> spawn() = 0;

	std::unique_ptr<const file> spawn()const{
		return const_cast<file*>(this)->spawn();
	}

public:
	/**
	 * @brief file guard class.
	 * Use this class to open the file within the particular scope.
	 * As the file guard object goes out of the scope it will close the file in its destructor.
	 * Usage:
	 * @code
	 *	file& fi;//assume we have some papki::file object visible in current scope.
	*	...
	*	{
	*		//assume the 'fi' is closed.
	*		//Let's create the file guard object. This will open the file 'fi'
	*		// for reading by calling fi.Open(papki::file::mode::read) method.
	*		papki::file::Guard fileGuard(fi, papki::file::mode::read);
	*
	*		...
	*		//do some reading
	*		fi.Read(...);
	*
	*		//going out of scope will destroy the 'fileGuard' object. In turn,
	*		//it will automatically close the file 'fi' in its destructor by
	*		//calling fi.Close() method.
	*	}
	* @endcode
	*/
	class guard{
		const file& f;
	public:
		guard(file &file, mode mode);

		guard(const file &file);

		~guard();
	};

	//TODO: deprecated, remove.
	typedef guard Guard;
};

//TODO: deprecated, remove.
typedef file File;

}
<commit_msg>build fix<commit_after>#pragma once

#include <string>
#include <memory>

#include <utki/debug.hpp>
#include <utki/config.hpp>
#include <utki/Buf.hpp>
#include <utki/Unique.hpp>

#include "exception.hpp"

namespace papki{

/**
 * @brief Abstract interface to a file system.
 * This class represents an abstract interface to a file system.
 */
class file{
	mutable std::string path_var;

	mutable bool isOpened_var = false;

	mutable size_t curPos_var = 0;//holds current position from file beginning

public:

	/**
	 * @brief Modes of opening the file.
	 */
	enum class mode{
		read, /// Open existing file for read only.
		READ = read, //TODO: deprecaed, remove.
		write, /// Open existing file for read and write.
		WRITE = write, //TODO: deprecated, remove.
		create, /// Create new file and open it for read and write. If file exists it will be replaced by empty file.
		CREATE = create //TODO: deprecated, remove.
	};

	//TODO: deprecated, remove.
	typedef mode mode;

protected:
	mode ioMode; // mode only matters when file is opened

	/**
	 * @brief Constructor.
	 * @param pathName - initial path to set to the newly created file instance.
	 */
	file(const std::string& pathName = std::string()) :
			path_var(pathName)
	{}

public:
	file(const file&) = delete;
	file(file&&) = delete;
	file& operator=(const file&) = delete;

	/**
	 * @brief Destructor.
	 * This destructor does not call Close() method, but it has an ASSERT which checks if the file is closed.
	 * The file shall be closed upon the object destruction, all the implementations should
	 * assure that.
	 */
	virtual ~file()noexcept{
		ASSERT(!this->isOpened())
	}

	/**
	 * @brief Set the path for this file instance.
	 * @param pathName - the path to a file or directory.
	 */
	void setPath(const std::string& pathName)const{
		if(this->isOpened()){
			throw utki::invalid_state("papki::file::set_path(): Cannot set path when file is opened");
		}

		this->setPathInternal(pathName);
	}

protected:
	virtual void setPathInternal(const std::string& pathName)const{
		this->path_var = pathName;
	}

public:

	/**
	 * @brief Get the current path being held by this file instance.
	 * @return The path this file instance holds.
	 */
	const std::string& path()const noexcept{
		return this->path_var;
	}

	/**
	 * @brief Get current position from beginning of the file.
	 * @return Current position from beginning of the file
	 */
	size_t curPos()const noexcept{
		return this->curPos_var;
	}

	/**
	 * @brief Get file extension.
	 * Returns a string containing the tail part of the file path, everything that
	 * goes after the last dot character ('.') in the file path string.
	 * I.e. if the file path is '/home/user/some.file.txt' then the return value
	 * will be 'txt'.
	 * Note, that on *nix systems if the file name starts with a dot then this file is treated as hidden,
	 * in that case it is thought that the file has no extension. I.e., for example
	 * , if the file path is '/home/user/.myfile' then the file has no extension and this function
	 * will return an empty string. Although, if the file path is '/home/user/.myfile.txt' then the file
	 * does have an extension and the function will return 'txt'.
	 * @return String representing file extension.
	 */
	std::string ext()const;

	/**
	 * @brief Get directory part of the path.
	 * Example: if path is '/home/user/some.file.txt' then the return value
	 * will be '/home/user/'.
	 * @return String representation of directory part of the path.
	 */
	std::string dir()const;

	/**
	 * @brief Get file part of the path.
	 * Example: if path is '/home/user/some.file.txt' then the return value
	 * will be 'some.file.txt'.
	 * @return String representation of directory part of the path.
	 */
	std::string notDir()const;

	/**
	 * @brief Open file.
	 * Opens file for reading/writing or creates the file.
	 * @param io_mode - file opening mode (reading/writing/create).
	 * @throw utki::invalid_state - if file is already opened.
	 */
	void open(mode io_mode){
		if(this->isOpened()){
			throw utki::invalid_state("papki::file::open(): file is already opened");
		}
		if(this->isDir()){
			throw utki::invalid_state("file refers to directory. Directory cannot be opened.");
		}
		this->openInternal(io_mode);

		//set open mode
		if(io_mode == mode::create){
			this->ioMode = mode::write;
		}else{
			this->ioMode = io_mode;
		}

		this->isOpened_var = true;

		this->curPos_var = 0;
	};

	/**
	 * @brief Open file for reading.
	 * This is equivalent to Open(mode::read);
	 * @throw utki::invalid_state - if file is already opened.
	 */
	void open()const{
		const_cast<file*>(this)->open(mode::read);
	}

protected:
	/**
	 * @brief Open file, internal implementation.
	 * Derived class should override this function with its own implementation.
	 * @param mode - opening mode.
	 */
	virtual void openInternal(mode io_mode) = 0;

public:
	/**
	 * @brief Close file.
	 */
	void close()const noexcept{
		if(!this->isOpened()){
			return;
		}
		this->closeInternal();
		this->isOpened_var = false;
	}

protected:
	/**
	 * @brief Close file, internal implementation.
	 * Derived class should override this function with its own implementation.
	 */
	virtual void closeInternal()const noexcept = 0;

public:
	/**
	 * @brief Check if the file is opened.
	 * @return true - if the file is opened.
	 * @return false - otherwise.
	 */
	bool isOpened()const noexcept{
		return this->isOpened_var;
	}

	/**
	 * @brief Returns true if path points to directory.
	 * Determines if the current path is a directory.
	 * This function just checks if the path finishes with '/'
	 * character, and if it does then it is a directory.
	 * Empty path refers to the current directory.
	 * @return true - if current path points to a directory.
	 * @return false - otherwise.
	 */
	bool isDir()const noexcept;

	/**
	 * @brief Get list of files and subdirectories of a directory.
	 * If this file instance holds a path to a directory then this method
	 * can be used to obtain the contents of the directory.
	 * @param maxEntries - maximum number of entries in the returned list. 0 means no limit.
	 * @return The array of string objects representing the directory entries.
	 */
	virtual std::vector<std::string> listDirContents(size_t maxEntries = 0)const;

	/**
	 * @brief Read data from file.
	 * All sane file systems should support file reading.
	 * Returns number of bytes actually read. It always reads the requested number
	 * of bytes, unless end of file reached, in which case the return value will
	 * be less than number of bytes to read was requested by argument.
	 * @param buf - buffer where to store the read data.
	 * @return Number of bytes actually read. Shall always be equal to number of bytes requested to read
	 *         except the case when end of file reached.
	 * @throw utki::invalid_state - if file is not opened.
	 */
	size_t read(utki::Buf<std::uint8_t> buf)const;

protected:
	/**
	 * @brief Read data from file.
	 * Override this function to implement reading routine. This function is called
	 * by Read() method after it has done some safety checks.
	 * It is assumed that the whole passed buffer needs to be filled with data.
	 * @param buf - buffer to fill with read data.
	 * @return number of bytes actually read.
	 */
	virtual size_t readInternal(utki::Buf<std::uint8_t> buf)const{
		throw utki::exception("readInternal(): unsupported");
	}

public:
	/**
	 * @brief Write data to file.
	 * Not all file systems support writing to a file, some file systems are read-only.
	 * @param buf - buffer holding the data to write.
	 * @return Number of bytes actually written. Normally, should always write all the passed data,
	 *         the only reasonable case when less data is written is when there is no more free space
	 *         in the file system.
	 * @throw utki::invalid_state - if file is not opened or opened for reading only.
	 */
	size_t write(const utki::Buf<std::uint8_t> buf);

protected:
	/**
	 * @brief Write data to file.
	 * Override this function to implement writing routine. This function is called
	 * by Write() method after it has done some safety checks.
	 * It is assumed that the whole passed buffer needs to be written to the file.
	 * @param buf - buffer containing the data to write.
	 * @return number of bytes actually written.
	 */
	virtual size_t writeInternal(const utki::Buf<std::uint8_t> buf){
		throw utki::exception("writeInternal(): unsupported");
	}

public:
	/**
	 * @brief Seek forward.
	 * Seek file pointer forward relatively to current position.
	 * There is a default implementation of this function which uses Read() method
	 * to skip the specified number of bytes by reading the data and wasting it away.
	 * It will not go beyond the end of file.
	 * @param numBytesToSeek - number of bytes to skip.
	 * @return number of bytes actually skipped.
	 * @throw utki::invalid_state - if file is not opened.
	 */
	size_t seekForward(size_t numBytesToSeek)const{
		if(!this->isOpened()){
			throw utki::invalid_state("seekForward(): file is not opened");
		}
		size_t ret = this->seekForwardInternal(numBytesToSeek);
		this->curPos_var += ret;
		return ret;
	}

protected:
	/**
	 * @brief Seek forward, internal implementation.
	 * This function is called by SeekForward() after it has done some safety checks.
	 * Derived class may override this function with its own implementation.
	 * Otherwise, there is a default implementation which just reads and wastes
	 * necessary amount of bytes.
	 * @param numBytesToSeek - number of bytes to seek.
	 * @return number of bytes actually skipped.
	 */
	virtual size_t seekForwardInternal(size_t numBytesToSeek)const;

public:

	/**
	 * @brief Seek backwards.
	 * Seek file pointer backwards relatively to he current position. Not all file systems
	 * support seeking backwards.
	 * @param numBytesToSeek - number of bytes to skip.
	 * @return number of bytes actually skipped.
	 * @throw utki::invalid_state - if file is not opened.
	 */
	size_t seekBackward(size_t numBytesToSeek)const{
		if(!this->isOpened()){
			throw utki::invalid_state("seekBackward(): file is not opened");
		}
		size_t ret = this->seekBackwardInternal(numBytesToSeek);
		ASSERT(ret <= this->curPos_var)
		this->curPos_var -= ret;
		return ret;
	}

protected:
	/**
	 * @brief Seek backwards, internal implementation.
	 * This function is called by SeekBackward() after it has done some safety checks.
	 * Derived class may override this function with its own implementation.
	 * @param numBytesToSeek - number of bytes to seek.
	 * @return number of bytes actually skipped.
	 */
	virtual size_t seekBackwardInternal(size_t numBytesToSeek)const{
		throw utki::exception("SeekBackward(): unsupported");
	}

public:

	/**
	 * @brief Seek to the beginning of the file.
	 * There is a default implementation of this operation by just closing and opening the file again.
	 * @throw utki::invalid_state - if file is not opened.
	 */
	void rewind()const{
		if(!this->isOpened()){
			throw utki::invalid_state("Rewind(): file is not opened");
		}
		this->rewindInternal();
		this->curPos_var = 0;
	}

protected:
	/**
	 * @brief Rewind, internal implementation.
	 * This function is called by Rewind() after it has done some safety checks.
	 * Derived class may override this function with its own implementation.
	 */
	virtual void rewindInternal()const{
		mode m = this->ioMode;
		this->close();
		const_cast<file*>(this)->open(m);
	}

public:

	/**
	 * @brief Create directory.
	 * If this file instance is a directory then try to create that directory on
	 * file system. Not all file systems are writable, so not all of them support
	 * directory creation.
	 * @throw utki::invalid_state - if file is opened.
	 */
	virtual void makeDir();

public:
	/**
	 * @brief Load the entire file into the RAM.
	 * @param maxBytesToLoad - maximum bytes to load. Default value is the maximum limit the size_t type can hold.
	 * @return Array containing loaded file data.
	 * @throw utki::invalid_state - if file is already opened.
	 */
	std::vector<std::uint8_t> loadWholeFileIntoMemory(size_t maxBytesToLoad = size_t(-1))const;

	/**
	 * @brief Check for file/directory existence.
	 * @return true - if file/directory exists.
	 * @return false - otherwise.
	 */
	virtual bool exists()const;

	/**
	 * @brief Creates another file object of same implementation.
	 * Creates a 'clone' of the file system implementation represented by this object.
	 * It does not copy current file path or open/close state etc. Spawned object is in
	 * initial state.
	 * @return Newly spawned file object.
	 */
	virtual std::unique_ptr<file> spawn() = 0;

	std::unique_ptr<const file> spawn()const{
		return const_cast<file*>(this)->spawn();
	}

public:
	/**
	 * @brief file guard class.
	 * Use this class to open the file within the particular scope.
	 * As the file guard object goes out of the scope it will close the file in its destructor.
	 * Usage:
	 * @code
	 *	file& fi;//assume we have some papki::file object visible in current scope.
	*	...
	*	{
	*		//assume the 'fi' is closed.
	*		//Let's create the file guard object. This will open the file 'fi'
	*		// for reading by calling fi.Open(papki::file::mode::read) method.
	*		papki::file::Guard fileGuard(fi, papki::file::mode::read);
	*
	*		...
	*		//do some reading
	*		fi.Read(...);
	*
	*		//going out of scope will destroy the 'fileGuard' object. In turn,
	*		//it will automatically close the file 'fi' in its destructor by
	*		//calling fi.Close() method.
	*	}
	* @endcode
	*/
	class guard{
		const file& f;
	public:
		guard(file &file, mode mode);

		guard(const file &file);

		~guard();
	};

	//TODO: deprecated, remove.
	typedef guard Guard;
};

//TODO: deprecated, remove.
typedef file File;

}
<|endoftext|>


<commit_before>/*
 * W.J. van der Laan 2011-2012
 */
#include "bitcoingui.h"
#include "clientmodel.h"
#include "walletmodel.h"
#include "optionsmodel.h"
#include "guiutil.h"
#include "guiconstants.h"

#include "init.h"
#include "ui_interface.h"
#include "qtipcserver.h"

#include <QApplication>
#include <QMessageBox>
#if QT_VERSION < 0x050000
#include <QTextCodec>
#endif
#include <QLocale>
#include <QTranslator>
#include <QSplashScreen>
#include <QLibraryInfo>

#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
#define _BITCOIN_QT_PLUGINS_INCLUDED
#define __INSURE__
#include <QtPlugin>
Q_IMPORT_PLUGIN(qcncodecs)
Q_IMPORT_PLUGIN(qjpcodecs)
Q_IMPORT_PLUGIN(qtwcodecs)
Q_IMPORT_PLUGIN(qkrcodecs)
Q_IMPORT_PLUGIN(qtaccessiblewidgets)
#endif

// Need a global reference for the notifications to find the GUI
static BitcoinGUI *guiref;
static QSplashScreen *splashref;

static void ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style)
{
    // Message from network thread
    if(guiref)
    {
        bool modal = (style & CClientUIInterface::MODAL);
        // In case of modal message, use blocking connection to wait for user to click a button
        QMetaObject::invokeMethod(guiref, "message",
                                   modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
                                   Q_ARG(QString, QString::fromStdString(caption)),
                                   Q_ARG(QString, QString::fromStdString(message)),
                                   Q_ARG(unsigned int, style));
    }
    else
    {
        printf("%s: %s\n", caption.c_str(), message.c_str());
        fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
    }
}

static bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
{
    if(!guiref)
        return false;
    if(nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon)
        return true;
    bool payFee = false;

    QMetaObject::invokeMethod(guiref, "askFee", GUIUtil::blockingGUIThreadConnection(),
                               Q_ARG(qint64, nFeeRequired),
                               Q_ARG(bool*, &payFee));

    return payFee;
}

static void ThreadSafeHandleURI(const std::string& strURI)
{
    if(!guiref)
        return;

    QMetaObject::invokeMethod(guiref, "handleURI", GUIUtil::blockingGUIThreadConnection(),
                               Q_ARG(QString, QString::fromStdString(strURI)));
}

static void InitMessage(const std::string &message)
{
    if(splashref)
    {
        splashref->showMessage(QString::fromStdString(message), Qt::AlignBottom|Qt::AlignHCenter, QColor(255,255,200));
        QApplication::instance()->processEvents();
    }
}

static void QueueShutdown()
{
    QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
}

/*
   Translate string to current locale using Qt.
 */
static std::string Translate(const char* psz)
{
    return QCoreApplication::translate("bitcoin-core", psz).toStdString();
}

/* Handle runaway exceptions. Shows a message box with the problem and quits the program.
 */
static void handleRunawayException(std::exception *e)
{
    PrintExceptionContinue(e, "Runaway exception");
    QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. BottleCaps can no longer continue safely and will quit.") + QString("\n\n") + QString::fromStdString(strMiscWarning));
    exit(1);
}

#ifndef BITCOIN_QT_TEST
int main(int argc, char *argv[])
{
    // Do this early as we don't want to bother initializing if we are just calling IPC
    ipcScanRelay(argc, argv);

#if QT_VERSION < 0x050000
    // Internal string conversion is all UTF-8
    QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
    QTextCodec::setCodecForCStrings(QTextCodec::codecForTr());
#endif

    Q_INIT_RESOURCE(bitcoin);
    QApplication app(argc, argv);

    // Install global event filter that makes sure that long tooltips can be word-wrapped
    app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app));

    // Command-line options take precedence:
    ParseParameters(argc, argv);

    // ... then bitcoin.conf:
    if (!boost::filesystem::is_directory(GetDataDir(false)))
    {
        // This message can not be translated, as translation is not initialized yet
        // (which not yet possible because lang=XX can be overridden in bitcoin.conf in the data directory)
        QMessageBox::critical(0, "BottleCaps",
                              QString("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"])));
        return 1;
    }
    ReadConfigFile(mapArgs, mapMultiArgs);

    // Application identification (must be set before OptionsModel is initialized,
    // as it is used to locate QSettings)
    app.setOrganizationName("BottleCaps");
    app.setOrganizationDomain("BottleCaps.su");
    if(GetBoolArg("-testnet")) // Separate UI settings for testnet
        app.setApplicationName("BottleCaps-Qt-testnet");
    else
        app.setApplicationName("BottleCaps-Qt");

    // ... then GUI settings:
    OptionsModel optionsModel;

    // Get desired locale (e.g. "de_DE") from command line or use system locale
    QString lang_territory = QString::fromStdString(GetArg("-lang", QLocale::system().name().toStdString()));
    QString lang = lang_territory;
    // Convert to "de" only by truncating "_DE"
    lang.truncate(lang_territory.lastIndexOf('_'));

    QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
    // Load language files for configured locale:
    // - First load the translator for the base language, without territory
    // - Then load the more specific locale translator

    // Load e.g. qt_de.qm
    if (qtTranslatorBase.load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
        app.installTranslator(&qtTranslatorBase);

    // Load e.g. qt_de_DE.qm
    if (qtTranslator.load("qt_" + lang_territory, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
        app.installTranslator(&qtTranslator);

    // Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in bitcoin.qrc)
    if (translatorBase.load(lang, ":/translations/"))
        app.installTranslator(&translatorBase);

    // Load e.g. bitcoin_de_DE.qm (shortcut "de_DE" needs to be defined in bitcoin.qrc)
    if (translator.load(lang_territory, ":/translations/"))
        app.installTranslator(&translator);

    // Subscribe to global signals from core
    uiInterface.ThreadSafeMessageBox.connect(ThreadSafeMessageBox);
    uiInterface.ThreadSafeAskFee.connect(ThreadSafeAskFee);
    uiInterface.ThreadSafeHandleURI.connect(ThreadSafeHandleURI);
    uiInterface.InitMessage.connect(InitMessage);
    uiInterface.QueueShutdown.connect(QueueShutdown);
    uiInterface.Translate.connect(Translate);

    // Show help message immediately after parsing command-line options (for "-lang") and setting locale,
    // but before showing splash screen.
    if (mapArgs.count("-?") || mapArgs.count("--help"))
    {
        GUIUtil::HelpMessageBox help;
        help.showOrPrint();
        return 1;
    }

    QSplashScreen splash(QPixmap(":/images/splash"), 0);
    if (GetBoolArg("-splash", true) && !GetBoolArg("-min"))
    {
        splash.show();
        splash.setAutoFillBackground(true);
        splashref = &splash;
    }

    app.processEvents();

    app.setQuitOnLastWindowClosed(false);

    try
    {
        // Regenerate startup link, to fix links to old versions
        if (GUIUtil::GetStartOnSystemStartup())
            GUIUtil::SetStartOnSystemStartup(true);

        BitcoinGUI window;
        guiref = &window;
        if(AppInit2())
        {
            {
                // Put this in a block, so that the Model objects are cleaned up before
                // calling Shutdown().

                optionsModel.Upgrade(); // Must be done after AppInit2

                if (splashref)
                    splash.finish(&window);

                ClientModel clientModel(&optionsModel);
                WalletModel walletModel(pwalletMain, &optionsModel);

                window.setClientModel(&clientModel);
                window.setWalletModel(&walletModel);

                // If -min option passed, start window minimized.
                if(GetBoolArg("-min"))
                {
                    window.showMinimized();
                }
                else
                {
                    window.show();
                }

                // Place this here as guiref has to be defined if we don't want to lose URIs
                ipcInit(argc, argv);

                app.exec();

                window.hide();
                window.setClientModel(0);
                window.setWalletModel(0);
                guiref = 0;
            }
            // Shutdown the core and its threads, but don't exit Bitcoin-Qt here
            Shutdown(NULL);
        }
        else
        {
            return 1;
        }
    } catch (std::exception& e) {
        handleRunawayException(&e);
    } catch (...) {
        handleRunawayException(NULL);
    }
    return 0;
}
#endif // BITCOIN_QT_TEST
<commit_msg>Version displayed at startup and text black<commit_after>/*
 * W.J. van der Laan 2011-2012
 */
#include "bitcoingui.h"
#include "clientmodel.h"
#include "walletmodel.h"
#include "optionsmodel.h"
#include "guiutil.h"
#include "guiconstants.h"

#include "init.h"
#include "ui_interface.h"
#include "qtipcserver.h"

#include <QApplication>
#include <QMessageBox>
#if QT_VERSION < 0x050000
#include <QTextCodec>
#endif
#include <QLocale>
#include <QTranslator>
#include <QSplashScreen>
#include <QLibraryInfo>

#if defined(BITCOIN_NEED_QT_PLUGINS) && !defined(_BITCOIN_QT_PLUGINS_INCLUDED)
#define _BITCOIN_QT_PLUGINS_INCLUDED
#define __INSURE__
#include <QtPlugin>
Q_IMPORT_PLUGIN(qcncodecs)
Q_IMPORT_PLUGIN(qjpcodecs)
Q_IMPORT_PLUGIN(qtwcodecs)
Q_IMPORT_PLUGIN(qkrcodecs)
Q_IMPORT_PLUGIN(qtaccessiblewidgets)
#endif

// Need a global reference for the notifications to find the GUI
static BitcoinGUI *guiref;
static QSplashScreen *splashref;

static void ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style)
{
    // Message from network thread
    if(guiref)
    {
        bool modal = (style & CClientUIInterface::MODAL);
        // In case of modal message, use blocking connection to wait for user to click a button
        QMetaObject::invokeMethod(guiref, "message",
                                   modal ? GUIUtil::blockingGUIThreadConnection() : Qt::QueuedConnection,
                                   Q_ARG(QString, QString::fromStdString(caption)),
                                   Q_ARG(QString, QString::fromStdString(message)),
                                   Q_ARG(unsigned int, style));
    }
    else
    {
        printf("%s: %s\n", caption.c_str(), message.c_str());
        fprintf(stderr, "%s: %s\n", caption.c_str(), message.c_str());
    }
}

static bool ThreadSafeAskFee(int64 nFeeRequired, const std::string& strCaption)
{
    if(!guiref)
        return false;
    if(nFeeRequired < MIN_TX_FEE || nFeeRequired <= nTransactionFee || fDaemon)
        return true;
    bool payFee = false;

    QMetaObject::invokeMethod(guiref, "askFee", GUIUtil::blockingGUIThreadConnection(),
                               Q_ARG(qint64, nFeeRequired),
                               Q_ARG(bool*, &payFee));

    return payFee;
}

static void ThreadSafeHandleURI(const std::string& strURI)
{
    if(!guiref)
        return;

    QMetaObject::invokeMethod(guiref, "handleURI", GUIUtil::blockingGUIThreadConnection(),
                               Q_ARG(QString, QString::fromStdString(strURI)));
}

static void InitMessage(const std::string &message)
{
    if(splashref)
    {
        splashref->showMessage(QString::fromStdString(message+'\n'+'\n') + QString::fromStdString(FormatFullVersion().c_str()), Qt::AlignBottom|Qt::AlignHCenter, QColor(0,0,0));
        QApplication::instance()->processEvents();
    }
}

static void QueueShutdown()
{
    QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection);
}

/*
   Translate string to current locale using Qt.
 */
static std::string Translate(const char* psz)
{
    return QCoreApplication::translate("bitcoin-core", psz).toStdString();
}

/* Handle runaway exceptions. Shows a message box with the problem and quits the program.
 */
static void handleRunawayException(std::exception *e)
{
    PrintExceptionContinue(e, "Runaway exception");
    QMessageBox::critical(0, "Runaway exception", BitcoinGUI::tr("A fatal error occurred. BottleCaps can no longer continue safely and will quit.") + QString("\n\n") + QString::fromStdString(strMiscWarning));
    exit(1);
}

#ifndef BITCOIN_QT_TEST
int main(int argc, char *argv[])
{
    // Do this early as we don't want to bother initializing if we are just calling IPC
    ipcScanRelay(argc, argv);

#if QT_VERSION < 0x050000
    // Internal string conversion is all UTF-8
    QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
    QTextCodec::setCodecForCStrings(QTextCodec::codecForTr());
#endif

    Q_INIT_RESOURCE(bitcoin);
    QApplication app(argc, argv);

    // Install global event filter that makes sure that long tooltips can be word-wrapped
    app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app));

    // Command-line options take precedence:
    ParseParameters(argc, argv);

    // ... then bitcoin.conf:
    if (!boost::filesystem::is_directory(GetDataDir(false)))
    {
        // This message can not be translated, as translation is not initialized yet
        // (which not yet possible because lang=XX can be overridden in bitcoin.conf in the data directory)
        QMessageBox::critical(0, "BottleCaps",
                              QString("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(mapArgs["-datadir"])));
        return 1;
    }
    ReadConfigFile(mapArgs, mapMultiArgs);

    // Application identification (must be set before OptionsModel is initialized,
    // as it is used to locate QSettings)
    app.setOrganizationName("BottleCaps");
    app.setOrganizationDomain("BottleCaps.su");
    if(GetBoolArg("-testnet")) // Separate UI settings for testnet
        app.setApplicationName("BottleCaps-Qt-testnet");
    else
        app.setApplicationName("BottleCaps-Qt");

    // ... then GUI settings:
    OptionsModel optionsModel;

    // Get desired locale (e.g. "de_DE") from command line or use system locale
    QString lang_territory = QString::fromStdString(GetArg("-lang", QLocale::system().name().toStdString()));
    QString lang = lang_territory;
    // Convert to "de" only by truncating "_DE"
    lang.truncate(lang_territory.lastIndexOf('_'));

    QTranslator qtTranslatorBase, qtTranslator, translatorBase, translator;
    // Load language files for configured locale:
    // - First load the translator for the base language, without territory
    // - Then load the more specific locale translator

    // Load e.g. qt_de.qm
    if (qtTranslatorBase.load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
        app.installTranslator(&qtTranslatorBase);

    // Load e.g. qt_de_DE.qm
    if (qtTranslator.load("qt_" + lang_territory, QLibraryInfo::location(QLibraryInfo::TranslationsPath)))
        app.installTranslator(&qtTranslator);

    // Load e.g. bitcoin_de.qm (shortcut "de" needs to be defined in bitcoin.qrc)
    if (translatorBase.load(lang, ":/translations/"))
        app.installTranslator(&translatorBase);

    // Load e.g. bitcoin_de_DE.qm (shortcut "de_DE" needs to be defined in bitcoin.qrc)
    if (translator.load(lang_territory, ":/translations/"))
        app.installTranslator(&translator);

    // Subscribe to global signals from core
    uiInterface.ThreadSafeMessageBox.connect(ThreadSafeMessageBox);
    uiInterface.ThreadSafeAskFee.connect(ThreadSafeAskFee);
    uiInterface.ThreadSafeHandleURI.connect(ThreadSafeHandleURI);
    uiInterface.InitMessage.connect(InitMessage);
    uiInterface.QueueShutdown.connect(QueueShutdown);
    uiInterface.Translate.connect(Translate);

    // Show help message immediately after parsing command-line options (for "-lang") and setting locale,
    // but before showing splash screen.
    if (mapArgs.count("-?") || mapArgs.count("--help"))
    {
        GUIUtil::HelpMessageBox help;
        help.showOrPrint();
        return 1;
    }

    QSplashScreen splash(QPixmap(":/images/splash"), 0);
    if (GetBoolArg("-splash", true) && !GetBoolArg("-min"))
    {
        splash.show();
        splash.setAutoFillBackground(true);
        splashref = &splash;
    }

    app.processEvents();

    app.setQuitOnLastWindowClosed(false);

    try
    {
        // Regenerate startup link, to fix links to old versions
        if (GUIUtil::GetStartOnSystemStartup())
            GUIUtil::SetStartOnSystemStartup(true);

        BitcoinGUI window;
        guiref = &window;
        if(AppInit2())
        {
            {
                // Put this in a block, so that the Model objects are cleaned up before
                // calling Shutdown().

                optionsModel.Upgrade(); // Must be done after AppInit2

                if (splashref)
                    splash.finish(&window);

                ClientModel clientModel(&optionsModel);
                WalletModel walletModel(pwalletMain, &optionsModel);

                window.setClientModel(&clientModel);
                window.setWalletModel(&walletModel);

                // If -min option passed, start window minimized.
                if(GetBoolArg("-min"))
                {
                    window.showMinimized();
                }
                else
                {
                    window.show();
                }

                // Place this here as guiref has to be defined if we don't want to lose URIs
                ipcInit(argc, argv);

                app.exec();

                window.hide();
                window.setClientModel(0);
                window.setWalletModel(0);
                guiref = 0;
            }
            // Shutdown the core and its threads, but don't exit Bitcoin-Qt here
            Shutdown(NULL);
        }
        else
        {
            return 1;
        }
    } catch (std::exception& e) {
        handleRunawayException(&e);
    } catch (...) {
        handleRunawayException(NULL);
    }
    return 0;
}
#endif // BITCOIN_QT_TEST
<|endoftext|>