<commit_before>#include "client.h"
#include "discovery.h"
#include "types.h"

#include <QUdpSocket>
#include <QBuffer>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QTimer>
#include <QHostInfo>

#ifdef Q_OS_WIN
#include <qjson/Parser>
#else // Q_OS_WIN
#include <QJson/parser.h>
#endif // Q_OS_WIN
#include <QDebug>

const QUrl masterUrl = QUrl("https://mplane.informatik.hs-augsburg.de:16001/register");
const quint32 magic = 0x1337;
const quint8 version = 0;

struct NegotiationPacket {
    quint16 magic;
    quint8 version;

    char host[64];
    quint16 port;

    quint16 ports[10];
};

class Client::Private : public QObject
{
    Q_OBJECT

public:
    Private(Client* q)
    : q(q)
    , status(Client::Unregistered)
    , networkAccessManager(new QNetworkAccessManager(q))
    {
        connect(&discovery, SIGNAL(finished()), this, SLOT(onDiscoveryFinished()));
        connect(&managerSocket, SIGNAL(readyRead()), this, SLOT(onDatagramReady()));
        connect(&aliveTimer, SIGNAL(timeout()), this, SLOT(onAliveTimer()));

        aliveTimer.setInterval(120 * 1000);
        aliveTimer.start();
    }

    Client* q;

    // Properties
    Client::Status status;
    RemoteInfoList remoteInfo;
    QNetworkAccessManager* networkAccessManager;
    Discovery discovery;
    QUdpSocket managerSocket;
    QTimer aliveTimer;
    QHostInfo aliveInfo;

    // Functions
    void setStatus(Client::Status status);

    void processDatagram(QBuffer& buffer, const QHostAddress& host, quint16 port);
    void processNegotiation(const NegotiationPacket& packet);

public slots:
    void onDatagramReady();
    void onLookupFinished(const QHostInfo &host);
    void onAliveTimer();
    void onDiscoveryFinished();
    void onRegisterFinished();
    void onRegisterError(QNetworkReply::NetworkError error);
};

void Client::Private::setStatus(Client::Status status)
{
    if ( this->status == status )
        return;

    this->status = status;
    emit q->statusChanged();
}

void Client::Private::processDatagram(QBuffer& buffer, const QHostAddress &host, quint16 port)
{
    // TODO: byte order checking
    NegotiationPacket packet;
    buffer.read((char*)&packet, sizeof(packet));

    if (packet.magic != magic) {
        qDebug() << "Received invalid packet from" << host.toString() << port;
        return;
    }

    if (packet.version != version) {
        qDebug() << "Packet version is different" << host.toString() << port;
        return;
    }

    processNegotiation(packet);
}

void Client::Private::processNegotiation(const NegotiationPacket &packet)
{
    qDebug() << "Received valid packet from" << packet.host << packet.port;

    // Post a alive-packet back and hope it gets through
    managerSocket.writeDatagram(QByteArray(), QHostAddress(packet.host), packet.port);
}

void Client::Private::onDatagramReady()
{
    while (managerSocket.hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(managerSocket.pendingDatagramSize());

        QHostAddress host;
        quint16 port;
        managerSocket.readDatagram(datagram.data(), datagram.size(), &host, &port);

        // Process the datagram using a buffer
        QBuffer buffer(&datagram);
        buffer.open(QIODevice::ReadOnly);
        processDatagram(buffer, host, port);
    }
}

void Client::Private::onLookupFinished(const QHostInfo& host)
{
    aliveInfo = host;

    if ( !host.addresses().isEmpty() )
        managerSocket.connectToHost(host.addresses().first(), 16000);

    onAliveTimer();
}

void Client::Private::onAliveTimer()
{
    if (aliveInfo.addresses().isEmpty()) {
        aliveInfo.lookupHost("mplane.informatik.hs-augsburg.de", this, SLOT(onLookupFinished(QHostInfo)));
        qDebug() << "Looking up alive host";
    } else {
        managerSocket.write(QByteArray());
        qDebug() << "Alive packet sent";
    }
}

void Client::Private::onDiscoveryFinished()
{
    q->register_();
}

void Client::Private::onRegisterFinished()
{
    bool ok = false;
    QJson::Parser parser;

    // Parse the reply data
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
    QVariant root = parser.parse(reply, &ok);
    if ( ok ) {
        setStatus(Client::Registered);

        RemoteInfoList remotes;
        foreach(const QVariant& entry, root.toList()) {
            RemoteInfo info;
            info.peerAddress = QHostAddress(entry.toString());

            remotes.append(info);
        }

        // Update the remote list
        if (!remotes.isEmpty())
            q->setRemoteInfo(remotes);

        setStatus(Client::Registered);
    } else
        setStatus(Client::Unregistered);
}

void Client::Private::onRegisterError(QNetworkReply::NetworkError error)
{
    setStatus(Client::Unregistered);

    qDebug() << "Registration error" << enumToString(QNetworkReply, "NetworkError", error);
}

Client::Client(QObject *parent)
: QObject(parent)
, d(new Private(this))
{
}

Client::~Client()
{
    delete d;
}

Client *Client::instance()
{
    static Client* ins = NULL;

    if ( !ins )
        ins = new Client();

    return ins;
}

bool Client::init()
{
    bool ok = false;
    ok |= d->managerSocket.bind(34366);

    // Cheat ...
    d->onAliveTimer();

    return ok;
}

Client::Status Client::status() const
{
    return d->status;
}

QNetworkAccessManager *Client::networkAccessManager() const
{
    return d->networkAccessManager;
}

QAbstractSocket *Client::managerSocket() const
{
    return &d->managerSocket;
}

void Client::setRemoteInfo(const RemoteInfoList &remoteInfo)
{
    d->remoteInfo = remoteInfo;
}

RemoteInfoList Client::remoteInfo() const
{
    return d->remoteInfo;
}

void Client::registerWithDiscovery()
{
    d->discovery.discover();
}

void Client::register_()
{
    // TODO: Fill data. Available tests, language, etc.
    QByteArray data = "ttl=60&";

    /*const QMetaObject* meta = &Discovery::staticMetaObject;
    QMetaEnum en = meta->enumerator(meta->indexOfEnumerator("DataType"));

    QHashIterator<Discovery::DataType, QVariant> iter(d->discovery.data());
    while (iter.hasNext()) {
        iter.next();

        // TODO: escapings
        data.append(en.valueToKey(iter.key()));
        data.append('=');
        data.append(iter.value().toString());
        data.append('&');
    }*/

    QNetworkRequest request(masterUrl);
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");

    QNetworkReply* reply = d->networkAccessManager->post(request, data);
    reply->ignoreSslErrors(); // TODO: Remove the evil
    connect(reply, SIGNAL(finished()), d, SLOT(onRegisterFinished()));
    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), d, SLOT(onRegisterError(QNetworkReply::NetworkError)));
}

void Client::unregister()
{
}

#include "client.moc"
<commit_msg>Fixed QJson includes.<commit_after>#include "client.h"
#include "discovery.h"
#include "types.h"

#include <QUdpSocket>
#include <QBuffer>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QTimer>
#include <QHostInfo>

#ifdef Q_OS_WIN
#include <QJson/Parser>
#else // Q_OS_WIN
#include <qjson/parser.h>
#endif // Q_OS_WIN
#include <QDebug>

const QUrl masterUrl = QUrl("https://mplane.informatik.hs-augsburg.de:16001/register");
const quint32 magic = 0x1337;
const quint8 version = 0;

struct NegotiationPacket {
    quint16 magic;
    quint8 version;

    char host[64];
    quint16 port;

    quint16 ports[10];
};

class Client::Private : public QObject
{
    Q_OBJECT

public:
    Private(Client* q)
    : q(q)
    , status(Client::Unregistered)
    , networkAccessManager(new QNetworkAccessManager(q))
    {
        connect(&discovery, SIGNAL(finished()), this, SLOT(onDiscoveryFinished()));
        connect(&managerSocket, SIGNAL(readyRead()), this, SLOT(onDatagramReady()));
        connect(&aliveTimer, SIGNAL(timeout()), this, SLOT(onAliveTimer()));

        aliveTimer.setInterval(120 * 1000);
        aliveTimer.start();
    }

    Client* q;

    // Properties
    Client::Status status;
    RemoteInfoList remoteInfo;
    QNetworkAccessManager* networkAccessManager;
    Discovery discovery;
    QUdpSocket managerSocket;
    QTimer aliveTimer;
    QHostInfo aliveInfo;

    // Functions
    void setStatus(Client::Status status);

    void processDatagram(QBuffer& buffer, const QHostAddress& host, quint16 port);
    void processNegotiation(const NegotiationPacket& packet);

public slots:
    void onDatagramReady();
    void onLookupFinished(const QHostInfo &host);
    void onAliveTimer();
    void onDiscoveryFinished();
    void onRegisterFinished();
    void onRegisterError(QNetworkReply::NetworkError error);
};

void Client::Private::setStatus(Client::Status status)
{
    if ( this->status == status )
        return;

    this->status = status;
    emit q->statusChanged();
}

void Client::Private::processDatagram(QBuffer& buffer, const QHostAddress &host, quint16 port)
{
    // TODO: byte order checking
    NegotiationPacket packet;
    buffer.read((char*)&packet, sizeof(packet));

    if (packet.magic != magic) {
        qDebug() << "Received invalid packet from" << host.toString() << port;
        return;
    }

    if (packet.version != version) {
        qDebug() << "Packet version is different" << host.toString() << port;
        return;
    }

    processNegotiation(packet);
}

void Client::Private::processNegotiation(const NegotiationPacket &packet)
{
    qDebug() << "Received valid packet from" << packet.host << packet.port;

    // Post a alive-packet back and hope it gets through
    managerSocket.writeDatagram(QByteArray(), QHostAddress(packet.host), packet.port);
}

void Client::Private::onDatagramReady()
{
    while (managerSocket.hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(managerSocket.pendingDatagramSize());

        QHostAddress host;
        quint16 port;
        managerSocket.readDatagram(datagram.data(), datagram.size(), &host, &port);

        // Process the datagram using a buffer
        QBuffer buffer(&datagram);
        buffer.open(QIODevice::ReadOnly);
        processDatagram(buffer, host, port);
    }
}

void Client::Private::onLookupFinished(const QHostInfo& host)
{
    aliveInfo = host;

    if ( !host.addresses().isEmpty() )
        managerSocket.connectToHost(host.addresses().first(), 16000);

    onAliveTimer();
}

