<commit_before>// Copyright Daniel Wallin & Arvid Norberg 2009. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <boost/python.hpp>
#include <libtorrent/create_torrent.hpp>
#include <libtorrent/file_storage.hpp>
#include "libtorrent/intrusive_ptr_base.hpp"

using namespace boost::python;
using namespace libtorrent;

void bind_create_torrent()
{
    void (file_storage::*add_file0)(file_entry const&) = &file_storage::add_file;
    void (file_storage::*add_file1)(fs::path const&, size_type) = &file_storage::add_file;

    class_<file_storage>("file_storage")
        .def("is_valid", &file_storage::is_valid)
        .def("add_file", add_file0)
        .def("add_file", add_file1)
        .def("num_files", &file_storage::num_files)
        .def("at", &file_storage::at, return_internal_reference<>())
        .def("total_size", &file_storage::total_size)
        .def("set_num_pieces", &file_storage::set_num_pieces)
        .def("num_pieces", &file_storage::num_pieces)
        .def("set_piece_length", &file_storage::set_piece_length)
        .def("piece_length", &file_storage::piece_length)
        .def("piece_size", &file_storage::piece_size)
        .def("set_name", &file_storage::set_name)
        .def("name", &file_storage::name, return_internal_reference<>())
        ;

    class_<create_torrent>("create_torrent", no_init)
        .def(init<file_storage&>())
        .def(init<file_storage&, int>())

        .def("generate", &create_torrent::generate)

        .def("files", &create_torrent::files, return_internal_reference<>())
        .def("set_comment", &create_torrent::set_comment)
        .def("set_creator", &create_torrent::set_creator)
        .def("set_hash", &create_torrent::set_hash)
        .def("add_url_seed", &create_torrent::add_url_seed)
        .def("add_node", &create_torrent::add_node)
        .def("add_tracker", &create_torrent::add_tracker)
        .def("set_priv", &create_torrent::set_priv)
        .def("num_pieces", &create_torrent::num_pieces)
        .def("piece_length", &create_torrent::piece_length)
        .def("piece_size", &create_torrent::piece_size)
        .def("priv", &create_torrent::priv)
        ;
}
<commit_msg>python binding fix for file_storage<commit_after>// Copyright Daniel Wallin & Arvid Norberg 2009. Use, modification and distribution is
// subject to the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#include <boost/python.hpp>
#include <libtorrent/create_torrent.hpp>
#include <libtorrent/file_storage.hpp>
#include "libtorrent/intrusive_ptr_base.hpp"

using namespace boost::python;
using namespace libtorrent;

