<commit_before>#include "oemhandler.hpp"
#include <host-ipmid/ipmid-api.h>
#include <fstream>
#include <stdio.h>
#include <string.h>
#include <systemd/sd-bus.h>
#include <endian.h>

void register_netfn_oem_partial_esel() __attribute__((constructor));

const char *g_esel_path = "/tmp/esel";
uint16_t g_record_id = 0x0001;

///////////////////////////////////////////////////////////////////////////////
// For the First partial add eSEL the SEL Record ID and offset
// value should be 0x0000. The extended data needs to be in
// the form of an IPMI SEL Event Record, with Event sensor type
// of 0xDF and Event Message format of 0x04. The returned
// Record ID should be used for all partial eSEL adds.
//
// This function creates a /tmp/esel file to store the
// incoming partial esel.  It is the role of some other
// function to commit the error log in to long term
// storage.  Likely via the ipmi add_sel command.
///////////////////////////////////////////////////////////////////////////////
ipmi_ret_t ipmi_ibm_oem_partial_esel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
                                     ipmi_request_t request, ipmi_response_t response,
                                     ipmi_data_len_t data_len, ipmi_context_t context)
{
	uint8_t *reqptr = (uint8_t *) request;
	esel_request_t esel_req;
	FILE *fp;
	int r = 0;
	uint8_t rlen;
	ipmi_ret_t rc = IPMI_CC_OK;
	const char *pio;

	esel_req.resid     = le16toh((((uint16_t) reqptr[1]) << 8) + reqptr[0]);
	esel_req.selrecord = le16toh((((uint16_t) reqptr[3]) << 8) + reqptr[2]);
	esel_req.offset    = le16toh((((uint16_t) reqptr[5]) << 8) + reqptr[4]);
	esel_req.progress  = reqptr[6];

	uint16_t used_res_id = get_sel_reserve_id();

	// According to IPMI spec, Reservation ID must be checked.
	if ( used_res_id != esel_req.resid ) {
		// 0xc5 means Reservation Cancelled or Invalid Reservation ID.
		printf("Used Reservation ID = %d\n", used_res_id);
		rc = IPMI_CC_INVALID_RESERVATION_ID;

		// clean g_esel_path.
		r = remove(g_esel_path);
		if(r < 0)
			fprintf(stderr, "Error deleting %s\n", g_esel_path);

		return rc;
	}

    // OpenPOWER Host Interface spec says if RecordID and Offset are
	// 0 then then this is a new request
	if (!esel_req.selrecord && !esel_req.offset)
		pio = "wb";
	else
		pio = "rb+";

	rlen = (*data_len) - (uint8_t) (sizeof(esel_request_t));

	printf("IPMI PARTIAL ESEL for %s  Offset = %d Length = %d\n",
		g_esel_path, esel_req.offset, rlen);

	if ((fp = fopen(g_esel_path, pio)) != NULL) {
		fseek(fp, esel_req.offset, SEEK_SET);
		fwrite(reqptr+(uint8_t) (sizeof(esel_request_t)), rlen, 1, fp);
		fclose(fp);

		*data_len = sizeof(g_record_id);
		memcpy(response, &g_record_id, *data_len);
	} else {
		fprintf(stderr, "Error trying to perform %s for esel%s\n",pio, g_esel_path);
		rc = IPMI_CC_INVALID;
		*data_len     = 0;
	}

	// The first bit prepresents that this is the last partial packet
	// coming down.  If that is the case advance the record id so we
	// don't overlap logs.  This allows anyone to establish a log
	// directory system.
	if (esel_req.progress & 1 ) {
		g_record_id++;
	}

	return rc;
}

// Prepare for FW Update.
// Execute needed commands to prepare the system for a fw update from the host.
ipmi_ret_t ipmi_ibm_oem_prep_fw_update(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
                                     ipmi_request_t request, ipmi_response_t response,
                                     ipmi_data_len_t data_len, ipmi_context_t context)
{
    ipmi_ret_t ipmi_rc = IPMI_CC_OK;
    *data_len = 0;

    int rc = 0;
    std::ofstream rwfs_file;
    const char  *busname = "org.openbmc.control.Bmc";
    const char  *objname = "/org/openbmc/control/bmc0";
    const char  *iface = "org.openbmc.control.Bmc";
    sd_bus *bus = ipmid_get_sd_bus_connection();
    sd_bus_message *reply = NULL;
    sd_bus_error error = SD_BUS_ERROR_NULL;
    int r = 0;

    // Set one time flag
    rc = system("fw_setenv openbmconce copy-files-to-ram copy-base-filesystem-to-ram");
    rc = WEXITSTATUS(rc);
    if (rc != 0) {
        fprintf(stderr, "fw_setenv openbmconce failed with rc=%d\n", rc);
        return IPMI_CC_UNSPECIFIED_ERROR;
    }

    // Touch the image-rwfs file to perform an empty update to force the save
    // in case we're already in ram and the flash is the same causing the ram files
    // to not be copied back to flash
    rwfs_file.open("/run/initramfs/image-rwfs", std::ofstream::out | std::ofstream::app);
    rwfs_file.close();

    // Reboot the BMC for settings to take effect
    r = sd_bus_call_method(bus, busname, objname, iface,
                           "warmReset", &error, &reply, NULL);
    if (r < 0) {
        fprintf(stderr, "Failed to reset BMC: %s\n", strerror(-r));
        return -1;
    }
    printf("Warning: BMC is going down for reboot!\n");
    sd_bus_error_free(&error);
    reply = sd_bus_message_unref(reply);

    return ipmi_rc;
}

void register_netfn_oem_partial_esel()
{
    printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_OEM, IPMI_CMD_PESEL);
    ipmi_register_callback(NETFUN_OEM, IPMI_CMD_PESEL, NULL, ipmi_ibm_oem_partial_esel,
                           SYSTEM_INTERFACE);

    printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_OEM, IPMI_CMD_PREP_FW_UPDATE);
    ipmi_register_callback(NETFUN_OEM, IPMI_CMD_PREP_FW_UPDATE, NULL, ipmi_ibm_oem_prep_fw_update,
                           SYSTEM_INTERFACE);

    return;
}
<commit_msg>Remove un-needed printf about esel<commit_after>#include "oemhandler.hpp"
#include <host-ipmid/ipmid-api.h>
#include <fstream>
#include <stdio.h>
#include <string.h>
#include <systemd/sd-bus.h>
#include <endian.h>

void register_netfn_oem_partial_esel() __attribute__((constructor));

const char *g_esel_path = "/tmp/esel";
uint16_t g_record_id = 0x0001;

///////////////////////////////////////////////////////////////////////////////
// For the First partial add eSEL the SEL Record ID and offset
// value should be 0x0000. The extended data needs to be in
// the form of an IPMI SEL Event Record, with Event sensor type
// of 0xDF and Event Message format of 0x04. The returned
// Record ID should be used for all partial eSEL adds.
//
// This function creates a /tmp/esel file to store the
// incoming partial esel.  It is the role of some other
// function to commit the error log in to long term
// storage.  Likely via the ipmi add_sel command.
///////////////////////////////////////////////////////////////////////////////
ipmi_ret_t ipmi_ibm_oem_partial_esel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
                                     ipmi_request_t request, ipmi_response_t response,
                                     ipmi_data_len_t data_len, ipmi_context_t context)
{
	uint8_t *reqptr = (uint8_t *) request;
	esel_request_t esel_req;
	FILE *fp;
	int r = 0;
	uint8_t rlen;
	ipmi_ret_t rc = IPMI_CC_OK;
	const char *pio;

	esel_req.resid     = le16toh((((uint16_t) reqptr[1]) << 8) + reqptr[0]);
	esel_req.selrecord = le16toh((((uint16_t) reqptr[3]) << 8) + reqptr[2]);
	esel_req.offset    = le16toh((((uint16_t) reqptr[5]) << 8) + reqptr[4]);
	esel_req.progress  = reqptr[6];

	uint16_t used_res_id = get_sel_reserve_id();

	// According to IPMI spec, Reservation ID must be checked.
	if ( used_res_id != esel_req.resid ) {
		// 0xc5 means Reservation Cancelled or Invalid Reservation ID.
		printf("Used Reservation ID = %d\n", used_res_id);
		rc = IPMI_CC_INVALID_RESERVATION_ID;

		// clean g_esel_path.
		r = remove(g_esel_path);
		if(r < 0)
			fprintf(stderr, "Error deleting %s\n", g_esel_path);

		return rc;
	}

    // OpenPOWER Host Interface spec says if RecordID and Offset are
	// 0 then then this is a new request
	if (!esel_req.selrecord && !esel_req.offset)
		pio = "wb";
	else
		pio = "rb+";

	rlen = (*data_len) - (uint8_t) (sizeof(esel_request_t));

	if ((fp = fopen(g_esel_path, pio)) != NULL) {
		fseek(fp, esel_req.offset, SEEK_SET);
		fwrite(reqptr+(uint8_t) (sizeof(esel_request_t)), rlen, 1, fp);
		fclose(fp);

		*data_len = sizeof(g_record_id);
		memcpy(response, &g_record_id, *data_len);
	} else {
		fprintf(stderr, "Error trying to perform %s for esel%s\n",pio, g_esel_path);
		rc = IPMI_CC_INVALID;
		*data_len     = 0;
	}

	// The first bit prepresents that this is the last partial packet
	// coming down.  If that is the case advance the record id so we
	// don't overlap logs.  This allows anyone to establish a log
	// directory system.
	if (esel_req.progress & 1 ) {
		g_record_id++;
	}

	return rc;
}

// Prepare for FW Update.
// Execute needed commands to prepare the system for a fw update from the host.
ipmi_ret_t ipmi_ibm_oem_prep_fw_update(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
                                     ipmi_request_t request, ipmi_response_t response,
                                     ipmi_data_len_t data_len, ipmi_context_t context)
{
    ipmi_ret_t ipmi_rc = IPMI_CC_OK;
    *data_len = 0;

    int rc = 0;
    std::ofstream rwfs_file;
    const char  *busname = "org.openbmc.control.Bmc";
    const char  *objname = "/org/openbmc/control/bmc0";
    const char  *iface = "org.openbmc.control.Bmc";
    sd_bus *bus = ipmid_get_sd_bus_connection();
    sd_bus_message *reply = NULL;
    sd_bus_error error = SD_BUS_ERROR_NULL;
    int r = 0;

    // Set one time flag
    rc = system("fw_setenv openbmconce copy-files-to-ram copy-base-filesystem-to-ram");
    rc = WEXITSTATUS(rc);
    if (rc != 0) {
        fprintf(stderr, "fw_setenv openbmconce failed with rc=%d\n", rc);
        return IPMI_CC_UNSPECIFIED_ERROR;
    }

    // Touch the image-rwfs file to perform an empty update to force the save
    // in case we're already in ram and the flash is the same causing the ram files
    // to not be copied back to flash
    rwfs_file.open("/run/initramfs/image-rwfs", std::ofstream::out | std::ofstream::app);
    rwfs_file.close();

    // Reboot the BMC for settings to take effect
    r = sd_bus_call_method(bus, busname, objname, iface,
                           "warmReset", &error, &reply, NULL);
    if (r < 0) {
        fprintf(stderr, "Failed to reset BMC: %s\n", strerror(-r));
        return -1;
    }
    printf("Warning: BMC is going down for reboot!\n");
    sd_bus_error_free(&error);
    reply = sd_bus_message_unref(reply);

    return ipmi_rc;
}

void register_netfn_oem_partial_esel()
{
    printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_OEM, IPMI_CMD_PESEL);
    ipmi_register_callback(NETFUN_OEM, IPMI_CMD_PESEL, NULL, ipmi_ibm_oem_partial_esel,
                           SYSTEM_INTERFACE);

    printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_OEM, IPMI_CMD_PREP_FW_UPDATE);
    ipmi_register_callback(NETFUN_OEM, IPMI_CMD_PREP_FW_UPDATE, NULL, ipmi_ibm_oem_prep_fw_update,
                           SYSTEM_INTERFACE);

    return;
}
<|endoftext|>


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