void Client::Private::onAliveTimer()
{
    if (aliveInfo.addresses().isEmpty()) {
        aliveInfo.lookupHost("mplane.informatik.hs-augsburg.de", this, SLOT(onLookupFinished(QHostInfo)));
        qDebug() << "Looking up alive host";
    } else {
        managerSocket.write(QByteArray());
        qDebug() << "Alive packet sent";
    }
}

void Client::Private::onDiscoveryFinished()
{
    q->register_();
}

void Client::Private::onRegisterFinished()
{
    bool ok = false;
    QJson::Parser parser;

    // Parse the reply data
    QNetworkReply* reply = qobject_cast<QNetworkReply*>(sender());
    QVariant root = parser.parse(reply, &ok);
    if ( ok ) {
        setStatus(Client::Registered);

        RemoteInfoList remotes;
        foreach(const QVariant& entry, root.toList()) {
            RemoteInfo info;
            info.peerAddress = QHostAddress(entry.toString());

            remotes.append(info);
        }

        // Update the remote list
        if (!remotes.isEmpty())
            q->setRemoteInfo(remotes);

        setStatus(Client::Registered);
    } else
        setStatus(Client::Unregistered);
}

void Client::Private::onRegisterError(QNetworkReply::NetworkError error)
{
    setStatus(Client::Unregistered);

    qDebug() << "Registration error" << enumToString(QNetworkReply, "NetworkError", error);
}

Client::Client(QObject *parent)
: QObject(parent)
, d(new Private(this))
{
}

Client::~Client()
{
    delete d;
}

Client *Client::instance()
{
    static Client* ins = NULL;

    if ( !ins )
        ins = new Client();

    return ins;
}

bool Client::init()
{
    bool ok = false;
    ok |= d->managerSocket.bind(34366);

    // Cheat ...
    d->onAliveTimer();

    return ok;
}

Client::Status Client::status() const
{
    return d->status;
}

QNetworkAccessManager *Client::networkAccessManager() const
{
    return d->networkAccessManager;
}

QAbstractSocket *Client::managerSocket() const
{
    return &d->managerSocket;
}

void Client::setRemoteInfo(const RemoteInfoList &remoteInfo)
{
    d->remoteInfo = remoteInfo;
}

RemoteInfoList Client::remoteInfo() const
{
    return d->remoteInfo;
}

void Client::registerWithDiscovery()
{
    d->discovery.discover();
}

void Client::register_()
{
    // TODO: Fill data. Available tests, language, etc.
    QByteArray data = "ttl=60&";

    /*const QMetaObject* meta = &Discovery::staticMetaObject;
    QMetaEnum en = meta->enumerator(meta->indexOfEnumerator("DataType"));

    QHashIterator<Discovery::DataType, QVariant> iter(d->discovery.data());
    while (iter.hasNext()) {
        iter.next();

        // TODO: escapings
        data.append(en.valueToKey(iter.key()));
        data.append('=');
        data.append(iter.value().toString());
        data.append('&');
    }*/

    QNetworkRequest request(masterUrl);
    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");

    QNetworkReply* reply = d->networkAccessManager->post(request, data);
    reply->ignoreSslErrors(); // TODO: Remove the evil
    connect(reply, SIGNAL(finished()), d, SLOT(onRegisterFinished()));
    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), d, SLOT(onRegisterError(QNetworkReply::NetworkError)));
}

void Client::unregister()
{
}

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


<commit_before>#include <climits>
#include <iostream>
#include <atomic>
#include <thread>
#include <chrono>
#include <set>

#include <wibble/commandline/parser.h>

#include <elevator/elevator.h>
#include <elevator/scheduler.h>
#include <elevator/udptools.h>
#include <elevator/udpqueue.h>

namespace elevator {

using namespace wibble;
using namespace wibble::commandline;
using namespace udp;

struct Main {

    const Address commSend{ IPv4Address::any, Port{ 64123 } };
    const Address commRcv{ IPv4Address::any, Port{ 64125 } };
    const Address commBroadcast{ IPv4Address::broadcast, Port{ 64125 } };

    const Port stateChangePort{ 64016 };
    const Port commandPort{ 64017 };

    StandardParser opts;
    OptionGroup *execution;
    IntOption *optNodes;
    BoolOption *avoidRecovery;
    const int peerMsg = 1000;
    std::set< IPv4Address > peerAddresses;
    int id = INT_MIN;
    int nodes = 1;

    Main( int argc, const char **argv ) : opts( "elevator", "0.1" ) {
        // setup options
        execution = opts.createGroup( "Execution options" );
        optNodes = execution->add< IntOption >(
                "nodes", 'n', "nodes", "",
                "specifies number of elevator nodes to expect" );

        avoidRecovery = execution->add< BoolOption >(
                "avoid recovery", 0, "avoid-recovery", "",
                "avoid auto-recovery when program is killed (do not fork)" );

        opts.usage = "";
        opts.description = "Elevator control software as a project for the "
                           "TTK4145 Real-Time Programming at NTNU. Controls "
                           "multiple elevator connected with local network.\n"
                           "(c) 2014, Vladimír Štill and Sameh Khalil\n"
                           "https://github.com/vlstill/ttk4145/tree/master/project";

        opts.add( execution );

        // parse options
        try {
            opts.parse( argc, argv );
        } catch ( exception::BadOption &ex ) {
            std::cerr << "FATAL: " << ex.fullInfo() << std::endl;
            exit( 1 );
        }
        if ( opts.help->boolValue() || opts.version->boolValue() )
            exit( 0 );
    }

    // initPhase == 0 means we don't know other peers
    // initPhase == 1 means we know but they may not know (so we must wait)
    // initPhase == 2 means all peers know other peers
    void sendToPeers( std::atomic< int > *initPhase ) {
        Socket snd_sock{ commSend, true };
        snd_sock.enableBroadcast();
        while( *initPhase < 2 ) {
            Packet pack( sizeof( int ) );
            pack.address() = commBroadcast;
            pack.get< int >() = peerMsg + (*initPhase > 0 ? 1 : 0);
            bool sent = snd_sock.sendPacket( pack );
            assert( sent, "send failed" );
            std::this_thread::sleep_for( std::chrono::milliseconds( 500 ) );
        }
    }

    void  findPeersListener( std::atomic< int > *initPhase ) {
        Socket rd_sock{ commRcv, true };
        std::set< IPv4Address > barrier;

        while ( *initPhase < 2 ) {
            Packet pack = rd_sock.recvPacketWithTimeout( 300 );
            if ( pack.size() != 0 ) {
                if ( pack.get< int >() == peerMsg ) {
                    peerAddresses.insert( pack.address().ip() );
                } else if ( pack.get< int >() == peerMsg + 1 ) {
                    peerAddresses.insert( pack.address().ip() ); // it might still be that we dont know
                    barrier.insert( pack.address().ip() );
                }
                if ( int( barrier.size() ) == nodes )
                    *initPhase = 2;
                else if ( int( peerAddresses.size() ) == nodes )
                    *initPhase = 1;
            }
        }
    }

    void main() {

        if ( optNodes->boolValue() && optNodes->intValue() > 1 ) {
            nodes = optNodes->intValue();
            std::atomic< int > initPhase{ 0 };
            std::thread findPeers( &Main::sendToPeers, this, &initPhase );
            findPeersListener( &initPhase );
            findPeers.join();

            auto localAddrs = IPv4Address::getMachineAddresses();
            int i = 0;
            // the set is sorted (guaranteed by C++) and same on all elevators
            for ( auto addr : peerAddresses ) {
                if ( localAddrs.find( addr ) != localAddrs.end() ) {
                    id = i;
                    break;
                }
                ++i;
            }
            assert_leq( 0, id, "Could not assing ID" );
            std::cout << "detected id " << id << std::endl;
        } else {
            id = 0;
        }

        if ( avoidRecovery->boolValue() ) {
            runElevator( id );
        } else {
            assert_unimplemented();
        }
    }

    void runElevator( int id ) {
        std::cout << "starting elevator, id " << id << " of " << nodes << " elevators" << std::endl;
        HeartBeatManager heartbeatManager;

        ConcurrentQueue< Command > commandsToLocalElevator;
        ConcurrentQueue< Command > commandsToOthers;
        ConcurrentQueue< StateChange > stateChangesIn;
        ConcurrentQueue< StateChange > stateChangesOut;

        std::unique_ptr< QueueReceiver< Command > > commandsToLocalElevatorReceiver;
        std::unique_ptr< QueueReceiver< StateChange > > stateChangesInReceiver;
        std::unique_ptr< QueueSender< StateChange > > stateChangesOutSender;
        std::unique_ptr< QueueSender< Command > > commandsToOthersReceiver;

        if ( nodes > 1 ) {
            commandsToOthersReceiver.reset( new QueueSender< Command >{
                    commSend,
                    Address{ IPv4Address::broadcast, commandPort },
                    commandsToOthers
                } );

            commandsToLocalElevatorReceiver.reset( new QueueReceiver< Command >{
                    Address{ IPv4Address::any, commandPort },
                    commandsToLocalElevator,
                    [id]( const Command &comm ) { return comm.targetElevatorId == id; }
                } );

            stateChangesInReceiver.reset( new QueueReceiver< StateChange >{
                    Address{ IPv4Address::any, stateChangePort },
                    stateChangesIn,
                    [id]( const StateChange &chan ) { return chan.state.id != id; }
                } );

            stateChangesOutSender.reset( new QueueSender< StateChange >{
                    commSend,
                    Address{ IPv4Address::broadcast, stateChangePort },
                    stateChangesOut
                } );
        }

        /* about heartbeat lengths:
         * - elevator loop is polling and never sleeping, therefore its scheduling
         *   is quite relieable and it can have short heartbeat,
         *   furthermore we need to make sure we will detect any floor change,
         *   therefore heartbeat it must respond faster then is time to cross sensor
         *   (approx 400ms), also note that even with heartbeat of 10ms the elevator
         *   seems to be running reliably
         * - scheduler again has quite tight demand, as it should be able to handle
         *   all state changes from elevator, but we have to be more carefull here
         *   as it is sleeping sometimes
         */
        Elevator elevator{ id, heartbeatManager.getNew( 500 /* ms */ ),
            commandsToLocalElevator, stateChangesIn };
        Scheduler scheduler{ id, heartbeatManager.getNew( 1000 /* ms */ ),
            elevator.info(),
            stateChangesIn, stateChangesOut, commandsToOthers, commandsToLocalElevator };

        if ( nodes > 1 ) {
            commandsToLocalElevatorReceiver->run();
            stateChangesInReceiver->run();
            commandsToOthersReceiver->run();
            stateChangesOutSender->run();
        }
        elevator.run();
        scheduler.run();

        // wait for 2 seconds so that everything has chance to start
        // it something fails to start in this time heartbeat will
        // fail and process will be terminated
        std::this_thread::sleep_for( std::chrono::seconds( 2 ) );
        // heartbeat failure will throw an exception which will terminate
        // process (as it is not catched)
        heartbeatManager.runInThisThread();
    }
};

}

