From f663a08007095e58f60fcf9a815a8b3d31b87c83 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Tue, 8 Sep 2020 00:11:49 +0200 Subject: Rewritten some code managing comments. --- plugins/arm/v7/fetch.c | 25 +- plugins/dalvik/link.c | 2 +- plugins/fmtp/parser.c | 34 +- plugins/lnxsyscalls/writer.c | 48 +- plugins/pychrysalide/analysis/db/items/Makefile.am | 1 + plugins/pychrysalide/analysis/db/items/comment.c | 550 ++++++++++++-- plugins/pychrysalide/analysis/db/items/comment.h | 20 + plugins/pychrysalide/analysis/db/items/constants.c | 129 ++++ plugins/pychrysalide/analysis/db/items/constants.h | 42 ++ plugins/pychrysalide/analysis/db/items/module.c | 1 + src/analysis/db/items/comment.c | 793 ++++++++------------- src/analysis/db/items/comment.h | 60 +- src/core/collections.c | 2 +- src/format/preload.c | 77 +- src/format/preload.h | 6 + 15 files changed, 1191 insertions(+), 599 deletions(-) create mode 100644 plugins/pychrysalide/analysis/db/items/constants.c create mode 100644 plugins/pychrysalide/analysis/db/items/constants.h diff --git a/plugins/arm/v7/fetch.c b/plugins/arm/v7/fetch.c index 876ad51..2d38cbf 100644 --- a/plugins/arm/v7/fetch.c +++ b/plugins/arm/v7/fetch.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -389,6 +390,7 @@ void help_fetching_with_instruction_ldr_literal_with_orig(GArchInstruction *inst GArchInstruction *loaded; /* Instruction de valeur */ bool inserted; /* Bilan d'une insertion */ char *desc; /* Description d'accompagnement*/ + size_t index; /* Indice d'un existant ? */ GDbComment *comment; /* Définition de commentaire */ GArchOperand *new; /* Instruction de ciblage */ @@ -494,30 +496,35 @@ void help_fetching_with_instruction_ldr_literal_with_orig(GArchInstruction *inst g_preload_info_lock_comments(info); - comment = _g_preload_info_find_comment_at(info, &loaded_addr); + comment = g_preload_info_find_comment_at(info, &loaded_addr, &index); - if (comment != NULL) + if (comment == NULL) { - g_db_comment_add_static_text(comment, "\n"); - g_db_comment_add_dynamic_text(comment, desc); + comment = g_db_comment_new(&loaded_addr, CET_INLINED, BLF_HAS_CODE, desc); + g_db_item_add_flag(G_DB_ITEM(comment), DIF_VOLATILE); - g_object_unref(G_OBJECT(comment)); + _g_preload_info_add_comment(info, comment); } else { - comment = g_db_comment_new_inlined(&loaded_addr, BLF_HAS_CODE, false); - g_db_item_add_flag(G_DB_ITEM(comment), DIF_VOLATILE); + desc = strprep(desc, "\n"); + desc = strprep(desc, g_db_comment_get_text(comment)); - g_db_comment_add_dynamic_text(comment, desc); + g_object_unref(G_OBJECT(comment)); - _g_preload_info_add_comment(info, comment); + comment = g_db_comment_new(&loaded_addr, CET_INLINED, BLF_HAS_CODE, desc); + g_db_item_add_flag(G_DB_ITEM(comment), DIF_VOLATILE); + + g_preload_info_replace_comment_at(info, index, comment); } g_preload_info_unlock_comments(info); + free(desc); + } /* Mise à jour de l'affichage et conclusion */ diff --git a/plugins/dalvik/link.c b/plugins/dalvik/link.c index d412511..9fb1992 100644 --- a/plugins/dalvik/link.c +++ b/plugins/dalvik/link.c @@ -358,7 +358,7 @@ void handle_dalvik_packed_switch_links(GArchInstruction *instr, GArchProcessor * } - item = g_db_comment_new_area(&comment->handler, BLF_NONE, msg, true); + item = g_db_comment_new(&comment->handler, CET_BEFORE, BLF_NONE, msg); g_db_item_add_flag(G_DB_ITEM(item), DIF_VOLATILE); g_proc_context_add_db_item(context, G_DB_ITEM(item)); diff --git a/plugins/fmtp/parser.c b/plugins/fmtp/parser.c index 4a8749d..84bb86f 100644 --- a/plugins/fmtp/parser.c +++ b/plugins/fmtp/parser.c @@ -25,10 +25,12 @@ #include +#include #include #include +#include #include @@ -63,6 +65,7 @@ static bool parse_field_definition(const fmt_field_def *def, GBinFormat *format, GArchInstruction *instr; /* Instruction décodée */ GImmOperand *imm; /* Opérande à transformer */ size_t i; /* Boucle de parcours */ + char *text; /* Texte du commentaire complet*/ const vmpa2t *addr; /* Emplacement d'instruction */ GDbComment *comment; /* Définition de commentaire */ uint64_t raw; /* Valeur brute à étudier */ @@ -125,15 +128,12 @@ static bool parse_field_definition(const fmt_field_def *def, GBinFormat *format, /* Commentaire */ - addr = get_mrange_addr(g_arch_instruction_get_range(instr)); - - comment = g_db_comment_new_inlined(addr, BLF_HAS_CODE, false); - g_db_item_add_flag(G_DB_ITEM(comment), DIF_VOLATILE); + text = NULL; switch (def->ctype) { case FCT_PLAIN: - g_db_comment_add_static_text(comment, _(def->comment.plain)); + text = strdup(_(def->comment.plain)); break; case FCT_SWITCH: @@ -155,13 +155,16 @@ static bool parse_field_definition(const fmt_field_def *def, GBinFormat *format, else if (raw != def->comment.choices[i].fixed) continue; - g_db_comment_add_static_text(comment, _(def->comment.choices[i].desc)); + text = strnadd(text, _(def->comment.choices[i].desc), strlen(_(def->comment.choices[i].desc))); break; } - if (i == def->comment.ccount) - g_db_comment_add_static_text(comment, _(def->comment.def_choice)); + if (text == NULL) + { + assert(i == def->comment.ccount); + text = strdup(_(def->comment.def_choice)); + } break; @@ -174,16 +177,16 @@ static bool parse_field_definition(const fmt_field_def *def, GBinFormat *format, if (part->is_static) { if (part->avoid_i18n) - g_db_comment_add_static_text(comment, part->static_text); + text = strnadd(text, part->static_text, strlen(part->static_text)); else - g_db_comment_add_static_text(comment, _(part->static_text)); + text = strnadd(text, _(part->static_text), strlen(_(part->static_text))); } else { if (part->avoid_i18n) - g_db_comment_add_dynamic_text(comment, part->dynamic_text); + text = strnadd(text, part->dynamic_text, strlen(part->dynamic_text)); else - g_db_comment_add_dynamic_text(comment, _(part->dynamic_text)); + text = strnadd(text, _(part->dynamic_text), strlen(_(part->dynamic_text))); } } @@ -192,6 +195,13 @@ static bool parse_field_definition(const fmt_field_def *def, GBinFormat *format, } + addr = get_mrange_addr(g_arch_instruction_get_range(instr)); + + comment = g_db_comment_new(addr, CET_INLINED, BLF_HAS_CODE, text); + g_db_item_add_flag(G_DB_ITEM(comment), DIF_VOLATILE); + + free(text); + /* Insertions */ inserted = g_preload_info_add_instruction(info, instr); diff --git a/plugins/lnxsyscalls/writer.c b/plugins/lnxsyscalls/writer.c index 743e5c6..0b90d68 100644 --- a/plugins/lnxsyscalls/writer.c +++ b/plugins/lnxsyscalls/writer.c @@ -29,6 +29,7 @@ #include +#include @@ -196,43 +197,60 @@ void write_all_comments(comment_writer *writer, GPreloadInfo *preload) { size_t i; /* Boucle de parcours #1 */ comment_data *target; /* Commentaire à éditer */ - GDbComment *comment; /* Commentaire final à intégrer*/ - bool new; /* Nature du commentaire */ + char *text; /* Texte du commentaire complet*/ size_t k; /* Boucle de parcours #2 */ + size_t index; /* Indice d'un existant ? */ + GDbComment *comment; /* Commentaire final à intégrer*/ for (i = 0; i < writer->count; i++) { target = &writer->comments[i]; - g_preload_info_lock_comments(preload); + /* Construction de la nouveauté */ - comment = _g_preload_info_find_comment_at(preload, &target->addr); + text = NULL; + + for (k = 0; k < target->count; k++) + { + if (k > 0) + text = stradd(text, " / "); - new = (comment == NULL); + text = stradd(text, target->text[k]); + + } + + /* Inclusion de l'existant */ + + g_preload_info_lock_comments(preload); + + comment = g_preload_info_find_comment_at(preload, &target->addr, &index); if (comment == NULL) { - comment = g_db_comment_new_inlined(&target->addr, BLF_HAS_CODE, false); + comment = g_db_comment_new(&target->addr, CET_INLINED, BLF_HAS_CODE, text); g_db_item_add_flag(G_DB_ITEM(comment), DIF_VOLATILE); - g_object_ref(G_OBJECT(comment)); - _g_preload_info_add_comment(preload, comment); } - g_preload_info_unlock_comments(preload); - - for (k = 0; k < target->count; k++) + else { - if (k > 0 || !new) - g_db_comment_add_static_text(comment, " / "); + text = strprep(text, " / "); + text = strprep(text, g_db_comment_get_text(comment)); - g_db_comment_add_dynamic_text(comment, strdup(target->text[k])); + g_object_unref(G_OBJECT(comment)); + + comment = g_db_comment_new(&target->addr, CET_INLINED, BLF_HAS_CODE, text); + g_db_item_add_flag(G_DB_ITEM(comment), DIF_VOLATILE); + + g_preload_info_replace_comment_at(preload, index, comment); } - g_object_unref(G_OBJECT(comment)); + g_preload_info_unlock_comments(preload); + + free(text); } diff --git a/plugins/pychrysalide/analysis/db/items/Makefile.am b/plugins/pychrysalide/analysis/db/items/Makefile.am index 07593f8..35f4ee6 100644 --- a/plugins/pychrysalide/analysis/db/items/Makefile.am +++ b/plugins/pychrysalide/analysis/db/items/Makefile.am @@ -4,6 +4,7 @@ noinst_LTLIBRARIES = libpychrysaanalysisdbitems.la libpychrysaanalysisdbitems_la_SOURCES = \ bookmark.h bookmark.c \ comment.h comment.c \ + constants.h constants.c \ module.h module.c \ switcher.h switcher.c diff --git a/plugins/pychrysalide/analysis/db/items/comment.c b/plugins/pychrysalide/analysis/db/items/comment.c index 845a118..78d4902 100644 --- a/plugins/pychrysalide/analysis/db/items/comment.c +++ b/plugins/pychrysalide/analysis/db/items/comment.c @@ -29,28 +29,57 @@ #include -#include #include +#include +#include "constants.h" +#include "../collection.h" #include "../item.h" #include "../../../access.h" #include "../../../helpers.h" #include "../../../arch/vmpa.h" +#include "../../../glibext/constants.h" +#include "../../../glibext/bufferline.h" +/* --------------------- ELABORATION D'UN ELEMENT DE COLLECTION --------------------- */ + + /* Crée un nouvel objet Python de type 'DbComment'. */ static PyObject *py_db_comment_new(PyTypeObject *, PyObject *, PyObject *); -/* Associe un contenu statique supplémentaire à un commentaire. */ -static PyObject *py_db_comment_add_text(PyObject *, PyObject *); +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_db_comment_init(PyObject *, PyObject *, PyObject *); + +/* Fournit l'adresse associée à un commentaire. */ +static PyObject *py_db_comment_get_address(PyObject *, void *); + +/* Indique le type d'incrustation prévue pour un commentaire. */ +static PyObject *py_db_comment_get_embedding_type(PyObject *, void *); + +/* Fournit les particularités d'accroche liées à un commentaire. */ +static PyObject *py_db_comment_get_flags(PyObject *, void *); /* Fournit le commentaire associé à un commentaire. */ static PyObject *py_db_comment_get_text(PyObject *, void *); +/* ---------------------- DEFINITION DE LA COLLECTION ASSOCIEE ---------------------- */ + + +/* Crée un nouvel objet Python de type 'CommentCollection'. */ +static PyObject *py_comment_collection_new(PyTypeObject *, PyObject *, PyObject *); + + + +/* ---------------------------------------------------------------------------------- */ +/* ELABORATION D'UN ELEMENT DE COLLECTION */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * * Paramètres : type = type de l'objet à instancier. * @@ -67,58 +96,170 @@ static PyObject *py_db_comment_get_text(PyObject *, void *); static PyObject *py_db_comment_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ - int repeatable; /* Note une répétition demandée*/ - const char *text; /* Eventuel premier commentaire*/ - int before; /* Indication sur l'emplacement*/ + 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_db_comment_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_DB_COMMENT, 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 en cas de succès, -1 sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_db_comment_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int result; /* Bilan à renvoyer */ vmpa2t *addr; /* Emplacement ciblé */ - unsigned long flags; /* Identifiants de ligne visée */ + CommentEmbeddingType type; /* Type d'incrustation */ + BufferLineFlags flags; /* Particularités de l'accroche*/ + const char *text; /* Eventuel contenu textuel */ int ret; /* Bilan de lecture des args. */ - GDbComment *comment; /* Version GLib du commentaire */ - - static char *kwlist[] = { "addr", "flags", "repeatable", "text", "before", NULL }; + GDbComment *comment; /* Version GLib du signet */ + bool status; /* Bilan de l'initialisation */ + +#define DB_COMMENT_DOC \ + "DbComment provides support for comments to embed into the disassembled" \ + " code.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " DbComment(addr, addr, type, flags, text=None)\n" \ + "\n" \ + "Where *addr* is a location of type pychrysalide.arch.vmpa, *type* defines" \ + " the kind of embedding as a" \ + " pychrysalide.analysis.db.items.DbComment.CommentEmbeddingType value," \ + " *flags* states for the pychrysalide.glibext.BufferLine.BufferLineFlags" \ + " property of the line to attach and *text* is an optional string for the" \ + " comment.\n" \ + "\n" \ + "An empty comment is not enough to delete a comment for a given address;" \ + " the *ERASER* flag from the pychrysalide.analysis.db.DbItem.DbItemFlags" \ + " enumeration must be explicitly add to the item by a call to the" \ + " pychrysalide.analysis.db.DbItem.add_flag() function." + + result = -1; /* Récupération des paramètres */ - repeatable = -1; text = NULL; - before = -1; - ret = PyArg_ParseTupleAndKeywords(args, kwds, "O&k|$psp", kwlist, - convert_any_to_vmpa, &addr, &flags, &repeatable, &text, &before); - if (!ret) return NULL; + ret = PyArg_ParseTuple(args, "O&O&O&|s", + convert_any_to_vmpa, &addr, + convert_to_comment_embedding_type, &type, + convert_to_buffer_line_flags, &flags, + &text); + if (!ret) goto exit; - /* Vérifications diverses */ + /* Initialisation d'un objet GLib */ - if (flags > BLF_ALL) + ret = forward_pygobjet_init(self); + if (ret == -1) { clean_vmpa_arg(addr); + goto exit; + } - PyErr_SetString(PyExc_ValueError, _("Invalid flag combination")); - return NULL; + /* Eléments de base */ - } + comment = G_DB_COMMENT(pygobject_get(self)); - if ((repeatable == -1 && before == -1) || (repeatable != -1 && before != -1)) + status = g_db_comment_fill(comment, addr, type, flags, text); + if (!status) { clean_vmpa_arg(addr); + goto exit; + } - PyErr_SetString(PyExc_ValueError, _("repeatable or before has to be defined")); - return NULL; + clean_vmpa_arg(addr); - } + result = 0; - /* Construction */ + exit: - if (repeatable) - comment = g_db_comment_new_inlined(addr, flags, repeatable); - else - comment = g_db_comment_new_area(addr, flags, text, before); + return result; - result = pygobject_new(G_OBJECT(comment)); - g_object_unref(comment); +} - clean_vmpa_arg(addr); + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit l'adresse associée à un commentaire. * +* * +* Retour : Adresse mémoire. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_db_comment_get_address(PyObject *self, void *closure) +{ + PyObject *result; /* Résultat à retourner */ + GDbComment *comment; /* Commentaire à consulter */ + const vmpa2t *addr; /* Localisation du commentaire */ + +#define DB_COMMENT_ADDRESS_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + address, py_db_comment, \ + "Location of the comment, provided as a" \ + " pychrysalide.arch.vmpa instance." \ +) + + comment = G_DB_COMMENT(pygobject_get(self)); + + addr = g_db_comment_get_address(comment); + + result = build_from_internal_vmpa(addr); return result; @@ -127,31 +268,74 @@ static PyObject *py_db_comment_new(PyTypeObject *type, PyObject *args, PyObject /****************************************************************************** * * -* Paramètres : self = classe représentant un commentaire. * -* args = arguments fournis à l'appel. * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * * * -* Description : Associe un contenu statique supplémentaire à un commentaire. * +* Description : Indique le type d'incrustation prévue pour un commentaire. * * * -* Retour : None. * +* Retour : Incrustation associée au commentaire. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_db_comment_add_text(PyObject *self, PyObject *args) +static PyObject *py_db_comment_get_embedding_type(PyObject *self, void *closure) { - const char *text; /* Commentaire complémentaire */ - int ret; /* Bilan de lecture des args. */ + PyObject *result; /* Résultat à retourner */ GDbComment *comment; /* Commentaire à consulter */ + CommentEmbeddingType type; /* Type d'incrustation */ - ret = PyArg_ParseTuple(args, "s", &text); - if (!ret) return NULL; +#define DB_COMMENT_EMBEDDING_TYPE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + embedding_type, py_db_comment, \ + "Type of embedding required for the comment, as a" \ + " pychrysalide.analysis.db.items.DbComment.CommentEmbeddingType value." \ +) comment = G_DB_COMMENT(pygobject_get(self)); - g_db_comment_add_static_text(comment, text); + type = g_db_comment_get_embedding_type(comment); + + result = cast_with_constants_group_from_type(get_python_db_comment_type(), "CommentEmbeddingType", type); - Py_RETURN_NONE; + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit les particularités d'accroche liées à un commentaire.* +* * +* Retour : Particularités éventuelles pour l'accroche. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_db_comment_get_flags(PyObject *self, void *closure) +{ + PyObject *result; /* Résultat à retourner */ + GDbComment *comment; /* Commentaire à consulter */ + BufferLineFlags flags; /* Fanions à rechercher */ + +#define DB_COMMENT_FLAGS_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + flags, py_db_comment, \ + "Flags of the line where to attach the comment, as a" \ + " pychrysalide.glibext.BufferLine.BufferLineFlags value." \ +) + + comment = G_DB_COMMENT(pygobject_get(self)); + + flags = g_db_comment_get_flags(comment); + + result = cast_with_constants_group_from_type(get_python_buffer_line_type(), "BufferLineFlags", flags); + + return result; } @@ -175,6 +359,13 @@ static PyObject *py_db_comment_get_text(PyObject *self, void *closure) GDbComment *comment; /* Commentaire à consulter */ char *text; /* Contenu textuel associé */ +#define DB_COMMENT_TEXT_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + text, py_db_comment, \ + "Content of the comment, as a string which may contain several lines," \ + " or None of no text is linked to the comment." \ +) + comment = G_DB_COMMENT(pygobject_get(self)); text = g_db_comment_get_text(comment); @@ -209,19 +400,14 @@ static PyObject *py_db_comment_get_text(PyObject *self, void *closure) PyTypeObject *get_python_db_comment_type(void) { static PyMethodDef py_db_comment_methods[] = { - { - "add_text", py_db_comment_add_text, - METH_VARARGS, - "add_text($self, text, /)\n--\n\nAppend extra text to a given comment." - }, { NULL } }; static PyGetSetDef py_db_comment_getseters[] = { - { - "text", py_db_comment_get_text, NULL, - "Give access to the content of a given comment.", NULL - }, + DB_COMMENT_ADDRESS_ATTRIB, + DB_COMMENT_EMBEDDING_TYPE_ATTRIB, + DB_COMMENT_FLAGS_ATTRIB, + DB_COMMENT_TEXT_ATTRIB, { NULL } }; @@ -234,11 +420,13 @@ PyTypeObject *get_python_db_comment_type(void) .tp_flags = Py_TPFLAGS_DEFAULT, - .tp_doc = "PyChrysalide comment for edited binary", + .tp_doc = DB_COMMENT_DOC, .tp_methods = py_db_comment_methods, .tp_getset = py_db_comment_getseters, - .tp_new = py_db_comment_new + + .tp_init = py_db_comment_init, + .tp_new = py_db_comment_new, }; @@ -279,8 +467,260 @@ bool ensure_python_db_comment_is_registered(void) if (!register_class_for_pygobject(dict, G_TYPE_DB_COMMENT, type, get_python_db_item_type())) return false; + if (!define_db_comment_constants(type)) + return false; + + } + + 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 commentaire de base. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_db_comment(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_db_comment_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 database comment"); + break; + + case 1: + *((GDbComment **)dst) = G_DB_COMMENT(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION DE LA COLLECTION ASSOCIEE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : type = type de l'objet à instancier. * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Crée un nouvel objet Python de type 'CommentCollection'. * +* * +* Retour : Instance Python mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_comment_collection_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 */ + +#define COMMENT_COLLECTION_DOC \ + "CommentCollection remembers all comment definitions.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " CommentCollection()\n" \ + "\n" \ + "There should be no need for creating such instances manually." + + /* Validations diverses */ + + base = get_python_db_comment_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_DB_COMMENT, 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 : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_comment_collection_type(void) +{ + static PyMethodDef py_comment_collection_methods[] = { + { NULL } + }; + + static PyGetSetDef py_comment_collection_getseters[] = { + { NULL } + }; + + static PyTypeObject py_comment_collection_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.db.items.CommentCollection", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = COMMENT_COLLECTION_DOC, + + .tp_methods = py_comment_collection_methods, + .tp_getset = py_comment_collection_getseters, + + .tp_new = py_comment_collection_new, + + }; + + return &py_comment_collection_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide....CommentCollection'.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_comment_collection_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'DbComment' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_comment_collection_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.db.items"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_db_collection_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_COMMENT_COLLECTION, type, get_python_db_collection_type())) + return false; + } 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 collection de commentaires. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_comment_collection(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_comment_collection_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 comment collection"); + break; + + case 1: + *((GCommentCollection **)dst) = G_COMMENT_COLLECTION(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/db/items/comment.h b/plugins/pychrysalide/analysis/db/items/comment.h index df02cc6..4e5af64 100644 --- a/plugins/pychrysalide/analysis/db/items/comment.h +++ b/plugins/pychrysalide/analysis/db/items/comment.h @@ -31,12 +31,32 @@ +/* --------------------- ELABORATION D'UN ELEMENT DE COLLECTION --------------------- */ + + /* Fournit un accès à une définition de type à diffuser. */ PyTypeObject *get_python_db_comment_type(void); /* Prend en charge l'objet 'pychrysalide.analysis.db.items.DbComment'. */ bool ensure_python_db_comment_is_registered(void); +/* Tente de convertir en commentaire de base. */ +int convert_to_db_comment(PyObject *, void *); + + + +/* ---------------------- DEFINITION DE LA COLLECTION ASSOCIEE ---------------------- */ + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_comment_collection_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.db.items.CommentCollection'. */ +bool ensure_python_comment_collection_is_registered(void); + +/* Tente de convertir en collection de commentaires. */ +int convert_to_comment_collection(PyObject *, void *); + #endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ITEMS_COMMENT_H */ diff --git a/plugins/pychrysalide/analysis/db/items/constants.c b/plugins/pychrysalide/analysis/db/items/constants.c new file mode 100644 index 0000000..e3ef99e --- /dev/null +++ b/plugins/pychrysalide/analysis/db/items/constants.c @@ -0,0 +1,129 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.c - ajout des constantes liées aux éléments de base + * + * 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "constants.h" + + +#include +#include + + +#include "../../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes relatives aux commentaires de base. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_db_comment_constants(PyTypeObject *type) +{ + bool result; /* Bilan à retourner */ + PyObject *values; /* Groupe de valeurs à établir */ + + values = PyDict_New(); + + result = add_const_to_group(values, "INLINED", CET_INLINED); + if (result) result = add_const_to_group(values, "REPEATED", CET_REPEATED); + if (result) result = add_const_to_group(values, "BEFORE", CET_BEFORE); + if (result) result = add_const_to_group(values, "AFTER", CET_AFTER); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group_to_type(type, false, "CommentEmbeddingType", values, + "Kinds of insertion for comments."); + + 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 CommentEmbeddingType. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_comment_embedding_type(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + unsigned long value; /* Valeur récupérée */ + + 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 CommentEmbeddingType"); + break; + + case 1: + value = PyLong_AsUnsignedLong(arg); + + if (value >= CET_COUNT) + { + PyErr_SetString(PyExc_TypeError, "invalid value to convert to CommentEmbeddingType"); + result = 0; + } + + else + *((CommentEmbeddingType *)dst) = value; + + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/db/items/constants.h b/plugins/pychrysalide/analysis/db/items/constants.h new file mode 100644 index 0000000..80210d9 --- /dev/null +++ b/plugins/pychrysalide/analysis/db/items/constants.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.h - prototypes pour l'ajout des constantes liées aux éléments de base + * + * 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ITEMS_CONSTANTS_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ITEMS_CONSTANTS_H + + +#include +#include + + + +/* Définit les constantes relatives aux commentaires de base. */ +bool define_db_comment_constants(PyTypeObject *); + +/* Tente de convertir en constante CommentEmbeddingType. */ +int convert_to_comment_embedding_type(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ITEMS_CONSTANTS_H */ diff --git a/plugins/pychrysalide/analysis/db/items/module.c b/plugins/pychrysalide/analysis/db/items/module.c index c963354..cbc367d 100644 --- a/plugins/pychrysalide/analysis/db/items/module.c +++ b/plugins/pychrysalide/analysis/db/items/module.c @@ -91,6 +91,7 @@ bool populate_analysis_db_items_module(void) result = true; if (result) result = ensure_python_bookmark_collection_is_registered(); + if (result) result = ensure_python_comment_collection_is_registered(); if (result) result = ensure_python_switcher_collection_is_registered(); if (result) result = ensure_python_db_bookmark_is_registered(); if (result) result = ensure_python_db_comment_is_registered(); diff --git a/src/analysis/db/items/comment.c b/src/analysis/db/items/comment.c index 4b22502..136b62b 100644 --- a/src/analysis/db/items/comment.c +++ b/src/analysis/db/items/comment.c @@ -27,6 +27,7 @@ #include #include #include +#include #include @@ -53,23 +54,10 @@ struct _GDbComment GDbItem parent; /* A laisser en premier */ vmpa2t addr; /* Adresse du commentaire */ + CommentEmbeddingType type; /* Type d'incrustation */ BufferLineFlags flags; /* Identification de l'accroche*/ flat_array_t *text; /* Contenu du commentaire */ - size_t count; /* Quantité de lignes affichées*/ - - bool inlined; /* Intégration dans une ligne ?*/ - - union - { - bool repeatable; /* Répétition aux lignes liées */ - bool before; /* Zone dédiée au dessus ? */ - }; - - GLineGenerator *previous; /* Commentaire remplacé */ - - GLineGenerator **old_inlined; /* Commentaires d'origine ? */ - size_t old_count; /* Nombre de places à restaurer*/ }; @@ -93,6 +81,15 @@ static void g_db_comment_dispose(GDbComment *); /* Procède à la libération totale de la mémoire. */ static void g_db_comment_finalize(GDbComment *); +/* Constitue un ensemble de lignes pour un commentaire. */ +static void g_db_comment_define_text_lines(GDbComment *, const char *); + +/* Calcule le condensat associé à l'élément vu comme clef. */ +static guint g_db_comment_hash_key(const GDbComment *); + +/* Compare deux éléments en tant que clefs. */ +static gboolean g_db_comment_cmp_key(const GDbComment *, const GDbComment *); + /* Effectue la comparaison entre deux commentaires enregistrés. */ static gint g_db_comment_cmp(const GDbComment *, const GDbComment *); @@ -120,19 +117,13 @@ static bool g_db_comment_load(GDbComment *, const bound_value *, size_t); /* Constitue les champs destinés à une insertion / modification. */ static bool g_db_comment_store(GDbComment *, bound_value **, size_t *); -/* Associe un contenu formaté supplémentaire à un commentaire. */ -static void g_db_comment_add_rle_string(GDbComment *, const rle_string *); - /* ------------------------ OFFRE DE CAPACITES DE GENERATION ------------------------ */ -/* Calcule le nombre de lignes suite à un changement de contenu. */ -static void g_db_comment_update_count_lines(GDbComment *); - /* Indique le nombre de ligne prêtes à être générées. */ -static size_t g_db_comment_count_lines(const GDbComment *); +static size_t g_db_comment_count_lines(GDbComment *); /* Retrouve l'emplacement correspondant à une position donnée. */ static void g_db_comment_compute_cursor(const GDbComment *, gint, size_t, size_t, GLineCursor **); @@ -141,7 +132,7 @@ static void g_db_comment_compute_cursor(const GDbComment *, gint, size_t, size_t static int g_db_comment_contain_cursor(const GDbComment *, size_t, size_t, const GLineCursor *); /* Renseigne sur les propriétés liées à un générateur. */ -static BufferLineFlags g_db_comment_get_flags(const GDbComment *, size_t, size_t); +static BufferLineFlags g_db_comment_get_generator_flags(const GDbComment *, size_t, size_t); /* Imprime dans une ligne de rendu le contenu représenté. */ static void g_db_comment_print(GDbComment *, GBufferLine *, size_t, size_t, const GBinContent *); @@ -222,6 +213,8 @@ static void g_db_comment_class_init(GDbCommentClass *klass) item->feature = DBF_COMMENTS; + item->hash_key = (hash_db_item_key_fc)g_db_comment_hash_key; + item->cmp_key = (cmp_db_item_key_fc)g_db_comment_cmp_key; item->cmp = (cmp_db_item_fc)g_db_comment_cmp; item->unpack = (unpack_db_item_fc)g_db_comment_unpack; @@ -251,8 +244,12 @@ static void g_db_comment_class_init(GDbCommentClass *klass) static void g_db_comment_init(GDbComment *comment) { + init_vmpa(&comment->addr, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL); + + comment->type = CET_COUNT; + comment->flags = BLF_NONE; + comment->text = NULL; - comment->count = 0; } @@ -274,7 +271,7 @@ static void g_db_comment_interface_init(GLineGeneratorInterface *iface) iface->count = (linegen_count_lines_fc)g_db_comment_count_lines; iface->compute = (linegen_compute_fc)g_db_comment_compute_cursor; iface->contain = (linegen_contain_fc)g_db_comment_contain_cursor; - iface->get_flags = (linegen_get_flags_fc)g_db_comment_get_flags; + iface->get_flags = (linegen_get_flags_fc)g_db_comment_get_generator_flags; iface->print = (linegen_print_fc)g_db_comment_print; } @@ -294,13 +291,6 @@ static void g_db_comment_interface_init(GLineGeneratorInterface *iface) static void g_db_comment_dispose(GDbComment *comment) { - size_t i; /* Boucle de parcours */ - - g_clear_object(&comment->previous); - - for (i = 0; i < comment->old_count; i++) - g_clear_object(&comment->old_inlined[i]); - G_OBJECT_CLASS(g_db_comment_parent_class)->dispose(G_OBJECT(comment)); } @@ -340,9 +330,6 @@ static void g_db_comment_finalize(GDbComment *comment) unlock_flat_array(&comment->text); - if (comment->old_inlined != NULL) - free(comment->old_inlined); - G_OBJECT_CLASS(g_db_comment_parent_class)->finalize(G_OBJECT(comment)); } @@ -350,11 +337,12 @@ static void g_db_comment_finalize(GDbComment *comment) /****************************************************************************** * * -* Paramètres : addr = adresse inamovible localisant une position. * -* flags = indentifiants supplémentaires de ligne visée. * -* repeatable = repétition aux instructions liées ? * +* Paramètres : addr = adresse inamovible localisant une position. * +* type = type d'incrustation à respecter pour l'insertion. * +* flags = indentifiants supplémentaires de ligne visée. * +* text = contenu textuel associé au commentaire ou NULL. * * * -* Description : Crée une définition de commentaire dans une zone de texte. * +* Description : Crée une définition de commentaire textuel. * * * * Retour : Commentaire mis en place ou NULL en cas d'erreur. * * * @@ -362,19 +350,59 @@ static void g_db_comment_finalize(GDbComment *comment) * * ******************************************************************************/ -GDbComment *g_db_comment_new_inlined(const vmpa2t *addr, BufferLineFlags flags, bool repeatable) +GDbComment *g_db_comment_new(const vmpa2t *addr, CommentEmbeddingType type, BufferLineFlags flags, const char *text) { - GDbComment *result; /* Instance à retourner */ + GDbComment *result; /* Instance à retourner */ + bool status; /* Bilan de l'initialisation */ result = g_object_new(G_TYPE_DB_COMMENT, NULL); - copy_vmpa(&result->addr, addr); + status = g_db_comment_fill(result, addr, type, flags, text); + if (!status) goto error; + + return result; + + error: + + g_object_unref(G_OBJECT(result)); + + return NULL; + +} + - result->flags = flags; +/****************************************************************************** +* * +* Paramètres : addr = adresse inamovible localisant une position. * +* type = type d'incrustation à respecter pour l'insertion. * +* flags = indentifiants supplémentaires de ligne visée. * +* text = contenu textuel associé au commentaire ou NULL. * +* * +* Description : Initialise la définition d'un commentaire à incruster. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ - result->inlined = true; +bool g_db_comment_fill(GDbComment *comment, const vmpa2t *addr, CommentEmbeddingType type, BufferLineFlags flags, const char *text) +{ + bool result; /* Bilan à retourner */ - result->repeatable = repeatable; + /** + * Cette fonction est principalement destinée aux initialisations + * depuis l'extension Python. + */ + + result = true; + + copy_vmpa(&comment->addr, addr); + + comment->type = type; + comment->flags = flags; + + g_db_comment_define_text_lines(comment, text); return result; @@ -383,34 +411,98 @@ GDbComment *g_db_comment_new_inlined(const vmpa2t *addr, BufferLineFlags flags, /****************************************************************************** * * -* Paramètres : addr = adresse inamovible localisant une position. * -* flags = indentifiants supplémentaires de ligne visée. * -* text = commentaire construit ou NULL. * -* before = précision quant à la position de la zone à définir. * +* Paramètres : comment = commentaire dont les lignes sont à constituer. * +* text = contenu textuel associé au commentaire ou NULL. * * * -* Description : Crée une définition de commentaire dans une zone de texte. * +* Description : Constitue un ensemble de lignes pour un commentaire. * * * -* Retour : Commentaire mis en place ou NULL en cas d'erreur. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -GDbComment *g_db_comment_new_area(const vmpa2t *addr, BufferLineFlags flags, const char *text, bool before) +static void g_db_comment_define_text_lines(GDbComment *comment, const char *text) { - GDbComment *result; /* Instance à retourner */ + char *tmp; /* Zone de travail modifiable */ + char **lines; /* Lignes du texte découpé */ + size_t count; /* Quantité de ces lignes */ + size_t i; /* Boucle de parcours */ + rle_string string; /* Fragment de texte à ajouter */ - result = g_object_new(G_TYPE_DB_COMMENT, NULL); + if (text != NULL) + { + tmp = strdup(text); + + tmp = strrpl(tmp, "\r", ""); + + lines = strtoka(tmp, "\n", &count); + + lock_flat_array(&comment->text); + + for (i = 0; i < count; i++) + { + init_dynamic_rle_string(&string, lines[i]); + + add_item_to_flat_array(&comment->text, &string, sizeof(rle_string)); + + } + + unlock_flat_array(&comment->text); + + free(lines); + + free(tmp); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : comment = élément de collection à consulter. * +* * +* Description : Calcule le condensat associé à l'élément vu comme clef. * +* * +* Retour : Condensat associé à l'élément. * +* * +* Remarques : - * +* * +******************************************************************************/ - copy_vmpa(&result->addr, addr); +static guint g_db_comment_hash_key(const GDbComment *comment) +{ + guint result; /* Valeur "unique" à renvoyer */ - result->flags = flags; + result = hash_vmpa(&comment->addr); - g_db_comment_add_dynamic_text(result, strdup(text)); + return result; - result->inlined = false; +} - result->before = before; + +/****************************************************************************** +* * +* Paramètres : a = premier élément de collection à consulter. * +* b = second élément de collection à consulter. * +* * +* Description : Compare deux éléments en tant que clefs. * +* * +* Retour : Bilan de la comparaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static gboolean g_db_comment_cmp_key(const GDbComment *a, const GDbComment *b) +{ + gboolean result; /* Bilan à retourner */ + int ret; /* Bilan intermédiaire */ + + ret = cmp_vmpa(&a->addr, &b->addr); + + result = (ret == 0); return result; @@ -440,8 +532,8 @@ static gint g_db_comment_cmp(const GDbComment *a, const GDbComment *b) if (result == 0) { - string_a = g_db_comment_get_text(a); - string_b = g_db_comment_get_text(b); + string_a = g_db_comment_get_text((GDbComment *)a); + string_b = g_db_comment_get_text((GDbComment *)b); if (string_a == NULL && string_b == NULL) result = 0; @@ -481,9 +573,9 @@ static gint g_db_comment_cmp(const GDbComment *a, const GDbComment *b) static bool g_db_comment_unpack(GDbComment *comment, packed_buffer *pbuf) { bool result; /* Bilan à retourner */ - uint32_t tmp32; /* Valeur sur 32 bits */ - rle_string string; /* Texte brut récupéré */ uint8_t tmp8; /* Valeur sur 8 bits */ + uint32_t tmp32; /* Valeur sur 32 bits */ + rle_string text; /* Texte brut récupéré */ result = G_DB_ITEM_CLASS(g_db_comment_parent_class)->unpack(G_DB_ITEM(comment), pbuf); @@ -492,29 +584,25 @@ static bool g_db_comment_unpack(GDbComment *comment, packed_buffer *pbuf) if (result) { - result = extract_packed_buffer(pbuf, &tmp32, sizeof(uint32_t), true); - comment->flags = tmp32; + result = extract_packed_buffer(pbuf, &tmp8, sizeof(uint8_t), true); + comment->type = tmp8; } if (result) { - result = unpack_rle_string(&string, pbuf); - - if (!is_rle_string_empty(&string) > 0) - g_db_comment_add_rle_string(comment, &string); - + result = extract_packed_buffer(pbuf, &tmp32, sizeof(uint32_t), true); + comment->flags = tmp32; } if (result) { - result = extract_packed_buffer(pbuf, &tmp8, sizeof(uint8_t), true); - comment->inlined = tmp8; - } + setup_empty_rle_string(&text); + result = unpack_rle_string(&text, pbuf); + + g_db_comment_define_text_lines(comment, get_rle_string(&text)); + + exit_rle_string(&text); - if (result) - { - result = extract_packed_buffer(pbuf, &tmp8, sizeof(uint8_t), true); - comment->repeatable = tmp8; } return result; @@ -546,6 +634,9 @@ static bool g_db_comment_pack(GDbComment *comment, packed_buffer *pbuf) result = pack_vmpa(&comment->addr, pbuf); if (result) + result = extend_packed_buffer(pbuf, (uint8_t []) { comment->type }, sizeof(uint8_t), true); + + if (result) result = extend_packed_buffer(pbuf, (uint32_t []) { comment->flags }, sizeof(uint32_t), true); if (result) @@ -555,12 +646,6 @@ static bool g_db_comment_pack(GDbComment *comment, packed_buffer *pbuf) exit_rle_string(&text); } - if (result) - result = extend_packed_buffer(pbuf, (uint8_t []) { comment->inlined }, sizeof(uint8_t), true); - - if (result) - result = extend_packed_buffer(pbuf, (uint8_t []) { comment->repeatable }, sizeof(uint8_t), true); - return result; } @@ -580,28 +665,40 @@ static bool g_db_comment_pack(GDbComment *comment, packed_buffer *pbuf) static char *g_db_comment_build_label(GDbComment *comment) { -#if 0 - VMPA_BUFFER(loc); /* Indication de position */ - size_t count; /* Nombre d'éléments textuels */ + char *result; /* Description à retourner */ + DbItemFlags flags; /* Propriétés de l'élément */ + const char *text; /* Commentaire associé */ + const char *prefix; /* Préfixe à ajouter */ - vmpa2_to_string(&comment->addr, MDS_UNDEFINED, loc, NULL); + flags = g_db_item_get_flags(G_DB_ITEM(comment)); - lock_flat_array(&comment->text); - count = count_flat_array_items(comment->text); - unlock_flat_array(&comment->text); + if (flags & DIF_ERASER) + asprintf(&result, _("Removed comment")); + + else if (flags & DIF_UPDATED) + { + text = "...";//get_rle_string(&comment->text); - if (count == 0) - asprintf(&G_DB_ITEM(comment)->label, _("Delete comment at %s"), loc); + if (text != NULL) + asprintf(&result, _("Updated comment: \"%s\""), text); + else + asprintf(&result, _("Reset comment")); + } else { - if (comment->inlined) - asprintf(&G_DB_ITEM(comment)->label, _("Enter inlined comment at %s"), loc); + prefix = _("Created"); + + text = "...";//get_rle_string(&comment->text); + + if (text != NULL) + asprintf(&result, _("%s comment \"%s\""), prefix, text); else - asprintf(&G_DB_ITEM(comment)->label, _("Enter comment area at %s"), loc); + asprintf(&result, _("%s empty comment"), prefix); + } -#endif - return NULL; + + return result; } @@ -638,46 +735,30 @@ static bool g_db_comment_run(GDbComment *comment, GLoadedBinary *binary, bool ap cache = g_loaded_binary_get_disassembly_cache(binary); - cursor = g_binary_cursor_new(); - g_binary_cursor_update(G_BINARY_CURSOR(cursor), &comment->addr); + g_buffer_cache_lock(cache); - index = g_buffer_cache_find_index_by_cursor(cache, cursor, true); + switch (comment->type) + { + case CET_INLINED: - g_object_unref(G_OBJECT(cursor)); + cursor = g_binary_cursor_new(); + g_binary_cursor_update(G_BINARY_CURSOR(cursor), &comment->addr); - index = g_buffer_cache_look_for_flag(cache, index, BLF_HAS_CODE); + index = g_buffer_cache_find_index_by_cursor(cache, cursor, true); - if (comment->inlined) - { + g_object_unref(G_OBJECT(cursor)); -#define RUN_INLINED_COMMENT(idx, new, old) \ - if (apply) \ - { \ - old = g_buffer_cache_delete_type_at(cache, idx, G_TYPE_DB_COMMENT, false, false); \ - \ - g_buffer_cache_insert_at(cache, idx, G_LINE_GENERATOR(new), BLF_NONE, false, false); \ - \ - } \ - else \ - { \ - g_buffer_cache_delete_type_at(cache, idx, G_TYPE_DB_COMMENT, false, false); \ - \ - if (old != NULL) \ - { \ - g_buffer_cache_insert_at(cache, idx, old, BLF_NONE, false, false); \ - g_object_unref(G_OBJECT(old)); \ - } \ - \ - } + index = g_buffer_cache_look_for_flag(cache, index, BLF_HAS_CODE); - /* Commentaire principal */ + g_buffer_cache_delete_type_at(cache, index, G_TYPE_DB_COMMENT, false, false); - RUN_INLINED_COMMENT(index, comment, comment->previous); + if (apply) + g_buffer_cache_insert_at(cache, index, G_LINE_GENERATOR(comment), BLF_NONE, false, false); - /* Renvois répétés */ + break; + + case CET_REPEATED: - if (comment->repeatable) - { proc = g_loaded_binary_get_processor(binary); instr = g_arch_processor_find_instr_by_address(proc, &comment->addr); @@ -685,12 +766,6 @@ static bool g_db_comment_run(GDbComment *comment, GLoadedBinary *binary, bool ap scount = g_arch_instruction_count_sources(instr); - if (apply) - { - comment->old_count = scount; - comment->old_inlined = realloc(comment->old_inlined, comment->old_count * sizeof(GLineGenerator *)); - } - for (i = 0; i < scount && result; i++) { source = g_arch_instruction_get_source(instr, i); @@ -713,202 +788,37 @@ static bool g_db_comment_run(GDbComment *comment, GLoadedBinary *binary, bool ap linked = g_buffer_cache_look_for_flag(cache, linked, BLF_HAS_CODE | BLF_IS_LABEL); - RUN_INLINED_COMMENT(linked, comment, comment->old_inlined[i]); - - unref_instr_link(source); - - } + g_buffer_cache_delete_type_at(cache, linked, G_TYPE_DB_COMMENT, false, false); - if (!apply) - { - free(comment->old_inlined); + if (apply) + g_buffer_cache_insert_at(cache, linked, G_LINE_GENERATOR(comment), BLF_NONE, false, false); - comment->old_inlined = NULL; - comment->old_count = 0; + unref_instr_link(source); } g_object_unref(G_OBJECT(proc)); + break; - } - - - - } - - else - { - - - - - - + case CET_BEFORE: + break; + case CET_AFTER: + break; + case CET_COUNT: + assert(false); + result = false; + break; } - - //void g_buffer_cache_insert_at(GBufferCache *cache, size_t index, GLineGenerator *generator, bool before, bool after) - - //GLineGenerator *g_buffer_cache_delete_type_at(GBufferCache *cache, size_t index, GType type, bool before, bool after) - - - + g_buffer_cache_unlock(cache); g_object_unref(G_OBJECT(cache)); return result; - - - -#if 0 - - bool result; /* Bilan à faire remonter */ - GCodeBuffer *buffer; /* Tampon de lignes à traiter */ - GBufferLine *line; /* Ligne de tampon à marquer */ - GArchProcessor *proc; /* Propriétaire d'instructions */ - GArchInstruction *instr; /* Instruction à traiter */ - instr_link_t *sources; /* Instructions diverses liées */ - size_t scount; /* Nbre de sources affichées */ - size_t i; /* Boucle de parcours */ - const mrange_t *range; /* Emplacement d'instruction */ - GBufferLine *linked; /* Ligne liée à traiter */ - GDbComment *old; /* Ancien élément à restaurer */ - - result = true; - - /* Recherche de la ligne visée */ - - buffer = g_loaded_binary_get_disassembled_buffer(binary); - - line = g_code_buffer_find_line_by_addr(buffer, &comment->addr, comment->flags, NULL); - if (line == NULL) - { - result = false; - goto exit_gui; - } - - /* Détermination de l'imprimeur précédent */ - - if (apply) - { - assert(comment->old_count == 0); - - comment->old_count = 1; - comment->oldies = calloc(comment->old_count, sizeof(GDbComment *)); - - } - - /* Applications globales finales */ - -#define g_code_buffer_update_inlined_comment_dummy(b, l, c, d, o) \ - g_code_buffer_update_inlined_comment(b, l, c, o) - - /** - * Note : on part du principe qu'un commentaire intégré ne peut remplacer qu'un - * commentaire intégré. Et pareil pour les commentaires en blocs. - */ - -#define RUN_COMMENT_ON(ln, idx, func) \ - if (apply) \ - { \ - comment->oldies[idx] = (GDbComment *)g_code_buffer_get_comment_creator(buffer, ln); \ - assert(comment->oldies[idx] == NULL || G_IS_DB_COMMENT(comment->oldies[idx])); \ - assert(comment->oldies[idx] == NULL || comment->oldies[idx]->inlined == comment->inlined); \ - \ - if (is_rle_string_empty(&comment->text)) \ - result = g_code_buffer_delete_lines_comment(buffer, ln); \ - else \ - result = func(buffer, ln, get_rle_string(&comment->text), \ - comment->before, G_OBJECT(comment)); \ - } \ - else \ - { \ - old = comment->oldies[idx]; \ - \ - if (old == NULL) \ - { \ - if (!is_rle_string_empty(&comment->text)) \ - result = g_code_buffer_delete_lines_comment(buffer, ln); \ - else \ - result = true; \ - } \ - else \ - { \ - if (is_rle_string_empty(&old->text)) \ - result = g_code_buffer_delete_lines_comment(buffer, ln); \ - else \ - result = func(buffer, ln, get_rle_string(&old->text), \ - old->before, G_OBJECT(old)); \ - } \ - \ - } - - if (comment->inlined) - { - /* Traitement d'un commentaire inscrusté */ - - RUN_COMMENT_ON(line, 0, g_code_buffer_update_inlined_comment_dummy); - - /* Traitement des répétitions ? */ - - if (comment->repeatable/* && result*/) - { - proc = g_loaded_binary_get_processor(binary); - - range = g_buffer_line_get_range(line); - - instr = g_arch_processor_find_instr_by_address(proc, get_mrange_addr(range)); - assert(instr != NULL); - - scount = g_arch_instruction_get_sources(instr, &sources); - - if (apply) - { - comment->old_count += scount; - comment->oldies = realloc(comment->oldies, comment->old_count * sizeof(GDbComment *)); - } - - for (i = 0; i < scount && result; i++) - { - range = g_arch_instruction_get_range(sources[i].linked); - - /** - * On recherche ici une ligne potentiellement BLF_HAS_CODE ou BLF_IS_LABEL. - * Comme on ne peut pas traiter les deux cas, on prend la première qui vient - * avec BLF_NONE. - */ - linked = g_code_buffer_find_line_by_addr(buffer, get_mrange_addr(range), BLF_NONE, NULL); - assert(linked != NULL); - - RUN_COMMENT_ON(linked, 1 + i, g_code_buffer_update_inlined_comment_dummy); - - } - - g_object_unref(G_OBJECT(instr)); - - g_object_unref(G_OBJECT(proc)); - - } - - } - - else - { - RUN_COMMENT_ON(line, 0, g_code_buffer_update_comment_area); - } - - g_object_unref(G_OBJECT(line)); - - exit_gui: - - /* TODO g_object_unref(G_OBJECT(buffer));*/ - - return result; -#endif } @@ -982,40 +892,38 @@ static bool g_db_comment_load(GDbComment *comment, const bound_value *values, si result = G_DB_ITEM_CLASS(g_db_comment_parent_class)->load(G_DB_ITEM(comment), values, count); - result &= load_vmpa(&comment->addr, NULL, values, count); + if (result) + result = load_vmpa(&comment->addr, NULL, values, count); if (result) { - value = find_bound_value(values, count, "lflags"); + value = find_bound_value(values, count, "type"); result = (value != NULL && value->type == SQLITE_INTEGER); if (result) - comment->flags = value->integer; + comment->type = value->integer; } - result &= load_rle_string(&string, "text", values, count); - - if (result) - g_db_comment_add_rle_string(comment, &string); - if (result) { - value = find_bound_value(values, count, "inlined"); - result = (value != NULL && value->type == SQLITE_BOOLEAN); + value = find_bound_value(values, count, "line_flags"); + result = (value != NULL && value->type == SQLITE_INTEGER); if (result) - comment->inlined = value->boolean; + comment->flags = value->integer; } if (result) { - value = find_bound_value(values, count, "repeatable"); - result = (value != NULL && value->type == SQLITE_BOOLEAN); + result = load_rle_string(&string, "text", values, count); if (result) - comment->repeatable = value->boolean; + { + g_db_comment_define_text_lines(comment, get_rle_string(&string)); + exit_rle_string(&string); + } } @@ -1063,7 +971,7 @@ static bool g_db_comment_store(GDbComment *comment, bound_value **values, size_t value = &(*values)[*count - 1]; - value->cname = "lflags"; + value->cname = "type"; value->built_name = false; value->type = SQLITE_INTEGER; @@ -1071,50 +979,39 @@ static bool g_db_comment_store(GDbComment *comment, bound_value **values, size_t if (value->has_value) { - value->integer = comment->flags; + value->integer = comment->type; value->delete = NULL; } - if (value->has_value) - { - init_dynamic_rle_string(&text, g_db_comment_get_text(comment)); - status = store_rle_string(&text, "text", values, count); - exit_rle_string(&text); - } - - if (!status) return false; - - *count += 2; + *count += 1; *values = realloc(*values, *count * sizeof(bound_value)); - value = &(*values)[*count - 2]; + value = &(*values)[*count - 1]; - value->cname = "inlined"; + value->cname = "line_flags"; value->built_name = false; - value->type = SQLITE_BOOLEAN; + value->type = SQLITE_INTEGER; value->has_value = (comment != NULL); if (value->has_value) { - value->boolean = comment->inlined; + value->integer = comment->flags; value->delete = NULL; } - value = &(*values)[*count - 1]; - - value->cname = "repeatable"; - value->built_name = false; - value->type = SQLITE_BOOLEAN; - - value->has_value = (comment != NULL); + if (comment == NULL) + status = store_rle_string(NULL, "text", values, count); - if (value->has_value) + else { - value->boolean = comment->repeatable; - value->delete = NULL; + init_dynamic_rle_string(&text, g_db_comment_get_text(comment)); + status = store_rle_string(&text, "text", values, count); + exit_rle_string(&text); } + if (!status) return false; + return true; } @@ -1122,19 +1019,27 @@ static bool g_db_comment_store(GDbComment *comment, bound_value **values, size_t /****************************************************************************** * * -* Paramètres : comment = informations à consulter. * +* Paramètres : key = clef de comparaison sous forme de localisation. * +* comment = informations de commentaire à consulter. * * * -* Description : Fournit l'adresse associée à un commentaire. * +* Description : Etablit la comparaison d'une adresse avec un commentaire. * * * -* Retour : Adresse mémoire. * +* Retour : Bilan de la comparaison. * * * * Remarques : - * * * ******************************************************************************/ -const vmpa2t *g_db_comment_get_address(const GDbComment *comment) +int compare_comment_by_addr(const vmpa2t *key, const GDbComment * const *comment) { - return &comment->addr; + int result; /* Bilan à retourner */ + const vmpa2t *addr; /* Position du commentaire */ + + addr = g_db_comment_get_address(*comment); + + result = cmp_vmpa(key, addr); + + return result; } @@ -1143,38 +1048,19 @@ const vmpa2t *g_db_comment_get_address(const GDbComment *comment) * * * Paramètres : comment = informations à consulter. * * * -* Description : Fournit le commentaire associé à un commentaire. * +* Description : Fournit l'adresse associée à un commentaire. * * * -* Retour : Commentaire existant à libérer après usage ou NULL. * +* Retour : Adresse mémoire. * * * * Remarques : - * * * ******************************************************************************/ -char *g_db_comment_get_text(GDbComment *comment) +const vmpa2t *g_db_comment_get_address(const GDbComment *comment) { - char *result; /* Chaîne constituée à renvoyer*/ - size_t count; /* Nombre d'éléments textuels */ - size_t i; /* Boucle de parcours */ - rle_string *string; /* Chaîne à consulter */ + const vmpa2t *result; /* Localisation à retourner */ - result = NULL; - - lock_flat_array(&comment->text); - - count = count_flat_array_items(comment->text); - - for (i = 0; i < count; i++) - { - string = get_flat_array_item(comment->text, i, sizeof(rle_string)); - - assert(!is_rle_string_empty(string)); - - result = stradd(result, get_rle_string(string)); - - } - - unlock_flat_array(&comment->text); + result = &comment->addr; return result; @@ -1184,30 +1070,22 @@ char *g_db_comment_get_text(GDbComment *comment) /****************************************************************************** * * * Paramètres : comment = informations à consulter. * -* text = commentaire construit ou NULL. * * * -* Description : Associe un contenu supplémentaire à un commentaire. * +* Description : Indique le type d'incrustation prévue pour un commentaire. * * * -* Retour : - * +* Retour : Incrustation associée au commentaire. * * * * Remarques : - * * * ******************************************************************************/ -void g_db_comment_add_dynamic_text(GDbComment *comment, char *text) +CommentEmbeddingType g_db_comment_get_embedding_type(const GDbComment *comment) { - rle_string string; /* Fragment de texte à ajouter */ - - if (text != NULL) - { - init_dynamic_rle_string(&string, text); + CommentEmbeddingType result; /* Type à renvoyer */ - g_db_comment_add_rle_string(comment, &string); + result = comment->type; - } - - else - g_db_comment_update_count_lines(comment); + return result; } @@ -1215,30 +1093,22 @@ void g_db_comment_add_dynamic_text(GDbComment *comment, char *text) /****************************************************************************** * * * Paramètres : comment = informations à consulter. * -* text = commentaire construit ou NULL. * * * -* Description : Associe un contenu statique supplémentaire à un commentaire. * +* Description : Fournit les particularités d'accroche liées à un commentaire.* * * -* Retour : - * +* Retour : Particularités éventuelles pour l'accroche. * * * * Remarques : - * * * ******************************************************************************/ -void g_db_comment_add_static_text(GDbComment *comment, const char *text) +BufferLineFlags g_db_comment_get_flags(const GDbComment *comment) { - rle_string string; /* Fragment de texte à ajouter */ + BufferLineFlags result; /* Type à renvoyer */ - if (text != NULL) - { - init_static_rle_string(&string, text); + result = comment->flags; - g_db_comment_add_rle_string(comment, &string); - - } - - else - g_db_comment_update_count_lines(comment); + return result; } @@ -1246,29 +1116,41 @@ void g_db_comment_add_static_text(GDbComment *comment, const char *text) /****************************************************************************** * * * Paramètres : comment = informations à consulter. * -* string = commentaire établi à inétgrer. * * * -* Description : Associe un contenu formaté supplémentaire à un commentaire. * +* Description : Fournit le commentaire associé à un commentaire. * * * -* Retour : - * +* Retour : Commentaire existant à libérer après usage ou NULL. * * * * Remarques : - * * * ******************************************************************************/ -static void g_db_comment_add_rle_string(GDbComment *comment, const rle_string *string) +char *g_db_comment_get_text(GDbComment *comment) { - /* Extension du contenu */ + char *result; /* Chaîne constituée à renvoyer*/ + size_t count; /* Nombre d'éléments textuels */ + size_t i; /* Boucle de parcours */ + rle_string *string; /* Chaîne à consulter */ + + result = NULL; lock_flat_array(&comment->text); - add_item_to_flat_array(&comment->text, string, sizeof(rle_string)); + count = count_flat_array_items(comment->text); - unlock_flat_array(&comment->text); + for (i = 0; i < count; i++) + { + string = get_flat_array_item(comment->text, i, sizeof(rle_string)); - /* Mise à jour de la taille de rendu */ + assert(!is_rle_string_empty(string)); - g_db_comment_update_count_lines(comment); + result = stradd(result, get_rle_string(string)); + + } + + unlock_flat_array(&comment->text); + + return result; } @@ -1281,64 +1163,27 @@ static void g_db_comment_add_rle_string(GDbComment *comment, const rle_string *s /****************************************************************************** * * -* Paramètres : comment = informations à réactualiser. * +* Paramètres : comment = générateur à consulter. * * * -* Description : Calcule le nombre de lignes suite à un changement de contenu.* +* 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 g_db_comment_update_count_lines(GDbComment *comment) +static size_t g_db_comment_count_lines(GDbComment *comment) { - char *full; /* Contenu textuel complet */ - char **lines; /* Lignes brutes à représenter */ - GCodingLanguage *lang; /* Langage de sortie préféré */ - size_t i; /* Boucle de parcours */ + size_t result; /* Quantité à retourner */ - full = g_db_comment_get_text(comment); - - if (full == NULL) - comment->count = 0; - - else - { - lines = strtoka(full, "\n", &comment->count); - - lang = g_asm_language_new(); - g_coding_language_encapsulate_comments(lang, &lines, &comment->count); - g_object_unref(G_OBJECT(lang)); - - for (i = 0; i < comment->count; i++) - free(lines[i]); - - if (lines != NULL) - free(lines); - - free(full); - - } - -} + lock_flat_array(&comment->text); + result = count_flat_array_items(comment->text); -/****************************************************************************** -* * -* Paramètres : comment = générateur à consulter. * -* * -* Description : Indique le nombre de ligne prêtes à être générées. * -* * -* Retour : Nombre de lignes devant apparaître au final. * -* * -* Remarques : - * -* * -******************************************************************************/ + unlock_flat_array(&comment->text); -static size_t g_db_comment_count_lines(const GDbComment *comment) -{ - return comment->count; + return result; } @@ -1413,7 +1258,7 @@ static int g_db_comment_contain_cursor(const GDbComment *comment, size_t index, * * ******************************************************************************/ -static BufferLineFlags g_db_comment_get_flags(const GDbComment *comment, size_t index, size_t repeat) +static BufferLineFlags g_db_comment_get_generator_flags(const GDbComment *comment, size_t index, size_t repeat) { return BLF_NONE; @@ -1454,11 +1299,6 @@ static void g_db_comment_print(GDbComment *comment, GBufferLine *line, size_t in g_coding_language_encapsulate_comments(lang, &lines, &count); g_object_unref(G_OBJECT(lang)); - if (count != comment->count) - printf("full=%s\n", full); - - assert(count == comment->count); - g_buffer_line_append_text(line, DLC_COMMENTS, SL(lines[repeat]), RTT_COMMENT, NULL); for (i = 0; i < count; i++) @@ -1616,13 +1456,12 @@ static bool g_comment_collection_create_db_table(const GCommentCollection *colle char *msg; /* Message d'erreur */ int ret; /* Bilan de la création */ - sql = "CREATE TABLE Comments (" \ - SQLITE_DB_ITEM_CREATE ", " \ - "%s, " \ - "lflags INTEGER, " \ - SQLITE_RLESTR_CREATE("text") ", " \ - "inlined INTEGER, " \ - "repeatable INTEGER" \ + sql = "CREATE TABLE Comments (" \ + SQLITE_DB_ITEM_CREATE ", " \ + "%s, " \ + "type INTEGER, " \ + "line_flags INTEGER, " \ + SQLITE_RLESTR_CREATE("text") \ ");"; addr_fields = create_vmpa_db_table(NULL); diff --git a/src/analysis/db/items/comment.h b/src/analysis/db/items/comment.h index 7049b28..fa1644f 100644 --- a/src/analysis/db/items/comment.h +++ b/src/analysis/db/items/comment.h @@ -37,12 +37,25 @@ /* --------------------- ELABORATION D'UN ELEMENT DE COLLECTION --------------------- */ -#define G_TYPE_DB_COMMENT g_db_comment_get_type() -#define G_DB_COMMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_db_comment_get_type(), GDbComment)) -#define G_IS_DB_COMMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_db_comment_get_type())) -#define G_DB_COMMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DB_COMMENT, GDbCommentClass)) -#define G_IS_DB_COMMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DB_COMMENT)) -#define G_DB_COMMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DB_COMMENT, GDbCommentClass)) +/* Incrustations possibles pour un commentaire */ +typedef enum _CommentEmbeddingType +{ + CET_INLINED, /* En bout de ligne */ + CET_REPEATED, /* Reproduit à chaque référence*/ + CET_BEFORE, /* Placé sur une ligne avant */ + CET_AFTER, /* Placé sur une ligne après */ + + CET_COUNT + +} CommentEmbeddingType; + + +#define G_TYPE_DB_COMMENT g_db_comment_get_type() +#define G_DB_COMMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_DB_COMMENT, GDbComment)) +#define G_IS_DB_COMMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_DB_COMMENT)) +#define G_DB_COMMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DB_COMMENT, GDbCommentClass)) +#define G_IS_DB_COMMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DB_COMMENT)) +#define G_DB_COMMENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DB_COMMENT, GDbCommentClass)) /* Commentaire à placer dans du texte quelconque (instance) */ @@ -55,35 +68,38 @@ typedef struct _GDbCommentClass GDbCommentClass; /* Indique le type défini pour un commentaire à l'intérieur d'une zone de texte. */ GType g_db_comment_get_type(void); -/* Crée une définition de commentaire dans une zone de texte. */ -GDbComment *g_db_comment_new_inlined(const vmpa2t *, BufferLineFlags, bool); +/* Crée une définition de commentaire textuel. */ +GDbComment *g_db_comment_new(const vmpa2t *, CommentEmbeddingType, BufferLineFlags, const char *); + +/* Initialise la définition d'un commentaire à incruster. */ +bool g_db_comment_fill(GDbComment *, const vmpa2t *, CommentEmbeddingType, BufferLineFlags, const char *); -/* Crée une définition de commentaire dans une zone de texte. */ -GDbComment *g_db_comment_new_area(const vmpa2t *, BufferLineFlags, const char *, bool); +/* Etablit la comparaison d'une adresse avec un commentaire. */ +int compare_comment_by_addr(const vmpa2t *, const GDbComment * const *); /* Fournit l'adresse associée à un commentaire. */ const vmpa2t *g_db_comment_get_address(const GDbComment *); -/* Fournit le commentaire associé à un commentaire. */ -char *g_db_comment_get_text(GDbComment *); +/* Indique le type d'incrustation prévue pour un commentaire. */ +CommentEmbeddingType g_db_comment_get_embedding_type(const GDbComment *); -/* Associe un contenu supplémentaire à un commentaire. */ -void g_db_comment_add_dynamic_text(GDbComment *, char *); +/* Fournit les particularités d'accroche liées à un commentaire. */ +BufferLineFlags g_db_comment_get_flags(const GDbComment *); -/* Associe un contenu statique supplémentaire à un commentaire. */ -void g_db_comment_add_static_text(GDbComment *, const char *); +/* Fournit le commentaire associé à un commentaire. */ +char *g_db_comment_get_text(GDbComment *); /* ---------------------- DEFINITION DE LA COLLECTION ASSOCIEE ---------------------- */ -#define G_TYPE_COMMENT_COLLECTION g_comment_collection_get_type() -#define G_COMMENT_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_comment_collection_get_type(), GCommentCollection)) -#define G_IS_COMMENT_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_comment_collection_get_type())) -#define G_COMMENT_COLLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_COMMENT_COLLECTION, GCommentCollectionClass)) -#define G_IS_COMMENT_COLLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_COMMENT_COLLECTION)) -#define G_COMMENT_COLLECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_COMMENT_COLLECTION, GCommentCollectionClass)) +#define G_TYPE_COMMENT_COLLECTION g_comment_collection_get_type() +#define G_COMMENT_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_COMMENT_COLLECTION, GCommentCollection)) +#define G_IS_COMMENT_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_COMMENT_COLLECTION)) +#define G_COMMENT_COLLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_COMMENT_COLLECTION, GCommentCollectionClass)) +#define G_IS_COMMENT_COLLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_COMMENT_COLLECTION)) +#define G_COMMENT_COLLECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_COMMENT_COLLECTION, GCommentCollectionClass)) /* Collection dédiée aux commentaires textuels (instance) */ diff --git a/src/core/collections.c b/src/core/collections.c index f5bccd7..660c981 100644 --- a/src/core/collections.c +++ b/src/core/collections.c @@ -114,7 +114,7 @@ bool load_hard_coded_collection_definitions(void) REGISTER_COLLECTION(G_TYPE_BM_COLLECTION, DBF_BOOKMARKS); - //REGISTER_COLLECTION(G_TYPE_COMMENT_COLLECTION, DBF_COMMENTS); + REGISTER_COLLECTION(G_TYPE_COMMENT_COLLECTION, DBF_COMMENTS); //REGISTER_COLLECTION(G_TYPE_MOVE_COLLECTION, DBF_MOVES); diff --git a/src/format/preload.c b/src/format/preload.c index dc254b2..c36db93 100644 --- a/src/format/preload.c +++ b/src/format/preload.c @@ -24,6 +24,9 @@ #include "preload.h" +#include + + #include "preload-int.h" @@ -629,7 +632,7 @@ void _g_preload_info_add_comment(GPreloadInfo *info, GDbComment *comment) * * * Description : Recherche un commentaire dans des préchargements. * * * -* Retour : Eventuel commenaire retrouvé ou NULL. * +* Retour : Eventuel commentaire retrouvé ou NULL. * * * * Remarques : - * * * @@ -640,23 +643,52 @@ GDbComment *_g_preload_info_find_comment_at(GPreloadInfo *info, const vmpa2t *ad GDbComment *result; /* Trouvaille à retourner */ GDbComment **ptr; /* Adresse dans le tableau */ - int cmp_comment_by_addr(const vmpa2t *key, const GDbComment * const *comment) + ptr = find_item_in_flat_array(info->comments, sizeof(GDbComment *), + (__compar_fn_t)compare_comment_by_addr, addr); + + if (ptr != NULL) { - const vmpa2t *caddr; /* Position du commentaire */ + result = *ptr; + g_object_ref(G_OBJECT(result)); + } + else + result = NULL; - caddr = g_db_comment_get_address(*comment); + return result; - return cmp_vmpa(key, caddr); +} - } + +/****************************************************************************** +* * +* Paramètres : info = instance à mettre à consulter. * +* addr = localisation du commentaire recherché. * +* index = indice du commentaire retrouvé ou NULL. [OUT] * +* * +* Description : Recherche un commentaire dans des préchargements. * +* * +* Retour : Eventuel commentaire retrouvé ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GDbComment *g_preload_info_find_comment_at(GPreloadInfo *info, const vmpa2t *addr, size_t *index) +{ + GDbComment *result; /* Trouvaille à retourner */ + GDbComment **ptr; /* Adresse dans le tableau */ ptr = find_item_in_flat_array(info->comments, sizeof(GDbComment *), - (__compar_fn_t)cmp_comment_by_addr, addr); + (__compar_fn_t)compare_comment_by_addr, addr); if (ptr != NULL) { result = *ptr; g_object_ref(G_OBJECT(result)); + + if (index != NULL) + *index = ((void **)ptr - info->comments); + } else result = NULL; @@ -668,6 +700,37 @@ GDbComment *_g_preload_info_find_comment_at(GPreloadInfo *info, const vmpa2t *ad /****************************************************************************** * * +* Paramètres : info = instance à mettre à jour. * +* index = indice du commentaire à remplacer. * +* comment = commentaire à venir associer. * +* * +* Description : Remplace un commentaire par un autre à un emplacement donné. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_preload_info_replace_comment_at(GPreloadInfo *info, size_t index, GDbComment *comment) +{ +#ifndef NDEBUG + GDbComment **current; /* Commentaire à remplacer */ +#endif + +#ifndef NDEBUG + current = get_flat_array_item(info->comments, index, sizeof(GDbComment *)); + + assert(cmp_vmpa(g_db_comment_get_address(*current), g_db_comment_get_address(comment))); +#endif + + rpl_item_in_flat_array(info->comments, index, &comment, sizeof(GDbComment *)); + +} + + +/****************************************************************************** +* * * Paramètres : info = instance à consulter. * * * * Description : Indique la quantité de commentaires préchargés disponibles. * diff --git a/src/format/preload.h b/src/format/preload.h index 5557253..587c35d 100644 --- a/src/format/preload.h +++ b/src/format/preload.h @@ -102,6 +102,12 @@ void _g_preload_info_add_comment(GPreloadInfo *, GDbComment *); /* Recherche un commentaire dans des préchargements. */ GDbComment *_g_preload_info_find_comment_at(GPreloadInfo *, const vmpa2t *); +/* Recherche un commentaire dans des préchargements. */ +GDbComment *g_preload_info_find_comment_at(GPreloadInfo *, const vmpa2t *, size_t *); + +/* Remplace un commentaire par un autre à un emplacement donné. */ +void g_preload_info_replace_comment_at(GPreloadInfo *, size_t, GDbComment *); + /* Indique la quantité de commentaires préchargés disponibles. */ size_t _g_preload_info_count_comments(const GPreloadInfo *); -- cgit v0.11.2-87-g4458