Author: Leonardo de Moura
*/
#include "kernel/abstract.h"
#include "kernel/instantiate.h"
#include "kernel/inductive/inductive.h"
#include "library/locals.h"
#include "library/tactic/tactic.h"
#include "library/reducible.h"
#include "library/tactic/expr_to_tactic.h"

namespace lean {
class inversion_tac {
    environment const &           m_env;
    io_state const &              m_ios;
    proof_state const &           m_ps;
    name_generator                m_ngen;
    substitution                  m_subst;
    std::unique_ptr<type_checker> m_tc;

    bool                          m_dep_elim;
    unsigned                      m_nparams;
    unsigned                      m_nindices;
    unsigned                      m_nminors;
    declaration                   m_I_decl;
    declaration                   m_cases_on_decl;

    void init_inductive_info(name const & n) {
        m_dep_elim      = inductive::has_dep_elim(m_env, n);
        m_nindices      = *inductive::get_num_indices(m_env, n);
        m_nparams       = *inductive::get_num_params(m_env, n);
        m_nminors       = *inductive::get_num_minor_premises(m_env, n);
        m_I_decl        = m_env.get(n);
        m_cases_on_decl = m_env.get({n, "cases_on"});
    }

    bool is_inversion_applicable(expr const & t) {
        buffer<expr> args;
        expr const & fn = get_app_args(t, args);
        if (!is_constant(fn))
            return false;
        if (!inductive::is_inductive_decl(m_env, const_name(fn)))
            return false;
        if (!m_env.find(name{const_name(fn), "cases_on"}) ||
            !m_env.find(name("eq")) || !m_env.find(name("heq")))
            return false;
        init_inductive_info(const_name(fn));
        if (args.size() != m_nindices + m_nparams)
            return false;
        return true;
    }

    pair<expr, expr> mk_eq(expr const & lhs, expr const & rhs) {
        expr lhs_type = m_tc->infer(lhs).first;
        expr rhs_type = m_tc->infer(rhs).first;
        level l       = sort_level(m_tc->ensure_type(lhs_type).first);
        constraint_seq cs;
        if (m_tc->is_def_eq(lhs_type, rhs_type, justification(), cs) && !cs) {
            return mk_pair(mk_app(mk_constant("eq", to_list(l)), lhs_type, lhs, rhs),
                           mk_app(mk_constant({"eq", "refl"}, to_list(l)), rhs_type, rhs));
        } else {
            return mk_pair(mk_app(mk_constant("heq", to_list(l)), lhs_type, lhs, rhs_type, rhs),
                           mk_app(mk_constant({"heq", "refl"}, to_list(l)), rhs_type, rhs));
        }
    }

    goal generalize_indices(goal const & g, expr const & h, expr const & h_type) {
        buffer<expr> hyps;
        g.get_hyps(hyps);
        expr m            = g.get_meta();
        expr m_type       = g.get_type();
        name h_new_name   = g.get_unused_name(local_pp_name(h));
        buffer<expr> I_args;
        expr const & I    = get_app_args(h_type, I_args);
        expr h_new_type  = mk_app(I, I_args.size() - m_nindices, I_args.data());
        expr d           = m_tc->whnf(m_tc->infer(h_new_type).first).first;
        unsigned eq_idx  = 1;
        name eq_prefix("H");
        buffer<expr> ts;
        buffer<expr> eqs;
        buffer<expr> refls;
        name t_prefix("t");
        unsigned nidx = 1;
        auto add_eq = [&](expr const & lhs, expr const & rhs) {
            pair<expr, expr> p = mk_eq(lhs, rhs);
            expr new_eq   = p.first;
            expr new_refl = p.second;
            eqs.push_back(mk_local(m_ngen.next(), g.get_unused_name(eq_prefix, eq_idx), new_eq, binder_info()));
            refls.push_back(new_refl);
        };
        for (unsigned i = I_args.size() - m_nindices; i < I_args.size(); i++) {
            expr t_type = binding_domain(d);
            expr t      = mk_local(m_ngen.next(), g.get_unused_name(t_prefix, nidx), t_type, binder_info());
            expr const & index = I_args[i];
            add_eq(t, index);
            h_new_type  = mk_app(h_new_type, t);
            hyps.push_back(t);
            ts.push_back(t);
            d           = instantiate(binding_body(d), t);
        }
        expr h_new    = mk_local(m_ngen.next(), h_new_name, h_new_type, local_info(h));
        if (m_dep_elim)
            add_eq(h_new, h);
        hyps.push_back(h_new);
        expr new_type = Pi(eqs, g.get_type());
        expr new_meta = mk_app(mk_metavar(m_ngen.next(), Pi(hyps, new_type)), hyps);
        goal new_g(new_meta, new_type);
        expr val      = g.abstract(mk_app(mk_app(mk_app(Fun(ts, Fun(h_new, new_meta)), m_nindices, I_args.end() - m_nindices), h),
                                          refls));
        m_subst.assign(g.get_name(), val);
        return new_g;
    }

    list<goal> apply_cases_on(goal const & g) {
        buffer<expr> hyps;
        g.get_hyps(hyps);
        expr const & h      = hyps.back();
        expr const & h_type = mlocal_type(h);
        buffer<expr> I_args;
        expr const & I      = get_app_args(h_type, I_args);
        expr g_type         = g.get_type();
        expr cases_on;
        if (length(m_cases_on_decl.get_univ_params()) != length(m_I_decl.get_univ_params())) {
            level g_lvl  = sort_level(m_tc->ensure_type(g_type).first);
            cases_on     = mk_constant({const_name(I), "cases_on"}, cons(g_lvl, const_levels(I)));
        } else {
            cases_on     = mk_constant({const_name(I), "cases_on"}, const_levels(I));
        }
        // add params
        cases_on          = mk_app(cases_on, m_nparams, I_args.data());
        // add type former
        expr type_former  = g_type;
        if (m_dep_elim)
            type_former   = Fun(h, type_former);
        type_former       = Fun(m_nindices, I_args.end() - m_nindices, type_former);
        cases_on          = mk_app(cases_on, type_former);
        // add indices
        cases_on          = mk_app(cases_on, m_nindices, I_args.end() - m_nindices);
        // add h
        cases_on          = mk_app(cases_on, h);
        buffer<expr> new_hyps;
        new_hyps.append(hyps.size() - m_nindices - 1, hyps.data());
        // add a subgoal for each minor premise of cases_on
        expr cases_on_type = m_tc->whnf(m_tc->infer(cases_on).first).first;
        buffer<goal> new_goals;
        for (unsigned i = 0; i < m_nminors; i++) {
            expr new_type = binding_domain(cases_on_type);
            expr new_meta = mk_app(mk_metavar(m_ngen.next(), Pi(new_hyps, new_type)), new_hyps);
            goal new_g(new_meta, new_type);
            new_goals.push_back(new_g);
            cases_on      = mk_app(cases_on, new_meta);
            cases_on_type = m_tc->whnf(binding_body(cases_on_type)).first; // the minor premises do not depend on each other
        }
        expr val        = g.abstract(cases_on);
        m_subst.assign(g.get_name(), val);
        return to_list(new_goals.begin(), new_goals.end());
    }

    // Store in \c r the number of arguments for each cases_on minor.
    void get_minors_nargs(buffer<unsigned> & r) {
        expr cases_on_type = m_cases_on_decl.get_type();
        for (unsigned i = 0; i < m_nparams + 1 + m_nindices + 1; i++)
            cases_on_type = binding_body(cases_on_type);
        for (unsigned i = 0; i < m_nminors; i++) {
            expr minor_type = binding_domain(cases_on_type);
            unsigned nargs  = 0;
            while (is_pi(minor_type)) {
                nargs++;
                minor_type = binding_body(minor_type);
            }
            r.push_back(nargs);
            cases_on_type   = binding_body(cases_on_type);
        }
    }

    list<goal> intros_minors_args(list<goal> gs) {
        buffer<unsigned> minors_nargs;
        get_minors_nargs(minors_nargs);
        lean_assert(length(gs) == minors_nargs.size());
        buffer<goal> new_gs;
        for (unsigned i = 0; i < minors_nargs.size(); i++) {
            goal const & g = head(gs);
            unsigned nargs = minors_nargs[i];
            buffer<expr> hyps;
            g.get_hyps(hyps);
            buffer<expr> new_hyps;
            new_hyps.append(hyps);
            expr g_type    = g.get_type();
            for (unsigned i = 0; i < nargs; i++) {
                expr type  = binding_domain(g_type);
                expr new_h = mk_local(m_ngen.next(), get_unused_name(binding_name(g_type), hyps), type, binder_info());
                new_hyps.push_back(new_h);
                g_type     = instantiate(binding_body(g_type), new_h);
            }
            g_type = head_beta_reduce(g_type);
            expr new_meta = mk_app(mk_metavar(m_ngen.next(), Pi(new_hyps, g_type)), new_hyps);
            goal new_g(new_meta, g_type);
            new_gs.push_back(new_g);
            expr val      = g.abstract(Fun(nargs, new_hyps.end() - nargs, new_meta));
            m_subst.assign(g.get_name(), val);
            gs = tail(gs);
        }
        return to_list(new_gs.begin(), new_gs.end());
    }

public:
    inversion_tac(environment const & env, io_state const & ios, proof_state const & ps):
        m_env(env), m_ios(ios), m_ps(ps),
        m_ngen(m_ps.get_ngen()),
        m_tc(mk_type_checker(m_env, m_ngen.mk_child(), m_ps.relax_main_opaque())) {
    }

    optional<proof_state> execute(name const & n) {
        goals const & gs  = m_ps.get_goals();
        if (empty(gs))
            return none_proof_state();
        goal  g           = head(gs);
        goals tail_gs     = tail(gs);
        auto p = g.find_hyp(n);
        if (!p)
            return none_proof_state();
        expr const & h    = p->first;
        expr h_type       = m_tc->whnf(mlocal_type(h)).first;
        if (!is_inversion_applicable(h_type))
            return none_proof_state();
        goal g1           = generalize_indices(g, h, h_type);
        list<goal> gs2    = apply_cases_on(g1);
        list<goal> gs3    = intros_minors_args(gs2);
        proof_state new_s(m_ps, append(gs3, tail_gs), m_subst, m_ngen);
        return some_proof_state(new_s);
    }
};

tactic inversion_tactic(name const & n) {
    auto fn = [=](environment const & env, io_state const & ios, proof_state const & ps) -> optional<proof_state> {
        inversion_tac tac(env, ios, ps);
        return tac.execute(n);
    };
    return tactic01(fn);
}

void initialize_inversion_tactic() {
    register_tac(name({"tactic", "inversion"}),
                 [](type_checker &, elaborate_fn const &, expr const & e, pos_info_provider const *) {
                     name n = tactic_expr_to_id(app_arg(e), "invalid 'inversion' tactic, argument must be an identifier");
                     return inversion_tactic(n);
                 });
}
void finalize_inversion_tactic() {}
}
<commit_msg>fix(library/tactic/inversion_tactic): bug in name generation<commit_after>/*
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.

Author: Leonardo de Moura
*/
#include "kernel/abstract.h"
#include "kernel/instantiate.h"
#include "kernel/inductive/inductive.h"
#include "library/locals.h"
#include "library/tactic/tactic.h"
#include "library/reducible.h"
#include "library/tactic/expr_to_tactic.h"

namespace lean {
class inversion_tac {
    environment const &           m_env;
    io_state const &              m_ios;
    proof_state const &           m_ps;
    name_generator                m_ngen;
    substitution                  m_subst;
    std::unique_ptr<type_checker> m_tc;

    bool                          m_dep_elim;
    unsigned                      m_nparams;
    unsigned                      m_nindices;
    unsigned                      m_nminors;
    declaration                   m_I_decl;
    declaration                   m_cases_on_decl;