int main( int args, const char **argv ) {
    elevator::Main m( args, argv );
    m.main();
}
<commit_msg>main: Plug in new sessionmanager (without recovery so far).<commit_after>#include <climits>
#include <iostream>
#include <atomic>
#include <thread>
#include <chrono>
#include <set>

#include <wibble/commandline/parser.h>

#include <elevator/elevator.h>
#include <elevator/scheduler.h>
#include <elevator/udptools.h>
#include <elevator/udpqueue.h>
#include <elevator/sessionmanager.h>

namespace elevator {

using namespace wibble;
using namespace wibble::commandline;
using namespace udp;

struct Main {

    const Address commSend{ IPv4Address::any, Port{ 64123 } };
    const Address commRcv{ IPv4Address::any, Port{ 64125 } };
    const Address commBroadcast{ IPv4Address::broadcast, Port{ 64125 } };

    const Port stateChangePort{ 64016 };
    const Port commandPort{ 64017 };

    StandardParser opts;
    OptionGroup *execution;
    IntOption *optNodes;
    BoolOption *avoidRecovery;
    const int peerMsg = 1000;
    std::set< IPv4Address > peerAddresses;
    int id = INT_MIN;
    int nodes = 1;

    Main( int argc, const char **argv ) : opts( "elevator", "0.1" ) {
        // setup options
        execution = opts.createGroup( "Execution options" );
        optNodes = execution->add< IntOption >(
                "nodes", 'n', "nodes", "",
                "specifies number of elevator nodes to expect" );

        avoidRecovery = execution->add< BoolOption >(
                "avoid recovery", 0, "avoid-recovery", "",
                "avoid auto-recovery when program is killed (do not fork)" );

        opts.usage = "";
        opts.description = "Elevator control software as a project for the "
                           "TTK4145 Real-Time Programming at NTNU. Controls "
                           "multiple elevator connected with local network.\n"
                           "(c) 2014, Vladimír Štill and Sameh Khalil\n"
                           "https://github.com/vlstill/ttk4145/tree/master/project";

        opts.add( execution );

        // parse options
        try {
            opts.parse( argc, argv );
        } catch ( exception::BadOption &ex ) {
            std::cerr << "FATAL: " << ex.fullInfo() << std::endl;
            exit( 1 );
        }
        if ( opts.help->boolValue() || opts.version->boolValue() )
            exit( 0 );
    }

    void main() {

        if ( avoidRecovery->boolValue() ) {
            runElevator();
        } else {
            assert_unimplemented();
        }
    }

    void runElevator() {
        int id;
        GlobalState global;
        SessionManager sessman{ global };
        if ( optNodes->boolValue() && optNodes->intValue() > 1 ) {
            sessman.connect( optNodes->intValue() );
            id = sessman.id();
        } else {
            id = 0;
        }

        std::cout << "starting elevator, id " << id << " of " << nodes << " elevators" << std::endl;
        HeartBeatManager heartbeatManager;

        ConcurrentQueue< Command > commandsToLocalElevator;
        ConcurrentQueue< Command > commandsToOthers;
        ConcurrentQueue< StateChange > stateChangesIn;
        ConcurrentQueue< StateChange > stateChangesOut;

        std::unique_ptr< QueueReceiver< Command > > commandsToLocalElevatorReceiver;
        std::unique_ptr< QueueReceiver< StateChange > > stateChangesInReceiver;
        std::unique_ptr< QueueSender< StateChange > > stateChangesOutSender;
        std::unique_ptr< QueueSender< Command > > commandsToOthersReceiver;

        if ( nodes > 1 ) {
            commandsToOthersReceiver.reset( new QueueSender< Command >{
                    commSend,
                    Address{ IPv4Address::broadcast, commandPort },
                    commandsToOthers
                } );

            commandsToLocalElevatorReceiver.reset( new QueueReceiver< Command >{
                    Address{ IPv4Address::any, commandPort },
                    commandsToLocalElevator,
                    [id]( const Command &comm ) { return comm.targetElevatorId == id; }
                } );

            stateChangesInReceiver.reset( new QueueReceiver< StateChange >{
                    Address{ IPv4Address::any, stateChangePort },
                    stateChangesIn,
                    [id]( const StateChange &chan ) { return chan.state.id != id; }
                } );

            stateChangesOutSender.reset( new QueueSender< StateChange >{
                    commSend,
                    Address{ IPv4Address::broadcast, stateChangePort },
                    stateChangesOut
                } );
        }

        /* about heartbeat lengths:
         * - elevator loop is polling and never sleeping, therefore its scheduling
         *   is quite relieable and it can have short heartbeat,
         *   furthermore we need to make sure we will detect any floor change,
         *   therefore heartbeat it must respond faster then is time to cross sensor
         *   (approx 400ms), also note that even with heartbeat of 10ms the elevator
         *   seems to be running reliably
         * - scheduler again has quite tight demand, as it should be able to handle
         *   all state changes from elevator, but we have to be more carefull here
         *   as it is sleeping sometimes
         */
        Elevator elevator{ id, heartbeatManager.getNew( 500 /* ms */ ),
            commandsToLocalElevator, stateChangesIn };
        Scheduler scheduler{ id, heartbeatManager.getNew( 1000 /* ms */ ),
            elevator.info(),
            stateChangesIn, stateChangesOut, commandsToOthers, commandsToLocalElevator };

        if ( nodes > 1 ) {
            commandsToLocalElevatorReceiver->run();
            stateChangesInReceiver->run();
            commandsToOthersReceiver->run();
            stateChangesOutSender->run();
        }
        elevator.run();
        scheduler.run();

        // wait for 2 seconds so that everything has chance to start
        // it something fails to start in this time heartbeat will
        // fail and process will be terminated
        std::this_thread::sleep_for( std::chrono::seconds( 2 ) );
        // heartbeat failure will throw an exception which will terminate
        // process (as it is not catched)
        heartbeatManager.runInThisThread();
    }
};

}

