<commit_before>
#include "id-resolver.h"

#include "../attribute.h"
#include "../declaration.h"
#include "../expression.h"
#include "../scope.h"
#include "../statement.h"
#include "../type.h"

using namespace binpac;
using namespace binpac::passes;

// A helper pass that replaces an ID expression with a different node within a subtree.
class IDExprReplacer : public ast::Pass<AstInfo>
{
public:
    IDExprReplacer(shared_ptr<ID> old, shared_ptr<Node> new_) : ast::Pass<AstInfo>("binpac::normalizer::IDExprReplacer", true) {
        _old = old;
        _new = new_;
    }

    virtual ~IDExprReplacer() {}

    bool run(shared_ptr<ast::NodeBase> node) override {
        return processAllPreOrder(node);
    }

protected:
    void visit(expression::ID* i) override {
        if ( i->id()->pathAsString() == _old->pathAsString() )
            i->replace(_new);
    }

private:
    shared_ptr<ID> _old;
    shared_ptr<Node> _new;
};

IDResolver::IDResolver() : Pass<AstInfo>("binpac::IDResolver", true)
{
}

IDResolver::~IDResolver()
{
}

bool IDResolver::run(shared_ptr<ast::NodeBase> module, bool report_unresolved)
{
    _report_unresolved = report_unresolved;
    return run(module);
}

bool IDResolver::run(shared_ptr<ast::NodeBase> module)
{
    return processAllPreOrder(module);
}

void IDResolver::visit(expression::ID* i)
{
    // Find the nearest to scope.
    shared_ptr<Scope> scope = nullptr;

    auto nodes = currentNodes();

    // std::cerr << "Lookup: " << i->id()->pathAsString() << std::endl;

    for ( auto i = nodes.rbegin(); i != nodes.rend(); i++ ) {
        auto n = *i;

        auto unit = ast::tryCast<type::Unit>(n);
        auto block = ast::tryCast<statement::Block>(n);
        auto item = ast::tryCast<type::unit::Item>(n);

        // std::cerr << "  block: " << block.get() << std::endl;
        // std::cerr << "  item: "  << item.get() << std::endl;
        // std::cerr << "  unit: "  << unit.get() << std::endl;

        if ( block ) {
            scope = block->scope();
            break;
        }

        if ( item ) {
            scope = item->scope();
            break;
        }

        if ( unit ) {
            scope = unit->scope();
            break;
        }
    }

    if ( ! scope ) {
        auto module = current<Module>();
        assert(module);
        scope = module->body()->scope();
        // std::cerr << "  module: " << module.get() << std::endl;
    }

    auto id = i->sharedPtr<expression::ID>();
    auto vals = scope->lookup(id->id(), true);

    if ( ! vals.size() ) {
        // We we're inside an externally defined hook, make sure to also
        // search the global scope of the module where it's defined.
        auto imod = i->firstParent<Module>();
        if ( imod ) {
            // std::cerr << "  imod: " << imod.get() << std::endl;
            // std::cerr << "  imod SCOPE: ";
            scope = imod->body()->scope();
            // scope->dump(std::cerr);
            vals = scope->lookup(id->id(), true);
        }
    }

    if ( ! vals.size() ) {
        if ( _report_unresolved )
            error(i, util::fmt("unknown ID %s", id->id()->pathAsString().c_str()));

        return;
    }

    if ( vals.size() > 1 ) {
        // Only functions can be overloaded.
        for ( auto v: vals ) {
            if ( ! ast::tryCast<expression::Function>(v) ) {
                error(i, util::fmt("ID %s defined more than once", id->id()->pathAsString().c_str()));
                return;
            }
        }

        // We resolve these later with overload-resolver.
        return;
    }

#if 0
    // Check use $$ here because we're going to replace it and thus the
    // valdiator won't see ID anymore.
    if ( id->id()->name() == "$$" ) {
        auto h = i->firstParent<Hook>();

        bool ok = false;

        if ( h && h->foreach() )
            ok = true;

        if ( (! h) && i->firstParent<type::Unit>() )
            ok = true;

        if ( ! ok )
            error(i, util::fmt("$$ not defined here"));
    }
#endif

    auto val = vals.front();

    id->replace(val);

    if ( id->id()->isScoped() )
        val->setScope(id->id()->scope());

}

void IDResolver::visit(expression::ListComprehension* c)
{
    auto etype = std::make_shared<type::UnknownElementType>(c->input());

    auto id = std::make_shared<ID>(::util::fmt("%s", c->variable()->name()));
    auto var = std::make_shared<variable::Local>(id, etype);
    auto evar = std::make_shared<expression::Variable>(var);

    IDExprReplacer replacer(c->variable(), evar);

    if ( c->predicate() )
        replacer.run(c->predicate());

    replacer.run(c->output());
}

void IDResolver::visit(type::Unknown* t)
{
    auto body = current<statement::Block>();

    if ( ! body ) {
        error(t, "ID expression outside of any scope");
        return;
    }

    auto id = t->id();

    if ( ! id )
        return;

    auto vals = body->scope()->lookup(id, true);

    if ( ! vals.size() ) {
        if ( _report_unresolved )
            error(t, util::fmt("unknown type ID %s", id->pathAsString().c_str()));
        return;
    }

    if ( vals.size() > 1 ) {
        error(t, util::fmt("ID %s defined more than once", id->pathAsString().c_str()));
        return;
    }

    auto val = vals.front();

    auto nt = ast::tryCast<expression::Type>(val);

    if ( ! nt ) {
        error(t, util::fmt("ID %s does not reference a type", id->pathAsString().c_str()));
        return;
    }

    auto tv = nt->typeValue();
    t->replace(tv);

    if ( ! tv->id() || ! (tv->id()->isScoped() && id->isScoped()) ) {
        tv->setID(id);

        if ( ! id->isScoped() )
            tv->setScope(current<Module>()->id()->name());
    }
}

void IDResolver::visit(declaration::Hook* h)
{
    // Determine the unit that we belong to. For a path "a::b::c::, "a::b"
    // must reference its type.
    auto path = h->id()->path();
    path.pop_back();

    if ( ! path.size() ) {
        error(h, "id does not reference a hook field");
        return;
    }

    auto module = current<Module>();
    assert(module);

    auto uid = std::make_shared<ID>(path);
    auto exprs = module->body()->scope()->lookup(uid, true);

    if ( ! exprs.size() ) {
        if ( _report_unresolved )
            error(h, "unknown id");
        return;
    }

    if ( exprs.size() > 1 ) {
        error(h, util::fmt("ID %s references more than one object", h->id()->pathAsString()));
        return;
    }

    auto expr = exprs.front();

    auto texpr = ast::tryCast<expression::Type>(expr);

    if ( ! texpr ) {
        error(h, "id does not reference a type");
        return;
    }

    auto unit = ast::tryCast<type::Unit>(texpr->typeValue());

    if ( ! unit ) {
        error(h, "id does not lead to a unit type");
        return;
    }

    // It's important here to run pre-order: setting the scope here links
    // the hook's scope to the unit's before descending down into the
    // statement.
    h->hook()->setUnit(unit);

    auto mid = h->firstParent<Module>()->id();
    assert(mid);

    unit->setID(std::make_shared<ID>(uid->pathAsString(mid)));
    unit->setScope(mid->name());
}

void IDResolver::visit(type::unit::item::field::Unknown* f)
{
    auto body = current<statement::Block>();

    if ( ! body ) {
        error(f, "ID expression outside of any scope");
        return;
    }

    auto id = f->scopeID();

    if ( ! id )
        internalError(f, "field::Unknown without scope ID");

    auto exprs = body->scope()->lookup(id, true);

    if ( ! exprs.size() ) {
        if ( _report_unresolved )
            error(f, util::fmt("unknown field ID %s", id->pathAsString()));
        return;
    }

    if ( exprs.size() > 1 ) {
        error(f, util::fmt("ID %s references more than one object", id->pathAsString()));
        return;
    }

    auto expr = exprs.front();

    auto attributes = f->attributes()->attributes();
    auto condition = f->condition();
    auto hooks = f->hooks();
    auto name = f->id();
    auto location = f->location();
    auto params = f->parameters();
    auto sinks = f->sinks();

    shared_ptr<type::unit::item::Field> nfield = nullptr;

    auto ctor = ast::tryCast<expression::Ctor>(expr);
    auto constant = ast::tryCast<expression::Constant>(expr);
    auto type = ast::tryCast<expression::Type>(expr);

    if ( ctor )
        nfield = std::make_shared<type::unit::item::field::Ctor>(name, ctor->ctor(), condition, hooks, attributes, sinks, location);

    if ( constant )
        nfield = std::make_shared<type::unit::item::field::Constant>(name, constant->constant(), condition, hooks, attributes, sinks, location);

    if ( type )
        nfield = type::unit::item::Field::createByType(type->typeValue(), name, condition, hooks, attributes, params, sinks, location);

    nfield->scope()->setParent(f->scope()->parent());

    assert(nfield);
    f->replace(nfield);

    if ( f->anonymous() )
        nfield->setAnonymous();
}
<commit_msg>Fix a case where ID resolving failed.<commit_after>
#include "id-resolver.h"

#include "../attribute.h"
#include "../declaration.h"
#include "../expression.h"
#include "../scope.h"
#include "../statement.h"
#include "../type.h"

using namespace binpac;
using namespace binpac::passes;

// A helper pass that replaces an ID expression with a different node within a subtree.
class IDExprReplacer : public ast::Pass<AstInfo>
{
public:
    IDExprReplacer(shared_ptr<ID> old, shared_ptr<Node> new_) : ast::Pass<AstInfo>("binpac::normalizer::IDExprReplacer", true) {
        _old = old;
        _new = new_;
    }

    virtual ~IDExprReplacer() {}

    bool run(shared_ptr<ast::NodeBase> node) override {
        return processAllPreOrder(node);
    }

protected:
    void visit(expression::ID* i) override {
        if ( i->id()->pathAsString() == _old->pathAsString() )
            i->replace(_new);
    }

private:
    shared_ptr<ID> _old;
    shared_ptr<Node> _new;
};

IDResolver::IDResolver() : Pass<AstInfo>("binpac::IDResolver", true)
{
}

IDResolver::~IDResolver()
{
}

bool IDResolver::run(shared_ptr<ast::NodeBase> module, bool report_unresolved)
{
    _report_unresolved = report_unresolved;
    return run(module);
}

bool IDResolver::run(shared_ptr<ast::NodeBase> module)
{
    return processAllPreOrder(module);
}