    void init_inductive_info(name const & n) {
        m_dep_elim      = inductive::has_dep_elim(m_env, n);
        m_nindices      = *inductive::get_num_indices(m_env, n);
        m_nparams       = *inductive::get_num_params(m_env, n);
        m_nminors       = *inductive::get_num_minor_premises(m_env, n);
        m_I_decl        = m_env.get(n);
        m_cases_on_decl = m_env.get({n, "cases_on"});
    }

    bool is_inversion_applicable(expr const & t) {
        buffer<expr> args;
        expr const & fn = get_app_args(t, args);
        if (!is_constant(fn))
            return false;
        if (!inductive::is_inductive_decl(m_env, const_name(fn)))
            return false;
        if (!m_env.find(name{const_name(fn), "cases_on"}) ||
            !m_env.find(name("eq")) || !m_env.find(name("heq")))
            return false;
        init_inductive_info(const_name(fn));
        if (args.size() != m_nindices + m_nparams)
            return false;
        return true;
    }

    pair<expr, expr> mk_eq(expr const & lhs, expr const & rhs) {
        expr lhs_type = m_tc->infer(lhs).first;
        expr rhs_type = m_tc->infer(rhs).first;
        level l       = sort_level(m_tc->ensure_type(lhs_type).first);
        constraint_seq cs;
        if (m_tc->is_def_eq(lhs_type, rhs_type, justification(), cs) && !cs) {
            return mk_pair(mk_app(mk_constant("eq", to_list(l)), lhs_type, lhs, rhs),
                           mk_app(mk_constant({"eq", "refl"}, to_list(l)), rhs_type, rhs));
        } else {
            return mk_pair(mk_app(mk_constant("heq", to_list(l)), lhs_type, lhs, rhs_type, rhs),
                           mk_app(mk_constant({"heq", "refl"}, to_list(l)), rhs_type, rhs));
        }
    }

    goal generalize_indices(goal const & g, expr const & h, expr const & h_type) {
        buffer<expr> hyps;
        g.get_hyps(hyps);
        expr m            = g.get_meta();
        expr m_type       = g.get_type();
        name h_new_name   = g.get_unused_name(local_pp_name(h));
        buffer<expr> I_args;
        expr const & I    = get_app_args(h_type, I_args);
        expr h_new_type  = mk_app(I, I_args.size() - m_nindices, I_args.data());
        expr d           = m_tc->whnf(m_tc->infer(h_new_type).first).first;
        unsigned eq_idx  = 1;
        name eq_prefix("H");
        buffer<expr> ts;
        buffer<expr> eqs;
        buffer<expr> refls;
        name t_prefix("t");
        unsigned nidx = 1;
        auto add_eq = [&](expr const & lhs, expr const & rhs) {
            pair<expr, expr> p = mk_eq(lhs, rhs);
            expr new_eq   = p.first;
            expr new_refl = p.second;
            eqs.push_back(mk_local(m_ngen.next(), g.get_unused_name(eq_prefix, eq_idx), new_eq, binder_info()));
            refls.push_back(new_refl);
        };
        for (unsigned i = I_args.size() - m_nindices; i < I_args.size(); i++) {
            expr t_type = binding_domain(d);
            expr t      = mk_local(m_ngen.next(), g.get_unused_name(t_prefix, nidx), t_type, binder_info());
            expr const & index = I_args[i];
            add_eq(t, index);
            h_new_type  = mk_app(h_new_type, t);
            hyps.push_back(t);
            ts.push_back(t);
            d           = instantiate(binding_body(d), t);
        }
        expr h_new    = mk_local(m_ngen.next(), h_new_name, h_new_type, local_info(h));
        if (m_dep_elim)
            add_eq(h_new, h);
        hyps.push_back(h_new);
        expr new_type = Pi(eqs, g.get_type());
        expr new_meta = mk_app(mk_metavar(m_ngen.next(), Pi(hyps, new_type)), hyps);
        goal new_g(new_meta, new_type);
        expr val      = g.abstract(mk_app(mk_app(mk_app(Fun(ts, Fun(h_new, new_meta)), m_nindices, I_args.end() - m_nindices), h),
                                          refls));
        m_subst.assign(g.get_name(), val);
        return new_g;
    }

    list<goal> apply_cases_on(goal const & g) {
        buffer<expr> hyps;
        g.get_hyps(hyps);
        expr const & h      = hyps.back();
        expr const & h_type = mlocal_type(h);
        buffer<expr> I_args;
        expr const & I      = get_app_args(h_type, I_args);
        expr g_type         = g.get_type();
        expr cases_on;
        if (length(m_cases_on_decl.get_univ_params()) != length(m_I_decl.get_univ_params())) {
            level g_lvl  = sort_level(m_tc->ensure_type(g_type).first);
            cases_on     = mk_constant({const_name(I), "cases_on"}, cons(g_lvl, const_levels(I)));
        } else {
            cases_on     = mk_constant({const_name(I), "cases_on"}, const_levels(I));
        }
        // add params
        cases_on          = mk_app(cases_on, m_nparams, I_args.data());
        // add type former
        expr type_former  = g_type;
        if (m_dep_elim)
            type_former   = Fun(h, type_former);
        type_former       = Fun(m_nindices, I_args.end() - m_nindices, type_former);
        cases_on          = mk_app(cases_on, type_former);
        // add indices
        cases_on          = mk_app(cases_on, m_nindices, I_args.end() - m_nindices);
        // add h
        cases_on          = mk_app(cases_on, h);
        buffer<expr> new_hyps;
        new_hyps.append(hyps.size() - m_nindices - 1, hyps.data());
        // add a subgoal for each minor premise of cases_on
        expr cases_on_type = m_tc->whnf(m_tc->infer(cases_on).first).first;
        buffer<goal> new_goals;
        for (unsigned i = 0; i < m_nminors; i++) {
            expr new_type = binding_domain(cases_on_type);
            expr new_meta = mk_app(mk_metavar(m_ngen.next(), Pi(new_hyps, new_type)), new_hyps);
            goal new_g(new_meta, new_type);
            new_goals.push_back(new_g);
            cases_on      = mk_app(cases_on, new_meta);
            cases_on_type = m_tc->whnf(binding_body(cases_on_type)).first; // the minor premises do not depend on each other
        }
        expr val        = g.abstract(cases_on);
        m_subst.assign(g.get_name(), val);
        return to_list(new_goals.begin(), new_goals.end());
    }

    // Store in \c r the number of arguments for each cases_on minor.
    void get_minors_nargs(buffer<unsigned> & r) {
        expr cases_on_type = m_cases_on_decl.get_type();
        for (unsigned i = 0; i < m_nparams + 1 + m_nindices + 1; i++)
            cases_on_type = binding_body(cases_on_type);
        for (unsigned i = 0; i < m_nminors; i++) {
            expr minor_type = binding_domain(cases_on_type);
            unsigned nargs  = 0;
            while (is_pi(minor_type)) {
                nargs++;
                minor_type = binding_body(minor_type);
            }
            r.push_back(nargs);
            cases_on_type   = binding_body(cases_on_type);
        }
    }

    list<goal> intros_minors_args(list<goal> gs) {
        buffer<unsigned> minors_nargs;
        get_minors_nargs(minors_nargs);
        lean_assert(length(gs) == minors_nargs.size());
        buffer<goal> new_gs;
        for (unsigned i = 0; i < minors_nargs.size(); i++) {
            goal const & g = head(gs);
            unsigned nargs = minors_nargs[i];
            buffer<expr> hyps;
            g.get_hyps(hyps);
            buffer<expr> new_hyps;
            new_hyps.append(hyps);
            expr g_type    = g.get_type();
            for (unsigned i = 0; i < nargs; i++) {
                expr type  = binding_domain(g_type);
                expr new_h = mk_local(m_ngen.next(), get_unused_name(binding_name(g_type), new_hyps), type, binder_info());
                new_hyps.push_back(new_h);
                g_type     = instantiate(binding_body(g_type), new_h);
            }
            g_type = head_beta_reduce(g_type);
            expr new_meta = mk_app(mk_metavar(m_ngen.next(), Pi(new_hyps, g_type)), new_hyps);
            goal new_g(new_meta, g_type);
            new_gs.push_back(new_g);
            expr val      = g.abstract(Fun(nargs, new_hyps.end() - nargs, new_meta));
            m_subst.assign(g.get_name(), val);
            gs = tail(gs);
        }
        return to_list(new_gs.begin(), new_gs.end());
    }

public:
    inversion_tac(environment const & env, io_state const & ios, proof_state const & ps):
        m_env(env), m_ios(ios), m_ps(ps),
        m_ngen(m_ps.get_ngen()),
        m_tc(mk_type_checker(m_env, m_ngen.mk_child(), m_ps.relax_main_opaque())) {
    }

    optional<proof_state> execute(name const & n) {
        goals const & gs  = m_ps.get_goals();
        if (empty(gs))
            return none_proof_state();
        goal  g           = head(gs);
        goals tail_gs     = tail(gs);
        auto p = g.find_hyp(n);
        if (!p)
            return none_proof_state();
        expr const & h    = p->first;
        expr h_type       = m_tc->whnf(mlocal_type(h)).first;
        if (!is_inversion_applicable(h_type))
            return none_proof_state();
        goal g1           = generalize_indices(g, h, h_type);
        list<goal> gs2    = apply_cases_on(g1);
        list<goal> gs3    = intros_minors_args(gs2);
        proof_state new_s(m_ps, append(gs3, tail_gs), m_subst, m_ngen);
        return some_proof_state(new_s);
    }
};

tactic inversion_tactic(name const & n) {
    auto fn = [=](environment const & env, io_state const & ios, proof_state const & ps) -> optional<proof_state> {
        inversion_tac tac(env, ios, ps);
        return tac.execute(n);
    };
    return tactic01(fn);
}

void initialize_inversion_tactic() {
    register_tac(name({"tactic", "inversion"}),
                 [](type_checker &, elaborate_fn const &, expr const & e, pos_info_provider const *) {
                     name n = tactic_expr_to_id(app_arg(e), "invalid 'inversion' tactic, argument must be an identifier");
                     return inversion_tactic(n);
                 });
}
void finalize_inversion_tactic() {}
}
<|endoftext|>


<commit_before>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2010 Klaus Post
    Copyright (C) 2014-2015 Pedro Côrte-Real
    Copyright (C) 2017 Roman Lebedev

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

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/SamsungV2Decompressor.h"
#include "common/Common.h"                // for uint32_t, uint16_t, int32_t
#include "common/Point.h"                 // for iPoint2D
#include "common/RawImage.h"              // for RawImage, RawImageData
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "io/BitPumpMSB32.h"              // for BitPumpMSB32
#include "io/ByteStream.h"                // for ByteStream
#include <algorithm>                      // for max
#include <cassert>                        // for assert
#include <type_traits>                    // for underlying_type, underlyin...

namespace rawspeed {

// Seriously Samsung just use lossless jpeg already, it compresses better too :)

// Thanks to Michael Reichmann (Luminous Landscape) for putting Pedro Côrte-Real
// in contact and Loring von Palleske (Samsung) for pointing to the open-source
// code of Samsung's DNG converter at http://opensource.samsung.com/

enum struct SamsungV2Decompressor::OptFlags : uint32_t {
  NONE = 0U,       // no flags
  SKIP = 1U << 0U, // Skip checking if we need differences from previous line
  MV = 1U << 1U,   // Simplify motion vector definition
  QP = 1U << 2U,   // Don't scale the diff values

  // all possible flags
  ALL = SKIP | MV | QP,
};

constexpr SamsungV2Decompressor::OptFlags
operator|(SamsungV2Decompressor::OptFlags lhs,
          SamsungV2Decompressor::OptFlags rhs) {
  return static_cast<SamsungV2Decompressor::OptFlags>(
      static_cast<std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
          lhs) |
      static_cast<std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
          rhs));
}

