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 | |
parent | 6c9e1b5f7ee0915036d47b83f1e34b87b44b1723 (diff) |
Updated the API for buffer caches.
-rw-r--r-- | plugins/pychrysalide/analysis/content.c | 31 | ||||
-rw-r--r-- | plugins/pychrysalide/analysis/content.h | 3 | ||||
-rw-r--r-- | plugins/pychrysalide/format/symbol.c | 1 | ||||
-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 | ||||
-rw-r--r-- | plugins/pychrysalide/helpers.c | 45 | ||||
-rw-r--r-- | plugins/pychrysalide/helpers.h | 5 | ||||
-rw-r--r-- | src/glibext/Makefile.am | 1 | ||||
-rw-r--r-- | src/glibext/gbuffercache-int.h | 96 | ||||
-rw-r--r-- | src/glibext/gbuffercache.c | 111 | ||||
-rw-r--r-- | src/glibext/gbuffercache.h | 15 | ||||
-rw-r--r-- | src/glibext/gbufferline.c | 5 | ||||
-rw-r--r-- | src/glibext/gbufferline.h | 14 | ||||
-rw-r--r-- | src/glibext/linegen.c | 22 | ||||
-rw-r--r-- | src/glibext/linegen.h | 4 | ||||
-rw-r--r-- | src/gtkext/hexdisplay.c | 3 | ||||
-rw-r--r-- | tests/glibext/buffercache.py | 49 |
22 files changed, 1956 insertions, 266 deletions
diff --git a/plugins/pychrysalide/analysis/content.c b/plugins/pychrysalide/analysis/content.c index a0eb11c..8a404ed 100644 --- a/plugins/pychrysalide/analysis/content.c +++ b/plugins/pychrysalide/analysis/content.c @@ -813,3 +813,34 @@ int convert_to_binary_content(PyObject *arg, void *dst) 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 contenu binaire ou NULL. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_binary_content_or_none(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + if (arg == Py_None) + { + *((GBinContent **)dst) = NULL; + result = 1; + } + + else + result = convert_to_binary_content(arg, dst); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/content.h b/plugins/pychrysalide/analysis/content.h index e56e29f..fab6b1b 100644 --- a/plugins/pychrysalide/analysis/content.h +++ b/plugins/pychrysalide/analysis/content.h @@ -40,6 +40,9 @@ bool ensure_python_binary_content_is_registered(void); /* Tente de convertir en contenu binaire. */ int convert_to_binary_content(PyObject *, void *); +/* Tente de convertir en contenu binaire ou NULL. */ +int convert_to_binary_content_or_none(PyObject *, void *); + #endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_CONTENT_H */ diff --git a/plugins/pychrysalide/format/symbol.c b/plugins/pychrysalide/format/symbol.c index 6f1c1d2..71832cb 100644 --- a/plugins/pychrysalide/format/symbol.c +++ b/plugins/pychrysalide/format/symbol.c @@ -306,6 +306,7 @@ static int py_binary_symbol_init(PyObject *self, PyObject *args, PyObject *kwds) } + /* ---------------------------------------------------------------------------------- */ /* FONCTIONNALITES BASIQUES POUR SYMBOLES */ /* ---------------------------------------------------------------------------------- */ 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 */ diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c index 47285f0..5e911ea 100644 --- a/plugins/pychrysalide/helpers.c +++ b/plugins/pychrysalide/helpers.c @@ -916,6 +916,51 @@ bool register_interface_for_pygobject(PyObject *dict, GType gtype, PyTypeObject * Paramètres : dict = dictionnaire où conserver une référence au type créé.* * gtype = type dans sa version GLib. * * type = type dans sa version Python. * +* * +* Description : Enregistre correctement une interface GObject pour Python. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_interface_for_pygobject_2(PyObject *dict, GType gtype, PyTypeObject *type, const GInterfaceInfo *info) +{ + bool result; /* Bilan à retourner */ + char *name; /* Désignation de la classe */ + + assert(gtype != G_TYPE_INVALID); + + name = strrchr(type->tp_name, '.'); + assert(name != NULL); + + name++; + + pyg_register_interface(dict, name, gtype, type); + + pyg_register_interface_info(gtype, info); + + if (startswith(type->tp_name, "pychrysalide.")) + { + define_auto_documentation(type); + + result = include_python_type_into_features(dict, type); + + } + else + result = true; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : dict = dictionnaire où conserver une référence au type créé.* +* gtype = type dans sa version GLib. * +* type = type dans sa version Python. * * base = type de base de l'objet. * * * * Description : Enregistre un type Python dérivant d'un type GLib dynamique. * diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h index 8ed9d9a..dbc9272 100644 --- a/plugins/pychrysalide/helpers.h +++ b/plugins/pychrysalide/helpers.h @@ -162,7 +162,10 @@ bool _register_class_for_pygobject(PyObject *, GType, PyTypeObject *, PyTypeObje _register_class_for_pygobject(dict, gtype, type, base, NULL) /* Enregistre correctement une interface GObject pour Python. */ -bool register_interface_for_pygobject(PyObject *, GType, PyTypeObject *); +bool register_interface_for_pygobject(PyObject *, GType, PyTypeObject *) __attribute__ ((deprecated)); + +/* Enregistre correctement une interface GObject pour Python. */ +bool register_interface_for_pygobject_2(PyObject *, GType, PyTypeObject *, const GInterfaceInfo *); /* Enregistre un type Python dérivant d'un type GLib dynamique. */ bool register_class_for_dynamic_pygobject(GType, PyTypeObject *, PyTypeObject *); diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am index af4f876..4739fef 100644 --- a/src/glibext/Makefile.am +++ b/src/glibext/Makefile.am @@ -11,6 +11,7 @@ libglibext_la_SOURCES = \ gbinarycursor.h gbinarycursor.c \ gbinportion-int.h \ gbinportion.h gbinportion.c \ + gbuffercache-int.h \ gbuffercache.h gbuffercache.c \ gbufferline.h gbufferline.c \ gbufferview.h gbufferview.c \ diff --git a/src/glibext/gbuffercache-int.h b/src/glibext/gbuffercache-int.h new file mode 100644 index 0000000..6886fb0 --- /dev/null +++ b/src/glibext/gbuffercache-int.h @@ -0,0 +1,96 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * gbuffercache-int.h - définitions internes d'affichage à la demande d'un ensemble de lignes + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _GLIBEXT_GBUFFERCACHE_INT_H +#define _GLIBEXT_GBUFFERCACHE_INT_H + + +#include "gbuffercache.h" + + + +/* --------------------- FONCTIONS AUXILIAIRES DE MANIPULATIONS --------------------- */ + + +/* Informations rattachées à la génération d'une ligne */ +typedef struct _generator_link +{ + GLineGenerator *instance; /* Fournisseur de contenu */ + size_t repeat; /* Compteur de successions */ + +} generator_link; + +/* Suivi interne de l'état d'une ligne */ +typedef struct _cache_info +{ + union + { + generator_link generator; /* Générateur unique */ + generator_link *generators; /* Liste de générateurs */ + }; + size_t count; /* Taille de cette liste */ + + GBufferLine *line; /* Ligne en place ou NULL */ + + BufferLineFlags extra_flags; /* Propriétés supplémentaires */ + +} cache_info; + + + +/* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ + + +/* Tampon pour gestion de lignes optimisée (instance) */ +struct _GBufferCache +{ + GObject parent; /* A laisser en premier */ + + GBinContent *content; /* Contenu binaire global */ + + cache_info *lines; /* Liste des lignes intégrées */ + size_t count; /* Quantité en cache */ + size_t used; /* Quantité utilisée */ + + GWidthTracker *tracker; /* Suivi des largeurs */ + +}; + +/* Tampon pour gestion de lignes optimisée (classe) */ +struct _GBufferCacheClass +{ + GObjectClass parent; /* A laisser en premier */ + + gint line_height; /* Hauteur maximale des lignes */ + gint left_margin; /* Marge gauche + espace */ + gint text_pos; /* Début d'impression du code */ + + /* Signaux */ + + void (* size_changed) (GBufferCache *, bool, size_t, size_t); + +}; + + + +#endif /* _GLIBEXT_GBUFFERCACHE_INT_H */ diff --git a/src/glibext/gbuffercache.c b/src/glibext/gbuffercache.c index 08ca020..d918a5d 100644 --- a/src/glibext/gbuffercache.c +++ b/src/glibext/gbuffercache.c @@ -29,6 +29,7 @@ #include <stdlib.h> +#include "gbuffercache-int.h" #include "chrysamarshal.h" @@ -36,31 +37,6 @@ /* --------------------- FONCTIONS AUXILIAIRES DE MANIPULATIONS --------------------- */ -/* Informations rattachées à la génération d'une ligne */ -typedef struct _generator_link -{ - GLineGenerator *instance; /* Fournisseur de contenu */ - size_t repeat; /* Compteur de successions */ - -} generator_link; - -/* Suivi interne de l'état d'une ligne */ -typedef struct _cache_info -{ - union - { - generator_link generator; /* Générateur unique */ - generator_link *generators; /* Liste de générateurs */ - }; - size_t count; /* Taille de cette liste */ - - GBufferLine *line; /* Ligne en place ou NULL */ - - BufferLineFlags extra_flags; /* Propriétés supplémentaires */ - -} cache_info; - - /* Gros verrou global pour alléger les structures... */ G_LOCK_DEFINE_STATIC(_line_update); @@ -97,37 +73,6 @@ static void reset_cache_info_line(cache_info *); /* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ -/* Tampon pour gestion de lignes optimisée (instance) */ -struct _GBufferCache -{ - GObject parent; /* A laisser en premier */ - - GBinContent *content; /* Contenu binaire global */ - - cache_info *lines; /* Liste des lignes intégrées */ - size_t count; /* Quantité en cache */ - size_t used; /* Quantité utilisée */ - - GWidthTracker *tracker; /* Suivi des largeurs */ - -}; - -/* Tampon pour gestion de lignes optimisée (classe) */ -struct _GBufferCacheClass -{ - GObjectClass parent; /* A laisser en premier */ - - gint line_height; /* Hauteur maximale des lignes */ - gint left_margin; /* Marge gauche + espace */ - gint text_pos; /* Début d'impression du code */ - - /* Signaux */ - - void (* size_changed) (GBufferCache *, bool, size_t, size_t); - -}; - - /* Taille des allocations de masse */ #define LINE_ALLOC_BULK 1000 @@ -388,7 +333,7 @@ static void get_cache_info_cursor(const cache_info *info, size_t index, gint x, else generator = &info->generators[0]; - g_line_generator_compute_cursor(generator->instance, x, index, generator->repeat, cursor); + *cursor = g_line_generator_compute_cursor(generator->instance, x, index, generator->repeat); } @@ -586,6 +531,12 @@ static void g_buffer_cache_class_init(GBufferCacheClass *class) static void g_buffer_cache_init(GBufferCache *cache) { + cache->content = NULL; + + cache->lines = NULL; + cache->count = 0; + cache->used = 0; + cache->tracker = g_width_tracker_new(cache); } @@ -723,6 +674,32 @@ gint g_buffer_cache_get_line_height(const GBufferCache *cache) * * * Paramètres : cache = tampon de lignes à consulter. * * * +* Description : Indique l'éventuel contenu binaire associé au cache. * +* * +* Retour : Eventuel contenu renseigné ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBinContent *g_buffer_cache_get_content(const GBufferCache *cache) +{ + GBinContent *result; /* Contenu à retourner */ + + result = cache->content; + + if (result != NULL) + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : cache = tampon de lignes à consulter. * +* * * Description : Fournit la taille réservée pour la marge gauche. * * * * Retour : Largeur en pixels. * @@ -895,14 +872,14 @@ void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator if (!before && !after) { - g_line_generator_compute_cursor(generator, 0, index, 0, &gen_cursor); + gen_cursor = g_line_generator_compute_cursor(generator, 0, index, 0); get_cache_info_cursor(&cache->lines[index], index, 0, &line_cursor); ret = g_line_cursor_compare(gen_cursor, line_cursor); - g_object_unref(G_OBJECT(gen_cursor)); g_object_unref(G_OBJECT(line_cursor)); + g_object_unref(G_OBJECT(gen_cursor)); assert(ret == 0); @@ -1264,8 +1241,6 @@ void g_buffer_cache_extend_with(GBufferCache *cache, size_t count, GLineGenerato cache->used = count; - g_object_unref(G_OBJECT(generator)); - if (added > 0) { g_width_tracker_update_added(cache->tracker, index, added); @@ -1297,8 +1272,6 @@ void g_buffer_cache_truncate(GBufferCache *cache, size_t max) size_t j; /* Boucle de parcours #2 */ size_t removed; /* Nombre de retraits effectués*/ - assert(max <= cache->used); - for (i = max; i < cache->used; i++) { info = &cache->lines[i]; @@ -1319,12 +1292,12 @@ void g_buffer_cache_truncate(GBufferCache *cache, size_t max) } - removed = cache->used - max; + if (max < cache->used) + { + removed = cache->used - max; - cache->used = max; + cache->used = max; - if (removed > 0) - { g_width_tracker_update_deleted(cache->tracker, max, max + removed - 1); g_signal_emit_by_name(cache, "size-changed", false, max, removed); @@ -1378,6 +1351,8 @@ BufferLineFlags g_buffer_cache_get_line_flags(const GBufferCache *cache, size_t const generator_link *generator; /* Générateur retenu */ size_t i; /* Boucle de parcours */ + // TODO : check lock + assert(index < cache->used); info = &cache->lines[index]; @@ -1650,6 +1625,8 @@ size_t g_buffer_cache_look_for_flag(const GBufferCache *cache, size_t start, Buf GLineCursor *next; /* Localisation suivante */ int ret; /* Bilan de comparaison */ + // TODO : check lock + assert(start < cache->used); result = start; diff --git a/src/glibext/gbuffercache.h b/src/glibext/gbuffercache.h index 58516b2..79158c4 100644 --- a/src/glibext/gbuffercache.h +++ b/src/glibext/gbuffercache.h @@ -39,12 +39,12 @@ /* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ -#define G_TYPE_BUFFER_CACHE (g_buffer_cache_get_type()) -#define G_BUFFER_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_CODE_BUFFER, GBufferCache)) -#define G_BUFFER_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_CODE_BUFFER, GBufferCacheClass)) -#define G_IS_BUFFER_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_CODE_BUFFER)) -#define G_IS_BUFFER_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_CODE_BUFFER)) -#define G_BUFFER_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_CODE_BUFFER, GBufferCacheClass)) +#define G_TYPE_BUFFER_CACHE g_buffer_cache_get_type() +#define G_BUFFER_CACHE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BUFFER_CACHE, GBufferCache)) +#define G_BUFFER_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BUFFER_CACHE, GBufferCacheClass)) +#define G_IS_BUFFER_CACHE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BUFFER_CACHE)) +#define G_IS_BUFFER_CACHE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BUFFER_CACHE)) +#define G_BUFFER_CACHE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BUFFER_CACHE, GBufferCacheClass)) /* Tampon pour gestion de lignes optimisée (instance) */ @@ -60,6 +60,9 @@ GType g_buffer_cache_get_type(void); /* Crée un nouveau composant de tampon pour code désassemblé. */ GBufferCache *g_buffer_cache_new(GBinContent *); +/* Indique l'éventuel contenu binaire associé au cache. */ +GBinContent *g_buffer_cache_get_content(const GBufferCache *); + /* Fournit la hauteur d'impression d'une ligne visualisée. */ gint g_buffer_cache_get_line_height(const GBufferCache *); diff --git a/src/glibext/gbufferline.c b/src/glibext/gbufferline.c index 9b0a5a9..e3482aa 100644 --- a/src/glibext/gbufferline.c +++ b/src/glibext/gbufferline.c @@ -546,13 +546,16 @@ GObject *g_buffer_line_find_first_segment_creator(const GBufferLine *line, Buffe * * ******************************************************************************/ -void g_buffer_line_append_text(GBufferLine *line, BufferLineColumn column, const char *text, size_t length, RenderingTagType type, GObject *creator) +void g_buffer_line_append_text(GBufferLine *line, size_t column, const char *text, size_t length, RenderingTagType type, GObject *creator) { size_t index; /* Indice d'insertion */ content_origin *origin; /* Définition d'une origine */ assert(length > 0); + if (column == -1) + column = BLC_LAST_USED; + if (column == BLC_MAIN) column = BLC_ASSEMBLY;//line->main_column; diff --git a/src/glibext/gbufferline.h b/src/glibext/gbufferline.h index e3d4894..11790fe 100644 --- a/src/glibext/gbufferline.h +++ b/src/glibext/gbufferline.h @@ -36,12 +36,12 @@ -#define G_TYPE_BUFFER_LINE (g_buffer_line_get_type()) -#define G_BUFFER_LINE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BUFFER_LINE, GBufferLine)) -#define G_BUFFER_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BUFFER_LINE, GBufferLineClass)) -#define G_IS_BUFFER_LINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BUFFER_LINE)) -#define G_IS_BUFFER_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BUFFER_LINE)) -#define G_BUFFER_LINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BUFFER_LINE, GBufferLineClass)) +#define G_TYPE_BUFFER_LINE g_buffer_line_get_type() +#define G_BUFFER_LINE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_BUFFER_LINE, GBufferLine)) +#define G_BUFFER_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_BUFFER_LINE, GBufferLineClass)) +#define G_IS_BUFFER_LINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_BUFFER_LINE)) +#define G_IS_BUFFER_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_BUFFER_LINE)) +#define G_BUFFER_LINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_BUFFER_LINE, GBufferLineClass)) /* Représentation de fragments de texte en ligne (instance) */ @@ -124,7 +124,7 @@ void g_buffer_line_fill_content(GBufferLine *, const GBinContent *, const mrange GObject *g_buffer_line_find_first_segment_creator(const GBufferLine *, BufferLineColumn); /* Ajoute du texte à formater dans une ligne donnée. */ -void g_buffer_line_append_text(GBufferLine *, BufferLineColumn, const char *, size_t, RenderingTagType, GObject *); +void g_buffer_line_append_text(GBufferLine *, size_t, const char *, size_t, RenderingTagType, GObject *); /* Remplace du texte dans une ligne donnée. */ bool g_buffer_line_replace_text(GBufferLine *, const GObject *, const char *, size_t); diff --git a/src/glibext/linegen.c b/src/glibext/linegen.c index 67b348a..42915ee 100644 --- a/src/glibext/linegen.c +++ b/src/glibext/linegen.c @@ -90,18 +90,18 @@ size_t g_line_generator_count_lines(const GLineGenerator *generator) * 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. * -* cursor = emplacement à constituer. [OUT] * * * * Description : Retrouve l'emplacement correspondant à une position donnée. * * * -* Retour : - * +* Retour : Emplacement constitué. * * * * Remarques : - * * * ******************************************************************************/ -void g_line_generator_compute_cursor(const GLineGenerator *generator, gint x, size_t index, size_t repeat, GLineCursor **cursor) +GLineCursor *g_line_generator_compute_cursor(const GLineGenerator *generator, gint x, size_t index, size_t repeat) { + GLineCursor *result; /* Emplacement à renvoyer */ GLineGeneratorIface *iface; /* Interface utilisée */ iface = G_LINE_GENERATOR_GET_IFACE(generator); @@ -111,7 +111,9 @@ void g_line_generator_compute_cursor(const GLineGenerator *generator, gint x, si assert(repeat < g_line_generator_count_lines(generator)); #endif - iface->compute(generator, x, index, repeat, cursor); + iface->compute(generator, x, index, repeat, &result); + + return result; } @@ -133,6 +135,7 @@ void g_line_generator_compute_cursor(const GLineGenerator *generator, gint x, si int g_line_generator_contains_cursor(const GLineGenerator *generator, size_t index, size_t repeat, const GLineCursor *cursor) { + int result; /* Bilan d'analyse à retourner */ GLineGeneratorIface *iface; /* Interface utilisée */ iface = G_LINE_GENERATOR_GET_IFACE(generator); @@ -142,7 +145,9 @@ int g_line_generator_contains_cursor(const GLineGenerator *generator, size_t ind assert(repeat < g_line_generator_count_lines(generator)); #endif - return iface->contains(generator, index, repeat, cursor); + result = iface->contains(generator, index, repeat, cursor); + + return result; } @@ -163,6 +168,7 @@ int g_line_generator_contains_cursor(const GLineGenerator *generator, size_t ind BufferLineFlags g_line_generator_get_flags(const GLineGenerator *generator, size_t index, size_t repeat) { + BufferLineFlags result; /* Fanions à retourner */ GLineGeneratorIface *iface; /* Interface utilisée */ iface = G_LINE_GENERATOR_GET_IFACE(generator); @@ -172,7 +178,9 @@ BufferLineFlags g_line_generator_get_flags(const GLineGenerator *generator, size assert(repeat < g_line_generator_count_lines(generator)); #endif - return iface->get_flags(generator, index, repeat); + result = iface->get_flags(generator, index, repeat); + + return result; } @@ -204,6 +212,6 @@ void g_line_generator_print(GLineGenerator *generator, GBufferLine *line, size_t assert(repeat < g_line_generator_count_lines(generator)); #endif - return iface->print(generator, line, index, repeat, content); + iface->print(generator, line, index, repeat, content); } diff --git a/src/glibext/linegen.h b/src/glibext/linegen.h index cb2e1fd..967e95e 100644 --- a/src/glibext/linegen.h +++ b/src/glibext/linegen.h @@ -34,7 +34,7 @@ -#define G_TYPE_LINE_GENERATOR (g_line_generator_get_type()) +#define G_TYPE_LINE_GENERATOR g_line_generator_get_type() #define G_LINE_GENERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_LINE_GENERATOR, GLineGenerator)) #define G_LINE_GENERATOR_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST((vtable), G_TYPE_LINE_GENERATOR, GLineGeneratorIface)) #define GTK_IS_LINE_GENERATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_LINE_GENERATOR)) @@ -56,7 +56,7 @@ GType g_line_generator_get_type(void) G_GNUC_CONST; size_t g_line_generator_count_lines(const GLineGenerator *); /* Retrouve l'emplacement correspondant à une position donnée. */ -void g_line_generator_compute_cursor(const GLineGenerator *, gint, size_t, size_t, GLineCursor **); +GLineCursor *g_line_generator_compute_cursor(const GLineGenerator *, gint, size_t, size_t); /* Détermine si le conteneur s'inscrit dans une plage donnée. */ int g_line_generator_contains_cursor(const GLineGenerator *, size_t, size_t, const GLineCursor *); diff --git a/src/gtkext/hexdisplay.c b/src/gtkext/hexdisplay.c index 685fc81..0f0bd30 100644 --- a/src/gtkext/hexdisplay.c +++ b/src/gtkext/hexdisplay.c @@ -321,10 +321,7 @@ static void gtk_hex_display_populate_cache(GtkHexDisplay *display) g_buffer_cache_truncate(display->cache, needed); else if (needed > count) - { - g_object_ref(G_OBJECT(display->generator)); g_buffer_cache_extend_with(display->cache, needed, G_LINE_GENERATOR(display->generator)); - } if (needed != count) gtk_widget_queue_resize(GTK_WIDGET(display)); diff --git a/tests/glibext/buffercache.py b/tests/glibext/buffercache.py new file mode 100644 index 0000000..30488f7 --- /dev/null +++ b/tests/glibext/buffercache.py @@ -0,0 +1,49 @@ + +from chrysacase import ChrysalideTestCase +from gi.repository import GObject +from pychrysalide.analysis.contents import MemoryContent +from pychrysalide.glibext import BufferCache +from pychrysalide.glibext import BufferLine +from pychrysalide.glibext import LineGenerator + + +class CommentBuilder(GObject.Object, LineGenerator): + def _count_lines(self): + return 1 + def _get_flags(self, index, repeat): + return BufferLine.BufferLineFlags.NONE + def _print(self, line, index, repeat, content): + line.append_text(0, '# Comment', BufferLine.RenderingTagType.PRINTABLE) + + +class TestBufferCache(ChrysalideTestCase): + """TestCase for glibext.BufferCache*""" + + def testCacheConstructor(self): + """Build all possible kinds of buffer caches.""" + + cache = BufferCache() + self.assertIsNotNone(cache) + self.assertIsNone(cache.content) + + cache = BufferCache(None) + self.assertIsNotNone(cache) + self.assertIsNone(cache.content) + + cnt = MemoryContent(b'\x00' * 8) + + cache = BufferCache(cnt) + self.assertIsNotNone(cache) + self.assertIsNotNone(cache.content) + + + def testCacheRendering(self): + """Check a buffer cache simple content.""" + + cache = BufferCache() + + cache.append(CommentBuilder(), BufferLine.BufferLineFlags.NONE) + + cache.append(CommentBuilder()) + + self.assertEqual(2, cache.lines_count) |