void IDResolver::visit(expression::ID* i)
{
    // Find the nearest to scope.
    shared_ptr<Scope> scope = nullptr;

    auto nodes = currentNodes();

    // std::cerr << "Lookup: " << i->id()->pathAsString() << std::endl;

    for ( auto i = nodes.rbegin(); i != nodes.rend(); i++ ) {
        auto n = *i;

        auto unit = ast::tryCast<type::Unit>(n);
        auto block = ast::tryCast<statement::Block>(n);
        auto item = ast::tryCast<type::unit::Item>(n);

        // std::cerr << "  block: " << block.get() << std::endl;
        // std::cerr << "  item: "  << item.get() << std::endl;
        // std::cerr << "  unit: "  << unit.get() << std::endl;

        if ( block ) {
            scope = block->scope();
            break;
        }

        if ( item ) {
            scope = item->scope();
            break;
        }

        if ( unit ) {
            scope = unit->scope();
            break;
        }
    }

    if ( ! scope ) {
        auto module = current<Module>();
        assert(module);
        scope = module->body()->scope();
        // std::cerr << "  module: " << module.get() << std::endl;
    }

    auto id = i->sharedPtr<expression::ID>();
    auto vals = scope->lookup(id->id(), true);

    if ( ! vals.size() ) {
        // Look it up in the current module if that's the namespace we are
        // interested in.
        auto module = current<Module>();
        assert(module);

        auto path = id->id()->path();

        if ( id->id()->isScoped() && path.front() == module->id()->name() ) {
            path.pop_front();
            auto x = std::make_shared<ID>(path);
	    vals = scope->lookup(x, true);
        }
    }

    if ( ! vals.size() ) {
        // We we're inside an externally defined hook, make sure to also
        // search the global scope of the module where it's defined.
        auto imod = i->firstParent<Module>();
        if ( imod ) {
            // std::cerr << "  imod: " << imod.get() << std::endl;
            // std::cerr << "  imod SCOPE: ";
            scope = imod->body()->scope();
            // scope->dump(std::cerr);
            vals = scope->lookup(id->id(), true);
        }
    }

    if ( ! vals.size() ) {
        if ( _report_unresolved )
            error(i, util::fmt("unknown ID %s", id->id()->pathAsString().c_str()));

        return;
    }

    if ( vals.size() > 1 ) {
        // Only functions can be overloaded.
        for ( auto v: vals ) {
            if ( ! ast::tryCast<expression::Function>(v) ) {
                error(i, util::fmt("ID %s defined more than once", id->id()->pathAsString().c_str()));
                return;
            }
        }

        // We resolve these later with overload-resolver.
        return;
    }

#if 0
    // Check use $$ here because we're going to replace it and thus the
    // valdiator won't see ID anymore.
    if ( id->id()->name() == "$$" ) {
        auto h = i->firstParent<Hook>();

        bool ok = false;

        if ( h && h->foreach() )
            ok = true;

        if ( (! h) && i->firstParent<type::Unit>() )
            ok = true;

        if ( ! ok )
            error(i, util::fmt("$$ not defined here"));
    }
#endif

    auto val = vals.front();

    id->replace(val);

    if ( id->id()->isScoped() )
        val->setScope(id->id()->scope());

}

void IDResolver::visit(expression::ListComprehension* c)
{
    auto etype = std::make_shared<type::UnknownElementType>(c->input());

    auto id = std::make_shared<ID>(::util::fmt("%s", c->variable()->name()));
    auto var = std::make_shared<variable::Local>(id, etype);
    auto evar = std::make_shared<expression::Variable>(var);

    IDExprReplacer replacer(c->variable(), evar);

    if ( c->predicate() )
        replacer.run(c->predicate());

    replacer.run(c->output());
}

void IDResolver::visit(type::Unknown* t)
{
    auto body = current<statement::Block>();

    if ( ! body ) {
        error(t, "ID expression outside of any scope");
        return;
    }

    auto id = t->id();

    if ( ! id )
        return;

    auto vals = body->scope()->lookup(id, true);

    if ( ! vals.size() ) {
        if ( _report_unresolved )
            error(t, util::fmt("unknown type ID %s", id->pathAsString().c_str()));
        return;
    }

    if ( vals.size() > 1 ) {
        error(t, util::fmt("ID %s defined more than once", id->pathAsString().c_str()));
        return;
    }

    auto val = vals.front();

    auto nt = ast::tryCast<expression::Type>(val);

    if ( ! nt ) {
        error(t, util::fmt("ID %s does not reference a type", id->pathAsString().c_str()));
        return;
    }

    auto tv = nt->typeValue();
    t->replace(tv);

    if ( ! tv->id() || ! (tv->id()->isScoped() && id->isScoped()) ) {
        tv->setID(id);

        if ( ! id->isScoped() )
            tv->setScope(current<Module>()->id()->name());
    }
}

void IDResolver::visit(declaration::Hook* h)
{
    // Determine the unit that we belong to. For a path "a::b::c::, "a::b"
    // must reference its type.
    auto path = h->id()->path();
    path.pop_back();

    if ( ! path.size() ) {
        error(h, "id does not reference a hook field");
        return;
    }

    auto module = current<Module>();
    assert(module);

    auto uid = std::make_shared<ID>(path);
    auto exprs = module->body()->scope()->lookup(uid, true);

    if ( ! exprs.size() ) {
        if ( _report_unresolved )
            error(h, "unknown id");
        return;
    }

    if ( exprs.size() > 1 ) {
        error(h, util::fmt("ID %s references more than one object", h->id()->pathAsString()));
        return;
    }

    auto expr = exprs.front();

    auto texpr = ast::tryCast<expression::Type>(expr);

    if ( ! texpr ) {
        error(h, "id does not reference a type");
        return;
    }

    auto unit = ast::tryCast<type::Unit>(texpr->typeValue());

    if ( ! unit ) {
        error(h, "id does not lead to a unit type");
        return;
    }

    // It's important here to run pre-order: setting the scope here links
    // the hook's scope to the unit's before descending down into the
    // statement.
    h->hook()->setUnit(unit);

    auto mid = h->firstParent<Module>()->id();
    assert(mid);

    unit->setID(std::make_shared<ID>(uid->pathAsString(mid)));
    unit->setScope(mid->name());
}

void IDResolver::visit(type::unit::item::field::Unknown* f)
{
    auto body = current<statement::Block>();

    if ( ! body ) {
        error(f, "ID expression outside of any scope");
        return;
    }

    auto id = f->scopeID();

    if ( ! id )
        internalError(f, "field::Unknown without scope ID");

    auto exprs = body->scope()->lookup(id, true);

    if ( ! exprs.size() ) {
        if ( _report_unresolved )
            error(f, util::fmt("unknown field ID %s", id->pathAsString()));
        return;
    }

    if ( exprs.size() > 1 ) {
        error(f, util::fmt("ID %s references more than one object", id->pathAsString()));
        return;
    }

    auto expr = exprs.front();

    auto attributes = f->attributes()->attributes();
    auto condition = f->condition();
    auto hooks = f->hooks();
    auto name = f->id();
    auto location = f->location();
    auto params = f->parameters();
    auto sinks = f->sinks();

    shared_ptr<type::unit::item::Field> nfield = nullptr;

    auto ctor = ast::tryCast<expression::Ctor>(expr);
    auto constant = ast::tryCast<expression::Constant>(expr);
    auto type = ast::tryCast<expression::Type>(expr);

    if ( ctor )
        nfield = std::make_shared<type::unit::item::field::Ctor>(name, ctor->ctor(), condition, hooks, attributes, sinks, location);

    if ( constant )
        nfield = std::make_shared<type::unit::item::field::Constant>(name, constant->constant(), condition, hooks, attributes, sinks, location);

    if ( type )
        nfield = type::unit::item::Field::createByType(type->typeValue(), name, condition, hooks, attributes, params, sinks, location);

    nfield->scope()->setParent(f->scope()->parent());

    assert(nfield);
    f->replace(nfield);

    if ( f->anonymous() )
        nfield->setAnonymous();
}
<|endoftext|>


<commit_before>#include "MsgInfo.hpp"
#include "Debug.hpp"

size_t MsgInfo::getViewDepth()
{
    return disp_state.cur_depth;
}

void MsgInfo::incViewDepth(size_t viewid)
{
    disp_state.recur_table[disp_state.cur_depth++] = viewid;
}

void MsgInfo::decViewDepth()
{
    assert(disp_state.cur_depth != 0);
    disp_state.cur_depth--;
}

void MsgInfo::display()
{
    const char *name = NULL;
    i64 hash = 0;
    if (metadata) {
        name = metadata->name.c_str();
        hash = metadata->info->get_hash();
    }

    printf("         Decoding %s (%s) %" PRIi64 ":\n", channel.c_str(), name, hash);

    if (last_msg)
        msg_display(db, *metadata, last_msg,  disp_state);
}

void MsgInfo::ensureHash(i64 h)
{
    if (hash == h)
        return;

    // if this not the first message, warn user
    if (hash != 0) {
        DEBUG(1, "WRN: hash changed, searching for new zcmtype on channel %s\n", channel.c_str());
    }

    // cleanup old memory if needed
    if (metadata && last_msg) {
        metadata->info->decode_cleanup(last_msg);
        free(last_msg);
        last_msg = NULL;
    }

    hash = h;
    metadata = db.getByHash(h);
    if (metadata == NULL) {
        DEBUG(1, "WRN: failed to find zcmtype for hash: 0x%" PRIx64 "\n", hash);
        return;
    }
}

u64 MsgInfo::latestUtime()
{
    return queue.last();
}

u64 MsgInfo::oldestUtime()
{
    return queue.first();
}

void MsgInfo::removeOld()
{
    u64 oldest_allowed = TimeUtil::utime() - QUEUE_PERIOD;
    while (!queue.isEmpty() && queue.first() < oldest_allowed)
        queue.dequeue();
}

void MsgInfo::addMessage(u64 utime, const zcm_recv_buf_t *rbuf)
{
    if (queue.isFull())
        queue.dequeue();
    queue.enqueue(utime);

    num_msgs++;

    /* decode the data */
    i64 hash = 0;
    __int64_t_decode_array(rbuf->data, 0, rbuf->data_size, &hash, 1);
    ensureHash(hash);

    if (metadata) {
        // do we need to allocate memory for 'last_msg' ?
        if (!last_msg) {
            size_t sz = metadata->info->struct_size();
            last_msg = malloc(sz);
        } else {
            metadata->info->decode_cleanup(last_msg);
        }

        // actually decode it
        metadata->info->decode(rbuf->data, 0, rbuf->data_size, last_msg);

        DEBUG(1, "INFO: successful decode on %s\n", channel.c_str());
    }
}

float MsgInfo::getHertz()
{
    removeOld();
    if (queue.isEmpty())
        return 0.0;

    int sz = queue.getSize();
    u64 oldest = oldestUtime();
    u64 latest = latestUtime();
    u64 dt = latest - oldest;
    if(dt == 0.0)
        return 0.0;

    return (float) sz / ((float) dt / 1000000.0);
}
<commit_msg>Fixed zcm spy lite hz calculation<commit_after>#include "MsgInfo.hpp"
#include "Debug.hpp"

size_t MsgInfo::getViewDepth()
{
    return disp_state.cur_depth;
}

void MsgInfo::incViewDepth(size_t viewid)
{
    disp_state.recur_table[disp_state.cur_depth++] = viewid;
}

void MsgInfo::decViewDepth()
{
    assert(disp_state.cur_depth != 0);
    disp_state.cur_depth--;
}

void MsgInfo::display()
{
    const char *name = NULL;
    i64 hash = 0;
    if (metadata) {
        name = metadata->name.c_str();
        hash = metadata->info->get_hash();
    }

    printf("         Decoding %s (%s) %" PRIi64 ":\n", channel.c_str(), name, hash);

    if (last_msg)
        msg_display(db, *metadata, last_msg,  disp_state);
}

void MsgInfo::ensureHash(i64 h)
{
    if (hash == h)
        return;

    // if this not the first message, warn user
    if (hash != 0) {
        DEBUG(1, "WRN: hash changed, searching for new zcmtype on channel %s\n", channel.c_str());
    }

    // cleanup old memory if needed
    if (metadata && last_msg) {
        metadata->info->decode_cleanup(last_msg);
        free(last_msg);
        last_msg = NULL;
    }

    hash = h;
    metadata = db.getByHash(h);
    if (metadata == NULL) {
        DEBUG(1, "WRN: failed to find zcmtype for hash: 0x%" PRIx64 "\n", hash);
        return;
    }
}

u64 MsgInfo::latestUtime()
{
    return queue.last();
}

u64 MsgInfo::oldestUtime()
{
    return queue.first();
}