int main( int args, const char **argv ) {
    elevator::Main m( args, argv );
    m.main();
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <set>
#include <string>

#include "chrome/browser/download/download_util.h"

#include "base/logging.h"
#include "base/string_util.h"

namespace download_util {

// For file extensions taken from mozilla:

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Mozilla Communicator client code, released
 * March 31, 1998.
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1998-1999
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Doug Turner <dougt@netscape.com>
 *   Dean Tessman <dean_tessman@hotmail.com>
 *   Brodie Thiesfield <brofield@jellycan.com>
 *   Jungshik Shin <jshin@i18nl10n.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

static const char* const g_executables[] = {
#if defined(OS_WIN)
  "ad",
  "ade",
  "adp",
  "app",
  "application",
  "asp",
  "asx",
  "bas",
  "bat",
  "chm",
  "cmd",
  "com",
  "cpl",
  "crt",
  "dll",
  "exe",
  "fxp",
  "hlp",
  "hta",
  "htm",
  "html",
  "htt",
  "inf",
  "ins",
  "isp",
  "jar",
  "js",
  "jse",
  "lnk",
  "mad",
  "maf",
  "mag",
  "mam",
  "maq",
  "mar",
  "mas",
  "mat",
  "mau",
  "mav",
  "maw",
  "mda",
  "mdb",
  "mde",
  "mdt",
  "mdw",
  "mdz",
  "mht",
  "mhtml",
  "msc",
  "msh",
  "mshxml",
  "msi",
  "msp",
  "mst",
  "ops",
  "pcd",
  "pif",
  "plg",
  "prf",
  "prg",
  "pst",
  "reg",
  "scf",
  "scr",
  "sct",
  "shb",
  "shs",
  "shtm",
  "shtml",
  "svg",
  "url",
  "vb",
  "vbe",
  "vbs",
  "vsd",
  "vsmacros",
  "vss",
  "vst",
  "vsw",
  "ws",
  "wsc",
  "wsf",
  "wsh",
  "xht",
  "xhtm",
  "xhtml",
  "xml",
  "xsl",
  "xslt",
#elif defined(OS_MACOSX)
  // TODO(thakis): Figure out what makes sense here -- crbug.com/19096
  "dmg",
#elif defined(OS_POSIX)
  // TODO(estade): lengthen this list.
  "exe",
  "pl",
  "py",
  "rb",
  "sh",
#endif
};

bool IsExecutableExtension(const std::string& extension) {
  for (size_t i = 0; i < arraysize(g_executables); ++i) {
    if (LowerCaseEqualsASCII(extension, g_executables[i]))
      return true;
  }
  return false;
}

}  // namespace download_util
<commit_msg>Add "deb" and "rpm" to dangerous extension list on linux.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <set>
#include <string>

#include "chrome/browser/download/download_util.h"

#include "base/logging.h"
#include "base/string_util.h"

namespace download_util {

// For file extensions taken from mozilla:

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is Mozilla Communicator client code, released
 * March 31, 1998.
 *
 * The Initial Developer of the Original Code is
 * Netscape Communications Corporation.
 * Portions created by the Initial Developer are Copyright (C) 1998-1999
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Doug Turner <dougt@netscape.com>
 *   Dean Tessman <dean_tessman@hotmail.com>
 *   Brodie Thiesfield <brofield@jellycan.com>
 *   Jungshik Shin <jshin@i18nl10n.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either of the GNU General Public License Version 2 or later (the "GPL"),
 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

static const char* const g_executables[] = {
#if defined(OS_WIN)
  "ad",
  "ade",
  "adp",
  "app",
  "application",
  "asp",
  "asx",
  "bas",
  "bat",
  "chm",
  "cmd",
  "com",
  "cpl",
  "crt",
  "dll",
  "exe",
  "fxp",
  "hlp",
  "hta",
  "htm",
  "html",
  "htt",
  "inf",
  "ins",
  "isp",
  "jar",
  "js",
  "jse",
  "lnk",
  "mad",
  "maf",
  "mag",
  "mam",
  "maq",
  "mar",
  "mas",
  "mat",
  "mau",
  "mav",
  "maw",
  "mda",
  "mdb",
  "mde",
  "mdt",
  "mdw",
  "mdz",
  "mht",
  "mhtml",
  "msc",
  "msh",
  "mshxml",
  "msi",
  "msp",
  "mst",
  "ops",
  "pcd",
  "pif",
  "plg",
  "prf",
  "prg",
  "pst",
  "reg",
  "scf",
  "scr",
  "sct",
  "shb",
  "shs",
  "shtm",
  "shtml",
  "svg",
  "url",
  "vb",
  "vbe",
  "vbs",
  "vsd",
  "vsmacros",
  "vss",
  "vst",
  "vsw",
  "ws",
  "wsc",
  "wsf",
  "wsh",
  "xht",
  "xhtm",
  "xhtml",
  "xml",
  "xsl",
  "xslt",
#elif defined(OS_MACOSX)
  // TODO(thakis): Figure out what makes sense here -- crbug.com/19096
  "dmg",
#elif defined(OS_POSIX)
  // TODO(estade): lengthen this list.
  "exe",
  "pl",
  "py",
  "rb",
  "sh",
  "deb",
  "rpm",
#endif
};

bool IsExecutableExtension(const std::string& extension) {
  for (size_t i = 0; i < arraysize(g_executables); ++i) {
    if (LowerCaseEqualsASCII(extension, g_executables[i]))
      return true;
  }
  return false;
}

}  // namespace download_util
<|endoftext|>


<commit_before>/*
* tinyjsonpp.cpp
*
* Created: 11-Sept-17 12:25:10
* Author : hydroflax
*/

#include <avr/io.h>
#include <string.h>
#include "tinyjsonpp.h"

tinyjsonpp::tinyjsonpp(bool store, unsigned int maxSize) {
    this->json = static_cast<char*>(calloc(maxSize, sizeof(char)));

    this->maxSize = maxSize;
    this->jsonSize = 0;
}

tinyjsonpp::tinyjsonpp(bool store, bool ignoreQuotes, unsigned int maxSize) {
    this->json = static_cast<char*>(calloc(maxSize, sizeof(char)));

    this->maxSize = maxSize;
    this->jsonSize = 0;
}

void* tinyjsonpp::operator new(size_t objsize) {
    return malloc(objsize);
}

void tinyjsonpp::operator delete(void* obj) {
    free(obj);
}

void tinyjsonpp::empty() {
    this->jsonSize = 0;
    memset(this->json, 0, this->maxSize);
    // Alternative to save compute time is to just set the first character to 0.
}

void tinyjsonpp::reset() {
    this->jsonSize = 0;
    memset(this->json, 0, this->maxSize);
    this->json[0] = '{';
    this->json[1] = '}';
}

void tinyjsonpp::addCharToJSONString(const char c) {
    // Ignore Newline, Space, Return Carriage Characters.
    if (c <= 0x20) {
        return;
    }

    this->json[this->jsonSize] = c;
    ++this->jsonSize;
}

Value tinyjsonpp::getValue(const char* key, const char* searchStart, const unsigned int searchSize) const {
    Key k;
    Value v;
    k.start = static_cast<char*>(memmem(searchStart, searchSize, key, strlen(key)));

    // The key was found in the JSON. (If not, key will be set to NULL).
    if(k.start) {
        k.size = strlen(key);

        // Set the current location
        unsigned int location = k.start - this->json;

        // Set the values key pointer (and vice versa).
        v.key = &k;
        k.value = &v;

        // Get the entire value.
        // loop through each char in the string until a "," or "}" is found or if an opening "[", then a "]" is found.
        bool valueFound = false;
        bool array = false;
        bool embeddedJSON = false;
        while(!valueFound) {

            // Start of Value after ':' or ':'
            if(this->json[location] == ':' && !embeddedJSON) {
                v.start = &this->json[location + 1];

                if (this->json[location + 2] >= '0' && this->json[location + 2] <= '9') {
                    // A int has been found (based off first letter).
                    v.type = 'i';
                } else if(this->json[location + 1] == '[') {
                    // An array has been found.
                    array = true;
                    v.type = 'a';
                } else if(this->json[location + 1] == '{') {
                    // An embeddedJSON object has been found.
                    embeddedJSON = true;
                    v.type = 'e';
                } else {
                    v.type = 's';
                }
            }

            if((this->json[location] == ',' || this->json[location] == '}') && !embeddedJSON) {
                if(!array) {
                    v.size = &this->json[location] - v.start;
                    valueFound = true;
                }
            }

            // Embedded JSON
            if(this->json[location] == '}' && embeddedJSON) {
                v.size = &this->json[location] - v.start + 1;
                valueFound = true;
            }

            // Array
            if(this->json[location] == ']') {
                v.size = &this->json[location] - v.start + 1;
                valueFound = true;
            }

            ++location;
        }
    } else {
        v.start = NULL;
        v.size = 0;
        v.type = 'n';
        v.key = NULL;
    }
    return v;
}

Value tinyjsonpp::getValue(const char* key) const {
    Value v = getValue(key, this->json, this->jsonSize);
    return v;
}

Value tinyjsonpp::getValue(const char* key, const char* parent) const {
    Value v;
    Key k;

    // Set initial memmem string search parameters.
    v.start = this->json;
    v.size = this->jsonSize;

    char* originalParent = static_cast<char*>(calloc(strlen(parent), sizeof(char)));
    originalParent = strcpy(originalParent, parent);

    char *token = strtok(originalParent, "/");
    while (token != NULL) {
        k.start = static_cast<char*>(memmem(v.start, v.size, token, strlen(token)));

        // The key was found in the JSON.
        if (k.start) {
            // Set the correct values.
            unsigned int location = k.start - this->json;
            v.start = &this->json[location + 2];

            // Faking the value size. Good enough for simple cases.
            v.size = this->jsonSize - (location + 2);
        } else {
            v.start = NULL;
            v.size = 0;
            v.type = 'n';
            v.key = NULL;
            return v;
        }
        token = strtok(NULL, "/");
    }

    // Standard getValue() can be called passing the key to be found along with the search range.
    v = getValue(key, v.start, v.size);
    free(originalParent);

    return v;
}

//void tinyjsonpp::insert(const char* key, const char* value) {
// Insert the key-value pair into the root JSON object.
//}

void tinyjsonpp::insert(const char* key, const char* value, const char* parent) {
    Value v;
    //Key k;
    // Uses getValue() for the insert place. e.g. if the parent was "3/user"and the k-v to insert was "hello": "world" then can getvalue of "user" in parent "3".

    // Separate the parent string into the parent and the key to get the value of.
    unsigned int forwardSlash = 0;
    unsigned int location = 0;

    while(location < strlen(parent)) {
        // Store the location of the last known '/'
        if(parent[location] == '/') {
            forwardSlash = location;
        }
        ++location;
    }

    // Set the forwardSlash to the end of the parent string.
    char* originalParent = static_cast<char*>(calloc(strlen(parent), sizeof(char)));
    originalParent = strcpy(originalParent, parent);
    originalParent[forwardSlash] = 0;

    // Creating a temporary value as if the key not in the value, this will be set to NULL.
    Value val = getValue(&originalParent[forwardSlash + 1], originalParent);

    // TODO: WRITE;
    // If the key is already in the JSON string then just change the value, else add the k-v pair to the JSON string.
    v = getValue(key, val.start, val.size);

    // The key does not already exists in the object.
    if (v.start == NULL) {
        // The space which will be freed up. (i.e. "<key>":"x").
        // If the current first thing is a {"key":"val"} then {"<key>":"x","key":"val"}
        // If the current first thing is a {"key":["val1", val2"]} then {"<key>":"x","key":["val1", val2"]}

        // If the value is an embedded/array then the value will have a starter of {
        // If it is not then it will be ".
        location = val.start - this->json + strlen(key) + 7;

        // If the key is the first to be inserted into the parent then no need for ,
        if(val.size > 2) {
            ++location;
        }

        // Move original information to make space for new key.
        memmove(&this->json[location], &this->json[val.start - this->json + 1], (this->jsonSize - (val.start - this->json + 1)));

        location = val.start - this->json + 1;
        this->json[location] = '"';
        memcpy(&this->json[location + 1], key, strlen(key));
        this->json[location + strlen(key) + 1] = '"';
        this->json[location + strlen(key) + 2] = ':';
        this->json[location + strlen(key) + 3] = '"';
        this->json[location + strlen(key) + 4] = 'x';
        this->json[location + strlen(key) + 5] = '"';

        if(val.size > 2) {
            this->json[location + strlen(key) + 6] = ',';
        }

        //k.start = &this->json[location + 1];
        //k.size = strlen(key);
        v.start = &this->json[location + strlen(key) + 3];
        v.size = 3;
        v.type = 's';

        // Set the values key pointer (and vice versa).
        //v.key = &k;
        //k.value = &v;
    }
    // The key previously existed in the object/it does now.
    // See what the length of the new value is. strlen(value)
    // See what length of old value was. this->value.size
    // Move original information to make space for new value.
    location = v.start - this->json;

    // Increase jsonSize. (Technically not correct but close enough).
    this->jsonSize = this->jsonSize + strlen(key) + 6;

    if(value[0] == '{' || value[0] == '[') {
        // If we have a "{ value }" OR a "[ value1, value2] then insert into key.
        memmove(&this->json[location + strlen(value)], &this->json[v.start - this->json + v.size], (this->jsonSize - (v.start - this->json)));

        //if (value[0] == '[') {
        //this->json[location + strlen(value)] = ']';
        //} else if(value[0] == '{') {
        //// If an embedded JSON object, do nothing.
        //this->json[location + strlen(value)] = '}';
        //}

        // Replace old value with new value.
        memcpy(&this->json[location], value, strlen(value));
    } else {
        // We have a value string and this should be surrounded by the "".
        memmove(&this->json[location + strlen(value) + 2], &this->json[v.start - this->json + v.size], (this->jsonSize - (v.start - this->json + 2)));
        this->json[location] = '"';
        this->json[location + strlen(value) + 1] = '"';

        // Replace old value with new value.
        memcpy(&this->json[location + 1], value, strlen(value));
    }

    this->jsonSize = strlen(this->json);

    free(originalParent);
}

char tinyjsonpp::getChar(const unsigned int i) {
    return this->json[i];
}

const char* const tinyjsonpp::getJSONString() {
    return this->json;
}

unsigned int tinyjsonpp::convertValueToInt(const Value v) const {
    if(v.type != 'i') {
        return 0;
    } else {
        // Extra space for Terminating character \0.
        char* value = static_cast<char*>(calloc(v.size - 1, sizeof(char)));
        memcpy(value, &this->json[v.start - this->json + 1], v.size - 2);
        value[v.size - 1] = 0;
        // We now have the value as a string.
        unsigned int val = atoi(value);
        free(value);
        return val;
    }
}
<commit_msg>Testing of Travis Release tagging.<commit_after>/*
* tinyjsonpp.cpp
*
* Created: 11-Sept-17 12:25:10
* Author : hydroflax
*/

#include <avr/io.h>
#include <string.h>
#include "tinyjsonpp.h"

tinyjsonpp::tinyjsonpp(bool store, unsigned int maxSize) {
    this->json = static_cast<char*>(calloc(maxSize, sizeof(char)));

    this->maxSize = maxSize;
    this->jsonSize = 0;
}

tinyjsonpp::tinyjsonpp(bool store, bool ignoreQuotes, unsigned int maxSize) {
    this->json = static_cast<char*>(calloc(maxSize, sizeof(char)));

    this->maxSize = maxSize;
    this->jsonSize = 0;
}

void* tinyjsonpp::operator new(size_t objsize) {
    return malloc(objsize);
}

void tinyjsonpp::operator delete(void* obj) {
    free(obj);
}

void tinyjsonpp::empty() {
    this->jsonSize = 0;
    memset(this->json, 0, this->maxSize);
    // Alternative to save compute time is to just set the first character to 0.
}

void tinyjsonpp::reset() {
    this->jsonSize = 0;
    memset(this->json, 0, this->maxSize);
    this->json[0] = '{';
    this->json[1] = '}';
}

void tinyjsonpp::addCharToJSONString(const char c) {
    // Ignore Newline, Space, Return Carriage Characters.
    if (c <= 0x20) {
        return;
    }

    this->json[this->jsonSize] = c;
    ++this->jsonSize;
}

Value tinyjsonpp::getValue(const char* key, const char* searchStart, const unsigned int searchSize) const {
    Key k;
    Value v;
    k.start = static_cast<char*>(memmem(searchStart, searchSize, key, strlen(key)));

    // The key was found in the JSON. (If not, key will be set to NULL).
    if(k.start) {
        k.size = strlen(key);

        // Set the current location
        unsigned int location = k.start - this->json;

        // Set the values key pointer (and vice versa).
        v.key = &k;
        k.value = &v;

        // Get the entire value.
        // loop through each char in the string until a "," or "}" is found or if an opening "[", then a "]" is found.
        bool valueFound = false;
        bool array = false;
        bool embeddedJSON = false;
        while(!valueFound) {

            // Start of Value after ':' or ':'
            if(this->json[location] == ':' && !embeddedJSON) {
                v.start = &this->json[location + 1];

                if (this->json[location + 2] >= '0' && this->json[location + 2] <= '9') {
                    // A int has been found (based off first letter).
                    v.type = 'i';
                } else if(this->json[location + 1] == '[') {
                    // An array has been found.
                    array = true;
                    v.type = 'a';
                } else if(this->json[location + 1] == '{') {
                    // An embeddedJSON object has been found.
                    embeddedJSON = true;
                    v.type = 'e';
                } else {
                    v.type = 's';
                }
            }

            if((this->json[location] == ',' || this->json[location] == '}') && !embeddedJSON) {
                if(!array) {
                    v.size = &this->json[location] - v.start;
                    valueFound = true;
                }
            }

            // Embedded JSON
            if(this->json[location] == '}' && embeddedJSON) {
                v.size = &this->json[location] - v.start + 1;
                valueFound = true;
            }

            // Array
            if(this->json[location] == ']') {
                v.size = &this->json[location] - v.start + 1;
                valueFound = true;
            }

            ++location;
        }
    } else {
        v.start = NULL;
        v.size = 0;
        v.type = 'n';
        v.key = NULL;
    }
    return v;
}

Value tinyjsonpp::getValue(const char* key) const {
    Value v = getValue(key, this->json, this->jsonSize);
    return v;
}

Value tinyjsonpp::getValue(const char* key, const char* parent) const {
    Value v;
    Key k;

    // Set initial memmem string search parameters.
    v.start = this->json;
    v.size = this->jsonSize;

    char* originalParent = static_cast<char*>(calloc(strlen(parent), sizeof(char)));
    originalParent = strcpy(originalParent, parent);

    char *token = strtok(originalParent, "/");
    while (token != NULL) {
        k.start = static_cast<char*>(memmem(v.start, v.size, token, strlen(token)));

        // The key was found in the JSON.
        if (k.start) {
            // Set the correct values.
            unsigned int location = k.start - this->json;
            v.start = &this->json[location + 2];

            // Faking the value size. Good enough for simple cases.
            v.size = this->jsonSize - (location + 2);
        } else {
            v.start = NULL;
            v.size = 0;
            v.type = 'n';
            v.key = NULL;
            return v;
        }
        token = strtok(NULL, "/");
    }

    // Standard getValue() can be called passing the key to be found along with the search range.
    v = getValue(key, v.start, v.size);
    free(originalParent);

    return v;
}

//void tinyjsonpp::insert(const char* key, const char* value) {
// Insert the key-value pair into the root JSON object.
//}

void tinyjsonpp::insert(const char* key, const char* value, const char* parent) {
    Value v;
    //Key k;
    // Uses getValue() for the insert place. e.g. if the parent was "3/user"and the k-v to insert was "hello": "world" then can getvalue of "user" in parent "3".

    // Separate the parent string into the parent and the key to get the value of.
    unsigned int forwardSlash = 0;
    unsigned int location = 0;

    while(location < strlen(parent)) {
        // Store the location of the last known '/'
        if(parent[location] == '/') {
            forwardSlash = location;
        }
        ++location;
    }

    // Set the forwardSlash to the end of the parent string.
    char* originalParent = static_cast<char*>(calloc(strlen(parent), sizeof(char)));
    originalParent = strcpy(originalParent, parent);
    originalParent[forwardSlash] = 0;

    // Creating a temporary value as if the key not in the value, this will be set to NULL.
    Value val = getValue(&originalParent[forwardSlash + 1], originalParent);

    // TODO: WRITE;
    // If the key is already in the JSON string then just change the value, else add the k-v pair to the JSON string.
    v = getValue(key, val.start, val.size);

    // The key does not already exists in the object.
    if (v.start == NULL) {
        // The space which will be freed up. (i.e. "<key>":"x").
        // If the current first thing is a {"key":"val"} then {"<key>":"x","key":"val"}
        // If the current first thing is a {"key":["val1", val2"]} then {"<key>":"x","key":["val1", val2"]}

        // If the value is an embedded/array then the value will have a starter of {
        // If it is not then it will be ".
        location = val.start - this->json + strlen(key) + 7;

        // If the key is the first to be inserted into the parent then no need for ,
        if(val.size > 2) {
            ++location;
        }

        // Move original information to make space for new key.
        memmove(&this->json[location], &this->json[val.start - this->json + 1], (this->jsonSize - (val.start - this->json + 1)));

        location = val.start - this->json + 1;
        this->json[location] = '"';
        memcpy(&this->json[location + 1], key, strlen(key));
        this->json[location + strlen(key) + 1] = '"';
        this->json[location + strlen(key) + 2] = ':';
        this->json[location + strlen(key) + 3] = '"';
        this->json[location + strlen(key) + 4] = 'x';
        this->json[location + strlen(key) + 5] = '"';

        if(val.size > 2) {
            this->json[location + strlen(key) + 6] = ',';
        }

        //k.start = &this->json[location + 1];
        //k.size = strlen(key);
        v.start = &this->json[location + strlen(key) + 3];
        v.size = 3;
        v.type = 's';

        // Set the values key pointer (and vice versa).
        //v.key = &k;
        //k.value = &v;
    }
    // The key previously existed in the object/it does now.
    // See what the length of the new value is. strlen(value)
    // See what length of old value was. this->value.size
    // Move original information to make space for new value.
    location = v.start - this->json;

    // Increase jsonSize. (Technically not correct but close enough).
    this->jsonSize = this->jsonSize + strlen(key) + 6;

    if(value[0] == '{' || value[0] == '[') {
        // If we have a "{ value }" OR a "[ value1, value2] then insert into key.
        memmove(&this->json[location + strlen(value)], &this->json[v.start - this->json + v.size], (this->jsonSize - (v.start - this->json)));

        //if (value[0] == '[') {
        //this->json[location + strlen(value)] = ']';
        //} else if(value[0] == '{') {
        //// If an embedded JSON object, do nothing.
        //this->json[location + strlen(value)] = '}';
        //}

        // Replace old value with new value.
        memcpy(&this->json[location], value, strlen(value));
    } else {
        // We have a value string and this should be surrounded by the "".
        memmove(&this->json[location + strlen(value) + 2], &this->json[v.start - this->json + v.size], (this->jsonSize - (v.start - this->json + 2)));
        this->json[location] = '"';
        this->json[location + strlen(value) + 1] = '"';

        // Replace old value with new value.
        memcpy(&this->json[location + 1], value, strlen(value));
    }

    this->jsonSize = strlen(this->json);

    free(originalParent);
}

char tinyjsonpp::getChar(const unsigned int i) {
    return this->json[i];
}

const char* const tinyjsonpp::getJSONString() {
    return this->json;
}

unsigned int tinyjsonpp::convertValueToInt(const Value v) const {
    if(v.type != 'i') {
        return 0;
    } else {
        // Extra space for Terminating character \0.
        char* value = static_cast<char*>(calloc(v.size - 1, sizeof(char)));
        memcpy(value, &this->json[v.start - this->json + 1], v.size - 2);
        value[v.size - 1] = 0;
        // We now have the value as a string.
        unsigned int val = atoi(value);
        free(value);
        return val;
    }
}<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui/theme_source.h"

#include "base/memory/ref_counted_memory.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/resources_util.h"
#include "chrome/browser/search/instant_io_context.h"
#include "chrome/browser/themes/browser_theme_pack.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/ui/webui/ntp/ntp_resource_cache.h"
#include "chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/browser_thread.h"
#include "net/url_request/url_request.h"
#include "ui/base/layout.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/webui/web_ui_util.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_rep.h"
#include "url/gurl.h"

using content::BrowserThread;

namespace {

std::string GetThemePath() {
  return std::string(content::kChromeUIScheme) + "://" +
         std::string(chrome::kChromeUIThemePath) + "/";
}

// use a resource map rather than hard-coded strings.
static const char* kNewTabCSSPath = "css/new_tab_theme.css";
static const char* kNewIncognitoTabCSSPath = "css/incognito_new_tab_theme.css";

}  // namespace

////////////////////////////////////////////////////////////////////////////////
// ThemeSource, public:

ThemeSource::ThemeSource(Profile* profile)
    : profile_(profile->GetOriginalProfile()) {
  NTPResourceCache::WindowType win_type = NTPResourceCache::GetWindowType(
      profile_, NULL);
  css_bytes_ =
      NTPResourceCacheFactory::GetForProfile(profile)->GetNewTabCSS(win_type);
}

ThemeSource::~ThemeSource() {
}

std::string ThemeSource::GetSource() const {
  return chrome::kChromeUIThemePath;
}

void ThemeSource::StartDataRequest(
    const std::string& path,
    int render_process_id,
    int render_frame_id,
    const content::URLDataSource::GotDataCallback& callback) {
  // Default scale factor if not specified.
  float scale_factor = 1.0f;
  std::string uncached_path;
  webui::ParsePathAndScale(GURL(GetThemePath() + path),
                           &uncached_path,
                           &scale_factor);

  if (uncached_path == kNewTabCSSPath ||
      uncached_path == kNewIncognitoTabCSSPath) {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);

    callback.Run(css_bytes_.get());
    return;
  }

  int resource_id = ResourcesUtil::GetThemeResourceId(uncached_path);
  if (resource_id != -1) {
    if (GetMimeType(path) == "image/png")
      SendThemeImage(callback, resource_id, scale_factor);
    else
      SendThemeBitmap(callback, resource_id, scale_factor);
    return;
  }

  // We don't have any data to send back.
  callback.Run(NULL);
}

