From 21537636cd8318cf5a720211619ad3c3023b52e9 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Wed, 22 Jul 2015 21:23:49 +0000 Subject: Fortified the client/server protocol and first exchanges. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@554 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 44 +++ src/analysis/binary.c | 6 +- src/analysis/db/cdb.c | 76 +++- src/analysis/db/client.c | 20 +- src/analysis/db/client.h | 2 +- src/analysis/db/collection-int.h | 4 + src/analysis/db/collection.c | 77 +++- src/analysis/db/collection.h | 4 +- src/analysis/db/item-int.h | 24 +- src/analysis/db/item.c | 151 ++++++-- src/analysis/db/item.h | 12 +- src/analysis/db/items/Makefile.am | 3 +- src/analysis/db/items/bookmark.c | 175 +++------ src/analysis/db/items/bookmark.h | 7 - src/analysis/db/items/comment.c | 400 +++++++++++++++++--- src/analysis/db/items/comment.h | 38 +- src/analysis/db/items/switcher.c | 755 ++++++++++++++++++++++++++++++++++++++ src/analysis/db/items/switcher.h | 121 ++++++ src/analysis/db/misc/rlestr.c | 166 ++++----- src/analysis/db/misc/rlestr.h | 27 +- src/analysis/db/protocol.h | 8 +- src/analysis/db/server.c | 141 ++++--- src/arch/vmpa.c | 11 +- src/arch/vmpa.h | 4 +- src/common/sqlite.h | 1 + src/core/collections.c | 38 +- src/core/collections.h | 7 +- src/dialogs/storage.c | 2 +- src/gui/menus/edition.c | 108 +++++- 29 files changed, 1987 insertions(+), 445 deletions(-) create mode 100644 src/analysis/db/items/switcher.c create mode 100644 src/analysis/db/items/switcher.h diff --git a/ChangeLog b/ChangeLog index e50be99..a2706b0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,47 @@ +15-07-22 Cyrille Bagard + + * src/analysis/binary.c: + Update code. + + * src/analysis/db/cdb.c: + * src/analysis/db/client.c: + * src/analysis/db/client.h: + * src/analysis/db/collection.c: + * src/analysis/db/collection.h: + * src/analysis/db/collection-int.h: + * src/analysis/db/item.c: + * src/analysis/db/item.h: + * src/analysis/db/item-int.h: + * src/analysis/db/items/bookmark.c: + * src/analysis/db/items/bookmark.h: + * src/analysis/db/items/comment.c: + * src/analysis/db/items/comment.h: + Fortify the client/server protocol and first exchanges. + + * src/analysis/db/items/Makefile.am: + Add the 'switcher.[ch]' files into libanalysisdbitems_la_SOURCES. + + * src/analysis/db/items/switcher.c: + * src/analysis/db/items/switcher.h: + New entries: prepare the next features. + + * src/analysis/db/misc/rlestr.c: + * src/analysis/db/misc/rlestr.h: + * src/analysis/db/protocol.h: + * src/analysis/db/server.c: + * src/arch/vmpa.c: + * src/arch/vmpa.h: + * src/common/sqlite.h: + Fortify the client/server protocol and first exchanges. + + * src/core/collections.c: + * src/core/collections.h: + * src/dialogs/storage.c: + Update code. + + * src/gui/menus/edition.c: + Prepare the next features. + 15-07-18 Cyrille Bagard * plugins/pychrysa/pychrysa.c: diff --git a/src/analysis/binary.c b/src/analysis/binary.c index d7682cd..ade1131 100644 --- a/src/analysis/binary.c +++ b/src/analysis/binary.c @@ -157,7 +157,7 @@ static void g_loaded_binary_init(GLoadedBinary *binary) binary->use_remote_server = false; binary->storages[DBF_COMMENTS] = DBS_ALL_LOCAL; - binary->storages[DBF_SEGMENTS_DISPLAY] = DBS_ALL_LOCAL; + binary->storages[DBF_DISPLAY_SWITCHERS] = DBS_ALL_LOCAL; binary->storages[DBF_BOOKMARKS] = DBS_ALL_LOCAL; binary->collections = create_collections_list(); @@ -412,7 +412,7 @@ static bool g_loaded_binary_load_storage(GLoadedBinary *binary, xmlXPathContextP case DBF_COMMENTS: access = stradd(access, "Comments"); break; - case DBF_SEGMENTS_DISPLAY: + case DBF_DISPLAY_SWITCHERS: access = stradd(access, "Segments"); break; case DBF_BOOKMARKS: @@ -507,7 +507,7 @@ static bool g_loaded_binary_save_storage(const GLoadedBinary *binary, xmlDocPtr case DBF_COMMENTS: access = stradd(access, "Comments"); break; - case DBF_SEGMENTS_DISPLAY: + case DBF_DISPLAY_SWITCHERS: access = stradd(access, "Segments"); break; case DBF_BOOKMARKS: diff --git a/src/analysis/db/cdb.c b/src/analysis/db/cdb.c index 46cfc23..96e69d5 100644 --- a/src/analysis/db/cdb.c +++ b/src/analysis/db/cdb.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,6 @@ #include "collection.h" #include "protocol.h" -#include "items/bookmark.h" #include "../../common/cpp.h" #include "../../common/extstr.h" #include "../../common/io.h" @@ -127,11 +127,14 @@ static bool g_cdb_archive_read(GCdbArchive *); +/* -------------------------- MANIPULATION DES PARTIES XML -------------------------- */ /* Crée la description XML correspondant à l'archive. */ static bool g_cdb_archive_create_xml_desc(GCdbArchive *, const rle_string *); +/* Vérifie la conformité d'une description XML avec le serveur. */ +static bool g_cdb_archive_check_xml_version(const GCdbArchive *); @@ -201,6 +204,8 @@ static void g_cdb_archive_class_init(GCdbArchiveClass *klass) static void g_cdb_archive_init(GCdbArchive *archive) { + archive->collections = create_collections_list(); + g_mutex_init(&archive->clients_access); g_mutex_init(&archive->id_access); @@ -330,7 +335,9 @@ GCdbArchive *g_cdb_archive_new(const char *owner, const rle_string *hash, const g_cdb_archive_create_xml_desc(result, user); g_cdb_archive_create_db(result, NULL); - if (g_cdb_archive_write(result) != DBE_NONE) + *error = g_cdb_archive_write(result); + + if (*error != DBE_NONE) goto gcan_error; } @@ -342,10 +349,19 @@ GCdbArchive *g_cdb_archive_new(const char *owner, const rle_string *hash, const if (!g_cdb_archive_read(result)) goto gcan_error; + if (!g_cdb_archive_check_xml_version(result)) + { + *error = DBE_XML_VERSION_ERROR; + goto gcan_error; + } + /* Chargement des éléments sauvegardés */ if (!g_cdb_archive_load_collections(result)) + { + *error = DBE_DB_LOADING_ERROR; goto gcan_error; + } return result; @@ -586,12 +602,9 @@ int g_cdb_archive_compare_hash(const GCdbArchive *archive, const rle_string *has - -/* --------------------- OPERATIONS DE LECTURE D'UN FICHIER XML --------------------- */ -/* --------------------- OPERATIONS DE LECTURE D'UN FICHIER XML --------------------- */ - - - +/* ---------------------------------------------------------------------------------- */ +/* MANIPULATION DES PARTIES XML */ +/* ---------------------------------------------------------------------------------- */ /****************************************************************************** @@ -639,8 +652,38 @@ static bool g_cdb_archive_create_xml_desc(GCdbArchive *archive, const rle_string } +/****************************************************************************** +* * +* Paramètres : archive = archive à consulter. * +* * +* Description : Vérifie la conformité d'une description XML avec le serveur. * +* * +* Retour : Bilan de la vérification. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_cdb_archive_check_xml_version(const GCdbArchive *archive) +{ + bool result; /* Bilan à retourner */ + char *version; /* Version protocolaire */ + unsigned long int used; /* Version utilisée */ + + result = NULL; + + version = get_node_text_value(archive->context, "/ChrysalideBinary/Protocol"); + if (version == NULL) return false; + + used = strtoul(version, NULL, 16); + result = (used == CDB_PROTOCOL_VERSION); + free(version); + + return result; + +} /* ---------------------------------------------------------------------------------- */ @@ -666,6 +709,8 @@ static bool g_cdb_archive_create_db(const GCdbArchive *archive, const core_db_in bool result; /* Bilan à retourner */ sqlite3 *db; /* Base de données à constituer*/ int ret; /* Bilan de la création */ + GList *iter; /* Boucle de parcours */ + GDbCollection *collec; /* Collection visée manipulée */ ret = sqlite3_open(archive->sql_db, &db); @@ -675,11 +720,16 @@ static bool g_cdb_archive_create_db(const GCdbArchive *archive, const core_db_in return false; } + result = true; - - result = create_bookmark_db_table(db); - - + for (iter = g_list_first(archive->collections); + iter != NULL && result; + iter = g_list_next(iter)) + { + collec = G_DB_COLLECTION(iter->data); + result = g_db_collection_create_db_table(collec, db); + fprintf(stderr, "STATUS :: %d\n", result); + } sqlite3_close(db); @@ -725,8 +775,6 @@ static bool g_cdb_archive_load_collections(GCdbArchive *archive) GList *iter; /* Boucle de parcours */ GDbCollection *collec; /* Collection visée manipulée */ - archive->collections = create_collections_list(); - for (iter = g_list_first(archive->collections); iter != NULL; iter = g_list_next(iter)) diff --git a/src/analysis/db/client.c b/src/analysis/db/client.c index c19a39e..f0d3d4b 100644 --- a/src/analysis/db/client.c +++ b/src/analysis/db/client.c @@ -162,7 +162,7 @@ static void g_db_client_finalize(GDbClient *client) * * ******************************************************************************/ -GDbClient *g_db_client_new(const char *name, const char *hash, GDbCollection *collections) +GDbClient *g_db_client_new(const char *name, const char *hash, GList *collections) { GDbClient *result; /* Adresse à retourner */ @@ -257,7 +257,8 @@ bool g_db_client_start(GDbClient *client, const char *host, unsigned short port, /** * Le serveur doit répondre pour un message type : * - la commande 'DBC_WELCOME'. - * - un identifiant d'erreur ('DBE_NONE' ou 'DBE_WRONG_VERSION'). + * - un identifiant d'erreur ('DBE_NONE', 'DBE_BAD_EXCHANGE' + * ou 'DBE_WRONG_VERSION' ... 'DBE_LOADING_ERROR'). */ if (!safe_recv(client->fd, &data, sizeof(uint32_t), 0)) @@ -286,8 +287,21 @@ bool g_db_client_start(GDbClient *client, const char *host, unsigned short port, goto gdcs_error; break; + case DBE_XML_VERSION_ERROR: + log_variadic_message(LMT_ERROR, _("The archive from the server '%s:%hu' does not use our protocol version (0x%08x)..."), + host, port, CDB_PROTOCOL_VERSION); + goto gdcs_error; + break; + + case DBE_DB_LOADING_ERROR: + log_variadic_message(LMT_ERROR, _("The server '%s:%hu' got into troubles while loading the database...."), + host, port); + goto gdcs_error; + break; + default: - log_variadic_message(LMT_ERROR, _("The server '%s:%hu' uses an unknown protocol..."), host, port); + log_variadic_message(LMT_ERROR, _("The server '%s:%hu' has run into an error (%u)..."), + host, port, error); goto gdcs_error; break; diff --git a/src/analysis/db/client.h b/src/analysis/db/client.h index 66ebb08..6e9f10b 100644 --- a/src/analysis/db/client.h +++ b/src/analysis/db/client.h @@ -51,7 +51,7 @@ typedef struct _GDbClientClass GDbClientClass; GType g_db_client_get_type(void); /* Prépare un client pour une connexion à une BD. */ -GDbClient *g_db_client_new(const char *, const char *, GDbCollection *); +GDbClient *g_db_client_new(const char *, const char *, GList *); /* Démarre la connexion à la base de données. */ bool g_db_client_start(GDbClient *, const char *, unsigned short, const char *); diff --git a/src/analysis/db/collection-int.h b/src/analysis/db/collection-int.h index 6ca9ab4..93e0ef8 100644 --- a/src/analysis/db/collection-int.h +++ b/src/analysis/db/collection-int.h @@ -32,6 +32,9 @@ +/* Crée la table associée à une collection d'éléments. */ +typedef bool (* collec_create_db_table_fc) (const GDbCollection *, sqlite3 *); + /* Décrit les colonnes utiles à un chargement de données. */ typedef bool (* collec_setup_load_fc) (GDbCollection *, bound_value **, size_t *); @@ -63,6 +66,7 @@ struct _GDbCollectionClass { GObjectClass parent; /* A laisser en premier */ + collec_create_db_table_fc create_table; /* Création de la table en SQL */ collec_setup_load_fc setup_load; /* Prépare le chargement */ collec_load_item load_item; /* Charge un élément */ collec_has_key_fc has_key; /* Recherche de présence */ diff --git a/src/analysis/db/collection.c b/src/analysis/db/collection.c index 84acc58..27f4ddb 100644 --- a/src/analysis/db/collection.c +++ b/src/analysis/db/collection.c @@ -31,6 +31,7 @@ #include "collection-int.h" +#include "misc/rlestr.h" #include "../../common/extstr.h" #include "../../common/io.h" #include "../../glibext/chrysamarshal.h" @@ -59,6 +60,9 @@ static void g_db_collection_finalize(GDbCollection *); /* Décrit les colonnes utiles à un chargement de données. */ +static bool _g_db_collection_setup_load(GDbCollection *, bound_value **, size_t *); + +/* Décrit les colonnes utiles à un chargement de données. */ static bool g_db_collection_setup_load(GDbCollection *, bound_value **, size_t *); /* Enregistre un élément de collection dans une base de données. */ @@ -93,6 +97,8 @@ static void g_db_collection_class_init(GDbCollectionClass *klass) object->dispose = (GObjectFinalizeFunc/* ! */)g_db_collection_dispose; object->finalize = (GObjectFinalizeFunc)g_db_collection_finalize; + klass->setup_load = (collec_setup_load_fc)_g_db_collection_setup_load; + g_signal_new("content-changed", G_TYPE_DB_COLLECTION, G_SIGNAL_RUN_LAST, @@ -578,6 +584,65 @@ bool _g_db_collection_modify_item(GDbCollection *collec, GDbItem *item, bool loc /****************************************************************************** * * +* Paramètres : collec = ensemble d'éléments spectateur des opérations. * +* db = accès à la base de données. * +* * +* Description : Crée la table d'élément dans une base de données. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_db_collection_create_db_table(const GDbCollection *collec, sqlite3 *db) +{ + fprintf(stderr, "CREATE '%s'\n", collec->name); + + return G_DB_COLLECTION_GET_CLASS(collec)->create_table(collec, db); + +} + + +/****************************************************************************** +* * +* Paramètres : collec = ensemble d'éléments à consulter. * +* values = tableau d'éléments à compléter. [OUT] * +* count = nombre de descriptions renseignées. [OUT] * +* * +* Description : Décrit les colonnes utiles à un chargement de données. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool _g_db_collection_setup_load(GDbCollection *collec, bound_value **values, size_t *count) +{ + *count += 2; + *values = (bound_value *)realloc(*values, *count * sizeof(bound_value)); + + (*values)[*count - 2].name = "created"; + + (*values)[*count - 1].name = "modified"; + + if (!setup_load_of_rle_string(NULL, "author", values, count)) + return false; + + if (!setup_load_of_rle_string(NULL, "tool", values, count)) + return false; + + if (!setup_load_of_rle_string(NULL, "label", values, count)) + return false; + + return true; + +} + + +/****************************************************************************** +* * * Paramètres : collec = ensemble d'éléments à consulter. * * values = tableau d'éléments à compléter. [OUT] * * count = nombre de descriptions renseignées. [OUT] * @@ -622,6 +687,7 @@ bool g_db_collection_load_all_items(GDbCollection *collec, sqlite3 *db) size_t i; /* Boucle de parcours */ sqlite3_stmt *stmt; /* Déclaration mise en place */ int ret; /* Bilan d'un appel à SQLite */ + GDbItem *new; /* Nouvel élément à insérer */ if (!g_db_collection_setup_load(collec, &values, &count)) return false; @@ -644,7 +710,7 @@ bool g_db_collection_load_all_items(GDbCollection *collec, sqlite3 *db) sql = stradd(sql, collec->name); sql = stradd(sql, ";"); - ret = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); + ret = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); if (ret != SQLITE_OK) { fprintf(stderr, "Can't prepare SELECT statment '%s' (ret=%d): %s\n", sql, ret, sqlite3_errmsg(db)); @@ -695,7 +761,10 @@ bool g_db_collection_load_all_items(GDbCollection *collec, sqlite3 *db) /* Chargement d'un nouvel élément */ - result = G_DB_COLLECTION_GET_CLASS(collec)->load_item(collec, values, count); + new = g_object_new(G_DB_COLLECTION(collec)->type, NULL); + + result = g_db_item_load(new, values, count); + result &= g_db_collection_add_item(G_DB_COLLECTION(collec), new); } @@ -707,8 +776,6 @@ bool g_db_collection_load_all_items(GDbCollection *collec, sqlite3 *db) free(sql); - printf("LOAD ? %d\n", result); - return result; } @@ -739,7 +806,7 @@ static bool g_db_collection_store_item(const GDbCollection *collec, const GDbIte int ret; /* Bilan d'un appel à SQLite */ int index; /* Indice de valeur attachée */ - if (!g_db_item_prepare_db_statement(item, true, &values, &count)) + if (!g_db_item_prepare_db_statement(item, &values, &count)) return false; result = false; diff --git a/src/analysis/db/collection.h b/src/analysis/db/collection.h index 268c2be..f190acc 100644 --- a/src/analysis/db/collection.h +++ b/src/analysis/db/collection.h @@ -114,12 +114,14 @@ bool _g_db_collection_modify_item(GDbCollection *, GDbItem *, bool); /* --------------------- MANIPULATIONS AVEC UNE BASE DE DONNEES --------------------- */ +/* Crée la table d'élément dans une base de données. */ +bool g_db_collection_create_db_table(const GDbCollection *, sqlite3 *); + /* Charge un ensemble d'éléments à partir d'une base de données. */ bool g_db_collection_load_all_items(GDbCollection *, sqlite3 *); - /* ------------------- CREATION DE L'ABSTRACTION POUR COLLECTIONS ------------------- */ diff --git a/src/analysis/db/item-int.h b/src/analysis/db/item-int.h index 0f75ed4..7b99f4a 100644 --- a/src/analysis/db/item-int.h +++ b/src/analysis/db/item-int.h @@ -31,9 +31,7 @@ #include - - - +#include "misc/rlestr.h" @@ -44,7 +42,10 @@ typedef bool (* recv_db_item_fc) (GDbItem *, int, int); typedef bool (* send_db_item_fc) (const GDbItem *, int, int); /* Constitue les champs destinés à une insertion / modification. */ -typedef bool (* prepare_db_statement) (const GDbItem *, bool, bound_value **, size_t *); +typedef bool (* prepare_db_statement) (const GDbItem *, bound_value **, size_t *); + +/* Charge les valeurs utiles pour une localisation. */ +typedef bool (* load_db_item_fc) (GDbItem *, const bound_value *, size_t); /* Base d'un élément pour collection générique (instance) */ @@ -55,6 +56,11 @@ struct _GDbItem uint64_t created; /* Date de création */ uint64_t modified; /* Date de modification */ + rle_string author; /* Utilisateur d'origine */ + rle_string tool; /* Eventuel outil automatique ?*/ + + rle_string label; /* Représentation humaine */ + bool is_volatile; /* Pas besoin de sauvegarde ? */ }; @@ -70,9 +76,19 @@ struct _GDbItemClass send_db_item_fc send; /* Emission depuis le réseau */ prepare_db_statement prepare_stmt; /* Préparation d'une requête */ + load_db_item_fc load; /* Chargement à partir d'une BD*/ }; +/* Définition du tronc commun pour les créations SQLite */ +#define SQLITE_DB_ITEM_CREATE \ + "created INTEGER, " \ + "modified INTEGER, " \ + SQLITE_RLESTR_CREATE("author") ", " \ + SQLITE_RLESTR_CREATE("tool") ", " \ + SQLITE_RLESTR_CREATE("label") + + #endif /* _ANALYSIS_DB_ITEM_INT_H */ diff --git a/src/analysis/db/item.c b/src/analysis/db/item.c index 7fa1a52..746ca27 100644 --- a/src/analysis/db/item.c +++ b/src/analysis/db/item.c @@ -24,6 +24,7 @@ #include "item.h" +#include #include #include @@ -61,7 +62,10 @@ static bool g_db_item_send_to_fd(const GDbItem *, int, int); /* Constitue les champs destinés à une insertion / modification. */ -static bool _g_db_item_prepare_db_statement(const GDbItem *, bool, bound_value **, size_t *); +static bool _g_db_item_prepare_db_statement(const GDbItem *, bound_value **, size_t *); + +/* Charge les valeurs utiles pour un élément de collection. */ +static bool _g_db_item_load(GDbItem *, const bound_value *, size_t); @@ -96,6 +100,7 @@ static void g_db_item_class_init(GDbItemClass *klass) klass->send = (send_db_item_fc)g_db_item_send_to_fd; klass->prepare_stmt = (prepare_db_statement)_g_db_item_prepare_db_statement; + klass->load = (load_db_item_fc)_g_db_item_load; } @@ -114,6 +119,15 @@ static void g_db_item_class_init(GDbItemClass *klass) static void g_db_item_init(GDbItem *item) { + const char *author; /* Identification à diffuser */ + bool status; /* Bilan d'une obtention */ + + status = g_generic_config_get_value(get_main_configuration(), MPK_AUTHOR_NAME, &author); + assert(status); + + set_rle_string(&item->author, author); + + item->is_volatile = false; } @@ -193,7 +207,7 @@ static gint g_db_item_cmp(GDbItem *a, GDbItem *b) result = -1; else - result = 0; + result = cmp_rle_string(&a->label, &b->label); } @@ -241,16 +255,25 @@ static bool g_db_item_recv_from_fd(GDbItem *item, int fd, int flags) uint64_t val64; /* Valeur sur 64 bits */ bool status; /* Bilan d'une réception */ - status = safe_recv(fd, &val64, sizeof(uint64_t), flags); + status = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL | flags); if (!status) return false; item->created = be64toh(val64); - status = safe_recv(fd, &val64, sizeof(uint64_t), flags); + status = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL | flags); if (!status) return false; item->modified = be64toh(val64); + status = recv_rle_string(&item->author, fd, flags); + if (!status) return false; + + status = recv_rle_string(&item->tool, fd, flags); + if (!status) return false; + + status = recv_rle_string(&item->label, fd, flags); + if (!status) return false; + return true; } @@ -295,14 +318,19 @@ static bool g_db_item_send_to_fd(const GDbItem *item, int fd, int flags) { bool status; /* Bilan d'une émission */ + status = safe_send(fd, (uint64_t []) { htobe64(item->created) }, sizeof(uint64_t), MSG_MORE | flags); + if (!status) return false; - printf(" FROM %s...\n", __FUNCTION__); + status = safe_send(fd, (uint64_t []) { htobe64(item->modified) }, sizeof(uint64_t), MSG_MORE | flags); + if (!status) return false; + status = send_rle_string(&item->author, fd, MSG_MORE | flags); + if (!status) return false; - status = safe_send(fd, (uint64_t []) { htobe64(item->created) }, sizeof(uint64_t), MSG_MORE | flags); + status = send_rle_string(&item->tool, fd, MSG_MORE | flags); if (!status) return false; - status = safe_send(fd, (uint64_t []) { htobe64(item->modified) }, sizeof(uint64_t), flags); + status = send_rle_string(&item->label, fd, flags); if (!status) return false; return true; @@ -379,7 +407,6 @@ bool g_db_item_is_volatile(const GDbItem *item) /****************************************************************************** * * * Paramètres : item = base d'éléments sur laquelle s'appuyer. * -* create = indique si la préparation vise une création ou non. * * values = couples de champs et de valeurs à lier. [OUT] * * count = nombre de ces couples. [OUT] * * * @@ -391,35 +418,35 @@ bool g_db_item_is_volatile(const GDbItem *item) * * ******************************************************************************/ -static bool _g_db_item_prepare_db_statement(const GDbItem *item, bool create, bound_value **values, size_t *count) +static bool _g_db_item_prepare_db_statement(const GDbItem *item, bound_value **values, size_t *count) { - char *author; /* Identification à diffuser */ + bool result; /* Bilan à retourner */ bound_value *value; /* Valeur à éditer / définir */ - if (!g_generic_config_get_value(get_main_configuration(), MPK_AUTHOR_NAME, &author)) - return false; + result = true; + + *count += 2; + *values = (bound_value *)realloc(*values, *count * sizeof(bound_value)); + + value = &(*values)[*count - 2]; + + value->name = "created"; + value->type = SQLITE_INT64; + value->integer64 = item->created; - *values = (bound_value *)realloc(*values, ++(*count) * sizeof(bound_value)); value = &(*values)[*count - 1]; - value->name = "user"; - value->type = SQLITE_TEXT; - value->string = author; - value->delete = free; + value->name = "modified"; + value->type = SQLITE_INT64; + value->integer64 = item->modified; - if (!create) - { - *values = (bound_value *)realloc(*values, ++(*count) * sizeof(bound_value)); - value = &(*values)[*count - 1]; + result &= prepare_db_statement_for_rle_string(&item->author, "author", values, count); - value->name = "modified"; - value->type = SQLITE_RAW; - value->string = "CURRENT_TIMESTAMP"; - value->delete = SQLITE_STATIC; + result &= prepare_db_statement_for_rle_string(&item->tool, "tool", values, count); - } + result &= prepare_db_statement_for_rle_string(&item->label, "label", values, count); - return true; + return result; } @@ -427,7 +454,6 @@ static bool _g_db_item_prepare_db_statement(const GDbItem *item, bool create, bo /****************************************************************************** * * * Paramètres : item = base d'éléments sur laquelle s'appuyer. * -* create = indique si la préparation vise une création ou non. * * values = couples de champs et de valeurs à lier. [OUT] * * count = nombre de ces couples. [OUT] * * * @@ -439,11 +465,76 @@ static bool _g_db_item_prepare_db_statement(const GDbItem *item, bool create, bo * * ******************************************************************************/ -bool g_db_item_prepare_db_statement(const GDbItem *item, bool create, bound_value **values, size_t *count) +bool g_db_item_prepare_db_statement(const GDbItem *item, bound_value **values, size_t *count) { *values = NULL; *count = 0; - return G_DB_ITEM_GET_CLASS(item)->prepare_stmt(item, create, values, count); + return G_DB_ITEM_GET_CLASS(item)->prepare_stmt(item, values, count); + +} + + +/****************************************************************************** +* * +* Paramètres : item = base d'éléments à charger depuis les réponses. * +* values = tableau d'éléments à consulter. * +* count = nombre de descriptions renseignées. * +* * +* Description : Charge les valeurs utiles pour un élément de collection. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool _g_db_item_load(GDbItem *item, const bound_value *values, size_t count) +{ + bool result; /* Bilan global à retourner */ + const bound_value *value; /* Valeur à éditer / définir */ + + value = find_bound_value(values, count, "created"); + if (value == NULL) return false; + if (value->type != SQLITE_INT64) return false; + + item->created = value->integer64; + + value = find_bound_value(values, count, "modified"); + if (value == NULL) return false; + if (value->type != SQLITE_INT64) return false; + + item->modified = value->integer64; + + result = true; + + result &= load_rle_string(&item->author, "author", values, count); + + result &= load_rle_string(&item->tool, "tool", values, count); + + result &= load_rle_string(&item->label, "label", values, count); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = base d'éléments à charger depuis les réponses. * +* values = tableau d'éléments à consulter. * +* count = nombre de descriptions renseignées. * +* * +* Description : Charge les valeurs utiles pour un élément de collection. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_db_item_load(GDbItem *item, const bound_value *values, size_t count) +{ + return G_DB_ITEM_GET_CLASS(item)->load(item, values, count); } diff --git a/src/analysis/db/item.h b/src/analysis/db/item.h index 2f8ee60..c70eefa 100644 --- a/src/analysis/db/item.h +++ b/src/analysis/db/item.h @@ -71,15 +71,11 @@ bool g_db_item_is_volatile(const GDbItem *); /* --------------------- MANIPULATIONS AVEC UNE BASE DE DONNEES --------------------- */ -/* Définition du tronc commun pour les créations SQLite */ -#define SQLITE_DB_ITEM_CREATE \ - "user TEXT, " \ - "created TIMESTAMP DEFAULT CURRENT_TIMESTAMP, " \ - "modified TIMESTAMP DEFAULT CURRENT_TIMESTAMP, " - - /* Constitue les champs destinés à une insertion / modification. */ -bool g_db_item_prepare_db_statement(const GDbItem *, bool, bound_value **, size_t *); +bool g_db_item_prepare_db_statement(const GDbItem *, bound_value **, size_t *); + +/* Charge les valeurs utiles pour un élément de collection. */ +bool g_db_item_load(GDbItem *, const bound_value *, size_t); diff --git a/src/analysis/db/items/Makefile.am b/src/analysis/db/items/Makefile.am index f026d44..c0e6b47 100644 --- a/src/analysis/db/items/Makefile.am +++ b/src/analysis/db/items/Makefile.am @@ -3,7 +3,8 @@ noinst_LTLIBRARIES = libanalysisdbitems.la libanalysisdbitems_la_SOURCES = \ bookmark.h bookmark.c \ - comment.h comment.c + comment.h comment.c \ + switcher.h switcher.c libanalysisdbitems_la_LIBADD = diff --git a/src/analysis/db/items/bookmark.c b/src/analysis/db/items/bookmark.c index a8182ce..c9d7b7a 100644 --- a/src/analysis/db/items/bookmark.c +++ b/src/analysis/db/items/bookmark.c @@ -30,10 +30,6 @@ #include "../collection-int.h" #include "../item-int.h" -#include "../misc/rlestr.h" - - - @@ -58,7 +54,6 @@ struct _GDbBookmarkClass }; - /* Initialise la classe des signets dans une zone de texte. */ static void g_db_bookmark_class_init(GDbBookmarkClass *); @@ -71,8 +66,6 @@ static void g_db_bookmark_dispose(GDbBookmark *); /* Procède à la libération totale de la mémoire. */ static void g_db_bookmark_finalize(GDbBookmark *); - - /* Effectue la comparaison entre deux signets de collection. */ static gint g_db_bookmark_cmp(GDbBookmark *, GDbBookmark *); @@ -83,18 +76,16 @@ static bool g_db_bookmark_recv_from_fd(GDbBookmark *, int, int); static bool g_db_bookmark_send_to_fd(const GDbBookmark *, int, int); /* Constitue les champs destinés à une insertion / modification. */ -static bool g_db_bookmark_prepare_db_statement(const GDbBookmark *, bool, bound_value **, size_t *); - - +static bool g_db_bookmark_prepare_db_statement(const GDbBookmark *, bound_value **, size_t *); +/* Charge les valeurs utiles pour un signet. */ +static bool g_db_bookmark_load(GDbBookmark *, const bound_value *, size_t); /* ---------------------- DEFINITION DE LA COLLECTION ASSOCIEE ---------------------- */ - - /* Collection dédiée aux signets (instance) */ struct _GBookmarkCollection { @@ -122,12 +113,12 @@ static void g_bookmark_collection_dispose(GBookmarkCollection *); /* Procède à la libération totale de la mémoire. */ static void g_bookmark_collection_finalize(GBookmarkCollection *); +/* Crée la table des signets dans une base de données. */ +static bool g_bookmark_collection_create_db_table(const GBookmarkCollection *, sqlite3 *); + /* Décrit les colonnes utiles à un chargement de données. */ static bool g_bookmark_collection_setup_load(GBookmarkCollection *, bound_value **, size_t *); -/* Charge les valeurs utiles pour une localisation. */ -static bool g_bookmark_collection_load_item(GBookmarkCollection *, const bound_value *, size_t); - /* Détermine si un élément est déjà présent ou non. */ static GDbItem *g_bookmark_collection_has_key(GBookmarkCollection *, va_list *); @@ -172,6 +163,7 @@ static void g_db_bookmark_class_init(GDbBookmarkClass *klass) item->send = (send_db_item_fc)g_db_bookmark_send_to_fd; item->prepare_stmt = (prepare_db_statement)g_db_bookmark_prepare_db_statement; + item->load = (load_db_item_fc)g_db_bookmark_load; } @@ -227,6 +219,8 @@ static void g_db_bookmark_dispose(GDbBookmark *bookmark) static void g_db_bookmark_finalize(GDbBookmark *bookmark) { + exit_rle_string(&bookmark->comment); + G_OBJECT_CLASS(g_db_bookmark_parent_class)->finalize(G_OBJECT(bookmark)); } @@ -260,11 +254,6 @@ GDbBookmark *g_db_bookmark_new(const vmpa2t *addr, const char *comment) } - - - - - /****************************************************************************** * * * Paramètres : a = premier élément à analyser. * @@ -287,8 +276,10 @@ static gint g_db_bookmark_cmp(GDbBookmark *a, GDbBookmark *b) if (result == 0) result = cmp_rle_string(&a->comment, &b->comment); - return result; + if (result == 0) + result = G_DB_ITEM_CLASS(g_db_bookmark_parent_class)->cmp(G_DB_ITEM(a), G_DB_ITEM(b)); + return result; } @@ -314,10 +305,10 @@ static bool g_db_bookmark_recv_from_fd(GDbBookmark *bookmark, int fd, int flags) status = G_DB_ITEM_CLASS(g_db_bookmark_parent_class)->recv(G_DB_ITEM(bookmark), fd, flags); if (!status) return false; - if (!recv_vmpa(&bookmark->addr, fd, 0)) + if (!recv_vmpa(&bookmark->addr, fd, flags)) return false; - if (!recv_rle_string(&bookmark->comment, fd, 0)) + if (!recv_rle_string(&bookmark->comment, fd, flags)) return false; return true; @@ -346,10 +337,6 @@ static bool g_db_bookmark_send_to_fd(const GDbBookmark *bookmark, int fd, int fl status = G_DB_ITEM_CLASS(g_db_bookmark_parent_class)->send(G_DB_ITEM(bookmark), fd, MSG_MORE | flags); if (!status) return false; - - printf(" FROM %s...\n", __FUNCTION__); - - if (!send_vmpa(&bookmark->addr, fd, MSG_MORE | flags)) return false; @@ -363,10 +350,9 @@ static bool g_db_bookmark_send_to_fd(const GDbBookmark *bookmark, int fd, int fl /****************************************************************************** * * -* Paramètres : item = base d'éléments sur laquelle s'appuyer. * -* create = indique si la préparation vise une création ou non. * -* values = couples de champs et de valeurs à lier. [OUT] * -* count = nombre de ces couples. [OUT] * +* Paramètres : bookmark = base d'éléments sur laquelle s'appuyer. * +* values = couples de champs et de valeurs à lier. [OUT] * +* count = nombre de ces couples. [OUT] * * * * Description : Constitue les champs destinés à une insertion / modification.* * * @@ -376,36 +362,51 @@ static bool g_db_bookmark_send_to_fd(const GDbBookmark *bookmark, int fd, int fl * * ******************************************************************************/ -static bool g_db_bookmark_prepare_db_statement(const GDbBookmark *bookmark, bool create, bound_value **values, size_t *count) +static bool g_db_bookmark_prepare_db_statement(const GDbBookmark *bookmark, bound_value **values, size_t *count) { bool status; /* Bilan d'opération initiale */ - bound_value *value; /* Valeur à éditer / définir */ - status = G_DB_ITEM_CLASS(g_db_bookmark_parent_class)->prepare_stmt(G_DB_ITEM(bookmark), create, values, count); + status = G_DB_ITEM_CLASS(g_db_bookmark_parent_class)->prepare_stmt(G_DB_ITEM(bookmark), values, count); if (!status) return false; - status = prepare_vmpa_db_statement(&bookmark->addr, create, values, count); + status = prepare_vmpa_db_statement(&bookmark->addr, values, count); if (!status) return false; - *values = (bound_value *)realloc(*values, ++(*count) * sizeof(bound_value)); - value = &(*values)[*count - 1]; - - value->name = "comment"; - value->type = SQLITE_TEXT; - value->cstring = g_db_bookmark_get_comment(bookmark); - value->delete = SQLITE_STATIC; + status &= prepare_db_statement_for_rle_string(&bookmark->comment, "comment", values, count); + if (!status) return false; return true; } +/****************************************************************************** +* * +* Paramètres : bookmark = bascule d'affichage à charger depuis les réponses.* +* values = tableau d'éléments à consulter. * +* count = nombre de descriptions renseignées. * +* * +* Description : Charge les valeurs utiles pour un signet. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ +static bool g_db_bookmark_load(GDbBookmark *bookmark, const bound_value *values, size_t count) +{ + bool result; /* Bilan à faire remonter */ + result = G_DB_ITEM_CLASS(g_db_bookmark_parent_class)->load(G_DB_ITEM(bookmark), values, count); + result &= load_vmpa(&bookmark->addr, values, count); + result &= load_rle_string(&bookmark->comment, "comment", values, count); + return result; +} /****************************************************************************** @@ -500,8 +501,8 @@ static void g_bookmark_collection_class_init(GBookmarkCollectionClass *klass) collec = G_DB_COLLECTION_CLASS(klass); + collec->create_table = (collec_create_db_table_fc)g_bookmark_collection_create_db_table; collec->setup_load = (collec_setup_load_fc)g_bookmark_collection_setup_load; - collec-> load_item = (collec_load_item)g_bookmark_collection_load_item; collec->has_key = (collec_has_key_fc)g_bookmark_collection_has_key; } @@ -553,7 +554,7 @@ static void g_bookmark_collection_dispose(GBookmarkCollection *collec) /****************************************************************************** * * -* Paramètres : bookmark = instance d'objet GLib à traiter. * +* Paramètres : collec = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * @@ -593,17 +594,10 @@ GBookmarkCollection *g_bookmark_collection_new(void) } - - - - - - - - /****************************************************************************** * * -* Paramètres : db = accès à la base de données. * +* Paramètres : collec = ensemble d'éléments spectateur des opérations. * +* db = accès à la base de données. * * * * Description : Crée la table des signets dans une base de données. * * * @@ -613,16 +607,16 @@ GBookmarkCollection *g_bookmark_collection_new(void) * * ******************************************************************************/ -bool create_bookmark_db_table(sqlite3 *db) +static bool g_bookmark_collection_create_db_table(const GBookmarkCollection *collec, sqlite3 *db) { char *sql; /* Requête à exécuter */ int ret; /* Bilan de la création */ char *msg; /* Message d'erreur */ sql = "CREATE TABLE Bookmarks (" \ - SQLITE_DB_ITEM_CREATE \ - SQLITE_VMPA_CREATE \ - "comment TEXT" \ + SQLITE_DB_ITEM_CREATE ", " \ + SQLITE_VMPA_CREATE ", " \ + SQLITE_RLESTR_CREATE("comment") \ ");"; ret = sqlite3_exec(db, sql, NULL, NULL, &msg); @@ -637,9 +631,6 @@ bool create_bookmark_db_table(sqlite3 *db) } - - - /****************************************************************************** * * * Paramètres : collec = ensemble d'éléments à consulter. * @@ -656,69 +647,19 @@ bool create_bookmark_db_table(sqlite3 *db) static bool g_bookmark_collection_setup_load(GBookmarkCollection *collec, bound_value **values, size_t *count) { - // TODO : classe supérieure + bool status; /* Bilan d'une préparation */ + + status = G_DB_COLLECTION_CLASS(g_bookmark_collection_parent_class)->setup_load(G_DB_COLLECTION(collec), \ + values, count); + if (!status) return false; if (!setup_load_for_vmpa(NULL, values, count)) return false; - *values = (bound_value *)realloc(*values, ++(*count) * sizeof(bound_value)); - - (*values)[*count - 1].name = "comment"; - - return true; - - -} - - -/****************************************************************************** -* * -* Paramètres : collec = ensemble d'éléments à compléter. * -* values = tableau d'éléments à consulter. * -* count = nombre de descriptions renseignées. * -* * -* Description : Charge les valeurs utiles pour une localisation. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool g_bookmark_collection_load_item(GBookmarkCollection *collec, const bound_value *values, size_t count) -{ - vmpa2t addr; /* Localisation d'un signet */ - const char *comment; /* Eventuel commentaire associé*/ - const bound_value *value; /* Valeur à intégrer */ - GDbBookmark *new; /* Nouvel élément à intégrer */ - - if (!load_vmpa(&addr, values, count)) + if (!setup_load_of_rle_string(NULL, "comment", values, count)) return false; - value = find_bound_value(values, count, "comment"); - if (value == NULL) return false; - - switch (value->type) - { - case SQLITE_TEXT: - comment = value->cstring; - break; - - case SQLITE_NULL: - comment = NULL; - break; - - default: - return false; - break; - - } - - new = g_db_bookmark_new(&addr, comment); - - printf(" LOAD new bm :: %p\n", new); - - return g_db_collection_add_item(G_DB_COLLECTION(collec), G_DB_ITEM(new)); + return true; } diff --git a/src/analysis/db/items/bookmark.h b/src/analysis/db/items/bookmark.h index de12b1b..61b2c01 100644 --- a/src/analysis/db/items/bookmark.h +++ b/src/analysis/db/items/bookmark.h @@ -35,13 +35,6 @@ -/* Crée la table des signets dans une base de données. */ -bool create_bookmark_db_table(sqlite3 *); - - - - - /* --------------------- ELABORATION D'UN ELEMENT DE COLLECTION --------------------- */ diff --git a/src/analysis/db/items/comment.c b/src/analysis/db/items/comment.c index 73a18b0..1bed0ab 100644 --- a/src/analysis/db/items/comment.c +++ b/src/analysis/db/items/comment.c @@ -28,17 +28,20 @@ #include +#include "../collection-int.h" #include "../item-int.h" -#include "../misc/rlestr.h" +/* --------------------- ELABORATION D'UN ELEMENT DE COLLECTION --------------------- */ + + /* Commentaire à placer dans du texte quelconque (instance) */ struct _GDbComment { GDbItem parent; /* A laisser en premier */ - vmpa2t *addr; /* Adresse du commentaire */ + vmpa2t addr; /* Adresse du commentaire */ rle_string text; /* Contenu du commentaire */ }; @@ -51,7 +54,6 @@ struct _GDbCommentClass }; - /* Initialise la classe des commentaires dans une zone de texte. */ static void g_db_comment_class_init(GDbCommentClass *); @@ -73,53 +75,58 @@ static bool g_db_comment_recv_from_fd(GDbComment *, int, int); /* Exporte la définition d'un commentaire dans un flux réseau. */ static bool g_db_comment_send_to_fd(const GDbComment *, int, int); +/* Constitue les champs destinés à une insertion / modification. */ +static bool g_db_comment_prepare_db_statement(const GDbComment *, bound_value **, size_t *); +/* Charge les valeurs utiles pour un commentaire. */ +static bool g_db_comment_load(GDbComment *, const bound_value *, size_t); -/****************************************************************************** -* * -* Paramètres : db = accès à la base de données. * -* * -* Description : Crée la table des commentaires dans une base de données. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ -bool create_comment_db_table(sqlite3 *db) +/* ---------------------- DEFINITION DE LA COLLECTION ASSOCIEE ---------------------- */ + + +/* Collection dédiée aux commentaires textuels (instance) */ +struct _GCommentCollection { - char *sql; /* Requête à exécuter */ - int ret; /* Bilan de la création */ - char *msg; /* Message d'erreur */ + GDbCollection parent; /* A laisser en premier */ - sql = "CREATE TABLE Comments (" \ - "id INT PRIMARY KEY NOT NULL, " \ - "user TEXT NOT NULL, " \ - "created INT NOT NULL, " \ - "address INT NOT NULL, " \ - "comment TEXT" \ - ");"; +}; - ret = sqlite3_exec(db, sql, NULL, NULL, &msg); - if (ret != SQLITE_OK) - { - fprintf(stderr, "sqlite3_exec(): %s\n", msg); - sqlite3_free(msg); - } +/* Collection dédiée aux commentaires textuels (classe) */ +struct _GCommentCollectionClass +{ + GDbCollectionClass parent; /* A laisser en premier */ - return (ret == SQLITE_OK); +}; -} +/* Initialise la classe des commentaires sous forme de texte. */ +static void g_comment_collection_class_init(GCommentCollectionClass *); + +/* Initialise un commentaire sous forme de zone de texte. */ +static void g_comment_collection_init(GCommentCollection *); + +/* Supprime toutes les références externes. */ +static void g_comment_collection_dispose(GCommentCollection *); +/* Procède à la libération totale de la mémoire. */ +static void g_comment_collection_finalize(GCommentCollection *); +/* Crée la table des commentaires dans une base de données. */ +static bool g_comment_collection_create_db_table(const GCommentCollection *, sqlite3 *); +/* Décrit les colonnes utiles à un chargement de données. */ +static bool g_comment_collection_setup_load(GCommentCollection *, bound_value **, size_t *); +/* Détermine si un élément est déjà présent ou non. */ +static GDbItem *g_comment_collection_has_key(GCommentCollection *, va_list *); +/* ---------------------------------------------------------------------------------- */ +/* ELABORATION D'UN ELEMENT DE COLLECTION */ +/* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour un commentaire à l'intérieur d'une zone de texte. */ @@ -155,6 +162,9 @@ static void g_db_comment_class_init(GDbCommentClass *klass) item->recv = (recv_db_item_fc)g_db_comment_recv_from_fd; item->send = (send_db_item_fc)g_db_comment_send_to_fd; + item->prepare_stmt = (prepare_db_statement)g_db_comment_prepare_db_statement; + item->load = (load_db_item_fc)g_db_comment_load; + } @@ -209,9 +219,7 @@ static void g_db_comment_dispose(GDbComment *comment) static void g_db_comment_finalize(GDbComment *comment) { - delete_vmpa(comment->addr); - - exit_rle_string(comment->text); + exit_rle_string(&comment->text); G_OBJECT_CLASS(g_db_comment_parent_class)->finalize(G_OBJECT(comment)); @@ -238,7 +246,7 @@ GDbComment *g_db_comment_new(const vmpa2t *addr, const char *text, bool is_volat result = g_object_new(G_TYPE_DB_COMMENT, NULL); - result->addr = dup_vmpa(addr); + copy_vmpa(&result->addr, addr); g_db_comment_set_text(result, text); @@ -266,11 +274,14 @@ static gint g_db_comment_cmp(GDbComment *a, GDbComment *b) { gint result; /* Bilan de la comparaison */ - result = cmp_vmpa_by_phy(a->addr, b->addr); + result = cmp_vmpa_by_phy(&a->addr, &b->addr); if (result == 0) result = cmp_rle_string(&a->text, &b->text); + if (result == 0) + result = G_DB_ITEM_CLASS(g_db_comment_parent_class)->cmp(G_DB_ITEM(a), G_DB_ITEM(b)); + return 0; } @@ -297,10 +308,10 @@ static bool g_db_comment_recv_from_fd(GDbComment *comment, int fd, int flags) status = G_DB_ITEM_CLASS(g_db_comment_parent_class)->recv(G_DB_ITEM(comment), fd, flags); if (!status) return false; - if (!recv_vmpa(comment->addr, fd, 0)) + if (!recv_vmpa(&comment->addr, fd, flags)) return false; - if (!recv_rle_string(&comment->text, fd, 0)) + if (!recv_rle_string(&comment->text, fd, flags)) return false; return true; @@ -329,7 +340,7 @@ static bool g_db_comment_send_to_fd(const GDbComment *comment, int fd, int flags status = G_DB_ITEM_CLASS(g_db_comment_parent_class)->send(G_DB_ITEM(comment), fd, MSG_MORE | flags); if (!status) return false; - if (!send_vmpa(comment->addr, fd, MSG_MORE | flags)) + if (!send_vmpa(&comment->addr, fd, MSG_MORE | flags)) return false; if (!send_rle_string(&comment->text, fd, flags)) @@ -342,6 +353,67 @@ static bool g_db_comment_send_to_fd(const GDbComment *comment, int fd, int flags /****************************************************************************** * * +* Paramètres : comment = base d'éléments sur laquelle s'appuyer. * +* values = couples de champs et de valeurs à lier. [OUT] * +* count = nombre de ces couples. [OUT] * +* * +* Description : Constitue les champs destinés à une insertion / modification.* +* * +* Retour : Etat du besoin en sauvegarde. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_db_comment_prepare_db_statement(const GDbComment *comment, bound_value **values, size_t *count) +{ + bool status; /* Bilan d'opération initiale */ + + status = G_DB_ITEM_CLASS(g_db_comment_parent_class)->prepare_stmt(G_DB_ITEM(comment), values, count); + if (!status) return false; + + status = prepare_vmpa_db_statement(&comment->addr, values, count); + if (!status) return false; + + status &= prepare_db_statement_for_rle_string(&comment->text, "text", values, count); + if (!status) return false; + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : comment = commentaire textuel à charger depuis les réponses. * +* values = tableau d'éléments à consulter. * +* count = nombre de descriptions renseignées. * +* * +* Description : Charge les valeurs utiles pour un commentaire. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_db_comment_load(GDbComment *comment, const bound_value *values, size_t count) +{ + bool result; /* Bilan à faire remonter */ + + result = G_DB_ITEM_CLASS(g_db_comment_parent_class)->load(G_DB_ITEM(comment), values, count); + + result &= load_vmpa(&comment->addr, values, count); + + result &= load_rle_string(&comment->text, "text", values, count); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : comment = informations à consulter. * * * * Description : Fournit l'adresse associée à un commentaire. * @@ -354,7 +426,7 @@ static bool g_db_comment_send_to_fd(const GDbComment *comment, int fd, int flags const vmpa2t *g_db_comment_get_address(GDbComment *comment) { - return comment->addr; + return &comment->addr; } @@ -396,3 +468,247 @@ void g_db_comment_set_text(GDbComment *comment, const char *text) set_rle_string(&comment->text, text); } + + + +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION DE LA COLLECTION ASSOCIEE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une collection de commentaires. */ +G_DEFINE_TYPE(GCommentCollection, g_comment_collection, G_TYPE_DB_COLLECTION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des commentaires sous forme de texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_comment_collection_class_init(GCommentCollectionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GDbCollectionClass *collec; /* Encore une autre vision... */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_comment_collection_dispose; + object->finalize = (GObjectFinalizeFunc)g_comment_collection_finalize; + + collec = G_DB_COLLECTION_CLASS(klass); + + collec->create_table = (collec_create_db_table_fc)g_comment_collection_create_db_table; + collec->setup_load = (collec_setup_load_fc)g_comment_collection_setup_load; + collec->has_key = (collec_has_key_fc)g_comment_collection_has_key; + +} + + +/****************************************************************************** +* * +* Paramètres : collec = instance à initialiser. * +* * +* Description : Initialise un commentaire sous forme de zone de texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_comment_collection_init(GCommentCollection *collec) +{ + + + G_DB_COLLECTION(collec)->featuring = 0; + G_DB_COLLECTION(collec)->type = G_TYPE_DB_COMMENT; + G_DB_COLLECTION(collec)->name = "Comments"; + + + +} + + +/****************************************************************************** +* * +* Paramètres : collec = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_comment_collection_dispose(GCommentCollection *collec) +{ + G_OBJECT_CLASS(g_comment_collection_parent_class)->dispose(G_OBJECT(collec)); + +} + + +/****************************************************************************** +* * +* Paramètres : collec = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_comment_collection_finalize(GCommentCollection *collec) +{ + G_OBJECT_CLASS(g_comment_collection_parent_class)->finalize(G_OBJECT(collec)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée une collection dédiée aux commentaires. * +* * +* Retour : Collection mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GCommentCollection *g_comment_collection_new(void) +{ + GCommentCollection *result; /* Instance à retourner */ + + result = g_object_new(G_TYPE_COMMENT_COLLECTION, NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : collec = ensemble d'éléments spectateur des opérations. * +* db = accès à la base de données. * +* * +* Description : Crée la table des commentaires dans une base de données. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_comment_collection_create_db_table(const GCommentCollection *collec, sqlite3 *db) +{ + char *sql; /* Requête à exécuter */ + int ret; /* Bilan de la création */ + char *msg; /* Message d'erreur */ + + sql = "CREATE TABLE Comments (" \ + SQLITE_DB_ITEM_CREATE ", " \ + SQLITE_VMPA_CREATE ", " \ + SQLITE_RLESTR_CREATE("text") \ + ");"; + + ret = sqlite3_exec(db, sql, NULL, NULL, &msg); + if (ret != SQLITE_OK) + { + fprintf(stderr, "sqlite3_exec(): %s\n", msg); + sqlite3_free(msg); + } + + return (ret == SQLITE_OK); + +} + + +/****************************************************************************** +* * +* Paramètres : collec = ensemble d'éléments à consulter. * +* values = tableau d'éléments à compléter. [OUT] * +* count = nombre de descriptions renseignées. [OUT] * +* * +* Description : Décrit les colonnes utiles à un chargement de données. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_comment_collection_setup_load(GCommentCollection *collec, bound_value **values, size_t *count) +{ + bool status; /* Bilan d'une préparation */ + + status = G_DB_COLLECTION_CLASS(g_comment_collection_parent_class)->setup_load(G_DB_COLLECTION(collec), \ + values, count); + if (!status) return false; + + if (!setup_load_for_vmpa(NULL, values, count)) + return false; + + if (!setup_load_of_rle_string(NULL, "text", values, count)) + return false; + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : collec = ensemble d'éléments à consulter. * +* ap = clef identifiant de manière unique un élément. * +* * +* Description : Détermine si un élément est déjà présent ou non. * +* * +* Retour : Elément trouvé ou NULL si aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GDbItem *g_comment_collection_has_key(GCommentCollection *collec, va_list *ap) +{ + GDbItem *result; /* Bilan à retourner */ + vmpa2t *ref; /* Adresse de référence */ + GList *items; /* Eléments déjà en place */ + GList *iter; /* Boucle de parcours */ + GDbComment *bm; /* Signet à consulter */ + + result = NULL; + + ref = va_arg(ap, vmpa2t *); + + items = g_db_collection_list_items(G_DB_COLLECTION(collec)); + + for (iter = g_list_first(items); iter != NULL && result == NULL; iter = g_list_next(iter)) + { + bm = G_DB_COMMENT(iter->data); + + if (cmp_vmpa(&bm->addr, ref) != 0) + + /** + * Un verrou est sensé être posé, donc il n'y a pas besoin + * de toucher au décompte des références car l'élément trouvé + * ne peut pas être supprimé. + */ + result = G_DB_ITEM(bm); + + } + + return result; + +} diff --git a/src/analysis/db/items/comment.h b/src/analysis/db/items/comment.h index 792fb92..316f4c5 100644 --- a/src/analysis/db/items/comment.h +++ b/src/analysis/db/items/comment.h @@ -35,11 +35,7 @@ -/* Crée la table des commentaires dans une base de données. */ -bool create_comment_db_table(sqlite3 *); - - - +/* --------------------- ELABORATION D'UN ELEMENT DE COLLECTION --------------------- */ #define G_TYPE_DB_COMMENT g_db_comment_get_type() @@ -74,4 +70,36 @@ void g_db_comment_set_text(GDbComment *, const char *); + + + + + + +/* ---------------------- 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)) + + +/* Collection dédiée aux commentaires textuels (instance) */ +typedef struct _GCommentCollection GCommentCollection; + +/* Collection dédiée aux commentaires textuels (classe) */ +typedef struct _GCommentCollectionClass GCommentCollectionClass; + + +/* Indique le type défini pour une collection de commentaires. */ +GType g_comment_collection_get_type(void); + +/* Crée une collection dédiée aux commentaires. */ +GCommentCollection *g_comment_collection_new(void); + + + #endif /* _ANALYSIS_DB_ITEMS_COMMENT_H */ diff --git a/src/analysis/db/items/switcher.c b/src/analysis/db/items/switcher.c new file mode 100644 index 0000000..5063a9c --- /dev/null +++ b/src/analysis/db/items/switcher.c @@ -0,0 +1,755 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * switcher.h - gestion des basculements d'affichage d'opérandes numériques + * + * Copyright (C) 2015 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA 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. + * + * OpenIDA 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 Foobar. If not, see . + */ + + +#include "switcher.h" + + +#include +#include + + +#include "../collection-int.h" +#include "../item-int.h" +#include "../../../common/io.h" + + + + + +/* --------------------- ELABORATION D'UN ELEMENT DE COLLECTION --------------------- */ + + +/* Bascule d'affichage pour un opérande numérique (instance) */ +struct _GDbSwitcher +{ + GDbItem parent; /* A laisser en premier */ + + vmpa2t addr; /* Adresse de l'instruction */ + size_t index; /* Indice de l'opérande visé */ + + ImmSwitchType type; /* Type de bascule */ + +}; + +/* Bascule d'affichage pour un opérande numérique (classe) */ +struct _GDbSwitcherClass +{ + GDbItemClass parent; /* A laisser en premier */ + +}; + + + +/* Initialise la classe des bascules d'affichage numérique. */ +static void g_db_switcher_class_init(GDbSwitcherClass *); + +/* Initialise une bascule d'affichage pour opérande numérique. */ +static void g_db_switcher_init(GDbSwitcher *); + +/* Supprime toutes les références externes. */ +static void g_db_switcher_dispose(GDbSwitcher *); + +/* Procède à la libération totale de la mémoire. */ +static void g_db_switcher_finalize(GDbSwitcher *); + +/* Effectue la comparaison entre deux signets de collection. */ +static gint g_db_switcher_cmp(GDbSwitcher *, GDbSwitcher *); + +/* Importe la définition d'un signet dans un flux réseau. */ +static bool g_db_switcher_recv_from_fd(GDbSwitcher *, int, int); + +/* Exporte la définition d'un signet dans un flux réseau. */ +static bool g_db_switcher_send_to_fd(const GDbSwitcher *, int, int); + +/* Constitue les champs destinés à une insertion / modification. */ +static bool g_db_switcher_prepare_db_statement(const GDbSwitcher *, bound_value **, size_t *); + +/* Charge les valeurs utiles pour un basculement d'affichage. */ +static bool g_db_switcher_load(GDbSwitcher *, const bound_value *, size_t); + + + + +/* ---------------------- DEFINITION DE LA COLLECTION ASSOCIEE ---------------------- */ + + +/* Collection dédiée aux basculements d'affichage (instance) */ +struct _GSwitcherCollection +{ + GDbCollection parent; /* A laisser en premier */ + +}; + +/* Collection dédiée aux basculements d'affichage (classe) */ +struct _GSwitcherCollectionClass +{ + GDbCollectionClass parent; /* A laisser en premier */ + +}; + + +/* Initialise la classe des signets dans une zone de texte. */ +static void g_switcher_collection_class_init(GSwitcherCollectionClass *); + +/* Initialise un signet dans une zone de texte. */ +static void g_switcher_collection_init(GSwitcherCollection *); + +/* Supprime toutes les références externes. */ +static void g_switcher_collection_dispose(GSwitcherCollection *); + +/* Procède à la libération totale de la mémoire. */ +static void g_switcher_collection_finalize(GSwitcherCollection *); + +/* Crée la table des basculements dans une base de données. */ +static bool g_switcher_collection_create_db_table(const GSwitcherCollection *, sqlite3 *); + +/* Décrit les colonnes utiles à un chargement de données. */ +static bool g_switcher_collection_setup_load(GSwitcherCollection *, bound_value **, size_t *); + +/* Détermine si un élément est déjà présent ou non. */ +static GDbItem *g_switcher_collection_has_key(GSwitcherCollection *, va_list *); + + + +/* ---------------------------------------------------------------------------------- */ +/* ELABORATION D'UN ELEMENT DE COLLECTION */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un signet à l'intérieur d'une zone de texte. */ +G_DEFINE_TYPE(GDbSwitcher, g_db_switcher, G_TYPE_DB_ITEM); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des bascules d'affichage numérique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_db_switcher_class_init(GDbSwitcherClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GDbItemClass *item; /* Encore une autre vision... */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_db_switcher_dispose; + object->finalize = (GObjectFinalizeFunc)g_db_switcher_finalize; + + item = G_DB_ITEM_CLASS(klass); + + item->cmp = (GCompareFunc)g_db_switcher_cmp; + + item->recv = (recv_db_item_fc)g_db_switcher_recv_from_fd; + item->send = (send_db_item_fc)g_db_switcher_send_to_fd; + + item->prepare_stmt = (prepare_db_statement)g_db_switcher_prepare_db_statement; + item->load = (load_db_item_fc)g_db_switcher_load; + +} + + +/****************************************************************************** +* * +* Paramètres : switcher = instance à initialiser. * +* * +* Description : Initialise une bascule d'affichage pour opérande numérique. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_db_switcher_init(GDbSwitcher *switcher) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : switcher = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_db_switcher_dispose(GDbSwitcher *switcher) +{ + G_OBJECT_CLASS(g_db_switcher_parent_class)->dispose(G_OBJECT(switcher)); + +} + + +/****************************************************************************** +* * +* Paramètres : switcher = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_db_switcher_finalize(GDbSwitcher *switcher) +{ + G_OBJECT_CLASS(g_db_switcher_parent_class)->finalize(G_OBJECT(switcher)); + +} + + +/****************************************************************************** +* * +* Paramètres : addr = adresse inamovible localisant une position donnée. * +* comment = commentaire construit ou NULL. * +* * +* Description : Crée une définition d'un signet dans une zone de texte. * +* * +* Retour : Signet mis en place ou NULL en cas d'erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GDbSwitcher *g_db_switcher_new(const GArchInstruction *instr, const GImmOperand *imm, ImmSwitchType type) +{ + GDbSwitcher *result; /* Instance à retourner */ + size_t count; /* Nombre d'opérandes à visiter*/ + size_t i; /* Boucle de parcours */ + const mrange_t *range; /* Localisation de l'instruct° */ + + /* Recherche de la position de l'opérande */ + + count = g_arch_instruction_count_operands(instr); + + for (i = 0; i < count; i++) + if (G_ARCH_OPERAND(imm) == g_arch_instruction_get_operand(instr, i)) + break; + + if (i == count) + return NULL; + + /* Sauvegarde des propriétés */ + + result = g_object_new(G_TYPE_DB_SWITCHER, NULL); + + range = g_arch_instruction_get_range(instr); + copy_vmpa(&result->addr, get_mrange_addr(range)); + + result->index = i; + + result->type = type; + + /* Création d'un intitulé adapté */ + + + + //g_db_switcher_set_comment(result, comment); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : a = premier élément à analyser. * +* b = second élément à analyser. * +* * +* Description : Effectue la comparaison entre deux signets de collection. * +* * +* Retour : Bilan de la comparaison : -1, 0 ou 1. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static gint g_db_switcher_cmp(GDbSwitcher *a, GDbSwitcher *b) +{ + gint result; /* Bilan de la comparaison */ + + result = cmp_vmpa(&a->addr, &b->addr); + + if (result == 0) + { + if (a->index < b->index) + result = -1; + + else if (a->index > b->index) + result = 1; + + } + + if (result == 0) + { + if (a->type < b->type) + result = -1; + + else if (a->type > b->type) + result = 1; + + } + + if (result == 0) + result = G_DB_ITEM_CLASS(g_db_switcher_parent_class)->cmp(G_DB_ITEM(a), G_DB_ITEM(b)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : switcher = bascule d'affichage aux infos à charger. [OUT] * +* fd = flux ouvert en lecture pour l'importation. * +* flags = éventuelles options d'envoi supplémentaires. * +* * +* Description : Importe la définition d'une bascule d'affichage d'opérande. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_db_switcher_recv_from_fd(GDbSwitcher *switcher, int fd, int flags) +{ + bool status; /* Bilan d'opération initiale */ + uint32_t val32; /* Valeur sur 32 bits */ + ssize_t got; /* Quantité de données reçues */ + + status = G_DB_ITEM_CLASS(g_db_switcher_parent_class)->recv(G_DB_ITEM(switcher), fd, flags); + if (!status) return false; + + if (!recv_vmpa(&switcher->addr, fd, flags)) + return false; + + got = safe_recv(fd, &val32, sizeof(uint32_t), MSG_WAITALL); + if (got != sizeof(uint32_t)) return false; + + switcher->index = be32toh(val32); + + got = safe_recv(fd, &val32, sizeof(uint32_t), MSG_WAITALL); + if (got != sizeof(uint32_t)) return false; + + switcher->type = be32toh(val32); + + if (switcher->type >= IST_COUNT) + return false; + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : switcher = bascule d'affichage aux infos à sauvegarder. * +* fd = flux ouvert en écriture pour l'exportation. * +* flags = éventuelles options d'envoi supplémentaires. * +* * +* Description : Exporte la définition d'une bascule d'affichage d'opérande. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_db_switcher_send_to_fd(const GDbSwitcher *switcher, int fd, int flags) +{ + bool status; /* Bilan d'opération initiale */ + + status = G_DB_ITEM_CLASS(g_db_switcher_parent_class)->send(G_DB_ITEM(switcher), fd, MSG_MORE | flags); + if (!status) return false; + + if (!send_vmpa(&switcher->addr, fd, MSG_MORE | flags)) + return false; + + status = safe_send(fd, (uint32_t []) { htobe32(switcher->index) }, sizeof(uint32_t), MSG_MORE | flags); + if (!status) return false; + + status = safe_send(fd, (uint32_t []) { htobe32(switcher->type) }, sizeof(uint32_t), flags); + if (!status) return false; + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : switcher = base d'éléments sur laquelle s'appuyer. * +* values = couples de champs et de valeurs à lier. [OUT] * +* count = nombre de ces couples. [OUT] * +* * +* Description : Constitue les champs destinés à une insertion / modification.* +* * +* Retour : Etat du besoin en sauvegarde. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_db_switcher_prepare_db_statement(const GDbSwitcher *switcher, bound_value **values, size_t *count) +{ + bool status; /* Bilan d'opération initiale */ + bound_value *value; /* Valeur à éditer / définir */ + + status = G_DB_ITEM_CLASS(g_db_switcher_parent_class)->prepare_stmt(G_DB_ITEM(switcher), values, count); + if (!status) return false; + + status = prepare_vmpa_db_statement(&switcher->addr, values, count); + if (!status) return false; + + *count += 2; + *values = (bound_value *)realloc(*values, *count * sizeof(bound_value)); + + value = &(*values)[*count - 2]; + + value->name = "op_index"; + value->type = SQLITE_INTEGER; + value->integer = switcher->index; + value->delete = NULL; + + value = &(*values)[*count - 2]; + + value->name = "type"; + value->type = SQLITE_INTEGER; + value->integer = switcher->type; + value->delete = NULL; + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : switcher = bascule d'affichage à charger depuis les réponses.* +* values = tableau d'éléments à consulter. * +* count = nombre de descriptions renseignées. * +* * +* Description : Charge les valeurs utiles pour un basculement d'affichage. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_db_switcher_load(GDbSwitcher *switcher, const bound_value *values, size_t count) +{ + bool result; /* Bilan à faire remonter */ + const bound_value *value; /* Valeur à éditer / définir */ + + result = G_DB_ITEM_CLASS(g_db_switcher_parent_class)->load(G_DB_ITEM(switcher), values, count); + + result &= load_vmpa(&switcher->addr, values, count); + + if (result) + { + value = find_bound_value(values, count, "op_index"); + result = (value != NULL && value->type == SQLITE_INTEGER); + + if (result) + switcher->index = value->integer; + + } + + if (result) + { + value = find_bound_value(values, count, "type"); + result = (value != NULL && value->type == SQLITE_INTEGER); + + if (result) + switcher->type = value->integer; + + } + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION DE LA COLLECTION ASSOCIEE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une collection de basculements d'affichage. */ +G_DEFINE_TYPE(GSwitcherCollection, g_switcher_collection, G_TYPE_DB_COLLECTION); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des signets dans une zone de texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_switcher_collection_class_init(GSwitcherCollectionClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GDbCollectionClass *collec; /* Encore une autre vision... */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_switcher_collection_dispose; + object->finalize = (GObjectFinalizeFunc)g_switcher_collection_finalize; + + collec = G_DB_COLLECTION_CLASS(klass); + + collec->create_table = (collec_create_db_table_fc)g_switcher_collection_create_db_table; + collec->setup_load = (collec_setup_load_fc)g_switcher_collection_setup_load; + collec->has_key = (collec_has_key_fc)g_switcher_collection_has_key; + +} + + +/****************************************************************************** +* * +* Paramètres : collec = instance à initialiser. * +* * +* Description : Initialise un signet dans une zone de texte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_switcher_collection_init(GSwitcherCollection *collec) +{ + + + G_DB_COLLECTION(collec)->featuring = 0; + G_DB_COLLECTION(collec)->type = G_TYPE_DB_SWITCHER; + G_DB_COLLECTION(collec)->name = "Switchers"; + + + +} + + +/****************************************************************************** +* * +* Paramètres : collec = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_switcher_collection_dispose(GSwitcherCollection *collec) +{ + G_OBJECT_CLASS(g_switcher_collection_parent_class)->dispose(G_OBJECT(collec)); + +} + + +/****************************************************************************** +* * +* Paramètres : collec = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_switcher_collection_finalize(GSwitcherCollection *collec) +{ + G_OBJECT_CLASS(g_switcher_collection_parent_class)->finalize(G_OBJECT(collec)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Crée une collection dédiée aux basculements d'affichage. * +* * +* Retour : Collection mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GSwitcherCollection *g_switcher_collection_new(void) +{ + GSwitcherCollection *result; /* Instance à retourner */ + + result = g_object_new(G_TYPE_SWITCHER_COLLECTION, NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : collec = ensemble d'éléments spectateur des opérations. * +* db = accès à la base de données. * +* * +* Description : Crée la table des basculements dans une base de données. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_switcher_collection_create_db_table(const GSwitcherCollection *collec, sqlite3 *db) +{ + char *sql; /* Requête à exécuter */ + int ret; /* Bilan de la création */ + char *msg; /* Message d'erreur */ + + sql = "CREATE TABLE Switchers (" \ + SQLITE_DB_ITEM_CREATE ", " \ + SQLITE_VMPA_CREATE ", " \ + "op_index INTEGER, " \ + "type INTEGER" \ + ");"; + + ret = sqlite3_exec(db, sql, NULL, NULL, &msg); + if (ret != SQLITE_OK) + { + fprintf(stderr, "sqlite3_exec(): %s\n", msg); + sqlite3_free(msg); + } + + return (ret == SQLITE_OK); + +} + + +/****************************************************************************** +* * +* Paramètres : collec = ensemble d'éléments à consulter. * +* values = tableau d'éléments à compléter. [OUT] * +* count = nombre de descriptions renseignées. [OUT] * +* * +* Description : Décrit les colonnes utiles à un chargement de données. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_switcher_collection_setup_load(GSwitcherCollection *collec, bound_value **values, size_t *count) +{ + bool status; /* Bilan d'une préparation */ + + status = G_DB_COLLECTION_CLASS(g_switcher_collection_parent_class)->setup_load(G_DB_COLLECTION(collec), \ + values, count); + if (!status) return false; + + if (!setup_load_for_vmpa(NULL, values, count)) + return false; + + *count += 2; + *values = (bound_value *)realloc(*values, *count * sizeof(bound_value)); + + (*values)[*count - 2].name = "op_index"; + + (*values)[*count - 1].name = "type"; + + return true; + + +} + + +/****************************************************************************** +* * +* Paramètres : collec = ensemble d'éléments à consulter. * +* ap = clef identifiant de manière unique un élément. * +* * +* Description : Détermine si un élément est déjà présent ou non. * +* * +* Retour : Elément trouvé ou NULL si aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GDbItem *g_switcher_collection_has_key(GSwitcherCollection *collec, va_list *ap) +{ + GDbItem *result; /* Bilan à retourner */ + vmpa2t *ref; /* Adresse de référence */ + GList *items; /* Eléments déjà en place */ + GList *iter; /* Boucle de parcours */ + GDbSwitcher *bm; /* Signet à consulter */ + + result = NULL; + + ref = va_arg(ap, vmpa2t *); + + items = g_db_collection_list_items(G_DB_COLLECTION(collec)); + + for (iter = g_list_first(items); iter != NULL && result == NULL; iter = g_list_next(iter)) + { + bm = G_DB_SWITCHER(iter->data); + + if (cmp_vmpa(&bm->addr, ref) != 0) + + /** + * Un verrou est sensé être posé, donc il n'y a pas besoin + * de toucher au décompte des références car l'élément trouvé + * ne peut pas être supprimé. + */ + result = G_DB_ITEM(bm); + + } + + return result; + +} diff --git a/src/analysis/db/items/switcher.h b/src/analysis/db/items/switcher.h new file mode 100644 index 0000000..a839b3a --- /dev/null +++ b/src/analysis/db/items/switcher.h @@ -0,0 +1,121 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * switcher.h - prototypes pour la gestion des basculements d'affichage d'opérandes numériques + * + * Copyright (C) 2015 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * OpenIDA 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. + * + * OpenIDA 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 Foobar. If not, see . + */ + + +#ifndef _ANALYSIS_DB_ITEMS_SWITCHER_H +#define _ANALYSIS_DB_ITEMS_SWITCHER_H + + +#include +#include +#include + + +#include "../../../arch/immediate.h" +#include "../../../arch/instruction.h" + + + +/* Crée la table des signets dans une base de données. */ +bool create_switcher_db_table(sqlite3 *); + + + + + +/* --------------------- ELABORATION D'UN ELEMENT DE COLLECTION --------------------- */ + + +/* Basculement d'affichage de valeurs immédiates */ +typedef enum _ImmSwitchType +{ + IST_DEFAULT, /* Impression par défaut */ + IST_HEXDECIMAL, /* Impression en hexadécimal */ + IST_DECIMAL, /* Impression en décimal */ + IST_OCTAL, /* Impression en octal */ + IST_BINARY, /* Impression en binaire */ + + IST_COUNT + +} ImmSwitchType; + + +#define G_TYPE_DB_SWITCHER g_db_switcher_get_type() +#define G_DB_SWITCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_db_switcher_get_type(), GDbSwitcher)) +#define G_IS_DB_SWITCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_db_switcher_get_type())) +#define G_DB_SWITCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_DB_SWITCHER, GDbSwitcherClass)) +#define G_IS_DB_SWITCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_DB_SWITCHER)) +#define G_DB_SWITCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_DB_SWITCHER, GDbSwitcherClass)) + + +/* Bascule d'affichage pour un opérande numérique (instance) */ +typedef struct _GDbSwitcher GDbSwitcher; + +/* Bascule d'affichage pour un opérande numérique (classe) */ +typedef struct _GDbSwitcherClass GDbSwitcherClass; + + +/* Indique le type défini pour un signet à l'intérieur d'une zone de texte. */ +GType g_db_switcher_get_type(void); + +/* Crée une définition d'un signet dans une zone de texte. */ +GDbSwitcher *g_db_switcher_new(const GArchInstruction *, const GImmOperand *, ImmSwitchType); + +#if 0 +/* Fournit l'adresse associée à un signet. */ +const vmpa2t *g_db_switcher_get_address(GDbSwitcher *); + +/* Fournit le commentaire associé à un signet. */ +const char *g_db_switcher_get_comment(const GDbSwitcher *); + +/* Définit le commentaire associé à un signet. */ +void g_db_switcher_set_comment(GDbSwitcher *, const char *); +#endif + + +/* ---------------------- DEFINITION DE LA COLLECTION ASSOCIEE ---------------------- */ + + +#define G_TYPE_SWITCHER_COLLECTION g_switcher_collection_get_type() +#define G_SWITCHER_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_switcher_collection_get_type(), GSwitcherCollection)) +#define G_IS_SWITCHER_COLLECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_switcher_collection_get_type())) +#define G_SWITCHER_COLLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SWITCHER_COLLECTION, GSwitcherCollectionClass)) +#define G_IS_SWITCHER_COLLECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SWITCHER_COLLECTION)) +#define G_SWITCHER_COLLECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SWITCHER_COLLECTION, GSwitcherCollectionClass)) + + +/* Collection dédiée aux basculements d'affichage (instance) */ +typedef struct _GSwitcherCollection GSwitcherCollection; + +/* Collection dédiée aux basculements d'affichage (classe) */ +typedef struct _GSwitcherCollectionClass GSwitcherCollectionClass; + + +/* Indique le type défini pour une collection de basculements d'affichage. */ +GType g_switcher_collection_get_type(void); + +/* Crée une collection dédiée aux basculements d'affichage. */ +GSwitcherCollection *g_switcher_collection_new(void); + + + +#endif /* _ANALYSIS_DB_ITEMS_SWITCH_H */ diff --git a/src/analysis/db/misc/rlestr.c b/src/analysis/db/misc/rlestr.c index 631b1e9..9986967 100644 --- a/src/analysis/db/misc/rlestr.c +++ b/src/analysis/db/misc/rlestr.c @@ -26,6 +26,7 @@ #include #include +#include #include @@ -33,25 +34,6 @@ - -#include -#include -#include - -#include -#include - - - - - - - - - - - - /****************************************************************************** * * * Paramètres : str = représentation de chaîne à traiter. * @@ -180,8 +162,9 @@ int cmp_rle_string(const rle_string *s1, const rle_string *s2) /****************************************************************************** * * -* Paramètres : str = informations à constituer. [OUT] * -* fd = flux ouvert en lecture pour l'importation. * +* Paramètres : str = informations à constituer. [OUT] * +* fd = flux ouvert en lecture pour l'importation. * +* flags = éventuelles options de réception supplémentaires. * * * * Description : Importe la définition d'une chaîne de caractères. * * * @@ -191,23 +174,25 @@ int cmp_rle_string(const rle_string *s1, const rle_string *s2) * * ******************************************************************************/ -bool load_rle_string(rle_string *str, int fd) +bool recv_rle_string(rle_string *str, int fd, int flags) { -#if 0 uint32_t val32; /* Valeur sur 32 bits */ - ssize_t got; /* Quantité de données reçues */ + bool status; /* Bilan d'une opération */ - got = safe_recv(fd, &val32, sizeof(uint32_t), MSG_WAITALL); - if (got != sizeof(uint32_t)) return false; + str->data = NULL; + str->length = 0; + + status = safe_recv(fd, &val32, sizeof(uint32_t), MSG_WAITALL | flags); + if (!status) return false; - str->length = le32toh(val32); + str->length = be32toh(val32); if (str->length > 0) { str->data = (char *)malloc(str->length + 1); - got = safe_recv(fd, str->data, str->length + 1, MSG_WAITALL); - if (got != (str->length + 1)) + status = safe_recv(fd, str->data, str->length + 1, MSG_WAITALL | flags); + if (!status) { unset_rle_string(str); return false; @@ -216,7 +201,7 @@ bool load_rle_string(rle_string *str, int fd) str->data[str->length] = '\0'; } -#endif + return true; } @@ -224,8 +209,9 @@ bool load_rle_string(rle_string *str, int fd) /****************************************************************************** * * -* Paramètres : str = informations à sauvegarer. * -* fd = flux ouvert en écriture pour l'exportation. * +* Paramètres : str = informations à sauvegarer. * +* fd = flux ouvert en écriture pour l'exportation. * +* flags = éventuelles options d'envoi supplémentaires. * * * * Description : Exporte la définition d'une chaîne de caractères. * * * @@ -235,44 +221,70 @@ bool load_rle_string(rle_string *str, int fd) * * ******************************************************************************/ -bool store_rle_string(const rle_string *str, int fd) +bool send_rle_string(const rle_string *str, int fd, int flags) { -#if 0 - ssize_t got; /* Quantité de données reçues */ + bool status; /* Bilan d'une opération */ - got = safe_send(fd, (uint32_t []) { htole32(str->length) }, sizeof(uint32_t), MSG_WAITALL); - if (got != sizeof(uint32_t)) return false; + status = safe_send(fd, (uint32_t []) { htobe32(str->length) }, sizeof(uint32_t), MSG_MORE | flags); + if (!status) return false; if (str->length > 0) { - got = safe_send(fd, str->data, str->length + 1, MSG_WAITALL); - if (got != (str->length + 1)) return false; + status = safe_send(fd, str->data, str->length + 1, flags); + if (!status) return false; } -#endif + return true; } +/* ---------------------------------------------------------------------------------- */ +/* MANIPULATIONS AVEC UNE BASE DE DONNEES */ +/* ---------------------------------------------------------------------------------- */ +/****************************************************************************** +* * +* Paramètres : str = chaîne de caractères aux informations inutiles. * +* name = désignation personnalisée du champ dans la BD. * +* values = couples de champs et de valeurs à lier. [OUT] * +* count = nombre de ces couples. [OUT] * +* * +* Description : Constitue les champs destinés à une insertion / modification.* +* * +* Retour : Bilan de l'opération : succès ou non. * +* * +* Remarques : - * +* * +******************************************************************************/ +bool prepare_db_statement_for_rle_string(const rle_string *str, const char *name, bound_value **values, size_t *count) +{ + bound_value *value; /* Valeur à éditer / définir */ + *values = (bound_value *)realloc(*values, ++(*count) * sizeof(bound_value)); + value = &(*values)[*count - 1]; + value->name = name; + value->type = SQLITE_TEXT; + value->cstring = get_rle_string(str); + value->delete = SQLITE_STATIC; + return true; - - +} /****************************************************************************** * * -* Paramètres : str = informations à constituer. [OUT] * -* fd = flux ouvert en lecture pour l'importation. * -* flags = éventuelles options de réception supplémentaires. * +* Paramètres : str = chaîne de caractères aux informations inutiles. * +* name = désignation personnalisée du champ dans la BD. * +* values = tableau d'éléments à compléter. [OUT] * +* count = nombre de descriptions renseignées. [OUT] * * * -* Description : Importe la définition d'une chaîne de caractères. * +* Description : Décrit les colonnes utiles à une chaîne de caractères. * * * * Retour : Bilan de l'opération. * * * @@ -280,46 +292,26 @@ bool store_rle_string(const rle_string *str, int fd) * * ******************************************************************************/ -bool recv_rle_string(rle_string *str, int fd, int flags) +bool setup_load_of_rle_string(const rle_string *str, const char *name, bound_value **values, size_t *count) { - uint32_t val32; /* Valeur sur 32 bits */ - bool status; /* Bilan d'une opération */ - - str->data = NULL; - str->length = 0; - - status = safe_recv(fd, &val32, sizeof(uint32_t), flags); - if (!status) return false; - - str->length = be32toh(val32); - - if (str->length > 0) - { - str->data = (char *)malloc(str->length + 1); - - status = safe_recv(fd, str->data, str->length + 1, flags); - if (!status) - { - unset_rle_string(str); - return false; - } - - str->data[str->length] = '\0'; + *values = (bound_value *)realloc(*values, ++(*count) * sizeof(bound_value)); - } + (*values)[*count - 1].name = name; return true; + } /****************************************************************************** * * -* Paramètres : str = informations à sauvegarer. * -* fd = flux ouvert en écriture pour l'exportation. * -* flags = éventuelles options d'envoi supplémentaires. * +* Paramètres : str = chaîne de caractères à compléter. * +* name = désignation personnalisée du champ dans la BD. * +* values = tableau d'éléments à consulter. * +* count = nombre de descriptions renseignées. * * * -* Description : Exporte la définition d'une chaîne de caractères. * +* Description : Charge les valeurs utiles pour une chaîne de caractères. * * * * Retour : Bilan de l'opération. * * * @@ -327,17 +319,27 @@ bool recv_rle_string(rle_string *str, int fd, int flags) * * ******************************************************************************/ -bool send_rle_string(const rle_string *str, int fd, int flags) +bool load_rle_string(rle_string *str, const char *name, const bound_value *values, size_t count) { - bool status; /* Bilan d'une opération */ + const bound_value *value; /* Valeur à intégrer */ - status = safe_send(fd, (uint32_t []) { htobe32(str->length) }, sizeof(uint32_t), MSG_MORE | flags); - if (!status) return false; + value = find_bound_value(values, count, name); + if (value == NULL) return false; - if (str->length > 0) + switch (value->type) { - status = safe_send(fd, str->data, str->length + 1, flags); - if (!status) return false; + case SQLITE_TEXT: + set_rle_string(str, value->cstring); + break; + + case SQLITE_NULL: + set_rle_string(str, NULL); + break; + + default: + return false; + break; + } return true; diff --git a/src/analysis/db/misc/rlestr.h b/src/analysis/db/misc/rlestr.h index 2aa863f..7faafd0 100644 --- a/src/analysis/db/misc/rlestr.h +++ b/src/analysis/db/misc/rlestr.h @@ -30,6 +30,9 @@ #include +#include "../../../common/sqlite.h" + + /* Informations de base pour tout élément ajouté */ typedef struct _rle_string @@ -49,6 +52,8 @@ void init_rle_string(rle_string *, const char *); #define get_rle_string(rle) (rle)->data +#define is_rle_string_empty(rle) ((rle)->data == NULL) + /* Constitue une représentation de chaîne de caractères. */ void set_rle_string(rle_string *, const char *); @@ -58,25 +63,29 @@ void unset_rle_string(rle_string *); /* Effectue la comparaison entre deux chaînes de caractères. */ int cmp_rle_string(const rle_string *, const rle_string *); - - /* Importe la définition d'une chaîne de caractères. */ -bool load_rle_string(rle_string *, int); +bool recv_rle_string(rle_string *, int, int); /* Exporte la définition d'une chaîne de caractères. */ -bool store_rle_string(const rle_string *, int); +bool send_rle_string(const rle_string *, int, int); -#define is_rle_string_empty(rle) ((rle)->data == NULL) +/* --------------------- MANIPULATIONS AVEC UNE BASE DE DONNEES --------------------- */ +/* Définition du tronc commun pour les créations SQLite */ +#define SQLITE_RLESTR_CREATE(n) \ + n " TEXT" -/* Importe la définition d'une chaîne de caractères. */ -bool recv_rle_string(rle_string *, int, int); +/* Constitue les champs destinés à une insertion / modification. */ +bool prepare_db_statement_for_rle_string(const rle_string *, const char *, bound_value **, size_t *); -/* Exporte la définition d'une chaîne de caractères. */ -bool send_rle_string(const rle_string *, int, int); +/* Décrit les colonnes utiles à une chaîne de caractères. */ +bool setup_load_of_rle_string(const rle_string *, const char *, bound_value **, size_t *); + +/* Charge les valeurs utiles pour une chaîne de caractères. */ +bool load_rle_string(rle_string *, const char *, const bound_value *, size_t); diff --git a/src/analysis/db/protocol.h b/src/analysis/db/protocol.h index 85d44cb..04bbd33 100644 --- a/src/analysis/db/protocol.h +++ b/src/analysis/db/protocol.h @@ -29,7 +29,7 @@ /** * Version de la définition courante du protocole. */ -#define CDB_PROTOCOL_VERSION 0xc0de0001 +#define CDB_PROTOCOL_VERSION 0xc0de0002 @@ -84,7 +84,7 @@ typedef enum _DBFeatures { DBF_BOOKMARKS, /* Signets dans le code */ DBF_COMMENTS, /* Commentaires ajoutés */ - DBF_SEGMENTS_DISPLAY, /* Choix d'affichage */ + DBF_DISPLAY_SWITCHERS, /* Choix d'affichage */ DBF_COUNT @@ -132,9 +132,13 @@ typedef enum _DBCommand typedef enum _DBError { DBE_NONE, /* Succès d'une opération */ + DBE_BAD_EXCHANGE, /* Incohérence des échanges */ + DBE_WRONG_VERSION, /* Proto Client != Serveur */ DBE_SYS_ERROR, /* Erreur suite à un appel sys.*/ DBE_ARCHIVE_ERROR, /* Soucis du côté libarchive */ + DBE_XML_VERSION_ERROR, /* Vieille archive présente */ + DBE_DB_LOADING_ERROR, /* Erreur pendant le chargement*/ DBE_COUNT diff --git a/src/analysis/db/server.c b/src/analysis/db/server.c index c51c21e..3ef1ce0 100644 --- a/src/analysis/db/server.c +++ b/src/analysis/db/server.c @@ -24,6 +24,7 @@ #include "server.h" +#include #include #include #include @@ -247,26 +248,14 @@ static void *g_db_server_listener(GDbServer *server) int fd; /* Canal établi vers un client */ char source[INET6_ADDRSTRLEN]; /* Adresse du client (IPv4/6) */ const char *ip; /* Statut de la conversion */ - - DBError error; /* Validation de la connexion */ - - uint32_t data; /* Mot de données lues */ - - + uint32_t cmd; /* Commande initiale lue */ + uint32_t version; /* Version du client lue */ rle_string hash; /* Empreinte du binaire visé */ rle_string user; /* Nom d'utilisateur du client */ - GList *iter; /* Boucle de parcours */ GCdbArchive *archive; /* Destinataire final du client*/ - - - //cdb_client *client; /* Mémorisation pour poursuite */ - - - - fds.fd = server->fd; fds.events = POLLIN | POLLPRI; @@ -307,39 +296,68 @@ static void *g_db_server_listener(GDbServer *server) * Tout ceci est à synchroniser avec la fonction g_db_client_start(). */ - if (!safe_recv(fd, &data, sizeof(uint32_t), 0)) - goto gdsl_error; + if (!safe_recv(fd, &cmd, sizeof(uint32_t), 0)) + { + log_variadic_message(LMT_ERROR, _("Error while getting the initial command from '%s:%hu'..."), + source, ntohs(peer.sin_port)); + error = DBE_BAD_EXCHANGE; + goto gdsl_error_sending; + } - if (be32toh(data) != DBC_HELO) + if (!safe_recv(fd, &version, sizeof(uint32_t), 0)) { - log_variadic_message(LMT_ERROR, _("The client from '%s:%hu' did not introduce itself!"), + log_variadic_message(LMT_ERROR, _("Error while getting the protocol version from '%s:%hu'..."), source, ntohs(peer.sin_port)); - goto gdsl_error; + error = DBE_BAD_EXCHANGE; + goto gdsl_error_sending; } - if (!safe_recv(fd, &data, sizeof(uint32_t), 0)) - goto gdsl_error; + if (!recv_rle_string(&hash, fd, 0)) + { + log_variadic_message(LMT_ERROR, _("Error while getting the binary hash from '%s:%hu'..."), + source, ntohs(peer.sin_port)); + error = DBE_BAD_EXCHANGE; + goto gdsl_error_sending; + } + + if (!recv_rle_string(&user, fd, 0)) + { + log_variadic_message(LMT_ERROR, _("Error while getting the user name from '%s:%hu'..."), + source, ntohs(peer.sin_port)); + error = DBE_BAD_EXCHANGE; + goto gdsl_error_sending; + } + + if (be32toh(cmd) != DBC_HELO) + { + log_variadic_message(LMT_ERROR, _("The client from '%s:%hu' did not introduce itself!"), + source, ntohs(peer.sin_port)); + error = DBE_BAD_EXCHANGE; + goto gdsl_error_sending; + } - if (be32toh(data) != CDB_PROTOCOL_VERSION) + if (be32toh(version) != CDB_PROTOCOL_VERSION) { log_variadic_message(LMT_ERROR, _("The client from '%s:%hu' does not use the same protocol: 0x%08x vs 0x%08x..."), - source, ntohs(peer.sin_port), be32toh(data), CDB_PROTOCOL_VERSION); + source, ntohs(peer.sin_port), be32toh(version), CDB_PROTOCOL_VERSION); error = DBE_WRONG_VERSION; goto gdsl_error_sending; } - if (!recv_rle_string(&hash, fd, 0) || is_rle_string_empty(&hash)) + if (is_rle_string_empty(&hash)) { - log_variadic_message(LMT_ERROR, _("Error while getting the binary hash from '%s:%hu'..."), + log_variadic_message(LMT_ERROR, _("The submitted binary hash from '%s:%hu' is empty!"), source, ntohs(peer.sin_port)); - goto gdsl_error; + error = DBE_BAD_EXCHANGE; + goto gdsl_error_sending; } - if (!recv_rle_string(&user, fd, 0) || is_rle_string_empty(&user)) + if (is_rle_string_empty(&user)) { - log_variadic_message(LMT_ERROR, _("Error while getting the user name from '%s:%hu'..."), + log_variadic_message(LMT_ERROR, _("No user is associated with the client from '%s:%hu'..."), source, ntohs(peer.sin_port)); - goto gdsl_error; + error = DBE_BAD_EXCHANGE; + goto gdsl_error_sending; } /** @@ -347,6 +365,8 @@ static void *g_db_server_listener(GDbServer *server) * en cas d'échec, et être le plus précis possible dans la courte réponse. */ + assert(error == DBE_NONE); + for (iter = g_list_first(server->archives); iter != NULL; iter = g_list_next(iter)) @@ -357,23 +377,13 @@ static void *g_db_server_listener(GDbServer *server) } if (iter == NULL) - { archive = g_cdb_archive_new(server->desc, &hash, &user, &error); - if (archive != NULL) - server->archives = g_list_append(server->archives, archive); - - } - - /* - if (archive != NULL) - error = g_cdb_archive_add_client(archive, fd, &user); - */ - /** * Le serveur doit répondre pour un message type : * - la commande 'DBC_WELCOME'. - * - un identifiant d'erreur ('DBE_NONE' ou 'DBE_WRONG_VERSION'). + * - un identifiant d'erreur ('DBE_NONE', 'DBE_BAD_EXCHANGE' + * ou 'DBE_WRONG_VERSION' ... 'DBE_LOADING_ERROR'). */ gdsl_error_sending: @@ -384,52 +394,37 @@ static void *g_db_server_listener(GDbServer *server) if (!safe_send(fd, (uint32_t []) { htobe32(error) }, sizeof(uint32_t), 0)) goto gdsl_error; - //if (error == DBE_NONE) continue; - + /** + * L'ajout dans la liste des clients connectés provoque un envoie de mises à jour. + * L'éventuelle erreur survenant pendant l'envoi ne peut donc pas être remontée + * lors des échanges initiaux, car ces derniers seraient alors précédés des mises à jour... + */ if (archive != NULL) + { + assert(error == DBE_NONE); + + server->archives = g_list_append(server->archives, archive); error = g_cdb_archive_add_client(archive, fd, &user); - continue; + exit_rle_string(&hash); + exit_rle_string(&user); + continue; - gdsl_error: + } + assert(error != DBE_NONE); - /* free RLE !!!! */ + gdsl_error: + exit_rle_string(&hash); + exit_rle_string(&user); close(fd); } - - - -#if 0 - g_mutex_lock(&server->mutex); - - client = (cdb_client *)calloc(1, sizeof(cdb_client)); - - g_object_ref(G_OBJECT(server)); - client->server = server; - - client->fd = fd; - client->peer = peer; - - server->clients = (cdb_client **)realloc(server->clients, - ++server->count * sizeof(cdb_client *)); - server->clients[server->count - 1] = client; - - client->thread = g_thread_new("cdb_process", (GThreadFunc)g_db_server_process, - &server->clients[server->count - 1]); - - g_mutex_unlock(&server->mutex); -#endif - - - - } return NULL; diff --git a/src/arch/vmpa.c b/src/arch/vmpa.c index d966341..9f2245c 100644 --- a/src/arch/vmpa.c +++ b/src/arch/vmpa.c @@ -320,12 +320,12 @@ bool recv_vmpa(vmpa2t *addr, int fd, int flags) virt_t val64; /* Valeur sur 64 bits */ bool status; /* Bilan d'une réception */ - status = safe_recv(fd, &val64, sizeof(virt_t), flags); + status = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL | flags); if (!status) return false; addr->physical = be64toh(val64); - status = safe_recv(fd, &val64, sizeof(virt_t), flags); + status = safe_recv(fd, &val64, sizeof(uint64_t), MSG_WAITALL | flags); if (!status) return false; addr->virtual = be64toh(val64); @@ -353,10 +353,10 @@ bool send_vmpa(const vmpa2t *addr, int fd, int flags) { bool status; /* Bilan d'une émission */ - status = safe_send(fd, (virt_t []) { htobe64(addr->physical) }, sizeof(virt_t), flags); + status = safe_send(fd, (uint64_t []) { htobe64(addr->physical) }, sizeof(uint64_t), MSG_MORE | flags); if (!status) return false; - status = safe_send(fd, (virt_t []) { htobe64(addr->virtual) }, sizeof(virt_t), flags); + status = safe_send(fd, (uint64_t []) { htobe64(addr->virtual) }, sizeof(uint64_t), flags); if (!status) return false; return true; @@ -612,7 +612,6 @@ bool load_vmpa(vmpa2t *addr, const bound_value *values, size_t count) /****************************************************************************** * * * Paramètres : addr = adresse virtuelle ou physique à traiter. * -* create = indique si la préparation vise une création ou non. * * values = couples de champs et de valeurs à lier. [OUT] * * count = nombre de ces couples. [OUT] * * * @@ -624,7 +623,7 @@ bool load_vmpa(vmpa2t *addr, const bound_value *values, size_t count) * * ******************************************************************************/ -bool prepare_vmpa_db_statement(const vmpa2t *addr, bool create, bound_value **values, size_t *count) +bool prepare_vmpa_db_statement(const vmpa2t *addr, bound_value **values, size_t *count) { bound_value *value; /* Valeur à éditer / définir */ diff --git a/src/arch/vmpa.h b/src/arch/vmpa.h index 368b765..8881ac1 100644 --- a/src/arch/vmpa.h +++ b/src/arch/vmpa.h @@ -138,7 +138,7 @@ vmpa2t *string_to_vmpa_virt(const char *); /* Définition du tronc commun pour les créations SQLite */ #define SQLITE_VMPA_CREATE \ "phys INTEGER, " \ - "virt INTEGER, " + "virt INTEGER" /* Décrit les colonnes utiles à un chargement de données. */ bool setup_load_for_vmpa(const vmpa2t *, bound_value **, size_t *); @@ -147,7 +147,7 @@ bool setup_load_for_vmpa(const vmpa2t *, bound_value **, size_t *); bool load_vmpa(vmpa2t *, const bound_value *, size_t); /* Constitue les champs destinés à une insertion / modification. */ -bool prepare_vmpa_db_statement(const vmpa2t *, bool, bound_value **, size_t *); +bool prepare_vmpa_db_statement(const vmpa2t *, bound_value **, size_t *); diff --git a/src/common/sqlite.h b/src/common/sqlite.h index 559af38..26dbd33 100644 --- a/src/common/sqlite.h +++ b/src/common/sqlite.h @@ -43,6 +43,7 @@ typedef struct _bound_value union { + int32_t integer; /* Nombre sur 32 bits */ int64_t integer64; /* Nombre sur 64 bits */ char *string; /* Chaîne de caractères #1 */ const char *cstring; /* Chaîne de caractères #2 */ diff --git a/src/core/collections.c b/src/core/collections.c index c867d57..08c97e1 100644 --- a/src/core/collections.c +++ b/src/core/collections.c @@ -32,20 +32,13 @@ #include "../analysis/db/collection.h" #include "../analysis/db/protocol.h" #include "../analysis/db/items/bookmark.h" +#include "../analysis/db/items/comment.h" +#include "../analysis/db/items/switcher.h" -/* Caractéristiques d'une collection */ -typedef struct _collec_t -{ - GType items; /* Type d'éléments rassemblés */ - create_db_table_fc create; /* Création de la BD associée */ - -} collec_t; - - /* Mémorisation des types de collection enregistrés */ -static collec_t *_collection_definitions = NULL; +static GType *_collection_definitions = NULL; static uint32_t _collection_definitions_count = 0; /* Verrou pour des accès atomiques */ @@ -55,8 +48,7 @@ static uint32_t _collection_definitions_count = 0; /****************************************************************************** * * -* Paramètres : items = type GLib des éléments constituant une collection. * -* create = création de la base de données correspondante. * +* Paramètres : items = type GLib des éléments constituant une collection. * * * * Description : Enregistre un type d'élément à gérer par collection. * * * @@ -66,7 +58,7 @@ static uint32_t _collection_definitions_count = 0; * * ******************************************************************************/ -uint32_t register_collection_type(GType items, create_db_table_fc create) +uint32_t register_collection_type(GType items) { uint32_t result; /* Identifiant à retourner */ @@ -74,11 +66,10 @@ uint32_t register_collection_type(GType items, create_db_table_fc create) result = _collection_definitions_count++; - _collection_definitions = (collec_t *)realloc(_collection_definitions, - _collection_definitions_count * sizeof(collec_t)); + _collection_definitions = (GType *)realloc(_collection_definitions, + _collection_definitions_count * sizeof(GType)); - _collection_definitions[result].items = items; - _collection_definitions[result].create = create; + _collection_definitions[result] = items; /* TODO : unlock */ @@ -109,9 +100,15 @@ bool load_hard_coded_collection_definitions(void) * afin de garder la correspondance entre les identifiants. */ - id = register_collection_type(G_TYPE_BM_COLLECTION, create_bookmark_db_table); + id = register_collection_type(G_TYPE_BM_COLLECTION); assert(id == DBF_BOOKMARKS); + id = register_collection_type(G_TYPE_COMMENT_COLLECTION); + assert(id == DBF_COMMENTS); + + id = register_collection_type(G_TYPE_SWITCHER_COLLECTION); + assert(id == DBF_DISPLAY_SWITCHERS); + return true; } @@ -156,16 +153,13 @@ GList *create_collections_list(void) { GList *result; /* Groupe à retourner */ uint32_t i; /* Boucle de parcours */ - const collec_t *def; /* Définition brute à lire */ GDbCollection *collec; /* Nouveau groupe à intégrer */ result = NULL; for (i = 0; i < _collection_definitions_count; i++) { - def = &_collection_definitions[i]; - //collec = g_db_collection_new(i, def->items, "Bookmarks"); - collec = g_object_new(def->items, NULL); + collec = g_object_new(_collection_definitions[i], NULL); result = g_list_append(result, collec); diff --git a/src/core/collections.h b/src/core/collections.h index b84bdd9..dbe869a 100644 --- a/src/core/collections.h +++ b/src/core/collections.h @@ -32,13 +32,8 @@ -/* Crée la table dans une base de données. */ -typedef bool (* create_db_table_fc) (sqlite3 *); - - - /* Enregistre un type d'élément à gérer par collection. */ -uint32_t register_collection_type(GType, create_db_table_fc); +uint32_t register_collection_type(GType); /* Charge les définitions de collections "natives". */ bool load_hard_coded_collection_definitions(void); diff --git a/src/dialogs/storage.c b/src/dialogs/storage.c index 3db3d97..614a46c 100644 --- a/src/dialogs/storage.c +++ b/src/dialogs/storage.c @@ -537,7 +537,7 @@ static void fill_storage_features(GtkTreeView *treeview, GLoadedBinary *binary) case DBF_COMMENTS: human_feature = _("Comments"); break; - case DBF_SEGMENTS_DISPLAY: + case DBF_DISPLAY_SWITCHERS: human_feature = _("Segments display"); break; case DBF_BOOKMARKS: diff --git a/src/gui/menus/edition.c b/src/gui/menus/edition.c index 040c8ab..d49f794 100644 --- a/src/gui/menus/edition.c +++ b/src/gui/menus/edition.c @@ -25,9 +25,13 @@ #include "edition.h" +#include + + #include +#include "../../analysis/db/items/switcher.h" #include "../../arch/target.h" #include "../../dialogs/bookmark.h" #include "../../dialogs/goto.h" @@ -40,6 +44,9 @@ /* Réagit avec le menu "Edition -> Aller à l'adresse...". */ static void mcb_edition_goto(GtkMenuItem *, GMenuBar *); +/* Réagit avec le menu "Edition -> Operande numérique -> ...". */ +static void mcb_edition_switch_numeric_operand(GtkMenuItem *, GMenuBar *); + /* Réagit avec le menu "Edition -> Suivre la référence". */ static void mcb_edition_follow_ref(GtkMenuItem *, GMenuBar *); @@ -87,6 +94,47 @@ GtkWidget *build_menu_edition(GObject *ref, GtkAccelGroup *accgroup, GMenuBar *b submenuitem = qck_create_menu_separator(); gtk_container_add(GTK_CONTAINER(menubar), submenuitem); + submenuitem = qck_create_menu_item(NULL, NULL, _("Numeric operand"), NULL, NULL); + gtk_container_add(GTK_CONTAINER(menubar), submenuitem); + + deepmenubar = gtk_menu_new(); + gtk_menu_item_set_submenu(GTK_MENU_ITEM(submenuitem), deepmenubar); + + deepmenuitem = qck_create_menu_item(NULL, NULL, _("Hexadecimal"), + G_CALLBACK(mcb_edition_switch_numeric_operand), bar); + add_accelerator_to_menu_item(deepmenuitem, "H", accgroup); + g_object_set_data(G_OBJECT(deepmenuitem), "kind_of_switch", GUINT_TO_POINTER(IST_HEXDECIMAL)); + gtk_container_add(GTK_CONTAINER(deepmenubar), deepmenuitem); + + deepmenuitem = qck_create_menu_item(NULL, NULL, _("Decimal"), + G_CALLBACK(mcb_edition_switch_numeric_operand), bar); + add_accelerator_to_menu_item(deepmenuitem, "D", accgroup); + g_object_set_data(G_OBJECT(deepmenuitem), "kind_of_switch", GUINT_TO_POINTER(IST_DECIMAL)); + gtk_container_add(GTK_CONTAINER(deepmenubar), deepmenuitem); + + deepmenuitem = qck_create_menu_item(NULL, NULL, _("Octal"), + G_CALLBACK(mcb_edition_switch_numeric_operand), bar); + add_accelerator_to_menu_item(deepmenuitem, "O", accgroup); + g_object_set_data(G_OBJECT(deepmenuitem), "kind_of_switch", GUINT_TO_POINTER(IST_OCTAL)); + gtk_container_add(GTK_CONTAINER(deepmenubar), deepmenuitem); + + deepmenuitem = qck_create_menu_item(NULL, NULL, _("Binary"), + G_CALLBACK(mcb_edition_switch_numeric_operand), bar); + add_accelerator_to_menu_item(deepmenuitem, "B", accgroup); + g_object_set_data(G_OBJECT(deepmenuitem), "kind_of_switch", GUINT_TO_POINTER(IST_BINARY)); + gtk_container_add(GTK_CONTAINER(deepmenubar), deepmenuitem); + + deepmenuitem = qck_create_menu_separator(); + gtk_container_add(GTK_CONTAINER(deepmenubar), deepmenuitem); + + deepmenuitem = qck_create_menu_item(NULL, NULL, _("Default"), + G_CALLBACK(mcb_edition_switch_numeric_operand), bar); + g_object_set_data(G_OBJECT(deepmenuitem), "kind_of_switch", GUINT_TO_POINTER(IST_DEFAULT)); + gtk_container_add(GTK_CONTAINER(deepmenubar), deepmenuitem); + + submenuitem = qck_create_menu_separator(); + gtk_container_add(GTK_CONTAINER(menubar), submenuitem); + submenuitem = qck_create_menu_item(ref, "mnu_edit_follow_ref", _("Follow the reference"), G_CALLBACK(mcb_edition_follow_ref), bar); add_accelerator_to_menu_item(submenuitem, "Return", accgroup); @@ -111,7 +159,6 @@ GtkWidget *build_menu_edition(GObject *ref, GtkAccelGroup *accgroup, GMenuBar *b add_accelerator_to_menu_item(deepmenuitem, "D", accgroup); gtk_container_add(GTK_CONTAINER(deepmenubar), deepmenuitem); - return result; } @@ -161,6 +208,65 @@ static void mcb_edition_goto(GtkMenuItem *menuitem, GMenuBar *bar) * Paramètres : menuitem = élément de menu sélectionné. * * bar = barre de menu parente. * * * +* Description : Réagit avec le menu "Edition -> Operande numérique -> ...". * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void mcb_edition_switch_numeric_operand(GtkMenuItem *menuitem, GMenuBar *bar) +{ + ImmSwitchType type; /* Type de basculement */ + GtkViewPanel *vpanel; /* Afficheur effectif de code */ + GBufferLine *line; /* Ligne de position courante */ + GBufferSegment *segment; /* Segment actif s'il existe */ + GObject *creator; /* Créateur à l'orgine du seg. */ + virt_t virt; /* Adresse virtuelle */ + vmpa2t addr; /* Adresse de destination */ + + type = GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(menuitem), "kind_of_switch")); + + vpanel = g_editor_item_get_current_view(G_EDITOR_ITEM(bar)); + + if (gtk_view_panel_get_position(vpanel, &line, &segment)) + { + if (segment != NULL) + creator = g_buffer_segment_get_creator(segment); + else + creator = NULL; + + if (creator != NULL) + { + assert(G_IS_TARGET_OPERAND(creator)); + + + + + + + + + + g_object_unref(creator); + + } + + if (segment != NULL) g_object_unref(G_OBJECT(segment)); + g_object_unref(G_OBJECT(line)); + + } + +} + + + +/****************************************************************************** +* * +* Paramètres : menuitem = élément de menu sélectionné. * +* bar = barre de menu parente. * +* * * Description : Réagit avec le menu "Edition -> Suivre la référence". * * * * Retour : - * -- cgit v0.11.2-87-g4458