void MsgInfo::removeOld()
{
    u64 oldest_allowed = TimeUtil::utime() - QUEUE_PERIOD;
    while (!queue.isEmpty() && queue.first() < oldest_allowed)
        queue.dequeue();
}

void MsgInfo::addMessage(u64 utime, const zcm_recv_buf_t *rbuf)
{
    if (queue.isFull())
        queue.dequeue();
    queue.enqueue(utime);

    num_msgs++;

    /* decode the data */
    i64 hash = 0;
    __int64_t_decode_array(rbuf->data, 0, rbuf->data_size, &hash, 1);
    ensureHash(hash);

    if (metadata) {
        // do we need to allocate memory for 'last_msg' ?
        if (!last_msg) {
            size_t sz = metadata->info->struct_size();
            last_msg = malloc(sz);
        } else {
            metadata->info->decode_cleanup(last_msg);
        }

        // actually decode it
        metadata->info->decode(rbuf->data, 0, rbuf->data_size, last_msg);

        DEBUG(1, "INFO: successful decode on %s\n", channel.c_str());
    }
}

float MsgInfo::getHertz()
{
    removeOld();
    if (queue.isEmpty())
        return 0.0;

    int sz = queue.getSize();
    if (sz < 2) return 0.0;
    u64 oldest = oldestUtime();
    u64 latest = latestUtime();
    u64 dt = latest - oldest;
    if (dt == 0.0)
        return INFINITY;

    return (float) (sz - 1) / ((float) dt / 1000000.0);
}
<|endoftext|>


<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) version 3.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "main.h"
#include <kgenericfactory.h>
#include <kaboutdata.h>
#include <kdeversion.h>
#include <QtGui/QBoxLayout>
#include <kdialog.h>
#include "outputdevicechoice.h"
#include <QtGui/QTabWidget>
#include "backendselection.h"

K_PLUGIN_FACTORY(PhononKcmFactory, registerPlugin<PhononKcm>();)
K_EXPORT_PLUGIN(PhononKcmFactory("kcm_phonon"))

PhononKcm::PhononKcm(QWidget *parent, const QVariantList &args)
    : KCModule(PhononKcmFactory::componentData(), parent, args)
{
    KAboutData *about = new KAboutData(
            "kcm_phonon", 0, ki18n("Phonon Configuration Module"),
            KDE_VERSION_STRING, KLocalizedString(), KAboutData::License_GPL,
            ki18n("Copyright 2006 Matthias Kretz"));
    about->addAuthor(ki18n("Matthias Kretz"), KLocalizedString(), "kretz@kde.org");
    setAboutData(about);

    setLayout(new QHBoxLayout);
    layout()->setMargin(0);
    layout()->setSpacing(0);

    QTabWidget *tabs = new QTabWidget(this);
    layout()->addWidget(tabs);

    m_outputDeviceWidget = new OutputDeviceChoice;
    tabs->addTab(m_outputDeviceWidget, i18n("Device Preference"));
    m_backendSelection = new BackendSelection;
    tabs->addTab(m_backendSelection, i18n("Backend"));
    load();
    connect(m_backendSelection, SIGNAL(changed()), SLOT(changed()));
    connect(m_outputDeviceWidget, SIGNAL(changed()), SLOT(changed()));
}

void PhononKcm::load()
{
    m_outputDeviceWidget->load();
    m_backendSelection->load();
}

void PhononKcm::save()
{
    m_outputDeviceWidget->save();
    m_backendSelection->save();
}

void PhononKcm::defaults()
{
    m_outputDeviceWidget->defaults();
    m_backendSelection->defaults();
}

#include "main.moc"
// vim: ts=4
<commit_msg>krazy thinks I should use KTabWidget. Not a bad idea.<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) version 3.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "main.h"
#include <kgenericfactory.h>
#include <ktabwidget.h>
#include <kaboutdata.h>
#include <kdeversion.h>
#include <QtGui/QBoxLayout>
#include <kdialog.h>
#include "outputdevicechoice.h"
#include "backendselection.h"

K_PLUGIN_FACTORY(PhononKcmFactory, registerPlugin<PhononKcm>();)
K_EXPORT_PLUGIN(PhononKcmFactory("kcm_phonon"))

PhononKcm::PhononKcm(QWidget *parent, const QVariantList &args)
    : KCModule(PhononKcmFactory::componentData(), parent, args)
{
    KAboutData *about = new KAboutData(
            "kcm_phonon", 0, ki18n("Phonon Configuration Module"),
            KDE_VERSION_STRING, KLocalizedString(), KAboutData::License_GPL,
            ki18n("Copyright 2006 Matthias Kretz"));
    about->addAuthor(ki18n("Matthias Kretz"), KLocalizedString(), "kretz@kde.org");
    setAboutData(about);

    setLayout(new QHBoxLayout);
    layout()->setMargin(0);
    layout()->setSpacing(0);

    KTabWidget *tabs = new KTabWidget(this);
    layout()->addWidget(tabs);

    m_outputDeviceWidget = new OutputDeviceChoice;
    tabs->addTab(m_outputDeviceWidget, i18n("Device Preference"));
    m_backendSelection = new BackendSelection;
    tabs->addTab(m_backendSelection, i18n("Backend"));
    load();
    connect(m_backendSelection, SIGNAL(changed()), SLOT(changed()));
    connect(m_outputDeviceWidget, SIGNAL(changed()), SLOT(changed()));
}

void PhononKcm::load()
{
    m_outputDeviceWidget->load();
    m_backendSelection->load();
}

void PhononKcm::save()
{
    m_outputDeviceWidget->save();
    m_backendSelection->save();
}

void PhononKcm::defaults()
{
    m_outputDeviceWidget->defaults();
    m_backendSelection->defaults();
}

#include "main.moc"
// vim: ts=4
<|endoftext|>


<commit_before>#include <QVariant>
#include <QByteArray>
#include <QDebug>
#include <QString>
#include "qbencodevalue.h"

QBencodeValue::QBencodeValue(Type type)
    : d(nullptr), list(nullptr), dict(nullptr)
{
    t = type;
}

QBencodeValue::QBencodeValue(const QString &s)
    : list(nullptr), dict(nullptr)
{
    t = String;
    extractBytesFromQString(s);
}

QBencodeValue::QBencodeValue(const QByteArray &bytes)
    : list(nullptr), dict(nullptr)
{
    t = String;
    d = new QVariant(bytes);
}

QBencodeValue::QBencodeValue(int n)
    : list(nullptr), dict(nullptr)
{
    t = Integer;
    d = new QVariant(n);
}

QBencodeValue::QBencodeValue(qint64 n)
    : list(nullptr), dict(nullptr)
{
    t = Integer;
    d = new QVariant(n);
}

QBencodeValue::QBencodeValue(const QBencodeList &list)
    : d(nullptr), dict(nullptr)
{
    t = List;
    this->list = new QBencodeList(list);
}

QBencodeValue::QBencodeValue(const QBencodeDict &dict)
    : d(nullptr), list(nullptr)
{
    t = Dict;
    this->dict = new QBencodeDict(dict);
}

QBencodeValue::~QBencodeValue()
{
    detach();
}

QBencodeValue::QBencodeValue(const QBencodeValue &other)
    : d(nullptr), list(nullptr), dict(nullptr)
{
    copyFrom(other);
}

QBencodeValue &QBencodeValue::operator =(const QBencodeValue &other)
{
    detach();
    copyFrom(other);
    return *this;
}

QBencodeValue::QBencodeValue(QBencodeValue &&other)
    : d(nullptr), list(nullptr), dict(nullptr), t(Null)
{
    auto tmpT = t;
    auto tmpD = d;
    auto tmpDict = dict;
    auto tmpList = list;
    t = other.t;
    d = other.d;
    dict = other.dict;
    list = other.list;
    other.t = tmpT;
    other.d = tmpD;
    other.dict = tmpDict;
    other.list = tmpList;
}

QBencodeValue &QBencodeValue::operator =(QBencodeValue &&other)
{
    auto tmpT = t;
    auto tmpD = d;
    auto tmpDict = dict;
    auto tmpList = list;
    t = other.t;
    d = other.d;
    dict = other.dict;
    list = other.list;
    other.t = tmpT;
    other.d = tmpD;
    other.dict = tmpDict;
    other.list = tmpList;

    return *this;
}

/*static*/ QBencodeValue QBencodeValue::fromVariant(const QVariant &variant)
{
    switch (variant.type()) {
    case QMetaType::QString:
        return QBencodeValue(variant.toString());
    case QMetaType::QByteArray:
        return QBencodeValue(variant.toByteArray());
    case QMetaType::Int:
    case QMetaType::LongLong:
        return QBencodeValue(variant.toLongLong());
    case QMetaType::QVariantList: {
        QBencodeList benlist;
        for (auto item : variant.toList()) {
            benlist.append(fromVariant(item));
        }
        return QBencodeValue(benlist);
    }
    case QMetaType::QVariantHash: {
        QBencodeDict bendict;
        QHash<QString, QVariant> hash = variant.toHash();
        for (auto key : hash.keys()) {
            bendict.insert(key, fromVariant(hash[key]));
        }
        return QBencodeValue(bendict);
    }
    default:
        return QBencodeValue();
    }
}

QVariant QBencodeValue::toVariant() const
{
    // TODO: QBencodeValue::toVariant method stub
    qDebug() << "FIXME: stub method QBencodeValue:toVariant";
    return QVariant();
}

qint64 QBencodeValue::toInteger(qint64 defaultValue) const
{
    if (t == Integer) {
        return d->toLongLong();
    } else {
        return defaultValue;
    }
}

/*!
  Returns the value as string, assume UTF-8 encoded.
 */
QString QBencodeValue::toString(const QString &defaultValue) const
{
    if (t == String) {
        return QString(d->toByteArray());
    } else {
        return defaultValue;
    }
}

QByteArray QBencodeValue::toByteArray(const QByteArray &defaultValue) const
{
    if (t == String) {
        return d->toByteArray();
    } else {
        return defaultValue;
    }
}

QBencodeList QBencodeValue::toList() const
{
    if (t == List) {
        return *list;
    } else {
        return QBencodeList();
    }
}

QBencodeList QBencodeValue::toList(const QBencodeList &defaultValue) const
{
    if (t == List) {
        return *list;
    } else {
        return defaultValue;
    }
}

QBencodeDict QBencodeValue::toDict() const
{
    if (t == Dict) {
        return *dict;
    } else {
        return QBencodeDict();
    }
}

QBencodeDict QBencodeValue::toDict(const QBencodeDict &defaultValue) const
{
    if (t == Dict) {
        return *dict;
    } else {
        return defaultValue;
    }
}

bool QBencodeValue::operator==(const QBencodeValue &other) const
{
    if (t != other.t) { return false; }
    switch (t) {
    case Integer:
    case String:
        return *d == *other.d;
    case List:
        return *list == *other.list;
    case Dict:
        return *dict == *other.dict;
    case Undefined:
        return true;
    default:
        return false;
    }
}

bool QBencodeValue::operator!=(const QBencodeValue &other) const
{
    return !(*this == other);
}

void QBencodeValue::extractBytesFromQString(const QString &s)
{
    d = new QVariant(s.toUtf8());
}

void QBencodeValue::detach()
{
    if (d != nullptr) {
        delete d;
        d = nullptr;
    }
    if (list != nullptr) {
        delete list;
        list = nullptr;
    }
    if (dict != nullptr) {
        delete dict;
        dict = nullptr;
    }
    t = Undefined;
}

void QBencodeValue::copyFrom(const QBencodeValue &other)
{
    t = other.t;
    switch (t) {
    case Dict:
        dict = new QBencodeDict(*other.dict);
        break;
    case List:
        list = new QBencodeList(*other.list);
        break;
    case Undefined:
    case Null:
        break;
    default:
        d = new QVariant(*other.d);
        break;
    }
}

