mirror of
https://github.com/idapython/src
synced 2026-06-08 14:47:00 +00:00
IDA Pro 6.6 support
What's new: - added the decompiler bindings - Expose simpleline_t type to IDAPython. That lets the user to set the bgcolor & text for each line in the decompilation. - Wrapped new functions from the IDA SDK Various fixes: for non-code locations, idc.GetOpnd() would create instructions instead of returning empty result - idb_event::area_cmt_changed was never received in IDB_Hooks (and descendants) - idb_event::ti_changed, and idb_event::op_ti_changed notifications were not accessible in IDAPython - op_t.value was truncated to 32 bits under IDA64. - print_tinfo() wouldn't return a valid string. - readsel2() was not usable. - read_selection() was buggy for 64-bit programs. - StructMembers() considered holes in structures, and didn't properly iterate through the whole structure definition. - There was no way to call calc_switch_cases() from IDAPython. - when using multi-select/multi-edit choosers, erroneous event codes could be sent at beginning & end of batch deletion of lines. - When, in a PluginForm#OnCreate, the layout of IDA was requested to change (for example by starting a debugging session), that PluginForm could be deleted and create an access violation. - tinfo_t objects created from IDAPython could cause an assertion failure at exit time. - Usage of IDAPython's DropdownListControl was broken.
This commit is contained in:
+35
-27
@@ -9,8 +9,6 @@
|
||||
#define DECLARE_FORM_ACTIONS form_actions_t *fa = (form_actions_t *)p_fa;
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
DECLARE_PY_CLINKED_OBJECT(textctrl_info_t);
|
||||
|
||||
static bool textctrl_info_t_assign(PyObject *self, PyObject *other)
|
||||
{
|
||||
textctrl_info_t *lhs = textctrl_info_t_get_clink(self);
|
||||
@@ -145,20 +143,21 @@ static PyObject *formchgcbfa_get_field_value(
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE();
|
||||
switch ( ft )
|
||||
{
|
||||
// dropdown list
|
||||
case 8:
|
||||
{
|
||||
// Readonly? Then return the selected index
|
||||
if ( sz == 1 )
|
||||
{
|
||||
int sel_idx;
|
||||
if ( fa->get_field_value(fid, &sel_idx) )
|
||||
if ( fa->get_combobox_value(fid, &sel_idx) )
|
||||
return PyLong_FromLong(sel_idx);
|
||||
}
|
||||
// Not readonly? Then return the qstring
|
||||
else
|
||||
{
|
||||
qstring val;
|
||||
if ( fa->get_field_value(fid, &val) )
|
||||
if ( fa->get_combobox_value(fid, &val) )
|
||||
return PyString_FromString(val.c_str());
|
||||
}
|
||||
break;
|
||||
@@ -167,15 +166,15 @@ static PyObject *formchgcbfa_get_field_value(
|
||||
case 7:
|
||||
{
|
||||
textctrl_info_t ti;
|
||||
if ( fa->get_field_value(fid, &ti) )
|
||||
if ( fa->get_text_value(fid, &ti) )
|
||||
return Py_BuildValue("(sII)", ti.text.c_str(), ti.flags, ti.tabsize);
|
||||
break;
|
||||
}
|
||||
// button - uint32
|
||||
case 4:
|
||||
{
|
||||
uint32 val;
|
||||
if ( fa->get_field_value(fid, &val) )
|
||||
uval_t val;
|
||||
if ( fa->get_unsigned_value(fid, &val) )
|
||||
return PyLong_FromUnsignedLong(val);
|
||||
break;
|
||||
}
|
||||
@@ -183,7 +182,7 @@ static PyObject *formchgcbfa_get_field_value(
|
||||
case 2:
|
||||
{
|
||||
ushort val;
|
||||
if ( fa->get_field_value(fid, &val) )
|
||||
if ( fa->_get_field_value(fid, &val) )
|
||||
return PyLong_FromUnsignedLong(val);
|
||||
break;
|
||||
}
|
||||
@@ -191,7 +190,7 @@ static PyObject *formchgcbfa_get_field_value(
|
||||
case 1:
|
||||
{
|
||||
char val[MAXSTR];
|
||||
if ( fa->get_field_value(fid, val) )
|
||||
if ( fa->get_ascii_value(fid, val, sizeof(val)) )
|
||||
return PyString_FromString(val);
|
||||
break;
|
||||
}
|
||||
@@ -200,7 +199,7 @@ static PyObject *formchgcbfa_get_field_value(
|
||||
{
|
||||
qstring val;
|
||||
val.resize(sz + 1);
|
||||
if ( fa->get_field_value(fid, val.begin()) )
|
||||
if ( fa->get_ascii_value(fid, val.begin(), val.size()) )
|
||||
return PyString_FromString(val.begin());
|
||||
break;
|
||||
}
|
||||
@@ -208,12 +207,11 @@ static PyObject *formchgcbfa_get_field_value(
|
||||
{
|
||||
intvec_t intvec;
|
||||
// Returned as 1-base
|
||||
if (fa->get_field_value(fid, &intvec))
|
||||
if (fa->get_chooser_value(fid, &intvec))
|
||||
{
|
||||
// Make 0-based
|
||||
for ( intvec_t::iterator it=intvec.begin(); it != intvec.end(); ++it)
|
||||
(*it)--;
|
||||
|
||||
ref_t l(PyW_IntVecToPyList(intvec));
|
||||
l.incref();
|
||||
return l.o;
|
||||
@@ -234,33 +232,38 @@ static PyObject *formchgcbfa_get_field_value(
|
||||
{
|
||||
case 'S': // sel_t
|
||||
{
|
||||
if ( fa->get_field_value(fid, &u.sel) )
|
||||
if ( fa->get_segment_value(fid, &u.sel) )
|
||||
return Py_BuildValue(PY_FMT64, u.sel);
|
||||
break;
|
||||
}
|
||||
// sval_t
|
||||
case 'n':
|
||||
case 'N':
|
||||
case 'D':
|
||||
case 'O':
|
||||
case 'Y':
|
||||
case 'H':
|
||||
{
|
||||
if ( fa->get_field_value(fid, &u.sval) )
|
||||
if ( fa->get_signed_value(fid, &u.sval) )
|
||||
return Py_BuildValue(PY_SFMT64, u.sval);
|
||||
break;
|
||||
}
|
||||
case 'L': // uint64
|
||||
case 'l': // int64
|
||||
{
|
||||
if ( fa->get_field_value(fid, &u.ull) )
|
||||
return Py_BuildValue(sz == 'L' ? "K" : "L", u.ull);
|
||||
if ( fa->_get_field_value(fid, &u.ull) )
|
||||
return Py_BuildValue("K", u.ull);
|
||||
break;
|
||||
}
|
||||
case 'N':
|
||||
case 'M': // uval_t
|
||||
{
|
||||
if ( fa->get_unsigned_value(fid, &u.uval) )
|
||||
return Py_BuildValue(PY_FMT64, u.uval);
|
||||
break;
|
||||
}
|
||||
case '$': // ea_t
|
||||
{
|
||||
if ( fa->get_field_value(fid, &u.uval) )
|
||||
if ( fa->get_ea_value(fid, &u.uval) )
|
||||
return Py_BuildValue(PY_FMT64, u.uval);
|
||||
break;
|
||||
}
|
||||
@@ -290,13 +293,13 @@ static bool formchgcbfa_set_field_value(
|
||||
if ( PyString_Check(py_val) )
|
||||
{
|
||||
qstring val(PyString_AsString(py_val));
|
||||
return fa->set_field_value(fid, &val);
|
||||
return fa->set_combobox_value(fid, &val);
|
||||
}
|
||||
// Readonly dropdown list
|
||||
else
|
||||
{
|
||||
int sel_idx = PyLong_AsLong(py_val);
|
||||
return fa->set_field_value(fid, &sel_idx);
|
||||
return fa->set_combobox_value(fid, &sel_idx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -304,24 +307,24 @@ static bool formchgcbfa_set_field_value(
|
||||
case 7:
|
||||
{
|
||||
textctrl_info_t *ti = (textctrl_info_t *)pyobj_get_clink(py_val);
|
||||
return ti == NULL ? false : fa->set_field_value(fid, ti);
|
||||
return ti == NULL ? false : fa->set_text_value(fid, ti);
|
||||
}
|
||||
// button - uint32
|
||||
case 4:
|
||||
{
|
||||
uint32 val = PyLong_AsUnsignedLong(py_val);
|
||||
return fa->set_field_value(fid, &val);
|
||||
uval_t val = PyLong_AsUnsignedLong(py_val);
|
||||
return fa->set_unsigned_value(fid, &val);
|
||||
}
|
||||
// ushort
|
||||
case 2:
|
||||
{
|
||||
ushort val = PyLong_AsUnsignedLong(py_val) & 0xffff;
|
||||
return fa->set_field_value(fid, &val);
|
||||
return fa->_set_field_value(fid, &val);
|
||||
}
|
||||
// strings
|
||||
case 3:
|
||||
case 1:
|
||||
return fa->set_field_value(fid, PyString_AsString(py_val));
|
||||
return fa->set_ascii_value(fid, PyString_AsString(py_val));
|
||||
// intvec_t
|
||||
case 5:
|
||||
{
|
||||
@@ -334,14 +337,14 @@ static bool formchgcbfa_set_field_value(
|
||||
for ( intvec_t::iterator it=intvec.begin(); it != intvec.end(); ++it)
|
||||
(*it)++;
|
||||
|
||||
return fa->set_field_value(fid, &intvec);
|
||||
return fa->set_chooser_value(fid, &intvec);
|
||||
}
|
||||
// Numeric
|
||||
case 6:
|
||||
{
|
||||
uint64 num;
|
||||
if ( PyW_GetNumber(py_val, &num) )
|
||||
return fa->set_field_value(fid, &num);
|
||||
return fa->_set_field_value(fid, &num);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -351,6 +354,11 @@ static bool formchgcbfa_set_field_value(
|
||||
|
||||
static size_t py_get_AskUsingForm()
|
||||
{
|
||||
// Return a pointer to the function. Note that, although
|
||||
// the C implementation of AskUsingForm_cv will do some
|
||||
// Qt/txt widgets generation, the Python's ctypes
|
||||
// implementation through which the call well go will first
|
||||
// unblock other threads. No need to do it ourselves.
|
||||
return (size_t)AskUsingForm_c;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ try:
|
||||
from _idaapi import set_script_timeout
|
||||
import idaapi
|
||||
from idaapi import py_clinked_object_t
|
||||
from idaapi import qstrvec_t
|
||||
from idaapi import _qstrvec_t
|
||||
stdalone = False
|
||||
except:
|
||||
stdalone = True
|
||||
@@ -50,7 +50,7 @@ try:
|
||||
from py_choose2 import *
|
||||
py_clinked_object_t = idaapi.py_clinked_object_t
|
||||
textctrl_info_t = idaapi.textctrl_info_t
|
||||
qstrvec_t = idaapi.qstrvec_t
|
||||
_qstrvec_t = idaapi._qstrvec_t
|
||||
|
||||
_idaapi.BADADDR = 0xFFFFFFFF
|
||||
_idaapi.MAXSTR = 1024
|
||||
@@ -776,7 +776,7 @@ class Form(object):
|
||||
Form.Control.free(self)
|
||||
|
||||
|
||||
class DropdownListControl(InputControl, qstrvec_t):
|
||||
class DropdownListControl(InputControl, _qstrvec_t):
|
||||
"""
|
||||
Dropdown control
|
||||
This control allows manipulating a dropdown control
|
||||
@@ -803,7 +803,7 @@ class Form(object):
|
||||
hlp)
|
||||
|
||||
# Init the associated qstrvec
|
||||
qstrvec_t.__init__(self, items)
|
||||
_qstrvec_t.__init__(self, items)
|
||||
|
||||
# Remember if readonly or not
|
||||
self.readonly = readonly
|
||||
@@ -814,7 +814,7 @@ class Form(object):
|
||||
val_addr = addressof(self.__selval)
|
||||
else:
|
||||
# Create an strvec with one qstring
|
||||
self.__selval = qstrvec_t([selval])
|
||||
self.__selval = _qstrvec_t([selval])
|
||||
# Get address of the first element
|
||||
val_addr = self.__selval.addressof(0)
|
||||
|
||||
|
||||
@@ -289,8 +289,8 @@ private:
|
||||
self,
|
||||
(char *)S_ON_DELETE_LINE,
|
||||
"i",
|
||||
lineno - 1));
|
||||
return pyres == NULL ? lineno : PyInt_AsLong(pyres.o) + 1;
|
||||
IS_CHOOSER_EVENT(lineno) ? lineno : lineno-1));
|
||||
return pyres == NULL ? 1 : PyInt_AsLong(pyres.o);
|
||||
}
|
||||
|
||||
int on_refresh(int lineno)
|
||||
|
||||
@@ -112,7 +112,6 @@ private:
|
||||
|
||||
static cmdid_map_t cmdid_pyg;
|
||||
|
||||
// TForm *form;
|
||||
bool refresh_needed;
|
||||
nodetext_cache_map_t node_cache;
|
||||
|
||||
@@ -122,6 +121,7 @@ private:
|
||||
// static callback
|
||||
static int idaapi s_callback(void *obj, int code, va_list va)
|
||||
{
|
||||
QASSERT(30453, py_customidamemo_t::lookup_info.find_by_py_view(NULL, NULL, (py_graph_t *) obj));
|
||||
PYW_GIL_GET;
|
||||
return ((py_graph_t *)obj)->gr_callback(code, va);
|
||||
}
|
||||
@@ -255,13 +255,13 @@ private:
|
||||
}
|
||||
|
||||
// a group is being created
|
||||
int on_creating_group(mutable_graph_t *my_g, intset_t *my_nodes)
|
||||
int on_creating_group(mutable_graph_t *my_g, intvec_t *my_nodes)
|
||||
{
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE();
|
||||
printf("my_g: %p; my_nodes: %p\n", my_g, my_nodes);
|
||||
newref_t py_nodes(PyList_New(my_nodes->size()));
|
||||
int i;
|
||||
intset_t::const_iterator p;
|
||||
intvec_t::const_iterator p;
|
||||
for ( i = 0, p=my_nodes->begin(); p != my_nodes->end(); ++p, ++i )
|
||||
PyList_SetItem(py_nodes.o, i, PyInt_FromLong(*p));
|
||||
newref_t py_result(
|
||||
@@ -331,6 +331,7 @@ private:
|
||||
TForm *form = create_tform(title, &hwnd);
|
||||
if ( hwnd != NULL ) // Created new tform
|
||||
{
|
||||
lookup_info_t::entry_t &e = lookup_info.new_entry(this);
|
||||
// get a unique graph id
|
||||
netnode id;
|
||||
char grnode[MAXSTR];
|
||||
@@ -342,8 +343,7 @@ private:
|
||||
viewer_fit_window(pview);
|
||||
bind(self, pview);
|
||||
refresh();
|
||||
// Link "form" and "py_graph"
|
||||
lookup_info.add(form, view, this);
|
||||
lookup_info.commit(e, form, view);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -700,7 +700,7 @@ int py_graph_t::gr_callback(int code, va_list va)
|
||||
case grcode_creating_group: // a group is being created
|
||||
{
|
||||
mutable_graph_t *g = va_arg(va, mutable_graph_t*);
|
||||
intset_t *nodes = va_arg(va, intset_t*);
|
||||
intvec_t *nodes = va_arg(va, intvec_t*);
|
||||
ret = on_creating_group(g, nodes);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -726,12 +726,9 @@ def RunPythonStatement(stmt):
|
||||
#</pydoc>
|
||||
*/
|
||||
|
||||
/*
|
||||
//---------------------------------------------------------------------------
|
||||
// qstrvec_t wrapper
|
||||
// qstrvec_t wrapper (INTERNAL! Don't expose. See py_idaapi.py)
|
||||
//---------------------------------------------------------------------------
|
||||
DECLARE_PY_CLINKED_OBJECT(qstrvec_t);
|
||||
|
||||
static bool qstrvec_t_assign(PyObject *self, PyObject *other)
|
||||
{
|
||||
qstrvec_t *lhs = qstrvec_t_get_clink(self);
|
||||
@@ -833,7 +830,7 @@ static bool qstrvec_t_remove(PyObject *self, size_t idx)
|
||||
sv->erase(sv->begin()+idx);
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
//</inline(py_idaapi)>
|
||||
|
||||
|
||||
+70
-51
@@ -171,6 +171,12 @@ class object_t(object):
|
||||
"""Allow access to object attributes by index (like dictionaries)"""
|
||||
return getattr(self, idx)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
def _bounded_getitem_iterator(self):
|
||||
"""Helper function, to be set as __iter__ method for qvector-, or array-based classes."""
|
||||
for i in range(len(self)):
|
||||
yield self[i]
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class plugin_t(pyidc_opaque_object_t):
|
||||
"""Base class for all scripted plugins."""
|
||||
@@ -237,72 +243,79 @@ class PyIdc_cvt_int64__(pyidc_cvt_helper__):
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# qstrvec_t clinked object
|
||||
# class qstrvec_t(py_clinked_object_t):
|
||||
# """Class representing an qstrvec_t"""
|
||||
class _qstrvec_t(py_clinked_object_t):
|
||||
"""
|
||||
WARNING: It is very unlikely an IDAPython user should ever, ever
|
||||
have to use this type. It should only be used for IDAPython internals.
|
||||
|
||||
# def __init__(self, items=None):
|
||||
# py_clinked_object_t.__init__(self)
|
||||
# # Populate the list if needed
|
||||
# if items:
|
||||
# self.from_list(items)
|
||||
For example, in py_askusingform.py, we ctypes-expose to the IDA
|
||||
kernel & UI a qstrvec instance, in case a DropdownListControl is
|
||||
constructed.
|
||||
That's because that's what AskUsingForm expects, and we have no
|
||||
choice but to make a DropdownListControl hold a qstrvec_t.
|
||||
This is, afaict, the only situation where a Python
|
||||
_qstrvec_t is required.
|
||||
"""
|
||||
|
||||
# def _create_clink(self):
|
||||
# return _idaapi.qstrvec_t_create()
|
||||
def __init__(self, items=None):
|
||||
py_clinked_object_t.__init__(self)
|
||||
# Populate the list if needed
|
||||
if items:
|
||||
self.from_list(items)
|
||||
|
||||
# def _del_clink(self, lnk):
|
||||
# return _idaapi.qstrvec_t_destroy(lnk)
|
||||
def _create_clink(self):
|
||||
return _idaapi.qstrvec_t_create()
|
||||
|
||||
# def _get_clink_ptr(self):
|
||||
# return _idaapi.qstrvec_t_get_clink_ptr(self)
|
||||
def _del_clink(self, lnk):
|
||||
return _idaapi.qstrvec_t_destroy(lnk)
|
||||
|
||||
# def assign(self, other):
|
||||
# """Copies the contents of 'other' to 'self'"""
|
||||
# return _idaapi.qstrvec_t_assign(self, other)
|
||||
def _get_clink_ptr(self):
|
||||
return _idaapi.qstrvec_t_get_clink_ptr(self)
|
||||
|
||||
# def __setitem__(self, idx, s):
|
||||
# """Sets string at the given index"""
|
||||
# return _idaapi.qstrvec_t_set(self, idx, s)
|
||||
def assign(self, other):
|
||||
"""Copies the contents of 'other' to 'self'"""
|
||||
return _idaapi.qstrvec_t_assign(self, other)
|
||||
|
||||
# def __getitem__(self, idx):
|
||||
# """Gets the string at the given index"""
|
||||
# return _idaapi.qstrvec_t_get(self, idx)
|
||||
def __setitem__(self, idx, s):
|
||||
"""Sets string at the given index"""
|
||||
return _idaapi.qstrvec_t_set(self, idx, s)
|
||||
|
||||
# def __get_size(self):
|
||||
# return _idaapi.qstrvec_t_size(self)
|
||||
def __getitem__(self, idx):
|
||||
"""Gets the string at the given index"""
|
||||
return _idaapi.qstrvec_t_get(self, idx)
|
||||
|
||||
# size = property(__get_size)
|
||||
# """Returns the count of elements"""
|
||||
def __get_size(self):
|
||||
return _idaapi.qstrvec_t_size(self)
|
||||
|
||||
# def addressof(self, idx):
|
||||
# """Returns the address (as number) of the qstring at the given index"""
|
||||
# return _idaapi.qstrvec_t_addressof(self, idx)
|
||||
size = property(__get_size)
|
||||
"""Returns the count of elements"""
|
||||
|
||||
# def add(self, s):
|
||||
# """Add a string to the vector"""
|
||||
# return _idaapi.qstrvec_t_add(self, s)
|
||||
def addressof(self, idx):
|
||||
"""Returns the address (as number) of the qstring at the given index"""
|
||||
return _idaapi.qstrvec_t_addressof(self, idx)
|
||||
|
||||
def add(self, s):
|
||||
"""Add a string to the vector"""
|
||||
return _idaapi.qstrvec_t_add(self, s)
|
||||
|
||||
# def from_list(self, lst):
|
||||
# """Populates the vector from a Python string list"""
|
||||
# return _idaapi.qstrvec_t_from_list(self, lst)
|
||||
def from_list(self, lst):
|
||||
"""Populates the vector from a Python string list"""
|
||||
return _idaapi.qstrvec_t_from_list(self, lst)
|
||||
|
||||
def clear(self, qclear=False):
|
||||
"""
|
||||
Clears all strings from the vector.
|
||||
@param qclear: Just reset the size but do not actually free the memory
|
||||
"""
|
||||
return _idaapi.qstrvec_t_clear(self, qclear)
|
||||
|
||||
# def clear(self, qclear=False):
|
||||
# """
|
||||
# Clears all strings from the vector.
|
||||
# @param qclear: Just reset the size but do not actually free the memory
|
||||
# """
|
||||
# return _idaapi.qstrvec_t_clear(self, qclear)
|
||||
def insert(self, idx, s):
|
||||
"""Insert a string into the vector"""
|
||||
return _idaapi.qstrvec_t_insert(self, idx, s)
|
||||
|
||||
|
||||
# def insert(self, idx, s):
|
||||
# """Insert a string into the vector"""
|
||||
# return _idaapi.qstrvec_t_insert(self, idx, s)
|
||||
|
||||
|
||||
# def remove(self, idx):
|
||||
# """Removes a string from the vector"""
|
||||
# return _idaapi.qstrvec_t_remove(self, idx)
|
||||
def remove(self, idx):
|
||||
"""Removes a string from the vector"""
|
||||
return _idaapi.qstrvec_t_remove(self, idx)
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
class PyIdc_cvt_refclass__(pyidc_cvt_helper__):
|
||||
@@ -580,7 +593,13 @@ class __IDAPython_Completion_Util(object):
|
||||
|
||||
return s
|
||||
|
||||
# Instantiate a completion object
|
||||
# Instantiate an IDAPython command completion object (for use with IDA's CLI bar)
|
||||
IDAPython_Completion = __IDAPython_Completion_Util()
|
||||
|
||||
def _listify_types(*classes):
|
||||
for cls in classes:
|
||||
cls.__getitem__ = cls.at
|
||||
cls.__len__ = cls.size
|
||||
cls.__iter__ = _bounded_getitem_iterator
|
||||
|
||||
#</pycode(py_idaapi)>
|
||||
|
||||
@@ -42,7 +42,8 @@ bool py_idaview_t::Bind(PyObject *self)
|
||||
else
|
||||
{
|
||||
py_view = new py_idaview_t();
|
||||
lookup_info.add(tform, v, py_view);
|
||||
lookup_info_t::entry_t &e = lookup_info.new_entry(py_view);
|
||||
lookup_info.commit(e, tform, v);
|
||||
}
|
||||
|
||||
// Finally, bind:
|
||||
|
||||
+136
-117
@@ -807,6 +807,15 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
enum areacb_type_t
|
||||
{
|
||||
AREACB_TYPE_UNKNOWN,
|
||||
AREACB_TYPE_FUNC,
|
||||
AREACB_TYPE_SEGMENT,
|
||||
AREACB_TYPE_HIDDEN_AREA,
|
||||
AREACB_TYPE_SRAREA,
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// IDB hooks
|
||||
//---------------------------------------------------------------------------
|
||||
@@ -827,8 +836,9 @@ public:
|
||||
// Hook functions to override in Python
|
||||
virtual int byte_patched(ea_t /*ea*/) { return 0; };
|
||||
virtual int cmt_changed(ea_t, bool /*repeatable_cmt*/) { return 0; };
|
||||
virtual int ti_changed(ea_t /*ea*/, const type_t * /*type*/, const p_list * /*fnames*/) { msg("ti_changed hook not supported yet\n"); return 0; };
|
||||
virtual int op_ti_changed(ea_t /*ea*/, int /*n*/, const type_t * /*type*/, const p_list * /*fnames*/) { msg("op_ti_changed hook not supported yet\n"); return 0; };
|
||||
virtual int area_cmt_changed(areacb_t * /*areas*/, area_t * /*area*/, const char * /*cmt*/, bool /*repeatable*/) { return 0; }
|
||||
virtual int ti_changed(ea_t /*ea*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; };
|
||||
virtual int op_ti_changed(ea_t /*ea*/, int /*n*/, const type_t * /*type*/, const p_list * /*fnames*/) { return 0; };
|
||||
virtual int op_type_changed(ea_t /*ea*/, int /*n*/) { return 0; };
|
||||
virtual int enum_created(enum_t /*id*/) { return 0; };
|
||||
virtual int enum_deleted(enum_t /*id*/) { return 0; };
|
||||
@@ -1365,8 +1375,8 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
|
||||
class IDB_Hooks *proxy = (class IDB_Hooks *)ud;
|
||||
ea_t ea, ea2;
|
||||
bool repeatable_cmt;
|
||||
/*type_t *type;*/
|
||||
/* p_list *fnames; */
|
||||
type_t *type;
|
||||
p_list *fnames;
|
||||
int n;
|
||||
enum_t id;
|
||||
const_t cid;
|
||||
@@ -1382,152 +1392,161 @@ int idaapi IDB_Callback(void *ud, int notification_code, va_list va)
|
||||
try {
|
||||
switch (notification_code)
|
||||
{
|
||||
case idb_event::byte_patched:
|
||||
ea = va_arg(va, ea_t);
|
||||
return proxy->byte_patched(ea);
|
||||
case idb_event::byte_patched:
|
||||
ea = va_arg(va, ea_t);
|
||||
return proxy->byte_patched(ea);
|
||||
|
||||
case idb_event::cmt_changed:
|
||||
ea = va_arg(va, ea_t);
|
||||
repeatable_cmt = va_arg(va, int);
|
||||
return proxy->cmt_changed(ea, repeatable_cmt);
|
||||
#if 0
|
||||
case idb_event::ti_changed:
|
||||
ea = va_arg(va, ea_t);
|
||||
type = va_arg(va, type_t *);
|
||||
fnames = va_arg(va, fnames);
|
||||
return proxy->ti_changed(ea, type, fnames);
|
||||
case idb_event::cmt_changed:
|
||||
ea = va_arg(va, ea_t);
|
||||
repeatable_cmt = va_arg(va, int);
|
||||
return proxy->cmt_changed(ea, repeatable_cmt);
|
||||
|
||||
case idb_event::op_ti_changed:
|
||||
ea = va_arg(va, ea_t);
|
||||
n = va_arg(va, int);
|
||||
type = va_arg(va, type_t *);
|
||||
fnames = va_arg(va, fnames);
|
||||
return proxy->op_ti_changed(ea, n, type, fnames);
|
||||
#endif
|
||||
case idb_event::op_type_changed:
|
||||
ea = va_arg(va, ea_t);
|
||||
n = va_arg(va, int);
|
||||
return proxy->op_type_changed(ea, n);
|
||||
case idb_event::area_cmt_changed:
|
||||
{
|
||||
areacb_t *cb = va_arg(va, areacb_t*);
|
||||
area_t *area = va_arg(va, area_t*);
|
||||
const char *cmt = va_arg(va, char*);
|
||||
repeatable_cmt = va_arg(va, int);
|
||||
return proxy->area_cmt_changed(cb, area, cmt, repeatable_cmt);
|
||||
}
|
||||
|
||||
case idb_event::enum_created:
|
||||
id = va_arg(va, enum_t);
|
||||
return proxy->enum_created(id);
|
||||
case idb_event::ti_changed:
|
||||
ea = va_arg(va, ea_t);
|
||||
type = va_arg(va, type_t *);
|
||||
fnames = va_arg(va, p_list *);
|
||||
return proxy->ti_changed(ea, type, fnames);
|
||||
|
||||
case idb_event::enum_deleted:
|
||||
id = va_arg(va, enum_t);
|
||||
return proxy->enum_deleted(id);
|
||||
case idb_event::op_ti_changed:
|
||||
ea = va_arg(va, ea_t);
|
||||
n = va_arg(va, int);
|
||||
type = va_arg(va, type_t *);
|
||||
fnames = va_arg(va, p_list *);
|
||||
return proxy->op_ti_changed(ea, n, type, fnames);
|
||||
|
||||
case idb_event::enum_bf_changed:
|
||||
id = va_arg(va, enum_t);
|
||||
return proxy->enum_bf_changed(id);
|
||||
case idb_event::op_type_changed:
|
||||
ea = va_arg(va, ea_t);
|
||||
n = va_arg(va, int);
|
||||
return proxy->op_type_changed(ea, n);
|
||||
|
||||
case idb_event::enum_cmt_changed:
|
||||
id = va_arg(va, enum_t);
|
||||
return proxy->enum_cmt_changed(id);
|
||||
case idb_event::enum_created:
|
||||
id = va_arg(va, enum_t);
|
||||
return proxy->enum_created(id);
|
||||
|
||||
case idb_event::enum_deleted:
|
||||
id = va_arg(va, enum_t);
|
||||
return proxy->enum_deleted(id);
|
||||
|
||||
case idb_event::enum_bf_changed:
|
||||
id = va_arg(va, enum_t);
|
||||
return proxy->enum_bf_changed(id);
|
||||
|
||||
case idb_event::enum_cmt_changed:
|
||||
id = va_arg(va, enum_t);
|
||||
return proxy->enum_cmt_changed(id);
|
||||
|
||||
#ifdef NO_OBSOLETE_FUNCS
|
||||
case idb_event::enum_member_created:
|
||||
case idb_event::enum_member_created:
|
||||
#else
|
||||
case idb_event::enum_const_created:
|
||||
case idb_event::enum_const_created:
|
||||
#endif
|
||||
id = va_arg(va, enum_t);
|
||||
cid = va_arg(va, const_t);
|
||||
return proxy->enum_member_created(id, cid);
|
||||
id = va_arg(va, enum_t);
|
||||
cid = va_arg(va, const_t);
|
||||
return proxy->enum_member_created(id, cid);
|
||||
|
||||
#ifdef NO_OBSOLETE_FUNCS
|
||||
case idb_event::enum_member_deleted:
|
||||
case idb_event::enum_member_deleted:
|
||||
#else
|
||||
case idb_event::enum_const_deleted:
|
||||
case idb_event::enum_const_deleted:
|
||||
#endif
|
||||
id = va_arg(va, enum_t);
|
||||
cid = va_arg(va, const_t);
|
||||
return proxy->enum_member_deleted(id, cid);
|
||||
id = va_arg(va, enum_t);
|
||||
cid = va_arg(va, const_t);
|
||||
return proxy->enum_member_deleted(id, cid);
|
||||
|
||||
case idb_event::struc_created:
|
||||
struc_id = va_arg(va, tid_t);
|
||||
return proxy->struc_created(struc_id);
|
||||
case idb_event::struc_created:
|
||||
struc_id = va_arg(va, tid_t);
|
||||
return proxy->struc_created(struc_id);
|
||||
|
||||
case idb_event::struc_deleted:
|
||||
struc_id = va_arg(va, tid_t);
|
||||
return proxy->struc_deleted(struc_id);
|
||||
case idb_event::struc_deleted:
|
||||
struc_id = va_arg(va, tid_t);
|
||||
return proxy->struc_deleted(struc_id);
|
||||
|
||||
case idb_event::struc_renamed:
|
||||
sptr = va_arg(va, struc_t *);
|
||||
return proxy->struc_renamed(sptr);
|
||||
case idb_event::struc_renamed:
|
||||
sptr = va_arg(va, struc_t *);
|
||||
return proxy->struc_renamed(sptr);
|
||||
|
||||
case idb_event::struc_expanded:
|
||||
sptr = va_arg(va, struc_t *);
|
||||
return proxy->struc_expanded(sptr);
|
||||
case idb_event::struc_expanded:
|
||||
sptr = va_arg(va, struc_t *);
|
||||
return proxy->struc_expanded(sptr);
|
||||
|
||||
case idb_event::struc_cmt_changed:
|
||||
struc_id = va_arg(va, tid_t);
|
||||
return proxy->struc_cmt_changed(struc_id);
|
||||
case idb_event::struc_cmt_changed:
|
||||
struc_id = va_arg(va, tid_t);
|
||||
return proxy->struc_cmt_changed(struc_id);
|
||||
|
||||
case idb_event::struc_member_created:
|
||||
sptr = va_arg(va, struc_t *);
|
||||
mptr = va_arg(va, member_t *);
|
||||
return proxy->struc_member_created(sptr, mptr);
|
||||
case idb_event::struc_member_created:
|
||||
sptr = va_arg(va, struc_t *);
|
||||
mptr = va_arg(va, member_t *);
|
||||
return proxy->struc_member_created(sptr, mptr);
|
||||
|
||||
case idb_event::struc_member_deleted:
|
||||
sptr = va_arg(va, struc_t *);
|
||||
member_id = va_arg(va, tid_t);
|
||||
ea = va_arg(va, ea_t);
|
||||
return proxy->struc_member_deleted(sptr, member_id, ea);
|
||||
case idb_event::struc_member_deleted:
|
||||
sptr = va_arg(va, struc_t *);
|
||||
member_id = va_arg(va, tid_t);
|
||||
ea = va_arg(va, ea_t);
|
||||
return proxy->struc_member_deleted(sptr, member_id, ea);
|
||||
|
||||
case idb_event::struc_member_renamed:
|
||||
sptr = va_arg(va, struc_t *);
|
||||
mptr = va_arg(va, member_t *);
|
||||
return proxy->struc_member_renamed(sptr, mptr);
|
||||
case idb_event::struc_member_renamed:
|
||||
sptr = va_arg(va, struc_t *);
|
||||
mptr = va_arg(va, member_t *);
|
||||
return proxy->struc_member_renamed(sptr, mptr);
|
||||
|
||||
case idb_event::struc_member_changed:
|
||||
sptr = va_arg(va, struc_t *);
|
||||
mptr = va_arg(va, member_t *);
|
||||
return proxy->struc_member_changed(sptr, mptr);
|
||||
case idb_event::struc_member_changed:
|
||||
sptr = va_arg(va, struc_t *);
|
||||
mptr = va_arg(va, member_t *);
|
||||
return proxy->struc_member_changed(sptr, mptr);
|
||||
|
||||
case idb_event::thunk_func_created:
|
||||
pfn = va_arg(va, func_t *);
|
||||
return proxy->thunk_func_created(pfn);
|
||||
case idb_event::thunk_func_created:
|
||||
pfn = va_arg(va, func_t *);
|
||||
return proxy->thunk_func_created(pfn);
|
||||
|
||||
case idb_event::func_tail_appended:
|
||||
pfn = va_arg(va, func_t *);
|
||||
tail = va_arg(va, func_t *);
|
||||
return proxy->func_tail_appended(pfn, tail);
|
||||
case idb_event::func_tail_appended:
|
||||
pfn = va_arg(va, func_t *);
|
||||
tail = va_arg(va, func_t *);
|
||||
return proxy->func_tail_appended(pfn, tail);
|
||||
|
||||
case idb_event::func_tail_removed:
|
||||
pfn = va_arg(va, func_t *);
|
||||
ea = va_arg(va, ea_t);
|
||||
return proxy->func_tail_removed(pfn, ea);
|
||||
case idb_event::func_tail_removed:
|
||||
pfn = va_arg(va, func_t *);
|
||||
ea = va_arg(va, ea_t);
|
||||
return proxy->func_tail_removed(pfn, ea);
|
||||
|
||||
case idb_event::tail_owner_changed:
|
||||
tail = va_arg(va, func_t *);
|
||||
ea = va_arg(va, ea_t);
|
||||
return proxy->tail_owner_changed(tail, ea);
|
||||
case idb_event::tail_owner_changed:
|
||||
tail = va_arg(va, func_t *);
|
||||
ea = va_arg(va, ea_t);
|
||||
return proxy->tail_owner_changed(tail, ea);
|
||||
|
||||
case idb_event::func_noret_changed:
|
||||
pfn = va_arg(va, func_t *);
|
||||
return proxy->func_noret_changed(pfn);
|
||||
case idb_event::func_noret_changed:
|
||||
pfn = va_arg(va, func_t *);
|
||||
return proxy->func_noret_changed(pfn);
|
||||
|
||||
case idb_event::segm_added:
|
||||
seg = va_arg(va, segment_t *);
|
||||
return proxy->segm_added(seg);
|
||||
case idb_event::segm_added:
|
||||
seg = va_arg(va, segment_t *);
|
||||
return proxy->segm_added(seg);
|
||||
|
||||
case idb_event::segm_deleted:
|
||||
ea = va_arg(va, ea_t);
|
||||
return proxy->segm_deleted(ea);
|
||||
case idb_event::segm_deleted:
|
||||
ea = va_arg(va, ea_t);
|
||||
return proxy->segm_deleted(ea);
|
||||
|
||||
case idb_event::segm_start_changed:
|
||||
seg = va_arg(va, segment_t *);
|
||||
return proxy->segm_start_changed(seg);
|
||||
case idb_event::segm_start_changed:
|
||||
seg = va_arg(va, segment_t *);
|
||||
return proxy->segm_start_changed(seg);
|
||||
|
||||
case idb_event::segm_end_changed:
|
||||
seg = va_arg(va, segment_t *);
|
||||
return proxy->segm_end_changed(seg);
|
||||
case idb_event::segm_end_changed:
|
||||
seg = va_arg(va, segment_t *);
|
||||
return proxy->segm_end_changed(seg);
|
||||
|
||||
case idb_event::segm_moved:
|
||||
ea = va_arg(va, ea_t);
|
||||
ea2 = va_arg(va, ea_t);
|
||||
size = va_arg(va, asize_t);
|
||||
return proxy->segm_moved(ea, ea2, size);
|
||||
case idb_event::segm_moved:
|
||||
ea = va_arg(va, ea_t);
|
||||
ea2 = va_arg(va, ea_t);
|
||||
size = va_arg(va, asize_t);
|
||||
return proxy->segm_moved(ea, ea2, size);
|
||||
}
|
||||
}
|
||||
catch (Swig::DirectorException &e)
|
||||
|
||||
+39
-24
@@ -5,30 +5,6 @@
|
||||
//<inline(py_kernwin)>
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def read_selection():
|
||||
"""
|
||||
Returns selected area boundaries
|
||||
|
||||
@return: tuple(ok: bool, start_ea, end_ea)
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
static PyObject *py_read_selection()
|
||||
{
|
||||
ea_t ea1, ea2;
|
||||
bool b = read_selection(&ea1, &ea2);
|
||||
|
||||
PYW_GIL_CHECK_LOCKED_SCOPE();
|
||||
return Py_BuildValue(
|
||||
"(i" PY_FMT64 PY_FMT64 ")",
|
||||
b ? 1 : 0,
|
||||
pyul_t(ea1), pyul_t(ea2));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
@@ -203,6 +179,45 @@ def free_custom_icon(icon_id):
|
||||
#</pydoc>
|
||||
*/
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def readsel2(view, p0, p1):
|
||||
"""
|
||||
Read the user selection, and store its information in p0 (from) and p1 (to).
|
||||
|
||||
This can be used as follows:
|
||||
|
||||
|
||||
>>> p0 = idaapi.twinpos_t()
|
||||
p1 = idaapi.twinpos_t()
|
||||
view = idaapi.get_current_viewer()
|
||||
idaapi.readsel2(view, p0, p1)
|
||||
|
||||
|
||||
At that point, p0 and p1 hold information for the selection.
|
||||
But, the 'at' property of p0 and p1 is not properly typed.
|
||||
To specialize it, call #place() on it, passing it the view
|
||||
they were retrieved from. Like so:
|
||||
|
||||
|
||||
>>> place0 = p0.place(view)
|
||||
place1 = p1.place(view)
|
||||
|
||||
|
||||
This will effectively "cast" the place into a specialized type,
|
||||
holding proper information, depending on the view type (e.g.,
|
||||
disassembly, structures, enums, ...)
|
||||
|
||||
@param view: The view to retrieve the selection for.
|
||||
@param p0: Storage for the "from" part of the selection.
|
||||
@param p1: Storage for the "to" part of the selection.
|
||||
@return: a bool value indicating success.
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
|
||||
@@ -135,6 +135,54 @@ idaman bool ida_export py_create_switch_xrefs(
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
struct cases_and_targets_t
|
||||
{
|
||||
casevec_t cases;
|
||||
eavec_t targets;
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
#<pydoc>
|
||||
def calc_switch_cases(insn_ea, si):
|
||||
"""
|
||||
Get information about a switch's cases.
|
||||
|
||||
The returned information can be used as follows:
|
||||
|
||||
for idx in xrange(len(results.cases)):
|
||||
cur_case = results.cases[idx]
|
||||
for cidx in xrange(len(cur_case)):
|
||||
print "case: %d" % cur_case[cidx]
|
||||
print " goto 0x%x" % results.targets[idx]
|
||||
|
||||
@param insn_ea: address of the 'indirect jump' instruction
|
||||
@param si: switch information
|
||||
|
||||
@return: a structure with 2 members: 'cases', and 'targets'.
|
||||
"""
|
||||
pass
|
||||
#</pydoc>
|
||||
*/
|
||||
idaman cases_and_targets_t *ida_export py_calc_switch_cases(
|
||||
ea_t insn_ea,
|
||||
PyObject *py_swi)
|
||||
{
|
||||
switch_info_ex_t *swi = switch_info_ex_t_get_clink(py_swi);
|
||||
if ( swi == NULL )
|
||||
return NULL;
|
||||
|
||||
cases_and_targets_t *ct = new cases_and_targets_t;
|
||||
if ( !calc_switch_cases(insn_ea, swi, &ct->cases, &ct->targets) )
|
||||
{
|
||||
delete ct;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return ct;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
/*
|
||||
|
||||
+43
-1
@@ -532,7 +532,49 @@ char idc_get_local_type_name(int ordinal, char *buf, size_t bufsize)
|
||||
qstrncpy(buf, name, bufsize);
|
||||
return true;
|
||||
}
|
||||
|
||||
//</inline(py_typeinf)>
|
||||
|
||||
//<code(py_typeinf)>
|
||||
//-------------------------------------------------------------------------
|
||||
// A set of tinfo_t objects that were created from IDAPython.
|
||||
// This is necessary in order to clear all the "type details" that are
|
||||
// associated, in the kernel, with the tinfo_t instances.
|
||||
//
|
||||
// Unfortunately the IDAPython plugin has to terminate _after_ the IDB is
|
||||
// closed, but the "type details" must be cleared _before_ the IDB is closed.
|
||||
static qvector<tinfo_t*> python_tinfos;
|
||||
void til_clear_python_tinfo_t_instances(void)
|
||||
{
|
||||
// Pre-emptive strike: clear all the python-exposed tinfo_t instances: if that
|
||||
// were not done here, ~tinfo_t() calls happening as part of the python shutdown
|
||||
// process will try and clear() their details. ..but the kernel's til-related
|
||||
// functions will already have deleted those details at that point.
|
||||
for ( size_t i = 0, n = python_tinfos.size(); i < n; ++i )
|
||||
python_tinfos[i]->clear();
|
||||
// NOTE: Don't clear() the array of pointers. All the python-exposed tinfo_t
|
||||
// instances will be deleted through the python shutdown/ref-decrementing
|
||||
// process anyway (which will cause til_deregister_..() calls), and the
|
||||
// entries will be properly pulled out of the vector when that happens.
|
||||
}
|
||||
|
||||
void til_register_python_tinfo_t_instance(tinfo_t *tif)
|
||||
{
|
||||
// Let's add_unique() it, because every reference to an object's
|
||||
// tinfo_t property will end up trying to register it.
|
||||
python_tinfos.add_unique(tif);
|
||||
}
|
||||
|
||||
void til_deregister_python_tinfo_t_instance(tinfo_t *tif)
|
||||
{
|
||||
qvector<tinfo_t*>::iterator found = python_tinfos.find(tif);
|
||||
if ( found != python_tinfos.end() )
|
||||
{
|
||||
tif->clear();
|
||||
python_tinfos.erase(found);
|
||||
}
|
||||
}
|
||||
|
||||
//</code(py_typeinf)>
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+4
-2
@@ -746,7 +746,7 @@ static PyObject *op_t_get_value(PyObject *self)
|
||||
op_t *link = op_t_get_clink(self);
|
||||
if ( link == NULL )
|
||||
Py_RETURN_NONE;
|
||||
return Py_BuildValue("I", link->value);
|
||||
return Py_BuildValue(PY_FMT64, (pyul_t)link->value);
|
||||
}
|
||||
|
||||
static void op_t_set_value(PyObject *self, PyObject *value)
|
||||
@@ -755,7 +755,9 @@ static void op_t_set_value(PyObject *self, PyObject *value)
|
||||
op_t *link = op_t_get_clink(self);
|
||||
if ( link == NULL )
|
||||
return;
|
||||
link->value = PyInt_AsLong(value);
|
||||
uint64 v(0);
|
||||
PyW_GetNumber(value, &v);
|
||||
link->value = uval_t(v);
|
||||
}
|
||||
|
||||
static PyObject *op_t_get_addr(PyObject *self)
|
||||
|
||||
+71
-25
@@ -15,16 +15,33 @@ class py_customidamemo_t;
|
||||
class lookup_info_t
|
||||
{
|
||||
public:
|
||||
void add(TForm *form, TCustomControl *view, py_customidamemo_t *py_view)
|
||||
struct entry_t
|
||||
{
|
||||
QASSERT(0, form != NULL && view != NULL && py_view != NULL
|
||||
&& !find_by_form(NULL, NULL, form)
|
||||
&& !find_by_view(NULL, NULL, view)
|
||||
&& !find_by_py_view(NULL, NULL, py_view));
|
||||
entry_t() : form(NULL), view(NULL), py_view(NULL) {}
|
||||
private:
|
||||
TForm *form;
|
||||
TCustomControl *view;
|
||||
py_customidamemo_t *py_view;
|
||||
friend class lookup_info_t;
|
||||
};
|
||||
|
||||
entry_t &new_entry(py_customidamemo_t *py_view)
|
||||
{
|
||||
QASSERT(30454, py_view != NULL && !find_by_py_view(NULL, NULL, py_view));
|
||||
entry_t &e = entries.push_back();
|
||||
e.py_view = py_view;
|
||||
return e;
|
||||
}
|
||||
|
||||
void commit(entry_t &e, TForm *form, TCustomControl *view)
|
||||
{
|
||||
QASSERT(30455, &e >= entries.begin() && &e < entries.end());
|
||||
QASSERT(30456, form != NULL && view != NULL && e.py_view != NULL
|
||||
&& !find_by_form(NULL, NULL, form)
|
||||
&& !find_by_view(NULL, NULL, view)
|
||||
&& find_by_py_view(NULL, NULL, e.py_view));
|
||||
e.form = form;
|
||||
e.view = view;
|
||||
e.py_view = py_view;
|
||||
}
|
||||
|
||||
#define FIND_BY__BODY(crit, res1, res2) \
|
||||
@@ -62,12 +79,6 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
struct entry_t
|
||||
{
|
||||
TForm *form;
|
||||
TCustomControl *view;
|
||||
py_customidamemo_t *py_view;
|
||||
};
|
||||
typedef qvector<entry_t> entries_t;
|
||||
entries_t entries;
|
||||
};
|
||||
@@ -131,6 +142,8 @@ class py_customidamemo_t
|
||||
|
||||
static void ensure_view_callbacks_installed();
|
||||
int cb_flags;
|
||||
// number of arguments for OnViewClick implementation
|
||||
int ovc_num_args;
|
||||
|
||||
protected:
|
||||
ref_t self;
|
||||
@@ -199,6 +212,7 @@ public:
|
||||
void on_view_switched(tcc_renderer_type_t rt);
|
||||
void on_view_mouse_over(const view_mouse_event_t *event);
|
||||
inline bool has_callback(int flag) { return (cb_flags & flag) != 0; }
|
||||
int get_py_method_arg_count(char *method_name);
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -208,6 +222,7 @@ py_customidamemo_t::py_customidamemo_t()
|
||||
{
|
||||
PYGLOG("%p: py_customidamemo_t()\n", this);
|
||||
ensure_view_callbacks_installed();
|
||||
ovc_num_args = -1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -402,7 +417,7 @@ PyObject *py_customidamemo_t::create_groups(PyObject *_groups_infos)
|
||||
{
|
||||
newref_t node(PySequence_GetItem(nodes.o, k));
|
||||
if ( PyInt_Check(node.o) )
|
||||
gi.nodes.insert(PyInt_AsLong(node.o));
|
||||
gi.nodes.add_unique(PyInt_AsLong(node.o));
|
||||
}
|
||||
if ( !gi.nodes.empty() )
|
||||
{
|
||||
@@ -410,18 +425,18 @@ PyObject *py_customidamemo_t::create_groups(PyObject *_groups_infos)
|
||||
gis.push_back(gi);
|
||||
}
|
||||
}
|
||||
intset_t groups;
|
||||
intvec_t groups;
|
||||
if ( gis.empty() || !viewer_create_groups(view, &groups, gis) || groups.empty() )
|
||||
Py_RETURN_NONE;
|
||||
|
||||
PyObject *py_groups = PyList_New(0);
|
||||
for ( intset_t::const_iterator it = groups.begin(); it != groups.end(); ++it )
|
||||
for ( intvec_t::const_iterator it = groups.begin(); it != groups.end(); ++it )
|
||||
PyList_Append(py_groups, PyInt_FromLong(long(*it)));
|
||||
return py_groups;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static void pynodes_to_idanodes(intset_t *idanodes, ref_t pynodes)
|
||||
static void pynodes_to_idanodes(intvec_t *idanodes, ref_t pynodes)
|
||||
{
|
||||
Py_ssize_t sz = PySequence_Size(pynodes.o);
|
||||
for ( Py_ssize_t i = 0; i < sz; ++i )
|
||||
@@ -429,7 +444,7 @@ static void pynodes_to_idanodes(intset_t *idanodes, ref_t pynodes)
|
||||
newref_t item(PySequence_GetItem(pynodes.o, i));
|
||||
if ( !PyInt_Check(item.o) )
|
||||
continue;
|
||||
idanodes->insert(PyInt_AsLong(item.o));
|
||||
idanodes->add_unique(PyInt_AsLong(item.o));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,7 +455,7 @@ PyObject *py_customidamemo_t::delete_groups(PyObject *_groups, PyObject *_new_cu
|
||||
Py_RETURN_NONE;
|
||||
borref_t groups(_groups);
|
||||
borref_t new_current(_new_current);
|
||||
intset_t ida_groups;
|
||||
intvec_t ida_groups;
|
||||
pynodes_to_idanodes(&ida_groups, groups);
|
||||
if ( ida_groups.empty() )
|
||||
Py_RETURN_NONE;
|
||||
@@ -460,7 +475,7 @@ PyObject *py_customidamemo_t::set_groups_visibility(PyObject *_groups, PyObject
|
||||
borref_t groups(_groups);
|
||||
borref_t expand(_expand);
|
||||
borref_t new_current(_new_current);
|
||||
intset_t ida_groups;
|
||||
intvec_t ida_groups;
|
||||
pynodes_to_idanodes(&ida_groups, groups);
|
||||
if ( ida_groups.empty() )
|
||||
Py_RETURN_NONE;
|
||||
@@ -499,6 +514,23 @@ void py_customidamemo_t::unbind()
|
||||
view = NULL;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
int py_customidamemo_t::get_py_method_arg_count(char *method_name)
|
||||
{
|
||||
newref_t method(PyObject_GetAttrString(self.o, method_name));
|
||||
if ( method != NULL && PyCallable_Check(method.o) )
|
||||
{
|
||||
newref_t fc(PyObject_GetAttrString(method.o, "func_code"));
|
||||
if ( fc != NULL )
|
||||
{
|
||||
newref_t ac(PyObject_GetAttrString(fc.o, "co_argcount"));
|
||||
if ( ac != NULL )
|
||||
return PyInt_AsLong(ac.o);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
void py_customidamemo_t::collect_class_callbacks_ids(callbacks_ids_t *out)
|
||||
{
|
||||
@@ -604,12 +636,26 @@ void py_customidamemo_t::on_view_popup()
|
||||
void py_customidamemo_t::on_view_click(const view_mouse_event_t *event)
|
||||
{
|
||||
CHK_EVT(GRBASE_HAVE_VIEW_CLICK);
|
||||
newref_t result(
|
||||
PyObject_CallMethod(
|
||||
self.o,
|
||||
(char *)S_ON_VIEW_CLICK,
|
||||
"iii",
|
||||
event->x, event->y, event->state));
|
||||
if ( ovc_num_args < 0 )
|
||||
ovc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_CLICK);
|
||||
if ( ovc_num_args == 5 )
|
||||
{
|
||||
newref_t result(
|
||||
PyObject_CallMethod(
|
||||
self.o,
|
||||
(char *)S_ON_VIEW_CLICK,
|
||||
"iiii",
|
||||
event->x, event->y, event->state, event->button));
|
||||
}
|
||||
else
|
||||
{
|
||||
newref_t result(
|
||||
PyObject_CallMethod(
|
||||
self.o,
|
||||
(char *)S_ON_VIEW_CLICK,
|
||||
"iii",
|
||||
event->x, event->y, event->state));
|
||||
}
|
||||
CHK_RES();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user