void bind_create_torrent()
{
    void (file_storage::*add_file0)(file_entry const&) = &file_storage::add_file;
    void (file_storage::*add_file1)(fs::path const&, size_type, int) = &file_storage::add_file;
    void (file_storage::*add_file2)(fs::wpath const&, size_type, int) = &file_storage::add_file;

    void (file_storage::*set_name0)(std::string const&) = &file_storage::set_name;
    void (file_storage::*set_name1)(std::wstring const&) = &file_storage::set_name;

    class_<file_storage>("file_storage")
        .def("is_valid", &file_storage::is_valid)
        .def("add_file", add_file0)
        .def("add_file", add_file1, (arg("path"), arg("size"), arg("flags") = 0))
        .def("add_file", add_file2, (arg("path"), arg("size"), arg("flags") = 0))
        .def("num_files", &file_storage::num_files)
        .def("at", &file_storage::at, return_internal_reference<>())
        .def("total_size", &file_storage::total_size)
        .def("set_num_pieces", &file_storage::set_num_pieces)
        .def("num_pieces", &file_storage::num_pieces)
        .def("set_piece_length", &file_storage::set_piece_length)
        .def("piece_length", &file_storage::piece_length)
        .def("piece_size", &file_storage::piece_size)
        .def("set_name", set_name0)
        .def("set_name", set_name1)
        .def("name", &file_storage::name, return_internal_reference<>())
        ;

    class_<create_torrent>("create_torrent", no_init)
        .def(init<file_storage&>())
        .def(init<file_storage&, int>())

        .def("generate", &create_torrent::generate)

        .def("files", &create_torrent::files, return_internal_reference<>())
        .def("set_comment", &create_torrent::set_comment)
        .def("set_creator", &create_torrent::set_creator)
        .def("set_hash", &create_torrent::set_hash)
        .def("add_url_seed", &create_torrent::add_url_seed)
        .def("add_node", &create_torrent::add_node)
        .def("add_tracker", &create_torrent::add_tracker)
        .def("set_priv", &create_torrent::set_priv)
        .def("num_pieces", &create_torrent::num_pieces)
        .def("piece_length", &create_torrent::piece_length)
        .def("piece_size", &create_torrent::piece_size)
        .def("priv", &create_torrent::priv)
        ;
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <algorithm>
#include "kernel/find_fn.h"
#include "kernel/instantiate.h"
#include "library/trace.h"
#include "library/locals.h"
#include "library/replace_visitor.h"
#include "library/equations_compiler/compiler.h"
#include "library/equations_compiler/util.h"
#include "library/equations_compiler/structural_rec.h"
#include "library/equations_compiler/unbounded_rec.h"
#include "library/equations_compiler/wf_rec.h"
#include "library/equations_compiler/elim_match.h"

namespace lean {
#define trace_compiler(Code) lean_trace("eqn_compiler", scope_trace_env _scope1(ctx.env(), ctx); Code)

static bool has_nested_rec(expr const & eqns) {
    return static_cast<bool>(find(eqns, [&](expr const & e, unsigned) {
                return is_local(e) && local_info(e).is_rec();
            }));
}

static eqn_compiler_result compile_equations_core(environment & env, options const & opts,
                                   metavar_context & mctx, local_context const & lctx,
                                   expr const & eqns) {
    type_context ctx(env, opts, mctx, lctx, transparency_mode::Semireducible);
    trace_compiler(tout() << "compiling\n" << eqns << "\n";);
    trace_compiler(tout() << "recursive:          " << is_recursive_eqns(ctx, eqns) << "\n";);
    trace_compiler(tout() << "nested recursion:   " << has_nested_rec(eqns) << "\n";);
    trace_compiler(tout() << "using_well_founded: " << is_wf_equations(eqns) << "\n";);
    equations_header const & header = get_equations_header(eqns);
    lean_assert(header.m_is_meta || !has_nested_rec(eqns));

    if (header.m_is_meta) {
        if (is_wf_equations(eqns)) {
            throw exception("invalid use of 'using_well_founded', we do not need to use well founded recursion for meta definitions, since they can use unbounded recursion");
        }
        return unbounded_rec(env, opts, mctx, lctx, eqns);
    }

    if (is_wf_equations(eqns)) {
        return wf_rec(env, opts, mctx, lctx, eqns);
    }

    if (header.m_num_fns == 1) {
        if (!is_recursive_eqns(ctx, eqns)) {
            return mk_nonrec(env, opts, mctx, lctx, eqns);
        } else if (auto r = try_structural_rec(env, opts, mctx, lctx, eqns)) {
            return *r;
        }
    }

    return wf_rec(env, opts, mctx, lctx, eqns);
}

/** Auxiliary class for pulling nested recursive calls.
    Example: given

    definition f : nat → (nat × nat) → nat
    | 0      m := m.1
    | (n+1)  m :=
      match m with
      | (a, b) := f n (b, a + 1)
      end

    when we compile

      match m with
      | (a, b) := f n (b, a + 1)
      end

    we consinder (f n (b, a + 1)) to be a nested recursive call.
    Then, we transform the expression to

      (fun g,
       match m with
       | (a, b) := g a b
       end) (fun a b, f n (b, a + 1))

    Compile the match, and then beta-reduce.
*/
struct pull_nested_rec_fn : public replace_visitor {
    environment &         m_env;
    options               m_opts;
    metavar_context &     m_mctx;
    buffer<local_context> m_lctx_stack;
    buffer<expr>          m_new_locals;
    buffer<expr>          m_new_values;

    pull_nested_rec_fn(environment & env, options const & opts, metavar_context & mctx, local_context const & lctx):
        m_env(env), m_opts(opts), m_mctx(mctx) {
        m_lctx_stack.push_back(lctx);
    }

    local_context & base_lctx() { return m_lctx_stack[0]; }

    local_context & lctx() { return m_lctx_stack.back(); }

    type_context mk_type_context(local_context const & lctx) {
        return type_context(m_env, m_opts, m_mctx, lctx, transparency_mode::Semireducible);
    }

    expr visit_lambda_pi_let(bool is_lam, expr const & e) {
        buffer<expr> locals;
        m_lctx_stack.push_back(m_lctx_stack.back());
        expr t = e;
        while (true) {
            if ((is_lam && is_lambda(t)) || (!is_lam && is_pi(t))) {
                expr d = instantiate_rev(binding_domain(t), locals.size(), locals.data());
                d = visit(d);
                expr x = lctx().mk_local_decl(binding_name(t), d, binding_info(t));
                locals.push_back(x);
                t = binding_body(t);
            } else if (is_let(t)) {
                expr d = instantiate_rev(let_type(t), locals.size(), locals.data());
                expr v = instantiate_rev(let_value(t), locals.size(), locals.data());
                d = visit(d);
                v = visit(v);
                expr x = lctx().mk_local_decl(let_name(t), d, v);
                locals.push_back(x);
                t = let_body(t);
            } else {
                break;
            }
        }
        t = instantiate_rev(t, locals.size(), locals.data());
        t = visit(t);
        type_context ctx = mk_type_context(lctx());
        t = is_lam ? ctx.mk_lambda(locals, t) : ctx.mk_pi(locals, t);
        m_mctx = ctx.mctx();
        m_lctx_stack.pop_back();
        /* We clear the cache whenever we visit a binder because of
           collect_local_props.

           When pulling a recursive call (f t), the resulting term
           may contain local variables that do not occur in (f t).
           Thus, the cached value for (f t) may not be valid
           in other contexts.

           By clearing the cache we conservatively fix this issue.

           Here is an example:

           def filter : list A → list A
           | nil      := nil
           | (a :: l) :=
              match (H a) with
              | (is_true h_1) := a :: filter l
              | (is_false h_2) := filter l
              end

           The first (filter l) is replaced with a term
           (_f_1 l h_1) where _f_1 is a new fresh local.
           We cannot replace the second (filter l)
           with (_f_1 l h_1), since h_1 is not in the scope.
        */
        m_cache.clear();
        return t;
    }

    virtual expr visit_lambda(expr const & e) override {
        return visit_lambda_pi_let(true, e);
    }

    virtual expr visit_let(expr const & e) override {
        return visit_lambda_pi_let(true, e);
    }

    virtual expr visit_pi(expr const & e) override {
        return visit_lambda_pi_let(false, e);
    }

    expr default_visit_app(expr const & e, expr const & fn, buffer<expr> & args) {
        expr new_fn   = visit(fn);
        bool modified = !is_eqp(fn, new_fn);
        for (expr & arg : args) {
            expr new_arg = visit(arg);
            if (!is_eqp(new_arg, arg))
                modified = true;
            arg = new_arg;
        }
        if (!modified)
            return e;
        else
            return mk_app(new_fn, args);
    }

    void collect_locals_core(expr const & e, name_set & found, buffer<expr> & R) {
        for_each(e, [&](expr const & e, unsigned) {
                if (is_local(e) && !base_lctx().find_local_decl(e) && !found.contains(mlocal_name(e))) {
                    found.insert(mlocal_name(e));
                    R.push_back(e);
                }
                return true;
            });
    }

    /* Collect local propositions. This is needed when the nested recursive call will
       be defined by well-founded recursion, and we don't know whether local propositions
       are hints for helping the "decreasing tactic".
       In the future, we should add a mechanism that will only include these propositions
       if the recursive call will be defined using well founded recursion.
    */
    void collect_local_props(name_set & found, buffer<expr> & R) {
        type_context ctx = mk_type_context(lctx());
        lctx().for_each([&](local_decl const & d) {
                if (!base_lctx().find_local_decl(d.get_name()) &&
                    !found.contains(d.get_name()) &&
                    !d.get_info().is_rec() &&
                    ctx.is_prop(d.get_type())) {
                    found.insert(d.get_name());
                    R.push_back(d.mk_ref());
                }
            });
    }

    void collect_locals(expr const & e, buffer<expr> & R) {
        name_set found;
        /* Collect used local declarations. */
        collect_locals_core(e, found, R);
        /* Collect local propositions. */
        collect_local_props(found, R);
        for (unsigned i = 0; i < R.size(); i++) {
            expr const & x = R[i];
            collect_locals_core(lctx().get_local_decl(x).get_type(), found, R);
        }
        std::sort(R.begin(), R.end(), [&](expr const & x1, expr const & x2) {
                return lctx().get_local_decl(x1).get_idx() < lctx().get_local_decl(x2).get_idx();
            });
    }

    expr declare_new_local(name const & uid, name const & n, expr const & type) {
        lean_assert(m_lctx_stack.size() > 1);
        expr r;
        for (unsigned i = 0; i < m_lctx_stack.size(); i++) {
            local_context & lctx = m_lctx_stack[i];
            if (i == 0) {
                r = lctx.mk_local_decl(uid, n, type);
            } else {
                DEBUG_CODE(expr r2 =) lctx.mk_local_decl(uid, n, type);
                lean_assert(r == r2);
            }
        }
        return r;
    }

    virtual expr visit_app(expr const & e) override {
        buffer<expr> args;
        expr const & fn = get_app_args(e, args);
        if (is_local(fn) && local_info(fn).is_rec() && base_lctx().find_local_decl(fn)) {
            buffer<expr> local_deps;
            collect_locals(e, local_deps);
            type_context ctx = mk_type_context(lctx());
            expr val         = ctx.mk_lambda(local_deps, e);
            expr val_type    = ctx.infer(val);
            name fn_aux      = name("_f").append_after(m_new_locals.size() + 1);
            name uid         = mk_local_decl_name();
            expr g           = declare_new_local(uid, fn_aux, val_type);
            m_new_locals.push_back(g);
            m_new_values.push_back(val);
            expr r           = g;
            for (expr const & d : local_deps) {
                if (!lctx().get_local_decl(d).get_value())
                    r = mk_app(r, d);
            }
            return r;
        } else {
            return default_visit_app(e, fn, args);
        }
    }

    eqn_compiler_result operator()(expr const & e) {
        expr new_e             = visit(e);
        lean_assert(m_lctx_stack.size() == 1);
        local_context new_lctx = m_lctx_stack[0];
        auto r                 = compile_equations_core(m_env, m_opts, m_mctx, new_lctx, new_e);
        type_context ctx       = mk_type_context(new_lctx);
        r.m_fns = map(r.m_fns, [&] (expr const & fn) { return replace_locals(fn, m_new_locals, m_new_values); });
        m_mctx                 = ctx.mctx();
        return r;
    }
};

static expr remove_aux_main_name(expr const & e) {
    buffer<expr> args;
    expr fn = get_app_args(e, args);
    if (!is_constant(fn)) return e;
    name n = const_name(fn);
    if (n.is_string() && n.get_string() == std::string("_main")) {
        n = n.get_prefix();
        fn = mk_constant(n, const_levels(fn));
        return mk_app(fn, args);
    }
    return e;
}

expr compile_equations(environment & env, options const & opts, metavar_context & mctx, local_context const & lctx,
                       expr const & _eqns) {
    expr eqns = _eqns;
    equations_header const & header = get_equations_header(eqns);
    eqn_compiler_result r;
    if (!header.m_is_meta && has_nested_rec(eqns)) {
        r = pull_nested_rec_fn(env, opts, mctx, lctx)(eqns);
    } else {
        r = compile_equations_core(env, opts, mctx, lctx, eqns);
    }

    if (r.m_counter_examples) {
        auto pp = mk_pp_ctx(env, opts, mctx, lctx);
        auto fmt = format("non-exhaustive match, the following cases are missing:");
        for (auto & ce : r.m_counter_examples) {
            fmt += line() + pp(remove_aux_main_name(ce));
        }
        throw formatted_exception(_eqns, fmt);
    }

    buffer<expr> fns; to_buffer(r.m_fns, fns);
    return mk_equations_result(fns.size(), fns.data());
}

void initialize_compiler() {
}
void finalize_compiler() {
}
}
<commit_msg>chore(library/equations_compiler): style<commit_after>/*
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include <algorithm>
#include <string>
#include "kernel/find_fn.h"
#include "kernel/instantiate.h"
#include "library/trace.h"
#include "library/locals.h"
#include "library/replace_visitor.h"
#include "library/equations_compiler/compiler.h"
#include "library/equations_compiler/util.h"
#include "library/equations_compiler/structural_rec.h"
#include "library/equations_compiler/unbounded_rec.h"
#include "library/equations_compiler/wf_rec.h"
#include "library/equations_compiler/elim_match.h"

namespace lean {
#define trace_compiler(Code) lean_trace("eqn_compiler", scope_trace_env _scope1(ctx.env(), ctx); Code)

static bool has_nested_rec(expr const & eqns) {
    return static_cast<bool>(find(eqns, [&](expr const & e, unsigned) {
                return is_local(e) && local_info(e).is_rec();
            }));
}

static eqn_compiler_result compile_equations_core(environment & env, options const & opts,
                                   metavar_context & mctx, local_context const & lctx,
                                   expr const & eqns) {
    type_context ctx(env, opts, mctx, lctx, transparency_mode::Semireducible);
    trace_compiler(tout() << "compiling\n" << eqns << "\n";);
    trace_compiler(tout() << "recursive:          " << is_recursive_eqns(ctx, eqns) << "\n";);
    trace_compiler(tout() << "nested recursion:   " << has_nested_rec(eqns) << "\n";);
    trace_compiler(tout() << "using_well_founded: " << is_wf_equations(eqns) << "\n";);
    equations_header const & header = get_equations_header(eqns);
    lean_assert(header.m_is_meta || !has_nested_rec(eqns));

    if (header.m_is_meta) {
        if (is_wf_equations(eqns)) {
            throw exception("invalid use of 'using_well_founded', we do not need to use well founded recursion for meta definitions, since they can use unbounded recursion");
        }
        return unbounded_rec(env, opts, mctx, lctx, eqns);
    }

    if (is_wf_equations(eqns)) {
        return wf_rec(env, opts, mctx, lctx, eqns);
    }

    if (header.m_num_fns == 1) {
        if (!is_recursive_eqns(ctx, eqns)) {
            return mk_nonrec(env, opts, mctx, lctx, eqns);
        } else if (auto r = try_structural_rec(env, opts, mctx, lctx, eqns)) {
            return *r;
        }
    }

    return wf_rec(env, opts, mctx, lctx, eqns);
}

/** Auxiliary class for pulling nested recursive calls.
    Example: given

    definition f : nat → (nat × nat) → nat
    | 0      m := m.1
    | (n+1)  m :=
      match m with
      | (a, b) := f n (b, a + 1)
      end

    when we compile

      match m with
      | (a, b) := f n (b, a + 1)
      end

    we consinder (f n (b, a + 1)) to be a nested recursive call.
    Then, we transform the expression to

      (fun g,
       match m with
       | (a, b) := g a b
       end) (fun a b, f n (b, a + 1))

    Compile the match, and then beta-reduce.
*/
struct pull_nested_rec_fn : public replace_visitor {
    environment &         m_env;
    options               m_opts;
    metavar_context &     m_mctx;
    buffer<local_context> m_lctx_stack;
    buffer<expr>          m_new_locals;
    buffer<expr>          m_new_values;

    pull_nested_rec_fn(environment & env, options const & opts, metavar_context & mctx, local_context const & lctx):
        m_env(env), m_opts(opts), m_mctx(mctx) {
        m_lctx_stack.push_back(lctx);
    }

    local_context & base_lctx() { return m_lctx_stack[0]; }

    local_context & lctx() { return m_lctx_stack.back(); }

    type_context mk_type_context(local_context const & lctx) {
        return type_context(m_env, m_opts, m_mctx, lctx, transparency_mode::Semireducible);
    }

    expr visit_lambda_pi_let(bool is_lam, expr const & e) {
        buffer<expr> locals;
        m_lctx_stack.push_back(m_lctx_stack.back());
        expr t = e;
        while (true) {
            if ((is_lam && is_lambda(t)) || (!is_lam && is_pi(t))) {
                expr d = instantiate_rev(binding_domain(t), locals.size(), locals.data());
                d = visit(d);
                expr x = lctx().mk_local_decl(binding_name(t), d, binding_info(t));
                locals.push_back(x);
                t = binding_body(t);
            } else if (is_let(t)) {
                expr d = instantiate_rev(let_type(t), locals.size(), locals.data());
                expr v = instantiate_rev(let_value(t), locals.size(), locals.data());
                d = visit(d);
                v = visit(v);
                expr x = lctx().mk_local_decl(let_name(t), d, v);
                locals.push_back(x);
                t = let_body(t);
            } else {
                break;
            }
        }
        t = instantiate_rev(t, locals.size(), locals.data());
        t = visit(t);
        type_context ctx = mk_type_context(lctx());
        t = is_lam ? ctx.mk_lambda(locals, t) : ctx.mk_pi(locals, t);
        m_mctx = ctx.mctx();
        m_lctx_stack.pop_back();
        /* We clear the cache whenever we visit a binder because of
           collect_local_props.

           When pulling a recursive call (f t), the resulting term
           may contain local variables that do not occur in (f t).
           Thus, the cached value for (f t) may not be valid
           in other contexts.

           By clearing the cache we conservatively fix this issue.

           Here is an example:

           def filter : list A → list A
           | nil      := nil
           | (a :: l) :=
              match (H a) with
              | (is_true h_1) := a :: filter l
              | (is_false h_2) := filter l
              end

           The first (filter l) is replaced with a term
           (_f_1 l h_1) where _f_1 is a new fresh local.
           We cannot replace the second (filter l)
           with (_f_1 l h_1), since h_1 is not in the scope.
        */
        m_cache.clear();
        return t;
    }

    virtual expr visit_lambda(expr const & e) override {
        return visit_lambda_pi_let(true, e);
    }

    virtual expr visit_let(expr const & e) override {
        return visit_lambda_pi_let(true, e);
    }

    virtual expr visit_pi(expr const & e) override {
        return visit_lambda_pi_let(false, e);
    }

    expr default_visit_app(expr const & e, expr const & fn, buffer<expr> & args) {
        expr new_fn   = visit(fn);
        bool modified = !is_eqp(fn, new_fn);
        for (expr & arg : args) {
            expr new_arg = visit(arg);
            if (!is_eqp(new_arg, arg))
                modified = true;
            arg = new_arg;
        }
        if (!modified)
            return e;
        else
            return mk_app(new_fn, args);
    }

    void collect_locals_core(expr const & e, name_set & found, buffer<expr> & R) {
        for_each(e, [&](expr const & e, unsigned) {
                if (is_local(e) && !base_lctx().find_local_decl(e) && !found.contains(mlocal_name(e))) {
                    found.insert(mlocal_name(e));
                    R.push_back(e);
                }
                return true;
            });
    }

    /* Collect local propositions. This is needed when the nested recursive call will
       be defined by well-founded recursion, and we don't know whether local propositions
       are hints for helping the "decreasing tactic".
       In the future, we should add a mechanism that will only include these propositions
       if the recursive call will be defined using well founded recursion.
    */
    void collect_local_props(name_set & found, buffer<expr> & R) {
        type_context ctx = mk_type_context(lctx());
        lctx().for_each([&](local_decl const & d) {
                if (!base_lctx().find_local_decl(d.get_name()) &&
                    !found.contains(d.get_name()) &&
                    !d.get_info().is_rec() &&
                    ctx.is_prop(d.get_type())) {
                    found.insert(d.get_name());
                    R.push_back(d.mk_ref());
                }
            });
    }

    void collect_locals(expr const & e, buffer<expr> & R) {
        name_set found;
        /* Collect used local declarations. */
        collect_locals_core(e, found, R);
        /* Collect local propositions. */
        collect_local_props(found, R);
        for (unsigned i = 0; i < R.size(); i++) {
            expr const & x = R[i];
            collect_locals_core(lctx().get_local_decl(x).get_type(), found, R);
        }
        std::sort(R.begin(), R.end(), [&](expr const & x1, expr const & x2) {
                return lctx().get_local_decl(x1).get_idx() < lctx().get_local_decl(x2).get_idx();
            });
    }

    expr declare_new_local(name const & uid, name const & n, expr const & type) {
        lean_assert(m_lctx_stack.size() > 1);
        expr r;
        for (unsigned i = 0; i < m_lctx_stack.size(); i++) {
            local_context & lctx = m_lctx_stack[i];
            if (i == 0) {
                r = lctx.mk_local_decl(uid, n, type);
            } else {
                DEBUG_CODE(expr r2 =) lctx.mk_local_decl(uid, n, type);
                lean_assert(r == r2);
            }
        }
        return r;
    }

    virtual expr visit_app(expr const & e) override {
        buffer<expr> args;
        expr const & fn = get_app_args(e, args);
        if (is_local(fn) && local_info(fn).is_rec() && base_lctx().find_local_decl(fn)) {
            buffer<expr> local_deps;
            collect_locals(e, local_deps);
            type_context ctx = mk_type_context(lctx());
            expr val         = ctx.mk_lambda(local_deps, e);
            expr val_type    = ctx.infer(val);
            name fn_aux      = name("_f").append_after(m_new_locals.size() + 1);
            name uid         = mk_local_decl_name();
            expr g           = declare_new_local(uid, fn_aux, val_type);
            m_new_locals.push_back(g);
            m_new_values.push_back(val);
            expr r           = g;
            for (expr const & d : local_deps) {
                if (!lctx().get_local_decl(d).get_value())
                    r = mk_app(r, d);
            }
            return r;
        } else {
            return default_visit_app(e, fn, args);
        }
    }

    eqn_compiler_result operator()(expr const & e) {
        expr new_e             = visit(e);
        lean_assert(m_lctx_stack.size() == 1);
        local_context new_lctx = m_lctx_stack[0];
        auto r                 = compile_equations_core(m_env, m_opts, m_mctx, new_lctx, new_e);
        type_context ctx       = mk_type_context(new_lctx);
        r.m_fns = map(r.m_fns, [&] (expr const & fn) { return replace_locals(fn, m_new_locals, m_new_values); });
        m_mctx                 = ctx.mctx();
        return r;
    }
};

static expr remove_aux_main_name(expr const & e) {
    buffer<expr> args;
    expr fn = get_app_args(e, args);
    if (!is_constant(fn)) return e;
    name n = const_name(fn);
    if (n.is_string() && n.get_string() == std::string("_main")) {
        n = n.get_prefix();
        fn = mk_constant(n, const_levels(fn));
        return mk_app(fn, args);
    }
    return e;
}

expr compile_equations(environment & env, options const & opts, metavar_context & mctx, local_context const & lctx,
                       expr const & _eqns) {
    expr eqns = _eqns;
    equations_header const & header = get_equations_header(eqns);
    eqn_compiler_result r;
    if (!header.m_is_meta && has_nested_rec(eqns)) {
        r = pull_nested_rec_fn(env, opts, mctx, lctx)(eqns);
    } else {
        r = compile_equations_core(env, opts, mctx, lctx, eqns);
    }

    if (r.m_counter_examples) {
        auto pp = mk_pp_ctx(env, opts, mctx, lctx);
        auto fmt = format("non-exhaustive match, the following cases are missing:");
        for (auto & ce : r.m_counter_examples) {
            fmt += line() + pp(remove_aux_main_name(ce));
        }
        throw formatted_exception(_eqns, fmt);
    }

    buffer<expr> fns; to_buffer(r.m_fns, fns);
    return mk_equations_result(fns.size(), fns.data());
}

void initialize_compiler() {
}
void finalize_compiler() {
}
}
<|endoftext|>