QDebug operator<<(QDebug out, const QBencodeValue &obj)
{
    out << "QBencodeValue(";
    switch (obj.t) {
    case QBencodeValue::Undefined:
        out << "Undefined";
        break;
    case QBencodeValue::Null:
        out << "Null";
        break;
    case QBencodeValue::String:
        out << "String, " << obj.toByteArray();
        break;
    case QBencodeValue::Integer:
        out << "Integer, " << obj.toInteger();
        break;
    case QBencodeValue::List:
        out << "List, " << obj.toList();
        break;
    case QBencodeValue::Dict:
        out << "Dict, " << obj.toDict();
        break;
    }
    out << ")";
    return out;
}
<commit_msg>QBencodeValue: fix compiler warning<commit_after>#include <QVariant>
#include <QByteArray>
#include <QDebug>
#include <QString>
#include "qbencodevalue.h"

QBencodeValue::QBencodeValue(Type type)
    : d(nullptr), list(nullptr), dict(nullptr)
{
    t = type;
}

QBencodeValue::QBencodeValue(const QString &s)
    : list(nullptr), dict(nullptr)
{
    t = String;
    extractBytesFromQString(s);
}

QBencodeValue::QBencodeValue(const QByteArray &bytes)
    : list(nullptr), dict(nullptr)
{
    t = String;
    d = new QVariant(bytes);
}

QBencodeValue::QBencodeValue(int n)
    : list(nullptr), dict(nullptr)
{
    t = Integer;
    d = new QVariant(n);
}

QBencodeValue::QBencodeValue(qint64 n)
    : list(nullptr), dict(nullptr)
{
    t = Integer;
    d = new QVariant(n);
}

QBencodeValue::QBencodeValue(const QBencodeList &list)
    : d(nullptr), dict(nullptr)
{
    t = List;
    this->list = new QBencodeList(list);
}

QBencodeValue::QBencodeValue(const QBencodeDict &dict)
    : d(nullptr), list(nullptr)
{
    t = Dict;
    this->dict = new QBencodeDict(dict);
}

QBencodeValue::~QBencodeValue()
{
    detach();
}

QBencodeValue::QBencodeValue(const QBencodeValue &other)
    : d(nullptr), list(nullptr), dict(nullptr)
{
    copyFrom(other);
}

QBencodeValue &QBencodeValue::operator =(const QBencodeValue &other)
{
    detach();
    copyFrom(other);
    return *this;
}

QBencodeValue::QBencodeValue(QBencodeValue &&other)
    : t(Null), d(nullptr), list(nullptr), dict(nullptr)
{
    auto tmpT = t;
    auto tmpD = d;
    auto tmpDict = dict;
    auto tmpList = list;
    t = other.t;
    d = other.d;
    dict = other.dict;
    list = other.list;
    other.t = tmpT;
    other.d = tmpD;
    other.dict = tmpDict;
    other.list = tmpList;
}

QBencodeValue &QBencodeValue::operator =(QBencodeValue &&other)
{
    auto tmpT = t;
    auto tmpD = d;
    auto tmpDict = dict;
    auto tmpList = list;
    t = other.t;
    d = other.d;
    dict = other.dict;
    list = other.list;
    other.t = tmpT;
    other.d = tmpD;
    other.dict = tmpDict;
    other.list = tmpList;

    return *this;
}

/*static*/ QBencodeValue QBencodeValue::fromVariant(const QVariant &variant)
{
    switch (variant.type()) {
    case QMetaType::QString:
        return QBencodeValue(variant.toString());
    case QMetaType::QByteArray:
        return QBencodeValue(variant.toByteArray());
    case QMetaType::Int:
    case QMetaType::LongLong:
        return QBencodeValue(variant.toLongLong());
    case QMetaType::QVariantList: {
        QBencodeList benlist;
        for (auto item : variant.toList()) {
            benlist.append(fromVariant(item));
        }
        return QBencodeValue(benlist);
    }
    case QMetaType::QVariantHash: {
        QBencodeDict bendict;
        QHash<QString, QVariant> hash = variant.toHash();
        for (auto key : hash.keys()) {
            bendict.insert(key, fromVariant(hash[key]));
        }
        return QBencodeValue(bendict);
    }
    default:
        return QBencodeValue();
    }
}

QVariant QBencodeValue::toVariant() const
{
    // TODO: QBencodeValue::toVariant method stub
    qDebug() << "FIXME: stub method QBencodeValue:toVariant";
    return QVariant();
}

qint64 QBencodeValue::toInteger(qint64 defaultValue) const
{
    if (t == Integer) {
        return d->toLongLong();
    } else {
        return defaultValue;
    }
}

/*!
  Returns the value as string, assume UTF-8 encoded.
 */
QString QBencodeValue::toString(const QString &defaultValue) const
{
    if (t == String) {
        return QString(d->toByteArray());
    } else {
        return defaultValue;
    }
}

QByteArray QBencodeValue::toByteArray(const QByteArray &defaultValue) const
{
    if (t == String) {
        return d->toByteArray();
    } else {
        return defaultValue;
    }
}

QBencodeList QBencodeValue::toList() const
{
    if (t == List) {
        return *list;
    } else {
        return QBencodeList();
    }
}

QBencodeList QBencodeValue::toList(const QBencodeList &defaultValue) const
{
    if (t == List) {
        return *list;
    } else {
        return defaultValue;
    }
}

QBencodeDict QBencodeValue::toDict() const
{
    if (t == Dict) {
        return *dict;
    } else {
        return QBencodeDict();
    }
}

QBencodeDict QBencodeValue::toDict(const QBencodeDict &defaultValue) const
{
    if (t == Dict) {
        return *dict;
    } else {
        return defaultValue;
    }
}

bool QBencodeValue::operator==(const QBencodeValue &other) const
{
    if (t != other.t) { return false; }
    switch (t) {
    case Integer:
    case String:
        return *d == *other.d;
    case List:
        return *list == *other.list;
    case Dict:
        return *dict == *other.dict;
    case Undefined:
        return true;
    default:
        return false;
    }
}

bool QBencodeValue::operator!=(const QBencodeValue &other) const
{
    return !(*this == other);
}

void QBencodeValue::extractBytesFromQString(const QString &s)
{
    d = new QVariant(s.toUtf8());
}

void QBencodeValue::detach()
{
    if (d != nullptr) {
        delete d;
        d = nullptr;
    }
    if (list != nullptr) {
        delete list;
        list = nullptr;
    }
    if (dict != nullptr) {
        delete dict;
        dict = nullptr;
    }
    t = Undefined;
}

void QBencodeValue::copyFrom(const QBencodeValue &other)
{
    t = other.t;
    switch (t) {
    case Dict:
        dict = new QBencodeDict(*other.dict);
        break;
    case List:
        list = new QBencodeList(*other.list);
        break;
    case Undefined:
    case Null:
        break;
    default:
        d = new QVariant(*other.d);
        break;
    }
}

QDebug operator<<(QDebug out, const QBencodeValue &obj)
{
    out << "QBencodeValue(";
    switch (obj.t) {
    case QBencodeValue::Undefined:
        out << "Undefined";
        break;
    case QBencodeValue::Null:
        out << "Null";
        break;
    case QBencodeValue::String:
        out << "String, " << obj.toByteArray();
        break;
    case QBencodeValue::Integer:
        out << "Integer, " << obj.toInteger();
        break;
    case QBencodeValue::List:
        out << "List, " << obj.toList();
        break;
    case QBencodeValue::Dict:
        out << "Dict, " << obj.toDict();
        break;
    }
    out << ")";
    return out;
}
<|endoftext|>


<commit_before>/*
/*TeamSpeak 3 plugin development kit
Copyright (c) 2008-2016 TeamSpeak Systems GmbH
Copyright (c) 2016 Sean McNamara <smcnam@gmail.com>

Available to the general public at https://www.teamspeak.com/downloads with no specified license.
The author of kynnaugh-cc does not claim to license this file under the Apache License, version 2.0.
This file is a derivative work of the example in the Plugin SDK.
*/

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <teamspeak/public_definitions.h>
#include <plugin_definitions.h>
#include <ts3_functions.h>
#include <kynnaugh.h>
#include <sampledef.h>
#include <QtCore>
#include <QtWidgets>
#include <tuple>
#include "dbg.h"
#include "speechrec.h"

#define PLUGIN_API_VERSION 21
#define PATH_BUFSIZE 512
#define COMMAND_BUFSIZE 128
#define INFODATA_BUFSIZE 128
#define SERVERINFO_BUFSIZE 256
#define CHANNELINFO_BUFSIZE 512
#define RETURNCODE_BUFSIZE 128

struct TS3Functions *ts3func::funcs = nullptr;
bool ts3func::useTeamspeaksQt = true;
static struct TS3Functions ts3Functions;
static QString *pluginID = NULL;
static QHash<std::tuple<quint64, anyID, qint32>, sampledef*> sampledefs = QHash<std::tuple<quint64, anyID, qint32>, sampledef*>();

#define STATIC_STRING(x) static QString var = x; static QByteArray arr = var.toUtf8(); return arr.constData();

/*********************************** Required functions ************************************/
/*
 * If any of these required functions is not implemented, TS3 will refuse to load the plugin
 */

/* Unique name identifying this plugin */
const char* ts3plugin_name() {
    STATIC_STRING("Kynnaugh")
}

/* Plugin version */
const char* ts3plugin_version() {
    STATIC_STRING("1.0")
}

/* Plugin API version. Must be the same as the clients API major version, else the plugin fails to load. */
int ts3plugin_apiVersion() {
    return PLUGIN_API_VERSION;
}

/* Plugin author */
const char* ts3plugin_author() {
    STATIC_STRING("Sean McNamara / Coorbin Faydedar <smcnam@gmail.com>")
}

/* Plugin description */
const char* ts3plugin_description() {
    STATIC_STRING("Speech recognition and text to speech for deaf users.")
}

/* Set TeamSpeak 3 callback functions */
void ts3plugin_setFunctionPointers(const struct TS3Functions funcs) {
    ts3Functions = funcs;
    ts3func::funcs = &ts3Functions;
}

/*
 * Custom code called right after loading the plugin. Returns 0 on success, 1 on failure.
 * If the function returns 1 on failure, the plugin will be unloaded again.
 */
int ts3plugin_init() {
    char appPath[PATH_BUFSIZE];
    char resourcesPath[PATH_BUFSIZE];
    char configPath[PATH_BUFSIZE];
    char pluginPath[PATH_BUFSIZE];

    /* Your plugin init code here */
    printf("KYNNAUGH PLUGIN: init\n");

    /* Example on how to query application, resources and configuration paths from client */
    /* Note: Console client returns empty string for app and resources path */
    ts3Functions.getAppPath(appPath, PATH_BUFSIZE);
    ts3Functions.getResourcesPath(resourcesPath, PATH_BUFSIZE);
    ts3Functions.getConfigPath(configPath, PATH_BUFSIZE);
    ts3Functions.getPluginPath(pluginPath, PATH_BUFSIZE);

    //This code hacks around situations (only possible on OS X and Windows) where two versions of Qt are loaded in the same address space.
    //Teamspeak's own Qt creates its own QApplication, but we have to make *another* if "our" Qt isn't TeamSpeak's Qt.
    //This *never* occurs on Linux because of the lack of a "Side-by-side" library compatibility subsystem.
    int argc = 1;
    char *first = "a";
    char **argv = &first;
    QCoreApplication *app = QApplication::instance();
    if(app == nullptr)
    {
        ts3func::useTeamspeaksQt = false;
        app = new QApplication(argc, argv);
    }

    //Here's where we initialize QSettings. Can't use it before now!
    QApplication::setOrganizationName("rootaccessorg");
    QApplication::setApplicationName("kynnaugh-cc");

#if defined(_WIN32) && defined(KYNNAUGH_DEBUG)
    //Redirect stdout and stderr to a log file because TS handles them weirdly/badly on Windows
    QString stdoutlogfile = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + QDir::separator() + "kynnaugh-cc-stdout-log.txt";
    QString stderrlogfile = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + QDir::separator() + "kynnaugh-cc-stderr-log.txt";
    freopen(qPrintable(stdoutlogfile),"w",stdout);
    freopen(qPrintable(stderrlogfile),"w",stderr);
#endif

    return 0;  /* 0 = success, 1 = failure, -2 = failure but client will not show a "failed to load" warning */
    /* -2 is a very special case and should only be used if a plugin displays a dialog (e.g. overlay) asking the user to disable
     * the plugin again, avoiding the show another dialog by the client telling the user the plugin failed to load.
     * For normal case, if a plugin really failed to load because of an error, the correct return value is 1. */
}