std::string ThemeSource::GetMimeType(const std::string& path) const {
  std::string uncached_path;
  webui::ParsePathAndScale(GURL(GetThemePath() + path), &uncached_path, NULL);

  if (uncached_path == kNewTabCSSPath ||
      uncached_path == kNewIncognitoTabCSSPath) {
    return "text/css";
  }

  return "image/png";
}

base::MessageLoop* ThemeSource::MessageLoopForRequestPath(
    const std::string& path) const {
  std::string uncached_path;
  webui::ParsePathAndScale(GURL(GetThemePath() + path), &uncached_path, NULL);

  if (uncached_path == kNewTabCSSPath ||
      uncached_path == kNewIncognitoTabCSSPath) {
    // We generated and cached this when we initialized the object.  We don't
    // have to go back to the UI thread to send the data.
    return NULL;
  }

  // If it's not a themeable image, we don't need to go to the UI thread.
  int resource_id = ResourcesUtil::GetThemeResourceId(uncached_path);
  if (!BrowserThemePack::IsPersistentImageID(resource_id))
    return NULL;

  return content::URLDataSource::MessageLoopForRequestPath(path);
}

bool ThemeSource::ShouldReplaceExistingSource() const {
  // We currently get the css_bytes_ in the ThemeSource constructor, so we need
  // to recreate the source itself when a theme changes.
  return true;
}