<commit_before>#include <unistd.h>
#include <iostream>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XShm.h>

using namespace std;

struct rsquare {
	float x, y;
	float s;
};

#define SSIZE 5

int main(int, char**)
{
	Display *d = XOpenDisplay((char *) NULL);

	const struct rsquare positions[] = {
		{0.1, 0.1, SSIZE},
		{0.9, 0.1, SSIZE},
		{0.1, 0.9, SSIZE},
		{0.9, 0.9, SSIZE},

		{0.3, 0.3, SSIZE},
		{0.7, 0.3, SSIZE},
		{0.3, 0.7, SSIZE},
		{0.7, 0.7, SSIZE},

		{0.4, 0.4, SSIZE},
		{0.6, 0.4, SSIZE},
		{0.4, 0.6, SSIZE},
		{0.6, 0.6, SSIZE},

		{0.5, 0.5, SSIZE}
	};

	if (d == NULL) {
		return 1;
	}

	const int nPositions = sizeof(positions) / sizeof(struct rsquare);
	XImage *image;

	while (1) {
		int rSum = 0, gSum = 0, bSum = 0, nSamples = 0;
		int screen = DefaultScreen (d);
		int width = DisplayWidth(d, screen);
		int height = DisplayHeight(d, screen);

		int colormap = DefaultColormap(d, screen);
		int rootWindow = RootWindow (d, screen);

		for (int i=0; i < nPositions; i++) {
			int x = width * positions[i].x;
			int y = height * positions[i].y;
			int s = positions[i].s;
			int sx = (s+x >= width) ? (width-x) : s;
			int sy = (s+y >= height) ? (height-y) : s;

			XColor c;

			image = XGetImage (d, rootWindow, x, y, sx, sy, AllPlanes, XYPixmap);

			for (int xi=0; xi < sx; xi++) {
				for (int yi=0; yi < sy; yi++) {
					c.pixel = XGetPixel (image, xi, yi);
					//cout << c.red/256 << " " << c.green/256 << " " << c.blue/256 << "\n";

					rSum += ((c.pixel >> 16) & 0xff);
					gSum += ((c.pixel >> 8) & 0xff);
					bSum += ((c.pixel) & 0xff);
					nSamples++;
				}
			}

			XFree (image);
		}

		cout  << rSum / nSamples << " " << gSum / nSamples << " " << bSum / nSamples << endl;

		// 1/60 second
		usleep(16666);
	}

	return 0;
}
<commit_msg>Fix memory leak<commit_after>#include <unistd.h>
#include <iostream>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/extensions/XShm.h>

using namespace std;

struct rsquare {
	float x, y;
	float s;
};

#define SSIZE 5