/* Custom code called right before the plugin is unloaded */
void ts3plugin_shutdown() {
    /* Your plugin cleanup code here */
    qWarning("KYNNAUGH PLUGIN: shutdown\n");

    /*
     * Note:
     * If your plugin implements a settings dialog, it must be closed and deleted here, else the
     * TeamSpeak client will most likely crash (DLL removed but dialog from DLL code still open).
     */

    /* Free pluginID if we registered it */
    if(pluginID) {
        free(pluginID);
        pluginID = NULL;
    }
}

/*
 * If the plugin wants to use error return codes, plugin commands, hotkeys or menu items, it needs to register a command ID. This function will be
 * automatically called after the plugin was initialized. This function is optional. If you don't use these features, this function can be omitted.
 * Note the passed pluginID parameter is no longer valid after calling this function, so you must copy it and store it in the plugin.
 */
void ts3plugin_registerPluginID(const char* id) {
    qInstallMessageHandler(0);
    pluginID = new QString(id);
    dbg::qStdOut() << "KYNNAUGH PLUGIN: registerPluginID: " << pluginID;
}

/* Required to release the memory for parameter "data" allocated in ts3plugin_infoData and ts3plugin_initMenus */
void ts3plugin_freeMemory(void* data) {
    free(data);
}

/*
 * Plugin requests to be always automatically loaded by the TeamSpeak 3 client unless
 * the user manually disabled it in the plugin dialog.
 * This function is optional. If missing, no autoload is assumed.
 */
int ts3plugin_requestAutoload() {
    return 1;  /* 1 = request autoloaded, 0 = do not request autoload */
}

void ts3plugin_onEditPlaybackVoiceDataEvent(uint64 serverConnectionHandlerID, anyID clientID, short *samples,
                                       int sampleCount, int channels) {

    //The below logging message is printed _very_ frequently; only use if you're not sure if this callback is being called at all.
    //ts3Functions.printMessageToCurrentTab("ts3plugin_onEditPlaybackVoiceDataEvent");

    std::tuple<quint64, anyID, qint32> key = sampledef::getKey(serverConnectionHandlerID, clientID, channels);
    if(sampledefs.contains(key))
    {
        sampledefs[key]->update(samples, sampleCount);
    }
    else
    {
        char *nickname;
        ts3Functions.getClientVariableAsString(serverConnectionHandlerID, clientID, ClientProperties::CLIENT_NICKNAME, &nickname);
        dbg::qStdOut() << "KYNNAUGH PLUGIN: New sampledef for client #" << clientID << ", " << nickname << " with " << channels << " channels.\n";
        ts3Functions.freeMemory(nickname);
        sampledef *def = new sampledef(0, serverConnectionHandlerID, clientID, channels);
        sampledefs.insert(key, def);
        def->update(samples, sampleCount);
    }
}

/* Tell client if plugin offers a configuration window.
 * If this function is not implemented, it's an assumed "does not offer" (PLUGIN_OFFERS_NO_CONFIGURE). */
int ts3plugin_offersConfigure() {
    printf("KYNNAUGH: offersConfigure\n");
    /*
     * Return values:
     * PLUGIN_OFFERS_NO_CONFIGURE         - Plugin does not implement ts3plugin_configure
     * PLUGIN_OFFERS_CONFIGURE_NEW_THREAD - Plugin does implement ts3plugin_configure and requests to run this function in an own thread
     * PLUGIN_OFFERS_CONFIGURE_QT_THREAD  - Plugin does implement ts3plugin_configure and requests to run this function in the Qt GUI thread
     */
    if(ts3func::useTeamspeaksQt)
    {
        return PLUGIN_OFFERS_CONFIGURE_QT_THREAD;
    }
    else
    {
        return PLUGIN_OFFERS_CONFIGURE_NEW_THREAD;
    }
}

/* Plugin might offer a configuration window. If ts3plugin_offersConfigure returns 0, this function does not need to be implemented. */
void ts3plugin_configure(void* handle, void* qParentWidget) {
    printf("KYNNAUGH: configure\n");

    if(ts3func::useTeamspeaksQt)
    {
        //Use qParentWidget, which is a QDialog*
    }
    else
    {
        //Use handle, which is an opaque handle to a parent window
    }
}

namespace std
{
    inline uint qHash(const std::tuple<quint64, anyID, qint32> &key, uint seed = 0)
    {
        const quint64 &one = std::get<0>(key);
        const anyID   &two = std::get<1>(key);
        const qint32  &three = std::get<2>(key);

        return ::qHash(one, seed) ^ ::qHash(two, seed) ^ ::qHash(three, seed);
    }
}
<commit_msg>It might help if I wired up the config to ts3plugin_configure...<commit_after>/*
/*TeamSpeak 3 plugin development kit
Copyright (c) 2008-2016 TeamSpeak Systems GmbH
Copyright (c) 2016 Sean McNamara <smcnam@gmail.com>

Available to the general public at https://www.teamspeak.com/downloads with no specified license.
The author of kynnaugh-cc does not claim to license this file under the Apache License, version 2.0.
This file is a derivative work of the example in the Plugin SDK.
*/

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <teamspeak/public_definitions.h>
#include <plugin_definitions.h>
#include <ts3_functions.h>
#include <kynnaugh.h>
#include <sampledef.h>
#include <QtCore>
#include <QtWidgets>
#include <tuple>
#include "dbg.h"
#include "speechrec.h"
#include "kynnconfigdlg.h"

#define PLUGIN_API_VERSION 21
#define PATH_BUFSIZE 512
#define COMMAND_BUFSIZE 128
#define INFODATA_BUFSIZE 128
#define SERVERINFO_BUFSIZE 256
#define CHANNELINFO_BUFSIZE 512
#define RETURNCODE_BUFSIZE 128

struct TS3Functions *ts3func::funcs = nullptr;
bool ts3func::useTeamspeaksQt = true;
static struct TS3Functions ts3Functions;
static QString *pluginID = NULL;
static QHash<std::tuple<quint64, anyID, qint32>, sampledef*> sampledefs = QHash<std::tuple<quint64, anyID, qint32>, sampledef*>();

#define STATIC_STRING(x) static QString var = x; static QByteArray arr = var.toUtf8(); return arr.constData();

/*********************************** Required functions ************************************/
/*
 * If any of these required functions is not implemented, TS3 will refuse to load the plugin
 */

/* Unique name identifying this plugin */
const char* ts3plugin_name() {
    STATIC_STRING("Kynnaugh")
}

/* Plugin version */
const char* ts3plugin_version() {
    STATIC_STRING("1.0")
}

/* Plugin API version. Must be the same as the clients API major version, else the plugin fails to load. */
int ts3plugin_apiVersion() {
    return PLUGIN_API_VERSION;
}

/* Plugin author */
const char* ts3plugin_author() {
    STATIC_STRING("Sean McNamara / Coorbin Faydedar <smcnam@gmail.com>")
}

/* Plugin description */
const char* ts3plugin_description() {
    STATIC_STRING("Speech recognition and text to speech for deaf users.")
}

/* Set TeamSpeak 3 callback functions */
void ts3plugin_setFunctionPointers(const struct TS3Functions funcs) {
    ts3Functions = funcs;
    ts3func::funcs = &ts3Functions;
}

/*
 * Custom code called right after loading the plugin. Returns 0 on success, 1 on failure.
 * If the function returns 1 on failure, the plugin will be unloaded again.
 */
int ts3plugin_init() {
    char appPath[PATH_BUFSIZE];
    char resourcesPath[PATH_BUFSIZE];
    char configPath[PATH_BUFSIZE];
    char pluginPath[PATH_BUFSIZE];

    /* Your plugin init code here */
    printf("KYNNAUGH PLUGIN: init\n");

    /* Example on how to query application, resources and configuration paths from client */
    /* Note: Console client returns empty string for app and resources path */
    ts3Functions.getAppPath(appPath, PATH_BUFSIZE);
    ts3Functions.getResourcesPath(resourcesPath, PATH_BUFSIZE);
    ts3Functions.getConfigPath(configPath, PATH_BUFSIZE);
    ts3Functions.getPluginPath(pluginPath, PATH_BUFSIZE);

    //This code hacks around situations (only possible on OS X and Windows) where two versions of Qt are loaded in the same address space.
    //Teamspeak's own Qt creates its own QApplication, but we have to make *another* if "our" Qt isn't TeamSpeak's Qt.
    //This *never* occurs on Linux because of the lack of a "Side-by-side" library compatibility subsystem.
    int argc = 1;
    char *first = "a";
    char **argv = &first;
    QCoreApplication *app = QApplication::instance();
    if(app == nullptr)
    {
        ts3func::useTeamspeaksQt = false;
        app = new QApplication(argc, argv);
    }

    //Here's where we initialize QSettings. Can't use it before now!
    QApplication::setOrganizationName("rootaccessorg");
    QApplication::setApplicationName("kynnaugh-cc");

#if defined(_WIN32) && defined(KYNNAUGH_DEBUG)
    //Redirect stdout and stderr to a log file because TS handles them weirdly/badly on Windows
    QString stdoutlogfile = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + QDir::separator() + "kynnaugh-cc-stdout-log.txt";
    QString stderrlogfile = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + QDir::separator() + "kynnaugh-cc-stderr-log.txt";
    freopen(qPrintable(stdoutlogfile),"w",stdout);
    freopen(qPrintable(stderrlogfile),"w",stderr);
#endif

    return 0;  /* 0 = success, 1 = failure, -2 = failure but client will not show a "failed to load" warning */
    /* -2 is a very special case and should only be used if a plugin displays a dialog (e.g. overlay) asking the user to disable
     * the plugin again, avoiding the show another dialog by the client telling the user the plugin failed to load.
     * For normal case, if a plugin really failed to load because of an error, the correct return value is 1. */
}

/* Custom code called right before the plugin is unloaded */
void ts3plugin_shutdown() {
    /* Your plugin cleanup code here */
    qWarning("KYNNAUGH PLUGIN: shutdown\n");

    /*
     * Note:
     * If your plugin implements a settings dialog, it must be closed and deleted here, else the
     * TeamSpeak client will most likely crash (DLL removed but dialog from DLL code still open).
     */

    /* Free pluginID if we registered it */
    if(pluginID) {
        free(pluginID);
        pluginID = NULL;
    }
}

/*
 * If the plugin wants to use error return codes, plugin commands, hotkeys or menu items, it needs to register a command ID. This function will be
 * automatically called after the plugin was initialized. This function is optional. If you don't use these features, this function can be omitted.
 * Note the passed pluginID parameter is no longer valid after calling this function, so you must copy it and store it in the plugin.
 */
