diff --git a/swig/kernwin.i b/swig/kernwin.i index 98458ce..4c40936 100644 --- a/swig/kernwin.i +++ b/swig/kernwin.i @@ -1,2191 +1,2191 @@ -// Ignore the va_list functions -%ignore AskUsingForm_cv; -%ignore close_form; -%ignore vaskstr; -%ignore vasktext; -%ignore add_menu_item; -%ignore vwarning; -%ignore vinfo; -%ignore vnomem; -%ignore vmsg; -%ignore show_wait_box_v; -%ignore askbuttons_cv; -%ignore askfile_cv; -%ignore askyn_cv; -%ignore askyn_v; -// Ignore these string functions. There are trivial replacements in Python. -%ignore addblanks; -%ignore trim; -%ignore skipSpaces; -%ignore stristr; - -// Ignore the cli_t class -%ignore cli_t; - -%include "typemaps.i" - -// Make askaddr(), askseg(), and asklong() return a -// tuple: (result, value) -%apply unsigned long *INOUT { sval_t *value }; -%rename (_asklong) asklong; -%apply unsigned long *INOUT { ea_t *addr }; -%rename (_askaddr) askaddr; -%apply unsigned long *INOUT { sel_t *sel }; -%rename (_askseg) askseg; - -%inline %{ -void refresh_lists(void) -{ - callui(ui_list); -} -%} - -%pythoncode %{ -def asklong(defval, format): - res, val = _idaapi._asklong(defval, format) - - if res == 1: - return val - else: - return None - -def askaddr(defval, format): - res, ea = _idaapi._askaddr(defval, format) - - if res == 1: - return ea - else: - return None - -def askseg(defval, format): - res, sel = _idaapi._askseg(defval, format) - - if res == 1: - return sel - else: - return None - -%} - -# This is for get_cursor() -%apply int *OUTPUT {int *x, int *y}; - -# This is for read_selection() -%apply unsigned long *OUTPUT { ea_t *ea1, ea_t *ea2 }; - -%{ - -// - -//--------------------------------------------------------------------------- -// Base class for all custviewer place_t providers -class custviewer_data_t -{ -public: - virtual void *get_ud() = 0; - virtual place_t *get_min() = 0; - virtual place_t *get_max() = 0; -}; - -//--------------------------------------------------------------------------- -class cvdata_simpleline_t: public custviewer_data_t -{ -private: - strvec_t lines; - simpleline_place_t pl_min, pl_max; -public: - void *get_ud() - { - return &lines; - } - place_t *get_min() - { - return &pl_min; - } - place_t *get_max() - { - return &pl_max; - } - strvec_t &get_lines() - { - return lines; - } - void set_minmax(size_t start=size_t(-1), size_t end=size_t(-1)) - { - if ( start == size_t(-1) && end == size_t(-1) ) - { - end = lines.size(); - pl_min.n = 0; - pl_max.n = end == 0 ? 0 : end - 1; - } - else - { - pl_min.n = start; - pl_max.n = end; - } - } - bool set_line(size_t nline, simpleline_t &sl) - { - if ( nline >= lines.size() ) - return false; - lines[nline] = sl; - return true; - } - bool del_line(size_t nline) - { - if ( nline >= lines.size() ) - return false; - lines.erase(lines.begin()+nline); - return true; - } - void add_line(simpleline_t &line) - { - lines.push_back(line); - } - void add_line(const char *str) - { - lines.push_back(simpleline_t(str)); - } - bool insert_line(size_t nline, simpleline_t &line) - { - if ( nline >= lines.size() ) - return false; - lines.insert(lines.begin()+nline, line); - return true; - } - bool patch_line(size_t nline, size_t offs, int value) - { - if ( nline >= lines.size() ) - return false; - qstring &L = lines[nline].line; - L[offs] = (uchar) value & 0xFF; - return true; - } - const size_t to_lineno(place_t *pl) const - { - return ((simpleline_place_t *)pl)->n; - } - bool curline(place_t *pl, size_t *n) - { - if ( pl == NULL ) - return false; - *n = to_lineno(pl); - return true; - } - simpleline_t *get_line(size_t nline) - { - return nline >= lines.size() ? NULL : &lines[nline]; - } - simpleline_t *get_line(place_t *pl) - { - return pl == NULL ? NULL : get_line(((simpleline_place_t *)pl)->n); - } - const size_t count() const - { - return lines.size(); - } - void clear_lines() - { - lines.clear(); - set_minmax(); - } -}; - -//--------------------------------------------------------------------------- -class customviewer_t -{ -protected: - qstring _title; - TForm *_form; - TCustomControl *_cv; - custviewer_data_t *_data; - int _features; - enum - { - HAVE_HINT = 0x0001, - HAVE_KEYDOWN = 0x0002, - HAVE_POPUP = 0x0004, - HAVE_DBLCLICK = 0x0008, - HAVE_CURPOS = 0x0010, - HAVE_CLICK = 0x0020, - HAVE_CLOSE = 0x0040 - }; -private: - struct pyw_popupctx_t - { - size_t menu_id; - customviewer_t *cv; - pyw_popupctx_t(): menu_id(0), cv(NULL) { } - pyw_popupctx_t(size_t mid, customviewer_t *v): menu_id(mid), cv(v) { } - }; - typedef std::map pyw_popupmap_t; - static pyw_popupmap_t _global_popup_map; - static size_t _global_popup_id; - qstring _curline; - intvec_t _installed_popups; - - static bool idaapi s_popup_cb(void *ud) - { - customviewer_t *_this = (customviewer_t *)ud; - return _this->on_popup(); - } - - static bool idaapi s_popup_menu_cb(void *ud) - { - size_t mid = (size_t)ud; - pyw_popupmap_t::iterator it = _global_popup_map.find(mid); - if ( it == _global_popup_map.end() ) - return false; - return it->second.cv->on_popup_menu(it->second.menu_id); - } - - static bool idaapi s_cv_keydown(TCustomControl * /*cv*/, int vk_key, int shift, void *ud) - { - customviewer_t *_this = (customviewer_t *)ud; - return _this->on_keydown(vk_key, shift); - } - // The popup menu is being constructed - static void idaapi s_cv_popup(TCustomControl * /*cv*/, void *ud) - { - customviewer_t *_this = (customviewer_t *)ud; - _this->on_popup(); - } - // The user clicked - static bool idaapi s_cv_click(TCustomControl *cv, int shift, void *ud) - { - customviewer_t *_this = (customviewer_t *)ud; - return _this->on_click(shift); - } - // The user double clicked - static bool idaapi s_cv_dblclick(TCustomControl * /*cv*/, int shift, void *ud) - { - customviewer_t *_this = (customviewer_t *)ud; - return _this->on_dblclick(shift); - } - // Cursor position has been changed - static void idaapi s_cv_curpos(TCustomControl * /*cv*/, void *ud) - { - customviewer_t *_this = (customviewer_t *)ud; - _this->on_curpos_changed(); - } - - //-------------------------------------------------------------------------- - static int idaapi s_ui_cb(void *ud, int code, va_list va) - { - customviewer_t *_this = (customviewer_t *)ud; - switch ( code ) - { - case ui_get_custom_viewer_hint: - { - TCustomControl *viewer = va_arg(va, TCustomControl *); - place_t *place = va_arg(va, place_t *); - int *important_lines = va_arg(va, int *); - qstring &hint = *va_arg(va, qstring *); - return ((_this->_features & HAVE_HINT) == 0 || place == NULL || _this->_cv != viewer) ? 0 : (_this->on_hint(place, important_lines, hint) ? 1 : 0); - } - case ui_tform_invisible: - { - TForm *form = va_arg(va, TForm *); - if ( _this->_form != form ) - break; - unhook_from_notification_point(HT_UI, s_ui_cb, _this); - _this->on_close(); - _this->on_post_close(); - } - break; - } - return 0; - } - - void on_post_close() - { - init_vars(); - clear_popup_menu(); - } - -public: - // All the overridable callbacks - // OnClick - virtual bool on_click(int /*shift*/) { return false; } - // OnDblClick - virtual bool on_dblclick(int /*shift*/) { return false; } - // OnCurorPositionChanged - virtual void on_curpos_changed() { } - // OnHostFormClose - virtual void on_close() { } - // OnKeyDown - virtual bool on_keydown(int /*vk_key*/, int /*shift*/) { return false; } - // OnPopupShow - virtual bool on_popup() { return false; } - // OnHint - virtual bool on_hint(place_t * /*place*/, int * /*important_lines*/, qstring &/*hint*/) { return false; } - // OnPopupMenuClick - virtual bool on_popup_menu(size_t menu_id) { return false; } - - void init_vars() - { - _data = NULL; - _features = 0; - _curline.clear(); - _cv = NULL; - _form = NULL; - } - - customviewer_t() - { - init_vars(); - } - - ~customviewer_t() - { - } - - void close() - { - if ( _form != NULL ) - close_tform(_form, FORM_SAVE); - } - - bool set_range( - const place_t *minplace = NULL, - const place_t *maxplace = NULL) - { - if ( _cv == NULL ) - return false; - set_custom_viewer_range( - _cv, - minplace == NULL ? _data->get_min() : minplace, - maxplace == NULL ? _data->get_max() : maxplace); - return true; - } - - place_t *get_place( - bool mouse = false, - int *x = 0, - int *y = 0) - { - return _cv == NULL ? NULL : get_custom_viewer_place(_cv, mouse, x, y); - } - - //-------------------------------------------------------------------------- - bool refresh() - { - if ( _cv == NULL ) - return false; - refresh_custom_viewer(_cv); - return true; - } - - //-------------------------------------------------------------------------- - bool refresh_current(bool mouse = false) - { - int x, y; - place_t *pl = get_place(mouse, &x, &y); - if ( pl == NULL ) - return false; - return jumpto(pl, x, y); - } - - //-------------------------------------------------------------------------- - bool get_current_word(bool mouse, qstring &word) - { - // query the cursor position - int x, y; - if ( get_place(mouse, &x, &y) == NULL ) - return false; - - // query the line at the cursor - const char *line = get_current_line(mouse, true); - if ( line == NULL ) - return false; - - if ( x >= (int)strlen(line) ) - return false; - - // find the beginning of the word - const char *ptr = line + x; - while ( ptr > line && !isspace(ptr[-1]) ) - ptr--; - - // find the end of the word - const char *begin = ptr; - ptr = line + x; - while ( !isspace(*ptr) && *ptr != '\0' ) - ptr++; - - word.qclear(); - word.append(begin, ptr-begin); - return true; - } - - //-------------------------------------------------------------------------- - const char *get_current_line(bool mouse, bool notags) - { - const char *r = get_custom_viewer_curline(_cv, mouse); - if ( r == NULL || !notags ) - return r; - size_t sz = strlen(r); - if ( sz == 0 ) - return r; - _curline.resize(sz + 5, '\0'); - tag_remove(r, &_curline[0], sz + 1); - return _curline.c_str(); - } - - //-------------------------------------------------------------------------- - bool is_focused() - { - return get_current_viewer() == _cv; - } - - //-------------------------------------------------------------------------- - bool jumpto(place_t *place, int x, int y) - { - return ::jumpto(_cv, place, x, y); - } - - //-------------------------------------------------------------------------- - void clear_popup_menu() - { - if ( _cv != NULL ) - set_custom_viewer_popup_menu(_cv, NULL); - - for (intvec_t::iterator it=_installed_popups.begin(), it_end=_installed_popups.end(); - it != it_end; - ++it) - { - _global_popup_map.erase(*it); - } - _installed_popups.clear(); - } - - //-------------------------------------------------------------------------- - size_t add_popup_menu( - const char *title, - const char *hotkey) - { - size_t menu_id = _global_popup_id + 1; - // Overlap / already exists? - if (_cv == NULL || // No custviewer? - menu_id == 0 || // Overlap? - _global_popup_map.find(menu_id) != _global_popup_map.end()) // Already exists? - { - return 0; - } - add_custom_viewer_popup_item(_cv, title, hotkey, s_popup_menu_cb, (void *)menu_id); - - // Save global association - _global_popup_map[menu_id] = pyw_popupctx_t(menu_id, this); - _global_popup_id = menu_id; - - // Remember what menu IDs are set with this form - _installed_popups.push_back(menu_id); - return menu_id; - } - - //-------------------------------------------------------------------------- - bool create(const char *title, int features, custviewer_data_t *data) - { - // Already created? (in the instance) - if ( _form != NULL ) - return true; - - // Already created? (in IDA windows list) - HWND hwnd(NULL); - TForm *form = create_tform(title, &hwnd); - if ( hwnd == NULL ) - return false; - - _title = title; - _data = data; - _form = form; - _features = features; - - // Create the viewer - _cv = create_custom_viewer( - title, - (TWinControl *)_form, - _data->get_min(), - _data->get_max(), - _data->get_min(), - 0, - _data->get_ud()); - - // Set user-data - set_custom_viewer_handler(_cv, CVH_USERDATA, (void *)this); - - // - // Set other optional callbacks - // - if ( (features & HAVE_KEYDOWN) != 0 ) - set_custom_viewer_handler(_cv, CVH_KEYDOWN, (void *)s_cv_keydown); - - if ( (features & HAVE_POPUP) != 0 ) - set_custom_viewer_handler(_cv, CVH_POPUP, (void *)s_cv_popup); - - if ( (features & HAVE_DBLCLICK) != 0 ) - set_custom_viewer_handler(_cv, CVH_DBLCLICK, (void *)s_cv_dblclick); - - if ( (features & HAVE_CURPOS) != 0 ) - set_custom_viewer_handler(_cv, CVH_CURPOS, (void *)s_cv_curpos); - - if ( (features & HAVE_CLICK) != 0 ) - set_custom_viewer_handler(_cv, CVH_CLICK, (void *)s_cv_click); - - // Hook to UI notifications (for TForm close event) - hook_to_notification_point(HT_UI, s_ui_cb, this); - - return true; - } - - //-------------------------------------------------------------------------- - bool show() - { - if ( _form == NULL ) - return false; - open_tform(_form, FORM_TAB|FORM_MENU|FORM_RESTORE); - return true; - } -}; - -customviewer_t::pyw_popupmap_t customviewer_t::_global_popup_map; -size_t customviewer_t::_global_popup_id = 0; -//--------------------------------------------------------------------------- -class py_simplecustview_t: public customviewer_t -{ -private: - cvdata_simpleline_t data; - PyObject *py_self, *py_this, *py_last_link; - int features; - - // Convert a tuple (String, [color, [bgcolor]]) to a simpleline_t - static bool py_to_simpleline(PyObject *py, simpleline_t &sl) - { - if ( PyString_Check(py) ) - { - sl.line = PyString_AsString(py); - return true; - } - Py_ssize_t sz; - if ( !PyTuple_Check(py) || (sz = PyTuple_Size(py)) <= 0 ) - return false; - PyObject *py_val = PyTuple_GetItem(py, 0); - if ( !PyString_Check(py_val) ) - return false; - sl.line = PyString_AsString(py_val); - - if ( (sz > 1) && (py_val = PyTuple_GetItem(py, 1)) && PyLong_Check(py_val) ) - sl.color = color_t(PyLong_AsUnsignedLong(py_val)); - - if ( (sz > 2) && (py_val = PyTuple_GetItem(py, 2)) && PyLong_Check(py_val) ) - sl.bgcolor = PyLong_AsUnsignedLong(py_val); - return true; - } - - // - // Callbacks - // - virtual bool on_click(int shift) - { - PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_CLICK, "i", shift); - PyShowErr(S_ON_CLICK); - bool ok = py_result != NULL && PyObject_IsTrue(py_result); - Py_XDECREF(py_result); - return ok; - } - - // OnDblClick - virtual bool on_dblclick(int shift) - { - PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_DBL_CLICK, "i", shift); - PyShowErr(S_ON_DBL_CLICK); - bool ok = py_result != NULL && PyObject_IsTrue(py_result); - Py_XDECREF(py_result); - return ok; - } - - // OnCurorPositionChanged - virtual void on_curpos_changed() - { - PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_CURSOR_POS_CHANGED, NULL); - PyShowErr(S_ON_CURSOR_POS_CHANGED); - Py_XDECREF(py_result); - } - - // OnHostFormClose - virtual void on_close() - { - // Call the close method if it is there and the object is still bound - if ( (features & HAVE_CLOSE) != 0 && py_self != NULL ) - { - PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_CLOSE, NULL); - PyShowErr(S_ON_CLOSE); - Py_XDECREF(py_result); - - // Cleanup - Py_DECREF(py_self); - py_self = NULL; - } - } - - // OnKeyDown - virtual bool on_keydown(int vk_key, int shift) - { - PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_KEYDOWN, "ii", vk_key, shift); - PyShowErr(S_ON_KEYDOWN); - bool ok = py_result != NULL && PyObject_IsTrue(py_result); - Py_XDECREF(py_result); - return ok; - } - - // OnPopupShow - virtual bool on_popup() - { - PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_POPUP, NULL); - PyShowErr(S_ON_POPUP); - bool ok = py_result != NULL && PyObject_IsTrue(py_result); - Py_XDECREF(py_result); - return ok; - } - - // OnHint - virtual bool on_hint(place_t *place, int *important_lines, qstring &hint) - { - size_t ln = data.to_lineno(place); - PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_HINT, PY_FMT64, pyul_t(ln)); - PyShowErr(S_ON_HINT); - bool ok = py_result != NULL && PyString_Check(py_result); - if ( ok ) - { - if ( important_lines != NULL ) - *important_lines = 0; - hint = PyString_AsString(py_result); - } - Py_XDECREF(py_result); - return ok; - } - - // OnPopupMenuClick - virtual bool on_popup_menu(size_t menu_id) - { - PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_POPUP_MENU, PY_FMT64, pyul_t(menu_id)); - PyShowErr(S_ON_POPUP_MENU); - bool ok = py_result != NULL && PyObject_IsTrue(py_result); - Py_XDECREF(py_result); - return ok; - } - - void refresh_range() - { - data.set_minmax(); - set_range(); - } - -public: - py_simplecustview_t() - { - py_this = py_self = py_last_link = NULL; - } - ~py_simplecustview_t() - { - } - // Edits an existing line - bool edit_line(size_t nline, PyObject *py_sl) - { - simpleline_t sl; - if ( !py_to_simpleline(py_sl, sl) ) - return false; - return data.set_line(nline, sl); - } - - // Low level: patches a line string directly - bool patch_line(size_t nline, size_t offs, int value) - { - return data.patch_line(nline, offs, value); - } - - // Insert a line - bool insert_line(size_t nline, PyObject *py_sl) - { - simpleline_t sl; - if ( !py_to_simpleline(py_sl, sl) ) - return false; - return data.insert_line(nline, sl); - } - - // Adds a line tuple - bool add_line(PyObject *py_sl) - { - simpleline_t sl; - if ( !py_to_simpleline(py_sl, sl) ) - return false; - data.add_line(sl); - refresh_range(); - return true; - } - - bool del_line(size_t nline) - { - bool ok = data.del_line(nline); - if ( ok ) - refresh_range(); - return ok; - } - - // Gets the position and returns a tuple (lineno, x, y) - PyObject *get_pos(bool mouse) - { - place_t *pl; - int x, y; - pl = get_place(mouse, &x, &y); - if ( pl == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("(" PY_FMT64 "ii)", pyul_t(data.to_lineno(pl)), x, y); - } - - // Returns the line tuple - PyObject *get_line(size_t nline) - { - simpleline_t *r = data.get_line(nline); - if ( r == NULL ) - Py_RETURN_NONE; - return Py_BuildValue("(sII)", r->line.c_str(), (unsigned int)r->color, (unsigned int)r->bgcolor); - } - - // Returns the count of lines - const size_t count() const - { - return data.count(); - } - - // Clears lines - void clear() - { - data.clear_lines(); - refresh_range(); - } - - bool jumpto(size_t ln, int x, int y) - { - return customviewer_t::jumpto(&simpleline_place_t(ln), x, y); - } - - // Initializes and links the Python object to this class - bool init(PyObject *py_link, const char *title) - { - // Already created? - if ( _form != NULL ) - return true; - - // Probe callbacks - features = 0; - static struct - { - const char *cb_name; - int feature; - } const cbtable[] = - { - {S_ON_CLICK, HAVE_CLICK}, - {S_ON_CLOSE, HAVE_CLOSE}, - {S_ON_HINT, HAVE_HINT}, - {S_ON_KEYDOWN, HAVE_KEYDOWN}, - {S_ON_POPUP, HAVE_POPUP}, - {S_ON_DBL_CLICK, HAVE_DBLCLICK}, - {S_ON_CURSOR_POS_CHANGED, HAVE_CURPOS} - }; - for ( size_t i=0; i - -bool idaapi py_menu_item_callback(void *userdata) -{ - PyObject *func, *args, *result; - bool ret = 0; - - // userdata is a tuple of ( func, args ) - // func and args are borrowed references from userdata - func = PyTuple_GET_ITEM(userdata, 0); - args = PyTuple_GET_ITEM(userdata, 1); - - // call the python function - result = PyEval_CallObject(func, args); - - // we cannot raise an exception in the callback, just print it. - if (!result) { - PyErr_Print(); - return 0; - } - - // if the function returned a non-false value, then return 1 to ida, - // overwise return 0 - if (PyObject_IsTrue(result)) { - ret = 1; - } - Py_DECREF(result); - - return ret; -} -%} - -%rename (add_menu_item) wrap_add_menu_item; -%inline %{ -// - -// -// Pywraps Simple Custom Viewer functions -// -PyObject *pyscv_init(PyObject *py_link, const char *title) -{ - py_simplecustview_t *_this = new py_simplecustview_t(); - bool ok = _this->init(py_link, title); - if ( !ok ) - { - delete _this; - Py_RETURN_NONE; - } - return _this->get_pythis(); -} -#define DECL_THIS py_simplecustview_t *_this = py_simplecustview_t::get_this(py_this) - -bool pyscv_refresh(PyObject *py_this) -{ - DECL_THIS; - if ( _this == NULL ) - return false; - return _this->refresh(); -} - -bool pyscv_delete(PyObject *py_this) -{ - DECL_THIS; - if ( _this == NULL ) - return false; - _this->close(); - delete _this; - return true; -} - -bool pyscv_refresh_current(PyObject *py_this, bool mouse) -{ - DECL_THIS; - if ( _this == NULL ) - return false; - return _this->refresh_current(mouse); -} - -PyObject *pyscv_get_current_line(PyObject *py_this, bool mouse, bool notags) -{ - DECL_THIS; - const char *line; - if ( _this == NULL || (line = _this->get_current_line(mouse, notags)) == NULL ) - Py_RETURN_NONE; - return PyString_FromString(line); -} - -bool pyscv_is_focused(PyObject *py_this) -{ - DECL_THIS; - if ( _this == NULL ) - return false; - return _this->is_focused(); -} - -void pyscv_clear_popup_menu(PyObject *py_this) -{ - DECL_THIS; - if ( _this != NULL ) - _this->clear_popup_menu(); -} - -size_t pyscv_add_popup_menu(PyObject *py_this, const char *title, const char *hotkey) -{ - DECL_THIS; - return _this == NULL ? 0 : _this->add_popup_menu(title, hotkey); -} - -size_t pyscv_count(PyObject *py_this) -{ - DECL_THIS; - return _this == NULL ? 0 : _this->count(); -} - -bool pyscv_show(PyObject *py_this) -{ - DECL_THIS; - return _this == NULL ? false : _this->show(); -} - -void pyscv_close(PyObject *py_this) -{ - DECL_THIS; - if ( _this != NULL ) - _this->close(); -} - -bool pyscv_jumpto(PyObject *py_this, size_t ln, int x, int y) -{ - DECL_THIS; - if ( _this == NULL ) - return false; - return _this->jumpto(ln, x, y); -} - -// Returns the line tuple -PyObject *pyscv_get_line(PyObject *py_this, size_t nline) -{ - DECL_THIS; - if ( _this == NULL ) - Py_RETURN_NONE; - return _this->get_line(nline); -} - -// Gets the position and returns a tuple (lineno, x, y) -PyObject *pyscv_get_pos(PyObject *py_this, bool mouse) -{ - DECL_THIS; - if ( _this == NULL ) - Py_RETURN_NONE; - return _this->get_pos(mouse); -} - -PyObject *pyscv_clear_lines(PyObject *py_this) -{ - DECL_THIS; - if ( _this != NULL ) - _this->clear(); - Py_RETURN_NONE; -} - -// Adds a line tuple -bool pyscv_add_line(PyObject *py_this, PyObject *py_sl) -{ - DECL_THIS; - return _this == NULL ? false : _this->add_line(py_sl); -} - -bool pyscv_insert_line(PyObject *py_this, size_t nline, PyObject *py_sl) -{ - DECL_THIS; - return _this == NULL ? false : _this->insert_line(nline, py_sl); -} - -bool pyscv_patch_line(PyObject *py_this, size_t nline, size_t offs, int value) -{ - DECL_THIS; - return _this == NULL ? false : _this->patch_line(nline, offs, value); -} - -bool pyscv_del_line(PyObject *py_this, size_t nline) -{ - DECL_THIS; - return _this == NULL ? false : _this->del_line(nline); -} - -PyObject *pyscv_get_selection(PyObject *py_this) -{ - DECL_THIS; - if ( _this == NULL ) - Py_RETURN_NONE; - return _this->py_get_selection(); -} - -PyObject *pyscv_get_current_word(PyObject *py_this, bool mouse) -{ - DECL_THIS; - if ( _this != NULL ) - { - qstring word; - if ( _this->get_current_word(mouse, word) ) - return PyString_FromString(word.c_str()); - } - Py_RETURN_NONE; -} - -// Edits an existing line -bool pyscv_edit_line(PyObject *py_this, size_t nline, PyObject *py_sl) -{ - DECL_THIS; - return _this == NULL ? false : _this->edit_line(nline, py_sl); -} -#undef DECL_THIS -// - -// -#ifdef CH_ATTRS -PyObject *choose2_find(const char *title); -#endif -int choose2_add_command(PyObject *self, const char *caption, int flags, int menu_index, int icon); -void choose2_refresh(PyObject *self); -void choose2_close(PyObject *self); -int choose2_show(PyObject *self); -void choose2_activate(PyObject *self); -// - -bool wrap_add_menu_item ( - const char *menupath, - const char *name, - const char *hotkey, - int flags, - PyObject *pyfunc, - PyObject *args) { - // FIXME: probably should keep track of this data, and destroy it when the menu item is removed - PyObject *cb_data; - - if (args == Py_None) { - Py_DECREF(Py_None); - args = PyTuple_New( 0 ); - if (!args) - return 0; - } - - if(!PyTuple_Check(args)) { - PyErr_SetString(PyExc_TypeError, "args must be a tuple or None"); - return 0; - } - - cb_data = Py_BuildValue("(OO)", pyfunc, args); - return add_menu_item(menupath, name, hotkey, flags, py_menu_item_callback, (void *)cb_data); -} -%} - -%include "kernwin.hpp" - -uint32 choose_choose(PyObject *self, - int flags, - int x0,int y0, - int x1,int y1, - int width); -%{ - -// - -//------------------------------------------------------------------------ -// Some defines -#define POPUP_NAMES_COUNT 4 -#define MAX_CHOOSER_MENU_COMMANDS 10 -#define thisobj ((py_choose2_t *) obj) -#define thisdecl py_choose2_t *_this = thisobj -#define MENU_COMMAND_CB(id) static uint32 idaapi s_menu_command_##id(void *obj, uint32 n) { return thisobj->on_command(id, int(n)); } - -//------------------------------------------------------------------------ -// Helper functions -class py_choose2_t; -typedef std::map pychoose2_to_choose2_map_t; -static pychoose2_to_choose2_map_t choosers; - -py_choose2_t *choose2_find_instance(PyObject *self) -{ - pychoose2_to_choose2_map_t::iterator it = choosers.find(self); - if ( it == choosers.end() ) - return NULL; - return it->second; -} - -void choose2_add_instance(PyObject *self, py_choose2_t *c2) -{ - choosers[self] = c2; -} - -void choose2_del_instance(PyObject *self) -{ - pychoose2_to_choose2_map_t::iterator it = choosers.find(self); - if ( it != choosers.end() ) - choosers.erase(it); -} - -//------------------------------------------------------------------------ -class py_choose2_t -{ -private: - enum - { - CHOOSE2_HAVE_DEL = 0x0001, - CHOOSE2_HAVE_INS = 0x0002, - CHOOSE2_HAVE_UPDATE = 0x0004, - CHOOSE2_HAVE_EDIT = 0x0008, - CHOOSE2_HAVE_ENTER = 0x0010, - CHOOSE2_HAVE_GETICON = 0x0020, - CHOOSE2_HAVE_GETATTR = 0x0040, - CHOOSE2_HAVE_COMMAND = 0x0080, - CHOOSE2_HAVE_ONCLOSE = 0x0100 - }; - int flags; - int cb_flags; - qstring title; - PyObject *self; - qstrvec_t cols; - // the number of declarations should follow the MAX_CHOOSER_MENU_COMMANDS value - MENU_COMMAND_CB(0) MENU_COMMAND_CB(1) - MENU_COMMAND_CB(2) MENU_COMMAND_CB(3) - MENU_COMMAND_CB(4) MENU_COMMAND_CB(5) - MENU_COMMAND_CB(6) MENU_COMMAND_CB(7) - MENU_COMMAND_CB(8) MENU_COMMAND_CB(9) - static chooser_cb_t *menu_cbs[MAX_CHOOSER_MENU_COMMANDS]; - int menu_cb_idx; - //------------------------------------------------------------------------ - // Static methods to dispatch to member functions - //------------------------------------------------------------------------ - static int idaapi ui_cb(void *obj, int notification_code, va_list va) - { - if ( notification_code != ui_get_chooser_item_attrs ) - return 0; - va_arg(va, void *); - int n = int(va_arg(va, uint32)); - chooser_item_attrs_t *attr = va_arg(va, chooser_item_attrs_t *); - thisobj->on_get_line_attr(n, attr); - return 1; - } - static uint32 idaapi s_sizer(void *obj) - { - return (uint32)thisobj->on_get_size(); - } - static void idaapi s_getl(void *obj, uint32 n, char * const *arrptr) - { - thisobj->on_get_line(int(n), arrptr); - } - static uint32 idaapi s_del(void *obj, uint32 n) - { - return uint32(thisobj->on_delete_line(int(n))); - } - static void idaapi s_ins(void *obj) - { - thisobj->on_insert_line(); - } - static uint32 idaapi s_update(void *obj, uint32 n) - { - return uint32(thisobj->on_refresh(int(n))); - } - static void idaapi s_edit(void *obj, uint32 n) - { - thisobj->on_edit_line(int(n)); - } - static void idaapi s_enter(void * obj, uint32 n) - { - thisobj->on_select_line(int(n)); - } - static int idaapi s_get_icon(void *obj, uint32 n) - { - return thisobj->on_get_icon(int(n)); - } - static void idaapi s_destroy(void *obj) - { - thisobj->on_close(); - } -private: - //------------------------------------------------------------------------ - // Member functions corresponding to each chooser2() callback - //------------------------------------------------------------------------ - void on_get_line(int lineno, char * const *line_arr) - { - if ( lineno == 0 ) - { - for ( size_t i=0; i=0; i-- ) - line_arr[i][0] = '\0'; - - // Call Python - PyObject *list = PyObject_CallMethod(self, (char *)S_ON_GET_LINE, "i", lineno - 1); - if ( list == NULL ) - return; - for ( int i=ncols-1; i>=0; i-- ) - { - PyObject *item = PyList_GetItem(list, Py_ssize_t(i)); - if ( item == NULL ) - continue; - const char *str = PyString_AsString(item); - if ( str != NULL ) - qstrncpy(line_arr[i], str, MAXSTR); - } - Py_DECREF(list); - } - - size_t on_get_size() - { - PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_GET_SIZE, NULL); - if ( pyres == NULL ) - return 0; - size_t res = PyInt_AsLong(pyres); - Py_DECREF(pyres); - return res; - } - - void on_close() - { -#ifdef CH_ATTRS - if ( (flags & CH_ATTRS) != 0 ) - unhook_from_notification_point(HT_UI, ui_cb, this); -#endif - // Call Python - PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_CLOSE, NULL); - Py_XDECREF(pyres); - Py_XDECREF(self); - - // Remove from list - choose2_del_instance(self); - - // delete this instance if none modal - if ( (flags & CH_MODAL) == 0 ) - delete this; -} - - int on_delete_line(int lineno) - { - PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_DELETE_LINE, "i", lineno - 1); - if ( pyres == NULL ) - return lineno; - size_t res = PyInt_AsLong(pyres); - Py_DECREF(pyres); - return res + 1; - } - - int on_refresh(int lineno) - { - PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_REFRESH, "i", lineno - 1); - if ( pyres == NULL ) - return lineno; - size_t res = PyInt_AsLong(pyres); - Py_DECREF(pyres); - return res + 1; - } - - void on_insert_line() - { - PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_INSERT_LINE, NULL); - Py_XDECREF(pyres); - } - - void on_select_line(int lineno) - { - PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_SELECT_LINE, "i", lineno - 1); - Py_XDECREF(pyres); - } - - void on_edit_line(int lineno) - { - PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_EDIT_LINE, "i", lineno - 1); - Py_XDECREF(pyres); - } - - int on_command(int cmd_id, int lineno) - { - PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_COMMAND, "ii", lineno - 1, cmd_id); - if ( pyres==NULL ) - return lineno; - size_t res = PyInt_AsLong(pyres); - Py_XDECREF(pyres); - return res; - } - - int on_get_icon(int lineno) - { - PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_GET_ICON, "i", lineno - 1); - size_t res = PyInt_AsLong(pyres); - Py_XDECREF(pyres); - return res; - } - void on_get_line_attr(int lineno, chooser_item_attrs_t *attr) - { - PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_GET_LINE_ATTR, "i", lineno - 1); - if ( pyres == NULL ) - return; - - if ( PyList_Check(pyres) ) - { - PyObject *item; - if ( (item = PyList_GetItem(pyres, 0)) != NULL ) - attr->color = PyInt_AsLong(item); - if ( (item = PyList_GetItem(pyres, 1)) != NULL ) - attr->flags = PyInt_AsLong(item); - } - Py_XDECREF(pyres); - } -public: - //------------------------------------------------------------------------ - // Public methods - //------------------------------------------------------------------------ - py_choose2_t() - { - flags = 0; - cb_flags = 0; - menu_cb_idx = 0; - self = NULL; - } - static py_choose2_t *find_chooser(const char *title) - { - return (py_choose2_t *) get_chooser_obj(title); - } - void close() - { - close_chooser(title.c_str()); - } - bool activate() - { - TForm *frm = find_tform(title.c_str()); - if ( frm == NULL ) - return false; - switchto_tform(frm, true); - return true; - } - - int choose2( - int fl, - int ncols, - const int *widths, - const char *title, - int deflt = -1, - // An array of 4 strings: ("Insert", "Delete", "Edit", "Refresh" - const char * const *popup_names = NULL, - int icon = -1, - int x1 = -1, int y1 = -1, int x2 = -1, int y2 = -1) - { - flags = fl; - if ( (flags & CH_ATTRS) != 0 ) - { - if ( !hook_to_notification_point(HT_UI, ui_cb, this) ) - flags &= ~CH_ATTRS; - } - this->title = title; - return ::choose2( - flags, - x1, y1, x2, y2, - this, - ncols, widths, - s_sizer, - s_getl, - title, - icon, - deflt, - cb_flags & CHOOSE2_HAVE_DEL ? s_del : NULL, - cb_flags & CHOOSE2_HAVE_INS ? s_ins : NULL, - cb_flags & CHOOSE2_HAVE_UPDATE ? s_update : NULL, - cb_flags & CHOOSE2_HAVE_EDIT ? s_edit : NULL, - cb_flags & CHOOSE2_HAVE_ENTER ? s_enter : NULL, - s_destroy, - popup_names, - cb_flags & CHOOSE2_HAVE_GETICON ? s_get_icon : NULL); - } - - int add_command(const char *caption, int flags=0, int menu_index=-1, int icon=-1) - { - if ( menu_cb_idx >= MAX_CHOOSER_MENU_COMMANDS ) - return -1; - bool ret = add_chooser_command(title.c_str(), caption, menu_cbs[menu_cb_idx], menu_index, icon, flags); - if ( !ret ) - return -1; - return menu_cb_idx++; - } - - int show(PyObject *self) - { - PyObject *attr; - // get title - if ( (attr = PyObject_TryGetAttrString(self, "title")) == NULL ) - return -1; - qstring title = PyString_AsString(attr); - Py_DECREF(attr); - - // get flags - if ( (attr = PyObject_TryGetAttrString(self, "flags")) == NULL ) - return -1; - int flags = PyInt_AsLong(attr); - Py_DECREF(attr); - - // get columns - if ( (attr = PyObject_TryGetAttrString(self, "cols")) == NULL ) - return -1; - - // get col count - int ncols = PyList_Size(attr); - - // get cols caption and widthes - intvec_t widths; - cols.qclear(); - for ( int i=0; iself = self; - - // Create chooser - int r = this->choose2(flags, ncols, &widths[0], title.c_str(), deflt, popup_names, icon, pts[0], pts[1], pts[2], pts[3]); - - // Clear temporary popup_names - if ( popup_names != NULL ) - { - for ( int i=0; iactivate(); - return 1; - } - c2 = new py_choose2_t(); - choose2_add_instance(self, c2); - return c2->show(self); -} - -//------------------------------------------------------------------------ -void choose2_close(PyObject *self) -{ - py_choose2_t *c2 = choose2_find_instance(self); - if ( c2 != NULL ) - c2->close(); -} - -//------------------------------------------------------------------------ -void choose2_refresh(PyObject *self) -{ - py_choose2_t *c2 = choose2_find_instance(self); - if ( c2 != NULL ) - c2->refresh(); -} - -//------------------------------------------------------------------------ -void choose2_activate(PyObject *self) -{ - py_choose2_t *c2 = choose2_find_instance(self); - if ( c2 != NULL ) - c2->activate(); -} - -//------------------------------------------------------------------------ -int choose2_add_command(PyObject *self, const char *caption, int flags=0, int menu_index=-1, int icon=-1) -{ - py_choose2_t *c2 = choose2_find_instance(self); - if ( c2 != NULL ) - return c2->add_command(caption, flags, menu_index, icon); - else - return -2; -} - -//------------------------------------------------------------------------ -#ifdef CH_ATTRS -PyObject *choose2_find(const char *title) -{ - py_choose2_t *c2 = py_choose2_t::find_chooser(title); - if ( c2 == NULL ) - return NULL; - return c2->get_self(); -} -#endif -// -uint32 idaapi choose_sizer(void *self) -{ - PyObject *pyres; - uint32 res; - - pyres = PyObject_CallMethod((PyObject *)self, "sizer", ""); - res = PyInt_AsLong(pyres); - Py_DECREF(pyres); - return res; -} - -char * idaapi choose_getl(void *self, uint32 n, char *buf) -{ - PyObject *pyres; - char *res; - - pyres = PyObject_CallMethod((PyObject *)self, "getl", "l", n); - - if (!pyres) - { - strcpy(buf, ""); - return buf; - } - - res = PyString_AsString(pyres); - - if (res) - { - strncpy(buf, res, MAXSTR); - res = buf; - } - else - { - strcpy(buf, ""); - res = buf; - } - - Py_DECREF(pyres); - return res; -} - -void idaapi choose_enter(void *self, uint32 n) -{ - PyObject_CallMethod((PyObject *)self, "enter", "l", n); - return; -} - -uint32 choose_choose(void *self, - int flags, - int x0,int y0, - int x1,int y1, - int width) -{ - PyObject *pytitle; - const char *title; - if ((pytitle = PyObject_GetAttrString((PyObject *)self, "title"))) - { - title = PyString_AsString(pytitle); - } - else - { - title = "Choose"; - pytitle = NULL; - } - int r = choose( - flags, - x0, y0, - x1, y1, - self, - width, - &choose_sizer, - &choose_getl, - title, - 1, - 1, - NULL, /* del */ - NULL, /* inst */ - NULL, /* update */ - NULL, /* edit */ - &choose_enter, - NULL, /* destroy */ - NULL, /* popup_names */ - NULL /* get_icon */ - ); - Py_XDECREF(pytitle); - return r; -} -%} - -%pythoncode %{ - -class Choose: - """ - Choose - class for choose() with callbacks - """ - def __init__(self, list, title, flags=0): - self.list = list - self.title = title - - self.flags = flags - self.x0 = -1 - self.x1 = -1 - self.y0 = -1 - self.y1 = -1 - - self.width = -1 - - # HACK: Add a circular reference for non-modal choosers. This prevents the GC - # from collecting the class object the callbacks need. Unfortunately this means - # that the class will never be collected, unless refhack is set to None explicitly. - if (flags & 1) == 0: - self.refhack = self - - def sizer(self): - """ - Callback: sizer - returns the length of the list - """ - return len(self.list) - - def getl(self, n): - """ - Callback: getl - get one item from the list - """ - if n == 0: - return self.title - if n <= self.sizer(): - return str(self.list[n-1]) - else: - return "" - - def ins(self): - pass - - def update(self, n): - pass - - def edit(self, n): - pass - - def enter(self, n): - print "enter(%d) called" % n - - def destroy(self): - pass - - def get_icon(self, n): - pass - - def choose(self): - """ - choose - Display the choose dialogue - """ - return _idaapi.choose_choose(self, self.flags, self.x0, self.y0, self.x1, self.y1, self.width) - -# -class simplecustviewer_t(object): - - def __init__(self): - self.this = None - - def __del__(self): - """Destructor. It also frees the associated C++ object""" - try: - _idaapi.pyscv_delete(self.this) - except: - pass - - @staticmethod - def make_sl_arg(line, fgcolor=None, bgcolor=None): - return line if (fgcolor is None and bgcolor is None) else (line, fgcolor, bgcolor) - - def Create(self, title): - """ - Creates the custom view. This should be the first method called after instantiation - - @param title: The title of the view - @return: Boolean whether it succeeds or fails. It may fail if a window with the same title is already open. - In this case better close existing windows - """ - self.title = title - self.this = _idaapi.pyscv_init(self, title) - return True if self.this else False - - def Close(self): - """ - Destroys the view. - One has to call Create() afterwards. - Show() can be called and it will call Create() internally. - @return: Boolean - """ - return _idaapi.pyscv_close(self.this) - - def Show(self): - """ - Shows an already created view. It the view was close, then it will call Create() for you - @return: Boolean - """ - return _idaapi.pyscv_show(self.this) - - def Refresh(self): - return _idaapi.pyscv_refresh(self.this) - - def RefreshCurrent(self, mouse = 0): - """Refreshes the current line only""" - return _idaapi.pyscv_refresh_current(self.this, mouse) - - def Count(self): - """Returns the number of lines in the view""" - return _idaapi.pyscv_count(self.this) - - def GetSelection(self): - """ - Returns the selected area or None - @return: - - tuple(x1, y1, x2, y2) - - None if no selection - """ - return _idaapi.pyscv_get_selection(self.this) - - def ClearLines(self): - """Clears all the lines""" - _idaapi.pyscv_clear_lines(self.this) - - def AddLine(self, line, fgcolor=None, bgcolor=None): - """ - Adds a colored line to the view - @return: Boolean - """ - return _idaapi.pyscv_add_line(self.this, self.make_sl_arg(line, fgcolor, bgcolor)) - - def InsertLine(self, lineno, line, fgcolor=None, bgcolor=None): - """ - Inserts a line in the given position - @return Boolean - """ - return _idaapi.pyscv_insert_line(self.this, lineno, self.make_sl_arg(line, fgcolor, bgcolor)) - - def EditLine(self, lineno, line, fgcolor=None, bgcolor=None): - """ - Edits an existing line. - @return Boolean - """ - return _idaapi.pyscv_edit_line(self.this, lineno, self.make_sl_arg(line, fgcolor, bgcolor)) - - def PatchLine(self, lineno, offs, value): - """Patches an existing line character at the given offset. This is a low level function. You must know what you're doing""" - return _idaapi.pyscv_patch_line(self.this, lineno, offs, value) - - def DelLine(self, lineno): - """ - Deletes an existing line - @return Boolean - """ - return _idaapi.pyscv_del_line(self.this, lineno) - - def GetLine(self, lineno): - """ - Returns a line - @param lineno: The line number - @return: - Returns a tuple (colored_line, fgcolor, bgcolor) or None - """ - return _idaapi.pyscv_get_line(self.this, lineno) - - def GetCurrentWord(self, mouse = 0): - """ - Returns the current word - @param mouse: Use mouse position or cursor position - @return: None if failed or a String containing the current word at mouse or cursor - """ - return _idaapi.pyscv_get_current_word(self.this, mouse) - - def GetCurrentLine(self, mouse = 0, notags = 0): - """ - Returns the current line. - @param mouse: Current line at mouse pos - @param notags: If True then tag_remove() will be called before returning the line - @return: Returns the current line (colored or uncolored) - """ - return _idaapi.pyscv_get_current_line(self.this, mouse, notags) - - def GetPos(self, mouse = 0): - """ - Returns the current cursor or mouse position. - @param mouse: return mouse position - @return: Returns a tuple (lineno, x, y) - """ - return _idaapi.pyscv_get_pos(self.this, mouse) - - def GetLineNo(self, mouse = 0): - """Calls GetPos() and returns the current line number only or None on failure""" - r = self.GetPos(mouse) - return None if not r else r[0] - - def Jump(self, lineno, x=0, y=0): - return _idaapi.pyscv_jumpto(self.this, lineno, x, y) - - def AddPopupMenu(self, title, hotkey=""): - """ - Adds a popup menu item - @param title: The name of the menu item - @param hotkey: Hotkey of the item or just empty - @return: Returns the - """ - return _idaapi.pyscv_add_popup_menu(self.this, title, hotkey) - - def ClearPopupMenu(self): - """ - Clears all previously installed popup menu items. - Use this function if you're generating menu items on the fly (in the OnPopup() callback), - and before adding new items - """ - _idaapi.pyscv_clear_popup_menu(self.this) - - def IsFocused(self): - """Returns True if the current view is the focused view""" - return _idaapi.pyscv_is_focused(self.this) - - # Here are all the supported events - # Uncomment any event to enable -# def OnClick(self, shift): -# """ -# User clicked in the view -# @param shift: Shift flag -# @return Boolean. True if you handled the event -# """ -# print "OnClick, shift=%d" % shift -# return True -# -# def OnDblClick(self, shift): -# """ -# User dbl-clicked in the view -# @param shift: Shift flag -# @return Boolean. True if you handled the event -# """ -# print "OnDblClick, shift=%d" % shift -# return True -# -# def OnCursorPosChanged(self): -# """ -# Cursor position changed. -# @return Nothing -# """ -# print "OnCurposChanged" -# -# def OnClose(self): -# """ -# The view is closing. Use this event to cleanup. -# @return Nothing -# """ -# print "OnClose" -# -# def OnKeydown(self, vkey, shift): -# """ -# User pressed a key -# @param vkey: Virtual key code -# @param shift: Shift flag -# @return Boolean. True if you handled the event -# """ -# print "OnKeydown, vk=%d shift=%d" % (vkey, shift) -# return False -# -# def OnPopup(self): -# """ -# Context menu popup is about to be shown. Create items dynamically if you wish -# @return Boolean. True if you handled the event -# """ -# print "OnPopup" -# -# def OnHint(self, lineno): -# """ -# Hint requested for the given line number. -# @param lineno: The line number (zero based) -# @return: -# - string: a string containing the hint -# - None: if no hint available -# """ -# return "OnHint, line=%d" % lineno -# -# def OnPopupMenu(self, menu_id): -# """ -# A context (or popup) menu item was executed. -# @param menu_id: ID previously registered with add_popup_menu() -# @return: Boolean -# """ -# print "OnPopupMenu, menu_id=" % menu_id -# return True - -# - -# -class Choose2: - """Choose2 wrapper class""" - - # refer to kernwin.hpp for more information on how to use these constants - CH_MODAL = 0x01 - CH_MULTI = 0x02 - CH_MULTI_EDIT = 0x04 - CH_NOBTNS = 0x08 - CH_ATTRS = 0x10 - CH_BUILTIN_MASK = 0xF80000 - - # column flags (are specified in the widths array) - CHCOL_PLAIN = 0x00000000 - CHCOL_PATH = 0x00010000 - CHCOL_HEX = 0x00020000 - CHCOL_DEC = 0x00030000 - CHCOL_FORMAT = 0x00070000 - - def __init__(self, title, cols, flags=0, popup_names=None, icon=-1, x1=-1, y1=-1, x2=-1, y2=-1): - self.title = title - self.flags = flags - # a list of colums; each list item is a list of two items - # example: [ ["Address", 10 | Choose2.CHCOL_HEX], ["Name", 30 | CHCOL_PLAIN] ] - self.cols = cols - self.deflt = -1 - # list of new captions to replace this list ["Insert", "Delete", "Edit", "Refresh"] - self.popup_names = popup_names - self.icon = icon - self.x1 = x1 - self.y1 = y1 - self.x2 = x2 - self.y2 = y2 - - def Show(self, modal=False): - """Activates or creates a chooser window""" - if modal: - self.flags |= Choose2.CH_MODAL - else: - self.flags &= ~Choose2.CH_MODAL - return _idaapi.choose2_show(self) - - def Activate(): - """Activates a visible chooser""" - return _idaapi.choose2_activate(self) - - def Refresh(): - """Causes the refresh callback to trigger""" - return _idaapi.choose2_refresh(self) - - def Close(): - """Closes the chooser""" - return _idaapi.choose2_close(self) - - def AddCommand(self, caption, flags = _idaapi.CHOOSER_POPUP_MENU, menu_index=-1,icon = -1): - """Adds a new chooser command - Save the returned value and later use it in the OnCommand handler - - @return: Returns a negative value on failure or the command index - """ - return _idaapi.choose2_add_command(self, caption, flags, menu_index, icon) - - # - # Implement these methods in the subclass: - # - -# def OnClose(self): -# # return nothing -# pass - -# def OnEditLine(self, n): -# # return nothing (mandatory callback) -# pass - -# def OnInsertLine(self): -# # return nothing -# pass - -# def OnSelectLine(self, n): -# # return nothing -# pass - -# def OnGetLine(self, n): -# # return a list [col1, col2, col3, ...] describing the n-th line -# return ["col1", "col2", ...] - -# def OnGetSize(self): -# # return the size (mandatory callback) -# return len(self.the_list) - -# def OnDeleteLine(self, n): -# # return new line number -# return self.n - -# def OnRefresh(self, n): -# # return new line number -# return self.n - -# def OnCommand(self, n, cmd_id): -# # return int ; check add_chooser_command() -# return 0 - -# def OnGetIcon(self, n): -# # return icon number (or -1) -# return -1 - -# def OnGetLineAttr(self, n): -# # return list [color, flags] or None; check chooser_item_attrs_t -# pass -# -%} +// Ignore the va_list functions +%ignore AskUsingForm_cv; +%ignore close_form; +%ignore vaskstr; +%ignore vasktext; +%ignore add_menu_item; +%ignore vwarning; +%ignore vinfo; +%ignore vnomem; +%ignore vmsg; +%ignore show_wait_box_v; +%ignore askbuttons_cv; +%ignore askfile_cv; +%ignore askyn_cv; +%ignore askyn_v; +// Ignore these string functions. There are trivial replacements in Python. +%ignore addblanks; +%ignore trim; +%ignore skipSpaces; +%ignore stristr; + +// Ignore the cli_t class +%ignore cli_t; + +%include "typemaps.i" + +// Make askaddr(), askseg(), and asklong() return a +// tuple: (result, value) +%apply unsigned long *INOUT { sval_t *value }; +%rename (_asklong) asklong; +%apply unsigned long *INOUT { ea_t *addr }; +%rename (_askaddr) askaddr; +%apply unsigned long *INOUT { sel_t *sel }; +%rename (_askseg) askseg; + +%inline %{ +void refresh_lists(void) +{ + callui(ui_list); +} +%} + +%pythoncode %{ +def asklong(defval, format): + res, val = _idaapi._asklong(defval, format) + + if res == 1: + return val + else: + return None + +def askaddr(defval, format): + res, ea = _idaapi._askaddr(defval, format) + + if res == 1: + return ea + else: + return None + +def askseg(defval, format): + res, sel = _idaapi._askseg(defval, format) + + if res == 1: + return sel + else: + return None + +%} + +# This is for get_cursor() +%apply int *OUTPUT {int *x, int *y}; + +# This is for read_selection() +%apply unsigned long *OUTPUT { ea_t *ea1, ea_t *ea2 }; + +%{ + +// + +//--------------------------------------------------------------------------- +// Base class for all custviewer place_t providers +class custviewer_data_t +{ +public: + virtual void *get_ud() = 0; + virtual place_t *get_min() = 0; + virtual place_t *get_max() = 0; +}; + +//--------------------------------------------------------------------------- +class cvdata_simpleline_t: public custviewer_data_t +{ +private: + strvec_t lines; + simpleline_place_t pl_min, pl_max; +public: + void *get_ud() + { + return &lines; + } + place_t *get_min() + { + return &pl_min; + } + place_t *get_max() + { + return &pl_max; + } + strvec_t &get_lines() + { + return lines; + } + void set_minmax(size_t start=size_t(-1), size_t end=size_t(-1)) + { + if ( start == size_t(-1) && end == size_t(-1) ) + { + end = lines.size(); + pl_min.n = 0; + pl_max.n = end == 0 ? 0 : end - 1; + } + else + { + pl_min.n = start; + pl_max.n = end; + } + } + bool set_line(size_t nline, simpleline_t &sl) + { + if ( nline >= lines.size() ) + return false; + lines[nline] = sl; + return true; + } + bool del_line(size_t nline) + { + if ( nline >= lines.size() ) + return false; + lines.erase(lines.begin()+nline); + return true; + } + void add_line(simpleline_t &line) + { + lines.push_back(line); + } + void add_line(const char *str) + { + lines.push_back(simpleline_t(str)); + } + bool insert_line(size_t nline, simpleline_t &line) + { + if ( nline >= lines.size() ) + return false; + lines.insert(lines.begin()+nline, line); + return true; + } + bool patch_line(size_t nline, size_t offs, int value) + { + if ( nline >= lines.size() ) + return false; + qstring &L = lines[nline].line; + L[offs] = (uchar) value & 0xFF; + return true; + } + const size_t to_lineno(place_t *pl) const + { + return ((simpleline_place_t *)pl)->n; + } + bool curline(place_t *pl, size_t *n) + { + if ( pl == NULL ) + return false; + *n = to_lineno(pl); + return true; + } + simpleline_t *get_line(size_t nline) + { + return nline >= lines.size() ? NULL : &lines[nline]; + } + simpleline_t *get_line(place_t *pl) + { + return pl == NULL ? NULL : get_line(((simpleline_place_t *)pl)->n); + } + const size_t count() const + { + return lines.size(); + } + void clear_lines() + { + lines.clear(); + set_minmax(); + } +}; + +//--------------------------------------------------------------------------- +class customviewer_t +{ +protected: + qstring _title; + TForm *_form; + TCustomControl *_cv; + custviewer_data_t *_data; + int _features; + enum + { + HAVE_HINT = 0x0001, + HAVE_KEYDOWN = 0x0002, + HAVE_POPUP = 0x0004, + HAVE_DBLCLICK = 0x0008, + HAVE_CURPOS = 0x0010, + HAVE_CLICK = 0x0020, + HAVE_CLOSE = 0x0040 + }; +private: + struct pyw_popupctx_t + { + size_t menu_id; + customviewer_t *cv; + pyw_popupctx_t(): menu_id(0), cv(NULL) { } + pyw_popupctx_t(size_t mid, customviewer_t *v): menu_id(mid), cv(v) { } + }; + typedef std::map pyw_popupmap_t; + static pyw_popupmap_t _global_popup_map; + static size_t _global_popup_id; + qstring _curline; + intvec_t _installed_popups; + + static bool idaapi s_popup_cb(void *ud) + { + customviewer_t *_this = (customviewer_t *)ud; + return _this->on_popup(); + } + + static bool idaapi s_popup_menu_cb(void *ud) + { + size_t mid = (size_t)ud; + pyw_popupmap_t::iterator it = _global_popup_map.find(mid); + if ( it == _global_popup_map.end() ) + return false; + return it->second.cv->on_popup_menu(it->second.menu_id); + } + + static bool idaapi s_cv_keydown(TCustomControl * /*cv*/, int vk_key, int shift, void *ud) + { + customviewer_t *_this = (customviewer_t *)ud; + return _this->on_keydown(vk_key, shift); + } + // The popup menu is being constructed + static void idaapi s_cv_popup(TCustomControl * /*cv*/, void *ud) + { + customviewer_t *_this = (customviewer_t *)ud; + _this->on_popup(); + } + // The user clicked + static bool idaapi s_cv_click(TCustomControl *cv, int shift, void *ud) + { + customviewer_t *_this = (customviewer_t *)ud; + return _this->on_click(shift); + } + // The user double clicked + static bool idaapi s_cv_dblclick(TCustomControl * /*cv*/, int shift, void *ud) + { + customviewer_t *_this = (customviewer_t *)ud; + return _this->on_dblclick(shift); + } + // Cursor position has been changed + static void idaapi s_cv_curpos(TCustomControl * /*cv*/, void *ud) + { + customviewer_t *_this = (customviewer_t *)ud; + _this->on_curpos_changed(); + } + + //-------------------------------------------------------------------------- + static int idaapi s_ui_cb(void *ud, int code, va_list va) + { + customviewer_t *_this = (customviewer_t *)ud; + switch ( code ) + { + case ui_get_custom_viewer_hint: + { + TCustomControl *viewer = va_arg(va, TCustomControl *); + place_t *place = va_arg(va, place_t *); + int *important_lines = va_arg(va, int *); + qstring &hint = *va_arg(va, qstring *); + return ((_this->_features & HAVE_HINT) == 0 || place == NULL || _this->_cv != viewer) ? 0 : (_this->on_hint(place, important_lines, hint) ? 1 : 0); + } + case ui_tform_invisible: + { + TForm *form = va_arg(va, TForm *); + if ( _this->_form != form ) + break; + unhook_from_notification_point(HT_UI, s_ui_cb, _this); + _this->on_close(); + _this->on_post_close(); + } + break; + } + return 0; + } + + void on_post_close() + { + init_vars(); + clear_popup_menu(); + } + +public: + // All the overridable callbacks + // OnClick + virtual bool on_click(int /*shift*/) { return false; } + // OnDblClick + virtual bool on_dblclick(int /*shift*/) { return false; } + // OnCurorPositionChanged + virtual void on_curpos_changed() { } + // OnHostFormClose + virtual void on_close() { } + // OnKeyDown + virtual bool on_keydown(int /*vk_key*/, int /*shift*/) { return false; } + // OnPopupShow + virtual bool on_popup() { return false; } + // OnHint + virtual bool on_hint(place_t * /*place*/, int * /*important_lines*/, qstring &/*hint*/) { return false; } + // OnPopupMenuClick + virtual bool on_popup_menu(size_t menu_id) { return false; } + + void init_vars() + { + _data = NULL; + _features = 0; + _curline.clear(); + _cv = NULL; + _form = NULL; + } + + customviewer_t() + { + init_vars(); + } + + ~customviewer_t() + { + } + + void close() + { + if ( _form != NULL ) + close_tform(_form, FORM_SAVE); + } + + bool set_range( + const place_t *minplace = NULL, + const place_t *maxplace = NULL) + { + if ( _cv == NULL ) + return false; + set_custom_viewer_range( + _cv, + minplace == NULL ? _data->get_min() : minplace, + maxplace == NULL ? _data->get_max() : maxplace); + return true; + } + + place_t *get_place( + bool mouse = false, + int *x = 0, + int *y = 0) + { + return _cv == NULL ? NULL : get_custom_viewer_place(_cv, mouse, x, y); + } + + //-------------------------------------------------------------------------- + bool refresh() + { + if ( _cv == NULL ) + return false; + refresh_custom_viewer(_cv); + return true; + } + + //-------------------------------------------------------------------------- + bool refresh_current(bool mouse = false) + { + int x, y; + place_t *pl = get_place(mouse, &x, &y); + if ( pl == NULL ) + return false; + return jumpto(pl, x, y); + } + + //-------------------------------------------------------------------------- + bool get_current_word(bool mouse, qstring &word) + { + // query the cursor position + int x, y; + if ( get_place(mouse, &x, &y) == NULL ) + return false; + + // query the line at the cursor + const char *line = get_current_line(mouse, true); + if ( line == NULL ) + return false; + + if ( x >= (int)strlen(line) ) + return false; + + // find the beginning of the word + const char *ptr = line + x; + while ( ptr > line && !isspace(ptr[-1]) ) + ptr--; + + // find the end of the word + const char *begin = ptr; + ptr = line + x; + while ( !isspace(*ptr) && *ptr != '\0' ) + ptr++; + + word.qclear(); + word.append(begin, ptr-begin); + return true; + } + + //-------------------------------------------------------------------------- + const char *get_current_line(bool mouse, bool notags) + { + const char *r = get_custom_viewer_curline(_cv, mouse); + if ( r == NULL || !notags ) + return r; + size_t sz = strlen(r); + if ( sz == 0 ) + return r; + _curline.resize(sz + 5, '\0'); + tag_remove(r, &_curline[0], sz + 1); + return _curline.c_str(); + } + + //-------------------------------------------------------------------------- + bool is_focused() + { + return get_current_viewer() == _cv; + } + + //-------------------------------------------------------------------------- + bool jumpto(place_t *place, int x, int y) + { + return ::jumpto(_cv, place, x, y); + } + + //-------------------------------------------------------------------------- + void clear_popup_menu() + { + if ( _cv != NULL ) + set_custom_viewer_popup_menu(_cv, NULL); + + for (intvec_t::iterator it=_installed_popups.begin(), it_end=_installed_popups.end(); + it != it_end; + ++it) + { + _global_popup_map.erase(*it); + } + _installed_popups.clear(); + } + + //-------------------------------------------------------------------------- + size_t add_popup_menu( + const char *title, + const char *hotkey) + { + size_t menu_id = _global_popup_id + 1; + // Overlap / already exists? + if (_cv == NULL || // No custviewer? + menu_id == 0 || // Overlap? + _global_popup_map.find(menu_id) != _global_popup_map.end()) // Already exists? + { + return 0; + } + add_custom_viewer_popup_item(_cv, title, hotkey, s_popup_menu_cb, (void *)menu_id); + + // Save global association + _global_popup_map[menu_id] = pyw_popupctx_t(menu_id, this); + _global_popup_id = menu_id; + + // Remember what menu IDs are set with this form + _installed_popups.push_back(menu_id); + return menu_id; + } + + //-------------------------------------------------------------------------- + bool create(const char *title, int features, custviewer_data_t *data) + { + // Already created? (in the instance) + if ( _form != NULL ) + return true; + + // Already created? (in IDA windows list) + HWND hwnd(NULL); + TForm *form = create_tform(title, &hwnd); + if ( hwnd == NULL ) + return false; + + _title = title; + _data = data; + _form = form; + _features = features; + + // Create the viewer + _cv = create_custom_viewer( + title, + (TWinControl *)_form, + _data->get_min(), + _data->get_max(), + _data->get_min(), + 0, + _data->get_ud()); + + // Set user-data + set_custom_viewer_handler(_cv, CVH_USERDATA, (void *)this); + + // + // Set other optional callbacks + // + if ( (features & HAVE_KEYDOWN) != 0 ) + set_custom_viewer_handler(_cv, CVH_KEYDOWN, (void *)s_cv_keydown); + + if ( (features & HAVE_POPUP) != 0 ) + set_custom_viewer_handler(_cv, CVH_POPUP, (void *)s_cv_popup); + + if ( (features & HAVE_DBLCLICK) != 0 ) + set_custom_viewer_handler(_cv, CVH_DBLCLICK, (void *)s_cv_dblclick); + + if ( (features & HAVE_CURPOS) != 0 ) + set_custom_viewer_handler(_cv, CVH_CURPOS, (void *)s_cv_curpos); + + if ( (features & HAVE_CLICK) != 0 ) + set_custom_viewer_handler(_cv, CVH_CLICK, (void *)s_cv_click); + + // Hook to UI notifications (for TForm close event) + hook_to_notification_point(HT_UI, s_ui_cb, this); + + return true; + } + + //-------------------------------------------------------------------------- + bool show() + { + if ( _form == NULL ) + return false; + open_tform(_form, FORM_TAB|FORM_MENU|FORM_RESTORE); + return true; + } +}; + +customviewer_t::pyw_popupmap_t customviewer_t::_global_popup_map; +size_t customviewer_t::_global_popup_id = 0; +//--------------------------------------------------------------------------- +class py_simplecustview_t: public customviewer_t +{ +private: + cvdata_simpleline_t data; + PyObject *py_self, *py_this, *py_last_link; + int features; + + // Convert a tuple (String, [color, [bgcolor]]) to a simpleline_t + static bool py_to_simpleline(PyObject *py, simpleline_t &sl) + { + if ( PyString_Check(py) ) + { + sl.line = PyString_AsString(py); + return true; + } + Py_ssize_t sz; + if ( !PyTuple_Check(py) || (sz = PyTuple_Size(py)) <= 0 ) + return false; + PyObject *py_val = PyTuple_GetItem(py, 0); + if ( !PyString_Check(py_val) ) + return false; + sl.line = PyString_AsString(py_val); + + if ( (sz > 1) && (py_val = PyTuple_GetItem(py, 1)) && PyLong_Check(py_val) ) + sl.color = color_t(PyLong_AsUnsignedLong(py_val)); + + if ( (sz > 2) && (py_val = PyTuple_GetItem(py, 2)) && PyLong_Check(py_val) ) + sl.bgcolor = PyLong_AsUnsignedLong(py_val); + return true; + } + + // + // Callbacks + // + virtual bool on_click(int shift) + { + PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_CLICK, "i", shift); + PyShowErr(S_ON_CLICK); + bool ok = py_result != NULL && PyObject_IsTrue(py_result); + Py_XDECREF(py_result); + return ok; + } + + // OnDblClick + virtual bool on_dblclick(int shift) + { + PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_DBL_CLICK, "i", shift); + PyShowErr(S_ON_DBL_CLICK); + bool ok = py_result != NULL && PyObject_IsTrue(py_result); + Py_XDECREF(py_result); + return ok; + } + + // OnCurorPositionChanged + virtual void on_curpos_changed() + { + PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_CURSOR_POS_CHANGED, NULL); + PyShowErr(S_ON_CURSOR_POS_CHANGED); + Py_XDECREF(py_result); + } + + // OnHostFormClose + virtual void on_close() + { + // Call the close method if it is there and the object is still bound + if ( (features & HAVE_CLOSE) != 0 && py_self != NULL ) + { + PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_CLOSE, NULL); + PyShowErr(S_ON_CLOSE); + Py_XDECREF(py_result); + + // Cleanup + Py_DECREF(py_self); + py_self = NULL; + } + } + + // OnKeyDown + virtual bool on_keydown(int vk_key, int shift) + { + PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_KEYDOWN, "ii", vk_key, shift); + PyShowErr(S_ON_KEYDOWN); + bool ok = py_result != NULL && PyObject_IsTrue(py_result); + Py_XDECREF(py_result); + return ok; + } + + // OnPopupShow + virtual bool on_popup() + { + PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_POPUP, NULL); + PyShowErr(S_ON_POPUP); + bool ok = py_result != NULL && PyObject_IsTrue(py_result); + Py_XDECREF(py_result); + return ok; + } + + // OnHint + virtual bool on_hint(place_t *place, int *important_lines, qstring &hint) + { + size_t ln = data.to_lineno(place); + PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_HINT, PY_FMT64, pyul_t(ln)); + PyShowErr(S_ON_HINT); + bool ok = py_result != NULL && PyString_Check(py_result); + if ( ok ) + { + if ( important_lines != NULL ) + *important_lines = 0; + hint = PyString_AsString(py_result); + } + Py_XDECREF(py_result); + return ok; + } + + // OnPopupMenuClick + virtual bool on_popup_menu(size_t menu_id) + { + PyObject *py_result = PyObject_CallMethod(py_self, (char *)S_ON_POPUP_MENU, PY_FMT64, pyul_t(menu_id)); + PyShowErr(S_ON_POPUP_MENU); + bool ok = py_result != NULL && PyObject_IsTrue(py_result); + Py_XDECREF(py_result); + return ok; + } + + void refresh_range() + { + data.set_minmax(); + set_range(); + } + +public: + py_simplecustview_t() + { + py_this = py_self = py_last_link = NULL; + } + ~py_simplecustview_t() + { + } + // Edits an existing line + bool edit_line(size_t nline, PyObject *py_sl) + { + simpleline_t sl; + if ( !py_to_simpleline(py_sl, sl) ) + return false; + return data.set_line(nline, sl); + } + + // Low level: patches a line string directly + bool patch_line(size_t nline, size_t offs, int value) + { + return data.patch_line(nline, offs, value); + } + + // Insert a line + bool insert_line(size_t nline, PyObject *py_sl) + { + simpleline_t sl; + if ( !py_to_simpleline(py_sl, sl) ) + return false; + return data.insert_line(nline, sl); + } + + // Adds a line tuple + bool add_line(PyObject *py_sl) + { + simpleline_t sl; + if ( !py_to_simpleline(py_sl, sl) ) + return false; + data.add_line(sl); + refresh_range(); + return true; + } + + bool del_line(size_t nline) + { + bool ok = data.del_line(nline); + if ( ok ) + refresh_range(); + return ok; + } + + // Gets the position and returns a tuple (lineno, x, y) + PyObject *get_pos(bool mouse) + { + place_t *pl; + int x, y; + pl = get_place(mouse, &x, &y); + if ( pl == NULL ) + Py_RETURN_NONE; + return Py_BuildValue("(" PY_FMT64 "ii)", pyul_t(data.to_lineno(pl)), x, y); + } + + // Returns the line tuple + PyObject *get_line(size_t nline) + { + simpleline_t *r = data.get_line(nline); + if ( r == NULL ) + Py_RETURN_NONE; + return Py_BuildValue("(sII)", r->line.c_str(), (unsigned int)r->color, (unsigned int)r->bgcolor); + } + + // Returns the count of lines + const size_t count() const + { + return data.count(); + } + + // Clears lines + void clear() + { + data.clear_lines(); + refresh_range(); + } + + bool jumpto(size_t ln, int x, int y) + { + return customviewer_t::jumpto(&simpleline_place_t(ln), x, y); + } + + // Initializes and links the Python object to this class + bool init(PyObject *py_link, const char *title) + { + // Already created? + if ( _form != NULL ) + return true; + + // Probe callbacks + features = 0; + static struct + { + const char *cb_name; + int feature; + } const cbtable[] = + { + {S_ON_CLICK, HAVE_CLICK}, + {S_ON_CLOSE, HAVE_CLOSE}, + {S_ON_HINT, HAVE_HINT}, + {S_ON_KEYDOWN, HAVE_KEYDOWN}, + {S_ON_POPUP, HAVE_POPUP}, + {S_ON_DBL_CLICK, HAVE_DBLCLICK}, + {S_ON_CURSOR_POS_CHANGED, HAVE_CURPOS} + }; + for ( size_t i=0; i + +bool idaapi py_menu_item_callback(void *userdata) +{ + PyObject *func, *args, *result; + bool ret = 0; + + // userdata is a tuple of ( func, args ) + // func and args are borrowed references from userdata + func = PyTuple_GET_ITEM(userdata, 0); + args = PyTuple_GET_ITEM(userdata, 1); + + // call the python function + result = PyEval_CallObject(func, args); + + // we cannot raise an exception in the callback, just print it. + if (!result) { + PyErr_Print(); + return 0; + } + + // if the function returned a non-false value, then return 1 to ida, + // overwise return 0 + if (PyObject_IsTrue(result)) { + ret = 1; + } + Py_DECREF(result); + + return ret; +} +%} + +%rename (add_menu_item) wrap_add_menu_item; +%inline %{ +// + +// +// Pywraps Simple Custom Viewer functions +// +PyObject *pyscv_init(PyObject *py_link, const char *title) +{ + py_simplecustview_t *_this = new py_simplecustview_t(); + bool ok = _this->init(py_link, title); + if ( !ok ) + { + delete _this; + Py_RETURN_NONE; + } + return _this->get_pythis(); +} +#define DECL_THIS py_simplecustview_t *_this = py_simplecustview_t::get_this(py_this) + +bool pyscv_refresh(PyObject *py_this) +{ + DECL_THIS; + if ( _this == NULL ) + return false; + return _this->refresh(); +} + +bool pyscv_delete(PyObject *py_this) +{ + DECL_THIS; + if ( _this == NULL ) + return false; + _this->close(); + delete _this; + return true; +} + +bool pyscv_refresh_current(PyObject *py_this, bool mouse) +{ + DECL_THIS; + if ( _this == NULL ) + return false; + return _this->refresh_current(mouse); +} + +PyObject *pyscv_get_current_line(PyObject *py_this, bool mouse, bool notags) +{ + DECL_THIS; + const char *line; + if ( _this == NULL || (line = _this->get_current_line(mouse, notags)) == NULL ) + Py_RETURN_NONE; + return PyString_FromString(line); +} + +bool pyscv_is_focused(PyObject *py_this) +{ + DECL_THIS; + if ( _this == NULL ) + return false; + return _this->is_focused(); +} + +void pyscv_clear_popup_menu(PyObject *py_this) +{ + DECL_THIS; + if ( _this != NULL ) + _this->clear_popup_menu(); +} + +size_t pyscv_add_popup_menu(PyObject *py_this, const char *title, const char *hotkey) +{ + DECL_THIS; + return _this == NULL ? 0 : _this->add_popup_menu(title, hotkey); +} + +size_t pyscv_count(PyObject *py_this) +{ + DECL_THIS; + return _this == NULL ? 0 : _this->count(); +} + +bool pyscv_show(PyObject *py_this) +{ + DECL_THIS; + return _this == NULL ? false : _this->show(); +} + +void pyscv_close(PyObject *py_this) +{ + DECL_THIS; + if ( _this != NULL ) + _this->close(); +} + +bool pyscv_jumpto(PyObject *py_this, size_t ln, int x, int y) +{ + DECL_THIS; + if ( _this == NULL ) + return false; + return _this->jumpto(ln, x, y); +} + +// Returns the line tuple +PyObject *pyscv_get_line(PyObject *py_this, size_t nline) +{ + DECL_THIS; + if ( _this == NULL ) + Py_RETURN_NONE; + return _this->get_line(nline); +} + +// Gets the position and returns a tuple (lineno, x, y) +PyObject *pyscv_get_pos(PyObject *py_this, bool mouse) +{ + DECL_THIS; + if ( _this == NULL ) + Py_RETURN_NONE; + return _this->get_pos(mouse); +} + +PyObject *pyscv_clear_lines(PyObject *py_this) +{ + DECL_THIS; + if ( _this != NULL ) + _this->clear(); + Py_RETURN_NONE; +} + +// Adds a line tuple +bool pyscv_add_line(PyObject *py_this, PyObject *py_sl) +{ + DECL_THIS; + return _this == NULL ? false : _this->add_line(py_sl); +} + +bool pyscv_insert_line(PyObject *py_this, size_t nline, PyObject *py_sl) +{ + DECL_THIS; + return _this == NULL ? false : _this->insert_line(nline, py_sl); +} + +bool pyscv_patch_line(PyObject *py_this, size_t nline, size_t offs, int value) +{ + DECL_THIS; + return _this == NULL ? false : _this->patch_line(nline, offs, value); +} + +bool pyscv_del_line(PyObject *py_this, size_t nline) +{ + DECL_THIS; + return _this == NULL ? false : _this->del_line(nline); +} + +PyObject *pyscv_get_selection(PyObject *py_this) +{ + DECL_THIS; + if ( _this == NULL ) + Py_RETURN_NONE; + return _this->py_get_selection(); +} + +PyObject *pyscv_get_current_word(PyObject *py_this, bool mouse) +{ + DECL_THIS; + if ( _this != NULL ) + { + qstring word; + if ( _this->get_current_word(mouse, word) ) + return PyString_FromString(word.c_str()); + } + Py_RETURN_NONE; +} + +// Edits an existing line +bool pyscv_edit_line(PyObject *py_this, size_t nline, PyObject *py_sl) +{ + DECL_THIS; + return _this == NULL ? false : _this->edit_line(nline, py_sl); +} +#undef DECL_THIS +// + +// +#ifdef CH_ATTRS +PyObject *choose2_find(const char *title); +#endif +int choose2_add_command(PyObject *self, const char *caption, int flags, int menu_index, int icon); +void choose2_refresh(PyObject *self); +void choose2_close(PyObject *self); +int choose2_show(PyObject *self); +void choose2_activate(PyObject *self); +// + +bool wrap_add_menu_item ( + const char *menupath, + const char *name, + const char *hotkey, + int flags, + PyObject *pyfunc, + PyObject *args) { + // FIXME: probably should keep track of this data, and destroy it when the menu item is removed + PyObject *cb_data; + + if (args == Py_None) { + Py_DECREF(Py_None); + args = PyTuple_New( 0 ); + if (!args) + return 0; + } + + if(!PyTuple_Check(args)) { + PyErr_SetString(PyExc_TypeError, "args must be a tuple or None"); + return 0; + } + + cb_data = Py_BuildValue("(OO)", pyfunc, args); + return add_menu_item(menupath, name, hotkey, flags, py_menu_item_callback, (void *)cb_data); +} +%} + +%include "kernwin.hpp" + +uint32 choose_choose(PyObject *self, + int flags, + int x0,int y0, + int x1,int y1, + int width); +%{ + +// + +//------------------------------------------------------------------------ +// Some defines +#define POPUP_NAMES_COUNT 4 +#define MAX_CHOOSER_MENU_COMMANDS 10 +#define thisobj ((py_choose2_t *) obj) +#define thisdecl py_choose2_t *_this = thisobj +#define MENU_COMMAND_CB(id) static uint32 idaapi s_menu_command_##id(void *obj, uint32 n) { return thisobj->on_command(id, int(n)); } + +//------------------------------------------------------------------------ +// Helper functions +class py_choose2_t; +typedef std::map pychoose2_to_choose2_map_t; +static pychoose2_to_choose2_map_t choosers; + +py_choose2_t *choose2_find_instance(PyObject *self) +{ + pychoose2_to_choose2_map_t::iterator it = choosers.find(self); + if ( it == choosers.end() ) + return NULL; + return it->second; +} + +void choose2_add_instance(PyObject *self, py_choose2_t *c2) +{ + choosers[self] = c2; +} + +void choose2_del_instance(PyObject *self) +{ + pychoose2_to_choose2_map_t::iterator it = choosers.find(self); + if ( it != choosers.end() ) + choosers.erase(it); +} + +//------------------------------------------------------------------------ +class py_choose2_t +{ +private: + enum + { + CHOOSE2_HAVE_DEL = 0x0001, + CHOOSE2_HAVE_INS = 0x0002, + CHOOSE2_HAVE_UPDATE = 0x0004, + CHOOSE2_HAVE_EDIT = 0x0008, + CHOOSE2_HAVE_ENTER = 0x0010, + CHOOSE2_HAVE_GETICON = 0x0020, + CHOOSE2_HAVE_GETATTR = 0x0040, + CHOOSE2_HAVE_COMMAND = 0x0080, + CHOOSE2_HAVE_ONCLOSE = 0x0100 + }; + int flags; + int cb_flags; + qstring title; + PyObject *self; + qstrvec_t cols; + // the number of declarations should follow the MAX_CHOOSER_MENU_COMMANDS value + MENU_COMMAND_CB(0) MENU_COMMAND_CB(1) + MENU_COMMAND_CB(2) MENU_COMMAND_CB(3) + MENU_COMMAND_CB(4) MENU_COMMAND_CB(5) + MENU_COMMAND_CB(6) MENU_COMMAND_CB(7) + MENU_COMMAND_CB(8) MENU_COMMAND_CB(9) + static chooser_cb_t *menu_cbs[MAX_CHOOSER_MENU_COMMANDS]; + int menu_cb_idx; + //------------------------------------------------------------------------ + // Static methods to dispatch to member functions + //------------------------------------------------------------------------ + static int idaapi ui_cb(void *obj, int notification_code, va_list va) + { + if ( notification_code != ui_get_chooser_item_attrs ) + return 0; + va_arg(va, void *); + int n = int(va_arg(va, uint32)); + chooser_item_attrs_t *attr = va_arg(va, chooser_item_attrs_t *); + thisobj->on_get_line_attr(n, attr); + return 1; + } + static uint32 idaapi s_sizer(void *obj) + { + return (uint32)thisobj->on_get_size(); + } + static void idaapi s_getl(void *obj, uint32 n, char * const *arrptr) + { + thisobj->on_get_line(int(n), arrptr); + } + static uint32 idaapi s_del(void *obj, uint32 n) + { + return uint32(thisobj->on_delete_line(int(n))); + } + static void idaapi s_ins(void *obj) + { + thisobj->on_insert_line(); + } + static uint32 idaapi s_update(void *obj, uint32 n) + { + return uint32(thisobj->on_refresh(int(n))); + } + static void idaapi s_edit(void *obj, uint32 n) + { + thisobj->on_edit_line(int(n)); + } + static void idaapi s_enter(void * obj, uint32 n) + { + thisobj->on_select_line(int(n)); + } + static int idaapi s_get_icon(void *obj, uint32 n) + { + return thisobj->on_get_icon(int(n)); + } + static void idaapi s_destroy(void *obj) + { + thisobj->on_close(); + } +private: + //------------------------------------------------------------------------ + // Member functions corresponding to each chooser2() callback + //------------------------------------------------------------------------ + void on_get_line(int lineno, char * const *line_arr) + { + if ( lineno == 0 ) + { + for ( size_t i=0; i=0; i-- ) + line_arr[i][0] = '\0'; + + // Call Python + PyObject *list = PyObject_CallMethod(self, (char *)S_ON_GET_LINE, "i", lineno - 1); + if ( list == NULL ) + return; + for ( int i=ncols-1; i>=0; i-- ) + { + PyObject *item = PyList_GetItem(list, Py_ssize_t(i)); + if ( item == NULL ) + continue; + const char *str = PyString_AsString(item); + if ( str != NULL ) + qstrncpy(line_arr[i], str, MAXSTR); + } + Py_DECREF(list); + } + + size_t on_get_size() + { + PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_GET_SIZE, NULL); + if ( pyres == NULL ) + return 0; + size_t res = PyInt_AsLong(pyres); + Py_DECREF(pyres); + return res; + } + + void on_close() + { +#ifdef CH_ATTRS + if ( (flags & CH_ATTRS) != 0 ) + unhook_from_notification_point(HT_UI, ui_cb, this); +#endif + // Call Python + PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_CLOSE, NULL); + Py_XDECREF(pyres); + Py_XDECREF(self); + + // Remove from list + choose2_del_instance(self); + + // delete this instance if none modal + if ( (flags & CH_MODAL) == 0 ) + delete this; +} + + int on_delete_line(int lineno) + { + PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_DELETE_LINE, "i", lineno - 1); + if ( pyres == NULL ) + return lineno; + size_t res = PyInt_AsLong(pyres); + Py_DECREF(pyres); + return res + 1; + } + + int on_refresh(int lineno) + { + PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_REFRESH, "i", lineno - 1); + if ( pyres == NULL ) + return lineno; + size_t res = PyInt_AsLong(pyres); + Py_DECREF(pyres); + return res + 1; + } + + void on_insert_line() + { + PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_INSERT_LINE, NULL); + Py_XDECREF(pyres); + } + + void on_select_line(int lineno) + { + PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_SELECT_LINE, "i", lineno - 1); + Py_XDECREF(pyres); + } + + void on_edit_line(int lineno) + { + PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_EDIT_LINE, "i", lineno - 1); + Py_XDECREF(pyres); + } + + int on_command(int cmd_id, int lineno) + { + PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_COMMAND, "ii", lineno - 1, cmd_id); + if ( pyres==NULL ) + return lineno; + size_t res = PyInt_AsLong(pyres); + Py_XDECREF(pyres); + return res; + } + + int on_get_icon(int lineno) + { + PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_GET_ICON, "i", lineno - 1); + size_t res = PyInt_AsLong(pyres); + Py_XDECREF(pyres); + return res; + } + void on_get_line_attr(int lineno, chooser_item_attrs_t *attr) + { + PyObject *pyres = PyObject_CallMethod(self, (char *)S_ON_GET_LINE_ATTR, "i", lineno - 1); + if ( pyres == NULL ) + return; + + if ( PyList_Check(pyres) ) + { + PyObject *item; + if ( (item = PyList_GetItem(pyres, 0)) != NULL ) + attr->color = PyInt_AsLong(item); + if ( (item = PyList_GetItem(pyres, 1)) != NULL ) + attr->flags = PyInt_AsLong(item); + } + Py_XDECREF(pyres); + } +public: + //------------------------------------------------------------------------ + // Public methods + //------------------------------------------------------------------------ + py_choose2_t() + { + flags = 0; + cb_flags = 0; + menu_cb_idx = 0; + self = NULL; + } + static py_choose2_t *find_chooser(const char *title) + { + return (py_choose2_t *) get_chooser_obj(title); + } + void close() + { + close_chooser(title.c_str()); + } + bool activate() + { + TForm *frm = find_tform(title.c_str()); + if ( frm == NULL ) + return false; + switchto_tform(frm, true); + return true; + } + + int choose2( + int fl, + int ncols, + const int *widths, + const char *title, + int deflt = -1, + // An array of 4 strings: ("Insert", "Delete", "Edit", "Refresh" + const char * const *popup_names = NULL, + int icon = -1, + int x1 = -1, int y1 = -1, int x2 = -1, int y2 = -1) + { + flags = fl; + if ( (flags & CH_ATTRS) != 0 ) + { + if ( !hook_to_notification_point(HT_UI, ui_cb, this) ) + flags &= ~CH_ATTRS; + } + this->title = title; + return ::choose2( + flags, + x1, y1, x2, y2, + this, + ncols, widths, + s_sizer, + s_getl, + title, + icon, + deflt, + cb_flags & CHOOSE2_HAVE_DEL ? s_del : NULL, + cb_flags & CHOOSE2_HAVE_INS ? s_ins : NULL, + cb_flags & CHOOSE2_HAVE_UPDATE ? s_update : NULL, + cb_flags & CHOOSE2_HAVE_EDIT ? s_edit : NULL, + cb_flags & CHOOSE2_HAVE_ENTER ? s_enter : NULL, + s_destroy, + popup_names, + cb_flags & CHOOSE2_HAVE_GETICON ? s_get_icon : NULL); + } + + int add_command(const char *caption, int flags=0, int menu_index=-1, int icon=-1) + { + if ( menu_cb_idx >= MAX_CHOOSER_MENU_COMMANDS ) + return -1; + bool ret = add_chooser_command(title.c_str(), caption, menu_cbs[menu_cb_idx], menu_index, icon, flags); + if ( !ret ) + return -1; + return menu_cb_idx++; + } + + int show(PyObject *self) + { + PyObject *attr; + // get title + if ( (attr = PyObject_TryGetAttrString(self, "title")) == NULL ) + return -1; + qstring title = PyString_AsString(attr); + Py_DECREF(attr); + + // get flags + if ( (attr = PyObject_TryGetAttrString(self, "flags")) == NULL ) + return -1; + int flags = PyInt_AsLong(attr); + Py_DECREF(attr); + + // get columns + if ( (attr = PyObject_TryGetAttrString(self, "cols")) == NULL ) + return -1; + + // get col count + int ncols = PyList_Size(attr); + + // get cols caption and widthes + intvec_t widths; + cols.qclear(); + for ( int i=0; iself = self; + + // Create chooser + int r = this->choose2(flags, ncols, &widths[0], title.c_str(), deflt, popup_names, icon, pts[0], pts[1], pts[2], pts[3]); + + // Clear temporary popup_names + if ( popup_names != NULL ) + { + for ( int i=0; iactivate(); + return 1; + } + c2 = new py_choose2_t(); + choose2_add_instance(self, c2); + return c2->show(self); +} + +//------------------------------------------------------------------------ +void choose2_close(PyObject *self) +{ + py_choose2_t *c2 = choose2_find_instance(self); + if ( c2 != NULL ) + c2->close(); +} + +//------------------------------------------------------------------------ +void choose2_refresh(PyObject *self) +{ + py_choose2_t *c2 = choose2_find_instance(self); + if ( c2 != NULL ) + c2->refresh(); +} + +//------------------------------------------------------------------------ +void choose2_activate(PyObject *self) +{ + py_choose2_t *c2 = choose2_find_instance(self); + if ( c2 != NULL ) + c2->activate(); +} + +//------------------------------------------------------------------------ +int choose2_add_command(PyObject *self, const char *caption, int flags=0, int menu_index=-1, int icon=-1) +{ + py_choose2_t *c2 = choose2_find_instance(self); + if ( c2 != NULL ) + return c2->add_command(caption, flags, menu_index, icon); + else + return -2; +} + +//------------------------------------------------------------------------ +#ifdef CH_ATTRS +PyObject *choose2_find(const char *title) +{ + py_choose2_t *c2 = py_choose2_t::find_chooser(title); + if ( c2 == NULL ) + return NULL; + return c2->get_self(); +} +#endif +// +uint32 idaapi choose_sizer(void *self) +{ + PyObject *pyres; + uint32 res; + + pyres = PyObject_CallMethod((PyObject *)self, "sizer", ""); + res = PyInt_AsLong(pyres); + Py_DECREF(pyres); + return res; +} + +char * idaapi choose_getl(void *self, uint32 n, char *buf) +{ + PyObject *pyres; + char *res; + + pyres = PyObject_CallMethod((PyObject *)self, "getl", "l", n); + + if (!pyres) + { + strcpy(buf, ""); + return buf; + } + + res = PyString_AsString(pyres); + + if (res) + { + strncpy(buf, res, MAXSTR); + res = buf; + } + else + { + strcpy(buf, ""); + res = buf; + } + + Py_DECREF(pyres); + return res; +} + +void idaapi choose_enter(void *self, uint32 n) +{ + PyObject_CallMethod((PyObject *)self, "enter", "l", n); + return; +} + +uint32 choose_choose(void *self, + int flags, + int x0,int y0, + int x1,int y1, + int width) +{ + PyObject *pytitle; + const char *title; + if ((pytitle = PyObject_GetAttrString((PyObject *)self, "title"))) + { + title = PyString_AsString(pytitle); + } + else + { + title = "Choose"; + pytitle = NULL; + } + int r = choose( + flags, + x0, y0, + x1, y1, + self, + width, + &choose_sizer, + &choose_getl, + title, + 1, + 1, + NULL, /* del */ + NULL, /* inst */ + NULL, /* update */ + NULL, /* edit */ + &choose_enter, + NULL, /* destroy */ + NULL, /* popup_names */ + NULL /* get_icon */ + ); + Py_XDECREF(pytitle); + return r; +} +%} + +%pythoncode %{ + +class Choose: + """ + Choose - class for choose() with callbacks + """ + def __init__(self, list, title, flags=0): + self.list = list + self.title = title + + self.flags = flags + self.x0 = -1 + self.x1 = -1 + self.y0 = -1 + self.y1 = -1 + + self.width = -1 + + # HACK: Add a circular reference for non-modal choosers. This prevents the GC + # from collecting the class object the callbacks need. Unfortunately this means + # that the class will never be collected, unless refhack is set to None explicitly. + if (flags & 1) == 0: + self.refhack = self + + def sizer(self): + """ + Callback: sizer - returns the length of the list + """ + return len(self.list) + + def getl(self, n): + """ + Callback: getl - get one item from the list + """ + if n == 0: + return self.title + if n <= self.sizer(): + return str(self.list[n-1]) + else: + return "" + + def ins(self): + pass + + def update(self, n): + pass + + def edit(self, n): + pass + + def enter(self, n): + print "enter(%d) called" % n + + def destroy(self): + pass + + def get_icon(self, n): + pass + + def choose(self): + """ + choose - Display the choose dialogue + """ + return _idaapi.choose_choose(self, self.flags, self.x0, self.y0, self.x1, self.y1, self.width) + +# +class simplecustviewer_t(object): + + def __init__(self): + self.this = None + + def __del__(self): + """Destructor. It also frees the associated C++ object""" + try: + _idaapi.pyscv_delete(self.this) + except: + pass + + @staticmethod + def make_sl_arg(line, fgcolor=None, bgcolor=None): + return line if (fgcolor is None and bgcolor is None) else (line, fgcolor, bgcolor) + + def Create(self, title): + """ + Creates the custom view. This should be the first method called after instantiation + + @param title: The title of the view + @return: Boolean whether it succeeds or fails. It may fail if a window with the same title is already open. + In this case better close existing windows + """ + self.title = title + self.this = _idaapi.pyscv_init(self, title) + return True if self.this else False + + def Close(self): + """ + Destroys the view. + One has to call Create() afterwards. + Show() can be called and it will call Create() internally. + @return: Boolean + """ + return _idaapi.pyscv_close(self.this) + + def Show(self): + """ + Shows an already created view. It the view was close, then it will call Create() for you + @return: Boolean + """ + return _idaapi.pyscv_show(self.this) + + def Refresh(self): + return _idaapi.pyscv_refresh(self.this) + + def RefreshCurrent(self, mouse = 0): + """Refreshes the current line only""" + return _idaapi.pyscv_refresh_current(self.this, mouse) + + def Count(self): + """Returns the number of lines in the view""" + return _idaapi.pyscv_count(self.this) + + def GetSelection(self): + """ + Returns the selected area or None + @return: + - tuple(x1, y1, x2, y2) + - None if no selection + """ + return _idaapi.pyscv_get_selection(self.this) + + def ClearLines(self): + """Clears all the lines""" + _idaapi.pyscv_clear_lines(self.this) + + def AddLine(self, line, fgcolor=None, bgcolor=None): + """ + Adds a colored line to the view + @return: Boolean + """ + return _idaapi.pyscv_add_line(self.this, self.make_sl_arg(line, fgcolor, bgcolor)) + + def InsertLine(self, lineno, line, fgcolor=None, bgcolor=None): + """ + Inserts a line in the given position + @return Boolean + """ + return _idaapi.pyscv_insert_line(self.this, lineno, self.make_sl_arg(line, fgcolor, bgcolor)) + + def EditLine(self, lineno, line, fgcolor=None, bgcolor=None): + """ + Edits an existing line. + @return Boolean + """ + return _idaapi.pyscv_edit_line(self.this, lineno, self.make_sl_arg(line, fgcolor, bgcolor)) + + def PatchLine(self, lineno, offs, value): + """Patches an existing line character at the given offset. This is a low level function. You must know what you're doing""" + return _idaapi.pyscv_patch_line(self.this, lineno, offs, value) + + def DelLine(self, lineno): + """ + Deletes an existing line + @return Boolean + """ + return _idaapi.pyscv_del_line(self.this, lineno) + + def GetLine(self, lineno): + """ + Returns a line + @param lineno: The line number + @return: + Returns a tuple (colored_line, fgcolor, bgcolor) or None + """ + return _idaapi.pyscv_get_line(self.this, lineno) + + def GetCurrentWord(self, mouse = 0): + """ + Returns the current word + @param mouse: Use mouse position or cursor position + @return: None if failed or a String containing the current word at mouse or cursor + """ + return _idaapi.pyscv_get_current_word(self.this, mouse) + + def GetCurrentLine(self, mouse = 0, notags = 0): + """ + Returns the current line. + @param mouse: Current line at mouse pos + @param notags: If True then tag_remove() will be called before returning the line + @return: Returns the current line (colored or uncolored) + """ + return _idaapi.pyscv_get_current_line(self.this, mouse, notags) + + def GetPos(self, mouse = 0): + """ + Returns the current cursor or mouse position. + @param mouse: return mouse position + @return: Returns a tuple (lineno, x, y) + """ + return _idaapi.pyscv_get_pos(self.this, mouse) + + def GetLineNo(self, mouse = 0): + """Calls GetPos() and returns the current line number only or None on failure""" + r = self.GetPos(mouse) + return None if not r else r[0] + + def Jump(self, lineno, x=0, y=0): + return _idaapi.pyscv_jumpto(self.this, lineno, x, y) + + def AddPopupMenu(self, title, hotkey=""): + """ + Adds a popup menu item + @param title: The name of the menu item + @param hotkey: Hotkey of the item or just empty + @return: Returns the + """ + return _idaapi.pyscv_add_popup_menu(self.this, title, hotkey) + + def ClearPopupMenu(self): + """ + Clears all previously installed popup menu items. + Use this function if you're generating menu items on the fly (in the OnPopup() callback), + and before adding new items + """ + _idaapi.pyscv_clear_popup_menu(self.this) + + def IsFocused(self): + """Returns True if the current view is the focused view""" + return _idaapi.pyscv_is_focused(self.this) + + # Here are all the supported events + # Uncomment any event to enable +# def OnClick(self, shift): +# """ +# User clicked in the view +# @param shift: Shift flag +# @return Boolean. True if you handled the event +# """ +# print "OnClick, shift=%d" % shift +# return True +# +# def OnDblClick(self, shift): +# """ +# User dbl-clicked in the view +# @param shift: Shift flag +# @return Boolean. True if you handled the event +# """ +# print "OnDblClick, shift=%d" % shift +# return True +# +# def OnCursorPosChanged(self): +# """ +# Cursor position changed. +# @return Nothing +# """ +# print "OnCurposChanged" +# +# def OnClose(self): +# """ +# The view is closing. Use this event to cleanup. +# @return Nothing +# """ +# print "OnClose" +# +# def OnKeydown(self, vkey, shift): +# """ +# User pressed a key +# @param vkey: Virtual key code +# @param shift: Shift flag +# @return Boolean. True if you handled the event +# """ +# print "OnKeydown, vk=%d shift=%d" % (vkey, shift) +# return False +# +# def OnPopup(self): +# """ +# Context menu popup is about to be shown. Create items dynamically if you wish +# @return Boolean. True if you handled the event +# """ +# print "OnPopup" +# +# def OnHint(self, lineno): +# """ +# Hint requested for the given line number. +# @param lineno: The line number (zero based) +# @return: +# - string: a string containing the hint +# - None: if no hint available +# """ +# return "OnHint, line=%d" % lineno +# +# def OnPopupMenu(self, menu_id): +# """ +# A context (or popup) menu item was executed. +# @param menu_id: ID previously registered with add_popup_menu() +# @return: Boolean +# """ +# print "OnPopupMenu, menu_id=" % menu_id +# return True + +# + +# +class Choose2: + """Choose2 wrapper class""" + + # refer to kernwin.hpp for more information on how to use these constants + CH_MODAL = 0x01 + CH_MULTI = 0x02 + CH_MULTI_EDIT = 0x04 + CH_NOBTNS = 0x08 + CH_ATTRS = 0x10 + CH_BUILTIN_MASK = 0xF80000 + + # column flags (are specified in the widths array) + CHCOL_PLAIN = 0x00000000 + CHCOL_PATH = 0x00010000 + CHCOL_HEX = 0x00020000 + CHCOL_DEC = 0x00030000 + CHCOL_FORMAT = 0x00070000 + + def __init__(self, title, cols, flags=0, popup_names=None, icon=-1, x1=-1, y1=-1, x2=-1, y2=-1): + self.title = title + self.flags = flags + # a list of colums; each list item is a list of two items + # example: [ ["Address", 10 | Choose2.CHCOL_HEX], ["Name", 30 | CHCOL_PLAIN] ] + self.cols = cols + self.deflt = -1 + # list of new captions to replace this list ["Insert", "Delete", "Edit", "Refresh"] + self.popup_names = popup_names + self.icon = icon + self.x1 = x1 + self.y1 = y1 + self.x2 = x2 + self.y2 = y2 + + def Show(self, modal=False): + """Activates or creates a chooser window""" + if modal: + self.flags |= Choose2.CH_MODAL + else: + self.flags &= ~Choose2.CH_MODAL + return _idaapi.choose2_show(self) + + def Activate(self): + """Activates a visible chooser""" + return _idaapi.choose2_activate(self) + + def Refresh(self): + """Causes the refresh callback to trigger""" + return _idaapi.choose2_refresh(self) + + def Close(self): + """Closes the chooser""" + return _idaapi.choose2_close(self) + + def AddCommand(self, caption, flags = _idaapi.CHOOSER_POPUP_MENU, menu_index=-1,icon = -1): + """Adds a new chooser command + Save the returned value and later use it in the OnCommand handler + + @return: Returns a negative value on failure or the command index + """ + return _idaapi.choose2_add_command(self, caption, flags, menu_index, icon) + + # + # Implement these methods in the subclass: + # + +# def OnClose(self): +# # return nothing +# pass + +# def OnEditLine(self, n): +# # return nothing (mandatory callback) +# pass + +# def OnInsertLine(self): +# # return nothing +# pass + +# def OnSelectLine(self, n): +# # return nothing +# pass + +# def OnGetLine(self, n): +# # return a list [col1, col2, col3, ...] describing the n-th line +# return ["col1", "col2", ...] + +# def OnGetSize(self): +# # return the size (mandatory callback) +# return len(self.the_list) + +# def OnDeleteLine(self, n): +# # return new line number +# return self.n + +# def OnRefresh(self, n): +# # return new line number +# return self.n + +# def OnCommand(self, n, cmd_id): +# # return int ; check add_chooser_command() +# return 0 + +# def OnGetIcon(self, n): +# # return icon number (or -1) +# return -1 + +# def OnGetLineAttr(self, n): +# # return list [color, flags] or None; check chooser_item_attrs_t +# pass +# +%}