bool ThemeSource::ShouldServiceRequest(const net::URLRequest* request) const {
  if (request->url().SchemeIs(chrome::kChromeSearchScheme))
    return InstantIOContext::ShouldServiceRequest(request);
  return URLDataSource::ShouldServiceRequest(request);
}

////////////////////////////////////////////////////////////////////////////////
// ThemeSource, private:

void ThemeSource::SendThemeBitmap(
    const content::URLDataSource::GotDataCallback& callback,
    int resource_id,
    float scale_factor) {
  ui::ScaleFactor resource_scale_factor =
      ui::GetSupportedScaleFactor(scale_factor);
  if (BrowserThemePack::IsPersistentImageID(resource_id)) {
    DCHECK_CURRENTLY_ON(BrowserThread::UI);
    ui::ThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_);
    DCHECK(tp);

    scoped_refptr<base::RefCountedMemory> image_data(
        tp->GetRawData(resource_id, resource_scale_factor));
    callback.Run(image_data.get());
  } else {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);
    const ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    callback.Run(
        rb.LoadDataResourceBytesForScale(resource_id, resource_scale_factor));
  }
}

void ThemeSource::SendThemeImage(
    const content::URLDataSource::GotDataCallback& callback,
    int resource_id,
    float scale_factor) {
  // If the resource bundle contains the data pack for |scale_factor|, we can
  // safely fallback to SendThemeBitmap().
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  if (ui::GetScaleForScaleFactor(rb.GetMaxScaleFactor()) >= scale_factor) {
    SendThemeBitmap(callback, resource_id, scale_factor);
    return;
  }

  // Otherwise, we should use gfx::ImageSkia to obtain the data. ImageSkia can
  // rescale the bitmap if its backend doesn't contain the representation for
  // the specified scale factor. This is the fallback path in case chrome is
  // shipped without 2x resource pack but needs to use HighDPI display, which
  // can happen in ChromeOS.
  // TODO(mukai): remove this method itself when we ship 2x resource to all
  // ChromeOS devices.
  gfx::ImageSkia image;
  if (BrowserThemePack::IsPersistentImageID(resource_id)) {
    DCHECK_CURRENTLY_ON(BrowserThread::UI);
    ui::ThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_);
    DCHECK(tp);

    image = *tp->GetImageSkiaNamed(resource_id);
  } else {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);
    image = *rb.GetImageSkiaNamed(resource_id);
  }

  const gfx::ImageSkiaRep& rep = image.GetRepresentation(scale_factor);
  scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes());
  gfx::PNGCodec::EncodeBGRASkBitmap(
      rep.sk_bitmap(), false /* discard transparency */, &data->data());
  callback.Run(data.get());
}
<commit_msg>Make sure ResourceBundle::GetImageSkiaNamed running on UI thread.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui/theme_source.h"

#include "base/memory/ref_counted_memory.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/resources_util.h"
#include "chrome/browser/search/instant_io_context.h"
#include "chrome/browser/themes/browser_theme_pack.h"
#include "chrome/browser/themes/theme_properties.h"
#include "chrome/browser/themes/theme_service.h"
#include "chrome/browser/themes/theme_service_factory.h"
#include "chrome/browser/ui/webui/ntp/ntp_resource_cache.h"
#include "chrome/browser/ui/webui/ntp/ntp_resource_cache_factory.h"
#include "chrome/common/url_constants.h"
#include "content/public/browser/browser_thread.h"
#include "net/url_request/url_request.h"
#include "ui/base/layout.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/webui/web_ui_util.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_rep.h"
#include "url/gurl.h"

using content::BrowserThread;

namespace {

std::string GetThemePath() {
  return std::string(content::kChromeUIScheme) + "://" +
         std::string(chrome::kChromeUIThemePath) + "/";
}

// use a resource map rather than hard-coded strings.
static const char* kNewTabCSSPath = "css/new_tab_theme.css";
static const char* kNewIncognitoTabCSSPath = "css/incognito_new_tab_theme.css";

void ProcessImageOnUIThread(const gfx::ImageSkia& image,
                            float scale_factor,
                            scoped_refptr<base::RefCountedBytes> data) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  const gfx::ImageSkiaRep& rep = image.GetRepresentation(scale_factor);
  gfx::PNGCodec::EncodeBGRASkBitmap(
      rep.sk_bitmap(), false /* discard transparency */, &data->data());
}

void ProcessResourceOnUIThread(int resource_id,
                               float scale_factor,
                               scoped_refptr<base::RefCountedBytes> data) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  ProcessImageOnUIThread(
      *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id),
      scale_factor, data);
}

}  // namespace

////////////////////////////////////////////////////////////////////////////////
// ThemeSource, public:

ThemeSource::ThemeSource(Profile* profile)
    : profile_(profile->GetOriginalProfile()) {
  NTPResourceCache::WindowType win_type = NTPResourceCache::GetWindowType(
      profile_, NULL);
  css_bytes_ =
      NTPResourceCacheFactory::GetForProfile(profile)->GetNewTabCSS(win_type);
}

ThemeSource::~ThemeSource() {
}

std::string ThemeSource::GetSource() const {
  return chrome::kChromeUIThemePath;
}

void ThemeSource::StartDataRequest(
    const std::string& path,
    int render_process_id,
    int render_frame_id,
    const content::URLDataSource::GotDataCallback& callback) {
  // Default scale factor if not specified.
  float scale_factor = 1.0f;
  std::string uncached_path;
  webui::ParsePathAndScale(GURL(GetThemePath() + path),
                           &uncached_path,
                           &scale_factor);

  if (uncached_path == kNewTabCSSPath ||
      uncached_path == kNewIncognitoTabCSSPath) {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);

    callback.Run(css_bytes_.get());
    return;
  }

  int resource_id = ResourcesUtil::GetThemeResourceId(uncached_path);
  if (resource_id != -1) {
    if (GetMimeType(path) == "image/png")
      SendThemeImage(callback, resource_id, scale_factor);
    else
      SendThemeBitmap(callback, resource_id, scale_factor);
    return;
  }

  // We don't have any data to send back.
  callback.Run(NULL);
}

std::string ThemeSource::GetMimeType(const std::string& path) const {
  std::string uncached_path;
  webui::ParsePathAndScale(GURL(GetThemePath() + path), &uncached_path, NULL);

  if (uncached_path == kNewTabCSSPath ||
      uncached_path == kNewIncognitoTabCSSPath) {
    return "text/css";
  }

  return "image/png";
}

base::MessageLoop* ThemeSource::MessageLoopForRequestPath(
    const std::string& path) const {
  std::string uncached_path;
  webui::ParsePathAndScale(GURL(GetThemePath() + path), &uncached_path, NULL);

  if (uncached_path == kNewTabCSSPath ||
      uncached_path == kNewIncognitoTabCSSPath) {
    // We generated and cached this when we initialized the object.  We don't
    // have to go back to the UI thread to send the data.
    return NULL;
  }

  // If it's not a themeable image, we don't need to go to the UI thread.
  int resource_id = ResourcesUtil::GetThemeResourceId(uncached_path);
  if (!BrowserThemePack::IsPersistentImageID(resource_id))
    return NULL;

  return content::URLDataSource::MessageLoopForRequestPath(path);
}

bool ThemeSource::ShouldReplaceExistingSource() const {
  // We currently get the css_bytes_ in the ThemeSource constructor, so we need
  // to recreate the source itself when a theme changes.
  return true;
}

bool ThemeSource::ShouldServiceRequest(const net::URLRequest* request) const {
  if (request->url().SchemeIs(chrome::kChromeSearchScheme))
    return InstantIOContext::ShouldServiceRequest(request);
  return URLDataSource::ShouldServiceRequest(request);
}

////////////////////////////////////////////////////////////////////////////////
// ThemeSource, private:

void ThemeSource::SendThemeBitmap(
    const content::URLDataSource::GotDataCallback& callback,
    int resource_id,
    float scale_factor) {
  ui::ScaleFactor resource_scale_factor =
      ui::GetSupportedScaleFactor(scale_factor);
  if (BrowserThemePack::IsPersistentImageID(resource_id)) {
    DCHECK_CURRENTLY_ON(BrowserThread::UI);
    ui::ThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_);
    DCHECK(tp);

    scoped_refptr<base::RefCountedMemory> image_data(
        tp->GetRawData(resource_id, resource_scale_factor));
    callback.Run(image_data.get());
  } else {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);
    const ResourceBundle& rb = ResourceBundle::GetSharedInstance();
    callback.Run(
        rb.LoadDataResourceBytesForScale(resource_id, resource_scale_factor));
  }
}

void ThemeSource::SendThemeImage(
    const content::URLDataSource::GotDataCallback& callback,
    int resource_id,
    float scale_factor) {
  // If the resource bundle contains the data pack for |scale_factor|, we can
  // safely fallback to SendThemeBitmap().
  ResourceBundle& rb = ResourceBundle::GetSharedInstance();
  if (ui::GetScaleForScaleFactor(rb.GetMaxScaleFactor()) >= scale_factor) {
    SendThemeBitmap(callback, resource_id, scale_factor);
    return;
  }

  // Otherwise, we should use gfx::ImageSkia to obtain the data. ImageSkia can
  // rescale the bitmap if its backend doesn't contain the representation for
  // the specified scale factor. This is the fallback path in case chrome is
  // shipped without 2x resource pack but needs to use HighDPI display, which
  // can happen in ChromeOS or Linux.
  scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes());
  if (BrowserThemePack::IsPersistentImageID(resource_id)) {
    DCHECK_CURRENTLY_ON(BrowserThread::UI);
    ui::ThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_);
    DCHECK(tp);

    ProcessImageOnUIThread(*tp->GetImageSkiaNamed(resource_id), scale_factor,
                           data);
    callback.Run(data.get());
  } else {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);
    // Fetching image data in ResourceBundle should happen on the UI thread. See
    // crbug.com/449277
    content::BrowserThread::PostTaskAndReply(
        content::BrowserThread::UI, FROM_HERE,
        base::Bind(&ProcessResourceOnUIThread, resource_id, scale_factor, data),
        base::Bind(callback, data));
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/pepper_plugin_registry.h"

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/native_library.h"
#include "base/path_service.h"
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "remoting/client/plugin/pepper_entrypoints.h"

namespace {

const char* kPDFPluginName = "Chrome PDF Viewer";
const char* kPDFPluginMimeType = "application/pdf";
const char* kPDFPluginExtension = "pdf";
const char* kPDFPluginDescription = "Portable Document Format";

const char* kNaClPluginName = "Chrome NaCl";
const char* kNaClPluginMimeType = "application/x-nacl";
const char* kNaClPluginExtension = "nexe";
const char* kNaClPluginDescription = "Native Client Executable";

#if defined(ENABLE_REMOTING)
const char* kRemotingPluginMimeType = "pepper-application/x-chromoting";
#endif

// Appends the known built-in plugins to the given vector. Some built-in
// plugins are "internal" which means they are compiled into the Chrome binary,
// and some are extra shared libraries distributed with the browser (these are
// not marked internal, aside from being automatically registered, they're just
// regular plugins).
void ComputeBuiltInPlugins(std::vector<PepperPluginInfo>* plugins) {
  // PDF.
  //
  // Once we're sandboxed, we can't know if the PDF plugin is available or not;
  // but (on Linux) this function is always called once before we're sandboxed.
  // So the first time through test if the file is available and then skip the
  // check on subsequent calls if yes.
  static bool skip_pdf_file_check = false;
  FilePath path;
  if (PathService::Get(chrome::FILE_PDF_PLUGIN, &path)) {
    if (skip_pdf_file_check || file_util::PathExists(path)) {
      PepperPluginInfo pdf;
      pdf.path = path;
      pdf.name = kPDFPluginName;
      pdf.mime_types.push_back(kPDFPluginMimeType);
      pdf.file_extensions = kPDFPluginExtension;
      pdf.type_descriptions = kPDFPluginDescription;
      plugins->push_back(pdf);

      skip_pdf_file_check = true;
    }
  }

  // Native client.
  //
  // Verify that we enable nacl on the command line. The name of the switch
  // varies between the browser and renderer process.
  if (PathService::Get(chrome::FILE_NACL_PLUGIN, &path) &&
      file_util::PathExists(path)) {
    PepperPluginInfo nacl;
    nacl.path = path;
    nacl.name = kNaClPluginName;
    nacl.mime_types.push_back(kNaClPluginMimeType);

    // TODO(bbudge) Remove this mime type after NaCl tree has been updated.
    const char* kNaClPluginOldMimeType = "application/x-ppapi-nacl-srpc";
    nacl.mime_types.push_back(kNaClPluginOldMimeType);

    nacl.file_extensions = kNaClPluginExtension;
    nacl.type_descriptions = kNaClPluginDescription;
    plugins->push_back(nacl);
  }

  // Remoting.
#if defined(ENABLE_REMOTING)
  if (CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kEnableRemoting)) {
    PepperPluginInfo info;
    info.is_internal = true;
    info.path = FilePath(FILE_PATH_LITERAL("internal-chromoting"));
    info.mime_types.push_back(kRemotingPluginMimeType);
    info.internal_entry_points.get_interface = remoting::PPP_GetInterface;
    info.internal_entry_points.initialize_module =
        remoting::PPP_InitializeModule;
    info.internal_entry_points.shutdown_module = remoting::PPP_ShutdownModule;

    plugins->push_back(info);
  }
#endif
}

// Appends any plugins from the command line to the given vector.
void ComputePluginsFromCommandLine(std::vector<PepperPluginInfo>* plugins) {
  const std::string value =
      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
          switches::kRegisterPepperPlugins);
  if (value.empty())
    return;

  bool out_of_process =
      CommandLine::ForCurrentProcess()->HasSwitch(switches::kPpapiOutOfProcess);

  // FORMAT:
  // command-line = <plugin-entry> + *( LWS + "," + LWS + <plugin-entry> )
  // plugin-entry = <file-path> + ["#" + <name> + ["#" + <description>]] +
  //                *1( LWS + ";" + LWS + <mime-type> )

  std::vector<std::string> modules;
  base::SplitString(value, ',', &modules);
  for (size_t i = 0; i < modules.size(); ++i) {
    std::vector<std::string> parts;
    base::SplitString(modules[i], ';', &parts);
    if (parts.size() < 2) {
      DLOG(ERROR) << "Required mime-type not found";
      continue;
    }

    std::vector<std::string> name_parts;
    base::SplitString(parts[0], '#', &name_parts);

    PepperPluginInfo plugin;
    plugin.is_out_of_process = out_of_process;
#if defined(OS_WIN)
    // This means we can't provide plugins from non-ASCII paths, but
    // since this switch is only for development I don't think that's
    // too awful.
    plugin.path = FilePath(ASCIIToUTF16(name_parts[0]));
#else
    plugin.path = FilePath(name_parts[0]);
#endif
    if (name_parts.size() > 1)
      plugin.name = name_parts[1];
    if (name_parts.size() > 2) {
      plugin.description = name_parts[2];
      plugin.type_descriptions = name_parts[2];
    }
    for (size_t j = 1; j < parts.size(); ++j)
      plugin.mime_types.push_back(parts[j]);

    plugins->push_back(plugin);
  }
}

}  // namespace

const char* PepperPluginRegistry::kPDFPluginName = ::kPDFPluginName;

PepperPluginInfo::PepperPluginInfo()
    : is_internal(false),
      is_out_of_process(false) {
}

PepperPluginInfo::~PepperPluginInfo() {}

// static
PepperPluginRegistry* PepperPluginRegistry::GetInstance() {
  static PepperPluginRegistry* registry = NULL;
  // This object leaks.  It is a temporary hack to work around a crash.
  // http://code.google.com/p/chromium/issues/detail?id=63234
  if (!registry)
    registry = new PepperPluginRegistry;
  return registry;
}

// static
void PepperPluginRegistry::ComputeList(std::vector<PepperPluginInfo>* plugins) {
  ComputeBuiltInPlugins(plugins);
  ComputePluginsFromCommandLine(plugins);
}

// static
void PepperPluginRegistry::PreloadModules() {
  std::vector<PepperPluginInfo> plugins;
  ComputeList(&plugins);
  for (size_t i = 0; i < plugins.size(); ++i) {
    if (!plugins[i].is_internal && !plugins[i].is_out_of_process) {
      base::NativeLibrary library = base::LoadNativeLibrary(plugins[i].path);
      LOG_IF(WARNING, !library) << "Unable to load plugin "
                                << plugins[i].path.value();
    }
  }
}

const PepperPluginInfo* PepperPluginRegistry::GetInfoForPlugin(
    const FilePath& path) const {
  for (size_t i = 0; i < plugin_list_.size(); ++i) {
    if (path == plugin_list_[i].path)
      return &plugin_list_[i];
  }
  return NULL;
}

webkit::ppapi::PluginModule* PepperPluginRegistry::GetLiveModule(
    const FilePath& path) {
  NonOwningModuleMap::iterator it = live_modules_.find(path);
  if (it == live_modules_.end())
    return NULL;
  return it->second;
}

void PepperPluginRegistry::AddLiveModule(const FilePath& path,
                                         webkit::ppapi::PluginModule* module) {
  DCHECK(live_modules_.find(path) == live_modules_.end());
  live_modules_[path] = module;
}

void PepperPluginRegistry::PluginModuleDestroyed(
    webkit::ppapi::PluginModule* destroyed_module) {
  // Modules aren't destroyed very often and there are normally at most a
  // couple of them. So for now we just do a brute-force search.
  for (NonOwningModuleMap::iterator i = live_modules_.begin();
       i != live_modules_.end(); ++i) {
    if (i->second == destroyed_module) {
      live_modules_.erase(i);
      return;
    }
  }
  NOTREACHED();  // Should have always found the module above.
}

PepperPluginRegistry::~PepperPluginRegistry() {
  // Explicitly clear all preloaded modules first. This will cause callbacks
  // to erase these modules from the live_modules_ list, and we don't want
  // that to happen implicitly out-of-order.
  preloaded_modules_.clear();

  DCHECK(live_modules_.empty());
}