void ts3plugin_registerPluginID(const char* id) {
    qInstallMessageHandler(0);
    pluginID = new QString(id);
    dbg::qStdOut() << "KYNNAUGH PLUGIN: registerPluginID: " << pluginID;
}

/* Required to release the memory for parameter "data" allocated in ts3plugin_infoData and ts3plugin_initMenus */
void ts3plugin_freeMemory(void* data) {
    free(data);
}

/*
 * Plugin requests to be always automatically loaded by the TeamSpeak 3 client unless
 * the user manually disabled it in the plugin dialog.
 * This function is optional. If missing, no autoload is assumed.
 */
int ts3plugin_requestAutoload() {
    return 1;  /* 1 = request autoloaded, 0 = do not request autoload */
}

void ts3plugin_onEditPlaybackVoiceDataEvent(uint64 serverConnectionHandlerID, anyID clientID, short *samples,
                                       int sampleCount, int channels) {

    //The below logging message is printed _very_ frequently; only use if you're not sure if this callback is being called at all.
    //ts3Functions.printMessageToCurrentTab("ts3plugin_onEditPlaybackVoiceDataEvent");

    std::tuple<quint64, anyID, qint32> key = sampledef::getKey(serverConnectionHandlerID, clientID, channels);
    if(sampledefs.contains(key))
    {
        sampledefs[key]->update(samples, sampleCount);
    }
    else
    {
        char *nickname;
        ts3Functions.getClientVariableAsString(serverConnectionHandlerID, clientID, ClientProperties::CLIENT_NICKNAME, &nickname);
        dbg::qStdOut() << "KYNNAUGH PLUGIN: New sampledef for client #" << clientID << ", " << nickname << " with " << channels << " channels.\n";
        ts3Functions.freeMemory(nickname);
        sampledef *def = new sampledef(0, serverConnectionHandlerID, clientID, channels);
        sampledefs.insert(key, def);
        def->update(samples, sampleCount);
    }
}

/* Tell client if plugin offers a configuration window.
 * If this function is not implemented, it's an assumed "does not offer" (PLUGIN_OFFERS_NO_CONFIGURE). */
int ts3plugin_offersConfigure() {
    printf("KYNNAUGH: offersConfigure\n");
    /*
     * Return values:
     * PLUGIN_OFFERS_NO_CONFIGURE         - Plugin does not implement ts3plugin_configure
     * PLUGIN_OFFERS_CONFIGURE_NEW_THREAD - Plugin does implement ts3plugin_configure and requests to run this function in an own thread
     * PLUGIN_OFFERS_CONFIGURE_QT_THREAD  - Plugin does implement ts3plugin_configure and requests to run this function in the Qt GUI thread
     */
    if(ts3func::useTeamspeaksQt)
    {
        return PLUGIN_OFFERS_CONFIGURE_QT_THREAD;
    }
    else
    {
        return PLUGIN_OFFERS_CONFIGURE_NEW_THREAD;
    }
}

/* Plugin might offer a configuration window. If ts3plugin_offersConfigure returns 0, this function does not need to be implemented. */
void ts3plugin_configure(void* handle, void* qParentWidget) {
    printf("KYNNAUGH: configure\n");
    if(ts3func::useTeamspeaksQt)
    {
        //Use qParentWidget, which is a QDialog*
        static KynnConfigDlg *confdlg_tsqt = new KynnConfigDlg(static_cast<QWidget*>(qParentWidget));
        confdlg_tsqt->exec();
    }
    else
    {
        //Use handle, which is an opaque handle to a parent window
        static KynnConfigDlg *confdlg_opaque = new KynnConfigDlg(nullptr);
        confdlg_opaque->exec();
    }
}

namespace std
{
    inline uint qHash(const std::tuple<quint64, anyID, qint32> &key, uint seed = 0)
    {
        const quint64 &one = std::get<0>(key);
        const anyID   &two = std::get<1>(key);
        const qint32  &three = std::get<2>(key);

        return ::qHash(one, seed) ^ ::qHash(two, seed) ^ ::qHash(three, seed);
    }
}
<|endoftext|>


<commit_before>/*************************************************************************/
/*  register_types.cpp                                                   */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/
#include "register_types.h"
#include "gdnative/gdnative.h"

#include "gdnative.h"

#include "io/resource_loader.h"
#include "io/resource_saver.h"

#include "nativescript/register_types.h"

#include "core/engine.h"
#include "core/os/os.h"
#include "core/project_settings.h"

#ifdef TOOLS_ENABLED
#include "editor/editor_node.h"

// Class used to discover singleton gdnative files

void actual_discoverer_handler();

class GDNativeSingletonDiscover : public Object {
	// GDCLASS(GDNativeSingletonDiscover, Object)

	virtual String get_class() const {
		// okay, this is a really dirty hack.
		// We're overriding get_class so we can connect it to a signal
		// This works because get_class is a virtual method, so we don't
		// need to register a new class to ClassDB just for this one
		// little signal.

		actual_discoverer_handler();

		return "Object";
	}
};

Set<String> get_gdnative_singletons(EditorFileSystemDirectory *p_dir) {

	Set<String> file_paths;

	// check children

	for (int i = 0; i < p_dir->get_file_count(); i++) {
		String file_name = p_dir->get_file(i);
		String file_type = p_dir->get_file_type(i);

		if (file_type != "GDNativeLibrary") {
			continue;
		}

		Ref<GDNativeLibrary> lib = ResourceLoader::load(p_dir->get_file_path(i));
		if (lib.is_valid() && lib->is_singleton_gdnative()) {
			file_paths.insert(p_dir->get_file_path(i));
		}
	}

	// check subdirectories
	for (int i = 0; i < p_dir->get_subdir_count(); i++) {
		Set<String> paths = get_gdnative_singletons(p_dir->get_subdir(i));

		for (Set<String>::Element *E = paths.front(); E; E = E->next()) {
			file_paths.insert(E->get());
		}
	}

	return file_paths;
}

void actual_discoverer_handler() {
	EditorFileSystemDirectory *dir = EditorFileSystem::get_singleton()->get_filesystem();

	Set<String> file_paths = get_gdnative_singletons(dir);

	Array files;
	files.resize(file_paths.size());
	int i = 0;
	for (Set<String>::Element *E = file_paths.front(); E; i++, E = E->next()) {
		files.set(i, E->get());
	}

	ProjectSettings::get_singleton()->set("gdnative/singletons", files);

	ProjectSettings::get_singleton()->save();
}

GDNativeSingletonDiscover *discoverer = NULL;

void discoverer_callback() {
	discoverer = memnew(GDNativeSingletonDiscover);
	EditorFileSystem::get_singleton()->connect("filesystem_changed", discoverer, "get_class");
}

#endif

godot_variant cb_standard_varcall(void *handle, godot_string *p_procedure, godot_array *p_args) {
	if (handle == NULL) {
		ERR_PRINT("No valid library handle, can't call standard varcall procedure");
		godot_variant ret;
		godot_variant_new_nil(&ret);
		return ret;
	}

	void *library_proc;
	Error err = OS::get_singleton()->get_dynamic_library_symbol_handle(
			handle,
			*(String *)p_procedure,
			library_proc,
			true); // we roll our own message
	if (err != OK) {
		ERR_PRINT((String("GDNative procedure \"" + *(String *)p_procedure) + "\" does not exists and can't be called").utf8().get_data());
		godot_variant ret;
		godot_variant_new_nil(&ret);
		return ret;
	}

	godot_gdnative_procedure_fn proc;
	proc = (godot_gdnative_procedure_fn)library_proc;

	return proc(NULL, p_args);
}

void cb_singleton_call(
		void *p_handle,
		godot_string *p_proc_name,
		void *p_data,
		int p_num_args,
		void **p_args,
		void *r_return) {
	if (p_handle == NULL) {
		ERR_PRINT("No valid library handle, can't call singleton procedure");
		return;
	}

	void *singleton_proc;
	Error err = OS::get_singleton()->get_dynamic_library_symbol_handle(
			p_handle,
			*(String *)p_proc_name,
			singleton_proc);

	if (err != OK) {
		return;
	}

	void (*singleton_procedure_ptr)() = (void (*)())singleton_proc;
	singleton_procedure_ptr();
}

GDNativeCallRegistry *GDNativeCallRegistry::singleton;

Vector<Ref<GDNative> > singleton_gdnatives;

void register_gdnative_types() {

#ifdef TOOLS_ENABLED

	if (Engine::get_singleton()->is_editor_hint()) {
		EditorNode::add_init_callback(discoverer_callback);
	}
#endif

	ClassDB::register_class<GDNativeLibrary>();
	ClassDB::register_class<GDNative>();

	GDNativeCallRegistry::singleton = memnew(GDNativeCallRegistry);

	GDNativeCallRegistry::singleton->register_native_call_type("standard_varcall", cb_standard_varcall);

	GDNativeCallRegistry::singleton->register_native_raw_call_type("gdnative_singleton_call", cb_singleton_call);

	register_nativescript_types();

	// run singletons

	Array singletons = ProjectSettings::get_singleton()->get("gdnative/singletons");

	singleton_gdnatives.resize(singletons.size());

	for (int i = 0; i < singletons.size(); i++) {
		String path = singletons[i];

		Ref<GDNativeLibrary> lib = ResourceLoader::load(path);

		singleton_gdnatives[i].instance();
		singleton_gdnatives[i]->set_library(lib);

		if (!singleton_gdnatives[i]->initialize()) {
			// Can't initialize. Don't make a native_call then
			continue;
		}

		singleton_gdnatives[i]->call_native_raw(
				"gdnative_singleton_call",
				"godot_gdnative_singleton",
				NULL,
				0,
				NULL,
				NULL);
	}
}

void unregister_gdnative_types() {

	for (int i = 0; i < singleton_gdnatives.size(); i++) {

		if (singleton_gdnatives[i].is_null()) {
			continue;
		}

		if (!singleton_gdnatives[i]->is_initialized()) {
			continue;
		}

		singleton_gdnatives[i]->terminate();
	}

	unregister_nativescript_types();

	memdelete(GDNativeCallRegistry::singleton);

#ifdef TOOLS_ENABLED
	if (Engine::get_singleton()->is_editor_hint()) {
		memdelete(discoverer);
	}
#endif

	// This is for printing out the sizes of the core types

	/*
	print_line(String("array:\t")     + itos(sizeof(Array)));
	print_line(String("basis:\t")     + itos(sizeof(Basis)));
	print_line(String("color:\t")     + itos(sizeof(Color)));
	print_line(String("dict:\t" )     + itos(sizeof(Dictionary)));
	print_line(String("node_path:\t") + itos(sizeof(NodePath)));
	print_line(String("plane:\t")     + itos(sizeof(Plane)));
	print_line(String("poolarray:\t") + itos(sizeof(PoolByteArray)));
	print_line(String("quat:\t")      + itos(sizeof(Quat)));
	print_line(String("rect2:\t")     + itos(sizeof(Rect2)));
	print_line(String("rect3:\t")     + itos(sizeof(Rect3)));
	print_line(String("rid:\t")       + itos(sizeof(RID)));
	print_line(String("string:\t")    + itos(sizeof(String)));
	print_line(String("transform:\t") + itos(sizeof(Transform)));
	print_line(String("transfo2D:\t") + itos(sizeof(Transform2D)));
	print_line(String("variant:\t")   + itos(sizeof(Variant)));
	print_line(String("vector2:\t")   + itos(sizeof(Vector2)));
	print_line(String("vector3:\t")   + itos(sizeof(Vector3)));
	*/
}
<commit_msg>Fixed attempt to delete NULL pointer error<commit_after>/*************************************************************************/
/*  register_types.cpp                                                   */
/*************************************************************************/
/*                       This file is part of:                           */
/*                           GODOT ENGINE                                */
/*                      https://godotengine.org                          */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur.                 */
/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md)    */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/
#include "register_types.h"
#include "gdnative/gdnative.h"

