diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2020-05-11 21:33:36 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2020-05-11 21:33:36 (GMT) |
commit | d2861533cc53fbcc217048bafebf34b1f70ba3aa (patch) | |
tree | 28c847a8093761fcaa0916be54445328d843096d /plugins/pychrysalide/glibext | |
parent | 6c9e1b5f7ee0915036d47b83f1e34b87b44b1723 (diff) |
Updated the API for buffer caches.
Diffstat (limited to 'plugins/pychrysalide/glibext')
-rw-r--r-- | plugins/pychrysalide/glibext/buffercache.c | 947 | ||||
-rw-r--r-- | plugins/pychrysalide/glibext/buffercache.h | 3 | ||||
-rw-r--r-- | plugins/pychrysalide/glibext/bufferline.c | 24 | ||||
-rw-r--r-- | plugins/pychrysalide/glibext/constants.c | 100 | ||||
-rw-r--r-- | plugins/pychrysalide/glibext/constants.h | 6 | ||||
-rw-r--r-- | plugins/pychrysalide/glibext/linegen.c | 734 | ||||
-rw-r--r-- | plugins/pychrysalide/glibext/linegen.h | 3 |
7 files changed, 1645 insertions, 172 deletions
diff --git a/plugins/pychrysalide/glibext/buffercache.c b/plugins/pychrysalide/glibext/buffercache.c index 9ce06c1..fec5844 100644 --- a/plugins/pychrysalide/glibext/buffercache.c +++ b/plugins/pychrysalide/glibext/buffercache.c @@ -28,63 +28,897 @@ #include <pygobject.h> -#include <glibext/gbuffercache.h> +#include <glibext/gbuffercache-int.h> +#include <plugins/dt.h> +#include "constants.h" +#include "bufferline.h" +#include "linegen.h" #include "../access.h" #include "../helpers.h" -#include "../arch/vmpa.h" +#include "../analysis/content.h" -#if 0 -/* Retrouve une ligne au sein d'un tampon avec une adresse. */ -static PyObject *py_code_buffer_find_line_by_addr(PyObject *, PyObject *); +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ +/* Accompagne la création d'une instance dérivée en Python. */ +static PyObject *py_buffer_cache_new(PyTypeObject *, PyObject *, PyObject *); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_buffer_cache_init(PyObject *, PyObject *, PyObject *); + + + +/* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ + + +/* Insère un générateur dans des lignes à une position donnée. */ +static PyObject *py_buffer_cache_insert_at(PyObject *, PyObject *); + +/* Retire une ligne du tampon. */ +static PyObject *py_buffer_cache_delete_at(PyObject *, PyObject *); + +/* Retire un type de générateur de lignes. */ +static PyObject *py_buffer_cache_delete_type_at(PyObject *, PyObject *); + +/* Ajoute en fin de tampon un générateur de lignes. */ +static PyObject *py_buffer_cache_append(PyObject *, PyObject *); + +/* Etend un tampon avec un générateur de lignes unique. */ +static PyObject *py_buffer_cache_extend_with(PyObject *, PyObject *); + +/* Réduit le tampon à une quantité de lignes précise. */ +static PyObject *py_buffer_cache_truncate(PyObject *, PyObject *); + +/* Détermine l'ensemble des propriétés attachées à une ligne. */ +static PyObject *py_buffer_cache_get_line_flags(PyObject *, PyObject *); + +/* Retrouve une ligne au sein d'un tampon avec un indice. */ +static PyObject *py_buffer_cache_find_line_by_index(PyObject *, PyObject *); + +/* Avance autant que possible vers une ligne idéale. */ +static PyObject *py_buffer_cache_look_for_flag(PyObject *, PyObject *); + +/* Indique l'éventuel contenu binaire associé au cache. */ +static PyObject *py_buffer_cache_get_content(PyObject *, void *); + +/* Fournit la hauteur d'impression d'une ligne visualisée. */ +static PyObject *py_buffer_cache_get_line_height(PyObject *, void *); + +/* Fournit la taille réservée pour la marge gauche. */ +static PyObject *py_buffer_cache_get_left_margin(PyObject *, void *); + +/* Fournit la position de départ pour l'impression de texte. */ +static PyObject *py_buffer_cache_get_text_position(PyObject *, void *); + +/* Compte le nombre de lignes rassemblées dans un tampon. */ +static PyObject *py_buffer_cache_get_lines_count(PyObject *, void *); + + + +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : type = type du nouvel objet à mettre en place. * +* args = éventuelle liste d'arguments. * +* kwds = éventuel dictionnaire de valeurs mises à disposition. * +* * +* Description : Accompagne la création d'une instance dérivée en Python. * +* * +* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_buffer_cache_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Objet à retourner */ + PyTypeObject *base; /* Type de base à dériver */ + bool first_time; /* Evite les multiples passages*/ + GType gtype; /* Nouveau type de processeur */ + bool status; /* Bilan d'un enregistrement */ + + /* Validations diverses */ + + base = get_python_buffer_cache_type(); + + if (type == base) + goto simple_way; + + /* Mise en place d'un type dédié */ + + first_time = (g_type_from_name(type->tp_name) == 0); + + gtype = build_dynamic_type(G_TYPE_BUFFER_CACHE, type->tp_name, NULL, NULL, NULL); + + if (first_time) + { + status = register_class_for_dynamic_pygobject(gtype, type, base); + + if (!status) + { + result = NULL; + goto exit; + } + + } + + /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ + + simple_way: + + result = PyType_GenericNew(type, args, kwds); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_buffer_cache_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GBinContent *content; /* Instance GLib du contenu */ + int ret; /* Bilan de lecture des args. */ + GBufferCache *cache; /* Version GLib du tampon */ + +#define BUFFER_CACHE_DOC \ + "The BufferCache object manages a group of lines intended to get" \ + " printed onto the screen or into a file.\n" \ + "\n" \ + "These lines are cached and rebuilt when needed.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " BufferCache(content=None)" \ + "\n" \ + "Where content is a pychrysalide.analysis.BinContent instance, if" \ + " defined. This content is provided to lines as argument when the" \ + " lines get printed, so it may not be always useful and thus can be" \ + " discarded when creating a new buffer cache." \ + + /* Récupération des paramètres */ + + content = NULL; + + ret = PyArg_ParseTuple(args, "|O&", convert_to_binary_content_or_none, &content); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + cache = G_BUFFER_CACHE(pygobject_get(self)); + + if (content != NULL) + { + cache->content = content; + g_object_ref(G_OBJECT(content)); + } + + return 0; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* TAMPON POUR CODE DESASSEMBLE */ +/* ---------------------------------------------------------------------------------- */ + /****************************************************************************** * * * Paramètres : self = classe représentant un tampon de code. * * args = arguments fournis à l'appel. * * * -* Description : Retrouve une ligne au sein d'un tampon avec une adresse. * +* Description : Insère un générateur dans des lignes à une position donnée. * * * -* Retour : Instance de la ligne trouvée. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_code_buffer_find_line_by_addr(PyObject *self, PyObject *args) +static PyObject *py_buffer_cache_insert_at(PyObject *self, PyObject *args) { PyObject *result; /* Trouvailles à retourner */ - PyObject *py_vmpa; /* Localisation version Python */ + size_t index; /* Indice de ligne à supprimer */ + GLineGenerator *generator; /* Générateur à associer */ + BufferLineFlags flags; /* Particularités nominales */ + int before; /* Insertion avant ? */ + int after; /* Insertion après ? */ int ret; /* Bilan de lecture des args. */ - vmpa2t *addr; /* Adresse visée par l'opérat° */ - GBuffercache *buffer; /* Version native */ - GBufferLine *line; /* Ligne trouvée */ + GBufferCache *cache; /* Tampon natif à consulter */ + +#define BUFFER_CACHE_INSERT_AT_METHOD PYTHON_METHOD_DEF \ +( \ + insert_at, "$self, index, generator, /, flags=" \ + "pychrysalide.glibext.BufferLine.BufferLineFlags.NONE," \ + " before=False, after=False", \ + METH_VARARGS, py_buffer_cache, \ + "Add an extra content generator to a given line.\n" \ + "\n" \ + "The new content generator for the line at, before or after" \ + " the provided index is a pychrysalide.glibext.LineGenerator" \ + " instance. Nominal properties can be set for this line as" \ + " extra pychrysalide.glibext.BufferLine.BufferLineFlags" \ + " values.\n" \ + "\n" \ + "An access lock has to be held for the cache; see the" \ + " pychrysalide.glibext.BufferCache.lock() function." \ +) - ret = PyArg_ParseTuple(args, "O", &py_vmpa); + flags = BLF_NONE; + before = 0; + after = 0; + + ret = PyArg_ParseTuple(args, "nO&|O&pp", &index, convert_to_line_generator, &generator, + convert_to_buffer_line_flags, &flags, &before, &after); if (!ret) return NULL; - ret = PyObject_IsInstance(py_vmpa, (PyObject *)get_python_vmpa_type()); + cache = G_BUFFER_CACHE(pygobject_get(self)); + + g_buffer_cache_insert_at(cache, index, generator, flags, before, after); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un tampon de code. * +* args = arguments fournis à l'appel. * +* * +* Description : Retire une ligne du tampon. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_buffer_cache_delete_at(PyObject *self, PyObject *args) +{ + PyObject *result; /* Trouvailles à retourner */ + size_t index; /* Indice de ligne à supprimer */ + int ret; /* Bilan de lecture des args. */ + GBufferCache *cache; /* Tampon natif à consulter */ + +#define BUFFER_CACHE_DELETE_AT_METHOD PYTHON_METHOD_DEF \ +( \ + delete_at, "$self, index, /", \ + METH_VARARGS, py_buffer_cache, \ + "Delete the line at the *index* position from a buffer cache.\n" \ + "\n" \ + "An access lock has to be held for the cache; see the" \ + " pychrysalide.glibext.BufferCache.lock() function." \ +) + + ret = PyArg_ParseTuple(args, "n", &index); if (!ret) return NULL; - addr = get_internal_vmpa(py_vmpa); - if (addr == NULL) return NULL; + cache = G_BUFFER_CACHE(pygobject_get(self)); + + g_buffer_cache_delete_at(cache, index); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un tampon de code. * +* args = arguments fournis à l'appel. * +* * +* Description : Retire un type de générateur de lignes. * +* * +* Retour : Générateur éventuellement trouvé ou NULL si aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_buffer_cache_delete_type_at(PyObject *self, PyObject *args) +{ + PyObject *result; /* Trouvailles à retourner */ + size_t index; /* Indice de ligne à supprimer */ + PyObject *py_gtype; /* Version Python d'un GType */ + int before; /* Insertion avant ? */ + int after; /* Insertion après ? */ + int ret; /* Bilan de lecture des args. */ + GType gtype; /* Type de générateur visé */ + GBufferCache *cache; /* Tampon natif à consulter */ + GLineGenerator *generator; /* Générateur retiré ou NULL */ + +#define BUFFER_CACHE_DELETE_TYPE_AT_METHOD PYTHON_METHOD_DEF \ +( \ + delete_type_at, "$self, index, gtype, /, before=False, after=False", \ + METH_VARARGS, py_buffer_cache, \ + "Delete the first generator of a given type found inside a line of a" \ + " buffer cache.\n" \ + "\n" \ + "The target type has to be a gobject.GType, usually provided by the" \ + " *__gtype__* attribute of a generator interface. The generator is" \ + " deleted from the line at, before or after the provided index.\n" \ + "\n" \ + "The function returns the deleted generator as a" \ + " pychrysalide.glibext.LineGenerator instance, or None if none found.\n"\ + "\n" \ + "An access lock has to be held for the cache; see the" \ + " pychrysalide.glibext.BufferCache.lock() function." \ +) + + before = 0; + after = 0; + + ret = PyArg_ParseTuple(args, "nO|pp", &index, &py_gtype, &before, &after); + if (!ret) return NULL; - buffer = G_CODE_BUFFER(pygobject_get(self)); + gtype = pyg_type_from_object(py_gtype); + if (gtype == 0) return NULL; - line = g_code_buffer_find_line_by_addr(buffer, addr, 0, NULL); - if (line == NULL) Py_RETURN_NONE; + cache = G_BUFFER_CACHE(pygobject_get(self)); - result = pygobject_new(G_OBJECT(line)); + generator = g_buffer_cache_delete_type_at(cache, index, gtype, before, after); + + if (generator != NULL) + { + result = pygobject_new(G_OBJECT(generator)); + g_object_unref(G_OBJECT(generator)); + } + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un tampon de code. * +* args = arguments fournis à l'appel. * +* * +* Description : Ajoute en fin de tampon un générateur de lignes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_buffer_cache_append(PyObject *self, PyObject *args) +{ + PyObject *result; /* Trouvailles à retourner */ + GLineGenerator *generator; /* Générateur à associer */ + BufferLineFlags flags; /* Particularités nominales */ + int ret; /* Bilan de lecture des args. */ + GBufferCache *cache; /* Tampon natif à consulter */ + +#define BUFFER_CACHE_APPEND_METHOD PYTHON_METHOD_DEF \ +( \ + append, "$self, generator, /, flags=" \ + "pychrysalide.glibext.BufferLine.BufferLineFlags.NONE", \ + METH_VARARGS, py_buffer_cache, \ + "Append a new line at the end of a buffer cache.\n" \ + "\n" \ + "The content generator for this new line is a" \ + " pychrysalide.glibext.LineGenerator instance. Nominal" \ + " properties can be set for the line as extra" \ + " pychrysalide.glibext.BufferLine.BufferLineFlags values.\n" \ + "\n" \ + "An access lock has to be held for the cache; see the" \ + " pychrysalide.glibext.BufferCache.lock() function." \ +) + + flags = BLF_NONE; + + ret = PyArg_ParseTuple(args, "O&|O&", convert_to_line_generator, &generator, + convert_to_buffer_line_flags, &flags); + if (!ret) return NULL; + + cache = G_BUFFER_CACHE(pygobject_get(self)); + + g_buffer_cache_append(cache, generator, flags); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un tampon de code. * +* args = arguments fournis à l'appel. * +* * +* Description : Etend un tampon avec un générateur de lignes unique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_buffer_cache_extend_with(PyObject *self, PyObject *args) +{ + PyObject *result; /* Trouvailles à retourner */ + size_t count; /* Quantité de lignes à créer */ + GLineGenerator *generator; /* Générateur à associer */ + int ret; /* Bilan de lecture des args. */ + GBufferCache *cache; /* Tampon natif à consulter */ + +#define BUFFER_CACHE_EXTEND_WITH_METHOD PYTHON_METHOD_DEF \ +( \ + extend_with, "$self, count, generator, /", \ + METH_VARARGS, py_buffer_cache, \ + "Extend the buffer cache so it will contain *count* lines.\n" \ + "\n" \ + "The *count* number should be greater than the current line" \ + " quantity, otherwise the call makes no sense. The generator" \ + " is a pychrysalide.glibext.LineGenerator instance used to" \ + " produce the extra new lines on demand." \ + "\n" \ + "An access lock has to be held for the cache; see the" \ + " pychrysalide.glibext.BufferCache.lock() function." \ +) + + ret = PyArg_ParseTuple(args, "nO&", &count, convert_to_line_generator, &generator); + if (!ret) return NULL; + + cache = G_BUFFER_CACHE(pygobject_get(self)); + + g_buffer_cache_extend_with(cache, count, generator); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un tampon de code. * +* args = arguments fournis à l'appel. * +* * +* Description : Réduit le tampon à une quantité de lignes précise. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_buffer_cache_truncate(PyObject *self, PyObject *args) +{ + PyObject *result; /* Trouvailles à retourner */ + size_t max; /* Nombre de lignes au maximum */ + int ret; /* Bilan de lecture des args. */ + GBufferCache *cache; /* Tampon natif à consulter */ + +#define BUFFER_CACHE_TRUNCATE_METHOD PYTHON_METHOD_DEF \ +( \ + truncate, "$self, max, /", \ + METH_VARARGS, py_buffer_cache, \ + "Shrink the buffer cache so it will contain at most *max* lines.\n" \ + "\n" \ + "The *max* number should be lesser than the current line quantity," \ + " otherwise no effect will happen." \ + "\n" \ + "An access lock has to be held for the cache; see the" \ + " pychrysalide.glibext.BufferCache.lock() function." \ +) + + ret = PyArg_ParseTuple(args, "n", &max); + if (!ret) return NULL; + + cache = G_BUFFER_CACHE(pygobject_get(self)); + + g_buffer_cache_truncate(cache, max); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un tampon de code. * +* args = arguments fournis à l'appel. * +* * +* Description : Détermine l'ensemble des propriétés attachées à une ligne. * +* * +* Retour : Somme de toutes les propriétés enregistrées. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_buffer_cache_get_line_flags(PyObject *self, PyObject *args) +{ + PyObject *result; /* Trouvailles à retourner */ + size_t index; /* Indice de la ligne visée */ + int ret; /* Bilan de lecture des args. */ + GBufferCache *cache; /* Tampon natif à consulter */ + BufferLineFlags flags; /* Fanions conservés */ + +#define BUFFER_CACHE_GET_LINE_FLAGS_METHOD PYTHON_METHOD_DEF \ +( \ + get_line_flags, "$self, index, /", \ + METH_VARARGS, py_buffer_cache, \ + "Provide the optional flags assigned to a given buffer line. The" \ + " line is located using the *index* argument.\n" \ + "\n" \ + "The result is a pychrysalide.glibext.BufferLine.BufferLineFlags" \ + " value.\n" \ + "\n" \ + "An access lock has to be held for the cache; see the" \ + " pychrysalide.glibext.BufferCache.lock() function." \ +) + + ret = PyArg_ParseTuple(args, "n", &index); + if (!ret) return NULL; + + cache = G_BUFFER_CACHE(pygobject_get(self)); + + flags = g_buffer_cache_get_line_flags(cache, index); + + result = cast_with_constants_group_from_type(get_python_buffer_line_type(), "BufferLineFlags", flags); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un tampon de code. * +* args = arguments fournis à l'appel. * +* * +* Description : Retrouve une ligne au sein d'un tampon avec un indice. * +* * +* Retour : Line retrouvée ou None en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_buffer_cache_find_line_by_index(PyObject *self, PyObject *args) +{ + PyObject *result; /* Trouvailles à retourner */ + size_t index; /* Indice de la ligne visée */ + int ret; /* Bilan de lecture des args. */ + GBufferCache *cache; /* Tampon natif à consulter */ + GBufferLine *line; /* Ligne trouvée ? */ + +#define BUFFER_CACHE_FIND_LINE_BY_INDEX_METHOD PYTHON_METHOD_DEF \ +( \ + find_line_by_index, "$self, index, /", \ + METH_VARARGS, py_buffer_cache, \ + "Retrieve the line contained in a buffer cache at a given index.\n" \ + "\n" \ + "The result is a pychrysalide.glibext.BufferLine instance or" \ + " None.\n" \ + "\n" \ + "An access lock has to be held for the cache; see the" \ + " pychrysalide.glibext.BufferCache.lock() function." \ +) + + ret = PyArg_ParseTuple(args, "n", &index); + if (!ret) return NULL; + + cache = G_BUFFER_CACHE(pygobject_get(self)); + + line = g_buffer_cache_find_line_by_index(cache, index); + + if (line != NULL) + { + result = pygobject_new(G_OBJECT(line)); + g_object_unref(G_OBJECT(line)); + } + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un tampon de code. * +* args = arguments fournis à l'appel. * +* * +* Description : Avance autant que possible vers une ligne idéale. * +* * +* Retour : Indice de la ligne recherchée, si elle existe. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_buffer_cache_look_for_flag(PyObject *self, PyObject *args) +{ + PyObject *result; /* Trouvailles à retourner */ + size_t index; /* Indice de la ligne visée */ + BufferLineFlags flag; /* Particularité à retrouver */ + int ret; /* Bilan de lecture des args. */ + GBufferCache *cache; /* Tampon natif à consulter */ + size_t found; /* Indice de la ligne trouvée */ + +#define BUFFER_CACHE_LOOK_FOR_FLAG_METHOD PYTHON_METHOD_DEF \ +( \ + look_for_flag, "$self, index, flag, /", \ + METH_VARARGS, py_buffer_cache, \ + "Iterate the buffer cache lines from a starting index until a" \ + " line with flags matching the provided flag is met.\n" \ + "\n" \ + "The *flag* argument has to be a" \ + " pychrysalide.glibext.BufferLine.BufferLineFlags value.\n" \ + "\n" \ + "The result is an index equal or greater than the starting index" \ + " or, if no match is found, the number of lines in the buffer" \ + " cache.\n" \ + "\n" \ + "An access lock has to be held for the cache; see the" \ + " pychrysalide.glibext.BufferCache.lock() function." \ +) + + ret = PyArg_ParseTuple(args, "nO&", &index, convert_to_buffer_line_flags, &flag); + if (!ret) return NULL; + + cache = G_BUFFER_CACHE(pygobject_get(self)); + + found = g_buffer_cache_look_for_flag(cache, index, flag); + + result = PyLong_FromSize_t(found); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique l'éventuel contenu binaire associé au cache. * +* * +* Retour : Eventuel contenu renseigné ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_buffer_cache_get_content(PyObject *self, void *closure) +{ + PyObject *result; /* Contenu binaire à retourner */ + GBufferCache *cache; /* Tampon natif à consulter */ + GBinContent *content; /* Contenu éventuel à renvoyer */ + +#define BUFFER_CACHE_CONTENT_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + content, py_buffer_cache, \ + "Binary content linked to the buffer cache, as a" \ + " pychrysalide.analysis.BinContent instance, or None." \ +) + + cache = G_BUFFER_CACHE(pygobject_get(self)); + + content = g_buffer_cache_get_content(cache); + + if (content != NULL) + { + result = pygobject_new(G_OBJECT(content)); + g_object_unref(G_OBJECT(content)); + } + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la hauteur d'impression d'une ligne visualisée. * +* * +* Retour : Hauteur de ligne en pixels. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_buffer_cache_get_line_height(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GBufferCache *cache; /* Tampon natif à consulter */ + gint height; /* Valeur obtenue du cache */ + +#define BUFFER_CACHE_LINE_HEIGHT_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + line_height, py_buffer_cache, \ + "Height of a line printed from the buffer cache." \ +) + + cache = G_BUFFER_CACHE(pygobject_get(self)); + + height = g_buffer_cache_get_line_height(cache); + + result = PyLong_FromLong(height); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la taille réservée pour la marge gauche. * +* * +* Retour : Largeur en pixels. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_buffer_cache_get_left_margin(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GBufferCache *cache; /* Tampon natif à consulter */ + gint width; /* Valeur obtenue du cache */ + +#define BUFFER_CACHE_LEFT_MARGIN_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + left_margin, py_buffer_cache, \ + "Width of the left margin inside of a buffer cache output." \ +) + + cache = G_BUFFER_CACHE(pygobject_get(self)); + + width = g_buffer_cache_get_left_margin(cache); + + result = PyLong_FromLong(width); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la position de départ pour l'impression de texte. * +* * +* Retour : Position en pixels. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_buffer_cache_get_text_position(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GBufferCache *cache; /* Tampon natif à consulter */ + gint pos; /* Valeur obtenue du cache */ + +#define BUFFER_CACHE_TEXT_POSITION_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + text_position, py_buffer_cache, \ + "Starting position of the text on the left of a buffer cache output." \ +) + + cache = G_BUFFER_CACHE(pygobject_get(self)); + + pos = g_buffer_cache_get_text_position(cache); + + result = PyLong_FromLong(pos); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Compte le nombre de lignes rassemblées dans un tampon. * +* * +* Retour : Nombre de lignes constituant le tampon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_buffer_cache_get_lines_count(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GBufferCache *cache; /* Tampon natif à consulter */ + size_t count; /* Décompte de première main */ + +#define BUFFER_CACHE_LINES_COUNT_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + lines_count, py_buffer_cache, \ + "Count the number of lines contained in a buffer cache.\n" \ + "\n" \ + "An access lock has to be held for the cache; see the" \ + " pychrysalide.glibext.BufferCache.lock() function." \ +) + + cache = G_BUFFER_CACHE(pygobject_get(self)); + + count = g_buffer_cache_count_lines(cache); + + result = PyLong_FromSize_t(count); return result; } -#endif /****************************************************************************** @@ -102,17 +936,24 @@ static PyObject *py_code_buffer_find_line_by_addr(PyObject *self, PyObject *args PyTypeObject *get_python_buffer_cache_type(void) { static PyMethodDef py_buffer_cache_methods[] = { -#if 0 - { - "find_line_by_addr", py_buffer_cache_find_line_by_addr, - METH_VARARGS, - "find_line_by_addr($self, addr, /)\n--\n\nFind a buffer line with a given address." - }, -#endif + BUFFER_CACHE_INSERT_AT_METHOD, + BUFFER_CACHE_DELETE_AT_METHOD, + BUFFER_CACHE_DELETE_TYPE_AT_METHOD, + BUFFER_CACHE_APPEND_METHOD, + BUFFER_CACHE_EXTEND_WITH_METHOD, + BUFFER_CACHE_TRUNCATE_METHOD, + BUFFER_CACHE_GET_LINE_FLAGS_METHOD, + BUFFER_CACHE_FIND_LINE_BY_INDEX_METHOD, + BUFFER_CACHE_LOOK_FOR_FLAG_METHOD, { NULL } }; static PyGetSetDef py_buffer_cache_getseters[] = { + BUFFER_CACHE_CONTENT_ATTRIB, + BUFFER_CACHE_LINE_HEIGHT_ATTRIB, + BUFFER_CACHE_LEFT_MARGIN_ATTRIB, + BUFFER_CACHE_TEXT_POSITION_ATTRIB, + BUFFER_CACHE_LINES_COUNT_ATTRIB, { NULL } }; @@ -125,11 +966,14 @@ PyTypeObject *get_python_buffer_cache_type(void) .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = "PyChrysalide code buffer", + .tp_doc = BUFFER_CACHE_DOC, .tp_methods = py_buffer_cache_methods, .tp_getset = py_buffer_cache_getseters, + .tp_init = py_buffer_cache_init, + .tp_new = py_buffer_cache_new + }; return &py_buffer_cache_type; @@ -171,3 +1015,48 @@ bool ensure_python_buffer_cache_is_registered(void) return true; } + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en tampon de lignes. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_buffer_cache(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_buffer_cache_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to buffer cache"); + break; + + case 1: + *((GBufferCache **)dst) = G_BUFFER_CACHE(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/glibext/buffercache.h b/plugins/pychrysalide/glibext/buffercache.h index 3135e22..1908434 100644 --- a/plugins/pychrysalide/glibext/buffercache.h +++ b/plugins/pychrysalide/glibext/buffercache.h @@ -37,6 +37,9 @@ PyTypeObject *get_python_buffer_cache_type(void); /* Prend en charge l'objet 'pychrysalide.glibext.BufferCache'. */ bool ensure_python_buffer_cache_is_registered(void); +/* Tente de convertir en tampon de lignes. */ +int convert_to_buffer_cache(PyObject *, void *); + #endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_BUFFERCACHE_H */ diff --git a/plugins/pychrysalide/glibext/bufferline.c b/plugins/pychrysalide/glibext/bufferline.c index 47b2bc4..af3cf1d 100644 --- a/plugins/pychrysalide/glibext/bufferline.c +++ b/plugins/pychrysalide/glibext/bufferline.c @@ -155,7 +155,7 @@ static PyObject *py_buffer_line_new(PyTypeObject *type, PyObject *args, PyObject static PyObject *py_buffer_line_append_text(PyObject *self, PyObject *args) { PyObject *result; /* Trouvailles à retourner */ - unsigned long column; /* Indice de colonne */ + size_t column; /* Indice de colonne */ const char *text; /* Texte à ajouter */ RenderingTagType type; /* Type de rendu attendu */ GObject *creator; /* Eventuel créateur à associer*/ @@ -177,7 +177,7 @@ static PyObject *py_buffer_line_append_text(PyObject *self, PyObject *args) creator = NULL; - ret = PyArg_ParseTuple(args, "ksO&|O&", &column, &text, + ret = PyArg_ParseTuple(args, "nsO&|O&", &column, &text, convert_to_rendering_tag_type, &type, convert_to_gobject, &creator); if (!ret) return NULL; @@ -228,9 +228,17 @@ static PyObject *py_buffer_line_get_text(PyObject *self, PyObject *args) line = G_BUFFER_LINE(pygobject_get(self)); text = g_buffer_line_get_text(line, first, end, markup); - result = PyUnicode_FromString(text); + if (text != NULL) + { + result = PyUnicode_FromString(text); + free(text); + } - free(text); + else + { + result = Py_None; + Py_INCREF(result); + } return result; @@ -398,11 +406,6 @@ static bool py_buffer_line_define_constants(PyTypeObject *obj_type) result &= PyDict_AddULongMacro(obj_type, BLC_FIRST); result &= PyDict_AddULongMacro(obj_type, BLC_DISPLAY); - result &= PyDict_AddULongMacro(obj_type, BLF_NONE); - result &= PyDict_AddULongMacro(obj_type, BLF_HAS_CODE); - result &= PyDict_AddULongMacro(obj_type, BLF_ENTRYPOINT); - result &= PyDict_AddULongMacro(obj_type, BLF_BOOKMARK); - return result; } @@ -509,6 +512,9 @@ bool ensure_python_buffer_line_is_registered(void) if (!define_line_segment_constants(type)) return false; + if (!define_buffer_line_constants(type)) + return false; + if (!py_buffer_line_define_constants(type)) return false; diff --git a/plugins/pychrysalide/glibext/constants.c b/plugins/pychrysalide/glibext/constants.c index d18e051..823465a 100644 --- a/plugins/pychrysalide/glibext/constants.c +++ b/plugins/pychrysalide/glibext/constants.c @@ -26,6 +26,7 @@ #include <glibext/linesegment.h> +#include <glibext/gbufferline.h> #include "../helpers.h" @@ -140,3 +141,102 @@ int convert_to_rendering_tag_type(PyObject *arg, void *dst) return result; } + + +/****************************************************************************** +* * +* Paramètres : type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes relatives aux lignes de tampon. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_buffer_line_constants(PyTypeObject *type) +{ + bool result; /* Bilan à retourner */ + PyObject *values; /* Groupe de valeurs à établir */ + + values = PyDict_New(); + + result = add_const_to_group(values, "NONE", BLF_NONE); + if (result) result = add_const_to_group(values, "HAS_CODE", BLF_HAS_CODE); + if (result) result = add_const_to_group(values, "IS_LABEL", BLF_IS_LABEL); + if (result) result = add_const_to_group(values, "ENTRYPOINT", BLF_ENTRYPOINT); + if (result) result = add_const_to_group(values, "BOOKMARK", BLF_BOOKMARK); + if (result) result = add_const_to_group(values, "WIDTH_MANAGER", BLF_WIDTH_MANAGER); + if (result) result = add_const_to_group(values, "ALL", BLF_ALL); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group_to_type(type, true, "BufferLineFlags", values, + "Optional flags linked to a rendering line."); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en constante BufferLineFlags. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_buffer_line_flags(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + unsigned long value; /* Valeur transcrite */ + + result = PyObject_IsInstance(arg, (PyObject *)&PyLong_Type); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to BufferLineFlags"); + break; + + case 1: + value = PyLong_AsUnsignedLong(arg); + + if ((value & BLF_ALL) != value) + { + PyErr_SetString(PyExc_TypeError, "invalid value for BufferLineFlags"); + result = 0; + } + + else + *((BufferLineFlags *)dst) = value; + + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/glibext/constants.h b/plugins/pychrysalide/glibext/constants.h index 472507b..a1c56af 100644 --- a/plugins/pychrysalide/glibext/constants.h +++ b/plugins/pychrysalide/glibext/constants.h @@ -37,6 +37,12 @@ bool define_line_segment_constants(PyTypeObject *); /* Tente de convertir en constante RenderingTagType. */ int convert_to_rendering_tag_type(PyObject *, void *); +/* Définit les constantes relatives aux lignes de tampon. */ +bool define_buffer_line_constants(PyTypeObject *); + +/* Tente de convertir en constante BufferLineFlags. */ +int convert_to_buffer_line_flags(PyObject *, void *); + #endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_CONSTANTS_H */ diff --git a/plugins/pychrysalide/glibext/linegen.c b/plugins/pychrysalide/glibext/linegen.c index 3ca7fcc..4d6d60d 100644 --- a/plugins/pychrysalide/glibext/linegen.c +++ b/plugins/pychrysalide/glibext/linegen.c @@ -28,26 +28,49 @@ #include <pygobject.h> -#include <common/cpp.h> -#include <glibext/linegen.h> +#include <glibext/linegen-int.h> +#include "bufferline.h" +#include "constants.h" +#include "linecursor.h" #include "../access.h" #include "../helpers.h" #include "../analysis/content.h" -#include "../arch/vmpa.h" -#include "../glibext/bufferline.h" +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ + + +/* Procède à l'initialisation de l'interface de génération. */ +static void py_line_generator_interface_init(GLineGeneratorIface *, gpointer *); + /* Indique le nombre de ligne prêtes à être générées. */ -static PyObject *py_line_generator_count_lines(PyObject *, PyObject *); +static size_t py_line_generator_count_lines_wrapper(const GLineGenerator *); /* Retrouve l'emplacement correspondant à une position donnée. */ -//static PyObject *py_line_generator_compute_addr(PyObject *, PyObject *); +static void py_line_generator_compute_cursor_wrapper(const GLineGenerator *, gint, size_t, size_t, GLineCursor **); /* Détermine si le conteneur s'inscrit dans une plage donnée. */ -//static PyObject *py_line_generator_contains_addr(PyObject *, PyObject *); +static int py_line_generator_contain_cursor_wrapper(const GLineGenerator *, size_t, size_t, const GLineCursor *); + +/* Renseigne sur les propriétés liées à un générateur. */ +static BufferLineFlags py_line_generator_get_flags_wrapper(const GLineGenerator *, size_t, size_t); + +/* Imprime dans une ligne de rendu le contenu représenté. */ +static void py_line_generator_print_wrapper(GLineGenerator *, GBufferLine *, size_t, size_t, const GBinContent *); + + + +/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */ + + +/* Retrouve l'emplacement correspondant à une position donnée. */ +static PyObject *py_line_generator_compute_cursor(PyObject *, PyObject *); + +/* Détermine si le conteneur s'inscrit dans une plage donnée. */ +static PyObject *py_line_generator_contain_cursor(PyObject *, PyObject *); /* Renseigne sur les propriétés liées à un générateur. */ static PyObject *py_line_generator_get_flags(PyObject *, PyObject *); @@ -55,12 +78,61 @@ static PyObject *py_line_generator_get_flags(PyObject *, PyObject *); /* Imprime dans une ligne de rendu le contenu représenté. */ static PyObject *py_line_generator_print(PyObject *, PyObject *); +/* Indique le nombre de ligne prêtes à être générées. */ +static PyObject *py_line_generator_get_lines_count(PyObject *, void *); + + + +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : self = classe représentant un générateur à manipuler. * -* args = arguments fournis à l'appel. * +* Paramètres : iface = interface GLib à initialiser. * +* unused = adresse non utilisée ici. * +* * +* Description : Procède à l'initialisation de l'interface de génération. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_line_generator_interface_init(GLineGeneratorIface *iface, gpointer *unused) +{ + +#define LINE_GENERATOR_DOC \ + "LineGenerator gives an interface to all objects which aim to produce" \ + " content for rendering lines. Such lines can be exported to graphical" \ + " interfaces or text files.\n" \ + "\n" \ + "A typical class declaration for a new implementation looks like:\n" \ + "\n" \ + " class NewImplem(GObject.Object, LineGenerator):\n" \ + " ...\n" \ + "\n" \ + "The following methods have to be defined for new implementations:\n" \ + "* pychrysalide.glibext.LineGenerator._count_lines();\n" \ + "* pychrysalide.glibext.LineGenerator._compute_cursor();\n" \ + "* pychrysalide.glibext.LineGenerator._contain_cursor();\n" \ + "* pychrysalide.glibext.LineGenerator._get_flags();\n" \ + "* pychrysalide.glibext.LineGenerator._print();\n" \ + + iface->count = py_line_generator_count_lines_wrapper; + iface->compute = py_line_generator_compute_cursor_wrapper; + iface->contains = py_line_generator_contain_cursor_wrapper; + iface->get_flags = py_line_generator_get_flags_wrapper; + iface->print = py_line_generator_print_wrapper; + +} + + +/****************************************************************************** +* * +* Paramètres : generator = générateur à consulter. * * * * Description : Indique le nombre de ligne prêtes à être générées. * * * @@ -70,17 +142,46 @@ static PyObject *py_line_generator_print(PyObject *, PyObject *); * * ******************************************************************************/ -static PyObject *py_line_generator_count_lines(PyObject *self, PyObject *args) +static size_t py_line_generator_count_lines_wrapper(const GLineGenerator *generator) { - PyObject *result; /* Décompte à retourner */ - GLineGenerator *generator; /* Version native */ - size_t count; /* Nombre de lignes présentes */ + size_t result; /* Décompte à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan de consultation */ + int ret; /* Bilan d'une conversion */ - generator = G_LINE_GENERATOR(pygobject_get(self)); +#define LINE_GENERATOR_COUNT_LINES_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _count_lines, "$self, /", \ + METH_NOARGS, \ + "Abstract method used to count the number of lines produced" \ + " by the current generator." \ +) - count = g_line_generator_count_lines(generator); + result = 0; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(generator)); + + if (has_python_method(pyobj, "_count_lines")) + { + pyret = run_python_method(pyobj, "_count_lines", NULL); + + if (pyret != NULL) + { + ret = PyLong_Check(pyret); + + if (ret) + result = PyLong_AsSize_t(pyret); + + Py_DECREF(pyret); + + } + + } - result = Py_BuildValue("k", count); + PyGILState_Release(gstate); return result; @@ -89,40 +190,358 @@ static PyObject *py_line_generator_count_lines(PyObject *self, PyObject *args) /****************************************************************************** * * +* Paramètres : generator = générateur à consulter. * +* x = position géographique sur la ligne concernée. * +* index = indice de cette même ligne dans le tampon global.* +* repeat = indice d'utilisations successives du générateur. * +* * +* Description : Retrouve l'emplacement correspondant à une position donnée. * +* * +* Retour : Emplacement constitué. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_line_generator_compute_cursor_wrapper(const GLineGenerator *generator, gint x, size_t index, size_t repeat, GLineCursor **cursor) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + int ret; /* Bilan d'une conversion */ + +#define LINE_GENERATOR_COMPUTE_CURSOR_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _compute_cursor, "$self, x, index, repeat, /", \ + METH_VARARGS, \ + "Abstract method used to create a new cursor for a given" \ + " location inside displayed lines.\n" \ + "\n" \ + "The position on the horizontal axis, the line index and the" \ + " number of repetitions (only relevant if the generator" \ + " produces several lines) give indications about the active" \ + " position.\n" \ + "\n" \ + "The result has to be a pychrysalide.glibext.LineCursor" \ + " instance." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(generator)); + + if (has_python_method(pyobj, "_compute_cursor")) + { + args = PyTuple_New(3); + PyTuple_SetItem(args, 0, PyLong_FromSize_t(x)); + PyTuple_SetItem(args, 1, PyLong_FromSize_t(index)); + PyTuple_SetItem(args, 2, PyLong_FromSize_t(repeat)); + + pyret = run_python_method(pyobj, "_compute_cursor", args); + + if (pyret != NULL) + { + ret = convert_to_line_cursor(pyret, cursor); + + if (ret != 1) + *cursor = NULL; + + Py_DECREF(pyret); + + } + + Py_DECREF(args); + + } + + PyGILState_Release(gstate); + +} + + +/****************************************************************************** +* * +* Paramètres : generator = générateur à consulter. * +* index = indice de cette même ligne dans le tampon global.* +* repeat = indice d'utilisations successives du générateur. * +* cursor = emplacement à analyser. * +* * +* Description : Détermine si le conteneur s'inscrit dans une plage donnée. * +* * +* Retour : Bilan de la détermination, utilisable en comparaisons. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_line_generator_contain_cursor_wrapper(const GLineGenerator *generator, size_t index, size_t repeat, const GLineCursor *cursor) +{ + int result; /* Bilan d'analyse à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + int ret; /* Bilan d'une conversion */ + +#define LINE_GENERATOR_CONTAIN_CURSOR_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _contain_cursor, "$self, index, repeat, cursor, /", \ + METH_VARARGS, \ + "Abstract method used to check the position of a cursor in" \ + " relation to rendering lines.\n" \ + "\n" \ + "The line index and the number of repetitions (only relevant" \ + " if the generator produces several lines) give indications" \ + " about the active position. The cursor is a" \ + " pychrysalide.glibext.LineCursor instance.\n" \ + "\n" \ + "The result has to be an integer less than, equal to, or" \ + " greater than zero if the cursor is, respectively, before," \ + " inside or after the area covered by the generator." \ +) + + result = 0; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(generator)); + + if (has_python_method(pyobj, "_contain_cursor")) + { + args = PyTuple_New(3); + PyTuple_SetItem(args, 0, PyLong_FromSize_t(index)); + PyTuple_SetItem(args, 1, PyLong_FromSize_t(repeat)); + PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(cursor))); + + pyret = run_python_method(pyobj, "_contain_cursor", args); + + if (pyret != NULL) + { + ret = PyLong_Check(pyret); + + if (ret) + result = PyLong_AsLong(pyret); + + Py_DECREF(pyret); + + } + + Py_DECREF(args); + + } + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : generator = générateur à consulter. * +* index = indice de cette même ligne dans le tampon global.* +* repeat = indice d'utilisations successives du générateur. * +* * +* Description : Renseigne sur les propriétés liées à un générateur. * +* * +* Retour : Propriétés particulières associées. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static BufferLineFlags py_line_generator_get_flags_wrapper(const GLineGenerator *generator, size_t index, size_t repeat) +{ + BufferLineFlags result; /* Fanions à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + int ret; /* Bilan d'une conversion */ + +#define LINE_GENERATOR_GET_FLAGS_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _get_flags, "$self, index, repeat, /", \ + METH_VARARGS, \ + "Abstract method used to provide flags for a given rendering" \ + " line.\n" \ + "\n" \ + "The line index and the number of repetitions (only relevant" \ + " if the generator produces several lines) give indications" \ + " about the active position.\n" \ + "\n" \ + "The result has to be a" \ + " pychrysalide.glibext.BufferLine.BufferLineFlags value.\n" \ +) + + result = BLF_NONE; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(generator)); + + if (has_python_method(pyobj, "_get_flags")) + { + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, PyLong_FromSize_t(index)); + PyTuple_SetItem(args, 1, PyLong_FromSize_t(repeat)); + + pyret = run_python_method(pyobj, "_get_flags", args); + + if (pyret != NULL) + { + ret = convert_to_buffer_line_flags(pyret, &result); + + if (ret != 1) + result = BLF_NONE; + + Py_DECREF(pyret); + + } + + Py_DECREF(args); + + } + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : generator = générateur à utiliser pour l'impression. * +* line = ligne de rendu à compléter. * +* index = indice de cette même ligne dans le tampon global.* +* repeat = indice d'utilisations successives du générateur. * +* content = éventuel contenu binaire brut à imprimer. * +* * +* Description : Imprime dans une ligne de rendu le contenu représenté. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_line_generator_print_wrapper(GLineGenerator *generator, GBufferLine *line, size_t index, size_t repeat, const GBinContent *content) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + +#define LINE_GENERATOR_PRINT_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _print, "$self, line, index, repeat, content, /", \ + METH_VARARGS, \ + "Abstract method used to generate content into a rendering" \ + " line, which is a provided pychrysalide.glibext.BufferLine" \ + " instance.\n" \ + "\n" \ + "The line index and the number of repetitions (only relevant" \ + " if the generator produces several lines) give indications" \ + " about the current rendering position.\n" \ + "\n" \ + "If set, the content is a pychrysalide.analysis.BinContent" \ + " instance providing access to the processed binary data." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(generator)); + + if (has_python_method(pyobj, "_print")) + { + args = PyTuple_New(4); + PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(line))); + PyTuple_SetItem(args, 1, PyLong_FromSize_t(index)); + PyTuple_SetItem(args, 2, PyLong_FromSize_t(repeat)); + PyTuple_SetItem(args, 3, pygobject_new(G_OBJECT(content))); + + pyret = run_python_method(pyobj, "_print", args); + + Py_DECREF(args); + + Py_XDECREF(pyret); + + } + + PyGILState_Release(gstate); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* CONNEXION AVEC L'API DE PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * * Paramètres : self = classe représentant un générateur à manipuler. * * args = arguments fournis à l'appel. * * * * Description : Retrouve l'emplacement correspondant à une position donnée. * * * -* Retour : - * +* Retour : Emplacement constitué. * * * * Remarques : - * * * ******************************************************************************/ -#if 0 -static PyObject *py_line_generator_compute_addr(PyObject *self, PyObject *args) + +static PyObject *py_line_generator_compute_cursor(PyObject *self, PyObject *args) { - PyObject *result; /* Localisation à retourner */ - GLineGenerator *generator; /* Version native */ - gint x; /* Position géographique */ + PyObject *result; /* Propriétés à retourner */ + int x; /* Position horizontale */ size_t index; /* Indice dans le tampon */ size_t repeat; /* Utilisations successives */ int ret; /* Bilan de lecture des args. */ - vmpa2t addr; /* Adresse visée par l'opérat° */ + GLineGenerator *generator; /* Version native */ + GLineCursor *cursor; /* Curseur nouveau obtenu */ + +#define LINE_GENERATOR_COMPUTE_CURSOR_METHOD PYTHON_METHOD_DEF \ +( \ + compute_cursor, "$self, x, index, repeat, /", \ + METH_VARARGS, py_line_generator, \ + "Create a a new cursor for a given location inside displayed" \ + " lines.\n" \ + "\n" \ + "The position on the horizontal axis, the line index and the" \ + " number of repetitions (only relevant if the generator" \ + " produces several lines) give indications about the active" \ + " position.\n" \ + "\n" \ + "The result has to be a pychrysalide.glibext.LineCursor" \ + " instance." \ +) + + ret = PyArg_ParseTuple(args, "inn", &x, &index, &repeat); + if (!ret) return NULL; generator = G_LINE_GENERATOR(pygobject_get(self)); - ret = PyArg_ParseTuple(args, "ikk", &x, &index, &repeat); - if (!ret) return NULL; + cursor = g_line_generator_compute_cursor(generator, x, index, repeat); - g_line_generator_compute_addr(generator, x, &addr, index, repeat); - - result = build_from_internal_vmpa(&addr); + if (cursor != NULL) + { + result = pygobject_new(G_OBJECT(cursor)); + g_object_unref(G_OBJECT(cursor)); + } + else + { + result = Py_None; + Py_INCREF(result); + } return result; } -#endif /****************************************************************************** @@ -137,30 +556,46 @@ static PyObject *py_line_generator_compute_addr(PyObject *self, PyObject *args) * Remarques : - * * * ******************************************************************************/ -#if 0 -static PyObject *py_line_generator_contains_addr(PyObject *self, PyObject *args) + +static PyObject *py_line_generator_contain_cursor(PyObject *self, PyObject *args) { - GLineGenerator *generator; /* Version native */ - PyObject *py_vmpa; /* Localisation version Python */ + PyObject *result; /* Propriétés à retourner */ size_t index; /* Indice dans le tampon */ size_t repeat; /* Utilisations successives */ + GLineCursor *cursor; /* Curseur à venir situer */ int ret; /* Bilan de lecture des args. */ - vmpa2t *addr; /* Adresse visée par l'opérat° */ + GLineGenerator *generator; /* Version native */ + int status; /* Bilan d'une analyse */ + +#define LINE_GENERATOR_CONTAIN_CURSOR_METHOD PYTHON_METHOD_DEF \ +( \ + contain_cursor, "$self, index, repeat, cursor, /", \ + METH_VARARGS, py_line_generator, \ + "Check the position of a cursor in relation to rendering" \ + " lines.\n" \ + "\n" \ + "The line index and the number of repetitions (only relevant" \ + " if the generator produces several lines) give indications" \ + " about the active position. The cursor is a" \ + " pychrysalide.glibext.LineCursor instance.\n" \ + "\n" \ + "The result has to be an integer less than, equal to, or" \ + " greater than zero if the cursor is, respectively, before," \ + " inside or after the area covered by the generator." \ +) + + ret = PyArg_ParseTuple(args, "nnO&", &index, &repeat, convert_to_line_cursor, &cursor); + if (!ret) return NULL; generator = G_LINE_GENERATOR(pygobject_get(self)); - ret = PyArg_ParseTuple(args, "O!kk", get_python_vmpa_type(), &py_vmpa, &index, &repeat); - if (!ret) return NULL; - - addr = get_internal_vmpa(py_vmpa); - if (addr == NULL) return NULL; + status = g_line_generator_contains_cursor(generator, index, repeat, cursor); - g_line_generator_contains_addr(generator, addr, index, repeat); + result = PyLong_FromLong(status); - Py_RETURN_NONE; + return result; } -#endif /****************************************************************************** @@ -179,20 +614,34 @@ static PyObject *py_line_generator_contains_addr(PyObject *self, PyObject *args) static PyObject *py_line_generator_get_flags(PyObject *self, PyObject *args) { PyObject *result; /* Propriétés à retourner */ - GLineGenerator *generator; /* Version native */ size_t index; /* Indice dans le tampon */ size_t repeat; /* Utilisations successives */ int ret; /* Bilan de lecture des args. */ + GLineGenerator *generator; /* Version native */ BufferLineFlags flags; /* Propriétés courantes */ - generator = G_LINE_GENERATOR(pygobject_get(self)); - - ret = PyArg_ParseTuple(args, "kk", &index, &repeat); +#define LINE_GENERATOR_GET_FLAGS_METHOD PYTHON_METHOD_DEF \ +( \ + get_flags, "$self, index, repeat, /", \ + METH_VARARGS, py_line_generator, \ + "Get the flags of a given position from the generator.\n" \ + "\n" \ + "The line index and the number of repetitions (only relevant" \ + " if the generator produces several lines) give indications" \ + " about the active position.\n" \ + "\n" \ + "The result is a pychrysalide.glibext.BufferLine.BufferLineFlags" \ + " value." \ +) + + ret = PyArg_ParseTuple(args, "nn", &index, &repeat); if (!ret) return NULL; + generator = G_LINE_GENERATOR(pygobject_get(self)); + flags = g_line_generator_get_flags(generator, index, repeat); - result = Py_BuildValue("I", flags); + result = cast_with_constants_group_from_type(get_python_buffer_line_type(), "BufferLineFlags", flags); return result; @@ -214,19 +663,33 @@ static PyObject *py_line_generator_get_flags(PyObject *self, PyObject *args) static PyObject *py_line_generator_print(PyObject *self, PyObject *args) { - GLineGenerator *generator; /* Version native */ GBufferLine *line; /* Ligne de rendu à compléter */ size_t index; /* Indice dans le tampon */ size_t repeat; /* Utilisations successives */ GBinContent *content; /* Contenu binaire associé */ + GLineGenerator *generator; /* Version native */ int ret; /* Bilan de lecture des args. */ - generator = G_LINE_GENERATOR(pygobject_get(self)); - - ret = PyArg_ParseTuple(args, "O&kkO&", convert_to_buffer_line, &line, &index, +#define LINE_GENERATOR_PRINT_METHOD PYTHON_METHOD_DEF \ +( \ + print, "$self, line, index, repeat, content, /", \ + METH_VARARGS, py_line_generator, \ + "Produce output into a rendering line with optional content.\n" \ + "\n" \ + "The line index and the number of repetitions (only relevant" \ + " if the generator produces several lines) give indications" \ + " about the current rendering position.\n" \ + "\n" \ + "If set, the content is a pychrysalide.analysis.BinContent" \ + " instance providing access to the processed binary data." \ +) + + ret = PyArg_ParseTuple(args, "O&nnO&", convert_to_buffer_line, &line, &index, &repeat, convert_to_binary_content, &content); if (!ret) return NULL; + generator = G_LINE_GENERATOR(pygobject_get(self)); + g_line_generator_print(generator, line, index, repeat, content); Py_RETURN_NONE; @@ -234,78 +697,45 @@ static PyObject *py_line_generator_print(PyObject *self, PyObject *args) } - - - - - - - - - - - -#if 0 - /****************************************************************************** * * -* Paramètres : - * +* Paramètres : self = classe représentant un générateur à manipuler. * +* closure = non utilisé ici. * * * -* Description : Fournit un accès à une définition de type à diffuser. * +* Description : Indique le nombre de ligne prêtes à être générées. * * * -* Retour : - * +* Retour : Nombre de lignes devant apparaître au final. * * * * Remarques : - * * * ******************************************************************************/ -static void python_line_generator_interface_init(GLineGeneratorIface *iface, PyTypeObject *type) +static PyObject *py_line_generator_get_lines_count(PyObject *self, void *closure) { - GLineGeneratorIface *parent; /* Défintion parente */ - size_t i; /* Boucle de parcours */ - PyObject *method; /* Méthode à associer */ - - static const char *meth_names[] = { - "count_lines", - "compute_addr", - "contains_addr", - "get_flags", - "print" - }; - - parent = g_type_interface_peek_parent(iface); - - for (i = 0; i < ARRAY_SIZE(meth_names); i++) - { - method = NULL; - - if (type != NULL) - method = PyObject_GetAttrString((PyObject *)type, meth_names[i]); - - if (method != NULL && PyObject_TypeCheck(method, &PyCFunction_Type) == 0) - /*iface->iface_method = _wrap_TestInterface__proxy_do_iface_method*/; + PyObject *result; /* Décompte à retourner */ + GLineGenerator *generator; /* Version native */ + size_t count; /* Nombre de lignes présentes */ - else - { - PyErr_Clear(); +#define LINE_GENERATOR_LINES_COUNT_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + lines_count, py_line_generator, \ + "Quantity of lines produced by the generator.\n" \ + "\n" \ + "This number may vary between calls, if a width has changed" \ + " for instance." \ +) - if (parent != NULL) - /*iface->iface_method = parent->iface_method*/; + generator = G_LINE_GENERATOR(pygobject_get(self)); - } + count = g_line_generator_count_lines(generator); - Py_XDECREF(method); + result = PyLong_FromSize_t(count); - } + return result; } -#endif - - - - /****************************************************************************** * * * Paramètres : - * @@ -321,37 +751,20 @@ static void python_line_generator_interface_init(GLineGeneratorIface *iface, PyT PyTypeObject *get_python_line_generator_type(void) { static PyMethodDef py_line_generator_methods[] = { - { - "count_lines", py_line_generator_count_lines, - METH_NOARGS, - "count_lines($self, /)\n--\n\nCount the number of lines which can be displayed." - }, -#if 0 - { - "compute_addr", py_line_generator_compute_addr, - METH_VARARGS, - "compute_addr($self, x, index, repeat, /)\n--\n\nReturn the position at a given location." - }, - { - "contains_addr", py_line_generator_contains_addr, - METH_VARARGS, - "contains_addr($self, addr, index, repeat, /)\n--\n\nTell if the generator contains an address." - }, -#endif - { - "get_flags", py_line_generator_get_flags, - METH_VARARGS, - "get_flags($self, index, repeat, /)\n--\n\nGet the flags of a position from the generator." - }, - { - "print", py_line_generator_print, - METH_VARARGS, - "print($self, line, index, repeat, content, /)\n--\n\nProduce output into a line from content." - }, + LINE_GENERATOR_COUNT_LINES_WRAPPER, + LINE_GENERATOR_COMPUTE_CURSOR_WRAPPER, + LINE_GENERATOR_CONTAIN_CURSOR_WRAPPER, + LINE_GENERATOR_GET_FLAGS_WRAPPER, + LINE_GENERATOR_PRINT_WRAPPER, + LINE_GENERATOR_COMPUTE_CURSOR_METHOD, + LINE_GENERATOR_CONTAIN_CURSOR_METHOD, + LINE_GENERATOR_GET_FLAGS_METHOD, + LINE_GENERATOR_PRINT_METHOD, { NULL } }; static PyGetSetDef py_line_generator_getseters[] = { + LINE_GENERATOR_LINES_COUNT_ATTRIB, { NULL } }; @@ -360,11 +773,11 @@ PyTypeObject *get_python_line_generator_type(void) PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "pychrysalide.glibext.LineGenerator", - //.tp_basicsize = sizeof(PyGObject), + .tp_basicsize = sizeof(PyObject), .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_doc = "PyChrysalide line content generator", + .tp_doc = LINE_GENERATOR_DOC, .tp_methods = py_line_generator_methods, .tp_getset = py_line_generator_getseters, @@ -394,6 +807,14 @@ bool ensure_python_line_generator_is_registered(void) PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ + static GInterfaceInfo info = { /* Paramètres d'inscription */ + + .interface_init = (GInterfaceInitFunc)py_line_generator_interface_init, + .interface_finalize = NULL, + .interface_data = NULL, + + }; + type = get_python_line_generator_type(); if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) @@ -402,7 +823,7 @@ bool ensure_python_line_generator_is_registered(void) dict = PyModule_GetDict(module); - if (!register_interface_for_pygobject(dict, G_TYPE_LINE_GENERATOR, type)) + if (!register_interface_for_pygobject_2(dict, G_TYPE_LINE_GENERATOR, type, &info)) return false; } @@ -410,3 +831,48 @@ bool ensure_python_line_generator_is_registered(void) return true; } + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en générateur de lignes. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_line_generator(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_line_generator_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to line generator"); + break; + + case 1: + *((GLineGenerator **)dst) = G_LINE_GENERATOR(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/glibext/linegen.h b/plugins/pychrysalide/glibext/linegen.h index 4502347..bfad885 100644 --- a/plugins/pychrysalide/glibext/linegen.h +++ b/plugins/pychrysalide/glibext/linegen.h @@ -37,6 +37,9 @@ PyTypeObject *get_python_line_generator_type(void); /* Prend en charge l'objet 'pychrysalide.glibext.LineGenerator'. */ bool ensure_python_line_generator_is_registered(void); +/* Tente de convertir en générateur de lignes. */ +int convert_to_line_generator(PyObject *, void *); + #endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_LINEGEN_H */ |