PepperPluginRegistry::PepperPluginRegistry() {
  ComputeList(&plugin_list_);

  // Note that in each case, AddLiveModule must be called before completing
  // initialization. If we bail out (in the continue clauses) before saving
  // the initialized module, it will still try to unregister itself in its
  // destructor.
  for (size_t i = 0; i < plugin_list_.size(); i++) {
    const PepperPluginInfo& current = plugin_list_[i];
    if (current.is_out_of_process)
      continue;  // Out of process plugins need no special pre-initialization.

    scoped_refptr<webkit::ppapi::PluginModule> module =
        new webkit::ppapi::PluginModule(current.name, this);
    AddLiveModule(current.path, module);
    if (current.is_internal) {
      if (!module->InitAsInternalPlugin(current.internal_entry_points)) {
        DLOG(ERROR) << "Failed to load pepper module: " << current.path.value();
        continue;
      }
    } else {
      // Preload all external plugins we're not running out of process.
      module = new webkit::ppapi::PluginModule(current.name, this);
      AddLiveModule(current.path, module);
      if (!module->InitAsLibrary(current.path)) {
        DLOG(ERROR) << "Failed to load pepper module: " << current.path.value();
        continue;
      }
    }
    preloaded_modules_[current.path] = module;
  }
}
<commit_msg>Remove double-initialization for plugin modules.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/pepper_plugin_registry.h"

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/native_library.h"
#include "base/path_service.h"
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "remoting/client/plugin/pepper_entrypoints.h"

namespace {

const char* kPDFPluginName = "Chrome PDF Viewer";
const char* kPDFPluginMimeType = "application/pdf";
const char* kPDFPluginExtension = "pdf";
const char* kPDFPluginDescription = "Portable Document Format";

const char* kNaClPluginName = "Chrome NaCl";
const char* kNaClPluginMimeType = "application/x-nacl";
const char* kNaClPluginExtension = "nexe";
const char* kNaClPluginDescription = "Native Client Executable";

#if defined(ENABLE_REMOTING)
const char* kRemotingPluginMimeType = "pepper-application/x-chromoting";
#endif

// Appends the known built-in plugins to the given vector. Some built-in
// plugins are "internal" which means they are compiled into the Chrome binary,
// and some are extra shared libraries distributed with the browser (these are
// not marked internal, aside from being automatically registered, they're just
// regular plugins).
void ComputeBuiltInPlugins(std::vector<PepperPluginInfo>* plugins) {
  // PDF.
  //
  // Once we're sandboxed, we can't know if the PDF plugin is available or not;
  // but (on Linux) this function is always called once before we're sandboxed.
  // So the first time through test if the file is available and then skip the
  // check on subsequent calls if yes.
  static bool skip_pdf_file_check = false;
  FilePath path;
  if (PathService::Get(chrome::FILE_PDF_PLUGIN, &path)) {
    if (skip_pdf_file_check || file_util::PathExists(path)) {
      PepperPluginInfo pdf;
      pdf.path = path;
      pdf.name = kPDFPluginName;
      pdf.mime_types.push_back(kPDFPluginMimeType);
      pdf.file_extensions = kPDFPluginExtension;
      pdf.type_descriptions = kPDFPluginDescription;
      plugins->push_back(pdf);

      skip_pdf_file_check = true;
    }
  }

  // Native client.
  //
  // Verify that we enable nacl on the command line. The name of the switch
  // varies between the browser and renderer process.
  if (PathService::Get(chrome::FILE_NACL_PLUGIN, &path) &&
      file_util::PathExists(path)) {
    PepperPluginInfo nacl;
    nacl.path = path;
    nacl.name = kNaClPluginName;
    nacl.mime_types.push_back(kNaClPluginMimeType);

    // TODO(bbudge) Remove this mime type after NaCl tree has been updated.
    const char* kNaClPluginOldMimeType = "application/x-ppapi-nacl-srpc";
    nacl.mime_types.push_back(kNaClPluginOldMimeType);

    nacl.file_extensions = kNaClPluginExtension;
    nacl.type_descriptions = kNaClPluginDescription;
    plugins->push_back(nacl);
  }

  // Remoting.
#if defined(ENABLE_REMOTING)
  if (CommandLine::ForCurrentProcess()->HasSwitch(
      switches::kEnableRemoting)) {
    PepperPluginInfo info;
    info.is_internal = true;
    info.path = FilePath(FILE_PATH_LITERAL("internal-chromoting"));
    info.mime_types.push_back(kRemotingPluginMimeType);
    info.internal_entry_points.get_interface = remoting::PPP_GetInterface;
    info.internal_entry_points.initialize_module =
        remoting::PPP_InitializeModule;
    info.internal_entry_points.shutdown_module = remoting::PPP_ShutdownModule;

    plugins->push_back(info);
  }
#endif
}

// Appends any plugins from the command line to the given vector.
void ComputePluginsFromCommandLine(std::vector<PepperPluginInfo>* plugins) {
  const std::string value =
      CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
          switches::kRegisterPepperPlugins);
  if (value.empty())
    return;

  bool out_of_process =
      CommandLine::ForCurrentProcess()->HasSwitch(switches::kPpapiOutOfProcess);

  // FORMAT:
  // command-line = <plugin-entry> + *( LWS + "," + LWS + <plugin-entry> )
  // plugin-entry = <file-path> + ["#" + <name> + ["#" + <description>]] +
  //                *1( LWS + ";" + LWS + <mime-type> )

  std::vector<std::string> modules;
  base::SplitString(value, ',', &modules);
  for (size_t i = 0; i < modules.size(); ++i) {
    std::vector<std::string> parts;
    base::SplitString(modules[i], ';', &parts);
    if (parts.size() < 2) {
      DLOG(ERROR) << "Required mime-type not found";
      continue;
    }

    std::vector<std::string> name_parts;
    base::SplitString(parts[0], '#', &name_parts);

    PepperPluginInfo plugin;
    plugin.is_out_of_process = out_of_process;
#if defined(OS_WIN)
    // This means we can't provide plugins from non-ASCII paths, but
    // since this switch is only for development I don't think that's
    // too awful.
    plugin.path = FilePath(ASCIIToUTF16(name_parts[0]));
#else
    plugin.path = FilePath(name_parts[0]);
#endif
    if (name_parts.size() > 1)
      plugin.name = name_parts[1];
    if (name_parts.size() > 2) {
      plugin.description = name_parts[2];
      plugin.type_descriptions = name_parts[2];
    }
    for (size_t j = 1; j < parts.size(); ++j)
      plugin.mime_types.push_back(parts[j]);

    plugins->push_back(plugin);
  }
}

}  // namespace

const char* PepperPluginRegistry::kPDFPluginName = ::kPDFPluginName;

PepperPluginInfo::PepperPluginInfo()
    : is_internal(false),
      is_out_of_process(false) {
}

PepperPluginInfo::~PepperPluginInfo() {}

// static
PepperPluginRegistry* PepperPluginRegistry::GetInstance() {
  static PepperPluginRegistry* registry = NULL;
  // This object leaks.  It is a temporary hack to work around a crash.
  // http://code.google.com/p/chromium/issues/detail?id=63234
  if (!registry)
    registry = new PepperPluginRegistry;
  return registry;
}

// static
void PepperPluginRegistry::ComputeList(std::vector<PepperPluginInfo>* plugins) {
  ComputeBuiltInPlugins(plugins);
  ComputePluginsFromCommandLine(plugins);
}

// static
void PepperPluginRegistry::PreloadModules() {
  std::vector<PepperPluginInfo> plugins;
  ComputeList(&plugins);
  for (size_t i = 0; i < plugins.size(); ++i) {
    if (!plugins[i].is_internal && !plugins[i].is_out_of_process) {
      base::NativeLibrary library = base::LoadNativeLibrary(plugins[i].path);
      LOG_IF(WARNING, !library) << "Unable to load plugin "
                                << plugins[i].path.value();
    }
  }
}

const PepperPluginInfo* PepperPluginRegistry::GetInfoForPlugin(
    const FilePath& path) const {
  for (size_t i = 0; i < plugin_list_.size(); ++i) {
    if (path == plugin_list_[i].path)
      return &plugin_list_[i];
  }
  return NULL;
}

webkit::ppapi::PluginModule* PepperPluginRegistry::GetLiveModule(
    const FilePath& path) {
  NonOwningModuleMap::iterator it = live_modules_.find(path);
  if (it == live_modules_.end())
    return NULL;
  return it->second;
}

void PepperPluginRegistry::AddLiveModule(const FilePath& path,
                                         webkit::ppapi::PluginModule* module) {
  DCHECK(live_modules_.find(path) == live_modules_.end());
  live_modules_[path] = module;
}

void PepperPluginRegistry::PluginModuleDestroyed(
    webkit::ppapi::PluginModule* destroyed_module) {
  // Modules aren't destroyed very often and there are normally at most a
  // couple of them. So for now we just do a brute-force search.
  for (NonOwningModuleMap::iterator i = live_modules_.begin();
       i != live_modules_.end(); ++i) {
    if (i->second == destroyed_module) {
      live_modules_.erase(i);
      return;
    }
  }
  NOTREACHED();  // Should have always found the module above.
}

PepperPluginRegistry::~PepperPluginRegistry() {
  // Explicitly clear all preloaded modules first. This will cause callbacks
  // to erase these modules from the live_modules_ list, and we don't want
  // that to happen implicitly out-of-order.
  preloaded_modules_.clear();

  DCHECK(live_modules_.empty());
}

PepperPluginRegistry::PepperPluginRegistry() {
  ComputeList(&plugin_list_);

  // Note that in each case, AddLiveModule must be called before completing
  // initialization. If we bail out (in the continue clauses) before saving
  // the initialized module, it will still try to unregister itself in its
  // destructor.
  for (size_t i = 0; i < plugin_list_.size(); i++) {
    const PepperPluginInfo& current = plugin_list_[i];
    if (current.is_out_of_process)
      continue;  // Out of process plugins need no special pre-initialization.

    scoped_refptr<webkit::ppapi::PluginModule> module =
        new webkit::ppapi::PluginModule(current.name, this);
    AddLiveModule(current.path, module);
    if (current.is_internal) {
      if (!module->InitAsInternalPlugin(current.internal_entry_points)) {
        DLOG(ERROR) << "Failed to load pepper module: " << current.path.value();
        continue;
      }
    } else {
      // Preload all external plugins we're not running out of process.
      if (!module->InitAsLibrary(current.path)) {
        DLOG(ERROR) << "Failed to load pepper module: " << current.path.value();
        continue;
      }
    }
    preloaded_modules_[current.path] = module;
  }
}
<|endoftext|>