#include "gdnative.h"

#include "io/resource_loader.h"
#include "io/resource_saver.h"

#include "nativescript/register_types.h"

#include "core/engine.h"
#include "core/os/os.h"
#include "core/project_settings.h"

#ifdef TOOLS_ENABLED
#include "editor/editor_node.h"

// Class used to discover singleton gdnative files

void actual_discoverer_handler();

class GDNativeSingletonDiscover : public Object {
	// GDCLASS(GDNativeSingletonDiscover, Object)

	virtual String get_class() const {
		// okay, this is a really dirty hack.
		// We're overriding get_class so we can connect it to a signal
		// This works because get_class is a virtual method, so we don't
		// need to register a new class to ClassDB just for this one
		// little signal.

		actual_discoverer_handler();

		return "Object";
	}
};

Set<String> get_gdnative_singletons(EditorFileSystemDirectory *p_dir) {

	Set<String> file_paths;

	// check children

	for (int i = 0; i < p_dir->get_file_count(); i++) {
		String file_name = p_dir->get_file(i);
		String file_type = p_dir->get_file_type(i);

		if (file_type != "GDNativeLibrary") {
			continue;
		}

		Ref<GDNativeLibrary> lib = ResourceLoader::load(p_dir->get_file_path(i));
		if (lib.is_valid() && lib->is_singleton_gdnative()) {
			file_paths.insert(p_dir->get_file_path(i));
		}
	}

	// check subdirectories
	for (int i = 0; i < p_dir->get_subdir_count(); i++) {
		Set<String> paths = get_gdnative_singletons(p_dir->get_subdir(i));

		for (Set<String>::Element *E = paths.front(); E; E = E->next()) {
			file_paths.insert(E->get());
		}
	}

	return file_paths;
}

void actual_discoverer_handler() {
	EditorFileSystemDirectory *dir = EditorFileSystem::get_singleton()->get_filesystem();

	Set<String> file_paths = get_gdnative_singletons(dir);

	Array files;
	files.resize(file_paths.size());
	int i = 0;
	for (Set<String>::Element *E = file_paths.front(); E; i++, E = E->next()) {
		files.set(i, E->get());
	}

	ProjectSettings::get_singleton()->set("gdnative/singletons", files);

	ProjectSettings::get_singleton()->save();
}

GDNativeSingletonDiscover *discoverer = NULL;

void discoverer_callback() {
	discoverer = memnew(GDNativeSingletonDiscover);
	EditorFileSystem::get_singleton()->connect("filesystem_changed", discoverer, "get_class");
}

#endif

godot_variant cb_standard_varcall(void *handle, godot_string *p_procedure, godot_array *p_args) {
	if (handle == NULL) {
		ERR_PRINT("No valid library handle, can't call standard varcall procedure");
		godot_variant ret;
		godot_variant_new_nil(&ret);
		return ret;
	}

	void *library_proc;
	Error err = OS::get_singleton()->get_dynamic_library_symbol_handle(
			handle,
			*(String *)p_procedure,
			library_proc,
			true); // we roll our own message
	if (err != OK) {
		ERR_PRINT((String("GDNative procedure \"" + *(String *)p_procedure) + "\" does not exists and can't be called").utf8().get_data());
		godot_variant ret;
		godot_variant_new_nil(&ret);
		return ret;
	}

	godot_gdnative_procedure_fn proc;
	proc = (godot_gdnative_procedure_fn)library_proc;

	return proc(NULL, p_args);
}

void cb_singleton_call(
		void *p_handle,
		godot_string *p_proc_name,
		void *p_data,
		int p_num_args,
		void **p_args,
		void *r_return) {
	if (p_handle == NULL) {
		ERR_PRINT("No valid library handle, can't call singleton procedure");
		return;
	}

	void *singleton_proc;
	Error err = OS::get_singleton()->get_dynamic_library_symbol_handle(
			p_handle,
			*(String *)p_proc_name,
			singleton_proc);

	if (err != OK) {
		return;
	}

	void (*singleton_procedure_ptr)() = (void (*)())singleton_proc;
	singleton_procedure_ptr();
}

GDNativeCallRegistry *GDNativeCallRegistry::singleton;

Vector<Ref<GDNative> > singleton_gdnatives;

void register_gdnative_types() {

#ifdef TOOLS_ENABLED

	if (Engine::get_singleton()->is_editor_hint()) {
		EditorNode::add_init_callback(discoverer_callback);
	}
#endif

	ClassDB::register_class<GDNativeLibrary>();
	ClassDB::register_class<GDNative>();

	GDNativeCallRegistry::singleton = memnew(GDNativeCallRegistry);

	GDNativeCallRegistry::singleton->register_native_call_type("standard_varcall", cb_standard_varcall);

	GDNativeCallRegistry::singleton->register_native_raw_call_type("gdnative_singleton_call", cb_singleton_call);

	register_nativescript_types();

	// run singletons

	Array singletons = ProjectSettings::get_singleton()->get("gdnative/singletons");

	singleton_gdnatives.resize(singletons.size());

	for (int i = 0; i < singletons.size(); i++) {
		String path = singletons[i];

		Ref<GDNativeLibrary> lib = ResourceLoader::load(path);

		singleton_gdnatives[i].instance();
		singleton_gdnatives[i]->set_library(lib);

		if (!singleton_gdnatives[i]->initialize()) {
			// Can't initialize. Don't make a native_call then
			continue;
		}

		singleton_gdnatives[i]->call_native_raw(
				"gdnative_singleton_call",
				"godot_gdnative_singleton",
				NULL,
				0,
				NULL,
				NULL);
	}
}

void unregister_gdnative_types() {

	for (int i = 0; i < singleton_gdnatives.size(); i++) {

		if (singleton_gdnatives[i].is_null()) {
			continue;
		}

		if (!singleton_gdnatives[i]->is_initialized()) {
			continue;
		}

		singleton_gdnatives[i]->terminate();
	}

	unregister_nativescript_types();

	memdelete(GDNativeCallRegistry::singleton);

#ifdef TOOLS_ENABLED
	if (Engine::get_singleton()->is_editor_hint() && discoverer != NULL) {
		memdelete(discoverer);
	}
#endif

	// This is for printing out the sizes of the core types

	/*
	print_line(String("array:\t")     + itos(sizeof(Array)));
	print_line(String("basis:\t")     + itos(sizeof(Basis)));
	print_line(String("color:\t")     + itos(sizeof(Color)));
	print_line(String("dict:\t" )     + itos(sizeof(Dictionary)));
	print_line(String("node_path:\t") + itos(sizeof(NodePath)));
	print_line(String("plane:\t")     + itos(sizeof(Plane)));
	print_line(String("poolarray:\t") + itos(sizeof(PoolByteArray)));
	print_line(String("quat:\t")      + itos(sizeof(Quat)));
	print_line(String("rect2:\t")     + itos(sizeof(Rect2)));
	print_line(String("rect3:\t")     + itos(sizeof(Rect3)));
	print_line(String("rid:\t")       + itos(sizeof(RID)));
	print_line(String("string:\t")    + itos(sizeof(String)));
	print_line(String("transform:\t") + itos(sizeof(Transform)));
	print_line(String("transfo2D:\t") + itos(sizeof(Transform2D)));
	print_line(String("variant:\t")   + itos(sizeof(Variant)));
	print_line(String("vector2:\t")   + itos(sizeof(Vector2)));
	print_line(String("vector3:\t")   + itos(sizeof(Vector3)));
	*/
}
<|endoftext|>


<commit_before>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
// This file originates from the openFABMAP project:
// [http://code.google.com/p/openfabmap/]
//
// For published work which uses all or part of OpenFABMAP, please cite:
// [http://ieeexplore.ieee.org/xpl/articleDetails.jsp?arnumber=6224843]
//
// Original Algorithm by Mark Cummins and Paul Newman:
// [http://ijr.sagepub.com/content/27/6/647.short]
// [http://ieeexplore.ieee.org/xpl/articleDetails.jsp?arnumber=5613942]
// [http://ijr.sagepub.com/content/30/9/1100.abstract]
//
//                           License Agreement
//
// Copyright (C) 2012 Arren Glover [aj.glover@qut.edu.au] and
//                    Will Maddern [w.maddern@qut.edu.au], all rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's 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.
//
//   * The name of the copyright holders may not 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 Intel Corporation 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.
//
//M*/

#include "opencv2/opencv.hpp"
#include "opencv2/nonfree/nonfree.hpp"
#include <boost/filesystem.hpp>
#include <cstdio>

using namespace cv;
using namespace std;

