#ifndef __PYWRAPS_NOTIFY_WHEN__ #define __PYWRAPS_NOTIFY_WHEN__ //------------------------------------------------------------------------ // //------------------------------------------------------------------------ //------------------------------------------------------------------------ class pywraps_notify_when_t { ppyobject_vec_t table[NW_EVENTSCNT]; qstring err; bool in_notify; struct notify_when_args_t { int when; PyObject *py_callable; }; typedef qvector notify_when_args_vec_t; notify_when_args_vec_t delayed_notify_when_list; //------------------------------------------------------------------------ static int idaapi idp_callback(void *ud, int event_id, va_list va) { pywraps_notify_when_t *_this = (pywraps_notify_when_t *)ud; switch ( event_id ) { case processor_t::newfile: case processor_t::oldfile: { int old = event_id == processor_t::oldfile ? 1 : 0; char *dbname = va_arg(va, char *); _this->notify(NW_OPENIDB_SLOT, old); } break; case processor_t::closebase: _this->notify(NW_CLOSEIDB_SLOT); break; } // event not processed, let other plugins or the processor module handle it return 0; } //------------------------------------------------------------------------ bool unnotify_when(int when, PyObject *py_callable) { int cnt = 0; for ( int slot=0; slot 0; } //------------------------------------------------------------------------ void register_callback(int slot, PyObject *py_callable) { ppyobject_vec_t &tbl = table[slot]; ppyobject_vec_t::iterator it_end = tbl.end(), it = std::find(tbl.begin(), it_end, py_callable); // Already added if ( it != it_end ) return; // Increment reference Py_INCREF(py_callable); // Insert the element tbl.push_back(py_callable); } //------------------------------------------------------------------------ void unregister_callback(int slot, PyObject *py_callable) { ppyobject_vec_t &tbl = table[slot]; ppyobject_vec_t::iterator it_end = tbl.end(), it = std::find(tbl.begin(), it_end, py_callable); // Not found? if ( it == it_end ) return; // Decrement reference Py_DECREF(py_callable); // Delete the element tbl.erase(it); } public: //------------------------------------------------------------------------ bool init() { return hook_to_notification_point(HT_IDP, idp_callback, this); } //------------------------------------------------------------------------ bool deinit() { // Uninstall all objects ppyobject_vec_t::iterator it, it_end; for ( int slot=0; slot 0; } //------------------------------------------------------------------------ bool notify(int slot, ...) { va_list va; va_start(va, slot); bool ok = notify_va(slot, va); va_end(va); return ok; } //------------------------------------------------------------------------ bool notify_va(int slot, va_list va) { // Sanity bounds check! if ( slot < 0 || slot >= NW_EVENTSCNT ) return false; bool ok = true; in_notify = true; int old = slot == NW_OPENIDB_SLOT ? va_arg(va, int) : 0; for (ppyobject_vec_t::iterator it = table[slot].begin(), it_end = table[slot].end(); it != it_end; ++it) { // Form the notification code PyObject *py_code = PyInt_FromLong(1 << slot); PyObject *py_result(NULL); switch ( slot ) { case NW_CLOSEIDB_SLOT: case NW_INITIDA_SLOT: case NW_TERMIDA_SLOT: { PYW_GIL_ENSURE; py_result = PyObject_CallFunctionObjArgs(*it, py_code, NULL); PYW_GIL_RELEASE; break; } case NW_OPENIDB_SLOT: { PyObject *py_old = PyInt_FromLong(old); PYW_GIL_ENSURE; py_result = PyObject_CallFunctionObjArgs(*it, py_code, py_old, NULL); PYW_GIL_RELEASE; Py_DECREF(py_old); } break; } Py_DECREF(py_code); if ( PyW_GetError(&err) || py_result == NULL ) { PyErr_Clear(); warning("notify_when(): Error occured while notifying object.\n%s", err.c_str()); ok = false; } Py_XDECREF(py_result); } in_notify = false; // Process any delayed notify_when() calls that if ( !delayed_notify_when_list.empty() ) { for (notify_when_args_vec_t::iterator it = delayed_notify_when_list.begin(), it_end=delayed_notify_when_list.end(); it != it_end; ++it) { notify_when(it->when, it->py_callable); } delayed_notify_when_list.qclear(); } return ok; } //------------------------------------------------------------------------ pywraps_notify_when_t() { in_notify = false; } }; static pywraps_notify_when_t *g_nw = NULL; //------------------------------------------------------------------------ // Initializes the notify_when mechanism // (Normally called by IDAPython plugin.init()) bool pywraps_nw_init() { if ( g_nw != NULL ) return true; g_nw = new pywraps_notify_when_t(); if ( g_nw->init() ) return true; // Things went bad, undo! delete g_nw; g_nw = NULL; return false; } //------------------------------------------------------------------------ bool pywraps_nw_notify(int slot, ...) { if ( g_nw == NULL ) return false; va_list va; va_start(va, slot); bool ok = g_nw->notify_va(slot, va); va_end(va); return ok; } //------------------------------------------------------------------------ // Deinitializes the notify_when mechanism bool pywraps_nw_term() { if ( g_nw == NULL ) return true; // If could not deinitialize then return w/o stopping nw if ( !g_nw->deinit() ) return false; // Cleanup delete g_nw; g_nw = NULL; return true; } // //------------------------------------------------------------------------ // //------------------------------------------------------------------------ /* # def notify_when(when, callback): """ Register a callback that will be called when an event happens. @param when: one of NW_XXXX constants @param callback: This callback prototype varies depending on the 'when' parameter: The general callback format: def notify_when_callback(nw_code) In the case of NW_OPENIDB: def notify_when_callback(nw_code, is_old_database) @return: Boolean """ pass # */ static bool notify_when(int when, PyObject *py_callable) { if ( g_nw == NULL || !PyCallable_Check(py_callable) ) return false; return g_nw->notify_when(when, py_callable); } // //------------------------------------------------------------------------ #endif