constexpr bool operator&(SamsungV2Decompressor::OptFlags lhs,
                         SamsungV2Decompressor::OptFlags rhs) {
  return SamsungV2Decompressor::OptFlags::NONE !=
         static_cast<SamsungV2Decompressor::OptFlags>(
             static_cast<
                 std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
                 lhs) &
             static_cast<
                 std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
                 rhs));
}

inline int32_t SamsungV2Decompressor::getDiff(BitPumpMSB32* pump,
                                              uint32_t len) {
  if (len == 0)
    return 0;
  int32_t diff = pump->getBits(len);
  // If the first bit is 1 we need to turn this into a negative number
  if (diff >> (len - 1))
    diff -= (1 << len);
  return diff;
}

SamsungV2Decompressor::SamsungV2Decompressor(const RawImage& image,
                                             const ByteStream& bs, int bit)
    : AbstractSamsungDecompressor(image), bits(bit) {
  if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
      mRaw->getBpp() != 2)
    ThrowRDE("Unexpected component count / data type");

  switch (bit) {
  case 12:
  case 14:
    break;
  default:
    ThrowRDE("Unexpected bit per pixel (%u)", bit);
  }

  static constexpr const auto headerSize = 16;
  bs.check(headerSize);

  BitPumpMSB32 startpump(bs);

  // Process the initial metadata bits, we only really use initVal, width and
  // height (the last two match the TIFF values anyway)
  startpump.getBits(16); // NLCVersion
  startpump.getBits(4);  // ImgFormat
  bitDepth = startpump.getBits(4) + 1;
  startpump.getBits(4); // NumBlkInRCUnit
  startpump.getBits(4); // CompressionRatio
  width = startpump.getBits(16);
  height = startpump.getBits(16);
  startpump.getBits(16); // TileWidth
  startpump.getBits(4);  // reserved

  // The format includes an optimization code that sets 3 flags to change the
  // decoding parameters
  const uint32_t optflags = startpump.getBits(4);
  if (optflags > static_cast<uint32_t>(OptFlags::ALL))
    ThrowRDE("Invalid opt flags %x", optflags);
  _flags = static_cast<OptFlags>(optflags);

  startpump.getBits(8); // OverlapWidth
  startpump.getBits(8); // reserved
  startpump.getBits(8); // Inc
  startpump.getBits(2); // reserved
  initVal = startpump.getBits(14);

  assert(startpump.getPosition() == headerSize);

  if (width == 0 || height == 0 || width % 16 != 0 || width > 6496 ||
      height > 4336)
    ThrowRDE("Unexpected image dimensions found: (%i; %i)", width, height);

  if (width != mRaw->dim.x || height != mRaw->dim.y)
    ThrowRDE("EXIF image dimensions do not match dimensions from raw header");

  data = startpump.getStream(startpump.getRemainSize());
}

void SamsungV2Decompressor::decompress() {
  switch (_flags) {
  case OptFlags::NONE:
    for (int row = 0; row < height; row++)
      decompressRow<OptFlags::NONE>(row);
    break;
  case OptFlags::ALL:
    for (int row = 0; row < height; row++)
      decompressRow<OptFlags::ALL>(row);
    break;

  case OptFlags::SKIP:
    for (int row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP>(row);
    break;
  case OptFlags::MV:
    for (int row = 0; row < height; row++)
      decompressRow<OptFlags::MV>(row);
    break;
  case OptFlags::QP:
    for (int row = 0; row < height; row++)
      decompressRow<OptFlags::QP>(row);
    break;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch"
  case OptFlags::SKIP | OptFlags::MV:
    for (int row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP | OptFlags::MV>(row);
    break;
  case OptFlags::SKIP | OptFlags::QP:
    for (int row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP | OptFlags::QP>(row);
    break;

  case OptFlags::MV | OptFlags::QP:
    for (int row = 0; row < height; row++)
      decompressRow<OptFlags::MV | OptFlags::QP>(row);
    break;
#pragma GCC diagnostic pop

  default:
    __builtin_unreachable();
  }
}

// The format is relatively straightforward. Each line gets encoded as a set
// of differences from pixels from another line. Pixels are grouped in blocks
// of 16 (8 green, 8 red or blue). Each block is encoded in three sections.
// First 1 or 4 bits to specify which reference pixels to use, then a section
// that specifies for each pixel the number of bits in the difference, then
// the actual difference bits

template <SamsungV2Decompressor::OptFlags optflags>
inline void SamsungV2Decompressor::prepareBaselineValues(BitPumpMSB32* pump,
                                                         int row, int col) {
  const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());

  if (!(optflags & OptFlags::QP) && !(col & 63)) {
    static constexpr std::array<int32_t, 3> scalevals = {{0, -2, 2}};
    uint32_t i = pump->getBits(2);
    scale = i < 3 ? scale + scalevals[i] : pump->getBits(12);
  }

  // First we figure out which reference pixels mode we're in
  if (optflags & OptFlags::MV)
    motion = pump->getBits(1) ? 3 : 7;
  else if (!pump->getBits(1))
    motion = pump->getBits(3);

  if ((row == 0 || row == 1) && (motion != 7))
    ThrowRDE("At start of image and motion isn't 7. File corrupted?");

  if (motion == 7) {
    // The base case, just set all pixels to the previous ones on the same
    // line If we're at the left edge we just start at the initial value
    for (int i = 0; i < 16; i++)
      out(row, col + i) = (col == 0) ? initVal : out(row, col + i - 2);
  } else {
    // The complex case, we now need to actually lookup one or two lines
    // above
    if (row < 2)
      ThrowRDE(
          "Got a previous line lookup on first two lines. File corrupted?");

    static constexpr std::array<int32_t, 7> motionOffset = {-4, -2, -2, 0,
                                                            0,  2,  4};
    static constexpr std::array<int32_t, 7> motionDoAverage = {0, 0, 1, 0,
                                                               1, 0, 0};

    int32_t slideOffset = motionOffset[motion];
    int32_t doAverage = motionDoAverage[motion];

    for (int i = 0; i < 16; i++) {
      int refRow = row;
      int refCol = col + i + slideOffset;

      if ((row + i) & 1) { // Red or blue pixels use same color two lines up
        refRow -= 2;
      } else { // Green pixel N uses Green pixel N from row above
        refRow -= 1;
        refCol += (i & 1) ? -1 : 1; // (top left or top right)
      }

      if (refCol < 0)
        ThrowRDE("Bad motion %u at the beginning of the row", motion);
      if ((refCol >= width) || (doAverage && (refCol + 2 >= width)))
        ThrowRDE("Bad motion %u at the end of the row", motion);

      // In some cases we use as reference interpolation of this pixel and
      // the next
      if (doAverage) {
        out(row, col + i) =
            (out(refRow, refCol) + out(refRow, refCol + 2) + 1) >> 1;
      } else
        out(row, col + i) = out(refRow, refCol);
    }
  }
}

template <SamsungV2Decompressor::OptFlags optflags>
inline std::array<uint32_t, 4>
SamsungV2Decompressor::decodeDiffLengths(BitPumpMSB32* pump, int row) {
  // Figure out how many difference bits we have to read for each pixel
  std::array<uint32_t, 4> diffBits = {};
  if (optflags & OptFlags::SKIP || !pump->getBits(1)) {
    std::array<uint32_t, 4> flags;
    for (unsigned int& flag : flags)
      flag = pump->getBits(2);

    for (int i = 0; i < 4; i++) {
      // The color is 0-Green 1-Blue 2-Red
      uint32_t colornum = (row % 2 != 0) ? i >> 1 : ((i >> 1) + 2) % 3;

      assert(flags[i] <= 3);
      switch (flags[i]) {
      case 0:
        diffBits[i] = diffBitsMode[colornum][0];
        break;
      case 1:
        diffBits[i] = diffBitsMode[colornum][0] + 1;
        break;
      case 2:
        if (diffBitsMode[colornum][0] == 0)
          ThrowRDE("Difference bits underflow. File corrupted?");
        diffBits[i] = diffBitsMode[colornum][0] - 1;
        break;
      case 3:
        diffBits[i] = pump->getBits(4);
        break;
      default:
        __builtin_unreachable();
      }

      diffBitsMode[colornum][0] = diffBitsMode[colornum][1];
      diffBitsMode[colornum][1] = diffBits[i];

      if (diffBits[i] > bitDepth + 1)
        ThrowRDE("Too many difference bits. File corrupted?");
    }
  }

  return diffBits;
}

template <SamsungV2Decompressor::OptFlags optflags>
inline std::array<int, 16>
SamsungV2Decompressor::decodeDifferences(BitPumpMSB32* pump, int row) {
  std::array<int, 16> diffs;

  // Figure out how many difference bits we have to read for each pixel
  const std::array<uint32_t, 4> diffBits =
      decodeDiffLengths<optflags>(pump, row);

  // Actually read the differences and reshuffle them.
  for (int i = 0; i < 16; i++) {
    uint32_t len = diffBits[i >> 2];
    int32_t diff = getDiff(pump, len);

    int p;
    // The differences are stored interlaced:
    // 0 2 4 6 8 10 12 14 1 3 5 7 9 11 13 15
    if (row % 2)
      p = ((i % 8) << 1) - (i >> 3) + 1;
    else
      p = ((i % 8) << 1) + (i >> 3);

    diffs[p] = diff * (scale * 2 + 1) + scale;
  }

  return diffs;
}

template <SamsungV2Decompressor::OptFlags optflags>
void SamsungV2Decompressor::decompressRow(int row) {
  const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());

  // Align pump to 16byte boundary
  const auto line_offset = data.getPosition();
  if ((line_offset & 0xf) != 0)
    data.skipBytes(16 - (line_offset & 0xf));

  BitPumpMSB32 pump(data);

  // Initialize the motion and diff modes at the start of the line
  motion = 7;
  // By default we are not scaling values at all
  scale = 0;

  for (auto& i : diffBitsMode)
    i[0] = i[1] = (row == 0 || row == 1) ? 7 : 4;

  assert(width >= 16);
  assert(width % 16 == 0);
  for (int col = 0; col < width; col += 16) {
    prepareBaselineValues<optflags>(&pump, row, col);

    // Figure out how many difference bits we have to read for each pixel
    const std::array<int, 16> diffs = decodeDifferences<optflags>(&pump, row);

    // Actually apply the differences and write them to the pixels
    for (int i = 0; i < 16; i++) {
      int diff = diffs[i];

      uint16_t& pixel = out(row, col + i);
      pixel = clampBits(static_cast<int>(pixel) + diff, bits);
    }
  }

  data.skipBytes(pump.getBufferPosition());
}

} // namespace rawspeed
<commit_msg>SamsungV2Decompressor::prepareBaselineValues(): early return<commit_after>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2010 Klaus Post
    Copyright (C) 2014-2015 Pedro Côrte-Real
    Copyright (C) 2017 Roman Lebedev

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

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

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decompressors/SamsungV2Decompressor.h"
#include "common/Common.h"                // for uint32_t, uint16_t, int32_t
#include "common/Point.h"                 // for iPoint2D
#include "common/RawImage.h"              // for RawImage, RawImageData
#include "decoders/RawDecoderException.h" // for ThrowRDE
#include "io/BitPumpMSB32.h"              // for BitPumpMSB32
#include "io/ByteStream.h"                // for ByteStream
#include <algorithm>                      // for max
#include <cassert>                        // for assert
#include <type_traits>                    // for underlying_type, underlyin...

namespace rawspeed {

// Seriously Samsung just use lossless jpeg already, it compresses better too :)

// Thanks to Michael Reichmann (Luminous Landscape) for putting Pedro Côrte-Real
// in contact and Loring von Palleske (Samsung) for pointing to the open-source
// code of Samsung's DNG converter at http://opensource.samsung.com/

enum struct SamsungV2Decompressor::OptFlags : uint32_t {
  NONE = 0U,       // no flags
  SKIP = 1U << 0U, // Skip checking if we need differences from previous line
  MV = 1U << 1U,   // Simplify motion vector definition
  QP = 1U << 2U,   // Don't scale the diff values