void help() {

}

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

    /*

    Note: the vocabulary and training data is specifically made for this openCV
    example. It is not reccomended for use with other datasets as it is
    intentionally small to reduce baggage in the openCV project.

    A new vocabulary can be generated using the supplied BOWMSCtrainer (or other
    clustering method such as K-means

    New training data can be generated by extracting bag-of-words using the
    openCV BOWImgDescriptorExtractor class.

    vocabulary, chow-liu tree, training data, and test data can all be saved and
    loaded using openCV's FileStorage class and it is not necessary to generate
    data each time as done in this example

    */

    cout << "This sample program demonstrates the FAB-MAP image matching "
        "algorithm" << endl << endl;

    string dataDir, mapDir;
    if (argc == 1) {
        dataDir = "fabmap/";
    } else if (argc == 2) {
        dataDir = string(argv[1]);
        dataDir += "/";
    } else if (argc == 3) {
		dataDir = string(argv[1]);
        dataDir += "/";
		mapDir = string(argv[2]);
		mapDir += "/";
	} else {
        //incorrect arguments
        cout << "Usage: live_fabmap <sample data directory> <map data dir>" <<
            endl;
        return -1;
    }

    FileStorage fs;

    //load/generate vocab
    cout << "Loading Vocabulary: " <<
        dataDir + string("vocab_big.yml") << endl << endl;
    fs.open(dataDir + string("vocab_big.yml"), FileStorage::READ);
    Mat vocab;
    fs["Vocabulary"] >> vocab;
    if (vocab.empty()) {
        cerr << "Vocabulary not found" << endl;
        return -1;
    }
    fs.release();

    //load/generate training data

    cout << "Loading Training Data: " <<
        dataDir + string("training_data.yml") << endl << endl;
    fs.open(dataDir + string("training_data.yml"), FileStorage::READ);
    Mat trainData;
    fs["BOWImageDescs"] >> trainData;
    if (trainData.empty()) {
        cerr << "Training Data not found" << endl;
        return -1;
    }
    fs.release();

    //create Chow-liu tree
    cout << "Making Chow-Liu Tree from training data" << endl <<
        endl;
    of2::ChowLiuTree treeBuilder;
    treeBuilder.add(trainData);
    Mat tree = treeBuilder.make();

    //generate test data
    cout << "Extracting Test Data from images" << endl <<
        endl;
    Ptr<FeatureDetector> detector =
        new DynamicAdaptedFeatureDetector(
        AdjusterAdapter::create("SURF"), 100, 130, 5);
    Ptr<DescriptorExtractor> extractor =
        // DescriptorExtractor::create("SIFT");
        new SurfDescriptorExtractor(1000, 4, 2, false, true);
    Ptr<DescriptorMatcher> matcher =
        DescriptorMatcher::create("FlannBased");

    BOWImgDescriptorExtractor bide(extractor, matcher);
    bide.setVocabulary(vocab);

    vector<string> imageNames;
    namespace bfs = boost::filesystem;

    bfs::path p(mapDir);
    bfs::directory_iterator end_iter;
    if (bfs::is_directory(p)) {
      for (bfs::directory_iterator dir_iter(p); dir_iter != end_iter;
          ++dir_iter) {
        if (bfs::is_regular_file(dir_iter->status()) ) {
          printf("%s\n", dir_iter->path().c_str());
          imageNames.push_back(dir_iter->path().native());
        }
      }
    }

    std::sort(imageNames.begin(), imageNames.end());

    printf("Number of image files being processed is %lu\n", imageNames.size());

    Mat testData;
    Mat frame;
    Mat bow;
    vector<KeyPoint> kpts;

    vector<Mat> map_images;

    for(size_t i = 0; i < imageNames.size(); i++) {
        cout << imageNames[i] << endl;
        frame = imread(imageNames[i]);
        if(frame.empty()) {
            cerr << "Test images not found" << endl;
            return -1;
        }

        map_images.push_back(frame);

        detector->detect(frame, kpts);

        bide.compute(frame, kpts, bow);

        testData.push_back(bow);

        // drawKeypoints(frame, kpts, frame);
        // imshow(imageNames[i], frame);
        // waitKey(10);
    }

    //run fabmap
    cout << "Running FAB-MAP algorithm" << endl <<
        endl;
    Ptr<of2::FabMap> fabmap;

    fabmap = new of2::FabMap2(tree, 0.39, 0, of2::FabMap::SAMPLED |
        of2::FabMap::CHOW_LIU);
    fabmap->addTraining(trainData);

    vector<of2::IMatch> matches;
    fabmap->compare(testData, matches, true);

    // read images from camera
    cv::VideoCapture cap(1);
    if (!cap.isOpened()) {
      printf("Opening the default camera did not succeed\n");
      return -1;
    }

    int framenum = 0;
    for (;;) {
      Mat frame;
      cap >> frame;

      Mat visualword_descriptor;
      vector<KeyPoint> kpts;
      detector->detect(frame, kpts);

      drawKeypoints(frame, kpts, frame);
      imshow("input RGB image", frame);
      bide.compute(frame, kpts, visualword_descriptor);

      vector<of2::IMatch> matches;
      fabmap->compare(visualword_descriptor, matches);

      vector<of2::IMatch>::iterator l;

      double max_prob = 0;
      int max_img_idx = -1;
      // cout << "---------------------" << endl;
      for (l = matches.begin(); l != matches.end(); l++) {
        cout << "prob is " << l->match << endl;
        if (max_prob < l->match) {
           max_prob = l->match;
           max_img_idx = l->imgIdx;
        }
      }

      // cout << " Max idx is " << max_img_idx << endl;
      cv::Mat disp_image;
      if (max_img_idx == -1) {
        disp_image = Mat::zeros(frame.rows, frame.cols, CV_8UC3);
      } else {
        disp_image = map_images[max_img_idx];
      }
      cv::imshow("Closest Map image", disp_image);
      int keyp = cv::waitKey(10);
      if (keyp == 27) {
        printf("Done capturing.\n");
        break;
      } else if (keyp == 'h') {
	help();
      }
    }

 #if 0
    //display output
    Mat result_small = Mat::zeros(imageNames.size(), imageNames.size(), CV_8UC1);
    vector<of2::IMatch>::iterator l;

    for(l = matches.begin(); l != matches.end(); l++) {
            if(l->imgIdx < 0) {
                result_small.at<char>(l->queryIdx, l->queryIdx) =
                    (char)(l->match*255);

            } else {
                result_small.at<char>(l->queryIdx, l->imgIdx) =
                    (char)(l->match*255);
            }
    }

    Mat result_large(100, 100, CV_8UC1);
    resize(result_small, result_large, Size(500, 500), 0, 0, CV_INTER_NN);

    cout << endl << "Press any key to exit" << endl;
    imshow("Confusion Matrix", result_large);
    waitKey();
  #endif
    return 0;
}
<commit_msg>updating help comments<commit_after>/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
// This file originates from the openFABMAP project:
// [http://code.google.com/p/openfabmap/]
//
// For published work which uses all or part of OpenFABMAP, please cite:
// [http://ieeexplore.ieee.org/xpl/articleDetails.jsp?arnumber=6224843]
//
// Original Algorithm by Mark Cummins and Paul Newman:
// [http://ijr.sagepub.com/content/27/6/647.short]
// [http://ieeexplore.ieee.org/xpl/articleDetails.jsp?arnumber=5613942]
// [http://ijr.sagepub.com/content/30/9/1100.abstract]
//
//                           License Agreement
//
// Copyright (C) 2012 Arren Glover [aj.glover@qut.edu.au] and
//                    Will Maddern [w.maddern@qut.edu.au], all rights reserved.
//
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's 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.
//
//   * The name of the copyright holders may not 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 Intel Corporation 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.
//
//M*/

#include "opencv2/opencv.hpp"
#include "opencv2/nonfree/nonfree.hpp"
#include <boost/filesystem.hpp>
#include <cstdio>

using namespace cv;
using namespace std;

void help() {

}

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

    /*

    Note: the vocabulary and training data is specifically made for this openCV
    example. It is not reccomended for use with other datasets as it is
    intentionally small to reduce baggage in the openCV project.

    A new vocabulary can be generated using the supplied BOWMSCtrainer (or other
    clustering method such as K-means

    New training data can be generated by extracting bag-of-words using the
    openCV BOWImgDescriptorExtractor class.

    vocabulary, chow-liu tree, training data, and test data can all be saved and
    loaded using openCV's FileStorage class and it is not necessary to generate
    data each time as done in this example

    */

    cout << "This sample program demonstrates the FAB-MAP image matching "
        "algorithm" << endl << endl;

    string dataDir, mapDir;
    if (argc == 1) {
        //incorrect arguments
        cout << "Usage: live_fabmap <vocab & train yml files directory> <map data dir>" <<
            endl;
        return (-1);
    } else if (argc == 2) {
        if(!strcmp(argv[1],"-h") || !strcmp(argv[1],"--help")) {
            cout << "Usage: live_fabmap <sample data directory> <map data dir>" <<
                endl;
            return(-1);
        }
        dataDir = string(argv[1]);
        dataDir += "/";
    } else if (argc == 3) {
	dataDir = string(argv[1]);
        dataDir += "/";
	mapDir = string(argv[2]);
	mapDir += "/";
    } else {
        //incorrect arguments
        cout << "Usage: live_fabmap <sample data directory> <map data dir>" <<
            endl;
        return -1;
    }

    FileStorage fs;

    //load/generate vocab
    cout << "Loading Vocabulary: " <<
        dataDir + string("vocab_big.yml") << endl << endl;
    fs.open(dataDir + string("vocab_big.yml"), FileStorage::READ);
    Mat vocab;
    fs["Vocabulary"] >> vocab;
    if (vocab.empty()) {
        cerr << "Vocabulary not found" << endl;
        return -1;
    }
    fs.release();

    //load/generate training data

    cout << "Loading Training Data: " <<
        dataDir + string("training_data.yml") << endl << endl;
    fs.open(dataDir + string("training_data.yml"), FileStorage::READ);
    Mat trainData;
    fs["BOWImageDescs"] >> trainData;
    if (trainData.empty()) {
        cerr << "Training Data not found" << endl;
        return -1;
    }
    fs.release();

    //create Chow-liu tree
    cout << "Making Chow-Liu Tree from training data" << endl <<
        endl;
    of2::ChowLiuTree treeBuilder;
    treeBuilder.add(trainData);
    Mat tree = treeBuilder.make();

    //generate test data
    cout << "Extracting Test Data from images" << endl <<
        endl;
    Ptr<FeatureDetector> detector =
        new DynamicAdaptedFeatureDetector(
        AdjusterAdapter::create("SURF"), 100, 130, 5);
    Ptr<DescriptorExtractor> extractor =
        // DescriptorExtractor::create("SIFT");
        new SurfDescriptorExtractor(1000, 4, 2, false, true);
    Ptr<DescriptorMatcher> matcher =
        DescriptorMatcher::create("FlannBased");

    BOWImgDescriptorExtractor bide(extractor, matcher);
    bide.setVocabulary(vocab);

    vector<string> imageNames;
    namespace bfs = boost::filesystem;

    bfs::path p(mapDir);
    bfs::directory_iterator end_iter;
    if (bfs::is_directory(p)) {
      for (bfs::directory_iterator dir_iter(p); dir_iter != end_iter;
          ++dir_iter) {
        if (bfs::is_regular_file(dir_iter->status()) ) {
          printf("%s\n", dir_iter->path().c_str());
          imageNames.push_back(dir_iter->path().native());
        }
      }
    }

    std::sort(imageNames.begin(), imageNames.end());

    printf("Number of image files being processed is %lu\n", imageNames.size());

    Mat testData;
    Mat frame;
    Mat bow;
    vector<KeyPoint> kpts;

    vector<Mat> map_images;

    for(size_t i = 0; i < imageNames.size(); i++) {
        cout << imageNames[i] << endl;
        frame = imread(imageNames[i]);
        if(frame.empty()) {
            cerr << "Test images not found" << endl;
            return -1;
        }

        map_images.push_back(frame);

        detector->detect(frame, kpts);

        bide.compute(frame, kpts, bow);

        testData.push_back(bow);

        // drawKeypoints(frame, kpts, frame);
        // imshow(imageNames[i], frame);
        // waitKey(10);
    }

    //run fabmap
    cout << "Running FAB-MAP algorithm" << endl <<
        endl;
    Ptr<of2::FabMap> fabmap;

    fabmap = new of2::FabMap2(tree, 0.39, 0, of2::FabMap::SAMPLED |
        of2::FabMap::CHOW_LIU);
    fabmap->addTraining(trainData);

    vector<of2::IMatch> matches;
    fabmap->compare(testData, matches, true);

    // read images from camera
    cv::VideoCapture cap(1);
    if (!cap.isOpened()) {
      printf("Opening the default camera did not succeed\n");
      return -1;
    }

    int framenum = 0;
    for (;;) {
      Mat frame;
      cap >> frame;

      Mat visualword_descriptor;
      vector<KeyPoint> kpts;
      detector->detect(frame, kpts);

      drawKeypoints(frame, kpts, frame);
      imshow("input RGB image", frame);
      bide.compute(frame, kpts, visualword_descriptor);

      vector<of2::IMatch> matches;
      fabmap->compare(visualword_descriptor, matches);

      vector<of2::IMatch>::iterator l;

      double max_prob = 0;
      int max_img_idx = -1;
      cout << "---------------------" << endl;
      for (l = matches.begin(); l != matches.end(); l++) {
        cout << "prob is " << l->match << endl;
        if (max_prob < l->match) {
           max_prob = l->match;
           max_img_idx = l->imgIdx;
        }
      }

      // cout << " Max idx is " << max_img_idx << endl;
      cv::Mat disp_image;
      if (max_img_idx == -1) {
        disp_image = Mat::zeros(frame.rows, frame.cols, CV_8UC3);
      } else {
        disp_image = map_images[max_img_idx];
      }
      cv::imshow("Closest Map image", disp_image);
      int keyp = cv::waitKey(10);
      if (keyp == 27) {
        printf("Done capturing.\n");
        break;
      } else if (keyp == 'h') {
	help();
      }
    }
    return 0;
}
<|endoftext|>


<commit_before><commit_msg>Planning: removed the duplicated calculation of speed_ in obstacle constructor.<commit_after><|endoftext|>