int main(int, char**)
{
	Display *d = XOpenDisplay((char *) NULL);

	const struct rsquare positions[] = {
		{0.1, 0.1, SSIZE},
		{0.9, 0.1, SSIZE},
		{0.1, 0.9, SSIZE},
		{0.9, 0.9, SSIZE},

		{0.3, 0.3, SSIZE},
		{0.7, 0.3, SSIZE},
		{0.3, 0.7, SSIZE},
		{0.7, 0.7, SSIZE},

		{0.4, 0.4, SSIZE},
		{0.6, 0.4, SSIZE},
		{0.4, 0.6, SSIZE},
		{0.6, 0.6, SSIZE},

		{0.5, 0.5, SSIZE}
	};

	if (d == NULL) {
		return 1;
	}

	const int nPositions = sizeof(positions) / sizeof(struct rsquare);
	XImage *image;

	while (1) {
		int rSum = 0, gSum = 0, bSum = 0, nSamples = 0;
		int screen = DefaultScreen (d);
		int width = DisplayWidth(d, screen);
		int height = DisplayHeight(d, screen);

		int colormap = DefaultColormap(d, screen);
		int rootWindow = RootWindow (d, screen);

		for (int i=0; i < nPositions; i++) {
			int x = width * positions[i].x;
			int y = height * positions[i].y;
			int s = positions[i].s;
			int sx = (s+x >= width) ? (width-x) : s;
			int sy = (s+y >= height) ? (height-y) : s;

			XColor c;

			image = XGetImage (d, rootWindow, x, y, sx, sy, AllPlanes, XYPixmap);

			for (int xi=0; xi < sx; xi++) {
				for (int yi=0; yi < sy; yi++) {
					c.pixel = XGetPixel (image, xi, yi);
					//cout << c.red/256 << " " << c.green/256 << " " << c.blue/256 << "\n";

					rSum += ((c.pixel >> 16) & 0xff);
					gSum += ((c.pixel >> 8) & 0xff);
					bSum += ((c.pixel) & 0xff);
					nSamples++;
				}
			}

			XDestroyImage(image);
		}

		cout  << rSum / nSamples << " " << gSum / nSamples << " " << bSum / nSamples << endl;

		// 1/60 second
		usleep(16666);
	}

	return 0;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016-2018 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */
#include "de_web_plugin.h"
#include "de_web_plugin_private.h"

/*! Inits permit join manager.

    The manager will observe and ensure the global permit join state.
 */
void DeRestPluginPrivate::initPermitJoin()
{
    permitJoinFlag = false;
    permitJoinTimer = new QTimer(this);
    permitJoinTimer->setSingleShot(false);
    connect(permitJoinTimer, SIGNAL(timeout()),
            this, SLOT(permitJoinTimerFired()));
    permitJoinTimer->start(1000);
    permitJoinLastSendTime = QTime::currentTime();

    resendPermitJoinTimer = new QTimer(this);
    resendPermitJoinTimer->setSingleShot(true);
    connect(resendPermitJoinTimer, SIGNAL(timeout()),
            this, SLOT(resendPermitJoinTimerFired()));
}

/*! Sets the permit join interval

    \param duration specifies the interval in which joining is enabled
               - 0 disabled
               - 1..254 duration in seconds until joining will be disabled
               - 255 always permit
 * \return
 */
bool DeRestPluginPrivate::setPermitJoinDuration(uint8_t duration)
{
    if (gwPermitJoinDuration != duration)
    {
        gwPermitJoinDuration = duration;
    }

    // force resend
    permitJoinLastSendTime = QTime();
    return true;
}

/*! Send Commissioning Mode command to GP proxy device.
 */
bool DeRestPluginPrivate::sendGPProxyCommissioningMode()
{
    deCONZ::ApsDataRequest req;

    req.setDstAddressMode(deCONZ::ApsNwkAddress);
    req.dstAddress().setNwk(deCONZ::BroadcastRouters);
    req.setProfileId(GP_PROFILE_ID);
    req.setClusterId(GREEN_POWER_CLUSTER_ID);
    req.setDstEndpoint(GREEN_POWER_ENDPOINT);
    req.setSrcEndpoint(GREEN_POWER_ENDPOINT);
    req.setTxOptions(nullptr);
    req.setRadius(0);

    QDataStream stream(&req.asdu(), QIODevice::WriteOnly);
    stream.setByteOrder(QDataStream::LittleEndian);

    deCONZ::ZclFrame zclFrame;

    zclFrame.setSequenceNumber(zclSeq++);
    zclFrame.setCommandId(0x02); // commissioning mode
    zclFrame.setFrameControl(deCONZ::ZclFCClusterCommand |
                             deCONZ::ZclFCDirectionServerToClient |
                             deCONZ::ZclFCDisableDefaultResponse);

    { // payload
        QDataStream stream(&zclFrame.payload(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);

        quint8 options = 0x0b; // enter commissioning mode, exit on window expire
        quint16 window = 40;
        stream << options;
        stream << window;
    }

    { // ZCL frame

        QDataStream stream(&req.asdu(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);
        zclFrame.writeToStream(stream);
    }

    // broadcast
    if (apsCtrl->apsdeDataRequest(req) == deCONZ::Success)
    {
        DBG_Printf(DBG_INFO, "send GP proxy commissioning mode\n");
        return true;
    }

    DBG_Printf(DBG_INFO, "send GP proxy commissioning mode failed\n");
    return false;
}

/*! Send Pair command to GP proxy device.
 */
bool DeRestPluginPrivate::sendGPPairing(quint32 gpdSrcId, quint16 sinkGroupId, quint8 deviceId, quint32 frameCounter, const quint8 *key)
{
    deCONZ::ApsDataRequest req;

    req.setDstAddressMode(deCONZ::ApsNwkAddress);
    req.dstAddress().setNwk(deCONZ::BroadcastRouters);
    req.setProfileId(GP_PROFILE_ID);
    req.setClusterId(GREEN_POWER_CLUSTER_ID);
    req.setDstEndpoint(GREEN_POWER_ENDPOINT);
    req.setSrcEndpoint(GREEN_POWER_ENDPOINT);
    req.setTxOptions(nullptr);
    req.setRadius(0);

    QDataStream stream(&req.asdu(), QIODevice::WriteOnly);
    stream.setByteOrder(QDataStream::LittleEndian);

    deCONZ::ZclFrame zclFrame;

    zclFrame.setSequenceNumber(zclSeq++);
    zclFrame.setCommandId(0x01); // pairing
    zclFrame.setFrameControl(deCONZ::ZclFCClusterCommand |
                             deCONZ::ZclFCDirectionServerToClient |
                             deCONZ::ZclFCDisableDefaultResponse);

    { // payload
        QDataStream stream(&zclFrame.payload(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);

        frameCounter = 0;

        quint8 options0 = 0x48; // enter commissioning mode, exit on window expire
        //quint8 options1 = key ? 0xe5 : 0x65;
        quint8 options1 = 0x40;
        quint8 options2 = 0x00;
        stream << options0;
        stream << options1;
        stream << options2;
        stream << gpdSrcId;
        stream << sinkGroupId;
        stream << deviceId;
        stream << frameCounter;

        if (key)
        {
//          for (size_t  i = 0; i < 16; i++)
//          {
//              stream << (quint8)key[i];
//          }
        }
    }

    { // ZCL frame

        QDataStream stream(&req.asdu(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);
        zclFrame.writeToStream(stream);
    }

    // broadcast
    if (apsCtrl->apsdeDataRequest(req) == deCONZ::Success)
    {
        DBG_Printf(DBG_INFO, "send GP pairing\n");
        return true;
    }

    DBG_Printf(DBG_INFO, "send GP pairing\n");
    return false;
}

/*! Handle broadcasting of permit join interval.

    This is done every PERMIT_JOIN_SEND_INTERVAL to ensure
    any node in the network has the same settings.
 */
void DeRestPluginPrivate::permitJoinTimerFired()
{
    Q_Q(DeRestPlugin);
    if (!q->pluginActive() || !apsCtrl)
    {
        return;
    }

    if ((gwPermitJoinDuration > 0) && (gwPermitJoinDuration < 255))
    {
        permitJoinFlag = true;
        gwPermitJoinDuration--;

        if ((gwPermitJoinDuration % 10) == 0)
        {
            // try to add light nodes even if they existed in deCONZ bevor and therefore
            // no node added event will be triggert in this phase
            int i = 0;
            const deCONZ::Node *node = nullptr;
            while (apsCtrl->getNode(i, &node) == 0)
            {
                if (node && !node->isZombie() &&
                        !node->nodeDescriptor().isNull() && node->nodeDescriptor().receiverOnWhenIdle())
                {
                    addLightNode(node);
                }
                i++;
            }
        }
        else if ((gwPermitJoinDuration % 15) == 0)
        {
            for (LightNode &l : nodes)
            {
                if (l.isAvailable() && l.modelId().isEmpty())
                {
                    queuePollNode(&l);
                }
            }
        }

        updateEtag(gwConfigEtag); // update Etag so that webApp can count down permitJoin duration
    }

    if (gwPermitJoinDuration == 0 && permitJoinFlag)
    {
        permitJoinFlag = false;
    }

    if (!isInNetwork())
    {
        return;
    }

    if (gwPermitJoinDuration == 0 && otauLastBusyTimeDelta() < (60 * 5))
    {
        // don't pollute channel while OTA is running
        return;
    }

    QTime now = QTime::currentTime();
    int diff = permitJoinLastSendTime.msecsTo(now);

    if (!permitJoinLastSendTime.isValid() || (diff > PERMIT_JOIN_SEND_INTERVAL))
    {
        deCONZ::ApsDataRequest apsReq;
        quint8 tcSignificance = 0x01;

        apsReq.setDstAddressMode(deCONZ::ApsNwkAddress);
        apsReq.dstAddress().setNwk(deCONZ::BroadcastRouters);
        apsReq.setProfileId(ZDP_PROFILE_ID);
        apsReq.setClusterId(ZDP_MGMT_PERMIT_JOINING_REQ_CLID);
        apsReq.setDstEndpoint(ZDO_ENDPOINT);
        apsReq.setSrcEndpoint(ZDO_ENDPOINT);
        apsReq.setTxOptions(0);
        apsReq.setRadius(0);

        QDataStream stream(&apsReq.asdu(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);

        stream << (uint8_t)now.second(); // seqno
        stream << gwPermitJoinDuration;
        stream << tcSignificance;

        DBG_Assert(apsCtrl != 0);

        if (!apsCtrl)
        {
            return;
        }

        // set for own node
        apsCtrl->setPermitJoin(gwPermitJoinDuration);

        // broadcast
        if (apsCtrl->apsdeDataRequest(apsReq) == deCONZ::Success)
        {
            DBG_Printf(DBG_INFO, "send permit join, duration: %d\n", gwPermitJoinDuration);
            permitJoinLastSendTime = now;

            if (gwPermitJoinDuration > 0)
            {
                // sendGPProxyCommissioningMode(); TODO enable when GP security is implemented
            }
        }
        else
        {
            DBG_Printf(DBG_INFO, "send permit join failed\n");
        }
    }
}

/*! Check if permitJoin is > 60 seconds then resend permitjoin with 60 seconds
 */
void DeRestPluginPrivate::resendPermitJoinTimerFired()
{
    resendPermitJoinTimer->stop();
    if (gwPermitJoinDuration <= 1)
    {
        if (gwPermitJoinResend > 0)
        {
            if (gwPermitJoinResend >= 60)
            {
                setPermitJoinDuration(60);
            }
            else
            {
                setPermitJoinDuration(gwPermitJoinResend);
            }
            gwPermitJoinResend -= 60;
            updateEtag(gwConfigEtag);
            if (gwPermitJoinResend <= 0)
            {
                gwPermitJoinResend = 0;
                return;
            }

        }
        else if (gwPermitJoinResend == 0)
        {
            setPermitJoinDuration(0);
            return;
        }
    }
    else if (gwPermitJoinResend == 0)
    {
        setPermitJoinDuration(0);
        return;
    }
    resendPermitJoinTimer->start(1000);
}
<commit_msg>Don't skip periodically permit join during ota<commit_after>/*
 * Copyright (c) 2016-2018 dresden elektronik ingenieurtechnik gmbh.
 * All rights reserved.
 *
 * The software in this package is published under the terms of the BSD
 * style license a copy of which has been included with this distribution in
 * the LICENSE.txt file.
 *
 */
#include "de_web_plugin.h"
#include "de_web_plugin_private.h"

/*! Inits permit join manager.

    The manager will observe and ensure the global permit join state.
 */
void DeRestPluginPrivate::initPermitJoin()
{
    permitJoinFlag = false;
    permitJoinTimer = new QTimer(this);
    permitJoinTimer->setSingleShot(false);
    connect(permitJoinTimer, SIGNAL(timeout()),
            this, SLOT(permitJoinTimerFired()));
    permitJoinTimer->start(1000);
    permitJoinLastSendTime = QTime::currentTime();

    resendPermitJoinTimer = new QTimer(this);
    resendPermitJoinTimer->setSingleShot(true);
    connect(resendPermitJoinTimer, SIGNAL(timeout()),
            this, SLOT(resendPermitJoinTimerFired()));
}

/*! Sets the permit join interval

    \param duration specifies the interval in which joining is enabled
               - 0 disabled
               - 1..254 duration in seconds until joining will be disabled
               - 255 always permit
 * \return
 */
bool DeRestPluginPrivate::setPermitJoinDuration(uint8_t duration)
{
    if (gwPermitJoinDuration != duration)
    {
        gwPermitJoinDuration = duration;
    }

    // force resend
    permitJoinLastSendTime = QTime();
    return true;
}

/*! Send Commissioning Mode command to GP proxy device.
 */
bool DeRestPluginPrivate::sendGPProxyCommissioningMode()
{
    deCONZ::ApsDataRequest req;

    req.setDstAddressMode(deCONZ::ApsNwkAddress);
    req.dstAddress().setNwk(deCONZ::BroadcastRouters);
    req.setProfileId(GP_PROFILE_ID);
    req.setClusterId(GREEN_POWER_CLUSTER_ID);
    req.setDstEndpoint(GREEN_POWER_ENDPOINT);
    req.setSrcEndpoint(GREEN_POWER_ENDPOINT);
    req.setTxOptions(nullptr);
    req.setRadius(0);

    QDataStream stream(&req.asdu(), QIODevice::WriteOnly);
    stream.setByteOrder(QDataStream::LittleEndian);

    deCONZ::ZclFrame zclFrame;

    zclFrame.setSequenceNumber(zclSeq++);
    zclFrame.setCommandId(0x02); // commissioning mode
    zclFrame.setFrameControl(deCONZ::ZclFCClusterCommand |
                             deCONZ::ZclFCDirectionServerToClient |
                             deCONZ::ZclFCDisableDefaultResponse);

    { // payload
        QDataStream stream(&zclFrame.payload(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);

        quint8 options = 0x0b; // enter commissioning mode, exit on window expire
        quint16 window = 40;
        stream << options;
        stream << window;
    }

    { // ZCL frame

        QDataStream stream(&req.asdu(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);
        zclFrame.writeToStream(stream);
    }

    // broadcast
    if (apsCtrl->apsdeDataRequest(req) == deCONZ::Success)
    {
        DBG_Printf(DBG_INFO, "send GP proxy commissioning mode\n");
        return true;
    }

    DBG_Printf(DBG_INFO, "send GP proxy commissioning mode failed\n");
    return false;
}

/*! Send Pair command to GP proxy device.
 */
bool DeRestPluginPrivate::sendGPPairing(quint32 gpdSrcId, quint16 sinkGroupId, quint8 deviceId, quint32 frameCounter, const quint8 *key)
{
    deCONZ::ApsDataRequest req;

    req.setDstAddressMode(deCONZ::ApsNwkAddress);
    req.dstAddress().setNwk(deCONZ::BroadcastRouters);
    req.setProfileId(GP_PROFILE_ID);
    req.setClusterId(GREEN_POWER_CLUSTER_ID);
    req.setDstEndpoint(GREEN_POWER_ENDPOINT);
    req.setSrcEndpoint(GREEN_POWER_ENDPOINT);
    req.setTxOptions(nullptr);
    req.setRadius(0);

    QDataStream stream(&req.asdu(), QIODevice::WriteOnly);
    stream.setByteOrder(QDataStream::LittleEndian);

    deCONZ::ZclFrame zclFrame;

    zclFrame.setSequenceNumber(zclSeq++);
    zclFrame.setCommandId(0x01); // pairing
    zclFrame.setFrameControl(deCONZ::ZclFCClusterCommand |
                             deCONZ::ZclFCDirectionServerToClient |
                             deCONZ::ZclFCDisableDefaultResponse);

    { // payload
        QDataStream stream(&zclFrame.payload(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);

        frameCounter = 0;

        quint8 options0 = 0x48; // enter commissioning mode, exit on window expire
        //quint8 options1 = key ? 0xe5 : 0x65;
        quint8 options1 = 0x40;
        quint8 options2 = 0x00;
        stream << options0;
        stream << options1;
        stream << options2;
        stream << gpdSrcId;
        stream << sinkGroupId;
        stream << deviceId;
        stream << frameCounter;

        if (key)
        {
//          for (size_t  i = 0; i < 16; i++)
//          {
//              stream << (quint8)key[i];
//          }
        }
    }

    { // ZCL frame

        QDataStream stream(&req.asdu(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);
        zclFrame.writeToStream(stream);
    }

    // broadcast
    if (apsCtrl->apsdeDataRequest(req) == deCONZ::Success)
    {
        DBG_Printf(DBG_INFO, "send GP pairing\n");
        return true;
    }

    DBG_Printf(DBG_INFO, "send GP pairing\n");
    return false;
}

/*! Handle broadcasting of permit join interval.

    This is done every PERMIT_JOIN_SEND_INTERVAL to ensure
    any node in the network has the same settings.
 */
void DeRestPluginPrivate::permitJoinTimerFired()
{
    Q_Q(DeRestPlugin);
    if (!q->pluginActive() || !apsCtrl)
    {
        return;
    }

    if ((gwPermitJoinDuration > 0) && (gwPermitJoinDuration < 255))
    {
        permitJoinFlag = true;
        gwPermitJoinDuration--;

        if ((gwPermitJoinDuration % 10) == 0)
        {
            // try to add light nodes even if they existed in deCONZ bevor and therefore
            // no node added event will be triggert in this phase
            int i = 0;
            const deCONZ::Node *node = nullptr;
            while (apsCtrl->getNode(i, &node) == 0)
            {
                if (node && !node->isZombie() &&
                        !node->nodeDescriptor().isNull() && node->nodeDescriptor().receiverOnWhenIdle())
                {
                    addLightNode(node);
                }
                i++;
            }
        }
        else if ((gwPermitJoinDuration % 15) == 0)
        {
            for (LightNode &l : nodes)
            {
                if (l.isAvailable() && l.modelId().isEmpty())
                {
                    queuePollNode(&l);
                }
            }
        }

        updateEtag(gwConfigEtag); // update Etag so that webApp can count down permitJoin duration
    }

    if (gwPermitJoinDuration == 0 && permitJoinFlag)
    {
        permitJoinFlag = false;
    }

    if (!isInNetwork())
    {
        return;
    }

//    if (gwPermitJoinDuration == 0 && otauLastBusyTimeDelta() < (60 * 5))
//    {
//        // don't pollute channel while OTA is running
//        return;
//    }

    QTime now = QTime::currentTime();
    int diff = permitJoinLastSendTime.msecsTo(now);

    if (!permitJoinLastSendTime.isValid() || (diff > PERMIT_JOIN_SEND_INTERVAL))
    {
        deCONZ::ApsDataRequest apsReq;
        quint8 tcSignificance = 0x01;

        apsReq.setDstAddressMode(deCONZ::ApsNwkAddress);
        apsReq.dstAddress().setNwk(deCONZ::BroadcastRouters);
        apsReq.setProfileId(ZDP_PROFILE_ID);
        apsReq.setClusterId(ZDP_MGMT_PERMIT_JOINING_REQ_CLID);
        apsReq.setDstEndpoint(ZDO_ENDPOINT);
        apsReq.setSrcEndpoint(ZDO_ENDPOINT);
        apsReq.setTxOptions(0);
        apsReq.setRadius(0);

        QDataStream stream(&apsReq.asdu(), QIODevice::WriteOnly);
        stream.setByteOrder(QDataStream::LittleEndian);

        stream << (uint8_t)now.second(); // seqno
        stream << gwPermitJoinDuration;
        stream << tcSignificance;

        DBG_Assert(apsCtrl != 0);

        if (!apsCtrl)
        {
            return;
        }

        // set for own node
        apsCtrl->setPermitJoin(gwPermitJoinDuration);

        // broadcast
        if (apsCtrl->apsdeDataRequest(apsReq) == deCONZ::Success)
        {
            DBG_Printf(DBG_INFO, "send permit join, duration: %d\n", gwPermitJoinDuration);
            permitJoinLastSendTime = now;

            if (gwPermitJoinDuration > 0)
            {
                // sendGPProxyCommissioningMode(); TODO enable when GP security is implemented
            }
        }
        else
        {
            DBG_Printf(DBG_INFO, "send permit join failed\n");
        }
    }
}

/*! Check if permitJoin is > 60 seconds then resend permitjoin with 60 seconds
 */
void DeRestPluginPrivate::resendPermitJoinTimerFired()
{
    resendPermitJoinTimer->stop();
    if (gwPermitJoinDuration <= 1)
    {
        if (gwPermitJoinResend > 0)
        {
            if (gwPermitJoinResend >= 60)
            {
                setPermitJoinDuration(60);
            }
            else
            {
                setPermitJoinDuration(gwPermitJoinResend);
            }
            gwPermitJoinResend -= 60;
            updateEtag(gwConfigEtag);
            if (gwPermitJoinResend <= 0)
            {
                gwPermitJoinResend = 0;
                return;
            }

        }
        else if (gwPermitJoinResend == 0)
        {
            setPermitJoinDuration(0);
            return;
        }
    }
    else if (gwPermitJoinResend == 0)
    {
        setPermitJoinDuration(0);
        return;
    }
    resendPermitJoinTimer->start(1000);
}
<|endoftext|>


<commit_before>/// \file PasskeyEntry.cpp
//-----------------------------------------------------------------------------

/*
  Passkey?  That's Russian for 'pass'.  You know, passkey
  down the streetsky.  [Groucho Marx]
*/

#include "PasswordSafe.h"
#include "corelib/PwsPlatform.h"
#include "ThisMfcApp.h"

#if defined(POCKET_PC)
  #include "pocketpc/resource.h"
  #include "pocketpc/PocketPC.h"
#else
  #include "resource.h"
#endif

#include "corelib/MyString.h"

#include "SysColStatic.h"

#include "PasskeyEntry.h"
#include "PwFont.h"
#include "TryAgainDlg.h"
#include "DboxMain.h" // for CheckPassword()

#include "corelib/Util.h"

int CPasskeyEntry::dialog_lookup[4] = {IDD_PASSKEYENTRY_FIRST,
										IDD_PASSKEYENTRY,
										IDD_PASSKEYENTRY,
										IDD_PASSKEYENTRY_WITHEXIT};

//-----------------------------------------------------------------------------
CPasskeyEntry::CPasskeyEntry(CWnd* pParent,
                             const CString& a_filespec, int index,
			                 bool bReadOnly, bool bForceReadOnly)
   : super(dialog_lookup[index],
             pParent),
     m_index(index),
     m_filespec(a_filespec),
     m_tries(0),
     m_status(TAR_INVALID),
     m_ReadOnly(bReadOnly ? TRUE : FALSE),
     m_bForceReadOnly(bForceReadOnly)
{
  const int FILE_DISP_LEN = 45;

  //{{AFX_DATA_INIT(CPasskeyEntry)
  //}}AFX_DATA_INIT

  DBGMSG("CPasskeyEntry()\n");
  if (m_index == GCP_FIRST) {
    DBGMSG("** FIRST **\n");
  }

  m_passkey = _T("");

  m_hIcon = app.LoadIcon(IDI_CORNERICON);

  if (a_filespec.GetLength() > FILE_DISP_LEN) {
    // m_message = a_filespec.Right(FILE_DISP_LEN - 3); // truncate for display
    // m_message.Insert(0, _T("..."));
    // changed by karel@VanderGucht.de to see beginning + ending of 'a_filespec'
    m_message =  a_filespec.Left(FILE_DISP_LEN/2-5) +
      _T(" ... ") + a_filespec.Right(FILE_DISP_LEN/2);
  } else {
    m_message = a_filespec;
  }
}

void CPasskeyEntry::DoDataExchange(CDataExchange* pDX)
{
   super::DoDataExchange(pDX);
   DDX_Text(pDX, IDC_PASSKEY, (CString &)m_passkey);

#if !defined(POCKET_PC)
   if (m_index == GCP_FIRST)
	DDX_Control(pDX, IDC_STATIC_LOGOTEXT, m_ctlLogoText);
#endif

   //{{AFX_DATA_MAP(CPasskeyEntry)
#if !defined(POCKET_PC)
	DDX_Control(pDX, IDC_STATIC_LOGO, m_ctlLogo);
	DDX_Control(pDX, IDOK, m_ctlOK);
#endif
	DDX_Control(pDX, IDC_PASSKEY, m_ctlPasskey);
	DDX_Text(pDX, IDC_MESSAGE, m_message);
	DDX_Check(pDX, IDC_READONLY, m_ReadOnly);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CPasskeyEntry, super)
	//{{AFX_MSG_MAP(CPasskeyEntry)
   ON_BN_CLICKED(ID_HELP, OnHelp)
   ON_BN_CLICKED(ID_BROWSE, OnBrowse)
   ON_BN_CLICKED(ID_CREATE_DB, OnCreateDb)
   ON_BN_CLICKED(ID_EXIT, OnExit)
   ON_BN_CLICKED(IDC_READONLY, OnReadOnly)
#if defined(POCKET_PC)
   ON_EN_SETFOCUS(IDC_PASSKEY, OnPasskeySetfocus)
   ON_EN_KILLFOCUS(IDC_PASSKEY, OnPasskeyKillfocus)
#endif
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL
CPasskeyEntry::OnInitDialog(void)
{
  SetPasswordFont(GetDlgItem(IDC_PASSKEY));

  switch(m_index) {
  	case GCP_FIRST:
  		// At start up - give the user the option unless file is R/O
  		if (m_bForceReadOnly)
  			GetDlgItem(IDC_READONLY)->EnableWindow(FALSE);
  		else
  			GetDlgItem(IDC_READONLY)->EnableWindow(TRUE);

  		GetDlgItem(IDC_READONLY)->ShowWindow(SW_SHOW);
  		break;
  	case GCP_NORMAL:
		// otherwise during open - user can - again unless file is R/O
  		if (m_bForceReadOnly)
  			GetDlgItem(IDC_READONLY)->EnableWindow(FALSE);
  		else
  			GetDlgItem(IDC_READONLY)->EnableWindow(TRUE);

  		GetDlgItem(IDC_READONLY)->ShowWindow(SW_SHOW);
  		break;
  	case GCP_UNMINIMIZE:
  	case GCP_WITHEXIT:
  		// on UnMinimize - user can't change status
  		GetDlgItem(IDC_READONLY)->EnableWindow(FALSE);
  		GetDlgItem(IDC_READONLY)->ShowWindow(SW_HIDE);
  		break;
  	default:
  		ASSERT(FALSE);
  }

#if defined(POCKET_PC)
  // If displaying IDD_PASSKEYENTRY_FIRST then bypass superclass and go
  // directly to CDialog::OnInitDialog() and display the dialog fullscreen
  // otherwise display as a centred dialogue.
  if ( m_nIDHelp == IDD )
    {
      super::super::OnInitDialog();
    }
  else
    {
#endif
      super::OnInitDialog();
#if defined(POCKET_PC)
    }
#endif

  if (m_message.IsEmpty() && m_index == GCP_FIRST)
    {
      m_ctlPasskey.EnableWindow(FALSE);
#if !defined(POCKET_PC)
      m_ctlOK.EnableWindow(FALSE);
#endif
      m_message = _T("[No current database]");
    }
  /*
   * this bit makes the background come out right on
   * the bitmaps
   */

#if !defined(POCKET_PC)
  if (m_index == GCP_FIRST) {
    m_ctlLogoText.ReloadBitmap(IDB_PSLOGO);
    m_ctlLogo.ReloadBitmap(IDB_CLOGO);
  } else {
    m_ctlLogo.ReloadBitmap(IDB_CLOGO_SMALL);
  }
#endif

  // Set the icon for this dialog.  The framework does this automatically
  //  when the application's main window is not a dialog

  SetIcon(m_hIcon, TRUE);  // Set big icon
  SetIcon(m_hIcon, FALSE); // Set small icon

  return TRUE;
}

#if defined(POCKET_PC)
/************************************************************************/
/* Restore the state of word completion when the password field loses   *//* focus.                                                               */
/************************************************************************/
void CPasskeyEntry::OnPasskeyKillfocus()
{
  EnableWordCompletion( m_hWnd );
}

/************************************************************************/
/* When the password field is activated, pull up the SIP and disable    */
/* word completion.                                                     */
/************************************************************************/
void CPasskeyEntry::OnPasskeySetfocus()
{
  DisableWordCompletion( m_hWnd );
}
#endif

void
CPasskeyEntry::OnReadOnly()
{
   m_ReadOnly = ((CButton*)GetDlgItem(IDC_READONLY))->GetCheck();
}

void
CPasskeyEntry::OnBrowse()
{
  m_status = TAR_OPEN;
  super::OnCancel();
}

void
CPasskeyEntry::OnCreateDb()
{
  m_status = TAR_NEW;
  super::OnCancel();
}

void
CPasskeyEntry::OnCancel()
{
  m_status = TAR_CANCEL;
  super::OnCancel();
}

void
CPasskeyEntry::OnExit()
{
  m_status = TAR_EXIT;
  super::OnCancel();
}

void
CPasskeyEntry::OnOK()
{
  UpdateData(TRUE);

  if (m_passkey.IsEmpty()) {
    AfxMessageBox(_T("The combination cannot be blank."));
    m_ctlPasskey.SetFocus();
    return;
  }

  DboxMain* pParent = (DboxMain*) GetParent();
  ASSERT(pParent != NULL);
  if (pParent->CheckPassword(m_filespec, m_passkey) != PWScore::SUCCESS) {
    if (m_tries >= 2) {
	  CTryAgainDlg errorDlg(this);

      int nResponse = errorDlg.DoModal();
      if (nResponse == IDOK) {
      } else if (nResponse == IDCANCEL) {
        m_status = errorDlg.GetCancelReturnValue();
        super::OnCancel();
      }
    } else {
      m_tries++;
      AfxMessageBox(_T("Incorrect passkey, not a PasswordSafe database, or a corrupt database. (backup database has same name as original, ending with '~')"));
      m_ctlPasskey.SetSel(MAKEWORD(-1, 0));
      m_ctlPasskey.SetFocus();
    }
  } else {
    super::OnOK();
  }
}

void
CPasskeyEntry::OnHelp()
{
#if defined(POCKET_PC)
  CreateProcess( _T("PegHelp.exe"), _T("pws_ce_help.html#comboentry"), NULL, NULL, FALSE, 0, NULL, NULL, NULL, NULL );
#else
  //WinHelp(0x200B9, HELP_CONTEXT);
  ::HtmlHelp(NULL,
             "pwsafe.chm::/html/create_new_db.html",
             HH_DISPLAY_TOPIC, 0);
#endif
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
<commit_msg>Missed a file from last update<commit_after>/// \file PasskeyEntry.cpp
//-----------------------------------------------------------------------------

/*
  Passkey?  That's Russian for 'pass'.  You know, passkey
  down the streetsky.  [Groucho Marx]
*/

#include "PasswordSafe.h"
#include "corelib/PwsPlatform.h"
#include "ThisMfcApp.h"

#if defined(POCKET_PC)
  #include "pocketpc/resource.h"
  #include "pocketpc/PocketPC.h"
#else
  #include "resource.h"
#endif

#include "corelib/MyString.h"

#include "SysColStatic.h"

#include "PasskeyEntry.h"
#include "PwFont.h"
#include "TryAgainDlg.h"
#include "DboxMain.h" // for CheckPassword()

#include "corelib/Util.h"

int CPasskeyEntry::dialog_lookup[4] = {IDD_PASSKEYENTRY_FIRST,
										IDD_PASSKEYENTRY,
										IDD_PASSKEYENTRY,
										IDD_PASSKEYENTRY_WITHEXIT};

//-----------------------------------------------------------------------------
CPasskeyEntry::CPasskeyEntry(CWnd* pParent,
                             const CString& a_filespec, int index,
			                 bool bReadOnly, bool bForceReadOnly)
   : super(dialog_lookup[index],
             pParent),
     m_index(index),
     m_filespec(a_filespec),
     m_tries(0),
     m_status(TAR_INVALID),
     m_ReadOnly(bReadOnly ? TRUE : FALSE),
     m_bForceReadOnly(bForceReadOnly)
{
  const int FILE_DISP_LEN = 45;

  //{{AFX_DATA_INIT(CPasskeyEntry)
  //}}AFX_DATA_INIT

  DBGMSG("CPasskeyEntry()\n");
  if (m_index == GCP_FIRST) {
    DBGMSG("** FIRST **\n");
  }

  m_passkey = _T("");

  m_hIcon = app.LoadIcon(IDI_CORNERICON);

  if (a_filespec.GetLength() > FILE_DISP_LEN) {
    // m_message = a_filespec.Right(FILE_DISP_LEN - 3); // truncate for display
    // m_message.Insert(0, _T("..."));
    // changed by karel@VanderGucht.de to see beginning + ending of 'a_filespec'
    m_message =  a_filespec.Left(FILE_DISP_LEN/2-5) +
      _T(" ... ") + a_filespec.Right(FILE_DISP_LEN/2);
  } else {
    m_message = a_filespec;
  }
}

void CPasskeyEntry::DoDataExchange(CDataExchange* pDX)
{
   super::DoDataExchange(pDX);
   DDX_Text(pDX, IDC_PASSKEY, (CString &)m_passkey);

#if !defined(POCKET_PC)
   if (m_index == GCP_FIRST)
	DDX_Control(pDX, IDC_STATIC_LOGOTEXT, m_ctlLogoText);
#endif

   //{{AFX_DATA_MAP(CPasskeyEntry)
#if !defined(POCKET_PC)
	DDX_Control(pDX, IDC_STATIC_LOGO, m_ctlLogo);
	DDX_Control(pDX, IDOK, m_ctlOK);
#endif
	DDX_Control(pDX, IDC_PASSKEY, m_ctlPasskey);
	DDX_Text(pDX, IDC_MESSAGE, m_message);
	DDX_Check(pDX, IDC_READONLY, m_ReadOnly);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CPasskeyEntry, super)
	//{{AFX_MSG_MAP(CPasskeyEntry)
   ON_BN_CLICKED(ID_HELP, OnHelp)
   ON_BN_CLICKED(ID_BROWSE, OnBrowse)
   ON_BN_CLICKED(ID_CREATE_DB, OnCreateDb)
   ON_BN_CLICKED(ID_EXIT, OnExit)
   ON_BN_CLICKED(IDC_READONLY, OnReadOnly)
#if defined(POCKET_PC)
   ON_EN_SETFOCUS(IDC_PASSKEY, OnPasskeySetfocus)
   ON_EN_KILLFOCUS(IDC_PASSKEY, OnPasskeyKillfocus)
#endif
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

BOOL
CPasskeyEntry::OnInitDialog(void)
{
  SetPasswordFont(GetDlgItem(IDC_PASSKEY));

  switch(m_index) {
  	case GCP_FIRST:
  		// At start up - give the user the option unless file is R/O
  		if (m_bForceReadOnly)
  			GetDlgItem(IDC_READONLY)->EnableWindow(FALSE);
  		else
  			GetDlgItem(IDC_READONLY)->EnableWindow(TRUE);

  		GetDlgItem(IDC_READONLY)->ShowWindow(SW_SHOW);
  		break;
  	case GCP_NORMAL:
		// otherwise during open - user can - again unless file is R/O
  		if (m_bForceReadOnly)
  			GetDlgItem(IDC_READONLY)->EnableWindow(FALSE);
  		else
  			GetDlgItem(IDC_READONLY)->EnableWindow(TRUE);

  		GetDlgItem(IDC_READONLY)->ShowWindow(SW_SHOW);
  		break;
  	case GCP_UNMINIMIZE:
  	case GCP_WITHEXIT:
  		// on UnMinimize - user can't change status
  		GetDlgItem(IDC_READONLY)->EnableWindow(FALSE);
  		GetDlgItem(IDC_READONLY)->ShowWindow(SW_HIDE);
  		break;
  	default:
  		ASSERT(FALSE);
  }

#if defined(POCKET_PC)
  // If displaying IDD_PASSKEYENTRY_FIRST then bypass superclass and go
  // directly to CDialog::OnInitDialog() and display the dialog fullscreen
  // otherwise display as a centred dialogue.
  if ( m_nIDHelp == IDD ) {
      super::super::OnInitDialog();
  } else {
      super::OnInitDialog();
  }
#else
  super::OnInitDialog();
#endif

  if (m_message.IsEmpty() && m_index == GCP_FIRST) {
      m_ctlPasskey.EnableWindow(FALSE);
#if !defined(POCKET_PC)
      m_ctlOK.EnableWindow(FALSE);
#endif
      m_message = _T("[No current database]");
  }
  /*
   * this bit makes the background come out right on
   * the bitmaps
   */

#if !defined(POCKET_PC)
  if (m_index == GCP_FIRST) {
    m_ctlLogoText.ReloadBitmap(IDB_PSLOGO);
    m_ctlLogo.ReloadBitmap(IDB_CLOGO);
  } else {
    m_ctlLogo.ReloadBitmap(IDB_CLOGO_SMALL);
  }
#endif

  // Set the icon for this dialog.  The framework does this automatically
  //  when the application's main window is not a dialog

  SetIcon(m_hIcon, TRUE);  // Set big icon
  SetIcon(m_hIcon, FALSE); // Set small icon

  if (app.WasHotKeyPressed()) {
	  // Need to get it to the top as a result of a hotkey.
	  // This is "stronger" than BringWindowToTop().
	  SetWindowPos(&CWnd::wndTopMost, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
	  // Reset it
	  app.SetHotKeyPressed(false);
  }

  if (m_ctlPasskey.IsWindowEnabled() == TRUE) {
    m_ctlPasskey.SetFocus();
    return FALSE;
  } else
    return TRUE;
}

#if defined(POCKET_PC)
/************************************************************************/
/* Restore the state of word completion when the password field loses   *//* focus.                                                               */
/************************************************************************/
void CPasskeyEntry::OnPasskeyKillfocus()
{
  EnableWordCompletion( m_hWnd );
}

/************************************************************************/
/* When the password field is activated, pull up the SIP and disable    */
/* word completion.                                                     */
/************************************************************************/
void CPasskeyEntry::OnPasskeySetfocus()
{
  DisableWordCompletion( m_hWnd );
}
#endif

void
CPasskeyEntry::OnReadOnly()
{
   m_ReadOnly = ((CButton*)GetDlgItem(IDC_READONLY))->GetCheck();
}

void
CPasskeyEntry::OnBrowse()
{
  m_status = TAR_OPEN;
  super::OnCancel();
}

void
CPasskeyEntry::OnCreateDb()
{
  m_status = TAR_NEW;
  super::OnCancel();
}

void
CPasskeyEntry::OnCancel()
{
  m_status = TAR_CANCEL;
  super::OnCancel();
}

void
CPasskeyEntry::OnExit()
{
  m_status = TAR_EXIT;
  super::OnCancel();
}

void
CPasskeyEntry::OnOK()
{
  UpdateData(TRUE);

  if (m_passkey.IsEmpty()) {
    AfxMessageBox(_T("The combination cannot be blank."));
    m_ctlPasskey.SetFocus();
    return;
  }

  DboxMain* pParent = (DboxMain*) GetParent();
  ASSERT(pParent != NULL);
  if (pParent->CheckPassword(m_filespec, m_passkey) != PWScore::SUCCESS) {
    if (m_tries >= 2) {
	  CTryAgainDlg errorDlg(this);

      int nResponse = errorDlg.DoModal();
      if (nResponse == IDOK) {
      } else if (nResponse == IDCANCEL) {
        m_status = errorDlg.GetCancelReturnValue();
        super::OnCancel();
      }
    } else {
      m_tries++;
      AfxMessageBox(_T("Incorrect passkey, not a PasswordSafe database, or a corrupt database. (backup database has same name as original, ending with '~')"));
      m_ctlPasskey.SetSel(MAKEWORD(-1, 0));
      m_ctlPasskey.SetFocus();
    }
  } else {
    super::OnOK();
  }
}

void
CPasskeyEntry::OnHelp()
{
#if defined(POCKET_PC)
  CreateProcess( _T("PegHelp.exe"), _T("pws_ce_help.html#comboentry"), NULL, NULL, FALSE, 0, NULL, NULL, NULL, NULL );
#else
  //WinHelp(0x200B9, HELP_CONTEXT);
  ::HtmlHelp(NULL,
             "pwsafe.chm::/html/create_new_db.html",
             HH_DISPLAY_TOPIC, 0);
#endif
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
<|endoftext|>


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

#include "base/memory/scoped_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_serializable_tree.h"
#include "ui/accessibility/ax_tree.h"
#include "ui/accessibility/ax_tree_serializer.h"

namespace ui {

TEST(AXTreeTest, SerializeSimpleAXTree) {
  AXNodeData root;
  root.id = 1;
  root.role = AX_ROLE_ROOT_WEB_AREA;
  root.state = (1 << AX_STATE_FOCUSABLE) | (1 << AX_STATE_FOCUSED);
  root.location = gfx::Rect(0, 0, 800, 600);
  root.child_ids.push_back(2);
  root.child_ids.push_back(3);

  AXNodeData button;
  button.id = 2;
  button.role = AX_ROLE_BUTTON;
  button.state = 0;
  button.location = gfx::Rect(20, 20, 200, 30);

  AXNodeData checkbox;
  checkbox.id = 3;
  checkbox.role = AX_ROLE_CHECK_BOX;
  checkbox.state = 0;
  checkbox.location = gfx::Rect(20, 50, 200, 30);

  AXTreeUpdate initial_state;
  initial_state.nodes.push_back(root);
  initial_state.nodes.push_back(button);
  initial_state.nodes.push_back(checkbox);
  AXSerializableTree src_tree(initial_state);

  scoped_ptr<AXTreeSource<AXNode> > tree_source(
      src_tree.CreateTreeSource());
  AXTreeSerializer<AXNode> serializer(tree_source.get());
  AXTreeUpdate update;
  serializer.SerializeChanges(src_tree.GetRoot(), &update);

  AXTree dst_tree;
  ASSERT_TRUE(dst_tree.Unserialize(update));

  AXNode* root_node = dst_tree.GetRoot();
  ASSERT_TRUE(root_node != NULL);
  EXPECT_EQ(root.id, root_node->id());
  EXPECT_EQ(root.role, root_node->data().role);

  ASSERT_EQ(2, root_node->child_count());

  AXNode* button_node = root_node->ChildAtIndex(0);
  EXPECT_EQ(button.id, button_node->id());
  EXPECT_EQ(button.role, button_node->data().role);

  AXNode* checkbox_node = root_node->ChildAtIndex(1);
  EXPECT_EQ(checkbox.id, checkbox_node->id());
  EXPECT_EQ(checkbox.role, checkbox_node->data().role);

  EXPECT_EQ(
      "id=1 ROOT_WEB_AREA FOCUSABLE FOCUSED (0, 0)-(800, 600) child_ids=2,3\n"
      "  id=2 BUTTON (20, 20)-(200, 30)\n"
      "  id=3 CHECKBOX (20, 50)-(200, 30)\n",
      dst_tree.ToString());
}

TEST(AXTreeTest, DeleteUnknownSubtreeFails) {
  AXNodeData root;
  root.id = 1;
  root.role = AX_ROLE_ROOT_WEB_AREA;

  AXTreeUpdate initial_state;
  initial_state.nodes.push_back(root);
  AXTree tree(initial_state);

  // This should fail because we're asking it to delete
  // a subtree rooted at id=2, which doesn't exist.
  AXTreeUpdate update;
  update.node_id_to_clear = 2;
  update.nodes.resize(1);
  update.nodes[0].id = 1;
  update.nodes[0].id = AX_ROLE_ROOT_WEB_AREA;
  EXPECT_FALSE(tree.Unserialize(update));
  ASSERT_EQ("Bad node_id_to_clear: 2", tree.error());
}

TEST(AXTreeTest, LeaveOrphanedDeletedSubtreeFails) {
  AXTreeUpdate initial_state;
  initial_state.nodes.resize(3);
  initial_state.nodes[0].id = 1;
  initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
  initial_state.nodes[0].child_ids.push_back(2);
  initial_state.nodes[0].child_ids.push_back(3);
  initial_state.nodes[1].id = 2;
  initial_state.nodes[2].id = 3;
  AXTree tree(initial_state);

  // This should fail because we delete a subtree rooted at id=2
  // but never update it.
  AXTreeUpdate update;
  update.node_id_to_clear = 2;
  update.nodes.resize(1);
  update.nodes[0].id = 3;
  EXPECT_FALSE(tree.Unserialize(update));
  ASSERT_EQ("Nodes left pending by the update: 2", tree.error());
}

TEST(AXTreeTest, LeaveOrphanedNewChildFails) {
  AXTreeUpdate initial_state;
  initial_state.nodes.resize(1);
  initial_state.nodes[0].id = 1;
  initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
  AXTree tree(initial_state);

  // This should fail because we add a new child to the root node
  // but never update it.
  AXTreeUpdate update;
  update.nodes.resize(1);
  update.nodes[0].id = 1;
  update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
  update.nodes[0].child_ids.push_back(2);
  EXPECT_FALSE(tree.Unserialize(update));
  ASSERT_EQ("Nodes left pending by the update: 2", tree.error());
}

TEST(AXTreeTest, DuplicateChildIdFails) {
  AXTreeUpdate initial_state;
  initial_state.nodes.resize(1);
  initial_state.nodes[0].id = 1;
  initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
  AXTree tree(initial_state);

  // This should fail because a child id appears twice.
  AXTreeUpdate update;
  update.nodes.resize(2);
  update.nodes[0].id = 1;
  update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
  update.nodes[0].child_ids.push_back(2);
  update.nodes[0].child_ids.push_back(2);
  update.nodes[1].id = 2;
  EXPECT_FALSE(tree.Unserialize(update));
  ASSERT_EQ("Node 1 has duplicate child id 2", tree.error());
}

TEST(AXTreeTest, InvalidReparentingFails) {
  AXTreeUpdate initial_state;
  initial_state.nodes.resize(3);
  initial_state.nodes[0].id = 1;
  initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
  initial_state.nodes[0].child_ids.push_back(2);
  initial_state.nodes[1].id = 2;
  initial_state.nodes[1].child_ids.push_back(3);
  initial_state.nodes[2].id = 3;

  AXTree tree(initial_state);

  // This should fail because node 3 is reparented from node 2 to node 1
  // without deleting node 1's subtree first.
  AXTreeUpdate update;
  update.nodes.resize(3);
  update.nodes[0].id = 1;
  update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
  update.nodes[0].child_ids.push_back(3);
  update.nodes[0].child_ids.push_back(2);
  update.nodes[1].id = 2;
  update.nodes[2].id = 3;
  EXPECT_FALSE(tree.Unserialize(update));
  ASSERT_EQ("Node 3 reparented from 2 to 1", tree.error());
}

}  // namespace ui
<commit_msg>Fix accessibility_unittests.<commit_after>// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/memory/scoped_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_serializable_tree.h"
#include "ui/accessibility/ax_tree.h"
#include "ui/accessibility/ax_tree_serializer.h"

namespace ui {

TEST(AXTreeTest, SerializeSimpleAXTree) {
  AXNodeData root;
  root.id = 1;
  root.role = AX_ROLE_ROOT_WEB_AREA;
  root.state = (1 << AX_STATE_FOCUSABLE) | (1 << AX_STATE_FOCUSED);
  root.location = gfx::Rect(0, 0, 800, 600);
  root.child_ids.push_back(2);
  root.child_ids.push_back(3);

  AXNodeData button;
  button.id = 2;
  button.role = AX_ROLE_BUTTON;
  button.state = 0;
  button.location = gfx::Rect(20, 20, 200, 30);

  AXNodeData checkbox;
  checkbox.id = 3;
  checkbox.role = AX_ROLE_CHECK_BOX;
  checkbox.state = 0;
  checkbox.location = gfx::Rect(20, 50, 200, 30);

  AXTreeUpdate initial_state;
  initial_state.nodes.push_back(root);
  initial_state.nodes.push_back(button);
  initial_state.nodes.push_back(checkbox);
  AXSerializableTree src_tree(initial_state);

  scoped_ptr<AXTreeSource<AXNode> > tree_source(
      src_tree.CreateTreeSource());
  AXTreeSerializer<AXNode> serializer(tree_source.get());
  AXTreeUpdate update;
  serializer.SerializeChanges(src_tree.GetRoot(), &update);

  AXTree dst_tree;
  ASSERT_TRUE(dst_tree.Unserialize(update));

  AXNode* root_node = dst_tree.GetRoot();
  ASSERT_TRUE(root_node != NULL);
  EXPECT_EQ(root.id, root_node->id());
  EXPECT_EQ(root.role, root_node->data().role);

  ASSERT_EQ(2, root_node->child_count());

  AXNode* button_node = root_node->ChildAtIndex(0);
  EXPECT_EQ(button.id, button_node->id());
  EXPECT_EQ(button.role, button_node->data().role);

  AXNode* checkbox_node = root_node->ChildAtIndex(1);
  EXPECT_EQ(checkbox.id, checkbox_node->id());
  EXPECT_EQ(checkbox.role, checkbox_node->data().role);

  EXPECT_EQ(
      "id=1 root_web_area FOCUSABLE FOCUSED (0, 0)-(800, 600) child_ids=2,3\n"
      "  id=2 button (20, 20)-(200, 30)\n"
      "  id=3 check_box (20, 50)-(200, 30)\n",
      dst_tree.ToString());
}

TEST(AXTreeTest, DeleteUnknownSubtreeFails) {
  AXNodeData root;
  root.id = 1;
  root.role = AX_ROLE_ROOT_WEB_AREA;

  AXTreeUpdate initial_state;
  initial_state.nodes.push_back(root);
  AXTree tree(initial_state);

  // This should fail because we're asking it to delete
  // a subtree rooted at id=2, which doesn't exist.
  AXTreeUpdate update;
  update.node_id_to_clear = 2;
  update.nodes.resize(1);
  update.nodes[0].id = 1;
  update.nodes[0].id = AX_ROLE_ROOT_WEB_AREA;
  EXPECT_FALSE(tree.Unserialize(update));
  ASSERT_EQ("Bad node_id_to_clear: 2", tree.error());
}

TEST(AXTreeTest, LeaveOrphanedDeletedSubtreeFails) {
  AXTreeUpdate initial_state;
  initial_state.nodes.resize(3);
  initial_state.nodes[0].id = 1;
  initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
  initial_state.nodes[0].child_ids.push_back(2);
  initial_state.nodes[0].child_ids.push_back(3);
  initial_state.nodes[1].id = 2;
  initial_state.nodes[2].id = 3;
  AXTree tree(initial_state);

  // This should fail because we delete a subtree rooted at id=2
  // but never update it.
  AXTreeUpdate update;
  update.node_id_to_clear = 2;
  update.nodes.resize(1);
  update.nodes[0].id = 3;
  EXPECT_FALSE(tree.Unserialize(update));
  ASSERT_EQ("Nodes left pending by the update: 2", tree.error());
}

TEST(AXTreeTest, LeaveOrphanedNewChildFails) {
  AXTreeUpdate initial_state;
  initial_state.nodes.resize(1);
  initial_state.nodes[0].id = 1;
  initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
  AXTree tree(initial_state);

  // This should fail because we add a new child to the root node
  // but never update it.
  AXTreeUpdate update;
  update.nodes.resize(1);
  update.nodes[0].id = 1;
  update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
  update.nodes[0].child_ids.push_back(2);
  EXPECT_FALSE(tree.Unserialize(update));
  ASSERT_EQ("Nodes left pending by the update: 2", tree.error());
}

TEST(AXTreeTest, DuplicateChildIdFails) {
  AXTreeUpdate initial_state;
  initial_state.nodes.resize(1);
  initial_state.nodes[0].id = 1;
  initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
  AXTree tree(initial_state);

  // This should fail because a child id appears twice.
  AXTreeUpdate update;
  update.nodes.resize(2);
  update.nodes[0].id = 1;
  update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
  update.nodes[0].child_ids.push_back(2);
  update.nodes[0].child_ids.push_back(2);
  update.nodes[1].id = 2;
  EXPECT_FALSE(tree.Unserialize(update));
  ASSERT_EQ("Node 1 has duplicate child id 2", tree.error());
}

TEST(AXTreeTest, InvalidReparentingFails) {
  AXTreeUpdate initial_state;
  initial_state.nodes.resize(3);
  initial_state.nodes[0].id = 1;
  initial_state.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
  initial_state.nodes[0].child_ids.push_back(2);
  initial_state.nodes[1].id = 2;
  initial_state.nodes[1].child_ids.push_back(3);
  initial_state.nodes[2].id = 3;

  AXTree tree(initial_state);

  // This should fail because node 3 is reparented from node 2 to node 1
  // without deleting node 1's subtree first.
  AXTreeUpdate update;
  update.nodes.resize(3);
  update.nodes[0].id = 1;
  update.nodes[0].role = AX_ROLE_ROOT_WEB_AREA;
  update.nodes[0].child_ids.push_back(3);
  update.nodes[0].child_ids.push_back(2);
  update.nodes[1].id = 2;
  update.nodes[2].id = 3;
  EXPECT_FALSE(tree.Unserialize(update));
  ASSERT_EQ("Node 3 reparented from 2 to 1", tree.error());
}

}  // namespace ui
<|endoftext|>