  // all possible flags
  ALL = SKIP | MV | QP,
};

constexpr SamsungV2Decompressor::OptFlags
operator|(SamsungV2Decompressor::OptFlags lhs,
          SamsungV2Decompressor::OptFlags rhs) {
  return static_cast<SamsungV2Decompressor::OptFlags>(
      static_cast<std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
          lhs) |
      static_cast<std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
          rhs));
}

constexpr bool operator&(SamsungV2Decompressor::OptFlags lhs,
                         SamsungV2Decompressor::OptFlags rhs) {
  return SamsungV2Decompressor::OptFlags::NONE !=
         static_cast<SamsungV2Decompressor::OptFlags>(
             static_cast<
                 std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
                 lhs) &
             static_cast<
                 std::underlying_type<SamsungV2Decompressor::OptFlags>::type>(
                 rhs));
}

inline int32_t SamsungV2Decompressor::getDiff(BitPumpMSB32* pump,
                                              uint32_t len) {
  if (len == 0)
    return 0;
  int32_t diff = pump->getBits(len);
  // If the first bit is 1 we need to turn this into a negative number
  if (diff >> (len - 1))
    diff -= (1 << len);
  return diff;
}

SamsungV2Decompressor::SamsungV2Decompressor(const RawImage& image,
                                             const ByteStream& bs, int bit)
    : AbstractSamsungDecompressor(image), bits(bit) {
  if (mRaw->getCpp() != 1 || mRaw->getDataType() != TYPE_USHORT16 ||
      mRaw->getBpp() != 2)
    ThrowRDE("Unexpected component count / data type");

  switch (bit) {
  case 12:
  case 14:
    break;
  default:
    ThrowRDE("Unexpected bit per pixel (%u)", bit);
  }

  static constexpr const auto headerSize = 16;
  bs.check(headerSize);

  BitPumpMSB32 startpump(bs);

  // Process the initial metadata bits, we only really use initVal, width and
  // height (the last two match the TIFF values anyway)
  startpump.getBits(16); // NLCVersion
  startpump.getBits(4);  // ImgFormat
  bitDepth = startpump.getBits(4) + 1;
  startpump.getBits(4); // NumBlkInRCUnit
  startpump.getBits(4); // CompressionRatio
  width = startpump.getBits(16);
  height = startpump.getBits(16);
  startpump.getBits(16); // TileWidth
  startpump.getBits(4);  // reserved

  // The format includes an optimization code that sets 3 flags to change the
  // decoding parameters
  const uint32_t optflags = startpump.getBits(4);
  if (optflags > static_cast<uint32_t>(OptFlags::ALL))
    ThrowRDE("Invalid opt flags %x", optflags);
  _flags = static_cast<OptFlags>(optflags);

  startpump.getBits(8); // OverlapWidth
  startpump.getBits(8); // reserved
  startpump.getBits(8); // Inc
  startpump.getBits(2); // reserved
  initVal = startpump.getBits(14);

  assert(startpump.getPosition() == headerSize);

  if (width == 0 || height == 0 || width % 16 != 0 || width > 6496 ||
      height > 4336)
    ThrowRDE("Unexpected image dimensions found: (%i; %i)", width, height);

  if (width != mRaw->dim.x || height != mRaw->dim.y)
    ThrowRDE("EXIF image dimensions do not match dimensions from raw header");

  data = startpump.getStream(startpump.getRemainSize());
}

void SamsungV2Decompressor::decompress() {
  switch (_flags) {
  case OptFlags::NONE:
    for (int row = 0; row < height; row++)
      decompressRow<OptFlags::NONE>(row);
    break;
  case OptFlags::ALL:
    for (int row = 0; row < height; row++)
      decompressRow<OptFlags::ALL>(row);
    break;

  case OptFlags::SKIP:
    for (int row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP>(row);
    break;
  case OptFlags::MV:
    for (int row = 0; row < height; row++)
      decompressRow<OptFlags::MV>(row);
    break;
  case OptFlags::QP:
    for (int row = 0; row < height; row++)
      decompressRow<OptFlags::QP>(row);
    break;

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wswitch"
  case OptFlags::SKIP | OptFlags::MV:
    for (int row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP | OptFlags::MV>(row);
    break;
  case OptFlags::SKIP | OptFlags::QP:
    for (int row = 0; row < height; row++)
      decompressRow<OptFlags::SKIP | OptFlags::QP>(row);
    break;

  case OptFlags::MV | OptFlags::QP:
    for (int row = 0; row < height; row++)
      decompressRow<OptFlags::MV | OptFlags::QP>(row);
    break;
#pragma GCC diagnostic pop

  default:
    __builtin_unreachable();
  }
}

// The format is relatively straightforward. Each line gets encoded as a set
// of differences from pixels from another line. Pixels are grouped in blocks
// of 16 (8 green, 8 red or blue). Each block is encoded in three sections.
// First 1 or 4 bits to specify which reference pixels to use, then a section
// that specifies for each pixel the number of bits in the difference, then
// the actual difference bits

template <SamsungV2Decompressor::OptFlags optflags>
inline void SamsungV2Decompressor::prepareBaselineValues(BitPumpMSB32* pump,
                                                         int row, int col) {
  const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());

  if (!(optflags & OptFlags::QP) && !(col & 63)) {
    static constexpr std::array<int32_t, 3> scalevals = {{0, -2, 2}};
    uint32_t i = pump->getBits(2);
    scale = i < 3 ? scale + scalevals[i] : pump->getBits(12);
  }

  // First we figure out which reference pixels mode we're in
  if (optflags & OptFlags::MV)
    motion = pump->getBits(1) ? 3 : 7;
  else if (!pump->getBits(1))
    motion = pump->getBits(3);

  if ((row == 0 || row == 1) && (motion != 7))
    ThrowRDE("At start of image and motion isn't 7. File corrupted?");

  if (motion == 7) {
    // The base case, just set all pixels to the previous ones on the same
    // line If we're at the left edge we just start at the initial value
    for (int i = 0; i < 16; i++)
      out(row, col + i) = (col == 0) ? initVal : out(row, col + i - 2);
    return;
  }

  // The complex case, we now need to actually lookup one or two lines above
  if (row < 2)
    ThrowRDE("Got a previous line lookup on first two lines. File corrupted?");

  static constexpr std::array<int32_t, 7> motionOffset = {-4, -2, -2, 0,
                                                          0,  2,  4};
  static constexpr std::array<int32_t, 7> motionDoAverage = {0, 0, 1, 0,
                                                             1, 0, 0};

  int32_t slideOffset = motionOffset[motion];
  int32_t doAverage = motionDoAverage[motion];

  for (int i = 0; i < 16; i++) {
    int refRow = row;
    int refCol = col + i + slideOffset;

    if ((row + i) & 1) { // Red or blue pixels use same color two lines up
      refRow -= 2;
    } else { // Green pixel N uses Green pixel N from row above
      refRow -= 1;
      refCol += (i & 1) ? -1 : 1; // (top left or top right)
    }

    if (refCol < 0)
      ThrowRDE("Bad motion %u at the beginning of the row", motion);
    if ((refCol >= width) || (doAverage && (refCol + 2 >= width)))
      ThrowRDE("Bad motion %u at the end of the row", motion);

    // In some cases we use as reference interpolation of this pixel and
    // the next
    if (doAverage) {
      out(row, col + i) =
          (out(refRow, refCol) + out(refRow, refCol + 2) + 1) >> 1;
    } else
      out(row, col + i) = out(refRow, refCol);
  }
}

template <SamsungV2Decompressor::OptFlags optflags>
inline std::array<uint32_t, 4>
SamsungV2Decompressor::decodeDiffLengths(BitPumpMSB32* pump, int row) {
  // Figure out how many difference bits we have to read for each pixel
  std::array<uint32_t, 4> diffBits = {};
  if (optflags & OptFlags::SKIP || !pump->getBits(1)) {
    std::array<uint32_t, 4> flags;
    for (unsigned int& flag : flags)
      flag = pump->getBits(2);

    for (int i = 0; i < 4; i++) {
      // The color is 0-Green 1-Blue 2-Red
      uint32_t colornum = (row % 2 != 0) ? i >> 1 : ((i >> 1) + 2) % 3;

      assert(flags[i] <= 3);
      switch (flags[i]) {
      case 0:
        diffBits[i] = diffBitsMode[colornum][0];
        break;
      case 1:
        diffBits[i] = diffBitsMode[colornum][0] + 1;
        break;
      case 2:
        if (diffBitsMode[colornum][0] == 0)
          ThrowRDE("Difference bits underflow. File corrupted?");
        diffBits[i] = diffBitsMode[colornum][0] - 1;
        break;
      case 3:
        diffBits[i] = pump->getBits(4);
        break;
      default:
        __builtin_unreachable();
      }

      diffBitsMode[colornum][0] = diffBitsMode[colornum][1];
      diffBitsMode[colornum][1] = diffBits[i];

      if (diffBits[i] > bitDepth + 1)
        ThrowRDE("Too many difference bits. File corrupted?");
    }
  }

  return diffBits;
}

template <SamsungV2Decompressor::OptFlags optflags>
inline std::array<int, 16>
SamsungV2Decompressor::decodeDifferences(BitPumpMSB32* pump, int row) {
  std::array<int, 16> diffs;

  // Figure out how many difference bits we have to read for each pixel
  const std::array<uint32_t, 4> diffBits =
      decodeDiffLengths<optflags>(pump, row);

  // Actually read the differences and reshuffle them.
  for (int i = 0; i < 16; i++) {
    uint32_t len = diffBits[i >> 2];
    int32_t diff = getDiff(pump, len);

    int p;
    // The differences are stored interlaced:
    // 0 2 4 6 8 10 12 14 1 3 5 7 9 11 13 15
    if (row % 2)
      p = ((i % 8) << 1) - (i >> 3) + 1;
    else
      p = ((i % 8) << 1) + (i >> 3);

    diffs[p] = diff * (scale * 2 + 1) + scale;
  }

  return diffs;
}

template <SamsungV2Decompressor::OptFlags optflags>
void SamsungV2Decompressor::decompressRow(int row) {
  const Array2DRef<uint16_t> out(mRaw->getU16DataAsUncroppedArray2DRef());

  // Align pump to 16byte boundary
  const auto line_offset = data.getPosition();
  if ((line_offset & 0xf) != 0)
    data.skipBytes(16 - (line_offset & 0xf));

  BitPumpMSB32 pump(data);

  // Initialize the motion and diff modes at the start of the line
  motion = 7;
  // By default we are not scaling values at all
  scale = 0;

  for (auto& i : diffBitsMode)
    i[0] = i[1] = (row == 0 || row == 1) ? 7 : 4;

  assert(width >= 16);
  assert(width % 16 == 0);
  for (int col = 0; col < width; col += 16) {
    prepareBaselineValues<optflags>(&pump, row, col);

    // Figure out how many difference bits we have to read for each pixel
    const std::array<int, 16> diffs = decodeDifferences<optflags>(&pump, row);

    // Actually apply the differences and write them to the pixels
    for (int i = 0; i < 16; i++) {
      int diff = diffs[i];

      uint16_t& pixel = out(row, col + i);
      pixel = clampBits(static_cast<int>(pixel) + diff, bits);
    }
  }

  data.skipBytes(pump.getBufferPosition());
}

} // namespace rawspeed
<|endoftext|>


<commit_before>//! \file
/*
**  Copyright (C) - Triton
**
**  This program is under the terms of the LGPLv3 License.
*/

#ifdef TRITON_PYTHON_BINDINGS

#include <api.hpp>
#include <pythonObjects.hpp>
#include <pythonUtils.hpp>
#include <pythonXFunctions.hpp>

/*! \page py_Instruction_page Instruction
    \brief [**python api**] All information about the Instruction python object.

\tableofcontents

\section py_Instruction_description Description

This object is used to represent an Instruction.

~~~~~~~~~~~~~{.py}
import  sys
from    triton import *

trace = [
    (0x400000, "\x48\x8b\x05\xb8\x13\x00\x00"), # mov        rax, QWORD PTR [rip+0x13b8]
    (0x400007, "\x48\x8d\x34\xc3"),             # lea        rsi, [rbx+rax*8]
    (0x40000b, "\x67\x48\x8D\x74\xC3\x0A"),     # lea        rsi, [ebx+eax*8+0xa]
    (0x400011, "\x66\x0F\xD7\xD1"),             # pmovmskb   edx, xmm1
    (0x400015, "\x89\xd0"),                     # mov        eax, edx
    (0x400017, "\x80\xf4\x99"),                 # xor        ah, 0x99
]

if __name__ == '__main__':

    #Set the arch
    setArchitecture(ARCH.X86_64)

    for (addr, opcodes) in trace:

        # Build an instruction
        inst = Instruction()

        # Setup opcodes
        inst.setOpcodes(opcodes)

        # Setup Address
        inst.setAddress(addr)

        # optional - Update register state
        inst.updateContext(Register(REG.RAX, 0x4444444455555555));
        inst.updateContext(Register(REG.RBX, 0x1111111122222222));

        # optional - Add memory access <addr, size, content>
        inst.updateContext(Memory(0x66666666, 4, 0x31323334));

        # Process everything
        processing(inst)

        print inst
        for op in inst.getOperands():
            print '\t', op
            if op.getType() == OPERAND.MEM:
                print '\t\t base  : ', op.getBaseReg()
                print '\t\t index : ', op.getIndexReg()
                print '\t\t disp  : ', op.getDisplacement()
                print '\t\t scale : ', op.getScale()
        print

    sys.exit(0)
~~~~~~~~~~~~~

\section Instruction_py_api Python API - Methods of the Instruction class

- **getAddress(void)**

Returns the instruction's address as integer.

- **getDisassembly(void)**

Returns the instruction's disassembly as string.

- **getNextAddress(void)**

Returns the next instruction's address as integer.

- **getOpcodes(void)**

Returns the instruction's opcodes as bytes.

- **getOpcodesSize(void)**

Returns the instruction's opcodes size as integer.

- **getOperands(void)**

Returns the instruction's operands as list of \ref py_Immediate_page, \ref py_Memory_page or \ref py_Register_page.

- **getSymbolicExpressions(void)**

Returns the instruction's symbolic expressions as list of \ref py_SymbolicExpression_page.

- **getThreadId(void)**

Returns the instruction's thread id as integer.

- **getType(void)**

Returns the instruction's type as \ref py_OPCODE_page.

- **isBranch(void)**

Returns true if the instruction modifies is a branch (i.e x86: JUMP, JCC).

- **isConditionTaken(void)**

Returns true if the condition is taken (i.e x86: JCC, CMOVCC, SETCC, ...).

- **isControlFlow(void)**

Returns true if the instruction modifies the control flow (i.e x86: JUMP, JCC, CALL, RET).

- **isTainted(void)**

Returns true if at least one of its expressions is tainted.

- **setAddress(integer addr)**

Sets the instruction's address.

- **setOpcodes(bytes opcodes, integer size)**

Sets the instruction's opcodes.

- **setThreadId(integer tid)**

Sets the instruction's thread id.

- **updateContext(\ref py_Memory_page memCtx)**

Updates the instruction's context by adding a concrete value for a **LOAD** memory access. Please note that you don't have to define a **STORE**
concrete value, this value will be computed symbolically - **Only LOAD** accesses are necessary.

- **updateContext(\ref py_Register_page regCtx)**

Updates the instruction's context by adding a concrete value for a specific register. Be careful you cannot update the context on a flag.

*/

namespace triton {
  namespace bindings {
    namespace python {

      //! Instruction's Destructor.
      void Instruction_dealloc(PyObject* self) {
        delete PyInstruction_AsInstruction(self);
        Py_DECREF(self);
      }

      static PyObject* Instruction_getAddress(PyObject* self, PyObject* noarg) {
        return PyLong_FromUint(PyInstruction_AsInstruction(self)->getAddress());
      }

      static PyObject* Instruction_getDisassembly(PyObject* self, PyObject* noarg) {
        return PyString_FromFormat("%s", PyInstruction_AsInstruction(self)->getDisassembly().c_str());
      }

      static PyObject* Instruction_getNextAddress(PyObject* self, PyObject* noarg) {
        return PyLong_FromUint(PyInstruction_AsInstruction(self)->getNextAddress());
      }

      static PyObject* Instruction_getOpcodes(PyObject* self, PyObject* noarg) {
        const triton::uint8* opcodes = PyInstruction_AsInstruction(self)->getOpcodes();
        triton::uint32 size          = PyInstruction_AsInstruction(self)->getOpcodesSize();
        return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(opcodes), size);
      }

      static PyObject* Instruction_getOpcodesSize(PyObject* self, PyObject* noarg) {
        return Py_BuildValue("k", PyInstruction_AsInstruction(self)->getOpcodesSize());
      }

      static PyObject* Instruction_getOperands(PyObject* self, PyObject* noarg) {
        triton::arch::ImmediateOperand  imm;
        triton::arch::MemoryOperand     mem;
        triton::arch::RegisterOperand   reg;
        triton::arch::Instruction*      inst;
        triton::uint32                  opSize;
        PyObject*                       operands;

        inst     = PyInstruction_AsInstruction(self);
        opSize   = inst->operands.size();
        operands = xPyList_New(opSize);

        for (triton::uint32 index = 0; index < opSize; index++) {
          PyObject* obj = nullptr;

          if (inst->operands[index].getType() == triton::arch::OP_IMM) {
            imm = inst->operands[index].getImm();
            obj = PyImmediateOperand(imm);
          }
          else if (inst->operands[index].getType() == triton::arch::OP_MEM) {
            mem = inst->operands[index].getMem();
            obj = PyMemoryOperand(mem);
          }
          else if (inst->operands[index].getType() == triton::arch::OP_REG) {
            reg = inst->operands[index].getReg();
            obj = PyRegisterOperand(reg);
          }
          else
            continue;

          PyList_SetItem(operands, index, obj);
        }

        return operands;
      }

      static PyObject* Instruction_getSymbolicExpressions(PyObject* self, PyObject* noarg) {
        triton::arch::Instruction*  inst;
        triton::uint32              exprSize;
        PyObject*                   symExprs;

        inst     = PyInstruction_AsInstruction(self);
        exprSize = inst->symbolicExpressions.size();
        symExprs = xPyList_New(exprSize);

        for (triton::uint32 index = 0; index < exprSize; index++) {
          PyObject* obj = nullptr;
          obj = PySymbolicExpression(inst->symbolicExpressions[index]);
          PyList_SetItem(symExprs, index, obj);
        }

        return symExprs;
      }

      static PyObject* Instruction_getThreadId(PyObject* self, PyObject* noarg) {
        return Py_BuildValue("k", PyInstruction_AsInstruction(self)->getThreadId());
      }

      static PyObject* Instruction_getType(PyObject* self, PyObject* noarg) {
        return Py_BuildValue("k", PyInstruction_AsInstruction(self)->getType());
      }

      static PyObject* Instruction_isBranch(PyObject* self, PyObject* noarg) {
        if (PyInstruction_AsInstruction(self)->isBranch() == true)
          Py_RETURN_TRUE;
        Py_RETURN_FALSE;
      }

      static PyObject* Instruction_isConditionTaken(PyObject* self, PyObject* noarg) {
        if (PyInstruction_AsInstruction(self)->isConditionTaken() == true)
          Py_RETURN_TRUE;
        Py_RETURN_FALSE;
      }

      static PyObject* Instruction_isControlFlow(PyObject* self, PyObject* noarg) {
        if (PyInstruction_AsInstruction(self)->isControlFlow() == true)
          Py_RETURN_TRUE;
        Py_RETURN_FALSE;
      }

      static PyObject* Instruction_isTainted(PyObject* self, PyObject* noarg) {
        if (PyInstruction_AsInstruction(self)->isTainted() == true)
          Py_RETURN_TRUE;
        Py_RETURN_FALSE;
      }

      static PyObject* Instruction_setAddress(PyObject* self, PyObject* addr) {
        if (!PyLong_Check(addr) && !PyInt_Check(addr))
          return PyErr_Format(PyExc_TypeError, "setAddress(): expected an integer as argument");
        PyInstruction_AsInstruction(self)->setAddress(PyLong_AsUint(addr));
        Py_INCREF(Py_None);
        return Py_None;
      }

      static PyObject* Instruction_setOpcodes(PyObject* self, PyObject* opc) {

        if (!PyBytes_Check(opc))
          return PyErr_Format(PyExc_TypeError, "setOpcodes(): expected a bytes array as argument");

        if (PyBytes_Size(opc) >= 32)
          return PyErr_Format(PyExc_TypeError, "setOpcodes(): Invalid size (too big)");

        PyInstruction_AsInstruction(self)->setOpcodes(reinterpret_cast<triton::uint8*>(PyBytes_AsString(opc)), PyBytes_Size(opc));
        Py_INCREF(Py_None);
        return Py_None;
      }

      static PyObject* Instruction_setThreadId(PyObject* self, PyObject* tid) {

        if (!PyLong_Check(tid) && !PyInt_Check(tid))
          return PyErr_Format(PyExc_TypeError, "setThreadId(): expected an integer as argument");

        PyInstruction_AsInstruction(self)->setThreadId(PyLong_AsUint(tid));
        Py_INCREF(Py_None);
        return Py_None;
      }

      static PyObject* Instruction_updateContext(PyObject* self, PyObject* ctx) {
        triton::arch::Instruction*     inst;
        triton::arch::MemoryOperand*   memCtx;
        triton::arch::RegisterOperand* regCtx;

        if (!PyMemoryOperand_Check(ctx) && !PyRegisterOperand_Check(ctx))
          return PyErr_Format(PyExc_TypeError, "updateContext(): expected a Memory or Register as argument");

        inst = PyInstruction_AsInstruction(self);

        if (PyMemoryOperand_Check(ctx)) {
          memCtx = PyMemoryOperand_AsMemoryOperand(ctx);
          inst->updateContext(*memCtx);
        }

        else if (PyRegisterOperand_Check(ctx)) {
          regCtx = PyRegisterOperand_AsRegisterOperand(ctx);
          if (regCtx->isFlag())
            return PyErr_Format(PyExc_TypeError, "updateContext(): You cannot update the context on an isolated flag.");
          inst->updateContext(*regCtx);
        }

        Py_INCREF(Py_None);
        return Py_None;
      }

      static PyObject* Instruction_str(Instruction_Object *obj) {
        std::stringstream str;
        str << *(obj->inst);
        return PyString_FromFormat("%s", str.str().c_str());
      }

      //! Instruction's methods.
      PyMethodDef Instruction_callbacks[] = {
        {"getAddress",                Instruction_getAddress,               METH_NOARGS,     ""},
        {"getDisassembly",            Instruction_getDisassembly,           METH_NOARGS,     ""},
        {"getNextAddress",            Instruction_getNextAddress,           METH_NOARGS,     ""},
        {"getOpcodes",                Instruction_getOpcodes,               METH_NOARGS,     ""},
        {"getOpcodesSize",            Instruction_getOpcodesSize,           METH_NOARGS,     ""},
        {"getOperands",               Instruction_getOperands,              METH_NOARGS,     ""},
        {"getSymbolicExpressions",    Instruction_getSymbolicExpressions,   METH_NOARGS,     ""},
        {"getThreadId",               Instruction_getThreadId,              METH_NOARGS,     ""},
        {"getType",                   Instruction_getType,                  METH_NOARGS,     ""},
        {"isBranch",                  Instruction_isBranch,                 METH_NOARGS,     ""},
        {"isConditionTaken",          Instruction_isConditionTaken,         METH_NOARGS,     ""},
        {"isControlFlow",             Instruction_isControlFlow,            METH_NOARGS,     ""},
        {"isTainted",                 Instruction_isTainted,                METH_NOARGS,     ""},
        {"setAddress",                Instruction_setAddress,               METH_O,          ""},
        {"setOpcodes",                Instruction_setOpcodes,               METH_O,          ""},
        {"setThreadId",               Instruction_setThreadId,              METH_O,          ""},
        {"updateContext",             Instruction_updateContext,            METH_O,          ""},
        {nullptr,                     nullptr,                              0,               nullptr}
      };

      PyTypeObject Instruction_Type = {
          PyObject_HEAD_INIT(&PyType_Type)
          0,                                          /* ob_size*/
          "Instruction",                              /* tp_name*/
          sizeof(Instruction_Object),                 /* tp_basicsize*/
          0,                                          /* tp_itemsize*/
          (destructor)Instruction_dealloc,            /* tp_dealloc*/
          0,                                          /* tp_print*/
          0,                                          /* tp_getattr*/
          0,                                          /* tp_setattr*/
          0,                                          /* tp_compare*/
          0,                                          /* tp_repr*/
          0,                                          /* tp_as_number*/
          0,                                          /* tp_as_sequence*/
          0,                                          /* tp_as_mapping*/
          0,                                          /* tp_hash */
          0,                                          /* tp_call*/
          (reprfunc)Instruction_str,                  /* tp_str*/
          0,                                          /* tp_getattro*/
          0,                                          /* tp_setattro*/
          0,                                          /* tp_as_buffer*/
          Py_TPFLAGS_DEFAULT,                         /* tp_flags*/
          "Instruction objects",                      /* tp_doc */
          0,                                          /* tp_traverse */
          0,                                          /* tp_clear */
          0,                                          /* tp_richcompare */
          0,                                          /* tp_weaklistoffset */
          0,                                          /* tp_iter */
          0,                                          /* tp_iternext */
          Instruction_callbacks,                      /* tp_methods */
          0,                                          /* tp_members */
          0,                                          /* tp_getset */
          0,                                          /* tp_base */
          0,                                          /* tp_dict */
          0,                                          /* tp_descr_get */
          0,                                          /* tp_descr_set */
          0,                                          /* tp_dictoffset */
          0,                                          /* tp_init */
          0,                                          /* tp_alloc */
          0,                                          /* tp_new */
      };

      PyObject* PyInstruction(void) {
        Instruction_Object *object;

        PyType_Ready(&Instruction_Type);
        object = PyObject_NEW(Instruction_Object, &Instruction_Type);
        if (object != NULL)
          object->inst = new triton::arch::Instruction();

        return (PyObject* )object;
      }

      PyObject* PyInstruction(triton::arch::Instruction &inst) {
        Instruction_Object *object;

        PyType_Ready(&Instruction_Type);
        object = PyObject_NEW(Instruction_Object, &Instruction_Type);
        if (object != NULL)
          object->inst = new triton::arch::Instruction(inst);

        return (PyObject* )object;
      }

    }; /* python namespace */
  }; /* bindings namespace */
}; /* triton namespace */

#endif /* TRITON_PYTHON_BINDINGS */
<commit_msg>Update doc<commit_after>//! \file
/*
**  Copyright (C) - Triton
**
**  This program is under the terms of the LGPLv3 License.
*/

#ifdef TRITON_PYTHON_BINDINGS

#include <api.hpp>
#include <pythonObjects.hpp>
#include <pythonUtils.hpp>
#include <pythonXFunctions.hpp>

/*! \page py_Instruction_page Instruction
    \brief [**python api**] All information about the Instruction python object.

\tableofcontents

\section py_Instruction_description Description

This object is used to represent an Instruction.

~~~~~~~~~~~~~{.py}
import  sys
from    triton import *

trace = [
    (0x400000, "\x48\x8b\x05\xb8\x13\x00\x00"), # mov        rax, QWORD PTR [rip+0x13b8]
    (0x400007, "\x48\x8d\x34\xc3"),             # lea        rsi, [rbx+rax*8]
    (0x40000b, "\x67\x48\x8D\x74\xC3\x0A"),     # lea        rsi, [ebx+eax*8+0xa]
    (0x400011, "\x66\x0F\xD7\xD1"),             # pmovmskb   edx, xmm1
    (0x400015, "\x89\xd0"),                     # mov        eax, edx
    (0x400017, "\x80\xf4\x99"),                 # xor        ah, 0x99
]

if __name__ == '__main__':

    #Set the arch
    setArchitecture(ARCH.X86_64)

    for (addr, opcodes) in trace:

        # Build an instruction
        inst = Instruction()

        # Setup opcodes
        inst.setOpcodes(opcodes)

        # Setup Address
        inst.setAddress(addr)

        # optional - Update register state
        inst.updateContext(Register(REG.RAX, 0x4444444455555555));
        inst.updateContext(Register(REG.RBX, 0x1111111122222222));

        # optional - Add memory access <addr, size, content>
        inst.updateContext(Memory(0x66666666, 4, 0x31323334));

        # Process everything
        processing(inst)

        print inst
        for op in inst.getOperands():
            print '\t', op
            if op.getType() == OPERAND.MEM:
                print '\t\t base  : ', op.getBaseReg()
                print '\t\t index : ', op.getIndexReg()
                print '\t\t disp  : ', op.getDisplacement()
                print '\t\t scale : ', op.getScale()
        print

    sys.exit(0)
~~~~~~~~~~~~~

\section Instruction_py_api Python API - Methods of the Instruction class

- **getAddress(void)**

Returns the instruction's address as integer.

- **getDisassembly(void)**

Returns the instruction's disassembly as string.

- **getNextAddress(void)**

Returns the next instruction's address as integer.

- **getOpcodes(void)**

Returns the instruction's opcodes as bytes.

- **getOpcodesSize(void)**

Returns the instruction's opcodes size as integer.

- **getOperands(void)**

Returns the instruction's operands as list of \ref py_Immediate_page, \ref py_Memory_page or \ref py_Register_page.

- **getSymbolicExpressions(void)**

Returns the instruction's symbolic expressions as list of \ref py_SymbolicExpression_page.

- **getThreadId(void)**

Returns the instruction's thread id as integer.

- **getType(void)**

Returns the instruction's type as \ref py_OPCODE_page.

- **isBranch(void)**

Returns true if the instruction modifies is a branch (i.e x86: JUMP, JCC).

- **isConditionTaken(void)**

Returns true if the condition is taken (i.e x86: JCC, CMOVCC, SETCC, ...).

- **isControlFlow(void)**

Returns true if the instruction modifies the control flow (i.e x86: JUMP, JCC, CALL, RET).

- **isTainted(void)**

Returns true if at least one of its \ref py_SymbolicExpression_page is tainted.

- **setAddress(integer addr)**

Sets the instruction's address.

- **setOpcodes(bytes opcodes, integer size)**

Sets the instruction's opcodes.

- **setThreadId(integer tid)**

Sets the instruction's thread id.

- **updateContext(\ref py_Memory_page memCtx)**

Updates the instruction's context by adding a concrete value for a **LOAD** memory access. Please note that you don't have to define a **STORE**
concrete value, this value will be computed symbolically - **Only LOAD** accesses are necessary.

- **updateContext(\ref py_Register_page regCtx)**

Updates the instruction's context by adding a concrete value for a specific register. Be careful you cannot update the context on a flag.

*/

namespace triton {
  namespace bindings {
    namespace python {

      //! Instruction's Destructor.
      void Instruction_dealloc(PyObject* self) {
        delete PyInstruction_AsInstruction(self);
        Py_DECREF(self);
      }

      static PyObject* Instruction_getAddress(PyObject* self, PyObject* noarg) {
        return PyLong_FromUint(PyInstruction_AsInstruction(self)->getAddress());
      }

      static PyObject* Instruction_getDisassembly(PyObject* self, PyObject* noarg) {
        return PyString_FromFormat("%s", PyInstruction_AsInstruction(self)->getDisassembly().c_str());
      }

      static PyObject* Instruction_getNextAddress(PyObject* self, PyObject* noarg) {
        return PyLong_FromUint(PyInstruction_AsInstruction(self)->getNextAddress());
      }

      static PyObject* Instruction_getOpcodes(PyObject* self, PyObject* noarg) {
        const triton::uint8* opcodes = PyInstruction_AsInstruction(self)->getOpcodes();
        triton::uint32 size          = PyInstruction_AsInstruction(self)->getOpcodesSize();
        return PyBytes_FromStringAndSize(reinterpret_cast<const char*>(opcodes), size);
      }

      static PyObject* Instruction_getOpcodesSize(PyObject* self, PyObject* noarg) {
        return Py_BuildValue("k", PyInstruction_AsInstruction(self)->getOpcodesSize());
      }

      static PyObject* Instruction_getOperands(PyObject* self, PyObject* noarg) {
        triton::arch::ImmediateOperand  imm;
        triton::arch::MemoryOperand     mem;
        triton::arch::RegisterOperand   reg;
        triton::arch::Instruction*      inst;
        triton::uint32                  opSize;
        PyObject*                       operands;

        inst     = PyInstruction_AsInstruction(self);
        opSize   = inst->operands.size();
        operands = xPyList_New(opSize);

        for (triton::uint32 index = 0; index < opSize; index++) {
          PyObject* obj = nullptr;

          if (inst->operands[index].getType() == triton::arch::OP_IMM) {
            imm = inst->operands[index].getImm();
            obj = PyImmediateOperand(imm);
          }
          else if (inst->operands[index].getType() == triton::arch::OP_MEM) {
            mem = inst->operands[index].getMem();
            obj = PyMemoryOperand(mem);
          }
          else if (inst->operands[index].getType() == triton::arch::OP_REG) {
            reg = inst->operands[index].getReg();
            obj = PyRegisterOperand(reg);
          }
          else
            continue;

          PyList_SetItem(operands, index, obj);
        }

        return operands;
      }

      static PyObject* Instruction_getSymbolicExpressions(PyObject* self, PyObject* noarg) {
        triton::arch::Instruction*  inst;
        triton::uint32              exprSize;
        PyObject*                   symExprs;

        inst     = PyInstruction_AsInstruction(self);
        exprSize = inst->symbolicExpressions.size();
        symExprs = xPyList_New(exprSize);

        for (triton::uint32 index = 0; index < exprSize; index++) {
          PyObject* obj = nullptr;
          obj = PySymbolicExpression(inst->symbolicExpressions[index]);
          PyList_SetItem(symExprs, index, obj);
        }

        return symExprs;
      }

      static PyObject* Instruction_getThreadId(PyObject* self, PyObject* noarg) {
        return Py_BuildValue("k", PyInstruction_AsInstruction(self)->getThreadId());
      }

      static PyObject* Instruction_getType(PyObject* self, PyObject* noarg) {
        return Py_BuildValue("k", PyInstruction_AsInstruction(self)->getType());
      }

      static PyObject* Instruction_isBranch(PyObject* self, PyObject* noarg) {
        if (PyInstruction_AsInstruction(self)->isBranch() == true)
          Py_RETURN_TRUE;
        Py_RETURN_FALSE;
      }

      static PyObject* Instruction_isConditionTaken(PyObject* self, PyObject* noarg) {
        if (PyInstruction_AsInstruction(self)->isConditionTaken() == true)
          Py_RETURN_TRUE;
        Py_RETURN_FALSE;
      }

      static PyObject* Instruction_isControlFlow(PyObject* self, PyObject* noarg) {
        if (PyInstruction_AsInstruction(self)->isControlFlow() == true)
          Py_RETURN_TRUE;
        Py_RETURN_FALSE;
      }

      static PyObject* Instruction_isTainted(PyObject* self, PyObject* noarg) {
        if (PyInstruction_AsInstruction(self)->isTainted() == true)
          Py_RETURN_TRUE;
        Py_RETURN_FALSE;
      }

      static PyObject* Instruction_setAddress(PyObject* self, PyObject* addr) {
        if (!PyLong_Check(addr) && !PyInt_Check(addr))
          return PyErr_Format(PyExc_TypeError, "setAddress(): expected an integer as argument");
        PyInstruction_AsInstruction(self)->setAddress(PyLong_AsUint(addr));
        Py_INCREF(Py_None);
        return Py_None;
      }

      static PyObject* Instruction_setOpcodes(PyObject* self, PyObject* opc) {

        if (!PyBytes_Check(opc))
          return PyErr_Format(PyExc_TypeError, "setOpcodes(): expected a bytes array as argument");

        if (PyBytes_Size(opc) >= 32)
          return PyErr_Format(PyExc_TypeError, "setOpcodes(): Invalid size (too big)");

        PyInstruction_AsInstruction(self)->setOpcodes(reinterpret_cast<triton::uint8*>(PyBytes_AsString(opc)), PyBytes_Size(opc));
        Py_INCREF(Py_None);
        return Py_None;
      }

      static PyObject* Instruction_setThreadId(PyObject* self, PyObject* tid) {

        if (!PyLong_Check(tid) && !PyInt_Check(tid))
          return PyErr_Format(PyExc_TypeError, "setThreadId(): expected an integer as argument");

        PyInstruction_AsInstruction(self)->setThreadId(PyLong_AsUint(tid));
        Py_INCREF(Py_None);
        return Py_None;
      }

      static PyObject* Instruction_updateContext(PyObject* self, PyObject* ctx) {
        triton::arch::Instruction*     inst;
        triton::arch::MemoryOperand*   memCtx;
        triton::arch::RegisterOperand* regCtx;

        if (!PyMemoryOperand_Check(ctx) && !PyRegisterOperand_Check(ctx))
          return PyErr_Format(PyExc_TypeError, "updateContext(): expected a Memory or Register as argument");

        inst = PyInstruction_AsInstruction(self);

        if (PyMemoryOperand_Check(ctx)) {
          memCtx = PyMemoryOperand_AsMemoryOperand(ctx);
          inst->updateContext(*memCtx);
        }

        else if (PyRegisterOperand_Check(ctx)) {
          regCtx = PyRegisterOperand_AsRegisterOperand(ctx);
          if (regCtx->isFlag())
            return PyErr_Format(PyExc_TypeError, "updateContext(): You cannot update the context on an isolated flag.");
          inst->updateContext(*regCtx);
        }

        Py_INCREF(Py_None);
        return Py_None;
      }

      static PyObject* Instruction_str(Instruction_Object *obj) {
        std::stringstream str;
        str << *(obj->inst);
        return PyString_FromFormat("%s", str.str().c_str());
      }

      //! Instruction's methods.
      PyMethodDef Instruction_callbacks[] = {
        {"getAddress",                Instruction_getAddress,               METH_NOARGS,     ""},
        {"getDisassembly",            Instruction_getDisassembly,           METH_NOARGS,     ""},
        {"getNextAddress",            Instruction_getNextAddress,           METH_NOARGS,     ""},
        {"getOpcodes",                Instruction_getOpcodes,               METH_NOARGS,     ""},
        {"getOpcodesSize",            Instruction_getOpcodesSize,           METH_NOARGS,     ""},
        {"getOperands",               Instruction_getOperands,              METH_NOARGS,     ""},
        {"getSymbolicExpressions",    Instruction_getSymbolicExpressions,   METH_NOARGS,     ""},
        {"getThreadId",               Instruction_getThreadId,              METH_NOARGS,     ""},
        {"getType",                   Instruction_getType,                  METH_NOARGS,     ""},
        {"isBranch",                  Instruction_isBranch,                 METH_NOARGS,     ""},
        {"isConditionTaken",          Instruction_isConditionTaken,         METH_NOARGS,     ""},
        {"isControlFlow",             Instruction_isControlFlow,            METH_NOARGS,     ""},
        {"isTainted",                 Instruction_isTainted,                METH_NOARGS,     ""},
        {"setAddress",                Instruction_setAddress,               METH_O,          ""},
        {"setOpcodes",                Instruction_setOpcodes,               METH_O,          ""},
        {"setThreadId",               Instruction_setThreadId,              METH_O,          ""},
        {"updateContext",             Instruction_updateContext,            METH_O,          ""},
        {nullptr,                     nullptr,                              0,               nullptr}
      };

      PyTypeObject Instruction_Type = {
          PyObject_HEAD_INIT(&PyType_Type)
          0,                                          /* ob_size*/
          "Instruction",                              /* tp_name*/
          sizeof(Instruction_Object),                 /* tp_basicsize*/
          0,                                          /* tp_itemsize*/
          (destructor)Instruction_dealloc,            /* tp_dealloc*/
          0,                                          /* tp_print*/
          0,                                          /* tp_getattr*/
          0,                                          /* tp_setattr*/
          0,                                          /* tp_compare*/
          0,                                          /* tp_repr*/
          0,                                          /* tp_as_number*/
          0,                                          /* tp_as_sequence*/
          0,                                          /* tp_as_mapping*/
          0,                                          /* tp_hash */
          0,                                          /* tp_call*/
          (reprfunc)Instruction_str,                  /* tp_str*/
          0,                                          /* tp_getattro*/
          0,                                          /* tp_setattro*/
          0,                                          /* tp_as_buffer*/
          Py_TPFLAGS_DEFAULT,                         /* tp_flags*/
          "Instruction objects",                      /* tp_doc */
          0,                                          /* tp_traverse */
          0,                                          /* tp_clear */
          0,                                          /* tp_richcompare */
          0,                                          /* tp_weaklistoffset */
          0,                                          /* tp_iter */
          0,                                          /* tp_iternext */
          Instruction_callbacks,                      /* tp_methods */
          0,                                          /* tp_members */
          0,                                          /* tp_getset */
          0,                                          /* tp_base */
          0,                                          /* tp_dict */
          0,                                          /* tp_descr_get */
          0,                                          /* tp_descr_set */
          0,                                          /* tp_dictoffset */
          0,                                          /* tp_init */
          0,                                          /* tp_alloc */
          0,                                          /* tp_new */
      };

      PyObject* PyInstruction(void) {
        Instruction_Object *object;

        PyType_Ready(&Instruction_Type);
        object = PyObject_NEW(Instruction_Object, &Instruction_Type);
        if (object != NULL)
          object->inst = new triton::arch::Instruction();

        return (PyObject* )object;
      }

      PyObject* PyInstruction(triton::arch::Instruction &inst) {
        Instruction_Object *object;

        PyType_Ready(&Instruction_Type);
        object = PyObject_NEW(Instruction_Object, &Instruction_Type);
        if (object != NULL)
          object->inst = new triton::arch::Instruction(inst);

        return (PyObject* )object;
      }

    }; /* python namespace */
  }; /* bindings namespace */
}; /* triton namespace */

#endif /* TRITON_PYTHON_BINDINGS */
<|endoftext|>


<commit_before>/// @file
/// @version 3.3
///
/// @section LICENSE
///
/// This program is free software; you can redistribute it and/or modify it under
/// the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause

#include <hltypes/hlog.h>
#include <hltypes/hstream.h>
#include <hltypes/hstring.h>
#include <hltypes/hresource.h>

#include "AudioManager.h"
#include "Source.h"
#include "xal.h"

namespace xal
{
	Source::Source(chstr filename, SourceMode sourceMode, BufferMode bufferMode) : streamOpen(false),
		size(0), channels(2), samplingRate(44100), bitsPerSample(16), duration(0.0f), stream(NULL)
	{
		this->filename = filename;
		this->sourceMode = sourceMode;
		this->bufferMode = bufferMode;
	}

	Source::~Source()
	{
		if (this->stream != NULL)
		{
			delete this->stream;
		}
	}

	int Source::getRamSize()
	{
		if (this->sourceMode == RAM && this->stream != NULL)
		{
			return this->stream->size();
		}
		return 0;
	}

	bool Source::open()
	{
		if (!hresource::exists(this->filename))
		{
			hlog::error(xal::logTag, "Unable to open: " + this->filename);
			this->close();
			return this->streamOpen;
		}
		if (this->stream == NULL)
		{
			hresource* resource = new hresource(this->filename);
			if (this->sourceMode == RAM || this->bufferMode == ASYNC)
			{
				this->stream = new hstream();
				this->stream->write_raw(*resource);
				delete resource;
				this->stream->rewind();
			}
			else // if sourceMode == DISK
			{
				this->stream = resource;
			}
		}
		else
		{
			this->stream->rewind();
		}
		this->streamOpen = true;
		return this->streamOpen;
	}

	void Source::close()
	{
		if (this->streamOpen)
		{
			if (this->sourceMode == DISK)
			{
				delete this->stream;
				this->stream = NULL;
			}
			this->streamOpen = false;
		}
	}

	void Source::rewind()
	{
		if (this->streamOpen)
		{
			this->stream->rewind();
		}
	}

	bool Source::load(hstream& output)
	{
		hlog::write(xal::logTag, "Loading file: " + this->filename);
		if (!this->streamOpen)
		{
			hlog::error(xal::logTag, "File not open: " + this->filename);
			return false;
		}
		return true;
	}

	int Source::loadChunk(hstream& output, int size)
	{
		if (!this->streamOpen)
		{
			hlog::error(xal::logTag, "File not open: " + this->filename);
			return 0;
		}
		return 1; // means that "something" was read
	}

}
<commit_msg>- hltypes deprecation update<commit_after>/// @file
/// @version 3.3
///
/// @section LICENSE
///
/// This program is free software; you can redistribute it and/or modify it under
/// the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause

#include <hltypes/hlog.h>
#include <hltypes/hstream.h>
#include <hltypes/hstring.h>
#include <hltypes/hresource.h>

#include "AudioManager.h"
#include "Source.h"
#include "xal.h"

namespace xal
{
	Source::Source(chstr filename, SourceMode sourceMode, BufferMode bufferMode) : streamOpen(false),
		size(0), channels(2), samplingRate(44100), bitsPerSample(16), duration(0.0f), stream(NULL)
	{
		this->filename = filename;
		this->sourceMode = sourceMode;
		this->bufferMode = bufferMode;
	}

	Source::~Source()
	{
		if (this->stream != NULL)
		{
			delete this->stream;
		}
	}

	int Source::getRamSize()
	{
		if (this->sourceMode == RAM && this->stream != NULL)
		{
			return this->stream->size();
		}
		return 0;
	}

	bool Source::open()
	{
		if (!hresource::exists(this->filename))
		{
			hlog::error(xal::logTag, "Unable to open: " + this->filename);
			this->close();
			return this->streamOpen;
		}
		if (this->stream == NULL)
		{
			hresource* resource = new hresource;
			resource->open(this->filename);
			if (this->sourceMode == RAM || this->bufferMode == ASYNC)
			{
				this->stream = new hstream();
				this->stream->write_raw(*resource);
				delete resource;
				this->stream->rewind();
			}
			else // if sourceMode == DISK
			{
				this->stream = resource;
			}
		}
		else
		{
			this->stream->rewind();
		}
		this->streamOpen = true;
		return this->streamOpen;
	}

	void Source::close()
	{
		if (this->streamOpen)
		{
			if (this->sourceMode == DISK)
			{
				delete this->stream;
				this->stream = NULL;
			}
			this->streamOpen = false;
		}
	}

	void Source::rewind()
	{
		if (this->streamOpen)
		{
			this->stream->rewind();
		}
	}

	bool Source::load(hstream& output)
	{
		hlog::write(xal::logTag, "Loading file: " + this->filename);
		if (!this->streamOpen)
		{
			hlog::error(xal::logTag, "File not open: " + this->filename);
			return false;
		}
		return true;
	}

	int Source::loadChunk(hstream& output, int size)
	{
		if (!this->streamOpen)
		{
			hlog::error(xal::logTag, "File not open: " + this->filename);
			return 0;
		}
		return 1; // means that "something" was read
	}

}
<|endoftext|>